Skip to content

<!-- Authored per the the-loop:writing skill. -->

Testing plan: the hosted ingress set follows the config ​

Derived from bugfix.md and design.md. Planned at test-planning, results recorded at verification (below).

Test matrix ​

#TypeApplies?Scope / what it provesWhere it runs
T1Unityes_wanted composes the same list for boot and reconcile; HostedIngresses.reconcile stops what is no longer wanted and starts what is newly wanted, drops a dead entry, and leaves a same-membership change alonecd cli && uv run pytest tests/test_hosted_reconcile.py
T2Integration (scenario, Gherkin-docstringed)yesa real config file, a supervisor with a short interval, the file rewritten: read.mode: off ends the listener's loop and releases its lock with no restart; socket again starts it with the new config; an unrelated edit and an unparseable edit change nothing; polling.enabled: false stops a hosted poller; shutdown stops the supervisor then the ingresses (R1.1–R1.6, R1.8)cd cli && uv run pytest tests/test_hosted_reconcile.py
T3Contract (OpenAPI)n/a — no API route or schema change; status --format json is unchanged (R2.2)
T4End-to-end (live)no — the Socket Mode client is faked at the seam issue-334's tests fake; the live B5 reproduction is the next Slack run's
T5UI / visualn/a
T6Snapshotn/a — the status line is asserted directly (T7)
T7CLI renderingyesthe-loop status prints the non-contradictory flag for a running-but-disabled row, hosted and standalone, and the plain flags otherwise (R2.1)cd cli && uv run pytest tests/test_lifecycle_cmd.py
T8Security / abuse caseyesan unparseable edit changes nothing (abuse 2); a reconcile whose starter raises records ingress.hosted_failed and the supervisor survives (abuse 3); the missing-token refusal on a reconcile start names the variable, not the valuewith T2
T9Accessibilityn/a
T10Migration / upgraden/a — no key, state or schema change; build_lifespan's new argument has a default
T11Manual exploratoryno — deferred to the next live Slack run (B5's own steps)
T12Regression (full suite)yesthe existing hosted-listener, hosted-ingress, lifecycle and SDK suites stay green: start_hosted_ingresses / stop_hosted_ingresses keep their contractcd cli && uv run pytest -q

Scenarios & requirement trace ​

RowRequirement(s)Scenario / case
T1R1.2, R1.3_wanted for {nothing, poller, receiver, socket listener, poll-mode listener} equals what start_hosted_ingresses composes
T2R1.1, R1.4, R1.8Scenario: read.mode goes from socket to off — the listener's stop event is set, its thread ends, its lock is released, ingress.hosted_stopped reason=config and config.reloaded are emitted, the service process is still up (no restart)
T2R1.2, R1.4Scenario: read.mode comes back to socket — a second listener starts, under the same lock, with the edited config; ingress.hosted emitted
T2R1.3Scenario: an unrelated key changes — same thread object still alive; no ingress event
T2R1.5Scenario: the edit is not valid YAML — nothing changes; the next valid edit is applied
T2R1.1Scenario: polling.enabled goes false — the hosted poller's stop event is set and its lock released
T2R1.6Scenario: shutdown — stop() ends the supervisor thread before the ingresses; no ingress is started by a tick after stop() returns
T2R1.2, T8Scenario: the newly wanted listener has no tokens — ingress.hosted_failed names the variable; the supervisor keeps ticking
T7R2.1hosted + running + disabled → disabled in config — still running; the service stops it on its next config check; standalone → \the-loop stop` ends it`; enabled rows unchanged
T12R1.7, allthe whole suite

Verification environment ​

  • Repositories: this repo only.
  • Services / containers: none; the Socket Mode client and the poller's run loop are faked at their seams, and the supervisor runs in-process on tmp_path.
  • Fixtures & data: a cli-config.yaml written per test under tmp_path.
  • Credentials: by reference only — THE_LOOP_SLACK_BOT_TOKEN, THE_LOOP_SLACK_APP_TOKEN, set to placeholder strings by monkeypatch.
  • Bring-up: uv sync · Tear-down: none.
  • If bring-up fails: record under Verification results, leave the rows unticked.

Evidence plan ​

RowEvidencePath under evidence/
T1, T2, T7, T8test names and run output, red → green notedautomated-tests.md
T12full-suite, lint, format, typecheck outputautomated-tests.md

Verification activities ​

  • [x] T1 + T2 + T8 — cd cli && uv run pytest -q tests/test_hosted_reconcile.py
  • [x] T7 — cd cli && uv run pytest -q tests/test_lifecycle_cmd.py
  • [x] T12 — cd cli && uv run pytest -q · uv run ruff check cli hooks · uv run ruff format --check cli hooks · uv run pyright cli

Verification results ​

Recorded in evidence/automated-tests.md.

ActivityCommand / procedureOutcomeEvidence
T1 + T2 + T8uv run --project cli python -m pytest -q cli/tests/test_hosted_reconcile.py cli/tests/test_hosted_listener.pypass — 14 passed (8 new, red before the fix)evidence/automated-tests.md
T7cd cli && uv run python -m pytest -q tests/test_lifecycle_cmd.py tests/test_instance.pypass — 72 passedevidence/automated-tests.md
T12cd cli && uv run python -m pytest -q · uv run ruff check cli hooks · uv run ruff format --check cli hooks · uv run pyright clipass — 4291 passed, 1 skipped; ruff and pyright clean; CI green on the PR headevidence/automated-tests.md

Review comments ​

None yet.

Released under the MIT License.