From 8e4b67fc5abe3ef47faad8869653547932ccac21 Mon Sep 17 00:00:00 2001 From: Serhii Tatarintsev Date: Mon, 13 Jul 2026 09:46:00 +0000 Subject: [PATCH 1/3] =?UTF-8?q?TML-2984:=20scope=20addition=20M2b=20?= =?UTF-8?q?=E2=80=94=20contractSpace=20lifted=20to=20core=20descriptor=20(?= =?UTF-8?q?spec+plan=20amended,=20slice=2003=20authored)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Serhii Tatarintsev --- .../lsp-interpreter-diagnostics/plans/plan.md | 23 ++++++ .../briefs/d1-r1.md | 57 +++++++++++++ .../03-contractspace-core-descriptor/spec.md | 82 +++++++++++++++++++ projects/lsp-interpreter-diagnostics/spec.md | 23 ++++++ .../lsp-interpreter-diagnostics/trace.jsonl | 5 ++ 5 files changed, 190 insertions(+) create mode 100644 projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/briefs/d1-r1.md create mode 100644 projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/spec.md diff --git a/projects/lsp-interpreter-diagnostics/plans/plan.md b/projects/lsp-interpreter-diagnostics/plans/plan.md index b5084fc0be..e0ca65f52c 100644 --- a/projects/lsp-interpreter-diagnostics/plans/plan.md +++ b/projects/lsp-interpreter-diagnostics/plans/plan.md @@ -74,6 +74,8 @@ Derived from the Project DoD (AC numbers = DoD order) and cross-cutting requirem | TC-16 | Playground manual QA: unresolvable relation appears live positioned on the span, disappears on fix, no restart; config break/fix cycle on the config URI | AC1, AC9 (manual halves) | | TC-17 | `pnpm lint:deps` green with the new psl-parser → config edge; cast-ratchet count unchanged | AC6 | +| TC-18 | Core `ControlExtensionDescriptor` declares `contractSpace?: ContractSpace`; both family overrides compile as covariant narrowings; `assembleExtensionContracts` + load-order reads use typed access; tightened grep gate: zero `contractJson` casts repo-wide | AC12 (scope addition) | + _TC-15 (end-to-end parity test, former AC2) dropped by operator decision (2026-07-09); the spec's DoD is amended accordingly. Build/editor parity is held by construction (one shared inner interpretation function per provider, pinned by TC-4/TC-6), span @@ -145,6 +147,27 @@ stack-shaped objects surface via typecheck and gain the new property. - [ ] Gate: existing emit/e2e tests, `pnpm fixtures:check`, `pnpm lint:deps`, cast-ratchet ≤ baseline +### Implement M2b: contractSpace declared on the core extension descriptor + +**Status:** ► In progress — slice 03, stacked on slice 02 (scope addition, operator-authorized 2026-07-10) + +_Outcomes_ +Core `ControlExtensionDescriptor` carries `contractSpace?: ContractSpace`; sql + mongo +overrides remain as covariant narrowings; the `assembleExtensionContracts` `blindCast` +and the structural descriptor views in `control-stack.ts` are deleted — typed access +end-to-end; the grep gate tightens from "outside framework-components" to "nowhere". +`extensionContracts` stays the consumer surface; only its construction changes. + +**Shipping strategy:** type-level addition; optional member, so every existing +descriptor remains valid; families' narrowed overrides are already assignable. +Behavior identical by construction (same values, typed instead of cast). + +**Tasks:** + +- [ ] Declare the member in core; delete the cast + structural views; verify the + `MigrationPackage` fit and whether the load-order dependency view can go typed; + tighten the grep-library gate (satisfies: TC-18) + ### Implement M3: Providers implement the capability (sql + mongo) **Status:** ☐ Not started diff --git a/projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/briefs/d1-r1.md b/projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/briefs/d1-r1.md new file mode 100644 index 0000000000..7d89677d5a --- /dev/null +++ b/projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/briefs/d1-r1.md @@ -0,0 +1,57 @@ +# Brief: S3-D1 — lift contractSpace declaration to core, delete the bridges + +## Task + +Declare `readonly contractSpace?: ContractSpace;` on `ControlExtensionDescriptor` +(`packages/1-framework/1-core/framework-components/src/control/control-descriptors.ts:80`, +importing `ContractSpace` from `./control-spaces`). Then delete the bridges the +missing declaration forced in `control-stack.ts`: remove +`ContractSpaceCarryingDescriptor`; make `assembleExtensionContracts` read +`descriptor.contractSpace?.contractJson` typed and **delete its `blindCast`**. +Investigate the load-order view (`DependencyDeclaringDescriptor`): if `Contract`'s +type exposes `extensionPacks` usably, type that read too and delete the view; if not, +keep it and state why in your report (no code comment needed). Type tests first: pin +that (a) sql + mongo family descriptors remain assignable to +`ControlExtensionDescriptor` with their narrowed `contractSpace`, (b) typed access to +`contractSpace.contractJson` yields `Contract` without casts, (c) family overrides +still compile (their descriptor-self-consistency suites are the proof). + +Tighten the grep-library gate (`drive/calibration/grep-library.md` § Contract-cast +hygiene): scope becomes "zero `contractSpace.contractJson` casts **anywhere**" — +drop the framework-components exclusion; keep the positive-control note (against the +pre-change tree, e.g. `git show` of the parent commit). Verify both directions. + +## Scope + +**In:** `packages/1-framework/1-core/framework-components/` (control-descriptors, +control-stack, tests); `drive/calibration/grep-library.md`; family packages ONLY if +typecheck demands (expected: zero changes — their overrides are already narrowings). +**Out:** `toExtensionInputs` and all CLI code (its `readonly unknown[]` boundary is a +separate concern); extension pack descriptor construction sites; `projects/**`; +behavior of any kind. + +## Completed when + +- [ ] Core declaration in place; `ContractSpaceCarryingDescriptor` gone; + `assembleExtensionContracts` cast-free; zero `contractJson` casts repo-wide. +- [ ] Load-order view either typed (view deleted) or kept-with-reason in the report. +- [ ] Type tests pin the covariant narrowing + typed access; family suites green + unchanged. +- [ ] Tightened gate documented + passing, with positive control. + +## Standing instruction + +Stay focused on the goal; control scope. If a variance snag surfaces in the family +overrides (e.g. an invariant generic), **halt and surface — do not loosen family +typing or widen core's member type.** + +## References + +- Slice spec: `projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/spec.md` +- Project spec § Place in the larger world (scope-addition bullet). + +## Operational metadata + +- **Time-box:** 45 min. Halt conditions: family override variance snag; descriptor + migrations fail `MigrationPackage` typing (the dirPath wrinkle materializing); + the declaration forces changes outside framework-components beyond type-test files. diff --git a/projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/spec.md b/projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/spec.md new file mode 100644 index 0000000000..e8e76f6c34 --- /dev/null +++ b/projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/spec.md @@ -0,0 +1,82 @@ +# Slice 03 — contractSpace declared on the core extension descriptor + +**Project:** [`../../spec.md`](../../spec.md) · **Project plan:** [`../../plans/plan.md`](../../plans/plan.md) § M2b · **Linear:** TML-2984 +**Stacked on:** slice 02 (`tml-2984-slice-02-extension-contracts`, PR #948) — consumes `extensionContracts` machinery it makes cast-free. + +## Design (operator-authorized scope addition, 2026-07-10) + +`ContractSpace` already lives in core +(`framework-components/src/control/control-spaces.ts:77` — "contract-space identity +is a framework concept, not a SQL-specific one"). Both families declare the identical +optional member, pinning only the storage generic +(`SqlControlExtensionDescriptor` → `ContractSpace>`, +`MongoControlExtensionDescriptor` → `ContractSpace>`). +The missing piece is the declaration site: + +1. **Core `ControlExtensionDescriptor`** (`framework-components/src/control/control-descriptors.ts:80`) + gains `readonly contractSpace?: ContractSpace;` (default generic). Optional member + → every existing descriptor stays valid; family overrides are covariant readonly + narrowings and must keep compiling unchanged. +2. **`control-stack.ts` sheds its structural bridges**: `ContractSpaceCarryingDescriptor` + is deleted and `assembleExtensionContracts` reads `descriptor.contractSpace.contractJson` + typed — **the `blindCast` goes**. The load-order view + (`DependencyDeclaringDescriptor`, reads `contractJson.extensionPacks`) goes typed + too **iff** the `Contract` type exposes `extensionPacks` with a usable shape; + otherwise it stays and the slice records why (in-code comment is not needed — the + report suffices). +3. **Grep gate tightens** in `drive/calibration/grep-library.md`: from "no + `contractSpace.contractJson` casts outside framework-components" to "none anywhere". +4. **Out of scope:** `toExtensionInputs` (its cast is a `readonly unknown[]` API + boundary, a separate concern); descriptor construction sites in extension packs; + any behavioral change. + +## Coherence rationale + +One reviewable PR: "declare in core what both families already agree on, and delete +the bridges the gap forced." Type-level only; bit-identical behavior by construction +(same values flow, typed instead of cast). + +## Slice Definition of Done (beyond CI / reviewer / project-DoD) + +- [ ] SDoD1 — Core `ControlExtensionDescriptor` declares `contractSpace?: ContractSpace`; + sql + mongo overrides compile unchanged (their existing + descriptor-self-consistency suites stay green); type test pins the covariant + narrowing (family descriptor assignable where core descriptor is expected, with + typed `contractSpace` access). +- [ ] SDoD2 — Zero `contractJson` casts repo-wide: `assembleExtensionContracts` + cast-free, `ContractSpaceCarryingDescriptor` deleted; tightened grep gate + documented and passing (with positive control against pre-change tree). +- [ ] SDoD3 — Load-order dependency view either typed (if `Contract.extensionPacks` + admits it) or explicitly reported as kept-with-reason. +- [ ] SDoD4 — `MigrationPackage` fit verified: both families' shipped descriptor + migrations satisfy core's `ContractSpace.migrations` (typecheck is the proof; + any wrinkle surfaces, not worked around). + +## Edge cases (pre-investigated) + +- The families' overrides re-declare the member; TypeScript requires override + compatibility, not identity — `ContractSpace>` must be + assignable to `ContractSpace` (readonly members, covariance holds if + `Contract` extends `Contract`'s default). If a variance snag surfaces + (e.g. invariant generic in `MigrationPackage`), halt — do not loosen family typing. +- The CLI's `DescriptorMigrationPackage` mirror ("minus `dirPath`") hints descriptor + migrations may be in-memory; but both families already type their member as + `ContractSpace<…>` today, so their descriptors already satisfy `MigrationPackage` — + expected non-issue, verify via typecheck. + +## Dispatch plan + +Single dispatch. + +### S3-D1 — lift the declaration, delete the bridges + +- **Outcome:** the § Design list, complete; SDoD1–4. +- **Builds on:** slice 02 (`assembleExtensionContracts`). +- **Hands to:** M3+ (cleaner base; no API change for them). +- **Focus:** `packages/1-framework/1-core/framework-components/` (descriptor + stack + + tests); `drive/calibration/grep-library.md`; family packages only if typecheck + demands (expected: no changes). +- **Gate:** `pnpm --filter @prisma-next/framework-components test` + typecheck + lint, + family descriptor-self-consistency suites + (`pnpm --filter @prisma-next/family-sql test`, `pnpm --filter @prisma-next/family-mongo test`), + `pnpm typecheck`, `pnpm test:packages`, `pnpm lint:deps`, tightened grep gate. diff --git a/projects/lsp-interpreter-diagnostics/spec.md b/projects/lsp-interpreter-diagnostics/spec.md index fa9029dd3b..4f6a5edaaf 100644 --- a/projects/lsp-interpreter-diagnostics/spec.md +++ b/projects/lsp-interpreter-diagnostics/spec.md @@ -159,6 +159,16 @@ graph TD module needed; the CLI's inline blindCasts are deleted and the one unavoidable `contractJson → Contract` cast lives in framework-components only (settled by operator, 2026-07-09). +- **Contract-space declaration lift** _(scope addition, operator-authorized 2026-07-10)_: + `ContractSpace` is already a framework-level type + (`framework-components/control/control-spaces.ts:77`, "contract-space identity is a + framework concept"), yet core's `ControlExtensionDescriptor` never declared the + member — both families declare identical `contractSpace?: ContractSpace<…>` overrides, + and every consumer bridges the gap with structural casts. The core descriptor gains + `contractSpace?: ContractSpace`; family overrides stay as covariant narrowings; the + `assembleExtensionContracts` blindCast and `control-stack.ts` structural views are + deleted (typed access). Verify in-slice: descriptors' shipped migrations satisfy + `MigrationPackage`; whether the load-order dependency view can go typed. - **Language server** (`packages/1-framework/3-tooling/language-server/`): consumes the guard + capability; `config-resolution.ts` grows the context construction (property picks off the control stack), `pipeline.ts` grows the interpret stage, @@ -265,6 +275,10 @@ durable and reusable. Commit: author an ADR (or a pattern doc under test). - [ ] ADR / pattern doc for the capability-intersection pattern authored and linked from `docs/architecture docs/`. +- [ ] Core `ControlExtensionDescriptor` declares `contractSpace?: ContractSpace`; + family overrides compile as narrowings; zero `contractJson` casts remain + anywhere in the repo (grep gate tightened accordingly). _(Scope addition, + operator-authorized 2026-07-10.)_ ## Open Questions @@ -288,6 +302,15 @@ function in `@prisma-next/config`, helper in config-loader, inline-in-both (adds Also settled: tracked as Linear issue TML-2984 (not a Linear Project); done when merged to `main`, no release cut._ +_Settled by operator (2026-07-10, mid-flight): scope addition — lift the +`contractSpace` member declaration to core `ControlExtensionDescriptor`. Triggered by +the operator's design challenge ("contract spaces should be framework-level"); code +review confirmed `ContractSpace` already lives in core and only the declaration site +was family-level — the orchestrator's earlier "hoisting family shape into core" +framing during OF1 was overstated and is corrected. Runs as its own slice stacked on +slice 02; `extensionContracts` (M2) remains the consumer surface — the lift makes its +construction cast-free._ + _Settled by operator (2026-07-09, plan refinement): the end-to-end parity-test DoD item ("LSP diagnostic set equals `contract emit` diagnostic set, demonstrated by a parity test") is dropped. Build/editor parity remains a cross-cutting requirement diff --git a/projects/lsp-interpreter-diagnostics/trace.jsonl b/projects/lsp-interpreter-diagnostics/trace.jsonl index bf04f637b7..9cca52967e 100644 --- a/projects/lsp-interpreter-diagnostics/trace.jsonl +++ b/projects/lsp-interpreter-diagnostics/trace.jsonl @@ -37,3 +37,8 @@ {"event_id":"5d20062b-3657-4a0b-a0ca-5971a8b875d5","schema_version":"1","ts":"2026-07-10T15:36:36.537Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"falsified-assumption","assumption_summary":"contract-emit.ts is the only inline ContractSourceContext assembly (project spec, Place in the larger world) — client.ts held a byte-identical twin incl. both blindCasts; both collapsed to stack.extensionContracts in S2-D2, net cast delta -3","triggered_by":"orchestrator-self-detected","artifact_path":"projects/lsp-interpreter-diagnostics/learnings.md"} {"event_id":"b27b34ea-f26f-4641-b9b5-585de1beb470","schema_version":"1","ts":"2026-07-10T15:40:42.006Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"round-end","dispatch_id":"c7d18402-8963-4933-85f5-340e051c8e58","round_id":"fdbc15e1-9104-44a6-9de9-7174cd8fd5d0","verdict":"satisfied","findings_filed":0,"wall_clock_ms":3300000} {"event_id":"73e0935c-5dc5-4ba6-8e1d-7ad55b0593e1","schema_version":"1","ts":"2026-07-10T15:40:42.479Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"dispatch-end","dispatch_id":"c7d18402-8963-4933-85f5-340e051c8e58","result":"completed","wall_clock_ms":3300000} +{"event_id":"d306921d-ea4f-40c0-b472-7325e9c40b5d","schema_version":"1","ts":"2026-07-13T09:45:11.463Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"spec-amended","spec_path":"projects/lsp-interpreter-diagnostics/spec.md","spec_kind":"project","byte_length":22251,"bytes_delta":1907,"reason":"operator-correction","sections_changed":["Place in the larger world","Project Definition of Done","Open Questions"],"edge_cases_count":null,"open_questions_count":0,"dod_items_count":13} +{"event_id":"776b7b07-43ac-4779-9119-adf6a8895c87","schema_version":"1","ts":"2026-07-13T09:45:28.096Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"plan-amended","plan_path":"projects/lsp-interpreter-diagnostics/plans/plan.md","plan_kind":"project","byte_length":18552,"bytes_delta":1485,"reason":"operator-correction","dispatch_count":null,"slice_count":7,"dispatch_size_distribution":null,"dispatches_added":null,"dispatches_removed":null,"dispatches_resized":null,"open_items_count":0} +{"event_id":"f3aad824-88e5-4c00-b702-69efcaeb7362","schema_version":"1","ts":"2026-07-13T09:45:28.704Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"slice-started","slice_slug":"m2b-contractspace-core-descriptor","slice_index":3,"linear_ref":"TML-2984"} +{"event_id":"3bef2c11-5e73-49c0-a987-c9f9e1310e5b","schema_version":"1","ts":"2026-07-13T09:45:29.364Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"spec-authored","spec_path":"projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/spec.md","spec_kind":"slice","byte_length":4908,"edge_cases_count":2,"open_questions_count":0,"dod_items_count":4} +{"event_id":"682d13fa-274c-43b4-9dc6-c895afcce0c0","schema_version":"1","ts":"2026-07-13T09:45:29.947Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"plan-authored","plan_path":"projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/spec.md","plan_kind":"slice","byte_length":4908,"dispatch_count":1,"slice_count":null,"dispatch_size_distribution":{"S":0,"M":1,"L":0,"XL":0},"open_items_count":0} From 2c3c1de7994d05518becb7adc50834105b0b91e1 Mon Sep 17 00:00:00 2001 From: Serhii Tatarintsev Date: Mon, 13 Jul 2026 09:54:17 +0000 Subject: [PATCH 2/3] TML-2984: declare contractSpace on the core extension descriptor ContractSpace was already a framework-level type; only the declaration site was family-level. ControlExtensionDescriptor now carries the optional member, families keep their storage-narrowed overrides, and the ControlStack bridges fall: ContractSpaceCarryingDescriptor is gone and assembleExtensionContracts property-picks a typed contractJson with no cast. Grep gate tightened: contractSpace.contractJson casts are forbidden repo-wide, both reach-through and picked-variable forms. Signed-off-by: Serhii Tatarintsev --- drive/calibration/grep-library.md | 13 ++++--- .../src/control/control-descriptors.ts | 2 ++ .../src/control/control-stack.ts | 22 +++--------- .../test/control-descriptors.types.test-d.ts | 36 +++++++++++++++++++ 4 files changed, 51 insertions(+), 22 deletions(-) create mode 100644 packages/1-framework/1-core/framework-components/test/control-descriptors.types.test-d.ts diff --git a/drive/calibration/grep-library.md b/drive/calibration/grep-library.md index 1c39f04c82..e522fb33d4 100644 --- a/drive/calibration/grep-library.md +++ b/drive/calibration/grep-library.md @@ -33,13 +33,16 @@ rg 'tables:\s*\{\s*[a-z][A-Za-z_]+\s*:' packages/ -g '*.test.ts' -g '*.test-d.ts ## Contract-cast hygiene ```bash -# Descriptor contractSpace.contractJson → Contract casts outside framework-components (forbidden): -# ControlStack owns the one sanctioned narrowing (extensionContracts assembly in -# control-stack.ts); consumers property-pick composed contracts from the stack -# instead of re-deriving them from extension descriptors. -U catches multi-line casts. +# Descriptor contractSpace.contractJson → Contract casts — forbidden anywhere: +# ControlExtensionDescriptor declares contractSpace: ContractSpace (typed contractJson), +# so every consumer — including ControlStack's extensionContracts assembly — property-picks; +# no narrowing cast is sanctioned anymore. -U catches multi-line casts. +# Form 1: reach-through (blindCast<...>(x.contractSpace.contractJson)): +rg -U 'blindCast<[^(]*\([^)]*contractSpace!?\??\.contractJson' packages/ +# Form 2: picked-variable (const contractJson = ...; blindCast<...>(contractJson)): +rg -U 'blindCast<[^(]*\(\s*contractJson\s*\)' packages/ # (Casts of other contractJson values — e.g. a query-builder accepting user-supplied # contract JSON at its API boundary — are separate boundaries, not this anti-pattern.) -rg -U 'blindCast<[^(]*\([^)]*contractSpace!?\??\.contractJson' packages/ -g '!**/1-core/framework-components/**' ``` ## Cross-cutting anti-patterns diff --git a/packages/1-framework/1-core/framework-components/src/control/control-descriptors.ts b/packages/1-framework/1-core/framework-components/src/control/control-descriptors.ts index b4af51a67f..696d390dc0 100644 --- a/packages/1-framework/1-core/framework-components/src/control/control-descriptors.ts +++ b/packages/1-framework/1-core/framework-components/src/control/control-descriptors.ts @@ -14,6 +14,7 @@ import type { ControlFamilyInstance, ControlTargetInstance, } from './control-instances'; +import type { ContractSpace } from './control-spaces'; import type { ControlStack } from './control-stack'; import type { EmissionSpi } from './emission-types'; @@ -85,5 +86,6 @@ export interface ControlExtensionDescriptor< TTargetId > = ControlExtensionInstance, > extends ExtensionDescriptor { + readonly contractSpace?: ContractSpace; create(): TExtensionInstance; } diff --git a/packages/1-framework/1-core/framework-components/src/control/control-stack.ts b/packages/1-framework/1-core/framework-components/src/control/control-stack.ts index 75e71be4bf..9ba57dea82 100644 --- a/packages/1-framework/1-core/framework-components/src/control/control-stack.ts +++ b/packages/1-framework/1-core/framework-components/src/control/control-stack.ts @@ -433,27 +433,15 @@ interface DependencyDeclaringDescriptor { }; } -interface ContractSpaceCarryingDescriptor { - readonly id: string; - readonly contractSpace?: { - readonly contractJson?: unknown; - }; -} - function assembleExtensionContracts( - extensions: ReadonlyArray, + extensions: ReadonlyArray< + Pick, 'id' | 'contractSpace'> + >, ): ReadonlyMap { const result = new Map(); for (const ext of extensions) { - const contractJson = ext.contractSpace?.contractJson; - if (contractJson === undefined) continue; - result.set( - ext.id, - blindCast< - Contract, - 'contractSpace.contractJson is the emitted, validated contract for this extension space' - >(contractJson), - ); + if (ext.contractSpace === undefined) continue; + result.set(ext.id, ext.contractSpace.contractJson); } return result; } diff --git a/packages/1-framework/1-core/framework-components/test/control-descriptors.types.test-d.ts b/packages/1-framework/1-core/framework-components/test/control-descriptors.types.test-d.ts new file mode 100644 index 0000000000..a860541768 --- /dev/null +++ b/packages/1-framework/1-core/framework-components/test/control-descriptors.types.test-d.ts @@ -0,0 +1,36 @@ +import type { Contract, StorageBase } from '@prisma-next/contract/types'; +import { expectTypeOf, test } from 'vitest'; +import type { ControlExtensionDescriptor } from '../src/control/control-descriptors'; +import type { ContractSpace } from '../src/control/control-spaces'; + +// Mirrors how the sql/mongo families narrow contractSpace to their storage shape. +interface DemoStorage extends StorageBase { + readonly demoOnly: true; +} + +interface NarrowedExtensionDescriptor extends ControlExtensionDescriptor<'sql', 'postgres'> { + readonly contractSpace?: ContractSpace>; +} + +test('core extension descriptor declares an optional framework-level contract space', () => { + expectTypeOf['contractSpace']>().toEqualTypeOf< + ContractSpace | undefined + >(); +}); + +test('family descriptors narrow contractSpace and stay assignable to the core descriptor', () => { + expectTypeOf().toExtend< + ControlExtensionDescriptor<'sql', 'postgres'> + >(); + expectTypeOf().toEqualTypeOf< + ContractSpace> | undefined + >(); +}); + +test('typed contract access needs no casts', () => { + const readComposedContract = ( + descriptor: ControlExtensionDescriptor, + ): Contract | undefined => descriptor.contractSpace?.contractJson; + + expectTypeOf(readComposedContract).returns.toEqualTypeOf(); +}); From c3a4f43649b16fc8a808995491f594908dff2242 Mon Sep 17 00:00:00 2001 From: Serhii Tatarintsev Date: Mon, 13 Jul 2026 10:08:26 +0000 Subject: [PATCH 3/3] =?UTF-8?q?TML-2984:=20slice=2003=20close-out=20?= =?UTF-8?q?=E2=80=94=20SDoD=20walked,=20learnings=20updated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Serhii Tatarintsev --- .../lsp-interpreter-diagnostics/plans/plan.md | 2 +- .../03-contractspace-core-descriptor/spec.md | 36 ++++++++++++------- .../lsp-interpreter-diagnostics/trace.jsonl | 5 +++ 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/projects/lsp-interpreter-diagnostics/plans/plan.md b/projects/lsp-interpreter-diagnostics/plans/plan.md index e0ca65f52c..c777e2b29e 100644 --- a/projects/lsp-interpreter-diagnostics/plans/plan.md +++ b/projects/lsp-interpreter-diagnostics/plans/plan.md @@ -149,7 +149,7 @@ stack-shaped objects surface via typecheck and gain the new property. ### Implement M2b: contractSpace declared on the core extension descriptor -**Status:** ► In progress — slice 03, stacked on slice 02 (scope addition, operator-authorized 2026-07-10) +**Status:** ► In progress — slice 03 delivered (`2c3c1de79`, SATISFIED 4/4 SDoD), stacked on slice 02; PR opens after #948 merges (scope addition, operator-authorized 2026-07-10) _Outcomes_ Core `ControlExtensionDescriptor` carries `contractSpace?: ContractSpace`; sql + mongo diff --git a/projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/spec.md b/projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/spec.md index e8e76f6c34..22eaad7607 100644 --- a/projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/spec.md +++ b/projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/spec.md @@ -38,19 +38,29 @@ the bridges the gap forced." Type-level only; bit-identical behavior by construc ## Slice Definition of Done (beyond CI / reviewer / project-DoD) -- [ ] SDoD1 — Core `ControlExtensionDescriptor` declares `contractSpace?: ContractSpace`; - sql + mongo overrides compile unchanged (their existing - descriptor-self-consistency suites stay green); type test pins the covariant - narrowing (family descriptor assignable where core descriptor is expected, with - typed `contractSpace` access). -- [ ] SDoD2 — Zero `contractJson` casts repo-wide: `assembleExtensionContracts` - cast-free, `ContractSpaceCarryingDescriptor` deleted; tightened grep gate - documented and passing (with positive control against pre-change tree). -- [ ] SDoD3 — Load-order dependency view either typed (if `Contract.extensionPacks` - admits it) or explicitly reported as kept-with-reason. -- [ ] SDoD4 — `MigrationPackage` fit verified: both families' shipped descriptor - migrations satisfy core's `ContractSpace.migrations` (typecheck is the proof; - any wrinkle surfaces, not worked around). +- [x] SDoD1 — Core declaration in place (`control-descriptors.ts:89`); sql + mongo + overrides compile with **zero edits** (298/298 + 170/170); test-d pins the + covariant narrowing structurally (core cannot import families — the + `extends`-declaration itself is the compile-time proof, `toExtend` as + belt-and-braces). ✓ `2c3c1de79` +- [x] SDoD2 — Zero `contractJson` casts repo-wide; view deleted; gate tightened to + **two regex forms** (reach-through + picked-variable — the exclusion-drop alone + would have been blind to the form the control-stack cast used); + reviewer-executed both directions with historical positive controls. ✓ +- [x] SDoD3 — Load-order view **kept-with-reason**, reviewer-accepted: + `buildExtensionLoadOrder` is public API (exported via `exports/control.ts`, + consumed by `family-sql/control-instance.ts`); its structural parameter is a + contract, not a cast bridge (casts nothing); typing it costs fixture + fabrication + API narrowing for zero cast savings. ✓ +- [x] SDoD4 — `MigrationPackage` fit proven by zero-edit family compiles under + override-compatibility checking; the dirPath wrinkle did not materialize. ✓ + +**Slice-close ritual (2026-07-10):** single dispatch SATISFIED; 4/4 SDoD PASS; manual +QA: **N/A — no user-observable change** (type-level declaration lift, bit-identical +behavior). Follow-up candidate recorded in `learnings.md`: `CrossSpaceFkView` +(`family-sql/control-instance.ts:382`) could take the same typed-declaration +treatment. Stacked on slice 02; PR mechanics per orchestrator (base = slice-02 branch +until #948 merges). ## Edge cases (pre-investigated) diff --git a/projects/lsp-interpreter-diagnostics/trace.jsonl b/projects/lsp-interpreter-diagnostics/trace.jsonl index 9cca52967e..fcffa6aeb9 100644 --- a/projects/lsp-interpreter-diagnostics/trace.jsonl +++ b/projects/lsp-interpreter-diagnostics/trace.jsonl @@ -42,3 +42,8 @@ {"event_id":"f3aad824-88e5-4c00-b702-69efcaeb7362","schema_version":"1","ts":"2026-07-13T09:45:28.704Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"slice-started","slice_slug":"m2b-contractspace-core-descriptor","slice_index":3,"linear_ref":"TML-2984"} {"event_id":"3bef2c11-5e73-49c0-a987-c9f9e1310e5b","schema_version":"1","ts":"2026-07-13T09:45:29.364Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"spec-authored","spec_path":"projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/spec.md","spec_kind":"slice","byte_length":4908,"edge_cases_count":2,"open_questions_count":0,"dod_items_count":4} {"event_id":"682d13fa-274c-43b4-9dc6-c895afcce0c0","schema_version":"1","ts":"2026-07-13T09:45:29.947Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"plan-authored","plan_path":"projects/lsp-interpreter-diagnostics/slices/03-contractspace-core-descriptor/spec.md","plan_kind":"slice","byte_length":4908,"dispatch_count":1,"slice_count":null,"dispatch_size_distribution":{"S":0,"M":1,"L":0,"XL":0},"open_items_count":0} +{"event_id":"2b4a61a8-c1ef-414c-80e9-3967b0335cbe","schema_version":"1","ts":"2026-07-13T09:46:14.005Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"dispatch-start","dispatch_id":"a8365892-9f71-4d8a-a94a-a64cecba21a3","dispatch_name":"S3-D1 lift contractSpace declaration to core","subagent_type":"spawn_agent","model":null,"parent_dispatch_id":"c7d18402-8963-4933-85f5-340e051c8e58"} +{"event_id":"ab3a6efa-a96f-4a3b-9c3b-ea180a4e5588","schema_version":"1","ts":"2026-07-13T09:46:14.510Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"round-start","dispatch_id":"a8365892-9f71-4d8a-a94a-a64cecba21a3","round_id":"2cb8ae19-0ba5-4541-939d-f4d0b90f4d63","round_number":1} +{"event_id":"b50ec839-b976-4abf-bf9c-52458501192d","schema_version":"1","ts":"2026-07-13T09:46:15.026Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"brief-issued","dispatch_id":"a8365892-9f71-4d8a-a94a-a64cecba21a3","round_id":"2cb8ae19-0ba5-4541-939d-f4d0b90f4d63","brief_byte_length":3009,"brief_content_hash":"95b22513fd63e76932ca55cf41f8e4dcae75de92a6778d18df40b5f0771d1848","brief_disposition":"initial"} +{"event_id":"5e5395b1-edf9-4c8d-89e6-7fd7539543b7","schema_version":"1","ts":"2026-07-13T10:07:50.099Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"round-end","dispatch_id":"a8365892-9f71-4d8a-a94a-a64cecba21a3","round_id":"2cb8ae19-0ba5-4541-939d-f4d0b90f4d63","verdict":"satisfied","findings_filed":0,"wall_clock_ms":2700000} +{"event_id":"5068fc2a-2390-47e6-bf12-027bc69804a8","schema_version":"1","ts":"2026-07-13T10:07:50.605Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"dispatch-end","dispatch_id":"a8365892-9f71-4d8a-a94a-a64cecba21a3","result":"completed","wall_clock_ms":2700000}