| analytical_package | goal
Replace the TypeScript analysis engine (parse-for-index, extract, SQLite index, search, export) with a Rust library behind the existing `createAnalysisRuntime` / `AnalysisApi` facade, shipped as per-architecture binaries and per-target VSIXes.
constraints
- Distribution: [distribution.rust_binary_distribution] + [distribution.vsix_export] — npm optional platform packages and host-targeted VSIX; website downloads and GitHub-release postinstall out of scope.
- Shared on-disk [ideas_index] under `<base>/.reqlan` is schema v4 rusqlite (native required; no sql.js fallback).
- The language server is [lsp_rust.language_server_rust]. This analytical plan does not replace that process. Do not switch the language to tree-sitter ([grammar_and_parser]).
- Port the context-sensitive lexer ([rust_port.lexer_rust]) rather than a parser-generator that cannot honour [syntax] brace/fence rules.
- [indexer.nonblocking_index] and [parser_lexer.parse_budget_timeout] still apply; [development_core.rust_mindset] and [constitution.supply_chain] (mature crates).
- Extension host requires the host-matching napi `.node` from the per-target VSIX ([distribution.extension_host_target]).
- Zustand host state, webviews, and HTML-export client JS stay TypeScript.
steps
1. Scaffold `crates/` + golden tests vs Langium ([rust_port.rust_crate_layout]).
2. Lexer, then parser with recovery and budget ([rust_port.lexer_rust], [rust_port.parser_rust]).
3. Extractor + rusqlite + incremental sync ([indexer.indexer_rust]).
4. Search analysers ([rust_port.search_rust]).
5. Export snapshot + writers; keep interactive HTML JS ([rust_port.export_rust]).
6. napi-rs per-arch host packages; CLI then MCP then extension via platform VSIX ([rust_port.native_bridge], [rust_port.cutover]).
7. Publish on `analytical/v*` and ship per-target VSIXes ([distribution.rust_binary_distribution], [distribution.vsix_export]).
open
- Language-server process: [lsp_rust.language_server_rust]. CLI `parse` uses the core Rust engine. | in-progress | | `packages/analytical` ( `@reqlan/analytical` ) is the shared requirement graph index and analysis layer.
It owns the [indexer]: extracts ideas and edges into a rusqlite store via the core native engine ( [workspace_index] ), holds Zustand analytical state, and exposes analysers and an analysis API.
Headless CLI / MCP entry is `@reqlan/analytical/core` via `openAnalysisApi` ( native required; no Langium ).
Consumers: [extension_package] ( thin editor adapter ), [mcp_package], [cli_package].
Depends on [language_package] for the editor LSP only. Published to npm alongside [cli_package]; version graph role: [package_versioning].
Rust engine port ( lexer / parser-for-index, indexer, search, export ): [rust_port.analytical_rust_port], shipped per [distribution.rust_binary_distribution]. | 0.167 |
| analytical_rust_port | goal
Same AnalysisApi behaviour, faster and native, distributed as per-arch npm packages and per-target VSIXes without breaking the shared `<base>/.reqlan` index. The editor LSP is Rust ([lsp_rust.language_server_rust]).
constraints
- Ship per [distribution.rust_binary_distribution] and [distribution.vsix_export]: npm platform packages + host-targeted VSIX; website listing and GitHub-release postinstall out of scope.
- On-disk ideas index schema stays compatible ([indexer.index]) so TS and Rust share application memory during cutover.
- Syntax requirements stay in [syntax]. The language server parses with `reqlan-parse` ([lsp_rust.language_server_rust]). Do not switch the language to tree-sitter (["../core-architecture.rq".grammar_and_parser]).
- Port the context-sensitive lexer, not a naive parser-generator ([parser_lexer.lexer_bridge_to_syntax], [syntax_edges.nested_curly_braces], [syntax_edges.context_sensitive_lexer_scaling]).
- Honour [indexer.nonblocking_index], [parser_lexer.parse_budget_timeout], [development_core.rust_mindset], [constitution.supply_chain].
- Extension host loads the host-matching napi `.node` from the per-target VSIX ([distribution.extension_host_target]); missing core engine is a hard error (no sql.js fallback).
- Interactive HTML graph/search JS and graph physics stay JS assets ([html_export.html_export_graph_layout]).
- Comment-file indexing is [indexer.index_code_files] (native sync, not a Langium comment-grammar pass).
steps
1. Scaffold crates + CI + golden harness ([rust_crate_layout]).
2. Lexer then parser with recovery and budget ([lexer_rust], [parser_rust]).
3. Extractor + rusqlite index + incremental sync ([indexer.indexer_rust]).
4. Search and analysers ([search_rust]).
5. Export snapshot and writers ([export_rust]).
6. napi-rs loader in `@reqlan/analytical`; CLI/MCP first ([native_bridge], [cutover]).
7. Publish platform packages on `analytical/v*` and ship per-target VSIXes ([distribution.rust_binary_distribution], [distribution.vsix_export]).
open
- Language-server process: [lsp_rust.language_server_rust]. CLI `parse` uses the core Rust engine. | in-progress | | Port ["../core-architecture.rq".analytical_package] to Rust: lexer, parser ( index path ), extractor, SQLite index, search, and export.
`@reqlan/analytical` remains the published JS facade ( `createAnalysisRuntime` / `AnalysisApi` / Zustand host state ).
Native work lives in a `crates/` Cargo workspace and ships as per-architecture binaries per [distribution.rust_binary_distribution].
The editor language server is [lsp_rust.language_server_rust]. This analytical port does not replace that process.
Component plans: [rust_crate_layout], [lexer_rust], [parser_rust], [parser_align], [indexer.indexer_rust], [search_rust], [export_rust], [native_bridge], [cutover]. | 0.243 |
| rust_binary_distribution | goal
Ship per-architecture core engine binaries beside `@reqlan/analytical` so CLI, MCP, and per-target VSIXes can load the Rust engine for the extension-host platform.
constraints
- optionalDependencies (not devDependencies) for runtime consumers.
- VSIX binaries come from Azure `build_native` on the `ext/v*` git tag, not from npm.
- Trusted publishing and `analytical/v*` tagging stay [npm_distribution] / [release_tagging] for CLI/MCP.
- gnu-only linux; musl and GitHub-release postinstall out of scope.
- Website binary listing deferred.
- Do not publish `@reqlan/analytical` until every platform package of that version is deployed ([npm_distribution]).
steps
1. Scaffold six platform packages with os/cpu and the napi binary. (done)
2. Wire optionalDependencies on published `@reqlan/analytical` only; git omits them so Changesets can ignore platform packages. (done)
3. Cross-compile `reqlan-napi` for [native_targets] on the npm channel. The platform package contains only the `.node`. That job does not build `reqlan-lsp`. (done in deploy-npm.yml)
4. Publish platform packages on `analytical/v*` before `@reqlan/analytical`.
5. Prefer optionalDependency resolution in the loader; keep crates/target fallback for local dev by walking to repo-root `crates/Cargo.toml` (not `packages/crates` from `out/native`). (done) | in-progress | | One platform-specific npm package per [native_targets] tuple: `@reqlan/analytical-<platform>-<arch>` ( napi suffixes: `linux-x64-gnu`, `linux-arm64-gnu`, `darwin-x64`, `darwin-arm64`, `win32-x64-msvc`, `win32-arm64-msvc` ).
Each package declares `os` and `cpu`, contains the matching core engine `.node`, and uses the `@reqlan/analytical` package. json version as the single source of truth. ["../../scripts/prepare-native-packages.mjs"] writes that version. Changesets ignores `@reqlan/analytical-*` in ["../../.changeset/config.json"]. Git `@reqlan/analytical` does not list platform packages as `optionalDependencies`; this workspace links them through `packageExtensions` in ["../../pnpm-workspace.yaml"]. The published tarball lists pinned optionalDependencies ( `--publish-versions` ) ( [version_management] ).
CLI and MCP install the host-matching binary from those published optionalDependencies.
The published tarball runs ["./native_host_binary.rq".published_host_native_install] so a host miss prints a warning.
Published on the existing `analytical/v*` channel ( [npm_distribution] / [release_tagging] ); not a separate tag channel.
The napi build runs when this channel moved: a direct `analytical/v*` tag, or `analytical_tag` from [deployment_flow]. The first npm tag ( `npm_ref` ) can be `language/v*` in the same release, so that ref is not the native-build gate.
Website download listing and GitHub-release postinstall are later follow-ups ( out of scope here ).
Engine port: ["../core_analysis/rust_port.rq".analytical_rust_port] / ["../core_analysis/rust_port.rq".native_bridge].
Per-target VSIX packaging uses the same package layout under ["../../packages/analytical-native/"], filled by Azure from this git commit ( [vsix_export], [vsix_native_not_from_npm] ). npm tarballs of those packages are for CLI / MCP only.
`collect-napi-binary.mjs` copies `reqlan-lsp` only with `--with-lsp`. The npm workflow does not pass that flag. Azure does, because the VSIX ships `bin/reqlan-lsp` ( [vsix_export] ).
Implementation: ["../../packages/analytical-native/"], ["../../scripts/prepare-native-packages.mjs"], ["../../scripts/require-natives-published.mjs"], ["../../packages/analytical/scripts/check-host-native.mjs"], ["../../.changeset/config.json"], ["../../.github/workflows/deploy-npm.yml"] build-native job, ["../../azure-pipelines.yml"] build_native job. | 0.380 |
| vsix_export | goal
Ship six host-targeted VSIXes, each containing only the core engine `.node` for that extension-host platform.
constraints
- Keep --no-dependencies for the bundled TS graph; stage only the matching native package.
- Git at the `ext/v*` tag is canonical ([vsix_native_not_from_npm]). Azure compiles the [native_targets] matrix from that commit and packs those binaries.
- npm platform packages remain a CLI/MCP install path on `analytical/v*` ([npm_distribution] / [rust_binary_distribution]). They are not an input to Azure.
- `vscode:prepublish` must not restage the host native addon (`--skip-native`); each VSIX `native/target.json` must equal that VSIX `--target`.
steps
1. Stage matching `@reqlan/analytical-<platform>-<arch>` into extension `native/` before vsce. (done)
2. Package with `vsce package --target <tuple> --no-dependencies` for each [native_targets] entry; skip native restage in vscode:prepublish; verify packed `native/target.json`. (done)
3. Compile the [native_targets] matrix in Azure and prepare packages from git versions + those artifacts. (done)
4. Publish each target to Marketplace and Open VSX ([extension_distribution], [openvsx_registry]). | in-progress | | One VSIX is built per [native_targets] tuple via `vsce package --target <tuple> --no-dependencies`.
Each VSIX keeps today's esbuild-bundled JS ( TS dependency graph stays bundled ); only the matching platform native package is staged into the VSIX so other targets' binaries are excluded.
The same VSIX packs `bin/reqlan-lsp` for that target ( ["../extension/language/support/language-server-rust.rq".language_server_rust] ). Azure `collect-napi-binary.mjs --with-lsp` copies that binary into the native artifact. The pack script checks that zip entry by `file_size`. It does not read the binary through a pipe. The napi addon stays for the index host. npm platform packages do not contain it ( [rust_binary_distribution] ).
Stamp `targetPlatform` so Marketplace / Open VSX route by extension host ( [extension_host_target], ["./native_host_binary.rq".native_host_binary_distributed] ).
Artifact name shape: `reqlan-extension-<version>-<target>.vsix`.
The VSIX includes logo assets from the extension media build: PNG for marketplace icon, language file icon, activity bar, and README; WebP as a raster fallback.
Implementation: ["../../scripts/package-extension-targets.mjs"], ["../../scripts/prepare-native-packages.mjs"], ["../../scripts/collect-napi-binary.mjs"], ["../../packages/extension/.vscodeignore"] ( `native/`, `bin/` ), ["../../azure-pipelines.yml"]. | 0.446 |
| language_server_rust | goal
A Rust language-server binary replaces the Langium process. Open buffers parse with reqlan-parse. Workspace names come from the ideas index. Closed files have no retained syntax tree.
constraints
- vscode-languageclient stays. Transport becomes stdio.
- lsp-server and lsp-types only. No second parser.
- Open-file links follow open_file_algorithm.
- UTF-8 spans convert to UTF-16 LSP positions.
- TextMate stays a checked-in grammar. The editor paints it before semantic tokens.
- With the rust engine, non-.rq comment links come from the server. The node engine keeps the host provider.
- Per-target VSIX ships bin/reqlan-lsp. The napi addon stays for the index host.
- Default engine is rust. Node starts only as a fallback.
steps
1. Write this idea and point language_server and grammar_and_parser at it.
2. Scaffold reqlan-lsp: initialize, didOpen, didChange, didClose, parse diagnostics.
3. Launch it from the extension. Default is rust.
4. Port open-file features: tokens, links, definition, hover, highlight, diagnostics.
5. Read the ideas index for completion, rename, code actions, lenses, and inlays.
6. Pack the binary in the VSIX matrix.
7. Keep Langium only for host helpers. The server process does not load it when the engine is rust.
open
- Host move/delete/barrel planners still use Langium DI. | in-progress | | A Rust binary replaces the Langium language-server process.
The extension launches `reqlan-lsp` over stdio.
Open `.rq` buffers parse with [parser_rust].
The open sequence is ["open-file-sequencing.rq".open_file_algorithm].
Workspace names and rename targets come from the ideas index under [application_memory].
Inbound hints wait for the host snapshot of that index.
The inbound inlay hover is markdown. It lists each referencer as a file link.
An idea hover shows styled idea content when ["../syntax/features-syntax.rq".idea_content_tooltip] is on.
A closed file has no retained syntax tree.
Go-to-definition cost is ["../syntax/features-syntax-highlighting.rq".reference_goto_definition_speed].
When the engine is `rust`, the server also serves `rq:[…]` document links, go-to-definition, and missing-idea diagnostics in non- `.rq` comments.
One resolution supplies the link, the definition target, and the underline.
The host strips file document links; Ctrl + click uses definition ( ["../syntax/features-syntax-highlighting.rq".editor_reference_activation] ).
The host serves those links when the engine is `node`.
Host commands prefer LSP custom requests, napi extract, and the ideas index.
Move / delete planners still use Langium until index-backed planners land.
The setting `reqlan.languageServer.engine` selects the binary.
The default is `rust`.
`node` remains only when the setting says so, or when the binary is not on disk yet.
A local extension build compiles this binary with the napi addon ( [extension_host_native_stage] ).
The extension launches `bin/reqlan-lsp`, else that release build. It never launches a debug build, because a debug build is slow and the extension build does not refresh it.
Code actions match ["../vsc-primitives.rq".code_actions]: ignore, create below, import fixes, search or wrap, idea move and delete, and barrel page.
Attribute and name catalogs drive completion. Rename and find-references use open buffers plus the ideas index.
Inlay hints honour `reqlan.referencesInlayHints.enabled` and the host inbound snapshot.
An import link uses the parser token span ( [import_from] ).
The path links to the file.
An imported idea name and its alias each link to that declaration.
A namespace reference links the alias and the idea as separate names.
A missing leaf reports an unresolved idea on that name.
Related: [language_server], [grammar_and_parser], [analytical_rust_port], [vsix_export]. | 0.580 |
| indexer_rust | goal
Native WorkspaceIndex: same rows and incremental behaviour, no Langium on the index path.
constraints
- Schema v4 rusqlite only (no sql.js fallback) after ["../core_analysis/rust_port.rq".cutover].
- [nonblocking_index] and [index_diagnostics_timing] still apply.
- Wildcard fan-out stays [wildcard_reference_edges].
- Extension requires the host-matching core engine `.node` from the per-target VSIX.
steps
1. Rust AST → IdeaRecord / EdgeRecord parity tests against the current extractor.
2. rusqlite store + migrations matching SCHEMA_VERSION 4.
3. Soft/hard sync, mtime skip, cancel, diagnostics.
4. Wire through ["../core_analysis/rust_port.rq".native_bridge] once parse+extract golden tests pass.
open
- Richer per-file timing rows from Rust sync into the diagnostics store. | in-progress | | The [index] engine ( parse-for-index → extract → SQLite persist → incremental sync ) should be written in Rust.
Crate: `reqlan-index` over `reqlan-parse` per ["../core_analysis/rust_port.rq".rust_crate_layout].
Extractor ports ["../../crates/reqlan-index/src/extract.rs"] including [wildcard_reference_edges].
Store ports schema v4 ( ["../../packages/analytical/src/index-store/schema.ts"] ) via rusqlite; diagnostics live in `index-diagnostics.sqlite` on the same engine.
Sync keeps [nonblocking_index]: per-file upsert, mtime skip, hard rebuild, cancellable progress.
Not the Langium LSP. Comment-file indexing: [index_code_files]. | 0.172 |
| string_and_reference_apostrophes | goal
Allow reqlan string literals in imports, idea names, and bracketed file/reference targets to use either double or single quotes with backslash escaping.
constraints
- [string_literals] documents escaping rules; double-quoted syntax must remain valid.
- [reference_file] bracketed quoted paths must resolve with either quote style.
- Embedded scanners and comment reference parsing must not treat // inside quoted strings as comments.
steps
1. Extend grammar STRING terminal and shared unquote helper for both quote styles.
2. Update import/path/comment/embedded reference scanners and completion to accept single-quoted literals.
3. Update TextMate highlighting for single-quoted strings.
4. Add parsing and reference-resolution tests for single-quoted paths and idea names.
open questions
- None for initial scope; both quote styles apply everywhere STRING is used. | | | strings should use double or single apostrophes interchangeably and support backslash escapes. | 0.040 |
| phase_4_write_the_eleven | order (
agent_context_showcase
interlock_showcase
broken_links_showcase
firmware_cloud_contract_showcase
audit_trail_showcase
module_surface_showcase
test_proves_showcase
legacy_archaeology_showcase
graph_view_showcase
attribute_dialect_showcase
antipatterns_showcase
) | done | | Write the eleven, one at a time, each validated by [phase_1_parse_gate]
before moving on.
Flagships first — [agent_context_showcase], [interlock_showcase],
[broken_links_showcase], [firmware_cloud_contract_showcase] —
so the format can be judged before committing to all eleven. | 0.040 |