Skip to content

Testing plan: the-loop ask + POST /api/v1/sessions/reply

Derived from requirements.md and design.md, before tasks.md. Authored at test-planning, completed at verification.

Test matrix

#TypeApplies?Scope / what it provesWhere it runs
T1Unityesask_session (marker stamped, event on success and on gh failure, empty-question/bad-ref refusals, comment URL captured), reply_session (framing, paused/missing/dead refusals, event, marked report comment), post_issue_comment_with_url parsing, attention's open/answered ruleuv run pytest -q cli/tests/test_core_sessions.py cli/tests/test_comments.py cli/tests/test_core_attention.py
T2Integration (scenario)yesThe route as served: delivered reply reaches the pane and emits reply_sent; 404 no-session / dead-pane without respawn; 400 paused / empty text; the report comment carries the marker; the CLI verb end-to-end with a fake ghuv run pytest -q cli/tests/test_ask_reply_integration.py
T3Contract (OpenAPI)yesThe authored contract gains exactly /api/v1/sessions/reply (replySession) and still equals the served schema (R2.7)uv run pytest -q cli/tests/test_api_contract_parity.py
T4End-to-endn/a — a real agent in a real tmux pane answering a real GitHub comment is T11's manual walk; every seam in between (paste, gh, events) is covered in-process
T5UI / visualn/a — the card exists since issue-207; this enables its controls, no layout/token change
T6Snapshotn/a — no serialized artifact is produced
T7Performance / loadn/a — one POST that shells two short-lived processes; no budget at stake
T8Security / abuse caseyesOne negative test per § Security design mechanism: no respawn on dead/missing session, paused refused, marked report body, marked question body, idempotent stampuv run pytest -q cli/tests/test_ask_reply_integration.py cli/tests/test_core_sessions.py
T9Accessibilityn/a in new work — the reply box shipped with aria-label in issue-207; enabling it changes no semantics
T10Migration / upgraden/a — no config key, schema, or stored format changes; old event logs simply lack the new types and attention derives nothing from them
T11Manual exploratoryyesA spawned session runs the-loop ask; the dashboard card lights, the reply box delivers into the pane, the card closesa human, a workstation with the daemon + a session
T12Docs parityyesThe new event types appear in the observability reference; CLI/API docs updateduv run pytest -q cli/tests/test_docs_parity.py
T13Schema validationn/a — no schema is touched (NFR2)
T14Lint / format / typesyesRepo gates, CI paritymake lint format-check typecheck
T15UI unityesThe reply box posts to the route, reports failure, clears on success; demo mode refuses; the awaitingInput model tests keep passingbun run test in ui/

Scenarios & requirement trace

RowRequirement(s)Scenario / case
T1R1.1, abuse 5the posted body ends with attribution + marker; an already-marked question is not double-stamped
T1R1.2, R1.3event emitted with comment_url on success; emitted with comment_posted: false when gh fails
T1R1.4empty question / malformed ref → error, nothing posted, nothing emitted
T1R2.1the framed prompt carries provenance + actor + the text
T1R2.6, abuse 4the report comment quotes the reply and carries the marker
T1R3.1open question → row; reply newer than question → no row; re-asked after reply → row again
T2R2.1, R2.2Scenario: an operator's reply is pasted into the waiting session
T2R2.3, abuse 2Scenario: a reply to a work item with no session is refused without spawning / …dead pane…
T2R2.4, abuse 3Scenario: a reply to a paused session is refused
T2R2.5Scenario: an empty reply is refused
T2R1.1–R1.3Scenario: the ask verb posts a marked question and records the wait (+ gh-failure variant)
T3R2.7contract parity over the new path
T12R3.2both event types documented
T15R5.1, R5.2the enabled reply box; demo refusal; stale copy gone
T11allthe full loop, by hand

Verification environment

  • Repositories: this repo only.
  • Services / containers: none for T1–T3, T8, T12, T14 — TestClient drives the app in-process; gh and tmux are injected/monkeypatched fakes. T15 needs bun. T11 needs a workstation with tmux, gh and a spawned session (a human's).
  • Fixtures & data: inline per test; state.root/registry dirs under tmp_path.
  • Credentials: none (fakes only).

Evidence to capture

evidence/verification.md: per-activity command + outcome, full suite tail, lint/type output, UI test output. No screenshots — the UI change is behavioural (T15 asserts it); T11 is deferred to the reviewer's workstation and said so honestly.

Activities checklist (ticked at verification, with results)

  • [x] T1 unit suites green — 1849 passed, 1 skipped (baseline 1819); see evidence/verification.md
  • [x] T2 integration scenarios green, Gherkin docstrings present (test_ask_reply_integration.py, 9 scenarios)
  • [x] T3 contract parity green (/api/v1/sessions/reply in both contract and served schema)
  • [x] T8 negative tests green (no-spawn, paused, marked bodies, idempotent stamp)
  • [x] T12 docs parity green (both event types documented in EVENT_TYPES)
  • [x] T14 lint / format / typecheck / markdownlint / schema validation clean
  • [x] T15 UI suite green — 52 passed, incl. the send-flow and inbox-dedupe tests; bun run build clean
  • [ ] T11 manual walk — deferred to a human with a workstation; the one activity this plan cannot run itself (steps in evidence/verification.md)

Verification results

Executed 2026-08-12 by the implementing session. Everything but T11 ran and passed; full command output in evidence/verification.md. One honesty note on TDD: the new tests were written alongside the implementation in one pass, not strictly red-first — the red→green transitions were observed per-assertion while iterating (one genuine red is recorded in the execution log), but this session cannot present a committed red state as evidence.

Released under the MIT License.