Uh oh!
There was an error while loading. Please reload this page.
docs(spec): fix AgentSchema's @example and four stale .strict() tombstone rationales - #10922
Conversation
…bstone rationales
`AgentSchema`'s own `@example` wrote `knowledge: { sources, indexes }` — a key the
same file declares as `retiredKey()` about 110 lines below. The canonical example an
upgrading author copies taught a key the schema rejects, and typed `never` fails
`tsc` at the authoring site. Drop the line; the example keeps `skills`, which is the
whole point of the block.
Four tombstone rationales still argued from "the schema is not `.strict()`, so a
plain deletion would silently strip the key". The #4001 `strictObject` conversion
made that false for `AgentSchema`, `FieldSchema` and `ActionSchema`, and for the
premise in `shared/retired-key.ts`'s own module docblock. Each now rests on the
reason that is load-bearing today: the prescription is the payload, because an
unknown-key rejection carries neither the FROM -> TO mapping nor the migration
command, and the key is typed `never` so the mistake still fails `tsc` first.
Every tombstone stays; only the stated reason changes.
Prose only — no schema shape, acceptance behaviour or `.describe()` semantic moves.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B4h3medzvhB9rpfoja9jcw📓 Docs Drift CheckThis PR changes 1 package(s): 11 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 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 1f890e73ff5a088a362d4b71234b2ae65f49c377 && git checkout 1f890e73ff5a088a362d4b71234b2ae65f49c377
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 58563be069a70d09c4d9cc5f522bb27c5f8a78b2 b3d1970d87704b475e950d95b1f55406e4b49eff && git checkout -B drift-repro 58563be069a70d09c4d9cc5f522bb27c5f8a78b2 && git merge --no-ff b3d1970d87704b475e950d95b1f55406e4b49eff
node scripts/docs-audit/affected-docs.mjs --json 58563be069a70d09c4d9cc5f522bb27c5f8a78b2
|
os-elon
commented
Aug 21, 2026
Review: ACCEPT (reviewer of record: PM seat domain:spec, session_01B4h3medzvhB9rpfoja9jcw) Verified against GitHub, not the report:
Contract-review gate (clause-②): path leg fires ( Sweep out-of-scope outputs (grouped, for triage) — sweep criterion: sites carrying the "not
Landing: waiting on CI convergence on Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32509544075 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Fixes#10731
Two contained prose repairs in
packages/spec/src/ai/agent.zod.ts, plus the triage-approvedsweep for the same stale phrasing across
packages/spec/src/. Prose only — every changedline is a comment; no schema shape, acceptance behaviour or
.describe()semantic moves.1.
AgentSchema's@exampletaught a key the same schema rejectsThe docblock example wrote
knowledge: { sources: […], indexes: […] }, while the same filedeclares
knowledgeasretiredKey()(i.e.z.never()) about 110 lines below. The line isdropped; the example keeps
skills, which is the block's whole point.Verified as an A/B against the built
dista consumer actually resolves — not asserted.Both snippets were type-checked against
packages/spec/dist/index.d.ts:Line 8 col 3 is exactly the
knowledge:line. The card's premise holds: the canonical examplean upgrading author copies did not compile.
Note on gate coverage, since it is easy to over-claim:
check:skill-examplescompiles onlymarked fences under
skills/andcontent/docs, and this@exampleis published to neither(
support_tier_1appears nowhere incontent/docs). Nothing in CI was compiling it — the A/Babove is the measurement, and it is why the defect survived.
2. The stale
.strict()rationale — and the sweepFour tombstone rationales still argued "the schema is not
.strict(), so a plain deletionwould silently strip the key". The #4001
strictObjectconversion made that false for theschemas named. Each now rests on what is load-bearing today: the prescription is the
payload — an unknown-key rejection carries neither the FROM → TO mapping nor the migration
command — plus the
nevertyping that still failstscat the authoring site. Everytombstone stays; only the stated reason changes.
Fixed (owning schema confirmed strict at the cited line):
ai/agent.zod.tstoolstombstone :226AgentSchema=strictObject(:143)data/field.zod.tsconditionalRequiredtombstone :1209FieldSchema=strictObject(:663)ui/action.zod.tsexecutetombstone :976ActionSchema←actionObject()=strictObject(:765)shared/retired-key.tsFieldSchema, now strictai/agent.test.tsThe card's assumption that the conversion was repo-wide is itself imprecise, and that
mattered — most sites carrying this phrasing are still accurate and were deliberately left
alone. Each was checked against its owning declaration rather than pattern-matched:
shared/retry-policy.zod.ts:116—RetryPolicySchemais a plainz.object(:176). Accurate.shared/mapping.zod.ts:88—FieldMappingSchemais a plainz.object(:74). Accurate.kernel/manifest.zod.ts:512—ManifestSchemais a plainz.object(:132). Accurate.kernel/metadata-plugin.zod.ts:495—MetadataPluginConfigSchemaplainz.object(:461). Accurate.api/rest-server.zod.ts:120, :511—RestApiConfigSchema(:48) /RestServerConfigSchema(:481) both plain. Accurate.integration/connector.zod.ts:798—ConnectorSchemaplainz.object(:690). Accurate.conversions/registry.ts:3114—BookGroupSchemaplainz.object(system/book.zod.ts:82). Accurate.migrations/registry.ts:3413—HookContextSchemaplainz.object(data/hook.zod.ts:334). Accurate.data/field.zod.ts:148— already past tense ("was not.strict()"). Accurate.FENCE honoured:
ui/component.zod.tsis held by in-flight #10054 and was not edited. Italso turns out to carry no strictness claim at all (
grepfor "not.strict()" therereturns nothing), so there was no hit to file either.
One bounded in-place fix, declared
data/field.zod.ts:1180said "This object is NOT.strict()" in the present tense aboutFieldSchema— false since #4001, and inconsistent with :148 in the same file, which alreadyuses the past tense for the same episode. Corrected to past tense with the closing noted. This
is outside the rider's literal wording (it is a removal-history comment, not a
retiredKeydocblock), so it is called out here rather than folded in silently: same defect class, same
file already open, mechanical, evidence-pinned, no new verification surface.
Clause-② proof (mechanical)
Every changed line classified against
^(//|\*|/\*\*|/\*|\*/)after trimming:Verification — gate union pinned to
b3d1970d87Gates were re-derived from the actual diff with
node scripts/pm/dispatch-gates.mjs(no pathspassed — it takes its own change set from the merge base), which named families beyond the
dispatch list, including the test-file convention gates. All of the following ran against
b3d1970d87with a clean tree, quoting each gate's own verdict line:pnpm --filter @objectstack/spec test→ 415 files / 11049 tests passedpnpm --filter @objectstack/spec typecheck→ EXIT 0pnpm --filter @objectstack/spec check:generated→ "✓ All 14 generated artifacts are up todate." — this prose feeds no generated artifact, so nothing was regenerated
check:strictness-ledger→ "✓ strictness ledger: 60 file(s) … no undeclared schema files"check:doc-formula-expressions→ "✓ 9 @example(s) judged clean across 977 packages/spec/src files"check:cross-package-test-inputs,check:empty-state,check:liveness,check:merge-driver,check:slot-lookup,check:spec-parsed-alias,check:test-source-alias,check:type-source-resolution,check:variant-docs,check-ci-filter-parity,check-plugin-teardown-shape,check-affected-docs,check:query-options-erasure,check:engine-double-contract,check:where-matcher,check:type-check-coverage,check:changeset-gate-self-tests,check:objectui-changeset,check-adr-0087-registration,check-changeset-no-major,check-empty-changeset,check:nul-bytesDeclared narrowings (CI runs the full farm regardless):
pnpm lintrepo-wide was narrowed to the changed files, and the narrowing is measured ratherthan assumed: population 4787 files, read from ESLint's own
isPathIgnored()configresolution (0 ignored) — not a guess about what counts; 5 files linted, count read from
--format jsonoutput length, 0 errors / 0 warnings; and config invariance — this reporuns one
eslint.config.mjswhich, in its own words at :327, "never enables type-awarelinting (no
parserOptions.project, no typed@typescript-eslintrules) for ANY file" — so acomment-only diff in 5 files cannot move the verdict on any of the 4782 untouched files.
check:type-check-debt --re-measureandcheck-dev-prereqswere not measured locally:both require the full workspace closure built, and this fresh worktree has only
@objectstack/specand@objectstack/formulabuilt.check-dev-prereqsreports theprecondition explicitly — "The workspace is not built — 66 of 67 workspace packages declare an
entry point under dist/ that is not on disk" — which is an unmet precondition, not a finding
against this diff. A comment-only diff cannot move a tsc error count.
Changeset
.changeset/olive-pumas-repeat.md,@objectstack/specpatch. TheAgentSchemadocblockships in the published
.d.ts, so the corrected example is consumer-visible text. Non-breaking,so no ADR-0087 marker is required —
check-adr-0087-registrationagrees: "this PR adds nodeclared-breaking changeset".
Generated by Claude Code
Generated by Claude Code