Repository navigation
Run all three engines against the site daily, and pin the Docker base - #17
Merged
Merged
Conversation
The audit's last two findings. One taken as offered, one taken in half with the declined half argued rather than ignored. THE CANARY TESTED ONE ENGINE OF THREE. Fair. The offline suite holds the engines to the same flags in both directions, the same shared-module signatures and one finish_run, so exit codes and sidecars cannot drift — but none of that tests whether they still agree about the SITE, and only Playwright ran against it on a schedule. The audit offered two remedies and this takes the second; the first was to declare Playwright the only supported engine, which contradicts the README and discards three working engines to close a gap one job closes. Compared on ids and schema, never on values: the runs are minutes apart and a prediction market reprices continuously, so equal prices would make a red badge about nothing. What must not differ is which markets exist, what the columns are called, and every field a market does not change by trading — an explicit allowlist, inverted from the obvious blocklist so a column added later is not compared by default and does not start failing the badge the first time the market moves. The allowlist is checked against the real columns each run, or it could shrink to nothing and pass by comparing almost nothing. data_source is in it on purpose: an engine that fell back to the DOM would match on everything else and differ only there. Verified by running it here before shipping it: all three engines on one event page returned the same 5 markets, the same 40 columns and the same 22 stable fields, with scraped_at the only field that differed. The three runs are spelled out rather than looped over $engine. A loop reads better and makes the engine names invisible to anything grepping the file, including the new check that the canary still covers every engine the README promises. PINNING. The Docker base is pinned by digest with the tag kept beside it, resolved from the tag it replaces. Built and run after pinning: 53 markets live from inside the container. Lock files are declined, and the reasoning is in the CHANGELOG: they would stop the daily canary testing new releases of the libraries, which is what catches a dependency change the morning it happens. The image is a build artefact and should be reproducible; the canary is a detector and should be exposed to what it detects. Four faults planted, suite red on a named check for each. One control first found a weakness in the CHECK rather than the code: it matched the engine's file name anywhere in the workflow, so an echo naming it was enough. It now requires an invocation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Oct 9, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The audit's last two findings. One is taken as offered, one is taken in half — with the declined half argued rather than ignored.
The canary tested one engine of three
Fair, and this takes the audit's second suggested remedy rather than its first.
The offline suite already asserts that the three engines take the same flags (in both directions — closing a documented difference fails too), bind the same shared-module signatures, and share one
finish_run, so their exit codes and sidecars cannot drift. What none of that tests is whether they still agree about the site, and only Playwright ran against it on a schedule.The first remedy on offer was to declare Playwright the only supported engine and demote the others. That contradicts the README and throws away three working engines to close a gap that one job closes.
Compared on ids and schema, not on values. The three runs happen minutes apart and a prediction market reprices continuously, so requiring equal prices would produce a red badge about nothing — and a check that is always red teaches everyone to ignore checks. What must not differ:
skuset),That last one is an explicit allowlist, inverted from the obvious blocklist on purpose: with a blocklist, a column added later is compared by default and starts failing the badge the first time the market moves. The allowlist is itself checked against the real columns on each run, or it could quietly shrink to nothing and the step would pass by comparing almost nothing.
data_sourceis in it deliberately. If one engine fell back to the DOM while its twins read the payload, every other field would still match and only that column would say so.Verified by running it here before shipping it, which is the part that would otherwise be a workflow nobody has executed:
The three engine runs are spelled out rather than looped over a
$enginevariable. A loop reads better and makes the engine names invisible to anything grepping the file — including the new offline check that asserts the canary still covers every engine the README promises. Three lines are worth a check that can fail.The job needs no secrets, like the rest of this canary. An engine that gets refused warns and says in the step summary that it did not test anything, rather than failing the badge for the runner's address; fewer than two engines returning rows is reported as "not a pass" rather than as success.
Pinning: the Docker base, yes; lock files, no
Taken. The base image is pinned by digest, with the tag kept beside it so a reader can see which release that digest is.
python:3.12-slimis a moving target, so the same Dockerfile built a month apart is a different image — a release and its own rebuild are then not the same artefact, and a regression arriving through the base reads as a regression in this code. Resolved from the tag it replaces, so it is 3.12-slim as of today rather than a version chosen here. Built and run after pinning: 53 markets live from inside the container.Declined: lock files for the Python dependencies. The audit puts these in the same breath as the Docker pin, and they are not the same trade.
A lock file would stop the daily canary from testing new releases of
requests,beautifulsoup4and the engine libraries. That daily test is the thing that catches a dependency change the morning it happens, rather than whenever someone next bumps a pin. The image is a build artefact and should be reproducible; the canary is a detector and should be exposed to exactly what it is meant to detect. Lower bounds plus a daily live run is the combination that reports breakage — pinning both halves would buy reproducibility by turning the detector off.The audit's related point about
pyproject.tomlextras drifting fromrequirements*.txtis real and is already checked offline; nothing new was needed.Verification
Four faults planted, suite required to go RED on a named check:
...pinned by digest, not by a moving tag...with the tag kept beside itthe canary runs selenium_scraper...and compares them on ids rather than on pricesThe canary-coverage check is pinned against
ENGINES, the same tuple the rest of the suite uses, so dropping an engine from the README and the canary together still fails. It skips only when the whole.github/directory is absent — the Dockerfile copies none, and this suite runs inside the image at build time — rather than when the file is missing, so a deleted workflow fails rather than passing silently.🤖 Generated with Claude Code