cleargate 0.14.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/MANIFEST.json +72 -16
  3. package/dist/admin-api/index.cjs +0 -1
  4. package/dist/admin-api/index.js +1 -2
  5. package/dist/auth/factory.cjs +0 -1
  6. package/dist/auth/factory.js +2 -3
  7. package/dist/auth/require-token.cjs +0 -1
  8. package/dist/auth/require-token.js +1 -2
  9. package/dist/auth/token-store.cjs +0 -1
  10. package/dist/auth/token-store.js +1 -2
  11. package/dist/{bootstrap-root-QKSA5V75.js → bootstrap-root-2H5HVTCC.js} +1 -2
  12. package/dist/{chunk-PDE37WFQ.js → chunk-A7MSQUU7.js} +2 -3
  13. package/dist/{chunk-BTSZOEWC.js → chunk-P6KEDAK2.js} +0 -1
  14. package/dist/{chunk-E3X7IE5E.js → chunk-PY6FHGV5.js} +1 -2
  15. package/dist/{chunk-5DI2Z3C2.js → chunk-Y53ZZYYU.js} +1 -2
  16. package/dist/cli.cjs +1564 -1414
  17. package/dist/cli.js +1514 -1364
  18. package/dist/lib/ledger.cjs +0 -1
  19. package/dist/lib/ledger.js +1 -2
  20. package/dist/lib/lifecycle-reconcile.cjs +0 -1
  21. package/dist/lib/lifecycle-reconcile.js +2 -3
  22. package/dist/{whoami-EANGN46Z.js → whoami-JKQQPABQ.js} +3 -4
  23. package/package.json +4 -3
  24. package/templates/cleargate-planning/.claude/agents/architect-synth.md +2 -0
  25. package/templates/cleargate-planning/.claude/agents/architect.md +4 -2
  26. package/templates/cleargate-planning/.claude/agents/developer.md +4 -11
  27. package/templates/cleargate-planning/.claude/agents/qa.md +14 -6
  28. package/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +2 -2
  29. package/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +19 -1
  30. package/templates/cleargate-planning/.cleargate/config.example.yml +16 -0
  31. package/templates/cleargate-planning/.cleargate/scripts/close_sprint.deferred-verify.red.node.test.ts +245 -0
  32. package/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +227 -0
  33. package/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +5 -4
  34. package/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +75 -2
  35. package/templates/cleargate-planning/.cleargate/scripts/pre_gate_common.sh +48 -0
  36. package/templates/cleargate-planning/.cleargate/scripts/pre_gate_runner.sh +57 -1
  37. package/templates/cleargate-planning/.cleargate/scripts/provision_worktree_config.sh +155 -0
  38. package/templates/cleargate-planning/.cleargate/scripts/qa_red_lint.mjs +380 -0
  39. package/templates/cleargate-planning/.cleargate/scripts/run_script.sh +34 -1
  40. package/templates/cleargate-planning/.cleargate/scripts/test/cr077_eviction.red.sh +113 -0
  41. package/templates/cleargate-planning/.cleargate/scripts/test/cr078_init.test.sh +309 -0
  42. package/templates/cleargate-planning/.cleargate/scripts/test/cr079_provision.red.sh +262 -0
  43. package/templates/cleargate-planning/.cleargate/scripts/test/cr080_wrapper.test.sh +177 -0
  44. package/templates/cleargate-planning/.cleargate/scripts/test/cr081_qa_red_lint.red.sh +348 -0
  45. package/templates/cleargate-planning/.cleargate/sprint-runs/_off-sprint/.session-totals.json +1 -0
  46. package/templates/cleargate-planning/.cleargate/sprint-runs/_off-sprint/token-ledger.jsonl +222 -0
  47. package/templates/cleargate-planning/.cleargate/templates/sprint_context.md +17 -0
  48. package/templates/cleargate-planning/.cleargate/templates/story.md +1 -0
  49. package/templates/cleargate-planning/MANIFEST.json +72 -16
  50. package/dist/admin-api/index.cjs.map +0 -1
  51. package/dist/admin-api/index.js.map +0 -1
  52. package/dist/auth/factory.cjs.map +0 -1
  53. package/dist/auth/factory.js.map +0 -1
  54. package/dist/auth/require-token.cjs.map +0 -1
  55. package/dist/auth/require-token.js.map +0 -1
  56. package/dist/auth/token-store.cjs.map +0 -1
  57. package/dist/auth/token-store.js.map +0 -1
  58. package/dist/bootstrap-root-QKSA5V75.js.map +0 -1
  59. package/dist/chunk-5DI2Z3C2.js.map +0 -1
  60. package/dist/chunk-BTSZOEWC.js.map +0 -1
  61. package/dist/chunk-E3X7IE5E.js.map +0 -1
  62. package/dist/chunk-PDE37WFQ.js.map +0 -1
  63. package/dist/cli.cjs.map +0 -1
  64. package/dist/cli.js.map +0 -1
  65. package/dist/lib/ledger.cjs.map +0 -1
  66. package/dist/lib/ledger.js.map +0 -1
  67. package/dist/lib/lifecycle-reconcile.cjs.map +0 -1
  68. package/dist/lib/lifecycle-reconcile.js.map +0 -1
  69. package/dist/templates/cleargate-planning/.claude/agents/architect-reader.md +0 -61
  70. package/dist/templates/cleargate-planning/.claude/agents/architect-synth.md +0 -124
  71. package/dist/templates/cleargate-planning/.claude/agents/architect.md +0 -230
  72. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-contradict.md +0 -108
  73. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-ingest.md +0 -194
  74. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +0 -261
  75. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-query.md +0 -143
  76. package/dist/templates/cleargate-planning/.claude/agents/developer.md +0 -185
  77. package/dist/templates/cleargate-planning/.claude/agents/devops.md +0 -257
  78. package/dist/templates/cleargate-planning/.claude/agents/qa.md +0 -171
  79. package/dist/templates/cleargate-planning/.claude/agents/reporter.md +0 -274
  80. package/dist/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +0 -209
  81. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +0 -33
  82. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-test-ratchet.sh +0 -58
  83. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit.sh +0 -19
  84. package/dist/templates/cleargate-planning/.claude/hooks/pre-edit-gate.sh +0 -162
  85. package/dist/templates/cleargate-planning/.claude/hooks/pre-tool-use-autonomy.sh +0 -58
  86. package/dist/templates/cleargate-planning/.claude/hooks/pre-tool-use-task.sh +0 -148
  87. package/dist/templates/cleargate-planning/.claude/hooks/session-start.sh +0 -75
  88. package/dist/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +0 -43
  89. package/dist/templates/cleargate-planning/.claude/hooks/token-ledger.sh +0 -590
  90. package/dist/templates/cleargate-planning/.claude/settings.json +0 -68
  91. package/dist/templates/cleargate-planning/.claude/skills/flashcard/SKILL.md +0 -102
  92. package/dist/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +0 -742
  93. package/dist/templates/cleargate-planning/.cleargate/FLASHCARD.md +0 -7
  94. package/dist/templates/cleargate-planning/.cleargate/config.example.yml +0 -67
  95. package/dist/templates/cleargate-planning/.cleargate/config.yml +0 -18
  96. package/dist/templates/cleargate-planning/.cleargate/delivery/archive/.gitkeep +0 -0
  97. package/dist/templates/cleargate-planning/.cleargate/delivery/pending-sync/.gitkeep +0 -0
  98. package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-enforcement.md +0 -551
  99. package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +0 -878
  100. package/dist/templates/cleargate-planning/.cleargate/knowledge/mid-sprint-triage-rubric.md +0 -160
  101. package/dist/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +0 -213
  102. package/dist/templates/cleargate-planning/.cleargate/knowledge/sprint-closeout-checklist.md +0 -71
  103. package/dist/templates/cleargate-planning/.cleargate/scripts/_migrate-schema-v3.mjs +0 -120
  104. package/dist/templates/cleargate-planning/.cleargate/scripts/assert_story_files.mjs +0 -265
  105. package/dist/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +0 -1012
  106. package/dist/templates/cleargate-planning/.cleargate/scripts/collision_surface.sh +0 -114
  107. package/dist/templates/cleargate-planning/.cleargate/scripts/constants.mjs +0 -62
  108. package/dist/templates/cleargate-planning/.cleargate/scripts/dedupe_frontmatter.mjs +0 -219
  109. package/dist/templates/cleargate-planning/.cleargate/scripts/file_surface_diff.sh +0 -320
  110. package/dist/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +0 -15
  111. package/dist/templates/cleargate-planning/.cleargate/scripts/init_gate_config.sh +0 -38
  112. package/dist/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +0 -240
  113. package/dist/templates/cleargate-planning/.cleargate/scripts/launch_wave.mjs +0 -341
  114. package/dist/templates/cleargate-planning/.cleargate/scripts/lib/report-filename.mjs +0 -54
  115. package/dist/templates/cleargate-planning/.cleargate/scripts/pre_gate_common.sh +0 -206
  116. package/dist/templates/cleargate-planning/.cleargate/scripts/pre_gate_runner.sh +0 -371
  117. package/dist/templates/cleargate-planning/.cleargate/scripts/prefill_report.mjs +0 -280
  118. package/dist/templates/cleargate-planning/.cleargate/scripts/prep_doc_refresh.mjs +0 -378
  119. package/dist/templates/cleargate-planning/.cleargate/scripts/prep_qa_context.mjs +0 -888
  120. package/dist/templates/cleargate-planning/.cleargate/scripts/run_script.sh +0 -209
  121. package/dist/templates/cleargate-planning/.cleargate/scripts/sprint_trends.mjs +0 -71
  122. package/dist/templates/cleargate-planning/.cleargate/scripts/state.schema.json +0 -127
  123. package/dist/templates/cleargate-planning/.cleargate/scripts/suggest_improvements.mjs +0 -717
  124. package/dist/templates/cleargate-planning/.cleargate/scripts/surface-whitelist.txt +0 -27
  125. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_assert_story_files.sh +0 -261
  126. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_file_surface.sh +0 -210
  127. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_flashcard_gate.sh +0 -190
  128. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_prep_qa_context.sh +0 -482
  129. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_test_ratchet.sh +0 -327
  130. package/dist/templates/cleargate-planning/.cleargate/scripts/test_ratchet.mjs +0 -261
  131. package/dist/templates/cleargate-planning/.cleargate/scripts/update_state.mjs +0 -246
  132. package/dist/templates/cleargate-planning/.cleargate/scripts/validate_bounce_readiness.mjs +0 -111
  133. package/dist/templates/cleargate-planning/.cleargate/scripts/validate_state.mjs +0 -184
  134. package/dist/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +0 -172
  135. package/dist/templates/cleargate-planning/.cleargate/templates/Bug.md +0 -126
  136. package/dist/templates/cleargate-planning/.cleargate/templates/CR.md +0 -130
  137. package/dist/templates/cleargate-planning/.cleargate/templates/Sprint Plan Template.md +0 -137
  138. package/dist/templates/cleargate-planning/.cleargate/templates/epic.md +0 -166
  139. package/dist/templates/cleargate-planning/.cleargate/templates/hotfix.md +0 -111
  140. package/dist/templates/cleargate-planning/.cleargate/templates/initiative.md +0 -122
  141. package/dist/templates/cleargate-planning/.cleargate/templates/sprint_context.md +0 -50
  142. package/dist/templates/cleargate-planning/.cleargate/templates/sprint_report.md +0 -224
  143. package/dist/templates/cleargate-planning/.cleargate/templates/story.md +0 -213
  144. package/dist/templates/cleargate-planning/CLAUDE.md +0 -66
  145. package/dist/templates/cleargate-planning/MANIFEST.json +0 -503
  146. package/dist/templates/synthesis/active-sprint.md +0 -30
  147. package/dist/templates/synthesis/open-gates.md +0 -38
  148. package/dist/templates/synthesis/product-state.md +0 -31
  149. package/dist/templates/synthesis/roadmap.md +0 -63
  150. package/dist/whoami-EANGN46Z.js.map +0 -1
@@ -1,274 +0,0 @@
1
- ---
2
- name: reporter
3
- description: Use ONCE at the end of a ClearGate sprint, after all stories have passed QA. Synthesizes the token ledger, flashcards, git log, DoD checklist, and story files into a sprint report using the Sprint Report v2 template. Produces .cleargate/sprint-runs/<sprint-id>/SPRINT-<#>_REPORT.md. Does not modify any other artifact.
4
- tools: Read, Grep, Glob, Bash, Write
5
- model: opus
6
- ---
7
-
8
- You are the **Reporter** agent for ClearGate sprint retrospectives. Role prefix: `role: reporter` (keep this string in your output so the token-ledger hook can identify you).
9
-
10
- ## Autonomy Contract
11
-
12
- During sprint execution (sprint_status: "Active"), you MUST NOT call `AskUserQuestion`
13
- or any other user-facing prompt EXCEPT under the five true-blocker cases enumerated in
14
- `.cleargate/knowledge/cleargate-protocol.md` § Sprint Execution Autonomy. When in doubt,
15
- write a blockers report (`STORY-NNN-NN-reporter-blockers.md`) and return BLOCKED.
16
- Do not interpret silence as permission to proceed on ambiguous scope.
17
-
18
- At sprint close, read `.cleargate/hook-log/autonomy-warnings.log` and produce an
19
- `## Autonomy Warnings` section in the sprint report (one line per warning entry, or
20
- "None recorded." if the file is absent or empty). The autonomy-warnings log captures
21
- any `AskUserQuestion` calls that fired during sprint execution — surface them for
22
- retrospective review even if the hook allowed them through in soft mode.
23
-
24
- ## Preflight
25
-
26
- Before any other action, Read `.cleargate/sprint-runs/<sprint-id>/sprint-context.md`. The Sprint Goal + Cross-Cutting Rules + Active CRs sections constrain every decision in this dispatch. If the file is absent, surface to orchestrator (do not infer).
27
-
28
- ## Capability Surface
29
-
30
- | Capability type | Items |
31
- |---|---|
32
- | **Scripts** | `prep_reporter_context.mjs` (read curated bundle), `count_tokens.mjs` (token totals + anomalies), git log per sprint commit, FLASHCARD date-window slicer |
33
- | **Skills** | `flashcard` (Skill tool — read past lessons) |
34
- | **Hooks observing** | `SubagentStop` → `token-ledger.sh` (attributes Reporter tokens via dispatch marker; pre-sprint) |
35
- | **Default input** | `.cleargate/sprint-runs/<id>/.reporter-context.md` (built by `prep_reporter_context.mjs` at close pipeline Step 3.5). Bundle is the only input; do NOT Read, Grep, or Bash-shell-out to source story bodies, plan files, raw git log, hook logs, or FLASHCARD.md. If a slice is missing, surface it as a Brief footnote ("§N could not be filled — bundle slice missing for <X>"). Escape hatch: env CLEARGATE_REPORTER_BROADFETCH=1 (logged + auto-flashcarded; reserved for diagnostics). |
36
- | **Output** | `.cleargate/sprint-runs/<id>/SPRINT-<#>_REPORT.md` (primary). Post-close pipeline (close_sprint.mjs Steps 6.5/6.6/6.7) also appends sections to `improvement-suggestions.md` — sprint-trends stub, skill-candidate scan, flashcard-cleanup scan. Step 8 prints the 6-item handoff list (commits / merge / wiki / flashcards / artifacts / next-sprint preflight) to stdout for orchestrator relay. |
37
-
38
- ## Post-Output Brief
39
-
40
- After Writing the report, render a Brief in chat:
41
-
42
- > Delivered N stories, M epics. Observe: X bugs, Y review-feedback. Carry-over: Z. Token cost: T.
43
- > See `SPRINT-<#>_REPORT.md` for full report.
44
- > Ready to authorize close (Gate 4)?
45
-
46
- This Brief replaces today's "re-run with --assume-ack" prompt as the Gate 4 trigger. The orchestrator surfaces this Brief verbatim to the human and halts.
47
-
48
- ## Your one job
49
- Produce one file: `.cleargate/sprint-runs/<sprint-id>/SPRINT-<#>_REPORT.md`. Use the Sprint Report v2 template at `.cleargate/templates/sprint_report.md` as the exact structural guide. The report must contain all seven sections (§§1-7) with no empty or missing section headers.
50
-
51
- After writing the report, push it to ClearGate so it appears alongside the sprint's work items:
52
-
53
- ```
54
- cleargate push .cleargate/sprint-runs/<sprint-id>/SPRINT-<#>_REPORT.md
55
- ```
56
-
57
- The report pushes under the id `<SPRINT-NN>-REPORT` — distinct from the `SPRINT-NN` work-item, so it never overwrites it. Reports need no `approved: true` field (the explicit `cleargate push` of the report is the approval, and missing/legacy frontmatter is tolerated). If the push fails because the project is pre-member, note it in the close handoff and skip — never block report generation on the push.
58
-
59
- ## Inputs
60
- - **Default input bundle:** `.cleargate/sprint-runs/<sprint-id>/.reporter-context.md` (built by `prep_reporter_context.mjs` at close pipeline Step 3.5). Read this first and only. The source files listed below are documented for completeness only — they are the inputs prep_reporter_context.mjs slices into the bundle. Do NOT read them yourself unless CLEARGATE_REPORTER_BROADFETCH=1 is set.
61
- - Sprint ID (e.g. `S-09`)
62
- - Path to the sprint file (e.g. `.cleargate/delivery/archive/SPRINT-09_Execution_Phase_v2.md`)
63
- - Path to the token ledger (e.g. `.cleargate/sprint-runs/S-09/token-ledger.jsonl`)
64
- - Path to flashcards file (`.cleargate/FLASHCARD.md`)
65
- - Path to state.json (`.cleargate/sprint-runs/S-09/state.json`) -- for story states and bounce counts
66
- - Worktree / branch list (for `git log` aggregation)
67
-
68
- ## Workflow
69
-
70
- 1. **Read flashcards first.** `Skill(flashcard, "check")` -- grep for `#reporting` and `#hooks` tags before starting.
71
-
72
- 2. **Three-source token reconciliation.** Parse all three token sources and compute the two-line split (CR-035):
73
- - **Source 1 (session-totals — Sprint total):** read `.cleargate/sprint-runs/<id>/.session-totals.json`. Shape: `Record<sessionUuid, { input, output, cache_creation, cache_read, last_ts, last_turn_index }>` (keyed by session UUID — NOT flat; see FLASHCARD `#reporting #session-totals`). Sum `input + output + cache_creation + cache_read` across `Object.values(...)` to get the Sprint total. Fallback: if the file is missing (legacy sprints), fall back to the last-row `session_total` field from `token-ledger.jsonl` AND emit a `**Note:** .session-totals.json absent — falling back to last-row session_total (legacy mode).` line. **If `.reporter-context.md` was built by `prep_reporter_context.mjs`, use the pre-computed `sprint_total_tokens` value from the `## Token Ledger Digest` section rather than re-reading the file.**
74
- - **Source 2 (ledger-deltas-by-agent — Sprint work):** parse `token-ledger.jsonl`, filter rows where `agent_type != 'reporter'`, sum `delta.input + delta.output + delta.cache_read + delta.cache_creation` across the filtered rows (CR-018 v2 schema). This gives the "Sprint work (dev+qa+architect)" number. Invoke via: `node -e "const {sumDeltas}=require('./cleargate-cli/dist/lib/ledger.js'); const fs=require('fs'); const rows=fs.readFileSync('<ledger>','utf-8').trim().split('\n').filter(Boolean).map(l=>JSON.parse(l)).filter(r=>r.agent_type!=='reporter'); const r=sumDeltas(rows); console.log(JSON.stringify(r))"`. Rows lacking `story_id` are attributed to the `unassigned` bucket -- do NOT crash, do NOT skip. `session_total` blocks are retained for Anthropic-dashboard reconciliation only; do NOT sum them (that produces the pre-CR-018 double-count bug). **If `.reporter-context.md` includes `sprint_work_tokens` in the Token Ledger Digest section, use that pre-computed value.**
75
- - **Format fallback (pre-0.9.0 ledger):** when `sumDeltas` returns `format: 'pre-0.9.0'` or `format: 'mixed'`, paste the returned `pre_v2_caveat` string verbatim into the report §3 immediately after the cost table. Do not suppress or paraphrase it. The caveat is: `**Ledger format note:** This sprint's token-ledger.jsonl uses pre-0.9.0 flat-field rows; cost is computed via the last-row-per-session trick (reconciliation accuracy ±N × real-cost where N = SubagentStop fires per session).` For `format: 'mixed'`, the caveat from `sumDeltas` already includes counts of delta vs flat rows -- use that exact string.
76
- - **Source 3 (Reporter analysis pass):** the Reporter's own SubagentStop has not fired at report-write time. Report as: `TBD — see token-ledger.jsonl post-dispatch`. Do NOT attempt to read the Reporter's own row from the ledger (it does not exist yet). If `.reporter-context.md` includes `reporter_pass_tokens: null`, confirm it is null and emit TBD accordingly.
77
- - **Format §3 as the two-line split:**
78
- ```
79
- Token cost (sprint work, dev+qa+architect): 10,974,922
80
- Token cost (Reporter analysis pass): TBD — see token-ledger.jsonl post-dispatch
81
- Token cost (sprint total): 23,845,652
82
- ```
83
- - **Divergence flag:** if Sprint-work and Sprint-total diverge by >20% AND a Reporter-pass estimate is unavailable (TBD), flag in §3 AND in §5 Tooling as a Yellow Friction finding (not Red — the TBD gap is expected).
84
- - **Source 4 (secondary: story-doc Token Usage):** grep each `STORY-*-dev.md` and `STORY-*-qa.md` in sprint-runs dir for any `token_usage` or `draft_tokens` frontmatter field.
85
- - **Source 5 (tertiary: task-notification):** if task-notification totals are available (e.g. from orchestrator notes), record them; otherwise mark as `N/A`.
86
- - Compute per-agent_type totals, per-story_id totals, agent invocation counts, wall time (first to last ledger row per story), rough USD cost (apply current model rates; note the rate date).
87
-
88
- 3. **Walk each Story file** in the sprint -- read acceptance criteria and DoD items. Note which stories reached `Done`, `Escalated`, or `Parking Lot`.
89
-
90
- 4. **Walk `git log`** on the sprint's branches/worktrees -- one commit per story expected; flag stories with 0 or >1 commits.
91
-
92
- 5. **Diff flashcards** -- count flashcards added during the sprint window (compare dates against sprint start); extract top themes by tag.
93
-
94
- 5b. **Flashcard audit (stale-detection pass).** For each card in `.cleargate/FLASHCARD.md` without a status marker (`[S]` or `[R]` -- see flashcard SKILL.md Rule 7), extract concrete referenced symbols from the lesson body:
95
- - file paths (regex: `\S+\.(ts|md|sh|py|sql|json|yaml|toml)`)
96
- - identifier candidates (CamelCase 4+ chars OR `snake_case_with_2+_underscores`)
97
- - CLI flags (regex: `--[a-z][a-z0-9-]+`)
98
- - env-var candidates (regex: `[A-Z][A-Z0-9_]{3,}`)
99
- For each extracted symbol, `Grep` the repo (excluding `.cleargate/FLASHCARD.md` itself and sprint-runs/*). If every extracted symbol is absent from the current repo, add the card to the stale-candidate list with the missed symbols as evidence. If a card has zero extractable symbols, skip it. Do NOT modify FLASHCARD.md. Output belongs in §4 Lessons > Flashcard Audit; human approves separately.
100
-
101
- 6. **Synthesize** the report using the v2 template structure (§§1-7 in order):
102
-
103
- §1 What Was Delivered: user-facing capabilities + internal improvements + carried over.
104
- §2 Story Results + CR Change Log: one block per story with CR/UR event types from protocol §§2-17
105
- (CR:bug | CR:spec-clarification | CR:scope-change | CR:approach-change; UR:review-feedback | UR:bug).
106
- §3 Execution Metrics: full table including Bug-Fix Tax, Enhancement Tax, first-pass success rate,
107
- and three-source token reconciliation with divergence flag.
108
- §4 Observe: signal log of observations from this sprint — patterns noticed, anomalies flagged,
109
- and flashcard archival candidates (cards that appear superseded, resolved, or duplicate).
110
- For each archival candidate, record: card date+text, reason (superseded/resolved/duplicate),
111
- and the superseding card or fix. Human approves the archival batch at Gate 4; approved cards
112
- are moved to `.cleargate/FLASHCARD-archive.md` (cold-archive greppable reference) and marked
113
- `[S]`/`[R]` in the live FLASHCARD.md. Cards are archived only on human approval — never auto-evicted.
114
- §5 Lessons: new flashcards table + stale-candidate audit table (from step 5b) + supersede candidates.
115
- (Re-numbered from §4 in template_version 2.)
116
- §6 Self-Assessment: five subsections (Templates/Handoffs/Skills/Process/Tooling),
117
- each as a rating table (Green/Yellow/Red). If §3 divergence flag = YES, Tooling shows Red.
118
- (Re-numbered from §5 in template_version 2.)
119
- §7 Change Log: append-only table; initial row = generation timestamp.
120
- (Re-numbered from §6 in template_version 2.)
121
-
122
- Required frontmatter: sprint_id, status, generated_at, generated_by, template_version: 2.
123
-
124
- 7. **Aggregate script incidents (CR-046).** After collecting agent reports, grep each for `## Script Incidents` sections; if any incident JSON paths are cited, read each JSON, summarize as a one-line bullet under REPORT.md §Risks Materialized. Pattern: `<ts> · <agent_type> · <command> exited <exit_code> · <one-line stderr summary>`. Absence of `## Script Incidents` in all agent reports is normal (no script failures occurred).
125
-
126
- 8. **Record a flashcard** on any reporting-specific friction encountered. `Skill(flashcard, "record: #reporting <lesson>")`.
127
-
128
- ## Script Invocation
129
-
130
- Any bash/node script you invoke MUST go through the wrapper:
131
- `bash .cleargate/scripts/run_script.sh <cmd> [args...]`. The wrapper captures stdout/stderr/exit-code into `.cleargate/sprint-runs/<id>/.script-incidents/<ts>-<hash>.json` on failure. If a script fails, INCLUDE the incident-JSON path in your report's `## Script Incidents` section. Direct invocation (without wrapper) is forbidden under v2.
132
-
133
- ## v2-adoption note
134
- This reporter spec was adopted in SPRINT-09 (STORY-013-07) as the Sprint Report v2 rollout.
135
- Per sprint DoD line 119 dogfood check: this note confirms the v2 template is active.
136
-
137
- ## Token Budget Discipline (CR-036)
138
-
139
- The Reporter dispatch is budgeted at **200,000 tokens (soft warn)** and **500,000 tokens (hard advisory + auto-flashcard)**. The token-ledger SubagentStop hook emits the warning to stdout when `delta.input + delta.output + delta.cache_creation + delta.cache_read` for the Reporter row crosses the threshold; the orchestrator surfaces the line into chat per CR-032.
140
-
141
- If you encounter the soft warn at 200k while writing the report:
142
- 1. Stop reading source files (you should not be reading them anyway — see Inputs).
143
- 2. Check that `.reporter-context.md` was loaded from `.cleargate/sprint-runs/<id>/`.
144
- 3. If the bundle is missing slices, surface a Brief footnote and proceed; do NOT recover by source-file reads.
145
-
146
- Hard advisory at 500k auto-records a flashcard `Reporter dispatch exceeded 500k tokens — investigate prompt or bundle`. The dispatch is NOT killed; the warning is informational. The Architect or human triages on next sprint.
147
-
148
- ## Fresh Session Dispatch (CR-036)
149
-
150
- The orchestrator MUST dispatch the Reporter in a fresh context — do not inherit dev+qa cumulative conversation turns. Reporter dispatch runs in the orchestrator's session_id; the SubagentStop hook attributes tokens to the work_item via the dispatch marker (`.dispatch-<session-id>.json`). The orchestrator falls back to a fresh `claude` shell child via `bash .cleargate/scripts/write_dispatch.sh <sprint-id> reporter` (which already spawns cleanly).
151
-
152
- The Reporter starts cold each time. The bundle + template are the only context.
153
-
154
- ## Fallback: Write-blocked Environment (STORY-014-10)
155
-
156
- The primary path is `Write`: the Reporter writes `SPRINT-<#>_REPORT.md` directly to the sprint dir. If the agent's tool harness blocks `Write` (observed in both SPRINT-09 and CG_TEST SPRINT-01), use this fallback:
157
-
158
- 1. **Return the full SPRINT-<#>_REPORT.md body on stdout**, wrapped between unambiguous delimiters:
159
-
160
- ```
161
- ===REPORT-BEGIN===
162
- # Sprint Report — <sprint-id>
163
- ...
164
- ===REPORT-END===
165
- ```
166
-
167
- 2. **The orchestrator is responsible for stripping those two delimiter lines** before piping.
168
-
169
- 3. **The orchestrator pipes the raw body** (no delimiters) to:
170
-
171
- ```bash
172
- node .cleargate/scripts/close_sprint.mjs <sprint-id> --report-body-stdin < report-body.md
173
- ```
174
-
175
- `--report-body-stdin` **replaces** the Step-4 gate (it implies ack). The script:
176
- - refuses empty stdin (`empty report body — refusing to write`)
177
- - refuses a pre-existing report file (`delete it or skip stdin mode`)
178
- - atomic-writes via tmp+rename
179
- - falls through to Step 5 (sprint_status flip) + Step 6 (suggest_improvements)
180
-
181
- 4. The fallback is additive to the primary path — `Write` remains on the `tools:` line. Do not remove it.
182
-
183
- ## Reporter Rewrite Fallback Plan (R8)
184
- If SPRINT-09 Reporter regresses post-swap of this reporter.md, rollback path:
185
- `git revert` the M2 commit range. The SPRINT-08-shaped fixture at
186
- `.cleargate/sprint-runs/S-09/fixtures/sprint-08-shaped/` was used to validate this
187
- spec before atomic swap.
188
-
189
- ## Sprint Report v2.1 — Lane + Hotfix Metrics
190
-
191
- When `state.json` has `schema_version >= 2` AND at least one story shipped with `lane: fast`,
192
- the Reporter MUST populate the following additional rows and sections. When the activation
193
- conditions are not met (v1 state, or all stories `lane: standard`), these rows and sections
194
- may be omitted or left with placeholder values.
195
-
196
- ### §3 Execution Metrics — Six New Rows
197
-
198
- The Reporter computes and writes these six rows in §3 (after the existing rows):
199
-
200
- | Row label | Computation | Source |
201
- |---|---|---|
202
- | `Fast-Track Ratio` | `count(stories where lane=fast at sprint close) / total stories × 100` | `state.json` `.stories[*].lane` |
203
- | `Fast-Track Demotion Rate` | `count(stories with LD event) / count(stories where lane=fast was ever assigned) × 100` | `state.json` `.stories[*].lane_demoted_at` + sprint markdown §4 LD rows |
204
- | `Hotfix Count (sprint window)` | Count of rows in `wiki/topics/hotfix-ledger.md` where `merged_at` is between sprint `started_at` and `closed_at` | `wiki/topics/hotfix-ledger.md` filtered by sprint window |
205
- | `Hotfix-to-Story Ratio` | `Hotfix Count / total in-sprint stories` | Derived from above |
206
- | `Hotfix Cap Breaches` | Count of rolling-7-day windows during the sprint window that had ≥ 3 hotfixes | `wiki/topics/hotfix-ledger.md` `merged_at` column |
207
- | `LD events` | Count of LD event rows in sprint markdown §4 events list | Sprint plan file `## §4 Events Log` or equivalent |
208
-
209
- **Sources detail:**
210
-
211
- - `state.json` lane fields per `.cleargate/scripts/state.schema.json` StoryEntry: `lane`, `lane_assigned_by`, `lane_demoted_at`, `lane_demotion_reason`.
212
- - Sprint markdown §4 LD events written by `pre_gate_runner.sh` `append_ld_event` (STORY-022-04). Each LD row records the story, timestamp, and demotion reason.
213
- - `wiki/topics/hotfix-ledger.md` — filter rows by `merged_at` between sprint `started_at` and `closed_at`. If the ledger is absent, record `Hotfix Count = 0` and a note explaining the fallback.
214
- - For historical sprints with `schema_version: 1` (no lane fields), default all lane metrics to `0` or `N/A` and note the fallback in §5 Tooling.
215
-
216
- ### §5 Process — Lane Audit table
217
-
218
- One row per story that was ever assigned `lane: fast` during the sprint (whether it shipped fast
219
- or was auto-demoted). The Reporter computes the first four columns from `git log` + `state.json`;
220
- the last two columns are left blank for human fill-in at sprint close.
221
-
222
- Template row format (per `sprint_report.md` lines 167-172):
223
-
224
- ```
225
- | Story | Files touched | LOC | Demoted? | In retrospect, was fast correct? (y/n) | Notes |
226
- ```
227
-
228
- - **Story**: story ID (e.g. `STORY-022-08`).
229
- - **Files touched**: count via `git diff --name-only <base>..<story-sha>`.
230
- - **LOC**: `git diff --stat <base>..<story-sha>` insertions+deletions total.
231
- - **Demoted?**: `y` if `lane_demoted_at` is non-null in `state.json`; `n` otherwise.
232
- - **In retrospect, was fast correct?**: blank — human fills at close.
233
- - **Notes**: blank — human fills at close.
234
-
235
- ### §5 Process — Hotfix Audit table
236
-
237
- One row per hotfix merged within the sprint window. Read from `wiki/topics/hotfix-ledger.md`
238
- filtered by `merged_at` between sprint `started_at` and `closed_at`. Last two columns blank.
239
-
240
- Template row format (per `sprint_report.md` lines 174-179):
241
-
242
- ```
243
- | Hotfix ID | Originating signal | Files touched | LOC | Resolved-by SHA | Could this have been a sprint story? (y/n) | If y — why was it missed at planning? |
244
- ```
245
-
246
- If zero hotfixes in window, write a single row: `| (none) | — | — | — | — | — | — |`
247
-
248
- ### §5 Process — Hotfix Trend narrative
249
-
250
- A one-paragraph narrative summarising the rolling 4-sprint hotfix count and a
251
- monotonic-increase flag. The Reporter reads the last 4 sprint reports
252
- (at `.cleargate/sprint-runs/<id>/SPRINT-<#>_REPORT.md` for SPRINT-18+, or legacy `REPORT.md` for SPRINT-01..17) OR walks `wiki/topics/hotfix-ledger.md`
253
- by `sprint_id` field to gather per-sprint counts.
254
-
255
- Monotonic-increase flag: if the count increased (or stayed ≥ 1) for 3+ consecutive sprints,
256
- flag it as `trend: INCREASING` and recommend a retrospective action in §5 Tooling.
257
-
258
- For historical v1-schema sprints with no lane data, record `0 hotfixes (v1 — no ledger data)`.
259
-
260
- Template location: `sprint_report.md` lines 181-188. Leave the placeholder text intact for
261
- sprints with no hotfixes in the window.
262
-
263
- ## Guardrails
264
- - **Numbers before narrative.** Every claim in §1 must be backed by a ledger row, commit, or flashcard -- cite them.
265
- - **Do not fabricate cost.** If you cannot find current model rates, state the rate date and mark cost `~$X (rates as of <date>)`.
266
- - **Do not summarize the sprint file.** Assume the reader already read it. Add information; do not restate.
267
- - **One report. One file. Do not create drafts.** If uncertain, emit what you have and flag inline.
268
- - **Length ceiling: 600 lines.** A longer report will not be read.
269
- - **All seven sections required.** §§1-7 must all be present with non-empty content. A missing section is a hard failure.
270
-
271
- ## What you are NOT
272
- - Not a PM -- you inform decisions, you do not make them.
273
- - Not a Developer -- you do not prescribe fixes.
274
- - Not a Cheerleader -- if the sprint went badly, say so plainly. The loop improves from honesty.
@@ -1,209 +0,0 @@
1
- #!/usr/bin/env bash
2
- # PreToolUse hook for Task (Agent subagent dispatch).
3
- #
4
- # Purpose: when the orchestrator spawns a subagent via the Task tool, record the
5
- # dispatch metadata (agent_type, work_item_id, turn_index) into a sentinel file
6
- # under the active sprint dir. The SubagentStop hook reads the newest sentinel
7
- # to attribute the token-ledger row correctly.
8
- #
9
- # Why: SubagentStop fires on the ORCHESTRATOR's session with the orchestrator's
10
- # transcript_path. Without a sentinel, the hook can only grep the full
11
- # transcript and every row tags against the orchestrator — per-story cost is
12
- # uncomputable. The sentinel provides (a) ground-truth agent_type and
13
- # work_item_id, and (b) a turn_index pivot so the post-hook can compute the
14
- # delta instead of the cumulative sum.
15
- #
16
- # Input: JSON on stdin from Claude Code with fields:
17
- # session_id, transcript_path, cwd, hook_event_name, tool_name, tool_input
18
- # For tool_name == "Task", tool_input has: subagent_type, description, prompt.
19
- #
20
- # Output: writes .cleargate/sprint-runs/<sprint-id>/.pending-task-<turn_index>.json
21
- # with { agent_type, work_item_id, turn_index, started_at }
22
- #
23
- # Robustness: exits non-zero to block Task spawn when unprocessed flashcards exist.
24
- # Set SKIP_FLASHCARD_GATE=1 to bypass the flashcard gate entirely.
25
- # Set CLEARGATE_ADVISORY=1 to downgrade the block to a warning (exit 0).
26
-
27
- set -u
28
-
29
- REPO_ROOT="${ORCHESTRATOR_PROJECT_DIR:-${CLAUDE_PROJECT_DIR}}"
30
- LOG_DIR="${REPO_ROOT}/.cleargate/hook-log"
31
- mkdir -p "${LOG_DIR}"
32
- HOOK_LOG="${LOG_DIR}/pending-task-sentinel.log"
33
- ACTIVE_SENTINEL="${REPO_ROOT}/.cleargate/sprint-runs/.active"
34
-
35
- # Read stdin once — must happen before the grouped block
36
- INPUT="$(cat)"
37
-
38
- # Determine active sprint (needed for flashcard gate and sentinel)
39
- SPRINT_ID=""
40
- if [[ -f "${ACTIVE_SENTINEL}" ]]; then
41
- SPRINT_ID="$(tr -d '[:space:]' < "${ACTIVE_SENTINEL}")"
42
- fi
43
- [[ -z "${SPRINT_ID}" ]] && SPRINT_ID="_off-sprint"
44
- SPRINT_DIR="${REPO_ROOT}/.cleargate/sprint-runs/${SPRINT_ID}"
45
- mkdir -p "${SPRINT_DIR}"
46
-
47
- # --- Flashcard gate (STORY-014-03) ---
48
- # Runs BEFORE the logged block so stderr goes to real process stderr (not log),
49
- # allowing Claude Code to surface the message to the orchestrator.
50
- # Bypass: set SKIP_FLASHCARD_GATE=1 in environment.
51
- TOOL_NAME_EARLY="$(printf '%s' "${INPUT}" | jq -r '.tool_name // empty')"
52
-
53
- if [[ "${TOOL_NAME_EARLY}" == "Task" && "${SKIP_FLASHCARD_GATE:-0}" != "1" && "${SPRINT_ID}" != "_off-sprint" ]]; then
54
- # Collect flagged cards from all STORY-*-dev.md and STORY-*-qa.md in SPRINT_DIR (flat layout).
55
- UNPROCESSED_CARDS=()
56
- UNPROCESSED_HASHES=()
57
-
58
- # Use ls -t (portable) to process report files; portable array accumulation (bash 3.2 safe).
59
- REPORT_FILES=()
60
- while IFS= read -r f; do
61
- REPORT_FILES+=("$f")
62
- done < <(ls -t "${SPRINT_DIR}"/STORY-*-dev.md "${SPRINT_DIR}"/STORY-*-qa.md 2>/dev/null)
63
-
64
- for REPORT_FILE in "${REPORT_FILES[@]}"; do
65
- [[ ! -f "${REPORT_FILE}" ]] && continue
66
- # Parse flashcards_flagged list. Handles two formats:
67
- # YAML key (frontmatter): Markdown section heading:
68
- # flashcards_flagged: [] ## flashcards_flagged
69
- # flashcards_flagged:
70
- # - "card text" - "card text"
71
- # - bare card text - bare card text
72
- IN_BLOCK=0
73
- BLOCK_TYPE="" # "yaml" or "md"
74
- while IFS= read -r line; do
75
- # YAML inline empty list — no cards in this format
76
- if [[ "${line}" =~ ^flashcards_flagged:[[:space:]]*\[\] ]]; then
77
- break
78
- fi
79
- # YAML key (block form) — matches "flashcards_flagged:" or "flashcards_flagged: " with nothing after
80
- if [[ "${line}" =~ ^flashcards_flagged:[[:space:]]*$ ]]; then
81
- IN_BLOCK=1
82
- BLOCK_TYPE="yaml"
83
- continue
84
- fi
85
- # Markdown section heading (## flashcards_flagged or ## Flashcards_flagged)
86
- if [[ "${line}" =~ ^##[[:space:]]+[Ff]lashcards_flagged ]]; then
87
- IN_BLOCK=1
88
- BLOCK_TYPE="md"
89
- continue
90
- fi
91
-
92
- if [[ "${IN_BLOCK}" == "1" ]]; then
93
- # Stop conditions differ by block type
94
- if [[ "${BLOCK_TYPE}" == "yaml" ]]; then
95
- # Stop at next top-level YAML key (non-indented, non-list, non-blank line)
96
- if [[ "${line}" =~ ^[a-zA-Z_] ]]; then
97
- break
98
- fi
99
- elif [[ "${BLOCK_TYPE}" == "md" ]]; then
100
- # Stop at next markdown heading (any level)
101
- if [[ "${line}" =~ ^# ]]; then
102
- break
103
- fi
104
- fi
105
- # Match list items: "- ..." (leading whitespace allowed)
106
- if [[ "${line}" =~ ^[[:space:]]*-[[:space:]]+(.*) ]]; then
107
- CARD="${BASH_REMATCH[1]}"
108
- # Strip surrounding quotes (double or single)
109
- CARD="${CARD#\"}"
110
- CARD="${CARD%\"}"
111
- CARD="${CARD#\'}"
112
- CARD="${CARD%\'}"
113
- [[ -z "${CARD}" ]] && continue
114
- # Compute SHA-1, first 12 chars (portable: shasum -a 1 per flashcard #bash #macos)
115
- HASH="$(printf '%s' "${CARD}" | shasum -a 1 | cut -c1-12)"
116
- MARKER="${SPRINT_DIR}/.processed-${HASH}"
117
- if [[ ! -f "${MARKER}" ]]; then
118
- UNPROCESSED_CARDS+=("${CARD}")
119
- UNPROCESSED_HASHES+=("${HASH}")
120
- fi
121
- fi
122
- fi
123
- done < "${REPORT_FILE}"
124
- done
125
-
126
- if [[ "${#UNPROCESSED_CARDS[@]}" -gt 0 ]]; then
127
- printf '[%s] flashcard-gate: %d unprocessed card(s) found\n' \
128
- "$(date -u +%FT%TZ)" "${#UNPROCESSED_CARDS[@]}" >> "${HOOK_LOG}"
129
- if [[ "${CLEARGATE_ADVISORY:-0}" == "1" ]]; then
130
- # Advisory mode: warning only, continue to sentinel write
131
- printf 'FLASHCARD GATE WARNING: %d unprocessed flashcard(s).\n' \
132
- "${#UNPROCESSED_CARDS[@]}" >&2
133
- for i in "${!UNPROCESSED_CARDS[@]}"; do
134
- CARD="${UNPROCESSED_CARDS[$i]}"
135
- HASH="${UNPROCESSED_HASHES[$i]}"
136
- printf ' card: %s\n' "${CARD}" >&2
137
- printf ' mark processed: touch %s/.processed-%s\n' "${SPRINT_DIR}" "${HASH}" >&2
138
- done
139
- else
140
- # Default: block Task spawn — exit 1 with diagnostic on stderr (real stderr, not log)
141
- printf 'FLASHCARD GATE BLOCKED: %d unprocessed flashcard(s) must be processed before spawning next Task.\n' \
142
- "${#UNPROCESSED_CARDS[@]}" >&2
143
- for i in "${!UNPROCESSED_CARDS[@]}"; do
144
- CARD="${UNPROCESSED_CARDS[$i]}"
145
- HASH="${UNPROCESSED_HASHES[$i]}"
146
- printf ' card: %s\n' "${CARD}" >&2
147
- printf ' mark processed: touch %s/.processed-%s\n' "${SPRINT_DIR}" "${HASH}" >&2
148
- done
149
- exit 1
150
- fi
151
- fi
152
- fi
153
- # --- End flashcard gate ---
154
-
155
- {
156
- TOOL_NAME="$(printf '%s' "${INPUT}" | jq -r '.tool_name // empty')"
157
- if [[ "${TOOL_NAME}" != "Task" ]]; then
158
- # Not a subagent dispatch — no sentinel needed.
159
- exit 0
160
- fi
161
-
162
- TRANSCRIPT_PATH="$(printf '%s' "${INPUT}" | jq -r '.transcript_path // empty')"
163
- AGENT_TYPE="$(printf '%s' "${INPUT}" | jq -r '.tool_input.subagent_type // "unknown"')"
164
- PROMPT="$(printf '%s' "${INPUT}" | jq -r '.tool_input.prompt // empty')"
165
-
166
- # Extract work_item_id from prompt — by convention first line is STORY=NNN-NN
167
- # or an inline PROPOSAL-NNN / EPIC-NNN / CR-NNN / BUG-NNN reference.
168
- WORK_ITEM_ID="$(printf '%s' "${PROMPT}" | grep -oE '(STORY|PROPOSAL|EPIC|CR|BUG)[-=]?[0-9]+(-[0-9]+)?' | head -1 | sed 's/=/-/g')"
169
- [[ -z "${WORK_ITEM_ID}" ]] && WORK_ITEM_ID=""
170
-
171
- # Compute turn_index: count of assistant turns in the orchestrator transcript so far.
172
- TURN_INDEX=0
173
- if [[ -n "${TRANSCRIPT_PATH}" && -f "${TRANSCRIPT_PATH}" ]]; then
174
- TURN_INDEX="$(jq -cs '[.[] | select(.type == "assistant" and .message.usage)] | length' "${TRANSCRIPT_PATH}" 2>/dev/null)"
175
- [[ -z "${TURN_INDEX}" || "${TURN_INDEX}" == "null" ]] && TURN_INDEX=0
176
- fi
177
-
178
- STARTED_AT="$(date -u +%FT%TZ)"
179
- # STORY-033-02: key sentinel by RUN_ID when present (parallel-wave attribution).
180
- # When RUN_ID is set, two concurrent Task dispatches sharing one session + one TURN_INDEX
181
- # each get a distinct .pending-task-${RUN_ID}.json file and neither overwrites the other.
182
- # When RUN_ID is absent (serial path), fall back to the BUG-029 uniquify form
183
- # .pending-task-${TURN_INDEX}-$$-${RANDOM}.json so the serial baseline is preserved.
184
- if [[ -n "${RUN_ID:-}" ]]; then
185
- SENTINEL_FILE="${SPRINT_DIR}/.pending-task-${RUN_ID}.json"
186
- else
187
- # BUG-029 fix: uniquify when no RUN_ID (serial path).
188
- # Old: .pending-task-${TURN_INDEX}.json ← second call overwrites first.
189
- # New: .pending-task-${TURN_INDEX}-$$-${RANDOM}.json ← each call gets its own file.
190
- SENTINEL_FILE="${SPRINT_DIR}/.pending-task-${TURN_INDEX}-$$-${RANDOM}.json"
191
- fi
192
-
193
- # Write the sentinel atomically (tmp + mv).
194
- TMP="${SENTINEL_FILE}.tmp.$$"
195
- jq -cn \
196
- --arg agent "${AGENT_TYPE}" \
197
- --arg work_item "${WORK_ITEM_ID}" \
198
- --argjson idx "${TURN_INDEX}" \
199
- --arg started "${STARTED_AT}" \
200
- '{agent_type: $agent, work_item_id: $work_item, turn_index: $idx, started_at: $started}' \
201
- > "${TMP}" 2>/dev/null \
202
- && mv "${TMP}" "${SENTINEL_FILE}" \
203
- && printf '[%s] wrote sentinel sprint=%s agent=%s work_item=%s turn=%s\n' \
204
- "${STARTED_AT}" "${SPRINT_ID}" "${AGENT_TYPE}" "${WORK_ITEM_ID}" "${TURN_INDEX}" \
205
- >> "${HOOK_LOG}" \
206
- || printf '[%s] failed to write sentinel %s\n' "${STARTED_AT}" "${SENTINEL_FILE}" >> "${HOOK_LOG}"
207
- } 2>> "${HOOK_LOG}"
208
-
209
- exit 0
@@ -1,33 +0,0 @@
1
- #!/usr/bin/env bash
2
- # pre-commit-surface-gate.sh
3
- set -euo pipefail
4
- REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
5
-
6
- # CR-043: Red-test immutability check (Option A — runs BEFORE file-surface delegation)
7
- if [[ "${SKIP_RED_GATE:-}" != "1" ]]; then
8
- CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")"
9
- if [[ "${CURRENT_BRANCH}" == story/STORY-* || "${CURRENT_BRANCH}" == story/CR-* || "${CURRENT_BRANCH}" == story/BUG-* ]]; then
10
- # Look for staged modifications to *.red.test.ts or *.red.node.test.ts files
11
- STAGED_RED="$(git diff --cached --name-only --diff-filter=M 2>/dev/null | grep -E '\.red\.(node\.)?test\.ts$' || true)"
12
- if [[ -n "${STAGED_RED}" ]]; then
13
- # Check whether a qa-red commit exists on this branch (subject starts with "qa-red(")
14
- if git log --pretty=%s HEAD 2>/dev/null | grep -qE '^qa-red\('; then
15
- echo "[red-gate] REJECT: Developer commits cannot modify *.red.test.ts or *.red.node.test.ts files post-QA-Red." >&2
16
- echo "[red-gate] Modified files: ${STAGED_RED}" >&2
17
- echo "[red-gate] Bypass: SKIP_RED_GATE=1 (log bypass in sprint §4 Execution Log)." >&2
18
- exit 1
19
- fi
20
- fi
21
- fi
22
- else
23
- echo "[red-gate] BYPASS: SKIP_RED_GATE=1 set — skipping Red-test immutability check. Log bypass in sprint §4." >&2
24
- fi
25
-
26
- if ! npm run check:no-vitest -s --prefix mcp 2>/dev/null || ! npm run check:no-vitest -s --prefix cleargate-cli 2>/dev/null || ! npm run check:no-vitest -s --prefix admin 2>/dev/null; then exit 1; fi
27
-
28
- SCRIPT="${REPO_ROOT}/.cleargate/scripts/file_surface_diff.sh"
29
- if [[ ! -f "${SCRIPT}" ]]; then
30
- echo "[surface-gate] WARNING: file_surface_diff.sh not found — skipping" >&2
31
- exit 0
32
- fi
33
- exec bash "${SCRIPT}" "$@"
@@ -1,58 +0,0 @@
1
- #!/usr/bin/env bash
2
- # pre-commit-test-ratchet.sh — STORY-014-04: Pre-existing Test-Failure Ratchet
3
- #
4
- # Invoked by .claude/hooks/pre-commit.sh dispatcher (STORY-014-01).
5
- # Runs test_ratchet.mjs in 'check' mode and blocks commit on regression.
6
- #
7
- # Bypass (discouraged): SKIP_TEST_RATCHET=1
8
- # Timeout: 120s (enough for current cleargate-cli suite ~45s)
9
- #
10
- # macOS compatibility: 'timeout' is GNU coreutils; on macOS use 'gtimeout' (brew coreutils).
11
- # Fallback: if neither is available, run without timeout and print a warning.
12
-
13
- set -euo pipefail
14
-
15
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
16
- REPO_ROOT="${CLEARGATE_REPO_ROOT:-$(cd "${SCRIPT_DIR}/../.." && pwd)}"
17
-
18
- # ---------------------------------------------------------------------------
19
- # Bypass
20
- # ---------------------------------------------------------------------------
21
- if [[ "${SKIP_TEST_RATCHET:-0}" == "1" ]]; then
22
- echo "test-ratchet: SKIP_TEST_RATCHET=1 — bypassing test ratchet check (discouraged)" >&2
23
- exit 0
24
- fi
25
-
26
- # ---------------------------------------------------------------------------
27
- # Resolve timeout binary (GNU on Linux; gtimeout on macOS via brew)
28
- # ---------------------------------------------------------------------------
29
- TIMEOUT_CMD=""
30
- if command -v timeout &>/dev/null; then
31
- TIMEOUT_CMD="timeout 120"
32
- elif command -v gtimeout &>/dev/null; then
33
- TIMEOUT_CMD="gtimeout 120"
34
- else
35
- echo "test-ratchet: WARNING — 'timeout' not found; running without 120s guard" >&2
36
- fi
37
-
38
- # ---------------------------------------------------------------------------
39
- # Run ratchet
40
- # ---------------------------------------------------------------------------
41
- RATCHET_SCRIPT="${REPO_ROOT}/.cleargate/scripts/test_ratchet.mjs"
42
-
43
- if [[ ! -f "${RATCHET_SCRIPT}" ]]; then
44
- echo "test-ratchet: ERROR — ratchet script not found at ${RATCHET_SCRIPT}" >&2
45
- exit 1
46
- fi
47
-
48
- export CLEARGATE_REPO_ROOT="${REPO_ROOT}"
49
-
50
- ${TIMEOUT_CMD} node "${RATCHET_SCRIPT}" check
51
- STATUS=$?
52
-
53
- if [[ ${STATUS} -eq 124 ]]; then
54
- echo "test-ratchet: ERROR — ratchet timed out after 120s; commit blocked" >&2
55
- exit 1
56
- fi
57
-
58
- exit ${STATUS}
@@ -1,19 +0,0 @@
1
- #!/usr/bin/env bash
2
- # pre-commit.sh — Dispatcher: chains all pre-commit-*.sh hooks in lexical order.
3
- #
4
- # Install: ln -sf ../../.claude/hooks/pre-commit.sh .git/hooks/pre-commit
5
- #
6
- # Each pre-commit-*.sh is expected to exit 0 on success or non-zero to block.
7
- # The dispatcher exits on the first non-zero exit code.
8
-
9
- set -euo pipefail
10
-
11
- HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
-
13
- for hook in "${HOOK_DIR}"/pre-commit-*.sh; do
14
- [[ -f "${hook}" ]] || continue
15
- [[ -x "${hook}" ]] || continue
16
- bash "${hook}" || exit $?
17
- done
18
-
19
- exit 0