<!-- Authored per the the-loop:writing skill. -->
Tasks: multi-modal messages are forwarded to the session, never parsed by the loop
The last spec artifact. Derived from design.md and testing-plan.md. Gate-less (issue-281): it advances on shape.
Execution DAG
Task list
- [x] 1. Write
cli/the_loop/channels/attachments.pywith its unit tests, red firstAttachment, the constants,kind_of,safe_name,vtt_to_text,github_attachment_urls,fetch_url(no auto-redirect, host check per hop, the cap),slack_attachments(with the transcript wait),github_attachments,render_section,record_lines.cli/tests/test_attachments.pywith the T1 and T8 scenarios; it fails on import before the module exists — that is the red.- Depends on: none
- Requirements: R1.2, R1.4–R1.6, R2.1–R2.4, R3.1, R3.2, R4.1, R6.2; abuse cases 1–5
- Test:
T1 / T8 — pytest cli/tests/test_attachments.py
- [x] 2. Declare the attachments directory in the state layout
StateLayout.attachments_dir→<root>/local/attachments; aGENERATED_PATHSentry (portable=False, itswhy); the tree line and the classification row ondocs/cli/state.md, with the no-retention sentence.- Depends on: 1
- Requirements: R6.1, R6.3
- Test:
T10 — pytest cli/tests/test_state_portability.py
- [x] 3. Carry
fileson the normalized Slack messageInboundReply.files: Tuple[Mapping, ...] = (); populated inhandle_socket_event(both branches),fetch_replies,fetch_kickoffs,fetch_channel_messages.- Depends on: 2
- Requirements: R1.1
- Test:
T2 — the poll-read and socket scenarios(written in task 7; the readers are exercised by the existing channel suites meanwhile)
- [x] 4. Fetch and render in the pipeline; name files in the snapshot and the kickoff
SlackBotChannel.fetch_attachments; inprocess_replythe record text gainsrecord_lines, the delivered textrender_section, for the three relayed kinds;snapshot_threadappends 📎 per file;process_kickoffappendsrecord_linesto the issue body.- Depends on: 3
- Requirements: R1.2, R1.3, R1.7, R2.1, R2.2, R3.1–R3.4; abuse case 6
- Test:
T2 — pytest cli/tests/test_attachments_integration.py -k "slack or voice or only or gate or snapshot or kickoff or stranger"
- [x] 5. Append the section to the GitHub prompt
Dispatcher._attachments_section(routed, work_item)after_render_prompt's render: bodies from the four containers, the configured host, the token fromintegrations.github.api.tokenEnv, reuse from disk.- Depends on: 4
- Requirements: R4.1–R4.5
- Test:
T2 — pytest cli/tests/test_attachments_integration.py -k githubandT10 — pytest cli/tests/test_interaction_integration.py(a prompt without attachments unchanged)
- [x] 6. Declare the scope and measure it
files:readinslack-app-manifest.yamlwith its reason;attachment_findingsbesidemention_findings, appended inprobe_subscription.- Depends on: 5
- Requirements: R5.1–R5.3
- Test:
T1 — pytest cli/tests/test_attachments.py -k finding;T10 — the manifest suites
- [x] 7. Write the integration scenarios
cli/tests/test_attachments_integration.py, Gherkin docstrings, every T2 row of the plan; fakes at the edges (FakeSlackClient+files_info, a fake fetch,FakeTmux).- Depends on: 6
- Requirements: all
- Test:
T2 — pytest cli/tests/test_attachments_integration.py
- [x] 8. Documentation and the decision record
docs/guide/slack.md: the manifest copy gainsfiles:read; a new Images and voice notes section; a line under Limits.docs/capabilities/channels.mdanddocs/capabilities/webhook-triggers.md: current-behaviour clauses and history rows.docs/decisions/decision-135.md+ its index row.evidence/documentation.md.- Depends on: 7
- Requirements: the loop's rule — docs change in the same PR
- Test:
T12 — pytest cli/tests/test_docs_parity.pyandmake lint
- [x] 9. Verify and record
make check; filltesting-plan.md§ Verification results; writeevidence/verification.md,self-review.md,security-review.md,pull-requests.md; the T11 procedure written down and marked not executed here.- Depends on: 8
- Requirements: all
- Test:
All — make check
Dependency graph (DAG)
Linear, as drawn above: each task builds on the seam the previous one opened, and the integration scenarios (7) need every seam in place.
Checkpoints
- After task 1: the module and its contract exist, offline-tested.
- After task 4: Slack end to end, provable with the existing fake client.
- After task 6: both channels and the scope; ready for the scenarios.
- After task 9: evidence recorded; ready for review.
Out of scope for this DAG
No task calls a model on a file, adds a config key, changes the excerpt contract, or touches the Cursor adapter. If one appears to need it, stop and raise it on the ticket.
Review comments
Appended by the-loop's
record-feedbackhook when a human gate approves with comments.