create-sdd-project 0.18.4 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/lib/doctor.js +90 -0
- package/lib/upgrade-generator.js +30 -0
- package/package.json +1 -1
- package/template/.claude/agents/code-review-specialist.md +1 -0
- package/template/.claude/commands/audit-merge.md +219 -48
- package/template/.claude/skills/development-workflow/references/merge-checklist.md +25 -4
- package/template/.claude/skills/development-workflow/references/ticket-template.md +12 -0
- package/template/.claude/skills/pm-orchestrator/SKILL.md +19 -0
- package/template/.claude/skills/pm-orchestrator/references/pm-session-template.md +2 -0
- package/template/.gemini/agents/code-review-specialist.md +1 -0
- package/template/.gemini/commands/audit-merge-instructions.md +219 -48
- package/template/.gemini/skills/development-workflow/references/merge-checklist.md +25 -4
- package/template/.gemini/skills/development-workflow/references/ticket-template.md +12 -0
- package/template/.gemini/skills/pm-orchestrator/SKILL.md +19 -0
- package/template/.gemini/skills/pm-orchestrator/references/pm-session-template.md +2 -0
|
@@ -65,12 +65,14 @@ Determine the target branch from `docs/project_notes/key_facts.md` → `branchin
|
|
|
65
65
|
|
|
66
66
|
## Action 8: Fill Merge Checklist Evidence
|
|
67
67
|
|
|
68
|
-
In the ticket, fill the `## Merge Checklist Evidence` table. For each action (0–7), mark `[x]` and write the actual evidence (not placeholders). Example:
|
|
68
|
+
In the ticket, fill the `## Merge Checklist Evidence` table. For each action (0–7), mark `[x]` and write the actual evidence (not placeholders). Then complete Action 9 below — it MUST appear as the 9th row of the same table. Example:
|
|
69
69
|
|
|
70
70
|
| Action | Done | Evidence |
|
|
71
71
|
|--------|:----:|----------|
|
|
72
72
|
| 0. Validate ticket structure | [x] | Sections verified: Spec, Plan, AC, DoD, Workflow, Log, Evidence |
|
|
73
73
|
| 1. Mark all items | [x] | AC: 12/12, DoD: 7/7, Workflow: 0-5/6 |
|
|
74
|
+
| ... (rows 2-7 follow same shape) | [x] | ... |
|
|
75
|
+
| 9. Run `/audit-merge` | [x] | See § "Audit Merge Output" below |
|
|
74
76
|
|
|
75
77
|
**Canonical form for the AC count claim:** write `AC: <marked>/<total>` — `marked` is the count of `[x]` Acceptance Criteria, `total` is the count of all AC items including any intentionally deferred `[ ]`. When all are checked use the matching form `AC: N/N` (or the shorthand `all N marked`). The `/audit-merge` P6 drift check parses both forms.
|
|
76
78
|
|
|
@@ -82,11 +84,30 @@ In the ticket, fill the `## Merge Checklist Evidence` table. For each action (0
|
|
|
82
84
|
|
|
83
85
|
Sub-scope tickets reach `Status: Done` independently while the parent feature's tracker row stays at its parent status (typically `pending` or `in-progress`) until ALL sub-scopes close. `/audit-merge` P11 detects the suffix and emits `P11 N/A` instead of flagging the parent/sub-scope status divergence as drift.
|
|
84
86
|
|
|
85
|
-
## Action 9: Run compliance audit
|
|
87
|
+
## Action 9: Run compliance audit (MANDATORY, added v0.20.0 as structural MCE row)
|
|
86
88
|
|
|
87
|
-
Run `/audit-merge`
|
|
89
|
+
**Action 9 is MANDATORY.** Run `/audit-merge` after Actions 0-8 are complete. Paste the FULL verbatim output (structural + drift tables + verdict + self-verification line `Structural: N/N PASS | Drift: K advisory | Verdict: X`) into the dedicated `## Audit Merge Output` section of the ticket, directly below the MCE table.
|
|
88
90
|
|
|
89
|
-
|
|
91
|
+
Do NOT abbreviate, summarize, or omit failing rows. If `/audit-merge` flags any STRUCTURAL check as FAIL, fix it and re-run until ALL structural checks PASS. Drift advisories may stay open with explanation in the surrounding ticket.
|
|
92
|
+
|
|
93
|
+
The ticket structure for Action 9 (added v0.20.0):
|
|
94
|
+
|
|
95
|
+
```markdown
|
|
96
|
+
## Merge Checklist Evidence
|
|
97
|
+
|
|
98
|
+
| Action | Done | Evidence |
|
|
99
|
+
|--------|:----:|----------|
|
|
100
|
+
| 0. … | [x] | … |
|
|
101
|
+
| 1. … | [x] | … |
|
|
102
|
+
| ... (rows 2-7) | [x] | … |
|
|
103
|
+
| 9. Run `/audit-merge` | [x] | See § "Audit Merge Output" below |
|
|
104
|
+
|
|
105
|
+
## Audit Merge Output
|
|
106
|
+
|
|
107
|
+
<verbatim /audit-merge output goes here — see ticket-template.md>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The `/audit-merge` structural check `D1` (added v0.20.0) verifies row 9 exists with `[x]` AND the `## Audit Merge Output` section has non-empty body with a structural-compliance signal. Skipping this Action is now structurally visible (row 9 stays unfilled if you forget).
|
|
90
111
|
|
|
91
112
|
## Action 10: Request merge approval
|
|
92
113
|
|
|
@@ -102,6 +102,18 @@ This creates a feedback loop for improving future reviews. -->
|
|
|
102
102
|
| 5. Commit documentation | [ ] | Commit: (hash) |
|
|
103
103
|
| 6. Verify clean working tree | [ ] | `git status`: clean |
|
|
104
104
|
| 7. Verify branch up to date | [ ] | merge-base: up to date / merged origin/<branch> |
|
|
105
|
+
| 9. Run `/audit-merge` | [ ] | See § "Audit Merge Output" below |
|
|
106
|
+
|
|
107
|
+
## Audit Merge Output
|
|
108
|
+
|
|
109
|
+
> Paste the FULL verbatim output of `/audit-merge` below. The block must include both tables
|
|
110
|
+
> (structural + drift), all rows, the combined verdict, AND the final self-verification line
|
|
111
|
+
> in the form `Structural: N/N PASS | Drift: K advisory | Verdict: <APPROVE|REVISE>`. Do NOT
|
|
112
|
+
> abbreviate, summarize, or omit failing rows. Required for the D1 structural check to PASS.
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
<paste /audit-merge output here>
|
|
116
|
+
```
|
|
105
117
|
|
|
106
118
|
---
|
|
107
119
|
|
|
@@ -87,8 +87,27 @@ For each feature in the batch:
|
|
|
87
87
|
- **Lock**: If `docs/project_notes/pm-session.lock` is missing → stop (session was terminated externally).
|
|
88
88
|
- **Circuit breaker**: If 3 consecutive features are `blocked` → stop and report to user.
|
|
89
89
|
- **Context check**: If **2+ features have been completed** in this session, STOP and tell the user to run `/compact` followed by `continue pm`. Do NOT continue to the next feature — context degradation causes skipped steps, lost constraints, and poor quality. This is mandatory, not a suggestion.
|
|
90
|
+
- **Session-coherence check (added v0.20.0)**: Read `.sdd-version` from the repo root and the `**SDD version at start:** X.Y.Z` field from `docs/project_notes/pm-session.md`. If they differ → emit ADVISORY (non-blocking) once per Step transition:
|
|
91
|
+
```
|
|
92
|
+
⚠ Session-coherence drift: SDD upgraded mid-session (X.Y.Z → CURRENT).
|
|
93
|
+
Cached workflow references and rules in this session may be stale.
|
|
94
|
+
Recommendation: complete current Step's atomic work, then run `/compact`
|
|
95
|
+
followed by `continue pm` to reload templates before next Step.
|
|
96
|
+
(Non-blocking — proceed if you've reviewed the upgrade CHANGELOG and
|
|
97
|
+
confirmed no workflow-affecting changes.)
|
|
98
|
+
```
|
|
99
|
+
Do NOT auto-update the pm-session.md value here — capture the current cached-context coherence state. The field is auto-updated only by `continue pm` after `/compact` (see "Auto-update on /compact" below).
|
|
90
100
|
- **Clean workspace**: Run `git status`. If dirty, commit or stash before proceeding.
|
|
91
101
|
|
|
102
|
+
##### Auto-update on `/compact` (added v0.20.0)
|
|
103
|
+
|
|
104
|
+
When `continue pm` resumes the orchestrator after a `/compact`:
|
|
105
|
+
1. Re-read current `.sdd-version`.
|
|
106
|
+
2. Update `**SDD version at start:** X.Y.Z` in `pm-session.md` to the current value.
|
|
107
|
+
3. Reset the per-Step advisory-emitted flag.
|
|
108
|
+
|
|
109
|
+
Rationale: `/compact` reloads the cached context from the filesystem. After /compact, the agent is operating on current SDD templates, so the `SDD version at start` field should reflect that. The drift advisory above targets the WINDOW between an SDD upgrade and the next /compact — that window is the risk zone.
|
|
110
|
+
|
|
92
111
|
#### b. Start Feature
|
|
93
112
|
|
|
94
113
|
1. Update `pm-session.md`:
|
|
@@ -19,6 +19,7 @@ Then go beyond checklist review — actively try to break the implementation:
|
|
|
19
19
|
- What happens under concurrent requests? Race conditions?
|
|
20
20
|
- What data could a malicious user inject?
|
|
21
21
|
- What if a transaction fails midway or cache is stale?
|
|
22
|
+
- **Defensive guards**: For every `if (cond)` / `if (!cond)` / SQL `WHERE` predicate / type-narrowing check that exists "to prevent X", trace the boolean with three concrete value scenarios — (a) the danger case the guard targets, (b) a normal/expected case, (c) an edge case (null/0/empty/duplicate). Does the guard fire ONLY on the danger case? Common failure: a defensive predicate is written that fires on the SAFE case and skips the DANGER case (boolean inverted). Treat any guard whose conditions you cannot mentally trace through values as a critical-review item — request author justification or write the trace yourself.
|
|
22
23
|
|
|
23
24
|
## Output Format
|
|
24
25
|
|
|
@@ -48,11 +48,82 @@ If DIVERGED, flag as FAIL with instruction to merge target branch first.
|
|
|
48
48
|
|
|
49
49
|
Run only if `git diff origin/<target-branch>..HEAD --name-only` shows `.json` files in seed-data or fixtures directories.
|
|
50
50
|
|
|
51
|
+
**12. CI State** (added v0.19.0) — Verify GitHub Actions / CI checks for the current PR show no FAILURE / ERROR / CANCELLED / TIMED_OUT conclusion. PENDING is acceptable (still running). Emits distinct `N/A` messages when `gh` is unavailable, `jq` is unavailable, or no PR is open for the current branch — these are not blockers. Empirical motivation: F107a (PR #279) shipped with `ci-success` BLOCKED on 3 real failures (test-api lint, test-web build, branch-protection gate); the agent claimed "CI: green" without verification. C3 makes the claim auditable structurally.
|
|
52
|
+
```bash
|
|
53
|
+
if ! command -v gh >/dev/null 2>&1; then
|
|
54
|
+
echo "C3 N/A: gh CLI unavailable"
|
|
55
|
+
elif ! command -v jq >/dev/null 2>&1; then
|
|
56
|
+
echo "C3 N/A: jq unavailable"
|
|
57
|
+
else
|
|
58
|
+
# In GitHub Actions `pull_request` jobs, `actions/checkout` defaults to a
|
|
59
|
+
# detached HEAD (no branch context), so `gh pr view` with no arg cannot
|
|
60
|
+
# resolve "the PR for the current branch". Read the PR number from
|
|
61
|
+
# GITHUB_REF (`refs/pull/<N>/merge`) when available so C3 still queries
|
|
62
|
+
# the right PR. Local runs (no GITHUB_REF) keep the no-arg behavior.
|
|
63
|
+
PR_NUM_FROM_CI=""
|
|
64
|
+
if [ -n "${GITHUB_REF:-}" ]; then
|
|
65
|
+
PR_NUM_FROM_CI=$(printf '%s' "$GITHUB_REF" | sed -n 's@^refs/pull/\([0-9]\{1,\}\)/.*@\1@p')
|
|
66
|
+
fi
|
|
67
|
+
if [ -n "$PR_NUM_FROM_CI" ]; then
|
|
68
|
+
PR_JSON=$(gh pr view "$PR_NUM_FROM_CI" --json number,statusCheckRollup 2>/dev/null || true)
|
|
69
|
+
else
|
|
70
|
+
PR_JSON=$(gh pr view --json number,statusCheckRollup 2>/dev/null || true)
|
|
71
|
+
fi
|
|
72
|
+
if [ -z "$PR_JSON" ]; then
|
|
73
|
+
echo "C3 N/A: no PR open for current branch"
|
|
74
|
+
else
|
|
75
|
+
PR_NUM=$(echo "$PR_JSON" | jq -r '.number // "unknown"')
|
|
76
|
+
FAILURES=$(echo "$PR_JSON" | jq -r '
|
|
77
|
+
.statusCheckRollup[]?
|
|
78
|
+
| select((.conclusion // .status) as $s
|
|
79
|
+
| $s == "FAILURE" or $s == "ERROR" or $s == "CANCELLED" or $s == "TIMED_OUT")
|
|
80
|
+
| .name // .context
|
|
81
|
+
' | sort -u)
|
|
82
|
+
if [ -n "$FAILURES" ]; then
|
|
83
|
+
flag "C3 BLOCKER: PR #$PR_NUM has failing checks — $(echo "$FAILURES" | tr '\n' ',' | sed 's/,$//')"
|
|
84
|
+
else
|
|
85
|
+
echo "C3 PASS: PR #$PR_NUM — all checks pass or pending"
|
|
86
|
+
fi
|
|
87
|
+
fi
|
|
88
|
+
fi
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**13. MCE Action 9 present** (D1, added v0.20.0) — Verify the ticket's `## Merge Checklist Evidence` table includes row 9 marked `[x]`, AND the dedicated `## Audit Merge Output` section below the MCE table has non-empty body content containing a structural-compliance signal (e.g. `Structural: 13/13 PASS` or `Verdict: APPROVE`). Stable ID `D1`. Empirical motivation: fx PR #299 F-WEB-HISTORY merged without `/audit-merge` having been run — MCE table contained Actions 0-8 only (no row 9). The prose instruction at `merge-checklist.md:87` ("Run /audit-merge to verify all compliance checks pass automatically") was easier to skip than a structural table row. D1 makes the skip falsifiable: row 9 stays unfilled if the audit didn't run.
|
|
92
|
+
```bash
|
|
93
|
+
ACTION_9_LINE=$(awk '/^## Merge Checklist Evidence/,/^---|^## (Audit Merge Output|Acceptance|$)/' "$TICKET" | grep -E '^\| 9\. ' | head -1)
|
|
94
|
+
AUDIT_SECTION=$(awk '/^## Audit Merge Output/,/^## |^---|^\*Ticket/' "$TICKET")
|
|
95
|
+
AUDIT_SECTION_BODY=$(printf '%s' "$AUDIT_SECTION" | sed '1d;$d' | grep -vE '^[[:space:]]*>' | tr -d '[:space:]')
|
|
96
|
+
# Compliance signal: case-insensitive. Mirrors JS twin's `.*?` semantics so
|
|
97
|
+
# `Structural: N/N PASS` (colon), `Structural — N/N` (em-dash), `Structural N/N`
|
|
98
|
+
# (space) all match. The `/audit-merge` Output Format section MUST emit at least
|
|
99
|
+
# one canonical signal per the Self-Verification Guarantee (see Output Format).
|
|
100
|
+
COMPLIANCE_HIT=$(printf '%s' "$AUDIT_SECTION" | grep -ciE '(structural[^[:alnum:]]+[0-9]+/[0-9]+)|(\b13/13\b)|(\ball[[:space:]]+(checks[[:space:]]+)?pass)|(verdict[[:space:]]*:[[:space:]]*approve)')
|
|
101
|
+
|
|
102
|
+
if [ -z "$ACTION_9_LINE" ] && [ -z "$AUDIT_SECTION" ]; then
|
|
103
|
+
# Legacy ticket predating v0.20.0 — neither row 9 NOR Audit Merge Output section exists.
|
|
104
|
+
# Emit N/A with migration hint instead of BLOCKER. Forward-looking: tickets created
|
|
105
|
+
# post-v0.20.0 will have at least the section header (from ticket-template.md), so
|
|
106
|
+
# legitimate skips still surface via the other branches below.
|
|
107
|
+
echo "D1 N/A: legacy ticket (no row 9 and no ## Audit Merge Output section) — add both per merge-checklist.md to comply with v0.20.0"
|
|
108
|
+
elif [ -z "$ACTION_9_LINE" ]; then
|
|
109
|
+
flag "D1 BLOCKER: MCE Action 9 row missing (required since v0.20.0; ## Audit Merge Output section exists but row 9 not added to MCE table)"
|
|
110
|
+
elif printf '%s' "$ACTION_9_LINE" | grep -qE '\| \[ \] \|'; then
|
|
111
|
+
flag "D1 BLOCKER: MCE Action 9 row unchecked — /audit-merge not run"
|
|
112
|
+
elif [ -z "$AUDIT_SECTION_BODY" ]; then
|
|
113
|
+
flag "D1 BLOCKER: ## Audit Merge Output section missing or empty"
|
|
114
|
+
elif [ "$COMPLIANCE_HIT" -eq 0 ]; then
|
|
115
|
+
flag "D1 BLOCKER: ## Audit Merge Output section present but no structural compliance signal (expect 'Structural: N/N PASS' or 'Verdict: APPROVE')"
|
|
116
|
+
else
|
|
117
|
+
CHAR_COUNT=$(printf '%s' "$AUDIT_SECTION" | wc -c | tr -d ' ')
|
|
118
|
+
echo "D1 PASS: ## Audit Merge Output section pasted (~${CHAR_COUNT} chars)"
|
|
119
|
+
fi
|
|
120
|
+
```
|
|
121
|
+
|
|
51
122
|
### Drift Checks (added v0.18.0) — ADVISORY, not blocking
|
|
52
123
|
|
|
53
|
-
|
|
124
|
+
Sixteen empirically-validated drift patterns. Failures are NOT blockers for the compliance verdict, but MUST be refreshed before requesting user authorization. Use BSD-grep-compatible regex (no `\K`).
|
|
54
125
|
|
|
55
|
-
**
|
|
126
|
+
**14. P1 — PR body test count stale (v0.18.3 multi-workspace extension — C1).** All PR-body ratios must appear in ticket evidence. Subset direction: PR ⊆ ticket. Three fallback cases: (a) ratios on both sides → walk each PR ratio; (b)/(c) missing on either side → emit `P1 N/A`.
|
|
56
127
|
```bash
|
|
57
128
|
TEST_KW_RE='(npm test|pnpm test|tests?[^|]*[0-9]|[*: ]tests?[*: ]+[0-9])'
|
|
58
129
|
PR_BODY=$(gh pr view --json body -q .body 2>/dev/null || true)
|
|
@@ -69,14 +140,14 @@ else
|
|
|
69
140
|
fi
|
|
70
141
|
```
|
|
71
142
|
|
|
72
|
-
**
|
|
143
|
+
**15. P2 — Merge Checklist Evidence aspirational.** `[x]` rows with future-tense text.
|
|
73
144
|
```bash
|
|
74
145
|
awk '/^## Merge Checklist Evidence/{flag=1; next} /^## /{flag=0} flag' "$TICKET" \
|
|
75
146
|
| grep -E '^\|.*\[x\].*(to be |will |pending|TBD|Will be |to be created|next commit|aspirational)' \
|
|
76
147
|
&& flag "P2 drift: aspirational row(s) found"
|
|
77
148
|
```
|
|
78
149
|
|
|
79
|
-
**
|
|
150
|
+
**16. P3 — Post-merge actions not logged** (post-merge only).
|
|
80
151
|
```bash
|
|
81
152
|
# Strip checkbox prefix before comparison; use grep -Fq fixed-string match.
|
|
82
153
|
grep -E "^- \[ \].*(post-merge|operator|prod rollout|pending verification)" "$TICKET" \
|
|
@@ -89,14 +160,14 @@ while IFS= read -r item; do
|
|
|
89
160
|
done < /tmp/pm_items.txt
|
|
90
161
|
```
|
|
91
162
|
|
|
92
|
-
**
|
|
163
|
+
**17. P4 — Remote branch orphan.**
|
|
93
164
|
```bash
|
|
94
165
|
BRANCH=$(grep -oE '\*\*[Bb]ranch:\*\*[[:space:]]*[^[:space:]|()]+' "$TICKET" | head -1 | sed -E 's/^\*\*[Bb]ranch:\*\*[[:space:]]*//')
|
|
95
166
|
git fetch origin --prune --quiet
|
|
96
167
|
git ls-remote --heads origin "$BRANCH" 2>/dev/null | grep -q refs/heads && flag "P4 drift: remote branch $BRANCH still exists (run: git push origin --delete $BRANCH)"
|
|
97
168
|
```
|
|
98
169
|
|
|
99
|
-
**
|
|
170
|
+
**18. P5 — Frozen ticket Status post-merge.** Multi-word status via sed char class, not `\w+`.
|
|
100
171
|
```bash
|
|
101
172
|
FROZEN_COUNT=0
|
|
102
173
|
for t in docs/tickets/*.md; do
|
|
@@ -114,30 +185,49 @@ done
|
|
|
114
185
|
[ "$FROZEN_COUNT" -eq 1 ] && flag "P5 drift: 1 frozen ticket"
|
|
115
186
|
```
|
|
116
187
|
|
|
117
|
-
**
|
|
188
|
+
**19. P6 — AC count off-by-N (header-form aware since v0.19.0).** Supports two AC forms: `[x]`/`[ ]` checkbox form and `### AC<N>` header form. Headers authoritative when present (≥ 1). A header is "deferred" when its body contains `**Status**: Deferred|Pending|Skipped|Blocked` before the next `### `. Two claim shapes: `all N marked` and `AC: X/Y done`. v0.19.0 drops the v0.18.3 `-ge 2` tolerance — exact-match (off-by-1 advisories surface).
|
|
118
189
|
```bash
|
|
119
190
|
AC_BLOCK=$(awk '/^## Acceptance Criteria/,/^## Definition of Done/' "$TICKET")
|
|
120
|
-
|
|
121
|
-
|
|
191
|
+
HEADER_ACS=$(echo "$AC_BLOCK" | grep -cE '^### AC[0-9]+')
|
|
192
|
+
|
|
193
|
+
if [ "$HEADER_ACS" -gt 0 ]; then
|
|
194
|
+
ACTUAL_TOTAL=$HEADER_ACS
|
|
195
|
+
# Per-AC pass: emit one line per AC ("marked" or "deferred"). Then count.
|
|
196
|
+
PER_AC=$(echo "$AC_BLOCK" | awk '
|
|
197
|
+
function flush() { if (have) { print (deferred ? "deferred" : "marked"); have=0; deferred=0 } }
|
|
198
|
+
/^### AC[0-9]+/ { flush(); have=1; next }
|
|
199
|
+
/^## / { flush(); next }
|
|
200
|
+
have && /^\*\*Status\*\*:[[:space:]]*(Deferred|Pending|Skipped|Blocked)/ { deferred=1 }
|
|
201
|
+
END { flush() }
|
|
202
|
+
')
|
|
203
|
+
ACTUAL_MARKED=$(printf '%s\n' "$PER_AC" | grep -c '^marked$' || true)
|
|
204
|
+
else
|
|
205
|
+
ACTUAL_TOTAL=$(echo "$AC_BLOCK" | grep -cE "^- \[[x ]\]")
|
|
206
|
+
ACTUAL_MARKED=$(echo "$AC_BLOCK" | grep -cE "^- \[x\]")
|
|
207
|
+
fi
|
|
208
|
+
|
|
122
209
|
CLAIM_LINE=$(grep -oE 'all [0-9]+ marked|AC: [0-9]+/[0-9]+' "$TICKET" | head -1)
|
|
123
210
|
if echo "$CLAIM_LINE" | grep -qE '^AC: [0-9]+/[0-9]+'; then
|
|
124
211
|
CLAIMED_MARKED=$(echo "$CLAIM_LINE" | grep -oE '[0-9]+' | head -1)
|
|
125
212
|
CLAIMED_TOTAL=$(echo "$CLAIM_LINE" | grep -oE '[0-9]+' | tail -1)
|
|
126
213
|
[ -n "$CLAIMED_TOTAL" ] && [ "$CLAIMED_TOTAL" != "$ACTUAL_TOTAL" ] \
|
|
127
|
-
&&
|
|
128
|
-
&& flag "P6 drift: claim AC total '$CLAIMED_TOTAL' vs actual total $ACTUAL_TOTAL"
|
|
214
|
+
&& flag "P6 drift: claim AC total '$CLAIMED_TOTAL' vs actual total $ACTUAL_TOTAL (form: $([ "$HEADER_ACS" -gt 0 ] && echo header || echo checkbox))"
|
|
129
215
|
[ -n "$CLAIMED_MARKED" ] && [ "$CLAIMED_MARKED" != "$ACTUAL_MARKED" ] \
|
|
130
|
-
&&
|
|
131
|
-
&& flag "P6 drift: claim AC marked '$CLAIMED_MARKED' vs actual marked $ACTUAL_MARKED"
|
|
216
|
+
&& flag "P6 drift: claim AC marked '$CLAIMED_MARKED' vs actual marked $ACTUAL_MARKED (form: $([ "$HEADER_ACS" -gt 0 ] && echo header || echo checkbox))"
|
|
132
217
|
elif [ -n "$CLAIM_LINE" ]; then
|
|
133
218
|
CLAIMED=$(echo "$CLAIM_LINE" | grep -oE '[0-9]+' | head -1)
|
|
134
|
-
[ -n "$CLAIMED" ]
|
|
135
|
-
|
|
136
|
-
|
|
219
|
+
if [ -n "$CLAIMED" ]; then
|
|
220
|
+
[ "$CLAIMED" != "$ACTUAL_TOTAL" ] \
|
|
221
|
+
&& flag "P6 drift: 'all $CLAIMED marked' vs actual AC total $ACTUAL_TOTAL (form: $([ "$HEADER_ACS" -gt 0 ] && echo header || echo checkbox))"
|
|
222
|
+
# `all N marked` IMPLIES all ACs are marked; flag when actual marked < N
|
|
223
|
+
# (e.g. some ACs deferred via `**Status**: Deferred` or unchecked `[ ]`).
|
|
224
|
+
[ "$CLAIMED" != "$ACTUAL_MARKED" ] \
|
|
225
|
+
&& flag "P6 drift: 'all $CLAIMED marked' but only $ACTUAL_MARKED actually marked (form: $([ "$HEADER_ACS" -gt 0 ] && echo header || echo checkbox))"
|
|
226
|
+
fi
|
|
137
227
|
fi
|
|
138
228
|
```
|
|
139
229
|
|
|
140
|
-
**
|
|
230
|
+
**20. P7 — Test count drift within ticket (final-sections only).**
|
|
141
231
|
```bash
|
|
142
232
|
TERMINAL=$(awk '/^## Completion Log/,/^## Merge Checklist/' "$TICKET" | grep -iE "(test|pass|green)" | grep -oE "[0-9]+/[0-9]+" | tail -1)
|
|
143
233
|
AC=$(awk '/^## Acceptance Criteria/,/^## Definition of Done/' "$TICKET")
|
|
@@ -148,7 +238,7 @@ for n in $FINAL_NUMS; do
|
|
|
148
238
|
done
|
|
149
239
|
```
|
|
150
240
|
|
|
151
|
-
**
|
|
241
|
+
**21. P8 — Completion Log gap vs Workflow Checklist.**
|
|
152
242
|
```bash
|
|
153
243
|
WORKFLOW=$(awk '/^## Workflow Checklist/,/^## Completion Log/' "$TICKET")
|
|
154
244
|
COMPLETION=$(awk '/^## Completion Log/,/^## Merge Checklist/' "$TICKET")
|
|
@@ -159,7 +249,7 @@ while read -r step_num; do
|
|
|
159
249
|
done <<< "$CHECKED_STEPS"
|
|
160
250
|
```
|
|
161
251
|
|
|
162
|
-
**
|
|
252
|
+
**22. P9 — Tracker header stale.**
|
|
163
253
|
```bash
|
|
164
254
|
TRACKER=docs/project_notes/product-tracker.md
|
|
165
255
|
HEADER_STEP=$(grep '^\*\*Last Updated:\*\*' "$TRACKER" | grep -oE '(Step )?[0-9]+/6' | head -1 | sed -E 's/^Step //')
|
|
@@ -168,7 +258,7 @@ DETAIL_STEP=$(grep -A 1 '^\*\*Active Feature:\*\*' "$TRACKER" | grep -oE '(Step
|
|
|
168
258
|
&& flag "P9 drift: tracker header says $HEADER_STEP, Active Feature says $DETAIL_STEP"
|
|
169
259
|
```
|
|
170
260
|
|
|
171
|
-
**
|
|
261
|
+
**23. P10 — Duplicate Completion Log rows.**
|
|
172
262
|
```bash
|
|
173
263
|
awk -F'|' '/^\| [0-9]{4}-[0-9]{2}-[0-9]{2}/ {
|
|
174
264
|
key = $2 "|" $3 "|" substr($4, 1, 80)
|
|
@@ -178,7 +268,7 @@ awk -F'|' '/^\| [0-9]{4}-[0-9]{2}-[0-9]{2}/ {
|
|
|
178
268
|
| while read -r dup; do flag "P10 drift: duplicate Completion Log row: $dup"; done
|
|
179
269
|
```
|
|
180
270
|
|
|
181
|
-
**
|
|
271
|
+
**24. P11 — Tracker Features table status vs ticket Status mismatch.**
|
|
182
272
|
```bash
|
|
183
273
|
TICKET_STATUS=$(grep -E "^\*\*Status:\*\*" "$TICKET" | head -1 \
|
|
184
274
|
| sed -E 's/^\*\*Status:\*\*[[:space:]]*\*?\*?//' \
|
|
@@ -215,7 +305,7 @@ case "$TICKET_BASENAME" in
|
|
|
215
305
|
esac
|
|
216
306
|
```
|
|
217
307
|
|
|
218
|
-
**
|
|
308
|
+
**25. P12 — Tracker HEAD references stale (added v0.18.2).** The `**Last Updated:**` and `**Active Feature:**` lines may embed `HEAD <sha>` or `HEAD: <sha>` references that were correct when written but went stale as further commits landed (empirically observed in fx F-WEB-MENU-VISION-001 audit cycle 2026-05-06: tracker said `HEAD: fd752e4` while `git rev-parse HEAD` was `6fa801e` after the agent's own self-edit commit). Compare each extracted SHA against the active branch HEAD. Bidirectional prefix tolerance: a 7-char tracker SHA matches the full 40-char actual HEAD if it's a prefix; a full 40-char tracker SHA matches if its first 7 chars equal the actual short form. Scoped strictly to the two header lines so narrative SHAs in "Last Completed" prose never false-positive-fire.
|
|
219
309
|
```bash
|
|
220
310
|
TRACKER=docs/project_notes/product-tracker.md
|
|
221
311
|
if [ -f "$TRACKER" ]; then
|
|
@@ -235,7 +325,7 @@ if [ -f "$TRACKER" ]; then
|
|
|
235
325
|
fi
|
|
236
326
|
```
|
|
237
327
|
|
|
238
|
-
**
|
|
328
|
+
**26. P13 — key_facts delta vs ticket atom-count mismatch (added v0.18.3).** Whitespace-safe iteration + FEATURE_ID anchoring.
|
|
239
329
|
```bash
|
|
240
330
|
KEY_FACTS=docs/project_notes/key_facts.md
|
|
241
331
|
if [ -f "$KEY_FACTS" ]; then
|
|
@@ -251,7 +341,7 @@ if [ -f "$KEY_FACTS" ]; then
|
|
|
251
341
|
fi
|
|
252
342
|
```
|
|
253
343
|
|
|
254
|
-
**
|
|
344
|
+
**27. P14 — MCE Action 1 row stale post-merge (added v0.18.3).** Strict awk state machine terminates MCE block at NEXT `^## ` of any name (not `[^M]`). Strict signal `Step 6 [ ]` / `Step 6 [-]` only — standalone `(this merge)` omitted to prevent false positives on past-tense narrative. Reuses `TICKET_STATUS` from P11. NIT severity.
|
|
255
345
|
```bash
|
|
256
346
|
if [ "$TICKET_STATUS" = "Done" ]; then
|
|
257
347
|
MCE_BLOCK=$(awk '
|
|
@@ -265,7 +355,7 @@ if [ "$TICKET_STATUS" = "Done" ]; then
|
|
|
265
355
|
fi
|
|
266
356
|
```
|
|
267
357
|
|
|
268
|
-
**
|
|
358
|
+
**28. P15 — AC with post-deploy keyword admitted without Completion Log evidence (added v0.18.3).** Line-safe iteration via `while IFS= read -r`.
|
|
269
359
|
```bash
|
|
270
360
|
COMPLETION=$(awk '/^## Completion Log/,/^## Merge Checklist/' "$TICKET")
|
|
271
361
|
AC_LINES=$(grep -nE '^[[:space:]]*-[[:space:]]*\[[ x]\][[:space:]]+AC-[A-Za-z0-9_-]+' "$TICKET" \
|
|
@@ -281,7 +371,7 @@ while IFS= read -r line; do
|
|
|
281
371
|
done <<< "$AC_LINES"
|
|
282
372
|
```
|
|
283
373
|
|
|
284
|
-
**
|
|
374
|
+
**29. P16 — Feature missing from Features table (added v0.18.3).** Strict signal: feature ID must appear as first cell of a pipe-table row (`| FEATURE_ID |`) — narrative mentions / `**Active Feature:**` references must not silence the drift. NIT severity. Reuses `TICKET_STATUS` and `FEATURE_ID` from P11.
|
|
285
375
|
```bash
|
|
286
376
|
TRACKER=docs/project_notes/product-tracker.md
|
|
287
377
|
case "$TICKET_STATUS" in
|
|
@@ -295,9 +385,66 @@ case "$TICKET_STATUS" in
|
|
|
295
385
|
esac
|
|
296
386
|
```
|
|
297
387
|
|
|
388
|
+
**30. P17 — Auth-touching backend change requires bearer-flow integration test on non-/me route** (added v0.20.0). When the diff modifies a backend auth-adjacent module (`auth*`, `actorResolver*`, `bearer*`, `rateLimit*`), the diff should ALSO include or modify an integration test that exercises the bearer flow on a NON-`/me` route. Empirically double-confirmed: BUG-PROD-013 (actorResolver bearer-path 500 on `/conversation/*` — non-`/me`), BUG-API-RATELIMIT-BEARER-001 (rateLimit helpers tested only api-key + IP, no bearer-through-global-limiter integration coverage). The `/me`-itself integrity bug class (F107a-FU2) is a distinct pattern — opt-out annotation `P17 N/A: <reason ≥ 1 word>` is recognized for frontend-only auth changes or other edge cases. Advisory, never blocks merge.
|
|
389
|
+
```bash
|
|
390
|
+
# P17 — Auth-touching change requires bearer-flow integration test on non-/me route.
|
|
391
|
+
AUTH_TOUCHED=$(git diff --name-only "$BASE_REF...HEAD" 2>/dev/null | \
|
|
392
|
+
grep -iE '(auth|actorResolver|bearer|rateLimit)' | \
|
|
393
|
+
grep -E '^(packages/api|api|server|backend|src/server|src/api)/' | \
|
|
394
|
+
grep -vE '\.(test|spec)\.[jt]sx?$|__tests__/|/web/|/frontend/|/client/' | head -20)
|
|
395
|
+
|
|
396
|
+
if [ -z "$AUTH_TOUCHED" ]; then
|
|
397
|
+
echo "P17 N/A: no backend auth-adjacent files in diff"
|
|
398
|
+
else
|
|
399
|
+
TOUCHED_COUNT=$(printf '%s\n' "$AUTH_TOUCHED" | wc -l | tr -d ' ')
|
|
400
|
+
|
|
401
|
+
# Explicit opt-out (Gemini R1 M4 strengthened: require `: <reason ≥ 1 word>`)
|
|
402
|
+
OPTOUT=$(grep -E 'P17[[:space:]]+(N/A|opt[- ]?out|exempt)[[:space:]]*:[[:space:]]+[A-Za-z0-9].{2,}' "$TICKET" 2>/dev/null | head -1)
|
|
403
|
+
if [ -n "$OPTOUT" ]; then
|
|
404
|
+
echo "P17 N/A: explicit opt-out — $(printf '%s' "$OPTOUT" | head -c 120)"
|
|
405
|
+
else
|
|
406
|
+
INTEGRATION_TESTS=$(git diff --name-only "$BASE_REF...HEAD" 2>/dev/null | \
|
|
407
|
+
grep -iE '(integration|__tests__/.*\.integration\.|/integration/)' | \
|
|
408
|
+
grep -E '\.(test|spec)\.[jt]sx?$')
|
|
409
|
+
|
|
410
|
+
# Two extraction passes (Codex R2 I-1 multi-line fix + Gemini R2 I-1 backticks):
|
|
411
|
+
# Pass A: dot-method calls — `.get('/path')` / `.post(\`/path\`)` (single-line).
|
|
412
|
+
# Pass B: `url: '...'` property values within multi-line app.inject({ ... }).
|
|
413
|
+
BEARER_NON_ME_HITS=0
|
|
414
|
+
while IFS= read -r test_file; do
|
|
415
|
+
[ -z "$test_file" ] && continue
|
|
416
|
+
[ ! -f "$test_file" ] && continue
|
|
417
|
+
if ! grep -qiE '(bearer|authorization)' "$test_file" 2>/dev/null; then
|
|
418
|
+
continue
|
|
419
|
+
fi
|
|
420
|
+
ROUTES_A=$(grep -iE "\.(get|post|put|patch|delete)\([\`\"'](/[^\`\"']+)[\`\"']" "$test_file" 2>/dev/null | \
|
|
421
|
+
grep -oE "[\`\"'](/[^\`\"']+)[\`\"']" | sed -E "s/^[\`\"']|[\`\"']\$//g")
|
|
422
|
+
ROUTES_B=$(grep -iE "url[[:space:]]*:[[:space:]]*[\`\"'](/[^\`\"']+)[\`\"']" "$test_file" 2>/dev/null | \
|
|
423
|
+
grep -oE "[\`\"'](/[^\`\"']+)[\`\"']" | sed -E "s/^[\`\"']|[\`\"']\$//g")
|
|
424
|
+
ROUTE_STRINGS=$(printf '%s\n%s\n' "$ROUTES_A" "$ROUTES_B" | grep -vE '^$' | sort -u)
|
|
425
|
+
# Strip ${...} template-literal interpolations
|
|
426
|
+
ROUTE_STRINGS=$(printf '%s\n' "$ROUTE_STRINGS" | sed -E 's/\$\{[^}]*\}//g')
|
|
427
|
+
if [ -n "$ROUTE_STRINGS" ]; then
|
|
428
|
+
if printf '%s\n' "$ROUTE_STRINGS" | grep -qvE '^/me($|/)' ; then
|
|
429
|
+
BEARER_NON_ME_HITS=$((BEARER_NON_ME_HITS + 1))
|
|
430
|
+
fi
|
|
431
|
+
fi
|
|
432
|
+
done <<EOF
|
|
433
|
+
$INTEGRATION_TESTS
|
|
434
|
+
EOF
|
|
435
|
+
|
|
436
|
+
if [ "$BEARER_NON_ME_HITS" -eq 0 ]; then
|
|
437
|
+
flag "P17 drift (advisory): $TOUCHED_COUNT backend auth-adjacent file(s) but no integration test exercises bearer on a non-/me route (BUG-PROD-013 / BUG-RATELIMIT-BEARER pattern). Add an integration test or annotate \`P17 N/A: <reason>\` in the ticket."
|
|
438
|
+
else
|
|
439
|
+
echo "P17 PASS: $TOUCHED_COUNT auth-adjacent backend file(s), $BEARER_NON_ME_HITS integration test(s) cover bearer non-/me routes"
|
|
440
|
+
fi
|
|
441
|
+
fi
|
|
442
|
+
fi
|
|
443
|
+
```
|
|
444
|
+
|
|
298
445
|
### Execution discipline (added v0.18.1)
|
|
299
446
|
|
|
300
|
-
For each of the
|
|
447
|
+
For each of the 17 drift checks (P1–P17), if you declare PASS, **include the literal command output** (or its absence — explicit "no rows matched", "extracted: feature/foo", "FROZEN_COUNT=0") as evidence in your report. A bare "PASS" without supporting output is treated as **NOT EXECUTED** by the auditor — re-run with output captured.
|
|
301
448
|
|
|
302
449
|
Recommended pattern:
|
|
303
450
|
|
|
@@ -316,7 +463,7 @@ Report two tables — one for **structural (blocking)** compliance, one for **dr
|
|
|
316
463
|
```
|
|
317
464
|
## Merge Compliance Audit — [FEATURE-ID]
|
|
318
465
|
|
|
319
|
-
### Structural (1-
|
|
466
|
+
### Structural (1-13) — blocking merge gate
|
|
320
467
|
|
|
321
468
|
| # | Check | Status | Detail |
|
|
322
469
|
|---|-------|:------:|--------|
|
|
@@ -324,46 +471,69 @@ Report two tables — one for **structural (blocking)** compliance, one for **dr
|
|
|
324
471
|
| 2 | Acceptance Criteria | PASS | 14/14 |
|
|
325
472
|
| 3 | Definition of Done | PASS | 7/7 |
|
|
326
473
|
| 4 | Workflow Checklist | PASS | 7/8 (Step 6 pending) |
|
|
327
|
-
| 5 | Merge Checklist Evidence | PASS |
|
|
474
|
+
| 5 | Merge Checklist Evidence | PASS | 9/9 with evidence |
|
|
328
475
|
| 6 | Completion Log | PASS | 5 entries, bugs documented |
|
|
329
476
|
| 7 | Tracker Sync | PASS | Active Session + Features table correct |
|
|
330
477
|
| 8 | key_facts.md | PASS | N/A — no new infrastructure |
|
|
331
478
|
| 9 | Merge Base | PASS | Up to date with develop |
|
|
332
479
|
| 10 | Working Tree | PASS | Clean |
|
|
333
480
|
| 11 | Data Files | PASS | N/A — no JSON seed files |
|
|
481
|
+
| 12 | CI State | PASS | PR #123 — all checks pass or pending |
|
|
482
|
+
| 13 | MCE Action 9 (D1) | PASS | ## Audit Merge Output section pasted (~3200 chars) |
|
|
334
483
|
|
|
335
484
|
**STRUCTURAL: READY FOR MERGE** (or **STRUCTURAL: NEEDS FIX — N blockers**)
|
|
336
485
|
|
|
337
|
-
### Drift (
|
|
486
|
+
### Drift (14-30) — advisory, refresh before user authorization
|
|
338
487
|
|
|
339
488
|
| # | Pattern | Status | Detail |
|
|
340
489
|
|---|---------|:------:|--------|
|
|
341
|
-
|
|
|
342
|
-
|
|
|
343
|
-
|
|
|
344
|
-
|
|
|
345
|
-
|
|
|
346
|
-
|
|
|
347
|
-
|
|
|
348
|
-
|
|
|
349
|
-
|
|
|
350
|
-
|
|
|
351
|
-
|
|
|
352
|
-
|
|
|
353
|
-
|
|
|
354
|
-
|
|
|
355
|
-
|
|
|
356
|
-
|
|
|
490
|
+
| 14 | P1 PR body test count stale | PASS | matches ticket terminal |
|
|
491
|
+
| 15 | P2 Aspirational Evidence rows | PASS | all past-tense |
|
|
492
|
+
| 16 | P3 Post-merge actions logged | PASS | N/A pre-merge |
|
|
493
|
+
| 17 | P4 Remote branch orphan | PASS | not checked pre-merge |
|
|
494
|
+
| 18 | P5 Frozen ticket Status | PASS | 0 frozen |
|
|
495
|
+
| 19 | P6 AC count off-by-N | PASS | claim matches actual (form: header) |
|
|
496
|
+
| 20 | P7 Intra-ticket test drift | PASS | final = terminal |
|
|
497
|
+
| 21 | P8 Completion Log gap | PASS | every [x] step has narrative |
|
|
498
|
+
| 22 | P9 Tracker header stale | PASS | header = detail |
|
|
499
|
+
| 23 | P10 Duplicate log rows | PASS | no duplicates |
|
|
500
|
+
| 24 | P11 Tracker status mismatch | PASS | status consistent |
|
|
501
|
+
| 25 | P12 Tracker HEAD reference | PASS | tracker HEAD = git HEAD |
|
|
502
|
+
| 26 | P13 key_facts delta mismatch | PASS | N/A — no quantified deltas |
|
|
503
|
+
| 27 | P14 MCE Action 1 stale post-merge | PASS | N/A pre-merge / row past-tense |
|
|
504
|
+
| 28 | P15 Post-deploy AC without evidence | PASS | no post-deploy keyword in ACs |
|
|
505
|
+
| 29 | P16 Feature missing from tracker | PASS | feature in Features table |
|
|
506
|
+
| 30 | P17 Auth integration coverage | PASS | 2 backend file(s), 1 integration test covers bearer non-/me |
|
|
357
507
|
|
|
358
508
|
**DRIFT: CLEAN** (or **DRIFT: N advisories — refresh before merge**)
|
|
359
509
|
|
|
360
510
|
### Combined verdict
|
|
361
511
|
|
|
362
|
-
- Both PASS → **READY FOR MERGE**
|
|
512
|
+
- Both PASS → **READY FOR MERGE** (compliance 13/13, drift clean)
|
|
363
513
|
- Structural fail → **NEEDS FIX — N blockers**
|
|
364
514
|
- Structural pass + drift advisories → **READY FOR MERGE PENDING DRIFT CLEANUP — N advisories**
|
|
365
515
|
```
|
|
366
516
|
|
|
517
|
+
**Recipe-output verbatim rule** (added v0.19.0): When filling Detail columns of either the structural or drift tables, use the **literal output of the corresponding recipe** — do not normalize, summarize, or smooth values. Specifically:
|
|
518
|
+
- Numeric ratios (`N/M`): preserve as emitted. `18/19` MUST NOT become `18/18` even when N < M.
|
|
519
|
+
- MCE row 1 claim text: when a check (e.g. P6) references it in its Detail message, quote it verbatim including parentheticals such as `(AC19 deploy-deferred)` or `(operator action pending)`. Do not strip qualifiers.
|
|
520
|
+
- "Form" annotations (e.g. P6 emits `(form: header)` or `(form: checkbox)`): preserve them so the reader can tell which AC form the ticket used.
|
|
521
|
+
- `N/A` reasons: quote the literal reason emitted by the recipe (`no PR open`, `gh CLI unavailable`, `jq unavailable`, `not checked pre-merge`).
|
|
522
|
+
|
|
523
|
+
This rule exists because an LLM auditor, given header-form tickets where checkbox count is 0, will hallucinate `18/18` to "agree" with the MCE row 1 claim. The recipe says `0` and the MCE says `18/19`; the audit Detail must reflect both honestly so the reader can spot the form mismatch.
|
|
524
|
+
|
|
525
|
+
**Audit Output Self-Verification Guarantee** (added v0.20.0, required by D1): after emitting all structural rows + drift rows + combined verdict, ALWAYS append a final single-line summary in this exact form, regardless of pass/fail:
|
|
526
|
+
|
|
527
|
+
```
|
|
528
|
+
Structural: <passed>/<total> PASS | Drift: <flagged> advisory | Verdict: <APPROVE|REVISE>
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
Examples:
|
|
532
|
+
- `Structural: 13/13 PASS | Drift: 0 advisory | Verdict: APPROVE`
|
|
533
|
+
- `Structural: 11/13 PASS | Drift: 4 advisory | Verdict: REVISE`
|
|
534
|
+
|
|
535
|
+
This line is the canonical compliance signal that `D1` (MCE Action 9 present, line 92) parses. Without it, a verbatim paste of legitimate audit output may fail D1's signal check. The line must always be the last non-empty line in the output.
|
|
536
|
+
|
|
367
537
|
### If issues are found
|
|
368
538
|
|
|
369
539
|
Fix them directly:
|
|
@@ -372,8 +542,9 @@ Fix them directly:
|
|
|
372
542
|
- Tracker stale → update Active Session and Features table
|
|
373
543
|
- Merge base diverged → `git merge origin/<target-branch>` and resolve conflicts
|
|
374
544
|
- Data file issues → fix the data
|
|
545
|
+
- CI failures (C3) → re-run failed jobs after addressing root cause; do NOT merge while `ci-success` is BLOCKED
|
|
375
546
|
|
|
376
|
-
**Drift advisories (
|
|
547
|
+
**Drift advisories (13-28) fixes:**
|
|
377
548
|
- **P1** → edit PR body npm test line to match ticket terminal count
|
|
378
549
|
- **P2** → rewrite `[x]` rows with past-tense + commit SHA
|
|
379
550
|
- **P3** → add Completion Log row for each post-merge execution
|
|
@@ -65,12 +65,14 @@ Determine the target branch from `docs/project_notes/key_facts.md` → `branchin
|
|
|
65
65
|
|
|
66
66
|
## Action 8: Fill Merge Checklist Evidence
|
|
67
67
|
|
|
68
|
-
In the ticket, fill the `## Merge Checklist Evidence` table. For each action (0–7), mark `[x]` and write the actual evidence (not placeholders). Example:
|
|
68
|
+
In the ticket, fill the `## Merge Checklist Evidence` table. For each action (0–7), mark `[x]` and write the actual evidence (not placeholders). Then complete Action 9 below — it MUST appear as the 9th row of the same table. Example:
|
|
69
69
|
|
|
70
70
|
| Action | Done | Evidence |
|
|
71
71
|
|--------|:----:|----------|
|
|
72
72
|
| 0. Validate ticket structure | [x] | Sections verified: Spec, Plan, AC, DoD, Workflow, Log, Evidence |
|
|
73
73
|
| 1. Mark all items | [x] | AC: 12/12, DoD: 7/7, Workflow: 0-5/6 |
|
|
74
|
+
| ... (rows 2-7 follow same shape) | [x] | ... |
|
|
75
|
+
| 9. Run `/audit-merge` | [x] | See § "Audit Merge Output" below |
|
|
74
76
|
|
|
75
77
|
**Canonical form for the AC count claim:** write `AC: <marked>/<total>` — `marked` is the count of `[x]` Acceptance Criteria, `total` is the count of all AC items including any intentionally deferred `[ ]`. When all are checked use the matching form `AC: N/N` (or the shorthand `all N marked`). The `/audit-merge` P6 drift check parses both forms.
|
|
76
78
|
|
|
@@ -82,11 +84,30 @@ In the ticket, fill the `## Merge Checklist Evidence` table. For each action (0
|
|
|
82
84
|
|
|
83
85
|
Sub-scope tickets reach `Status: Done` independently while the parent feature's tracker row stays at its parent status (typically `pending` or `in-progress`) until ALL sub-scopes close. `/audit-merge` P11 detects the suffix and emits `P11 N/A` instead of flagging the parent/sub-scope status divergence as drift.
|
|
84
86
|
|
|
85
|
-
## Action 9: Run compliance audit
|
|
87
|
+
## Action 9: Run compliance audit (MANDATORY, added v0.20.0 as structural MCE row)
|
|
86
88
|
|
|
87
|
-
Run `/audit-merge`
|
|
89
|
+
**Action 9 is MANDATORY.** Run `/audit-merge` after Actions 0-8 are complete. Paste the FULL verbatim output (structural + drift tables + verdict + self-verification line `Structural: N/N PASS | Drift: K advisory | Verdict: X`) into the dedicated `## Audit Merge Output` section of the ticket, directly below the MCE table.
|
|
88
90
|
|
|
89
|
-
|
|
91
|
+
Do NOT abbreviate, summarize, or omit failing rows. If `/audit-merge` flags any STRUCTURAL check as FAIL, fix it and re-run until ALL structural checks PASS. Drift advisories may stay open with explanation in the surrounding ticket.
|
|
92
|
+
|
|
93
|
+
The ticket structure for Action 9 (added v0.20.0):
|
|
94
|
+
|
|
95
|
+
```markdown
|
|
96
|
+
## Merge Checklist Evidence
|
|
97
|
+
|
|
98
|
+
| Action | Done | Evidence |
|
|
99
|
+
|--------|:----:|----------|
|
|
100
|
+
| 0. … | [x] | … |
|
|
101
|
+
| 1. … | [x] | … |
|
|
102
|
+
| ... (rows 2-7) | [x] | … |
|
|
103
|
+
| 9. Run `/audit-merge` | [x] | See § "Audit Merge Output" below |
|
|
104
|
+
|
|
105
|
+
## Audit Merge Output
|
|
106
|
+
|
|
107
|
+
<verbatim /audit-merge output goes here — see ticket-template.md>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The `/audit-merge` structural check `D1` (added v0.20.0) verifies row 9 exists with `[x]` AND the `## Audit Merge Output` section has non-empty body with a structural-compliance signal. Skipping this Action is now structurally visible (row 9 stays unfilled if you forget).
|
|
90
111
|
|
|
91
112
|
## Action 10: Request merge approval
|
|
92
113
|
|
|
@@ -102,6 +102,18 @@ This creates a feedback loop for improving future reviews. -->
|
|
|
102
102
|
| 5. Commit documentation | [ ] | Commit: (hash) |
|
|
103
103
|
| 6. Verify clean working tree | [ ] | `git status`: clean |
|
|
104
104
|
| 7. Verify branch up to date | [ ] | merge-base: up to date / merged origin/<branch> |
|
|
105
|
+
| 9. Run `/audit-merge` | [ ] | See § "Audit Merge Output" below |
|
|
106
|
+
|
|
107
|
+
## Audit Merge Output
|
|
108
|
+
|
|
109
|
+
> Paste the FULL verbatim output of `/audit-merge` below. The block must include both tables
|
|
110
|
+
> (structural + drift), all rows, the combined verdict, AND the final self-verification line
|
|
111
|
+
> in the form `Structural: N/N PASS | Drift: K advisory | Verdict: <APPROVE|REVISE>`. Do NOT
|
|
112
|
+
> abbreviate, summarize, or omit failing rows. Required for the D1 structural check to PASS.
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
<paste /audit-merge output here>
|
|
116
|
+
```
|
|
105
117
|
|
|
106
118
|
---
|
|
107
119
|
|