Skip to content

roadmap(#229): P1 precompact hook stale-handoff auto-expire - #227

Merged
BaseInfinity merged 4 commits into
mainfrom
roadmap-229-stale-handoff-expire
Apr 24, 2026
Merged

roadmap(#229): P1 precompact hook stale-handoff auto-expire#227
BaseInfinity merged 4 commits into
mainfrom
roadmap-229-stale-handoff-expire

Conversation

@BaseInfinity

@BaseInfinity BaseInfinity commented Apr 23, 2026

Copy link
Copy Markdown
Owner

Summary

P1 wizard UX bug found during 2026-04-23 live-fire shepherd session. The precompact-seam-check hook blocked a manual /compact because .reviews/handoff.json was stuck at PENDING_RECHECK from the original review that SHIPPED the hook (review_id: precompact-seam-001).

That review was written BEFORE the self-heal pr_number feature (ROADMAP #209) existed, so there's no PR to auto-query. The handoff is stuck forever until manually flipped.

Every wizard user who did a seam review before #209 has this landmine in their repo.

Fix (shipped in 58d1a86 / d761028)

hooks/precompact-seam-check.sh now has two self-heal paths:

Paths are mutually exclusive: if [ -n "$PR_NUMBER" ] / else structure ensures an OPEN PR with an old mtime is still treated as live and blocks.

Tests

4 new tests in tests/test-hooks.sh, all passing (19/19 precompact tests green):

  • test_precompact_unblocks_stale_pending_without_pr_number — stale + no pr → unblock + WARN
  • test_precompact_still_blocks_fresh_pending_without_pr_number — fresh + no pr → still block (regression guard)
  • test_precompact_stale_with_pr_number_prefers_self_heal — stale + pr OPEN → still block (pr_number wins)
  • test_precompact_stale_threshold_overrideSDLC_HANDOFF_STALE_DAYS=0 → all PENDING stale

Rationale for 14-day default

  • Typical Codex review round-trip: <1 day
  • PR rebase cycles rarely exceed 7 days
  • 14 is ~2x the 99th-percentile review lifetime — wide enough to not fire on legitimate in-flight work, tight enough to rescue forgotten artifacts

Power users can tune via SDLC_HANDOFF_STALE_DAYS env var.

Shepherd loop

  • TDD RED: 2 new tests fail against old hook
  • TDD GREEN: all 4 new + 15 existing precompact tests pass
  • Full test-hooks.sh: 114 passed (1 pre-existing failure on main, unrelated)
  • Cross-model Codex review (in flight — see .reviews/latest-review.md when complete)
  • CI green
  • Merge after Codex CERTIFIED + CI green

CI caught a real portability bug: `stat -f %m` on Linux is
`--file-system` (dumps FS info to stdout, exit 0), not format.
My `||` fallback never fired, $MTIME got garbage, and arithmetic
blew up on every PENDING handoff path — regressing the existing
PENDING_REVIEW/RECHECK blocks.

Fix: try GNU `stat -c %Y` first (BSD errors → falls through).
Add numeric case-guard so any junk in $MTIME skips the stale
check entirely and falls through to HOLD (safe default).

Locally macOS green. Pushing to verify Linux CI passes now.
@github-actions

Copy link
Copy Markdown
Contributor

Claude Code Review Summary

Status: Skipped (trivial changes)

This PR only contains documentation or configuration changes. Code review skipped to save API costs.


To force a review, add the needs-review label.

Codex review of PR #227 caught: `SDLC_HANDOFF_STALE_DAYS=foo` leaked
`[: foo: integer expression expected` to stderr before the normal HOLD
text. A typo in the env var should silently fall back, not emit shell
diagnostics.

Fix: non-negative-integer case-pattern guard. Empty, non-numeric,
negative, or decimal values fall back to default 14.

Test: test_precompact_stale_threshold_invalid_falls_back asserts rc=2,
PENDING_REVIEW in stderr, and NO `integer expression` noise. 20/20
precompact tests green.

Codex score: 8/10 CERTIFIED (this addresses the sole P2 finding).
@BaseInfinity
BaseInfinity merged commit 07807b4 into main Apr 24, 2026
4 of 5 checks passed
Live-fire bug 2026-04-23: at session end, /compact was blocked by
the precompact-seam hook because .reviews/handoff.json is stuck at
PENDING_RECHECK from the review that SHIPPED the hook itself.

That original review was written BEFORE the self-heal pr_number
feature (#209) existed, so there's no PR to auto-query. Handoff is
stuck forever until manually flipped.

Every wizard user who did a seam review before #209 has this
landmine in their repo.

Fix: add stale-handoff auto-expire. PENDING_* + no pr_number +
mtime > N days → treat as CERTIFIED with WARN (not HOLD). Rescues
stale handoffs without bypassing live reviews.

P1 because it silently blocks a core UX (manual /compact) and the
user hit it mid-session.
Fix UX landmine where handoff.json reviews predating the #209 pr_number
self-heal feature would block manual /compact forever.

Hook now heals via two paths:
- (a) #209: pr_number + gh says MERGED → silent unblock
- (b) #229: no pr_number + mtime > SDLC_HANDOFF_STALE_DAYS (default 14)
      → unblock with one-line WARN

PR-linked handoffs still ignore mtime — an OPEN PR with old mtime is
still a live review.

Tests: 4 new in test-hooks.sh covering stale-unblocks, fresh-still-blocks,
stale-with-pr_number-prefers-self-heal, threshold-override. 19/19
precompact tests green.

Caught live-fire 2026-04-23 when session-end /compact blocked on a
review that shipped the hook itself.
BaseInfinity added a commit that referenced this pull request Apr 28, 2026
…pdate (#271)

Two `cusum.sh --add` calls in weekly-update.yml (version-test + community-
e2e-test jobs) appended scores to tests/e2e/score-history.txt, which is
tracked by git. Result: every weekly run opened a PR whose only diff was
the legacy side-file append — pure noise (Codex finding PR213-02 on auto-
PR #213, 2026-04-23).

The canonical history is score-history.jsonl, written via the CI Tier 2
persist step in ci.yml. The PR bodies already cite Phase A / baseline
scores directly, so removing the standalone CUSUM update steps loses
nothing functional.

Per Codex consult this session: prefer "stop writing the .txt" over
"close PRs with only that diff" (avoids GitHub API edge cases, simpler).

New regression test test_weekly_update_does_not_call_legacy_cusum_add
in tests/test-workflow-triggers.sh greps for `cusum.sh --add ` (legacy
.txt write) and fails if reintroduced. --add-json (canonical .jsonl) is
unaffected.

Closes #227
BaseInfinity added a commit that referenced this pull request Apr 29, 2026
Closes #227 (Codex finding PR213-02). The PR-noise source was the
scan-community job appending to legacy score-history.txt via
`cusum.sh --add`. #231 Phase 3c (v1.53.0) deleted that whole job, so
the noise source is already gone — Test 227 in
test-workflow-triggers.sh:2445 is the regression check.

Cleanup pass:
- Delete empty tests/e2e/score-history.txt from the repo (was a stale
  runtime artifact, never appended-to since Phase 3c)
- Add tests/e2e/score-history.txt to .gitignore (test-cusum.sh
  recreates it on runs that exercise legacy --add mode)
- Drop the stale .txt mention in plans/AUTO_SELF_UPDATE.md (was a
  Files Structure block listing both .txt and .jsonl; .jsonl is the
  canonical store now)

cusum.sh keeps both modes (--add legacy plain-text + --add-json
canonical JSONL) for users who want plain-text mode for ad-hoc CLI
work. No interface change.

No version bump — zero user-facing change. Tests still 169/169 +
50/50 (cusum) green.
BaseInfinity added a commit that referenced this pull request May 5, 2026
Codex review of PR #227 caught: `SDLC_HANDOFF_STALE_DAYS=foo` leaked
`[: foo: integer expression expected` to stderr before the normal HOLD
text. A typo in the env var should silently fall back, not emit shell
diagnostics.

Fix: non-negative-integer case-pattern guard. Empty, non-numeric,
negative, or decimal values fall back to default 14.

Test: test_precompact_stale_threshold_invalid_falls_back asserts rc=2,
PENDING_REVIEW in stderr, and NO `integer expression` noise. 20/20
precompact tests green.

Codex score: 8/10 CERTIFIED (this addresses the sole P2 finding).
BaseInfinity added a commit that referenced this pull request May 5, 2026
* release: v1.36.0

See CHANGELOG for details. Bumps:
- package.json: 1.35.0 -> 1.36.0
- SDLC.md metadata + visible table
- CLAUDE_CODE_SDLC_WIZARD.md example version (2 places)
- skills/update/SKILL.md example output Latest line
- CHANGELOG new section

* chore: record E2E score [skip ci]

* roadmap(#224-227): follow-ups from Codex review of auto-PRs #210, #213

Four new backlog items surfaced by Codex batch review of the
auto-generated PRs (2026-04-23):

From PR #210 (CC 2.1.118 auto-update analysis):
- #224: runtime test for sdlc-prompt-check.sh double-firing — CC
        2.1.118 shipped the fix, we have no assertion it holds.
- #225: document cleanupPeriodDays minimum — TodoWrite checklists
        now fall under that retention sweep (CC 2.1.117).

From PR #213 (community patterns, closed):
- #226: P1 — weekly-update workflow reports fake 5-trial CI
        (re-scores one transcript N times, not N simulations).
        Current STABLE verdicts aren't trustworthy.
- #227: stop writing legacy score-history.txt in community PRs.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
BaseInfinity added a commit that referenced this pull request May 5, 2026
…pdate (#271)

Two `cusum.sh --add` calls in weekly-update.yml (version-test + community-
e2e-test jobs) appended scores to tests/e2e/score-history.txt, which is
tracked by git. Result: every weekly run opened a PR whose only diff was
the legacy side-file append — pure noise (Codex finding PR213-02 on auto-
PR #213, 2026-04-23).

The canonical history is score-history.jsonl, written via the CI Tier 2
persist step in ci.yml. The PR bodies already cite Phase A / baseline
scores directly, so removing the standalone CUSUM update steps loses
nothing functional.

Per Codex consult this session: prefer "stop writing the .txt" over
"close PRs with only that diff" (avoids GitHub API edge cases, simpler).

New regression test test_weekly_update_does_not_call_legacy_cusum_add
in tests/test-workflow-triggers.sh greps for `cusum.sh --add ` (legacy
.txt write) and fails if reintroduced. --add-json (canonical .jsonl) is
unaffected.

Closes #227
BaseInfinity added a commit that referenced this pull request May 5, 2026
Closes #227 (Codex finding PR213-02). The PR-noise source was the
scan-community job appending to legacy score-history.txt via
`cusum.sh --add`. #231 Phase 3c (v1.53.0) deleted that whole job, so
the noise source is already gone — Test 227 in
test-workflow-triggers.sh:2445 is the regression check.

Cleanup pass:
- Delete empty tests/e2e/score-history.txt from the repo (was a stale
  runtime artifact, never appended-to since Phase 3c)
- Add tests/e2e/score-history.txt to .gitignore (test-cusum.sh
  recreates it on runs that exercise legacy --add mode)
- Drop the stale .txt mention in plans/AUTO_SELF_UPDATE.md (was a
  Files Structure block listing both .txt and .jsonl; .jsonl is the
  canonical store now)

cusum.sh keeps both modes (--add legacy plain-text + --add-json
canonical JSONL) for users who want plain-text mode for ad-hoc CLI
work. No interface change.

No version bump — zero user-facing change. Tests still 169/169 +
50/50 (cusum) green.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant