Skip to content

Scraper API on the shared output contract; --url keeps its market; docs and packaging - #11

Merged
jehrr merged 1 commit into
mainfrom
docs/scraper-api-contract-and-packaging
Oct 22, 2026
Merged

jehrr merged 1 commit into
mainfrom
docs/scraper-api-contract-and-packaging

Conversation

@jehrr

@jehrr jehrr commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

Problem

From the manual test of v0.2.0 (#14, #15, #16), plus one defect found while verifying #14.

--url lost its market (new). --gl/--hl defaulted to US/en and were written over the URL, so --url ".../search?q=vpn&hl=ja&gl=JP" fetched the US store without saying so: USD prices, English titles, rows labelled US. Comparing the Scraper API with Playwright on that URL showed 23 of 30 apps shared and 58 differing fields, and the Scraper API was the one returning JPY.

Scraper API (#14): wrote rows only — no .meta.json (so diff_runs.py could not use the output), page/position empty, --format both where the engines default to json, and docstring/help text saying it had not been run on this site. It also sent a URL without hl/gl as-is, so Play chose the market from the API's exit while the rows were labelled with a default.

#15: diff_runs.py ended every refusal with "re-run the incomplete side", including when both runs were complete; original_price/discount_pct were always null with no explanation; the rotation log in reviews (fixed in #7).
#16: .dockerignore sent per-engine virtualenvs and captures/ to the build, about 240 MB.

Behaviour after

  • The URL's own gl/hl outrank the defaults. A typed --gl/--hl replaces them and logs --gl DE replaces gl=JP in --url.
  • Scraper API: page state through the engines' _handle_state; output through finish_run (sidecar, the same exit codes); page/position filled; --format json; --out normalised; hl/gl pinned in the request. An app row from parse_products gets position 1, as the engines' app run gives it.
  • diff_runs.py gives advice for the actual reason: the same --gl, the same --mode, re-run the incomplete side, or compare reviews on review_id.
  • README: why original_price/discount_pct are null, the Scraper API row in the engine table, and pyppeteer on Apple Silicon (its Chromium download has no arm64 entry).
  • .dockerignore: .venv-*/, venv-*/, captures/.

Evidence (2026-10-22)

  • Market: after the fix, Playwright and the Scraper API on the JP search returned the same 30 apps with no field different. A category grid shared 82 of 96 apps between the two; the same grid fetched twice from one address was identical (95/95), so which apps fill a grid depends on the requesting address. The README says so.
  • Scraper API live: category 96 rows, JP search 30 (JPY, Japanese titles), app 1 (page 1, position 1, screenshot_count 9), developer 10, all exit 0 with a sidecar; gl=xx → exit 2. $0.0006 for the five requests.
  • Null columns: original_price/discount_pct null on 0 of 411 rows parsed from the captures and 0 of 877 rows from today's live runs.
  • Docker: build with a planted 20 MB .venv-playwright → 288 kB of context; the image builds, runs --help, and contains no .env and no captures.
  • Tests: Scraper API through its own main() with captures in place of the network; market precedence (resolution and a fake-driver JP run); diff_runs advice for two complete markets and for an incomplete run. Six controls, each caught by its named check. One of them showed the diff test matching "same --gl" in the problem text rather than the advice, and the test now reads the advice line.
  • Offline suite green with core requirements and in each engine venv; credential scan clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VrpkXSoXyZMGV5nqF9JV6P

…cs and packaging

From a manual test of v0.2.0 (#14, #15, #16), plus one defect found while
verifying #14.

A market in --url was overwritten. `--gl`/`--hl` defaulted to US/en and were
written over the URL, so `--url ".../search?q=vpn&hl=ja&gl=JP"` fetched the
US store — USD, English titles, rows labelled US — silently. Found by
comparing the Scraper API with Playwright on that URL: 23 of 30 apps shared
and 58 field differences, with the Scraper API the one showing JPY. The
URL's own gl/hl now outrank the defaults; a typed flag replaces them and
says so. After the fix the two engines returned the same 30 apps with no
field different.

Scraper API (#14): it wrote rows only — no `.meta.json`, so `diff_runs.py`
could not use it; `page`/`position` empty; `--format both` where the
engines default to json; and "not run against this site" text. It now reads
the page state through the engines' `_handle_state` and writes through
`finish_run`, fills page and position, defaults to json, normalises `--out`
the same way, and pins hl/gl in the request — without them Play chose the
market from the API's exit while rows were labelled with a default. Run live
2026-10-22: a category (96 rows), a JP search (30), an app (1, position 1),
a developer (10), all exit 0 with a sidecar; a `gl` Play does not serve
exits 2; $0.0006 for the five requests. An app row from `parse_products`
also gets position 1, as the engines' own app run gives it.

diff_runs (#15): a refusal now ends with advice for its actual reason (the
same --gl, the same --mode, re-run the incomplete side, compare reviews on
review_id) instead of "re-run the incomplete side" for every reason.

Docs (#15, #16 and the pyppeteer note): README explains why
`original_price` and `discount_pct` are null (0 of 411 capture rows, 0 of
877 live rows); the Scraper API is in the engine table; pyppeteer on Apple
Silicon is documented — its Chromium download has no arm64 entry.
`.dockerignore` leaves out `.venv-*/`, `venv-*/` and `captures/`: a build
with a planted 20 MB venv sent 288 kB of context, the image built, ran
`--help` and holds no `.env` and no captures.

Tests: the Scraper API path through its own `main()` with the network
replaced by captures; market precedence for `--url` with and without typed
flags, and a fake-driver run of a JP URL; diff_runs' advice line for two
complete markets and for an incomplete run. Six controls, each caught by its
named check — one of them showed the diff test matching "same --gl" in the
problem text rather than the advice, and the test now reads the advice line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VrpkXSoXyZMGV5nqF9JV6P
@jehrr
jehrr merged commit 0a07337 into main Oct 22, 2026
7 checks passed
@jehrr
jehrr deleted the docs/scraper-api-contract-and-packaging branch October 22, 2026 22:20
@jehrr jehrr mentioned this pull request Oct 22, 2026
jehrr added a commit that referenced this pull request Oct 22, 2026
Version and changelog for the five fixes merged as #7-#11, from a manual
test of v0.2.0. The section opens with the behaviour changes an existing
caller will see — reviews order and paging, exit 2 for a --gl Play does not
serve, --url keeping its market, --out suffixes, the no_new_products
stop_reason, and the Scraper API's json default and sidecar — followed by
the correction of the README's earlier claim about the store's review
orderings.

The auditor's own reproduction steps were re-run against the merged code
before this commit: 13 of 13 runnable items now give the expected result.


Claude-Session: https://claude.ai/code/session_01VrpkXSoXyZMGV5nqF9JV6P

Co-authored-by: Petr <petr@2captcha.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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