Uh oh!
There was an error while loading. Please reload this page.
docs(spec): widen DELIVERY_NOT_ELIGIBLE's ledger gloss to both delivery surfaces - #12089
Conversation
…ry surfaces The ERROR_CODE_LEDGER entry glossed the code as "delivery row is in a non-terminal state" — one refusal on one surface. The code is now raised on two, and the two refuse OPPOSITE halves of the state space, so the old wording was not merely incomplete: it was backwards for half the uses, describing terminal rows as the acceptable ones while INotificationOutbox.ack refuses exactly those. The gloss is now stated per surface, and names every refusal family a repo-wide grep of the code finds, not only the two the card named: - IHttpOutbox.redeliver (HttpRedeliverError): a row that is NOT terminal; the producer's RedeliverGuard refusing or itself throwing (fail-closed); and the terminal re-check at the write missing after a dispatcher tick re-claimed the row. - INotificationOutbox.ack (NotificationAckError): a row that is not in_flight — both an unclaimed pending row and an already-terminal one — plus SqlNotificationOutbox's compare-and-set read-back showing the claim was lost mid-ack. Comment only. No code is registered or removed, no wire value changes, and no acceptance or refusal behaviour moves. packages/spec publishes src/**/*.zod.ts, so the corrected gloss ships to consumers; patch changeset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NDGG54XF5gbTLdQzCtnaVV
📓 Docs Drift CheckThis PR changes 1 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin d19a6dd555ea87f6b01628d09f0c1f3d6bf46755 && git checkout d19a6dd555ea87f6b01628d09f0c1f3d6bf46755
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8450eeacb64a0d831b4d569d9bd43dca4c2abc4a 285254d25a7918a3364cdf11c0a7275ee477fa9b && git checkout -B drift-repro 8450eeacb64a0d831b4d569d9bd43dca4c2abc4a && git merge --no-ff 285254d25a7918a3364cdf11c0a7275ee477fa9b
node scripts/docs-audit/affected-docs.mjs --json 8450eeacb64a0d831b4d569d9bd43dca4c2abc4a
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#11892
ERROR_CODE_LEDGER's entry forDELIVERY_NOT_ELIGIBLEglossed the code as "delivery row is in a non-terminal state". The code is now raised on two delivery surfaces, and they refuse opposite halves of the state space — so the old wording was not merely incomplete, it was backwards for half the code's uses: it describes terminal rows as the acceptable ones, whileINotificationOutbox.ackrefuses exactly those.Comment only. No code is registered or removed, no wire value changes, and no acceptance or refusal behaviour moves. The reuse itself is the ruled shape (PR #11858's contract-review PASS ruled option B; a second near-synonym code was rejected for the vocabulary sprawl ADR-0112 exists to prevent) — only the comment lagged.
What the gloss now says, and how the refusal set was derived
The card named two surfaces. A repo-wide
git grep -rn "DELIVERY_NOT_ELIGIBLE" -- 'packages/**/*.ts'over the real throw sites found six, in two families — the gloss covers the measured set, not the card's reading:IHttpOutbox.redeliver(HttpRedeliverError)redeliverwantssuccess/failed/dead)http-outbox.tsassertHttpRedeliverableRedeliverGuardreturned a refusalhttp-outbox.tsassertRedeliverAllowedRedeliverGuarditself threw — fail-closed, "we could not check" must never read as "allowed"http-outbox.tsassertRedeliverAllowedsql-http-outbox.ts,memory-http-outbox.tsINotificationOutbox.ack(NotificationAckError)in_flight— covers an unclaimedpendingrow (the ack-as-cancel trap) and an already-terminal onesql-outbox.ts,memory-outbox.tsclaimTtlMs)sql-outbox.tsThe two guard-based redeliver refusals and the two compare-and-set misses are not state predicates at all, which is the second reason no single-clause gloss covers this code. The entry keeps the neighbouring
DELIVERY_NEVER_SENT"Distinct from…" contrast, now pointed both ways.Premise check against
origin/mainThe card's premise holds; two details in the dispatch reading did not survive verification, and neither changes the fix:
error-code-ledger.zod.ts:511; the entry is at :513 onf7b25c5(line drift).DELIVERY_NEVER_SENT's gloss on the line above, and both sit in the same@objectstack/service-messagingsection — so there is one place to write, not a per-section sweep.Generated ledger docs: correctly unchanged
content/docs/references/api/error-code-ledger.mdxis an auto-generated artifact, but the generator emits only the code-name list — it never carries the inline glosses (grepfor the old wording in the page returns nothing). So this change produces no docs delta, and no generated file belongs in this PR. Proven rather than assumed, aftergen:schemasupplied the requiredjson-schematree:Verification — union re-run on the final commit
285254dGate families derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackagainst the real change set (26 families; broader than the dispatch list, which predated the changeset file). Re-run on the committed HEAD, quoting each gate's own verdict line:check:error-code-casing—✓ no unlisted lowercase error codes in 4660 scanned file(s) (ADR-0112).check:dispatcher-error-vocabulary—OK — 21 unregistered code-stamping site(s), all classified; 1 awaiting a ledger entry (#8846).@objectstack/spec check:docs—✅ 229 generated files in sync with packages/spec@objectstack/spec check:liveness—✓ … the README state table carries a row for each of the 31 governed type(s) it claims to index.@objectstack/spec check:empty-state—✓ all classified (1 closed, 2 open, 4 output, 9 scope)@objectstack/spec check:strictness-ledger—✓ strictness ledger: 60 file(s) across 5 triaged director(ies) …@objectstack/spec typecheck—check:test-typecheck: OK — @objectstack/spec's test layer compiles …@objectstack/specledger suite —Test Files 1 passed (1) · Tests 17 passed (17)Green earlier in the same tree:
check:changeset-gate-self-tests,check:cross-package-test-inputs,check:merge-driver,check:objectui-changeset,check:published-files,check:slot-lookup,check:spec-parsed-alias,check:test-source-alias,check:type-source-resolution,check:variant-docs,check:doc-formula-expressions(✓ … 22 record-scoped formula example(s) across 421 files / 1449 TS blocks judged clean, after building@objectstack/formulaand@objectstack/lint, whose absence had made it exit before measuring anything), pluscheck-adr-0087-registration,check-changeset-no-major,check-ci-filter-parity,check-cross-package-test-inputs,check-empty-changeset,check-plugin-teardown-shape,check-affected-docs,check-drift-comment,release-rehearsal-clone --self-test,check-nul-bytes.Declared narrowings
check-dev-prereqs.mjswas not run to a verdict. Its precondition is a built workspace (it reported 67 of 67 packages missing theirdist/entry point) and it measured nothing. A fullpnpm buildis a repo-scale run CI owns and performs before this gate.pnpm lintnarrowed to the changed files, and the narrowing is measured, not assumed. ESLint's own config declines the changeset (File ignored because no matching configuration was supplied.), so the linted population of this diff is the single.tsfile;--format jsonreports 2 entries / 0 errors, 0 real warnings. The narrowing excludes nothing because this repo runs oneeslint.config.mjsthat never enables type-aware linting for any file (noparserOptions.project, no typed@typescript-eslintrules — stated in the config with a measured positive control), so a two-file comment diff cannot move the verdict of any untouched file.Scope
Clause ② is no — prose only; the set of legal metadata and every accept/reject decision is byte-for-byte identical before and after. The diff touches
packages/spec/src/**, so it still routes throughneeds:contract-reviewbefore enqueue. Draft, and staying draft.