Skip to content

Commit 682873f

Browse files
docs(spec): re-anchor the dead tracker citations in stack.zod.ts and data/analytics.zod.ts to the commits that decided them (stage 7) (#20616)
Part of #20234 Clause-②: no Stage 7 of the staged sweep: `packages/spec/src/stack.zod.ts` and `packages/spec/src/data/analytics.zod.ts`, both freed by landings (PR #20579 and PR #20458). Its claim is `5885635758`. Every comment or docblock line in those two files that cited a tracker number answering 404 now cites the commit on `main` that decided its rule, in ruling C+D's form C, and says in its own words what was decided. Comments only: 12 lines out, 12 in, across 2 files. No code token, string literal or `describe()` text moves. No dead site stays: none of the 12 is read by literal. The census is the gate's own `node scripts/check-issue-citations.mjs --census --json`, filtered to the two paths. Before: base `0f6dcac5e9`, board enumerated (185 pages, frontier #20611). After: head `cc0580d404`, board enumerated (185 pages, frontier #20615). ## Measurement | file (under `packages/spec/src/`) | dead before | after | numbers, then anchor | |---|---:|---:|---| | `stack.zod.ts` | 9 | 0 | #10485 ×2 (`:415`, `:1023`) to `35ad101bc`; #6238 (`:633`) to `c8d6f6e08`; #14192 (`:1233`) to `4d0d9445a`; #14686 ×2 (`:3037`, `:3194`) to `279431e7a`; #14662 ×3 (`:4510`, `:5070`, `:5293`) to `35dffeace` | | `data/analytics.zod.ts` | 3 | 0 | #10194 ×3 (`:404`, `:407`, `:485`) to `2306a765c` | | **2 files** | **12** | **0** | 6 numbers removed, 6 distinct shas | Per-file counts at base equal the claim's (9 and 3, from stage 6's census). A second instrument agrees site for site: every `#N` in the two files, classified by the TypeScript parser, and each of the 84 distinct numbers of 100 or more probed by REST `issues/N` without following redirects (the other 3 are the ordinals `Prime Directive #12`, `batch #23`, `batch #57`). - Base: 244 sites, all in comments (0 strings, 0 code). 78 numbers answer 200 and 6 answer 404: the same 6 numbers and the same 12 sites as the gate. - Its string-class positive control found 11 string sites in `kernel/manifest-unknown-keys.test.ts` and `packages/cli/src/utils/lower-callables.test.ts`. - Head: 232 sites, 78 numbers, all 78 answer 200 (the same 78), none answers 404. - Lit controls #16862, #16847 and #17698 answered 200 at every checkpoint (3 at base, 3 at head); dead controls #16714, #16715 and #16697 answered 404 at every checkpoint. ## Why each anchor decides its line Each sha resolves uniquely, is an ancestor of `origin/main` (and of the base), and has one parent. No file under `docs/adr/**`, `docs/NORTH-STAR.md` or `scripts/adr-anchors/` names any of the six numbers or records these rules, so each takes the commit rung, as stages 1–6 did. - **#10485 to `35ad101bc`** (`:415`, `:1023`): retires the `themes` carrier key and `ThemeSchema` under ADR-0049. Its message records the ruling, "Ruled B (退役授权面, 2026-08-21)", and its own `stack.zod.ts` diff wrote both lines. `:415` keeps ADR-0049 and the ruling in its words; the D3 entry `stack-themes-carrier-retired` it names on `:423` is unchanged. This is the anchor stages 1, 5 and 6 used for the same retirement. - **#6238 to `c8d6f6e08`** (`:633`): widens the array member of `functions` so its `handler` also takes the lowered string ref, which is the fix for `objectstack build` refusing its own array output. Its message names #6238, and its own diff wrote the line. #4343 and #4976 on the same line stay (both 200). - **#14192 to `4d0d9445a`** (`:1233`): turns `ManifestSchema` and its nested blocks into `strictObject` and flips the assembled-body strip pin to a refusal pin; each of its sub-commits names #14192. The line itself was written later by `c78c9180de`, whose own message says "#14192 closed ManifestSchema with strictObject", so the commit that closed it is the anchor. - **#14686 to `279431e7a`** (`:3037`, `:3194`): "defineStack refuses two actions that resolve to one scope-qualified runtime key". Its subject names #14686, and its diff adds `collectDuplicateActionKeyErrors` and the changeset for that refusal. Both lines were written later by `773a99960a` (PR #15022), whose message describes the same "same-key rule, which runs before the merge". - **#14662 to `35dffeace`** (`:4510`, `:5070`, `:5293`): "composeStacks refuses two stacks whose actions resolve to one scope-qualified runtime key". It checks the composed set with the rule `defineStack` applies within one stack, with no `actionConflict` option (maintainer ruling 2026-09-03). Its message does not name #14662; its own `stack.zod.ts` diff wrote all three `(#14662)` lines. - **#10194 to `2306a765c`** (`analytics.zod.ts:404`, `:407`, `:485`): binds `analytics_cube` (and `theme`) in `UNREGISTERED_KIND_SCHEMAS`, so `PUT /meta/analytics_cube/:name` parses through `CubeSchema`, and gives `CubeSchema` the `...MetadataProtectionFields` spread. Its message names #10194, and its own diff wrote all three lines. The `[#10194]` markers become `[commit 2306a76]`, the spelling stages 1 and 5 already use in `kernel/metadata-type-schemas.ts`. ## Mechanical proof - **Token guard** (my `tokcmp.mjs`: TypeScript 6.0.3 leaf tokens, JSDoc kinds excluded, controls mutate the head text in memory only). Base `0f6dcac5e9` against the head, 2 files, 17,249 base tokens: - Real run: 0 files with a token change (exit 0). - Comment-insertion control (`data/analytics.zod.ts`): 0 (exit 0). - Code-insertion positive control (`stack.zod.ts`, a declaration appended): DIFFER at token 15388 (exit 1). - String positive control (the first `StringLiteral` the parser locates in each file): DIFFER at token 5 (exit 1), once per file. - `describe()` positive control (the first `.describe()` string argument the parser locates: `stack.zod.ts:133`, `analytics.zod.ts:244`): DIFFER at tokens 507 and 442 (exit 1). - **Line balance**: `stack.zod.ts` +9/−9, `data/analytics.zod.ts` +3/−3; line counts equal at base and head (5344 and 853). - **Tracker numbers**: added-not-removed is empty in both files, and no `PR #N` is on an added line. Net-removed: 12 sites, 6 numbers. The only numbers on added lines are #4343 and #4976, which stay on `:633`. - **Shas**: 6 distinct on added lines, 0 on removed lines. - `rev-parse --disambiguate` answers 1 object for each. - `merge-base --is-ancestor` exits 0 for each, against `origin/main` `7510663c87` and against the base; each is single-parent; the repository is not shallow. - **Literal readers**: all 26 string, template and regex literals in the repository that carry one of the six numbers (42 code files) were matched against the two files' base text: 0 occur there. Each removed line was also cut into 4-word windows (96) and searched across the tree: the 9 hits inside string literals are other files' own test titles sharing a phrase ("the ADR-0010 protection envelope", "an assembled body is"), and none reads either file. The source-text readers of the two files read code, not these comments: `compose-stacks-refusal-envelopes.test.ts` counts `throw new Error(`, and `check-stack-collection-maps.mjs` and `check-skill-top-level-keys.mjs` read the declared collections and keys. ## Tests and gates (at head `cc0580d404`) - `pnpm exec turbo run build --concurrency=2 --filter=./packages/* --filter=./packages/*/*` under `os-verify-lock`: Tasks 71 successful, 71 total, VERDICT command-exit 0. - `pnpm --filter @objectstack/spec check:generated` under the lock: all 15 generated artifacts up to date, `check:docs` over `content/docs/references/**` included; VERDICT command-exit 0. No reference page projects any of the 12 lines, so none is regenerated. - `vitest run --maxWorkers=2` under the lock over the two files' own suites (`src/stack*`, `src/compose-stacks*`, `src/define-stack*`, `src/assembled-package-body`, `src/data/analytics*`, `src/data/cube*`): Test Files 35 passed (35), Tests 976 passed (976). - The 37 spec suites that read source text across `src/`, or carry one of these numbers, under the lock: Test Files 37 passed (37), Tests 759 passed (759). - `scripts/{category-title,dist-freshness,dist-freshness-adoption,file-description,strictness-ledger,strictness-ledger-doc,root-index,skill-map-guards,export-origins,split-entries,root-entry-type-nameability.pin}`, `scripts/liveness/{evidence,tombstoned-row-status}`; - `src/type-alias-convention.pin`, `src/eager-entry-import`, `src/api/{api-entry-graph.pin,auth,export-job-family-retirement}`, `src/ai/tool-confirmation-prescription-tense.pin`, `src/data/{currency-mode-family-closure.pin,external-lookup-retirement}`, `src/identity/position-delegatable-enforcer.pin`, `src/integration/{connector-connection-timeout-retirement,connector-resilience-keys-retirement}`, `src/security/rls-tags-retirement`, `src/shared/{alias-integrity,retired-key-migrate-sentence}`, `src/system/{compliance-families-retirement,constants/platform-object-names,email-template-floor-locale-parity.pin,message-queue-retirement}`, `src/ui/{action-requires-confirmation-docblock.pin,i18n,interaction-config-retirement,strictness-batch14}`, `src/kernel/{manifest-unknown-keys,metadata-type-schemas}`. - Left to CI: `scripts/{build-schemas-check-mode,def-key-collisions,openapi-self-consistency}` (each rebuilds artifacts in a temp tree) and `scripts/{check-generated-ledger,check-generated-fix-rebuild.pin}` (read the ledger and `dist`). None reads comment text. - `pnpm --filter @objectstack/spec typecheck` under the lock: exit 0; `check:test-typecheck` OK (53 files / 251 errors / 138 pinned signatures held). - Lint, a proven narrowing: `eslint --no-inline-config --format json` over the 2 files gives 2 files, 0 errors, 0 warnings. - `isPathIgnored` is false for both, read through eslint's API. - `eslint.config.mjs:327-328` says type-aware linting is never enabled, so a comment edit cannot move an untouched file's verdict. - The repo-wide `pnpm lint` is CI's. - `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands`: 79 families derived and run, every one exit 0. `--ran` reads "79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN". Among them: - `pnpm check:issue-citations` (self-test, 114 cases in 8 batteries) and the live diff-scoped `node scripts/check-issue-citations.mjs`: it judged the 2 citations on added lines, #4343 and #4976, and both are live issues. - `pnpm check:doc-authoring`: 16,804 customer-facing strings across 1,179 spec sources clean; the sibling baseline holds. - `pnpm check:stack-collection-maps`: 8 enumerations reconciled against 31 declared collections. - Changeset: `patch` for `@objectstack/spec`. Both files are `src/**/*.zod.ts`, which `files[]` ships verbatim, and the rewritten docblocks reach `dist`: "posture: commit 4d0d944 closed" and "[commit 2306a76] This docblock used to say" are each in 2 `.d.ts`, their old spellings in 0. Positive control: the unchanged neighbouring sentence "BY INHERITANCE — an undeclared key on one is REFUSED" is in the same 2 `.d.ts`. - Merge probe: a no-driver `merge-tree` of the head onto `origin/main` `7510663c87`, from a bare shared clone, exits 0. The 3 commits `main` gained since the base touch neither file nor the citation or derivation scripts, and a re-derivation prints the same 79 commands. No merge was made. - No ablation or reverse verification: the change is comment-only, so there is no behaviour to invert. ## Hypotheses (measured first) 1. **Holds.** 12 dead sites at the tip, 9 in `stack.zod.ts` and 3 in `data/analytics.zod.ts`, equal per file to stage 6's census. 2. **Holds.** Read at 2026-09-29T07:36Z and again at 08:16Z, after the last push and before this PR was opened: all open PRs' full file lists (9 PRs, 166 files at the second read) and the newest `Claim:` on all 11 `pm:dispatched` cards. None names either file, except this card's own claim. 3. **Holds, with nothing to keep.** All 12 sites are comments. No test string, exported string or `describe()` text carries one, and no test or script reads any of them by literal. 4. **Holds.** No generated reference page projects these lines; `check:docs` is green with no regeneration. ## Deviations - None to the file surface: the 12 claimed lines and one changeset, no generated page needed. - Commit trailers follow AGENTS.md's model-free pair (`Claude-Session` plus `Co-authored-by: Claude`); the pre-push trailer check passed on every push. ## Acceptance notes **What stays for later stages.** The gate's census at this PR's head (base `0f6dcac5e9` plus this PR) reads **248** dead sites (29 numbers) in `packages/spec/src`. The only `packages/spec/src` change `main` has made since the base (#20610's migrations entry and registry) adds four live numbers and removes none, so 248 also stands at the tip `7510663c87` plus this PR: - `migrations/` **233**: #20233 edits the same entry files (PR #20607 holds `migrations/registry.ts`). - `conversions/registry.ts` **12**: PRs #20570 and #20587 hold it. - `integration/connector.zod.ts` **1**: PR #20587 (#20287). - `data/api-derivation.ts:163` (#6259) and `identity/identity.zod.ts:230` (#8715), **1** each: kept because tests read them by literal, so removing them is form D. **Outside the gate's census: test files.** The gate defers `*.test.ts`. The same six dead numbers still stand at 15 comment sites and 10 test-title strings in `packages/spec/src` test files: - `data/analytics-strictness-batchd.test.ts:96` (comment, #10194) and its title `:93`. This file is in the `analytics*` set stages 3 and 4 excluded while PR #20458 held it; `analytics-date-range-two-bound-window.test.ts` and `cube-member-inner-name-retirement.test.ts` were in that set too and are not re-measured here. - The package root: `compose-stacks-action-echo.test.ts:20`, `:34`, `:200` (#14686) and titles `:176`, `:224`; `compose-stacks-action-key-collision.test.ts:3` (#14662); `stack-top-level-strict.test.ts:103` (#10485) and title `:128`; `type-alias-convention.pin.test.ts:257`, `:1572`, `:1937` (#10485). - `shared/`: `metadata-collection.test.ts:250`, `metadata-url-spelling.test.ts:51`, `:72`, `:168` (#10485), `:257` (#10194), title `:254`. `automation/sync-retirement.test.ts:207` (#10485). - `kernel/`: `manifest-unknown-keys.test.ts`, four titles (#14192); `metadata-type-schemas.test.ts:422`, a title (#10194). - Stage 6 took the package root, `shared/` and `automation/` through the gate's census, which never lists a test file, so test-file comment lines there may carry other dead numbers as well. That wider population is not measured here. **Outside `packages/spec/src`.** The same six numbers stand at 44 more sites (`packages/{metadata-protocol,objectql,rest,runtime,cli,core,metadata,qa}`, `examples/`, `scripts/`, `packages/spec/scripts/`), and at 19 sites in `migrations/` (the #20233 area). **Rung.** The #10485 retirement also has the ADR-0087 D3 entry `stack-themes-carrier-retired`, which `:423` already names. This PR takes the commit rung, as stages 1–6 did. **Wording, each true of its commit.** `:3037` and `:3194` now read "commit 279431e's same-key refusal": the refusal that commit added, in lines `773a99960a` wrote. `:1233` reads "commit 4d0d944 closed `ManifestSchema`", in a line `c78c9180de` wrote. --- _Generated by [Claude Code](https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent ed6f734 commit 682873f

3 files changed

Lines changed: 26 additions & 12 deletions

File tree

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 `stack.zod.ts` and `data/analytics.zod.ts` were re-anchored
6+
7+
Twelve comment and docblock lines in `src/stack.zod.ts` and
8+
`src/data/analytics.zod.ts` cited tracker numbers that no longer resolve on
9+
GitHub. They now cite the commit in this repository's history that decided
10+
the matter: the `themes` carrier retirement, the lowered-handler array form of
11+
`functions`, the closed `ManifestSchema`, the same-key action refusal in
12+
`defineStack` and its cross-stack twin in `composeStacks`, and the
13+
`analytics_cube` binding at the `/meta` write door. Comments only: no type,
14+
schema, export, `describe()` text or runtime behaviour changes.

‎packages/spec/src/data/analytics.zod.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,10 +401,10 @@ export const CubeJoinSchema = lazySchema(() => strictObject(
401401
* showcase example authors through) and `defineStack({ analyticsCubes })` /
402402
* artifact ingest, both of which parse `StackSchema` → `analyticsCubes[]`.
403403
*
404-
* [#10194] This docblock used to say the ADR-0010 protection envelope is
404+
* [commit 2306a765c] This docblock used to say the ADR-0010 protection envelope is
405405
* deliberately NOT declared here, on the premise that `analytics_cube`
406406
* resolves no `getMetadataTypeSchema` entry (so `saveMetaItem` never 422s
407-
* it). #10194 retired that premise: `analytics_cube` is now bound in
407+
* it). Commit 2306a765c retired that premise: `analytics_cube` is now bound in
408408
* `UNREGISTERED_KIND_SCHEMAS`, so `PUT /meta/analytics_cube/:name` parses a
409409
* body through THIS schema — and the `getMetaItemLayered` → `saveMetaItem`
410410
* round-trip carries the `applyProtection` stamp. The shape is `.strict()`,
@@ -482,7 +482,7 @@ export const CubeSchema = lazySchema(() => strictObject(
482482
),
483483

484484
// ADR-0010 — runtime protection envelope (internal — set by loader).
485-
// [#10194] See the docblock above for why this spread became load-bearing
485+
// [commit 2306a765c] See the docblock above for why this spread became load-bearing
486486
// the day the `/meta` write door started parsing bodies with this schema.
487487
...MetadataProtectionFields,
488488
},

‎packages/spec/src/stack.zod.ts‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ const STACK_DEFINITION_COLLECTIONS_SHAPE = {
412412
+ 'composeStacks runs the same key rule across its input stacks (counting distinct stacks, not sites) '
413413
+ 'and names both source stacks on a collision.',
414414
),
415-
// `themes` was REMOVED in 17.1 (#10485, ADR-0049 enforce-or-remove — ruled
415+
// `themes` was REMOVED in 17.1 (commit 35ad101bc, ADR-0049 enforce-or-remove — ruled
416416
// 退役授权面, 2026-08-21). The pipeline was live from authoring gate through
417417
// artifact ingest and stopped there: no framework package ever read the
418418
// stored items, `theme` was never a registered metadata type, no first-party
@@ -630,7 +630,7 @@ const STACK_DEFINITION_COLLECTIONS_SHAPE = {
630630
*
631631
* BOTH shapes therefore reach this schema twice: once as authored, once
632632
* lowered. All four combinations (map/array × bare/declared) are accepted —
633-
* the map's two lowered forms since #4343 and #4976, the array's since #6238.
633+
* the map's two lowered forms since #4343 and #4976, the array's since commit c8d6f6e08.
634634
* `packages/cli`'s `lower-callables.test.ts` pins every cell against what the
635635
* lowering actually emits, rather than against a belief about it.
636636
*/
@@ -1020,7 +1020,7 @@ export const COMPOSE_KEY_DISPOSITIONS = Object.freeze({
10201020
reports: 'concat',
10211021
datasets: 'concat',
10221022
actions: 'concat',
1023-
// `themes` left this table with the key (#10485) — the total-record type is
1023+
// `themes` left this table with the key (commit 35ad101bc) — the total-record type is
10241024
// what forces this comment to move in lockstep with the schema.
10251025
flows: 'concat',
10261026
jobs: 'concat',
@@ -1230,7 +1230,7 @@ function assembledPackageBodyShape(): Pick<typeof STACK_DEFINITION_COLLECTIONS_S
12301230
*
12311231
* NO `strictObject` spelling appears here, and none is needed. This schema is
12321232
* `ManifestSchema.extend(...)`, and `.extend()` carries the base's unknown-key
1233-
* posture: #14192 closed `ManifestSchema`, so an assembled body is closed too,
1233+
* posture: commit 4d0d9445a closed `ManifestSchema`, so an assembled body is closed too,
12341234
* BY INHERITANCE — an undeclared key on one is REFUSED, by name and with the
12351235
* declared spelling offered for a near miss. ⛔ Do not read the absence of the
12361236
* `strictObject` spelling as a declined posture; it is an inherited one.
@@ -3034,7 +3034,7 @@ function sortActionsByOrder<T extends { order?: number }>(actions: T[]): T[] {
30343034
* and before this the second merge doubled every bound action in the composed
30353035
* object (three copies for two declarations under `objectConflict: 'override'`
30363036
* / `'merge'`). Identity, deliberately not equality: an author writing one
3037-
* action in both positions produces two distinct objects, which #14686's
3037+
* action in both positions produces two distinct objects, which commit 279431e7a's
30383038
* same-key refusal (run before this merge) rejects and which this merge must
30393039
* not quietly fold.
30403040
*
@@ -3191,7 +3191,7 @@ function mergeActionsIntoObjects(config: ObjectStackDefinition): ObjectStackDefi
31913191
// surviving objects through as-is — ran this merge a second time over that
31923192
// echo and doubled every bound action. A hand-written twin (one action
31933193
// authored in both positions) is two objects after the strict parse, and
3194-
// #14686's same-key refusal has already run ahead of this merge to refuse
3194+
// commit 279431e7a's same-key refusal has already run ahead of this merge to refuse
31953195
// it; an equality skip here would have swallowed it instead.
31963196
const fresh = (actionsByObject.get(obj.name) ?? []).filter((action) => !base.includes(action));
31973197
const merged = fresh.length > 0 ? [...base, ...fresh] : base;
@@ -4507,7 +4507,7 @@ function mergeObjects(
45074507
}
45084508

45094509
/**
4510-
* Cross-stack duplicate action keys over the COMPOSED action set (#14662).
4510+
* Cross-stack duplicate action keys over the COMPOSED action set (commit 35dffeace).
45114511
*
45124512
* `defineStack` refuses two declarations that resolve to one scope-qualified
45134513
* runtime key within ONE stack ({@link collectDuplicateActionKeyErrors}), and
@@ -5067,7 +5067,7 @@ function collectArtifactCrossReferenceErrors(
50675067
* stacks declaring *different* values throw an error naming both stacks
50685068
* (#5005; `i18n` joined them in #5051).
50695069
* **Actions** concatenate like every other collection, and the composed set is
5070-
* then checked the way `defineStack` checks one stack (#14662): two input
5070+
* then checked the way `defineStack` checks one stack (commit 35dffeace): two input
50715071
* stacks whose declarations resolve to one scope-qualified runtime key
50725072
* (`objectName:name`, or `global:name` for an object-less action) throw, and
50735073
* the error names both stacks by manifest id and where each declaration sits.
@@ -5290,7 +5290,7 @@ export function composeStacks(
52905290
if (single.declared) composed[key] = single.value;
52915291
}
52925292

5293-
// 6. Cross-stack action key collisions (#14662) — the check `defineStack`
5293+
// 6. Cross-stack action key collisions (commit 35dffeace) — the check `defineStack`
52945294
// runs within one stack, over what composition actually carries. AFTER
52955295
// every collection is composed, and BEFORE `mergeActionsIntoObjects`
52965296
// copies each bound standalone action into its object: that copy is the

0 commit comments

Comments
 (0)