Skip to content

Commit 2bd8071

Browse files
committed
test(bench): Phase 2–3 shop-symbols golden and CLI smoke e2e
Add shop-symbols-recipe golden, cmd-test-bench-e2e for show/snippet/impact/ validate/SARIF on fixtures/minimal, and an agent-eval probe. Mark plan phases 2–3 largely complete in in-repo-test-bench.md.
1 parent 4213898 commit 2bd8071

7 files changed

Lines changed: 190 additions & 25 deletions

File tree

docs/plans/in-repo-test-bench.md

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# In-repo test bench (no external corpus)
22

3-
**Status:** Open — Phase 1 shipped on `feat/unresolved-calls-staging` follow-ups; Phases 2–4 backlog.
3+
**Status:** Open — Phase 1–3 in progress on `feat/unresolved-calls-staging`; Phase 4 backlog.
44
**Effort:** M (ongoing; expand incrementally).
55
**Supersedes for maintainers:** relying on Tier B `CODEMAP_ROOT` / private clones to validate Codemap itself.
66

@@ -38,21 +38,18 @@ fixtures/
3838
- [x] Substrate pin-down goldens + `index-table-stats`
3939
- [x] Clarify Tier B = consumer-only in `golden-queries.md`
4040

41-
### Phase 2 — Corpus depth (next)
41+
### Phase 2 — Corpus depth
4242

43-
Target gaps from `knownGaps` in the manifest:
44-
45-
| Gap | Fixture slice | Golden |
46-
| ------------------------------- | --------------------------------------------------- | ------------------------------------------ |
47-
| Method-call resolution | `src/bench/method-call-sites.ts` | `calls-method-ping-unresolved` |
48-
| Qualified heritage / namespaces | extend `heritage-qualified.ts` or `src/bench/` | new SQL scenarios |
49-
| `affected-tests` param matrix | already partial — ensure all 6 scenarios stay green |
50-
| Project-local recipe | `.codemap/recipes/shop-symbols` | dedicated scenario (not only files-hashes) |
43+
- [x] Method-call slice — `src/bench/method-call-sites.ts` + `calls-method-ping-unresolved`
44+
- [x] Qualified heritage — `type-ancestors-qualified-child` on `heritage-qualified.ts`
45+
- [x] `affected-tests` — six param scenarios in `scenarios.json`
46+
- [x] Project-local recipe — `shop-symbols-recipe` golden
5147

5248
### Phase 3 — CLI / MCP bench pack
5349

54-
- [ ] `src/cli/cmd-test-bench-e2e.test.ts` — spawn CLI against `fixtures/minimal` for: `show`, `snippet`, `impact`, `trace`, `validate`, `context`, `query --format sarif` (smoke exit 0)
55-
- [ ] Expand `test:agent-eval` probes to cover one scenario per capability group in `CAPABILITIES.json`
50+
- [x] `src/cli/cmd-test-bench-e2e.test.ts` — show, snippet, impact, validate, `shop-symbols`, SARIF (`boundary-violations`)
51+
- [x] `cmd-cli-parity-e2e.test.ts` — trace, explore, node, context, batch, resources
52+
- [ ] Expand `test:agent-eval` to one probe per `CAPABILITIES.json` group (6/16 today)
5653

5754
### Phase 4 — Scale (optional, replaces Tier B′)
5855

docs/testing-coverage.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88

99
## Harness layers
1010

11-
| Layer | Command | What it proves |
12-
| ---------------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
13-
| **Unit** | `bun test ./src` | Parsers, DB DDL, engines, CLI/MCP handlers in isolation (`:memory:` or mocks). |
14-
| **In-repo test bench** | `bun run test:golden` | Index `fixtures/minimal/` (bench corpus) → compare `fixtures/golden/minimal/*.json`. Map: `fixtures/CAPABILITIES.json`. |
15-
| **Golden guard** | `bun run test:scripts` | `scripts/query-golden-coverage-matrix.test.mjs` — every bundled recipe + substrate table has a scenario. |
16-
| **Agent eval** | `bun run test:agent-eval` | Probe arms vs golden ids (MCP-on vs glob/read). |
17-
| **Integration (git)** | `src/application/run-index.test.ts` | `runCodemapIndex` incremental paths: heritage + calls re-resolution, delete/reindex. |
18-
| **CLI e2e** | `cmd-cli-parity-e2e.test.ts` | Spawned CLI against `fixtures/minimal`. |
19-
| **Check** | `bun run check` | build + lint + unit + scripts + golden + agent-eval. |
11+
| Layer | Command | What it proves |
12+
| ---------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
13+
| **Unit** | `bun test ./src` | Parsers, DB DDL, engines, CLI/MCP handlers in isolation (`:memory:` or mocks). |
14+
| **In-repo test bench** | `bun run test:golden` | Index `fixtures/minimal/` (bench corpus) → compare `fixtures/golden/minimal/*.json`. Map: `fixtures/CAPABILITIES.json`. |
15+
| **Golden guard** | `bun run test:scripts` | `scripts/query-golden-coverage-matrix.test.mjs` — every bundled recipe + substrate table has a scenario. |
16+
| **Agent eval** | `bun run test:agent-eval` | Probe arms vs golden ids (MCP-on vs glob/read). |
17+
| **Integration (git)** | `src/application/run-index.test.ts` | `runCodemapIndex` incremental paths: heritage + calls re-resolution, delete/reindex. |
18+
| **CLI e2e** | `cmd-test-bench-e2e.test.ts`, `cmd-cli-parity-e2e.test.ts` | Spawned CLI on `fixtures/minimal` (bench smoke + resource parity). |
19+
| **Check** | `bun run check` | build + lint + unit + scripts + golden + agent-eval. |
2020

2121
Refresh Tier A goldens after intentional fixture or schema changes:
2222

@@ -90,6 +90,7 @@ Codemap development uses **only** the committed bench ([fixtures/README.md](../f
9090
| Call sites | `find-call-sites` |
9191
| Call resolution stats | `call-resolution-stats` |
9292
| Import specifiers | `import-specifiers-consumer` |
93+
| Project-local recipe | `shop-symbols-recipe` |
9394

9495
---
9596

fixtures/CAPABILITIES.json

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,24 +189,41 @@
189189
"affected-tests-direct"
190190
]
191191
},
192+
{
193+
"id": "recipes.project-local",
194+
"description": "State-dir recipes under .codemap/recipes/",
195+
"fixtureFiles": [
196+
".codemap/recipes/shop-symbols.sql",
197+
".codemap/recipes/shop-symbols.md"
198+
],
199+
"goldenScenarios": ["shop-symbols-recipe"]
200+
},
192201
{
193202
"id": "recipes.bundled",
194203
"description": "Every templates/recipes/*.sql id has a golden scenario",
195204
"fixtureFiles": [],
196205
"goldenScenarios": [],
197206
"enforcedBy": "scripts/query-golden-coverage-matrix.test.mjs"
198207
},
208+
{
209+
"id": "cli.bench-smoke",
210+
"description": "Spawned CLI smoke on fixtures/minimal (show, snippet, impact, validate, SARIF)",
211+
"fixtureFiles": [],
212+
"goldenScenarios": [],
213+
"unitTests": [
214+
"src/cli/cmd-test-bench-e2e.test.ts",
215+
"src/cli/cmd-cli-parity-e2e.test.ts"
216+
]
217+
},
199218
{
200219
"id": "cli.mcp.http",
201-
"description": "Consumer surfaces (show, trace, audit, MCP, HTTP) — not golden-indexed",
220+
"description": "MCP/HTTP handlers and audit baselines — unit-tested",
202221
"fixtureFiles": [],
203222
"goldenScenarios": [],
204223
"unitTests": [
205-
"src/cli/cmd-cli-parity-e2e.test.ts",
206224
"src/application/mcp-server.test.ts",
207225
"src/application/tool-handlers.test.ts"
208-
],
209-
"knownGaps": ["No single spawned CLI matrix over full corpus yet"]
226+
]
210227
}
211228
]
212229
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[
2+
{
3+
"name": "ApiBridge",
4+
"file_path": "src/components/shop/ApiBridge.tsx",
5+
"line_start": 4,
6+
"signature": "ApiBridge()"
7+
},
8+
{
9+
"name": "ProductCard",
10+
"file_path": "src/components/shop/ProductCard.tsx",
11+
"line_start": 10,
12+
"signature": "ProductCard(props)"
13+
},
14+
{
15+
"name": "FormatPrice",
16+
"file_path": "src/components/shop/ShopButton.tsx",
17+
"line_start": 4,
18+
"signature": "FormatPrice(cents): string"
19+
},
20+
{
21+
"name": "ShopButton",
22+
"file_path": "src/components/shop/ShopButton.tsx",
23+
"line_start": 8,
24+
"signature": "ShopButton()"
25+
}
26+
]

fixtures/golden/scenarios.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,11 @@
688688
"prompt": "boundary_rules reconciled from minimal .codemap/config.json",
689689
"sql": "SELECT name, action, from_glob, to_glob FROM boundary_rules ORDER BY name"
690690
},
691+
{
692+
"id": "shop-symbols-recipe",
693+
"prompt": "Project-local shop-symbols recipe lists exported shop functions",
694+
"recipe": "shop-symbols"
695+
},
691696
{
692697
"id": "call-resolution-stats",
693698
"prompt": "Call-resolution phase counts on minimal fixture (total, resolved, queue, meta residual)",

scripts/agent-eval/scenarios.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@
4545
"regex": "import\\s+\\{[^}]+\\}\\s+from",
4646
"mode": "matches"
4747
}
48+
},
49+
{
50+
"id": "shop-symbols-recipe",
51+
"goldenId": "shop-symbols-recipe",
52+
"traditional": {
53+
"globs": ["src/components/shop/**/*.tsx"],
54+
"regex": "export\\s+function\\s+\\w+",
55+
"mode": "matches"
56+
}
4857
}
4958
]
5059
}

src/cli/cmd-test-bench-e2e.test.ts

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**
2+
* Phase 3 in-repo test bench: spawn CLI against fixtures/minimal after one index.
3+
* Complements cmd-cli-parity-e2e (resources, batch, trace) with show/snippet/impact/validate/SARIF.
4+
*/
5+
import { beforeAll, describe, expect, it } from "bun:test";
6+
import { existsSync } from "node:fs";
7+
import { join } from "node:path";
8+
9+
const repoRoot = join(import.meta.dir, "..", "..");
10+
const indexTs = join(repoRoot, "src", "index.ts");
11+
const benchRoot = join(repoRoot, "fixtures", "minimal");
12+
let bunBin: string | null = null;
13+
14+
async function runCli(
15+
args: string[],
16+
env: Record<string, string> = {},
17+
): Promise<{ exitCode: number; out: string; err: string }> {
18+
if (bunBin === null) {
19+
throw new Error(
20+
"cmd-test-bench-e2e.test: bunBin not initialised by beforeAll.",
21+
);
22+
}
23+
const proc = Bun.spawn([bunBin, indexTs, ...args], {
24+
cwd: repoRoot,
25+
stdout: "pipe",
26+
stderr: "pipe",
27+
env: { ...process.env, CODEMAP_ROOT: benchRoot, ...env },
28+
});
29+
const exitCode = await proc.exited;
30+
const out = await new Response(proc.stdout).text();
31+
const err = await new Response(proc.stderr).text();
32+
return { exitCode, out, err };
33+
}
34+
35+
beforeAll(async () => {
36+
bunBin = Bun.which("bun");
37+
if (!bunBin || !existsSync(indexTs)) {
38+
throw new Error(
39+
`cmd-test-bench-e2e.test: cannot locate Bun (${bunBin}) or src entry (${indexTs}).`,
40+
);
41+
}
42+
const idx = await runCli(["--full"]);
43+
expect(idx.exitCode).toBe(0);
44+
}, 120_000);
45+
46+
describe("in-repo test bench CLI smoke — fixtures/minimal", () => {
47+
it("show returns symbol matches", async () => {
48+
const r = await runCli(["show", "usePermissions", "--json"]);
49+
expect(r.exitCode).toBe(0);
50+
expect(r.err).toBe("");
51+
const payload = JSON.parse(r.out) as { matches: unknown[] };
52+
expect(payload.matches.length).toBeGreaterThan(0);
53+
});
54+
55+
it("snippet returns source for a symbol", async () => {
56+
const r = await runCli(["snippet", "usePermissions", "--json"]);
57+
expect(r.exitCode).toBe(0);
58+
const payload = JSON.parse(r.out) as {
59+
matches: Array<{ source?: string; missing: boolean }>;
60+
};
61+
expect(payload.matches[0]?.missing).toBe(false);
62+
expect(payload.matches[0]?.source).toContain("usePermissions");
63+
});
64+
65+
it("impact returns neighborhood matches", async () => {
66+
const r = await runCli([
67+
"impact",
68+
"usePermissions",
69+
"--json",
70+
"--depth",
71+
"1",
72+
]);
73+
expect(r.exitCode).toBe(0);
74+
const payload = JSON.parse(r.out) as { matches: unknown[] };
75+
expect(payload.matches.length).toBeGreaterThan(0);
76+
});
77+
78+
it("validate reports no drift on a fresh index", async () => {
79+
const r = await runCli(["validate", "--json"]);
80+
expect(r.exitCode).toBe(0);
81+
expect(JSON.parse(r.out)).toEqual([]);
82+
});
83+
84+
it("query --recipe shop-symbols returns project-local recipe rows", async () => {
85+
const r = await runCli(["query", "--recipe", "shop-symbols", "--json"]);
86+
expect(r.exitCode).toBe(0);
87+
const rows = JSON.parse(r.out) as Array<{
88+
name: string;
89+
file_path: string;
90+
actions?: unknown[];
91+
}>;
92+
expect(rows.some((row) => row.name === "ProductCard")).toBe(true);
93+
expect(rows[0]?.actions?.length).toBeGreaterThan(0);
94+
});
95+
96+
it("query --format sarif emits SARIF for boundary-violations", async () => {
97+
const r = await runCli([
98+
"query",
99+
"--recipe",
100+
"boundary-violations",
101+
"--format",
102+
"sarif",
103+
]);
104+
expect(r.exitCode).toBe(0);
105+
expect(r.err).toBe("");
106+
const payload = JSON.parse(r.out) as { version: string; runs: unknown[] };
107+
expect(payload.version).toBe("2.1.0");
108+
expect(payload.runs.length).toBeGreaterThan(0);
109+
});
110+
});

0 commit comments

Comments
 (0)