@windyroad/retrospective 0.21.0-preview.389 → 0.21.1-preview.393

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.
@@ -66,5 +66,5 @@
66
66
  }
67
67
  },
68
68
  "name": "wr-retrospective",
69
- "version": "0.21.0"
69
+ "version": "0.21.1"
70
70
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/retrospective",
3
- "version": "0.21.0-preview.389",
3
+ "version": "0.21.1-preview.393",
4
4
  "description": "Session retrospectives that update briefings and create problem tickets",
5
5
  "bin": {
6
6
  "windyroad-retrospective": "./bin/install.mjs"
@@ -179,13 +179,60 @@ fi
179
179
  emit_bucket decisions "$decisions_bytes" "$decisions_present"
180
180
 
181
181
  # ── Bucket: problems ────────────────────────────────────────────────────────
182
+ # Dual-tolerant enumeration per RFC-002 T4 (the proven reconcile-readme.sh
183
+ # pattern). RFC-002 T5 / ADR-031 migrated tickets from the flat layout
184
+ # (docs/problems/<NNN>-*.<state>.md) to per-state subdirs
185
+ # (docs/problems/<state>/<NNN>-*.md). Walk BOTH layouts; a flat-only glob
186
+ # misses the subdir tickets and under-counts the bucket ~99% post-migration
187
+ # (P182). Dedup on ticket ID (the per-state layout drops the `.<state>`
188
+ # suffix, so the same ticket has different basenames across layouts — key on
189
+ # ID, not basename, mirroring reconcile-readme.sh). Non-ticket files (README)
190
+ # live only at the top level and never collide with subdir content, so they
191
+ # key on full basename. The per-state subdir loop runs AFTER the flat loop so
192
+ # the per-state copy wins on collision (ADR-031 §"Authoritative state signal").
182
193
 
183
194
  problems_dir="$PROJECT_ROOT/docs/problems"
184
195
  problems_present=0
185
196
  problems_bytes=0
186
197
  if [ -d "$problems_dir" ]; then
187
198
  problems_present=1
188
- problems_bytes=$( cd "$PROJECT_ROOT" && sum_globs "docs/problems/*.md" )
199
+ problems_bytes=$(
200
+ cd "$PROJECT_ROOT" 2>/dev/null && {
201
+ declare -A seen
202
+ shopt -s nullglob
203
+ # Flat layout: top-level *.md (READMEs + any pre-migration flat tickets).
204
+ for f in docs/problems/*.md; do
205
+ [ -f "$f" ] || continue
206
+ base="$(basename "$f")"
207
+ case "$base" in
208
+ [0-9][0-9][0-9]-*) key="${base%%-*}" ;; # ticket: dedup on numeric ID
209
+ *) key="$base" ;; # README etc: full basename
210
+ esac
211
+ seen["$key"]="$f"
212
+ done
213
+ # Per-state subdir layout (RFC-002 T5 / ADR-031) — wins on ID collision.
214
+ for state in open known-error verifying closed parked; do
215
+ for f in docs/problems/"$state"/*.md; do
216
+ [ -f "$f" ] || continue
217
+ base="$(basename "$f")"
218
+ case "$base" in
219
+ [0-9][0-9][0-9]-*) key="${base%%-*}" ;;
220
+ *) key="$base" ;;
221
+ esac
222
+ seen["$key"]="$f"
223
+ done
224
+ done
225
+ shopt -u nullglob
226
+ total=0
227
+ for f in "${seen[@]}"; do
228
+ if [ -r "$f" ]; then
229
+ b=$(wc -c < "$f" 2>/dev/null | tr -d ' ')
230
+ total=$(( total + ${b:-0} ))
231
+ fi
232
+ done
233
+ echo "$total"
234
+ }
235
+ )
189
236
  fi
190
237
  emit_bucket problems "$problems_bytes" "$problems_present"
191
238
 
@@ -169,6 +169,68 @@ teardown() {
169
169
  echo "$output" | grep -qE '^BUCKET problems bytes=[0-9]+$'
170
170
  }
171
171
 
172
+ # ── Dual-tolerant per-state subdir enumeration (P182 / RFC-002 T4 / ADR-031) ─
173
+ # RFC-002 T5 migrated problem tickets from the flat layout
174
+ # (docs/problems/<NNN>-*.<state>.md) to per-state subdirs
175
+ # (docs/problems/<state>/<NNN>-*.md). The flat-only glob misses the subdir
176
+ # tickets and under-counts the bucket ~99% post-migration (P182). The fix
177
+ # walks BOTH layouts and dedups on ticket ID — the per-state subdir copy
178
+ # wins on collision per ADR-031 §"Authoritative state signal" — mirroring
179
+ # the proven reconcile-readme.sh pattern.
180
+
181
+ @test "measure-context-budget: per-state subdir problem tickets are counted" {
182
+ mkdir -p "$FIXTURE_DIR/docs/problems/open" "$FIXTURE_DIR/docs/problems/known-error"
183
+ printf '# Problem 100\nbody body body\n' > "$FIXTURE_DIR/docs/problems/open/100-foo.md"
184
+ printf '# Problem 101\nbody body\n' > "$FIXTURE_DIR/docs/problems/known-error/101-bar.md"
185
+ run bash "$SCRIPT" "$FIXTURE_DIR"
186
+ [ "$status" -eq 0 ]
187
+ echo "$output" | grep -qE '^BUCKET problems bytes=[0-9]+$'
188
+ problems_line=$(echo "$output" | grep '^BUCKET problems ')
189
+ bytes_value="${problems_line##*bytes=}"
190
+ [ "$bytes_value" -gt 0 ]
191
+ }
192
+
193
+ @test "measure-context-budget: problems bucket sums flat + per-state subdir tickets" {
194
+ mkdir -p "$FIXTURE_DIR/docs/problems/open" "$FIXTURE_DIR/docs/problems/verifying"
195
+ # Flat top-level (README + a pre-migration flat ticket) and per-state
196
+ # subdir tickets must all contribute to the bucket total.
197
+ printf '# Problems index\nrow\n' > "$FIXTURE_DIR/docs/problems/README.md"
198
+ printf '# Problem 050 legacy flat\nbody\n' > "$FIXTURE_DIR/docs/problems/050-legacy.open.md"
199
+ printf '# Problem 100\nbody body\n' > "$FIXTURE_DIR/docs/problems/open/100-foo.md"
200
+ printf '# Problem 101\nbody body body body\n' > "$FIXTURE_DIR/docs/problems/verifying/101-bar.md"
201
+ expected=0
202
+ for f in "$FIXTURE_DIR/docs/problems/README.md" \
203
+ "$FIXTURE_DIR/docs/problems/050-legacy.open.md" \
204
+ "$FIXTURE_DIR/docs/problems/open/100-foo.md" \
205
+ "$FIXTURE_DIR/docs/problems/verifying/101-bar.md"; do
206
+ b=$(wc -c < "$f" | tr -d ' ')
207
+ expected=$(( expected + b ))
208
+ done
209
+ run bash "$SCRIPT" "$FIXTURE_DIR"
210
+ [ "$status" -eq 0 ]
211
+ problems_line=$(echo "$output" | grep '^BUCKET problems ')
212
+ bytes_value="${problems_line##*bytes=}"
213
+ [ "$bytes_value" -eq "$expected" ]
214
+ }
215
+
216
+ @test "measure-context-budget: same ticket in flat + per-state subdir counted once (per-state wins)" {
217
+ # Mid-migration race: the same ticket ID exists as a flat file
218
+ # (200-dup.open.md) AND a per-state subdir file (open/200-dup.md) with a
219
+ # DIFFERENT byte size. ID-keyed dedup must count it once; the per-state
220
+ # subdir copy wins (ADR-031). Asserting the total equals the subdir file's
221
+ # size alone proves both: counted-once (not flat+subdir) and per-state-wins
222
+ # (subdir size, not flat size).
223
+ mkdir -p "$FIXTURE_DIR/docs/problems/open"
224
+ printf 'flat\n' > "$FIXTURE_DIR/docs/problems/200-dup.open.md"
225
+ printf 'per-state subdir copy is longer\n' > "$FIXTURE_DIR/docs/problems/open/200-dup.md"
226
+ subdir_bytes=$(wc -c < "$FIXTURE_DIR/docs/problems/open/200-dup.md" | tr -d ' ')
227
+ run bash "$SCRIPT" "$FIXTURE_DIR"
228
+ [ "$status" -eq 0 ]
229
+ problems_line=$(echo "$output" | grep '^BUCKET problems ')
230
+ bytes_value="${problems_line##*bytes=}"
231
+ [ "$bytes_value" -eq "$subdir_bytes" ]
232
+ }
233
+
172
234
  @test "measure-context-budget: populated briefing bucket reports byte count" {
173
235
  mkdir -p "$FIXTURE_DIR/docs/briefing"
174
236
  printf '# Topic\nentry\n' > "$FIXTURE_DIR/docs/briefing/foo.md"