Skip to content

Testing plan: a channel's gate answer reaches the gate

Derived from bugfix.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
T1Unityesthe reader equals the dispatcher's coupling (control config, control-store root, allow-list, registry dir); coupling off → False; no record → None; the read mutates no graph state; each row of the classification table through process_reply with the read patched to True / False / None, with and without the grant; the keyword still outranks; the deferred record is unmarked, enveloped gate.feedback, attributed as a reply; channel.reply_received carries gateuv run --project cli python -m pytest -q cli/tests/test_channels.py
T2Integration (scenario)yesthe issue's reproduction, real state end to end: a checkout with origin, a registry record with that cwd, graph-state.json parked at requirements-approval, a recorded start, the default control policy; an authorized Slack reply through poll_once → an unmarked gate.feedback record the ledger's ingress attributes to the person; and the no-session-record scenario → the same record, attributed as a replyuv run --project cli python -m pytest -q cli/tests/test_bus_integration.py
T3Contract (OpenAPI / GraphQL SDL)n/a — no API route changes
T4End-to-endn/a — the ledger's ingress and the gate hooks are exercised by their own suites (test_graphlink_integration.py, test_routing.py); T2 hands them the record shape they already accept
T5UI / visualn/a — no UI
T6Snapshotn/a — assertions on a record body and an event field
T7Performance / loadn/a — one registry read and one state read per reply, as before
T8Security / abuse caseyesone negative test per abuse case A1–A5 (bugfix.md § Security considerations)uv run --project cli python -m pytest -q cli/tests/test_channels.py -k "without_the_grant_is_a_marked_reply or unlisted_member_is_dropped_before or keyword_outranks_an_unreadable or defers_to_the_ledger or read_moves_nothing"
T9Accessibilityn/a — no UI
T10Migration / upgradeyesno config change; a 13.3.0 config with publish: [work-item.reply] behaves exactly as before (T1's no-grant rows); the event catalog's description still pins docs and CLI togetheruv run --project cli python -m pytest -q cli/tests/test_docs_parity.py cli/tests/test_config_schema_parity.py
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
T1R1.2test_the_pipeline_reads_the_graph_through_the_dispatchers_own_coupling
T1R1.3, R2.2, A4test_an_unreadable_gate_defers_to_the_ledger_when_the_channel_may_answer_gates
T1R1.4, A1test_an_unreadable_gate_without_the_grant_is_a_marked_reply_as_before
T1R1.5test_a_disabled_graph_coupling_means_no_gate_to_answer
T1R1.6test_a_graph_that_says_not_at_a_gate_keeps_the_reply_direct
T1R1.7, A3test_a_control_keyword_outranks_an_unreadable_gate
T1A2test_an_unlisted_member_is_dropped_before_the_gate_is_even_read
T1A5test_the_pipelines_read_moves_nothing
T1R1.3test_no_session_record_is_an_unknown_gate_not_a_closed_one
T1R2.1test_the_reply_event_says_what_the_gate_read_returned
T2R1.1, R1.8Scenario: An approval from Slack reaches the gate under the daemon's default control policy
T2R1.3Scenario: A reply for a work item with no session record is left to the ledger
T10R3.1docs parity, schema parity

Verification environment

  • Repositories: this repo only. T2 runs git init and git remote add in a temp directory (the coupling's ownership check reads the checkout's origin).
  • Services / containers: none. The Slack SDK client, the ledger writer and session delivery are faked at their injection points.
  • Fixtures & data: temp directories per test; graph state written by GraphState.
  • Credentials: none. THE_LOOP_SLACK_BOT_TOKEN is set to a dummy value by name.
  • 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
  • [x] T2 — uv run --project cli python -m pytest -q cli/tests/test_bus_integration.py
  • [x] T8 — uv run --project cli python -m pytest -q cli/tests/test_channels.py -k "without_the_grant_is_a_marked_reply or unlisted_member_is_dropped_before or keyword_outranks_an_unreadable or defers_to_the_ledger or read_moves_nothing"
  • [x] T10 — uv run --project cli python -m pytest -q cli/tests/test_docs_parity.py cli/tests/test_config_schema_parity.py
  • [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.pypass — 73 passed (11 new)evidence/verification.md
T2uv run --project cli python -m pytest -q cli/tests/test_bus_integration.pypass — 10 passed (the two scenarios, red first)evidence/verification.md
T8uv run --project cli python -m pytest -q cli/tests/test_channels.py -k "…"pass — 5 passed (A1–A5)evidence/verification.md
T10uv run --project cli python -m pytest -q cli/tests/test_docs_parity.py cli/tests/test_config_schema_parity.pypass — 8 passedevidence/verification.md
T12make checkpass — lint (ruff, markdownlint over 965 files), format, pyright, config validation, full suite: 3033 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.