Skip to content

fix(spec): the error-code waiver reasons and the auth-feature registry notes state each decision in words instead of a tracker number (stage 7) - #21636

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-20749-spec-strings-stage7
Oct 3, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-20749-spec-strings-stage7

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #20749
Clause-②: no

Stage 7 of the domain:spec lane's share of the runtime-string burn-down (ruling 5902360492, A / A; form D per 5749154545): class (f), the internal registry rationales in packages/spec/src. Every rewritten reason or note now states in words what the cited decision was, or drops a citation its sentence already explained. Text only. The card stays open for its later stages (migrations/registry.ts, then the test strings).

What changed

  • 17 messages / 33 tracker ids / 22 distinct cited records (21 cards and one PR) in two files:
    • api/error-code-ledger.zod.ts: the reason of all five STANDARD_SYNONYM_WAIVERS entries and of nine PROVENANCE_WAIVERS entries (14 messages / 29 ids).
    • kernel/public-auth-features.ts: PUBLIC_AUTH_FEATURES.deviceAuthorization.exempt.reason, .phoneNumber.notes and .phoneNumberOtp.exempt.reason (3 / 4).
  • One @objectstack/spec patch changeset, Clause-②: no. These are exported constants, and the new text ships in the package's dist: measured in 14 .js and 14 .mjs chunks, and in no .d.ts (the reasons are + chains, so their type is string).
  • No generated artifact moves (check:generated: all 15 up to date). No reader matches these strings by their text (see "Readers" below), so no test or gate moves.
  • Landing site: packages/spec, as the claim predicted. Each producer is the constant itself, so no other package is touched.

Census at the base (A1)

The earlier stages' census.cjs is not on disk in this container. I re-implemented it from stage 3's stated semantics, then held it to two references:

  • The gate's own per-literal leg. check-doc-authoring.mjs --census was run from a scratch copy whose PACKAGES_PROSE_ROOT / PACKAGES_PROSE_EXCLUDED were pointed at packages/spec/src and at nothing (two lines differ, nothing else). Result: 3 files, 231 = 231 ids, 0 per-file differences.
  • Stage 6's numbers at 2f30de851c. Test strings 1804 / 1920 in 425 files, identical. Class (f) 17 / 33, identical, line for line against stage 3's table.

At base 045b946256, 1849 files were scanned and 1346 parsed after the byte prefilter, with 0 parse diagnostics:

file (under packages/spec/src) messages / ids message by message (line:id)
api/error-code-ledger.zod.ts 14 / 29 1618:8111 1619:8211 · 1625:13353 1627:8211 · 1633:8211 · 1639:19441 1640:8211 · 1646:8211 1647:8211 · 1752:11142,11230 · 1760:9415,9446 · 1766:9415,9446 · 1773:10025,11504,10413 1774:10576 · 1782:13353 1786:8016 · 1793:7870 1796:13353 · 1812:8016,3918 · 1821:8016,16322 · 1838:7780 1839:20492
kernel/public-auth-features.ts 3 / 4 197:2513,2874 (the 2513 is the cross-repo objectui#2513) · 220:2871 · 230:2780

The claim's raw-grep figures (192 and 14 lines) include comments. Comments are out of this stage.

Controls.

  • Lit, multi-line: error-code-ledger.zod.ts:1773-1776 reads as ONE message, with 4 ids on lines 1773-1774.
  • Lit, single: public-auth-features.ts:220 reads as one message, #2871.
  • Dark: error-code-ledger.zod.ts:1589 (docblock, #8211), :1687 (a // heading, #13353), public-auth-features.ts:106 (// [#11544]) and :209 (a // inside the array, #9968) each read 0.
  • Whole tree: 2151 hit lines, none on a comment line.

The rest of the non-test population at this base is migrations/registry.ts: 45 messages / 198 ids. Stage 6 read 43 / 196 at 2f30de851c, so main has since added two messages there. That file is the next stage's.

Delivered (A2): each site, the decision as read, the new words

I read each cited card in full through REST, body and every comment. The decision column names the record. Line is the base line of the message.

file:line ids decision as read old → new
error-code-ledger.zod.ts:1618 (CONFLICT) 8111, 8211 8111: dev report 5272495731 (census-first route 5271501976). The record-sharing errors moved onto the ADR-0112 envelope, and the unregistered 409 CONFLICT was registered as it stood under @objectstack/rest, so the wire stayed byte-identical. 8211: triage adjudication 5273232415, option C. The admission gate refuses a semantic synonym unless waived. The existing synonyms are grandfathered by waivers, and consolidation (B) is deferred until a specific code has a measured victim (respondSharingError 409 arm; registered by #8111). Wire value kept; consolidation deferred per #8211. → (respondSharingError 409 arm), registered as it stood when the record-sharing errors moved onto the ADR-0112 envelope, so the wire stayed byte-identical. Wire value kept; consolidation deferred until it has a measured victim.
error-code-ledger.zod.ts:1625 (FORBIDDEN) 13353, 8211 13353: dev report 5489077644 and ACCEPT 5489099444. The provenance gate landed, and cloud-connection's own-route 403 got its FORBIDDEN row; this waiver's reason was extended, not endorsed. 8211 as above #13353 added the cloud-connection provenance row for the same pre-existing wire value → cloud-connection lists the same pre-existing wire value under its own provenance row; the closing clause as for CONFLICT
error-code-ledger.zod.ts:1633 (INTERNAL) 8211 as above consolidation deferred per #8211. → consolidation deferred until it has a measured victim.
error-code-ledger.zod.ts:1639 (NOT_FOUND) 19441, 8211 19441: dev report 5788584892. plugin-security's class-field stamps got their rows, the overlay-discard 404's NOT_FOUND among them, and this waiver's reason named the new emitter. 8211 as above #19441 added the plugin-security provenance row for the same pre-existing wire value → plugin-security lists the same pre-existing wire value under its own provenance row; the closing clause as for CONFLICT
error-code-ledger.zod.ts:1646 (UNAUTHORIZED) 8211 ×2 as above. The card named four synonyms, and the detector found this fifth when it landed surfaced by the detector when the #8211 gate landed, beyond the four the card named → surfaced by the synonym detector when it landed, beyond the four first reported; the closing clause as for CONFLICT
error-code-ledger.zod.ts:1752 (UPDATE_ID_MISMATCH) 11142, 11230 maintainer rulings 5383569192 (unequal scalar where.id) and 5386672884 (non-scalar where.id). Both shapes are refused 400 with one code, from metadata-core's shared constructor, thrown by ObjectQL.update. The objectql row's comment records it records "hence registered here" (#11142/#11230). → records "hence registered here". (the sentence already said it)
error-code-ledger.zod.ts:1760 (FLOW_DISABLED) 9415, 9446 9415: card body and delivery 5322602563. A disabled flow answers 409 FLOW_DISABLED, registered under runtime because the door names the wire vocabulary. 9446: maintainer ruling 5322867819. The status table is a property of the flow-dispatch contract, so every door converges answer 409 (#9415/#9446; the runtime row's comment records the decision). → answer 409 — every door that dispatches a flow answers from one status table, by ruling (the runtime row's comment records the decision).
error-code-ledger.zod.ts:1766 (FLOW_NO_START_NODE) 9415, 9446 as above, the 422 row Same decision as FLOW_DISABLED, 422 arm (#9415/#9446): → Same decision as FLOW_DISABLED, its 422 arm:
error-code-ledger.zod.ts:1773 (FLOW_INPUT_SCHEMA_INVALID) 10025, 11504, 10413, 10576 10025: maintainer ruling 5353928368 (B). A definition-level input-schema refusal is non-retryable and becomes a never-dispatched exit with its own code. 11504 (the card answers 404; its comments are still served, claim 5429880388, dev report 5430346333): the contract half of that ruling, which minted the code ahead of its producer. 10413 / 10576: maintainer ruling 5364977280 filed the contract half as its own card, ahead of the implementing half. That is the split shape Registered ahead of its producer by design (#10025 → #11504, the #10413 → #10576 split shape): → Registered ahead of its producer by design: the ruling that a definition-level input-schema refusal is non-retryable and never dispatched split into a contract half, which minted this code, and a services half that emits it, the contract half landing first.
error-code-ledger.zod.ts:1782 (EXTERNAL_IMPORT_ERROR) 13353, 8016 13353: as above. This entry was the first adjudication: a door case, so a waiver, not a row. 8016: dispatch ruling 5267576256 and dev report 5268577504. One thrown-error mapping (resolveThrownHttpError, @objectstack/types) shared by both doors honours a throw's own status and code. importNameRefusedError sets exactly those two (external-datasource-service.ts:337-342) Adjudicated on #13353: → Adjudicated when the provenance gate landed:; is the #8016 declaration shape, → declares its own `status` and `code`, the shape the shared thrown-error resolver honours,
error-code-ledger.zod.ts:1793 (UPLOAD_SESSION_EXPIRED) 7870, 13353 7870: promotion 5270541620 and dev report 5274803860. resumeUpload short-circuits on expired with the server's 410 pair. 13353: ACCEPT 5489099444. The scope question stays recorded on the waiver, with no new card, for want of pull Client-side synthesis (#7870): → Client-side synthesis:; is the open scope question #13353 recorded — → is an open scope question, recorded when the provenance gate landed and left unruled for want of pull —
error-code-ledger.zod.ts:1812 (VALIDATION_FAILED) 8016, 3918 3918: card body. The dispatcher's exits answer a validation failure 400 with its fields[], never 500, matching rest. 8016: validationFailure moved into @objectstack/types beside the shared mapping (validation-failure.ts header) Shared constructor by design (#8016/#3918): `validationFailure()` lives in the dependency-light package so BOTH doors recognise one shape; → Shared constructor by design: `validationFailure()` lives in the dependency-light package beside the one thrown-error mapping both doors share, so BOTH doors recognise one shape and answer it 400 with its `fields[]`, never 500;
error-code-ledger.zod.ts:1821 (ANALYTICS_DATE_RANGE_UNRECOGNIZED) 8016, 16322 16322: card body (the driver half of the date-range contract, director ruling batch 57, option A). Memory and SQL analytics drivers refuse an unrecognised dateRange identically, held by one shared conformance fixture. 8016: the shared-constructor shape, which the sentence already states Shared constructor one package over, the #8016 shape (#16322): → Shared constructor one package over:; refuse identically — which is the property the card's shared conformance fixture → refuse an unrecognised `dateRange` identically — which is the property the shared date-range conformance fixture
error-code-ledger.zod.ts:1838 (TENANT_SCOPE_REQUIRED) 7780, 20492 7780: maintainer ruling 5261730657. An uninstall across every tenant must be declared explicitly; no organization and no flag is a loud 400, never every tenant's rows. 20492: triage 5877470267 and dev report 5878755305. Every refusal runs before uninstallPackage, so a refused request changes nothing refuses with (#7780), so a refused uninstall changes nothing (#20492). → refuses a scope-less uninstall with (an uninstall across every organization must be declared, never inferred from a missing one), so a refused uninstall changes nothing.
public-auth-features.ts:197 (deviceAuthorization) 2513 (objectui), 2874 objectui 2513: card body, closed completed 2026-07-15. DeviceAuthPage reads features.deviceAuthorization and shows a not-enabled state instead of calling the endpoints; the client type gained the key. 2874: card body. P2② is the login-surface audit of objectui's consumption Known gap: objectui DeviceAuthPage hits the device-auth endpoints without checking this flag (absent from its client type) — tracked in objectui#2513 (#2874 P2②). → Login consumption verified: objectui DeviceAuthPage reads this flag and, when it is off, says device authorization is not enabled instead of calling the device-auth endpoints. (see Acceptance notes: the old text was stale)
public-auth-features.ts:220 (phoneNumber) 2871 2871 (a PR): body. The create-user form follows the plugin: the phoneNumber param is visible only on features.phoneNumber == true, and default-loading the plugin was rejected The original #2871 fix. → The fix this registry generalizes: create-user's phone field follows the opt-in phoneNumber plugin instead of offering a field the backend refuses.
public-auth-features.ts:230 (phoneNumberOtp) 2780 2780: card body. SMS provider and messaging sms channel for phone OTP. isPhoneOtpDeliverable() (auth-manager.ts:7735-7740) answers false without an SMS service, and false for a log-only one in production when SMS is actually deliverable (#2780). → when an SMS service can actually deliver the code; a log-only transport in production keeps it off.

Six of the longer reasons (FLOW_INPUT_SCHEMA_INVALID, EXTERNAL_IMPORT_ERROR, UPLOAD_SESSION_EXPIRED, VALIDATION_FAILED, ANALYTICS_DATE_RANGE_UNRECOGNIZED, TENANT_SCOPE_REQUIRED) were re-wrapped after the edit so no continuation line is ragged. A script compared each message's joined string value before and after the re-wrap: identical, read back from disk. Code spans never break across a line.

Readers (A3)

  • Programmatic readers check non-emptiness only.
    • StandardSynonymWaiverSchema / ProvenanceWaiverSchema require reason: z.string().min(1). error-code-ledger.test.ts and check:error-code-provenance parse every waiver through them.
    • public-auth-features.test.ts:54 requires exempt.reason.length > 0.
    • Control: all of them ran green on the head. 45 of 45 in the two spec files. check:error-code-provenance: "OK — every registered-code stamp site is listed under its own owner key or carries a recorded waiver (10 waiver(s), all live)", 330 sites, 311 listed, 19 waived.
  • Nothing reads the text.
    • Every 32-character window of the 17 old messages that the new text no longer contains (1274 windows) was searched with git grep -F across the tree, the two edited files excluded. One hit: a // section heading in packages/runtime/src/domains/packages-uninstall-refuse-before-mutate.test.ts:221, not an assertion.
    • No content/docs/** page, skills/** file, snapshot or generated artifact quotes a changed message.
    • The platform-objects and plugin-auth registry guards read keys, semantics and gatedInputs, never notes or reason.

Text only (A4)

The earlier stages' skeleton.cjs is not on disk either, so I re-implemented it from its stated semantics, with TypeScript 6.0.3:

  • Leg 1 is an AST skeleton. Every string's text is masked, and a + chain's adjacent string operands read as one string. Identifiers, numbers, regex literals, keywords and punctuation are kept, and comments are never read.
  • Leg 2 is the text of every string group. Each changed group must carry a tracker id before and none after; every other group must be byte-identical.

Base copies against the committed head 151a8ce4ed:

file skeleton tokens string groups changed verdict
error-code-ledger.zod.ts 3184 429 14 SAME, exit 0
public-auth-features.ts 1639 112 3 SAME, exit 0

Parse diagnostics were 0 / 0. The 17 changed groups are the 17 census messages.

Controls, on scratch copies of the head ledger. Each mutation was counted on disk: anchor hits 1, replacement present 1, anchor left 0, differs from head.

mutation expected got
standardSynonymViolations renamed DIFF DIFF, exit 1
=== flipped to !== in the waiver check DIFF DIFF, exit 1
one literal re-split into two + operands SAME SAME, exit 0, still 14 changed
text changed in a .describe() string that never carried an id VIOLATION VIOLATION, exit 3
a rewritten reason given a tracker id back VIOLATION VIOLATION, exit 3

No repo file was mutated for the controls.

Edits were applied by a script whose 20 anchors each had to hit exactly once in the original text before any write. They were read back from disk after it: 20 gone, 20 replacements present once.

Census after: class (f) 0 / 0. Non-test went from 62 / 231 to 45 / 198, all of it migrations/registry.ts. That file is the lit control: the instrument still sees its ids, so the zero is not blindness. Test strings are unchanged at 1804 / 1920. The gate's per-literal leg agrees: 198 ids, all in migrations/registry.ts.

Gates

All heavy runs went through scripts/pm/os-verify-lock.sh (slot dev-20749-s7). Every exit code was written to a file before it was read. All runs are at 151a8ce4ed.

  • pnpm --filter @objectstack/spec build: exit 0, "38/38 declared declaration file(s) present".
  • pnpm --filter @objectstack/spec check:generated: exit 0, "All 15 generated artifacts are up to date".
  • pnpm --filter @objectstack/spec test: "Test Files 608 passed (608) / Tests 18017 passed | 1 todo (18018)".
  • pnpm --filter @objectstack/spec run typecheck: exit 0, "check:test-typecheck: OK … 52 file(s) / 246 error(s) / 135 pinned signature(s) held".
  • The repo project's one file that reads a changed module (scripts/file-description.test.ts, which reads the ledger file's opening docblock): 111 of 111.
  • pnpm turbo run build --concurrency=2 over every package: 71 / 71. This fed the dist-reading gates. On the first pass, before this build, three of them answered PREREQUISITE NOT MET (exit 3): check:doc-formula-expressions, check:dual-build-cjs-loads and check:lean-entry-closure. The other two (check:dts-closure, check:sourcemap-no-sources-content) had swept only 1 built package. All five were re-run after the build.
  • Derived union. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) derived 82 commands for 3 paths vs merge base 045b94625: 139 changed lines (+85 / -54), under 5000. All 82 exit 0 on the built tree. --ran: "82 derived famil(ies) accounted for — 82 run, 0 NOT-MEASURED (a DERIVED zero — all 82 recorded an exit code and none of them is 3)".
    • check:doc-authoring: "17351 customer-facing string(s) across 1255 spec sources clean" / "0 pinned site(s) … no growth, no burn-down unrecorded".
    • check:nul-bytes: "OK (scanned 9998 text file(s) …)". A self-scan of the added lines for raw control bytes found none.
    • check:issue-citations, check:api-surface and check:error-code-provenance all exit 0.
  • NOT MEASURED here, reason: the derivation names them as taking a value from the workflow (check-issue-citations --census, the shard attestations, check-test-completeness). They are CI's.
  • ESLint, a proven narrowing. eslint --no-inline-config --format json over the 2 changed TS files read 2 files, 0 errors, 0 warnings. Population comes from ESLint's own config: calculateConfigForFile returns a config for each, and isPathIgnored is false. Invariance: no type-aware linting (parserOptions.project / projectService are null for both), so a string-text edit cannot move an untouched file's verdict. Repo-wide pnpm lint is CI's.
  • The PR-body gates (check-changeset-no-major --event, check-partof-closing-keyword) were run against this exact title and body before it was sent; their lines are in the dev report.

Acceptance notes

  • One reason was stale, and the rewrite states the delivered decision. The deviceAuthorization exemption said objectui's DeviceAuthPage called the device-auth endpoints without checking the flag, a gap "tracked in" objectui 2513. That card closed completed on 2026-07-15. At the .objectui-sha pin 89cad75d55, apps/console/src/pages/auth/DeviceAuthPage.tsx:66-130 reads features.deviceAuthorization and renders "Device authorization not enabled" when it is off, and packages/auth/src/types.ts:286 declares the key. Stating that card's decision in words makes the text say the gap is closed. The registry's semantics, surface and keys are untouched.
  • A cited card answers 404. Card 11504 returns 404 from the issues endpoint. Its comments are still served (claim, dev report, ACCEPT), and its decision was read from them; it did not read as unclear.
  • Main moved two commits after the base (a4f0cb0a45, 0fc80878f8: service-automation and lint, plus their changesets). Neither touches this PR's three paths or packages/spec, so main was not merged; the merge queue rebuilds onto current main. No open PR touches these paths: 12 open PRs read, file lists included.
  • Left for later stages, untouched here: migrations/registry.ts (45 / 198 at this base), the test strings (1804 / 1920), the two .mjs gate scripts, and every comment, including the docblocks and the // headings beside these tables.
  • Not governed: no .claude/**, skills/**, ADR, NORTH-STAR or AGENTS.md path.

Line budget

139 changed lines (+85 / -54) over 3 files vs merge base 045b94625 (dispatch-gates): the ledger (+59 / -48), the auth registry (+9 / -6), and the changeset (+17). No generated file, no governed surface.


Generated by Claude Code

…y notes state each decision in words instead of a tracker number (stage 7)

Class (f) of the spec lane's runtime-string share: 17 registry rationales
(33 tracker ids) in STANDARD_SYNONYM_WAIVERS / PROVENANCE_WAIVERS and
PUBLIC_AUTH_FEATURES. Each now states the cited decision in words, or drops
a citation its sentence already explained. Text only; one patch changeset.

Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added the size/m label Oct 3, 2026
@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling labels Oct 3, 2026
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 9 documentable anchor(s).

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

  • content/docs/api/client-sdk.mdx (via packages.uninstall (sdk, the route ledger binds it to DELETE /packages/:id))
  • content/docs/api/environment-routing.mdx (via /packages/:id (route, a path literal in reason))
  • content/docs/api/metadata-api.mdx (via /packages/:id (route, a path literal in reason))
  • content/docs/data-modeling/formulas.mdx (via /packages/:id (route, a path literal in reason))
  • content/docs/deployment/publish-and-preview.mdx (via /packages/:id (route, a path literal in reason))
  • content/docs/kernel/contracts/metadata-service.mdx (via /packages/:id (route, a path literal in reason))
  • content/docs/permissions/authentication.mdx (via deviceAuthorization (symbol, a field of const object PUBLIC_AUTH_FEATURES), phoneNumber (symbol, a field of const object PUBLIC_AUTH_FEATURES))
  • content/docs/permissions/permission-sets.mdx (via /packages/:id (route, a path literal in reason))
  • content/docs/permissions/sso.mdx (via deviceAuthorization (symbol, a field of const object PUBLIC_AUTH_FEATURES))
  • content/docs/permissions/system-context.mdx (via /packages/:id (route, a path literal in reason))
  • content/docs/protocol/kernel/error-handling.mdx (via /packages/:id (route, a path literal in reason))
  • content/docs/protocol/objectui/actions.mdx (via phoneNumber (symbol, a field of const object PUBLIC_AUTH_FEATURES))

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

  • content/docs/releases/v15.mdx (via phoneNumber (symbol, a field of const object PUBLIC_AUTH_FEATURES), /packages/:id (route, a path literal in reason))
  • content/docs/releases/v17/17-0.mdx (via /packages/:id (route, a path literal in reason))
  • content/docs/releases/v17/17-2.mdx (via datasources.external.import (sdk, the route ledger binds it to POST /api/v1/datasources/:name/external/tables/:remote/import, selected by route anchor /tables/:remote/import), /tables/:remote/import (route, a path literal in reason))
  • content/docs/releases/v17/17-4.mdx (via /packages/:id (route, a path literal in reason))
  • content/docs/releases/v17/17-5.mdx (via packages.get (sdk, the route ledger binds it to GET /packages/:id))

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 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 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; 97 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.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 138 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 0fc80878f859d434b1d4cf52cc91d486b2b4ada6 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 2222890b5baabfc72e66382a9a317cda2f939eb1 — the merge of head 151a8ce4ed95321fd74fb3ff9b57ad892b0b1e80 into base 0fc80878f859d434b1d4cf52cc91d486b2b4ada6, 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 2222890b5baabfc72e66382a9a317cda2f939eb1 && git checkout 2222890b5baabfc72e66382a9a317cda2f939eb1
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 0fc80878f859d434b1d4cf52cc91d486b2b4ada6 151a8ce4ed95321fd74fb3ff9b57ad892b0b1e80 && git checkout -B drift-repro 0fc80878f859d434b1d4cf52cc91d486b2b4ada6 && git merge --no-ff 151a8ce4ed95321fd74fb3ff9b57ad892b0b1e80

node scripts/docs-audit/affected-docs.mjs --json 0fc80878f859d434b1d4cf52cc91d486b2b4ada6

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

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 size/m tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants