Skip to content

Testing plan: the thread is the work item's

Derived from requirements.md and design.md, before tasks.md. Authored at test-planning; the results section is filled at verification.

This file is executable content. Commands below are what the agent runs; credentials appear by reference only.

Test matrix

#TypeApplies?Scope / what it provesWhere it runs
T1UnityesChannelState: the conversations map, bind writing both maps, thread_for preferring it, legacy backfill, eviction with the cap, the lock; SlackBotChannel.post: root shape, event as first reply, reuse, failure without a second root, permalink best-effort; channels threads and status outputuv run --project cli python -m pytest -q cli/tests/test_channels.py cli/tests/test_eventlog.py
T2Integration (scenario)yesthe five Gherkin scenarios below through the real modules with the SDK client and gh fakeduv run --project cli python -m pytest -q cli/tests/test_channels_integration.py cli/tests/test_bus_integration.py cli/tests/test_standing_channels_integration.py
T3Contract (OpenAPI / GraphQL SDL)n/a — no API route changes
T4End-to-endn/a — needs a Slack workspace; the integration rows fake exactly the SDK client
T5UI / visualn/a — the root's Block Kit is asserted structurally (T1)
T6Snapshotn/a — field-by-field assertions on one root shape are stricter and survive a reorder
T7Performance / loadn/a — one root post and one permalink call per work item; the lock covers a single request
T8Security / abuse caseyesone negative test per abuse case A1–A5 (design.md § Security design)uv run --project cli python -m pytest -q cli/tests -k "root_shaped or ref_alone or failed_permalink or corrupt_state or without_flock"
T9Accessibilityn/a — no UI
T10Migration / upgradeyesa slack.json written before this work item (threads + cursors only) loads, answers thread_for, and is rewritten with conversations on the next save; no config migration (no config key changes)uv run --project cli python -m pytest -q cli/tests/test_channels.py cli/tests/test_channels_integration.py -k pre_issue_312
T11Manual exploratoryn/a — the reviewer's walk-through is the PR briefing's "what to check"
T12Lint / format / typecheck / config validation / full suiteyesthe repository's own gates, as pre-commit and CI run themmake check
T13Security review (gate)yesthe-loop checklist against A1–A5, recorded as evidence; tier 3 needs no human sign-off (humanSignOffMinTier: 4)evidence/security-review.md

Scenarios & requirement trace

RowRequirement(s)Scenario / case
T1R3.1, R3.4, R3.5bind writes both maps; thread_for reads the conversation; a threads-only file backfills; eviction drops the conversation; no token in the file
T1R1.4two locked() sections on one path serialize (a second thread waits)
T1R1.1, R1.2, R1.3, R2.2the first post is a root + a reply; the second is one reply; the root names the ref and carries the link button; the reply carries the event's blocks
T1R2.3a failing reply raises ChannelError and posts no root
T1R3.2, R3.3channel.thread_opened is emitted with ids only; channels threads lists and filters; status counts work items
T2R1.1–R1.3, R2.1Scenario: Every message about a work item is a reply in its one thread
T2R1.4Scenario: Two writers open one thread
T2R1.5, R3.1Scenario: A kickoff thread is the work item's conversation
T2R3.4Scenario: A pre-issue-312 state file keeps its threads
T2R3.3Scenario: channels threads lists the conversation
T2R1.6the standing-session scenarios (issue-277), re-pointed: the announcement is the first reply
T8A1–A5one negative test each, named in design.md § Security design
T10R3.4the legacy-file cases above

Verification environment

  • Repositories: this repo only.
  • Services / containers: none. The Slack SDK client is faked at the process boundary; gh is faked where a scenario records on the ledger; tmux is not needed.
  • Fixtures & data: in-test dicts; a temp state.root per test; a hand-written pre-issue-312 slack.json.
  • Credentials: none. THE_LOOP_SLACK_BOT_TOKEN is set to a dummy value inside tests that need the channel enabled — by name, never a real token.
  • Bring-up: uv sync · Tear-down: none.
  • If bring-up fails: record it under Verification results and escalate.

Evidence plan

RowEvidencePath under evidence/
T1, T2, T8, T10, T12command, counts, duration, raw tail of the output; red → green per taskverification.md
T13the abuse-case table with verdicts and the tests that close eachsecurity-review.md

Verification activities

  • [x] T1 — uv run --project cli python -m pytest -q cli/tests/test_channels.py cli/tests/test_eventlog.py
  • [x] T2 — uv run --project cli python -m pytest -q cli/tests/test_channels_integration.py cli/tests/test_bus_integration.py cli/tests/test_standing_channels_integration.py
  • [x] T8 — uv run --project cli python -m pytest -q cli/tests -k "root_shaped or ref_alone or failed_permalink or corrupt_state or without_flock"
  • [x] T10 — uv run --project cli python -m pytest -q cli/tests/test_channels.py cli/tests/test_channels_integration.py -k pre_issue_312
  • [x] T12 — make check
  • [x] T13 — evidence/security-review.md

Verification results

ActivityCommand / procedureOutcomeEvidence
T1uv run --project cli python -m pytest -q cli/tests/test_channels.py cli/tests/test_eventlog.pypass — 70 passedevidence/verification.md
T2uv run --project cli python -m pytest -q cli/tests/test_channels_integration.py cli/tests/test_bus_integration.py cli/tests/test_standing_channels_integration.pypass — 29 passed (the five scenarios among them)evidence/verification.md
T8uv run --project cli python -m pytest -q cli/tests -k "root_shaped or ref_alone or failed_permalink or corrupt_state or without_flock"pass — 5 passed (A1–A5)evidence/verification.md
T10uv run --project cli python -m pytest -q cli/tests/test_channels.py cli/tests/test_channels_integration.py -k pre_issue_312pass — 2 passedevidence/verification.md
T12make checkpass — lint, format, typecheck, config validation, 2950 passed / 1 skippedevidence/verification.md
T13the-loop checklist over A1–A5pass; no human sign-off at tier 3evidence/security-review.md

Not executed: none.

Review comments

Appended by the-loop's record-feedback hook when a human gate approves with comments (issue-109). Append-only and attributed: an approval never silently discards a reviewer's suggestions, and the feedback travels with the document it concerns rather than living in a side-channel tracker.

Released under the MIT License.