AI Primitives Hub Full Test Plan
All 19 plans covering the manual verification surface across the extension, the CLI, and the published packages.
This page is not the release gate — Golden Path Test Cases is. Run the golden path for every release. Come here when a PR touches a specific area and you want something concrete to run, or when the whole surface needs reviewing end to end.
| Page | Scope |
|---|---|
| Golden Path Test Cases | The three mandatory scenarios — start here |
| Testing | How to run the automated suites |
| Validation | Local CI simulation, per-commit checks |
| Releasing | Version bump and publish mechanics |
| Full Test Plan (this page) | Area-by-area manual coverage |
Relationship To The Golden Path
Rows marked ⭐ are part of the golden path. The golden path page is the lightweight run sheet for those — three chained scenarios with the setup they need, and nothing else. Coverage detail lives here, not there; here the ⭐ rows also sit in their home plan so an area-focused run does not miss them.
| Golden scenario | Plans it draws on |
|---|---|
| G1 — Collection user | TP-01, TP-04, TP-05, TP-07 |
| G2 — Collection author | TP-14, TP-05 |
| G3 — Update | TP-10 |
Reading The Automation Column
Every scenario carries the automation that already covers it, so manual effort lands where it is actually needed rather than re-proving what vitest and Mocha already assert. Growing this coverage is tracked in #370.
| Marker | Meaning | How to treat it |
|---|---|---|
| 🟢 Auto | The logic is asserted by a test suite | Quick confirmation. First thing to drop when short on time |
| 🟡 Partial | Automation covers the logic, but not the real host, network, filesystem or rendering | Focus on the named gap, not the logic |
| 🔴 Manual | No automated coverage exists | Full attention. These justify the whole page |
Suite paths are relative to apps/vscode-extension/ for test/…, and to the repository root for packages/… and lib/….
A useful shortcut: if a plan is entirely 🟢, running it is a smoke test. If it contains 🔴 rows, those rows are the plan.
Step-level breakdowns. TP-07, TP-11 and TP-17 each carry a Coverage breakdown section decomposing every scenario into the individual assertions behind it, as [x] covered or [ ] gap. Those three were done first because they carry the release risk — TP-11 and TP-17 are the non-waivable plans, and TP-07 is the core value path. The remaining plans currently document coverage at suite level only; extending them is tracked in #370.
🟢 almost always means "green against a fake"
Before treating a 🟢 as settled, check what the suite talks to. Very little here touches a real network, filesystem or editor:
| Double | Where | What it hides |
|---|---|---|
nock — canned HTTP | 11 suites, including every extension test/e2e/** | Real GitHub redirects, rate limits, auth challenges, pagination, archive layout, ETag behaviour |
Fake ports — injected HttpClient/TokenProvider, InMemoryFileSystem | packages/* (19 suites use InMemoryFileSystem) | No real HTTP, no real disk: path casing, permissions, symlinks, partial writes |
Mocked vscode — test/mocha.setup.js intercepts require('vscode') | Everything outside test/suite/** | Activation order, webview lifecycle, context keys, real auth providers |
Real filesystem — os.tmpdir(), or a repo-local temp dir | ~25 extension and CLI suites, e.g. user-scope-service, repository-scope-service, mcp-config-service, scaffold-command | Nothing, at the fs layer. Still one platform and one host per run |
Practical consequence: the install and update flows are 🟢 largely on the strength of nock plus a mocked vscode, so they have never run against real GitHub inside a real editor. Host path routing is the happier case — it is asserted against a real filesystem.
When closing a gap for #370, a new test that fakes the very boundary carrying the risk buys little. Prefer real-fs or contract tests where the risk is I/O.
Host Coverage — VS Code and Kiro
The extension does not just install for Kiro and VS Code — it runs inside both. Kiro is a VS Code fork, so the same VSIX is loaded by both editors and has to behave correctly in each. Every plan below that touches the filesystem or the UI is therefore run twice: once with the extension running in VS Code, once with it running in Kiro.
Nothing is tested in Kiro. The extension runs there fine — Kiro is a VS Code fork and loads the same build — but no automated suite exercises it, because test/runExtensionTests.js calls runTests() without a version option and so always launches VS Code.
That does not mean Kiro behaviour is untested. Be precise about the split, because it changes where manual effort is worth spending:
| Kiro concern | Status |
|---|---|
Path routing (.kiro/, steering/ folding, skills dirs, git-exclude, unsync) | ✅ Covered against a real temp filesystem — test/services/repository-scope-service.test.ts (Host-Aware Destinations), test/services/user-scope-service.test.ts |
Layout config for the kiro target | ✅ packages/infra/test/stores/layout-config-store.test.ts, packages/app/test/writers/file-tree-writer.test.ts |
| Signal → target mapping | ✅ packages/infra/test/host-app/host-app-target.test.ts |
| Activation, UI, webviews, settings inside Kiro | ❌ Not tested there — manual only |
The real appName/uriScheme a shipped Kiro build reports | ❌ Untested — the one input that decides whether the vscode fallback fires |
Worth knowing while reading the rest of this page: the harness also never reads the
VSCODE_VERSIONenvironment variable, even though the CI matrix sets it tostableandinsiders. Both matrix legs currently exercise the same default build, so "tested on Insiders" is not something this document can rely on.
How the host is detected
resolveHostApp (in packages/infra/src/host-app/host-app-target.ts) matches the lowercased combination of vscode.env.appName and vscode.env.uriScheme against ordered rules:
| Signal contains | Resolved target |
|---|---|
kiro | kiro |
windsurf or devin | windsurf |
insiders | vscode-insiders |
| anything else | vscode (the default .github/ layout) |
The failure mode to watch for: detection falls back to vscode when a host is unrecognized. In Kiro that fallback is silent and wrong — content lands in .github/ instead of .kiro/. The extension logs the resolved target on every detection ([host-app] detectHostApp: appName="…", uriScheme="…" -> …), so the Output channel is the fastest way to confirm the host was identified correctly.
packages/infra/test/host-app/host-app-target.test.ts asserts the signal→target mapping for known inputs. What it cannot assert is what appName and uriScheme a real Kiro build actually reports — which is precisely the input that decides whether the fallback fires.
Which plans run per host
| Plan | VS Code | Kiro | Note |
|---|---|---|---|
| TP-01 Fresh install and activation | ✅ | ✅ | Host detection happens here |
| TP-02 First-run setup | ✅ | ✅ | |
| TP-06 Marketplace discovery | ✅ | ✅ | Webview theming differs between the two editors |
| TP-07 Bundle installation | ✅ | ✅ | Different destinations and different kind routing |
| TP-08 / TP-09 Profiles | ✅ | ✅ | Activation writes primitives to the host layout |
| TP-11 Repository scope and lockfile | ✅ | ✅ | Host detection decides .github/ vs .kiro/ |
| TP-12 Uninstall and cleanup | ✅ | ✅ | |
| TP-15 CLI | ✅ | ✅ | Via explicit kiro and vscode targets, not detection |
| TP-17 Upgrade and migration | ✅ | ✅ | |
| TP-03, TP-04, TP-05, TP-10, TP-13, TP-14, TP-16, TP-18, TP-19 | ✅ | — | Host-agnostic; run once unless your change touches host handling |
Claude Code and Windsurf are install targets, not hosts that run this extension — Claude Code is a CLI and never loads it. Cover them through TP-07 and the CLI's explicit target flags.
How To Read This Page
The plans run in the order written — a user journey where state carries forward, so you are not rebuilding fixtures for every case. Running a subset is normal: pick the plans covering what changed, and check the preceding plans for state a chosen plan depends on.
Plans are happy paths by default — resilience and performance belong in automation, not here. The exception is a small set of rows marked "Reported from testing": failure modes someone actually hit, where the product fails silently or blocks the user with no way out. Those earn a place because a passing happy path does not reveal them.
TP-01 — Fresh Install and Activation
Run the whole plan twice — once in VS Code, once in Kiro.
| # | Scenario | Expected result | Automation → where to focus |
|---|---|---|---|
| ⭐ 1.1 | Install the compiled extension into a brand-new VS Code profile, reload, and confirm it runs | Activates; Output channel shows a clean startup with no errors | 🟡 test/suite/integration-scenarios.test.ts activates in a real VS Code host |
| ⭐ 1.2 | Install the same build into a clean Kiro profile, then reload | Activates identically; no errors caused by the fork | 🔴 No test covers Kiro — verify manually |
| ⭐ 1.3 | In each host, read the [host-app] detectHostApp: line in the Output channel | Resolves to vscode in VS Code and kiro in Kiro — not the vscode fallback while running in Kiro | 🟡 packages/infra/test/host-app/host-app-target.test.ts covers the mapping. The signals Kiro really reports are untested |
| 1.4 | Open the command palette and type the AI Primitives Hub: category | All 66 contributed commands listed and invocable in both hosts | 🟡 test/suite/integration-scenarios.test.ts asserts registration for 6 scope commands only (syncAllSources, moveToUser, moveToRepositoryCommit, moveToRepositoryLocalOnly, switchToLocalOnly, switchToCommit) — the file is otherwise placeholders. The other 60 commands are unverified |
| 1.5 | Open the extension's settings page | All 9 promptregistry.* settings appear with documented defaults | 🟡 test/config/package-configuration.test.ts covers only the 4 updateCheck.* settings. autoCheckUpdates, installationScope, enableLogging, githubToken and updateCheck.cacheTTL are unasserted |
TP-02 — First-Run Setup
Run in both VS Code and Kiro.
| # | Scenario | Expected result | Automation → where to focus |
|---|---|---|---|
| ⭐ 2.1 | Activate for the first time with no prior state | Setup flow appears and leads to a usable state | 🟢 test/services/setup-state-manager.test.ts, test/e2e/setup-state-flows.test.ts |
| 2.2 | Complete it, then reload | Does not reappear; the state it produced is intact |