The Bench, M2: answer a card by tapping a number, and the board says how - #26
Merged
Merged
Conversation
Item gains an Answer (reactionId, option, answeredAt) and a recorded marker, both serde-defaulted so an M1 state.json loads unchanged. pick_answer derives the answer from the approvers' kind-7 reactions on the live card: latest valid tap wins (owner decision; first-wins is reserved for tool approvals later). render_card appends a Recorded trailer through plain_title; render_board takes the clock, moves answered items out of Needs you into an Answered section and flags them after 24 h. Tests live in bench/tests/answers.rs so tests.rs stays under the 1500-line ratchet. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…piry Split query()/query_writer so the Bench can read the approvers' kind-7 reactions on its live cards; poll_answers re-derives every answer from that set each tick (latest valid reaction wins, a retraction is one that stopped coming back), writes outbox/<writer>/<id>.json before state records the answer, and only ever considers a card at the item's current hash so a stale card awaiting delete never re-supplies an answer. expire() folds a past-deadline pending item. The fake relay logs every /query body so tests can assert the filter shape. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…cleanup publish (a) leaves answered items out of the wanted cards and counts the kept answered cards against MAX_CARDS. New (a2), run before any card churn, edits the live card to show or drop its Recorded trailer, driven by the difference between Item.recorded and the answer; a refused edit on a hand-deleted card drops the card and keeps the answer. (b) exempts an answered card from the not-wanted delete for ANSWER_KEEP_SECS, then retires it with card and recorded reset, never to be reposted. intake removes the outbox file on the hash-change re-drop that acks an answer. The 40003 tag boilerplate moves into edit(), next to delete(). Tests: owner_tap_records_answer_and_writes_outbox now asserts the card Recorded edit ahead of the board edit and `recorded`; retraction_unrecords_in_place_and_latest_wins, answered_card_kept_24h_then_retired_never_reposted, recorded_edit_not_found_drops_card_keeps_answer and ack_by_redrop_clears_answer_and_outbox are new. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
serve() raises a single tauri_plugin_notification toast titled Bench with the tick error on the last_error None -> Some edge; an Ok tick re-arms it, so a relay outage is one toast, not one per 2 s tick. No Ctx or Cargo change: the plugin is already registered in lib.rs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- poll_answers only skips when the same reaction is already recorded, so the None arm runs every tick: a failed remove (Windows sharing violation) or a crash before save_state no longer leaves a withdrawn answer in outbox/ for the writer to act on. The ack re-drop sweeps the file unconditionally for the same reason. - poll_answers iterates items in place (no key clone, no second lookup). - Tests: retracted_answer_file_is_swept_when_state_forgot, truncated_answers_are_reported, kept_answered_cards_count_against_max_cards. - Not changed: a hard (a2) edit error still aborts the tick, as in M1 for every relay refusal; swallowing it would hide the failure from lastError and the toast. Build step 6 on the hosted relay decides. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The board gets a one-line legend under its header and bullets instead of ordinals under Needs you, so its lines no longer read like option keycaps. Unanswered pending cards get one line above 'as of' saying to tap a number below; answered cards keep only the Recorded trailer. CARD_FORMAT (2) is folded into the card version, not into the Drop hash: cards are posted and tagged at '<Drop hash>.<CARD_FORMAT>'. Publish (b) and orphan adoption compare against that, so every live unanswered card from an older build is deleted and reposted once, and a relaunch reads the new tag and reposts nothing. item.hash is untouched, so an identical re-drop is still a no-op and never clears an answer or the outbox file. live_card matches on the Drop part only, so an answered older-format card keeps its answer, keeps taking late pills and keeps its 24 h keep. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…r board A Recorded edit re-renders the whole card, so it now stamps card.hash with the current card format: undo (or an empty poll) on a card from an older build un-records it in place instead of (b) deleting it the same tick. Cards retired while showing the same Drop (format refresh, overflow, hand-deleted, recovered orphan) repost without the owner p tag via a persisted Item.quiet_repost, so the upgrade does not burst the phone. Board: blank line before each section so the desktop stops folding section names into the previous bullet; answered lines link their kept card; header reads 'needs you: N · answered: M'; legend and card hint say to tap one number and to untap before changing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…refresh Covers the verifier's surviving mutation: publish (b) retiring answered cards on a card-format mismatch. The test fails under that mutation and passes on the real code. Co-Authored-By: Claude Opus 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.
What this is
M2 of the Bench: the owner answers a card by tapping a number under it, and the Bench records the answer. It also makes the Bench explain itself, because nothing on M1's board or cards said how to answer.
Answering
/queryfor kind 7 reactions on the live cards, from the owner and anymembers.txtkey. The answer set is re-derived from scratch each time, so a removed reaction simply stops counting.etag is the current card, and the content exactly matches one of the seeded keycaps. Foreign keys, the Bench's own seeds, other emoji and stale cards are ignored.Recorded: 2. Move · HH:MM. It also writes~/.dreamforge/bench/outbox/<writer>/<id>.jsonwith the signed reaction for the session that asked. Undo reverses both.Self-explanatory
To answer: tap one number under a card. To undo or change it, tap that number again first.Tap one number below to answer.CARD_FORMAT = 2reposts cards from older builds once, without pinging the phone again. Cards that are already answered keep their answer, event id and outbox file.Verified
bench::55 passed, 0 failed.egress_guard18 passed. No clippy diagnostics underbench/.fmt --checkand the file-size ratchet are clean.Still to check on the hosted relay (needs an installed build)
#hplus#escoping of kind 7 on HTTP/querybehaves like this fork's relay.🤖 Generated with Claude Code