Skip to content

Commit 66e266c

Browse files
docs(spec): anchor five dead tracker citations to commits, and measure the true clean-up scale (#20226)
Fixes #19123 Clause-②: no ## What changed Five lines in `packages/spec/src/ui` cited two tracker numbers GitHub no longer serves (`#16714`, `#16715`: REST 404, no 301, re-probed today against lit controls). They are rewritten on ruling C+D (comment 5749154545 on this card): each line now anchors to the commit in this repository's history that decided it, and says in its own words what that commit decided, so a reader never needs the link. | Line (base `4df101c38`) | Was | Anchored to | What the line now says | |---|---|---|---| | `app.zod.ts:457` (shipped as source) | `(#16714)` | commit `4cfc93b802` | the `filters` docblock states no precedence order because objectui's hand-written mirror copied one and accepted a combination the schema refuses | | `app.zod.ts:504` (shipped as source) | `EXPORTED (#16714)` | commit `4cfc93b802` | the guard is exported so a mirror chains the schema's own rule; no accept set moves | | `app-nav-target-exclusivity-export.test.ts:4` | `[#16714]` header tag | commit `4cfc93b802`, with PR #16862 beside it as a convenience link only | the three things that commit decided: export the guard, state no order in the `filters` docblock, move no accept set | | `app-nav-target-exclusivity-export.test.ts:243` | test title `(#16714 ruling)` | the title now carries the lesson; the comment under it anchors to `4cfc93b802` | "the export deliberately moved no accept set" | | `object-refinement-check-exports.test.ts:469` | `(#16715)` | commit `b37f0b1767`, the diff that added the line | the declaration-count hardening closes a residual hole in the pin; no live shadowing existed | No ADR, ruling docblock or `scripts/adr-anchors/` entry records either decision (`objectNavTargetExclusivity` in `docs/adr` and `scripts/adr-anchors`: 0 files), so both take the commit-sha rung of C. The two `app.zod.ts` lines are the two shipped-tarball lines the ruling puts under D first: they now carry no tracker number, only the lesson and a sha. The `patch` changeset for `@objectstack/spec` says a docblock citation changed and nothing else. Prose, comments and one test title only. No assertion changes meaning and no accept set moves. ## Premise, re-measured on `4df101c38` - The ruling's first D act, the refusal string in `packages/spec/scripts/manifest-prescription.ts:78`, has no live target. That file and `check-react-blocks-declaration-parity.ts` were retired by `28ce61260`. `git grep` over the whole tree finds the three numbers on 5 lines, all in the table above, and `#16697` on 0. - `#16715` has a durable in-repo object. Commit `b37f0b1767` added the very line that cited it, and its message records the lesson: "a residual hole in the pin, not a live shadowing". ## Census: the true clean-up scale (read-only, nothing swept) **Population.** Every tracker-shaped token in `packages/spec/src/**` (1,594 tracked files) that names this repository: bare `#N` and `objectstack-ai/objectstack#N`, with N of 100 or more. Ordinals (`batch #`, `summon #`, `Directive #`, `item #` and similar) and 3- or 6-digit colour literals are excluded. Cross-repo tokens (`objectui#`, `cloud#`, `ui#`) are counted separately. ### Instrument 1: the REST status of every number (a full census, not a sample) `GET /repos/objectstack-ai/objectstack/issues/N` without following redirects, 2026-09-27T11:13Z to 11:16Z, plus 5 fully-qualified numbers at about 12:05Z. | status | numbers | |---|---| | probed | 1,958 (every distinct in-repo number) | | 200 | 1,786 | | **404** | **172 (8.8%)** | | 301 | 0 | **Controls.** They were re-probed at the start, after every 250 probes and at the end, 9 checkpoints in all. The lit controls `#16862`, `#16847` and `#17698` answered 200 at 9 of 9. The dead controls `#16714`, `#16715` and `#16697` answered 404 at 9 of 9. So the channel stayed up for the whole run, and the 404s are real readings. **The dead rate depends on the number's era** (bare numbers): | numbers | dead | |---|---| | below 5000 | 0% | | 6000s | 21.2% | | 7000s | 0% | | 8000s | 14.0% | | 9000s | 10.6% | | 10000s | 40.0% | | 11000s | 26.7% | | 12000s | 18.5% | | 13000s | 16.4% | | 14000s | 22.5% | | 15000s | 0% | | 16000s | 14.3% | | 17000s | 10.5% | | 18000s | 7.7% | | 19000s | 3.5% | **Contamination bound.** Five numbers are cited only as sibling-repo PRs, written bare (for example `objectui PR` followed by the number). One of them, `8887`, is among the 404s, and `8758` is cited both ways. So the in-repo dead count is 170 to 172 out of 1,953 to 1,958. **Cross-repo tokens.** `objectui` (183 distinct) and `cloud` (36) are NOT MEASURED: this session's REST gate answers 403 for both repositories. `hotcrm` answered 200 for 7 of 7 (lit control `hotcrm#1961`: 200). ### Instrument 2: who owns the squash commit `GET /repos/objectstack-ai/objectstack/commits/SHA/pulls` for every dead number that appears as a squash suffix in `origin/main` history (8,715 commits, back to 2026-06-22). 11 of the 172 do, and all 11 answer `[]`: the PR object is gone. Controls: `b37f0b1767` answers `[16847]` and `1124c45641` answers `[19107]` (lit); `7936b29ce5`, the card's known-dead `#16697`, answers `[]`. The other 161 dead numbers carry no squash suffix. They were cards, not PRs, and this instrument does not reach them. ### Independent cross-check: `check-issue-citations --census` I ran the repository's own citation gate in census mode at about 12:02Z. The board frontier is 20,223 and the board size is 18,050, so 2,173 minted numbers (10.7%) are holes. Tree-wide there are 2,779 unresolvable sites, 664 of them in `packages/spec/src`. On the gate's surface (non-test comment prose), the two instruments agree on 661 of those 664 sites. The 3 sites only the gate found use the `objectstack-ai/objectstack#N` spelling, which my first extraction pass missed; I probed them afterwards and they are included above. My 297 extra comment sites break down as 271 in test files (the gate's declared deferred surface) and 26 `re-charter #13135` sites that the gate reads as an ordinal. ### What remains after this PR On this head, `packages/spec/src/**` still has **1,295 dead-cited sites on 1,277 lines in 327 files, citing 170 numbers**. On the base it was 1,300 sites, 1,282 lines, 330 files and 172 numbers. | class | sites | lines | files | |---|---|---|---| | non-test comment | 691 | 683 | 180 | | non-test string or code (text an author can be shown) | 186 | 184 | 48 | | test comment | 271 | 266 | 103 | | test string or code (titles, fixtures) | 147 | 144 | 54 | By area: migrations 438, data 239, api 153, ui 107, kernel 105, contracts 81, system 38, conversions 24, shared 20, other 90. **Load-bearing share.** I read a seeded random sample of 40 dead-cited lines. 37 of the 40 cite a ruling, a deliberate tolerance or exclusion, a retirement, or a cautionary measurement, which is the dispatch's definition of load-bearing. The other 3 are incidental: a bare `Refs`, a label, a process note. Applied to 1,277 lines, that is roughly 1,100 to 1,200 load-bearing lines, a sweep the ruling keeps out of a single PR. **None of them is rewritten here.** **The runtime-text slice is the D half.** `os migrate meta` prints each migration entry's `replacement`, `why:` (`reason`) and `verify:` (`acceptanceCriteria`) to the author (`packages/cli/src/commands/migrate/meta.ts:523-525`). Across `packages/spec/src/migrations/**`, those strings hold 2,060 tracker-id sites (478 distinct numbers; 178 sites are dead). `pnpm check:doc-authoring` is green over all of them, for two reasons: its Rule 3 does not recognise those property positions, and its cross-package leg excludes `packages/spec/src`. I report this to the seat as a finding and do not fix it here. **Every dead number still cited**, as number and sites/files, in numeric order. Any line is recoverable with `git grep -n` on the number under `packages/spec/src`. - `#5970` 6/3 · `#6037` 11/5 · `#6048` 8/3 · `#6072` 1/1 · `#6075` 2/2 · `#6083` 10/7 · `#6085` 2/1 · `#6111` 3/3 - `#6148` 10/6 · `#6206` 14/7 · `#6216` 2/2 · `#6238` 1/1 · `#6239` 10/6 · `#6259` 5/2 · `#6276` 13/2 · `#6279` 2/2 - `#6287` 18/2 · `#6300` 2/1 · `#6306` 1/1 · `#6345` 32/11 · `#6361` 20/11 · `#6362` 9/5 · `#6363` 12/6 · `#6483` 6/1 - `#6511` 7/3 · `#6523` 11/5 · `#6527` 1/1 · `#6571` 10/2 · `#6573` 2/2 · `#6604` 3/2 · `#6605` 3/1 · `#6640` 2/2 - `#6704` 6/3 · `#6723` 1/1 · `#6725` 5/2 · `#6745` 2/1 · `#8460` 2/1 · `#8495` 59/27 · `#8656` 1/1 · `#8696` 34/13 - `#8714` 4/2 · `#8715` 47/24 · `#8758` 9/6 · `#8772` 11/5 · `#8778` 1/1 · `#8794` 5/3 · `#8836` 4/3 · `#8873` 10/6 - `#8874` 1/1 · `#8876` 11/7 · `#8885` 2/1 · `#8887` 2/2 · `#9040` 20/6 · `#9041` 28/5 · `#9740` 3/1 · `#9741` 23/2 - `#9933` 9/2 · `#9934` 4/4 · `#9972` 4/2 · `#10165` 7/2 · `#10194` 12/4 · `#10238` 1/1 · `#10264` 1/1 · `#10274` 7/3 - `#10329` 10/4 · `#10330` 3/1 · `#10338` 6/3 · `#10347` 5/2 · `#10485` 43/23 · `#10527` 3/2 · `#10627` 12/7 · `#10724` 47/20 - `#10726` 15/9 · `#10812` 6/5 · `#10926` 11/6 · `#11006` 15/3 · `#11065` 7/3 · `#11071` 1/1 · `#11166` 2/1 · `#11195` 5/3 - `#11215` 1/1 · `#11284` 10/4 · `#11328` 2/2 · `#11330` 2/1 · `#11331` 2/1 · `#11332` 19/7 · `#11333` 3/3 · `#11350` 9/5 - `#11408` 3/2 · `#11453` 1/1 · `#11504` 5/3 · `#11507` 8/4 · `#11513` 2/2 · `#11658` 6/3 · `#11693` 2/2 · `#11703` 3/2 - `#11741` 9/4 · `#11753` 6/2 · `#11757` 4/2 · `#11846` 30/10 · `#11858` 1/1 · `#11859` 2/1 · `#12010` 5/2 · `#12144` 2/1 - `#12165` 1/1 · `#12176` 2/1 · `#12194` 4/4 · `#12245` 2/1 · `#12248` 17/4 · `#12380` 4/2 · `#12493` 6/2 · `#12868` 9/6 - `#12950` 3/2 · `#12961` 10/2 · `#13031` 3/2 · `#13109` 1/1 · `#13135` 70/25 · `#13156` 4/4 · `#13195` 3/1 · `#13197` 1/1 - `#13218` 7/2 · `#13608` 5/2 · `#13644` 3/2 · `#13670` 1/1 · `#13672` 3/2 · `#13681` 1/1 · `#14143` 2/2 · `#14162` 1/1 - `#14192` 5/2 · `#14312` 1/1 · `#14365` 4/3 · `#14369` 24/13 · `#14419` 2/2 · `#14426` 2/2 · `#14474` 1/1 · `#14526` 2/2 - `#14662` 4/2 · `#14676` 22/10 · `#14686` 7/2 · `#14691` 50/16 · `#14722` 4/2 · `#14723` 1/1 · `#14748` 2/2 · `#14902` 2/2 - `#14919` 2/2 · `#14996` 1/1 · `#16126` 2/2 · `#16559` 2/1 · `#16626` 3/3 · `#16649` 12/2 · `#16659` 5/4 · `#16685` 4/2 - `#16786` 3/2 · `#16864` 2/2 · `#16867` 3/2 · `#17014` 3/2 · `#17058` 1/1 · `#17081` 1/1 · `#17124` 3/3 · `#17147` 5/2 - `#17286` 1/1 · `#17348` 1/1 · `#17590` 1/1 · `#17987` 13/2 · `#18003` 1/1 · `#18012` 10/5 · `#18177` 7/2 · `#18335` 1/1 - `#19307` 1/1 · `#19377` 8/4 ## Gates (head `98edadd03`) - **Derived gate families.** `node scripts/pm/dispatch-gates.mjs --ran` reports 83 derived, 79 run with exit 0, 4 NOT MEASURED and 0 unrun. The four exited 3 (PREREQUISITE NOT MET): `check:doc-formula-expressions`, `check:dual-build-cjs-loads`, `check:lean-entry-closure` and `check:type-check-debt`. Each needs other packages' `dist/`, and both attempts to take the shared verify lock for that build ended in queue-timeout (99). This is a declared narrowing: the diff changes comment and test-title text in one package and nothing those four gates read, and CI's `Lint & Repo Gates` runs them. - **Roster gates.** The six artifact-roster gates whose roster sits under a changed path (`check-changeset-fixed`, `check:meta-url-spelling`, `check:spec-changes`, `check:authz-resolver`, `check:error-code-casing`, `check:filter-alias-parity`) all exit 0. - **Build, tests, typecheck.** `pnpm --filter @objectstack/spec build` exits 0. The two edited test files pass: 2 files, 141 tests. `pnpm --filter @objectstack/spec typecheck` exits 0. - **Citation verdict.** `node scripts/check-issue-citations.mjs --base 4df101c` (the diff-scoped verdict) exits 0. The change adds one citation, `#16862`, and it answers 200. ## Acceptance notes - This change adds one tracker number: PR #16862, once, in a test docblock, as a convenience link beside the sha it cites. The ruling allows that, and nothing else in the change cites a number. - **Where this departs from the dispatch.** The dispatch said to rewrite any load-bearing dead-cited line found in `packages/spec/src` beyond the five, in this PR. At the measured 1,277 lines, about 92% of them load-bearing, that is the sweep the ruling keeps out of one PR, so this PR measures and lists them and rewrites none. - D's first named act, the refusal string, was retired upstream by `28ce61260`. The live D population is the migration-entry text above. - **Instrument notes**, reconciled above and not filed: the gate's ordinal list reads `re-charter #N` as a non-citation, which hides 26 real citations of `#13135`. My own first extraction pass missed the `owner/repo#N` spelling (3 sites). --- _Generated by [Claude Code](https://claude.ai/code/session_01CiCTczDo7tGhafXjf61dUJ)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent fc91239 commit 66e266c

4 files changed

Lines changed: 34 additions & 11 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
`app.zod.ts` docblocks: the navigation target-exclusivity guard now cites the commit that decided it, and says what that commit decided
6+
7+
Two docblock sentences in `src/ui/app.zod.ts` (which ships as source through the
8+
package's `src/**/*.zod.ts` entry) cited a tracker number that no longer resolves
9+
on GitHub. They now carry the lesson in words and anchor to commit `4cfc93b802`
10+
in this repository's history: the `filters` docblock deliberately states no
11+
precedence order, because objectui's hand-written mirror copied one from this
12+
docblock and ended up accepting a combination the schema refuses; and
13+
`objectNavTargetExclusivity` is exported so a mirror chains the schema's own rule.
14+
15+
Docblock text only. No schema, guard, accept set, export or `.describe()` string
16+
changes.

‎packages/spec/src/ui/app-nav-target-exclusivity-export.test.ts‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
22

33
/**
4-
* [#16714] `objectNavTargetExclusivity` is EXPORTED, and the export IS the
5-
* check the navigation door runs — the spec half of the objectui mirror gap.
4+
* `objectNavTargetExclusivity` is EXPORTED, and the export IS the check the
5+
* navigation door runs — the spec half of the objectui mirror gap. Decided
6+
* and landed in commit 4cfc93b802 (PR #16862 is a convenience link beside
7+
* that sha, not the citation): export the guard so a mirror chains the
8+
* schema's own rule, state no precedence order in the `filters` docblock,
9+
* and move no schema's accept set.
610
*
711
* Why: objectui's `NavigationItemSchema` is hand-written (not `.shape`-derived,
812
* so the #16489 mechanism does not reach it) and its own `superRefine` checks
@@ -240,8 +244,9 @@ describe('the mount — the union branch carries the check, the exported ObjectN
240244
expect(vectorOf(runExport, matrix)).not.toBe(vectorOf(() => [], matrix));
241245
});
242246

243-
it('ObjectNavItemSchema carries no object-level check — the export moved no accept set (#16714 ruling)', () => {
244-
// Deliberate non-change: which schema mounts the check is a separate
247+
it('ObjectNavItemSchema carries no object-level check — the export deliberately moved no accept set', () => {
248+
// Deliberate non-change, decided with the export itself (commit
249+
// 4cfc93b802): which schema mounts the check is a separate
245250
// question from whether a mirror can chain it, and it is NOT decided by
246251
// this export. A later ruling that mounts the guard on the exported
247252
// schema flips this pin on purpose; until then every fixture on the

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,10 @@ export const ObjectNavItemSchema = lazySchema(() => strictObject(navItemSurface(
454454
* without the guard a consumer would have to resolve the combination by
455455
* picking one field and silently ignoring the rest, and a mirror that
456456
* copies an ordering from this docblock instead of chaining the guard ends
457-
* up accepting what this schema refuses (#16714). The guard's own docblock
458-
* names the one legacy combination it tolerates (`recordId` + `viewName`).
457+
* up accepting what this schema refuses — objectui's hand-written mirror
458+
* did exactly that, which is why commit 4cfc93b802 took the ordering out of
459+
* this docblock. The guard's own docblock names the one legacy combination
460+
* it tolerates (`recordId` + `viewName`).
459461
*/
460462
filters: z.record(z.string(), z.string()).optional().describe(
461463
'URL filter conditions — targets the /:objectName/data bare surface via filter[<field>]=<value> params instead of a saved view. Values support template vars {current_user_id}, {current_org_id}. Mutually exclusive with recordId/viewName.',
@@ -501,8 +503,8 @@ export const ObjectNavItemSchema = lazySchema(() => strictObject(navItemSurface(
501503
* tolerated: it predates this guard and is documented as "viewName is
502504
* ignored when recordId is set".
503505
*
504-
* EXPORTED (#16714), one function per refinement, the same posture as the
505-
* `check*` exports of #16489: a hand-written mirror of the object nav item
506+
* EXPORTED (commit 4cfc93b802), one function per refinement, the same posture
507+
* as the `check*` exports of #16489: a hand-written mirror of the object nav item
506508
* chains this very function in its own `superRefine` instead of restating
507509
* the rule from prose — a restatement is what drifts. Its one mount in this
508510
* module is the `type: 'object'` branch of {@link NavigationItemSchema}; the

‎packages/spec/src/ui/object-refinement-check-exports.test.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -464,9 +464,9 @@ describe('each schema attaches its export BY IDENTIFIER — no inline copy', ()
464464
// a second, shadowing binding of the same name — a local `function checkX` inside
465465
// another function, say — satisfies every one of them while the door chains a
466466
// different function object, and if it happened to agree on the fixture matrix it
467-
// would satisfy leg 2 as well. Measured on the diff that added this: four names,
468-
// one declaration each — so this closes a residual hole in the pin, it does not fix
469-
// a live shadowing (#16715). It must stay green.
467+
// would satisfy leg 2 as well. Measured on the diff that added this (commit
468+
// b37f0b1767): four names, one declaration each — so this closes a residual hole
469+
// in the pin; no live shadowing existed to fix. It must stay green.
470470
const declarations = (src: string, name: string): number =>
471471
src.match(new RegExp(`^\\s*(export )?function ${name}\\b`, 'gm'))?.length ?? 0;
472472

0 commit comments

Comments
 (0)