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
This commit is contained in:
parent
49bae2657f
commit
1543830c52
12 changed files with 821 additions and 9 deletions
24
README.md
24
README.md
|
|
@ -550,6 +550,7 @@ Shared modules used by all scanners — useful if you're reading the source or e
|
|||
| `suppression.mjs` | `.config-audit-ignore` parsing, finding suppression, audit trail |
|
||||
| `active-config-reader.mjs` | Read-only inventory of plugins/skills/MCP/hooks/CLAUDE.md cascade with token estimates |
|
||||
| `tokenizer-api.mjs` | Anthropic `count_tokens` wrapper for `--accurate-tokens` (v5 N5); 5s timeout, 429 backoff, key masking |
|
||||
| `write-scope.mjs` | Classifies a write target against the current project (`SCOPE_CLASSES`, `classifyWriteTarget()`); one source for class, gate strength and wording |
|
||||
|
||||
### Action Engines
|
||||
|
||||
|
|
@ -562,6 +563,7 @@ Shared modules used by all scanners — useful if you're reading the source or e
|
|||
| `manifest.mjs` | CLI: ranked component-level source table w/ load-pattern accounting (v5 N2; v5.6 B) |
|
||||
| `whats-active.mjs` | CLI: read-only active-config inventory (v3.1.0+) |
|
||||
| `token-hotspots-cli.mjs` | CLI: token hotspots ranking with optional `--accurate-tokens` |
|
||||
| `write-scope-cli.mjs` | CLI: classify write targets before an approval surface (`--target`, repeatable) |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -665,6 +667,28 @@ This plugin is cautious by design — configuration files are important, and a b
|
|||
| **Verification pass** | A separate agent confirms changes actually work |
|
||||
| **Human-in-the-loop** | You approve the plan before anything is implemented |
|
||||
| **Post-edit guard** | Hook blocks the session if a new critical/high finding is introduced |
|
||||
| **Scope disclosed before every write** | Each write target is classified against the project you are in, and the approval surface says when a change leaves it |
|
||||
|
||||
### Writes That Leave Your Project
|
||||
|
||||
config-audit reads configuration across projects and machine-wide, so some of what
|
||||
it proposes does not land where you are standing. A count of files cannot tell those
|
||||
cases apart: a plan that edits `~/.claude/CLAUDE.md` and one that edits your
|
||||
project's own `CLAUDE.md` are both "1 file".
|
||||
|
||||
Every write target is therefore classified before you are asked to approve it, and
|
||||
the class — not the command — decides how strong the gate is:
|
||||
|
||||
| Where the write lands | What happens |
|
||||
|---|---|
|
||||
| Inside the project you are working in | No extra gate; the usual confirmation applies |
|
||||
| config-audit's own session state and backups | No extra gate; this is the plugin's bookkeeping, not your configuration |
|
||||
| Your machine-wide Claude configuration (`~/.claude`) | Stated plainly, and it needs an explicit go-ahead — a change here affects every project you open |
|
||||
| A different project | Stated plainly, including that directories will be created there. `campaign export` does this deliberately, so this is disclosure, not refusal |
|
||||
| Anywhere else | Stated plainly, and it needs an explicit go-ahead |
|
||||
|
||||
Where a machine-wide or cross-project write is involved, the safe option is listed
|
||||
first — the default is never "proceed".
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue