Skip to content

Bench: a closed card says a tap doesn't count and loses its buttons - #151

Merged
QuicksilverSlick merged 9 commits into
mainfrom
fix/bench-old-receipts
Nov 10, 2026
Merged

QuicksilverSlick merged 9 commits into
mainfrom
fix/bench-old-receipts

Conversation

@QuicksilverSlick

Copy link
Copy Markdown
Owner

Factory-Task: bench/old-receipts
Built-by: claude-code/claude-opus-5-5
Claude-Account: russelledeming@gmail.com
Undo: revert the merge. Older builds ignore the new receiptsTodo key in state.json. Receipts already edited keep their first line and missing seeds.

Stacked on the cards PR (fix/bench-old-cards): merge that first. It is the same work split to keep each PR under the lane's ~600 lines. When both ride one train, one launch check covers both.

Needs a desktop launch check, because it touches desktop/. The code it changes is Bench service code, which does not run in a debug build, so the launch check only shows the app still starts. The first real test is the installed app after the update.

What changes

#125 named these as the largest group of dead pills. There were 55 on 1 Nov and there are 92 on 4 Nov, about 20 more a day.

  • A close-out does what a replaced card does. The receipt gets "No longer asked. A tap here doesn't count." on its first line and the Closed note, and loses its seeds. For 24 h a tap on it gets one reply. It stays item.card, so the kit's findCard is unaffected, and the answer it closed with is no new tap.
  • Old receipts catch up. The ones in state get the same edit and lose their seeds, one at a time, in about 4 minutes after the update. They are not watched: most closed days ago, past the 24 h window, and a tap there gets no reply.
  • A receipt's edit can't fail a tick. It used to set lastError, which stops the kit's approvals. It now goes on the board under "Old cards".
  • A later close-out gets its own 24 h, for its retries and for a tap's reply.
  • A close-out waits for its channel. In a channel that isn't ready nothing is owed yet, so nothing can run out. The edit goes once the channel is ready.
  • A new card format is no close-out. A CARD_FORMAT bump edits every receipt again, unwatched, as the catch-up does, so it can't fill WATCH_MAX or raise a false alarm.

Two visible side effects. A receipt's edit now follows the tick's other work, so the board may update first. Its Outcome shows when the close-out came in, not the tick that edited it, which is the same minute unless the budget delayed the edit.

The #782 search evidence is in fix/bench-old-cards. Its row "Back to you: Release refreshed lead..." is one of these receipts, daa8272a0b23, with 4 seeds.

How to verify on the phone

Each step takes under a minute.

  1. After the update, wait about 4 minutes. Open #bench in the channel, not search, which keeps showing the old text. Find the "Back to you: Release refreshed lead..." card. Its first line should say "No longer asked. A tap here doesn't count." Its number pills should be gone, except any you tapped. If they stay, Block's build ignores the removal: the first line still holds, but tell us.
  2. On the next card closed out after the update, add a number from the reaction picker. Within seconds there should be an inbox mention and a "1 reply" link saying "That tap didn't count". Nothing should be recorded.

For the session doing the launch check: after the update, receiptsTodo in ~/.dreamforge/bench/state.json should fall to [] in about 4 minutes, with lastError null and no "Old cards" on the board.

Budgets

Sizes are from state.json on 4 Nov 2026: 92 receipts with 279 seeds. The limits are those in fix/bench-old-cards: 4 writes and 1 lookup a tick, WATCH_MAX 100.

  • One close-out costs: 1 edit, 1 lookup and up to 4 removals. A reply adds 1 lookup and 1 post.
  • Old receipts: 92 edits and 279 removals, 371 writes in about 106 ticks. One at a time, behind live work.
  • A CARD_FORMAT bump: 1 edit and 1 lookup per receipt, all owed at once. The 1 lookup a tick sets the pace, about 2 s a receipt, so 103 receipts take about 4 minutes and the 24 h holds about 43,000.
  • When it fills: a relay refusing them holds one on the board ("Would not update"), not all of them in state. A receipt waiting on a channel that isn't ready stays listed. A close-out there keeps its old hash and goes out once the channel is ready, however long that takes, and the board's "Cards refused" says why. There are no such channels today.
  • WATCH_MAX: about 20 close-outs a day sit inside the 100. Ten times that passes it, and the board then says the oldest go unread and what to do. Old receipts don't count, before or after a format bump, as they aren't watched.

Known limits

What was exercised, and how

All of this ran on this Windows machine. The real app, Block's relay and Block's phone were not run. The relay in the Rust tests is the harness's fake one.

Rebased on 9 Nov 2026 onto the cards PR, itself on main at 5e1fce0cb. The only conflict was two additions landing side by side in bench/replaced.rs, and both stayed. After the second review's fixes, also on 9 Nov, I re-ran the Bench tests, the whole cargo test --lib, cargo fmt --check, clippy, check-file-sizes and git merge-tree at this head. The other results below are from before those fixes.

  • Rust: cargo test --lib bench:: gave 229 passed, 0 failed, 2 ignored at this head, which is the cards PR's 220 and this one's 9. The whole cargo test --lib at this head gave 3527 passed, 0 failed, 16 ignored. The mesh-llm and compiled-flags lanes were not run; Linux CI covers them.
  • Rust checks: cargo fmt --check exits 0. cargo clippy -p buzz-desktop --lib --tests exits 0 with nothing under src/bench. check-file-sizes exits 0, with mod.rs at 1500 of 1500, so its next line needs a move.
  • Mutations: I took out 8 guards one at a time, and each fails a test: making a close-out an old post, one post for a later close-out, forgetting a card gone from the relay, running the backfill, one at a time, unwatched, never touching a card asked again (it would edit a live card), and waiting for a channel that isn't ready. After the review, 5 more at this head, each failing a test: the thread root taken out of a receipt's reply, a close-out not waiting for its channel, a later close-out keeping the first one's clock, and a format bump watching every receipt or a real close-out watching none.
  • Desktop: no JS or test vector changed. pnpm test gave 7201 + 193 passed, 0 failed. The parser already handles this text from fix(bench): a replaced card says so, and a tap on it is told it didn't count #125 (a replaced receipt lays its Outcome out as its own card).
  • Kit: not touched and its tests not re-run. findCard reads item.card, which this keeps, and kind, which a receipt already fails.
  • Merges: git merge-tree is clean against main at 849bd8bbb.
  • Not done: the desktop launch check.

Review

An independent review covered both branches on 9 Nov 2026 and found four things here. None needs a decision.

  • A close-out in a channel not ready for over 24 h lost its edit silently. Fixed (a_close_out_in_a_channel_not_ready_keeps_its_edit).
  • A later close-out inherited the first one's 24 h, so a failed edit late in that window was never retried. Fixed (a_later_close_out_gets_its_own_window).
  • A format bump watched every old receipt. Fixed (a_format_bump_watches_no_old_receipt).
  • Nothing tested the thread root on a receipt's one reply, which the real relay checks and the fake one doesn't. A test now pins it (a_tap_on_a_receipt_in_a_thread_is_told_under_its_root).

Size: 481 changed lines, 133 of code and 348 of tests.

🤖 Generated with Claude Code

QuicksilverSlick and others added 9 commits November 9, 2026 13:52
A phone that lost its socket across a delete keeps showing the card, the
relay refuses a tap on it and the phone's code ignores the refusal, so
the tap vanishes with nothing said. An untouched re-drop or a card no
longer asked now stays, as a kept one does: its first line says a tap
doesn't count, its seeds come off and a tap on it gets one reply.

Publish (b) no longer calls the relay, so nothing there can fail a tick.
The edit, its lookup and any failure are the old posts' tick's, on the
same budgets, and on the board under "Old cards".

Claude-Account: russelledeming@gmail.com
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every card retired in a thread added a kept_at entry, including untouched
ones main deleted and left no entry for. An older card still open in that
thread then stopped taking replies that name only the root, for good,
with nothing said.

A retired post in a thread now reads what is on it once it is edited, and
adds the entry only if there is something besides its seeds and its own
closing edit, as main did. It costs one lookup more, on the old posts'
one a tick, and only for a post in a thread.

Claude-Account: russelledeming@gmail.com
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Retired posts now stay on the relay with their bench:card marker. With
state lost and the same Drop asked again, publish (c) adopted one as the
live card: a seedless post saying a tap doesn't count, whose tap would
then be read as the answer.

An orphan edited closed now goes to kept like any orphan with something
on it, and a new card goes up. One lookup per orphan, after lost state
only.

Claude-Account: russelledeming@gmail.com
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing failed with `held` taken out of publish (b)'s guard: a re-worded
drop waits in the inbox before it gets there, so only a card whose format
moved reaches it. Without the guard that card is retired for good with a
tap on it unread.

Claude-Account: russelledeming@gmail.com
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Close-out receipts are the largest group of dead pills: 92 on 4 Nov. A
close-out now makes its card an old post: first line, Closed note, seeds
off, and for 24 h one reply to a tap. It stays item.card, so the kit's
findCard is unaffected, and its edit no longer fails a tick.

Receipts already in state catch up one at a time behind live work,
unwatched, in about 4 minutes.

Claude-Account: russelledeming@gmail.com
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The real relay refuses a reply whose root doesn't match the thread, but
the fake one doesn't check, so every Bench test still passed with the
root taken out of showing(). A tap on a receipt in a thread would have
failed its one reply for the whole window, with CI green.

Claude-Account: russelledeming@gmail.com
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Publish (a2b) moved the card's hash on and owed the edit even in a channel
that isn't ready. The old posts' tick skips those, so past 24 h the entry
went with no try and no alarm, and the hash had already moved, so the
receipt kept its live text for good.

The hash now stays behind until the channel is ready, so the close-out
is picked up then, however long that takes.

Claude-Account: russelledeming@gmail.com
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A later close-out on a receipt still in `replaced` changed only what it
shows and kept the first one's clock. An edit failing once near the end
of those 24 h was let go before its retry, and the hash had moved on, so
the phone kept the older report with nothing said after that.

Claude-Account: russelledeming@gmail.com
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A format bump changes every receipt's hash, so publish (a2b) made each one
a watched old post in one tick. That filled WATCH_MAX with posts closed
days ago, put a false alarm on the board and pushed real old posts out of
the read.

Only a real close-out is watched now. When just the format or stamp moved
the receipt is edited again unwatched, as the backfill does.

Claude-Account: russelledeming@gmail.com
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@QuicksilverSlick QuicksilverSlick added the lane:ready Builder is done: green, agent-reviewed, exercised. The steward puts it in the next train. label Nov 9, 2026
@QuicksilverSlick
QuicksilverSlick changed the base branch from fix/bench-old-cards to main November 10, 2026 00:18
@QuicksilverSlick
QuicksilverSlick merged commit 5c9efad into main Nov 10, 2026
63 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lane:ready Builder is done: green, agent-reviewed, exercised. The steward puts it in the next train.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant