Skip to content

TML-2984: LSP serves interpreter diagnostics from cached artifacts - #972

Merged
SevInf merged 6 commits into
mainfrom
tml-2984-slice-05-lsp-interpret
Jul 14, 2026
Merged

TML-2984: LSP serves interpreter diagnostics from cached artifacts#972
SevInf merged 6 commits into
mainfrom
tml-2984-slice-05-lsp-interpret

Conversation

@SevInf

@SevInf SevInf commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Slice 05 of the lsp-interpreter-diagnostics project (TML-2984, follows #939/#948/#971) — the payoff slice: interpreter diagnostics (unresolvable relations, type/codec binding, extension-block semantics) now appear live in the editor instead of only at contract emit.

Changes

  • config-resolution.ts: when the loaded config has PSL inputs and its contract source passes hasPslInterpreter, the resolution additionally carries interpretation: { source, context } — the guarded capability plus a full ContractSourceContext assembled once per config (re)load by property picks off a single createControlStack call (the extensionContracts machinery from TML-2984: contract spaces declared in core; ControlStack exposes extension contracts; CLI emit context becomes pure property picks #948). Without the capability the member is absent and every code path behaves exactly as before.
  • diagnostic-mapping.ts: maps ContractSourceDiagnostic line/column spans (1-based, per rangeToPslSpan — the new mapper is its verified inverse) to LSP ranges; span-less diagnostics anchor at document start (0,0→0,1, the tsserver convention) rather than being dropped.
  • project-artifacts.ts: each cached document gains a lazily computed, memoized interpret slot — interpret runs only when a diagnostics response is being assembled, at most once per document version, invalidated by the existing documentChanged/documentClosed lifecycle. runPipeline is untouched: semantic tokens, folding, and completion never pay interpretation cost (spy-verified through real request paths).
  • server.ts: one combinedDiagnostics assembly (parse + symbol-table + mapped interpreter findings) consumed by both the push channel and the pull handler.

Why

The whole project existed for this hop: the LSP already parses and builds symbol tables incrementally from editor buffers, and since #971 the providers can interpret exactly those cached artifacts — no re-parse, no disk read, no forked pipeline (load and interpret share one path by construction). Laziness is the performance contract: interpretation is pull-time-only and memoized. Degradation is byte-for-byte: configs without the capability (typescript sources, third-party providers) keep today's behavior exactly, deep-equal-verified on both channels. Test doubles are typed PslInterpretCapable['interpret'] so the compiler enforces fidelity to the real capability; the real-provider integration is pinned in #971's suites, and the playground QA (final slice) exercises the full chain in a live editor.

Project spec + plan live under projects/lsp-interpreter-diagnostics/ (deleted at project close-out).

Summary by CodeRabbit

  • New Features

    • Language Server diagnostics now include interpreter errors for supported configurations.
    • Interpreter diagnostics are mapped to precise document ranges, with span-less errors anchored at the document start.
    • Diagnostics are evaluated lazily and cached until a document changes.
    • Pull and push diagnostic workflows now provide consistent combined results.
  • Bug Fixes

    • Prevented unnecessary interpreter execution during completion, folding, and semantic-token requests.
  • Documentation

    • Clarified interpretation behavior and its input-handling constraints.

@SevInf
SevInf requested a review from a team as a code owner July 14, 2026 11:08
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The language server now resolves optional PSL interpretation context, lazily computes and maps interpreter diagnostics per document, combines them with existing diagnostics for pull and push flows, and re-runs interpretation after document changes.

Changes

Interpreter diagnostics

Layer / File(s) Summary
Resolve interpretation context
packages/1-framework/2-authoring/psl-parser/src/interpret.ts, packages/1-framework/3-tooling/language-server/package.json, packages/1-framework/3-tooling/language-server/src/config-resolution.ts, packages/1-framework/3-tooling/language-server/test/config-resolution.test.ts
Configuration resolution derives pipeline inputs and optional ProjectInterpretation context for capable PSL sources, with coverage for supported and unsupported configurations.
Lazy document interpretation
packages/1-framework/3-tooling/language-server/src/diagnostic-mapping.ts, packages/1-framework/3-tooling/language-server/src/project-artifacts.ts, packages/1-framework/3-tooling/language-server/test/diagnostic-mapping.test.ts, packages/1-framework/3-tooling/language-server/test/project-artifacts.test.ts
Document artifacts lazily memoize interpreter execution, invalidate results after document changes, and map span-based or span-less diagnostics to LSP ranges.
Publish combined diagnostics
packages/1-framework/3-tooling/language-server/src/server.ts, packages/1-framework/3-tooling/language-server/test/server.test.ts
Pull reports and push notifications combine interpreter diagnostics with existing diagnostics while preserving capability-less behavior and invocation constraints.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant LspClient
  participant LanguageServer
  participant DocumentArtifacts
  participant PslInterpretCapable
  participant mapInterpreterDiagnostics
  LspClient->>LanguageServer: request diagnostics
  LanguageServer->>DocumentArtifacts: combinedDiagnostics
  DocumentArtifacts->>PslInterpretCapable: interpret document with context
  PslInterpretCapable-->>DocumentArtifacts: ContractSourceDiagnostic[]
  DocumentArtifacts->>mapInterpreterDiagnostics: map diagnostics
  mapInterpreterDiagnostics-->>DocumentArtifacts: LspDiagnostic[]
  DocumentArtifacts-->>LanguageServer: combined diagnostics
  LanguageServer-->>LspClient: diagnostic report
Loading

Possibly related PRs

  • prisma/prisma-next#887: Adds the lazy project-artifact and server diagnostic flow extended here with interpreter diagnostics.
  • prisma/prisma-next#939: Introduces the interpreter-capable contract-source seam consumed by this language-server integration.
  • prisma/prisma-next#971: Provides the PSL interpretation capability and diagnostic types used by this pipeline.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: serving interpreter diagnostics from cached artifacts in the LSP.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tml-2984-slice-05-lsp-interpret

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

@prisma-next/extension-author-tools

npm i https://pkg.pr.new/@prisma-next/extension-author-tools@972

@prisma-next/mongo-runtime

npm i https://pkg.pr.new/@prisma-next/mongo-runtime@972

@prisma-next/family-mongo

npm i https://pkg.pr.new/@prisma-next/family-mongo@972

@prisma-next/sql-runtime

npm i https://pkg.pr.new/@prisma-next/sql-runtime@972

@prisma-next/family-sql

npm i https://pkg.pr.new/@prisma-next/family-sql@972

@prisma-next/extension-arktype-json

npm i https://pkg.pr.new/@prisma-next/extension-arktype-json@972

@prisma-next/middleware-cache

npm i https://pkg.pr.new/@prisma-next/middleware-cache@972

@prisma-next/mongo

npm i https://pkg.pr.new/@prisma-next/mongo@972

@prisma-next/extension-paradedb

npm i https://pkg.pr.new/@prisma-next/extension-paradedb@972

@prisma-next/extension-pgvector

npm i https://pkg.pr.new/@prisma-next/extension-pgvector@972

@prisma-next/extension-postgis

npm i https://pkg.pr.new/@prisma-next/extension-postgis@972

@prisma-next/postgres

npm i https://pkg.pr.new/@prisma-next/postgres@972

@prisma-next/sql-orm-client

npm i https://pkg.pr.new/@prisma-next/sql-orm-client@972

@prisma-next/sqlite

npm i https://pkg.pr.new/@prisma-next/sqlite@972

@prisma-next/extension-supabase

npm i https://pkg.pr.new/@prisma-next/extension-supabase@972

@prisma-next/target-mongo

npm i https://pkg.pr.new/@prisma-next/target-mongo@972

@prisma-next/adapter-mongo

npm i https://pkg.pr.new/@prisma-next/adapter-mongo@972

@prisma-next/driver-mongo

npm i https://pkg.pr.new/@prisma-next/driver-mongo@972

@prisma-next/contract

npm i https://pkg.pr.new/@prisma-next/contract@972

@prisma-next/utils

npm i https://pkg.pr.new/@prisma-next/utils@972

@prisma-next/config

npm i https://pkg.pr.new/@prisma-next/config@972

@prisma-next/errors

npm i https://pkg.pr.new/@prisma-next/errors@972

@prisma-next/framework-components

npm i https://pkg.pr.new/@prisma-next/framework-components@972

@prisma-next/operations

npm i https://pkg.pr.new/@prisma-next/operations@972

@prisma-next/ts-render

npm i https://pkg.pr.new/@prisma-next/ts-render@972

@prisma-next/contract-authoring

npm i https://pkg.pr.new/@prisma-next/contract-authoring@972

@prisma-next/ids

npm i https://pkg.pr.new/@prisma-next/ids@972

@prisma-next/psl-parser

npm i https://pkg.pr.new/@prisma-next/psl-parser@972

@prisma-next/psl-printer

npm i https://pkg.pr.new/@prisma-next/psl-printer@972

@prisma-next/cli

npm i https://pkg.pr.new/@prisma-next/cli@972

@prisma-next/cli-telemetry

npm i https://pkg.pr.new/@prisma-next/cli-telemetry@972

@prisma-next/config-loader

npm i https://pkg.pr.new/@prisma-next/config-loader@972

@prisma-next/emitter

npm i https://pkg.pr.new/@prisma-next/emitter@972

@prisma-next/language-server

npm i https://pkg.pr.new/@prisma-next/language-server@972

@prisma-next/migration-tools

npm i https://pkg.pr.new/@prisma-next/migration-tools@972

prisma-next

npm i https://pkg.pr.new/prisma-next@972

@prisma-next/vite-plugin-contract-emit

npm i https://pkg.pr.new/@prisma-next/vite-plugin-contract-emit@972

@prisma-next/mongo-codec

npm i https://pkg.pr.new/@prisma-next/mongo-codec@972

@prisma-next/mongo-contract

npm i https://pkg.pr.new/@prisma-next/mongo-contract@972

@prisma-next/mongo-value

npm i https://pkg.pr.new/@prisma-next/mongo-value@972

@prisma-next/mongo-contract-psl

npm i https://pkg.pr.new/@prisma-next/mongo-contract-psl@972

@prisma-next/mongo-contract-ts

npm i https://pkg.pr.new/@prisma-next/mongo-contract-ts@972

@prisma-next/mongo-emitter

npm i https://pkg.pr.new/@prisma-next/mongo-emitter@972

@prisma-next/mongo-schema-ir

npm i https://pkg.pr.new/@prisma-next/mongo-schema-ir@972

@prisma-next/mongo-query-ast

npm i https://pkg.pr.new/@prisma-next/mongo-query-ast@972

@prisma-next/mongo-orm

npm i https://pkg.pr.new/@prisma-next/mongo-orm@972

@prisma-next/mongo-query-builder

npm i https://pkg.pr.new/@prisma-next/mongo-query-builder@972

@prisma-next/mongo-lowering

npm i https://pkg.pr.new/@prisma-next/mongo-lowering@972

@prisma-next/mongo-wire

npm i https://pkg.pr.new/@prisma-next/mongo-wire@972

@prisma-next/sql-contract

npm i https://pkg.pr.new/@prisma-next/sql-contract@972

@prisma-next/sql-errors

npm i https://pkg.pr.new/@prisma-next/sql-errors@972

@prisma-next/sql-operations

npm i https://pkg.pr.new/@prisma-next/sql-operations@972

@prisma-next/sql-schema-ir

npm i https://pkg.pr.new/@prisma-next/sql-schema-ir@972

@prisma-next/sql-contract-psl

npm i https://pkg.pr.new/@prisma-next/sql-contract-psl@972

@prisma-next/sql-contract-ts

npm i https://pkg.pr.new/@prisma-next/sql-contract-ts@972

@prisma-next/sql-contract-emitter

npm i https://pkg.pr.new/@prisma-next/sql-contract-emitter@972

@prisma-next/sql-lane-query-builder

npm i https://pkg.pr.new/@prisma-next/sql-lane-query-builder@972

@prisma-next/sql-relational-core

npm i https://pkg.pr.new/@prisma-next/sql-relational-core@972

@prisma-next/sql-builder

npm i https://pkg.pr.new/@prisma-next/sql-builder@972

@prisma-next/target-postgres

npm i https://pkg.pr.new/@prisma-next/target-postgres@972

@prisma-next/target-sqlite

npm i https://pkg.pr.new/@prisma-next/target-sqlite@972

@prisma-next/adapter-postgres

npm i https://pkg.pr.new/@prisma-next/adapter-postgres@972

@prisma-next/adapter-sqlite

npm i https://pkg.pr.new/@prisma-next/adapter-sqlite@972

@prisma-next/driver-postgres

npm i https://pkg.pr.new/@prisma-next/driver-postgres@972

@prisma-next/driver-sqlite

npm i https://pkg.pr.new/@prisma-next/driver-sqlite@972

commit: 054f9fa

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown

size-limit report 📦

Path Size
postgres / no-emit 155.93 KB (0%)
postgres / emit 130.97 KB (0%)
mongo / no-emit 98.71 KB (0%)
mongo / emit 89.43 KB (0%)
cf-worker / no-emit 182.94 KB (0%)
cf-worker / emit 155.41 KB (0%)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/1-framework/3-tooling/language-server/src/server.ts (1)

258-275: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer ifDefined over inline ternary spreads.

Two new ...(x === undefined ? {} : { key: x }) spreads are added here for interpretation (and the formatter spread is rewritten the same way). Based on learnings, this repo prefers ifDefined(key, value) from prisma-next/utils/defined for conditional object spreads instead of inline ternary-based spreads.

♻️ Proposed refactor
     const artifacts = createProjectArtifacts({
       inputs: resolution.inputs,
       controlStack: resolution.controlStack,
       getText: (uri) => documents.get(uri)?.getText(),
-      ...(resolution.interpretation === undefined
-        ? {}
-        : { interpretation: resolution.interpretation }),
+      ...ifDefined('interpretation', resolution.interpretation),
     });
     const project: ProjectState = {
       configPath,
       inputs: resolution.inputs,
       controlStack: resolution.controlStack,
       artifacts,
-      ...(resolution.formatter === undefined ? {} : { formatter: resolution.formatter }),
-      ...(resolution.interpretation === undefined
-        ? {}
-        : { interpretation: resolution.interpretation }),
+      ...ifDefined('formatter', resolution.formatter),
+      ...ifDefined('interpretation', resolution.interpretation),
     };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/1-framework/3-tooling/language-server/src/server.ts` around lines
258 - 275, Replace the inline ternary-based conditional spreads for
interpretation and formatter in the createProjectArtifacts options and
ProjectState construction with the repository’s ifDefined helper from
prisma-next/utils/defined. Preserve the existing omission behavior when either
value is undefined.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/1-framework/3-tooling/language-server/src/project-artifacts.ts`:
- Around line 47-75: Guard the interpretation call inside createInterpretSlot by
catching exceptions from interpretation.source.interpret and falling back to an
empty diagnostic list. Preserve memoization by assigning the fallback or mapped
diagnostics to memo before returning, matching the existing handling pattern for
external calls.

---

Nitpick comments:
In `@packages/1-framework/3-tooling/language-server/src/server.ts`:
- Around line 258-275: Replace the inline ternary-based conditional spreads for
interpretation and formatter in the createProjectArtifacts options and
ProjectState construction with the repository’s ifDefined helper from
prisma-next/utils/defined. Preserve the existing omission behavior when either
value is undefined.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: c0a89109-b2e3-456b-b08d-34d822f5f967

📥 Commits

Reviewing files that changed from the base of the PR and between a7344a3 and fbf9549.

⛔ Files ignored due to path filters (6)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • projects/lsp-interpreter-diagnostics/plans/plan.md is excluded by !projects/**
  • projects/lsp-interpreter-diagnostics/slices/05-lsp-interpret/briefs/d1-r1.md is excluded by !projects/**
  • projects/lsp-interpreter-diagnostics/slices/05-lsp-interpret/briefs/d2-r1.md is excluded by !projects/**
  • projects/lsp-interpreter-diagnostics/slices/05-lsp-interpret/spec.md is excluded by !projects/**
  • projects/lsp-interpreter-diagnostics/trace.jsonl is excluded by !projects/**
📒 Files selected for processing (10)
  • packages/1-framework/2-authoring/psl-parser/src/interpret.ts
  • packages/1-framework/3-tooling/language-server/package.json
  • packages/1-framework/3-tooling/language-server/src/config-resolution.ts
  • packages/1-framework/3-tooling/language-server/src/diagnostic-mapping.ts
  • packages/1-framework/3-tooling/language-server/src/project-artifacts.ts
  • packages/1-framework/3-tooling/language-server/src/server.ts
  • packages/1-framework/3-tooling/language-server/test/config-resolution.test.ts
  • packages/1-framework/3-tooling/language-server/test/diagnostic-mapping.test.ts
  • packages/1-framework/3-tooling/language-server/test/project-artifacts.test.ts
  • packages/1-framework/3-tooling/language-server/test/server.test.ts

Comment on lines +47 to +75
const { inputs, controlStack, getText, interpretation } = options;
const documents = new Map<string, DocumentArtifacts>();
let symbolTable: SymbolTable | undefined;

function createInterpretSlot(
uri: string,
computed: DocumentDiagnostics,
): () => readonly LspDiagnostic[] {
if (interpretation === undefined) {
return () => [];
}
let memo: readonly LspDiagnostic[] | undefined;
return () => {
if (memo === undefined) {
const result = interpretation.source.interpret(
{
document: computed.document,
sourceFile: computed.sourceFile,
symbolTable: computed.symbolTable,
sourceId: uri,
},
interpretation.context,
);
memo = mapInterpreterDiagnostics(result.ok ? [] : result.failure.diagnostics);
}
return memo;
};
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## target file outline\n'
ast-grep outline packages/1-framework/3-tooling/language-server/src/project-artifacts.ts --view expanded || true

printf '\n## relevant symbols/search\n'
rg -n "interpretation\.source\.interpret|formatDocument|completeDocument|publishSafely|buildDocumentDiagnosticReport|on\\(" packages/1-framework/3-tooling/language-server/src -S

printf '\n## target file excerpt\n'
nl -ba packages/1-framework/3-tooling/language-server/src/project-artifacts.ts | sed -n '1,220p'

Repository: prisma/prisma-next

Length of output: 5793


🏁 Script executed:

#!/bin/bash
set -euo pipefail

nl -ba packages/1-framework/3-tooling/language-server/src/project-artifacts.ts | sed -n '1,140p'

Repository: prisma/prisma-next

Length of output: 196


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Minimal inspection for the specific concern
nl -ba packages/1-framework/3-tooling/language-server/src/project-artifacts.ts | sed -n '35,95p'
rg -n "try \\{|catch \\{|interpretation\\.source\\.interpret|buildDocumentDiagnosticReport|publishSafely|combinedDiagnostics" packages/1-framework/3-tooling/language-server/src -S

Repository: prisma/prisma-next

Length of output: 196


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## project-artifacts excerpt\n'
sed -n '1,140p' packages/1-framework/3-tooling/language-server/src/project-artifacts.ts | cat -n

printf '\n## server excerpt around diagnostics/format/completion\n'
sed -n '120,420p' packages/1-framework/3-tooling/language-server/src/server.ts | cat -n

Repository: prisma/prisma-next

Length of output: 18630


Guard interpretation.source.interpret(...) here. A throw will skip memoization and fail diagnostics for this document; wrap it like the other external calls and fall back to an empty diagnostic list.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/1-framework/3-tooling/language-server/src/project-artifacts.ts`
around lines 47 - 75, Guard the interpretation call inside createInterpretSlot
by catching exceptions from interpretation.source.interpret and falling back to
an empty diagnostic list. Preserve memoization by assigning the fallback or
mapped diagnostics to memo before returning, matching the existing handling
pattern for external calls.

SevInf added 6 commits July 14, 2026 15:37
Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…onfigResolution

When a psl-input config source passes hasPslInterpreter, the resolution
carries the narrowed provider and a ContractSourceContext assembled by
property picks off the single createControlStack call the pipeline-input
derivation already makes. ProjectState threads the member; nothing
consumes it yet. Configs without the capability resolve exactly as
before. language-server gains a direct @prisma-next/config dependency
for the context type.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
The payoff path: mapInterpreterDiagnostics inverts rangeToPslSpan
(1-based span to 0-based LSP range) and anchors span-less findings at
document start instead of dropping them; DocumentArtifacts gains a
lazily computed interpret slot memoized per artifacts instance (the
existing documentChanged/documentClosed drop is the invalidation),
invoking the provider capability as a method with the document URI as
sourceId; push and pull share one combined-diagnostics assembly, so
interpretation runs only when a diagnostics response is built --
semantic tokens, folding, and completion never pay it. Capability-less
configs respond byte-for-byte as before. Dead resolveControlStackInputs
wrapper folded; its pins ported to resolveConfigInputs level.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…xture stubs

The span-to-range mapping now recovers positions from the span offsets
through SourceFile.positionAt -- the literal inverse of how
rangeToPslSpan derives them -- which also keeps the framework packages
family-vocabulary-clean. Test stubs stop borrowing family names for
arbitrary strings.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
@SevInf
SevInf force-pushed the tml-2984-slice-05-lsp-interpret branch from 3e64561 to 054f9fa Compare July 14, 2026 15:42

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
packages/1-framework/3-tooling/language-server/src/project-artifacts.ts (1)

60-74: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard interpretation.source.interpret(...) here.

A throw will skip memoization and fail diagnostics for this document; wrap it like the other external calls and fall back to an empty diagnostic list.

🛡️ Proposed fix to add try/catch guard
-        const result = interpretation.source.interpret(
-          {
-            document: computed.document,
-            sourceFile: computed.sourceFile,
-            symbolTable: computed.symbolTable,
-            sourceId: uri,
-          },
-          interpretation.context,
-        );
-        memo = mapInterpreterDiagnostics(
-          result.ok ? [] : result.failure.diagnostics,
-          computed.sourceFile,
-        );
+        try {
+          const result = interpretation.source.interpret(
+            {
+              document: computed.document,
+              sourceFile: computed.sourceFile,
+              symbolTable: computed.symbolTable,
+              sourceId: uri,
+            },
+            interpretation.context,
+          );
+          memo = mapInterpreterDiagnostics(
+            result.ok ? [] : result.failure.diagnostics,
+            computed.sourceFile,
+          );
+        } catch {
+          memo = [];
+        }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/1-framework/3-tooling/language-server/src/project-artifacts.ts`
around lines 60 - 74, Wrap the interpretation call in the memoization block of
project artifact processing with a try/catch, following the existing pattern for
guarding external calls. Preserve normal diagnostic mapping for successful
results, and set memo to an empty diagnostic list when interpretation throws so
the document remains memoized and processing continues.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@packages/1-framework/3-tooling/language-server/src/project-artifacts.ts`:
- Around line 60-74: Wrap the interpretation call in the memoization block of
project artifact processing with a try/catch, following the existing pattern for
guarding external calls. Preserve normal diagnostic mapping for successful
results, and set memo to an empty diagnostic list when interpretation throws so
the document remains memoized and processing continues.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 77fb5666-bea6-47c8-bac5-d2652456b6bc

📥 Commits

Reviewing files that changed from the base of the PR and between fbf9549 and 054f9fa.

⛔ Files ignored due to path filters (6)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • projects/lsp-interpreter-diagnostics/plans/plan.md is excluded by !projects/**
  • projects/lsp-interpreter-diagnostics/slices/05-lsp-interpret/briefs/d1-r1.md is excluded by !projects/**
  • projects/lsp-interpreter-diagnostics/slices/05-lsp-interpret/briefs/d2-r1.md is excluded by !projects/**
  • projects/lsp-interpreter-diagnostics/slices/05-lsp-interpret/spec.md is excluded by !projects/**
  • projects/lsp-interpreter-diagnostics/trace.jsonl is excluded by !projects/**
📒 Files selected for processing (10)
  • packages/1-framework/2-authoring/psl-parser/src/interpret.ts
  • packages/1-framework/3-tooling/language-server/package.json
  • packages/1-framework/3-tooling/language-server/src/config-resolution.ts
  • packages/1-framework/3-tooling/language-server/src/diagnostic-mapping.ts
  • packages/1-framework/3-tooling/language-server/src/project-artifacts.ts
  • packages/1-framework/3-tooling/language-server/src/server.ts
  • packages/1-framework/3-tooling/language-server/test/config-resolution.test.ts
  • packages/1-framework/3-tooling/language-server/test/diagnostic-mapping.test.ts
  • packages/1-framework/3-tooling/language-server/test/project-artifacts.test.ts
  • packages/1-framework/3-tooling/language-server/test/server.test.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/1-framework/2-authoring/psl-parser/src/interpret.ts
  • packages/1-framework/3-tooling/language-server/test/diagnostic-mapping.test.ts
  • packages/1-framework/3-tooling/language-server/src/server.ts
  • packages/1-framework/3-tooling/language-server/test/project-artifacts.test.ts
  • packages/1-framework/3-tooling/language-server/test/server.test.ts
  • packages/1-framework/3-tooling/language-server/test/config-resolution.test.ts
  • packages/1-framework/3-tooling/language-server/src/config-resolution.ts

@SevInf
SevInf merged commit 7adfdb5 into main Jul 14, 2026
21 checks passed
@SevInf
SevInf deleted the tml-2984-slice-05-lsp-interpret branch July 14, 2026 16:10
SevInf added a commit that referenced this pull request Jul 20, 2026
…last-good project on reload failure (#974)

Slice 06 of the lsp-interpreter-diagnostics project
([TML-2984](https://linear.app/prisma-company/issue/TML-2984), follows
#939/#948/#971/#972) — the final build slice: config failures become
visible and non-destructive.

## Changes

- **Config-failure diagnostics** (`language-server/src/server.ts`): any
throw from the project-load flow (`loadConfig`, `createControlStack`,
input resolution — opaque runtime errors from executed TypeScript)
surfaces as one diagnostic on the **config-file URI** at (0,0)–(0,1)
(`PRISMA_NEXT_CONFIG_LOAD_FAILED`, message carries the error text).
Published via push **unconditionally** — the config file belongs to the
TypeScript language service, so pull never reaches this server for it
(tsserver `configFileDiag` precedent). Exactly-once per failed load is
structural (the diagnostic publishes from the single shared load
promise, guarded by `isCurrentLoad` so superseded loads stay silent).
Cleared on the next successful load and when the last document under the
config closes.
- **Last-good retention**: the loading entry now carries the previous
`ProjectState`; a failed *reload* resolves with the retained project —
schema documents keep serving their full diagnostics (parse,
symbol-table, and interpreter findings through the retained context)
with the config diagnostic alongside, instead of today's wipe-everything
(rust-analyzer `switch_workspaces` precedent: only switch to a broken
workspace if you have none at all). A failed *first* load keeps today's
behavior exactly.

## Why

Before this slice, breaking your config while editing meant every schema
diagnostic silently vanished — the server dropped the project and
cleared the markers, leaving no clue why. Now the editor tells you two
things at once: the config is broken (marker on the config file itself,
position (0,0) since no spans exist into executed TS) and your schema
work continues against the last working configuration. One deliberate
re-pin: the test that encoded destroy-on-reload was rewritten to encode
retention — that behavior change is this slice's entire charter.

One residual, by design of the lazy load lifecycle: after a failed
*first* load with no schema documents open, the config marker persists
until a schema document reopens (no load fires for a config with no open
inputs). Self-heals with any document open; exercised in the upcoming
playground QA.

Project spec + plan live under `projects/lsp-interpreter-diagnostics/`
(deleted at project close-out).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Preserve the previously successful (“last-good”) diagnostics when a
configuration reload fails, keeping affected schema documents managed
until a successful recovery.
* Emit `PRISMA_NEXT_CONFIG_LOAD_FAILED` configuration-load-failure
diagnostics exactly once per failing config, with deduplication across
concurrent loads and suppression for superseded failures.
* Clear configuration-failure diagnostics after a successful reload, and
when the last related managed document is closed.

* **Tests**
* Added/expanded end-to-end coverage for config reload failure/success
behavior, diagnostic deduplication, and cleanup/suppression.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
SevInf added a commit that referenced this pull request Jul 21, 2026
…facts

Six slices merged (#939, #948, #971, #972, #974); pattern doc landed in
docs/architecture docs/patterns/; retro lessons in drive/project and
drive/calibration; QA 11/11. History preserves spec, plans, briefs,
trace, and QA artifacts up to this commit.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
SevInf added a commit that referenced this pull request Jul 21, 2026
…facts

Six slices merged (#939, #948, #971, #972, #974); pattern doc landed in
docs/architecture docs/patterns/; retro lessons in drive/project and
drive/calibration; QA 11/11. History preserves spec, plans, briefs,
trace, and QA artifacts up to this commit.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
SevInf added a commit that referenced this pull request Jul 21, 2026
…facts

Six slices merged (#939, #948, #971, #972, #974); pattern doc landed in
docs/architecture docs/patterns/; retro lessons in drive/project and
drive/calibration; QA 11/11. History preserves spec, plans, briefs,
trace, and QA artifacts up to this commit.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
SevInf added a commit that referenced this pull request Jul 21, 2026
…of, retro landings, project deletion (#1012)

Close-out PR for the lsp-interpreter-diagnostics project
([TML-2984](https://linear.app/prisma-company/issue/TML-2984)). All six
build slices are merged (#939, #948, #971, #972, #974); this PR delivers
the remaining project-DoD items and burns the scaffolding.

## Changes

- **Pattern doc** (`docs/architecture
docs/patterns/capability-intersection.md`, linked from the catalogue):
the pattern this project proved — higher-layer capability type +
structural attachment at the factory + evidence-based guard at the
consumer, as the sanctioned alternative to type erasure across layer
frontiers. Reference implementations: the psl-parser capability, both
`prismaContract` providers, the LSP consumer.
- **QA-driven fix** (`language-server`): the headless QA run against the
real server binary caught a Blocker every automated gate missed —
config-load failures published `"Unexpected error"` instead of the
thrown text, because `config-loader` wraps raw throws in a
`CliStructuredError` whose `why` carries the detail and the server read
only `.message`. Fixed via the errors package's own shape guard
(`error.why ?? error.message`), pinned by a unit test that rejects with
a real `CliStructuredError` (the exact seam the mocks had hidden),
re-verified headless: 11/11 scenarios pass.
- **Retro landings**: `drive/calibration/failure-modes.md` gains F18
(CI-red on an unbriefed repo ratchet + misdiagnosed fix-brief);
`drive/project/README.md` gains the single-issue auto-close convention
and the PR-boundaries-under-scope-shift rule (fold, don't stack, when a
scope addition rewrites an unmerged slice).
- **Playground comment** corrected: the language server never invokes
`load`, but since the interpret capability it does exercise the pipeline
for diagnostics.
- **`projects/lsp-interpreter-diagnostics/` deleted** — spec, plans,
slice specs, briefs, trace, and QA artifacts are preserved in history up
to the deletion commit.

## Why

The project's purpose is shipped and proven: interpreter diagnostics
(relation resolution, type/codec binding, extension-block semantics)
appear live in editors from cached artifacts — lazily, memoized,
span-mapped, degrading byte-for-byte for capability-less configs — and
config failures surface on the config file with last-good retention
instead of silent wipes. The close-out QA run existed precisely to
exercise the one un-doubled link (real binary, real provider, real
protocol) and it earned its keep by finding the message-quality Blocker
fixed here.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved language-server config-load diagnostics by extracting
structured failure details for clearer, more relevant error messages.
* **Documentation**
* Clarified default PostgreSQL configuration behavior for interpreter
diagnostics, noting that config loading is not invoked.
* Updated contribution guidance on PR boundaries during mid-flight scope
shifts, including stacked PR handling.
* **Tests**
* Expanded language-server config failure tests to cover structured
unexpected errors and validate published diagnostic messaging.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant