You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit c02ba52
Browse filesBrowse the repository at this point in the historyBrowse files
fix(vscode): route merged single-file test runs to the deepest project (#60)
* fix(vscode): route merged single-file test runs to the deepest project
* refactor(vscode): route by published item roots and report dropped items skipped
* fix(vscode): route test runs by file or case identity, not file URI alone
* fix(vscode): include suite/case type in the run routing key
Copy file name to clipboardExpand all lines: CONTEXT.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -27,6 +27,10 @@ Glossary of terms used across rstack-editor. Code, docs, commit messages and rev
27
27
-**Config root** — the directory a tool's config is loaded from, which is also the directory the tool's process stands in. For the fmt server the editor anchors it at the workspace folder root, so it loads the config a terminal opened on that folder would, and a subproject that needs its own config becomes its own workspace folder. The test stack does not share this anchor: a project's cwd is set per project (for native configs, upstream's config-file-directory rule). _Avoid_: config directory, project root.
28
28
-**Ownership** — the editor-side rule choosing one config source for a tool's unit of work when both a native config and a Rstack config are present: the atomic tool's native config wins and the bridge yields. The unit is the tool's own — a project for test (one per config directory), a workspace folder for lint (one config choice per folder, locked for each lint runtime's lifetime). This rule exists only in the editor; upstream CLIs never face the choice, since each reads only its own config.
29
29
30
+
## test
31
+
32
+
-**Test file owner** — for one run request, a project whose root is deepest among the published items sharing a file URI, with ties sharing ownership. This per-request choice routes single-file/case selections across projects; explicit single-project selections and project-wide runs retain CLI scope.
33
+
30
34
## lint
31
35
32
36
-**Rslint core** — one `@rslint/core` package directory, identified by its real path (two copies of the same version are two cores; a symlink to one copy is that copy). Everything a lint runtime runs — the Go binary, config host, protocol version, plugin host — derives from one Rslint core. _Avoid_: core (bare), installation, binary.
Copy file name to clipboardExpand all lines: packages/vscode/AGENTS.md
+5-2Lines changed: 5 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,13 +5,13 @@ One extension replacing the standalone `rstack.rslint` and `rstack.rstest` exten
5
5
## The copies are intentional
6
6
7
7
-`stacks/lint` and `stacks/test` are deliberate near-verbatim copies of the upstream extensions, kept close to upstream so changes can be synced by diffing. Do NOT deduplicate or refactor across the two stacks — the duplication is the point; consolidation is a later, explicit phase.
8
-
- The copies diverge from upstream in exactly nine ways (the "adaptations" below). When syncing upstream, preserve them. A tenth divergence is either a bug or must be added to this list.
8
+
- The copies diverge from upstream in exactly ten ways (the "adaptations" below). When syncing upstream, preserve them. An eleventh divergence is either a bug or must be added to this list.
9
9
-**Tracked upstream state.**`stacks/lint` is synced to web-infra-dev/rslint `packages/vscode-extension` at **39536fd6** (#1617 — per-document core resolution, `CoreResolver` + `RuntimeManager`, `corePath`, PnP removed) and **892482e0** (#1630 — `configPath` on `rslint/configRefresh`). Targeted later ports are **84f9c9b5** (#1967 — languageclient-owned live LSP tracing) and **b7176723** (#1951 — remove legacy JSON config watching); the Unicode BOM E2E comes from **5fc197a5** (#1560), with its native-config fixture shape from **b7176723**. `CoreResolver.ts` / `RuntimeManager.ts` / `WorkspaceDocumentRouter.ts` / `Rslint.ts` are the files to diff when syncing further; record the new commits here when you do.
10
10
- **Ahead of upstream — offer these back when syncing** (bug fixes, not adaptations): (1) `RuntimeManager.reconcile` resolves the document's core **before** sweeping pending uses (`planDocumentCore`), so a reconcile landing on the key a pending start is already producing adopts that start instead of tearing it down mid-`initialize` — the teardown made vscode-languageclient force-notify ("couldn't create connection to server") whenever the register-time pass, a detection change and `didOpen` landed inside one worker startup window (`tests/stacks/lint/runtimeManager.test.ts`). (2) `Rslint.close()` gives a still-Starting language client a bounded chance to settle before tearing down its transport, so a legitimate mid-start close (document closed during start, core key changed) stops cleanly instead of triggering the same force-notified toasts. (3) The registry-harness E2E gives its never-settling startup operation 500ms to begin and accepts only the in-flight timeout message, so a stalled runner cannot satisfy the assertion through the already-expired path (`e2e/lint/suite/registry-harness.test.ts`). (4) `Project.retryFailedConfig()` keeps a failed Rstest project and retries its config evaluation in place with one single-flight promise, so repeated dependency-change passes neither overlap workers nor repeat an unchanged not-installed warning. (5) `RuntimeManager` retires a stopped client even when its resolved key is unchanged. The existing closing barrier and pending-use adoption share one replacement across documents; running and starting clients remain untouched (`tests/stacks/lint/runtimeManager.test.ts`).
11
11
12
12
-**Targeted Rstest lifecycle port:**`RstestApi.getNormalizedConfig()` closes its worker in `finally`, including rejected config evaluation, matching web-infra-dev/rstest `packages/vscode/src/master.ts` at `d82db4fc31a61ee74b2a74917f14a458e1bca419`. This fixes a leak in our older copy; it is already fixed upstream. Dependency passes retry failed projects, including real config errors, while preserving single-flight loading and worker cleanup.
13
13
14
-
## The nine adaptations
14
+
## The ten adaptations
15
15
16
16
1.**Shell activation** — stacks never self-activate; `register()` returns fast and never blocks on starting a server/worker.
17
17
2.**Namespace** — everything user-visible is `rstack.*`. Legacy `rslint.*` / `rstest.*` settings and command ids are not read, aliased or migrated (breaking old settings and keybindings was an accepted cost).
@@ -23,6 +23,8 @@ One extension replacing the standalone `rstack.rslint` and `rstack.rstest` exten
23
23
8.**Self-documenting Rslint diagnostics** — client-side providers parse Inline directives into per-rule hover, DocumentLink and underline-decoration affordances (the hover renders `Rslint(rule-id)`, the shape VS Code gives the published diagnostics), and the router enriches today's `[rule-id] message` diagnostics with a derived Rule docs link. No rule metadata or network lookup is bundled (ADR 0004). The hover provider yields whenever the owning language client's resolved capabilities advertise `hoverProvider`; an optional `Rslint.onClosed` hook identity-safely prunes the controller's capability mirror; the diagnostic synthesis is removed once upstream publishes `code` / `codeDescription` natively.
24
24
9.**Color env parity with the CLI** (test) — upstream hard-codes `FORCE_COLOR: '1'` into the worker's spawn env; ours mirrors the CLI's `getForceColorEnv` (rstest `packages/core/src/utils/logger.ts`) instead (`stacks/test/shared/colorEnv.ts`): the master injects `FORCE_COLOR=1` into the composed spawn env only when neither `FORCE_COLOR` nor `NO_COLOR` is already set (marking the injection with `RSTACK_FORCE_COLOR_INJECTED`), and the worker retracts the marked injection right after config load if the config set `NO_COLOR` — the CLI's own decision point. Otherwise a project whose config sets `process.env.NO_COLOR` (rstack-cli does) hits Node's "'NO_COLOR' env is ignored" warning in every pool process. A user-set `FORCE_COLOR` beside a config-set `NO_COLOR` still warns, exactly as the bare CLI does.
25
25
26
+
10.**Test file ownership** (test) — publication mirrors the CLI per project. When a request carries the same file or the same case from several projects (merged gutter, run-at-cursor, run-current-file; all three profiles reach `startTestRun`), only items of the deepest project root run and the others are reported skipped to clear stale merged gutter state — implemented in `runRouting.ts`, `index.ts` (`startTestRun`), and `master.ts` (`RstestApi.project` made public). Explicit single-project selections, project/folder/Run All, and `rstack.rstest.runInTerminal` (VS Code supplies one explicitly picked item) keep CLI scope.
27
+
26
28
## Rules
27
29
28
30
-**Pre-1.0.0 the extension breaks freely.** No compatibility is owed with earlier unpublished states of this extension — settings, command ids and behavior may change without deprecation paths, and dead compat code for them is removed, not kept. No settings migration exists either — not for earlier states of this extension, and not for the two retired standalone extensions (removed in #15; users re-enter their settings under `rstack.*`). Testing and fixtures track only the latest published releases, pinned exactly and bumped by Renovate; a green E2E run speaks only for those releases. `SUPPORT_MATRIX` floors are the minimum versions the extension accepts: each entry is the lowest release evidence shows works with the current code, and its comment records that evidence. Move a floor only when a change makes older releases stop working, never because a devDependency or fixture moved. Raising a floor needs no transition story; the status names the required version.
@@ -41,6 +43,7 @@ One extension replacing the standalone `rstack.rslint` and `rstack.rstest` exten
41
43
42
44
## Gotchas — decisions that look wrong but aren't
43
45
46
+
-**Why test file ownership exists** (adaptation 10): native configs can overlap upstream too, and the Rstack bridge adds a root contender. VS Code merges same-location items into one gutter action; routing chooses among the request's published items, which already reflect each config's include/exclude rules.
44
47
- fmt's `handleShowMessage` suppresses only the classified config-dependency Error. Non-classified `window/showMessage` notifications are re-presented exactly as vscode-languageclient's default handler would (Error/Warning/Info toast). An exact-prefix `rs fmt cannot format this workspace:` Error that is not a missing dependency also reports `crashed` and one Output error line per distinct message; the known config error survives server restarts so polling continues until a format produces edits. This passes through the server's protocol UI request unchanged; "stacks own no UI chrome" constrains UI the stack originates, not protocol UI it relays. Warning and error episodes end on nonempty formatting edits, not merely a response with no new notification: the server returns empty edits on failure and deduplicates showMessage.
45
48
- The lint × `rstack.config.*` bridge stays thin on purpose: only a root Rstack config can claim a bridged folder, any native config anywhere in the folder wins ownership, and the worker evaluates rstack's published shim from the folder root. Never generate a shim, load the Rstack config in the extension host, or interpret `define.lint()` ourselves.
46
49
-**Yarn Plug'n'Play is unsupported by decision, extension-wide.** Every stack resolves through physical `node_modules` (`shared/packageResolve.ts`, `resolution.ts`'s rstack → `@rslint/core` chain, the fmt bin probe, the rstest package lookup) and the lint worker's own `createRequire` from the core directory does too. Lint once carried a `.pnp.cjs` branch for the find-`@rslint/core` hop only; nothing after that hop (config evaluation, plugin resolution, the other stacks) had PnP hooks, so it never produced a working folder, and upstream removed its own PnP path in the same refactor that introduced `corePath`. Real support would be a PnP editor-SDK-shaped project across all three stacks, not a resolver branch — do not reintroduce one.
0 commit comments