DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path current-status/cr-2026-162-step-0-halt-report-v0_1.md

CR-2026-162 — Step 0 halt report — v0.1

Version. 0.1 Date. 2026-08-02 Executed by. Claude Code, execution session on DUNIN7-M4. CR. change-requests/cr-2026-162-render-flow-v0_4.md — confirmed the highest version present (numeric sort; the record holds v0.1 and v0.4, and the gap is deliberate). Charter. standing-notes/dunin7-standing-authorization-charter-v0_1. Halt condition. §6 determination 2, as the CR itself specifies: "If they cannot, halt and report rather than displaying a judgement the data does not support." Status. HALTED AT STEP 0. No code written, in either repository. Both trees clean, both still on main, no branch created.


1. Pre-flight

| Check | Result | |---|---| | Operator Layer | main 7e81e30, matches origin/main, tree clean | | Engine | main a6a3ed6, matches origin/main, tree clean | | CR number | CR-2026-162 — nothing higher filed | | Branch discipline | Both repos still on main. Nothing committed, so nothing needed a branch. | | playground_dev | Never connected to. |

Operator Layer baseline, recorded by name:


Test Files  106 passed (106)
Tests       630 passed (630)      0 failed
Errors      12 unhandled rejections     exit code 1

Rejection set by origin: operator/Home.test.tsx ×7, nav/NavBar.test.tsx ×4, nav/AppShell.test.tsx ×1 — all fetchPlatformLevel.

> v0.4's baseline correction earned its keep immediately. The header states 630. v0.1 stated 610, and a Step 0 comparison against that figure would have read as a divergence and halted for nothing. The corrected number matched the observed run exactly.

Engine baseline, recorded by name, run against playground_test:


FAILED tests/test_stele_router_mount.py::test_stele_router_mounts_and_begin_resolves_end_to_end
1 failed, 3459 passed, 68 skipped

The single failure is the long-standing unrelated 401 (build-list B-33), exactly as the CR's header states. Both baseline sets are therefore on record, though neither was needed for this halt — no code was written in either repository.


2. Determination 1 — the download routes: PASS, nothing needs changing

All three routes exist at a6a3ed6, in api/routers/renders.py:

| Route | Handler | Returns | |---|---|---| | GET …/renders/{object_id}/download | download_render_route (:793) | Response with media_type=result.content_type and Content-Disposition: attachment; filename="…" | | GET …/renders/{object_id}/content | render_content_route (:969) | content in its native shapeinline_dict → JSON, binary_blob → bytes, external_reference → JSON envelope | | GET …/renders/{object_id}/files/{filename:path} | render_file_route (:1100) | per-file retrieval within a multi-file render |

/download carries the format override the findings described: format: str | None = Query(default=None)"grab an HTML or MD copy of a render whose declared format is PDF, without producing a second render." Error paths return JSONResponse 404 and 422. Only produced renders can be downloaded.

The authentication question, which looked like a halt and is not. All four render routes — including the list route the surface already calls successfully today — depend on get_contributing_contributor. That reads as a bearer-token contributor path, which the Operator Layer does not use.

It resolves. get_current_contributor (api/deps.py:773) accepts both paths and documents the precedence: "Session cookie (humans). Resolved via the person + membership tables… Synthesizes a Contributor view with kind='human', id=person.id", and "Cookie takes precedence." The Operator's session satisfies it, exactly as it already does for the list route.

No engine route needs changing. D1 does not halt.


3. Determination 2 — the halt. These fields cannot distinguish current from superseded

The answer is no, and the reason is stronger than the CR anticipated: the engine has no superseded render.

The CR's counter named the trigger as "two renders can hold the same state with no ordering between them." What the read establishes is adjacent but more fundamental.

What was read at a6a3ed6:

  1. Producing a render never touches its predecessor. engagement/composition_orchestrator.py — the production path — contains zero references to retire, supersede or invalidate. A sweep of the render modules for supersed* returns nothing at all.
  2. Retirement is an explicit act, not a consequence. _retire_render (engagement/render.py:12) is "operator-driven retirement" and is called from exactly one place: retire_render_route (api/routers/renders.py:1291). _invalidate_render is drift-routed, fired when an upstream consideration closes.
  3. display_number is ordered, but only within a scope. assign_render_display_number (engagement/display_numbers.py:141) is MAX+1 "scoped to (engagement_id, declared_render_type_ref)", with None forming the separate ad-hoc scope.

So two renders of the same declared type sit in produced indefinitely, and neither supersedes the other. The older one is not stale, not replaced, and remains a legitimate downloadable output.

What the three fields can and cannot support:

| Claim | Supported? | |---|---| | "this render is newer than that one" (same declared type) | yesdisplay_number is strictly ordered in that scope | | "this render is newer" (across declared types, or against an ad-hoc render) | no — separate MAX+1 sequences, not comparable | | "this render is retired / invalidated" | yesstate says so, but only after an explicit act | | "this render is current and that one is superseded" | NO — there is no supersession, so there is nothing to be superseded by |

Displaying a current-marker would be face 2 — the surface asserting a status the record has never established. That is precisely what the CR's own honest counter said to halt on, and it is why this halts rather than proceeding to Step 4.

What this means for B-7's second half. The build-list framing is "nothing says which is current." The engine does not have a notion of a current render, so the gap is not that the surface fails to display one — it is that the concept does not exist. B-7's second half rests on a premise the substrate does not carry.

A constructive path exists and is deliberately not taken here. The surface could honestly display recencydisplay_number ordering within a type, plus created_at and state — which solves the user-facing problem of telling an older output from a newer one without claiming currency. That is a different feature from the one B-7 describes, and choosing it would be resolving an ambiguous determination by choosing, which the kickoff forbids in as many words.


4. Determination 3 — no. Two declarations change, not four

Does a discovery extraction ever reach UploadResultItem or PerFileUploadResponse? No — and the trace is short.

PerFileUploadResponse.source_mode (api/routers/uploads.py:470) is populated from _source_mode_for_selected_chain (:883, defined :501), which reads a fixed map, _SKILL_SOURCE_MODE (:489-498):


image_vision_analysis → image     pdf_extraction    → pdf
image_ocr             → image     text_extraction   → text
image_metadata        → image     docx_extraction   → text
audio_transcription   → voice     html_extraction   → text

There is no discovery entry, and unmapped skills return None (:508). UploadResultItem is constructed from the same shape (uploads.py:1061).

The upload pipeline and the contribution endpoint use different registries. The upload path dispatches over the detection-chain skills above; discovery_to_seed lives in the contribution endpoint's ExtractionSkillRegistry, registered against text/markdown at skills/registry.py:201. The two never meet.

So the upload-side pair must NOT be changed. Adding discovery there would declare a value that path cannot produce — the exact mirror of the text member that is allowed and emitted by nobody, which D-2 names as half of what made this defect possible in the first place.

D-2's conditional resolves to: two declarations, api/schemas.py:2524 and :2806. Both re-confirmed at a6a3ed6, on AddAssertionRequest and AssertionResponse. No fifth declaration exists — the sweep returns exactly four across src/.


5. What is unblocked, and what is not

D1 and D3 are settled and favourable. If the Operator resolves D2, the CR can resume with:

> The halt is confined to one step. Three of the four in-scope items are ready to build. Nothing about D2 blocks B-28 or the download half, and a v0.5 could drop or re-scope Step 4 and ship the rest.


6. Queued for the Operator

Q-13 — does a "current render" exist, and should it?

| | | |---|---| | Question | The engine has no supersession for renders: producing one never retires another, and two renders of the same declared type sit in produced indefinitely. B-7's second half asks the surface to say which is current. There is no current. Is the right answer (a) display recency and drop the currency framing, (b) build supersession in the engine so there is a current render, or (c) leave B-7's second half unbuilt? | | Default | (a) — display recency, re-scope B-7's second half. It solves the Operator-facing problem, uses only fields already sent, asserts nothing the record does not carry, and costs no engine change. | | Blocks | Step 4 only. | | Proceeds regardless | B-28 (Step 1), the adapter (Step 2), the Download control (Step 3). |

Q-12 is answered and should be closed. It asked whether renders need an explicit current-marker. They cannot have one derived from what is sent, because nothing is ever superseded — so the question is no longer "surface-first or engine-first" but "does the concept exist at all," which is Q-13.


7. Recommendation

A v0.5 from a drafting session, carrying:

  1. Step 4 re-scoped or removed, per Q-13. If re-scoped to recency, it needs its own wording — the display may say "newer" within a declared type and may not say "current".
  2. D-2's conditional collapsed to two declarations, with D3's finding recorded so the upload-side pair is excluded on evidence rather than re-litigated at each execution.
  3. §6 determination 3 marked settled, and determination 1 likewise — both are answered here and need not be re-run.
  4. The acceptance gate's item 7"states nothing the data cannot support" — is the item that caught this. It should survive into v0.5 unchanged; it is the only reason Step 4 did not ship a false marker.

DUNIN7 — Done In Seven LLC — Miami, Florida CR-2026-162 — Step 0 halt report — v0.1 — 2026-08-02 Nothing is superseded, so nothing is current. The surface was about to say otherwise.