@windyroad/retrospective 0.18.2-preview.337 → 0.19.0-preview.339

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.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "wr-retrospective",
3
- "version": "0.18.2",
3
+ "version": "0.19.0",
4
4
  "description": "Session retrospective reminders and plan review for Claude Code"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/retrospective",
3
- "version": "0.18.2-preview.337",
3
+ "version": "0.19.0-preview.339",
4
4
  "description": "Session retrospectives that update briefings and create problem tickets",
5
5
  "bin": {
6
6
  "windyroad-retrospective": "./bin/install.mjs"
@@ -331,12 +331,12 @@ The script's threshold defaults to `5120` bytes (the upper bound of ADR-040's Ti
331
331
  - If a coherent sub-topic boundary exists (a sub-section that's grown big enough to stand alone, ≥1 KB; e.g. a worked example in a topic that's grown to its own sub-section): **split-by-subtopic** — extract to `docs/briefing/<sub-topic>.md`, update README Topic Index.
332
332
  - Else: **split-by-date** — this is the **safe default** when no sub-topic boundary is obvious. Older entries archive cleanly without semantic judgement (mtime-sort + median-age threshold), so the action is mechanical and AFK-safe. Archive oldest entries to `docs/briefing/<topic>-archive.md`. Do NOT pick split-by-subtopic with a weak boundary just because it appears first in the heuristic — split-by-date is preferred when the boundary is unclear because it has zero false-split risk.
333
333
 
334
- **Branch B — file has only OVER line (ratio between 1.0× and 2.0× ceiling)**: the original four-option heuristic applies. Defer is permitted because the ratio is still inside the reassessment trigger envelope; one or two more retros of accumulation will escalate to MUST_SPLIT and force action via Branch A.
334
+ **Branch B — file has only OVER line (ratio between 1.0× and 2.0× ceiling)**: rotation is required. Being OVER threshold IS the evidence; "wait for more signal to accumulate" is the fictional-defer anti-pattern P247 closes (sibling-class to P246's calendar-trigger anti-pattern at the cohort-graduation surface). Per the P246 principle (evidence-based, not time-based — user direction verbatim 2026-05-17: *"The 14 files are over the limit, but you are deferring splitting them. Why? When are you hoping they will get dealt with?"*), the agent picks the best-fit rotation shape from the three concrete options below; fall-through is **split-by-date** as the safe default (zero false-split risk per Branch A precedent), NOT "leave-as-is".
335
335
 
336
336
  - If a coherent sub-topic boundary exists (≥1 KB sub-section): **split-by-subtopic** — extract to `docs/briefing/<sub-topic>.md`, update README Topic Index.
337
337
  - Else if the file has clear date-stratified entries (HTML-comment `first-written` fields per Step 1.5) AND ≥30% of bytes are entries older than the median age: **split-by-date** — archive oldest entries to `docs/briefing/<topic>-archive.md`.
338
- - Else if Step 1.5 surfaced ≥3 noise-classified entries in this file this retro: **trim-noise** — defer rotation; let the next retro's Step 1.5 shrink the file across cycles.
339
- - Else: **leave-as-is** — record the OVER state in the Step 5 summary; no action this retro. Picks up next retro when more signal accumulates.
338
+ - Else if Step 1.5 surfaced ≥3 noise-classified entries in this file this retro: **trim-noise** — apply the Step 1.5 noise-trim decisions inline; if the trim alone brings the file below threshold, record `trim-noise` as the rotation action with the per-entry deltas in the Step 5 summary. If the file is still OVER after trim, fall through to split-by-date in the same retro turn — do NOT defer.
339
+ - Else (no subtopic boundary AND no date stratification AND no ≥3 noise entries): **split-by-date (safe default)** — mtime-sort entries, archive the oldest half to `docs/briefing/<topic>-archive.md`. This is the same safe-default Branch A uses when its boundary is unclear; the fall-through here aligns Branch B with Branch A's evidence-based rotation discipline. Per ADR-013 Rule 5 (policy-authorised silent proceed) + ADR-044 framework-mediated surface ("Briefing add / remove / rotate" line 77), the rotation is silent agent judgement — no per-file `AskUserQuestion`.
340
340
 
341
341
  Apply the chosen rotation; record the choice + rationale + per-file delta (`bytes before` → `bytes after`) in the Step 5 summary `Topic File Rotation` section. User reads the summary and corrects via authentic-correction (ADR-044 category 6) if the rotation was wrong (rotations are reversible — `git mv` the archive sibling back; restore deletions from git).
342
342
 
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env bats
2
+ #
3
+ # P247: run-retro SKILL.md Step 3 Tier 3 Branch B MUST encode the
4
+ # evidence-based rotation contract — "leave-as-is" is eliminated; the
5
+ # fall-through when none of the three concrete triggers (subtopic /
6
+ # date / ≥3 noise entries) fire is **split-by-date as the safe default**,
7
+ # mirroring Branch A's existing precedent.
8
+ #
9
+ # This file mirrors the architecture established for P148's Stage 1
10
+ # fallback-gating clause: behavioural assertions exercise the
11
+ # enforcement layer (check-briefing-budgets.sh) for the OVER /
12
+ # MUST_SPLIT signal shape that drives Branch B input, plus narrow
13
+ # structural backstops linking SKILL.md prose (canonical human source)
14
+ # to the enforcement layer + driver-ticket evidence trail.
15
+ #
16
+ # Architect verdict (2026-05-18, P247): the rotation decision itself
17
+ # is silent agent judgement per ADR-044 framework-mediated surface
18
+ # "Briefing add / remove / rotate" — there is no script to behaviourally
19
+ # exercise the rotation. The script-side behavioural coverage for the
20
+ # Branch B INPUT signal (OVER without MUST_SPLIT) lives in
21
+ # `packages/retrospective/scripts/test/check-briefing-budgets.bats`;
22
+ # this file is the SKILL-prose backstop that confirms the prose names
23
+ # the evidence-based contract terms and the driver ticket.
24
+ #
25
+ # # @adr ADR-037 permitted exception — narrowest justifiable scope.
26
+ # # @adr ADR-044 framework-mediated surface boundary (silent agent rotation).
27
+ # # @adr ADR-061 evidence-based-not-time-based principle (parent class).
28
+ # # @adr ADR-013 Rule 5 (policy-authorised silent proceed).
29
+ # # @adr ADR-052 behavioural-tests-default (structural backstops permitted
30
+ # # for SKILL-prose-to-enforcement-layer linkage per P081).
31
+ # # @ticket P247 — Branch B fictional-defer (driver).
32
+ # # @ticket P246 — sibling-class at cohort-graduation surface (mirror precedent).
33
+ # # @ticket P145 — predecessor at this surface (MUST_SPLIT subset already
34
+ # # evidence-based; P247 generalises to OVER subset).
35
+ # # @ticket P081 — behavioural-tests-preferred direction.
36
+
37
+ setup() {
38
+ REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
39
+ SKILL_MD="$REPO_ROOT/packages/retrospective/skills/run-retro/SKILL.md"
40
+ SCRIPT="$REPO_ROOT/packages/retrospective/scripts/check-briefing-budgets.sh"
41
+ FIXTURE_DIR="$(mktemp -d)"
42
+ }
43
+
44
+ teardown() {
45
+ rm -rf "$FIXTURE_DIR"
46
+ }
47
+
48
+ # Helper: write a markdown file with N bytes of body content.
49
+ write_briefing_entry() {
50
+ local path="$1"
51
+ local target_bytes="$2"
52
+ : > "$path"
53
+ printf '# Topic\n\n' >> "$path"
54
+ local header_size
55
+ header_size=$(wc -c < "$path" | tr -d ' ')
56
+ local body_target=$(( target_bytes - header_size ))
57
+ if [ "$body_target" -gt 0 ]; then
58
+ local line="- entry text padded out to a known length for byte-budget testing. "
59
+ local line_size=${#line}
60
+ line+=$'\n'
61
+ local line_count=$(( (body_target + line_size) / (line_size + 1) ))
62
+ local i=0
63
+ while [ "$i" -lt "$line_count" ]; do
64
+ printf '%s' "$line" >> "$path"
65
+ i=$(( i + 1 ))
66
+ done
67
+ fi
68
+ }
69
+
70
+ # ── Behavioural: Branch B INPUT signal shape ────────────────────────────────
71
+ #
72
+ # Branch B is defined as "file has only OVER line (ratio between 1.0× and
73
+ # 2.0× ceiling)". The check-briefing-budgets.sh script is the enforcement
74
+ # layer that produces this signal. These assertions confirm the signal
75
+ # shape the SKILL contract reads — they exercise the script (not the
76
+ # agent's rotation choice), giving Branch B its input definition.
77
+
78
+ @test "Branch B input: file at 1.5x ratio emits OVER without MUST_SPLIT (Branch B selector)" {
79
+ # 1.5x of default 5120 ceiling = 7680 bytes — the canonical Branch B input.
80
+ mkdir -p "$FIXTURE_DIR/briefing"
81
+ write_briefing_entry "$FIXTURE_DIR/briefing/branch-b-canonical.md" 7680
82
+ run "$SCRIPT" "$FIXTURE_DIR/briefing"
83
+ [ "$status" -eq 0 ]
84
+ echo "$output" | grep -E "^OVER branch-b-canonical.md bytes=[0-9]+ threshold=5120"
85
+ ! echo "$output" | grep -q "^MUST_SPLIT branch-b-canonical.md"
86
+ }
87
+
88
+ @test "Branch B input: file at 1.0x exactly emits OVER without MUST_SPLIT (Branch B lower edge)" {
89
+ mkdir -p "$FIXTURE_DIR/briefing"
90
+ printf '%.0s.' $(seq 1 5120) > "$FIXTURE_DIR/briefing/branch-b-lower-edge.md"
91
+ run "$SCRIPT" "$FIXTURE_DIR/briefing"
92
+ [ "$status" -eq 0 ]
93
+ echo "$output" | grep -E "^OVER branch-b-lower-edge.md bytes=5120 threshold=5120"
94
+ ! echo "$output" | grep -q "^MUST_SPLIT branch-b-lower-edge.md"
95
+ }
96
+
97
+ @test "Branch B input: file just under 2.0x (e.g. 1.96x) emits OVER without MUST_SPLIT (P247 evidence — hooks-and-gates-archive.md at 1.96x was deferred)" {
98
+ # 1.96x of 5120 = 10035 bytes — the upper edge of Branch B, exactly the
99
+ # case the 2026-05-17 session-4 wrap retro hit and deferred via the
100
+ # now-eliminated "leave-as-is" branch.
101
+ mkdir -p "$FIXTURE_DIR/briefing"
102
+ printf '%.0s.' $(seq 1 10035) > "$FIXTURE_DIR/briefing/upper-edge.md"
103
+ run "$SCRIPT" "$FIXTURE_DIR/briefing"
104
+ [ "$status" -eq 0 ]
105
+ echo "$output" | grep -E "^OVER upper-edge.md bytes=10035 threshold=5120"
106
+ ! echo "$output" | grep -q "^MUST_SPLIT upper-edge.md"
107
+ }
108
+
109
+ @test "Branch B input: file UNDER threshold emits NEITHER signal (no Branch B action)" {
110
+ # The pre-existing skip path: file below threshold = no rotation pass
111
+ # entry. The SKILL contract's "Empty stdout means no files are over
112
+ # budget — skip the rest of this pass" precedent is preserved.
113
+ mkdir -p "$FIXTURE_DIR/briefing"
114
+ write_briefing_entry "$FIXTURE_DIR/briefing/within-budget.md" 3000
115
+ run "$SCRIPT" "$FIXTURE_DIR/briefing"
116
+ [ "$status" -eq 0 ]
117
+ ! echo "$output" | grep -q "within-budget.md"
118
+ }
119
+
120
+ @test "Branch B / Branch A boundary: file at exactly 2.0x emits BOTH OVER and MUST_SPLIT (Branch A selector)" {
121
+ # The contract boundary: 2.0x and above is Branch A (rotation required,
122
+ # no defer options eligible). 1.0x-2.0x is Branch B. The script-side
123
+ # MUST_SPLIT signal is the discriminator the SKILL prose reads.
124
+ mkdir -p "$FIXTURE_DIR/briefing"
125
+ printf '%.0s.' $(seq 1 10240) > "$FIXTURE_DIR/briefing/exactly-2x.md"
126
+ run "$SCRIPT" "$FIXTURE_DIR/briefing"
127
+ [ "$status" -eq 0 ]
128
+ echo "$output" | grep -E "^OVER exactly-2x.md bytes=10240 threshold=5120"
129
+ echo "$output" | grep -E "^MUST_SPLIT exactly-2x.md reason=ratio-exceeds-2x"
130
+ }
131
+
132
+ # ── Structural backstops: SKILL.md prose contract terms (narrow per P081) ───
133
+ #
134
+ # These assertions link SKILL.md prose (canonical human-readable source)
135
+ # to the evidence-based-rotation contract and the driver ticket. Without
136
+ # these links, the prose contract could drift independently from the
137
+ # enforcement layer + driver-ticket evidence trail. Per P081, the scope
138
+ # is narrowed to the smallest set of tokens that prove the contract
139
+ # terms exist in the prose; assertions intentionally avoid coupling to
140
+ # line numbers or sentence-level structure.
141
+
142
+ @test "Branch B prose: SKILL.md no longer permits the 'leave-as-is' fall-through (P247 fix verification)" {
143
+ # The contract negative-assertion: the eliminated branch's literal
144
+ # token "leave-as-is" must NOT appear as a permitted Branch B
145
+ # rotation option. The token may legitimately appear inside a
146
+ # historical-reference context (e.g. "the eliminated 'leave-as-is'
147
+ # branch") — that's why we don't grep for the bare token but for the
148
+ # specific surface that previously authorised the defer.
149
+ ! grep -F "Else: **leave-as-is**" "$SKILL_MD"
150
+ }
151
+
152
+ @test "Branch B prose: SKILL.md names 'split-by-date (safe default)' as the Branch B fall-through (P247 fix verification)" {
153
+ # The contract positive-assertion: the new fall-through must be named
154
+ # explicitly as "split-by-date (safe default)" — the same naming
155
+ # Branch A already uses, so a reader of the prose sees the alignment
156
+ # without having to cross-reference Branch A's bullet.
157
+ grep -F "split-by-date (safe default)" "$SKILL_MD"
158
+ }
159
+
160
+ @test "Branch B prose: SKILL.md cites P247 as the driver ticket (audit-trail link)" {
161
+ # Audit-trail link: the prose names P247 so future readers can locate
162
+ # the evidence trail (user correction quote, sibling-class relationship
163
+ # to P246, the 14-file evidence from 2026-05-17 session 4 wrap retro).
164
+ grep -F "P247" "$SKILL_MD"
165
+ }
166
+
167
+ @test "Branch B prose: SKILL.md cites P246 sibling fix as the evidence-based principle precedent (cross-class linkage)" {
168
+ # Cross-class linkage: P246 (cohort-graduation surface) is the immediate
169
+ # sibling fix. The Branch B prose must cite it so the evidence-based-
170
+ # not-time-based principle is discoverable as a class, not a one-off
171
+ # SKILL fix.
172
+ grep -F "P246" "$SKILL_MD"
173
+ }
174
+
175
+ @test "Branch B prose: SKILL.md cites ADR-044 framework-mediated surface for silent rotation (governance link)" {
176
+ # Governance link: per architect verdict, Branch B's silent-rotation
177
+ # discipline is authorised by ADR-044's framework-resolution boundary
178
+ # ("Briefing add / remove / rotate" line 77). The prose must cite the
179
+ # ADR so a reader sees the authority for not firing AskUserQuestion
180
+ # per file in Branch B's fall-through.
181
+ grep -F "ADR-044" "$SKILL_MD"
182
+ }
183
+
184
+ @test "Branch B prose: SKILL.md cites ADR-013 Rule 5 for policy-authorised silent proceed (governance link)" {
185
+ # Companion governance link: ADR-013 Rule 5 is the originating rule
186
+ # for silent-proceed under policy. Branch B inherits this discipline;
187
+ # the citation makes the rule chain explicit.
188
+ grep -F "ADR-013 Rule 5" "$SKILL_MD"
189
+ }