Skip to content

fix: extract --json always carries the extraction inline - #190

Open
yzld2002 wants to merge 1 commit into
mainfrom
fix/extract-json-extraction-inline
Open

fix: extract --json always carries the extraction inline#190
yzld2002 wants to merge 1 commit into
mainfrom
fix/extract-json-extraction-inline

Conversation

@yzld2002

Copy link
Copy Markdown
Member

Closes #189

What I found

The two paths are not separate code: fresh completions and cached hits both
render through the single emit_summary in extract.py, and extraction is
built unconditionally from the same dict on both — the response result on a
fresh run, the byte-identical extract.json on a cached one. Driving both
paths through the CLI seam across every input form (parse item, extract -d
reuse, extract -d parse-first, --markdown, --markdown-url) and a forced
re-extract, the payloads come out key-for-key and value-for-value identical
apart from cached, with extraction inline in each. The reported summary
shape does not reproduce, and no version of this repo can produce it: the key
has been unconditional since the first commit, on every branch and every tag,
so there is no maintainer evidence of an intentional summary shape to
document — the contract stands as written.

What was actually broken

There was one way a successful run could reach stdout with no result in it: a
completed body whose result carried no extraction. The summary read it
with .get, so the run reported status: extracted, billed, wrote an
extract.json with no result in it, and printed extraction: null — silently
handing a consumer a payload it cannot read, which is the failure the issue
describes from the consumer's side.

That now fails whole in the consume-before-write block, next to the existing
extraction_metadata and markdown-echo guards: unsupported_result_schema,
the ticket marked unreadable with the reason, no artifact written, and a
re-run that re-polls the same job instead of re-billing.

Changes

  • extract.py: a completed result with no usable extraction (key missing,
    or not an object/array) is rejected before any write, instead of reporting
    a billed success with extraction: null.
  • tests/test_extract.py: parity tests pinning fresh ≡ cached payload shape
    across the input forms and a forced re-extract, plus the regression test
    for the guard (fails on main, both parametrisations).
  • help.py + docs/reference/help.json: ade help extract --json now says
    outright that extraction is inline on every successful run, cached hits
    included.

Notes

  • Full offline suite green (749 passed, 8 skipped); ruff and ty clean.
  • Pre-existing items whose stored extract.json has no extraction (written
    before this guard) still serve extraction: null on a cached hit. Nothing
    can create one from here, so I left the store read alone rather than have a
    cached hit re-bill.
  • Unrelated, spotted while reading the same help block: credits is
    documented as "0 on a cached hit", but both parse and extract report the
    original bill on a cached hit. Left alone here.

🤖 Generated with Claude Code

The documented contract is that `ade extract --json` puts the whole result
on stdout: the payload's `extraction` key is the schema-shaped result
itself, not a pointer to `<store_dir>/extract.json`. Reported (#189) as a
fresh-vs-cached shape divergence, with downstream tooling breaking one step
later on a payload with no `extraction` key.

Both paths already go through one `emit_summary`, and the payload's keys are
identical on a fresh completion and a cached hit — checked across every input
form (parse item, `extract -d` reuse, `extract -d` parse-first, `--markdown`,
`--markdown-url`) and a forced re-extract. The new parity tests pin that, so
no refactor can split the two paths again; the only key that legitimately
differs is the parse provenance of the invocation (`parsed_first` on a fresh
`extract -d` that had to parse, `reused_parse` on its re-run).

The one way a successful run could still reach stdout with no result in it
was a completed body whose `result` carried no `extraction`: the summary read
it with `.get`, so the run reported `status: extracted`, billed, wrote an
`extract.json` with no result in it, and printed `extraction: null`. That now
fails whole in the consume-before-write block, the same posture as any other
unreadable completion — the ticket is marked unreadable with the reason and
no artifact is written.

`ade help extract --json` now says outright that `extraction` is inline on
every successful run, cached hits included.

Co-Authored-By: Claude Opus 5 (1M context) <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.

extract --json: fresh-run stdout omits the extraction key (cached re-runs include it)

1 participant