diff --git a/.claude/skills/titan-forge/SKILL.md b/.claude/skills/titan-forge/SKILL.md index d79d89ae..2f6dc220 100644 --- a/.claude/skills/titan-forge/SKILL.md +++ b/.claude/skills/titan-forge/SKILL.md @@ -1,7 +1,7 @@ --- name: titan-forge description: Execute the sync.json plan — refactor code, validate with /titan-gate, commit, and advance state (Titan Paradigm Phase 4) -argument-hint: <--phase N> <--target name> <--dry-run> <--yes> +argument-hint: <--phase N> <--target name> <--dry-run> allowed-tools: Bash, Read, Write, Edit, Glob, Grep, Skill, Agent --- @@ -18,7 +18,7 @@ Your goal: read `sync.json`, find the next incomplete execution phase, make the - `--phase N` → jump to specific phase - `--target ` → run single target only (for retrying failures) - `--dry-run` → show what would be done without changing code -- `--yes` → skip confirmation prompt +- `--yes` → skip confirmation prompt (typically passed by `/titan-run` orchestrator) --- @@ -55,7 +55,8 @@ Your goal: read `sync.json`, find the next incomplete execution phase, make the "failedTargets": [], "commits": [], "currentSubphase": null, - "completedSubphases": [] + "completedSubphases": [], + "diffWarnings": [] } } ``` @@ -135,26 +136,101 @@ For each target in the current phase: 7. **Apply the change** based on phase strategy (Step 1) + gauntlet recommendation. -8. **Run tests:** +8. **Stage changed files:** ```bash - npm test 2>&1 + git add ``` - If tests fail → go to rollback (step 11). -9. **Run /titan-gate:** - Use the Skill tool to invoke `titan-gate`. If FAIL → go to rollback (step 11). +9. **Diff review (intent verification):** + Before running gate or tests, verify the diff matches the intent. This catches cases where the code change is structurally valid but doesn't match what was planned. -10. **On success:** + Collect the context: + ```bash + git diff --cached --stat + git diff --cached + ``` + + Load the gauntlet entry for this target (from `gauntlet.ndjson`) and the sync plan entry (from `sync.json → executionOrder[currentPhase]`). + + **Check all of the following:** + + **D1. Scope — only planned files touched:** + Compare staged file paths against `sync.json → executionOrder[currentPhase].targets` and their known file paths (from gauntlet entries). Flag any file NOT associated with the current target or phase. + - File in a completely different domain → **DIFF FAIL** + - File is a direct dependency of the target (consumer or import) → **OK** (expected ripple) + - Test file for the target → **OK** + + **D2. Intent match — diff aligns with gauntlet recommendation:** + First, check if this target is a dead-code target (present in `titan-state.json → roles.deadSymbols`). If so, the expected recommendation is "remove dead code" — skip gauntlet entry lookup (dead-code targets have no gauntlet.ndjson entry) and verify the diff shows only deletions (no new functions or logic added). If the diff contains non-trivial additions for a dead-code target → **DIFF FAIL**. + + Otherwise, read the gauntlet entry's `recommendation` field and `violations` list. Verify the diff addresses them: + - If recommendation says "split" → diff should show new functions extracted, original simplified + - If recommendation says "remove dead code" → diff should show deletions, not additions + - If violation was "complexity > threshold" → diff should reduce complexity, not just move code around + - If the diff does something **entirely different** from the recommendation → **DIFF FAIL** + + **D3. Commit message accuracy:** + Compare the planned commit message from `sync.json` against what the diff actually does. + - Message says "remove dead code" but diff adds new functions → **DIFF WARN** + - Message says "extract X from Y" but diff only modifies Y without creating X → **DIFF FAIL** + + **D4. Deletion audit:** + If the diff deletes code (lines removed > 10), identify deleted symbols by comparing the pre-change file against removed lines: + ```bash + # Get the pre-change version's symbols (temp file for shell portability) + D4_PRE_TMP=$(mktemp /tmp/titan-d4-pre-XXXXXX) + git show HEAD: > "$D4_PRE_TMP" + codegraph where --file "$D4_PRE_TMP" -T --json 2>/dev/null + rm -f "$D4_PRE_TMP" + ``` + Cross-reference with `git diff --cached -- ` to find symbols whose definitions appear only in removed lines (lines starting with `-`). For each deleted symbol: + ```bash + codegraph fn-impact -T --json 2>/dev/null + ``` + If the deleted symbol has active callers not updated in this diff → **DIFF FAIL**: "Deleted still has callers not updated in this commit." + + **D5. Leftover check:** + If the gauntlet recommendation mentioned specific symbols to remove/refactor, verify they were actually addressed: + - Dead symbols listed for removal but still present in the diff → **DIFF WARN**: "Gauntlet listed `` for removal but it was not deleted." + - Functions marked for decomposition but original is unchanged → **DIFF WARN**: "Gauntlet recommended decomposing `` but original function was not simplified." + - If all recommended symbols were addressed → **DIFF PASS** (implicit — no warnings emitted) + + **On DIFF FAIL:** + ```bash + git reset HEAD + git checkout -- + ``` + Add to `execution.failedTargets` with reason starting with `"diff-review: "`. Continue to next target. + **On DIFF WARN:** Log the warning but proceed to gate. Include the warning in the gate-log entry. + +10. **Run tests** (detect the project's test command from package.json scripts — `npm test`, `yarn test`, `pnpm test`, etc.): + ```bash + 2>&1 + ``` + If tests fail → go to rollback (step 13). + + > **Note:** Gate (Step 11) also runs tests. This pre-gate test is a fast-fail optimization — it catches obvious breakage before running the full gate checks (codegraph analysis, semantic assertions, arch snapshot). For projects with fast test suites the duplication is negligible; for slow suites, the tradeoff is: catch failures ~2x faster at the cost of ~2x test time on passing targets. + +11. **Run /titan-gate:** + Use the Skill tool to invoke `titan-gate`. + - If FAIL on **test/lint/build** (gate auto-rolls back staged changes) → go to rollback (step 13) to also revert working tree. + - If FAIL on **semantic/structural** (gate does not auto-rollback its staging area, but forge must clean up for the next target) → unstage with `git reset HEAD && git checkout -- `, add to `execution.failedTargets` with reason, log the gate report, and continue to the next target. Do NOT go to step 13 — that step is for test/gate failures where gate already unstaged; going there again would attempt a duplicate rollback. + +12. **On success:** ```bash - git add git commit -m "" ``` - Record commit SHA in `execution.commits` - Add target to `execution.completedTargets` + - Record any diff-review warnings in `execution.diffWarnings` (if any). Each entry must follow this schema: + ```json + { "target": "", "check": "D1|D3|D5", "message": "", "phase": N } + ``` - Update `titan-state.json` -11. **On failure (test or gate):** +13. **On failure (test or gate):** ```bash + git reset HEAD git checkout -- ``` - Add to `execution.failedTargets` with reason: `{ "target": "", "reason": "", "phase": N }` diff --git a/.claude/skills/titan-gate/SKILL.md b/.claude/skills/titan-gate/SKILL.md index 3121ed3a..7ba8b092 100644 --- a/.claude/skills/titan-gate/SKILL.md +++ b/.claude/skills/titan-gate/SKILL.md @@ -17,82 +17,25 @@ Your goal: validate staged changes against codegraph quality checks AND the proj --- -## Step 0 — Pre-flight: find Titan state and validate +## Step 0 — Pre-flight -1. **Locate the Titan session (if not already in one).** If `.codegraph/titan/titan-state.json` does not exist locally, search for it: - - ```bash - git worktree list - ``` - - For each worktree, check: - ```bash - ls /.codegraph/titan/titan-state.json 2>/dev/null - ``` - - Also check branches: - ```bash - git branch -a --list '*titan*' - ``` - - **Decision logic:** - - **Found a worktree/branch with Titan state:** Merge its branch into your worktree to pick up the artifacts: `git merge --no-edit` - - **Found multiple:** Pick the one with the most recent `lastUpdated` and `currentPhase` closest to `"sync"` (GATE runs after SYNC). If ambiguous, ask the user. - - **Found nothing:** That's fine — GATE can run standalone. Proceed with defaults. - -2. **Worktree check:** +1. **Worktree check:** ```bash git rev-parse --show-toplevel && git worktree list ``` If not in a worktree, stop: "Run `/worktree` first." -3. **Staged changes?** +2. **Staged changes?** ```bash git diff --cached --name-only ``` If nothing staged, stop: "Nothing staged. Use `git add` first." -4. **Load state (optional).** Read `.codegraph/titan/titan-state.json` if it exists — use for thresholds, baseline comparison, and sync alignment. If missing or corrupt, proceed with defaults. +3. **Load state (optional).** Read `.codegraph/titan/titan-state.json` if it exists — use for thresholds, baseline comparison, and sync alignment. If missing or corrupt, proceed with defaults. --- -## Step 1 — Drift detection: has main moved since last gate run? - -GATE may run many times across a long pipeline. Check for upstream changes each time. - -1. **Compare main SHA:** - ```bash - git rev-parse origin/main - ``` - Compare against `titan-state.json → mainSHA` (if state exists). If identical, skip to Step 2. - -2. **If main has advanced**, find what changed: - ```bash - git diff --name-only ..origin/main - ``` - -3. **Cross-reference with staged files:** - - Do any staged files also appear in the main diff? If yes, there may be **merge conflicts waiting** after the commit. - - Did main change files that are callers/callees of staged changes? Use diff-impact to check. - -4. **Classify staleness:** - - | Level | Condition | Action | - |-------|-----------|--------| - | **none** | main unchanged | Continue normally | - | **low** | Main changed but no overlap with staged files or their callers | Continue — note drift | - | **moderate** | Main changed files that are callers/callees of staged changes | **Warn:** "Main has changes that interact with your staged files. Consider merging main first: `git merge origin/main`" | - | **high** | Main changed the same files you're staging | **Warn strongly:** "Main modified files you're about to commit. Merge main first to avoid conflicts downstream." | - -5. **Write/update drift report** (same schema, `"detectedBy": "gate"`). - -6. **Update state:** Set `titan-state.json → mainSHA` to current `origin/main`. - -7. **If `sync.json` exists:** Check if main's changes invalidate any execution phases. If a phase's targets were changed on main, add a drift warning to the gate-log entry. - ---- - -## Step 2 — Structural validation (codegraph) +## Step 1 — Structural validation (codegraph) Run the full change validation predicates in one call: @@ -112,7 +55,7 @@ Extract: changed functions (count + names), direct callers affected, transitive --- -## Step 3 — Cycle check +## Step 2 — Cycle check ```bash codegraph cycles --json @@ -124,7 +67,7 @@ Compare against RECON baseline (if `titan-state.json` exists): --- -## Step 4 — Complexity delta +## Step 3 — Complexity delta For each changed file (from diff-impact): @@ -141,7 +84,7 @@ Check all metrics against thresholds: --- -## Step 5 — Lint, build, and test +## Step 4 — Lint, build, and test Detect project tools from `package.json`: @@ -161,13 +104,150 @@ npm run build 2>&1 || echo "BUILD_FAILED" (Skip if no `build` script.) ```bash -npm test 2>&1 || echo "TEST_FAILED" +# Detect test command from package.json scripts (npm test, yarn test, pnpm test, etc.) + test 2>&1 || echo "TEST_FAILED" ``` If any fail → overall verdict is FAIL → proceed to auto-rollback. --- +## Step 5 — Semantic assertions (API compatibility) + +Verify that code changes don't silently break callers by changing public contracts. This goes beyond structural checks — it catches signature changes, removed exports, and new forbidden dependencies. + +### 5a. Export signature stability + +Get the list of changed files from diff-impact (Step 1): + +```bash +codegraph exports -T --json +``` + +For each **exported** symbol in changed files: +- Check if the symbol existed before this change: `git show HEAD:` and compare function signatures +- If a function's **parameter list changed** (added required params, removed params, changed types): + ```bash + codegraph fn-impact -T --json + ``` + Count callers. If callers > 0 and callers are NOT also staged → **FAIL**: "Signature change in `` breaks callers not updated in this commit: " +- If an **export was removed entirely** and callers exist → **FAIL**: "Removed export `` still imported by files" + +### 5b. Import resolution integrity + +From the `codegraph check` results already collected in Step 1 (which includes `--staged`), extract any `unresolved_import` warnings. + +If any `unresolved_import` warnings appear for files NOT changed in this commit → **FAIL**: "Change broke import resolution for : " + +### 5c. Dependency direction assertions + +From the diff-impact results already collected in Step 1, extract any **new** edges (imports that didn't exist before). + +For each new dependency: +- Check against `GLOBAL_ARCH.md` layer rules (if Titan artifacts exist) +- Check the Step 1 `codegraph check --staged --boundaries` results for violations on this edge (already collected — do not re-run) +- New dependency from a lower layer to a higher layer → **FAIL**: "New upward dependency: `` → `` violates layer boundary" +- New dependency on a module flagged in sync.json as "to be removed" or "to be split" → **WARN**: "New dependency on `` which is scheduled for decomposition" + +### 5d. Re-export chain validation + +If the change modifies an index/barrel file (e.g., `index.js`, `mod.rs`): + +Capture the pre-change export list from the committed version (write the temp path to a sidecar file so it persists across Bash invocations): +```bash +BARREL_TMP=$(mktemp /tmp/titan-barrel-XXXXXX) +echo "$BARREL_TMP" > .codegraph/titan/.barrel-tmp +git show HEAD: > "$BARREL_TMP" +codegraph exports "$BARREL_TMP" -T --json +``` + +Then capture the current (staged) export list: +```bash +codegraph exports -T --json +``` + +Compare export count before and after. If exports were **accidentally dropped** (count decreased and the removed exports have callers) → **FAIL**: "Barrel file `` dropped exports that have active callers: . Use `codegraph exports -T` to review." + +Clean up the temp file (recover path from sidecar). **This MUST run even if Step 5d produced a FAIL verdict — run it before proceeding to Step 9:** +```bash +BARREL_TMP=$(cat .codegraph/titan/.barrel-tmp 2>/dev/null) +if [ -n "$BARREL_TMP" ]; then rm -f "$BARREL_TMP"; fi +rm -f .codegraph/titan/.barrel-tmp +``` + +--- + +## Step 5.5 — Architectural snapshot comparison + +Compare the codebase's architectural properties before and after this change. This catches "technically correct but architecturally wrong" changes — e.g., a valid refactor that puts code in the wrong layer. + +### Load pre-forge snapshot + +Read `.codegraph/titan/arch-snapshot.json` if it exists (created by `/titan-run` before forge begins). If missing, skip this step — it only works within the orchestrated pipeline. + +### Capture current state + +Use `mktemp -d` to create a unique temporary directory that persists across Bash invocations (shell variables like `$TITAN_TMP_ID` do not survive between separate Bash tool calls): + +```bash +TITAN_ARCH_DIR=$(mktemp -d /tmp/titan-arch-XXXXXX) +echo "$TITAN_ARCH_DIR" > .codegraph/titan/.arch-tmpdir +codegraph communities -T --json > "$TITAN_ARCH_DIR/current-communities.json" +codegraph structure --depth 2 --json > "$TITAN_ARCH_DIR/current-structure.json" +codegraph communities --drift -T --json > "$TITAN_ARCH_DIR/current-drift.json" +``` + +> The path is written to `.codegraph/titan/.arch-tmpdir` so subsequent Bash invocations can recover it via `TITAN_ARCH_DIR=$(cat .codegraph/titan/.arch-tmpdir)`. + +### Compare + +In a new Bash invocation, recover the temp dir path first: +```bash +TITAN_ARCH_DIR=$(cat .codegraph/titan/.arch-tmpdir) +``` + +**A1. Community stability:** +Use the drift output (which uses content-based matching, not raw IDs, to track community movements across runs): + +Read `.codegraph/titan/arch-snapshot.json → drift` (the pre-forge drift baseline) and compare against `$TITAN_ARCH_DIR/current-drift.json`: +- For each **new** drift warning in current that was NOT present in the snapshot: if the drifted symbol was NOT touched in the diff → **WARN**: "Symbol `` drifted community as a side effect" +- If > 5 untouched symbols appear in new drift warnings → **FAIL**: "Significant community restructuring detected — symbols drifted communities. This change may have unintended architectural impact." + +**A2. Dependency direction between domains:** +From `GLOBAL_ARCH.md`, extract the expected dependency direction between domains (e.g., "presentation depends on features, not the reverse"). + +Check if any new cross-domain dependency violates the expected direction. Use the Step 1 diff-impact results to extract only the edges introduced by the staged changes — do not re-run `codegraph deps` on the full file (that returns all dependencies including pre-existing ones). For each new edge in the diff-impact output, the source and target file paths are already present in the edge data. Resolve the domain/layer of each endpoint by matching its file path against the domain map in `GLOBAL_ARCH.md` (e.g., `src/presentation/` → presentation layer, `src/features/` → features layer). No additional codegraph command is needed — the diff-impact edge output contains the file paths directly. +- New upward dependency (lower layer importing higher layer) introduced in this diff → **FAIL** +- Pre-existing boundary violations not surfaced by Step 5c's staged-diff results → advisory-only (not gating) +- New lateral dependency within the same layer → **OK** + +**A3. Cohesion delta:** +Compare directory cohesion scores from `structure`: +- If any directory's cohesion dropped by > 0.2 → **WARN**: "Directory `` cohesion dropped from to " +- If a directory went from above 0.5 to below 0.3 → **FAIL**: "Directory `` became tangled (cohesion )" + +**A4. Resolved drift warnings (positive signal):** +Compare drift warnings between snapshot and current. A1 already covers new drift warnings — A4 only reports resolved ones: +- If any drift warning that was present in the snapshot is absent from `$TITAN_ARCH_DIR/current-drift.json` → note as positive: "Symbol `` community drift resolved — architecture improved" + +### Cleanup (MUST run even on failure or early exit) + +This cleanup block MUST execute regardless of the verdict — including FAIL paths and early exits. Run it before proceeding to Step 9 (verdict aggregation), not after. + +```bash +TITAN_ARCH_DIR=$(cat .codegraph/titan/.arch-tmpdir 2>/dev/null) +if [ -n "$TITAN_ARCH_DIR" ]; then + rm -rf "$TITAN_ARCH_DIR" +fi +rm -f .codegraph/titan/.arch-tmpdir +``` + +### Verdict integration + +Architectural failures are reported as part of the overall gate verdict. They participate in the PASS/WARN/FAIL aggregation like all other checks. + +--- + ## Step 6 — Branch structural diff ```bash @@ -228,7 +308,7 @@ Aggregate all checks: > "GATE FAIL: [reason]. Graph restored, changes unstaged but preserved. Fix and re-stage." -For structural-only failures (Steps 2-4, 6-8), do NOT auto-rollback — report and let user decide. +For structural-only and semantic failures (Steps 1-3, 5, 5.5, 6-8), do NOT auto-rollback — report and let user decide. ### Snapshot cleanup on pipeline completion @@ -258,6 +338,8 @@ Append to `.codegraph/titan/gate-log.ndjson`: "manifesto": "pass|fail", "cycles": "pass|fail", "complexity": "pass|warn|fail", + "semanticAssertions": "pass|warn|fail|skipped", + "archSnapshot": "pass|warn|fail|skipped", "lint": "pass|fail|skipped", "build": "pass|fail|skipped", "tests": "pass|fail|skipped", @@ -279,6 +361,7 @@ Update `titan-state.json` (if exists): increment `progress.fixed`, update `fileA GATE PASS — safe to commit Changed: 3 functions across 2 files Blast radius: 12 transitive callers + Structural: pass | Semantic: pass | Architecture: pass Lint: pass | Build: pass | Tests: pass Complexity: all within thresholds (worst: halstead.bugs 0.3) ``` @@ -290,9 +373,11 @@ GATE WARN — review before committing Warnings: - utils.js historically co-changes with config.js (not staged) - parseConfig MI improved 18 → 35 but still below 50 + - Semantic: new dependency on module scheduled for decomposition + - Architecture: directory src/domain/ cohesion dropped 0.6 → 0.45 ``` -**FAIL:** +**FAIL (test/lint/build failures — rollback triggered):** ``` GATE FAIL — changes unstaged, graph restored Failures: @@ -301,24 +386,15 @@ GATE FAIL — changes unstaged, graph restored Fix issues, re-stage, re-run /titan-gate ``` ---- - -## Issue Tracking - -During validation, if you encounter any of the following, append a JSON line to `.codegraph/titan/issues.ndjson`: - -- **Codegraph bugs:** wrong diff-impact, false cycle detection, incorrect complexity after changes -- **Tooling issues:** check command failures, snapshot errors, build tool problems -- **Process suggestions:** threshold adjustments, missing checks, workflow improvements -- **Codebase observations:** test gaps, flaky tests, build warnings worth noting - -Format (one JSON object per line, append-only): - -```json -{"phase": "gate", "timestamp": "", "severity": "bug|limitation|suggestion", "category": "codegraph|tooling|process|codebase", "description": "", "context": ""} +**FAIL (structural/semantic failures — no rollback):** +``` +GATE FAIL — changes preserved for review — manual unstage if needed + Failures: + - Semantic: removed export `parseConfig` still imported by 3 files + - Architecture: new upward dependency presentation/ → domain/ + Staged changes are intact. Fix the issues above, or manually run `git reset HEAD` to unstage. + Re-stage and re-run /titan-gate when ready. ``` - -Log issues as they happen. The `/titan-close` phase compiles these into the final report. --- @@ -332,7 +408,6 @@ Log issues as they happen. The `/titan-close` phase compiles these into the fina - **Force mode** downgrades WARN → PASS but cannot override FAIL. - **Run the project's own lint/build/test** — codegraph checks are necessary but not sufficient. - **Use the correct check flags:** `--cycles`, `--blast-radius `, `--boundaries`. -- If any check produces unexpected output, **log it to `issues.ndjson`** before continuing. ## Self-Improvement diff --git a/.claude/skills/titan-run/SKILL.md b/.claude/skills/titan-run/SKILL.md new file mode 100644 index 00000000..d774857f --- /dev/null +++ b/.claude/skills/titan-run/SKILL.md @@ -0,0 +1,621 @@ +--- +name: titan-run +description: Run the full Titan Paradigm pipeline end-to-end by dispatching each phase to sub-agents with fresh context windows. Orchestrates recon → gauntlet → sync → forge automatically. +argument-hint: <--skip-recon> <--skip-gauntlet> <--start-from forge> <--gauntlet-batch-size 5> <--yes> +allowed-tools: Agent, Read, Bash, Glob, Write, Edit +--- + +# Titan RUN — End-to-End Pipeline Orchestrator + +You are the **orchestrator** for the full Titan Paradigm pipeline. Your job is to dispatch each phase to a **sub-agent** (fresh context window), **validate the results**, and loop phases that require multiple invocations — all without human intervention. + +> **You are lightweight.** You do NOT run codegraph commands, audit files, or make code changes yourself. You only: (1) spawn sub-agents, (2) read and validate state files, (3) decide what to run next. + +**Arguments** (from `$ARGUMENTS`): +- No args → full pipeline from scratch, target `.` +- `` → target path (passed to recon) +- `--skip-recon` → skip recon (assumes artifacts exist) +- `--skip-gauntlet` → skip gauntlet (assumes artifacts exist) +- `--start-from ` → jump to phase: `recon`, `gauntlet`, `sync`, `forge` +- `--gauntlet-batch-size ` → batch size for gauntlet (default: 5) +- `--yes` → skip all confirmation prompts in the orchestrator (pre-pipeline, forge checkpoint, and resume prompts) and in forge (per-phase confirmation) + +--- + +## Step 0 — Pre-flight + +1. **Worktree check:** + ```bash + git rev-parse --show-toplevel && git worktree list + ``` + If you are NOT in a worktree, **stop:** "Run `/worktree` first. The Titan pipeline writes artifacts and makes code changes — worktree isolation is required." + +2. **Parse arguments.** Determine: + - `targetPath` (default: `.`) + - `startPhase` (default: `recon`) + - `gauntletBatchSize` (default: `5`) + - `autoConfirm` (default: `false`) + +3. **Check existing state.** Read `.codegraph/titan/titan-state.json` if it exists. + - If state exists and `--start-from` not specified, ask user: "Existing Titan state found (phase: ``). Resume from current state, or start fresh with `/titan-reset` first?" + - If `--yes` is set, resume automatically. + +4. **Sync with main** (once, before any sub-agent runs): + ```bash + git fetch origin main && git merge origin/main --no-edit + ``` + If merge conflict → stop: "Merge conflict after syncing with main. Resolve conflicts and re-run `/titan-run`." + +5. **Print plan:** + ``` + Titan Pipeline — End-to-End Run + Target: + Starting from: + Gauntlet batch size: + + Phases: recon → gauntlet (loop) → sync → [PAUSE] → forge (loop) + Each phase runs in a sub-agent with a fresh context window. + Forge requires explicit confirmation (analysis phases are safe to automate). + ``` + + If `--yes` is NOT set, ask user to confirm before proceeding. + +--- + +## Pre-Agent Gate (run before EVERY sub-agent dispatch) + +Before spawning any sub-agent, run these checks. This catches git state drift, concurrent interference, and corruption left by a crashed agent. + +### G1. Git health check +```bash +git status --porcelain +``` +- **Unexpected dirty files** (files not in `.codegraph/titan/`): Print warning with the file list. Ask user to confirm proceeding, or stop. If `--yes`, log the warning and continue — but do NOT stage or commit these files. +- **Merge conflicts** (lines starting with `UU`, `AA`, `DD`, `AU`, `UA`, `DU`, `UD`): Stop immediately: "Unresolved merge conflict detected. Resolve before continuing." + +### G2. Worktree still valid +```bash +git rev-parse --is-inside-work-tree +``` +If this fails (worktree was pruned or moved), stop: "Worktree is no longer valid. Create a new one with `/worktree`." + +### G3. State file integrity +If `.codegraph/titan/titan-state.json` should exist at this point (i.e., we're past recon): +```bash +node -e "try { JSON.parse(require('fs').readFileSync('.codegraph/titan/titan-state.json','utf8')); console.log('OK'); } catch(e) { console.log('CORRUPT: '+e.message); process.exit(1); }" +``` +- If **CORRUPT** → attempt recovery from backup: + 1. Check if `.codegraph/titan/titan-state.json.bak` exists. + 2. If the backup exists, validate it is valid JSON: + ```bash + node -e "try { JSON.parse(require('fs').readFileSync('.codegraph/titan/titan-state.json.bak','utf8')); console.log('BACKUP OK'); } catch(e) { console.log('BACKUP CORRUPT: '+e.message); process.exit(1); }" + ``` + 3. If the backup is valid → restore it: `cp .codegraph/titan/titan-state.json.bak .codegraph/titan/titan-state.json` + 4. If the backup is also corrupt or missing → stop: "State file corrupted with no valid backup. Run `/titan-reset` and start over." + +### G4. State backup +Before every sub-agent dispatch, back up the current state file: +```bash +cp .codegraph/titan/titan-state.json .codegraph/titan/titan-state.json.bak 2>/dev/null || true +``` +If a sub-agent corrupts the state, G3 on the next iteration will detect it and restore from `.bak`. + +--- + +## Step 0.5 — Artifact pre-validation (phase skip) + +**Run this step if `--start-from` was specified, `--skip-recon` is set, or `--skip-gauntlet` is set.** Any of these flags cause phases to be skipped — their artifacts must exist and be valid before proceeding. When `--skip-recon` is set, validate recon artifacts. When `--skip-gauntlet` is set, validate both recon and gauntlet artifacts. + +For each phase BEFORE `startPhase`, run the corresponding V-checks: + +| Skipped phase | Required artifacts + checks | +|---------------|-----------------------------| +| `recon` | V1 (titan-state.json structure), V2 (GLOBAL_ARCH.md), V3 (snapshot exists — WARN if missing), V4 (cross-check counts) | +| `gauntlet` | V5 (coverage ≥ 50%), V6 (entry completeness sample), V7 (summary consistency); also run NDJSON integrity check (2c) | +| `sync` | V8 (sync.json structure), V9 (targets trace to gauntlet), V10 (dependency order) | + +If ANY required artifact is **missing** → stop: "Cannot start from `` — `` is missing. Run the full pipeline or start from an earlier phase." + +If ANY V-check that is normally VALIDATION FAILED would fail → stop with the same message as it would during normal execution. + +WARN-level V-checks from skipped phases are surfaced as prefixed warnings: "[skipped-phase pre-validation] " — they do not stop the pipeline. + +--- + +## Step 1 — RECON + +**Skip if:** `--skip-recon`, `--start-from` is after recon, or `titan-state.json` already has `currentPhase` beyond `"recon"`. + +### 1a. Run Pre-Agent Gate (G1-G4) + +### 1b. Dispatch sub-agent + +Use the **Agent tool** to spawn a sub-agent: + +``` +prompt: | + You are running the Titan RECON phase. Read and follow the skill file at + .claude/skills/titan-recon/SKILL.md exactly. Target path: . + + IMPORTANT: Skip the worktree check (Step 0.1) — the orchestrator already verified this. + IMPORTANT: Skip the "sync with main" step (Step 0.2) — the orchestrator already did this. + Execute Steps 1-13 as documented. +``` + +### 1c. Post-phase validation + +After the agent returns, validate the artifacts: + +**V1. titan-state.json structure:** +Read `.codegraph/titan/titan-state.json` and verify ALL of these fields exist and are non-empty: +- `version` — must be a number +- `initialized` — must be an ISO 8601 string +- `currentPhase` — must equal `"recon"` +- `stats.totalNodes` — must be > 0 +- `stats.totalEdges` — must be > 0 +- `stats.totalFiles` — must be > 0 +- `domains` — must be an array with length > 0 +- `batches` — must be an array with length > 0 +- `priorityQueue` — must be an array with length > 0 + +If any field is missing, zero, or wrong type → **VALIDATION FAILED.** Print which fields failed and stop: "RECON produced incomplete state. Re-run with `/titan-run --start-from recon`." + +**V2. GLOBAL_ARCH.md exists and has content:** +Read `.codegraph/titan/GLOBAL_ARCH.md`: +- Must exist +- Must contain `## Domain Map` heading +- Must have > 10 lines + +If missing or empty → **VALIDATION FAILED.** + +**V3. Snapshot created:** +```bash +codegraph snapshot list 2>/dev/null | grep titan-baseline || echo "NO_SNAPSHOT" +``` +If `NO_SNAPSHOT` → **WARN** (not fatal, but note it: "No baseline snapshot — rollback in GATE will not work"). + +**V4. Cross-check counts:** +- `titan-state.json → stats.totalFiles` should roughly match the number of targets across all batches (batches are subsets of files, so `sum(batch.files.length)` should be ≤ `totalFiles`) +- `priorityQueue.length` should be > 0 and ≤ `totalNodes` + +If wildly inconsistent (e.g., 0 batches but 500 nodes) → **WARN** with details. + +Print: `RECON validated. Domains: , Batches: , Priority targets: , Quality score: ` + +--- + +## Step 2 — GAUNTLET (loop) + +**Skip if:** `--skip-gauntlet` or `--start-from` is after gauntlet. + +### 2a. Pre-loop check + +Read `.codegraph/titan/gauntlet-summary.json` if it exists: +- If `"complete": true` → run gauntlet post-validation (2d) and skip loop if it passes +- Otherwise, count completed batches from `titan-state.json` for progress tracking + +Compute `expectedTargetCount` from `titan-state.json → priorityQueue.length` (or sum of batch file counts). This is the ground truth for "how many targets should gauntlet audit." + +### 2b. Gauntlet loop + +Set `maxIterations = 50` (safety limit). +Set `stallCount = 0`, `maxStalls = 3` (consecutive no-progress iterations before abort). + +``` +previousAuditedCount = titan-state.json → progress.audited (or 0) +iteration = 0 + +while iteration < maxIterations: + iteration += 1 + + # Run Pre-Agent Gate (G1-G4) + + # Dispatch sub-agent + Agent → "Run /titan-gauntlet with batch size . + Read .claude/skills/titan-gauntlet/SKILL.md and follow it exactly. + Batch size: . + Skip worktree check and main sync — already handled. + Process as many batches as context allows, then save state and stop." + + # Check completion + Read .codegraph/titan/gauntlet-summary.json (if exists) + if "complete": true → break + + # Progress tracking + Read .codegraph/titan/titan-state.json + currentAuditedCount = progress.audited + + if currentAuditedCount == previousAuditedCount: + stallCount += 1 + Print: "WARNING: Gauntlet iteration made no progress (stall /)" + if stallCount >= maxStalls: + Stop: "Gauntlet stalled for consecutive iterations at / targets. Likely stuck on a problematic target. Check gauntlet.ndjson for the last successful entry and investigate the next target in the batch." + else: + stallCount = 0 # reset on any progress + + countBeforeUpdate = previousAuditedCount + previousAuditedCount = currentAuditedCount + + # Efficiency check: if progress is very slow (< 2 targets per iteration), warn + # Only fire when stallCount == 0 — if stalled, the stall warning already covers it + targetsThisIteration = currentAuditedCount - countBeforeUpdate + if targetsThisIteration == 1 and iteration > 3 and stallCount == 0: + Print: "WARNING: Only 1 target per iteration — agent may be spending too much context. Consider increasing batch size." + + Print: "Gauntlet iteration : / targets audited" +``` + +### 2c. NDJSON integrity check + +After the loop completes (or on each iteration if you prefer lightweight checks): + +```bash +node -e " +const fs = require('fs'); +const path = '.codegraph/titan/gauntlet.ndjson'; +if (!fs.existsSync(path)) { + console.log(JSON.stringify({ valid: 0, corrupt: 0, total: 0, missing: true })); + process.exit(0); +} +const lines = fs.readFileSync(path,'utf8').trim().split('\n'); +let valid = 0, corrupt = 0; +for (const line of lines) { + try { JSON.parse(line); valid++; } catch { corrupt++; } +} +console.log(JSON.stringify({ valid, corrupt, total: lines.length, missing: false })); +" +``` + +- If `missing == true`: treat as equivalent to `valid == 0` — the file does not exist yet (expected on first iteration, error if the loop should have produced entries). +- If `corrupt > 0`: Print "WARNING: corrupt lines in gauntlet.ndjson (likely from a crashed sub-agent). These targets may need re-auditing." +- If `valid == 0` and `missing == false`: Stop: "gauntlet.ndjson has no valid entries. Something went wrong." + +### 2d. Post-loop validation + +**V5. Gauntlet coverage:** +- Count distinct `target` values in `gauntlet.ndjson` (valid lines only) +- Compare against `expectedTargetCount` +- If coverage < 80%: **WARN** "Gauntlet only audited / targets (%). Consider re-running with `/titan-run --start-from gauntlet`." +- If coverage < 50%: **VALIDATION FAILED.** Stop. + +**V6. Gauntlet entry completeness (sample check):** +Read first 5 and last 5 entries from `gauntlet.ndjson`. Each entry MUST have: +- `target` — non-empty string +- `file` — non-empty string +- `verdict` — one of `PASS`, `WARN`, `FAIL`, `DECOMPOSE` +- `pillarVerdicts` — object with keys `I`, `II`, `III`, `IV` +- `metrics` — object with at least `cognitive` and `cyclomatic` (numeric) +- `violations` — array + +If any sampled entry is missing required fields → **WARN**: "Gauntlet entry for is incomplete — sub-agent may have skipped rules. Fields missing: ." + +**V7. Summary consistency:** +Read `gauntlet-summary.json`: +- `summary.totalAudited` should equal the valid NDJSON line count +- `summary.pass + summary.warn + summary.fail + summary.decompose` should equal `summary.totalAudited` + +If mismatched → **WARN** with details (not fatal — the NDJSON is the source of truth, summary is derived). + +Print: `GAUNTLET validated. Audited: / targets. Pass: , Warn: , Fail: , Decompose: . NDJSON integrity: / lines OK.` + +--- + +## Step 3 — SYNC + +**Skip if:** `--start-from` is after sync, or `titan-state.json` has `currentPhase: "sync"` with existing `sync.json`. + +### 3a. Run Pre-Agent Gate (G1-G4) + +### 3b. Dispatch sub-agent + +``` +Agent → "Run /titan-sync. Read .claude/skills/titan-sync/SKILL.md and follow it exactly. + Skip worktree check and main sync — already handled. + Read GAUNTLET artifacts and produce sync.json." +``` + +### 3c. Post-phase validation + +**V8. sync.json structure:** +Read `.codegraph/titan/sync.json` and verify: +- `phase` — must equal `"sync"` +- `executionOrder` — must be an array with length > 0 +- Each entry in `executionOrder` must have: `phase` (number), `label` (string), `targets` (array), `commit` (string) +- `executionOrder` phases must be in ascending order +- No duplicate phase numbers + +If missing or structurally invalid → **VALIDATION FAILED.** Stop: "SYNC produced invalid plan. Re-run with `/titan-run --start-from sync`." + +**V9. Sync targets trace back to gauntlet:** +Collect all target names from `sync.json → executionOrder[*].targets` (flatten). +For each, verify it appears in `gauntlet.ndjson` as a `target` field, OR in `titan-state.json → roles.deadSymbols` (dead code targets come from recon, not gauntlet). + +If > 20% of sync targets have no gauntlet entry and aren't dead symbols → **WARN**: "SYNC references targets not found in gauntlet results. The sub-agent may have hallucinated targets." + +**V10. Execution order dependency check:** +For entries with `dependencies` arrays, verify that each dependency phase number exists in `executionOrder` and has a lower phase number. Circular dependencies in the execution plan → **VALIDATION FAILED.** + +Print: `SYNC validated. Execution phases: , Total targets: , Estimated commits: .` + +--- + +## Step 3.5 — Pre-forge: Architectural Snapshot + Human Checkpoint + +### 3.5a. Capture architectural snapshot + +Before any code changes, snapshot the codebase's architectural properties. This becomes the baseline for the architectural comparator in `/titan-gate` (Step 5.5). + +```bash +codegraph communities -T --json > .codegraph/titan/arch-snapshot-communities.json +codegraph structure --depth 2 --json > .codegraph/titan/arch-snapshot-structure.json +codegraph communities --drift -T --json > .codegraph/titan/arch-snapshot-drift.json +``` + +Combine into a single snapshot file: + +```bash +TITAN_HEAD_SHA=$(git rev-parse HEAD) +node -e " +const fs = require('fs'); +try { + const communities = JSON.parse(fs.readFileSync('.codegraph/titan/arch-snapshot-communities.json','utf8')); + const structure = JSON.parse(fs.readFileSync('.codegraph/titan/arch-snapshot-structure.json','utf8')); + const drift = JSON.parse(fs.readFileSync('.codegraph/titan/arch-snapshot-drift.json','utf8')); + const snapshot = { + timestamp: new Date().toISOString(), + capturedBefore: 'forge', + headSha: '$TITAN_HEAD_SHA', + communities, + structure, + drift + }; + fs.writeFileSync('.codegraph/titan/arch-snapshot.json', JSON.stringify(snapshot, null, 2)); +} catch (e) { + console.error('WARNING: Failed to build arch-snapshot.json: ' + e.message); + console.error('Architectural comparison (titan-gate A1/A3/A4) will be skipped.'); +} +" +``` + +Clean up temp files: +```bash +rm -f .codegraph/titan/arch-snapshot-communities.json .codegraph/titan/arch-snapshot-structure.json .codegraph/titan/arch-snapshot-drift.json +``` + +This snapshot is read by `/titan-gate` Step 5.5 during every commit validation. + +### 3.5b. Human checkpoint + +**This is a mandatory pause.** Analysis phases (recon, gauntlet, sync) are read-only. FORGE makes real code changes and commits. The user must see the plan. + +Print: +``` +================================================================ + ANALYSIS COMPLETE — FORGE CHECKPOINT +================================================================ + +The analysis phases (recon → gauntlet → sync) are done. +FORGE will now make code changes and commit them. + +Execution plan summary: + Phase 1: