Skip to content

fix(wake-drain): surface unread status once via presentation cursor - #59

Merged
withally merged 2 commits into
mainfrom
fm/fm-unread-once-cursor-t1
Aug 20, 2026
Merged

withally merged 2 commits into
mainfrom
fm/fm-unread-once-cursor-t1

Conversation

@withally

Copy link
Copy Markdown
Owner

Intent

Stop fm-wake-drain from reprinting the entire unread-since-last-drain status history, including the observed 169KB-class dump to surface one new line, by selectively adapting public upstream commit db0280f/kunchenguid#2331 unread-once presentation-cursor design into this fork current unified presentation and annotation path. Reconcile it with this fork current version-5 incremental OPEN DECISIONS cursor precedent from #57/bf01a42 rather than blind cherry-picking or inventing a fork-only cap. Preserve upstream identity-level behavior for every unread note and pending-reply resolution and every unread direct-signal annotation, preserve transactional identity-bound presentation and teardown retirement, and retain the existing session-start annotation cap. Do not change OPEN DECISIONS identity or behavior from #57, watcher-arm count, successor-first coordinator, Grok idle work, VPS teardown work, or any product repository. Prove the cause against code and add behavior-level regression coverage, including migration from existing per-task decision cursors so only newly appended bytes surface, with invalid cursors failing safely. Measure a representative copied corpus before and after for a signal dump, empty warm drain, and cold drain; do not add a fork-only cold-refold optimizer unless the post-fix cold path still crosses about 15 seconds, and report numbers instead if it does. Account in the report for every relevant upstream commit after bf01a42 touching drain/classify/wake-lib and identify what the fork lacked. Deliver only through no-mistakes to a PR with CI-ready checks green; do not merge.

What Changed

  • Added a status_presentation_cursor in bin/fm-classify-lib.sh so wake-drain only re-emits status bytes appended since the last drain, instead of replaying the entire unread-since-last-drain history (previously a ~169KB dump to surface a single new line), while preserving unified presentation/annotation, transactional identity-bound retirement, and the session-start annotation cap.
  • Seeded the new presentation cursor from the existing per-task OPEN DECISIONS cursor (perf(wake-drain): bound open-decision scans by newly appended status bytes #57/bf01a42) so first-drain migration bounds output to newly appended bytes, with invalid cursors failing safe to byte zero.
  • Added tests/fm-wake-drain-unread-status.test.sh (5 regression cases) covering once-only note/pending-reply surfacing, annotation-cap preservation, decision-cursor migration bounds, and invalid-cursor fallback; registered the suite in bin/fm-test-run.sh and documented the cursor seeding in docs/architecture.md.

Risk Assessment

✅ Low: The change adds a read-only migration seed that fully re-validates the reused version-5 cursor and fails safe to byte zero, leaves the OPEN DECISIONS incremental fold untouched, and is covered by end-to-end regression tests for every intent-required behavior.

Testing

Baseline: the new regression suite tests/fm-wake-drain-unread-status.test.sh runs green (5/5). Primary product evidence: an A/B run of the real fm-wake-drain.sh against an identical ~168KB unread-since-last-drain corpus shows the pre-fix classify library emits a 473,097-byte dump replaying the whole history twice to surface one line, whereas the target fix emits 297 bytes surfacing only the newly appended line with zero history replays; empty warm drain is identical (54B). Migration from an existing per-task OPEN DECISIONS cursor and invalid-cursor fail-safe are both exercised. Cold-drain timing (22.5s post-fix) crosses the intent's ~15s threshold but is pre-existing and unchanged by this fix (base 28.0s) and sits in the classify fold, not the presentation cursor — reported as informational per the intent. Overall: the intended behavior is demonstrated working end-to-end; no test failures. Worktree left clean.

Evidence: A/B signal-dump measurement (base flood vs fixed bounded output)
BASE-prefix history=182400B signal_dump=473097B history_lines_replayed=2400 warm_drain=54B
TARGET-fix history=182400B signal_dump=297B history_lines_replayed=0 warm_drain=54B
Evidence: Target fixed drain output (complete, 297B)
<seq> signal task.status signal: copied corpus
wake annotation: latest wake-EVENT observed at drain, not current state: task.status: note: one newly appended signal line
UNREAD STATUS (new since last drain, not re-printed after this presentation):
task note: one newly appended signal line
Evidence: Cold-path timing (pre-existing, unchanged by fix)
BASE cold drain: 28.02s
TARGET cold drain: 22.54s
isolated presentation-cursor scan on 167KB corpus: 0.23s
realistic post-fix migration drain (1 new line over 168KB history): 1.13s
Evidence: Evidence summary
# fm-wake-drain unread-once presentation cursor — test evidence

Branch fm/fm-unread-once-cursor-t1 (target ddd46e1) vs base 2866370.
Library A/B: production drain run against an identical ~168KB unread-since-last-drain
status corpus, once with the base (pre-fix) classify library and once with the target.

## Signal dump (168KB history, ONE new line appended, decision cursor already at end)
| variant            | history | signal-dump output | history lines replayed | empty warm drain |
|--------------------|--------:|-------------------:|-----------------------:|-----------------:|
| BASE (pre-fix)     | 182400B |          473097B   |                   2400 |             54B  |
| TARGET (fix)       | 182400B |             297B   |                      0 |             54B  |

Base reprints the full history twice (as wake annotations + UNREAD STATUS) to surface
one line — the 169KB-class dump. The fix surfaces only the one new line: 473097B -> 297B.
Empty warm drain identical (54B) in both.

## Target signal-dump output (complete, 297B)
    <seq> signal task.status signal: copied corpus
    wake annotation: latest wake-EVENT observed at drain, not current state: task.status: note: one newly appended signal line
    UNREAD STATUS (new since last drain, not re-printed after this presentation):
    task note: one newly appended signal line

## Timing (representative 1200-line / ~167KB corpus)
- Realistic post-fix MIGRATION drain (decision cursor exists, 1 new line): 1.13s, bounded output.
- Isolated presentation-cursor scan on 167KB corpus: 0.23s.
- Cold drain (fresh state, huge pre-existing history, ZERO cursors): BASE 28.02s, TARGET 22.54s.
  The cold path is PRE-EXISTING (base is slower), lives in the classify fold not the
  presentation-cursor logic, and is unchanged/slightly improved by this fix. It crosses
  the intent's ~15s threshold, so the numbers are reported here rather than adding a
  fork-only cold-refold optimizer.

## Regression suite (tests/fm-wake-drain-unread-status.test.sh) — all 5 pass
- buried notes surface once (never replay)
- signal annotations retain fork cap without dropping unread identities
- pending-reply resolution surfaces once, OPEN DECISIONS behavior unchanged
- existing decision cursor bounds first presentation to appended bytes (migration)
- invalid decision cursor falls back to byte zero (fails safe, cannot hide history)
- Outcome: ⚠️ 1 info across 1 run (6m43s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

⚠️ **Test** - 1 info
  • ℹ️ Cold drain (fresh state, ~167KB pre-existing status, zero cursors) measures 22.5s post-fix, crossing the intent's ~15s threshold. This is pre-existing and unchanged by this fix (base is slower at 28.0s), and lives in the classify fold, not the presentation-cursor logic (isolated cursor scan = 0.23s; realistic post-fix migration drain = 1.13s). The fix correctly did not add a fork-only cold-refold optimizer; per the intent the number should be reported in the PR report. Non-blocking.
  • bash tests/fm-wake-drain-unread-status.test.sh — all 5 regression cases pass (buried notes surface once, annotation cap preserved, pending-reply resolves once, decision-cursor migration bounds first presentation, invalid cursor falls back to byte zero)
  • A/B: ran production bin/fm-wake-drain.sh against an identical ~168KB corpus with base vs target fm-classify-lib.sh; measured signal-dump bytes (BASE 473097B / 2400 replays vs TARGET 297B / 0 replays) and empty warm drain (54B both)
  • Timing: realistic post-fix migration drain=1.13s, isolated status_presentation_cursor_offset scan on 167KB=0.23s, cold drain BASE 28.02s vs TARGET 22.54s
  • Verified test-runner registration of the new suite in bin/fm-test-run.sh (family + line-count row)
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@withally
withally merged commit 816e659 into main Aug 20, 2026
16 of 25 checks passed
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