Tasks: the tmux session name the-loop records and posts is the name tmux gave the session
Phase 3 of 3 (requirements → design → tasks). Derived from the approved
design.md. TDD per task (tdd.mode: standard): the test is written first and watched red before the production change.
Task list
[x] 1.
tmux_session_name()— mirror tmux'ssession_check_name()- Add the pure helper to
cli/the_loop/sessions/registry.py(./:→_), export it fromthe_loop.sessions. - Depends on: none
- Requirements: R1 (AC1, AC2)
- Test:
pytest cli/tests/test_tmux_runner.py -k TestTmuxSessionName— plain names pass through, dotted/colon'd names are rewritten, idempotent (red→green)
- Add the pure helper to
[x] 2.
TmuxRunner.target_formints only names tmux keeps- Apply the helper; update the docstring to say why (tmux rewrites them, and re-parses them as
session:window.paneon the way back). - Depends on: 1
- Requirements: R1 (AC1, AC2)
- Test:
pytest cli/tests/test_tmux_runner.py -k "target_for"—test_target_for_strips_tmux_target_syntaxandtest_target_for_unchanged_for_plain_slugs(red→green)
- Apply the helper; update the docstring to say why (tmux rewrites them, and re-parses them as
[x] 3.
Session.__post_init__normalisestmux_target- Every construction path (
from_dicton a legacy record, the dispatcher's direct construction, tests) lands on the name tmux uses;""stays"". - Depends on: 1
- Requirements: R2 (AC3)
- Test:
pytest cli/tests/test_tmux_runner.py -k legacy_tmux_target(red→green)
- Every construction path (
[x] 4. The announced attach command names a session tmux can find
- No code change expected in
announce.py— the test proves the fix reaches the human-facing surface the issue is about. - Depends on: 3
- Requirements: R2 (AC4)
- Test:
pytest cli/tests/test_announce.py -k real_tmux_session(red→green)
- No code change expected in
[x] 5. Every tmux argv addresses the normalised target
deliver/kill/ probes built from a legacy dotted record name the underscore session.- Depends on: 3
- Requirements: R2 (AC5)
- Test:
pytest cli/tests/test_tmux_runner.py -k normalised_target(red→green)
[x] 6. Security:
_LOOP_TARGET_RErejects tmux target syntax- Drop
.from the charset (:was never in it) so the guard authorisingterminate_harnessto signal pane pids cannot admit a string tmux re-parses assession:window.pane. - Depends on: none
- Requirements: R3 (AC6)
- Test (negative, abuse case):
pytest cli/tests/test_tmux_runner.py -k only_the_loops_own_sessions— a hand-editedloop-other.session/loop-other:0.1is refused and no signal is sent (red→green)
- Drop
[x] 7. Security: pin the
./_aliasing as known and non-destructive- Amend
_clear_target's docstring so its "an occupant is always this work item's own agent" reasoning states the alias exception instead of misleading the next reader. - Depends on: 2
- Requirements: R3 (AC6),
design.md§ Security design (abuse-case coverage) - Test:
pytest cli/tests/test_tmux_runner.py -k aliases_dot_and_underscore(documents the alias; fails if a future change makes it destructive)
- Amend
[x] 8. Teach the stub tmux tmux's own rename
cli/tests/test_tmux_runner_integration.py:new-sessioncreatesname.replace('.','_').replace(':','_');has-session/list-panes/kill-sessionanswer about that name.- Depends on: none
- Requirements: R4 (AC8)
- Test: the existing integration suite stays green with the stub change alone
[x] 9. Integration test — the reporter's scenario, end to end
- Gherkin scenario: a work item whose repo name contains a dot is spawned; the name recorded, logged and announced is the name the stub tmux created, and a second event pastes into it instead of respawning.
- Depends on: 2, 3, 8
- Requirements: R4 (AC7, AC8)
- Test:
pytest cli/tests/test_tmux_runner_integration.py -k dotted(red→green)
[x] 10. Capability docs + execution log
docs/capabilities/interactive-sessions.md: the session-naming behaviour and its history row.- Depends on: 1–9
- Requirements: all
- Test:
markdownlintclean;the-loop check issue-154 --recompute --fail-on block
[x] 11. Full gate + PR with the reviewer briefing
- ruff (check + format), pyright, pytest, markdownlint — the same commands the pre-commit hooks and CI run — then the PR and its briefing.
- Depends on: 10
- Requirements: all
- Test: the full suite, plus
the-loop check issue-154 --recompute --fail-on block
Dependency graph (DAG)
flowchart LR
T1["1 tmux_session_name()"] --> T2["2 target_for"]
T1 --> T3["3 Session.__post_init__"]
T3 --> T4["4 announce"]
T3 --> T5["5 tmux argv"]
T6["6 _LOOP_TARGET_RE"] --> T10["10 capability docs"]
T2 --> T7["7 alias docstring"]
T8["8 stub tmux rename"] --> T9["9 integration scenario"]
T2 --> T9
T3 --> T9
T4 --> T10
T5 --> T10
T7 --> T10
T9 --> T10
T10 --> T11["11 gate + PR"]1 → 2 → 7, 1 → 3 → {4, 5}, 8 → 9, 6, all → 10 → 11.
Checkpoints
- After tasks 1–3:
pytest cli/tests/test_tmux_runner.py— the naming unit tests are green and nothing else in the runner regressed. - After tasks 4–7: full
pytest, plus ruff/pyright on the touched files. - After task 9: full
pytest— the stub's new rename must not have broken any existing integration scenario. - After task 10:
markdownlint+the-loop check issue-154 --recompute --fail-on block. - After task 11: the self/critic review rounds and the security review gate (
security.review), recorded inexecution-log.md, before the work item is marked ready.
Review comments
Appended by the-loop's
record-feedbackhook when a human gate approves with comments (issue-109).