Skip to content

docs(spec): anchor the BatchOptions.validateOnly tombstone to the release that removed it - #13127

Merged
os-trump merged 1 commit into
mainfrom
claude/issue-13020-validateonly-version-anchor
Aug 29, 2026
Merged

docs(spec): anchor the BatchOptions.validateOnly tombstone to the release that removed it#13127
os-trump merged 1 commit into
mainfrom
claude/issue-13020-validateonly-version-anchor

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#13020

Executes the maintainer ruling on that card (comment 5459668566, verbatim 「同意」 — option B, machine-sourced): the options.validateOnly tombstone gains a version anchor, with the removal version read mechanically from packages/spec/CHANGELOG.md rather than recalled.

The anchor

packages/spec/src/api/batch.zod.ts, one line inside the retiredKey(...) prescription:

prescription opens
before`options.validateOnly` was removed from BatchOptions in @objectstack/spec.
after`options.validateOnly` was removed from BatchOptions in @objectstack/spec 17.0.0.

Nothing else in the string moves. The key stays retired, stays typed never, and is still rejected with the same prescription — this is guidance text gaining a citation, not an accept-set change.

Why it was owed

Of the 132 audited tombstone prescriptions, this was the only one the #12522 strip left citing nothing durable: no ADR id, no os migrate command, and — uniquely — no version anchor either. retiredKey's own contract asks for one:

State what replaced the key, the version that removed it, and the one-line fix — this string IS the migration doc for anyone who hits it.

128 siblings carry it. This one now does too.

The three-source reading

The ruling required the version be read, with a positive control in the same population. All three sources agree on 17.0.0:

sourcemethodreading
packages/spec/CHANGELOG.mdgrep the retirement entry, then take the nearest preceding ## version headingentry ec796d5: feat(spec)!: retire BatchOptions.validateOnly — a dry-run flag that was never implemented (#4052) at line 9927, under ## 17.0.0 → Major Changes. The same entry also appears at line 57120 under ## 17.0.0-rc.1 — the pre-release that first carried it.
git log --follow -- packages/spec/src/api/batch.zod.tsmap the retiring commit to the release that carried itcommit ec796d5fd (feat(spec)!: retire BatchOptions.validateOnly — a dry-run flag never implemented (#4052), 2026-07-30). git tag --contains ec796d5fd names 7 spec tags; the earliest GA one is @objectstack/spec@17.0.0, and no pre-17 spec tag carries it.
packages/spec/spec-changes.jsonthe ADR-0087 ledger entry for the surfacesurface: api.batchOptions.validateOnly · migrationId: batch-options-validate-only-retired · toMajor: 17

Agreement statement: the changelog GA heading, the earliest GA tag containing the retiring commit, and the ledger's toMajor all name the 17 line, and the two that carry a full triple name 17.0.0. There is no disagreement to adjudicate, so the question does not return to the card.

Positive controls

The nearest-heading method was validated on two sibling retirements in the same population before the target reading was trusted — each one already carries a version anchor in its own source tombstone, so the method's answer is checkable against an independent fact:

controlmethod's answeranchor already written in its source
global_nav from ACTION_LOCATIONS (e027b3e)## 17.0.0ui/action.zod.ts: ... in @objectstack/spec 17 (#6888, ADR-0049 ...)
IDataDriver.findStream (c6d1cb4)## 17.0.0data/driver.zod.ts: ... was removed in 17.0.0 (#4484, ADR-0049 ...)

Both controls also reproduce the target's exact two-hit shape — one hit under a 17.0.0-rc.N heading, one under GA 17.0.0 — so the target's duplicate hit is the population's normal shape, not an ambiguity.

Sibling-form citation

The anchor spelling byte-matches the convention in the same api/ familypackages/spec/src/api/analytics.zod.ts line 52:

'`query` was removed from AnalyticsQueryRequest in @objectstack/spec 17.0.0. ' +

Same unbackticked type name, same in @objectstack/spec VERSION. tail, same trailing period-plus-space before the continuation. Across packages/spec/src the anchored spellings count 87 × @objectstack/spec 17.0.0 and 70 × @objectstack/spec 17; the fuller triple is both the majority form and the one this file's nearest sibling uses.

Consequentials

content/docs/references/** is a generator-owned artifact (scripts/regen-artifacts.mjs), and the API reference pages carry the prescription verbatim. Regenerated by toolingpnpm --filter @objectstack/spec gen:docs — never by hand:

  • content/docs/references/api/batch.mdx — 5 lines
  • content/docs/references/api/protocol.mdx — 2 lines

Measured: reducing every changed line in those two files to its delta yields exactly 7 × removed in @objectstack/spec. It was never and 7 × added in @objectstack/spec 17.0.0. It was never, and the count of changed lines not containing validateOnly is 0. The regeneration moved the anchor and nothing else.

One patch changeset: .changeset/batch-validateonly-tombstone-version-anchor.md.

Verification

Gate family derived mechanically at the final commit — node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, which reads its own change set from the merge base (4 paths, three-dot semantics) rather than a hand-built list. 52 families matched; all were run.

Union re-run on the final commit 931104930, with each gate's own verdict line:

gateverdict line it printed
check:generated✓ All 14 generated artifacts are up to date.
check:docs✅ 231 generated files in sync with packages/spec
check:authorable-surface✓ check:authorable-surface authorable-surface/ + authorable-defaults/ (+ its .base.json anchor) + JSON schemas
check:nul-bytescheck-nul-bytes: OK (scanned 7286 text file(s) ... no raw ASCII control bytes).
check:strictness-ledger, check:liveness, check:merge-driverexit 0

Tests and typecheck:

  • pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/api/batch.test.ts src/api/validate-data.test.ts src/shared/retired-key-migrate-sentence.test.tsTest Files 3 passed (3) · Tests 52 passed (52)
  • pnpm --filter @objectstack/spec typecheck → exit 0; check:test-typecheck: OK — @objectstack/spec's test layer compiles under packages/spec/tsconfig.test.json
  • Coverage proof (the typecheck claim is only worth what it read): tsc --noEmit --listFiles puts the edited file in the program — packages/spec/src/api/batch.zod.ts, 1 occurrence out of 1002 program files.

Pin triage. No test asserts the literal guidance string: grepping the old sentence across all *.test.ts returns nothing. The two suites that exercise the tombstone match on regexes that are indifferent to the anchor — toMatch(/validateOnly.*removed|never implemented/i) and toMatch(/validateOnly/) — so neither a pin update nor a pin replacement is owed here. retired-key-migrate-sentence.test.ts pins the os migrate sentence class-wide and is untouched by this edit; it was run anyway and is green.

No ablation is owed. This is a one-line prose anchor inside a describe/error string. There is no guard to delete and no behaviour whose absence a mutation could demonstrate — the rejection it participates in is already covered by the two suites above.

Not measured — stated as such, not as green

Three derived families exited non-zero for a reason that is not a finding, each self-declaring it:

  • check:dual-build-cjs-loadsPREREQUISITE NOT MET ... ⛔ This is NOT a pass: nothing was measured. It needs a full workspace build (34 packages lack dist/). Repo-wide build gate; CI owns that run.
  • scripts/check-dev-prereqs.mjsThe workspace is not built — 1 unmet precondition, not a list of problems. Same cause.
  • scripts/check-test-completeness.mjs — a usage error when invoked bare: it consumes a turbo test log CI produces.

A fourth, scripts/pm/check-half-states.mjs, exits 3 with PREREQUISITE NOT MET — the token in the environment is not a valid GitHub credential ... It is not a clean board and it is not a dirty one — it is no reading at all. The form CI actually runs is the --self-test alias pnpm check:pm-half-states, which is green.

Three further gates first failed as PREREQUISITE NOT MET — package not built (check:skill-examples, check:doc-formula-expressions, check:doc-security-posture). Their prerequisites were built and all three then passed — they are counted green above, not waived.


Generated by Claude Code

…elease that removed it
The tombstone read "... was removed from BatchOptions in @objectstack/spec." —
a removal citing nothing durable. Of the 132 audited tombstone prescriptions it
was the only one left with no reference at all: no ADR id, no `os migrate`
command, and — uniquely — no version anchor either. `retiredKey`'s own contract
asks for one ("State what replaced the key, the version that removed it, and
the one-line fix"), and 128 siblings carry it.
The version is READ, never recalled. Three independent sources agree on 17.0.0:
* packages/spec/CHANGELOG.md — "ec796d5: feat(spec)!: retire
`BatchOptions.validateOnly` ..." sits under the `## 17.0.0` Major Changes
heading. The nearest-heading method was validated first against two
positive controls in the same population (`global_nav` from
`ACTION_LOCATIONS`; `IDataDriver.findStream`), both of which resolve to
17.0.0 and match the anchors already written in their own tombstones.
* git log --follow -- packages/spec/src/api/batch.zod.ts — commit ec796d5;
the earliest GA tag containing it is @objectstack/spec@17.0.0, and no
pre-17 spec tag carries it.
* packages/spec/spec-changes.json — batch-options-validate-only-retired,
toMajor: 17.
Anchor spelling byte-matches the sibling convention in the same api/ family
(analytics.zod.ts: "`query` was removed from AnalyticsQueryRequest in
@objectstack/spec 17.0.0.").
Guidance text only: the key stays retired, stays typed `never`, and is still
rejected with the same prescription. The generated API reference pages under
content/docs/references/ carry the prescription verbatim and were regenerated
by tooling (`gen:docs`), moving exactly the 7 lines that spell it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LpRNHxWZgSUgVnFT9mQQo4
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to listnot a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 126 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 adf70f763bce48915cf4eb90b66de5b0dc5249f8packageMentionDocs.

Which tree this was computed on

This run read content/docs from 74ae54b9ab94cf88a6f9ebdb928bc60853cfe05f — the merge of head 93110493089672bcf09077cbf4411a2559efc055 into base adf70f763bce48915cf4eb90b66de5b0dc5249f8, 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 74ae54b9ab94cf88a6f9ebdb928bc60853cfe05f && git checkout 74ae54b9ab94cf88a6f9ebdb928bc60853cfe05f
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin adf70f763bce48915cf4eb90b66de5b0dc5249f8 93110493089672bcf09077cbf4411a2559efc055 && git checkout -B drift-repro adf70f763bce48915cf4eb90b66de5b0dc5249f8 && git merge --no-ff 93110493089672bcf09077cbf4411a2559efc055
node scripts/docs-audit/affected-docs.mjs --json adf70f763bce48915cf4eb90b66de5b0dc5249f8

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

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/stooling

Projects

None yet

2 participants

@os-trump@claude