Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/mcp-affected-tool.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"codemap": patch
---

Add MCP/HTTP `affected` tool — same preprocessor as `codemap affected`, composes the `affected-tests` recipe. Respects `CODEMAP_MCP_TOOLS` allowlist.
2 changes: 2 additions & 0 deletions .codemap/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
index.db
index.db-shm
index.db-wal
index.lock
errors.log
audit-cache/
25 changes: 14 additions & 11 deletions docs/architecture.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ Boolean flag on a project-local recipe entry that has the same `id` as a bundled

### `recipe_recency` (table) / recipe recency / `recipeRecency: false`

Per-recipe `last_run_at` (epoch ms) + `run_count` for agent-host ranking — surfaces inline on every `--recipes-json` entry and the matching `codemap://recipes` / `codemap://recipes/{id}` resources (live read every call; the resource cache was dropped to avoid freezing recency at first-read for the server-process lifetime). Counts only successful recipe runs; failed runs / param-validation rejections / SQL errors don't write. Default ON; opt-out via `.codemap/config` `recipeRecency: false` (short-circuits before any DB write — no rows ever land). 90-day rolling window enforced eagerly on the write path (single transactional `DELETE` + `INSERT … ON CONFLICT` inside `recordRecipeRun`); reads filter at SELECT, never mutate. Local-only — no upload primitive (resists telemetry-creep PRs by construction). Two write sites — `handleQueryRecipe` in `application/tool-handlers.ts` (covers MCP + HTTP) and `runQueryCmd` in `cli/cmd-query.ts` (CLI) — both call `tryRecordRecipeRun` (the failure-isolated wrapper around `recordRecipeRun`) from `application/recipe-recency.ts`. Failure-isolated: a recency-write throw NEVER blocks the recipe response (warning to stderr unless `quiet`). Schema: see [architecture.md § `recipe_recency`](./architecture.md#recipe_recency--per-recipe-last-run--run-count-user-data-strict-without-rowid).
Per-recipe `last_run_at` (epoch ms) + `run_count` for agent-host ranking — surfaces inline on every `--recipes-json` entry and the matching `codemap://recipes` / `codemap://recipes/{id}` resources (live read every call; the resource cache was dropped to avoid freezing recency at first-read for the server-process lifetime). Counts only successful recipe runs; failed runs / param-validation rejections / SQL errors don't write. Default ON; opt-out via `.codemap/config` `recipeRecency: false` (short-circuits before any DB write — no rows ever land). 90-day rolling window enforced eagerly on the write path (single transactional `DELETE` + `INSERT … ON CONFLICT` inside `recordRecipeRun`); reads filter at SELECT, never mutate. Local-only — no upload primitive (resists telemetry-creep PRs by construction). Write sites — `handleQueryRecipe` + `handleAffected` in `application/tool-handlers.ts` (MCP + HTTP) and `runQueryCmd` in `cli/cmd-query.ts` + `runAffectedCmd` in `cli/cmd-affected.ts` (CLI) — each calls `tryRecordRecipeRun` (the failure-isolated wrapper around `recordRecipeRun`) from `application/recipe-recency.ts`. Failure-isolated: a recency-write throw NEVER blocks the recipe response (warning to stderr unless `quiet`). Schema: see [architecture.md § `recipe_recency`](./architecture.md#recipe_recency--per-recipe-last-run--run-count-user-data-strict-without-rowid).

### research

Expand Down
33 changes: 21 additions & 12 deletions docs/plans/affected-tests-recipe.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# Affected tests recipe — plan

> **Status:** open · **Priority:** P1 · **Effort:** M (~1–2 weeks)
> **Status:** shipped · **Priority:** P1 · **Effort:** M (~1–2 weeks)
>
> **Motivator:** CI can skip full test suites if only a subgraph changed. Codemap already has `dependencies` and `test_suites` — missing a recipe + CLI alias to list test files transitively impacted by changed sources.
>
> **Roadmap:** [§ Backlog](../roadmap.md#backlog) (test-impact item) · [agent-surface-and-ops § P1](./agent-surface-and-ops.md#p1)
> **Roadmap:** [§ Backlog](../roadmap.md#backlog) (test-impact item) · [agent-surface-and-ops § P1](./agent-surface-and-ops.md#p1) · **Shipped:** [#132](https://github.com/stainless-code/codemap/pull/132) (recipe + CLI), [#133](https://github.com/stainless-code/codemap/pull/133) (MCP/HTTP `affected` tool)

---

## Pre-locked decisions

| # | Decision | Source |
| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------ |
| L.1 | **Moat-A clean** — `affected-tests` recipe satisfies the agent surface; **`query_recipe`** is the MCP/HTTP path. Optional dedicated CLI verb **`codemap affected`** for CI (`stdin` / git path discovery) — not a 6th outcome alias. | [Moat A](../roadmap.md#moats-load-bearing) |
| L.2 | Algorithm: reverse BFS on `dependencies` from changed files → filter test paths via `test_suites.file_path` and configurable globs. | Uses existing substrate |
| L.3 | **Stdin support** — accept changed paths from `git diff --name-only` (same ergonomics as CI scripts). | CLI ergonomics |
| L.4 | Not a verdict — output is file paths only; CI composes exit policy. | Moat A |
| # | Decision | Source |
| --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| L.1 | **Moat-A clean** — `affected-tests` recipe is the substrate; **`query_recipe`** remains the Moat-A path. Optional **`codemap affected`** CLI + MCP/HTTP **`affected`** tool for ergonomics — not a 6th outcome alias. | [Moat A](../roadmap.md#moats-load-bearing) |
| L.2 | Algorithm: reverse BFS on `dependencies` from changed files → filter test paths via `test_suites.file_path` and configurable globs. | Uses existing substrate |
| L.3 | **Stdin support** — accept changed paths from `git diff --name-only` (same ergonomics as CI scripts). | CLI ergonomics |
| L.4 | Not a verdict — output is file paths only; CI composes exit policy. | Moat A |

---

Expand All @@ -26,8 +26,8 @@
**Params (frontmatter):**

- `changed_files` — multiline or repeated (from `--params` or stdin preprocessor)
- `test_glob` — default `**/*.{test,spec}.{ts,tsx,js,jsx}`
- `max_depth` — optional cap on BFS
- `test_glob` — optional SQLite GLOB; when set, replaces default suffix globs (`test_suites` always included)
- `max_depth` — optional non-negative integer BFS cap (default 50)

**SQL shape:**

Expand All @@ -48,7 +48,9 @@ Dedicated `cmd-affected.ts` (not an outcome alias — 5-alias cap unchanged). Sh

## Agent surface (Moat A)

No dedicated MCP tool required — agents call **`query_recipe`** with `recipe: "affected-tests"` and `params.changed_files` (ASCII RS between paths when multiple). The recipe is the Moat-A substrate; the CLI verb is CI ergonomics only.
**Substrate:** **`query_recipe`** with `recipe: "affected-tests"` and `params.changed_files` (ASCII RS between paths when multiple).

**Convenience surfaces (Phase 2):** MCP/HTTP **`affected`** (`paths?`, `changed_since?`, …) and CLI **`codemap affected`** — thin composers over the same engine + recipe. Moat-A reviewers still verify via `query --recipe affected-tests`.

---

Expand All @@ -59,7 +61,13 @@ No dedicated MCP tool required — agents call **`query_recipe`** with `recipe:
3. Document test-file conventions in recipe `.md`
4. Optional GitHub Action input `mode: affected` in [github-marketplace-action](./github-marketplace-action.md) (follow-up)

**Out of scope:** dedicated MCP/HTTP `affected` tool (same outcome reachable via `query_recipe`; revisit only if agent eval shows friction).
**Out of scope (v1):** ~~dedicated MCP/HTTP `affected` tool~~ — shipped Phase 2 follow-up (`affected` tool; same engine as CLI). `query_recipe` remains the Moat-A substrate.

---

## Phase 2 (shipped)

MCP/HTTP **`affected`** — `{ paths?, changed_since?, test_glob?, max_depth? }` → shared `affected-engine` → `affected-tests` recipe. Documented in `mcp-instructions`; respects `CODEMAP_MCP_TOOLS` allowlist. [#133](https://github.com/stainless-code/codemap/pull/133).

---

Expand All @@ -68,6 +76,7 @@ No dedicated MCP tool required — agents call **`query_recipe`** with `recipe:
- [x] Recipe returns test file paths for a known fixture delta
- [x] Stdin mode works in shell pipeline
- [x] Documented in README + skill
- [x] MCP/HTTP `affected` tool (Phase 2)

---

Expand Down
28 changes: 14 additions & 14 deletions docs/plans/agent-surface-delivery.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@

## Quick resume

| Next action | Detail |
| -------------------- | ---------------------------------------------------------------------------------- |
| **Review / merge** | PR 5 — affected tests ([#132](https://github.com/stainless-code/codemap/pull/132)) |
| **Start next** | **PR 6** — MCP trace tools (`trace` / `explore` / `node`) |
| **Do not start yet** | PR 9 (eval harness) until PR 8 |
| Next action | Detail |
| -------------------- | --------------------------------------------------------------------------- |
| **Review / merge** | [#133](https://github.com/stainless-code/codemap/pull/133) — MCP `affected` |
| **Start next** | **PR 6** — MCP trace tools (`trace` / `explore` / `node`) |
| **Do not start yet** | PR 9 (eval harness) until PR 8 |

Update the table below when a PR merges or a new branch opens.

Expand All @@ -35,15 +35,15 @@ Merge each PR to `main` directly. No long-lived integration branch (`feat/agent-

Max **3 parallel tracks** at once.

| PR | Plans | Status | Blocked by | Parallel with |
| ----- | ----------------------------------------------------------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
| **3** | [`index-lock-and-error-log`](./index-lock-and-error-log.md) → [`parse-worker-hardening`](./parse-worker-hardening.md) (stack) | merged | [#129](https://github.com/stainless-code/codemap/pull/129), [#130](https://github.com/stainless-code/codemap/pull/130) | 4, 5 |
| **4** | Recipe half of [`mcp-trace-explore-tools`](./mcp-trace-explore-tools.md) (`call-path`, `symbol-neighborhood` SQL + tests) | merged | [#131](https://github.com/stainless-code/codemap/pull/131) | 3, 5 |
| **5** | [`affected-tests-recipe`](./affected-tests-recipe.md) | open | [#132](https://github.com/stainless-code/codemap/pull/132) | 3, 4 |
| **6** | MCP half of trace (`trace` / `explore` / `node` tools) + update instructions | planned | PR 1, PR 4 | — |
| **7** | [`field-qualified-search`](./field-qualified-search.md) | planned | PR 1 | 4, 5 if `mcp-server.ts` untouched |
| **8** | [`agents-init-mcp-wiring`](./agents-init-mcp-wiring.md) | planned | PR 1 | 3–5 |
| **9** | [`agent-eval-harness`](./agent-eval-harness.md) | planned | PR 1, PR 8, allowlist | **last P1** |
| PR | Plans | Status | Blocked by | Parallel with |
| ----- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
| **3** | [`index-lock-and-error-log`](./index-lock-and-error-log.md) → [`parse-worker-hardening`](./parse-worker-hardening.md) (stack) | merged | [#129](https://github.com/stainless-code/codemap/pull/129), [#130](https://github.com/stainless-code/codemap/pull/130) | 4, 5 |
| **4** | Recipe half of [`mcp-trace-explore-tools`](./mcp-trace-explore-tools.md) (`call-path`, `symbol-neighborhood` SQL + tests) | merged | [#131](https://github.com/stainless-code/codemap/pull/131) | 3, 5 |
| **5** | [`affected-tests-recipe`](./affected-tests-recipe.md) (+ Phase 2 MCP `affected` in [#133](https://github.com/stainless-code/codemap/pull/133)) | merged | [#132](https://github.com/stainless-code/codemap/pull/132), [#133](https://github.com/stainless-code/codemap/pull/133) | 3, 4 |
| **6** | MCP half of trace (`trace` / `explore` / `node` tools) + update instructions | planned | PR 1, PR 4 | — |
| **7** | [`field-qualified-search`](./field-qualified-search.md) | planned | PR 1 | 4, 5 if `mcp-server.ts` untouched |
| **8** | [`agents-init-mcp-wiring`](./agents-init-mcp-wiring.md) | planned | PR 1 | 3–5 |
| **9** | [`agent-eval-harness`](./agent-eval-harness.md) | planned | PR 1, PR 8, allowlist | **last P1** |

**Parallelization constraints**

Expand Down
2 changes: 1 addition & 1 deletion docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Prioritized agent & indexing ops queue (2026-05). Index: [`plans/agent-surface-a

- [ ] **MCP trace / explore / node** — recipe twins + thin MCP composers. Plan: [`plans/mcp-trace-explore-tools.md`](./plans/mcp-trace-explore-tools.md). Effort: M.
- [ ] **Agents init MCP wiring** — `agents init --mcp` + permissions. Plan: [`plans/agents-init-mcp-wiring.md`](./plans/agents-init-mcp-wiring.md). Effort: M.
- [ ] **Affected tests recipe** — dep-graph test selection + stdin. Plan: [`plans/affected-tests-recipe.md`](./plans/affected-tests-recipe.md). Effort: M.
- [x] **Affected tests recipe** — dep-graph test selection + stdin + MCP `affected` tool. Plan: [`plans/affected-tests-recipe.md`](./plans/affected-tests-recipe.md). Shipped #132 + #133.
- [ ] **Index lock + error log** — cross-process lock, `unlock`, `errors.log`. Plan: [`plans/index-lock-and-error-log.md`](./plans/index-lock-and-error-log.md). Effort: M.
- [ ] **Parse worker hardening** — per-file timeout + worker recycle. Plan: [`plans/parse-worker-hardening.md`](./plans/parse-worker-hardening.md). Effort: M.
- [ ] **Field-qualified search** — `kind:` / `path:` / `name:` → SQL. Plan: [`plans/field-qualified-search.md`](./plans/field-qualified-search.md). Effort: M.
Expand Down
Loading
Loading