@chief-clancy/plan 0.4.0 → 0.4.2
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 +4 -2
- package/package.json +1 -1
- package/src/commands/approve-plan.md +1 -1
- package/src/workflows/approve-plan.md +15 -8
- package/src/workflows/plan.md +30 -19
- package/src/workflows/workflows.test.ts +77 -10
package/README.md
CHANGED
|
@@ -101,9 +101,11 @@ sha256=d2c9f3a1b4e6c8f09123456789abcdef0123456789abcdef0123456789abcd
|
|
|
101
101
|
approved_at=2026-04-08T22:30:00Z
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
The full 64-character hex hash is what `.approved` actually stores —
|
|
104
|
+
The full 64-character hex hash is what `.approved` actually stores — any plan-implementing tool reads the marker, hashes the current plan file the same way, and blocks implementation on any mismatch.
|
|
105
105
|
|
|
106
|
-
The marker is the gate
|
|
106
|
+
The marker is the gate plan-implementing tools check before applying changes — if the plan file is edited after approval, the SHA mismatch blocks implementation until you re-approve. A dedicated `/clancy:implement-from` slash command was originally scoped for the plan package but is **deferred** until `@chief-clancy/dev` is extracted (the slash command is convenience, not capability — Claude Code can already do the SHA gate + structured plan parse via natural-language instruction). In the meantime, you can apply approved plans by asking Claude Code directly — for example: `Implement .clancy/plans/add-dark-mode-2.md, verifying the .approved marker's sha256 first` — or by installing the full Clancy pipeline (`npx chief-clancy`) for the board-driven flow.
|
|
107
|
+
|
|
108
|
+
Clancy also tries to update the brief file's `<!-- planned:1,2 -->` marker to `<!-- approved:1 planned:1,2 -->` so `/clancy:plan --list` knows which rows are approved, but that brief-marker update is best-effort and may warn-and-skip if the expected brief metadata or matching marker is missing.
|
|
107
109
|
|
|
108
110
|
### Standalone+board (board credentials but no full pipeline)
|
|
109
111
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Approve a Clancy implementation plan. Behaviour depends on the install context and the argument:
|
|
4
4
|
|
|
5
|
-
- **Local plan file:** `/clancy:approve-plan add-dark-mode-2` — write a `.clancy/plans/{stem}.approved` marker (with the plan's SHA-256 + approval timestamp) and update the source brief's row marker. The marker is the gate `/clancy:implement-from`
|
|
5
|
+
- **Local plan file:** `/clancy:approve-plan add-dark-mode-2` — write a `.clancy/plans/{stem}.approved` marker (with the plan's SHA-256 + approval timestamp) and update the source brief's row marker. The marker is the gate any plan-implementing tool checks before applying changes (a dedicated `/clancy:implement-from` slash command is deferred until `@chief-clancy/dev` is extracted)
|
|
6
6
|
- **Board ticket:** `/clancy:approve-plan PROJ-123` — promote an approved plan from a ticket comment to the ticket description, edit the plan comment with an approval note, swap the ticket labels (`CLANCY_LABEL_PLAN` → `CLANCY_LABEL_BUILD`, both with sensible defaults), and — only if `CLANCY_STATUS_PLANNED` is configured — transition the ticket status. Requires board credentials. Runs in both standalone+board and terminal modes (the full pipeline is not required for the board transport flow itself; it is only required for downstream `/clancy:implement` to consume the result)
|
|
7
7
|
- **No argument:** auto-select the oldest unapproved plan. In standalone mode this scans `.clancy/plans/`; in standalone+board / terminal mode it scans `.clancy/progress.txt` for board tickets
|
|
8
8
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Approve a Clancy implementation plan. Behaviour depends on the install context:
|
|
6
6
|
|
|
7
|
-
- **Standalone mode** (no `.clancy/.env`): write a local `.clancy/plans/{stem}.approved` marker file with the plan's SHA-256 and approval timestamp. The marker is the gate `/clancy:implement-from`
|
|
7
|
+
- **Standalone mode** (no `.clancy/.env`): write a local `.clancy/plans/{stem}.approved` marker file with the plan's SHA-256 and approval timestamp. The marker is the gate any plan-implementing tool checks before applying changes (a dedicated `/clancy:implement-from` slash command is deferred until `@chief-clancy/dev` is extracted; users in the meantime ask Claude Code to apply the plan via natural-language instruction or install the full pipeline)
|
|
8
8
|
- **Standalone+board mode** (`.clancy/.env` present, no full pipeline): with a board ticket key, run the existing comment-to-description transport flow; with a plan-file stem, write the local marker (board push lands in PR 9)
|
|
9
9
|
- **Terminal mode** (full pipeline installed): existing behaviour — promote an approved plan from a ticket comment to the ticket description and transition the ticket to the implementation queue
|
|
10
10
|
|
|
@@ -360,7 +360,7 @@ After confirmation in plan-file stem mode, jump to Step 4a (local marker write).
|
|
|
360
360
|
|
|
361
361
|
## Step 4a — Write local marker
|
|
362
362
|
|
|
363
|
-
Run this step instead of Steps 5, 5b, 6 when the resolved argument was a plan-file stem (standalone mode, or standalone+board / terminal mode where Step 2 found a matching plan file). Write a `.clancy/plans/{stem}.approved` marker that gates
|
|
363
|
+
Run this step instead of Steps 5, 5b, 6 when the resolved argument was a plan-file stem (standalone mode, or standalone+board / terminal mode where Step 2 found a matching plan file). Write a `.clancy/plans/{stem}.approved` marker that gates plan implementation (see "Marker is the gate for future implementation tooling" below for the deferral context).
|
|
364
364
|
|
|
365
365
|
### Compute the SHA-256
|
|
366
366
|
|
|
@@ -370,7 +370,7 @@ Run this step instead of Steps 5, 5b, 6 when the resolved argument was a plan-fi
|
|
|
370
370
|
2. Compute the SHA-256 hash of those bytes — no normalisation (no line-ending fix, no trailing-whitespace strip, no BOM removal). Hex-encode lowercase.
|
|
371
371
|
3. **Then** (only after the hash is computed) open the `.approved` marker for exclusive create as described below.
|
|
372
372
|
|
|
373
|
-
The `.approved` file is **never** included in the hash — only `.clancy/plans/{stem}.md` is hashed, and only its on-disk byte content at the moment of step 1.
|
|
373
|
+
The `.approved` file is **never** included in the hash — only `.clancy/plans/{stem}.md` is hashed, and only its on-disk byte content at the moment of step 1. The marker is designed so a future implementer (deferred to `@chief-clancy/dev`) can re-read the same plan file, hash it the same way, and compare to the `sha256=` value stored in the marker. Until that consumer ships, the gate is enforced manually: a user (or Claude Code via natural-language instruction) reads the marker, hashes the plan file, and refuses to apply the plan on mismatch. Any divergence (re-edit, line-ending change, trailing whitespace tweak) is detectable.
|
|
374
374
|
|
|
375
375
|
### Write the marker file with O_EXCL
|
|
376
376
|
|
|
@@ -381,7 +381,7 @@ sha256={hex sha256 of the plan file at approval time}
|
|
|
381
381
|
approved_at={ISO 8601 UTC timestamp, e.g. 2026-04-08T22:30:00Z}
|
|
382
382
|
```
|
|
383
383
|
|
|
384
|
-
Two `key=value` lines, each terminated with `\n`. No JSON, no extra whitespace, no comments.
|
|
384
|
+
Two `key=value` lines, each terminated with `\n`. No JSON, no extra whitespace, no comments. A future implementer (deferred to `@chief-clancy/dev`) will parse this with a tolerant `^(sha256|approved_at)=(.+)$` regex per line. Until that consumer ships, the format is also human-readable for ad-hoc verification.
|
|
385
385
|
|
|
386
386
|
### Handle EEXIST (already-approved)
|
|
387
387
|
|
|
@@ -397,9 +397,14 @@ To re-approve (e.g. after revising the plan):
|
|
|
397
397
|
|
|
398
398
|
A `--fresh` flag for `/clancy:approve-plan` is not implemented in this release. Manual deletion is the supported re-approval path.
|
|
399
399
|
|
|
400
|
-
### Marker is the gate for
|
|
400
|
+
### Marker is the gate for future implementation tooling
|
|
401
401
|
|
|
402
|
-
The `.approved` marker is the gate
|
|
402
|
+
The `.approved` marker is designed as the gate that any plan-implementing tool checks before applying changes. The conceptual flow: read the marker, hash the current plan file, compare to the stored `sha256`. Match → proceed; mismatch → block with a "plan changed since approval" error. This is why the SHA must be computed over the plan file content (not just touched as an empty file).
|
|
403
|
+
|
|
404
|
+
A dedicated `/clancy:implement-from` slash command is **deferred** until `@chief-clancy/dev` is extracted (the slash command is convenience, not capability — Claude Code can already do the SHA gate + structured plan parse via natural-language instruction). In the meantime, users apply approved plans by:
|
|
405
|
+
|
|
406
|
+
1. Asking Claude Code to read the plan file directly: `Implement .clancy/plans/{stem}.md, verifying the .approved marker's sha256 first`
|
|
407
|
+
2. Installing the full Clancy pipeline (`npx chief-clancy`) for the board-driven flow
|
|
403
408
|
|
|
404
409
|
### After writing the marker
|
|
405
410
|
|
|
@@ -1164,7 +1169,9 @@ Clancy — Approve Plan (local)
|
|
|
1164
1169
|
Marker: .clancy/plans/{stem}.approved
|
|
1165
1170
|
sha256: {first 12 hex chars}…
|
|
1166
1171
|
|
|
1167
|
-
Next:
|
|
1172
|
+
Next:
|
|
1173
|
+
• Ask Claude Code: "Implement .clancy/plans/{stem}.md (verify the .approved marker's sha256 first)"
|
|
1174
|
+
• Or run `npx chief-clancy` for the full board-driven pipeline
|
|
1168
1175
|
|
|
1169
1176
|
"Book 'em, Lou."
|
|
1170
1177
|
```
|
|
@@ -1183,7 +1190,7 @@ Append to `.clancy/progress.txt`:
|
|
|
1183
1190
|
YYYY-MM-DD HH:MM | {stem} | LOCAL_APPROVE_PLAN | sha256={first 12 hex}
|
|
1184
1191
|
```
|
|
1185
1192
|
|
|
1186
|
-
The `LOCAL_APPROVE_PLAN` token mirrors the `LOCAL_PLAN` / `LOCAL_REVISED` convention used by `/clancy:plan --from` (see [`plan.md` Step 6](./plan.md)).
|
|
1193
|
+
The `LOCAL_APPROVE_PLAN` token mirrors the `LOCAL_PLAN` / `LOCAL_REVISED` convention used by `/clancy:plan --from` (see [`plan.md` Step 6](./plan.md)). The token is for human audit only — any future plan-implementing tool reads the `.clancy/plans/{stem}.approved` marker directly rather than scanning `progress.txt` for approval state.
|
|
1187
1194
|
|
|
1188
1195
|
---
|
|
1189
1196
|
|
package/src/workflows/plan.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
Fetch backlog tickets from the board, explore the codebase, and generate structured implementation plans. In board mode, plans are posted as comments on the ticket for human review. With `--from`, plans from local brief files are saved to `.clancy/plans/`, with an optional board comment when credentials are available. Does not implement anything — planning only.
|
|
5
|
+
Fetch backlog tickets from the board, explore the codebase, and generate structured implementation plans. In board mode, plans are posted as comments on the ticket for human review. With `--from`, plans from local brief files are saved to `.clancy/plans/`, with an optional board comment when credentials are available. Does not implement anything — planning only. Use `/clancy:approve-plan` to approve plans in any install mode — it ships with this package, writes a local `.approved` marker for plan-file stems, and runs the board transport flow for ticket keys only when board credentials are available.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -24,7 +24,7 @@ Check for `.clancy/.env`:
|
|
|
24
24
|
If `.clancy/.env` is present, check for `.clancy/clancy-implement.js`:
|
|
25
25
|
|
|
26
26
|
- **Present** → **terminal mode**. Full Clancy pipeline installed.
|
|
27
|
-
- **Absent** → **standalone+board mode**. Board credentials available via `/clancy:board-setup`. Board ticket mode works. Step 5 works.
|
|
27
|
+
- **Absent** → **standalone+board mode**. Board credentials available via `/clancy:board-setup`. Board ticket mode works. Step 5 works. `/clancy:approve-plan` also works in this mode — it ships with the plan package and runs the board transport flow for ticket keys or writes a local `.approved` marker for plan-file stems.
|
|
28
28
|
|
|
29
29
|
### 2. Terminal-mode preflight (skip in standalone mode and standalone+board mode)
|
|
30
30
|
|
|
@@ -822,7 +822,7 @@ Write the plan in this exact template:
|
|
|
822
822
|
|
|
823
823
|
---
|
|
824
824
|
|
|
825
|
-
_Generated by [Clancy](https://github.com/Pushedskydiver/chief-clancy). To request changes: comment on this ticket, then re-run `/clancy:plan` to revise. To start over: `/clancy:plan --fresh`. To approve: `/clancy:approve-plan {KEY}
|
|
825
|
+
_Generated by [Clancy](https://github.com/Pushedskydiver/chief-clancy). To request changes: comment on this ticket, then re-run `/clancy:plan` to revise. To start over: `/clancy:plan --fresh`. To approve: `/clancy:approve-plan {KEY}`._
|
|
826
826
|
```
|
|
827
827
|
|
|
828
828
|
**If re-planning with feedback**, prepend a section before Summary:
|
|
@@ -885,7 +885,7 @@ Replace the `**Ticket:** [{KEY}] {Title}` line from the board template with `**S
|
|
|
885
885
|
**Local plan footer:** Replace the board-specific footer with:
|
|
886
886
|
|
|
887
887
|
```
|
|
888
|
-
_Generated by [Clancy](https://github.com/Pushedskydiver/chief-clancy). To request changes: add a ## Feedback section to this file, then re-run `/clancy:plan --from {path}` to revise. To start over: `/clancy:plan --fresh --from {path}`. To approve:
|
|
888
|
+
_Generated by [Clancy](https://github.com/Pushedskydiver/chief-clancy). To request changes: add a ## Feedback section to this file, then re-run `/clancy:plan --from {path}` to revise. To start over: `/clancy:plan --fresh --from {path}`. To approve: `/clancy:approve-plan {plan-id}`._
|
|
889
889
|
```
|
|
890
890
|
|
|
891
891
|
**Re-planning:** If `--fresh` was used, the existing plan file is overwritten (same slug + row number = same filename).
|
|
@@ -1052,8 +1052,7 @@ Planned {N} ticket(s):
|
|
|
1052
1052
|
⏭️ [{KEY4}] {Title} — not a codebase change
|
|
1053
1053
|
|
|
1054
1054
|
Plans written to your board. After review:
|
|
1055
|
-
|
|
1056
|
-
Standalone: install the full pipeline — npx chief-clancy
|
|
1055
|
+
/clancy:approve-plan {KEY}
|
|
1057
1056
|
|
|
1058
1057
|
"Let me dust this for prints..."
|
|
1059
1058
|
```
|
|
@@ -1068,7 +1067,7 @@ Single row:
|
|
|
1068
1067
|
|
|
1069
1068
|
✅ Saved to .clancy/plans/{slug}-{row-number}.md
|
|
1070
1069
|
|
|
1071
|
-
To approve:
|
|
1070
|
+
To approve: /clancy:approve-plan {slug}-{row-number}
|
|
1072
1071
|
|
|
1073
1072
|
"Let me dust this for prints..."
|
|
1074
1073
|
```
|
|
@@ -1083,7 +1082,7 @@ Multi-row (`--afk`):
|
|
|
1083
1082
|
✅ Row 2: {title} — Saved to .clancy/plans/{slug}-2.md
|
|
1084
1083
|
⏭️ Row 3: {title} — already planned
|
|
1085
1084
|
|
|
1086
|
-
To approve:
|
|
1085
|
+
To approve: /clancy:approve-plan {slug}-{row-number} (or use /clancy:plan --list to see all plans)
|
|
1087
1086
|
|
|
1088
1087
|
"Let me dust this for prints..."
|
|
1089
1088
|
```
|
|
@@ -1101,35 +1100,47 @@ Scan `.clancy/plans/` for all `.md` files. For each file, parse the local plan h
|
|
|
1101
1100
|
- **Row** — value of the `**Row:**` line (e.g. `#2 — Add toggle component`). Display `?` if absent or empty.
|
|
1102
1101
|
- **Source** — value of the `**Source:**` line (the brief's Source field). Display `?` if absent or empty.
|
|
1103
1102
|
- **Planned** — value of the `**Planned:**` line (the YYYY-MM-DD planned date). Display `?` if absent or unparseable as a date.
|
|
1104
|
-
- **Status** —
|
|
1103
|
+
- **Status** — derived live from the sibling `.approved` marker written by `/clancy:approve-plan` (PR 7b). The reader is filesystem-only — no `.clancy/.env` or board access required. For each plan file, follow this procedure (every numbered step either branches to a verdict or feeds the next step):
|
|
1104
|
+
1. Check whether `.clancy/plans/{plan-id}.approved` exists. If marker absent → `Planned` (verdict)
|
|
1105
|
+
2. Marker exists. Read and validate its `sha256=` line (the marker body is two `key=value` lines: `sha256={hex}` and `approved_at={ISO 8601}`) AND hash the current plan file's bytes the same way `/clancy:approve-plan` Step 4a does (lowercase hex SHA-256, no normalisation, no line-ending fix)
|
|
1106
|
+
3. If the marker exists but is malformed, missing its `sha256=` line, has a non-hex or wrong-length `sha256` value, or otherwise cannot be parsed deterministically → `Stale (re-approve)` (verdict). Print a hint after the table: `Marker .clancy/plans/{plan-id}.approved is malformed. Delete it and re-run /clancy:approve-plan {plan-id} to recreate.` Folding this into `Stale` (rather than inventing a new state) keeps the inventory deterministic — the user's remediation is the same as for a hash drift: delete the marker and re-approve
|
|
1107
|
+
4. If the marker's valid `sha256` matches the current plan file's hash → `Approved` (verdict)
|
|
1108
|
+
5. If the marker exists and its valid `sha256` differs from the current hash → `Stale (re-approve)` (verdict) — the plan file was edited after approval. Any future plan-implementing tool will refuse to run against a stale plan until it is re-approved
|
|
1109
|
+
|
|
1110
|
+
A future `Implemented` state — derived from `LOCAL_IMPLEMENT` entries in `.clancy/progress.txt` — will land alongside the dedicated plan-implementing tool (deferred to `@chief-clancy/dev`). Today the inventory shows three states (`Planned`, `Approved`, `Stale (re-approve)`), with malformed `.approved` markers folded into `Stale (re-approve)`; the table format is stable so the future addition will be a one-line extension.
|
|
1105
1111
|
|
|
1106
1112
|
A field is considered missing if the line is absent or its value is empty after the colon. Plans missing all expected fields are still listed (with `?` placeholders) so the user can find and clean them up.
|
|
1107
1113
|
|
|
1108
1114
|
**Sort:** by `**Planned**` date, newest first. Tie-break on same date by Plan ID, alphabetical ascending. Files with a missing or unparseable date sort last (after all dated plans), and tie-break among themselves by Plan ID alphabetical ascending. The sort must be deterministic across runs.
|
|
1109
1115
|
|
|
1110
|
-
|
|
1116
|
+
**Summary line:** after the table, print one line in the format `{N} local plan(s). {A} approved, {S} stale, {P} planned.` where the counts match the rows above. Omit zero-count states for brevity (e.g. `3 local plan(s). 2 approved, 1 planned.` if no plans are stale). A `Stale (re-approve)` row means the plan file was edited after approval — re-running `/clancy:approve-plan {plan-id}` (after deleting the existing marker) will refresh the SHA.
|
|
1117
|
+
|
|
1118
|
+
Display the inventory as a pipe-delimited table so each Status value is unambiguous to scan and parse:
|
|
1111
1119
|
|
|
1112
1120
|
```
|
|
1113
1121
|
Clancy — Plans
|
|
1114
1122
|
================================================================
|
|
1115
1123
|
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1124
|
+
| # | Plan ID | Planned | Status | Row | Brief | Source |
|
|
1125
|
+
|---|--------------------|------------|---------------------|----------------------------------|------------------------------------|-----------|
|
|
1126
|
+
| 1 | add-dark-mode-2 | 2026-04-08 | Approved | #2 — Add toggle component | 2026-04-01-add-dark-mode.md | #50 |
|
|
1127
|
+
| 2 | add-dark-mode-1 | 2026-04-07 | Stale (re-approve) | #1 — Wire theme context | 2026-04-01-add-dark-mode.md | #50 |
|
|
1128
|
+
| 3 | customer-portal-3 | 2026-04-05 | Planned | #3 — Billing page | 2026-03-28-customer-portal.md | PROJ-200 |
|
|
1119
1129
|
|
|
1120
|
-
3 local plan(s).
|
|
1130
|
+
3 local plan(s). 1 approved, 1 stale, 1 planned.
|
|
1121
1131
|
|
|
1122
|
-
To
|
|
1123
|
-
To
|
|
1124
|
-
To
|
|
1132
|
+
To approve a plan: /clancy:approve-plan {plan-id}
|
|
1133
|
+
To re-approve a stale plan: delete .clancy/plans/{plan-id}.approved, then /clancy:approve-plan {plan-id}
|
|
1134
|
+
To revise: add a `## Feedback` section to the plan file, then re-run /clancy:plan --from {brief}
|
|
1135
|
+
To start over: /clancy:plan --fresh --from {brief}
|
|
1125
1136
|
```
|
|
1126
1137
|
|
|
1127
|
-
The first column
|
|
1138
|
+
The first column (after `#`) is the Plan ID (filename without `.md`), not the brief slug. Pipe-table format is intentional — Status values like `Stale (re-approve)` contain spaces, and a column-aligned space-delimited layout would make them ambiguous to read.
|
|
1128
1139
|
|
|
1129
1140
|
If `.clancy/plans/` does not exist or contains no `.md` files:
|
|
1130
1141
|
|
|
1131
1142
|
```
|
|
1132
|
-
No plans found. Run /clancy:plan --from .clancy/briefs
|
|
1143
|
+
No plans found. Run /clancy:plan --from .clancy/briefs/{brief}.md to create one.
|
|
1133
1144
|
```
|
|
1134
1145
|
|
|
1135
1146
|
Stop after display. The `--list` step never logs to `.clancy/progress.txt` and never modifies any file — it is purely a read-only inventory view of the local plans directory.
|
|
@@ -595,13 +595,77 @@ describe('plan inventory step', () => {
|
|
|
595
595
|
expect(content).toContain(
|
|
596
596
|
'**Plan ID** — the plan filename minus the `.md` extension',
|
|
597
597
|
);
|
|
598
|
-
expect(content).toContain('first column
|
|
598
|
+
expect(content).toContain('first column (after `#`) is the Plan ID');
|
|
599
599
|
});
|
|
600
600
|
|
|
601
|
-
it('
|
|
601
|
+
it('Status column reads sibling .approved marker for live state', () => {
|
|
602
602
|
expect(content).toContain('**Status**');
|
|
603
|
-
expect(content).toContain('
|
|
604
|
-
|
|
603
|
+
expect(content).toContain('sibling `.approved` marker');
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
it('Status is Planned when no marker exists', () => {
|
|
607
|
+
expect(content).toContain('marker absent → `Planned`');
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
it('Status is Approved when marker sha256 matches the current plan file', () => {
|
|
611
|
+
expect(content).toContain('sha256` matches the current plan file');
|
|
612
|
+
expect(content).toContain('→ `Approved`');
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
it('Status is Stale (re-approve) when marker sha256 drifts from the plan file', () => {
|
|
616
|
+
expect(content).toContain('Stale (re-approve)');
|
|
617
|
+
expect(content).toContain('sha256` differs');
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
it('inventory example shows at least one Approved row', () => {
|
|
621
|
+
// Match a pipe-delimited table cell on both sides (literal `|`s with
|
|
622
|
+
// tolerant whitespace) so the test proves the example output is in the
|
|
623
|
+
// pipe-delimited table format, not just that the word `Approved` happens
|
|
624
|
+
// to appear in nearby prose.
|
|
625
|
+
expect(content).toMatch(/\|\s*Approved\s*\|/);
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
it('inventory example shows at least one Stale row', () => {
|
|
629
|
+
expect(content).toMatch(/\|\s*Stale \(re-approve\)\s*\|/);
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
it('inventory example still shows at least one Planned row', () => {
|
|
633
|
+
expect(content).toMatch(/\|\s*Planned\s*\|/);
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
it('inventory documents the summary line format and zero-count omission', () => {
|
|
637
|
+
expect(content).toContain('Summary line');
|
|
638
|
+
expect(content).toContain(
|
|
639
|
+
'{N} local plan(s). {A} approved, {S} stale, {P} planned.',
|
|
640
|
+
);
|
|
641
|
+
expect(content).toContain('Omit zero-count states');
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
it('explains that Stale means the plan was edited after approval', () => {
|
|
645
|
+
expect(content).toContain('plan file was edited after approval');
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
it('reserves an Implemented state for the deferred plan-implementing tool', () => {
|
|
649
|
+
expect(content).toContain('Implemented');
|
|
650
|
+
expect(content).toMatch(
|
|
651
|
+
/deferred[\s\S]{0,120}(?:plan-implementing tool|future implementation tooling)|(?:plan-implementing tool|future implementation tooling)[\s\S]{0,120}deferred/i,
|
|
652
|
+
);
|
|
653
|
+
expect(content).toContain('shows three states');
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
it('folds malformed .approved markers into Stale (re-approve)', () => {
|
|
657
|
+
expect(content).toContain('marker exists but is malformed');
|
|
658
|
+
expect(content).toContain('non-hex or wrong-length');
|
|
659
|
+
expect(content).toContain('cannot be parsed deterministically');
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
it('uses {plan-id} placeholder consistently in the footer (no <plan-id>)', () => {
|
|
663
|
+
expect(content).not.toContain('<plan-id>');
|
|
664
|
+
expect(content).toContain('/clancy:approve-plan {plan-id}');
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
it('inventory footer hint points at /clancy:approve-plan', () => {
|
|
668
|
+
expect(content).toContain('/clancy:approve-plan');
|
|
605
669
|
});
|
|
606
670
|
|
|
607
671
|
it('sort is deterministic with explicit tie-breakers', () => {
|
|
@@ -791,9 +855,12 @@ describe('approve-plan local marker (Step 4a)', () => {
|
|
|
791
855
|
expect(content).toContain('already approved');
|
|
792
856
|
});
|
|
793
857
|
|
|
794
|
-
it('explains the marker is the gate for
|
|
795
|
-
expect(content).toContain('/clancy:implement-from');
|
|
858
|
+
it('explains the marker is the gate for future implementation tooling', () => {
|
|
796
859
|
expect(content).toContain('gate');
|
|
860
|
+
expect(content).toContain('future implementation tooling');
|
|
861
|
+
expect(content).toMatch(
|
|
862
|
+
/deferred[\s\S]{0,120}(?:plan-implementing tool|future implementation tooling)|(?:plan-implementing tool|future implementation tooling)[\s\S]{0,120}deferred/i,
|
|
863
|
+
);
|
|
797
864
|
});
|
|
798
865
|
|
|
799
866
|
it('after writing the marker, Step 4a jumps to Step 7 (log) and skips board flow', () => {
|
|
@@ -880,10 +947,10 @@ describe('approve-plan local-mode log + summary (Step 7)', () => {
|
|
|
880
947
|
expect(content).toContain('sha256={first 12 hex}');
|
|
881
948
|
});
|
|
882
949
|
|
|
883
|
-
it('local success summary points
|
|
884
|
-
expect(content).toContain(
|
|
885
|
-
|
|
886
|
-
);
|
|
950
|
+
it('local success summary points users at the deferred next-step paths', () => {
|
|
951
|
+
expect(content).toContain('Ask Claude Code:');
|
|
952
|
+
expect(content).toContain('Implement .clancy/plans/{stem}.md');
|
|
953
|
+
expect(content).toContain('npx chief-clancy');
|
|
887
954
|
});
|
|
888
955
|
|
|
889
956
|
it('preserves board-mode APPROVE_PLAN log entry', () => {
|