@shahboura/harness 3.0.4

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 (62) hide show
  1. package/.opencode/agents/developer.md +60 -0
  2. package/.opencode/agents/planner.md +51 -0
  3. package/.opencode/agents/reviewer.md +53 -0
  4. package/.opencode/commands/add-repo.md +26 -0
  5. package/.opencode/commands/dev-workflow.md +40 -0
  6. package/.opencode/commands/init-workspace.md +22 -0
  7. package/.opencode/commands/migrate-workspace.md +28 -0
  8. package/.opencode/commands/repo-map-refresh.md +23 -0
  9. package/.opencode/commands/story-workflow.md +24 -0
  10. package/.opencode/commands/workflow-status.md +23 -0
  11. package/.opencode/commands/workspace-config.md +27 -0
  12. package/.opencode/package.json +9 -0
  13. package/.opencode/plugins/harness-guards.ts +290 -0
  14. package/.opencode/skills/add-repo/SKILL.md +96 -0
  15. package/.opencode/skills/dev-workflow/SKILL.md +105 -0
  16. package/.opencode/skills/dev-workflow/shared/diagram-styling.md +65 -0
  17. package/.opencode/skills/dev-workflow/shared/engineering.md +14 -0
  18. package/.opencode/skills/dev-workflow/shared/status-block.md +29 -0
  19. package/.opencode/skills/dev-workflow/steps/analyze-comments.md +32 -0
  20. package/.opencode/skills/dev-workflow/steps/apply-fixes.md +24 -0
  21. package/.opencode/skills/dev-workflow/steps/comment-analysis.md +11 -0
  22. package/.opencode/skills/dev-workflow/steps/create-pr.md +39 -0
  23. package/.opencode/skills/dev-workflow/steps/develop-task.md +54 -0
  24. package/.opencode/skills/dev-workflow/steps/develop.md +60 -0
  25. package/.opencode/skills/dev-workflow/steps/fetch.md +34 -0
  26. package/.opencode/skills/dev-workflow/steps/fixup-task.md +12 -0
  27. package/.opencode/skills/dev-workflow/steps/gate.md +53 -0
  28. package/.opencode/skills/dev-workflow/steps/harden-task.md +12 -0
  29. package/.opencode/skills/dev-workflow/steps/harden.md +30 -0
  30. package/.opencode/skills/dev-workflow/steps/intake.md +52 -0
  31. package/.opencode/skills/dev-workflow/steps/metrics.md +21 -0
  32. package/.opencode/skills/dev-workflow/steps/plan-task.md +108 -0
  33. package/.opencode/skills/dev-workflow/steps/plan.md +80 -0
  34. package/.opencode/skills/dev-workflow/steps/pre-pr-fixes.md +16 -0
  35. package/.opencode/skills/dev-workflow/steps/pre-pr-review.md +14 -0
  36. package/.opencode/skills/dev-workflow/steps/pre-pr.md +14 -0
  37. package/.opencode/skills/dev-workflow/steps/preflight.md +32 -0
  38. package/.opencode/skills/dev-workflow/steps/quick-recheck.md +14 -0
  39. package/.opencode/skills/dev-workflow/steps/reconcile.md +27 -0
  40. package/.opencode/skills/dev-workflow/steps/review-task.md +32 -0
  41. package/.opencode/skills/dev-workflow/steps/security.md +18 -0
  42. package/.opencode/skills/dev-workflow/steps/triage-request.md +15 -0
  43. package/.opencode/skills/init-workspace/SKILL.md +155 -0
  44. package/.opencode/skills/migrate-workspace/SKILL.md +122 -0
  45. package/.opencode/skills/repo-map-refresh/SKILL.md +43 -0
  46. package/.opencode/skills/story-workflow/SKILL.md +78 -0
  47. package/.opencode/skills/story-workflow/commands/analyze.md +40 -0
  48. package/.opencode/skills/story-workflow/commands/groom.md +58 -0
  49. package/.opencode/skills/story-workflow/commands/improve.md +47 -0
  50. package/.opencode/skills/story-workflow/commands/refine.md +44 -0
  51. package/.opencode/skills/story-workflow/shared/context.md +22 -0
  52. package/.opencode/skills/story-workflow/shared/provider-io.md +73 -0
  53. package/.opencode/skills/story-workflow/templates/readiness-report.md +57 -0
  54. package/.opencode/skills/story-workflow/templates/story-template.md +51 -0
  55. package/.opencode/skills/story-workflow/templates/technical-notes.md +48 -0
  56. package/.opencode/skills/workflow-status/SKILL.md +30 -0
  57. package/.opencode/skills/workspace-config/SKILL.md +97 -0
  58. package/.opencode/tsconfig.json +11 -0
  59. package/CHANGELOG.md +396 -0
  60. package/LICENSE +21 -0
  61. package/README.md +351 -0
  62. package/package.json +32 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,396 @@
1
+ # Changelog
2
+
3
+ All notable changes to `ai-sdlc-harness` are documented here.
4
+
5
+ ---
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [3.0.4] — 2026-07-12
10
+
11
+ > **The repo map now reaches the planner it was built for.** Generation, staleness tracking, and stamping were already solid; this release closes the gap on the consumption side, plus a false-fresh hole in the stamp itself.
12
+
13
+ ### Release highlights
14
+
15
+ | Theme | What changed |
16
+ |---|---|
17
+ | **Plans are now explicitly grounded in the repo map** | The plan-mode planning instruction points directly at `.claude/context/repo-map/<repo-name>/` and prescribes the tiered reading order (index first, then only the areas the story touches) — previously whether a plan consulted the map came down to model initiative, not the instruction. The intake step's ask carries the same map location. |
18
+ | **`repo-map-stamp` refuses to certify an empty map** | Stamping after a failed or empty map generation used to mark a nonexistent map "fresh" for the next 50 commits (or your configured staleness window), with nothing left to notice. The stamp now requires real map content first. |
19
+
20
+ ### Verification on tag tip
21
+
22
+ - `python -m harness.schema` — declared data valid
23
+ - `python tools/budget_check.py` — line budget green
24
+ - `python -m unittest discover -s tests` — 606 tests green
25
+
26
+ ## [3.0.3] — 2026-07-12
27
+
28
+ > **Native Windows support — the CI lane is now enforcing.** The harness was built and tested on macOS/Linux; the Windows CI lane was informational (`continue-on-error`) and admitted to being written blind. First real triage took the suite from **290 failures to 0**, and the lane now gates PRs like the other two — followed by an adversarial-review pass that closed four more gaps before shipping.
29
+
30
+ ### Release highlights
31
+
32
+ | Theme | What changed |
33
+ |---|---|
34
+ | **Windows CI lane now gates PRs** | Was `continue-on-error` (informational only, written blind); first real triage took the suite from **290 failures to 0** on Windows, and the lane now blocks merges like the Linux and macOS lanes. |
35
+ | **Hooks, launcher, and provider CLIs resolve the Windows layout** | `hooks/hooks.json` / `bin/harness` probe `.venv/Scripts/python.exe` alongside the POSIX layout and fall back `python3` → `python`; provider CLI resolution goes through `shutil.which` (walks PATHEXT) instead of bare `CreateProcess`, so `az.cmd` and similar shims are found; `/init-workspace`, `harness.schema`'s remediation text, and the README instructions cover both venv layouts. |
36
+ | **Guard layer is Windows-path aware** | All new behavior gated on `os.name == "nt"`, POSIX behavior untouched: scratch root is `%TEMP%`; a literal `/tmp/…` in a Bash command is recognized as Git Bash's temp mount; drive-letter absolute targets (`C:/x`, `C:\x`) are visible to write-confinement and the destructive-verb sweep; rootless msys targets (`/etc/x`) no longer slip past confinement as "relative"; backslash-spelled authority paths block like forward-slash ones. |
37
+ | **`merge-task --autosquash` works on Windows** | The blind-written `cmd /c exit 0` no-op editor was itself the breakage — git mangles multi-word editors through its sh layer. Plain `GIT_SEQUENCE_EDITOR=true` works everywhere because Git for Windows bundles its own sh. |
38
+ | **UTF-8 output is a contract, not a locale accident** | The CLI and guard hooks emit UTF-8 on every OS (`cp1252` mojibaked every em-dash in a detail string); every subprocess the harness runs (`git`, test suites, forge CLIs, scanners) is decoded as UTF-8 with replacement, and all production file IO carries an explicit `encoding="utf-8"`. |
39
+ | **`init-verify` measures not-found instead of assuming it** | `cmd /c missing-cmd` exits **1** on Windows, not the assumed 9009 — indistinguishable from a red-but-runnable suite by code alone, so a not-found-shaped exit now also requires the command's first token to resolve to nothing. |
40
+ | **Test suite made OS-portable** | Fake forge CLIs (`gh`/`glab`/`az`) are real PE launchers on Windows; `tests/support.py` centralizes the platform seams (read-only-safe `rmtree` for git fixtures, wrapper resolution, scratch-root constants); a hardcoded `:` PATH separator that let the real host `glab` answer for a stub is fixed; a new Windows-only guard-shape test class covers the `nt`-conditional forms. |
41
+ | **Adversarial-review pass closed 4 gaps before shipping** | A lone-surrogate character in a payload path could crash a fail-open guard's block message and flip BLOCK to ALLOW (`backslashreplace` now explicit everywhere); the scratch allowance sanctioned `rm -rf /tmp` itself when the workspace lived under the scratch root (ancestor targets now refuse); Git Bash's `/c/…` and case-variant `/TMP/…` spellings now translate like `/tmp`, and quoted `\\server\share` UNC targets are now swept; the not-found gate resolved the command's first token against the harness process cwd instead of the repo the command ran in (misclassifying legitimately-red repo-local runners), and the CLI now refuses interpreters below Python 3.10. |
42
+ | **CI triage caught 2 more real bugs the enforcing matrix exposed for the first time** | `tests/support.py`'s read-only-safe `rmtree` crashed with `TypeError` on macOS/Ubuntu: Python's fd-based rmtree walker can hand its retry callback `os.open` (needs a `flags` arg) instead of `os.unlink`/`os.rmdir`, not just on Windows's classic path — the callback now decides unlink vs. rmdir from the path's own type instead of trusting the callback function's arity. Separately, `harness/ndjson.now_iso()`'s microsecond-precision timestamp could still tie between two calls microseconds apart on a courser OS clock grain (only ever observed on a Windows Python 3.10 CI image), silently failing the reviewer-verdict ledger's strict-postdate ordering rule; timestamps are now clamped to strictly increasing within the process instead of trusting the OS clock's actual resolution. |
43
+
44
+ ### Known residuals (documented, not fixed)
45
+
46
+ - Multi-line arguments to a `.cmd`-implemented CLI (e.g. some `az` operations) are lossy at the `cmd.exe` parser layer; `gh`/`glab` ship as `.exe` and are unaffected.
47
+ - Pre-venv on a Windows host whose only `python`/`python3` is the Microsoft Store alias, hooks degrade open until `/init-workspace` creates the venv — consistent with the existing pre-setup posture.
48
+ - msys mounts other than `/tmp` and `/<drive>` (e.g. `/etc`, `/usr`) stay untranslated in the guards — they live inside the Git installation, so fail-closed is the intended answer.
49
+
50
+ ### Verification on tag tip
51
+
52
+ - `python -m harness.schema` — declared data valid
53
+ - `python tools/budget_check.py` — 0 errors (3 pre-existing soft-cap warnings)
54
+ - `python -m unittest discover -s tests` — 603 tests, OK on Windows 11 (skipped=2: two POSIX-only permission/symlink assertions) and on Linux (containerized clone of the same tree)
55
+ - `/verify`: 5/5 PASS, fresh stamp written
56
+
57
+ ## [3.0.2] — 2026-07-11
58
+
59
+ > **Guard scope, not guard bypass.** The one guard rule that ignored workspace boundaries now respects them — raw git stays blocked exactly where you've actually turned the harness on, nowhere else.
60
+
61
+ ### Release highlights
62
+
63
+ | Theme | What changed |
64
+ |---|---|
65
+ | **Raw-git block scoped to harness workspaces** | The raw-git block (`commit`/`merge`/`rebase`/`cherry-pick`/`revert`/`am`/`pull`/`push` redirected to the owned `harness` verbs) used to apply in **any** session and repo the moment the plugin was enabled, even ones with nothing to do with the harness — a real problem for anyone enabling the plugin at user scope rather than per-project. It now only applies inside a workspace that has actually completed `/init-workspace`; a project you've never initialized sees ordinary git, no need to disable the plugin for it. Two residuals are documented rather than closed here: a session opened directly inside a repo registered to a *sibling* workspace (rather than the workspace itself) isn't recognized yet; and the bootstrap marker this check reads isn't tamper-protected the way `state.yaml` is, so a direct edit to it can silently turn the block back off. Both were flagged by an adversarial-review pass before this shipped and accepted as known limitations rather than expanding the fix's scope. |
66
+
67
+ ### Verification on tag tip
68
+
69
+ - `python -m harness.schema` — declared data valid
70
+ - `python tools/budget_check.py` — line budget green (0 errors, 3 pre-existing soft-cap warnings, unrelated files)
71
+ - `python -m unittest discover -s tests` — 594 tests, OK (skipped=6)
72
+ - `/verify`: 5/5 PASS, fresh stamp written
73
+
74
+ ## [3.0.1] — 2026-07-10
75
+
76
+ > **Linux CI fix.** The v3.0 rewrite's first CI run failed on every Linux job — a real confinement gap in the guard layer, not a flaky test. This patch closes it.
77
+
78
+ ### Release highlights
79
+
80
+ | Theme | What changed |
81
+ |---|---|
82
+ | **Guard confinement under `/tmp`** | The guard layer's "`/tmp` is scratch space" allowance could swallow a workspace or registered repo that itself lives under `/tmp` — the default tempdir root on Linux, and a plausible layout for CI/container/sandbox workspaces — silently defeating the developer's repo/worktree confinement, the reviewer's read-only guarantee, and the planner's repo-source immunity. Scratch is now recognized only when a write target falls outside both the confined workspace and every registered repo, regardless of where either sits on disk. An adversarial-review pass on the fix itself, before it shipped, also caught and closed a related regression: a multi-repo workspace (two or more repos registered under one shared parent directory, the `/add-repo` layout) could wrongly block writes into every registered repo except whichever was listed first in `repos.yaml`. |
83
+
84
+ ### Verification on tag tip
85
+
86
+ - `python -m harness.schema` — declared data valid
87
+ - `python tools/budget_check.py` — line budget green (0 errors, 3 pre-existing soft-cap warnings, unrelated files)
88
+ - `python -m unittest discover -s tests` — 586 tests green
89
+
90
+ ## [3.0.0] — 2026-07-08
91
+
92
+ > **The ground-up rewrite.** Almost all of the v2.x line's accumulated complexity compensated for one root cause: orchestration logic lived in markdown prose an LLM had to faithfully execute every run, with hooks bolted on to catch the cases where it didn't. v3.0 replaces that with a **declared-data pipeline enforced by a Python core** — every mechanical rule moves into code that just runs, and the model is reserved for judgment. This is a breaking change; `/migrate-workspace` adopts an existing v2.x workspace (config carries over — run history stays archived in place).
93
+
94
+ ### Release highlights
95
+
96
+ | Theme | What changed |
97
+ |---|---|
98
+ | **Declared-data pipeline** | The pipeline is now data, not prose. `pipeline/manifest.yaml` (steps, modes, gates, escalations), `pipeline/task-fsm.yaml` (legal task-status transitions), and `pipeline/surfaces.yaml` (subagent shapes, write surfaces, out-of-run spawns) are the single source of truth — read by **both** the orchestrator and the enforcement layer, so there is no second hardcoded copy to drift. Replaces the v2.x prose phase files the orchestrator re-derived every run. |
99
+ | **Python core (the engine)** | New `harness/` package behind every owned verb: `cli.py` (the verb surface), `workflow.py` (step implementations), `state.py` · `transitions.py` · `gates.py` · `chain.py` (sealed state + FSM + gate parser), `gitops.py` (owned git machinery). A launcher (`bin/harness`) resolves the plugin venv. Requires Python 3.10+ and PyYAML. |
100
+ | **Owned entry points; raw git blocked** | Git now runs through owned verbs (`harness commit` / `merge-task` / `sync-branch` / `push` …) instead of raw `git` calls reverse-engineered after the fact by `shlex`-parsing hooks. The raw mutating verbs are blocked outright by a standing, workspace-scoped invocation rule. |
101
+ | **Tamper-evident workflow state** | `tracker.md` honor-system updates are gone. Workflow state is an HMAC-chain-sealed `state.yaml` plus append-only ndjson evidence ledgers — tamper-evident, with out-of-band edits failing closed (`exit 3`). |
102
+ | **Proof-anchored TDD** | The TDD mechanism is anchored on a proven-red gate: a task's tests must be demonstrated failing before implementation is allowed to proceed, captured as ledger evidence rather than asserted in prose. |
103
+ | **Code-modular providers** | Work-item / git providers are Python modules under `harness/providers/` (ADO, Jira, GitLab, GitHub, Zoho, local-markdown; CLI **and** MCP transports). MCP-transport providers declare a tool mapping and pipe the raw result to `harness fetch --from-raw` for the same shared normalize + bootstrap path. |
104
+ | **Story-quality workflow (`/story-workflow`)** | The PO-facing story tooling comes across to v3.0 — `/story-workflow <command> <work-item-id>` with `analyze` (readiness report with flags), `refine` (section-by-section restructure), `improve` (adaptive single-pass: assess → gap-fill → draft), and `groom` (codebase-aware per-repo technical notes). Distinct from `/dev-workflow`: it shapes the story and never starts a run or touches run state. Provider I/O rides the owned `harness provider` verbs (`work_item.fetch` / `work_item.add_comment`) — CLI/file transports post directly, MCP transports name the tool to invoke with `provider-normalize` giving a run-free read — replacing the v2.x per-provider markdown adapters. Domain context comes from `.claude/context/repos.yaml` + the auto-generated `repo-map/` (the retired `repos-metadata.md` / `conventions.md` are gone); `groom` refreshes with `git fetch` and reports how far behind the checkout is, but never pulls (raw `git pull` / `merge` / `reset` are guard-blocked workspace-wide). Registered USER-ENTRY and human-only in `pipeline/surfaces.yaml`, so the invocation guard blocks it from subagent context like every other entry point. |
105
+ | **One guard entry point** | All hook enforcement + capture consolidates into a single dispatcher (`hooks/guards.py`, registered in `hooks/hooks.json`), with an explicit per-guard fail-open / fail-closed policy. `shape_of` maps a spawned agent identifier back to the pipeline's bare role vocabulary. |
106
+ | **Agents follow the ai-sdlc-harness convention** | Three agent shapes — `ai-sdlc-planner`, `ai-sdlc-developer`, `ai-sdlc-reviewer` — spawned **only** by the dev-workflow orchestrator with a `harness-mode` header (the spawn guard enforces the manifest's spawn-set). Test review and PR-comment analysis are reviewer modes; there is no separate tester agent. |
107
+ | **v2.x workspace adoption** | `/migrate-workspace` adopts an existing v2.x workspace: it fingerprints the legacy setup, inventories leftover runs (flagging in-flight ones), and proposes v3.0 config sections — provider (with v2.x spellings like `glab-cli` mapped over), repos, per-repo test commands, stories directory — which you confirm and apply through the same verification gate as a fresh `/init-workspace`. Legacy config files are archived to `.claude/context/legacy-2.1/` with a migration report. Run history is never converted (v3.0 state is sealed evidence v2.x never produced); old `ai/` run dirs stay in place as readable archives. Existing `local-markdown` stories work unmodified — v2.x `> Status:` blockquotes are read correctly and upgrade to the v3.0 form on first write-back. Forks can ship their own adoption logic by swapping one module and one skill file. |
108
+ | **Composability, proven** | Adding a scratch mode and a scratch step must validate and walk the pipeline with **zero Python changes** — the composability probes in the suite assert exactly that, so the declared-data boundary is enforced, not aspirational. |
109
+ | **Test suite + CI** | 582 stdlib-`unittest` tests cover the state engine, gate grammar, guard behavior (subprocess against real payloads), provider contracts, git machinery against real temp repos, breadth walks of both pipeline modes, composability probes, and declared-data schema / invocation / line-budget meta-checks. A full end-to-end validation walk — cold workspace → `/init-workspace` → four `/dev-workflow` runs → real PRs → PR-comment round-trips → teardown — exercised the live pipeline and hardened a few seams it surfaced (honest `init-verify` reporting, transactional/idempotent `preflight`, a live deferral-count gauge, grep-able-only contract fragments). A GitHub Actions workflow (`.github/workflows/ci.yml`) runs them on every push. |
110
+
111
+ ### Upgrade notes
112
+
113
+ - **Breaking — run history does not migrate.** The v2.x and v3.0 state models are disjoint: `/migrate-workspace` carries your *config* into v3.0, but finish (or abandon) any in-flight v2.x stories on the v2.x line first — old runs stay behind as readable archives. On a workspace with no v2.x past, use `/init-workspace` instead.
114
+ - **New runtime dependency:** Python 3.10+ and PyYAML. `/init-workspace` bootstraps the plugin venv and verifies the dependency up front.
115
+ - **Layout, command surface, and hooks are all new.** The v2.x prose phase files, `scripts/` hook helpers, and `tracker.md` are gone; workflow state lives in `ai/<run>/state.yaml` + ndjson ledgers inside your working directory (never inside the plugin repo).
116
+ - **Agent identifiers changed** to `ai-sdlc-planner` / `ai-sdlc-developer` / `ai-sdlc-reviewer`; they are harness-internal and spawned only by the orchestrator — never invoke them directly.
117
+
118
+ ---
119
+
120
+ ## [2.1.0] — 2026-05-21
121
+
122
+ > **The Quick-Mode + observability release.** A fast-path for trivial changes, a workspace-wide metrics report, a manifest schema for every command, enforced markdown-size budgets, and the cost / token-count plumbing that makes per-phase economics measurable. Plus the doc surgery that brought the largest context / command files back under their CC-04.8 line caps.
123
+
124
+ ### Release highlights
125
+
126
+ | Theme | What changed |
127
+ |---|---|
128
+ | **Quick Mode (`/dev-workflow quick`)** | New fast-path phase for trivial changes — Developer + Reviewer only, no Planner, no Tester. CC-05.8 declares the contract; `scripts/quick-mode-classify.py` is the eligibility heuristic; `QPhaseGuard` enforces the invariants (no Planner / no Tester invocation, single commit). Tracker carries `Mode: quick` + `Quick-Mode: true` so P9 metrics segments quick vs. full runs. |
129
+ | **Aggregate report (`/dev-workflow report`)** | New utility command rolls up `ai/_metrics-log.csv` across stories with `--since`, `--format md\|json`, `--story` filters. Markdown output is a Mermaid scorecard; JSON is plain rows for downstream tooling. |
130
+ | **Manifest schema for commands** | Every dev-workflow command file ships a sibling `<command>.manifest.yaml` declaring prerequisites, produced artifacts, exit criteria, gate emissions. A `manifest-schema.md` doc + parity check live alongside. Consumers read manifests instead of grepping command prose. |
131
+ | **Markdown size budgets (CC-04.8)** | New `cc-check-md-budget` Convention-Check enforces per-file size caps from `agents/shared/markdown-budgets.md` (command files ≤ 400 lines, context files ≤ 200). Started WARN, flipped to BLOCK in this release. The top-4 oversized command files were surgically reduced — `orchestrator-rules.md` 420 → 164, `plan-generator/SKILL.md` 830 → 337, plus surgery on `develop.md`, `plan.md`, `requirements.md`, `create-pr.md`. |
132
+ | **Cost + token observability** | New Stop hook `scripts/metrics-token-collector.sh` (+ `_metrics_token_collector.py` body) aggregates per-turn token counts into the tracker. `_metrics-log.csv` schema bumped to v1.1.0 — `metrics_collector.py` performs the upgrade in-place on the next append (no separate migration command). New `cost-config.md` template carries per-model rate cards; `init-workspace` Step 6d lays it down at workspace bootstrap. P9 `metrics-collector` reads these fields when assembling per-workflow + workspace-level reports. **Hardening pass before tag**: `metrics_collector.py` now parses the canonical v2.1 tracker layout (the pre-tag draft was still reading the v2.0 layout for a couple of fields); it's guarded against premature-trigger invocations (the Stop hook would previously fire before the tracker existed and append a half-row); `metrics-report.md` rendering is humanised with per-task duration / token breakdowns and a per-phase summary that explicitly caveats short phases where Stop-hook attribution gaps produce token totals lower than the per-phase delta; and the Stop hook ships with the executable bit set. |
133
+ | **Schema amendments (v1.1)** | Approved v2.1 amendment batch applied to `agents/shared/tracker-field-schema.md` and `agents/shared/status-schema.md`: `Mode:` header, `Workflow-Dir:` field, `Test hardening completed` / `Security review completed` / `Ad-hoc requests started/completed` stamps, `Quick-Mode:` flag. |
134
+ | **Test Outline relocation** | `test-outline.md` is now the sole home for the Test Outline — every consumer (Planner, Tester, `develop.md`, `review-response.md`, `handle-request.md`, the Phase 6 per-repo copy step) reads / writes the separable `ai/<YYYY-MM-DD>-<id>/test-outline.md` artifact instead of the legacy `plan.md`-embedded section, restoring CC-04.5 DRY and CC-05.2 separable-artifact compliance. `plan-generator/SKILL.md` Step 5 carries a NON-NEGOTIABLE Sync rule that regenerates `test-outline.md` in lock-step with every tracker change (GATE #1 revisions, `pr-response-tasks`, `ad-hoc-tasks`). Paired with the authority-spec wording amendment journaled in [execution-log.md](execution-log.md#2026-05-22--authority-spec-amendment-test-outline-relocation). |
135
+ | **Subagent_type mapping** | `skills/dev-workflow/context/orchestrator-rules.md` now spells out the fully-qualified `subagent_type` for each `@ai-sdlc-X` mention (the four agent roles plus the reviewer's four modes). Eliminates the model-side pattern-matching ambiguity that occasionally produced `Agent type 'ai-sdlc-harness:planner' not found` retries. |
136
+ | **Planner TDD-skip heuristics** | `agents/planner/index.md` carries a new section on when to recommend Quick Mode at story intake. Heuristics live in `scripts/quick-mode-classify.py` so they're testable and tunable in one place. |
137
+ | **Integration tests** | Two new end-to-end integration tests: `tests/integration/quick-mode-round-trip/test.sh` exercises the full Quick Mode flow (Developer + Reviewer, no Planner / no Tester, single commit) against a real fixture; `tests/integration/p9-metrics-collector/test.sh` exercises the P9 metrics-collection contract end-to-end (337 lines, runs `metrics_collector.py` against the canonical v2.1 tracker layout and asserts per-workflow + workspace-level outputs). |
138
+
139
+ ### Upgrade notes
140
+
141
+ - No breaking changes vs. v2.0. The `Mode:` and `Quick-Mode:` tracker fields are optional — pre-v2.1 trackers continue to read with `Mode` treated as `full`.
142
+ - The `_metrics-log.csv` schema bump to v1.1.0 is applied automatically by `scripts/metrics_collector.py` on the next append — existing rows are preserved and the five new columns (`tokens_input`, `tokens_output`, `tokens_cache_read`, `tokens_cache_write`, `mode`) are back-filled with `null`.
143
+ - `cc-check-md-budget` is now BLOCK-mode; if you maintain a fork with oversized markdown files, run `python3 scripts/markdown-size-report.py` to see the surface and trim under the caps.
144
+
145
+ ---
146
+
147
+ ## [2.0.0] — 2026-05-18
148
+
149
+ > **The workflow-state release.** Per-workflow artefact directories, first-class
150
+ > ad-hoc requests, a re-ordered pre-flight, schema clarifications, and the
151
+ > parser + hook hardening that keeps every guard load-bearing across shells,
152
+ > paths, and edge cases.
153
+
154
+ ### Release highlights
155
+
156
+ | Theme | What changed |
157
+ |---|---|
158
+ | **Per-workflow artefact layout** | New `ai/<YYYY-MM-DD>-<work-item-id>/` directory replaces the legacy `ai/plans/` + `ai/tasks/` split. One directory per story keeps plan, tracker, snapshots, and metrics co-located and easy to archive. |
159
+ | **Ad-hoc requests are first-class** | Mid-workflow change requests at GATE #2, GATE #3, or via `/dev-workflow request` are triaged against the approved plan, gated by GATE #5, and land in a dedicated `## Ad-hoc Tasks (Batch <N>)` section — never silently merged. Out-of-scope items surface back to the human with explicit options. |
160
+ | **Pre-flight runs after GATE #1** | Feature branches are now created only in the repos the plan named, eliminating the prior orphan branches in unaffected repos. The plan commit moves into pre-flight so it lands on the feature branch. |
161
+ | **Workspace-mirror agent reads** | Subagents read shared markdown from `<workspace>/.claude/context/agents-shared/` via the new `scripts/refresh-shared.sh`. Phase 2 no longer reports shared files as `not found`. |
162
+ | **Post-Phase-5 re-hardening** | Ad-hoc batches and Phase 7 amendments re-trigger `T-TEST-<Repo>` so the 90 % coverage gate runs against the union of original + new code. |
163
+ | **Orchestrator-owned worktrees** | The orchestrator creates and reconciles the worktree before any sub-agent launches; agents no longer own worktree setup. UID8-suffixed paths survive crash-resume; fallback `git reset --soft` handles lock failures. |
164
+ | **Schema rename** | `Development completed` → `Initial development completed` (the first Phase 3 close). Phase 7 re-entries are tracked separately by `PR review response completed`; ad-hoc batches by `Ad-hoc requests completed`. |
165
+ | **Parser + hook hardening** | Structural `git commit` parser (`_git_argparse.py`), unresolvable-`-C` guard on `squash-merge-verify`, chained-commit HEAD-lookup fallthrough, shared hook library (`_hook-lib.sh`), and a `bash-write-guard` that closes the shell-redirect loophole. |
166
+
167
+ ### Upgrade notes
168
+
169
+ - Run `scripts/refresh-shared.sh` (or `init-workspace --refresh-shared`) once after upgrading to mirror the latest `agents/shared/*.md` into your workspace.
170
+ - Trackers carrying the legacy `Development completed` field continue to read; the new write path emits `Initial development completed`.
171
+ - Branch-naming snippets across docs now use the literal `feature/` segment — the never-wired `<type>` placeholder has been removed.
172
+ - `format_command` in `language-discovery.md` is now a self-contained shell command — `{FILE}` and `{PROJECT_ROOT}` placeholders are stripped on schema upgrade.
173
+
174
+ ---
175
+
176
+ ### Fixes (agent-runtime path resolution + parser hardening)
177
+
178
+ - **Subagent shared-file reads now resolve via a workspace mirror.** Subagents (planner / developer / tester / reviewer) reference shared markdown via paths like `agents/shared/engineering-principles.md` — but `CLAUDE_PLUGIN_ROOT` is only exported to hook processes (verified by an env-probe inside a general-purpose subagent and per Claude Code's own [hooks documentation](https://code.claude.com/docs/en/hooks.md)), **not** to agent runtimes. The path resolved against the user's project workspace where the file didn't exist, and the planner's `Startup reads:` field surfaced `engineering-principles.md and status-schema.md reported as "not found"` on every Phase 2 invocation (non-blocking but noisy). Resolution: new script [`scripts/refresh-shared.sh`](scripts/refresh-shared.sh) discovers the latest installed plugin version under `~/.claude/plugins/cache/ai-sdlc-harness/ai-sdlc-harness/<version>/` and mirrors every `agents/shared/*.md` into `<workspace>/.claude/context/agents-shared/`. New Step 6c in [`init-workspace/SKILL.md`](skills/init-workspace/SKILL.md) invokes it; a new `--refresh-shared` flag re-runs only this step for existing workspaces after a plugin upgrade. All 4 agent index files (planner, developer, tester, reviewer — 11 references) updated to read from the workspace-mirror path. [`tests/skills/status-schema.test.sh`](tests/skills/status-schema.test.sh) updated to accept both the new `agents-shared/` path and the legacy `agents/shared/` path (back-compat for in-flight changes).
179
+ - **`squash-merge-verify` no longer false-positives on unresolvable `-C "$VAR"`.** When the orchestrator emits a chained command like `REPO_PATH="…" && git -C "$REPO_PATH" merge --squash X && git -C "$REPO_PATH" commit -m "…"`, the variable is a shell-local assignment — not exported, never reaches the hook process. `shlex.split` keeps `$REPO_PATH` as a literal token, every git subprocess (conflict check, chained-commit HEAD lookup, staged-count, the FF merge-base check) returns `FileNotFoundError`, and the hook previously fell through to the "no staged changes" warning even though the merge + commit succeeded in-shell. Added an unresolvable-cwd guard at [`_squash_merge_verify.py`](scripts/_squash_merge_verify.py): if `git_c` is set but the path isn't a directory, exit 0 silently — better than a false-positive. Regression test `test_unexpanded_shell_var_in_dash_C_does_not_false_warn` covers the unresolved-variable pattern; all 12 existing squash-merge-verify tests still pass.
180
+
181
+ ### Features
182
+
183
+ - **Pre-flight moved from before Phase 1 to between Phase 2 and Phase 3.** Previously, preflight was the first step of the pipeline and had to create feature branches in **every** repo listed in `repos-paths.md` as a "safe default" because the Planner had not yet identified the affected repos — every single run produced orphan branches in unaffected repos (no cleanup step existed anywhere in the workflow to reclaim them). Now preflight runs immediately after GATE #1 clears: it reads the plan's `## Repo Status` section and creates branches in exactly the repos the plan named. The plan commit moved into preflight too (single-repo workspace-is-git-repo case only) so it lands on the just-created feature branch instead of on the default branch. Phase 1 and Phase 2 no longer require a feature branch — they produce only workspace files. Touches `skills/dev-workflow/SKILL.md` (pipeline order, command-table phase column), `commands/requirements.md` (drops the feature-branch prerequisite), `commands/plan.md` (defers the plan commit to preflight, repoints `Next Phase`), `commands/preflight.md` (full rewrite — prerequisites, Repo-Status-driven branch creation, plan commit step, explicit forbiddance of the prior "all known repos" fallback), `commands/develop.md` (prerequisites update), `CLAUDE.md` (Workflow Phases section names pre-flight after GATE #1), and the `README.md` sequence diagram. New doc-grep test `tests/skills/preflight-ordering.test.sh` (18 assertions) locks the cross-file contract — pipeline order, prerequisite removal, commit-step location, fallback-forbidden text, README diagram wording.
184
+ - **Post-Phase-5 ad-hoc batches and Phase 7 amendments now re-trigger `T-TEST-<RepoName>` hardening.** Previously, ad-hoc tasks landing at GATE #3 or Phase 7 amendments reused the existing `T-TEST-<RepoName>` row (already `✅ Done` from the original Phase 5 run) without re-running the 90% coverage gate — new production code shipped in the PR with no coverage enforcement against the union of original + new code. Now `commands/review-response.md` Step 8b and `commands/handle-request.md` Step 7b read the `T-TEST-<RepoName>` row after the new batch lands; if it's `✅ Done` and the batch added at least one task to that repo, the orchestrator drives the legal `✅ Done → 🔧 In Progress` rework transition and re-invokes `commands/test.md` Step 1 (auto-harden Tester) + Step 2 (Reviewer). Pre-Phase-5 batches (`source: gate-2` and pre-Phase-5 `mid-phase`) are a no-op because the upcoming Phase 5 run naturally covers the new code. Multiple repos re-trigger in parallel per the standard Phase 5 parallel-hardening pattern. Workflow Metrics `Test hardening started` / `Test hardening completed` are NOT re-stamped — they record the first Phase 5 run; the re-trigger is recorded by the per-row `Completed` Task Metric on `T-TEST-<RepoName>` and the `PR review response completed` / `Ad-hoc requests completed` metrics. New doc-grep assertions in `tests/skills/handle-request.test.sh` and `tests/skills/review-response.test.sh` lock the cross-file contract.
185
+
186
+ ### Fixes (second-pass review)
187
+
188
+ - **Phase 7 Step 9 workspace-IS-git-repo path now also stages `ai/plans/`.** An earlier fix closed the workspace-NOT-git-repo case for plan re-sync after a Phase 7 `[a] Expand scope` amendment, but the single-repo workspace-is-code-repo branch in [review-response.md](skills/dev-workflow/commands/review-response.md) Step 9 still only staged `ai/tasks/`. Effect was identical to the original bug: an amendment to the workspace plan file landed via `MODE: plan-amendment`, but the Step 9 commit didn't include the plan delta, so the per-branch plan file stayed at its pre-amendment state. Fix: `git add ai/tasks/` → `git add ai/tasks/ ai/plans/` in the git-repo branch, mirroring the not-git-repo branch's Read+Write pattern. New doc-grep assertions in `tests/skills/review-response.test.sh` lock both branches.
189
+ - **`format_command` placeholder requirement dropped — it was never wired up.** [language-discovery.md:39](skills/init-workspace/language-discovery.md:39) and the schema row required `{FILE}` and `{PROJECT_ROOT}` placeholders for an "auto-format hook" that was never implemented. The developer and tester agents (per [developer/index.md:196](agents/developer/index.md:196) and [tester/index.md:158](agents/tester/index.md:158)) invoked the `format_command` verbatim at the repo root — so a value like `poetry run ruff format {FILE}` ran with a literal `{FILE}` string and crashed. The schema now declares `format_command` as a self-contained shell command with no placeholder substitution (matching `build_command`, `test_command`, etc.); the example block uses `poetry run ruff format .`. [schema-upgrade.md](skills/init-workspace/schema-upgrade.md) gets a `--keep-legacy` migration rule that strips `{FILE}`/`{PROJECT_ROOT}` from legacy values and surfaces the change to the human. New doc-grep test `tests/skills/format-command-self-contained.test.sh` (8 assertions) — including a tripwire that fails if anyone adds an auto-format hook to `hooks.json` (in which case the schema would need the placeholders back).
190
+ - **Worktree reconciliation now handles multiple matched worktrees for the same In Progress / In Review task.** An earlier change added a UID8 to the worktree path so a crashed-mid-task resume could create a fresh worktree without colliding with the orphan still on disk — but the [orchestrator-rules.md:206-216](skills/dev-workflow/context/orchestrator-rules.md:206) reconciliation classified both worktrees as `preserve` when the task was In Progress, leaving the orchestrator with no deterministic way to pick which one the resumed lane should use. The rule now explicitly handles the multi-match case: pick the most recently modified worktree (`git log -1 --format=%ct HEAD` as the tie-breaker, falling back to directory mtime) and classify the rest as `remove` with the reason "duplicate worktree for task T<n>". The `stop-failure-recovery.sh` injected recovery prompt picks up the same rule.
191
+ - **Re-trigger doc now calls out `Started` overwrite too, not just `Completed`.** The universal orchestrator rule (`rule #3`) sets `Task Metrics Started` on every transition to `🔧 In Progress` — so a `✅ Done → 🔧 In Progress` re-trigger overwrites the original Phase 5 `Started` stamp along with `Completed`. Previously the wording in [review-response.md](skills/dev-workflow/commands/review-response.md) Step 8b and [handle-request.md](skills/dev-workflow/commands/handle-request.md) Step 7b only mentioned `Completed` being overwritten, hiding the `Started` behaviour that would actually occur. Now the doc explicitly says both fields are overwritten and points at `Test hardening started` in Workflow Metrics as the unchanged first-run audit trail.
192
+ - **Phase 5 `[R<n>]` handling: T-TEST lane state pinned during human triage.** An earlier change said "do NOT silently relay `[R<n>]` to the Tester" but didn't specify what state to leave `T-TEST-<RepoName>` in while waiting for the human to resolve the stray finding. Now [test.md](skills/dev-workflow/commands/test.md) Step 2 splits the case: if there are `[T<n>]/[S<n>]` comments alongside the `[R<n>]`, transition to 🔧 In Progress normally (the lane keeps advancing on the legitimate findings, and the `[R<n>]` is surfaced separately to the human); if there are ONLY `[R<n>]` comments, the Tester has nothing to do, leave T-TEST in 🔄 In Review (do NOT transition — the universal-rule `Started` overwrite would lose audit fidelity) and pause the lane until the human resolves.
193
+ - **workflow-status now renders the post-Phase-7 re-hardening state distinctly.** Previously, after a Phase 7 re-trigger of `T-TEST-<Repo>` (✅ → 🔧), workflow-status rendered `Phase 5: Testing + Phase 6: PR Open` — both technically true but visually identical to a first-time Phase 5 run. Now the detector splits on the `PR created` metric: T-TEST 🔧/🔄 with `PR created` UNset → `Phase 5: Testing` (first-time); T-TEST 🔧/🔄 with `PR created` SET → `Phase 5: Re-hardening (post-Phase-7 / post-Gate-3 batch)`. A new worked example in the *Examples* block walks through the multi-valued phase render.
194
+ - **Preflight error message distinguishes "Planner never ran" from "Planner failed mid-write".** Previously, [preflight.md:12](skills/dev-workflow/commands/preflight.md:12) said "If the tracker has no Repo Status section, the Planner failed" — which mis-described the case where Planner was never invoked (e.g. someone runs `/dev-workflow preflight <id>` standalone before Phase 2). Now a 3-row error table maps "no tracker found" / "tracker exists but no Repo Status" / "repo named in plan but missing from `repos-paths.md`" to distinct error messages and recovery paths. 3 new doc-grep assertions in `tests/skills/preflight-ordering.test.sh`.
195
+ - **CLAUDE.md Worktree Fallback section now matches the orchestrator-owned reality.** Previously it described legacy behaviour: "the Developer reports `Worktree: failed` in its status, and the orchestrator re-invokes without worktree isolation". That's wrong — the orchestrator owns worktree creation in `develop.md` Step 1 sub-step 5 and the agent never sees the failure path. Now the section describes the actual flow: orchestrator attempts the add, retries once, then inlines `worktree_failed: true` in REPO_CTX; Step 4's APPROVED branch uses `git reset --soft <feature_head>` instead of `git merge --squash` in fallback mode; the agent reports `Worktree: not used (direct branch)` and `Worktree branch: n/a` per the schema.
196
+ - **`pr-creator` `Reuse:` output now has a literal terminator block as the parser anchor.** Previously, the `Reuse: <true | false>` output contract lived as a free-floating field; the orchestrator-side parser in `commands/create-pr.md` Step 9 had no anchor to grep against. If the LLM running pr-creator buried `Reuse:` mid-prose, the parser missed it. Now the output is wrapped in `--- PR CREATOR RESULT ---` (followed by `Reuse:`, `PR URL:`, `PR Number:`, `PR State:` — one field per line, fixed names, no empty values). Same approach as `📋 AGENT STATUS` for subagents — gives the parser a deterministic anchor.
197
+ - **story-workflow command files handle `local-markdown` explicitly.** Previously, all four commands (improve, refine, analyze, groom) said "use the **add comment** tool from the active provider adapter" at the post-back step — but `local-markdown` has no `work_item.add_comment` capability (refinements are saved by overwriting the source `.md` via the `Write` tool, per the adapter). The mismatch worked by LLM charity but was brittle. Now each command branches explicitly:
198
+ - `improve` / `refine` route local-markdown to the adapter's *Post Back / Save Refined Story* section (overwrite the source file).
199
+ - `analyze` keeps the readiness report in the conversation only — it must NOT overwrite the source (that's the refining commands' role); the doc surfaces this to the user with a "save as a sibling `.md` if you want to persist it" suggestion.
200
+ - `groom` offers two persistence paths: a sibling `<story-basename>-technical-notes.md` (recommended), or an Edit-append into the source file IF AND ONLY IF the source has a `## Technical Notes` heading (per the recommended local-markdown story template).
201
+ New doc-grep test `tests/skills/story-workflow-local-markdown.test.sh` (9 assertions) locks all four command files' local-markdown branches plus the "do NOT overwrite" rule on `analyze`.
202
+
203
+ ### Schema
204
+
205
+ - **`Development completed` Workflow Metric renamed to `Initial development completed`.** The pre-rename name was misleading after Phase 7 amendments and ad-hoc batches re-entered Phase 3 — the metric stayed at the original Phase 4 timestamp and never updated, so a tracker reading "Development completed: 2026-05-10" alongside an amendment commit dated 2026-05-15 was honest only if the reader knew the rename history. The new name makes the meaning explicit: this metric records the **first** Phase 3 close. Phase 7 re-entries are tracked by `PR review response completed`; ad-hoc batches by `Ad-hoc requests completed`. `Development started` keeps its original name intentionally — the start date is the relevant one regardless of later re-entries. Touches `plan-generator/tracker-schema.md` (canonical definition + rationale on the `started` row), `plan-generator/SKILL.md` (tracker template), `orchestrator-rules.md`, `commands/approve-impl.md` (record step), and the README sequence diagram. New doc-grep test `tests/skills/initial-development-completed.test.sh` (12 assertions) locks both directions — the new name appears everywhere and the legacy name appears nowhere (CHANGELOG entries are exempt for historical accuracy).
206
+
207
+ ### Fixes
208
+
209
+ - **`<type>` placeholder removed from branch-naming snippets.** The harness consistently used `<team-name>/feature/<id>-<slug>` for branches (preflight, validator help, pr-creator, hooks all hard-coded `feature`), but the documented form in CLAUDE.md, README, reviewer/index.md, and three command files was `<team>/<type>/<id>-<slug>` with a `<type>` placeholder that was never wired to anything. Readers reasonably assumed `<type>` was configurable. Now every doc snippet uses the literal `feature` segment; the README adds a one-line explanation that the placeholder is unwired. New doc-grep test `tests/skills/branch-naming.test.sh` (10 assertions) locks the rule — six files must not contain `<type>` in branch snippets, the README is allowed exactly one mention (the explanation paragraph), and CLAUDE.md / README / reviewer all document the canonical `feature/` form.
210
+ - **`pr-creator` reuse path no longer triggers a force-push amend.** Previously, `commands/create-pr.md` Step 9 unconditionally amended the just-committed tracker commit and force-pushed — even when the human had picked `[1] Reuse` against an existing open PR/MR. That produced force-push noise on the open PR (reviewer notifications, "Force-pushed" timeline banner, orphaned inline-comment references on most providers) and silently overwrote the original `PR created` metric with the current re-run timestamp. Now `pr-creator/SKILL.md` Step 0 declares a `Reuse: <true | false>` output flag, and `commands/create-pr.md` Step 9 branches on it: create path keeps the amend + force-push as before; reuse path writes a fresh `#TTRACKER: record PR created timestamp on reuse` commit on top of Step 6's tracker commit and fast-forward pushes (no `--force-with-lease`, no orphaned comment refs). The reuse path also preserves an already-set `PR created` value — the original creation date wins over the re-run timestamp. 6 new doc-grep assertions in `tests/skills/pr-creator.test.sh`.
211
+ - **Phase 7 task filter is now section-based, not content-based.** Previously, `commands/review-response.md` Step 8 filtered Phase 7 re-entry tasks by "rows whose Notes column contains `PR-comment:`". This worked only because the `PR-comment:` token was unique to Amendment rows by convention (per `tracker-schema.md`) — a future change that allowed the token in any other section would silently widen the filter. Now the filter is "rows that live under a `## Amendments (PR Review Round <N>)` heading AND have `Status: ⏳ Pending`" — section-based, durable, doesn't drift if tokens are reused elsewhere. 2 new doc-grep assertions in `tests/skills/review-response.test.sh`.
212
+ - **Phase 5 `[R<n>]` handling is now explicit about the prefix mismatch.** Previously, `commands/test.md` Step 2's CHANGES_REQUESTED handling said all comments (including `[R<n>]`) are routed to the Tester "the last is an out-of-band reviewer error worth surfacing — include them verbatim and flag the prefix mismatch to the human if they recur". That left "what to actually do with `[R<n>]`" ambiguous — the Tester could either ignore it (silently dropping a real finding) or step out of scope to address production code (violating Phase 5's test-only scope). Now the wording is explicit: `[R<n>]` in Phase 5 is a Reviewer-side error; surface the prefix mismatch verbatim and the comment body so the human can decide whether the underlying issue warrants a new story / ad-hoc request, and do NOT silently relay to the Tester.
213
+ - **`stop-failure-recovery.sh` heredoc split into independent blocks.** Previously the recovery prompt was a single `cat <<EOF` heredoc with an `${SNAPSHOT_BLOCK:+...}` parameter expansion that spanned multiple lines, embedded prose, and had a closing `}` on its own line. Functional but fragile — any future edit that broke a brace boundary silently turned the entire recovery prompt into a no-op. Now the script uses three sequential `cat <<EOF` blocks gated by `if [ -n "$SNAPSHOT_BLOCK" ]`. Same output bytes for every input; cleaner to edit. All 11 existing `tests/hooks/stop-failure-recovery/` assertions still pass.
214
+ - **`tracker-update-reminder` hook matcher pinned to the test fixture's `tool_name`.** A new test at `tests/hooks/tracker-update-reminder-matcher/` extracts the PostToolUse matcher from `hooks/hooks.json` for the tracker-update-reminder script and the `tool_name` value from `mk_agent_payload` in `tests/hooks/lib/assert.sh`, and asserts they match. Catches the failure mode where Claude Code renames the sub-agent tool (e.g. `Agent` → `Task`) and the fixture is updated but the matcher isn't, or vice-versa — in which case the hook silently stops firing in production while the unit tests (which call the script directly, bypassing the matcher) continue to pass. Currently both are `Agent`; the test passes; the link is now load-bearing.
215
+ - **`agents/shared/engineering-principles.md` stale line refs removed.** The header comment referenced `agents/developer/index.md:118` and `agents/reviewer/index.md:178`, but the actual references had drifted to lines 136 and 186 respectively across earlier rounds of edits. Replaced with symbolic references ("see the Startup Protocol section") plus an inline note that line numbers are deliberately omitted because they rot.
216
+ - **`status-schema.md` Phase enum for `request-triage` corrected.** Previously the enum line said "Phase 4 and 6 are valid" for the reviewer's request-triage mode. But mid-phase `/dev-workflow request` submissions land at Phase 3 or 5, and the `request-triage.md` agent file already declared `<3 | 4 | 5 | 6>` correctly. Now the schema line says "Phases 3, 4, 5, and 6 are all valid" with explicit per-source mapping (3/5 for mid-phase, 4/6 for gate submissions). Folded in during the same pass.
217
+ - **Local-markdown commit subjects now match the harness convention.** The local-markdown provider adapter previously documented commit subjects as `auth-story #T1: description` (no leading `#`), which `validate-commit-msg` rejected — every commit from a local-markdown story would have been blocked by the PreToolUse hook. The adapter's *ID Format* section now prescribes `#<filename-without-ext>` as the story-ID slot, with explicit examples for every phase (Phase 3 TDD `test:`/`impl:`, Phase 3 non-TDD, Phase 5 `test-harden:`, Phase 6 `#TPLAN`/`#TTRACKER`, Phase 7 `#TPR-RESP`). A new adapter test suite (`tests/adapters/local-markdown-commit-format/`) runs every documented subject through the real validator and asserts the legacy unprefixed form stays rejected, so the contradiction can't silently re-appear.
218
+ - **`agents/shared/status-schema.md` now matches what the agents actually emit.** The schema's per-agent field tables had drifted from the agent templates — declaring `Build:` / `Tests:` on the Developer and Reviewer Phase 3/5 blocks (the templates emit `Build result:` / `Build verified:` / `Tests verified:`), omitting `Self-review:`, `Build attempts:`, `Concerns:`, `Spec compliance:`, `Code quality verdict:`, `Review comments:`, `AC coverage:`, `Task coverage:`, `Critical issues:`, `Warnings:`, `Suggestions:`, and the entire `Tests written:` / `Tests passing:` / `Test attempts:` block from the Tester auto-harden mode. The schema is now the source of truth for every field the agent templates declare. `tests/skills/status-schema.test.sh` gains drift-catcher assertions for every renamed and newly-required field — including `_assert_field_absent` checks for the legacy `Build:` / `Tests:` names so they can't silently come back. The schema's `Phase:` enum line also corrects the request-triage range from "Phase 4 and 6" to "Phases 3, 4, 5, and 6" (mid-phase `/dev-workflow request` submissions land at Phase 3 or 5).
219
+ - **Worktree path now carries the same UID8 as the worktree branch.** Previously, the path was `<REPO_PATH>/../worktrees/<repo-name>-t<n>` and the branch was `worktree/<story-id>-t<n>-${UID8}` — the UID8 lived in the branch only. A session that crashed mid-task and left the worktree directory on disk would collide with the next resume's `git worktree add` (the directory already exists, so the add aborts). Now the path becomes `<REPO_PATH>/../worktrees/<repo-name>-t<n>-${UID8}` — a fresh resume always succeeds and the orphan worktree is surfaced and cleaned via the existing reconciliation flow in `orchestrator-rules.md` → *Worktree Reconciliation on Resume*. `tests/integration/worktree-ownership/test.sh` gains 3 new assertions: the path basename matches `<repo>-t<n>-<8-hex>`, a second `git worktree add` at the same path correctly fails, and a fresh UID8 path succeeds even while the original is still on disk. New doc-grep assertion in `tests/skills/develop-md.test.sh` locks the UID8-in-path shape and rejects the legacy form.
220
+ - **Phase 7 plan re-sync for non-git workspaces.** Previously, `review-response.md` Step 9 (workspace-NOT-a-git-repo path) re-synced only `ai/tasks/` into the affected repos. If the Phase 7 batch arrived via the inter-gate `[a] Expand scope` flow, the workspace plan had been amended via `MODE: plan-amendment` (appending a `## Plan Amendment — Ad-Hoc Round <N>` section) — but the per-repo plan copy committed in Phase 6 stayed frozen at the pre-amendment state. The next holistic review (or any human reading the merged PR) would see a tracker referring to a plan section that didn't exist in the repo's plan file. Now Step 9 re-syncs both `ai/tasks/` and `ai/plans/` via the standard Read+Write pattern (`bash-write-guard` blocks Bash writes to `ai/` paths), and the commit step stages both directories. The handle-request path is unchanged — `gate-3` ad-hoc batches return through `create-pr.md` Step 6 which already re-syncs both. New doc-grep test `tests/skills/review-response.test.sh` (11 assertions) locks the Step 9 contract.
221
+ - **Tester Phase 5 status block now declares "direct branch" as a fixed default.** Previously, the Tester's `auto-harden` status block specified `Worktree:` and `Worktree branch:` with the same fallback wording as `auto-tdd` — "from WORKTREE DETAILS, or 'not used (direct branch)' if worktree_failed: true". But Phase 5 never uses a worktree at all — the orchestrator's `commands/test.md` Step 1 invokes the auto-harden Tester with `REPO_CTX`, not `WORKTREE_CTX`, and `worktree_failed` doesn't apply. Now the block declares `Worktree: not used (direct branch)` and `Worktree branch: n/a` as fixed values with explicit "do NOT inspect worktree_failed" guidance. `agents/shared/status-schema.md` Tester table mirrors the same.
222
+ - **Phase 3 squash-merge now handles the worktree-failed fallback.** `develop.md` Step 4's APPROVED branch previously ran `git merge --squash <worktree-branch-from-developer-status>` unconditionally — but in fallback mode (`worktree_failed: true`) the agents commit directly on the feature branch and no worktree branch exists, so the merge would fail at hook time on every Windows lock-failure path the rest of the workflow already documents as a happy path. The step is now branched: worktree mode keeps `git merge --squash`, fallback mode uses `git reset --soft <feature_head>` (the SHA captured at Step 1 sub-step 3 — previously captured-and-unused, now load-bearing) followed by the same squash commit. The cleanup step (`git worktree remove` + `git branch -D`) is also gated on worktree mode — there's nothing to remove in fallback. The two CHANGES_REQUESTED rework prompts (Tester and Developer re-invocation) now use the same `WORKTREE_CTX if WORKTREE_FAILED=false, else REPO_CTX` conditional the initial-launch prompts already use, so rework cycles in fallback mode don't ask the agent to work in a worktree that doesn't exist. `feature_head` is now an explicit lane-state field. A new behavioural integration test (`tests/integration/worktree-failed-fallback/`) runs the fallback path end-to-end on a real git fixture — 3 agent commits, soft-reset, fresh squash commit — and verifies the squashed tree is byte-identical to the pre-reset tree, the commit subject passes `validate-commit-msg`, and the now-impossible "merge --squash against a nonexistent branch" command still fails loudly so a future regression can't paper over the contradiction.
223
+
224
+ ### Known limitations
225
+
226
+ - **Plan-snapshot lookup is human-gated across session crashes.** When the orchestrator takes a plan snapshot before invoking `MODE: plan-amendment` (during `[a] Expand scope` in the ad-hoc request flow), the snapshot filename `<plan-basename>-<timestamp>-<uid8>.md` is written to `ai/.snapshots/`. The orchestrator remembers the exact filename in session state so the matching delete-on-approve or restore-on-reject step uses the right snapshot. If the session is interrupted between the snapshot write and the disposition, that in-memory mapping is lost — `stop-failure-recovery.sh` lists every orphan snapshot on resume and prompts the human to pick (`Do NOT auto-restore or auto-delete`). This is safe but not robust to concurrent amendments across a crash. A future change can add a `Snapshot` column to `## Pending Requests` so the snapshot path travels with the in-flight request.
227
+
228
+ ### Features
229
+
230
+ - **Ad-hoc requests between approval gates are now first-class.** When the human submits a change request mid-workflow — at GATE #2 (`approve-impl`) instead of `APPROVED`, at GATE #3 (`create-pr`) instead of `APPROVED` / `DRAFT`, or mid-phase via `/dev-workflow request <story-id> "<text>"` — the harness triages every request against the approved plan and acceptance criteria before any code work begins. In-scope items (regressions in already-Done tasks, missed acceptance criteria) require a one-click human confirmation (GATE #5), then land as new tasks under a separate `## Ad-hoc Tasks (Batch <N>)` heading in the tracker and re-enter the standard Phase 3 TDD loop (Tester → Developer → Reviewer → squash-merge). Out-of-scope or plan-conflicting requests are surfaced back to the human with explicit options — expand the current story (Planner runs a scoped plan amendment that re-enters a scoped GATE #1), defer as a new work item, or withdraw — and never merge silently. After the batch completes the workflow resumes the gate that was interrupted, with the per-repo summary or pre-PR review re-rendered against the new commits. The same triage flow runs whether the request arrives at a gate or mid-phase; mid-phase requests are queued and drained at the next safe checkpoint without preempting in-flight agents. Provenance is recorded via the `ad-hoc: [AHR-<n>] · source: <gate>` Notes token, and a `## Deferred Requests` section captures the requests that didn't become tasks. New `Ad-hoc requests started` / `Ad-hoc requests completed` Workflow Metrics close the loop.
231
+
232
+ ---
233
+
234
+ ## [1.2.0] — 2026-05-15
235
+
236
+ ### Features
237
+
238
+ - **Harness agents use unique `ai-sdlc-` prefixed names.** The four harness agents are now registered as `ai-sdlc-planner`, `ai-sdlc-developer`, `ai-sdlc-reviewer`, and `ai-sdlc-tester` (previously `planner`, `developer`, `reviewer`, `tester`). Generic single-word names could conflict with user-defined agents of the same name in global or project setups; the prefix makes the harness agents unambiguous. The reviewer's mode-specific agents follow the same pattern: `ai-sdlc-pre-pr` and `ai-sdlc-pr-comment-analysis`. The `agent-status-check` hook, the tester activation guard, all skill invocations, and the status-block schema are updated accordingly. Agent instance names used for parallel-lane tracking (`tester-<repo>`, `developer-<repo>`, `reviewer-<repo>`) are instance labels, not agent identifiers, and are unchanged.
239
+ - **`bash-write-guard` hook** — new `PreToolUse` guard on `Bash` that closes the loophole where shell-driven writes (redirects, `tee`, `cp`, `mv`, `install`, `dd of=…`) bypassed the existing Write/Edit guards. Blocks shell writes that target `ai/` (orchestrator/planner territory) or any sensitive file pattern. When the payload carries subagent identity, applies role-aware rules: reviewers cannot write at all; planners may only write under `ai/`.
240
+ - **Shared hook library (`scripts/_hook-lib.sh`)** — every guard hook now sources a common helper for the python probe, payload reading, dotted-path field extraction (including list-shaped `tool_response` blocks), exit helpers, and workspace-root walk-up. Removes duplicated JSON parsing across eight scripts.
241
+ - **Structural commit-arg parser (`scripts/_git_argparse.py`)** — `shlex`-based parser for `git commit` invocations replaces the old single-regex extractor. Handles `git -C <path>`, `git -c key=val`, env-var prefixes, chained commands (`cd repo && …`, `(cd repo; …)`), multiple `-m` flags, `--message=`, `-F`, `--amend`, and heredoc bodies (including `<<-TAG` tab-stripping).
242
+ - **Fail-policy inventory (`scripts/README.md`)** — every hook now declares fail-closed vs. fail-open in a single table so the contract is reviewable at a glance.
243
+ - **Orchestrator-owned worktrees.** `develop.md` Step 1 sub-step 5 now creates the worktree in the orchestrator session before any agent launches (retry once, fall back to direct branch on lock failures). Tester and Developer prompts use a `WORKTREE_CTX` block on first launch; `REPO_CTX` is reserved for the fallback path and carries `worktree_failed: true`. Agent definitions no longer describe worktree creation as part of their job, and the unreachable `Next action: "worktree failed — retry without isolation"` enum option is removed from the developer status block. Closes a stall mode where sub-agents silently hung doing pre-write research during worktree setup with no diagnostic trail. Post-worktree stalls now always leave the worktree on disk for inspection.
244
+ - **Bounded pattern hints for the Tester.** `plan-generator` Step 5b emits 0–2 filename-glob pattern hints per `test-required` task — strictly ≤ 5 globs × ≤ 2 matches, no content reads (content-based file comparison is the exact stall surface this addresses, so relocating it to Phase 2 would just shift the stall earlier). The human curates the hints at the planning gate; the Tester consumes them verbatim via `PATTERN_HINTS_CTX` with an explicit "do NOT browse the tree" fallback for tasks the hints don't fit.
245
+ - **Canonical UTC date source — orchestrator constraint #14.** `date -u +'%Y-%m-%d %H:%M UTC'` is now the single authority for tracker stamps (Started, Completed, Plan approved, etc.); `date -u +%Y-%m-%d` is the authority for date-only fields including plan and tracker filenames. The system-reminder `currentDate` is orientation-only and must never be written into artefacts. `plan-generator` Step 6/7 switched from local-TZ `date +%Y-%m-%d`. Catches a TZ-skew bug where the orchestrator could stamp the plan with the system-reminder date while `date -u` reported the previous day.
246
+ - **Orchestrator constraint #15 — Conflict-Surfacing Rule.** New rule in `skills/dev-workflow/context/orchestrator-rules.md`: when a command-file step appears to conflict with an orchestrator rule, a hook block, another command file, or discovered state, the orchestrator must stop and surface the conflict to the human — never silently drop the step, invent a workaround (`cp` into a hook-guarded path, `--no-verify`, etc.), or declare itself authoritative over either side. Triggered by a session where the orchestrator silently skipped a Phase 2 commit step by citing rule #8 as an "override" instead of surfacing the contradiction.
247
+ - **Phase 6 Contract Verification table.** The pre-PR reviewer now emits a structured Contract Verification table per repo (new section 3b plus `Contracts verified` field in the AGENT STATUS block). `create-pr.md` Step 2b does a lexical cross-repo compare on the Observed Signature strings produced by each repo's reviewer — drift or a missing side routes to the existing `CHANGES_REQUESTED` branch so the human picks which side moves. No orchestrator-side source reading.
248
+ - **Tracker dependency graph (Mermaid).** `plan-generator` Step 7 renders a static `flowchart LR` in a new `## Dependency Graph` section: `-` → `_` for Mermaid node IDs, labels truncated to 40 chars, subgraph per repo only for multi-repo stories, and implicit Phase 5 edges from every dev task into `T-TEST-<RepoName>` made explicit. The outer Format fence was bumped to 4 backticks so the nested ```` ```mermaid ```` block doesn't close it. `review-response.md` Step 7 regenerates the graph when Phase 7 appends PR-response tasks.
249
+ - **Canonical `depends: T<n>[, T<n>...]` task token.** Cross-task dependencies are now declarable in the tracker Notes column with a single canonical token (regex + ` · ` combiner spelled out in `plan-generator/SKILL.md`). `develop.md` Step 1 gates each lane on every listed Task ID being ✅ Done. Unknown Task IDs in a `depends:` token are planner errors and pause the lane.
250
+ - **Worktree reconciliation on resume.** New `orchestrator-rules.md` procedure: list worktrees, match the canonical branch pattern, look each up in the tracker, classify (preserve / remove) by status — surface the table and ask the human; never auto-remove. Injected via the `stop-failure-recovery` and `PostCompact` hook prompts so resumed sessions can't silently lose work.
251
+ - **Three-prefix reviewer comment model `[R<n>]` / `[T<n>]` / `[S<n>]`.** `[T<n>]` is now the canonical test-code prefix in `reviewer/index.md` (previously referenced by `develop.md` and `test.md` but never defined). The fake "non-blocking suggestion" prefix is dropped — `SUGGESTION` is a severity inside `[R<n>]`/`[T<n>]`. Orchestrator routing: `R` → Developer, `T` → Tester, `S` → by file path (production → Developer, test → Tester); Tester runs first when both impl and test comments exist. Phase 5 routes every prefix to the Tester.
252
+ - **Hook helpers extracted to the wrapper/helper pattern.** `tracker-metrics-guard` and `tester-activation-guard` moved their inline Python into `_tracker_metrics_guard.py` and `_tester_activation_guard.py` (matching every other hook). The tester guard now detects the Status (and Task ID) column position from the tracker header instead of hard-coding `$4`/`$5` in `awk` — adding new tracker columns no longer breaks detection; a broken schema is blocked with a clear error.
253
+ - **`tests/run.sh` aggregator.** Single CI/local entry point that runs the hooks, skills, and integration suites. Adds 22 doc-grep assertions under `tests/skills/` (catch regressions that re-add agent-side worktree creation, drop bounded heuristics in pattern hints, or copy local-TZ date commands into skill files) and a 6-assertion behavioural worktree fixture under `tests/integration/worktree-ownership/` (verifies the orchestrator-side `git worktree add` snippet works on a real git fixture and that `bash-write-guard` allows the call from an orchestrator session).
254
+ - **`story-intake` documents `local-markdown` and `zoho` providers** — Arguments section, fetch examples, extraction notes, and a Provider field in the output template now cover both providers.
255
+ - **`agent-status-check` tail window scales with response length.** Window size is `max(5, min(50, line_count // 4))` — short responses can no longer pass with the AGENT STATUS block mid-body.
256
+ - **PR review response (`/dev-workflow review-response`) is now wired up end-to-end on GitHub.** Provider adapters gain a separate `pr-comments.md` file declaring the list/reply primitives Phase 7 needs. GitHub's adapter uses the `gh` CLI for both fetching unresolved review threads (`gh api graphql` with `reviewThreads.isResolved`) and posting replies (`POST .../pulls/{pr}/comments/{id}/replies`). The orchestrator now points at `pr-comments.md` for these capabilities and surfaces an explicit setup error when the configured git provider has not yet declared them — previously the phase routed at `pull-requests.md`, which only exposes PR-creation primitives, and could fail silently mid-flow. The other git providers (ADO, GitLab, gh-cli, glab-cli, Jira) do not yet ship `pr-comments.md` — they remain on the follow-up list and Phase 7 will surface that gap rather than no-op.
257
+ - **Provider capability surface.** New `skills/providers/shared/capabilities.md` enumerates the work-item and PR/MR capabilities every adapter is expected to declare (`work_item.fetch`, `pr.create`, `pr.list_review_comments`, …). Each adapter file gains a `## Capabilities` section using a ✅ / 🟡 (emulated) / ❌ table — currently shipped for GitHub. `scripts/lint-capabilities.py` (run via `tests/adapters/`) enforces declarations on the scoped adapters: missing `## Capabilities` heading or missing required capability row fails CI.
258
+ - **`Verdict:` field on the Phase 7 reviewer AGENT STATUS block** (`ANALYSIS_COMPLETE` / `ANALYSIS_PARTIAL` / `PLAN_NOT_FOUND`), with orchestrator routing in `review-response.md` Step 4: partial classifications surface as an `## Unclassified Comments` block above the GATE #4 prompt; `PLAN_NOT_FOUND` escalates without proceeding to the human gate. Closes the case where an analyser could not classify every comment but the orchestrator still merged the report as if complete.
259
+ - **Canonical AGENT STATUS schema (`agents/shared/status-schema.md`).** Single source of truth for the fields every subagent emits, per agent × mode. Field-name renames applied: Tester `test_commit:` → `Commit:` (both auto-tdd and auto-harden), Planner now declares `Tracker path:` and `Plan path:` in Phase 2, Tester auto-harden gains `Worktree branch:` to match auto-tdd. Every agent index/mode file links the schema so renames stay synchronised, and a doc-grep regression suite (`tests/skills/status-schema.test.sh`) enforces the contract at build time.
260
+ - **`agent-status-check` floor tightened.** The SubagentStop hook now requires `Agent:` with a recognised name (planner | developer | tester | reviewer) and `Next action:` with a non-empty value, in addition to the existing `Outcome:`/`Verdict:` presence check. Mode-specific field enforcement remains in the doc-grep suite — the hook doesn't try to dispatch by mode at runtime. Tail-window floor bumped from 5 to 10 lines so a typical 7-field block plus a one-line prose preamble doesn't get cut off in short responses. Test count for the hook: 9 → 15.
261
+ - **Reviewer Phase 0 trimmed to checks no hook covers.** Removed the duplicated commit-message-regex and sensitive-files-absent checks — both are now enforced by `validate-commit-msg.sh` and `sensitive-file-guard.sh` respectively, and re-asserting them in the Reviewer was drifting. Kept the forbidden-`ai/`-writes check (no Write/Edit hook covers it) and the GitHub emoji-shortcode check (no hook covers it yet) with explicit coverage notes.
262
+ - **Engineering-principles file stripped of agent-style frontmatter.** `agents/shared/engineering-principles.md` is a reference document that the Developer and Reviewer `Read` as a regular file, not an invocable sub-agent. The `name:` / `description:` / `tools:` / `model:` frontmatter misleadingly suggested otherwise and is removed.
263
+ - **`/dev-workflow create-pr` is now safe to re-run after a partial failure.** New idempotency check (Step 0 in `pr-creator`) queries the git provider's `pr.find_for_branch` capability before any push — if an open PR/MR already exists for the feature branch, the human is prompted to reuse it or fail the run rather than the orchestrator silently creating a duplicate. The reuse path skips PR creation and records the existing URL into the tracker; the fail path stops the invocation cleanly. Resolves the case where a push succeeded but the create-PR step failed mid-flow and a retry duplicated the PR.
264
+ - **Draft PR mode at the Phase 6 GATE.** The pre-PR review approval prompt is now multi-choice: `[1] APPROVED` opens a normal review-ready PR, `[2] DRAFT` opens the PR in draft state for cases where external team review is intentionally deferred (e.g. waiting on a dependent PR in another repo), `[3] CHANGES` re-enters the fix loop. The choice is passed into `pr-creator` as a `PR_MODE` context block and applied per adapter (`isDraft`, `draft:`, `--draft` depending on the provider).
265
+ - **Default branch sourced from `.claude/context/repos-metadata.md` in `pr-creator`.** The skill previously read `<default-branch>` implicitly and could silently default to `main` for repos using `master` or a release branch. The pre-flight checks now read the `Default Branch` field per repo from `repos-metadata.md` and pass it explicitly into every step.
266
+ - **Auth-failure copy in `pr-creator`.** When `git push` or PR creation fails with an authentication error, the skill surfaces a clear message pointing at the configured adapter's `**Prerequisites**` section in `pull-requests.md` with provider-specific fixes (`gh auth status` for GitHub/gh-cli, PAT rotation checks for ADO/GitLab MCP). The idempotency check in Step 0 picks up cleanly on the next run after the auth is restored — no duplicate PR.
267
+ - **`mcp__zoho__*` dropped from `pr-creator` allowed-tools.** Zoho is a work-item provider only; the PR creator never calls it. Tightens the skill's tool surface.
268
+ - **Plan generation has a minimum-input gate.** `plan-generator` Step 0a verifies the requirements summary has a non-empty description, ≥ 1 acceptance criterion, and ≥ 1 repo declared in `repos-metadata.md` before any expensive design work. If any check fails, the skill exits with `Outcome: BLOCKED` and a clear bounce-back message pointing at `/story-intake` (or `/init-workspace` if the repos table is empty). Resolves the failure mode where a thin story produced an unusable plan and wasted the human's review time at GATE #1.
269
+ - **`plan-generator` declares its Phase 7 Amendment Mode.** Previously the orchestrator's `review-response.md` carried inline instructions for the Planner with no corresponding declaration on the skill side, leaving the contract implicit. The skill now documents `MODE: pr-response-tasks`: the canonical amendment-row template (Notes column carries `PR-comment: [PC-<n>] thread_id=<...>` so Phase 9 can reply on the original thread), the `## Amendments (PR Review Round <N>)` heading convention, the no-reorder / no-remove invariant on existing rows, and the dependency-graph regeneration rules. The orchestrator's prompt is reduced to context (paths, story ID, accepted comments, round number) and now passes a `Round: <N>` value so multiple PR review cycles append cleanly under successive headings.
270
+ - **`story-intake` now pulls comments and parent context by default.** New Step 1b fetches the last 20 non-bot comments via `work_item.list_comments` (when the configured adapter declares the capability) and, if the work item has a `parent` / `epic` link, fetches one level of parent title + description. Both feed the gap analysis in Step 3 and appear in the Requirements Summary. Closes the gap where the Planner was reasoning from the story body alone while the reviewer had been talking out the AC ambiguities in the comments thread.
271
+ - **`story-intake` closed-state guard.** If the work item is already in a closed/done/resolved state, the skill surfaces a confirmation prompt before producing a Requirements Summary. Catches the common "wrong story ID pasted" failure and the "re-running intake on a shipped story by accident" case.
272
+ - **Canonical Acceptance Criteria schema in the Requirements Summary.** ACs are now emitted as a numbered list with optional `Given:` / `When:` / `Then:` sub-fields, the latter populated only when the source already wrote them (no synthesis from prose). Plan-generator's Step 0a minimum-input check counts ACs from this single shape regardless of which provider produced the story. Removes the previous freeform AC rendering that the Planner had to interpret per provider.
273
+ - **`key_dependencies` scope locked down explicitly.** The four supported manifest formats (pom.xml, package.json, go.mod, pyproject.toml) are now declared as the deliberate scope, with the canonical comment `# manifest unsupported` for any other format. The `[API: <lib> v<version>]` annotation in `plan-generator` is **omitted entirely** when a concrete version cannot be resolved — no placeholder `v?` / `v0` / `v(unknown)` guesses, because a wrong-anchor annotation is worse than no annotation. `plan-generator` Step 1c also distinguishes "scope-down declared" (don't retry) from "field absent" (read the manifest directly). Extension to Gradle / Cargo / Gemfile / composer is a follow-up gated on a real user need.
274
+ - **API-compatibility check is now a developer precondition, not a recovery step.** The Developer's responsibilities list gains a new Step 4 that runs **before** any production code is written: for every `[API: <lib> v<version>]` annotation on the task's Notes column, the Developer must open the library's official docs for that exact version and verify the prescribed method/type signatures. Previously this check only fired reactively inside Build Failure Recovery — meaning a wrong-API-version assumption was already compiled in by the time it surfaced. Build Failure Recovery now frames an API mismatch as a "Step 4 escape" rather than a primary diagnosis path.
275
+ - **UID8 generation hard-fails when empty.** `develop.md` Step 1 sub-step 5 (orchestrator-owned worktree creation) now exits with a clear error if both `uuidgen` and `python3 -c "import uuid; ..."` fail to produce a value. Previously an empty `UID8` would silently produce a worktree branch like `worktree/<story>-t<n>-` with a trailing dash, which could collide across lanes.
276
+ - **PR review-response works on all five git providers.** The provider capability sweep now covers ADO, GitHub, gh-cli, GitLab, and glab-cli — each ships a `pr-comments.md` adapter with `pr.find_for_branch`, `pr.list_review_comments`, and `pr.reply_to_review_comment` primitives, plus a `## Capabilities` declaration on its `pull-requests.md` (or `merge-requests.md` for GitLab) and `work-items.md` files. The canonical Phase 7 path is provider-native: `gh api graphql` reviewThreads for GitHub/gh-cli, `glab api projects/.../discussions` for glab-cli, and REST via `curl` for ADO and GitLab (with provider-specific auth, branch-ref prefixes, and discussion-vs-thread quirks documented per adapter). MCP wrappers for review-thread listing/replying are marked 🟡 across the board — verify the actual tool surface in your harness install before relying on them; the CLI/REST paths are the verified baseline. `scripts/lint-capabilities.py` now enforces declaration presence across all five providers (was github-only). `skills/providers/shared/capabilities.md` ships a sweep-status table so adding a new provider is mechanical: adapter files + lint allow-list entry + test assertion.
277
+
278
+ ### Fixes
279
+
280
+ - **`validate-commit-msg` rewritten to fail closed.** The old regex-based extractor missed `git -C` commits, multiple `-m` flags, `--message=`, `-F`, `--amend`, indented heredocs, and the Phase 5 `test-harden` exception — and silently allowed anything it couldn't parse. The rewrite reconstructs the message structurally and refuses commits whose form is undetermined. Also drops the "description must start lowercase" rule that rejected legitimate proper nouns (`AWS`, `URL`, `OAuth`).
281
+ - **`tracker-transition-guard` rewritten.** Matcher broadened from `Edit`-only to `Write|Edit|MultiEdit`. The hook now applies the edit in-memory, diffs task statuses by ID, and validates every row that changed (the old hook only checked the first emoji). Whole-file `Write` is covered; metadata-only edits (Notes, Commit, Verdict, timestamps) pass through.
282
+ - **`sensitive-file-guard` rewritten.** Matcher broadened to `Write|Edit|MultiEdit|NotebookEdit`. Deny-list extracted into a shared `_sensitive_patterns.py` module (reused by `bash-write-guard`) and expanded — most notably catching `.env.local`/`.env.production` that the old `\.env$` regex missed.
283
+ - **`tracker-update-reminder` rewritten.** Fixes a `PROMPT=… echo … | python` envvar leak that broke the orchestrator-prompt task-ID fallback. Accepts the recent SDK's list-of-content-blocks `tool_response` shape. Tracker selection now matches story ID against tracker filenames (with mtime as fallback) instead of blindly taking the most recent file.
284
+ - **`agent-status-check` rewritten.** Removed the `/tmp/agent-status-debug.json` write that ran on every invocation. Presence check upgraded from "phrase appears anywhere" to "phrase near the response tail with a non-empty `Outcome:` or `Verdict:` field" — mid-prose mentions no longer satisfy the gate. Fails closed on extractable responses; fails open with a stderr warning when no response text is locatable.
285
+ - **`squash-merge-verify` rewritten.** Command detection now `shlex`-aware, handling `cd repo && git merge --squash …`, subshells, env-var prefixes, and `git -c` flags. Implicit cwd from `cd <path>` is carried into the verification. Dropped the brittle `MERGE_MSG`-file AND-condition; relies on `git diff --name-only --diff-filter=U` alone.
286
+ - **`stop-failure-recovery` cwd dependency removed.** The inline marker-writer assumed cwd was the workspace root, so a directory change before failure silently swallowed the marker. Replaced with `stop-failure-marker.sh` using the shared workspace walk-up.
287
+ - **Workflow consistency: Phase 6 / Phase 7 file moves into a code repo now use Read+Write, not `cp`.** `create-pr.md` Step 6 and Step 9, and `review-response.md` Step 9, previously called `cp ai/... <REPO_PATH>/ai/...` to move plan/tracker into the repo in workspace-separated setups. `bash-write-guard` blocks Bash writes to `/ai/` paths by design (the `ai/` tree is owned by Read/Write tool calls). The command files now use the Read + Write tools for those copies; only `git add`/`commit`/`push` remain as shell calls.
288
+ - **Workflow consistency: Phase 2 plan commit is now conditional on workspace == repo.** When the workspace is itself a git repo, the orchestrator commits the plan as before. When the workspace is separate from the code repo, the commit is skipped — the plan stays in the workspace per orchestrator rule #8 and travels into the repo at Phase 6 alongside the tracker. The previous unconditional `git add ai/plans/ && git commit` either failed or pushed the orchestrator into copying the plan into the repo (tripping `bash-write-guard`).
289
+ - **Phase 7 Step 9 creates a new tracker-update commit instead of amending HEAD.** By Phase 7 Step 9, HEAD is the most recent Phase 7 task squash-merge — not the Phase 6 tracker commit — so `commit --amend` would silently rewrite a task commit's tree with tracker content. The replacement uses a new commit on top (fast-forward, no `--force-with-lease`) and keeps the tracker's recorded task SHAs accurate (an autosquash back into the Phase 6 tracker commit would rewrite every Phase 7 task SHA above it). Also adds the previously-missing `git push` — Phase 7 fixes were never reaching the remote PR.
290
+ - **Phase 6 Step 9 force-pushes after amend.** The amend rewrites the tracker commit SHA, and `pr-creator` already pushed the branch in Step 7. The workspace-is-git-repo branch was missing `git push --force-with-lease origin <feature-branch>` (asymmetric with the workspace-not-git branch which had it). Without the push, the remote PR was stale relative to the local tracker commit.
291
+ - **Orchestrator commits now use canonical-form meta Task IDs.** The Phase 2 plan, Phase 6 tracker, and Phase 7 tracker-update commit subjects previously used story-only form (`#<STORY-ID>: …`), which `validate-commit-msg` fail-closes — the only story-only exception is the Phase 5 `test-harden` form. The subjects now use `#TPLAN`, `#TTRACKER`, and `#TPR-RESP` respectively — valid instances of the existing canonical regex, so no hook change was required. Documented in README "Branch & Commit Conventions".
292
+ - **`tracker-transition-guard` now blocks new rows added to an existing tracker unless they start in ⏳ Pending.** Closes the bypass where appending a row already marked ✅ Done skipped the workflow entirely.
293
+ - **`bash-write-guard` normalises paths and resolves symlinks before deny-list checks.** Uses `os.path.normpath` plus `os.path.realpath` so `foo/../ai/x` and symlinks pointing at `ai/` or sensitive files no longer wave through.
294
+ - **`_git_argparse` bounds-checks the token after `--fixup` / `--squash`.** A missing or flag-shaped ref now surfaces as `parse_error`, and `validate-commit-msg` blocks the commit instead of allowing it via the autosquash short-circuit.
295
+ - **Phase 6 reviewer `APPROVED_WITH_CONCERNS` verdict is now routed correctly.** `create-pr.md` gains a dedicated Phase 6 Verdict matrix: `APPROVED_WITH_CONCERNS` routes to Gate 3 with warnings surfaced; `CHANGES_REQUESTED` routes to the fix-or-override branch; a `FAILED` outcome still wins over Verdict. Previously the orchestrator decision matrix described only Outcome-based actions, so `APPROVED_WITH_CONCERNS` had no defined handler.
296
+ - **Phase 6 Step 6 documented as the single sanctioned `ai/`-into-repo copy point.** Orchestrator rule #8 forbade copying `ai/` into a code repo before Phase 6, but Phase 6 Step 6 must do exactly that when the workspace is not a git repo. The rule now carries an explicit exception clause naming Step 6, requiring Read+Write tools (since `bash-write-guard` blocks `cp`), and keeping the workspace copy canonical for any later amendments. Resolves the rule-vs-step contradiction without weakening either side.
297
+ - **Self-review is now a commit precondition.** `developer/index.md` Step 5 forbids commit when any self-review check still fails; the AGENT STATUS field schema spells out that `Outcome: SUCCESS` is invalid when any `FAIL` result is present (`FAIL` is only valid with `Outcome ∈ {PARTIAL, BLOCKED, FAILED}`). The orchestrator parses any `SUCCESS + FAIL` combination as `PARTIAL` and re-routes via the standard `PARTIAL` handler.
298
+ - **Cannot-self-resolve escalation when a previously-green test breaks under T(n)'s implementation.** Developer sets `Outcome: BLOCKED` with structured Blockers and Next action "escalate to human — spec judgement: test vs impl". `develop.md`'s `BLOCKED` handler surfaces the branch choice (impl fix vs Tester-led test update) to the human rather than auto-routing. `tester/index.md` acknowledges that `auto-tdd` can be re-invoked for bounded test-edit scopes when the human chooses that path.
299
+ - **Phase 5 coverage gate explicitly covers `test-required: false` task code.** `test.md` and `tester/index.md` now say the 90 % target spans every new/modified file in the story, not just `test-required: true` tasks. The Tester writes the minimum meaningful tests when a `test-required: false` task produces production code that ends up under coverage and flags the mis-classification in Blockers; padding tests stay forbidden.
300
+
301
+ ### Tests
302
+
303
+ - **`tests/hooks/` pure-bash harness** — no `bats` dependency. One suite per hook, canned payloads piped through the real scripts, assertions on exit code and stderr. Current coverage: `validate-commit-msg` (33 cases, including the orchestrator meta-ID forms and `--fixup` / `--squash` bounds checks), `bash-write-guard` (36, including normpath and symlink-resolution cases), `tracker-transition-guard` (22, including the new-row-must-start-Pending check), `sensitive-file-guard` (19), `tracker-update-reminder` (10), `agent-status-check` (9), `squash-merge-verify` (10), `stop-failure-recovery` (7), plus an `integration` suite (11). Run individually via `tests/hooks/run.sh`.
304
+ - **`tests/skills/` doc-grep suite** — 22 assertions that catch regressions which re-add agent-side worktree creation, drop bounded heuristics in pattern hints, or copy local-TZ date commands into skill files. Run via `tests/skills/run.sh`.
305
+ - **`tests/integration/worktree-ownership/`** — 6 behavioural assertions on a real git fixture, verifying the orchestrator-side `git worktree add` snippet works and that `bash-write-guard` allows the call from an orchestrator session (no `agent_type` in payload).
306
+ - **`tests/run.sh` aggregator** — single entry point for hooks + skills + integration.
307
+
308
+ ---
309
+
310
+ ## [1.1.1] — 2026-04-25
311
+
312
+ ### Features
313
+
314
+ - **Dependency version detection and API-compat annotations** — `init-workspace` language-discovery Phase 2 now extracts `key_dependencies` (flat `name: version` list) from `pom.xml`, `package.json`, `go.mod`, and `pyproject.toml` (Gradle, Cargo, and Gemfile produce an empty list with a comment). The `plan-generator` reads this map in a new Step 1c and stamps each task's Notes column with `[API: <lib> v<version>]` for any task that prescribes a named library method or type, so developers verify the exact API signature before implementing. The developer's build-recovery Attempt 1 now begins with an API-compatibility check when the error looks like a version mismatch, directing the developer to the `[API:]` annotation before trying arbitrary workarounds.
315
+ - **Phase 6 autosquash before pre-PR review** — Developer commits Phase 6 reviewer-requested fixes as `fixup! <task-commit-subject>` (targeting the most recently committed task commit whose files the fix touches). After the developer completes, the orchestrator runs a non-interactive autosquash rebase (`GIT_SEQUENCE_EDITOR=true git rebase -i --autosquash`) so the pre-PR reviewer always sees clean, consolidated history. After the rebase, the orchestrator re-derives task commit hashes from `git log` and refreshes the tracker `Commit(s)` column before it is committed in Step 6 — the rebase rewrites SHAs, so stale hashes would otherwise be persisted. Rebase failure aborts and escalates to the human with the conflict output.
316
+ - **T-TEST tracker rows for Phase 5 test hardening** — `T-TEST-<RepoName>` rows are now included in every generated tracker (one per affected repo). The orchestrator advances them through the full Pending → In Progress → In Review → Done lifecycle during Phase 5, recording the tester commit hash in `Commit(s)` and the reviewer verdict in `Reviewer Verdict`, mirroring how Phase 3 dev tasks are tracked. Workflow Metrics field names aligned to `Test hardening started` / `Test hardening completed` everywhere (orchestrator-rules, create-pr prerequisites, README). Legacy trackers without T-TEST rows continue to work — `tester-activation-guard.sh` already skips T-TEST when checking dev-task completion.
317
+
318
+ ### Fixes
319
+
320
+ - **story-groom: enforce fetch → pull → scan order** — Step 3 is now an explicit hard prerequisite for Step 4: the codebase scan must not begin until fetch and pull complete for every confirmed repo. Fetch failure stops that repo entirely (no pull, no scan). Pull failure also stops the scan — the command reports and asks the user to resolve manually rather than proceeding on stale code. The "proceed on current branch" option now surfaces a staleness warning in the technical notes output. The `Important` section states "Fetch → Pull → Scan is the non-negotiable order."
321
+ - **Enforce date-prefixed naming convention for plan and tracker files** — Plan and tracker save paths now use an explicit `date +%Y-%m-%d` Bash step rather than inline shell substitution, preventing silent date-prefix drops. Orchestrators are prohibited from injecting explicit save paths into the planner — the planner always derives the canonical path from the date command output and `WORKSPACE_ROOT`.
322
+ - **Anchor plan and tracker saves to `WORKSPACE_ROOT`** — Orchestrator constraint #8 now defines `WORKSPACE_ROOT` as the directory whose `.claude/context/` holds `provider-config.md` and prohibits copying `ai/` files into any code repo before Phase 6. The plan-generator derives `WORKSPACE_ROOT` from the `.claude/context/` location before saving, replacing ambiguous relative paths that could resolve to a code-repo directory in multi-repo setups. The error-recovery block now instructs the planner to use the absolute workspace path.
323
+ - **Tester worktree must use `-b` to create a new branch** — `git worktree add` without `-b` tries to check out the feature branch directly, which Git refuses when it is already checked out in the main worktree. Both the tester agent startup protocol and the orchestrator's tester launch template now always create a fresh branch (`git worktree add <path> -b worktree/<story>-t<n>-<uuid> <feature-branch>`). Rework re-invocations navigate to the existing worktree path instead of creating a new one.
324
+
325
+ ---
326
+
327
+ ## [1.1.0] — 2026-04-23
328
+
329
+ ### Features
330
+
331
+ - **Claude Code attribution on all outputs** — every generated document (plan, tracker, user story, technical notes, requirements summary, PR/MR body) now ends with `🤖 Generated with [Claude Code](https://claude.ai/claude-code)`.
332
+ - **Co-author trailer on every commit** — all commits produced by the harness (tester, developer, orchestrator squash-merge, plan commit, tracker commit) include `Co-Authored-By: Claude Code <noreply@anthropic.com>` in the commit body.
333
+ - **Pre-PR review report enriched** — four new sections: Change Surface file list with categories (§0), Risk & Assumptions review vs plan (§8), Open Items carried forward — `TODO`/`FIXME`/`HACK` + unanswered story questions (§9), and a ready-to-use Suggested PR Description draft (§10).
334
+ - **Pre-PR AC verification strengthened** — reviewer now performs a mandatory active code search for each acceptance criterion, locating both the implementing code and a covering test with concrete `file:line` evidence. AC table extended with separate Implementation and Test evidence columns.
335
+ - **Full contract assertions required in integration/E2E tests** — tester must assert all response body fields defined in the plan's API contract, not just HTTP status codes. Error responses must assert status code AND every error envelope field.
336
+ - **Story-groom auto-pulls latest default branch** — `/story-groom` now runs `git fetch origin` before any repo analysis and automatically pulls with `--ff-only` when behind the remote. Stops with a clear error if the pull fails rather than analysing stale code.
337
+ - **Non-git workspace support in Phase 6** — when the workspace `ai/tasks/` directory is not inside a git repo, the tracker and plan are copied into each affected repo's `ai/` directories and committed from there, so artefacts travel with the feature branch.
338
+
339
+ ### Fixes
340
+
341
+ - **Path quoting in all shell snippets** — repo paths, worktree paths, and file paths in every Bash snippet are now wrapped in double quotes to handle spaces in paths (common on macOS developer machines). New orchestrator rule #13 mandates this across the harness.
342
+ - **UUID-based worktree branch names** — worktree branch suffix changed from `$(date +%s)` (collision-prone on fast consecutive launches) to an 8-character UUID (`uuidgen` with `python3` fallback).
343
+ - **PR comment thread IDs persisted in tracker** — thread IDs are written into the tracker's Notes column at planning time so reply posting in Phase 7 survives session interruptions and does not rely on in-memory state.
344
+ - **Commit convention clarified for Phase 5 test-harden commits** — `#<STORY-ID> test-harden: <desc>` (Story ID only, no Task ID) is now explicitly documented as the correct and only valid exception to the two-ID rule. Applied to reviewer Phase 0 pre-check, PR checklist, and pre-PR git hygiene section.
345
+
346
+ ### Docs
347
+
348
+ - **Sequence diagram always visible** — removed the collapsed `<details>` wrapper; the Mermaid diagram now renders inline in the README.
349
+ - **Coverage scope clarified** — all coverage threshold mentions now explicitly state "on new/modified code only — do NOT go out of scope to cover pre-existing code."
350
+
351
+ ---
352
+
353
+ ## [1.0.0] — 2026-04-12
354
+
355
+ First public release.
356
+
357
+ ### Features
358
+
359
+ - **7-phase development workflow** — Requirements → Plan → Develop → Human Approval → Test Hardening → PR Creation → PR Review Response, with human approval gates at phases 2, 4, and 6.
360
+ - **TDD pattern** — Tester commits failing tests first; Developer makes them green; Reviewer reviews the combined diff before squash-merge. Every task starts red.
361
+ - **Multi-repo support** — Parallel developer agents across repos, strictly sequential within each repo. Cross-repo boundaries resolved via contracts defined in the planning phase.
362
+ - **Phase 7: PR Review Response** — On-demand phase triggered after PR comments arrive. Reviewer classifies each comment as VALID / INVALID / PARTIAL; human selects which to address; Planner adds rework tasks and re-enters the Phase 3 loop.
363
+ - **Language-agnostic, discovery-driven** — `/init-workspace` discovers language, toolchain, build, test, and coverage commands via negotiate-and-confirm. Supports any language (frontend + backend).
364
+
365
+ ### Work Item Providers
366
+
367
+ | Provider | Notes |
368
+ |----------|-------|
369
+ | Azure DevOps | Work items via MCP |
370
+ | Jira | Issues via MCP |
371
+ | GitLab | Issues via MCP |
372
+ | GitHub | Issues via MCP |
373
+ | Zoho | Mail Group Tasks via MCP |
374
+ | local-markdown | Local `.md` files — no external provider needed |
375
+
376
+ ### Git / PR Providers
377
+
378
+ | Provider | Notes |
379
+ |----------|-------|
380
+ | Azure DevOps | Pull Requests via MCP |
381
+ | GitLab | Merge Requests via MCP |
382
+ | GitHub | Pull Requests via MCP |
383
+ | gh-cli | Pull Requests via `gh` CLI (no MCP required) |
384
+ | glab-cli | Merge Requests via `glab` CLI (no MCP required) |
385
+
386
+ ### Guardrail Hooks
387
+
388
+ - `tracker-transition-guard` — enforces legal tracker status transitions
389
+ - `tracker-metrics-guard` — validates tracker metric fields on every write
390
+ - `tracker-update-reminder` — reminds the orchestrator to sync tracker status
391
+ - `sensitive-file-guard` — blocks writes to secrets and credentials files
392
+ - `validate-commit-msg` — enforces `#<STORY-ID> #<TASK-ID>` commit format
393
+ - `squash-merge-verify` — prevents squash-merge before Reviewer approval
394
+ - `agent-status-check` — verifies agents end responses with a `📋 AGENT STATUS` block
395
+ - `tester-activation-guard` — prevents the Developer from starting before failing tests are committed
396
+ - `stop-failure-recovery` — surfaces recovery instructions on unexpected agent stops
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mostafa Ashraf
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.