Skip to content

Testing plan: the Slack digest — the ask first, choices numbered, pointers, cut at a sentence

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
T1Unityesto_mrkdwn (each rule, idempotence, plain prose is the identity); strip_comments (closed, unclosed, foreign); condense (the ask leads, the reply-instruction fallback, no ask → the first sentence, lists numbered with ☑ / ☐, fences / tables / traces as pointers with counts, paths shortened and URLs untouched, the sentence / clause / whitespace cut, the footer with and without a URL, the budget honoured, the faithfulness property, empty / whitespace / unicode inputs); fit (short untouched, truncate is the 13.10.0 output, the raw length is the threshold); the config (long_messages parse, unknown → default with a warning, schema default parity); render_blocks (the section is the digest, the excerpt too, the fallback text matches, the marker never reaches Slack, truncate keeps the old cut); channels status (the line per value)uv run --project cli python -m pytest -q cli/tests/test_channels_digest.py cli/tests/test_channels.py::test_config_defaults_match_the_schema
T2Integration (scenario)yesthrough publish_comment → the bus → the channel with a fake Slack client: a long agent comment arrives as the digest (the ask first, no fence, within maxChars, the link, the ledger untouched); a short comment passes through untouched; a notification's artifact excerpt is digesteduv run --project cli python -m pytest -q cli/tests/test_channels_integration.py -k "digest or untouched or excerpt"
T3Contract (OpenAPI / GraphQL SDL)n/a — no API route changes
T4End-to-endn/a — no Slack workspace is reachable; T2 exercises every module up to the SDK boundary
T5UI / visualn/a — Slack draws Block Kit; the section text is asserted in T1/T2 and the before/after is in design.md
T6Snapshotn/a — assertions on strings and block dictionaries, the faithfulness property instead of a golden file
T7Performance / loadyesa 64 KB comment of unclosed **, <!--, [ and fence openers digests within a generous wall-clock bound (the linearity claim of the design, abuse case A1)uv run --project cli python -m pytest -q cli/tests/test_channels_digest.py -k pathological
T8Security / abuse caseyesone negative test per abuse case A1–A5 (requirements.md § Security considerations)uv run --project cli python -m pytest -q cli/tests/test_channels_digest.py -k "pathological or broadcast or footer_links or foreign_comment or reads_the_digest"
T9Accessibilityn/a — no UI of the-loop's own
T10Migration / upgradeyesa 13.10.0 config parses unchanged and gains digest; both schema copies identical; docs parity on the new heading; the existing channel suites greenuv run --project cli python -m pytest -q cli/tests/test_config_schema_parity.py cli/tests/test_docs_parity.py cli/tests/test_configschema.py cli/tests/test_channels.py cli/tests/test_channels_buttons.py cli/tests/test_channels_integration.py cli/tests/test_bus.py cli/tests/test_channels_commands.py
T11Manual exploratoryn/a — no Slack workspace is reachable from this session; 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-offevidence/security-review.md

Scenarios & requirement trace

RowRequirement(s)Scenario / case
T1R1.1, R1.2, R1.3test_a_long_text_is_digested_within_the_limit, test_the_cut_falls_on_a_sentence_boundary, test_a_sentence_too_long_for_the_room_is_cut_at_a_clause_then_a_space, test_the_footer_names_the_link_or_the_ticket
T1R1.4test_truncate_is_the_13_10_0_cut, test_an_unknown_long_messages_value_resolves_to_digest
T1R1.5test_the_fallback_text_carries_the_digest
T1R2.1test_the_first_question_leads, test_a_reply_instruction_leads_when_nothing_asks, test_without_an_ask_the_first_sentence_leads
T1R2.2, R2.3test_a_list_becomes_numbered_lines_with_its_boxes, test_the_authors_order_is_kept_after_the_ask
T1R3.1test_fences_tables_and_traces_become_pointers
T1R3.2test_absolute_paths_are_shortened_and_urls_untouched
T1R3.3, R3.4test_html_comments_never_reach_slack, test_to_mrkdwn_draws_markdown_as_slack_does, test_to_mrkdwn_is_idempotent_and_leaves_prose_alone
T1R4.1, R4.2test_a_short_text_passes_through_untouched, test_the_threshold_is_the_raw_length, test_config_defaults_match_the_schema
T1R4.3test_status_prints_the_long_messages_line
T1NFR faithfultest_every_digest_line_is_the_authors
T2R1.1, R2.1, R3.1, R1.3Scenario: A long agent comment reaches Slack as a digest that leads with the ask
T2R4.1Scenario: A short comment reaches Slack untouched
T2R1.1 (excerpt)Scenario: A notification's artifact excerpt is digested too
T7, T8A1test_a_pathological_comment_digests_in_linear_time
T8A2test_a_slack_broadcast_in_a_comment_is_neutralised
T8A3test_the_footer_links_the_event_never_the_text
T8A4test_nothing_but_the_renderer_reads_the_digest (the pipeline modules import no digest symbol)
T8A5test_a_foreign_html_comment_is_removed_too
T10R4.2, R5.1schema parity, docs parity, config validation, the existing suites

Verification environment

  • Repositories: this repo only.
  • Services / containers: none. The Slack SDK is faked at its injection point (client_factory / build_client); the ledger writer (post_comment) is faked as the existing suites fake it; no tmux, no gh.
  • Fixtures & data: temp directories per test; fixture texts inside the test module (a checklist shaped like the phase-selection hook's, a traceback, a table, a long paragraph).
  • Credentials: none. THE_LOOP_SLACK_BOT_TOKEN is set to a dummy value by name where a channel is built.
  • 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, T7, 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 — the unit selection above
  • [x] T2 — the scenario selection above
  • [x] T7 — the pathological-input test
  • [x] T8 — the abuse-case selection above
  • [x] T10 — the parity and existing-suite selection above
  • [x] T12 — make check
  • [x] T13 — evidence/security-review.md

Verification results

Filled at verification (2026-09-11, head of claude/github-issue-338-lk8282).

RowCommandOutcomeEvidence
T1uv run --project cli python -m pytest -q cli/tests/test_channels_digest.py cli/tests/test_channels.py::test_config_defaults_match_the_schemapass — 42 passedevidence/verification.md
T2uv run --project cli python -m pytest -q cli/tests/test_channels_integration.py -k "digest or untouched or excerpt"pass — 4 passed (the three issue-338 scenarios plus an issue-337 scenario the selection also matches)evidence/verification.md
T7… test_channels_digest.py -k pathologicalpass — a 64 KB crafted comment, three digests plus the drawing plus the cut, in 0.05 s against a 5 s boundevidence/verification.md
T8… test_channels_digest.py -k "pathological or broadcast or footer_links or foreign_comment or reads_the_digest"pass — 4 passed, A1–A5 each closed by a named test (A5 shares foreign_comment with html_comments_never_reach_slack)evidence/verification.md, evidence/security-review.md
T10schema parity, docs parity, config validation, the channel, bus and command suitespass — 303 passed; both schema copies identical; channels.slack.longMessages documented with type and default; a 13.10.0 config parses unchangedevidence/verification.md
T12make checkpass — ruff, ruff format, markdownlint, pyright, validate_config, the full suiteevidence/verification.md
T13the-loop checklistpass — five abuse cases, five closed; no human sign-off at tier 3evidence/security-review.md

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.