Repository navigation
Selenium and pyppeteer no longer crash on a no-proxy block, read --mode job pages, and CSV cells are formula-safe - #7
Merged
Conversation
…de job pages, and CSV cells are formula-safe - Selenium/pyppeteer: the block retry without a proxy pool re-fetches through the same path instead of raising AttributeError; pyppeteer rotates on a load failure only for a dead exit with a pool. - Selenium/pyppeteer pass --mode to every classify call, so job pages are read as jobs instead of parse errors. - Playwright/pyppeteer pass the HTTP status to the classifier, so a 404 exits 4; the Scraper API client handles not_found the same way. - CSV cells starting with = + - @ TAB CR LF get a leading apostrophe (text only, CSV only); the sidecar records csv_cells_escaped. - .env.example ships WELLFOUND_URL commented out, and an environment URL yields to --role/--location/--remote and an explicit --mode job/jobs. - Counting flags reject values that skipped the fetch or crashed (--pages, --concurrency, --proxy-block-retries, --delay, --retry-delay; --timeout/--retries/--retry-delay in the Scraper API client). - Credential scan exclusions are judged inside the repository, and a scan of 0 files fails. - Canary fails with an error naming WELLFOUND_PROXY when it is missing, and a bare-runner job requires the datacentre refusal to be recognised. - .gitignore covers --dump-html page files, live/ and root-level HTML. - Comments and help no longer describe other sites, a nonexistent challenge state or mode, or cite private notes; 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 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
mainatd92df63(2026-10-14) reproduced these problems:mask(pool.current)/pool.advance()withpool = Noneand raisedAttributeError. pyppeteer did the same on a plain load timeout. A datacentre address is refused on every route, so this was the expected path for those engines.--mode jobpage. Their classify calls omittedmode, so a job page was judged as a listing and came outparse_error: zero rows, exit 5.not_foundwas unreachable in every engine, so a removed job was waited on, re-fetched and reported as exit 5. The 0.1.2 notes said a 404 exits 4.=HYPERLINK(...)reached the CSV unchanged..env.examplebroke the builder flags. Its activeWELLFOUND_URLmade--role Xand--mode jobsexit 2, as if--urlhad been typed alongside them.build/,venv/and similar directories scanned 0 files and printed ok.WELLFOUND_PROXY./p/<slug>hubs, Akamai, a--mode profile, a SHOP FRONT), and achallengestate that does not exist. Tracked files also cited private working notes.Resulting behaviour
Behaviour changes are listed under
[Unreleased]in the CHANGELOG.blocked(exit 3). pyppeteer rotates on a load failure only for a dead exit with a pool.modeis passed to every classify call.--mode jobyields its row in all three engines.gotoresponse. Its status goes to the first classification and is reset toNoneafter a wait or a solve, because by then it may describe a different document.not_foundand exits 4. The Scraper API client does the same.= + - @TAB, CR or LF get a leading'in the CSV only, after list joining. Numbers and the JSON output are untouched. The sidecar recordscsv_cells_escaped, merged under the caller'sextra..env.exampleand the builder flags..env.exampleshipsWELLFOUND_URLcommented out. Each engine records the URL that was typed before the environment is applied. A URL from the environment yields to--role,--locationand--remote, and to an explicit--mode jobor--mode jobs. A typed--urlgiven together with--roleis still refused.--pagesand--concurrencymust be at least 1.--proxy-block-retriesmust be at least 0. A negative value made the block looprange(0), so nothing was fetched.--delayand--retry-delaymust be at least 0. A negative value crashed intime.sleep.--timeoutmust be at least 1, and--retriesand--retry-delaymust be at least 0.path.relative_to(REPO).parts, and a scan that reads 0 files fails.pyvenv.cfgdetection and the scanning of untracked files are unchanged.listingjob fails with::error::namingWELLFOUND_PROXYwhen the secret is absent.datacentrejob is documented as "datacentre refusal expected". It runs from the bare runner and requires exit 3 with the refusal page saved, or real rows. Exit 1 or 5 there is red..gitignorenow covers*.page[0-9]*(--dump-htmlpage files with any base name),live/and root-level*.html.blocked, and a task is built only when a sitekey was captured.Evidence
Offline suite.
python smoke_test.pygives 524 passed, 0 failed, 18 groups skipped (404 before this change).New checks run in every venv. They load each engine with its driver library stubbed and drive the real
_fetch_one_pagewith a fake session, so they do not skip when the driver is absent.Fault controls. Each fault was planted in a fresh copy with
PYTHONDONTWRITEBYTECODE=1and__pycache__removed. Each made the named check fail, and the restored tree is green.selenium_scraper: a branded refusal with no proxy is reported, not raisedfails withAttributeErrorpuppeteer_scraper: a load timeout with no proxy is reported, not raisedfailsmode=dropped from one Selenium classify callselenium_scraper:637 classify(...) passes modeand...is classified content(gotparse_error) fail...is classified not_found(gotunknown) and...and is not re-fetchedfail--mode jobsgate brokenenv URL + --mode jobs reads the feedfailsthe sidecar counts the escaped cellsfailpath.partsrestored in the scanvenv/,build/,.venv/and__pycache__/parent checks faila scan that read 0 files FAILS instead of passingfailsREADME.md:1 cites no private notesfails--proxy-block-retriesback totype=intselenium_scraper --proxy-block-retries -1 exits 2 naming the flagfailsWELLFOUND_URLuncommented in.env.exampleWELLFOUND_URL is an example, not an active settingfailsProbes.
_run_oncewith a stubbedfetch_html: 404 gives 4, 403 gives 3, and a served job page that parses to nothing gives 5.ci_checks.py --help-check --sample-check --secret-check: ok.git check-ignore:canary_dump.json.page3,out.page2,live/x.htmlandfoo.htmlare ignored. The tracked sources and the samples are not.No live, paid, proxy or credentialled requests were made.
Not changed, and why
connect(ignoreHTTPSErrors)and client hints (audit L4). These are candidates that need a pyppeteer browser and an authenticated proxy to verify. Neither was available within this task's limits: no browser downloads, no proxies.status: "failed"on a genuinely empty--allow-emptyrun (audit L6). This is a sidecar vocabulary question for the owner.price-monitoring.The canary stays red until a residential
WELLFOUND_PROXYsecret is set. That is intended: until then it has not tested the site.🤖 Generated with Claude Code