Skip to content

Commit 2123fcc

Browse files
docs(spec): re-anchor the dead tracker citations in ui/ and two freed sites to the commits that decided them (stage 5) (#20576)
Part of #20234 Clause-②: no ## What changed This is stage 5 of the staged sweep: the `ui/` area (`packages/spec/src/ui/**`, 133 files), plus two sites freed since stage 4: `data/filter-subtree-provenance.ts` (PR #20460 landed without touching it) and `meta-spelling/manifest-collection-spelling.ts` (the census hand-over, comment 5882628946 on #20234). `ui/view-grouping-query.ts` is excluded because #20446's claim holds it; it carries 4 citations and none of them is dead, so the exclusion removes nothing. Later stages cover the other areas, so this PR says `Part of`. Every comment and docblock site in that population that cites a tracker number answering 404 has been rewritten in ruling C+D's form C (comment 5749154545 on #19123). That is **87 comment sites**: 84 re-anchored and 3 respelled. - **84 re-anchored, over 25 numbers.** Each rewritten line now cites the commit in `origin/main` history that decided what the line describes, and says in its own words what that commit decided. One line (`ui/dashboard.zod.ts:686`) quotes ADR-0087 itself; it keeps ADR-0087 as its citation and paraphrases the amendment heading instead of quoting its number. - **3 respelled**, so each number of a sibling pair carries its own qualifier: `ui/view.zod.ts:3634` now reads `objectui#6110 + objectui#6111`, and `ui/component.zod.ts:3479` and `:4140` now read `objectui#8221's PR objectui#8758`. Each second number answers 404 here, and the sentence attributes it to objectui (objectui REST: `issues/6111` 200, `pulls/8758` 200, merged 2026-09-09). Only comments changed, plus the one generated reference page they project into and a patch changeset. Every source file keeps its line count (90 lines out, 90 in, over 25 files). Three of the 90 lines held no dead number; each is the other half of a rewritten sentence: `ui/action.zod.ts:400`, `ui/action-param-carryover.test.ts:13` and `ui/expression-bindable-text-keys.test.ts:119`. No code token moves (see the guard below). **No tracker number is added.** Every tracker number on an added line was already on the lines it replaces, and no `PR #N` is added. ## Census: before and after **Instrument.** This is the instrument of stages 1 to 4, rebuilt for this stage. It sends REST `GET /repos/objectstack-ai/objectstack/issues/N` without following redirects, for every distinct number cited in the population. The population is: - the citation gate's own exported `CITATION_RE` and `NON_CITATION_HEADS` at the base, kept when the qualifier is none, `objectstack`, `objectstack-ai/objectstack`, `framework`, `pre-` or `post-`; - matched case-insensitively (`Pre-`, `POST-`, `Framework`); - N of 100 or more, excluding `summon` heads. A qualifier covers only the number it is joined to. Each site is classified by the TypeScript parser as a line comment, a docblock, a block comment or a string. **Controls.** The lit controls were `#16862`, `#16847` and `#17698`. The dead controls were `#16714`, `#16715` and `#16697`. They were probed at the start, after every 100 numbers and at the end: 18 of 18 lit (200) and 18 of 18 dead (404) over 6 checkpoints in the base run, and 15 of 15 and 15 of 15 over 5 checkpoints in the head run. | reading | tree | numbers probed | 200 | 404 | 301 or other | dead sites | lines | files | of which comments | of which strings | |---|---|---|---|---|---|---|---|---|---|---| | before | base `487a7846df`, probed 2026-09-29T02:57:01Z to 02:59:36Z | 400 | 372 | 28 | 0 | **111** | 110 | 26 | 90 | 21 | | after | head `83e39641d0`, probed 2026-09-29T03:15:00Z to 03:18:06Z | 383 | 372 | 11 | 0 | **24** | 23 | 8 | 3 | 21 | The head probe found no number newly dead since the base probe: the same 372 numbers answer 200. The head was probed at `83e39641d0`; every census file is byte-identical at the final head. **Cross-check under the grammar that landed during this stage.** PR #20554 (`199002b3e4`) landed the closed qualifier set while this stage ran, and it reads `objectui PR #8758` as objectui's number. Re-run with that gate's own `extractCitations` and `namesThisRepository`, the same population reads **108** dead sites before and **21** after, all 21 test strings. The difference is exactly the three `objectui PR #8758` prose sites below, which that PR's own header measured as "census deaths here that are not deaths at all". **Per file.** Cited sites are every in-repo citation the population reads, live or dead. | file | cited sites (base) | dead before | by class | dead after | |---|---|---|---|---| | `data/filter-subtree-provenance.ts` | 9 | 3 | 3 docblock | 0 | | `meta-spelling/manifest-collection-spelling.ts` | 8 | 2 | 2 line comment | 0 | | `ui/action-param-carryover.test.ts` | 5 | 3 | 2 line comment, 1 string | 1 | | `ui/action.test.ts` | 39 | 3 | 3 line comment | 0 | | `ui/action.zod.ts` | 90 | 7 | 5 docblock, 2 line comment | 0 | | `ui/bulk-action.test.ts` | 9 | 4 | 2 line comment, 2 string | 2 | | `ui/bulk-action.zod.ts` | 9 | 3 | 2 docblock, 1 line comment | 0 | | `ui/component-element-navigation-17987.test.ts` | 8 | 5 | 1 docblock, 4 string | 4 | | `ui/component-type-vocabulary.test.ts` | 8 | 2 | 2 docblock | 0 | | `ui/component-type-vocabulary.ts` | 2 | 1 | 1 docblock | 0 | | `ui/component.test.ts` | 190 | 22 | 11 line comment, 11 string | 11 | | `ui/component.zod.ts` | 265 | 20 | 16 docblock, 4 line comment | 0 | | `ui/dashboard.zod.ts` | 52 | 1 | 1 docblock | 0 | | `ui/expression-bindable-text-keys.test.ts` | 3 | 2 | 2 line comment | 0 | | `ui/expression-bindable-text-keys.zod.ts` | 4 | 2 | 2 docblock | 0 | | `ui/form-select-option.test.ts` | 3 | 1 | 1 docblock | 0 | | `ui/index.ts` | 15 | 2 | 2 line comment | 0 | | `ui/interaction-config-retirement.test.ts` | 19 | 1 | 1 docblock | 0 | | `ui/react-blocks.test.ts` | 9 | 2 | 1 docblock, 1 string | 1 | | `ui/react-blocks.ts` | 17 | 4 | 2 docblock, 2 line comment | 0 | | `ui/view-form-features-root.test.ts` | 4 | 1 | 1 line comment | 0 | | `ui/view-metadata-schema.test.ts` | 31 | 3 | 2 line comment, 1 string | 1 | | `ui/view-submit-redirect-url.test.ts` | 8 | 1 | 1 line comment | 0 | | `ui/view.test.ts` | 136 | 2 | 1 docblock, 1 string | 2 | | `ui/view.zod.ts` | 331 | 13 | 10 docblock, 3 line comment | 2 | | `ui/widget-i18n-retirement.test.ts` | 17 | 1 | 1 line comment | 0 | `ui/` alone went from 106 dead sites in 24 files to 24. The other 107 `ui/` files carry no dead site. ## Per-number table Anchors are 9-hex commit abbreviations. "Wrote" means the commit's own diff added the line being rewritten. | number | comment sites / files | anchor: what it decided | |---|---|---| | `#5970` | 4 / 2, `action.zod.ts:819`, `action.test.ts:268`, `:304`, `:354` | `97e7e3caa`: `ActionSchema.visible` / `disabled` speak one condition shape; `visible` gains its boolean arm. Stage 1's anchor for the same number | | `#6276` | 7 / 1, `component.zod.ts:34`, `:165`, `:568`, `:2455`, `:2546`, `:2554`, `component.test.ts:2126` | `78f0be872`: declares `element:record_picker`'s flat `sort` / `limit` on the #5611 rule (maintainer ruling 2026-08-08, direction A). It wrote `:34`, `:2455` and the "enumerate by the renderer's read pattern" lesson | | `#8794`, `#8836` | 3 / 1, `filter-subtree-provenance.ts:130`, `:131`, `:156` | `1850ebbb0`: corrects the reuse-safety claim from the survey and pins the invariant. It wrote `:131` itself. Stages 1 and 3 gave both numbers this anchor | | `#9933` | 7 / 2, `view.zod.ts:2517`, `:5060`, `:5086`, `:5118`, `:5513`, `view-metadata-schema.test.ts:398`, `:410` | `d5552ca13`: admits `columnState` as an explicitly runtime-only view-overlay key, rejected by name at every authoring door. It wrote "explicitly out of #9933's scope" | | `#9972` | 3 / 2 (+1 unread), `component.zod.ts:2213`, `component.test.ts:382`, `:3565`; also `:3612`'s `#9881/#9972`, a slash-joined spelling the grammar does not read | `60e0f900a`: records the live read point of `page:tabs` `items[].icon` and its accept-pin. It wrote the `:382` header | | `#10194` | 1 / 1, `manifest-collection-spelling.ts:71` (`pre-#10194`) | `2306a765c`: `/meta/theme` and `/meta/analytics_cube` stop storing any JSON as success and validate at the write door. The line now says "the store-anything branch from before commit 2306a76". Stage 1's anchor | | `#10274` | 6 / 2, `component.zod.ts:2304`, `component.test.ts:308`, `:405`, `:3591`, `:3603`, `:3612` | `d1ba685ec`: re-measures the four pin citations and gates the class. Its gate header records that the re-measure found two anchors wrong since they were written, which is why a refresh re-reads. Stage 3's anchor | | `#10485` | 4 / 4, `index.ts:51`, `interaction-config-retirement.test.ts:116`, `widget-i18n-retirement.test.ts:112`, `manifest-collection-spelling.ts:67` | `35ad101bc`: retires the `themes` carrier and `ThemeSchema` whole (ruled B, 2026-08-21; ADR-0049 stays cited). Stage 1's anchor | | `#11284` | 5 / 2, `react-blocks.ts:39`, `:94`, `:109`, `:295`, `react-blocks.test.ts:139` | `5383fa670`: the react tier converges on the metadata-tier vocabulary, deprecate-first. Its changeset heads "(#11284, maintainer ruling 2026-08-23)" | | `#11350` | 1 / 1, `index.ts:105` | `ece4dad31`: records the maintainer ruling of 2026-08-23 that a type in an entry's public declarations must be nameable from that entry. Same wording as stage 1's `kernel/index.ts:53` | | `#11507` | 2 / 2, `component.zod.ts:1465`, `component.test.ts:2726` | `88b9d749a`: declares `sys_activity.type` an open, author-extensible vocabulary (maintainer ruling 2026-08-24, direction 4). Stage 3's anchor | | `#11658` | 2 / 2, `component.zod.ts:1464`, `component.test.ts:2725` | `1a6a19c31`: opens `RecordActivityProps.types` to author-contributed kinds, executing that ruling. Stage 3's anchor | | `#11703` | 3 / 2, `action.zod.ts:399` to `:400`, `:460`, `action-param-carryover.test.ts:12` to `:13` | `5cb62d88b`: `clone_permission_set` carries all five copied facets; its params list had silently dropped three. The lines now name "the silent-drop shape commit 5cb62d8 fixed" | | `#11753` | 5 / 2, `action.zod.ts:66`, `:390`, `:398`, `:409`, `action-param-carryover.test.ts:1` | `0e4e51b0a`: `ActionParamSchema.carryOver`, the spec half of the 2026-08-25 maintainer ruling (recommendation A). It wrote every one of these lines, and its changeset records the `visible: false` measurement `:398` names | | `#12194` | 1 / 1, `view.zod.ts:4838` | `311433f6b`: declares the metadata item-name grammar (`QUALIFIED_ITEM_NAME_PATTERN` among it) and refuses it at the publish door. Stage 2's anchor | | `#12868` | 5 / 2, `view.zod.ts:2938`, `:2966`, `:3179`, `:7087`, `form-select-option.test.ts:4` | `c459da6bc`: narrows the per-option `default` key out of the form-view options vocabulary. Its changeset records the ruled census `:2966` cites ("measured ZERO occurrences"). Stages 3 and 4's anchor | | `#12950` | 3 / 2, `component-type-vocabulary.ts:4`, `component-type-vocabulary.test.ts:4`, `:101` | `225e7690f`: created `component-type-vocabulary.ts`; its message records the readiness read `:101` pins (`global:search` and `global:notifications` stay declared) | | `#13156` | 2 / 2, `view-form-features-root.test.ts:70`, `view-submit-redirect-url.test.ts:110` | `fd289be45`: strips tracker ids from function-declaration-built refusal prose. It wrote both lines. Stage 3's wording ("commit fd289be's strip") | | `#13670` | 1 / 1, `expression-bindable-text-keys.zod.ts:72` | `8c6a7fc0b`: records `text.value` as deliberately omitted; its message states the ruling that `text`'s evaluation channel is `content` alone | | `#13672` | 3 / 2, `expression-bindable-text-keys.zod.ts:89`, `.test.ts:65`, `:118` | `e854a531a`: narrows the `button` row to the spelling its key reaches, and records `action:button` and `ui:button` as deliberately out | | `#16626` | 1 / 1, `component.test.ts:2336` | `30b099078`: the objectui pin bump to `53ded82bf7a4` that ships objectui#7754's array-analytics lowering, the door the family waited on. The association is PR #16788's body (it names #16626 as the card it lands), and `30b099078` is that PR's merge commit; neither its message nor its diff names #16626 (the stage-3 #11065 precedent) | | `#17987` | 9 / 2, `component.zod.ts:10`, `:4014`, `:4062`, `:4153`, `:4193`, `:5068`, `:5226`, `:5457`, `component-element-navigation-17987.test.ts:4` | `e233db9db`: declares element-level `navigation` on `object-kanban` / `object-calendar` and gives `object-timeline` its `ComponentPropsMap` row, executing the objectui#8652 ruling (verbatim `B`) | | `#18003` | 1 / 1, `dashboard.zod.ts:686` | **ADR-0087**, the rung above a commit. The line quoted the ADR's own amendment heading, number included. It now reads "(ADR-0087, its 2026-09-13 amendment, 「the level half」)": the ADR stays the citation and the fragment it quotes is verbatim | | `#18177` | 5 / 2, `bulk-action.zod.ts:51`, `:169`, `:262`, `bulk-action.test.ts:61`, `:307` | `adabccf5f`: `BulkActionParamSchema` is strict and declares `dependsOn`, executing decision batch #146 item 4, letter A | | `#6111` | 1 / 1, `view.zod.ts:3634` | respelled `objectui#6111` (not re-anchored): it is objectui's number | | `#8758` | 2 / 1, `component.zod.ts:3479`, `:4140` | respelled `PR objectui#8758` (not re-anchored): objectui's PR #8758, merged 2026-09-09 | No ADR or ruling-record file in `docs/adr/` or `scripts/adr-anchors/` records the decision behind any of the 25 re-anchored numbers except #18003. ADR-0126 mentions #11703 and #11753 only as references ("permission-set precedent"), not as the record of either decision. **Anchor checks.** Every sha on an added line is one of 23, and none is on a removed line. At the base `487a7846df`: - each matches exactly one object (`git rev-parse --disambiguate`, count 1, 23 of 23); - each is an ancestor (`git merge-base --is-ancestor`, exit 0, 23 of 23); the control leg `e9584681a4` also exits 0, and the repository is not shallow; - for 22 of the 23, a grep of the commit's own message or diff finds the number it replaces (the message for 16; the diff for `0e4e51b0a`, `5383fa670`, `c459da6bc`, `225e7690f`, `e854a531a`, and for #8836 in `1850ebbb0`). `30b099078` is the exception explained in the table. - Each commit was read for the rule its line states, not only for the number. In most cases the commit wrote the very line it now anchors. Wordings to check, each true of its commit: - `filter-subtree-provenance.ts:130` and `:156` read 「survey commit 1850ebb records」: the survey was the card's, and the commit's message records its measurement. It is stage 3's wording for the same relation (「from the survey it records」). - `component.zod.ts:1465` and `component.test.ts:2726` read 「maintainer ruling commit 88b9d74 declared」: that commit landed the ruling (direction 4) as the `sys_activity.type` declaration. - `manifest-collection-spelling.ts:71` reads 「the store-anything branch from before commit 2306a76」: before that commit, `PUT /meta/theme/:name` stored any JSON as success. ## Mechanical guard: no code token moves The check compares leaf tokens with comments stripped, base `487a7846df` against the head. It uses the TypeScript parser's leaf tokens from the head's lockfile, so template literals are scanned in context, and it excludes JSDoc nodes. It ran over all 25 touched `.ts` files, and every control mutates the head text in memory only. - Real run: 101,836 base tokens, **0 files with a token change** (exit 0). - Comment-insertion control (`ui/index.ts`): 0 files changed (exit 0). - Positive control (a declaration inserted into `ui/view.zod.ts`): 1 file reads DIFFER at token 19222 (exit 1). - Positive control (one digit changed in a `component.test.ts` test title): 1 file reads DIFFER at token 14972 (exit 1). Line balance holds in every file, 90 out and 90 in over the 25, and every line count is equal at base and head. Tracker numbers: added-not-removed is empty in every file. The net-removed numbers are the 25 in the table, 85 sites: the census's 84 comment sites, plus the slash-joined `#9972` at `component.test.ts:3612`. ## Generated page `check:generated` proved one artifact stale: `content/docs/references/ui/expression-bindable-text-keys.mdx`, the projection of `expression-bindable-text-keys.zod.ts`'s module docblock. `check:generated --fix` regenerated only that page, and a re-run read `All 15 generated artifacts are up to date`. Its two changed lines are the `:72` and `:89` substitutions verbatim. No other docblock here projects into a reference page, and nothing under `skills/**` moved. ## Changeset This change ships bytes, so a `patch` changeset for `@objectstack/spec` is included. It says only that the provenance comments were re-anchored. `Clause-②: no`: no export, key, value or type moves (the guard above). Measured on the head's built package: 6 touched sources are `src/**/*.zod.ts`, which `files[]` ships verbatim. The rewritten comments also reach `dist`: - `c459da6bc` appears in 32 bundled `.js` files and 2 `.d.ts`; - `adabccf5f` in 24 `.js` and 2 `.d.ts`; `d5552ca13` and `0e4e51b0a` in 24 `.js` each; `e233db9db` and `78f0be872` in 2 `.js` and 2 `.d.ts` each; - the positive control, the pre-existing sentence 「the object-field face enforces」, appears in 32 files. ## Gates (head `1b885d3c27`) - **Citation judging pass, run as CI runs it:** `pnpm check:issue-citations && node scripts/check-issue-citations.mjs`, both under the grammar PR #20554 landed, exit 0. The self-test passes 114 cases in 8 batteries. The live, diff-scoped run judged 13 citations across 11 files: 3 resolve and 10 are declared cross-repo references. It reads "every citation this change adds resolves". - **Doc authoring:** `pnpm check:doc-authoring` exits 0. Its 16,759 customer-facing strings across 1,174 spec sources carry no internal issue id, and the sibling-package prose-id baseline holds with no growth. - **Derived gates:** `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` at this head derived 112 families, and all 112 exit 0. `--ran` reports 112 run, 0 NOT MEASURED, 0 unrun. A full `turbo run build` of `./packages/*` at this head ran first, under the shared verify lock: 71 of 71 tasks, VERDICT command-exit 0. So no gate met an unbuilt prerequisite. - **Five roster gates the derivation flags for this diff** (their rosters sit in `.changeset/` or `packages/`, so their silence proves nothing): `node scripts/check-changeset-fixed.mjs`, `pnpm --filter @objectstack/spec run check:spec-changes`, `pnpm check:authz-resolver`, `pnpm check:error-code-casing` and `pnpm check:filter-alias-parity`. All exit 0. - `pnpm --filter @objectstack/spec run check:generated` (derived) reads `All 15 generated artifacts are up to date`, and `check:docs` reads `226 generated files in sync`. - **Tests and typecheck, under the lock:** - `pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/ui src/meta-spelling`: Test Files 98 passed (98), Tests 3452 passed (3452), VERDICT command-exit 0 (the chain held the lock 142s on a shared box). - The 16 spec suites outside `src/ui` that read the touched files' source text or pin their lines: Test Files 16 passed (16), Tests 489 passed (489). They are `scripts/{export-origins,file-description,root-index,schema-closure,skill-map-guards,strictness-ledger}.test.ts`, `src/ai/tool-confirmation-prescription-tense.pin.test.ts`, `src/api/api-entry-graph.pin.test.ts`, `src/contracts/scoped-context.test.ts`, `src/data/filter-subtree-provenance.test.ts`, `src/shared/{alias-integrity,evaluated-slot-population,retired-key-migrate-sentence,union-author-message-pins}.test.ts`, `src/system/constants/platform-object-names.test.ts` and `src/type-alias-convention.pin.test.ts`. Three more suites matched the reader scan and are not run here: `scripts/build-schemas-check-mode.test.ts` only imports `ViewItemSchema` (code the guard proves unchanged) and rebuilds schemas in a temp tree; `scripts/def-key-collisions.test.ts` names `ui/view.zod.ts` only in a comment; `scripts/published-projection-choke-point.test.ts` matched on `build-react-blocks-contract.ts`, not a touched file. They are left to CI. - `pnpm --filter @objectstack/spec typecheck`: exit 0, including `check:test-typecheck` (53 files, 251 errors, 138 pinned signatures held). The same three runs also passed, with the same counts, on the pre-merge tree. - **Lint, as a proven narrowing:** `eslint --no-inline-config --format json` over the 25 touched `.ts` files gives 25 files, 0 errors and 0 warnings. All 25 are in eslint's own population (`isPathIgnored` is false for each, read through eslint's API). `eslint.config.mjs` never enables type-aware linting (no `parserOptions.project`, which its own lines 327 to 328 state), so a comment edit here cannot move the verdict on any untouched file. The repo-wide `pnpm lint` is CI's run. - **Merge probe:** a `merge-tree` of the head onto `origin/main` `f572a7eb3c`, from a bare shared clone with no merge driver registered, exits 0 (2026-09-29T04:15Z). ## Acceptance notes - **Base and merge.** The branch forked from `487a7846df`, one commit past the claim's stamp `6154165484` (PR #20551, outside the surface). `origin/main` then moved three commits, and `199002b3e4` (PR #20554) changed `scripts/check-issue-citations.mjs`, so the gate derivation read STALE TREE. `origin/main` `dee9b26f6c` was merged in (`1b885d3c27`): a clean merge with no driver-routed path and no lockfile change, touching none of this diff's files. The PR's delta against `dee9b26f6c` is exactly its 27 files. `origin/main` has since moved one more commit, `1c761c0d71` (PR #20565, tests in two other packages), which touches none of them. - **One site beyond the hand-over's list.** The hand-over named `manifest-collection-spelling.ts:71` (`pre-#10194`). The same comment's first line, `:67`, cites `#10485`, which also answers 404, and it is rewritten too. The claim names this file; the fix is the same defect class, mechanical in the form stages 1 to 4 fixed, in a file no other claim holds, under the same gates. Reverting it would be one line. - **Open PRs, re-read at 2026-09-29T04:22Z:** 8 open PRs, and none touches any file in this diff. The one that touches `ui/` is #20570 (#20446's), on the excluded `view-grouping-query.ts`. The in-flight `Claim:` comments on the 12 `pm:dispatched` cards were read too: only #20446's names a `ui/` file (`view-grouping-query.ts`, excluded above). - **Hypothesis 2, measured.** In `ui/`, 14 sibling-qualified pairs leave the second number bare: 13 on one line (`+`, `and`, `,`, `/` or `'s PR` between them) and `component.zod.ts:3478` to `:3479`, split across a line break. In 3 of them the second number answers 404 here and the sentence attributes it to objectui (`#6111` once, `#8758` twice); they are respelled above. In the other 11 the second number answers 200 here, so it is judged as this repository's and left: `action.zod.ts:1603`, `component.test.ts:2052`, `:2199`, `:2315`, `component.zod.ts:3276`, `:3793`, `:4812`, `expression-bindable-text-keys.zod.ts:33`, `page.test.ts:696`, `react-blocks.ts:256` and `widget.zod.ts:34`. The PR #20554 header measured `,` and `and` pairs as naming this repository's number and `/` pairs as mostly, but not always, the qualifier's. Whether any `/` pair here names objectui's number is not measured; a 200 here cannot tell. - **What stays in this population: 24 dead sites** (21 under the landed grammar). - **21 test strings**, left as tokens (vitest `it` / `describe` titles in 7 test files): `#6276` ×6, `#11658` ×3 and `#11507` ×1 in `component.test.ts`; `#9972` in `component.test.ts:411`; `#17987` ×4 in `component-element-navigation-17987.test.ts`; `#18177` ×2 in `bulk-action.test.ts`; `#9933` in `view-metadata-schema.test.ts:406`; `#11284` in `react-blocks.test.ts:147`; `#11753` in `action-param-carryover.test.ts:17`; `objectstack#11195` in `view.test.ts:3396`. None is a Zod `.describe()` text, an exported string or a migration-entry field, so no form D site arises here. - **3 comments that name objectui's live PR #8758 in prose** (`objectui PR #8758`): `view.zod.ts:2354`, `:2579` and `view.test.ts:426`. They are not pairs, and the landed grammar reads them as objectui's. - **Left for later stages of #20234** (the stage-4 landing comment 5882686893's list, unchanged): the migrations area, the `liveness/**` notes, the `why` strings and the `PROVENANCE_WAIVERS` reason, `rest-server.zod.ts`, the held `analytics*` and `driver/turso.*` files, the 2 `AGGREGATION_CASES` note strings, and `data/`'s test strings and deliberate markers. - **The same rot outside `packages/spec/src`** is #20556's, not this card's. Examples met here: ADR-0087's own amendment heading (`docs/adr/0087-metadata-protocol-upgrade-contract.md:390`, `:397`) cites the dead `#18003`, and ADR-0126 cites `#11703` and `#11753`; both are governed. `packages/spec/scripts/strictness-ledger.test.ts:375`, `:380` cite `#9933`, and `check-objectui-pin-citations.ts` cites `#10274` and `#9972`. - **Unchanged wording.** `react-blocks.test.ts:140` says the 2026-08-23 ruling was "recorded on-card". The card is gone, and the changeset of `5383fa670` (now cited on `:139`) records the ruling. The line holds no number, so it is left. - **The citation gate's reach.** It defers `packages/**/*.test.ts`. The 11 touched non-test files are in its judging population. --- _Generated by [Claude Code](https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 24d521e commit 2123fcc

27 files changed

Lines changed: 106 additions & 92 deletions
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
Provenance comments in `ui/` were re-anchored
6+
7+
Comment and docblock lines under `src/ui/`, and in
8+
`src/data/filter-subtree-provenance.ts` and
9+
`src/meta-spelling/manifest-collection-spelling.ts`, that cited tracker numbers
10+
which no longer resolve on GitHub now cite the commit in this repository's
11+
history that decided the matter, or the ADR amendment they quote, and say in
12+
their own words what was decided. Two references to objectui numbers now name
13+
objectui on each number. Comments only: no type, schema, export or runtime
14+
behaviour changes.

‎content/docs/references/ui/expression-bindable-text-keys.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ above, its omission is not merely unmeasured: `value` there is a fallback
7474
spelling for the same slot `content` already evaluates (see `content` NOT a
7575
member, above), not a second read point, so a `text: ['value']` row would
7676
legitimize the fallback spelling and give one slot two declared evaluation
77-
paths. The objectstack#13670 ruling settled `text`'s intended evaluation
77+
paths. The ruling that commit 8c6a7fc0b records settled `text`'s intended evaluation
7878
channel as `content` alone and declared `text.value` OUT on those grounds —
7979
this omission is deliberate, not pending measurement. Adding a row is
8080
additive and spec-first; do it here, never as a renderer-side inference.
@@ -91,7 +91,7 @@ rule would in the same motion grant rows to `element:button` and
9191
`properties` bag and never read these keys at the node's top level.
9292

9393
`action:button` is therefore deliberately OUT, and `ui:button` with it
94-
(objectstack#13672); the `button` row above covers the bare `button`
94+
(commit e854a531a); the `button` row above covers the bare `button`
9595
spelling alone, which is why its citation names `form/button.tsx` only. Two
9696
measured grounds, the same two kinds every other row runs on — zero pull
9797
(the objectui corpus census of 736 JSON documents / 2747 typed nodes finds 5

‎packages/spec/src/data/filter-subtree-provenance.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ export const FILTER_SUBTREE_PROVENANCE: symbol = Symbol.for(
127127
* This paragraph used to end by calling the mark *"safe on filter objects that
128128
* are reused across requests (view metadata, cached scopes): the
129129
* classification of one subtree does not change between requests"*. The
130-
* #8794 survey measured that claim and it is true in ONE direction only; the
131-
* correction is pinned by `filter-subtree-provenance.test.ts` (#8836). The
130+
* survey commit 1850ebbb0 records measured that claim and it is true in ONE direction only; the
131+
* correction is pinned by `filter-subtree-provenance.test.ts` (same commit). The
132132
* claim holds where provenance is **intrinsic** to the subtree, and a caller's
133133
* `where` is the half where it is not:
134134
*
@@ -153,7 +153,7 @@ export const FILTER_SUBTREE_PROVENANCE: symbol = Symbol.for(
153153
* > that vouched it.
154154
*
155155
* It holds across every in-repo caller today — enumerated with controls in
156-
* #8794 — and it holds *incidentally*: every caller in a markable position
156+
* the survey commit 1850ebbb0 records — and it holds *incidentally*: every caller in a markable position
157157
* (`options.where` itself, or an arm of a pure `$and` root) happens to build
158158
* its filter fresh per request. This module does not and cannot enforce it,
159159
* because "the request" is not a concept it can see. What is enforced is that

‎packages/spec/src/meta-spelling/manifest-collection-spelling.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,11 @@ export const PLURAL_TO_SINGULAR: Record<string, string> = {
6464
reports: 'report',
6565
datasets: 'dataset',
6666
actions: 'action',
67-
// `themes: 'theme'` was removed at #10485 (ADR-0049; the carrier key is
67+
// `themes: 'theme'` was removed by commit 35ad101bc (ADR-0049; the carrier key is
6868
// retired). Its absence here is load-bearing twice over: the generated
6969
// `META_URL_TO_SINGULAR` (gen:meta-url-spelling) loses the fold, so
7070
// `/meta/theme` gets `unrecognisedMetaTypeRefusal`'s loud verdict instead of
71-
// the pre-#10194 store-anything branch; and `applyConversionsToStoredItem`
71+
// the store-anything branch from before commit 2306a765c; and `applyConversionsToStoredItem`
7272
// passes legacy `theme` rows through untouched rather than manufacturing a
7373
// collection for them.
7474
flows: 'flow',

‎packages/spec/src/ui/action-param-carryover.test.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// #11992 — `ActionParamSchema.carryOver`, the #11753 ruling's spec half
1+
// #11992 — `ActionParamSchema.carryOver` (commit 0e4e51b0a), the carry-over ruling's spec half
22
// (maintainer 2026-08-25, recommendation A): a declared carry-over param is
33
// seeded from the row, rendered as a NON-EDITABLE summary, and submitted
44
// VERBATIM. These pins hold the ruled shape: the accept set (key + parsed
@@ -9,8 +9,8 @@
99
//
1010
// Measured constraint restated from the parent card, because it is the reason
1111
// the key exists at all: `visible: false` is NOT this contract — it omits the
12-
// param from the dialog AND from the submission, which is the #11703
13-
// silent-drop shape. `carryOver` must keep the param in the submission.
12+
// param from the dialog AND from the submission, which is the silent-drop
13+
// shape commit 5cb62d88b fixed. `carryOver` must keep the param in the submission.
1414
import { describe, it, expect } from 'vitest';
1515
import { ActionParamSchema } from './action.zod';
1616

‎packages/spec/src/ui/action.test.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ describe('requiresFeature lowering', () => {
265265
expect(bare).not.toHaveProperty('requiresFeature');
266266
});
267267

268-
// #5970 gave `visible` a boolean arm, so the lowering now meets two literals
268+
// Commit 97e7e3caa gave `visible` a boolean arm, so the lowering now meets two literals
269269
// it never could before. Boolean algebra decides both, in opposite directions.
270270
it('treats `visible: true` as the explicit default — lowers to the gate alone', () => {
271271
const result = ActionSchema.parse({
@@ -301,7 +301,7 @@ describe('requiresFeature lowering', () => {
301301
});
302302
});
303303

304-
// ── #5970 — `visible` / `disabled` speak ONE shape ────────────────────────────
304+
// ── commit 97e7e3caa — `visible` / `disabled` speak ONE shape ─────────────────
305305
// Ruled 2026-08-06: both keys are `boolean | string(CEL) | {dialect, source}`.
306306
// Before this, `visible` had no boolean arm while `disabled` did, so the very
307307
// common `visible: true` was a spec-side parse error that objectui's `ActionDef`
@@ -351,7 +351,7 @@ describe('ActionSchema — visible/disabled unified condition shape', () => {
351351
});
352352

353353
// The widening must not shrink the rejection surface by one shape. Each
354-
// of these was rejected before #5970 and is asserted to still be.
354+
// of these was rejected before commit 97e7e3caa and is asserted to still be.
355355
it.each([
356356
['an empty CEL string', ''],
357357
['a number', 1],

‎packages/spec/src/ui/action.zod.ts‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ const ACTION_PARAM_KEY_ALIASES: Readonly<Record<string, string>> = {
6363
default: 'defaultValue',
6464
// The words an author borrows from `FieldSchema` (`readonly`) or widget
6565
// vocabulary (`disabled`) for "the user must not edit this". On a param the
66-
// declared contract is `carryOver` (#11753): non-editable AND still
66+
// declared contract is `carryOver` (commit 0e4e51b0a): non-editable AND still
6767
// submitted verbatim — which is the half `readonly`'s field semantics
6868
// (write-path strip) would get exactly wrong here.
6969
readonly: 'carryOver',
@@ -387,17 +387,17 @@ export const ActionParamSchema = lazySchema(() => strictObject(
387387
*/
388388
defaultFromRow: z.boolean().optional().meta({ title: 'Default From Row' }),
389389
/**
390-
* Carry-over declaration (#11753 ruling, 2026-08-25): the param's value is
390+
* Carry-over declaration (maintainer ruling 2026-08-25, commit 0e4e51b0a): the param's value is
391391
* carried through the dialog rather than collected from the user — seeded
392392
* from the current row (`defaultFromRow` is required alongside), rendered as
393393
* a NON-EDITABLE summary, and submitted VERBATIM in the request body.
394394
*
395395
* The knob exists because neither neighbour expresses this contract:
396396
*
397397
* - `visible: false` omits the param from the dialog AND from the submission
398-
* — measured on #11753; a clone action that hid its facet params this way
399-
* would silently stop copying them, which is exactly the #11703 defect
400-
* shape.
398+
* — the measurement commit 0e4e51b0a records; a clone action that hid its facet params this way
399+
* would silently stop copying them, which is exactly the defect shape
400+
* commit 5cb62d88b fixed in `clone_permission_set`.
401401
* - Leaving the param editable invites the failure the ruling names: the
402402
* clone dialog offered `member_default`'s `row_level_security` — a JSON
403403
* array of 17+ policy objects — as a prefilled textarea on the platform's
@@ -406,7 +406,7 @@ export const ActionParamSchema = lazySchema(() => strictObject(
406406
* (`PermissionSetSchema` validates shape, not intent).
407407
*
408408
* "Not editable" is expressed by contract and enforced by the renderer
409-
* (maintainer ruling on #11753, recommendation A): objectui's
409+
* (maintainer ruling 2026-08-25, recommendation A, commit 0e4e51b0a): objectui's
410410
* `ActionParamDialog` renders a declared carry-over as a read-only summary
411411
* while keeping the seeded value in its submit state, so what is declared is
412412
* what is sent. Requiring `defaultFromRow: true` is the declared = enforced
@@ -457,7 +457,7 @@ export const ActionParamSchema = lazySchema(() => strictObject(
457457
// A carry-over param must have its row seed declared. The pair is checked at
458458
// parse time because the failure it prevents is silent at runtime: a
459459
// `carryOver: true` param with no `defaultFromRow` would render an empty
460-
// read-only control and submit `undefined` — the #11703 silent-drop shape,
460+
// read-only control and submit `undefined` — the silent-drop shape commit 5cb62d88b fixed,
461461
// reintroduced through the very key added to close it.
462462
(p) => !p.carryOver || p.defaultFromRow === true,
463463
{
@@ -816,7 +816,7 @@ export type ActionAiParsed = z.infer<typeof ActionAiSchema>;
816816
* | `string` | `disabled: "record.status == 'closed'"` | CEL shorthand, normalized to the envelope at parse time |
817817
* | `{ dialect, source }` | `{ dialect: 'cel', source: '…', meta: { rationale } }` | the full envelope, for authorship metadata or a non-default dialect |
818818
*
819-
* The two keys were asymmetric until #5970 — `visible` had no `boolean` arm, so
819+
* The two keys were asymmetric until commit 97e7e3caa — `visible` had no `boolean` arm, so
820820
* the very common `visible: true` was a parse error on the spec side while
821821
* objectui's `ActionDef` accepted it and stored metadata was already written
822822
* that way. An asymmetry between two keys that mean the same *kind* of thing is

‎packages/spec/src/ui/bulk-action.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ describe('BulkActionDefSchema (#4457)', () => {
5858
expect(def.params?.[0]).toMatchObject({ object: 'sys_user', labelField: 'name' });
5959
});
6060

61-
// ── RE-JUDGED, NOT RE-SPELLED (#18177) ─────────────────────────────────
61+
// ── RE-JUDGED, NOT RE-SPELLED (commit adabccf5f) ───────────────────────
6262
// This case used to be `forwards unknown WIDGET config on a param — the
6363
// renderer declares a catch-all`, and it asserted that `min`/`max`/`step`
6464
// rode through. That is the exact behaviour letter A removed, so the
@@ -304,7 +304,7 @@ describe('BulkActionDefSchema (#4457)', () => {
304304
});
305305

306306
// ─────────────────────────────────────────────────────────────────────────
307-
// #18177 — maintainer ruling batch #146 item 4, letter A.
307+
// Commit adabccf5f — maintainer ruling batch #146 item 4, letter A.
308308
//
309309
// The card that produced this ruling turned on ONE measurement: the open
310310
// shape accepted `zzz_nonsense_key_that_no_producer_emits_8755` in the same

‎packages/spec/src/ui/bulk-action.zod.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ import { FieldType } from '../data/field.zod';
4848
// error for a blank screen. Localizing means declaring a real action and
4949
// naming it in `bulkActions`: THAT path runs through the i18n resolver
5050
// (`toBulkActionDef`'s `localize`).
51-
// - `params[]` is STRICT (#18177, maintainer ruling batch #146 item 4,
51+
// - `params[]` is STRICT (commit adabccf5f, maintainer ruling batch #146 item 4,
5252
// letter A). It used to be `.passthrough()`, mirroring the
5353
// `[key: string]: unknown` catch-all on objectui's `BulkActionParam` — and
5454
// that made its accept a NULL READING: measured against installed spec
@@ -166,7 +166,7 @@ const BULK_PARAM_WIDGET_CONFIG_KEYS = [
166166
* (merged over the def's static `patch`); for an aggregate `custom` def they
167167
* ride along as the action's params.
168168
*
169-
* STRICT since #18177 — see the module header. An unknown key is refused by
169+
* STRICT since commit adabccf5f — see the module header. An unknown key is refused by
170170
* name, carrying either the rename or the prescription that fixes it, exactly
171171
* as on `ActionParamSchema`. The sentence this replaced said strictness "would
172172
* lie" at this level; the measurement said the opposite — the OPEN shape was
@@ -259,7 +259,7 @@ export const BulkActionParamSchema = lazySchema(() => strictObject(
259259

260260
/**
261261
* Cascade binding — the ONE key this close DECLARES rather than refuses
262-
* (#18177, ruling batch #146 item 4 letter A).
262+
* (commit adabccf5f, ruling batch #146 item 4 letter A).
263263
*
264264
* Shape and description mirror the single-record twin. ⚠️ That twin is
265265
* `FieldSchema.dependsOn` (`data/field.zod.ts`), NOT `ActionParamSchema`,

‎packages/spec/src/ui/component-element-navigation-17987.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
22

33
/**
4-
* [#17987] Record-click navigation on the STANDALONE element faces — the spec
4+
* [commit e233db9db] Record-click navigation on the STANDALONE element faces — the spec
55
* half of the objectui#8652 maintainer ruling (four options were put; the reply
66
* was verbatim `B`: declare `navigation` on the platform element schemas).
77
*

0 commit comments

Comments
 (0)