Skip to content

Commit 76b5d51

Browse files
committed
harden: E.3 boolean truncation, docs parity, golden fixture
Use json('true') for list-cap markers; exercise >3 caller branch via ProductCard now() fixture; fix stale unimported-exports action text; add architecture + skill evidence lines; refresh affected goldens.
1 parent 86062e2 commit 76b5d51

24 files changed

Lines changed: 55 additions & 38 deletions

docs/architecture.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ Three **mutually exclusive** CLI entry shapes; all converge on `applyDiffPayload
190190

191191
**Show / snippet wiring:** **`src/cli/show-snippet-args.ts`** (shared argv parser) + **`src/cli/show-snippet-render.ts`** (shared terminal/JSON error helpers) + **`src/cli/cmd-show.ts`** + **`src/cli/cmd-snippet.ts`** — sibling CLI verbs sharing the same parser shape (`<name>` or **`--query '<field:value …>'`** + **`--with-fts`** + `--kind` + `--in <path>` + `--json`; show adds **`--print-sql`**) and the pure engines **`src/application/show-engine.ts`** (exact lookup + envelope builders), **`src/application/search-query-parser.ts`** + **`src/application/search-engine.ts`** (field-qualified search → parameterized SQL on `symbols`, optional `source_fts` join), and **`src/application/show-search-mode.ts`** (shared parse/normalize + FTS resolution + **`executeShowLookup`** + **`formatShowSearchSqlForQuery`** for CLI/MCP/HTTP). Exact lookup: `findSymbolsByName({db, name, kind?, inPath?})`. Query lookup: `searchSymbols({db, parsed, withFts?})`. Snippet FS read: `readSymbolSource({match, projectRoot, indexedContentHash?})` + `getIndexedContentHash(db, filePath)`. **`buildShowResult`** + **`buildSnippetResult`** envelope builders — same engines the MCP show/snippet tools call. Both verbs return the same `{matches, disambiguation?, warning?}` envelope — single match → `{matches: [{...}]}`; multi-match adds `{n, by_kind, files, hint}`; optional **`warning`** when FTS was requested but `source_fts` is empty. Snippet matches add `source` / `stale` / `missing` fields (additive — no shape divergence). **`--in <path>`** and **`path:`** inside **`--query`** normalize through `toProjectRelative(projectRoot, p)` (from **`src/application/validate-engine.ts`**). Stale-file behavior on `snippet`: `hashContent` (from **`src/hash.ts`**) compares on-disk content against `files.content_hash`; mismatch sets `stale: true` but source IS still returned. MCP tools `show` and `snippet` register parallel to the CLI surface (see [§ MCP wiring](#cli-usage)).
192192

193+
**Evidence columns (high-judgment recipes):** Some bundled recipes add optional **`reason`** and **`evidence_json`** TEXT columns on each result row — factual detection path for agents, not pass/fail verdicts. Contract: [golden-queries.md § Evidence columns](./golden-queries.md#evidence-columns-high-judgment-recipes).
194+
193195
**Recipes wiring:** **`src/application/recipes-loader.ts`** (pure transport-agnostic loader) + **`src/application/query-recipes.ts`** (cache + public API — `getQueryRecipeSql` / `getQueryRecipeActions` / `getQueryRecipeParams` / `listQueryRecipeIds` / `listQueryRecipeCatalog` / `getQueryRecipeCatalogEntry`, shared by CLI + MCP). Recipes live as file pairs: **`<id>.sql`** + optional **`<id>.md`**. The loader reads `templates/recipes/` (bundled, ships in npm package next to `templates/agents/`) and `<state-dir>/recipes/` (project-local — default `.codemap/recipes/`; honors `--state-dir` / `CODEMAP_STATE_DIR`; root-only resolution per the registry plan, no walk-up). Project recipes win on id collision; entries that override a bundled id carry **`shadows: true`** in the catalog so agents reading `codemap://recipes` at session start see when a recipe behaves differently from the documented bundled version. Per-row **`actions`** templates and recipe **`params`** declarations live in YAML frontmatter on each `<id>.md` — uniform shape across bundled + project. Param types are `string | number | boolean`; CLI passes values via repeatable `--params key=value[,key=value]`, MCP / HTTP pass nested `params: {key: value}` to `query_recipe`. Validation runs before SQL binding; missing / unknown / malformed params return the same `{error}` envelope as query failures. Hand-rolled YAML parser is scoped to block-list `actions:` and `params:` only (no `js-yaml` dep). Load-time validation rejects empty SQL and DML / DDL keywords (`INSERT` / `UPDATE` / `DELETE` / `DROP` / `CREATE` / `ALTER` / `ATTACH` / `DETACH` / `REPLACE` / `TRUNCATE` / `VACUUM` / `PRAGMA`) with recipe-aware error messages — defence in depth alongside the runtime `PRAGMA query_only=1` backstop in `query-engine.ts` (PR #35). `<state-dir>/index.db` is gitignored; `<state-dir>/recipes/` is NOT (verified via `git check-ignore`) — recipes are git-tracked source code authored for human review.
194196

195197
**Tool / resource handlers (transport-agnostic):** **`src/application/tool-handlers.ts`** + **`src/application/resource-handlers.ts`** — pure functions that take the args object an MCP tool / resource URI accepts and return a discriminated **`ToolResult`** (`{ok: true, format: 'json'|'sarif'|'annotations'|'mermaid'|'diff'|'diff-json'|'codeclimate'|'badge', payload}` — badge arm also carries `badgeStyle`; `{ok: false, error}`) or a **`ResourcePayload`** (`{mimeType, text}`). MCP and HTTP both wrap the same handlers — MCP translates to `{content: [{type: "text", text}]}`, HTTP translates to `(status, body)` with the right `Content-Type`. Engine layer untouched; transport changes don't ripple into the SQL.

docs/plans/agent-enrichment-wave.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,4 @@ Each PR: `harden-pr full` → merge. Do not batch plans 1–4 into one PR.
9191

9292
## Current slice
9393

94-
**Active:** Plan 1 **complete** (slices 1.0–1.4 on `feat/evidence-chains-boundary`) — open **PR #B**, then Plan 2 spike **2.0**.
94+
**Active:** Plan 1 shipped in [**PR #174**](https://github.com/stainless-code/codemap/pull/174) (awaiting merge) — next: Plan 2 spike **2.0** (`graph-estimated-crap.md`).

fixtures/golden/minimal/call-resolution-stats.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
22
{
3-
"total_calls": 47,
4-
"resolved_calls": 26,
3+
"total_calls": 48,
4+
"resolved_calls": 27,
55
"method_calls_deferred": 20,
66
"unresolved_queue": 1,
77
"residual_meta": "1"

fixtures/golden/minimal/components-touching-deprecated.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
[
2+
{
3+
"component": "ProductCard",
4+
"component_file": "src/components/shop/ProductCard.tsx",
5+
"deprecated_symbol": "now",
6+
"deprecated_file": "src/utils/date.ts",
7+
"via": "call"
8+
},
29
{
310
"component": "ShopButton",
411
"component_file": "src/components/shop/ShopButton.tsx",

fixtures/golden/minimal/coverage-rows-after-ingest.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,15 @@
22
{
33
"file_path": "src/components/shop/ProductCard.tsx",
44
"name": "ProductCard",
5-
"hit_statements": 3,
6-
"total_statements": 3,
5+
"hit_statements": 2,
6+
"total_statements": 2,
7+
"coverage_pct": 100
8+
},
9+
{
10+
"file_path": "src/components/shop/ProductCard.tsx",
11+
"name": "spread",
12+
"hit_statements": 1,
13+
"total_statements": 1,
714
"coverage_pct": 100
815
},
916
{

fixtures/golden/minimal/deprecated-symbols.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"signature": "now(): number",
1818
"doc_comment": "@deprecated Use `Date.now()` directly. Kept as a fixture for the\n`deprecated-symbols` recipe golden test.",
1919
"reason": "has_callers",
20-
"evidence_json": "[{\"kind\":\"caller\",\"name\":\"ShopButton\",\"file_path\":\"src/components/shop/ShopButton.tsx\",\"line_start\":10},{\"kind\":\"caller\",\"name\":\"run\",\"file_path\":\"src/consumer.ts\",\"line_start\":27},{\"kind\":\"caller\",\"name\":\"run\",\"file_path\":\"src/consumer.ts\",\"line_start\":30}]"
20+
"evidence_json": "[{\"kind\":\"caller\",\"name\":\"ProductCard\",\"file_path\":\"src/components/shop/ProductCard.tsx\",\"line_start\":12},{\"kind\":\"caller\",\"name\":\"ShopButton\",\"file_path\":\"src/components/shop/ShopButton.tsx\",\"line_start\":10},{\"kind\":\"caller\",\"name\":\"run\",\"file_path\":\"src/consumer.ts\",\"line_start\":27},{\"truncated\":true}]"
2121
},
2222
{
2323
"name": "epochMs",

fixtures/golden/minimal/files-hashes.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,9 @@
115115
},
116116
{
117117
"path": "src/components/shop/ProductCard.tsx",
118-
"content_hash": "27b25a905655574a3002adc140b36e91b95f8f1a5db0758ba172115595134122",
118+
"content_hash": "130e72381a5b03071f22f161e178d2800c48124d1bbc33359520218ad48e3a1e",
119119
"language": "tsx",
120-
"line_count": 23
120+
"line_count": 24
121121
},
122122
{
123123
"path": "src/components/shop/ShopButton.default.ts",

fixtures/golden/minimal/files-largest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
},
4444
{
4545
"path": "src/components/shop/ProductCard.tsx",
46-
"line_count": 23,
47-
"size": 654,
46+
"line_count": 24,
47+
"size": 748,
4848
"language": "tsx"
4949
},
5050
{

fixtures/golden/minimal/find-export-sites.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"is_re_export": 0,
88
"re_export_source": null,
99
"line_start": 10,
10-
"line_end": 22,
10+
"line_end": 23,
1111
"column_start": 16,
1212
"column_end": 27
1313
},

fixtures/golden/minimal/find-jsx-usages.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
{
33
"file_path": "src/components/shop/ProductCard.tsx",
44
"component_name": "article",
5-
"line_start": 15,
6-
"line_end": 19,
5+
"line_start": 16,
6+
"line_end": 20,
77
"is_self_closing": 0,
88
"is_fragment": 0,
99
"is_lowercase": 1,

0 commit comments

Comments
 (0)