Repository navigation
Bench: a card no longer asked is edited closed instead of deleted - #150
Merged
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Factory-Task: bench/old-cards-edited
Built-by: claude-code/claude-opus-5-5
Claude-Account: russelledeming@gmail.com
Undo: revert the merge. Older builds ignore the new
fromPostkey in state.json. Posts already edited keep their first line and missing seeds, and a card kept instead of deleted stays in the feed.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 (see the phone steps).The receipts PR (
fix/bench-old-receipts) is stacked on this one and does the close-out receipts. It is separate because together they pass the lane's ~600 lines. When both ride one train, one launch check covers both.Russell accepted one trade on 9 Nov 2026 (decision 6, yes). A retired card now stays for good in the phone's Search and Activity lists, reading as it was first posted. In return, an old post says on its first line that a tap doesn't count, and a tap after a socket gap gets an answer instead of vanishing with nothing said. See "Search and Activity" under Known limits. Reverting this PR alone restores the deletes. I did not try that revert with the stacked PR on top.
What changes
Follow-up to #125, for the path it left alone.
replaced.rsdoes the rest behind live work.lastErrorstops the kit's approvals, so failures go on the board under "Old cards". A failed delete or close there used to setlastError.One visible side effect: an old post is now edited after its new card goes up, not before, so live work goes first.
Not changed:
CARD_FORMAT, the kit'sfindCard, the text the kit parses andWATCH_MAX. The orphan path, which needs lost state, still deletes an orphan nobody touched. Its one change is that a post edited closed is never adopted as the live card (see "Repost storm").What the block#782 search shows
His screenshots do not show a deleted card staying on the phone. A search cannot show one.
mobile/lib/features/search/search_provider.dart). The relay drops deleted events twice:deleted_at IS NULLin the search query and again when it loads the hits. This is the fork's relay code. Block's hosted relay was not read.Each row lines up with a post the Bench never deleted. The screenshots show no ids, so I matched them by title, heading and time.
8848ebead096kept51d8c27105e0kept, no answer recorded (inferred)9bc794e294f4keptdaa8272a0b23be8c7de7da99#125 has never fired in production.
kepthas held 8 since 1 Nov 20:10 CT, before #125 merged at 22:33, andreplacedis empty in every backup since. The three kept block#782 posts predate it and were not backfilled, so they still have their pills.The channel view differs, and that is where a deleted card can stay. It shows edits and pills. A fresh open reads the relay, and a kind 5 that arrives live removes the post. But a card deleted while the socket was down stays on screen until the app restarts:
_initmerges the rows it holds with the new page, and the page's deletion markers only cover rows it returns. A tap there is refused ("reaction target event not found"), and the unawaitedaddReactionshows nothing. This is why the delete path goes, at the cost of a few more dead posts. I read this in the fork'smobile/. I did not run it (no Flutter on this machine) and did not read Block's build.The lost tap on block#782 is not settled. State records no deletes, so I cannot rule out a deleted block#782 card: the Orchestrator's writes at 01:31 and 01:49 UTC on 1 Nov could have posted one that went at 01:57. But a tap on a kept post with its pills fits with no delete at all.
51d8c27105e0looks like that post. At 00:15 UTC on 2 Nov,9bc794e294f4had noprevious, so it carried no earlier answer. That only says51d8c27105e0closed with none recorded ifb37fa9531d0awas not a block#782 card.keptlists it between the two, it appears in no sampled state, andcarry_cardcan lose an earlier answer across a close-out. Phone step 1 tests this: a highlighted pill settles it, and no highlight leaves it open.A phone fix can't reach him from this repo. The fix is about 15 lines plus tests: catch the refusal at the 4
addReactioncall sites and say so, and drop rows the new page no longer returns. But his phone runs Block's Play build, last confirmed by him on 16 Sep and noted again on 29 Oct, and the fork has never released a phone app. So it needs Block to ship it, or a sideloaded build with its own signing and app id. Filing it upstream needs his OK.How to verify on the phone
Steps 2 and 3 take under a minute each. Step 1 may take longer.
b37fa9531d0awas not a fix(desktop): sync persona pack directory across worktree instances block/buzz#782 card. So if a number pill there is highlighted as yours, that is the lost tap, and it landed on a kept post. If none is, the tap went somewhere else and a deleted card stays possible.~/.dreamforge/bench/inbox/<writer>/, then drop it again reworded. Leave the first one untapped. In #bench, in the channel rather than search, the old post should stay. Its first line should say "Replaced by a newer card. A tap here doesn't count." and its pills should be gone.Budgets
WATCH_MAX, unchanged)MAX_CARDS+OVER_CAP) with 4 options each, that is 200 writes for the new cards (50 ticks), then 200 for the old posts at 2 ticks each (80 ticks, or 3 ticks each for one in a thread): about 4 minutes. The test runs 5 cards against the same budgets and checks every tick stays inside them.Repost storm: none found. Publish (b) decides staleness from the card's hash against its item, and editing an old post changes neither. An old post is pushed to
keptbefore the card is forgotten, so a relaunch never adopts it (an_old_post_never_brings_a_repost, which also covers state lost). Withkeptlost too and the same Drop asked again, a post edited closed stays an old post and a new card goes up (lost_state_never_adopts_a_post_edited_closed). One outside cause remains: aroles.jsonthat flaps every tick would repost every tick, as it does today, but the old posts would now stay. Writes stay inside the 4 a tick. I saw no sign of this.Known limits
#pand shows the event's owncontent. An edit is kind 40003. So each untouched re-ask adds a Search row, and an Activity row if the card pinged him (ping_ownertags pending needs-you cards). The row reads as the original card, including "Tap one number below to answer", with no "Replaced by" line. On main, deleting an untouched card removed it from both, since the relay's search drops deleted rows. Search is where the fix(desktop): sync persona pack directory across worktree instances block/buzz#782 question started, and this change only adds rows there. I read the kinds and thecontentin the fork'smobile/and at Block's tagsmobile-v0.20.0-rc.1andmobile-v0.27.0-rc.15, and did not run any of it. The cost is slow, at the rate below. This is the trade he accepted on 9 Nov 2026: a few stale-looking rows in those lists, against a tap that vanishes after a socket gap.CARD_FORMATbump would leave one old post per open card.lastErrorfor that tick. This change adds a few a day to that count.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 main at
5e1fce0cb, with no conflict. The five commits it picked up touch onlyCargo.lock,deny.tomlandcrates/buzz-huddle-bridge, nothing in the Bench. After the second review's fixes, also on 9 Nov, I re-ran the Bench tests, the wholecargo test --lib,cargo fmt --check, clippy,check-file-sizesandgit merge-treeat this head. The other results below are from before those fixes.cargo test --lib bench::gave 220 passed, 0 failed, 2 ignored at this head. Main before the rebase gave 212 passed, 0 failed, 2 ignored. The wholecargo test --libat this head gave 3518 passed, 0 failed, 16 ignored. Themesh-llmand compiled-flags lanes were not run; Linux CI covers them.cargo fmt --checkexits 0.cargo clippy -p buzz-desktop --lib --testsexits 0 with nothing undersrc/bench.check-file-sizesexits 0.kept_at, its root for the reply, and#[serde(default)]on the new key. Two survived at first (the lookup cap and charging the edit), so the tests got sharper and I re-ran those two. A third showed a check inidle()was redundant, so it came out. The first ran on this commit. The other 10 ran on the stack's combined tree, not on this commit alone. I also tried a one-wordbreakin place of thereturnthe tick takes when lookups run out: it frees failed posts too, but drops an owed post past its window with no try, for example after the Bench was off for a day, sopast_its_window_a_post_still_gets_its_try_when_lookups_run_outfails on it. After the second review, 6 more at this head, each failing a test:heldtaken out of (b)'s guard; a retired post in a thread always adding itskept_atentry, never adding it, or counting its own closing edit as something on it; adopting a post edited closed; and treating any edit as a closing one.pnpm testgave 7201 + 193 passed, 0 failed.state.items, and this adds one key underreplaced.git merge-treeis clean against main at849bd8bbb, five commits past this branch's base. On 9 Novgh pr listshows no other open PR touching the Bench.Review
One adversarial review has run on this branch. It found three things, all in this body now: Search and Activity (Known limits), failed posts outliving their 24 h when lookups ran out (fixed, with a test), and phone step 1 and one time in the table (corrected).
A second, independent review covered both branches on 9 Nov 2026 and found three things here. None needs a decision.
a_retired_card_nobody_touched_ends_no_older_cards_window).lost_state_never_adopts_a_post_edited_closed).heldin (b)'s guard. The code was right, and a test now pins it (a_cut_owner_page_leaves_a_stale_format_card_up).Size: 599 changed lines, 186 of code and 413 of tests.
🤖 Generated with Claude Code