config-audit/commands/plan.md
Kjell Tore Guttormsen 1543830c52 feat(commands): a write that leaves the repo says so before you approve it (M-BUG-41)
The chain observed configuration across repos but presented every write it then
proposed as though it landed where the session stands. STATE named two arms;
measuring found five, and two of them are worse than the two already known:

- implement — the approval prompt named NO path at all, only a count, so a plan
  editing ~/.claude/CLAUDE.md and one editing ./CLAUDE.md produced byte-identical
  prompts.
- rollback — the file list rendered `.claude/settings.json`, a repo-relative
  FORM, while the restore writes to the absolute original. The other arms were
  silent; this one pointed the wrong way.
- fix — paths were visible but unclassified, and --global mixed machine-wide and
  project rows into one unmarked table.

The gate's strength comes from the target's scope class, never from the command
asking: five command-owned policies would drift apart the way five copies of the
lever table did. SCOPE_CLASSES is one source for class, gate, wording and
predicate; templates render `disclosures[]` from the CLI instead of restating
what a class means.

Two orderings in that table are load-bearing, and both were measured:

- plugin-managed before user-scope. Both ~/.claude/config-audit/ and the legacy
  ~/.config-audit/ are live, and every command writes session state there. The
  other order fires the gate on every write ever made and gets it switched off,
  which is worse than no gate.
- user-scope before cross-repo. ~/.claude/.git EXISTS, so a plain .git-upward
  walk answers "another repo" for ~/.claude/CLAUDE.md and silently downgrades
  the strongest gate on the subtraction axis's primary target to disclosure.

disclose is not require-ok: campaign export is cross-repo by design, so the gate
there says so rather than refusing. Distinct from require-target-dir.mjs, which
asks whether a scan ROOT is readable (exit 3) — a different invariant, left
unmerged along with its four inline copies.

Also structural, both found while building this: the hand-maintained GUARDED
list in the unknown-flag sweep now derives its completeness from the directory
(measured complete at 14 of 14 first, so nothing was hiding — but the 15th CLI
would have been swept by nothing); and prose shape-guards use whitespace-
tolerant patterns, after one went red against a command file that did say the
right thing, line-wrapped.

Gated: implement, fix, rollback, plan, campaign export. Suite 1596 -> 1625/0,
frozen v5.0.0 and default-output baselines 0 changed files. No new GAP dimension,
no lever, no finding code — utilization denominators untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013941cEohSD5Aw56FVAtBgZ
2026-08-10 05:40:12 +02:00

127 lines
5.5 KiB
Markdown

---
name: config-audit:plan
description: Phase 4 - Generate prioritized action plan with risk assessment
allowed-tools: Read, Write, Glob, Grep, Agent, Bash
model: opus
---
# Config-Audit: Plan Generation (Phase 4)
Generate a prioritized action plan based on analysis results.
## Prerequisites
- Must have completed Phase 2 (analysis)
- Phase 3 (interview) is optional — plan works with or without it
## Arguments
- `$ARGUMENTS` may contain `--raw` to forward to the planner-agent's instructions; in `--raw` mode the agent renders v5.0.0 verbatim severity prefiks instead of humanized `userActionLanguage` urgency phrasing.
## Implementation
### Step 1: Verify session state
Find the most recent session with analysis completed using the **Glob tool** on `~/.claude/config-audit/sessions/*/state.yaml`, then Read the newest match. The Read tool takes one literal path and does not expand `*` — pointing it at the glob makes this step report "no analysis results" even when a valid session exists.
If no session is found: "No analysis results found. Run `/config-audit` first to scan your configuration."
Then confirm the report itself exists — a session can carry a valid `state.yaml` and still be missing its report. Read `~/.claude/config-audit/sessions/{session-id}/analysis-report.md`. If it is absent: "Session {session-id} has no analysis report. Run `/config-audit analyze` to generate it." Stop — the planner agent has nothing to read.
### Step 2: Tell the user what's happening
```
## Creating Action Plan
Building a prioritized plan based on your analysis results...
Actions are ordered by impact, with risk assessment and dependency tracking.
```
### Step 3: Parse flags and spawn planner agent
Check whether `$ARGUMENTS` contains `--raw`. Carry the answer yourself: the agent
prompt below is **not** a shell, so a variable assigned in a bash block cannot be
referenced from it. Substitute `{mode}` literally with `--raw` or with `humanized`
when writing the prompt.
Tell the user: **"Generating your action plan (this takes about 30 seconds)..."**
```
Agent(subagent_type: "config-audit:planner-agent")
model: opus
prompt: |
Generate action plan based on:
- Analysis: ~/.claude/config-audit/sessions/{session-id}/analysis-report.md
- Interview: ~/.claude/config-audit/sessions/{session-id}/interview.md (if exists)
Mode: {mode} ("humanized" = humanized; "--raw" = v5.0.0 verbatim severity prefiks)
Create a prioritized plan that consumes the humanized finding fields:
- Group actions by userImpactCategory (e.g., "Configuration mistake",
"Conflict", "Wasted tokens", "Missed opportunity", "Dead config")
- Lead each action with userActionLanguage ("Fix this now," "Fix soon,"
"Fix when convenient," "Optional cleanup," "FYI") rather than raw
severity. The humanizer already replaced jargon-heavy
title/description/recommendation strings with plain-language
equivalents — render them verbatim, do not paraphrase.
- Surface relevanceContext when it isn't "affects-everyone" so the
user knows whether a fix touches shared config or just their machine
- Include risk assessment per action (low/medium/high)
- Rollback strategy
- Dependency ordering
- Effort estimates
Output to: ~/.claude/config-audit/sessions/{session-id}/action-plan.md
```
### Step 4: Present the plan summary
Read the generated plan, then classify the files its actions target. This summary
IS the approval surface — there is no separate confirmation step here, so a plan
that proposes writing to machine-wide configuration has to say so where the user
reads it. Pass one `--target` per distinct file the plan touches:
```bash
node ${CLAUDE_PLUGIN_ROOT}/scanners/write-scope-cli.mjs --target "<file-1>" --target "<file-2>" --repo "$PWD" --output-file /tmp/config-audit-plan-scope.json 2>/dev/null; echo $?
```
Exit 0 = classified; 3 = argument error (show the stderr message). Read
`/tmp/config-audit-plan-scope.json`. If `gate` is not `"silent"`, render each
distinct string in `disclosures[]` verbatim directly under the action table, and
mark the affected rows — not in a footnote further down, where a user scanning the
table would miss it.
Show a concise overview:
```markdown
### Action Plan Ready
**{N} actions** organized by priority:
| # | Action | Risk | Effort |
|---|--------|------|--------|
| 1 | {title} | {low/med/high} | {quick/moderate/involved} |
| 2 | ... | ... | ... |
| ... | ... | ... | ... |
Full plan: `~/.claude/config-audit/sessions/{session-id}/action-plan.md`
You can edit the plan file to remove, reorder, or modify actions before implementing.
### What's next
- **`/config-audit implement`** — Execute the plan with automatic backup and verification
- **`/config-audit interview`** — Set preferences first to customize the plan (optional)
```
### Step 5: Update state
Update `state.yaml` with all four fields `.claude/rules/state-management.md` requires — a partial write drops the fields that make an interrupted run resumable:
- `current_phase: "plan"`
- `completed_phases`: append `plan` to the existing array (read it first; never overwrite it with a fresh list)
- `next_phase: "implement"`
- `updated_at`: current timestamp
The planner agent may already have written these. Read the file before writing and preserve whichever fields it set — a full-file Write that names only two fields silently deletes the other two.
## Plan Modification
Users can edit `action-plan.md` before implementation — remove unwanted actions, adjust priority, or add custom actions. The implementer parses the modified plan.