Skip to content

CSV formula escaping, JUSTJOIN_URL as a default, facets diff, scan from any directory - #6

Merged
jehrr merged 2 commits into
mainfrom
fix/audit-2026-10-14
Oct 15, 2026
Merged

jehrr merged 2 commits into
mainfrom
fix/audit-2026-10-14

Conversation

@jehrr

@jehrr jehrr commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator

Fixes the findings from the 2026-10-14 audit that the owner's draft PR #5 does not already cover. Base: main at 3222f2e (the audited SHA).

Covered by #5, deliberately not touched here

Atomic output writes (F1), --retries 0 (F3), the pyppeteer no-proxy crash (F4), the missing Scraper API sidecar / diff_runs without a sidecar (F10), offer mode in Selenium/pyppeteer and the queue stopping on a 404 (F11), --route ssr filters (F12). The 2026-10-08 and 2026-10-10 canary failures were both that 404-ends-the-queue bug (logs: page 1 / page 4 not_found, then exit 5 / pages_completed: 4), so #5 is what turns the offer canary reliably green.

What changes

Finding Problem Now
F2 CSV formulas =HYPERLINK(...) in a title reached the CSV as a live formula String cells starting = + - @ TAB CR LF get a leading ' in CSV only (after list joining); numbers and JSON untouched; csv_cells_escaped in the sidecar, merged under the caller's extra
F5 credential scan skip list matched against ABSOLUTE path parts, so a clone under build/, env/ or venv/ scanned 0 files, exit 0 matched on path.relative_to(REPO).parts; pyvenv.cfg detection and untracked-file scanning unchanged
F6 JUSTJOIN_URL the listings URL shipped in .env.example made --mode offer / --mode facets exit 2 in all three engines although nobody typed --url engines capture the typed --url before env_config.apply; an env URL naming another mode is ignored with an info line, a typed one is still refused. .env.example shows the variable commented out
F7 facets diff TRACKED_FIELDS is all JobPosting columns, so offer_count 100 -> 250 reported "0 changed", exit 0 FACET_TRACKED_FIELDS (title, offer_count, is_cumulative, overlaps_other_keys) chosen by the sidecar's mode, or by row shape without one. site_total deliberately not tracked (same on every row)
F8 private citations ~240 lines cited an internal document by name and section number each rule stated in place or the citation dropped, including the released CHANGELOG sections (citations only, nothing else in them changed); new suite check check_no_private_document_is_cited (tokens assembled from pieces)
F9 --dump-html help pointed at a nonexistent TROUBLESHOOTING.md points at the README's traps section
F14 engine comments described a challenge state that does not exist describe STATE_POLICY as it is
F16 canary_dump.json.page3, live/x.html, root.html not ignored *.page[0-9]*, live/, /*.html (checked with git check-ignore)
F17 badge claimed 3.13, CI tested 3.9/3.12 matrix adds 3.13
F18/F19 canary comment repeated the retracted "credentials live about a day"; a shop_rating example in run_meta reworded

Behaviour changes are led with a blockquote under [Unreleased].

Evidence

  • Offline suite, core-only venv (Python 3.13): 808 passed, 0 failed, 15 groups skipped (engine absent). Per-engine venvs (requirements + that engine, no browser download): playwright 849/0, selenium 835/0, pyppeteer 835/0, each with only the OTHER engines skipped.
  • Planted-fault controls, each confirmed RED on the named check, then restored to green (PYTHONDONTWRITEBYTECODE=1, __pycache__ removed between runs):
    • CSV escape disabled -> a formula title is escaped in the CSV
    • stats merged OVER caller extra -> a caller's value wins a name collision with the count
    • scan back on absolute parts -> the scan finds a planted key in a clone under build/
    • facets mapped to job columns -> a facets diff (mode 'facets') sees an offer_count change
    • CLAUDE + .md planted in env_config.py -> env_config.py cites no private ...
    • JUSTJOIN_URL uncommented -> the example ships JUSTJOIN_URL commented out
    • typed-URL test removed in selenium_scraper (selenium venv) -> selenium_scraper --mode facets ignores a listings JUSTJOIN_URL
  • Behavioural: two facets runs via finish_run, offer_count 100 -> 250, diff_runs.py --fail-on-change -> 1 changed, exit 1 (was 0 changed, exit 0).
  • .github/ci_checks.py --secret-check on this tree: 33 files scanned, clean.
  • Release notes v0.1.0-v0.1.3 contain no citations; not edited. Repo metadata had no finding for this repo; not edited.
  • Canary: already ungated, daily, requires exit 0 and real rows (row floors, non-null core columns, PLN present); exit 3/4/5 are red. No logic change needed; only the comment above.

Conflict with #5

Merging this with #5 conflicts in 5 files, one hunk each: CHANGELOG.md (both append under [Unreleased]), output_writer.py (both edit write_csv/around _csv_value), and the three engines (a comment where a citation was removed, adjacent to code #5 rewrote). #5 also ADDS about 12 new private-citation lines; once both land, check_no_private_document_is_cited will flag them, so whichever merges second should drop those citations (it names each file).

Not changed

  • Everything covered by 0.1.4: fixes from the audit (offer queue, ssr filters, facets, diff sidecar, atomic writes) #5 (above). No version bump, tag or release.
  • F13 (captcha budget) is already compliant. F15 (pyppeteer UA override / page.authenticate / ignoreHTTPSErrors) needs a live proxy and Chromium to verify first; not touched.
  • F20 commit subject, T10 shared-loop refactor, T11 schema/sinks: owner decisions.
  • Canary skip/notice policy: nothing to change, it is not gated.

🤖 Generated with Claude Code

jehrr and others added 2 commits October 15, 2026 06:57
…iff facets runs

- CSV: a string cell starting with = + - @ TAB CR LF gets a leading
  apostrophe (CSV only; JSON and numbers untouched); the count is
  recorded in the sidecar as csv_cells_escaped, under caller extra.
- JUSTJOIN_URL from .env no longer makes --mode offer/facets exit 2: the
  engines capture the typed --url before env_config.apply and only check
  a typed URL against --mode. .env.example shows the variable commented.
- diff_runs compares facets runs on their own columns (offer_count, ...)
  instead of the job columns, which a facet row does not have.
- The credential scan matches its skip list against the path inside the
  repo, so a clone under build/, env/ or venv/ is scanned.
- Comments, docstrings and changelog entries state their rules in place
  instead of citing internal notes; a suite check guards it.
- Small: --dump-html help link, engine comments about the solve state,
  .gitignore for page dumps of any extension, CI on Python 3.13, canary
  comment no longer repeats a retracted credential-lifetime claim.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jehrr
jehrr marked this pull request as ready for review October 15, 2026 21:15
@jehrr
jehrr merged commit e649a9a into main Oct 15, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant