Repository navigation
One paid solve per page, atomic outputs, and matching exit codes in every engine - #42
Merged
Merged
Conversation
…very engine
- Captcha: a per-page SolveBudget checked before every purchase in all three
engines, not reset by retries or exit rotation (a 3-exit pool bought 3 solves
for one page before).
- Output: JSON, CSV and the sidecar are written atomically with umask-honouring
modes; CSV cells starting with = + - @ tab CR LF get an apostrophe, counted
as csv_cells_escaped in the sidecar. JSON is unchanged.
- CDP: a refused --cdp-endpoint connect exits 5 with a credential-free message;
transient 500/profile_locked retried; pyppeteer connect bounded.
- pyppeteer keeps the goto status, Selenium reads it from the browser; both
report HTTP errors and parser drift as Playwright does (exit 5, not 4).
- Suite: the skip report reads the module-level record again; new checks for
all of the above, driven through stubbed drivers.
- Credential scan: relative-path exclusions, fails on 0 files, reads data
files and .env.* backups. .gitignore covers dump/capture shapes.
- env: {...} placeholders read as unset; an empty value is not a warning.
- Docs: README exit table and stop_reason_for docstring corrected; private
citations removed and guarded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The no-proxy job is refused from GitHub's datacentre addresses (exit 3 on every one of the last 10 runs) and the proxy job skipped green without its secret, so the badge stayed green while nothing reached farfetch.com. The proxy job now fails with an ::error:: naming the missing secret; the no-proxy job is documented as "datacentre refusal expected" and is the only one that may excuse a block. The suite check that pinned the old skip is rewritten. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fallback parser wrote `currency or "USD"`, presenting a guess as a fact. It now writes only what the tile states (ISO code, prefixed or bare symbol) and null otherwise. A suite check forces an unattributed price and asserts None; planting the old default turns it red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jehrr
marked this pull request as ready for review
October 15, 2026 21:14
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, base
97b1d96.Problems and resulting behaviour
--solve-captcha alwaysbought 3 solves for one page.SolveBudget(incaptcha_solver.py) is checked before each purchase in all three engines. It is created outside the rotation loop and is not reset. Stub probe: 1 solve.connect_over_cdpfailure escaped as a traceback (exit 1). Its text repeats the endpoint,user:passincluded. pyppeteerconnect()had no timeout.profile_locked/500 is retried 3× at 3 s. The run exits 5. pyppeteer connect is bounded at 30 s.open(path,"w"): a failedjson.dumpturned a good file into a truncated one._atomic: a temp file in the target's dir, fsync, thenos.replace, with cleanup on error. A new file gets0o666 & ~umaskand an existing file keeps its mode. Checked under 022/002/077 and for a 0640 file.= + - @ \t \r \ngets a leading'(CSV only; numbers untouched; JSON untouched). The sidecar recordscsv_cells_escaped, merged under existing keys.gotostatus, so an HTTP 403 with an unknown body exited 4. Neither mirror reported parser drift. README and docstring said drift exits 4.PerformanceNavigationTiming.responseStatus. Both mirrors reporthttp_errorandparse_driftas Playwright does. Stub probe: pyppeteer 403 now exits 5. README table and docstring corrected.main()rebound_skips/_skipped_engineslocally, soSKIPPED_ENGINES:was always empty and the engine-smoke gate could not fail.venv/scanned 0 files and reported "clean". JSON and.env.*were never read.relative_to(REPO).parts, fails on 0 files, and also reads.json .csv .html .toml .cfgand.env.*backups. Thepyvenv.cfgskip is kept.currency or "USD".null. A suite check forces an unattributed price and assertsNone; the plantedor "USD"turns it red. Current output is unchanged, because every recognised price shape carries a symbol or ISO code.X.page3,live/,captures/and a rootdump.htmlwere not ignored..env.example, the samples,tests/and.github/are still tracked (checked withgit check-ignore).{login}/{password}values were applied as real credentials, and empty values logged a placeholder warning.{…}slot reads as unset, and the warning names the slot, not the value. An empty value is unset with no warning.The CHANGELOG
[Unreleased]section opens with a blockquote listing the behaviour changes: mirror exit codes, CSV escaping, and CDP-failure exit 5.Evidence
SKIPPED_ENGINES, and--helpworks in each.ruff check .is clean._fetch_one_pageand pyppeteer'sscrape()through stub drivers loaded from disk, so they run in the core-only CI job too.PYTHONDONTWRITEBYTECODE=1and__pycache__cleared. Each turned the suite red on the expected named check, with no crash, and the restored tree was green. The faults:write_jsonback toopen("w");0o644mode;_skipped_enginesre-added;.env.*read removed;Canary (owner request, 2026-10-15)
Before:
reachabilityjob was refused from the runner (exit 3, reported as a notice).production-likejob skipped with a notice, becauseFARFETCH_PROXYis not set. The repo's only secret isCLAUDE_CODE_OAUTH_TOKEN.After:
production-likefails with::error::namingFARFETCH_PROXYwhen the secret is absent.reachabilityis renamed and documented as "datacentre refusal expected". It is the only job allowed--allow-block, and a suite check pins that.completestatus, and a named fail onparse_drift. These test the parser, not merchandising.Dispatched on this branch: run 38694719863.
production-like: failure, "The FARFETCH_PROXY secret is not set…". This is the expected result until the owner adds the secret.reachability: success, with the notice "Blocked … (exit 3)".Secret required:
FARFETCH_PROXY, a residential proxy URL. It is read from the environment and never put on a command line.Not changed
--retries 0message (L4), and making--cdp-endpointcombined with--concurrency/--proxy/--fingerprintexit 2 instead of warning (L5). Both are owner decisions.FARFETCH_PROXYsecret itself (M6): the owner needs to set it.page.authenticateand client hints (L6), thechallenge-platformmarker count (L7) and detail-mode retries/captcha (L8). Each needs a live run.(§12)commit subject on main: history is not rewritten.🤖 Generated with Claude Code