claudemd-cli 0.56.0 → 0.57.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/CHANGELOG.md CHANGED
@@ -8,6 +8,22 @@ All notable changes to the `claudemd` plugin. This changelog tracks plugin artif
8
8
  - **Canonical spec version source**: `spec/CLAUDE.md` top-line title (`# AI-CODING-SPEC vX.Y.Z — Core`) + `spec/CLAUDE-changelog.md` top `##` entry.
9
9
  - **Plugin semver vs spec semver** are independent: plugin patch (0.2.0 → 0.2.1) may ship when spec is unchanged (this release); plugin minor (0.1.9 → 0.2.0) ships when spec minor updates (v0.2.0 shipped spec v6.10.0).
10
10
 
11
+ ## [0.57.0] - 2026-07-25
12
+
13
+ Closes the 2026-07-25 audit's remaining open items — five decided as "do", three explicitly closed as "won't do" (see `tasks/audit-2026-07-25-deferred.md`). Spec unchanged (**v6.22.0**). Minor bump: an opt-in hook is removed.
14
+
15
+ **What changes for users**: `mid-spine-yield-scan` is gone — if you had `MID_SPINE_YIELD_SCAN=1` set, that Stop advisory no longer fires and `DISABLE_MID_SPINE_YIELD_HOOK` / `/claudemd-toggle mid-spine-yield-scan` are no-ops (the §11 rule itself is unchanged and still self-enforced; only its observation mirror is retired). `banned-vocab` bypass rows change shape, and a same-day re-run of `/claudemd-sampling-audit` now refuses to overwrite its own report.
16
+
17
+ - **remove: the `mid-spine-yield-scan` Stop hook (16 → 15 hooks).** Zero events for its entire lifetime (v0.15.0 → now) — it shipped default-OFF per the behavior-layer convention and was never enabled anywhere, while still spawning a bash process on every Stop to exit at its opt-in guard, and its stderr text had drifted to quote the pre-v6.21.1 rule wording. By the project's own §13.1 criterion (hook-enforced, 0 hits in window) it was the cleanest demote candidate in the tree; syncing it to the v6.22.0 precondition would have been spend on something that has never run. `spec/hard-rules.json` is untouched: `§11-mid-spine-yield` is `enforcement: "self"` with `rule_hits_section: null`, so the §13 partition (7 hook / 14 self / 1 both / 1 external) is unaffected. Removed: the hook, its 12-case suite, the `hooks.json` registration, the registry entry (drops `DISABLE_MID_SPINE_YIELD_HOOK`), the doctor kill-switch row, the contract DOCUMENTED entry, and the count assertions in `full-lifecycle` / `hook-registry` / `install` / README (16 → 15 together). The `mid-spine-advisory` event is retired but historical rows stay valid — `session-end-check`'s L2+ heuristic still counts them.
18
+ - **feat(telemetry): `banned-vocab` bypass rows carry the term they suppressed.** The demote question is "which word does the operator keep overriding", and the data could not answer it: deny rows carried `{matched}`, bypass rows carried only `{token}`, and the token short-circuited before the scan ran. The scan now runs first and the bypass row is emitted at the hit with `{token, matched, path}`. **Measurement-semantics change**: a token on a command that would have passed anyway now records nothing (it was inflating the override rate with prophylactic tokens), so the 51.6% figure and any post-0.57.0 rate are not comparable. This is the instrumentation the §13.2 review needs before deciding anything about §10-V — the decision itself stays deferred.
19
+ - **fix(doctor): the demote label cited a rule the spec does not contain.** `rule-usage:<section>` reported "§0.1 demotion candidate" above a 50% bypass ratio, but §0.1 demotes on ZERO hits and a bypass threshold appears only as a §13.3 **promotion** gate (<10% to advance). The high-override signal is real; the action it licenses is a review, not a demotion. Relabeled to point at the §13.2 batch review and to say outright that no demote-by-bypass-rate rule exists — the mislabel had cost a full re-adjudication every run (`tasks/banned-vocab-demote-evaluation-2026-07-25.md` settled exactly this question for §10-V and the check kept re-asking it).
20
+ - **fix(hard-rules-audit): safety-class rules are exempt from the demote queue.** §8 rules are §5.1 Never-downgrade AND sparse by design — the attack surface they guard is rare, not absent — so listing `§8-curl-sh` as a 0-hit demote candidate recommended a forbidden action. They move to a new `safetyClassExempt` field, still visible (a safety gate that never fires may be broken, but that is an FN-matrix question, not a demotion one).
21
+ - **fix(sampling-audit): refuse to overwrite an existing report.** The output path is date-based, so a same-day re-run always collides — on 2026-07-25 a plain run replaced a committed, hand-annotated 216-line calibration record with a 16-line fresh scan (recovered via git). Now refuses unless `--force`; `--json` still prints without writing.
22
+ - **test: class-level repo-write guard in `run-all.sh`.** Records `git rev-list --count HEAD` before and after the suite and fails if it moved. `perf-baseline.sh` escaped for two months because only the files someone thought to check were checked; two lines now cover every existing and future suite. Verified RED against a deliberately-escaping fixture test.
23
+ - **docs**: the 0.55.0 entry's noop-commit count is corrected in place — 46 across two clusters (40 on 07-17, 6 on 05-10), not 48 all on one day; the May cluster dated to the night `perf-baseline.sh` first shipped and had gone unnoticed.
24
+
25
+ **Explicitly not done** (recorded in `tasks/audit-2026-07-25-deferred.md`): the §8-rm-rf-var scratch-cleanup friction — 0.56.0 changed the deny message to hand out the mktemp recipe, and measuring that intervention comes before stacking a second one; a byte cap on `MEMORY.md` — 78% of its 60 entries are durable `feedback_*` lessons, so a cap deletes lessons, and the recoverable space is in consolidating 9 closed-loop `project_*` audit entries; slash-command usage telemetry — an unused command's cost is 5,380 B of frontmatter, which compression addresses without building a measurement apparatus.
26
+
11
27
  ## [0.56.0] - 2026-07-25
12
28
 
13
29
  Fix batch from the 2026-07-25 four-dimension audit (`docs/comprehensive-audit-2026-07-25-v0.55.0.md`, local-only per the docs/ gitignore convention). Ships spec **v6.22.0** (minor). Minor bump: the §8 curl-sh and rm-rf-var deny surfaces both widen (user-visible default behavior change).
@@ -33,7 +49,7 @@ Ships spec **v6.21.2** (patch) plus two hermeticity/observability fixes surfaced
33
49
  **What changes for users**: SessionStart now banners when Claude Code is loading hooks from an older build than the marketplace cache holds — the exact drift that let two releases (0.53.0, 0.54.0) run unnoticed on a stale 0.52.0 install; `scripts/perf-baseline.sh` can no longer commit into your repo or write live telemetry.
34
50
 
35
51
  - **feat(session-start): stale-registration banner (`stale_cache_check`).** `upstream_check` compares the cache max against the REMOTE tag, so after a release + local marketplace update (cache == remote) it stays silent even though the registered root is older — reproduced 2026-07-25: hooks running v0.52.0 while cache and remote both held v0.54.0, zero banners for two releases; only `doctor`'s on-demand `plugin cache:staleness` check saw it. The new check compares the running root against the local cache max — no network, no 24h sentinel, repeats every SessionStart until `/claudemd-refresh` re-registers. Skips the redundant remote probe when it fires. Telemetry reuses the registered `stale-root` event with `{hook_version, cache_max_version}` extra (no new event name). Shared `semver_cache_max()` helper replaces the inline glob in `upstream_check` (one source for the cache scan). Tests: `session-start.test.sh` cases 23-24 — case 23 RED pre-fix (hook emitted nothing on a newer cache), 24/24 post-fix.
36
- - **fix(perf-baseline): probes run in a throwaway repo + telemetry off.** The `git commit --allow-empty -m 'noop'` probe executed in the CALLER's cwd — 48 stray `noop` commits landed on this repo's main on 2026-07-17 (all stamped 15:14:04-05) and were pushed with the next release. All probe commands now execute inside a `mktemp -d` sandbox repo (trap-cleaned, spec §8.V3), and the script exports `DISABLE_RULE_HITS_LOG=1` so its synthetic hook invocations stop polluting live telemetry (`feedback_manual_hook_probe_pollutes_telemetry`). New regression gate `tests/integration/perf-baseline-hermetic.test.sh`: RED pre-fix (caller repo commits 1 → 3 at `--runs 1`), 3/3 post-fix.
52
+ - **fix(perf-baseline): probes run in a throwaway repo + telemetry off.** The `git commit --allow-empty -m 'noop'` probe executed in the CALLER's cwd — 48 stray `noop` commits landed on this repo's main on 2026-07-17 (all stamped 15:14:04-05) and were pushed with the next release. *(Correction, 0.57.0: the real count is 46 across **two** clusters — 40 on 2026-07-17 15:14:04-05 and 6 on 2026-05-10 02:58:04-05, the night `perf-baseline.sh` first shipped in v0.9.7. The May cluster went unnoticed at the time and was folded into the July narrative above. `git log --grep='^noop$'` is the check.)* All probe commands now execute inside a `mktemp -d` sandbox repo (trap-cleaned, spec §8.V3), and the script exports `DISABLE_RULE_HITS_LOG=1` so its synthetic hook invocations stop polluting live telemetry (`feedback_manual_hook_probe_pollutes_telemetry`). New regression gate `tests/integration/perf-baseline-hermetic.test.sh`: RED pre-fix (caller repo commits 1 → 3 at `--runs 1`), 3/3 post-fix.
37
53
  - **change(spec v6.21.2): §EXT §10-V compressed to OK-shapes + pointers** — rationale and demote-evaluation record in `spec/CLAUDE-changelog.md`. `banned-vocab-canonical.json` updated in step (pattern rows kept as in_spec=false, ten spec-only rows retired); `hooks/banned-vocab.patterns` untouched — mechanical enforcement byte-identical.
38
54
 
39
55
  ## [0.54.0] - 2026-07-24
package/README.md CHANGED
@@ -57,7 +57,7 @@ Verify in one command (Linux): `node --version && jq --version && gh --version &
57
57
 
58
58
  | Layer | Contents |
59
59
  |---|---|
60
- | 16 shell hooks | `banned-vocab-check` · `pre-bash-safety-check` · `ship-baseline-check` · `residue-audit` · `memory-read-check` · `memory-prompt-hint` · `mid-spine-yield-scan` · `sandbox-disposal-check` · `session-start-check` · `session-extended-read` · `session-summary` · `session-end-check` · `transcript-vocab-scan` · `transcript-structure-scan` · `version-sync` · `mem-audit` |
60
+ | 15 shell hooks | `banned-vocab-check` · `pre-bash-safety-check` · `ship-baseline-check` · `residue-audit` · `memory-read-check` · `memory-prompt-hint` · `sandbox-disposal-check` · `session-start-check` · `session-extended-read` · `session-summary` · `session-end-check` · `transcript-vocab-scan` · `transcript-structure-scan` · `version-sync` · `mem-audit` |
61
61
  | 16 slash commands | `/claudemd-install` · `/claudemd-status` · `/claudemd-update` · `/claudemd-refresh` · `/claudemd-audit` · `/claudemd-toggle` · `/claudemd-doctor` · `/claudemd-analyze` · `/claudemd-uninstall` · `/claudemd-rules` · `/claudemd-clean-residue` · `/claudemd-sparkline` · `/claudemd-sampling-audit` · `/claudemd-bypass-audit` · `/claudemd-design-adopt` · `/claudemd-statusline` |
62
62
  | 1 standalone CLI | `claudemd-cli lint` · `claudemd-cli audit` ([npm: `claudemd-cli`](https://www.npmjs.com/package/claudemd-cli)) |
63
63
  | Spec v6.22 | `~/.claude/CLAUDE.md` · `CLAUDE-extended.md` · `CLAUDE-changelog.md` · `OPERATOR.md` (backup-before-overwrite) |
@@ -183,7 +183,6 @@ export DISABLE_TRANSCRIPT_STRUCTURE_SCAN_HOOK=1 # v0.9.10+ — Stop §10 four-s
183
183
  export DISABLE_MEM_AUDIT_HOOK=1 # v0.9.4+ — Stop Why:-less citation advisory
184
184
  export DISABLE_SESSION_END_CHECK_HOOK=1 # v0.9.27+ — SessionEnd §11-session-exit mid-SPINE check
185
185
  export DISABLE_SESSION_EXTENDED_READ_HOOK=1 # v0.10.1+ — PreToolUse:Read §13.1-extended-read denominator signal
186
- export DISABLE_MID_SPINE_YIELD_HOOK=1 # v0.15.0+ — Stop §11-mid-spine-yield advisory (opt-in via MID_SPINE_YIELD_SCAN=1)
187
186
  ```
188
187
 
189
188
  **2a. Per-sub-feature** (v0.4.0+). Sub-flags inside an enabled hook, named without the `_HOOK` suffix:
@@ -348,7 +347,7 @@ claudemd/
348
347
  ├── .claude-plugin/
349
348
  │ ├── plugin.json # minimal manifest (name, version, author, license, keywords)
350
349
  │ └── marketplace.json # marketplace catalog entry
351
- ├── hooks/ # 16 shell hooks + hooks/lib/ (hook-common, rule-hits, platform)
350
+ ├── hooks/ # 15 shell hooks + hooks/lib/ (hook-common, rule-hits, platform)
352
351
  │ └── hooks.json # authoritative hook registration (v0.1.5+); CC expands ${CLAUDE_PLUGIN_ROOT} here
353
352
  ├── commands/ # 16 slash-command markdown files
354
353
  ├── bin/ # standalone CLI entrypoint (claudemd-lint.js → `npx claudemd-cli` on npmjs.org)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudemd-cli",
3
- "version": "0.56.0",
3
+ "version": "0.57.0",
4
4
  "description": "Standalone CLI for §10-V banned-vocab + transcript scanning. Companion to the claudemd Claude Code plugin (github.com/sdsrss/claudemd) for use in git pre-commit hooks, GitHub Actions, and other agents.",
5
5
  "type": "module",
6
6
  "bin": {