Skip to content

feat(spec): retire BATCH_PARTIAL_FAILURE, BATCH_COMPLETE_FAILURE, TRANSACTION_FAILED from StandardErrorCode - #9723

Merged
os-elon merged 4 commits into
mainfrom
claude/issue-9266-batch-error-statuses
Aug 18, 2026
Merged

feat(spec): retire BATCH_PARTIAL_FAILURE, BATCH_COMPLETE_FAILURE, TRANSACTION_FAILED from StandardErrorCode#9723
os-elon merged 4 commits into
mainfrom
claude/issue-9266-batch-error-statuses

Conversation

@os-elon

Copy link
Copy Markdown
Collaborator

Fixes#9266

Retires BATCH_PARTIAL_FAILURE, BATCH_COMPLETE_FAILURE and TRANSACTION_FAILED from StandardErrorCode, per the maintainer ruling of 2026-08-18 (verbatim, untranslated): 「9266 同意 A」 — ADR-0049 enforce-or-remove applied to the error vocabulary. Evidence of record is the dev report on #9266: zero producers ever (measured by whole-tree grep and git log -S), zero consumers, and the real batch failure vocabulary (per-row ROLLED_BACK / NOT_ATTEMPTED, ledger-registered, HTTP 200) already richer than an envelope code could be.

Ruled scope, delivered

  • 3 enum members removedpackages/spec/src/api/errors.zod.ts (with a retirement comment naming the ADR-0112 amendment).
  • 3 catalog entries removedcontent/docs/api/error-catalog.mdx, whole ## Batch Operation Errors section (it covered nothing else); advertised count 53 → 50 on the same page (the D7 bijection guard pins both directions and the count; the spec suite is green at 50).
  • 3 rows removed from scripts/error-status-unpinned-baseline.json (shrink-only; the census now reports unpinned: 34 (baselined: 34), ungraded: 0, and no nowPinned findings — the baseline rows moved in the same diff as the doc entries).
  • 2 test fixture uses swapped to surviving codes — batch.test.ts envelope fixture now uses INTERNAL_ERROR; errors.test.ts's batch-codes acceptance block is replaced by a retirement refusal pin: all three retired spellings fail StandardErrorCode.safeParse.
  • ADR-0112 amendment (Prime Directive 13) — recorded under D2/D3 in docs/adr/0112-error-code-vocabulary-and-ledger.md, carrying the ruling verbatim, the measurement, and the ADR-0087 disposition.
  • ADR-0087 conversion-entry judgement — see below.
  • api-surface regeneration — ran check:generated against the rebuilt dist: the api-surface/ snapshot is unchanged by design (it records that an export exists, never what it resolves to — StandardErrorCode still exists, narrowed). The regenerated artifacts that did move are content/docs/references/** (contract.mdx, errors.mdx, error-code-ledger.mdx via gen:docs) and packages/spec/src/migrations/registry.ts (via gen:migration-registry).
  • Changeset@objectstack/specminor (house rule: never major), body carries the FROM → TO mapping, the one-line fix, and the ADR-0087 marker.

ADR-0087 conversion-entry judgement: registered, as a notification channel

Callers pattern-matching the retired codes are owed a ledger entry, and it is registered: standard-error-code-batch-members-retired (semantic entry, packages/spec/src/migrations/entries/semantic/18.standard-error-code-batch-members-retired.ts). Reasoning:

  • No mechanical conversion exists or is possible. Error codes are wire vocabulary, not stored metadata — there is no sys_metadata row for the D2 chain to rewrite, and a dead branch has no correct mechanical rewrite target (the per-row codes carry strictly more information than the envelope verdict the branch expected). This matches the two standing precedents for non-stored-metadata surfaces: enhanced-api-error-field-errors-renamed (a response surface) and driver-sql-upsert-cross-row-identity-merge-refused (a code-path API), both of which registered semantic entries explicitly as "the notification channel".
  • The entry is still owed rather than skipped because the ledger is the sole channel that reaches an upgrader (objectstack migrate meta, the upgrade guide): the accept-set narrowing (clause-②) is observable outside this repo — a consumer test fixture or fake server constructing an ApiError with a retired spelling parses today and refuses after upgrade — and for that author the entry carries the prescription (delete the dead branch; read results[].errors[].code).
  • The changeset therefore carries adr-0087: registered standard-error-code-batch-members-retired, verified by check-adr-0087-registration (green).

Verification (all at the head commit; union re-run noted in the report)

  • Premise re-verified on origin/main before editing: census byte-identical to the card (3 ungraded at :465/:470/:475); producer grep still empty; PR fix(tooling): error-status gate names the real cause when a code leaves the ungraded set (#9563) #9577's gate-message fix (793567fdc) confirmed on origin/main.
  • pnpm --filter @objectstack/spec test — 412 files, 10963 passed (includes the D7 bijection guard at 50 and the new refusal pin); pnpm --filter @objectstack/spec typecheck green.
  • Full packages/* + packages/*/* turbo build closure (70 tasks) green against the rebuilt spec — the downstream-consumer direction.
  • pnpm --filter @objectstack/runtime test — 171 files, 2543 passed, including the The dispatcher emits unregistered error.code values verbatim — three suites pin bodies that ApiErrorSchema would reject #8087 error-envelope conformance pins (error-envelope.conformance, package-door-error-parity, actions-validation-envelope).
  • Reverse verification (type-level, from the committed state): a temporary probe in packages/client (imports StandardErrorCode from @objectstack/spec/api, i.e. through the rebuilt dist .d.ts) went red on exactly the retired spelling — TS2322: Type '"BATCH_PARTIAL_FAILURE"' is not assignable to … 50-member union — while the survivor line stayed green; probe deleted, clean typecheck re-confirmed. Direction as predicted: red, on the retired member only.
  • check:error-status-conformance on the diff: greenungraded: 0, unpinned: 34 (baselined: 34), no nowPinned finding (PM mechanism assumption 1 confirmed: with fix(tooling): error-status gate names the real cause when a code leaves the ungraded set (#9563) #9577 landed, the two-cause message is in the self-test; on this diff the question never arises because baseline rows and doc entries move together).
  • Gates: the dispatch-named list plus everything node scripts/pm/dispatch-gates.mjs (no paths — merge-base derivation) added on the actual diff, all green; details in the dev report.

Not swept (deliberately)

  • The gate's own self-test fixtures in scripts/check-error-status-conformance.mjs use TRANSACTION_FAILED as a synthetic fixture string — self-contained, not the enum; out of ruled scope.
  • The historical audit note in docs/audits/2026-06-handwritten-docs-accuracy-followups.md mentioning TRANSACTION_FAILED is a dated audit record, not a live claim.
  • ADR-0112's own historical counts ("51 concepts", "53") are readings at their own dates; the amendment says so rather than rewriting them.

Generated by Claude Code


Generated by Claude Code

…NSACTION_FAILED from StandardErrorCode
ADR-0049 enforce-or-remove applied to the error vocabulary, per maintainer
ruling on #9266 (2026-08-18): no producer has ever emitted any of the three;
the batch surface reports these conditions per row via ledger-registered
ROLLED_BACK / NOT_ATTEMPTED at HTTP 200. Removes the 3 enum members, the 3
catalog entries (+ count 53 -> 50), the 3 unpinned-baseline rows, swaps the
two test fixture uses to surviving codes, adds a retirement refusal pin, an
ADR-0112 amendment, and the ADR-0087 semantic notification entry.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016D9wdJR14KKCxz1WgdAzcw
@github-actions

github-actionsBot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 2 documentable anchor(s).

4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/api/error-catalog.mdx(via StandardErrorCode (symbol))
  • content/docs/api/error-handling-server.mdx(via StandardErrorCode (symbol))
  • content/docs/api/index.mdx(via StandardErrorCode (symbol))
  • content/docs/api/wire-format.mdx(via StandardErrorCode (symbol))

1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v17.mdx(via StandardErrorCode (symbol))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 4 name(s) were too generic to anchor anything (single lowercase words)

Coarse fallback — 115 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 10bbc1971e1d8ac4a2c76e9548a75ad71b96502epackageMentionDocs.

Which tree this was computed on

This run read content/docs from 9fd09cec5aa5bb74f4acc762616a357d4ce3de86 — the merge of head ad9ec0702180ccb9cf30f00c7ef7bd7e6232a762 into base 10bbc1971e1d8ac4a2c76e9548a75ad71b96502e, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 9fd09cec5aa5bb74f4acc762616a357d4ce3de86 && git checkout 9fd09cec5aa5bb74f4acc762616a357d4ce3de86
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 10bbc1971e1d8ac4a2c76e9548a75ad71b96502e ad9ec0702180ccb9cf30f00c7ef7bd7e6232a762 && git checkout -B drift-repro 10bbc1971e1d8ac4a2c76e9548a75ad71b96502e && git merge --no-ff ad9ec0702180ccb9cf30f00c7ef7bd7e6232a762
node scripts/docs-audit/affected-docs.mjs --json 10bbc1971e1d8ac4a2c76e9548a75ad71b96502e

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 10bbc1971e1d8ac4a2c76e9548a75ad71b96502e → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@os-elon
os-elon marked this pull request as ready for review August 18, 2026 21:59
@os-elon
os-elon requested a review from hotlong as a code ownerAugust 18, 2026 21:59
@os-elon
os-elon added this pull request to the merge queueAug 18, 2026
Merged via the queue into main with commit 079b457Aug 18, 2026
27 checks passed
@os-elon
os-elon deleted the claude/issue-9266-batch-error-statuses branch August 18, 2026 22:33
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

2 participants

@os-elon@claude