claudemd-cli 0.9.11 → 0.9.13

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.
Files changed (2) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -8,6 +8,56 @@ 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.9.13] - 2026-05-10
12
+
13
+ **Patch — `session-summary.sh` window calculation: missing `platform.sh` source + self-owned sentinel.** Spec v6.11.7 unchanged. Two coupled defects in window discipline, both surfaced while reasoning about the v0.9.12 fix's "Bug 2" follow-up.
14
+
15
+ ### Fixed
16
+
17
+ - `[fix]` **`hook_lib/platform.sh` was never sourced by `hooks/session-summary.sh`** (regression latent since v0.8.0 ship of the hook). The window-start computation guards on `command -v platform_stat_mtime`, but with `platform.sh` not sourced the function name was undefined, the guard silently fell false, `SINCE_TS` stayed empty, and **every** session-summary invocation since v0.8.0 took the 24h-rolling fallback path instead of the documented "since last Stop" window. Hard evidence in the wild: pre-fix `last-session-summary.json` shipped with `since == ts - 24h00m00s` exactly — only the fallback `date -u -d '24 hours ago'` produces that. Banner counts were therefore mixing rule activity across multiple sessions in the same calendar day.
18
+ - `[fix]` **Window sentinel decoupled from `session-start.ref`**. The shared sentinel was also being written by `hooks/sandbox-disposal-check.sh` during the same Stop event (declared earlier in `hooks/hooks.json`). With the platform.sh source restored above, that sharing would surface as a parallel/serial-ordering race — parallel hooks may let session-summary stat the file before sandbox-disposal touches it (OK), but a future CC harness running Stop hooks serially in declaration order (sandbox first / summary last) would produce `mtime == NOW` → empty window → banner permanently empty. New private sentinel `session-summary.lastrun` is read + always-touched by session-summary alone; sandbox-disposal continues to own `session-start.ref` for its tmp-dir scan baseline.
19
+ - `[fix]` **Always-touch sentinel before the no-event early-exit**. A no-event Stop (zero rule activity) previously exited without advancing the window, so the next session would silently extend the window backward through the gap. New code touches `SUMMARY_REF` unconditionally before the `total > 0` guard so window discipline is event-count-independent.
20
+
21
+ ### Added
22
+
23
+ - `[test]` **Cases 8 + 9 in `tests/hooks/session-summary.test.sh` (7/7 → 9/9)**:
24
+ - Case 8: SUMMARY_REF is created on no-event Stop (no summary file written, but sentinel exists for next-window boundary).
25
+ - Case 9: SUMMARY_REF mtime correctly gates the window — a row dated 5 minutes before sentinel mtime is excluded; a fresh row is included; final summary asserts `denies==1 total==1`. Pre-fix this case fails with `denies==2 total==2` (24h fallback regression detector).
26
+ - `[test]` **Case 2 + new cases retargeted from `session-start.ref` to `session-summary.lastrun`** to match the new ownership boundary.
27
+
28
+ ### Why no L3 / pre-ship-review chain
29
+
30
+ `fix:` per spec §2 hard-upgrade exclusion list — both items restore documented/intended hook behavior (the v0.8.0 R-N4 design comment in the source file already says "Window: from session-start.ref mtime to now," which the missing source line silently broke). L2 ceiling applies. Diff: 1 hook (~25 lines net), 1 test (~45 lines added), 0 spec/contract change.
31
+
32
+ ### Versioning
33
+
34
+ - `package.json`, `plugin.json`, `marketplace.json` (×2 fields) → `0.9.13`. Spec trio unchanged at v6.11.7.
35
+
36
+ ---
37
+
38
+ ## [0.9.12] - 2026-05-10
39
+
40
+ **Patch — `session-summary.sh` `top_section` bucket pollution fix.** Spec v6.11.7 unchanged. Empirical session run produced banner `[claudemd] last session: 61 denies, 3 bypasses, 134 warns, top: (unset)` despite the log holding 95 `§8.V4` warns and 54 `§10-V` denies in window — i.e. `(unset)` should not have won.
41
+
42
+ ### Fixed
43
+
44
+ - `[fix]` **`top_section` calculation in `hooks/session-summary.sh`**: previously `group_by(.spec_section // "(unset)")` over **all** events in window, including operational telemetry that lacks `spec_section` by design (`session-start.bootstrap`, `user-prompt-submit.version-sync`, `session-start.upstream-banner`, `ship-baseline.pass`, `ship-baseline.pass-known-red`). On a healthy session those ops events outnumber rule-violation events ≥1:1, so the synthetic `"(unset)"` bucket dominates and the banner reads `top: (unset)` regardless of actual rule activity. Reproducer (24h window): 18 events total, 2 deny `§10-V` + 1 warn `§8.V4` + 15 housekeeping (no `spec_section`) → `top_section = "(unset)"` (wrong; correct: `§10-V`).
45
+ - `[fix]` Now restricts `top_section` aggregation to the same three event types whose counts the banner reports — `deny` + `bypass-escape-hatch` + `warn` — and drops null-`spec_section` rows. `top_section` becomes "the most-cited spec_section among events that contributed to the displayed counts," internally consistent with denies/bypasses/warns numerals.
46
+
47
+ ### Added
48
+
49
+ - `[test]` **Case 7 in `tests/hooks/session-summary.test.sh` (6/6 → 7/7)**: regression for the pollution scenario. 2 deny `§10-V` + 1 warn `§8.V4` + 15 housekeeping events (5× bootstrap + 5× version-sync + 5× pass) → asserts `top_section == "§10-V"` and `denies == 2 && warns == 1`. Pre-fix this test fails with `top_section == "(unset)"`.
50
+
51
+ ### Why no L3 / pre-ship-review chain
52
+
53
+ `fix:` (bugfix restoring intended behavior, not feat/change) per spec §2 hard-upgrade exclusion list — `top_section` is meant to surface "what rule hit you most this session," docstring at hook L8 reads "the agent sees its own recent tendency"; the polluted `(unset)` form fails that intent. L2 ceiling applies. Diff: 1 hook (12 lines net), 1 test (33 lines added), 0 spec/contract change. CHANGELOG `fix:` voice.
54
+
55
+ ### Versioning
56
+
57
+ - `package.json`, `plugin.json`, `marketplace.json` (×2 fields) → `0.9.12`. Spec trio unchanged at v6.11.7.
58
+
59
+ ---
60
+
11
61
  ## [0.9.11] - 2026-05-10
12
62
 
13
63
  **Patch — `transcript-structure-scan.sh` regex coverage gap fix.** Spec v6.11.7 unchanged. v0.9.10 shipped the hook with `^Done:` / `^Not done:` etc. line-anchored regex (canonical spec form). Empirical run against 5 real session transcripts (`~/.claude/projects/-mnt-data-ssd-dev-projects-claudemd/*.jsonl`) showed the prevalent style in this project is the **markdown-header form** (`## Done` / `## Done — <title>` / `## Not done`) per memory `feedback_done_section_chinese_prose` example — not canonical inline. v0.9.10 hook missed those entirely.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudemd-cli",
3
- "version": "0.9.11",
3
+ "version": "0.9.13",
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": {