Repository navigation
One captcha solve per page, OPENSEA_URL never overrides --collection, atomic writes - #7
Merged
Merged
Conversation
… atomic writes - Both challenge checks in every engine now draw on one per-page solve allowance (page_flow.SolveBudget), spent just before the purchase and not reset by retries or rotation: 5 solver calls against a limit of 1 became 1, in all three engines. - The typed --url is captured before the environment is applied, so OPENSEA_URL no longer replaces --collection/--category or blocks --mode collections; .env.example ships it commented out. - JSON, CSV and sidecar are written atomically with the mode open() would give; CSV formula-shaped strings are escaped and counted in csv_cells_escaped (merged under the caller's extra). - diff_runs compares per-mode columns, so collections and activity changes are no longer reported as 0 changed; its text describes OpenSea. - Credential scan exclusions are relative to the repo, and a scan of 0 files fails. - Numeric flags refuse values below their floor, naming the flag. - .gitignore covers NAME.pageN dumps and scratch directories by kind. - The canary fails instead of warning when OpenSea was not read. - Shipped files state their rules in their own words instead of citing section numbers of an internal document; a suite check guards it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jehrr
marked this pull request as ready for review
October 15, 2026 13:04
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.
Fixes from the 2026-10-14 audit of
mainat9dbf278, in one batch.Problems and resulting behaviour
Captcha budget (high). Each engine checks for a challenge before and after classifying page 1, and re-fetches up to 3 more times. Only the second check was counted, so a page that kept coming back as a challenge bought up to 5 solves against
SOLVES_PER_PAGE = 1in all three engines. Now both call sites take from onepage_flow.SolveBudgetper page. It is spent immediately beforesolve_recaptchaand is never reset by a retry, a fresh context or a rotation. Stub-driven probe: 1 solver call per engine.OPENSEA_URLvs builder flags (high). With the value.env.exampleshipped,--collection pudgypenguinssilently scrapedboredapeyachtclub, and--mode collectionsexited 2. The cause wasenv_config.applyfilling--urlbefore the builder ran.--collection,--categoryor--mode collections.--urlthat names a different collection from--collectionis refused..env.exampleships the variable commented out.Atomic writes.
write_json,write_csvandwrite_run_metanow write through_atomic: a temp file in the target's directory, fsync,os.replace, and cleanup on error. A new file gets0o666 & ~umask; an existing file keeps its mode. Before, an injected error insidejson.dumpleft 12 bytes of invalid JSON.CSV formula guard. Strings starting with
= + - @ TAB CR LF(checked after list joining) get a leading', in the CSV only. Numbers are untouched and the JSON is untouched.csv_cells_escapedis merged into the sidecar under the caller'sextra.diff_runs.py. Fields are now tracked per mode (items,collections,activity). The mode comes from the sidecar, or is inferred from the rows. Before, planted changes to collections volume or activityevent_typegave 0 changed. The docstring and help text no longer describe another site.Credential scan. Exclusions are now evaluated on
path.relative_to(REPO).parts. Before, a clone underlive/,captures/orvenv-work/scanned 0 files and reported clean. A 0-file scan now fails. Virtualenvs are still detected bypyvenv.cfg.CLI validation. Values below the floor now exit 2 with an argparse error naming the flag:
--pages 0,--limit 0,--concurrency 0, and negative--delay,--retry-delay,--proxy-block-retries;scraper_api_client.py:--retries -1(0 stays legal there, because it counts extra attempts).Private citations. All
§N/CLAUDE.mdreferences are gone from tracked files (about 240). That includes the citation-only edits in the released CHANGELOG section. The rules are restated in plain words. A new suite check (tokens assembled from pieces) fails if they come back. The v0.1.0 release notes contained none, so none were edited.Small items:
.gitignorenow covers*.page[0-9]*dumps,out/,output/,runs/,results/,tmp/,dumps/and root*.html. A check pins both the ignored and the must-ship sides..dockerignorenow has.env*.use_antidetectwording is removed from a docstring.tests.ymlinline sample heredoc is replaced byci_checks.py --sample-check. Theoriginal_pricecount is dropped from that check.Canary. The canary used to end green on a block. Now:
priced >= 100is replaced by "at least one priced row" plus the existing match against OpenSea's ownlistedItemCount.No secrets are needed: the canary has passed ungated from GitHub runners (2026-10-15 run: 350/148/300 rows). The three sanity blocks were re-run against that run's artefacts and all pass.
Evidence
smoke_test.py→ 11754 checks, OK.ci_checks.py --all→ OK, with 36 files scanned.pytest→ 1 passed.PYTHONDONTWRITEBYTECODE=1and__pycache__cleared. Each went red on the named check, and the tree was green after restore:--pages type=int--retries type=intwrite_jsonextraci_checks§3planted in READMECLAUDE.mdplanted.env.exampleURL uncommented.gitignorecontrol (removing*.page[0-9]*) also went red.Not changed
[Unreleased]section carries the notes).parse_rowsonshould_parse(audit L2, candidate only, no real phantom-row case).page.authenticateproxy auth (L8: needs an authorised proxy run).floors >= 50%threshold (L7, candidate).Owner questions
activityrows be diffable at all? This PR tracks every event column, so a re-indexed event surfaces.🤖 Generated with Claude Code