Repository navigation
docs(spec): re-anchor the last six dead tracker citations in packages/spec/src to the commits that decided them - #21642
Conversation
…/spec/src to the commits that decided them Six comment sites cited tracker numbers that answer 404 (#9040, #17590, #12380, #6276 twice, #9972). Each now cites, in ruling C+D form C, the commit on main that decided the rule, the same anchor earlier stages already landed for that number in sibling files: 2420641, e04a0af, 4045b95, 78f0be8 and 60e0f90. The live sibling numbers in each slash-joined group stay. Comment text only. Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ Co-authored-by: Claude <noreply@anthropic.com>
…venance comments Three of the four edited files ship verbatim through the package's `src/**/*.zod.ts` files entry, and four of the six comments reach the built dist bundles or declarations, so the change publishes text. Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): ⛔ 3 release-owned page(s) name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 138 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 d87dcbd25a12951e82ba3fc6046aa759aeded25b && git checkout d87dcbd25a12951e82ba3fc6046aa759aeded25b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 36e4647520b1e292c75cc4ded2c7a3bcb916ba91 dbacec5f91e9de02df5b513a9b8a1b38ad12f905 && git checkout -B drift-repro 36e4647520b1e292c75cc4ded2c7a3bcb916ba91 && git merge --no-ff dbacec5f91e9de02df5b513a9b8a1b38ad12f905
node scripts/docs-audit/affected-docs.mjs --json 36e4647520b1e292c75cc4ded2c7a3bcb916ba91
|
…eld — the console derives the line-position field from the child object (objectstack-ai#21589) (objectstack-ai#21632) Fixes objectstack-ai#21589 Clause-②: no (narrowing) ## What this does Retires `sortField` from the `object-master-detail-form` detail entry (`ComponentPropsMap['object-master-detail-form'].details[]`). The console reads no authored value for it. At the `.objectui-sha` pin `89cad75d5570` (and unchanged at the current pin `ab1879721595`: `MasterDetailForm.tsx` and `deriveMasterDetail.ts` are byte-identical between the two), `MasterDetailDetailConfig` has no `sortField` member (`plugin-form/src/MasterDetailForm.tsx:83`). The field the line grid stamps with each line's position is the one `deriveDetail` derives from the child object (`deriveMasterDetail.ts:540`), and it reaches the grid as `sort_field` (`:874`). The spec still declared the key, so an authored `sortField` went through `os validate` clean and was then dropped. This executes the direction triage confirmed (`5969870827`), the one recorded on objectstack-ai#21220's landing (`5937457620`) and mirrored on objectstack-ai/objectui#11396 ③: a `retiredKey()` tombstone, one ADR-0087 D2 conversion and one D3 entry, with no staged window because the writer census is zero. There is no objectui edit here: the objectui#11396 mirror follows once a published `@objectstack/spec` carries this. ## The retirement kit - **Tombstone** on the strict detail entry (`packages/spec/src/ui/component.zod.ts`). The refusal is the prescription, and the key's input type is the retired-key mark, so `tsc` refuses it too. The prescription opens with the fully qualified key: `object-master-detail-form` property `details[].sortField`. It ends with the house `os migrate meta --from 17` sentence. - **One declaration of the derived sort-field names.** `INLINE_GRID_SORT_FIELDS` (the same six names in the same order as the renderer's `SORT_FIELD_NAMES`) moves out of `data/inline-grid-columns.ts` into `data/inline-grid-sort-fields.ts`, a module reached only by relative import, like `ui/action-target-aliases.ts`. Exported from `inline-grid-columns.ts`, it would have reached the published API through the `data` barrel. `inline-grid-columns.ts` imports it, and the tombstone's prescription and `record:line_items`' answer print the list from it (`INLINE_GRID_SORT_FIELD_LIST`). `check:api-surface` is unchanged, as expected. - **D2 conversion `object-master-detail-form-detail-sort-field-removed`** (step 18, `retiredFromLoadPath`, `retiredAfter: '17.6.0'`, order 60). It is a lossless delete of `sortField` from each `properties.details[]` entry of an `object-master-detail-form`, scoped by component type and by position. Its fixture covers region, nested-card and slotted positions, an open-namespace control with the same shape, and an entry that is not an object. - **`RETIRED_KEYS_BY_MAJOR[18]`** registers the nested key `ui/ObjectMasterDetailFormProps:details.sortField` (an array member, spelled without its `[]`). It has no `authorable-surface/` line, so checks (b2) and (b3) resolve it against the emitted schema, and `check:authorable-surface` is green on it. - **D3 entry `object-master-detail-form-detail-sort-field-retired`**, plus a `STEP18_RATIONALE` fragment at order 70. - **Texts that became false, changed in this PR:** - the entry docblock: "exactly the twelve keys" becomes eleven plus the tombstone, re-read at the pin, and "the three it adds … and `sortField`" now says the line-position field is derived; - `record:line_items`' guidance for `sortField`, which used to say the key "belongs to an `object-master-detail-form` detail entry" and now says no block takes it; - the generated reference page row (`content/docs/references/ui/component.mdx`); - the carriers test's every-key control (`FULL_DETAIL_ENTRY`, now 11 keys); - two landed step-18 D3 entries. `ui-object-master-detail-form-details-closed` listed `sortField?` among the keys to write, and `ui-record-line-items-props-closed` sent `sortField` to the detail entry. Both entries shipped in 17.6.0's `registry.ts`. Step 18 is still open, so the 17 → 18 upgrade guide will be generated from these texts. Reviewer, please confirm that this correction belongs in this PR. - **Changeset** `@objectstack/spec` `minor`, with a BREAKING banner, the FROM → TO table and the ADR-0087 `registered` disposition. ## Premise checks (measured on origin/main 9a4182a, objectui at the pin 89cad75d5570) - Locations: the key was at `component.zod.ts:5566`, the docblock at `:5539` and the `record:line_items` guidance at `:2201`–`:2202`, as the claim said. - Renderer: `MasterDetailForm.tsx:83` says "⛔ No `sortField` member". The only `sortField` on that path is the derived one (`:372`, `:874`, `:1066`, `:1081`; `deriveMasterDetail.ts:55` and `:540`). A fully configured entry (FK plus every column typed) loads no child schema (`:977`–`:979`), so it stamps no line position. The prescription says this. - Writer census, `git grep -n -w sortField` over `examples apps packages skills content/docs`, excluding `packages/spec/**` and CHANGELOGs: 1 hit, the generated reference page. Same instrument, control `addLabel`: 6 hits, including the showcase project workspace's detail entry. At the objectui pin, the only detail entries that write the key are probes asserting that nothing reads it (`masterDetailDetailsMembers-8071.test.tsx` rows 2c and `:295`/`:304`). No objectui source assigns it through a spec type. - Landing site: `packages/spec` is the producer of the declared key. No other package was involved. ## Evidence All on the final head `f765e8caaf` unless noted. The branch merged `origin/main` three times: at `e367002e11` (which carries the sibling element:text landing `36ad3210d4`), at `5b5e83f446` (which carries objectstack-ai#21622's landing `3f1bc816a2`), and at `15fe567c9c` (which carries objectstack-ai#21625's pin bump `1cbe165bfc` and objectstack-ai#21642's `15fe567c9c`). Readings marked `69f42d393d` predate the second merge. - `@objectstack/spec` local project at `f765e8caaf`: 609 files and 18059 tests passed (1 todo), with no skip. - `@objectstack/spec` repo project at `f765e8caaf`: the three merge-shape and retirement files (`step18-rationale-merge`, `conversions-major18-merge` and `master-detail-detail-sort-field-retirement`) passed 41 tests. The wider repo-project run is a `69f42d393d` reading: 52 of 53 files passed. NOT MEASURED: `scripts/build-schemas-check-mode.test.ts`, which alone exceeds the 590 s foreground cap. `check:authorable-surface`, the gate whose mode it tests, is green at `f765e8caaf`. - `pnpm --filter @objectstack/spec typecheck`: exit 0, including `check:test-typecheck`. The new pin's `@ts-expect-error` is compiled there, so an unused directive would be red. - Consumer packages that author an `object-master-detail-form` `details[]` entry: - `@objectstack/lint` at `f765e8caaf`: `validate-component-props.test.ts` passed 51 tests (including the new advisory pin). At `69f42d393d`, all 119 files and 5621 tests passed, and its typecheck passed; - `@objectstack/example-showcase` at `69f42d393d`: its typecheck passed, and 32 files and 399 tests passed. - `pnpm --filter @objectstack/spec check:generated`: all 15 artifacts are up to date. - Gates: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 114 commands at `f765e8caaf` (the same set as at `a1b0552acd`), and all 114 exited 0 on the first attempt after a full build. `--ran` reconciled them as 114 derived, 114 run, 0 NOT-MEASURED, 0 UNRUN. At `a1b0552acd`, the round report that first quoted the same reading had stale provenance; the seat's note `5974199078` on the card corrects it. - ESLint, as a proven narrowing rather than the repo-wide `pnpm lint`: - Population: `eslint.config.mjs` lints `**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}` minus `NEVER_LINTED`. - `--no-inline-config --format json` over the 12 changed lintable files at the final head `f765e8caaf` reported 12 files, 0 errors and 0 warnings (no ignored-file warnings, so all 12 are in the population). An earlier run, before the two D3 entry text edits, read 10 files with the same result. - Invariance: the config never enables type-aware linting (no `parserOptions.project` and no `projectService`), and the diff touches neither the config nor its baselines, so no verdict on an untouched file can move. - Ablations: one-shot runs through `scripts/ablation-replace.mjs`, wrapped in a trap. Each restore is proven by blob == HEAD and an empty `git diff HEAD`. - The tombstone reverted to `z.string().optional()`: 5 of the pin's tombstone rows went red (refusal, list, props-lint row, tombstone-not-strict-arm, tsc channel), and 15 stayed green. - `sortField: 'position'` planted on the showcase workspace's detail entry: the tree-scoped absence walk went red, naming `examples/app-showcase/src/ui/pages/project-workspace.page.ts authors sortField: 'position'`. ## New pins - `packages/spec/src/ui/master-detail-detail-sort-field-retirement.test.ts`, in the repo project because it walks the tree. It covers: - the tombstone: issue `code` `invalid_type`, path `details.0.sortField`, the prescription, and the derived names drawn from the one declaration; - that the props-lint row is the same schema; - the tombstone against the strict-arm control; - the walked shape keeping the key; - the tsc channel; - that the page parse never refuses; - `record:line_items`' answer; - the D2 strip: stored row, built artifact in every position, by-reference control, type and position scoping, idempotence, retired from the load path; - the ledger row and the D3 entry; - a tree-scoped absence walk over the radius `@objectstack/spec` already declares. `check:cross-package-test-inputs` is green, and the test is listed in `vitest.repo-tests.json`. - `packages/lint/src/validate-component-props.test.ts`: a detail-entry `sortField` is a `component-props-invalid` warning at `properties.details.1.sortField`, carrying the prescription. ## Acceptance notes - The D3 entry's `replacement` spells out the six derived names literally. The generator copies entry values into `registry.ts` and keeps no imports, so it cannot read the declaration. The pin asserts that every member of `INLINE_GRID_SORT_FIELDS` appears in it. - Deployed metadata is NOT MEASURED. Stored pages are converted by the D2 strip when they are read, and the props lint reports live sources. - Merge order with this seat's siblings: the element:text variant retirement (`36ad3210d4`) landed first at conversion order 59 and rationale order 68. objectstack-ai#21622 (`3f1bc816a2`) landed next with rationale order 69. This PR takes 60 and 70. All three merges went through `scripts/pm/os-regen-merge.sh`. Each time, the os-regen driver kept this branch's copy of `component.mdx` and dropped main's rows: the variant row, then objectstack-ai#21622's `object-metric` rows, then objectstack-ai#21625's `object-grid` `keyboardNavigation` row. Each time, the page was regenerated from the merged source in its own commit (the last is `f765e8caaf`). Measured by comparing change lines, the head's delta against `main` is this PR's own delta at `a1b0552acd`, file by file; and the head's delta against `a1b0552acd` is `main`'s own delta. objectstack-ai#21625 did not touch the detail entry or its docblock. - CI at `f765e8caaf`: complete and green, 33 success and 2 skipped (`Console Pin Gate` and the opt-in packed-tarball smoke, by their own filters). `Lint & Repo Gates`, red at `a1b0552acd` only because GitHub's issues API answered HTTP 503 in `check-issue-citations`, is success on this head. --------- Co-authored-by: Claude <noreply@anthropic.com>
Part of #20234
Clause-②: no
The next stage of the dead-citation sweep under ruling C+D (record
5749154545on #19123): the six comment sites the census pointer5923089344names, claimed in5973700515. Each cited a tracker number that answers 404. Each now cites, in form C, the commit onmainthat decided the rule, and in every case that is the anchor an earlier stage of this card already landed for the same number in a sibling site. Comment text only: no string literal,.describe()text, schema, type, export or test changes.The rule applied
Form C, as triage's first grade (
5856637615) states it and stages 1 to 11 applied it: "the ADR or ruling record, else the commit sha, with a PR number allowed only beside it as a link", and "Each rewritten line says what the cited object decided … Where nothing answers, keep the sentence's reason in words and drop the citation." Stage 10's ACCEPT (5902947213) adds: "Where the number alone carried the meaning, the decision is also said in words." Live numbers stay (stage 9's ACCEPT5899135835: "its claims forbid removing a lit citation"). A slash group keeps its live numbers and takes the commit beside them, as stage 5 did for#9881/#9972incomponent.test.ts(nowthe #9881 / commit 60e0f900a records).What changes (line numbers at base
5b5e83f446)maindata/datasource.zod.ts:701#9040in#8082/#8336/#9040#8082/#8336, or the refusal of a credential in mongo's options passthrough (commit 24206416a)data/datasource-credential-redaction.ts,data/driver/common.zod.ts(stage 3)data/filter.zod.ts:1067@seeURL of#17590@see commit e04a0aff2 (the membership reading, landed with the SQL family)data/filter.zod.ts:979(stage 3)data/value-roundtrip-conformance.ts:100@seeURL of#12380@see commit 4045b954d (the measured boundary set)v_jsonparagraph (stage 3)ui/component.zod.ts:675#6276in#5611/#5775/#6276#5611 / #5775 / commit 78f0be872ui/component.zod.ts:71,:207,:682(stage 5)ui/component.zod.ts:751#6276in#5611/#5775/#6276#5611 / #5775 / commit 78f0be872ui/component.zod.ts:4555#9972in#9881/#9972#9881 / commit 60e0f900aui/component.zod.ts:2609,ui/component.test.ts:407(stage 5)The datasource line is the one site whose sentence did not say what the dead number decided, so it now says it in words, from the code: the mongo
optionspassthrough refusal is part of the config gate (credentialFreeMongoOptionsonMongoConfigSchema.options). That comment reflows from two lines to three. Every other edit is one line for one line, and each of those sentences already stated its decision in words.Evidence
The six are dead, measured with the gate's own instrument.
node scripts/check-issue-citations.mjs --census --json(read-only, board enumerated, 195 pages) at base5b5e83f446lists exactly these six plus the two literal-read sites stage 6 kept on purpose (data/api-derivation.ts:163[#6259],identity/identity.zod.ts:230#8715). Lines match the claim. No seventh dead number inpackages/spec/src. RESTissues/N, redirects not followed:#9040,#17590,#12380,#6276,#9972answer 404; the lit controls#8082,#8336,#5611,#5775,#9881,#5286,#12624answer 200.After, at head
dbacec5f91: the same census readsallocated-but-absent119 → 113 repo-wide and 8 → 2 inpackages/spec/src. Gone: exactly the six. New: none.Each anchor is on
mainand names its number. RESTcompare/SHA...5b5e83f446answersahead,behind_by: 0for all five shas (controls:5b5e83f446~1answersahead,behind_by: 0; the off-main branch commit25fb56f1b7answersdiverged,behind_by: 3). The localmerge-base --is-ancestorexits 1 for all five on this shallow checkout, which is the shallow false negative, so the REST reading is the one cited. Each commit's own text names the number it replaces:24206416a(subject: refuse a credential in the mongo options passthrough at publish,#9040);e04a0aff2(its body names#17590as the card it delivers, and its diff wrote the very@seeline rewritten here);4045b954d("Part of #12380", with the live 17-value measurement across three dialects);78f0be872(subject names#6276);60e0f900a(subject names#9972).Comment-only, proved two ways.
.describe()string edit, a template-literal edit and a regex-literal edit each report DIFFERS; a line-comment edit, a JSDoc edit and an@see-line edit each report IDENTICAL.Generated artifacts. After a spec build,
check:generatedreports 15 of 15 up to date. No reference page renders any of the six comments (content/docs/references/holds neither the old nor the new text). Nothing was regenerated.Changeset:
@objectstack/specpatch. Measured after the build:datasource.zod.ts,filter.zod.tsandcomponent.zod.tsship verbatim through the package'sfilesentrysrc/**/*.zod.ts; indist, the threecomponent.zod.tscomments are in 14.js/.mjsbundles and thevalue-roundtrip-conformance.ts@seeis indist/data/index.d.tsand.d.mts. The datasource and filter comments reach nodistfile. Positive control: themaxVisible.describe()text is in 14distfiles. So the change publishes text, andskip-changesetdoes not apply.Tests and gates, at head
dbacec5f91.pnpm --filter @objectstack/spec build: exit 0. Speclocalvitest: 609 files, 18,057 passed, 1 todo.pnpm --filter @objectstack/spec typecheck: exit 0.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 79 families;--ranreconciles 78 run, all exit 0, and 1 NOT MEASURED, 0 unrun.check:dual-build-cjs-loads, reason: it refuses (exit 3) until every publishable package is built, and a full monorepo build was not run locally. Narrowed and declared: the diff is comment-only inpackages/spec, and of the gate's 106requireentries (its own--list), spec's 19 all load at head. CI runs the full gate.@objectstack/lintcheck:doc-formula-expressions,check:lean-entry-closure). After buildingformula,lintandobjectql(14 of 14 turbo tasks), both exit 0.Overlap. Open PR #21632 and PR #21625 touch
ui/component.zod.tsin other regions. Neither had landed atorigin/main36e4647520, re-fetched before this PR opened, so no merge was taken. Amerge-treeof this head onto that tip exits 0, and none of the five changed paths is routed to the regeneration merge driver, so the local answer is GitHub's.Acceptance notes
docs/audits/2026-07-unknown-key-strictness-ledger.md:676still names the#5611/#5775/#6276rule. It is outside this stage's file surface and outside the census surface. Carrier: none.#17590the commit rung was taken, althoughe04a0aff2's message names a director-seat ruling record. That matches stage 3's anchor for the same number atfilter.zod.ts:979, reviewed PASS.docs/adr/,.claude/,skills/,AGENTS.mdorCLAUDE.md. 29 changed lines.Generated by Claude Code