docs(spec): two docblocks that promised a future which has already arrived (#16835, #15239) - #16947
Conversation
…rived (#16835, #15239) `automation/control-flow.zod.ts` said the schema and `validateControlFlow` "do not overlap and cannot fight" and met at "one seam". #16134 removed that division deliberately: `FlowSchema`'s `superRefine` now refuses a duplicate node id — a structural fact — over one node-id space spanning the top-level `nodes[]` and every region body. The docblock now names both seams and the boundary: the #4001 region-slot `safeParse`, and the #16134 node-id space judged at every depth `collectFlowGraphs` walks, which stops at `MAX_REGION_DEPTH` (32) — past the ceiling a region is left raw and `analyzeRegion`'s own `duplicate node id` line is the only refusal of a within-region duplicate, a cross-region collision beyond it not judged at all. `security/sharing.zod.ts` said in two places that a `field` rule is skipped at seed "until [#15072] lands". It landed (`9fa577535`): `mapRecipientType` maps `field` through and `SharingRuleService.expandRecipientForRecord` reads the named column per matched record. Both sentences now name that executor rather than a schedule. The third sentence the card counted is left alone and is still true: `queue` is "NOT authorable until the implementation lands" is about `sys_queue`, not about `field`, and no `sys_queue` object exists in the tree. Comment text only — no schema, export, key or predicate moves. `content/docs/references/automation/control-flow.mdx` regenerated by `gen:docs`; `sharing.zod.ts`'s blocks do not reach the generated tree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x
📓 Docs Drift Check
What this run could not see
Coarse fallback — 131 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
ACCEPT —
|
| card | grep | origin/main |
PR head | control (main → head) |
|---|---|---|---|---|
| #16835 | cannot fight |
1 | 0 | validateControlFlow 10 → 10 |
| #16835 | one seam |
1 | 0 | (same) |
| #15239 | until it lands, the |
1 | 0 | — |
| #15239 | until that lands a |
1 | 0 | — |
⭐⭐ The :110 call — the sharpest thing in this dispatch, and it went the right way
The card's title counts three sentences. The dispatch required :110 to be judged on its own terms because it is about queue / sys_queue, not field / #15072. The dev's verdict: STILL TRUE, LEFT ALONE. Independently confirmed by this seat:
| reading | value |
|---|---|
no \sys_queue` yetinsharing.zod.ts`, main → head |
1 → 1 (untouched) |
sys-queue object files in the tree |
0 |
positive control — sys-team object files |
2 |
⇒ sys_queue does not exist, the sentence is true, and this PR corrects two sentences rather than the three the card counted — said so in the PR rather than quietly editing a third line. ⛔ That is the difference between fixing a card and obeying its title.
⭐⭐ The docs-drift advisory was blind, the hand-scan was not, and it found a real hit
The bot reported NOT COVERED — both changed files yielded no anchor. ⛔ Read as "the instrument was blind", not "no page is affected". The hand-scan then found what it could not:
docs/audits/2026-07-unknown-key-strictness-ledger.md:738
… **`validateControlFlow` is a sibling guard, not a key gate, and the two do not fight** …
They meet at exactly one seam — …
control: `control-flow` in that file → 4
⇒ Both retired sentences, paraphrased, in a file no anchor-based check would ever list. Verified by this seat at that line.
⛔ Filed as #16948 rather than fixed, and the reasoning is right: the claim fences the file surface to "Nothing else", and docs/audits/** carries a merge=os-regen driver plus a gated .counts.md companion — a new verification surface, which fails the in-place-fix exemption's own limb. The four hand-written permissions pages were checked too and already describe the post-#15072 state correctly; each is named in the PR with its reason for being left alone.
The generated page moved, and that answers the open question
content/docs/references/automation/control-flow.mdx is in the diff (+28/−?) — the generator was run and the page belongs there, the same shape as sibling PR #16930. gen:docs "may want" a re-run for sharing.zod.ts; measured, it does not — only the @module docblock renders, and sharing's edited text sits in the ShareRecipientType / SharingRuleSchema blocks. Only control-flow.mdx regenerated.
Other readings this seat took
| reading | value | instrument |
|---|---|---|
| diff shape | 4 files, +60 / −21 | git diff --stat |
| clause-② pairs | exit 0 on both cards, no widening tell | check-clause2-carriers.mjs --pair 16947 |
| governed surface | NOT governed | check-governed-merges.mjs --test |
| model tier | 265 harness-stamped "model":"claude-opus-5", no other value |
subagent transcript grep |
⭐ Gates: the best-measured run of this shift
93 derived, 93 run, ALL exit 0, 0 NOT-MEASURED, 0 UNRUN. Five gates first returned PREREQUISITE NOT MET on an unbuilt workspace — read as NOT MEASURED, ⛔ never as red — and were then made green by building what they read, including whole-tree check:dual-build-cjs-loads, which every other delivery this shift declared as not-measured and handed to CI. ⛔ No narrowing was declared and none was needed. The lock wait (125s queued behind another agent, then held 100s) was spent on lock-free work rather than by ending the round.
Landing
⛔ Not enqueued yet — 31 names seen, 10 still running, 0 non-green. Enqueueing when every name closes completed with success/skipped, aggregated by name.
sharing.zod.ts: the dev notes that :110 is itself a temporal promise — true today, and nothing goes red when sys_queue lands. ⛔ Not a defect under any filing class today, so correctly not filed; the carrier is whichever PR introduces sys_queue.
Generated by Claude Code
Fixes #16835
Fixes #15239
Clause-②: no
Comment text only. No accept set moves, no export is added or renamed, no key lands on a
published payload, no predicate changes. Both cards are one defect shape — a docblock
sentence promising a future that has already arrived — and both corrections rewrite the
sentence to what the tree does. 拉回已声明契约 ⇒ 常规档.
The dispatch's fence held: neither correction needed a behaviour change, so nothing here
required an at-tier contract review.
Two expired temporal promises, both of the form "until it lands, …" where the thing has
landed. Each card's own acceptance criterion is answered separately below, and one of the
three sentences the cards counted turned out to be still true and is deliberately
untouched.
Changeset — MEASURED, not assumed
The default guess for a comment-only diff is
skip-changeset. It is wrong here, and thiswas measured rather than reasoned:
src/**/*.zod.tsis infiles[], so a TSDoc comment in either edited file is a publishedbyte. Confirmed against a real pack rather than against the glob:
Both sibling
.test.tsfiles are absent, so the listing is discriminating and not merelyanswering "yes" to everything. ⇒ a real changeset is owed:
.changeset/spec-expired-until-it-lands-docblocks.md,@objectstack/spec: patch.The regenerated
content/docs/references/automation/control-flow.mdxis not in thepackage (it is the docs site), so it is not what makes the changeset owed — the two source
files are.
#16835 — the premise, re-derived rather than believed
The card asserts that #16134's landing falsifies two sentences. The claim comment explicitly
reserved that reading for me and did not verify it. It holds. Landed as
21aabbc7b(PR #16825, merged 14:55Z), which added to
FlowSchema'ssuperRefine:Sentence 1 — "The two do not overlap and cannot fight: the schema rejects undeclared
KEYS, the analysis rejects malformed STRUCTURE." False. The schema now refuses a
duplicate node id, which is a structural fact, not a key fact. The clean division the
sentence draws is precisely what the ruling removed. They also now do overlap: within the
depth ceiling both the schema and
analyzeRegionrefuse the same collision.Sentence 2 — "They do now meet at one seam." False. Two seams: the #4001
region-slot
safeParse, and the #16134 node-id-collision refusal.The replacement prose names both seams and the boundary between them, and it was checked
against the two in-tree comments that came through that PR's own reviews —
analyzeRegion'sheader and
FlowSchema'ssuperRefineheader — rather than paraphrased from the card:FlowSchemaholds one node-id space across the top-levelnodes[]and every region body,judged at every depth
collectFlowGraphswalks;MAX_REGION_DEPTH(32), so past the ceiling a region is left raw andanalyzeRegion's ownduplicate node idline is the only refusal of a within-regionduplicate;
suggested wording ("
analyzeRegionremains the refusal past that ceiling") is looser thanthe tree, and the docblock now says the precise thing.
Positive control on that file while locating the sentences:
validateControlFlow→ 10 hits,so the grep fires.
content/docs/references/automation/control-flow.mdxcarries this module docblock verbatimand was regenerated with
gen:docs— ⛔ never hand-edited.#15239 — two sentences, not three
Triage's executable unlock predicate reads TRUE, re-taken on this tree:
:91and:262both said afieldrule is skipped at seed "until [#15072] lands". Bothnow name the artefact instead of a schedule:
mapRecipientTypemapsfieldthrough, andSharingRuleService.expandRecipientForRecordreads the named column on each matched record.⭐
:110— the third sentence is STILL TRUE and is left aloneThat sentence is about
queue/sys_queue, not aboutfield/ #15072, and its truthturns on a question neither card asked. Measured:
The control finds the definition file for a
sys_*object that does exist, so the instrumentfires; there is no
sys_queuedefinition. Every one of the 10 in-treesys_queuementions isprose saying "no
sys_queueyet", including three live ones —spec/src/contracts/sharing-service.ts("reserved: nosys_queueyet,expandRecipientreturns
[]"),plugin-sharing/src/bu-tree-recompute.ts("returns[](nosys_queueyet)") and
packages/lint/src/validate-org-axis-red-lines.ts.ShareRecipientType'sz.enumdoes not carryqueue.⇒
:110is still true. Untouched. This PR corrects two sentences, not the three thecard's title counted. Editing a third line because a title said "three" would have replaced a
true sentence with a false one.
⛔ No correction reintroduces the defect
Both cards exist because a sentence promised a future. Neither replacement sentence contains
another one — verified mechanically over both files:
The one surviving "until … lands" in the tree is
:110, which is a true statement about afuture that has not arrived.
Gates
Derived by name and reconciled, never hand-listed:
93 / 93 run, every one exit 0. Exit codes were captured before any pipe.
Five first returned exit 3 /
PREREQUISITE NOT MET— an unbuilt workspace package, whichthose gates report as "Nothing was measured … NOT a finding" rather than as a red. They were
re-run after building the prerequisites and all are green:
@objectstack/lint check:doc-formula-expressions@objectstack/lint check:doc-security-posture@objectstack/spec check:skill-examplescheck:docs-transcript-driftcheck:dual-build-cjs-loadscheck:skill-examplesis the materially relevant one — it type-checks the spec sourceTSDoc surface this PR edits, and reports
258 prose examples type-check across 3 surface(s).Spec artifacts, regenerated up front per AGENTS.md:
check:authorable-surfaceis green across that run, which independently confirms the diffmoved no authorable key — the reading a prose-only claim needs.
Control-byte self-scan beyond
check:nul-bytes, on both edited sources:Not owed here: no
skills/**path, so no line budget; no governed surface(
docs/adr/**·.claude/**·skills/**·AGENTS.md·CLAUDE.md) is touched, so nomaintainer brief section.
验收备注
noted, not filed::110is itself a temporal promise, true today and load-bearing whensys_queueeventually lands — nothing goes red at that moment. It is not a defect now (thesentence is true), so it is an observation rather than a card. Carrier: whichever PR
introduces
sys_queue, which will be editing this enum anyway.Docs-drift advisory came back NOT COVERED — answered by hand
The bot could derive no anchor for the two changed
.zod.tsfiles, so it did not clear thepages documenting them. Read as "the instrument was blind here", never as "no page is
affected". All readings below are on PR head
c5ee37f6cwithgit status --porcelainempty(the advisory computed against a merge into base
34a76c480, so a different list there is adifferent tree, not a wrong row).
1. Generated pages — the generator was run, and it moved exactly one file
⇒
control-flow.zod.tsdoes feed a generated page, exactly as #16835's title says, and thatpage is in the diff. ⇒
sharing.zod.tsdoes not. That is gate-backed rather than asserted:check:docsis green with the sharing edits already applied, so no generated page carriesthose blocks — only the
@moduledocblock is rendered, andsharing.zod.ts's edited text sitsin the
ShareRecipientTypeandSharingRuleSchemablocks. This corrects #15239's own flag thatgen:docs"may want" a re-run for it: measured, it does not.2. Hand-written pages that restate the same claims — scanned, and one is a real hit
Searched
content/docs/**,docs/**,skills/**and every*.md/*.mdxfor paraphrases,not just verbatim strings. Every zero below sits next to a control on the same corpus.
Claim A (
cannot fight/one seam/ the keys-vs-structure division):cannot fightrejects undeclared KEYSreferences/automation/control-flow.mdx+spec/CHANGELOG.mdmalformed STRUCTUREreferences/automation/control-flow.mdxsibling guardreferences/automation/control-flow.mdx,docs/audits/2026-07-unknown-key-strictness-ledger.md, 4 × CHANGELOGone seamdocs/audits/2026-07-unknown-key-strictness-ledger.md, thecontrol-flow.zod.tsrow,restates BOTH claims as a paraphrase — "the two do not fight" and "They meet at exactly one
seam" — and both are now false for exactly #16835's reason. Filed as #16948, deliberately
not fixed here: this PR's governing claim fences the file surface with "⛔ Nothing else",
and
docs/audits/**carries amerge=os-regendriver plus a generated.counts.mdcompaniongated by
check:strictness-ledger— a verification surface this fold does not carry, which isthe limb the bounded in-place-fix exemption requires.
Claim B (
fieldrule skipped until #15072):content/docs/permissions/permissions-matrix.mdx:155fieldrecipient (#14103), expanded once per matched record by its executor (#15072)"content/docs/permissions/sharing-rules.mdx:146content/docs/protocol/objectql/security.mdx:386, :422content/docs/permissions/capabilities.mdx(skipped loudly)⇒ every hand-written permissions page already describes the post-#15072 state. Nothing to fix
for claim B, and each page left alone is named above with its reason.
⛔
content/docs/releases/**was not touched and is read-only regardless:releases/v17.mdxmatched only the broad
one seam/until it landscontrols, not either claim.3. Changeset, measured in BOTH halves
Half 1 — path vs
files[]: the pack listing above. Half 2 — is the changed TEXT in thepublished
dist? Yes, anddistis itself infiles[]:⇒ the edited TSDoc is published twice over — as
src/**/*.zod.tsand asdist/*.d.tsdeclarations.
skip-changesetis wrong on both halves.Generated by Claude Code