Skip to content

docs(spec): stop restating a plugin-local union's members, and name the mis-aimed nav-group case - #16958

Merged
zhuangjianguo merged 1 commit into
mainfrom
claude/issue-16708-expired-tsdoc-member-counts
Sep 8, 2026
Merged

docs(spec): stop restating a plugin-local union's members, and name the mis-aimed nav-group case#16958
zhuangjianguo merged 1 commit into
mainfrom
claude/issue-16708-expired-tsdoc-member-counts

Conversation

@zhuangjianguo

Copy link
Copy Markdown
Collaborator

Fixes #16708
Fixes #16507

Clause-②: no
Both defects are a source comment that states a count or a scope the tree contradicts.
Rewriting them moves no accept set, adds no export, changes no type and puts no new key on
any payload. The whole diff is comment text plus one changeset. 拉回已声明契约 ⇒ 常规档.

Two cards, one family: a comment that stated a count (#16708) or a command scope
(#16507) the tree had already contradicted. One fix method in both — rewrite the sentence to
what the tree does, code untouched.

#16708 — the member list is removed, not refreshed

Re-derived from the type itself, not from the card's count
(packages/plugins/plugin-approvals/src/approval-service.ts:516, the tree's only declaration
of it):

export type StrandedRunState = 'missing' | 'failed' | 'repairable' | 'snapshot_dropped' | 'unrepairable';

Five members — the card's number is correct. The spec docblock named two.

The copy is deleted rather than corrected, and that is a measurement, not a preference. A
two-leg ablation from the committed state, each leg proved on disk and each restore proved by
blob hash against HEAD:

leg mutation, proved on disk automation-result-status.pin.test.ts
baseline exit 0, 8 passed
A the token StrandedRunState removed from that docblock (occurrences 1 → 0, injected marker present 1×) exit 1AssertionError: expected '/**\n * Lifecycle status…' to contain 'StrandedRunState'; 1 failed / 7 passed
B the deleted two-member list put back verbatim, 'missing' then 'failed', in its original parenthetical exit 0, 8 passed

Leg A proves the pin really reads this docblock — the instrument is not blind. Leg B proves
nothing pins the member list: a refreshed five-member copy would sit exactly as unguarded
as the two-member one did, and would go stale the next time the plugin splits an arm. The pin
test says so itself in its header — plugin-approvals' StrandedRunState is on its list of
things "⛔ Not pinned, deliberately". So the docblock now names where the members live and
why they are not restated here, instead of counting them.

Restore after each leg: blob 2d82047493ca63e6b4ea7f945de61ba74370844c == HEAD,
git diff HEAD empty, git status --porcelain empty.

#16507 — both spots, line numbers re-taken from the tree

The card's line numbers were stale; these are this tree's.

  1. packages/spec/src/ui/app.zod.ts — the NavigationContributionSchema JSDoc (the card said
    "around :739"; the block is :744-769, the schema at :770). It documented only the
    omitted group case while the .describe() at :780 — corrected in docs(spec): navigationContributions[].group describe() documents the omitted case but not the mis-aimed one #14925 — also
    names the case where group is present and names no group the target app declares. The
    JSDoc now carries that case in the spelling the .describe() and
    content/docs/ui/setup-app.mdx:99 already use, plus the one clause that makes it matter:
    an author cannot detect it from their own source, because the target app belongs to another
    package. ⛔ No third spelling was invented.
  2. examples/app-multi-package/src/packages/orders/index.ts — the fixture comment (the card
    said :47; it is :47 still) credited only os build. findNavGroupDiagnostics is
    imported by packages/cli/src/commands/compile.ts:49 and
    packages/cli/src/commands/validate.ts:44 (the card said :43) and folded into the same
    warnings key from compile.ts:506 / validate.ts:355. It now names both commands.

Closing self-check, with a firing control (triage's acceptance point 4 — ⛔ not a single
grep):

probe tracked-file hits
the JSDoc-unique phrase declare is not refused either 1packages/spec/src/ui/app.zod.ts only
control, the sibling .describe() phrase, same instrument, same tree 3 — the source plus content/docs/references/ui/app.mdx and content/docs/references/kernel/manifest.mdx
the JSDoc phrase inside packages/spec/json-schema/ 0
control, the .describe() phrase inside packages/spec/json-schema/ 24

The control fires, so the zero is a reading. The edited JSDoc reaches no generated artefact;
the .describe() beside it does, and it was already correct.

Hand-scan of the docs, not an anchor check — every page that carries this claim already
says "os build and os validate" (content/docs/ui/setup-app.mdx:99,
references/ui/app.mdx:569, references/kernel/manifest.mdx:108). docs/audits/** and
content/** carry no occurrence of StrandedRunState, snapshot_dropped or unrepairable
(control on the same file set: nav_contribution_group_missing → 2 files). ⛔
content/docs/releases/** untouched.

Changeset — measured in two halves, and they DISAGREE on one file

skip-changeset was not assumed. Positive and negative controls on both halves.

file half 1 — path vs files[] half 2 — text in the built dist verdict
packages/spec/src/contracts/automation-service.ts NOfiles[] publishes src/**/*.zod.ts, and this is not a .zod.ts YESreport-only labeldist/contracts/index.d.ts + .d.mts published
packages/spec/src/ui/app.zod.ts YES — matched by src/**/*.zod.ts, shipped as source YESmirroring object extender orderingdist/app.zod-CHxLLVKs.d.ts + .d.mts published
examples/app-multi-package/src/packages/orders/index.ts not published — "private": true, no files[] n/a not published

Controls for half 2, over the same dist/: positive Naming a group the target app does not declare20 files; negative zzz_no_such_string_control0.

⇒ Half 1 alone would have called automation-service.ts unpublished and been wrong: its
TSDoc is emitted into the published .d.ts. A patch changeset for @objectstack/spec is
owed and is in the diff. Nothing that reaches a generated artefact moved —
pnpm --filter @objectstack/spec check:generated reports all 15 artifacts up to date and left
git status empty.

Gates — derived, run, reconciled

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands71
families
; every one run; reconciled with --ran:

✓ dispatch-gates --ran: 71 derived famil(ies) accounted for — 71 run, 0 NOT-MEASURED.
Run reconciliation — 71 derived, 71 run, 0 NOT-MEASURED, 0 UNRUN.

Six of them first refused with PREREQUISITE NOT MET (a stale packages/spec/dist; unbuilt
@objectstack/formula / @objectstack/lint; and check:dual-build-cjs-loads wanting every
package's dist). ⛔ Those were NOT MEASURED, never red — so the prerequisite was built
rather than declared: pnpm --filter @objectstack/spec build, then
turbo run build --filter=@objectstack/spec --filter=@objectstack/formula --filter=@objectstack/lint,
then a full turbo run build --concurrency=2 (74/74 tasks). All six then ran and returned 0:
check:doc-formula-expressions, check:api-surface, check:browser-reachable-entries,
check:dual-source-exports, check:entry-nameability, check:dual-build-cjs-loads.

Every heavy run went through scripts/pm/os-verify-lock.sh; exit codes read from its printed
VERDICT command-exit line, ⛔ never from a bare $? behind a pipe.

Tests

run result
pnpm --filter @objectstack/spec test (full, under the lock) VERDICT command-exit 0467 files, 13100 tests passed
targeted: automation-result-status.pin.test.ts + ui/app.test.ts VERDICT command-exit 0 — 2 files, 110 passed
pnpm --filter @objectstack/spec typecheck SPEC_TC_EXIT=0
pnpm --filter @objectstack/example-multi-package typecheck EX_TC_EXIT=0
ablation, both legs table above

Lint — a declared narrowing, with its three readings (all at c0143fd83, the final commit):

  1. Receiving population, read from eslint's own config — not guessed:
    ESLint#isPathIgnored answers false for all three changed paths, so no part of this diff
    sits outside the lint population.
  2. File count from --format jsoneslint --no-inline-config --format json over the three
    paths: 3 files linted, 0 errors, 0 warnings, exit 0.
  3. Invariance for untouched fileseslint.config.mjs:324-334 records that this repo
    "never enables type-aware linting (no parserOptions.project, no typed
    @typescript-eslint rules) for ANY file". A comment-only diff in three files therefore
    cannot move any untouched file's verdict.

All three are present, so the narrowing is a measurement rather than a skipped run. The
repo-wide pnpm lint remains CI's.

验收备注

Triage's acceptance criteria for #16507, answered in order:

  1. Wording taken from setup-app.mdx and the post-docs(spec): navigationContributions[].group describe() documents the omitted case but not the mis-aimed one #14925 .describe() — ⛔ no third
    spelling invented.
  2. os validate added to the fixture comment, matching "os build and os validate".
  3. ⛔ Nothing behavioural touchedfindNavGroupDiagnostics untouched,
    nav_contribution_group_missing still warn.
  4. Closing check ran with a firing control, table above — ⛔ not one bare grep.
  5. content/docs/releases/ untouched.

On triage's 第 4 条 (the "cannot be split" judgement) — reported, ⛔ not acted on. Triage is
right that the two spots are uncoupled: different files, different packages, different facts,
and neither reaches a generated artefact. Splitting was mechanically available. It was not
done, per the dispatch fence. Measured cost of folding, for triage's ledger: the two halves
shared one gate sweep (71 families), one full spec build and one changeset — a split would have
paid all three twice, and examples/app-multi-package typechecks against the built spec anyway,
so the "examples/ half need not wait for the spec half" argument does not hold in this tree.
⇒ The fold looks cheaper here than the split; triage's instinct is sound in general but the
saving would have been negative on this pair.

Notes, not filed (⛔ neither is a reproducible defect, a contract violation, or an
authoring trap, so ⛔ no card):


Generated by Claude Code

…he mis-aimed nav-group case

`AutomationResult.status`'s docblock carried a copy of plugin-approvals'
`StrandedRunState` members (`'missing' | 'failed'`). That union has since
split `'failed'` three ways, so the copy contradicted the type. Removed
rather than refreshed: the union is plugin-local and the spec pin test
excludes it on purpose, so a member list here is unpinned prose.

`NavigationContributionSchema`'s JSDoc documented only the omitted-`group`
case while the `.describe()` below it already named the mis-aimed one; the
JSDoc now uses the same spelling. The `app-multi-package` fixture comment
credited only `os build` for a finding both `os build` and `os validate`
report.

Card relationships are declared in the PR body, not here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x
@github-actions github-actions Bot added the size/s label Sep 8, 2026
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 1 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/spec/src/ui/app.zod.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

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

  • content/docs/api/client-sdk.mdx (via AutomationResult (symbol, a top-level interface))
  • content/docs/automation/flows.mdx (via AutomationResult (symbol, a top-level interface))

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

  • content/docs/releases/v17.mdx (via AutomationResult (symbol, a top-level interface))

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
  • 1 changed file(s) yielded no anchor (packages/spec/src/ui/app.zod.ts) — pages documenting those are invisible to this run
  • 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 — 131 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 97adce2faa9d27d7811f1f299f5ed806a467f624packageMentionDocs.

Which tree this was computed on

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

node scripts/docs-audit/affected-docs.mjs --json 97adce2faa9d27d7811f1f299f5ed806a467f624

⚠️ 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 97adce2faa9d27d7811f1f299f5ed806a467f624 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:ui tooling labels Sep 8, 2026
@zhuangjianguo
zhuangjianguo marked this pull request as ready for review September 8, 2026 20:03
@zhuangjianguo
zhuangjianguo added this pull request to the merge queue Sep 8, 2026
Merged via the queue into main with commit 3e21cf0 Sep 8, 2026
36 checks passed
@zhuangjianguo
zhuangjianguo deleted the claude/issue-16708-expired-tsdoc-member-counts branch September 8, 2026 20:30
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 protocol:ui size/s tooling

Projects

None yet

2 participants