Skip to content
Open
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
4 changes: 3 additions & 1 deletion .claude/skills/titan-gauntlet/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,9 @@ codegraph co-change <f> -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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Ambiguous empty-result trigger may miss the exact failure scenario this PR targets

The GAUNTLET smoke-test condition "if it errors or returns empty where a hit would be expected" leaves the executing agent to judge subjectively whether a hit from codegraph search "test query" --json is "expected" — and for a generic query like "test query", the agent will almost always decide no hit is expected. This means GAUNTLET will not trigger regeneration on a silent-empty response, which is precisely what the incident report says happened: codegraph search ran without erroring and returned empty results without any explicit ENGINE_UNAVAILABLE signal.

RECON's condition is more concrete ("not an error/ENGINE_UNAVAILABLE"), but the two conditions aren't symmetrically guarding against the same failure mode. The most deterministic fix would be to have RECON record the worktree path alongside embeddingsAvailable (e.g., a new embeddingsWorktreePath field in titan-state.json) and have GAUNTLET compare its current working directory against that value — a mismatch would be an unambiguous trigger for regeneration regardless of what the smoke test returns.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — RECON now records embeddingsWorktreePath (git rev-parse --show-toplevel) in titan-state.json alongside embeddingsAvailable. GAUNTLET's Rule 11 note now does a deterministic path comparison against that field first (mismatch or missing field = don't trust the flag), and the smoke-test fallback now uses the same explicit error/ENGINE_UNAVAILABLE criterion RECON uses instead of the subjective "empty where a hit would be expected" judgment call.

>
> 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
Expand Down
9 changes: 9 additions & 0 deletions .claude/skills/titan-recon/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Missing worktree identity record makes downstream verification probabilistic

The skill correctly smoke-tests the engine before setting embeddingsAvailable: true, but doesn't persist which worktree those embeddings belong to. Without an embeddingsWorktreePath field (e.g., the output of git rev-parse --show-toplevel) stored alongside the flag in titan-state.json, GAUNTLET has no deterministic way to know whether the flag it reads applies to its own working directory. It falls back to the ambiguous "where a hit would be expected" heuristic, which cannot reliably distinguish "engine healthy but zero semantic matches" from "engine silently returning nothing due to missing embeddings" — the exact failure mode this PR is addressing.

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — RECON now records embeddingsWorktreePath (output of git rev-parse --show-toplevel) alongside embeddingsAvailable in titan-state.json, including in the schema example. GAUNTLET compares its own worktree path against this field for a deterministic identity check before falling back to the smoke test.

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.

---

## Step 3 — Collect baseline metrics
Expand Down Expand Up @@ -236,6 +244,7 @@ Include the preserved `phaseTimestamps` in the state file below.
"lastBatch": null
},
"embeddingsAvailable": true,
"embeddingsWorktreePath": "<git rev-parse --show-toplevel>",
"stats": {
"totalFiles": 0,
"totalNodes": 0,
Expand Down
Loading