Skip to content

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

Testing plan: the /the-loop:init onboarding a person can finish ​

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

What is testable here, and what is not ​

This work item ships schema metadata, agent instructions and documentation. That split decides the whole matrix, so state it before the table:

  • The metadata is mechanically checkable against the schema it annotates, and that is where every failure mode with teeth lives — a renamed key, a forgotten group, a profile path that resolves to nothing, a rung reaching a key it must never reach. It gets a test module.
  • The instructions (commands/init.md, reference/onboarding.md) are executed by an agent in a conversation. A test that asserts prose contains a phrase is a test that fails on a rewording and passes on a lie; it buys nothing. These are verified by a manual exploratory run of /the-loop:init --dry-run against a scratch repository, with the transcript committed as evidence.
  • The existing suites that this change can break (schema parity, the keyword guard, docs parity) are run in full, because they are the ones that turn "I copied the schema over" from a promise into a fact.

Test matrix ​

#TypeApplies?Scope / what it provesWhere it runs
T1Unityesx-onboarding in cli-config.schema.json is internally consistent and consistent with the schema it annotates: group coverage, key existence, profile path resolution, ask-level vocabulary parity with the harness schema (A1–A3, A6–A7 of design §Testing strategy)uv run --project cli python -m pytest -q cli/tests/test_onboarding_schema.py
T2Integration (scenario)n/a — nothing new crosses a process, a socket or a subprocess boundary. The new artifacts are read by an agent, not by a running daemon; the CLI surface the walkthrough calls (channels status --probe, doctor slack) is unchanged by this work item and already covered by test_channels*.py and test_doctor_slack.py.
T3Contract (OpenAPI / GraphQL)n/a — no API surface is touched.
T4End-to-endn/a — an end-to-end run of this feature is T11: a human-driven conversation in a harness. Automating it would mean scripting an agent's dialogue, which tests the script.
T5UI / visualn/a — no rendered surface (design §UI/UX design).
T6Snapshotn/a — the schema is reviewed as a diff; a snapshot of it would be the same bytes twice.
T7Performance / loadn/a — no runtime path changes; init's cost is a conversation.
T8Security / abuse caseyesThe autonomy ladder cannot reach a gate (A5) — every profile value's top-level block is in the allowed set, asserted per rung. Plus a static check that no new instruction reads a credential's value rather than its presence.uv run --project cli python -m pytest -q cli/tests/test_onboarding_schema.py -k profile_values and the grep in T8's activity line
T9Accessibilityn/a — no rendered surface.
T10Migration / upgradeyesAn existing cli-config.yaml and the shipped template still validate against the edited schema, and the packaged copy is byte-identical to the authored oneuv run python scripts/validate_config.py and uv run --project cli python -m pytest -q cli/tests/test_config_schema_parity.py cli/tests/test_configschema.py
T11Manual exploratoryyesThe walkthrough is followable: a --dry-run init reaches every new step, the profile question renders, the Slack explanation is short enough to read, and the credential preflight names variables without valuesA scratch repository; transcript committed
T12Documentation parityyesThe new root-level x-onboarding adds no undocumented schema leaf, and the docs site's own parity assertions still holduv run --project cli python -m pytest -q cli/tests/test_docs_parity.py

Scenarios & requirement trace ​

RowRequirement(s)Scenario / case
T1R1.2Scenario: the CLI config schema declares an onboarding block
T1R1.2, R7.2Scenario: both schemas speak one ask-level vocabulary
T1R1.3Scenario: every onboarding group names keys the schema defines
T1R1.3Scenario: every configurable block belongs to exactly one group
T1R2.1, R2.4Scenario: every profile value names a key the schema defines
T1R2.4Scenario: every profile value is legal for the key it sets
T1R2.5Scenario: the first rung is the shipped defaults
T1R2.1, R2.2, R2.6Scenario: every rung explains itself and what still needs a human
T8R3.1, R3.2Scenario: no autonomy profile reaches a key that guards a human gate
T8R6.2, abuse case 2Static check: no new instruction step reads a credential value
T10NFR — packaged paritytest_config_schema_parity.py byte equality
T10NFR — no new keywordtest_configschema.py::test_the_schemas_use_no_keyword_the_validator_ignores
T12NFR — schema/doc paritytest_docs_parity.py P3/P4
T11R4, R5, R6, R7A --dry-run walkthrough on a scratch repository

Verification environment ​

  • Repositories: this repo only. T11 additionally uses a throwaway git repository created under the session's scratch directory — never a real project.
  • Services / containers: none. No daemon is started; no Slack workspace is contacted. T11 runs --dry-run, which by contract writes nothing and interacts with nothing.
  • Fixtures & data: none beyond the repository's own schemas and templates.
  • Credentials: none are required, and none are used. T11 deliberately runs with the Slack and webhook variables unset, because the behaviour under test is what the preflight reports when a credential is missing. Referenced by name only: THE_LOOP_SLACK_BOT_TOKEN, THE_LOOP_SLACK_APP_TOKEN, THE_LOOP_GH_WEBHOOK_SECRET, GH_TOKEN / GITHUB_TOKEN.
  • Bring-up: uv sync · Tear-down: delete the scratch repository.
  • If bring-up fails: record it under Verification results, leave the dependent activities unticked, and escalate on the ticket.

Evidence plan ​

RowEvidencePath under evidence/
T1, T8new test module output, with counts and the Gherkin scenario titlesverification.md
T10, T12validate_config.py, parity and keyword-guard outputverification.md
T1–T12the full make check run (lint, format, typecheck, validate, test)verification.md
T11the --dry-run walkthrough transcript, credentials unset, redactedverification.md
R3, R6the security review against the abuse casessecurity-review.md
—self-review against the requirementsself-review.md
—capability-doc and guide updatesdocumentation.md
—the pull request opened for this work itempull-requests.md

Redaction. The T11 transcript is produced with every credential variable unset, so there is nothing to redact by construction; it is still read before committing, and any absolute path naming the operator's home directory is elided.

Verification activities ​

  • [x] T1 — uv run --project cli python -m pytest -q cli/tests/test_onboarding_schema.py
  • [x] T8 — uv run --project cli python -m pytest -q cli/tests/test_onboarding_schema.py -k profile
  • [x] T8 — static check: grep -nE '\$\{?(THE_LOOP_SLACK|THE_LOOP_GH|GH_TOKEN|GITHUB_TOKEN)' commands/init.md skills/the-loop/reference/onboarding.md returns no line that expands a value
  • [x] T10 — uv run python scripts/validate_config.py
  • [x] T10 — uv run --project cli python -m pytest -q cli/tests/test_config_schema_parity.py cli/tests/test_configschema.py
  • [x] T12 — uv run --project cli python -m pytest -q cli/tests/test_docs_parity.py
  • [x] All — make check
  • [x] T11 — walk /the-loop:init --dry-run against a scratch repository with credentials unset; capture the transcript

Verification results ​

Every planned activity ran. Raw output: evidence/verification.md.

uv is invoked as python3 -m uv throughout: the container shipped 0.8.17, below this repo's required-version pin (>=0.12,<0.13), and could not self-update behind the proxy; pip install uv supplied 0.12.17. The commands are otherwise exactly as planned.

ActivityCommand / procedureOutcomeEvidence
T1pytest -q cli/tests/test_onboarding_schema.pypass — 7 failed before the schema block landed, 7 passed afterverification.md § T1 / T8
T8pytest -q cli/tests/test_onboarding_schema.py -k profilepass — A4–A7 including the confinement assertionverification.md § T1 / T8
T8the credential-value greppass — 3 prose mentions of variable names, 0 shell expansionsverification.md § T8
T10scripts/validate_config.pypass — all 6 configs validverification.md § T10
T10pytest -q test_config_schema_parity.py test_configschema.pypass — byte parity held; the keyword guard passes with x-onboarding declared documentation-onlyverification.md § T10
T12pytest -q cli/tests/test_docs_parity.pypass — no new schema leaf, P3/P4 unaffectedverification.md § T12
Allmake check (lint · format · typecheck · validate · test)pass, with 4 pre-existing failures — see belowverification.md § The full suite
T11the --dry-run walkthrough, credentials unsetpass — 18/18 blocks covered, the ladder renders, the preflight names variables without values, the scratch repo is untouchedverification.md § T11

The 4 failures in make check are not this work item's. All four are in cli/tests/test_instance.py, concern the argv a tmux spawn is built with, and reproduce identically with the entire change stashed. The container's tmux predates TMUX_ENV_MIN_VERSION (3.2), so the spawn omits -e by design. Recorded rather than fixed: it is outside this work item's scope.

Not executed: a live Slack probe — no workspace, app or tokens exist in this environment, and manufacturing them would prove nothing about the walkthrough. The CLI-absent path was exercised (T11, reported as unverified), and the probe commands themselves are unchanged here and covered by test_channels*.py / test_doctor_slack.py. T4 stays n/a for the reason the matrix gives.

Review comments ​

Appended by the-loop's record-feedback hook when a human gate approves with comments.

Released under the MIT License.