Skip to content
This repository was archived by the owner on Aug 25, 2026. It is now read-only.

Commit 2a29f81

Browse files
committed
TML-2984: slice 05 close-out — SDoD walked
Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
1 parent 327bbb7 commit 2a29f81

4 files changed

Lines changed: 99 additions & 18 deletions

File tree

projects/lsp-interpreter-diagnostics/plans/plan.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ behavior is unchanged (same inner function, same seed diagnostics). No consumer
196196

197197
### Implement M4: LSP interpreter diagnostics (lazy, mapped, degrading)
198198

199-
**Status:** ► In progress — slice 05, branch `tml-2984-slice-05-lsp-interpret`
199+
**Status:** ► In progress — slice 05 delivered (`958c1fbd0` + `e1f1f584d`, 5/5 SDoD), PR open; complete on merge
200200

201201
_Outcomes_
202202
The LSP serves interpreter diagnostics on pull and push for capability-bearing
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Brief: S5-D2 — span mapper + lazy memoized interpret + assembly wiring
2+
3+
## Task
4+
5+
Complete the data path (all in `packages/1-framework/3-tooling/language-server/`):
6+
7+
1. **`diagnostic-mapping.ts`** — new mapper `ContractSourceDiagnostic → LspDiagnostic`:
8+
spans carry `{offset, line, column}` positions — verify the base (0- vs 1-based)
9+
against `rangeToPslSpan` (psl-parser's forward conversion; your mapper is its
10+
inverse) and pin with a hand-computed expected range in a test. **Span-less
11+
diagnostics anchor at document start** (synthetic 0,0→0,1 range) — never dropped.
12+
2. **`project-artifacts.ts`**`DocumentArtifacts` gains a lazily computed, memoized
13+
interpret slot: on first request (diagnostics assembly only), invoke
14+
`interpretation.source.interpret({document, sourceFile, symbolTable, sourceId},
15+
interpretation.context)` **as a method — never detach it** (slice-04 hazard, now
16+
live); unwrap `notOk → failure.diagnostics`, `ok → []`; map via (1); cache until
17+
the existing `documentChanged`/`documentClosed` drop. `sourceId` = the document
18+
URI (same URI form as D1's `resolvedInputs` — consistency pinned in a test).
19+
`runPipeline` untouched. **No try/catch around `interpret`** — a throw is a real
20+
bug that must surface (slice-04 no-throw pins are the guarantee; config-load
21+
failures are slice 06).
22+
3. **Assembly wiring** — one combined-diagnostics function (parse/symbol-table +
23+
mapped interpreter findings) consumed by BOTH the push path (`publish`) and the
24+
pull handler (`buildDocumentDiagnosticReport`) — do not implement it twice.
25+
Interpretation runs only when a diagnostics response/publication is built.
26+
4. **Reviewer carry-overs from D1 (all three):**
27+
- Fold the now-dead `resolveControlStackInputs` export (port its three pins into
28+
the surviving shape).
29+
- Add a one-line doc note on `PslInterpretCapable` (psl-parser): `interpret` must
30+
not read disk or `context.resolvedInputs`; those are load-path concerns.
31+
- (The as-a-method rule is restated in (2).)
32+
33+
Tests first:
34+
35+
- **SDoD1 (TC-9):** capability config + schema with an unresolvable relation → the
36+
diagnostics response contains the interpreter diagnostic at the hand-verifiable
37+
range; fixing the schema clears it on the next pull.
38+
- **SDoD2 (TC-10):** span-less diagnostic → anchored at document start (real span-less
39+
producer if one is reachable, else a capability-shaped test double — document the
40+
choice).
41+
- **SDoD3 (TC-11):** byte-for-byte degradation regression — full diagnostic responses
42+
(push and pull) for a capability-less config deep-equal the pre-slice shape.
43+
- **SDoD4 (TC-12):** spy on `interpret`: semantic-token, folding-range, and completion
44+
requests → zero calls; two consecutive pulls on unchanged content → exactly one
45+
call; an edit → exactly one more on the next pull.
46+
47+
## Scope
48+
49+
**In:** `language-server/src/{diagnostic-mapping,project-artifacts,document-diagnostics,server,config-resolution}.ts` + tests; the one-line doc note in
50+
`psl-parser/src/interpret.ts`.
51+
**Out:** `pipeline.ts` behavior; config-failure surfacing / last-good retention
52+
(slice 06); CLI; providers; `projects/**`; GitHub threads.
53+
54+
## Completed when
55+
56+
- [ ] SDoD1–4 tests green; combined assembly single-sourced for push + pull.
57+
- [ ] Dead wrapper folded; doc note landed; zero casts; zero try/catch around
58+
`interpret`.
59+
- [ ] Gates: `pnpm --filter @prisma-next/language-server test` + typecheck + lint,
60+
`pnpm typecheck`, `pnpm test:packages`, `pnpm lint:deps`.
61+
62+
## Operational metadata
63+
64+
- **Time-box:** 90 min. Halt: the span base cannot be pinned against a real
65+
interpreter diagnostic (mapping ambiguity — surface, never guess); the pull and
66+
push paths resist a shared assembly without restructuring beyond this slice's
67+
files; memoization cannot key cleanly on the existing document-drop lifecycle.

projects/lsp-interpreter-diagnostics/slices/05-lsp-interpret/spec.md

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,23 +48,30 @@ transitional-shape constraint: never publish without position mapping).
4848

4949
## Slice Definition of Done (beyond CI / reviewer / project-DoD)
5050

51-
- [ ] SDoD1 — For a `prismaContract` config and a schema with an interpreter error
52-
(e.g. unresolvable relation), the LSP's diagnostics response contains the
53-
interpreter diagnostic with the correct LSP range (span-mapping base pinned by
54-
test); fixing the schema clears it on the next pull (TC-9).
55-
- [ ] SDoD2 — A span-less interpreter diagnostic surfaces anchored at document start,
56-
not dropped (TC-10; construct via a real span-less producer or a
57-
capability-shaped test double — implementer's choice, documented).
58-
- [ ] SDoD3 — Graceful degradation (TC-11): a config whose provider lacks the
59-
capability (typescript source, opaque provider, absent contract) produces LSP
60-
behavior byte-for-byte identical to pre-slice — regression test comparing
61-
full diagnostic responses.
62-
- [ ] SDoD4 — Laziness (TC-12): semantic-token, folding-range, and completion
63-
requests never invoke `interpret` (spy); repeated diagnostic pulls on unchanged
64-
content interpret at most once; an edit invalidates the memo (spy count
65-
increments exactly once after change).
66-
- [ ] SDoD5 — Zero new casts; `pnpm lint:deps` green (language-server already
67-
depends on psl-parser and config; no new edges expected — flag if one appears).
51+
- [x] SDoD1 — interpreter diagnostic in the response at a hand-verifiable mapped
52+
range (1-based PslSpan → 0-based LSP, base pinned against the real
53+
`rangeToPslSpan` via roundtrip inversion); fix clears on next pull. ✓
54+
`e1f1f584d` (server tests; doubles typed `PslInterpretCapable['interpret']`
55+
compiler-enforced fidelity; real-provider integration pinned in slice 04;
56+
end-to-end closes in M6 playground QA).
57+
- [x] SDoD2 — span-less → document-start anchor (0,0→0,1), never dropped. ✓
58+
(capability-shaped double, choice documented).
59+
- [x] SDoD3 — degradation byte-for-byte on both channels (full diagnostic objects
60+
deep-equaled; absent-capability slot is a constant `[]`). ✓
61+
- [x] SDoD4 — laziness matrix through real harness request paths: semantic
62+
tokens/folding/completion → 0 interpret calls; two pulls → 1; edit + pull → 2;
63+
memo rides the existing document-drop lifecycle. ✓
64+
- [x] SDoD5 — zero production casts; one new dependency edge flagged as instructed
65+
(language-server → config, direct instead of transitive — honest, downward,
66+
lint:deps green); no D2 edges. ✓
67+
68+
**Slice-close ritual (2026-07-14):** D1+D2 SATISFIED R1, zero findings; 5/5 SDoD
69+
PASS; `origin/main` rebased (one attribute-specs commit) + gates re-verified
70+
(typecheck 143/143, LSP 218/218, psl-parser 625/625); manual QA: covered by M6
71+
playground script (reviewer directive: include one real `prismaContract` project
72+
with an interpreter error — the last un-doubled link). Grep gate: zero `projects/`
73+
references in long-lived files. Method-detachment hazard converted to a failing
74+
test (`spy.mock.contexts[0]`).
6875

6976
## Edge cases (pre-investigated)
7077

projects/lsp-interpreter-diagnostics/trace.jsonl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,10 @@
9393
{"event_id":"b25a1805-b36f-4730-a145-6fffb4665b45","schema_version":"1","ts":"2026-07-14T10:17:06.535Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"dispatch-start","dispatch_id":"d37c6085-80ae-453f-9e45-5a246f20d289","dispatch_name":"S5-D1 context assembly + guarded provider in ConfigResolution","subagent_type":"spawn_agent","model":null,"parent_dispatch_id":"8a692f9a-e70d-4d9d-8919-ca2b7aec491c"}
9494
{"event_id":"bcf6b179-fd0f-4591-a32e-5969c201937a","schema_version":"1","ts":"2026-07-14T10:17:07.009Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"round-start","dispatch_id":"d37c6085-80ae-453f-9e45-5a246f20d289","round_id":"98460ddb-b4fe-43ba-90ec-d14bb4777685","round_number":1}
9595
{"event_id":"62f368a5-36ab-4e9f-a0ff-5c73a7f46d80","schema_version":"1","ts":"2026-07-14T10:17:07.468Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"brief-issued","dispatch_id":"d37c6085-80ae-453f-9e45-5a246f20d289","round_id":"98460ddb-b4fe-43ba-90ec-d14bb4777685","brief_byte_length":3039,"brief_content_hash":"e6b6d324e6f0c92370f3928abe40b4eda1f5893f082aaea8c44399f0e7ff9aaa","brief_disposition":"initial"}
96+
{"event_id":"13ec0349-0a12-471d-9ae4-4b5426a07e1d","schema_version":"1","ts":"2026-07-14T10:30:53.883Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"round-end","dispatch_id":"d37c6085-80ae-453f-9e45-5a246f20d289","round_id":"98460ddb-b4fe-43ba-90ec-d14bb4777685","verdict":"satisfied","findings_filed":0,"wall_clock_ms":3300000}
97+
{"event_id":"4b4753b8-d175-4e58-b0f0-c3827a293d07","schema_version":"1","ts":"2026-07-14T10:30:54.310Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"dispatch-end","dispatch_id":"d37c6085-80ae-453f-9e45-5a246f20d289","result":"completed","wall_clock_ms":3300000}
98+
{"event_id":"50c86174-4fab-49a0-be8c-f271bdd4188f","schema_version":"1","ts":"2026-07-14T10:31:55.107Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"dispatch-start","dispatch_id":"af03de09-e8b6-4379-918c-581e95e0e241","dispatch_name":"S5-D2 span mapper + lazy memoized interpret + assembly wiring","subagent_type":"spawn_agent","model":null,"parent_dispatch_id":"d37c6085-80ae-453f-9e45-5a246f20d289"}
99+
{"event_id":"965ba5d1-e0bf-4f14-a041-b92c3a70608a","schema_version":"1","ts":"2026-07-14T10:31:55.543Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"round-start","dispatch_id":"af03de09-e8b6-4379-918c-581e95e0e241","round_id":"dfa84e61-62e0-4610-9e75-8a9083393be6","round_number":1}
100+
{"event_id":"e45ed77d-ed22-4909-9b86-744ec94ea4ae","schema_version":"1","ts":"2026-07-14T10:31:55.962Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"brief-issued","dispatch_id":"af03de09-e8b6-4379-918c-581e95e0e241","round_id":"dfa84e61-62e0-4610-9e75-8a9083393be6","brief_byte_length":3908,"brief_content_hash":"1af2485621d743831e23e337a363918842de0f5d521a4ddfbb79c6a459f5127f","brief_disposition":"initial"}
101+
{"event_id":"a8c3f797-ff06-4d2e-859f-2552da9973ad","schema_version":"1","ts":"2026-07-14T11:05:28.579Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"round-end","dispatch_id":"af03de09-e8b6-4379-918c-581e95e0e241","round_id":"dfa84e61-62e0-4610-9e75-8a9083393be6","verdict":"satisfied","findings_filed":0,"wall_clock_ms":4200000}
102+
{"event_id":"5e1e764d-9f62-4e14-be2f-427510f6d1e0","schema_version":"1","ts":"2026-07-14T11:05:29.043Z","project_run_id":"lsp-interpreter-diagnostics","orchestrator_agent_id":null,"event_type":"dispatch-end","dispatch_id":"af03de09-e8b6-4379-918c-581e95e0e241","result":"completed","wall_clock_ms":4200000}

0 commit comments

Comments
 (0)