Skip to content

Commit 0134944

Browse files
refactor: lift cli/* engine helpers into application/* (close all layer-reversal imports) (#41)
* refactor(audit): lift resolveAuditBaselines cmd-audit → audit-engine (Tracer 1 of 5) Pure move — function logic unchanged. Closes one of the 5 layer-reversal imports application/mcp-server.ts had on cli/* (called out in PR #35 self-audit). Now MCP server imports resolveAuditBaselines from the engine alongside runAudit, like the proper cmd-* ↔ *-engine seam. cmd-audit.ts test imports updated; CLI handler still calls the function (now via engine import). No behavior change. * refactor(recipes): lift cli/query-recipes → application/query-recipes (Tracer 2a of 5) Pre-req for lifting buildContextEnvelope in Tracer 2b — query-recipes is engine-shaped (no CLI args, just exports for both CLI and MCP), so its location in cli/ was a misfile. git mv preserves history; only changes are the import paths in 6 callers and the relative paths inside the moved files. * refactor(context): lift buildContextEnvelope cmd-context → context-engine (Tracer 2b of 5) buildContextEnvelope, classifyIntent, ContextEnvelope, readScalarInt are pure (DB read + envelope build, no I/O / argv / printing) — engine-shaped. Same pattern as audit-engine in Tracer 1. cmd-context.ts now holds parse/help/run only. mcp-server imports from the new engine instead of the CLI shell. * refactor(validate): lift computeValidateRows + toProjectRelative cmd-validate → validate-engine (Tracer 3 of 5) Both functions are pure (no argv, no printing — just DB rows + filesystem hash compare). toProjectRelative was already public-API for cmd-show / cmd-snippet (cross-CLI reuse) and the MCP show/snippet handlers; this lift removes the cli→cli import edge and the mcp→cli edge in one move. cmd-validate.ts now holds parse / help / run only. * refactor(show): lift buildShowResult + buildSnippetResult cmd-show/snippet → show-engine (Tracer 4 of 5) Closes the last 2 layer-reversal imports application/mcp-server.ts had on cli/* (originally called out in PR #35 self-audit). Verified: `grep 'from "../cli/' src/application` is empty. Both envelope builders are pure (transform a SymbolMatch[] into a {matches, disambiguation?} shape; snippet additionally enriches via readSymbolSource). They sit naturally next to the engine functions that produce / read their inputs (findSymbolsByName, readSymbolSource, getIndexedContentHash). cmd-show.ts and cmd-snippet.ts now hold parse/help/run/render only — same cmd-* ↔ *-engine seam Tracers 1-3 established. * docs: sync architecture.md / research / benchmark to lifted application/* layering (Tracer 5 of 5) - architecture.md table (line ~23) + 'Repository layout' (line ~100): expand application/ description to enumerate all engines (run-index, index-engine, query-engine, audit-engine, context-engine, validate-engine, show-engine, query-recipes, recipes-loader, mcp-server) + state the never-import-cli/ rule. - 'Validate / Audit / Context / Show-snippet / Recipes wiring' paragraphs: name the new engine files, point toProjectRelative at validate-engine, point QUERY_RECIPES at application/. - docs/research/competitive-scan-2026-04.md + fallow.md: dangling src/cli/query-recipes.ts links updated to src/application/query-recipes.ts; context/validate rows now name both shell + engine. - docs/benchmark.md: getQueryRecipeSql import path updated. - changeset: patch — internal refactor, no behavior / public API change. * chore(mcp-server): drop outdated // Layer note (PR #41 obsoleted it) The note described the old state — engine helpers used to live under src/cli/ and we imported them here as 'pure data'. Tracers 1-4 of this PR lifted every one of them into src/application/, so the note's prediction ("future refactor may lift them...") is now history. With every import below from ./*-engine, the comment carried no info a teammate couldn't re-derive in <30s. User-confirmed delete per preserve-comments Rule 4.
1 parent 8e99e92 commit 0134944

26 files changed

Lines changed: 487 additions & 478 deletions
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@stainless-code/codemap": patch
3+
---
4+
5+
Internal refactor — lift `cli/*` envelope builders + path helpers into `application/*` engines so `application/mcp-server.ts` no longer reaches sideways into `cli/`. Affected modules: `audit-engine` (added `resolveAuditBaselines`), new `context-engine` (`buildContextEnvelope`, `classifyIntent`, `ContextEnvelope`), new `validate-engine` (`computeValidateRows`, `toProjectRelative`), `show-engine` (added `buildShowResult`, `buildSnippetResult`, `ShowResult`, `SnippetResult`, `SnippetMatch`), `query-recipes` moved from `cli/` to `application/`. CLI verbs stay shells (parse / help / run / render). No behavior change, no public API change — `cli/cmd-*` and `application/*` are internal modules; the published surface (`api.ts`, the `codemap` binary, the MCP server) is untouched.

docs/architecture.md

Lines changed: 32 additions & 32 deletions
Large diffs are not rendered by default.

docs/benchmark.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ On a small repo, totals move with noise and thermal variance. On a large indexed
167167

168168
The script’s **reindex** section averages **3 internal runs** per mode; full-rebuild wall time varies with disk and CPU load.
169169

170-
The indexed CSS scenario uses `ORDER BY name LIMIT 50`. The **fan-out** row’s indexed path uses **`getQueryRecipeSql("fan-out")`** from **`src/cli/query-recipes.ts`** (same text as **`codemap query --recipe fan-out`**). Other default scenarios’ SQL lives in **`src/benchmark-default-scenarios.ts`**; custom JSON is loaded in **`src/benchmark-config.ts`** (keep **`fixtures/benchmark/scenarios.example.json`** in sync when recipe SQL changes).
170+
The indexed CSS scenario uses `ORDER BY name LIMIT 50`. The **fan-out** row’s indexed path uses **`getQueryRecipeSql("fan-out")`** from **`src/application/query-recipes.ts`** (same text as **`codemap query --recipe fan-out`**). Other default scenarios’ SQL lives in **`src/benchmark-default-scenarios.ts`**; custom JSON is loaded in **`src/benchmark-config.ts`** (keep **`fixtures/benchmark/scenarios.example.json`** in sync when recipe SQL changes).
171171

172172
### Key takeaways
173173

docs/research/competitive-scan-2026-04.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ Sources:
4444

4545
| Idea (originally §3 / §4 / §5 of this scan) | Shipped where | Inspired by |
4646
| --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------- |
47-
| `codemap context` JSON envelope (incl. `--for "<intent>"` thin classifier, `--compact`) | `src/cli/cmd-context.ts` | JordanCoin (`codemap context`) |
48-
| `codemap validate` (hash-based staleness, no re-read) | `src/cli/cmd-validate.ts` | AZidan (`codemap validate`) |
47+
| `codemap context` JSON envelope (incl. `--for "<intent>"` thin classifier, `--compact`) | `src/cli/cmd-context.ts` + `src/application/context-engine.ts` | JordanCoin (`codemap context`) |
48+
| `codemap validate` (hash-based staleness, no re-read) | `src/cli/cmd-validate.ts` + `src/application/validate-engine.ts` | AZidan (`codemap validate`) |
4949
| `--performance` per-phase timing + top-10 slowest files | `src/application/index-engine.ts` | own roadmap, sharpened by JordanCoin's daemon framing |
50-
| `deprecated-symbols` recipe | `src/cli/query-recipes.ts` | fallow JSDoc visibility tags |
51-
| `visibility-tags` recipe (`@internal` / `@private` / `@alpha` / `@beta`) | `src/cli/query-recipes.ts` | fallow JSDoc visibility tags |
52-
| `barrel-files` recipe (top files by export count) | `src/cli/query-recipes.ts` | own derivation from JordanCoin "hubs" framing |
53-
| `files-hashes` recipe powering `validate` | `src/cli/query-recipes.ts` | AZidan |
50+
| `deprecated-symbols` recipe | `src/application/query-recipes.ts` | fallow JSDoc visibility tags |
51+
| `visibility-tags` recipe (`@internal` / `@private` / `@alpha` / `@beta`) | `src/application/query-recipes.ts` | fallow JSDoc visibility tags |
52+
| `barrel-files` recipe (top files by export count) | `src/application/query-recipes.ts` | own derivation from JordanCoin "hubs" framing |
53+
| `files-hashes` recipe powering `validate` | `src/application/query-recipes.ts` | AZidan |
5454
| `-r` short alias for `--recipe`, cleaner `--help` | `src/cli/cmd-query.ts` | own UX polish |
5555
| Friendlier "no `.codemap.db`" error | `src/application/index-engine.ts` | own UX polish |
5656
| Anti-pitch — "What Codemap is not" | [why-codemap.md § What Codemap is not](../why-codemap.md#what-codemap-is-not) | AZidan |

docs/research/fallow.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ Action hints in this section are **proposals** — not commitments. Tier hints r
6161

6262
### Tier A — Ship now (≤1 week each, mostly mechanical)
6363

64-
| # | Candidate | Sketch | Why this tier |
65-
| --- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
66-
| A.1 | **Per-row `actions` array on common recipes** | Each row from `query --recipe <id>` optionally carries `actions: [{type, auto_fixable, description}]`. Examples: `zero-fan-in-files` row → `[{type:"delete-file", auto_fixable:false}]`; `deprecated-symbols` row → `[{type:"open-deprecation-issue"}]`; `barrel-files` row → `[{type:"split-barrel"}]`. Recipe authors define the action template; the SQL stays untouched. Future ad-hoc SQL doesn't get actions automatically — that's fine, it's a recipe-only feature. | Mirrors fallow's killer agent-facing detail. Pure recipe-layer change in [`src/cli/query-recipes.ts`](../../src/cli/query-recipes.ts) — no schema impact. |
67-
| A.2 | **`--changed-since <ref>` on `query`** | Filters every query result row to files whose path matches `git diff --name-only <ref>...HEAD`. Implementation: pre-compute the changed-file set, append `AND <left-table>.file_path IN (...)` (or `from_path` / `to_path` for `dependencies` queries) to the SQL. Same primitive fallow uses for `--changed-since main`. | Unlocks PR-scoped queries without `codemap audit` (which is bigger — see B.5). Cheap; no schema impact. |
68-
| A.3 | **`--group-by owner\|directory\|package`** | Partition any `file_path`-bearing query result by CODEOWNERS first-owner / first directory component / workspace package. Implementation: post-process at JSON emit time; no SQL change required. | Layered on top of existing query output; no schema impact. CODEOWNERS reading is the only new bit. |
69-
| A.4 | **`--summary` flag** | Counts only, no rows. Useful pair with `--recipe` for dashboards / agent context windows. | Trivial; aligns with `codemap context --compact`. |
64+
| # | Candidate | Sketch | Why this tier |
65+
| --- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
66+
| A.1 | **Per-row `actions` array on common recipes** | Each row from `query --recipe <id>` optionally carries `actions: [{type, auto_fixable, description}]`. Examples: `zero-fan-in-files` row → `[{type:"delete-file", auto_fixable:false}]`; `deprecated-symbols` row → `[{type:"open-deprecation-issue"}]`; `barrel-files` row → `[{type:"split-barrel"}]`. Recipe authors define the action template; the SQL stays untouched. Future ad-hoc SQL doesn't get actions automatically — that's fine, it's a recipe-only feature. | Mirrors fallow's killer agent-facing detail. Pure recipe-layer change in [`src/application/query-recipes.ts`](../../src/application/query-recipes.ts) — no schema impact. |
67+
| A.2 | **`--changed-since <ref>` on `query`** | Filters every query result row to files whose path matches `git diff --name-only <ref>...HEAD`. Implementation: pre-compute the changed-file set, append `AND <left-table>.file_path IN (...)` (or `from_path` / `to_path` for `dependencies` queries) to the SQL. Same primitive fallow uses for `--changed-since main`. | Unlocks PR-scoped queries without `codemap audit` (which is bigger — see B.5). Cheap; no schema impact. |
68+
| A.3 | **`--group-by owner\|directory\|package`** | Partition any `file_path`-bearing query result by CODEOWNERS first-owner / first directory component / workspace package. Implementation: post-process at JSON emit time; no SQL change required. | Layered on top of existing query output; no schema impact. CODEOWNERS reading is the only new bit. |
69+
| A.4 | **`--summary` flag** | Counts only, no rows. Useful pair with `--recipe` for dashboards / agent context windows. | Trivial; aligns with `codemap context --compact`. |
7070

7171
### Tier B — Ship next (1–3 weeks; meaningful design work)
7272

scripts/query-golden.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { dirname, join, resolve } from "node:path";
44
import { fileURLToPath } from "node:url";
55

66
import { createCodemap } from "../src/api";
7-
import { getQueryRecipeSql } from "../src/cli/query-recipes";
7+
import { getQueryRecipeSql } from "../src/application/query-recipes";
88
import { parseScenariosJson } from "./query-golden/schema";
99
import type { GoldenMatch, GoldenScenario } from "./query-golden/schema";
1010

src/application/audit-engine.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,34 @@ export const V1_DELTAS: readonly AuditDeltaSpec[] = [
119119
*/
120120
export type AuditBaselineMap = Partial<Record<string, string>>;
121121

122+
/**
123+
* Compose the `AuditBaselineMap` from CLI / MCP arg shapes. Per-delta
124+
* explicit names override auto-resolved slots. Auto-resolved slots that
125+
* don't exist in `query_baselines` are silently absent — the delta just
126+
* doesn't run. Same shape both `cmd-audit.ts` and the MCP `audit` tool
127+
* call before handing off to {@link runAudit}.
128+
*/
129+
export function resolveAuditBaselines(opts: {
130+
db: CodemapDatabase;
131+
baselinePrefix: string | undefined;
132+
perDelta: Record<string, string>;
133+
}): AuditBaselineMap {
134+
const map: AuditBaselineMap = {};
135+
for (const spec of V1_DELTAS) {
136+
if (opts.baselinePrefix !== undefined) {
137+
const candidate = `${opts.baselinePrefix}-${spec.key}`;
138+
if (getQueryBaseline(opts.db, candidate) !== undefined) {
139+
map[spec.key] = candidate;
140+
}
141+
}
142+
}
143+
// Per-delta flags override the auto-resolved slot for that key.
144+
for (const [key, name] of Object.entries(opts.perDelta)) {
145+
map[key] = name;
146+
}
147+
return map;
148+
}
149+
122150
/**
123151
* Run an audit against the per-delta baseline mapping. Each requested delta
124152
* (key present in `baselines`) loads its baseline, validates column-set

0 commit comments

Comments
 (0)