Implements the §P4 acceptance gate from plan-migration.md, with one
scope adjustment confirmed up-front: full Vue Dashboard (~1650 lines)
deferred to a future UI phase, replaced by extending the existing
P3 static status page with Sign Off / Abandon / Feedback controls.
All P4 backend acceptance criteria are scripted (phase4-verify.js).
Project status FSM (project.json.status):
- server/src/core/devloop/loop-controller.js
* draft → running → shipped → shipped-final | abandoned
↓ ↓
l2_blocked (feedback flips back to running)
l2_exhausted
* `_setProjectStatus` validates transitions via STATUS_TRANSITIONS,
emits SSE `project.status`, writes timeline event.
* createProject seeds status=draft; runDocsPhase end → running;
runProject(shipped) → shipped; all dead-end branches (l2_blocked,
l2_exhausted) also propagate to status via _safeSetStatus.
L3 helpers:
- signOff(pid, opts) — requires status=shipped → shipped-final; commits
a `chore: sign-off` git entry; rejects other source states with
InvalidProjectStatusTransition.
- abandon(pid, opts) — any non-terminal → abandoned; commits + calls
sseBroker.close(pid) to send SSE close frame to subscribers.
- submitFeedback(pid, text, opts) — rejects in shipped-final/abandoned;
invokes PM in incremental mode; on prd_rev bump writes
changelog.ndjson prd_rev entry + emits prd.updated SSE; if prior
status was shipped, flips back to running so next runProject can
rebuild.
PM incremental mock fixture:
- fixtures/devloop-mock/devloop-pm.json — converted to sequence form:
* sequence[0] (init) — original P1 fixture (PRD rev=1, 14 files).
* sequence[1] (incremental) — appends a new section to
prd/feature/feature-tree.html, bumps article data-rev to 2,
writes history/prd-rev-002.html.
Baseline happy-path Integrator:
- fixtures/devloop-mock/devloop-integrator.json — single-shot pass.
Makes vanilla runProject ship without a scenario override.
P4 happy-path scenario:
- fixtures/devloop-mock-scenarios/happy_path/devloop-architect.json —
single-unit (todo-be only) Architect so end-to-end ship works with
the baseline Coder/Tester (which only know todo-be paths).
Routes:
- server/routes/devloop.js:
* POST /projects/:pid/sign-off — 400 InvalidProjectStatusTransition
when status != 'shipped'; 200 returns { status }.
* POST /projects/:pid/abandon — body { by?, reason?, note? }; 400 on
terminal state; 200 returns { status: 'abandoned' }.
* POST /projects/:pid/feedback — body { text (req), by?,
mockFixtureDir? }; 400 on missing text or shipped-final/abandoned;
200 returns { prd_rev_before, prd_rev_after, status }.
* POST /projects: now accepts optional `mockFixtureDir` so the same
fixture dir threads through both the create call and later
feedback (keeps mock-sequence counters aligned).
Static status page (replaces full Vue Dashboard for P4):
- server/public/devloop-status.html — adds:
* Status badge in header (color-coded per status).
* Sign Off / Abandon control buttons (disabled per current state).
* Feedback textarea + Submit button → POST /feedback.
* Buttons reflect FSM (signoff only when shipped; abandon/feedback
locked at terminal states).
Acceptance:
- scripts/phase4-verify.js — 9 steps, full HTTP path:
① POST /projects → running
② POST /run → shipped
③ POST /feedback → PRD rev 1→2 + running (+ changelog entry)
④ POST /run again → shipped
⑤ POST /sign-off → shipped-final
⑥ POST /feedback (after sign-off) → 400
⑦ POST /sign-off (after sign-off) → 400
⑧ second project: POST /abandon → abandoned
⑨ POST /abandon (after abandon) → 400
Tests (+19 cases):
- server/tests/devloop/p4-l3-feedback.test.js
* 14 FSM cases covering happy path + abandon path + signOff
pre-conditions + empty feedback rejection.
* 5 route cases via fetch on ephemeral express app.
Results:
- phase0-verify: 8/8
- phase0-test-call: 7/7
- phase1-verify: 7/7
- phase2-verify: 6/6
- phase3-verify: 9/9
- phase4-verify: 9/9
- vitest devloop+acp-core: 213/213 (was 194 → +19)
Spec deviations explicit:
- Full Vue DevLoopDashboard.vue + Ops 4 sub-pages NOT implemented;
static status page handles the demoable surface area instead.
- All backend endpoints from §P4 (sign-off, abandon, feedback) are
complete and tested.
Specs: docs/prd/newfunction/_spec/plan-migration.md · P4 L3 + UI
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>