-
Notifications
You must be signed in to change notification settings - Fork 3
fix(skills): track real phase timestamps, open GitHub issues, enforce batch size #702
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
cf04d99
df24886
4b41ad2
c532565
b4766af
bfbccfa
1a7dc27
6d2e62a
6e963d8
1ee6bc6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,6 +40,24 @@ You are the **orchestrator** for the full Titan Paradigm pipeline. Your job is t | |
| - If state exists and `--start-from` not specified, ask user: "Existing Titan state found (phase: `<currentPhase>`). Resume from current state, or start fresh with `/titan-reset` first?" | ||
| - If `--yes` is set, resume automatically. | ||
|
|
||
| **Initialize the phase timestamps helper.** Throughout the pipeline, you will record wall-clock timestamps for each phase. Use this helper to write them into `titan-state.json`: | ||
|
|
||
| ```bash | ||
| # Record phase start (safe for resume — only sets startedAt if not already present): | ||
| node -e "const fs=require('fs');const s=JSON.parse(fs.readFileSync('.codegraph/titan/titan-state.json','utf8'));s.phaseTimestamps=s.phaseTimestamps||{};s.phaseTimestamps['<PHASE>']=s.phaseTimestamps['<PHASE>']||{};if(!s.phaseTimestamps['<PHASE>'].startedAt){s.phaseTimestamps['<PHASE>'].startedAt=new Date().toISOString();fs.writeFileSync('.codegraph/titan/titan-state.json',JSON.stringify(s,null,2));}" | ||
|
|
||
| # Record phase completion: | ||
| node -e "const fs=require('fs');const s=JSON.parse(fs.readFileSync('.codegraph/titan/titan-state.json','utf8'));s.phaseTimestamps=s.phaseTimestamps||{};s.phaseTimestamps['<PHASE>']=s.phaseTimestamps['<PHASE>']||{};s.phaseTimestamps['<PHASE>'].completedAt=new Date().toISOString();fs.writeFileSync('.codegraph/titan/titan-state.json',JSON.stringify(s,null,2));" | ||
| ``` | ||
|
|
||
| Replace `<PHASE>` with `recon`, `gauntlet`, `sync`, `forge`, or `close`. **Run the start command immediately before dispatching each phase's first sub-agent, and the completion command immediately after post-phase validation passes.** If resuming a phase (e.g., gauntlet loop iteration 2+), do NOT overwrite `startedAt` — only set it if it doesn't already exist. | ||
|
|
||
| **Timestamp validation:** After recording `completedAt` for any phase, verify `startedAt < completedAt`: | ||
| ```bash | ||
| node -e "const s=JSON.parse(require('fs').readFileSync('.codegraph/titan/titan-state.json','utf8'));const p=s.phaseTimestamps?.['<PHASE>'];if(p?.startedAt&&p?.completedAt){const start=new Date(p.startedAt),end=new Date(p.completedAt);if(end<=start){console.log('WARNING: <PHASE> completedAt ('+p.completedAt+') is not after startedAt ('+p.startedAt+')');process.exit(0);}console.log('<PHASE> duration: '+((end-start)/60000).toFixed(1)+' min');}else{console.log('WARNING: <PHASE> missing startedAt or completedAt');}" | ||
| ``` | ||
| If the check fails, log a warning but do not stop the pipeline — clock skew or immediate completion of short phases can cause this. | ||
|
|
||
| 4. **Sync with main** (once, before any sub-agent runs): | ||
| ```bash | ||
| git fetch origin main && git merge origin/main --no-edit | ||
|
|
@@ -128,6 +146,17 @@ WARN-level V-checks from skipped phases are surfaced as prefixed warnings: "[ski | |
|
|
||
| ### 1a. Run Pre-Agent Gate (G1-G4) | ||
|
|
||
| ### 1a.1. Record phase start timestamp | ||
| Record `phaseTimestamps.recon.startedAt` (only if not already set — it may exist from a prior crashed run). | ||
|
Comment on lines
+149
to
+150
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Step 1a.1 instructs the orchestrator to record Furthermore, even if the orchestrator pre-created a stub file, titan-recon Step 12 overwrites it wholesale with a freshly built JSON object that has no The end result: on every fresh run Recommended fix: Add {
"version": 1,
"initialized": "<ISO 8601>",
...
"phaseTimestamps": {
"recon": {
"startedAt": "<ISO 8601 — set at start of Step 1>"
}
}
}Alternatively, have titan-recon record its own
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed -- addressed the ENOENT issue in two places:
This ensures Regarding the |
||
|
|
||
| **Note:** On a fresh run, `titan-state.json` does not yet exist (titan-recon creates it in Step 12). Use this safe variant that creates a minimal stub if the file is missing: | ||
|
|
||
| ```bash | ||
| node -e "const fs=require('fs');const p='.codegraph/titan/titan-state.json';let s;try{s=JSON.parse(fs.readFileSync(p,'utf8'));}catch{fs.mkdirSync('.codegraph/titan',{recursive:true});s={};}s.phaseTimestamps=s.phaseTimestamps||{};s.phaseTimestamps['recon']=s.phaseTimestamps['recon']||{};if(!s.phaseTimestamps['recon'].startedAt){s.phaseTimestamps['recon'].startedAt=new Date().toISOString();fs.writeFileSync(p,JSON.stringify(s,null,2));}" | ||
| ``` | ||
|
|
||
| This ensures `recon.startedAt` is recorded even on first-time runs. titan-recon Step 12 merges any existing `phaseTimestamps` into the full state file it writes. | ||
|
|
||
| ### 1b. Dispatch sub-agent | ||
|
|
||
| Use the **Agent tool** to spawn a sub-agent: | ||
|
|
@@ -177,11 +206,14 @@ If `NO_SNAPSHOT` → **WARN** (not fatal, but note it: "No baseline snapshot — | |
| **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` | ||
| - **Batch size check:** Every batch must have ≤ 5 files. If any batch exceeds 5, **WARN**: "Batch <id> has <N> files (max 5). Large batches cause context overload in gauntlet sub-agents." | ||
|
|
||
| If wildly inconsistent (e.g., 0 batches but 500 nodes) → **WARN** with details. | ||
|
|
||
| Print: `RECON validated. Domains: <count>, Batches: <count>, Priority targets: <count>, Quality score: <score>` | ||
|
|
||
| Record `phaseTimestamps.recon.completedAt`. | ||
|
|
||
| --- | ||
|
|
||
| ## Step 2 — GAUNTLET (loop) | ||
|
|
@@ -190,6 +222,8 @@ Print: `RECON validated. Domains: <count>, Batches: <count>, Priority targets: < | |
|
|
||
| ### 2a. Pre-loop check | ||
|
|
||
| Record `phaseTimestamps.gauntlet.startedAt` (only if not already set — gauntlet may be resuming). | ||
|
|
||
| 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 | ||
|
|
@@ -298,6 +332,8 @@ If mismatched → **WARN** with details (not fatal — the NDJSON is the source | |
|
|
||
| Print: `GAUNTLET validated. Audited: <N>/<M> targets. Pass: <N>, Warn: <N>, Fail: <N>, Decompose: <N>. NDJSON integrity: <valid>/<total> lines OK.` | ||
|
|
||
| Record `phaseTimestamps.gauntlet.completedAt`. | ||
|
|
||
| --- | ||
|
|
||
| ## Step 3 — SYNC | ||
|
|
@@ -306,6 +342,9 @@ Print: `GAUNTLET validated. Audited: <N>/<M> targets. Pass: <N>, Warn: <N>, Fail | |
|
|
||
| ### 3a. Run Pre-Agent Gate (G1-G4) | ||
|
|
||
| ### 3a.1. Record phase start timestamp | ||
| Record `phaseTimestamps.sync.startedAt`. | ||
|
|
||
| ### 3b. Dispatch sub-agent | ||
|
|
||
| ``` | ||
|
|
@@ -337,6 +376,8 @@ For entries with `dependencies` arrays, verify that each dependency phase number | |
|
|
||
| Print: `SYNC validated. Execution phases: <N>, Total targets: <N>, Estimated commits: <N>.` | ||
|
|
||
| Record `phaseTimestamps.sync.completedAt`. | ||
|
|
||
| --- | ||
|
|
||
| ## Step 3.5 — Pre-forge: Architectural Snapshot + Human Checkpoint | ||
|
|
@@ -453,6 +494,8 @@ Once the user confirms (or `--yes` was set), `autoConfirm` is already `true` (se | |
|
|
||
| ### 4a. Pre-loop check | ||
|
|
||
| Record `phaseTimestamps.forge.startedAt` (only if not already set — forge may be resuming). | ||
|
|
||
| Read `.codegraph/titan/sync.json` → count total phases in `executionOrder`. | ||
| Read `.codegraph/titan/titan-state.json` → check `execution.completedPhases` (may not exist yet if forge hasn't started). | ||
|
|
||
|
|
@@ -575,6 +618,8 @@ If `.codegraph/titan/gate-log.ndjson` exists: | |
|
|
||
| Print forge summary. | ||
|
|
||
| Record `phaseTimestamps.forge.completedAt`. | ||
|
|
||
| --- | ||
|
|
||
| ## Step 5 — CLOSE (report + PRs) | ||
|
|
@@ -583,6 +628,9 @@ After forge completes, dispatch `/titan-close` to produce the final report with | |
|
|
||
| ### 5a. Run Pre-Agent Gate (G1-G4) | ||
|
|
||
| ### 5a.1. Record phase start timestamp | ||
| Record `phaseTimestamps.close.startedAt`. | ||
|
|
||
| ### 5b. Dispatch sub-agent | ||
|
|
||
| ``` | ||
|
|
@@ -598,6 +646,8 @@ After the agent returns, verify: | |
|
|
||
| If the agent created PRs, print the PR URLs. | ||
|
|
||
| Record `phaseTimestamps.close.completedAt`. | ||
|
|
||
| --- | ||
|
|
||
| ## Error Handling | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
close.completedAtis never available when the report is generatedphaseTimestamps.close.completedAtis written by titan-run after titan-close returns (seetitan-run/SKILL.mdStep 5c). When titan-close is building the Pipeline Timeline table,completedAtfor the CLOSE phase does not yet exist intitan-state.json— onlystartedAtis present.The template on this line says
<computed from phaseTimestamps.close>, but with a missingcompletedAtan AI agent following these instructions has no real value to compute from. This is the same "fabricated timestamps" failure mode the PR was written to fix: an agent asked to compute a duration it cannot derive will either guess or use a placeholder.The simplest fix is to have titan-close record its own
completedAtimmediately before writing the final report, then use that value in the table:Then titan-run's existing "Record
phaseTimestamps.close.completedAt" step (Step 5c) can be kept as a safety backstop or removed to avoid overwriting the more-accurate in-close value.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed -- added a "Record CLOSE completion timestamp" step in titan-close Step 7, immediately before writing the report. titan-close now records its own
phaseTimestamps.close.completedAtso the Pipeline Timeline CLOSE row has accurate duration data. The existing titan-run Step 5c recording is preserved as a safety backstop but the report no longer depends on it.