cleargate 0.14.0 → 0.15.0
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.
- package/CHANGELOG.md +16 -0
- package/dist/MANIFEST.json +71 -15
- package/dist/admin-api/index.cjs +0 -1
- package/dist/admin-api/index.js +1 -2
- package/dist/auth/factory.cjs +0 -1
- package/dist/auth/factory.js +2 -3
- package/dist/auth/require-token.cjs +0 -1
- package/dist/auth/require-token.js +1 -2
- package/dist/auth/token-store.cjs +0 -1
- package/dist/auth/token-store.js +1 -2
- package/dist/{bootstrap-root-QKSA5V75.js → bootstrap-root-2H5HVTCC.js} +1 -2
- package/dist/{chunk-PDE37WFQ.js → chunk-A7MSQUU7.js} +2 -3
- package/dist/{chunk-BTSZOEWC.js → chunk-P6KEDAK2.js} +0 -1
- package/dist/{chunk-E3X7IE5E.js → chunk-PY6FHGV5.js} +1 -2
- package/dist/{chunk-5DI2Z3C2.js → chunk-Y53ZZYYU.js} +1 -2
- package/dist/cli.cjs +1564 -1414
- package/dist/cli.js +1514 -1364
- package/dist/lib/ledger.cjs +0 -1
- package/dist/lib/ledger.js +1 -2
- package/dist/lib/lifecycle-reconcile.cjs +0 -1
- package/dist/lib/lifecycle-reconcile.js +2 -3
- package/dist/{whoami-EANGN46Z.js → whoami-JKQQPABQ.js} +3 -4
- package/package.json +4 -3
- package/templates/cleargate-planning/.claude/agents/architect.md +4 -2
- package/templates/cleargate-planning/.claude/agents/developer.md +4 -11
- package/templates/cleargate-planning/.claude/agents/qa.md +14 -6
- package/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +2 -2
- package/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +19 -1
- package/templates/cleargate-planning/.cleargate/config.example.yml +16 -0
- package/templates/cleargate-planning/.cleargate/scripts/close_sprint.deferred-verify.red.node.test.ts +245 -0
- package/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +227 -0
- package/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +5 -4
- package/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +75 -2
- package/templates/cleargate-planning/.cleargate/scripts/pre_gate_common.sh +48 -0
- package/templates/cleargate-planning/.cleargate/scripts/pre_gate_runner.sh +57 -1
- package/templates/cleargate-planning/.cleargate/scripts/provision_worktree_config.sh +155 -0
- package/templates/cleargate-planning/.cleargate/scripts/qa_red_lint.mjs +380 -0
- package/templates/cleargate-planning/.cleargate/scripts/run_script.sh +34 -1
- package/templates/cleargate-planning/.cleargate/scripts/test/cr077_eviction.red.sh +113 -0
- package/templates/cleargate-planning/.cleargate/scripts/test/cr078_init.test.sh +309 -0
- package/templates/cleargate-planning/.cleargate/scripts/test/cr079_provision.red.sh +262 -0
- package/templates/cleargate-planning/.cleargate/scripts/test/cr080_wrapper.test.sh +177 -0
- package/templates/cleargate-planning/.cleargate/scripts/test/cr081_qa_red_lint.red.sh +348 -0
- package/templates/cleargate-planning/.cleargate/sprint-runs/_off-sprint/.session-totals.json +1 -0
- package/templates/cleargate-planning/.cleargate/sprint-runs/_off-sprint/token-ledger.jsonl +27 -0
- package/templates/cleargate-planning/.cleargate/templates/sprint_context.md +17 -0
- package/templates/cleargate-planning/.cleargate/templates/story.md +1 -0
- package/templates/cleargate-planning/MANIFEST.json +71 -15
- package/dist/admin-api/index.cjs.map +0 -1
- package/dist/admin-api/index.js.map +0 -1
- package/dist/auth/factory.cjs.map +0 -1
- package/dist/auth/factory.js.map +0 -1
- package/dist/auth/require-token.cjs.map +0 -1
- package/dist/auth/require-token.js.map +0 -1
- package/dist/auth/token-store.cjs.map +0 -1
- package/dist/auth/token-store.js.map +0 -1
- package/dist/bootstrap-root-QKSA5V75.js.map +0 -1
- package/dist/chunk-5DI2Z3C2.js.map +0 -1
- package/dist/chunk-BTSZOEWC.js.map +0 -1
- package/dist/chunk-E3X7IE5E.js.map +0 -1
- package/dist/chunk-PDE37WFQ.js.map +0 -1
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/lib/ledger.cjs.map +0 -1
- package/dist/lib/ledger.js.map +0 -1
- package/dist/lib/lifecycle-reconcile.cjs.map +0 -1
- package/dist/lib/lifecycle-reconcile.js.map +0 -1
- package/dist/templates/cleargate-planning/.claude/agents/architect-reader.md +0 -61
- package/dist/templates/cleargate-planning/.claude/agents/architect-synth.md +0 -124
- package/dist/templates/cleargate-planning/.claude/agents/architect.md +0 -230
- package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-contradict.md +0 -108
- package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-ingest.md +0 -194
- package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +0 -261
- package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-query.md +0 -143
- package/dist/templates/cleargate-planning/.claude/agents/developer.md +0 -185
- package/dist/templates/cleargate-planning/.claude/agents/devops.md +0 -257
- package/dist/templates/cleargate-planning/.claude/agents/qa.md +0 -171
- package/dist/templates/cleargate-planning/.claude/agents/reporter.md +0 -274
- package/dist/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +0 -209
- package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +0 -33
- package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-test-ratchet.sh +0 -58
- package/dist/templates/cleargate-planning/.claude/hooks/pre-commit.sh +0 -19
- package/dist/templates/cleargate-planning/.claude/hooks/pre-edit-gate.sh +0 -162
- package/dist/templates/cleargate-planning/.claude/hooks/pre-tool-use-autonomy.sh +0 -58
- package/dist/templates/cleargate-planning/.claude/hooks/pre-tool-use-task.sh +0 -148
- package/dist/templates/cleargate-planning/.claude/hooks/session-start.sh +0 -75
- package/dist/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +0 -43
- package/dist/templates/cleargate-planning/.claude/hooks/token-ledger.sh +0 -590
- package/dist/templates/cleargate-planning/.claude/settings.json +0 -68
- package/dist/templates/cleargate-planning/.claude/skills/flashcard/SKILL.md +0 -102
- package/dist/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +0 -742
- package/dist/templates/cleargate-planning/.cleargate/FLASHCARD.md +0 -7
- package/dist/templates/cleargate-planning/.cleargate/config.example.yml +0 -67
- package/dist/templates/cleargate-planning/.cleargate/config.yml +0 -18
- package/dist/templates/cleargate-planning/.cleargate/delivery/archive/.gitkeep +0 -0
- package/dist/templates/cleargate-planning/.cleargate/delivery/pending-sync/.gitkeep +0 -0
- package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-enforcement.md +0 -551
- package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +0 -878
- package/dist/templates/cleargate-planning/.cleargate/knowledge/mid-sprint-triage-rubric.md +0 -160
- package/dist/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +0 -213
- package/dist/templates/cleargate-planning/.cleargate/knowledge/sprint-closeout-checklist.md +0 -71
- package/dist/templates/cleargate-planning/.cleargate/scripts/_migrate-schema-v3.mjs +0 -120
- package/dist/templates/cleargate-planning/.cleargate/scripts/assert_story_files.mjs +0 -265
- package/dist/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +0 -1012
- package/dist/templates/cleargate-planning/.cleargate/scripts/collision_surface.sh +0 -114
- package/dist/templates/cleargate-planning/.cleargate/scripts/constants.mjs +0 -62
- package/dist/templates/cleargate-planning/.cleargate/scripts/dedupe_frontmatter.mjs +0 -219
- package/dist/templates/cleargate-planning/.cleargate/scripts/file_surface_diff.sh +0 -320
- package/dist/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +0 -15
- package/dist/templates/cleargate-planning/.cleargate/scripts/init_gate_config.sh +0 -38
- package/dist/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +0 -240
- package/dist/templates/cleargate-planning/.cleargate/scripts/launch_wave.mjs +0 -341
- package/dist/templates/cleargate-planning/.cleargate/scripts/lib/report-filename.mjs +0 -54
- package/dist/templates/cleargate-planning/.cleargate/scripts/pre_gate_common.sh +0 -206
- package/dist/templates/cleargate-planning/.cleargate/scripts/pre_gate_runner.sh +0 -371
- package/dist/templates/cleargate-planning/.cleargate/scripts/prefill_report.mjs +0 -280
- package/dist/templates/cleargate-planning/.cleargate/scripts/prep_doc_refresh.mjs +0 -378
- package/dist/templates/cleargate-planning/.cleargate/scripts/prep_qa_context.mjs +0 -888
- package/dist/templates/cleargate-planning/.cleargate/scripts/run_script.sh +0 -209
- package/dist/templates/cleargate-planning/.cleargate/scripts/sprint_trends.mjs +0 -71
- package/dist/templates/cleargate-planning/.cleargate/scripts/state.schema.json +0 -127
- package/dist/templates/cleargate-planning/.cleargate/scripts/suggest_improvements.mjs +0 -717
- package/dist/templates/cleargate-planning/.cleargate/scripts/surface-whitelist.txt +0 -27
- package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_assert_story_files.sh +0 -261
- package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_file_surface.sh +0 -210
- package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_flashcard_gate.sh +0 -190
- package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_prep_qa_context.sh +0 -482
- package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_test_ratchet.sh +0 -327
- package/dist/templates/cleargate-planning/.cleargate/scripts/test_ratchet.mjs +0 -261
- package/dist/templates/cleargate-planning/.cleargate/scripts/update_state.mjs +0 -246
- package/dist/templates/cleargate-planning/.cleargate/scripts/validate_bounce_readiness.mjs +0 -111
- package/dist/templates/cleargate-planning/.cleargate/scripts/validate_state.mjs +0 -184
- package/dist/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +0 -172
- package/dist/templates/cleargate-planning/.cleargate/templates/Bug.md +0 -126
- package/dist/templates/cleargate-planning/.cleargate/templates/CR.md +0 -130
- package/dist/templates/cleargate-planning/.cleargate/templates/Sprint Plan Template.md +0 -137
- package/dist/templates/cleargate-planning/.cleargate/templates/epic.md +0 -166
- package/dist/templates/cleargate-planning/.cleargate/templates/hotfix.md +0 -111
- package/dist/templates/cleargate-planning/.cleargate/templates/initiative.md +0 -122
- package/dist/templates/cleargate-planning/.cleargate/templates/sprint_context.md +0 -50
- package/dist/templates/cleargate-planning/.cleargate/templates/sprint_report.md +0 -224
- package/dist/templates/cleargate-planning/.cleargate/templates/story.md +0 -213
- package/dist/templates/cleargate-planning/CLAUDE.md +0 -66
- package/dist/templates/cleargate-planning/MANIFEST.json +0 -503
- package/dist/templates/synthesis/active-sprint.md +0 -30
- package/dist/templates/synthesis/open-gates.md +0 -38
- package/dist/templates/synthesis/product-state.md +0 -31
- package/dist/templates/synthesis/roadmap.md +0 -63
- 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
|