DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path change-requests/cr-2026-184-loomworks-b37-failed-production-visible-v0_2.md

DUNIN7-M4 — INFRASTRUCTURE CHANGE REQUEST

CR-2026-184 — B-37: a failed Shape production is invisible (v0.2)

Version. 0.2 · Date. 2026-08-07 · Author. Claude.ai (v0.1 drafting) / Claude Code (v0.2 amendment) / Marvin Percival (approving). Supersedes. v0.1 at record 43841fe, which stands as a sibling. Target. /Users/dunin7/loomworks-engine and /Users/dunin7/loomworks. Baseline. Engine 699f9ea (post CR-2026-183); surface 852124b.

What changed from v0.1. Step 1's read disproved the premise §2 was written against. The defect is real and worse than described; the remedy moves; two build steps are withdrawn on finding; and the engine half turns out to be already complete.


1. Correction to v0.1's §1 — the defect is a false impression, not missing information

v0.1 said: "When a Shape production job fails, the surface shows nothing that distinguishes it from a job still running. The person waits for something that is never coming."

It does not look like one still running. It drops out of the active list entirely.

dashboard.py:93 filters sj.status IN ('queued', 'dispatched'); render jobs the same at :111; the counts query repeats both at :145-150. A job that reaches failed or declined no longer matches, so it disappears.

> So the person is not left waiting on an item that never resolves. They watch the item vanish and reasonably conclude it finished. That is a positive false impression, not an absence of information — and it is the worse defect. A person who is still waiting will eventually ask; a person who believes the work completed will not.

Operator, 2026-08-07: "That's a positive false impression, not missing information, and it's the worse defect."

2. Correction: the Shape response cannot carry this

A failed production produces no Shape at all. In agents/shaping.py, the ShapeEvent is constructed and appended inside the try block (:688, :719); mark_completed(shape_event_object_id=shape_event.id) runs only after. Any exception before that reaches mark_failed (:399) — and no ShapeEvent was ever created.

shape_event_object_id on shaping_jobs is therefore a result pointer, not a link: populated at completion (shaping_jobs.py:111), and necessarily null on failure because there is nothing to point at.

Two build steps are withdrawn on finding, not skipped:

Both were written against a premise Step 1 disproved. Recording them as withdrawn-on-finding rather than as shortfall, per the Operator's direction.

3. The pre-settled decision, and how it transfers

v0.1 settled: "a new field on the existing response, not a new route."

Operator, 2026-08-07: "The decision transfers in spirit, not in object. What I was settling was 'no new route, no new auth and caching story for status.' That holds. But a failed production produces no Shape, so the Shape response can't carry it. Put the status on whichever existing response already carries the JOB."

Confirmed at Step 1 rather than assumed: the dashboard's active list is built from shaping_jobs and render_jobs directly (dashboard.py:90, :110). It already carries the job. It is also the only place a person watches for this work, and the surface's DashboardView is what renders it.

Remedy: widen the active list to include terminal-failed, and carry the status and reason through. Existing response, existing auth, existing caching. No new route.

Rejected, in the Operator's words:

4. The engine half was already complete

GET /engagements/{eid}/shaping-jobs/{shaping_job_id} (shape_events.py:352) already returns status — including failed — and error_message, which mark_failed populates with the exception text and mark_declined with the reason.

The surface has never called it. Zero references to shaping-jobs anywhere in the surface.

So no new failure-capture was needed, exactly as v0.1 required — but for a stronger reason than it anticipated: the exposure already existed and was simply unreachable in practice, keyed by an id the surface holds only at trigger time and never again.

> This is the fifth item this session opened and found already built or already satisfied — after B-12 (satisfied), B-13 (built), B-17 (built, then unbuilt by a redesign), and B-43 (data layer built, unconsumed). B-19's standing check is extended accordingly: the list's statuses are not the only thing drifting from reality — its READY items include work already done.

5. Retry — confirmed absent, as v0.1 required

mark_failed is terminal. Nothing re-dispatches a failed shaping job; there is no retry path in the engine. Therefore no retry control appears on the surface, per v0.1 §2.5's only-show-what-is-available instruction. Reported, not built.

6. Revised build steps

| Step | What | Mode | State | |---|---|---|---| | 0 | Pre-flight, both repos | Auto | done | | 1 | Read the job record; confirm which response carries the job | Auto | done — §1–§5 | | — | ~~Populate the link column at creation~~ | — | withdrawn on finding (§2) | | — | ~~Status field on the Shape response~~ | — | withdrawn on finding (§2) | | 2 | Active list includes terminal-failed; carries status + reason | Auto | pending | | 3 | Surface renders the failed state distinctly; no retry control | Auto | pending | | 4 | Engine suite + surface sweep; ruff 0; mypy at/below baseline | Auto | pending | | A | Checkpoint | Checkpoint | pending | | 5 | Tag cr-2026-184-b37-failed-production-visible in both repos | Auto | pending |

7. Acceptance gate, revised

  1. A terminal-failed production appears in the active list rather than vanishing from it — the actual defect, restated per §1.
  2. A test that fails if a terminal-failed job is absent from that list, observed failing before it is trusted.
  3. No retry control, because no retry path exists (§5).
  4. Both suites green, both gates clean.

Dropped from v0.1's gate: "link column populated at creation; existing rows with a null link reported and backfilled." There is nothing to backfill — a null link on a failed job is correct and permanent.


DUNIN7 — Done In Seven LLC — Miami, Florida CR-2026-184 — B-37 failed production visible — v0.2 — 2026-08-07