Tasks: the kickoff holds its message and asks which repository
Derived mechanically from the locked
design.mdandtesting-plan.md. No approval gate (issue-281) — it advances on shape alone. Each_Test:_names a row of the testing plan.
flowchart LR
T1["1 · resolver: askable,<br/>uniform text, question_text"] --> T4["4 · the fork in<br/>process_kickoff"]
T2["2 · state: the pending map"] --> T4
T3["3 · slack: the picker blocks,<br/>the select read, the status"] --> T4
T4 --> T5["5 · process_kickoff_answer<br/>+ the action route"]
T1 --> T6["6 · tests: resolver"]
T2 --> T7["7 · tests: state"]
T3 --> T8["8 · tests: rendering"]
T5 --> T9["9 · tests: fork + answer"]
T5 --> T10["10 · tests: abuse cases A1–A10"]
T5 --> T11["11 · tests: integration (Gherkin)"]
T5 --> T12["12 · docs, capability docs,<br/>decision-122"]
T6 --> T13["13 · verification + evidence"]
T7 --> T13
T8 --> T13
T9 --> T13
T10 --> T13
T11 --> T13
T12 --> T13Tasks
[x] 1 ·
channels/kickoff.py: what is askable, and one meaning fortextAddKickoffTarget.askable. Make_strip_prefixapply wherever a prefix was actually read (ambiguous-repo, qualifiedunknown-repo), sotextmeans "the message the issue is composed from" on every outcome; route a now-empty message toempty-message. Addquestion_text(target)besiderefusal_text— one preamble per askable outcome, one shared closing line naming the<repo>:shortcut, nothing of the member's message. Update the module docstring's outcome table. Requirements: R1.1–R1.4, R1.6, R2.5. Test: T1.[x] 2 ·
channels/state.py: the pending map A fourth map,pending, loaded as{}from a file that lacks it and always saved.PENDING_TTL_SECONDS = 24 * 60 * 60,PENDING_CAP = 50. Methodsask,pending,claim,restore,prune_pending, with expiry read as absence and swept on write, and the cap dropping the oldest. Update the module docstring. Requirements: R3.1, R3.2, R3.3, R3.4. Test: T2.[x] 3 ·
channels/slack.py: the picker, the select read, the statusKICKOFF_REPO_ACTION,BUTTON_CHOICE_LIMIT = 5,OPTION_LIMIT = 100;render_kickoff_question(text, options)choosing buttons or astatic_select;_action_value(action)preferringselected_option.value; aBUTTON_NAMESentry;SlackChannelConfig.kickoff_picker. Requirements: R2.1–R2.4, R4.2, R5.1. Test: T3.[x] 4 ·
channels/inbound.py: the fork and_open_work_itemLift the create/bind/reply tail ofprocess_kickoffinto_open_work_itemunchanged, and call it from the resolved path. Add the askable branch: options (matched candidates forambiguous-repo, otherwise every declared slug),kickoff_picker, a non-empty option set, no record already pending — thenstate.ask+ the question, with the record removed if the post fails. Requirements: R1.1–R1.5, R3.7, R5.1, R5.3. Test: T4.[x] 5 ·
channels/inbound.py:process_kickoff_answerand the action route RouteKICKOFF_REPO_ACTIONinhandle_socket_actionabove theprocess_replypath. Five gates in order — the channel's own permission re-read at press time, authorized, the message's own author, a live record, a value in both the offered set and the declared set — each with its own drop reason; then claim,_open_work_item, restore on failure, andreport_pressfor every press above the allow-list (KICKOFF_REFUSALSgives the refusals their words; only a press that opened something takes the picker away). Widen the action filter throughaction_value. Requirements: R3.4, R3.5, R3.6, R4.1–R4.6; A1–A4, A6, A7, A10. Test: T5, T11.[x] 6 · Tests: the resolver —
cli/tests/test_channels_kickoff.py. Test: T1.[x] 7 · Tests: the pending record —
cli/tests/test_channel_state.py. Test: T2.[x] 8 · Tests: rendering and the payload read —
cli/tests/test_channels_slack.py. Test: T3.[x] 9 · Tests: the fork and the answer —
cli/tests/test_channels_inbound.py. Test: T4, T5.[x] 10 · Tests: abuse cases A1–A10 — one negative test each, named so the trace is readable from the test name alone. Test: T11.
[x] 11 · Tests: integration —
cli/tests/test_channels_kickoff_integration.py, Gherkin docstrings withRequirement:links, throughhandle_socket_eventandhandle_socket_actionas they are actually composed. Test: T8.[x] 12 · Docs, capability docs, decision-122
channels statusline;docs/cli/state.md(the fourth map);docs/capabilities/channels.md(current behaviour + a history row);docs/config/cli/channels-options.mdanddocs/guide/slack.md(whatread.mode: socketnow also buys); the event catalog entry forchannel.kickoff_asked;docs/decisions/decisions.md. Requirements: R5.2; the skill's capability-docs and user-facing-docs rules. Test: T14.[x] 13 · Verification + evidence — execute the testing plan, tick each activity only once it has run, and commit
evidence/verification.mdandevidence/security-review.md. Test: T16, T17.