Tasks: submit with a paste, and say so on the ticket when a comment is lost
The last spec artifact (bugfix → design → testing plan → tasks). Derived from
design.mdandtesting-plan.md.
Eight tasks, two independent red roots. The tmux side (1 → 3) and the poller side (2 → 4) touch different files and can be worked in either order; they meet at task 6. tdd.mode: standard holds throughout: every production change below is preceded by the test that motivates it, and the red run is committed before any of it is written.
flowchart LR
T1["1. tmux tests (red)"] --> T3["3. deliver() without send-keys"]
T2["2. poller tests (red)"] --> T4["4. giveup notice"]
T3 --> T5["5. live tmux verification"]
T4 --> T5
T5 --> T6["6. capability + user docs"]
T6 --> T7["7. full suite, lint, typecheck"]
T7 --> T8["8. evidence + execution log"]Task list
[x] 1. Write the tmux delivery tests, and watch them fail
- Rewrite
test_deliver_pastes_with_bracketed_paste_then_enter(cli/tests/test_tmux_runner.py:308) astest_deliver_pastes_bracketed_then_submits_without_send_keys: assert the exact four-command argv sequence, that no command issend-keys, and that both pastes carry-d. - Add
test_deliver_removes_both_temporary_files: bothmkstemppaths are gone afterwards, including when the second paste fails. - Update the sequence assertion in
cli/tests/test_tmux_runner_integration.py:313under its existing Gherkin docstring. - Run against unfixed code and capture the failing output for
evidence/red.md. - Depends on: none
- Requirements: R4.1, R4.2
- Test:
T2, T5(red)
- Rewrite
[x] 2. Write the give-up notice tests, and watch them fail
cli/tests/test_poller.py:giveup_noticecarries the self-comment marker, a visible attribution line, the attempt count, the comment link and the recovery; and — the abuse case — contains none of an adversarial comment body, which it has no parameter to receive.cli/tests/test_poller_integration.py: Gherkin-documented scenarios for a give-up that posts exactly one notice, for the ledger being written even when the post fails, and for a second cycle posting nothing more.- Run against unfixed code and append the failing output for
evidence/red.md. - Depends on: none
- Requirements: R4.1, R4.3
- Test:
T3, T4, T6(red)
[x] 3. Submit with an unbracketed paste instead of
send-keyscli/the_loop/runner.py: add_SUBMIT_BUFFERand_SUBMIT_BYTESbeside_EVENT_BUFFER, with the reason (\r, not\n; a constant, never caller data).deliver: write both buffers through one tempfile helper, issue the four commands, return the first failure unchanged, and unlink both files infinally.- Leave every other branch — the empty-target guard,
has_live_session,session_missing,kill— untouched. - Depends on: 1
- Requirements: R1.1–R1.5, R3.1–R3.4
- Test:
T2, T5
[x] 4. Report a give-up on the ticket
cli/the_loop/poller/poller.py: add module-levelgiveup_notice(...)(pure,mark_self_authored, no parameter that can carry a comment body) andPoller._report_giveup(...)(best-effort; catches everything; emitspoll.giveup_reported/poll.giveup_report_failed).- Call it at the end of the give-up branch, after
resolve_comment(gave_up=True). - Take the
ghbinary fromself.dispatcher.config.announce.gh_binary; add no config key. - Depends on: 2
- Requirements: R2.1–R2.6
- Test:
T3, T4, T6
[x] 5. Verify the mechanism against a live tmux
- Execute T1 and T11 of the testing plan and write
evidence/manual.md: session set-up, a genuinetmux attach -rclient with#{client_readonly}=1, the bracketed paste, the CR paste, the pane's own output, and the per-releasecmd-send-keys.cguard counts. - Depends on: 3
- Requirements: R1.1, R1.3, R1.4
- Test:
T1, T11
- Execute T1 and T11 of the testing plan and write
[x] 6. Update the capability docs and the user-facing docs
docs/capabilities/interactive-sessions.md: how an event is delivered, and the read-only guarantee stated as behaviour with an issue-240 history row.- The poller capability doc: a give-up is reported on the ticket, and what the notice says.
- Any user-facing page describing
--read-onlyor the delivery mechanics. - Depends on: 4, 5
- Requirements: ready-to-ship gate
- Test:
markdownlint
[x] 7. Run what CI runs
make lint,make format-check,make typecheck,make test.- Depends on: 6
- Requirements: R3.1, R3.2
- Test:
T15
[x] 8. Complete the evidence and the execution log
evidence/red.md,evidence/unit-and-integration.md,evidence/manual.md;testing-plan.md§ Verification results;execution-log.md.- Depends on: 7
- Requirements: evidence gate
- Test: n/a — the record itself
Deviations
Production changes made that the design did not name, recorded here before they are done rather than explained afterwards.
TmuxRunner._buffer_fileis a new (private, static) helper. The design said "write both buffers through one tempfile helper"; naming it on the class rather than inlining it twice is that sentence made concrete, and it is what lets the write-failure cleanup be asserted directly (test_a_buffer_file_that_cannot_be_written_leaves_nothing_behind).Poller.__init__gainedcomment_runner. The design namedpost_issue_commentbut not how a test would drive it without a realgh. Added with asubprocess.rundefault, mirroringSessionAnnouncer/GitHubReactor— the conventioncomments.pydocuments._report_giveuptakes the polledWorkItem, notrefs. Self-review finding: a PR's refs lead with the issue it is linked to, so the design's impliedrefs[0]would have answered on the wrong ticket. Seeexecution-log.md, round 1.eventlog.EVENT_TYPESgained two entries. Not a design decision — the repository's owntest_every_emitted_event_type_is_documentedrequires every emitted type to be described, and it caught the omission.uv.lockregenerated. Not this work item's change: the10.2.1bump updatedcli/pyproject.tomland not the lock, so this branch is the first to runuv syncagainst the drift. Committed because CI cannot go green without it — the same thing issue-238 found at10.2.0, which makes it a recurring gap in the bump, flagged on the PR.