Repository navigation
Keep good output on a failed write, escape CSV formulas, fail the canary without a secret - #3
Merged
Merged
Conversation
…ags win over WEBMOTORS_URL - JSON, CSV, the sidecar and diff_runs --out are written atomically (temp file beside the target, fsync, rename; new files 0o666 & ~umask, existing files keep their mode). - CSV string cells starting with = + - @ tab CR LF get a leading apostrophe; numbers and JSON untouched; csv_cells_escaped in the sidecar under the caller's extra. - .env.example ships WEBMOTORS_URL commented out, and an environment URL gives way to typed search flags, --ads-file or a different --mode. - Negative delays/counts and --concurrency/--pages below 1 are usage errors naming the flag, in every engine and the Scraper API client. - The CDP 401 hint no longer claims credentials last about a day. - The canary fails by name without WEBMOTORS_PROXY/WEBMOTORS_CDP_ENDPOINT instead of skipping green, accepts either, and covers ad mode. - Bug template example uses this scraper's flags; banned-wording scan skips virtualenvs; comments state rules instead of citing private notes, with a suite guard against their return. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jehrr
marked this pull request as ready for review
October 15, 2026 22:19
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.
Problem
An audit of
mainat 47789df found:json.dumpfailed partway, a good 994-byteout.jsonand itsout.meta.jsonwere left as 16 bytes of invalid JSON. The previous good run was destroyed by the attempt to replace it.=HYPERLINK(...),+SP,@meand-cmdcame back from the CSV unchanged. These columns hold third-party text: titles, attributes, optionals, dealer names..env.examplebroke the README examples. It shipped an activeWEBMOTORS_URL, so aftercp .env.example .env,--make volkswagen --model golexited 2 in all three engines..env.examplerepeated it, and the canary used it to justify having no secret. That figure is not a constant.--delay,--retry-delay,--proxy-block-retriesand--concurrencyvalues, and--retriesin the Scraper API client, were accepted or crashed later.Resulting behaviour
Atomic writes.
output_writer._atomicwrites a temporary file in the target's directory, then flushes, fsyncs andos.replaces it. On any error it unlinks the temporary file. A new file gets0o666 & ~umask, and an existing file keeps its mode. JSON, CSV (newline=""), the sidecar anddiff_runs.py --outall go through it. The three files are replaced one at a time, not as one transaction.CSV escaping. A string cell starting with
= + - @ \t \r \ngets a leading', applied after list joining. Numbers are left alone and JSON is unchanged.csv_cells_escapedgoes into the sidecar, underneath any keys the caller passes inextra.WEBMOTORS_URL..env.exampleships the line commented out. Each engine recordstyped_urlbeforeenv_config.apply. An environment URL then gives way to typed search flags, to--ads-file, or to a--modethat differs from it. A typed--urltogether with filter flags is still refused.CLI validation. These are now argparse errors (exit 2) that name the flag:
--delay,--retry-delay,--proxy-block-retries--concurrency,--pagesscraper_api_client.py--retries,--delay,--retry-delayscraper_api_client.py--pages--retries 0is still legal in the Scraper API client because there it counts extra attempts.The 401 hint now says the credentials were refused (expired, revoked or mistyped). It no longer states a lifetime.
Canary. With neither the
WEBMOTORS_PROXYnor theWEBMOTORS_CDP_ENDPOINTsecret, every job fails with::error::naming both. Either secret enables the run, and both are mapped intoenv:. The car-search job also reads its first 3 adverts in ad mode, which has its own assertions. Exit 3, 4, 5 or 6, or zero rows, makes the job red.Smaller fixes:
pyvenv.cfg.check_no_private_citations_in_shipped_files, fails if such a citation comes back. Its tokens are assembled from pieces so the check does not match itself.Evidence
Offline suite, core-only venv: 445 passed, 0 failed (388 before). The 6 skipped groups are absent engine libraries.
One venv per engine (
requirements.txtplusrequirements-<engine>.txt, no browser download,pip checkclean):ci_checks.py:--help-check,--sample-checkand--secret-check(45 files) are all clean.Controls. Each was run with
PYTHONDONTWRITEBYTECODE=1and__pycache__removed. Every one turned the suite red on the named check, and the restored tree was green again:0o644extraWEBMOTORS_URLin.env.example--delayunvalidated in playwright--concurrencyunvalidated in selenium--retriesunvalidated::notice::skip.pyfile, a section sign in CHANGELOG and one in a workflow.venv(green withpyvenv.cfg, red without it)Probe:
parse_argsfor all three engines, with driver modules stubbed,env -i, and a copied.env:--make volkswagen --model gol --pages 3and--category motos --make honda --sort year-descparse, both with the new example and withWEBMOTORS_URLactive.--url ... --make fiatstill exits 2.No paid calls, credentials, proxies or live requests.
Not changed
--proxy/--concurrency/--fingerprintwith--cdp-endpoint,--solve-captcha always,--captcha-api,--min-score) should error instead of warn.The canary stays red until the owner sets
WEBMOTORS_PROXY(a residential exit) orWEBMOTORS_CDP_ENDPOINT(a 2Captcha Scraping Browser API endpoint, country-br).🤖 Generated with Claude Code