From 74853d73cbd57107edabc474b221a66b4caffe37 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 9 Oct 2026 15:49:21 +0000 Subject: [PATCH 1/3] test(spec): the six reader-bound test strings move with their readers, stating each cited decision in words instead of a tracker number (stage 31) Each needle and every reader site it matched move in lockstep, one span per line: the build-progress module docblock and its two liveness-watch needles, the continueRestoredRun docblock sibling citation, the ./ui notification tombstone label and its anchor, the no-door retirement both ui modules record, and the ComponentPropsMap opaque-member ruling with its assertion. Two class (e) titles that regrew since stage 30 drop a number the title already explains. Text only: no schema shape, key, describe string or behaviour moves. Claude-Session: https://claude.ai/code/session_01DhTqaEHqPVSVnAkjG3jywn Co-authored-by: Claude --- packages/spec/src/ai/build-progress.test.ts | 4 ++-- packages/spec/src/ai/build-progress.zod.ts | 16 ++++++++-------- .../spec/src/automation/end-node-outcome.test.ts | 2 +- .../spec/src/automation/io-node-config.test.ts | 2 +- .../spec/src/contracts/approval-service.test.ts | 2 +- packages/spec/src/contracts/approval-service.ts | 2 +- .../component-props-unknown-members.pin.test.ts | 4 ++-- packages/spec/src/ui/notification.test.ts | 4 ++-- packages/spec/src/ui/notification.zod.ts | 6 +++--- packages/spec/src/ui/sharing.zod.ts | 4 ++-- packages/spec/src/ui/strictness-batch14.test.ts | 2 +- 11 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/spec/src/ai/build-progress.test.ts b/packages/spec/src/ai/build-progress.test.ts index 9add52a3a9d..ba4b916177c 100644 --- a/packages/spec/src/ai/build-progress.test.ts +++ b/packages/spec/src/ai/build-progress.test.ts @@ -233,7 +233,7 @@ describe('module docblock provenance', () => { } // The point of the watch: no gate notices, so the paragraph is the notice. expect(SOURCE).toContain('ADR-0049'); - expect(SOURCE).toContain('cloud#2172'); - expect(SOURCE).toContain('objectui#7388 block 2'); + expect(SOURCE).toContain('the cloud build-progress card'); + expect(SOURCE).toContain('block 2 of the objectui build-panel card'); }); }); diff --git a/packages/spec/src/ai/build-progress.zod.ts b/packages/spec/src/ai/build-progress.zod.ts index d1f4bb211c4..974f47dea2b 100644 --- a/packages/spec/src/ai/build-progress.zod.ts +++ b/packages/spec/src/ai/build-progress.zod.ts @@ -5,7 +5,7 @@ import { lazySchema } from '../shared/lazy-schema'; /** * Build-progress PHASE vocabulary for the `data-build-progress` stream frame - * (cloud#2172 ruling A). + * (the cloud build-progress card, ruling A). * * ## How to read the claims in this module * @@ -24,7 +24,7 @@ import { lazySchema } from '../shared/lazy-schema'; * ## Producer * * The cloud AI-studio **agent loop** — deliberately not the tool it just ran. - * **Declared by ruling**: cloud#2172 ruling A owns WHERE in the loop a frame is + * **Declared by ruling**: the cloud build-progress card's ruling A owns WHERE in the loop a frame is * emitted; this module declares only what such a frame may SAY. * * A build turn applies its change through `apply_blueprint` / `apply_edit` and @@ -74,15 +74,15 @@ import { lazySchema } from '../shared/lazy-schema'; * (**measured on named reachable sources** — each reading is recorded in the * source beside its surface: on `BUILD_PROGRESS_PHASES` for the phase, and on * the `hop` / `tool` field declarations). They stand on a ruling instead - * (**declared by ruling**): cloud#2172 ruled the vocabulary in, and + * (**declared by ruling**): the cloud build-progress card ruled the vocabulary in, and * objectui#7388 asked the panel to be able to name the phase. That is a good * reason, and it is not a measurement. * * ⛔ No gate watches this. The ADR-0049 liveness ledger is rooted in the * metadata-type registry, and `BuildProgressFrame` is not a registered * metadata type, so the liveness job stays green however long these three go - * unused. Two named carriers are meant to close it — cloud#2172 for the - * emitter, objectui#7388 block 2 for the consumer's strict parse. If neither + * unused. Two named carriers are meant to close it — the cloud build-progress card for the + * emitter, block 2 of the objectui build-panel card for the consumer's strict parse. If neither * lands, the three become enforce-or-remove candidates with nothing watching * them, and the only thing that notices is a person reading this paragraph. */ @@ -105,7 +105,7 @@ import { lazySchema } from '../shared/lazy-schema'; * `dda8f3815`; line numbers drift, the two symbols are the anchor. * - `verify` — **declared by ruling**, ⛔ not measured: the post-apply * verification window objectui#7388 asks the panel to be able to name, and - * the reason cloud#2172 ruled this vocabulary into the spec. At objectui + * the reason the cloud build-progress card ruled this vocabulary into the spec. At objectui * `dda8f3815` `packages/plugin-chatbot` has ZERO occurrences of `'verify'` * (bright control, same instrument: `'structure'` hits 4 files there), and * this repository emits no frame at all, so `verify` has no reachable @@ -120,7 +120,7 @@ import { lazySchema } from '../shared/lazy-schema'; * assuming every phase occurs. The two illustrations of a phase being skipped * — a turn that applies no seed data never reporting `data`, and `apply_edit` * turns not reporting `structure` — are **inferred**: no reachable repository - * records either, and cloud#2172's emitter has not landed. ⛔ The guidance + * records either, and the cloud build-progress card's emitter has not landed. ⛔ The guidance * does not rest on them; treat every phase as optional whatever a producer * turns out to do. * @@ -174,7 +174,7 @@ export const BuildProgressFrameSchema = lazySchema(() => z.looseObject({ * * Typed as a non-negative integer rather than pinned to a base: whether the * loop counts its first hop as 0 or 1 is part of the emitter's placement, - * which cloud#2172 owns and this card does not decide. ⛔ Consumers render it + * which the cloud build-progress card owns and this card does not decide. ⛔ Consumers render it * as progress, never as an index into anything here. * * ⛔ Zero emitters and zero readers in every reachable repository at this diff --git a/packages/spec/src/automation/end-node-outcome.test.ts b/packages/spec/src/automation/end-node-outcome.test.ts index b6612ea6039..2d8606c372b 100644 --- a/packages/spec/src/automation/end-node-outcome.test.ts +++ b/packages/spec/src/automation/end-node-outcome.test.ts @@ -64,7 +64,7 @@ describe('EndConfigSchema — the `end` node contract: it may refuse the run wit expect(issue.message).toContain('{{ record.name }}'); }); - it('REFUSES a single-brace token in the `message` — a text slot reads `{{ }}` holes (#22110)', () => { + it('REFUSES a single-brace token in the `message` — a text slot reads `{{ }}` holes', () => { const result = EndConfigSchema.safeParse({ outcome: 'refused', message: 'Refused: {record.name}' }); expect(result.success).toBe(false); if (result.success) return; diff --git a/packages/spec/src/automation/io-node-config.test.ts b/packages/spec/src/automation/io-node-config.test.ts index 0bd8e4ac802..22069c59a06 100644 --- a/packages/spec/src/automation/io-node-config.test.ts +++ b/packages/spec/src/automation/io-node-config.test.ts @@ -469,7 +469,7 @@ describe('NotifyConfigSchema — an unknown key is refused, not stripped', () => } }); - it('refuses a single-brace token left from the 17.x dialect, in either spelling, naming its hole spelling (#22110)', () => { + it('refuses a single-brace token left from the 17.x dialect, in either spelling, naming its hole spelling', () => { for (const key of ['title', 'message'] as const) { for (const value of ['Deal {record.name} won', tmpl`Deal {record.name} won`]) { const label = `${key} = ${JSON.stringify(value)}`; diff --git a/packages/spec/src/contracts/approval-service.test.ts b/packages/spec/src/contracts/approval-service.test.ts index 44472f92ecc..043365757f1 100644 --- a/packages/spec/src/contracts/approval-service.test.ts +++ b/packages/spec/src/contracts/approval-service.test.ts @@ -271,7 +271,7 @@ describe('continueRestoredRun — the approvals operator repair verb, declared', const doc = source.slice(source.lastIndexOf('/**', at), at); // The sibling this was ruled to copy, named where a later author reads it. - expect(doc).toContain('#16495'); + expect(doc).toContain('the automation-service contract'); // What the engine verb leaves undone, which is the whole reason this exists. expect(doc).toMatch(/the[\s*]+continuation[\s*]+must[\s*]+be[\s*]+re-issued/); // ⛔ It replays a recorded outcome; it does not re-decide. diff --git a/packages/spec/src/contracts/approval-service.ts b/packages/spec/src/contracts/approval-service.ts index 4b458e36cc5..e9a06b0c6ca 100644 --- a/packages/spec/src/contracts/approval-service.ts +++ b/packages/spec/src/contracts/approval-service.ts @@ -996,7 +996,7 @@ export interface IApprovalService { /** * **Operator verb — re-issue the continuation for a run an operator has * re-armed** (#15389; the maintainer ruling of 2026-09-09, decision batch - * #106 item 3, declared here exactly as #16495 declared + * #106 item 3, declared here exactly as the automation-service contract declared * `IAutomationService.cancelRun` / `restoreConsumedSuspension`). * * The missing half of `IAutomationService.restoreConsumedSuspension`, for diff --git a/packages/spec/src/ui/component-props-unknown-members.pin.test.ts b/packages/spec/src/ui/component-props-unknown-members.pin.test.ts index 04babefd5cc..c4c152136a8 100644 --- a/packages/spec/src/ui/component-props-unknown-members.pin.test.ts +++ b/packages/spec/src/ui/component-props-unknown-members.pin.test.ts @@ -319,7 +319,7 @@ on(['object-grid'], ['pagination.*'], { // none. on(['object-timeline'], ['items[].content'], { kind: 'opaque', - ruling: 'decision card #21704, fork 4, letter B (record 5979239990)', + ruling: 'decision card on the five members the last typing stage stopped on, fork 4, letter B (record 5979239990)', why: 'child schema nodes no measured writer authors; it becomes a slot position the page walks judge once one does', }); @@ -414,7 +414,7 @@ describe('§2 each recorded reason holds', () => { expect(opaque.map(([key]) => key)).toEqual(['object-timeline items[].content']); for (const [key, reason] of opaque) { expect(members.get(key)?.describe ?? '', key).toMatch(/Held opaque/); - expect(reason.kind === 'opaque' && reason.ruling, key).toMatch(/#21704/); + expect(reason.kind === 'opaque' && reason.ruling, key).toMatch(/the five members the last typing stage stopped on/); } }); diff --git a/packages/spec/src/ui/notification.test.ts b/packages/spec/src/ui/notification.test.ts index 1ca8001fe09..d054f485c00 100644 --- a/packages/spec/src/ui/notification.test.ts +++ b/packages/spec/src/ui/notification.test.ts @@ -120,7 +120,7 @@ describe('./ui notification tombstone — corrected evidence, no false FROM → */ const tombstone = (() => { const source = fs.readFileSync(SOURCE, 'utf8'); - const start = source.indexOf('// [#4610]'); + const start = source.indexOf('// [dual-source removal]'); return source .slice(start) .split('\n') @@ -131,7 +131,7 @@ describe('./ui notification tombstone — corrected evidence, no false FROM → })(); it('finds the tombstone note at all (anti-vacuity)', () => { - expect(tombstone).toMatch(/^\[#4610\]/); + expect(tombstone).toMatch(/^\[dual-source removal\]/); expect(tombstone).toMatch(/NotificationConfigSchema/); expect(tombstone.length).toBeGreaterThan(800); }); diff --git a/packages/spec/src/ui/notification.zod.ts b/packages/spec/src/ui/notification.zod.ts index 859328886fd..ec3266bc2e3 100644 --- a/packages/spec/src/ui/notification.zod.ts +++ b/packages/spec/src/ui/notification.zod.ts @@ -45,7 +45,7 @@ export const NotificationPositionSchema = lazySchema(() => z.enum([ export type NotificationPosition = z.input; -// [#5015] `NotificationActionSchema` / `NotificationAction` were REMOVED per +// [no-door retirement] `NotificationActionSchema` / `NotificationAction` were REMOVED per // ADR-0049 enforce-or-remove, ruled REMOVE on 2026-08-04. // // The shape declared an interactive action button inside a notification — @@ -91,7 +91,7 @@ export type NotificationPosition = z.input; // enforce route of ADR-0049 — a carrier key on a real metadata type, with a // renderer that reads it, in one change. Vocabulary second, never first. -// [#4610] `NotificationSchema` / `Notification` and `NotificationConfigSchema` +// [dual-source removal] `NotificationSchema` / `Notification` and `NotificationConfigSchema` // / `NotificationConfig` were removed from this module (dual-source cleanup, // #4535 C3). The bare name `Notification(Schema)` now belongs to // `@objectstack/spec/api` alone: the REST inbox-row contract served by @@ -100,7 +100,7 @@ export type NotificationPosition = z.input; // `./system` twin was wired into no parent schema and contradicted ADR-0030's // accepted delivery model. What survives on this module is the presentation // vocabulary above: `NotificationType` / `NotificationSeverity` / -// `NotificationPosition` — three enums, not four, since #5015 took +// `NotificationPosition` — three enums, not four, since the no-door retirement took // `NotificationAction` — which objectui's toaster reads as a vocabulary. // // ⚠️ [#5781] The retirement STANDS; the evidence #4610 published for it does diff --git a/packages/spec/src/ui/sharing.zod.ts b/packages/spec/src/ui/sharing.zod.ts index f23cdd48460..e5bdd28da98 100644 --- a/packages/spec/src/ui/sharing.zod.ts +++ b/packages/spec/src/ui/sharing.zod.ts @@ -21,7 +21,7 @@ * `@objectstack/metadata-core` re-exports to the server's doors). Both * example apps author it (`app-showcase` `inquiry.view.ts`, `app-crm` * `lead.view.ts`). It is `strictObject` as of #4001 批 14. - * - `EmbedConfigSchema` was **REMOVED** at #5015 (ADR-0049 enforce-or-remove) — + * - `EmbedConfigSchema` was **REMOVED** at the no-door retirement (ADR-0049 enforce-or-remove) — * see the block below where it stood. * * The ledger's classification question is *"who writes this schema's input?"*, @@ -111,7 +111,7 @@ export const SharingConfigSchema = lazySchema(() => strictObject({ .describe('Allow access without authentication'), })); -// [#5015] `EmbedConfigSchema` / `EmbedConfig` were REMOVED per ADR-0049 +// [no-door retirement] `EmbedConfigSchema` / `EmbedConfig` were REMOVED per ADR-0049 // enforce-or-remove, ruled REMOVE on 2026-08-04. // // The shape described iframe embedding of an app, page or form — `enabled`, diff --git a/packages/spec/src/ui/strictness-batch14.test.ts b/packages/spec/src/ui/strictness-batch14.test.ts index d2adcb86add..b214cabc793 100644 --- a/packages/spec/src/ui/strictness-batch14.test.ts +++ b/packages/spec/src/ui/strictness-batch14.test.ts @@ -392,7 +392,7 @@ describe('批 14 — the file that split, after its dead half was retired', () = const notification = fs.readFileSync(path.join(SPEC_SRC, 'ui/notification.zod.ts'), 'utf8'); const sharing = fs.readFileSync(path.join(SPEC_SRC, 'ui/sharing.zod.ts'), 'utf8'); for (const source of [notification, sharing]) { - expect(source).toContain('#5015'); + expect(source).toContain('no-door retirement'); expect(source).toContain('ADR-0049'); } // The surviving module still explains its own live door, so a later reader From fbec38c32957f11ed194a8d96ed52fba5b54df38 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 9 Oct 2026 15:53:58 +0000 Subject: [PATCH 2/3] docs(spec): regenerate the build-progress and sharing reference pages from their docblocks, and add the patch changeset (stage 31) gen:docs output only: the two pages follow the module docblocks that now name their decisions in words. The changeset records the shipped comment text. Claude-Session: https://claude.ai/code/session_01DhTqaEHqPVSVnAkjG3jywn Co-authored-by: Claude --- .changeset/20749-reader-needles-in-words.md | 16 ++++++++++++++++ content/docs/references/ai/build-progress.mdx | 12 ++++++------ content/docs/references/ui/sharing.mdx | 2 +- 3 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 .changeset/20749-reader-needles-in-words.md diff --git a/.changeset/20749-reader-needles-in-words.md b/.changeset/20749-reader-needles-in-words.md new file mode 100644 index 00000000000..30f646beea6 --- /dev/null +++ b/.changeset/20749-reader-needles-in-words.md @@ -0,0 +1,16 @@ +--- +'@objectstack/spec': patch +--- + +Source comments that cited a tracker number now say in words which decision they mean, and the pin tests that read those comments match the new words + +Clause-②: no + +The package ships its `src/**/*.zod.ts` sources, and `dist` carries the member docblocks. Four of those texts named a decision only by its tracker number. Each now names the decision in words. The pin test that reads each text matches the new words, at the places the old number stood: + +- `ai/build-progress.zod.ts`: the cloud card that ruled the build-progress phase vocabulary in, and that owns where the emitter sits, is now "the cloud build-progress card" in all seven places. The consumer's strict-parse carrier is "block 2 of the objectui build-panel card". The `ai/build-progress` reference page is regenerated from the module docblock, so its description now ends with "(the cloud build-progress card, ruling A)". +- `contracts/approval-service.ts`: the `IApprovalService.continueRestoredRun` docblock says the verb is declared "exactly as the automation-service contract declared" `IAutomationService.cancelRun` / `restoreConsumedSuspension`. +- `ui/notification.zod.ts`: the tombstone note for the removed `./ui` `Notification` / `NotificationConfig` wrappers is labelled `[dual-source removal]`. The `NotificationAction` removal is called "the no-door retirement". +- `ui/sharing.zod.ts`: `EmbedConfigSchema` is recorded as removed "at the no-door retirement (ADR-0049 enforce-or-remove)". The `ui/sharing` reference page is regenerated from the module docblock. + +Comments and docblocks only. No key, type, default, accepted value, `.describe()` string or export changes. diff --git a/content/docs/references/ai/build-progress.mdx b/content/docs/references/ai/build-progress.mdx index 750ef34cf44..059fe43db7a 100644 --- a/content/docs/references/ai/build-progress.mdx +++ b/content/docs/references/ai/build-progress.mdx @@ -1,13 +1,13 @@ --- title: Build Progress schema — AI Protocol reference navTitle: Build Progress -description: "Build-progress PHASE vocabulary for the data-build-progress stream frame." +description: "Build-progress PHASE vocabulary for the data-build-progress stream frame (the cloud build-progress card, ruling A)." --- {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} Build-progress PHASE vocabulary for the `data-build-progress` stream frame -(cloud#2172 ruling A). +(the cloud build-progress card, ruling A). ## How to read the claims in this module @@ -26,7 +26,7 @@ therefore carries exactly one of three labels, and none is left bare: ## Producer The cloud AI-studio **agent loop** — deliberately not the tool it just ran. -**Declared by ruling**: cloud#2172 ruling A owns WHERE in the loop a frame is +**Declared by ruling**: the cloud build-progress card's ruling A owns WHERE in the loop a frame is emitted; this module declares only what such a frame may SAY. A build turn applies its change through `apply_blueprint` / `apply_edit` and @@ -76,15 +76,15 @@ repository reachable from here they have zero emitters and zero readers (**measured on named reachable sources** — each reading is recorded in the source beside its surface: on `BUILD_PROGRESS_PHASES` for the phase, and on the `hop` / `tool` field declarations). They stand on a ruling instead -(**declared by ruling**): cloud#2172 ruled the vocabulary in, and +(**declared by ruling**): the cloud build-progress card ruled the vocabulary in, and objectui#7388 asked the panel to be able to name the phase. That is a good reason, and it is not a measurement. ⛔ No gate watches this. The ADR-0049 liveness ledger is rooted in the metadata-type registry, and `BuildProgressFrame` is not a registered metadata type, so the liveness job stays green however long these three go -unused. Two named carriers are meant to close it — cloud#2172 for the -emitter, objectui#7388 block 2 for the consumer's strict parse. If neither +unused. Two named carriers are meant to close it — the cloud build-progress card for the +emitter, block 2 of the objectui build-panel card for the consumer's strict parse. If neither lands, the three become enforce-or-remove candidates with nothing watching them, and the only thing that notices is a person reading this paragraph. diff --git a/content/docs/references/ui/sharing.mdx b/content/docs/references/ui/sharing.mdx index 6c8af4e8eab..912362d5c9e 100644 --- a/content/docs/references/ui/sharing.mdx +++ b/content/docs/references/ui/sharing.mdx @@ -24,7 +24,7 @@ asymmetry survives as the reason this file reads the way it does: `@objectstack/metadata-core` re-exports to the server's doors). Both example apps author it (`app-showcase` `inquiry.view.ts`, `app-crm` `lead.view.ts`). It is `strictObject` as of #4001 批 14. -- `EmbedConfigSchema` was **REMOVED** at #5015 (ADR-0049 enforce-or-remove) — +- `EmbedConfigSchema` was **REMOVED** at the no-door retirement (ADR-0049 enforce-or-remove) — see the block below where it stood. The ledger's classification question is *"who writes this schema's input?"*, From a766d439f48953f3404f6d3d7afed0cd2617ada1 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 9 Oct 2026 16:36:44 +0000 Subject: [PATCH 3/3] test(spec): the attachedOnRead ledger reason cites its ruling by record and letter, without a tracker number (stage 31 patch round) One span on one line: the why value keeps ruling record 6070963704 and says letter A in place of the card number. Text only; no assertion reads the text. Claude-Session: https://claude.ai/code/session_01DhTqaEHqPVSVnAkjG3jywn Co-authored-by: Claude --- .../spec/src/system/metadata-form-zod-reconciliation.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/spec/src/system/metadata-form-zod-reconciliation.test.ts b/packages/spec/src/system/metadata-form-zod-reconciliation.test.ts index 1ea5190ed65..fc09e28ce9e 100644 --- a/packages/spec/src/system/metadata-form-zod-reconciliation.test.ts +++ b/packages/spec/src/system/metadata-form-zod-reconciliation.test.ts @@ -494,7 +494,7 @@ const LEDGER: ReadonlyArray = [ type: 'object', path: ROOT_PATH, key: 'attachedOnRead', - why: "not a form's to offer, by ruling (ruling record 6070963704, #22211 A): the blocks a service attaches to the rows it serves, computed per caller and never stored, which the ruling says no form reads; a block is declared in code beside the service that attaches it (plugin-approvals' `viewer` on `sys_approval_request`), because nothing authored in a designer can make a service attach a block, and its one reader is the shared build validator", + why: "not a form's to offer, by ruling (ruling record 6070963704, letter A): the blocks a service attaches to the rows it serves, computed per caller and never stored, which the ruling says no form reads; a block is declared in code beside the service that attaches it (plugin-approvals' `viewer` on `sys_approval_request`), because nothing authored in a designer can make a service attach a block, and its one reader is the shared build validator", }, { kind: 'omit',