Skip to content

fix(spec): label every producer claim in the build-progress docblock — measured, ruled, or inferred - #18870

Merged
os-bill merged 2 commits into
mainfrom
claude/issue-18552-build-progress-docblock-provenance
Sep 18, 2026
Merged

os-bill merged 2 commits into
mainfrom
claude/issue-18552-build-progress-docblock-provenance

Conversation

@os-bill

@os-bill os-bill commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes #18552

Clause-②: no

The module docblock on packages/spec/src/ai/build-progress.zod.ts stated three producer claims as MEASUREMENTS. It ships inside the published @objectstack/spec tarball and is rendered verbatim into content/docs/references/ai/build-progress.mdx, and for a CLOSED vocabulary it is the audit trail the "re-measure before you move the array" discipline reads. One of the three was false for verify. Every producer claim now carries exactly one of three labels, defined at the top of the module: measured on a named reachable source / declared by ruling / inferred.

⛔ Nothing about the vocabulary or the schemas moves. BUILD_PROGRESS_PHASES, BuildProgressPhaseSchema and BuildProgressFrameSchema accept and refuse exactly what they did before — measured, below.

Clause-② declaration

no, on the authority the dispatch cited: references/lanes/spec.md — only widening the accepted set or enlarging the public surface is clause ②. Neither happens here. Measured both halves rather than asserted: check:api-surface is green with the artifact untouched (no export added, removed or renamed), and the parse-behaviour matrix below is byte-identical before and after.

Claim-by-claim

Original sentence Now Label Basis
"Membership was MEASURED against the two ends of the channel, not designed — every member below is one a real producer emits or a real consumer already discriminates" "Membership is MIXED-PROVENANCE, not uniformly measured. Each member carries its own label …" (headline retired; each member labelled) False for verify at this head — the reading is below
"structure, data, done — the consumer's own declared union …" same, prefixed measured on a named reachable source, cited with the tree it was read against measured on a named reachable source objectui dda8f3815: ChatbotEnhanced.tsx:163 and mapMessages.ts:743
"verify — the post-apply verification window objectui#7388 asks the panel to be able to name …" same reason, now prefixed declared by ruling, ⛔ not measured, with the zero-occurrence reading and its bright control recorded beside it declared by ruling cloud#2172 ruling A; objectui#7388. ⛔ The member itself is untouched
"Corroborated in this repo by the verify_build tool that service-ai-studio actually registers" kept, and narrowed: it corroborates the TOOL's registration, not the phase measured on a named reachable source packages/spec/src/system/constants/platform-tool-names.ts:85
"measured on cloud#1838: 111 seconds and 9 tool calls after apply_blueprint returned" "The only record of that window is the cloud#1838 turn, reported there as 111 seconds and 9 tool calls … carried here, not measured" inferred objectstack-ai/cloud is not reachable from this session's credential, so the figure cannot be re-measured from this repo. ⛔ Nothing was deleted
"one of them the registered verify_build tool" "WHICH tools those 9 calls were is recorded nowhere reachable either … so 'one of them ran the registered verify_build tool' is inferred as well" inferred Neither #18451 nor objectui#7388 names the 9 calls
"A tool's own ctx.onProgress handle dies when the tool returns, so a frame emitted in that window can only come from the loop" same, now labelled and sourced inferred (from a reachable contract) AIToolContext.onProgress in ../contracts/ai-service declares the emit as happening WHILE the tool executes, before it returns; that the handle is then gone is the deduction
"The cloud AI-studio agent loop — deliberately not the tool it just ran" same, now labelled declared by ruling cloud#2172 ruling A owns where the emitter sits
"a turn that applies no seed data never reports data" kept as an illustration, labelled inferred inferred No reachable repository records it; cloud#2172's emitter has not landed
"apply_edit turns need not report structure" kept as an illustration, labelled inferred inferred Same
hop: "the counter behind the '9 tool calls' cloud#1838 measured" "… the cloud#1838 turn record reports … Inferred that a producer counts hops at all" inferred Same unreachable record

The consumer guidance around the two skipped-phase illustrations is unchanged and does not rest on them: treat every phase as optional, compare by value.

The reading behind (a), re-taken here with a bright control

Taken in this session, in the local objectstack-ai/objectui checkout at commit dda8f3815df6eb92e944a33745070e361e8d6e40, one instrument:

git grep -l "'verify'"    -- packages/plugin-chatbot   ->  0 files
git grep -l "'structure'" -- packages/plugin-chatbot   ->  4 files   (bright control)
      packages/plugin-chatbot/src/ChatbotEnhanced.tsx
      packages/plugin-chatbot/src/__tests__/ChatbotEnhanced.test.tsx
      packages/plugin-chatbot/src/__tests__/buildPanelI18n-7388.test.tsx
      packages/plugin-chatbot/src/mapMessages.ts

The control fires, so the zero is a real zero and not a dead instrument. Confirmed at the two symbols:

  • ChatbotEnhanced.tsx:163phase: 'structure' | 'data' | 'done';
  • mapMessages.ts:743const phase = d.phase === 'data' || d.phase === 'done' ? d.phase : 'structure';

Repo-wide in objectui, 'verify' occurs twice, both in app-shell/src/console/RemediationOverlay.tsx as a password-remediation step — unrelated to build progress. On this side, data-build-progress occurs in 4 files, every one of them this module's own declaration, its test, the ai/index.ts line and the contracts/ai-service example (control: onProgress occurs in 10 files) — zero emitters.

⚠️ The docblock previously cited mapMessages.ts:744; at the tree read here the line is 743. The citation now carries the tree it was read against, per the "a reading is a count plus the tree" rule.

DARK — the parse behaviour reads 0 change

A 29-line probe over BuildProgressPhaseSchema and BuildProgressFrameSchema (14 phase inputs, 13 frame inputs, plus the exported array and frame-type literals), run against the source before the edit and again after:

diff dark-BEFORE.txt dark-AFTER.txt   ->  empty, exit 0   (29 lines each)

Covered on both sides: all four declared phases parse; designing / rebuilding / VERIFY / '' / 3 / 1.5 / null / undefined / {} / ['verify'] are refused with invalid_value carrying the full accepted set; the frame refuses hop: -1 (too_small), hop: 1.5 (invalid_type), tool: '' (too_small), an undeclared phase located at ['phase'], and a frame with no phase; the shipping panel fields (appLabel, items, done, total, seq) still survive the loose parse.

packages/spec test suite: 487 files / 14058 tests, all passing — every pre-existing assertion in build-progress.test.ts untouched.

Generated-artifact reconciliation

gen:docs writes 224 files. After it, exactly one is modified:

$ git status --porcelain
 M content/docs/references/ai/build-progress.mdx
 M packages/spec/src/ai/build-progress.zod.ts

The .mdx diff is 27 insertions of the two module-docblock sections (## How to read the claims in this module, ## Liveness watch) and the rewritten Producer paragraphs, and 8 deletions of the paragraph they replace. Nothing else in the page moves — the schema tables, the allowed-values list and the TypeScript-usage block are byte-identical. The BUILD_PROGRESS_PHASES and field docblocks are not rendered by build-docs.ts, which is why (a) and (c) produce no .mdx change at all.

content/docs/references/** is on the merge=os-regen roster (verified here: git check-attr merge answers os-regen for this path, and unspecified for the hand-written .zod.ts beside it — the instrument discriminates). origin/main was merged in through bash scripts/pm/os-regen-merge.sh; it kept the branch's bytes because main did not touch the page, and the regeneration was re-run and re-checked afterwards.

The card's second job — the liveness watch

verify, hop and tool have zero emitters and zero readers in every reachable repository. That is declared-ahead by ruling, not neglect, and it sits outside the ADR-0049 liveness ledger (registry-rooted; BuildProgressFrame is not a registered metadata type, so the liveness job is green). A new ## Liveness watch section in the docblock records all three: what they stand on, who is supposed to close it (cloud#2172 for the emitter, objectui#7388 block 2 for the consumer's strict parse), and that no gate watches it. ⛔ No enum member moves and no enforce-or-remove is attempted here.

Tests

Three added, none changed. describe('module docblock provenance') pins the narrow, load-bearing part and ⛔ not the wording: that the three labels are defined, that the verify bullet carries declared by ruling and the retired headline is gone, and that the liveness watch is still present with its carriers. It is the only leg in the file whose subject is text, and the docblock explains why that is legitimate here — the text ships and is rendered, and for a closed enum it is the audit trail.

Gates

  • check:generatedall 15 green, including check:docs, check:api-surface, check:authorable-surface. Tree clean after the run (no regeneration drift).
  • check:api-surface did not move, which is the expected reading: no export surface was touched.
  • pnpm --filter @objectstack/spec typecheck — green (check:scripts-typecheck + check:test-typecheck, ledger unchanged).
  • pnpm --filter @objectstack/spec test — 487 files / 14058 tests green.
  • pnpm lint (repo-wide eslint . --no-inline-config) — green, exit 0, at this head. Not narrowed.
  • Derived gate families: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack produced 106 commands; all 106 accounted for, 103 run green, 0 unrun, plus the 6 artifact-roster families whose roster sits under a directory one of these paths is in. 3 are NOT MEASURED (exit 3, PREREQUISITE NOT MET: check:dual-build-cjs-loads, check:lean-entry-closure, check:type-check-debt each need the whole workspace's built output, which this container cannot build inside one foreground window). Those three read other packages' emitted bytes and cannot be moved by a docblock; CI owns them.

Acceptance notes

  • .changeset/build-progress-phase-vocabulary.md was left untouched. Re-read at the start of this round: the file is still on origin/main, and PR chore: version packages #17076 (chore: version packages) is still open and unmerged, and holds a deletion of it. Its "never reports data" sentence therefore still wants the same softening, and this branch is not the place to contend for that file. Re-measured with a bright control: git grep -c "never reports" -- '*CHANGELOG.md' returns zero hits across the 80 CHANGELOG files the instrument sees, and so does the whole-sentence control data-build-progress, while changeset hits many of them — so the sentence has NOT been compiled into any published CHANGELOG yet. Naming it for the dispatching seat to judge, as instructed.
  • noted, not filed: the docblock of packages/spec/src/ai/build-progress.test.ts carries the same retired claim in its own words — "Each member was measured against a real end of the channel". It is the identical defect class, it predates this branch, and it does not ship (the tarball carries .zod.ts sources, not tests) nor render into any page. It was left alone because the dispatch fenced that file and the seat's file-surface declaration cannot be extended from here. Carrier: whoever next edits that pin. Dedupe words: build-progress test docblock measured claim, verify phase zero emitters, closed enum audit trail re-measure.

Generated by Claude Code

The module docblock on `ai/build-progress.zod.ts` stated three producer
claims as MEASUREMENTS. It ships inside the published `@objectstack/spec`
tarball and is rendered verbatim into the generated reference page, and for
a CLOSED vocabulary it is the audit trail the "re-measure before you move
the array" discipline reads — so a reader deciding whether a fifth phase is
warranted read all three as readings. One of them was false.

Every producer claim now carries exactly one of three labels, defined at the
top of the module: measured on a named reachable source / declared by ruling
/ inferred.

- Membership is no longer described as uniformly measured. `structure`,
  `data` and `done` stay measured, cited with the tree they were read
  against; `verify` is declared by ruling (cloud#2172, objectui#7388), with
  the zero-occurrence reading and its bright control recorded beside it.
- The cloud#1838 window (111 seconds, 9 tool calls, one of them
  `verify_build`) is inferred: that record is unreachable from this repo.
  What is measured is narrower and stated as such — `verify_build` is a
  registered platform tool.
- The two skipped-phase illustrations are inferred; the consumer guidance
  around them is unchanged and does not rest on them.

Adds a `## Liveness watch` section recording that `verify`, `hop` and `tool`
are declared ahead of any code that uses them, who the named carriers are,
and that no gate watches it — `BuildProgressFrame` is not a registered
metadata type, so the ADR-0049 liveness ledger never sees it.

No schema, export or parse behaviour moves. `content/docs/references/ai/
build-progress.mdx` is regenerated from the docblock by `gen:docs`.

Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3
Co-authored-by: Claude <noreply@anthropic.com>
@os-bill os-bill added documentation Improvements or additions to documentation domain:spec priority:p2 Medium: important, M3 tests labels Sep 18, 2026 — with Claude
@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 60 of 215 client-bound route-ledger rows — the other 155 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 155: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 100 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 — 136 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 36583e989b0b598f7974a275445655bc2989d763packageMentionDocs.

Which tree this was computed on

This run read content/docs from 32da22366f5ac3616aea45df34e585a0652d591d — the merge of head 5d12a8885045c32b3dc26892ecaec9481b853d33 into base 36583e989b0b598f7974a275445655bc2989d763, 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 32da22366f5ac3616aea45df34e585a0652d591d && git checkout 32da22366f5ac3616aea45df34e585a0652d591d
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 36583e989b0b598f7974a275445655bc2989d763 5d12a8885045c32b3dc26892ecaec9481b853d33 && git checkout -B drift-repro 36583e989b0b598f7974a275445655bc2989d763 && git merge --no-ff 5d12a8885045c32b3dc26892ecaec9481b853d33

node scripts/docs-audit/affected-docs.mjs --json 36583e989b0b598f7974a275445655bc2989d763

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

@os-bill
os-bill marked this pull request as ready for review September 18, 2026 03:21
@os-bill
os-bill added this pull request to the merge queue Sep 18, 2026
Merged via the queue into main with commit 0b31d90 Sep 18, 2026
53 checks passed
@os-bill
os-bill deleted the claude/issue-18552-build-progress-docblock-provenance branch September 18, 2026 03:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation domain:spec priority:p2 Medium: important, M3 protocol:ai size/m tests tooling

Projects

None yet

2 participants