Requirements: test and verification as nodes in the PDLC
Phase 1 of 3 (requirements → design → tasks). Ticket: issue #163.
Introduction
the-loop can only claim a work item is done if it can verify the work item. Today verification is implied rather than declared: design.md carries a one-paragraph Testing strategy, tasks.md carries a _Test:_ line per task, and the shipped process graph (cli/the_loop/graph/pdlc.yaml) has an implementation node whose exit chain runs verify-tests — a hook that is skipped unless a node declares a command. Everything after implementation (self-review … reviewer-briefing) is about opinion, not about proof.
The consequence is the one the ticket names: whether a work item was tested at all, which kinds of testing applied, whether the plan was executed, and what the evidence was, are all left to the agent's judgement at the moment of writing the PR. Nothing gates them, so nothing guarantees them — the same defect shape as issue-124 (a gate reporting success without running) and issue-148 (prose describing a process the graph did not execute).
This work item makes testing a planned, gated, evidenced part of the loop by adding two nodes to the process graph:
test-planning— derives atesting-plan.mdartifact from the locked requirements and design: which kinds of testing apply to this work item, which explicitly do not and why, what environment/setup the verification needs, and what evidence will be captured.verification— after implementation, executes that plan, ticks it off, and records the results and evidence in the same artifact.
the-loop does not take ownership of a project's testing complexity (multi-repo setups, bespoke harnesses, staging environments). It owns the declaration — the plan, the gate, and the evidence — and delegates the mechanics to the project's own tooling and to customInstructions.
Requirements
Requirement 1 — a testing plan is a first-class, locked artifact
User story: As an engineer working an item under the-loop, I want a testing-plan.md alongside requirements.md and design.md, so that how the work will be proved is decided and reviewed before code is written, not improvised afterwards.
Acceptance criteria (EARS)
- WHEN a work item's
design.mdis locked THEN the loop SHALL derive<specDir>/<id>/testing-plan.mdfrom the locked requirements and design beforetasks.mdis written, and before the design's human approval gate, so that one gate reviews the design and the plan derived from it (revised on PR #166). - The
test-planningnode SHALL block untiltesting-plan.mdexists, is locked (status: approved), and carries a non-empty Test matrix, Verification environment, Evidence plan and Verification results section. - WHEN
tasks.mdis derived THEN each task's_Test:_SHALL name a row of the testing plan's matrix, so plan and DAG cannot describe different work. - IF a bundled template authors
testing-plan.mdTHEN that template SHALL already satisfy every section its node gates on (the issue-124 rule: a template that cannot pass its own gate is a defect).
Requirement 2 — the plan states which kinds of testing apply, and which do not
User story: As a reviewer, I want the plan to enumerate the candidate testing types and record an explicit decision for each, so that "we didn't do performance testing" is a recorded judgement rather than an omission I have to notice.
Acceptance criteria (EARS)
- The testing plan SHALL present a matrix whose rows are testing types — at minimum unit, integration (scenario), contract, end-to-end, UI/visual, snapshot, performance, security/abuse-case, accessibility, migration/upgrade and manual-exploratory.
- WHEN a testing type does not apply to the work item THEN the row SHALL be marked
n/awith a written reason; an unmarked or reasonless row SHALL fail the gate's completeness expectation. - The matrix SHALL be work-item dependent: no type is mandatory in itself, and the loop SHALL NOT require a work item to run a kind of testing its change cannot exercise.
- WHILE the work item is security-relevant (a trust boundary named in
design.md§Security design) the abuse-case row SHALL name the negative test proving the boundary, consistent withreference/security.md.
Requirement 3 — verification is a node, executed against the plan
User story: As an operator, I want the loop to stop at a verification node after implementation, so that "the tests were run" is a gate outcome and not a claim in prose.
Acceptance criteria (EARS)
- The process graph SHALL contain a
verificationnode betweenimplementationandself-review, with its own phase label (<phaseLabelPrefix>verification). - The
verificationnode SHALL gate on the sametesting-plan.mdartifact: every planned activity ticked (- [ ]→- [x]) and a non-empty Verification results section — the same produce-then-re-gate shapetasks-breakdown→implementationalready uses fortasks.md. - IF a planned activity cannot be executed THEN the loop SHALL NOT tick it; it SHALL record the reason in Verification results and either replan (edit the matrix, with the reason) or escalate — silently dropping a planned activity is not permitted.
- WHEN the verification gate passes THEN the loop SHALL advance to
self-review, and the laterevidencenode SHALL summarise from the verification results rather than re-deriving them.
Requirement 4 — evidence is captured, not described
User story: As a reviewer, I want to see what was actually run and what it produced, so that I can trust the result without re-running it myself.
Acceptance criteria (EARS)
- The Verification results section SHALL record, per executed activity, the exact command (or procedure), the outcome, and a link to the evidence.
- WHEN verification produces file evidence (test output, screenshots, recordings, reports) THEN it SHALL be written under
<specDir>/<id>/evidence/and referenced from the plan; the directory is optional and only exists when there is evidence. - WHEN the work item has a user-facing surface and UI verification runs THEN the evidence SHALL include rendered screenshots of the verified states, and an animated capture (GIF or equivalent) WHEN the behaviour under test is a flow rather than a state.
- WHEN the change adds or alters integration behaviour THEN the reviewer briefing SHALL embed
the-loop scenarios --format markdown, and the plan SHALL reference it rather than duplicating the scenario list. - Evidence SHALL be committed with the work item; a link to a transient location (a CI run that expires, a local path) is not evidence.
Requirement 5 — the loop facilitates verification without owning it
User story: As an operator with a complex system (several repositories, a staging environment, a bespoke harness), I want the-loop to make room for my setup rather than model it, so that the loop stays useful without becoming my test runner.
Acceptance criteria (EARS)
- The testing plan SHALL carry a Verification environment section declaring what the verification needs: repositories to check out, services to run, fixtures/data, credentials by reference (never values), and the commands that bring it up.
- WHEN the setup is described by an operator document THEN the plan SHALL reference it through
customInstructions.docsrather than restating it, and the loop SHALL read those docs before planning verification. - the-loop SHALL NOT introduce a runner, orchestrator or environment manager of its own for this purpose; the plan names the project's commands and the loop executes them.
- IF the environment cannot be brought up THEN the loop SHALL record the failure in Verification results, mark the affected activities unexecuted, and escalate rather than passing the gate.
Requirement 6 — one process, described once
User story: As a maintainer, I want the two new nodes to exist in the graph, the config, the manifest, the templates and the prose consistently, so that the-loop does not grow a second, divergent description of its own process.
Acceptance criteria (EARS)
workflow.phases(schema default, this repo's config and the bundled template config) SHALL declaretest-planningandverificationin graph order, and the existing P4 parity test SHALL enforce it..the-loop/manifest.yamlSHALL trackdocs/specs/<id>/testing-plan.mdat phasetest-planninganddocs/specs/<id>/evidence/as an optional directory, and the existing P1–P3 parity tests SHALL hold graph, manifest and template together.SKILL.md,reference/workflow.md,reference/testing.md, the execution-log template and the capability docs SHALL render the new sequence; none of them SHALL redefine it.tokenEconomy.modelRouting.stagesandtokenEconomy.thinkingEffort.stagesSHALL carry entries for the two new stages, so routing does not fall through a hole.
Non-functional requirements
- No new runtime dependency. The change is declarative (graph, schema, manifest, templates, prose) plus tests; the minimalism ladder forbids a test-orchestration dependency for a problem the project's own tooling already solves.
- Backwards behaviour for in-flight items. A work item whose spec folder predates this change has no
testing-plan.md; the new gate blocks it attest-planningexactly as any missing artifact does, and the operator either writes the plan or uses the auditedthe-loop graph forceescape hatch. No silent skip. - Cost. Two more nodes means two more agent stages; both are routed at
standard/economytiers so the added cost is bounded (reference/token-economy.md).
Security considerations
Threat-model-lite (
security.threatModel.required). Seereference/security.md.
- Actors & trust: the actors are unchanged — the operator (trusted), the agent running the loop (semi-trusted; it authors the artifacts), and, on the daemon path, GitHub webhook payloads (untrusted). This change adds no ingress: nothing here parses a payload, opens a socket, or accepts remote input. The new node data comes from checked-in markdown in the repository's own spec folder.
- Trust boundaries & data: two boundaries are touched, not created.
- Evidence is repository content.
<specDir>/<id>/evidence/is committed, so anything captured there is as public as the repository. Test output, screenshots of an authenticated UI and environment dumps routinely contain tokens, cookies, customer data and internal hostnames. - The verification environment describes credentials. A plan that names what the setup needs is one edit away from a plan that contains what the setup needs.
- Evidence is repository content.
- Abuse cases (EARS):
- WHEN verification captures output containing a secret, token, cookie or personal data THEN the loop SHALL redact it before committing the evidence, and SHALL NOT commit a capture it cannot redact.
- WHEN the Verification environment section is authored THEN credentials SHALL be named by reference (env var name, secret-store key) and never by value; a literal secret in the plan SHALL be treated as a leaked secret (rotate, do not merely edit).
- WHEN a testing plan names a command to run THEN it SHALL be reviewed as executable content, like
reviews.critics[]entries already are (decision-043) — a plan is a committed file that instructs an agent to run something, so it is code for review purposes. - WHEN the graph gains a node THEN that node SHALL NOT weaken an existing gate:
security-reviewstaysrequired: true, andverificationsits before the review chain so a failed verification is visible to it.
- Fail closed: an activity that was not executed is not ticked; a plan that cannot be read, is unlocked, or has an empty Verification results section blocks the node. The graph's own contract already fails closed on a missing artifact — this work item adds no bypass, and the only override remains the audited
the-loop graph force.
Out of scope
- A test runner, environment orchestrator or multi-repo checkout mechanism owned by the-loop (R5.3 is explicit that this stays with the project).
- Automated redaction tooling for evidence — the rule is stated and reviewed; enforcing it mechanically is a separate work item.
- A human-approval node of its own for the testing plan. Revised on PR #166: rather than no gate at all, the plan is ordered before
design-approvalso that existing gate covers it — one approval, two artifacts, no sixth stop. - Retro-fitting testing plans onto completed work items.
- Changing
the-loop scenarios, the Gherkin docstring rule, or the contract-first API conventions — the plan references them.
Open questions
- Should
test-planningsit before or aftertasks-breakdown? Resolved in design (D1): before, sotasks.mdcan reference matrix rows. - Should the testing plan get its own human-approval node? Resolved (D2): no node of its own — and, revised at the owner's request on PR #166, it is ordered before
design-approvalso that gate reviews the design and the plan together. - Should
verificationproduce a separateverification-report.md? Resolved (D3): no — it re-gatestesting-plan.md, mirroring howimplementationre-gatestasks.md.
Review comments
Appended by the-loop's
record-feedbackhook when a human gate approves with comments (issue-109).