Requirements: every phase is selectable — the human is the floor
Phase 1 of 4 (requirements → design → testing plan → tasks). Ticket: issue #179.
Introduction
Issue #177 made part of the loop selectable: at the phase-selection gate an authorized human unticks phases, and the work item routes around them. The vocabulary it shipped was deliberately narrow — the spec chain only — because decision-067 D2 held that a fixed floor (test-planning, implementation, verification, the review chain, security-review, human-approval) was what bounded the damage of any illegitimate declaration.
The ticket opens on the first crack in that floor: "For documentation related changes, there's no testing plan that's required. Make that phase also optional and hence selectable from the phase selection step." A doc fix that unticks its whole spec chain still has to author a locked testing-plan.md whose every matrix row says n/a.
The owner's direction on this ticket goes further and settles the general case: every phase is selectable and skippable. Not the spec chain plus one; everything the loop walks. That is a deliberate reversal of decision-067 D2 and of the required: true markers decision-063 put on security-review and human-approval — and it relocates the floor rather than removing it:
- The structural floor becomes a declared one. Nothing is protected by the graph refusing to skip it. What protects the process is that a named, authorized human must choose each omission, before any work starts, on the ticket, and that every omission is recorded with provenance and travels with the work item.
- What does not move:
phase-selectionitself. The gate that asks the question is the one node no declaration can reach — it isrequired: trueand unskippable, so a work item can never walk past the act of choosing. That single invariant is what keeps "everything is selectable" from meaning "the harness decided". - What is still refused: the harness declaring anything, an unauthorized commenter declaring anything, a declaration reaching a node the pointer has already passed, and a declaration inventing a node the graph does not have.
A second requirement travels with the first, and it is what keeps a kept phase meaningful. verification gates testing-plan.md. Once the plan is selectable, a work item can keep verification and skip its plan — and under issue-177's planned-absence rule the gate would then assert nothing at all: a node reporting success without running, the issue-124/167 failure this repository has now fixed twice. So a gate whose subject was declared away must move its subject, not lose it.
Requirements
Requirement 1 — the vocabulary is every phase but the gate itself
User story: As the authorized user starting a work item, I want to select any phase of the loop, so that the process fits the change instead of the change fitting the process.
Acceptance criteria
- WHEN the shipped outer loop (
pdlc-work-item-loop) is compiled THEN every node SHALL beskippable: trueexceptphase-selectionand the terminal nodes (complete,escalated) — specifically includingtest-planning,implementation,verification,self-review,critic-review,security-review,evidence,capability-docs,reviewer-briefingandhuman-approval. - WHEN
phase-selectionis compiled THEN it SHALL remainrequired: trueand SHALL NOT be skippable — no declaration, from any channel, may route around the act of selecting. - WHEN
security-reviewandhuman-approvalare compiled in the outer loop THEN they SHALL no longer carryrequired: true(a node cannot be both required and skippable), and the graph SHALL say in place why the marker was traded. - WHEN any newly skippable node is compiled THEN it SHALL declare its own
on: skippededge to its ordinary forward successor — routing is authored, never inferred, so a missing edge is a compile failure before any traversal. - WHEN the shipped skip sets are expanded THEN
spec-chainSHALL namebrainstorming,requirements-definition,requirements-approval,design,test-planning,design-approval,tasks-breakdown(the chain the project's own vocabulary describes: requirements → design → testing-plan → tasks), and a newreview-chainset SHALL nameself-review,critic-review,security-review,evidence,capability-docs,reviewer-briefing— the six nodes that were oneneeds-reviewlabel. - WHEN the inner
pdlc-pr-loopis compiled THEN it SHALL be unchanged: no skippable node, nophase-selection, andsecurity-reviewstillrequired: true. Declared skips remain outer-loop only (issue-177 R4.1). - WHEN the
phase-selectionchecklist is posted THEN it SHALL list every selectable phase pre-ticked, and WHEN no phase of the loop is protected THEN the checklist SHALL say so plainly — naming that every phase is the user's to decide and that each omission is recorded against their name — rather than printing an empty "always runs" block. - WHEN a phase is declared skipped — from the selection gate or the audited
the-loop graph skipverb — THEN it SHALL route along itson: skippededge without running any hook, SHALL record outcomeskipped, and SHALL be reported bythe-loop checkas skipped by declaration with provenance — never as a pass. This is issue-177's behaviour, unchanged, now reaching every node.
Requirement 2 — a kept gate keeps a subject
User story: As a reviewer, I want a work item that skipped its testing plan but kept verification to still show me what was verified, so that a kept phase is never a phase that silently asserts nothing.
Acceptance criteria
- WHEN
verificationis reached andtest-planningwas not declared skipped THEN its gate SHALL be exactly what it is today —testing-plan.mdpresent, checkmarks complete,Verification resultsnon-empty — and SHALL require no new section anywhere. - WHEN
verificationis reached,test-planningwas declared skipped, and notesting-plan.mdexists THENverificationSHALL instead gate the sharedexecution-log.mdfor a non-emptyVerification resultssection, and SHALL block until it is written. - WHEN
test-planningwas declared skipped but atesting-plan.mdexists anyway THEN that artifact SHALL be gated normally and the execution-log fallback SHALL NOT apply — a declaration tolerates only an absence, and the proof is never demanded twice. - WHEN
verificationitself is declared skipped THEN neither gate SHALL run — the node is not walked at all, and the omission is on the record like every other. - WHEN the bundled
templates/execution-log.mdis authored THEN it SHALL offer aVerification resultssection, so a work item created from the template never blocks on a heading it was never given (the issue-167 shape, pinned by the P5c parity test).
Requirement 3 — a conditional gate is declared, and can only narrow
User story: As the maintainer of the process graph, I want the fallback expressed in the graph and bounded by the same vocabulary as everything else, so that no hook decides for itself when a gate applies.
Acceptance criteria
- WHEN a
validate-artifactsentry declaresonlyWhenSkipped: <artifact>THEN the entry SHALL apply only while every named artifact is a planned absence — its authoring node declared-skipped and no accepted name present on disk — and SHALL reportskippedwith a reason otherwise. - WHEN a hook entry omits
onlyWhenSkippedTHEN its behaviour SHALL be exactly what it is today: the parameter is additive, and every existing node, graph and consuming repository is unaffected. - WHEN
onlyWhenSkippednames an artifact that no declared-skipped node authors THEN the entry SHALL never apply — the parameter reads only the runtime's filteredskipped_artifacts, so it can narrow a gate's applicability and never widen what may be skipped.
Requirement 4 — the reversal is on the record, and the residual is stated
User story: As someone reading why the floor moved, I want the decisions that built it and the decision that dismantled it to point at each other, so the change reads as a revision rather than a contradiction.
Acceptance criteria
- WHEN this work item ships THEN a new decision SHALL record the revision of decision-067 D2 and of the
required: truemarkers from decision-063, SHALL name the one invariant that remains (phase-selection), and SHALL state plainly what a work item can now legitimately omit — up to and including the security review and the human approval gate. - WHEN decision-063 and decision-067 are read THEN each SHALL carry a pointer to the revising decision at the affected point, so nobody follows a superseded rule from an older document.
- WHEN the operating-model surfaces are read (
SKILL.md,reference/workflow.md,reference/security.md,docs/capabilities/process-graph.md,docs/cli/commands/graph.md) THEN each SHALL describe the widened vocabulary, thephase-selectioninvariant and the execution-log fallback — none SHALL still claim a structural floor of never-skippable phases. - WHEN the agent-facing rules are read THEN they SHALL still forbid the harness from declaring or proposing a skip by answering the gate — the widened vocabulary makes that rule more load-bearing, not less.
Security considerations
Threat-model-lite (
security.threatModel.required). This work item dismantles a security boundary and rebuilds it in one place. It is the highest-risk change the declared-skips mechanism has taken, and the honest framing is that the graph no longer guarantees any phase runs; a human does.
- Untrusted actors. Unchanged from issue-177: (a) the agent/harness working the item — it writes
graph-state.json, spec files and (with the operator's credentials) ticket comments, and the whole design assumes it will try to skip conveniently; (b) anyone who can comment on the ticket but is not inrouting.authorizedUsers; (c) a hand-edited or corrupted state file. - Trust boundaries — two of three unchanged, one deliberately widened.
- Who may declare —
routing.authorizedUsers, checked by the shared_authorized_commentsreader, which drops the-loop's own self-marked comments so the gate can never answer itself. Unchanged, and now carrying the whole weight. - What may be declared — still the compiled graph's
skippableset, still shipped as CLI package data a repository cannot override, still re-filtered on every read. What changes is its contents: every phase butphase-selection. A repository, a session or a hook still cannot widen it, andphase-selectionstill cannot be declared away. - When — only nodes still ahead of the pointer. Unchanged.
- Who may declare —
- What the widening costs, stated plainly. An authorized human may now declare a work item that skips its security review and its human approval and walks straight to
complete. Nothing in the graph prevents it. What remains is: the selection is a human act by a named actor; it happens before any phase runs; it is recorded with provenance ingraph-state.jsonand frozen into the portable work-item record; it is posted as a confirmation comment on the ticket; andthe-loop checkreports every omission as skipped by declaration — by whom forever after. The mechanism's guarantee moves from "these phases always ran" to "every phase that did not run is attributable to a person". - Abuse cases.
- The agent posts
the-loop executeto skip its own review. Refused: its comments carry the self-authored marker and are dropped before authorization is considered, and it is not inauthorizedUsers. The skill states the prohibition explicitly, and R4.4 keeps it stated as the vocabulary widens. - An unauthorized commenter selects phases away. Ignored; the gate keeps waiting.
- The harness routes past the selection gate itself. Structurally refused (R1.2):
phase-selectionis required and unskippable, so the loop cannot begin without a human's answer. This is the invariant everything else now rests on. - A late declaration excuses a node already walked. Not recorded (issue-177 R2.12), unchanged — a skip is a plan, not an amnesty.
- The agent hand-writes skips into
graph-state.json. Previously bounded by the protected floor; now bounded only by detectability. A forged declaration claims a channel (selection/cli) whose off-repo trail — the authorized reply, the marked confirmation comment, thegraph.skips_declaredevent — does not corroborate it, and the frozen graph recorded at selection time is the contemporaneous record to compare against. Stated honestly: within the repository the enforcement is now audit alone, not audit-plus-floor. This is the residual the owner accepted in widening the vocabulary, and it is why R4.1 requires the decision record to say so. - A kept gate is hollowed out by skipping what it reads. Answered by R2.2 for the one case that exists in the shipped graph (
verificationovertesting-plan.md), and by R3.1/R3.3 structurally: the conditional parameter can only ever narrow. - Integration outage at the gate. Fail-closed, unchanged: the gate waits, nothing is skipped, no phase runs.
- The agent posts
- Fail-closed expectations. Every failure still degrades to more process: no authorized reply → nothing runs at all; an unparseable or empty selection → the full process; an invalid token → no skip; a missing
on: skippededge → compile failure; a keptverificationwhose plan was declared away → blocked until the results are written down.