From 3b9dcef86c1b6b90d1f632e03294f7a9d5d3886a Mon Sep 17 00:00:00 2001 From: carlos-alm Date: Sun, 5 Jul 2026 00:05:13 -0600 Subject: [PATCH 1/2] fix(titan): verify embeddings per-worktree instead of trusting stale state flag .codegraph/ is gitignored, so graph.db and its embeddings are local, per-worktree filesystem state that never travels via git merge or a worktree switch. A v3.15.0 Titan run hit embeddingsAvailable: true in titan-state.json carried over from a different worktree's DB, causing GAUNTLET's Rule 11 (DRY) semantic search to silently return empty results for the entire run instead of erroring. titan-recon now smoke-tests codegraph search against the current worktree before setting embeddingsAvailable, and titan-gauntlet re-verifies it (and regenerates if stale) before relying on it for Rule 11 checks. --- .claude/skills/titan-gauntlet/SKILL.md | 4 +++- .claude/skills/titan-recon/SKILL.md | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.claude/skills/titan-gauntlet/SKILL.md b/.claude/skills/titan-gauntlet/SKILL.md index 00f976d58..100ac6ec5 100644 --- a/.claude/skills/titan-gauntlet/SKILL.md +++ b/.claude/skills/titan-gauntlet/SKILL.md @@ -240,7 +240,9 @@ codegraph co-change -T --json ``` Find semantically similar functions. If `codegraph search` fails (no embeddings), use grep for function signature patterns. **Warn:** similar patterns. **Fail:** near-verbatim copy. -> Note: requires embeddings from `/titan-recon`. If `titan-state.json → embeddingsAvailable` is false, skip semantic search and note it. +> **Don't trust `embeddingsAvailable` blindly — verify it against the current worktree.** `.codegraph/` is gitignored, so `graph.db` and its embeddings are local, per-worktree filesystem state; they are never carried over by a branch merge or a "switch to that worktree's state" step in Step 0. A `titan-state.json` merged in from a different worktree/session can say `embeddingsAvailable: true` while the graph.db actually open right now has none — `codegraph search` will then run without erroring and silently return empty results, so Rule 11 looks clean when it never actually checked anything. +> +> Before relying on `embeddingsAvailable`, run a one-time smoke-test at the start of Step 2 (not per-file): `codegraph search "test query" --json`. If it errors or returns empty where a hit would be expected, regenerate for **this** worktree — `codegraph embed -m minilm` — and update `titan-state.json → embeddingsAvailable` accordingly before trusting it for any Rule 11 check this run. If regeneration also fails, fall back to grep-only DRY checks and log it to `issues.ndjson` rather than proceeding on a false green. #### Rule 12 — Naming symmetry ```bash diff --git a/.claude/skills/titan-recon/SKILL.md b/.claude/skills/titan-recon/SKILL.md index 2544c611a..7ad457d30 100644 --- a/.claude/skills/titan-recon/SKILL.md +++ b/.claude/skills/titan-recon/SKILL.md @@ -55,6 +55,14 @@ codegraph embed -m minilm This enables `codegraph search` for duplicate code detection in downstream phases. If it fails (e.g., missing model), note it and continue — DRY checks will be grep-only. +**Verify, don't assume.** `.codegraph/` is gitignored — `graph.db` (and its embeddings) is local filesystem state, per worktree. It is never carried over by `git merge`, a branch switch, or a snapshot restore. Before setting `embeddingsAvailable` in `titan-state.json`, smoke-test the current worktree's DB directly: + +```bash +codegraph search "test query" --json +``` + +Only set `embeddingsAvailable: true` if this returns results (or a valid empty match, not an error/`ENGINE_UNAVAILABLE`). If a downstream phase (e.g. GAUNTLET) ends up operating in a **different worktree** than the one RECON ran `codegraph embed` in — including via "merge the other worktree's branch into mine" — its `graph.db` will not have embeddings even though a stale `titan-state.json` from elsewhere claims `embeddingsAvailable: true`. Re-run `codegraph embed -m minilm` for the worktree actually being used, and re-verify with the smoke-test above, whenever the operating worktree changes. + --- ## Step 3 — Collect baseline metrics From 6e29c046e12f443713ff8d3635ef32cba6d8ba19 Mon Sep 17 00:00:00 2001 From: carlos-alm Date: Sun, 5 Jul 2026 01:33:37 -0600 Subject: [PATCH 2/2] fix: record embeddingsWorktreePath for deterministic per-worktree checks (#1805) RECON now stores the worktree path (git rev-parse --show-toplevel) alongside embeddingsAvailable in titan-state.json. GAUNTLET compares this against its own worktree path before trusting the flag, replacing the ambiguous "empty result where a hit would be expected" heuristic with a deterministic check, and tightens the smoke-test fallback to the same explicit ENGINE_UNAVAILABLE criterion RECON already uses. --- .claude/skills/titan-gauntlet/SKILL.md | 2 +- .claude/skills/titan-recon/SKILL.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.claude/skills/titan-gauntlet/SKILL.md b/.claude/skills/titan-gauntlet/SKILL.md index 100ac6ec5..49d2a3736 100644 --- a/.claude/skills/titan-gauntlet/SKILL.md +++ b/.claude/skills/titan-gauntlet/SKILL.md @@ -242,7 +242,7 @@ Find semantically similar functions. If `codegraph search` fails (no embeddings) > **Don't trust `embeddingsAvailable` blindly — verify it against the current worktree.** `.codegraph/` is gitignored, so `graph.db` and its embeddings are local, per-worktree filesystem state; they are never carried over by a branch merge or a "switch to that worktree's state" step in Step 0. A `titan-state.json` merged in from a different worktree/session can say `embeddingsAvailable: true` while the graph.db actually open right now has none — `codegraph search` will then run without erroring and silently return empty results, so Rule 11 looks clean when it never actually checked anything. > -> Before relying on `embeddingsAvailable`, run a one-time smoke-test at the start of Step 2 (not per-file): `codegraph search "test query" --json`. If it errors or returns empty where a hit would be expected, regenerate for **this** worktree — `codegraph embed -m minilm` — and update `titan-state.json → embeddingsAvailable` accordingly before trusting it for any Rule 11 check this run. If regeneration also fails, fall back to grep-only DRY checks and log it to `issues.ndjson` rather than proceeding on a false green. +> Before relying on `embeddingsAvailable`, do a deterministic identity check first: compare `git rev-parse --show-toplevel` (this worktree) against `titan-state.json → embeddingsWorktreePath` (the worktree RECON actually ran `codegraph embed` in). Any mismatch — or a missing `embeddingsWorktreePath` from an older state file — means `embeddingsAvailable` cannot be trusted as-is; treat it as `false` until re-verified. Then, at the start of Step 2 (not per-file), run a one-time smoke-test: `codegraph search "test query" --json`. Treat only an explicit error or `ENGINE_UNAVAILABLE` as failure — the same concrete criterion RECON uses — not a subjective "no hit where one seemed likely" judgment call, since a generic query legitimately returning zero results is not itself proof of a broken engine. If either check fails, regenerate for **this** worktree — `codegraph embed -m minilm` — and update both `titan-state.json → embeddingsAvailable` and `embeddingsWorktreePath` before trusting it for any Rule 11 check this run. If regeneration also fails, fall back to grep-only DRY checks and log it to `issues.ndjson` rather than proceeding on a false green. #### Rule 12 — Naming symmetry ```bash diff --git a/.claude/skills/titan-recon/SKILL.md b/.claude/skills/titan-recon/SKILL.md index 7ad457d30..f4cea12c5 100644 --- a/.claude/skills/titan-recon/SKILL.md +++ b/.claude/skills/titan-recon/SKILL.md @@ -61,7 +61,7 @@ This enables `codegraph search` for duplicate code detection in downstream phase codegraph search "test query" --json ``` -Only set `embeddingsAvailable: true` if this returns results (or a valid empty match, not an error/`ENGINE_UNAVAILABLE`). If a downstream phase (e.g. GAUNTLET) ends up operating in a **different worktree** than the one RECON ran `codegraph embed` in — including via "merge the other worktree's branch into mine" — its `graph.db` will not have embeddings even though a stale `titan-state.json` from elsewhere claims `embeddingsAvailable: true`. Re-run `codegraph embed -m minilm` for the worktree actually being used, and re-verify with the smoke-test above, whenever the operating worktree changes. +Only set `embeddingsAvailable: true` if this returns results (or a valid empty match, not an error/`ENGINE_UNAVAILABLE`). Alongside the flag, record `embeddingsWorktreePath` in `titan-state.json` as the output of `git rev-parse --show-toplevel` — this gives downstream phases a deterministic identity to compare against instead of having to re-derive trust from a smoke test alone. If a downstream phase (e.g. GAUNTLET) ends up operating in a **different worktree** than the one RECON ran `codegraph embed` in — including via "merge the other worktree's branch into mine" — its `graph.db` will not have embeddings even though a stale `titan-state.json` from elsewhere claims `embeddingsAvailable: true`; a mismatch between `embeddingsWorktreePath` and that worktree's own `git rev-parse --show-toplevel` is the unambiguous signal for this. Re-run `codegraph embed -m minilm` for the worktree actually being used, update both `embeddingsAvailable` and `embeddingsWorktreePath`, and re-verify with the smoke-test above, whenever the operating worktree changes. --- @@ -244,6 +244,7 @@ Include the preserved `phaseTimestamps` in the state file below. "lastBatch": null }, "embeddingsAvailable": true, + "embeddingsWorktreePath": "", "stats": { "totalFiles": 0, "totalNodes": 0,