Context
2026-07-26: hover died editor-wide. Tutorial fixture prompts (apps/site/content/tutorial/*/{files,solution}/greeting.napl) collided with the examples corpus at the repo-root workspace: discovery aborted on duplicate module 'greeting', and the single napl-lsp process died with it, killing hover for src/** too.
In-session fixes (landing today): fixture files renamed off prompt extensions with loader display-name mapping; a discovery smoke test now runs the pinned binary's status from repo root and src/ in the standing test gate so colliding content can never land silently again.
Remaining toolchain hardening (this issue)
- The LSP must degrade gracefully when workspace discovery fails: surface the duplicate-module error as a diagnostic on the offending files, fall back to single-file behavior elsewhere, never exit. A dead server on bad content is the real defect.
- Discovery ignore configuration: lock.json gains an ignore-path list consumed by the walker (paths_walk), so content trees (apps/site) can be fenced out of a workspace explicitly instead of by file-extension dodges.
Constraints
Prompt-only implementation (paths_walk, lsp shell, lock schema prompts + conformance cases). Cannot take effect before the store campaign's rust-final repin — schedule after it.
Acceptance criteria
- A duplicate-module workspace yields hover everywhere except a diagnostic on the colliding files; the server stays alive.
- lock.json ignore paths are strict-parsed, honored by discovery, covered by conformance cases (ignored-dir collision does not abort).
- The tutorial fixture renames can then be reverted if desired (fenced via ignore config instead).
Context
2026-07-26: hover died editor-wide. Tutorial fixture prompts (apps/site/content/tutorial/*/{files,solution}/greeting.napl) collided with the examples corpus at the repo-root workspace: discovery aborted on duplicate module 'greeting', and the single napl-lsp process died with it, killing hover for src/** too.
In-session fixes (landing today): fixture files renamed off prompt extensions with loader display-name mapping; a discovery smoke test now runs the pinned binary's status from repo root and src/ in the standing test gate so colliding content can never land silently again.
Remaining toolchain hardening (this issue)
Constraints
Prompt-only implementation (paths_walk, lsp shell, lock schema prompts + conformance cases). Cannot take effect before the store campaign's rust-final repin — schedule after it.
Acceptance criteria