Version. v0.8
Date. 2026-08-01
Supersedes. v0.7, v0.6 and v0.5, all drafted and never filed — each halted at pre-flight. v0.4 at record 26a6f2c and v0.1 at a276e5b stand as siblings, unaltered. v0.2 and v0.3 were also drafted and never filed. The record holds v0.1, v0.4 and v0.7.
Changes from v0.7. One cross-reference deleted. §4.1 opened with "[This is the one exception to §2's read-only engine]" — describing the §2 that v0.7 removed. §2 states no read-only rule for it to be an exception to; it names the engine change up front and says the engine is otherwise read for one purpose. The bracket re-asserted the framing v0.7 exists to remove, one section after removing it — the correction landed in §2 and the pointer at §2 still described the old text. Nothing built changes; §4.1's instruction was already correct and unambiguous.
Changes from v0.6. One false claim deleted, and with it the annotation that had been correcting it. §2 opened "It does not change the engine… No engine file is edited", which was false from v0.1 — B-28's fix has always been in the engine's schema module. A correction block beneath §4.1 carried the exception and went stale in three consecutive versions, because it explained scope rather than stating it and so read as commentary in every sweep. §2 is now simply true and the block is gone. D-2's table also still showed the upload-side pair as "determination first" when the determination was answered; it now shows them excluded on evidence.
Changes from v0.5. No new decision — v0.5 made the decisions and did not carry them everywhere they bite. Checkpoint A still asked for a live demonstration that one render is "distinguishable as current" — the thing D-3 forbids and gate item 7 rules out, so a session reaching the checkpoint would have had to build what §3 prohibits or fail. The kickoff still instructed settling Step 0's determinations in a document whose §6 records Step 0 as complete. §4.1 and D-2 still phrased determination 3 as unanswered while §6 stated its answer. And §1 still framed the defect as "nothing says which is current", the premise §3 overturns. The generator: a decision was changed in the section that states it, and not swept for the sections that depend on it.
Status of the build. RESUME. Step 0 is complete on main in both repositories — no branch created, no code written, no database connected. Enter at Step 1.
Changes from v0.4. Step 0 halted on its own condition, and the answer inverts one of this CR's premises. The engine has no superseded render, and that is the seed implemented correctly rather than a gap — automatic state transitions on artifacts the Operator has authority over are a category error, so the substrate declines to say which render is current. Currency is therefore not merely unbuildable here, it is the wrong thing to display, and the room shows recency instead. The engine supersession marker planned as a follow-on is dropped for the same reason. Determinations 1 and 3 came back favourable: no engine route changes, and two declarations, not four.
Changes from v0.3, superseded but recorded. One count dropped, in two places. v0.3 said a correction had reached the body and not the kickoff "for the fourth time"; two instances can be substantiated, not four — CR-2026-161 v0.2's residual imperative and CR-2026-162 v0.1's TWO LITERALS. The change request C brief is not a third: its kickoff would have drifted had only the named line been corrected, but the whole class was swept, and a prevented near-miss is not an occurrence. The number is removed rather than corrected to two — it was ornament in the sentence introducing the mechanism against ornament, and the argument stands without it.
Changes from v0.2, carried. Two stale counts, and a structural fix so the class stops recurring. §4.1's own correction block still said "two literals" directly beneath the sentence establishing four. And the kickoff said "TWO LITERALS in schemas.py" — contradicting §4.1, §6 and the gate, and naming one module when two of the four candidates are in others. A session following it would have changed two, looked in one place, and never found the rest. A correction has now reached the body and not the kickoff more than once, so the kickoff no longer restates any fact the body carries — it points, and a block that points cannot drift.
Changes from v0.1, carried. Two, both found by the executing session at v0.1's filing, and both would have changed what a session does. The source_mode literal is declared in four places, not two — v0.1 named two and asked for a sweep for a third. The two extra are upload-side, and whether they need the member is now Step 0's third determination rather than an absorption or a halt. And the Operator Layer baseline is corrected from 610 to 630 — 610 was the pre-B-5 figure, and CR-2026-160 added twenty tests, so a Step 0 comparison against the stated number would have read as a divergence and halted for nothing.
Author. Claude.ai (drafting session). Approving: Marvin Percival.
Charter. standing-notes/dunin7-standing-authorization-charter-v0_1. No session executes a change request it drafted (§1).
Target. /Users/dunin7/loomworks at main 7e81e30, and /Users/dunin7/loomworks-engine at main a6a3ed6 — two repositories, and §2 explains why.
Baseline. Neither repository is green. Operator Layer: 630 passed, 0 failed, exit code 1, twelve unhandled fetchPlatformLevel rejections. Engine: 1 failed (test_stele_router_mount), the rest passing. The criterion is no new failure and no new unhandled rejection, against sets recorded at Step 0. Exit 0 is not reachable and is not the criterion.
Build-list items. B-28, B-7.
CR number. CR-2026-162. Highest confirmed is CR-2026-161. [EXECUTING SESSION: verify; advance if taken.]
Grounding. inspection-briefs/loomworks-cr-c-step-0-findings-v0_1 — every anchor below comes from it.
Status. Pre-execution.
What changed from the plan. Change request C was scoped as B-6, B-7 and B-28 together. B-6 is split out — see D-1. This CR is the small, surface-facing half, and it ships a user-visible fix and a user-visible capability without waiting for the larger room.
B-28 — contributed Markdown is refused and the work is lost. A type declaration disagrees with what the system actually emits — in four places, two of which need a determination before they are touched. (v0.1 said "two lines". Wrong by at least two; see D-2.)
B-7, first half — there is no way to download a finished render. The engine has served download routes all along. The surface has never called them. A wire, not a build.
B-7, second half — when an older and a newer render sit side by side, the surface shows nothing about either. It already receives created_at, display_number and state and displays none of them.
> **B-7's own framing was "nothing says which is current", and this CR does not adopt it. Step 0 established that the substrate deliberately does not say which render is current, and D-3 explains why that is correct. The defect is that the Operator is shown nothing to judge by** — not that the system withholds a verdict.
The engine change is one file and two lines: the source_mode literal at api/schemas.py:2524 and :2806. That is B-28, and §4.1 carries it. Nothing else in the engine changes — no route, no schema beyond those two literals, no migration, no behaviour.
The engine is otherwise read for one purpose: confirming the download routes' contracts before the surface calls them. /renders/{id}/download, /content and /files/ exist, and Step 0 read their parameters, response shapes and format-conversion behaviour. If any route turns out to need changing, halt — that is an engine change request, not this one.
Two repositories means two branches, two commit series, two merges and two tags. Never one commit spanning both.
> (Rewritten at v0.7. v0.1–v0.6 opened this section with "It does not change the engine" and "No engine file is edited", which was false from v0.1 — B-28's fix has always been in the engine's schema module. A correction block beneath §4.1 carried the exception, and went stale in three consecutive versions because it explained scope rather than stating it, and read as commentary in every sweep. The block is removed and §2 is simply true instead. The recurring failure was a false claim kept alive by an annotation; deleting the claim deletes the annotation.)
D-1 — B-6, the Shaping room, is split into its own change request.
The Step 0 read establishes that Shaping's engine surface is not what Manifestation's was: it carries a confirm/retire lifecycle, executors, and asynchronous jobs. B-5 needed no engine work, and inheriting that as though the rooms were the same size is the error the findings warn against.
B-6 gets its own scoping and its own Step 0, covering the lifecycle, what the surface must show while a job is running, and whether the shape-type-to-render-type mapping is enforced or merely exposed — the second of the findings' two unread items.
Nothing in this CR is blocked by that split. B-28 and B-7 touch neither Shaping's room nor its adapter.
D-2 — B-28 is fixed at both declarations, and the routing question is opened separately. (Queue entry Q-11, taken.)
text/markdown is registered to the discovery-to-seed skill, which emits source_mode="discovery". The assertion schema declares Literal["text", "voice", "pdf", "image"] at schemas.py:2524 and again at :2806. discovery is emitted and not allowed; text is allowed and emitted by no skill.
The literal is declared in four places, not two.
| Declaration | Model | Status |
|---|---|---|
| api/schemas.py:2524 | AddAssertionRequest | Fix. On the contribution path. |
| api/schemas.py:2806 | AssertionResponse | Fix. On the contribution path. |
| orchestration/schemas.py:1208 | UploadResultItem | Excluded. Step 0 established no discovery extraction reaches it. |
| api/routers/uploads.py:228 | PerFileUploadResponse | Excluded, same evidence. |
The two on the contribution path are fixed. A fix reaching one and not the other leaves the second to fail identically — that is the shape of the defect.
The two upload-side declarations are not touched. Step 0 settled it: a discovery extraction never reaches those responses. _SKILL_SOURCE_MODE maps only to image, pdf, text and voice and returns None when unmapped, and the upload pipeline and the contribution endpoint use different registries.
So adding the member there would declare a value that path cannot produce — the exact mirror of the text member that is allowed and emitted by nobody, which is half of what made this defect possible. (v0.1–v0.5 carried this as a conditional. Resolved: two declarations, not four.)
> Corrections preserved. v0.1 named two declarations and asked the executing session to sweep for "any third." There are four. The undercount originated in the Step 0 findings, which read schemas.py only and concluded two lines, and this CR inherited it. The second time an undercount has crossed from a findings document into a change request — the first was a line-distance in CR-2026-161. The gate would have caught it; the headline would still have been wrong.
Reasoning, and the question deliberately not answered. The findings note that contributed Markdown currently routes through seed extraction, while that registration's own comment says the canonical path is elsewhere. Whether the routing is right is a real question and it is not this one. Making an allowed set match what the system actually emits is not a design commitment — it makes a declaration honest about current behaviour, and if the routing moves later the literal moves with it. The routing question becomes its own build-list item. Deciding it here is the scope absorption C-3 forbids.
What this does not require. Nothing is lost and nothing needs recovering. The assertion is written at contributions.py:268, the response is built after it, and get_db_session rolls back on any exception — so the durable state is as if nothing happened, and the uploaded file row survives, meaning the same file_id re-contributes once the mismatch is fixed. No migration, no backfill, no data repair. The loss is of the person's work, not of their bytes.
D-3 — RESOLVED by Step 0, and the answer inverts the question. The room displays recency, never currency. (Queue entries Q-12 and Q-13, both taken.)
**The engine has no superseded render, and a sweep of the render modules for supersed* returns nothing at all.** composition_orchestrator, the production path, carries zero retire, supersede or invalidate references — producing a render never touches its predecessor. _retire_render is operator-driven and called from exactly one place: the explicit Operator route. Two renders of the same declared type sit in produced indefinitely and neither supersedes the other.
This is not a gap in the substrate. It is the seed implemented correctly. The seed holds that automatic state transitions on artifacts the Operator has authority over are a category error — and a render is precisely such an artifact. The engine declines to decide which render is current because that decision is the Operator's, not the system's.
So currency is not merely unavailable to display. It is the wrong thing to display. A current-marker would be the surface asserting an Operator judgement the substrate deliberately withholds — face 2 in a new place, and this CR's own gate item 7 forbids it.
What the room shows instead. created_at, display_number and state, presented as ordering and provenance information rather than a verdict: when each render was produced, in what sequence within its declared type, and what state it is in. The Operator reads which is current. The surface does not tell them.
> What display_number can and cannot carry. It orders renders only within (engagement, declared_render_type). The display must not imply an ordering across types, and must not present the highest number as the current render — that is the verdict again, wearing a number.
The alternative set aside. v0.1 through v0.4 planned a currency display and, failing that, an engine supersession marker as a follow-on item. Both are dropped. Building a marker would import into the substrate the automatic transition the seed forbids, and it would answer a question the Operator is meant to answer.
What replaces it, as its own item. _retire_render exists, is operator-driven, and is exposed on a route. Surfacing it as an Operator control is how the Operator expresses the judgement the system correctly refuses to make — and it is a new control on a room this CR is already touching, so it is scope growth and becomes a build-list item rather than a step here.
D-4 — the Download control appears only where a download is possible.
RenderingRoom carries a comment recording that no Download button was built because there was no route to call. There is one. The seed's only-show-what-is-available constraint forbids a disabled or greyed control — so the button appears when the render is downloadable and is absent otherwise, never present-and-inert.
And it obeys the room state contract. A download control rendered from a failed read would imply the render exists when no read established that. It appears on populated only.
4.1 B-28, engine repository — the engine change §2 names. Add discovery to the source_mode literal at api/schemas.py:2524 and :2806. Those two only. orchestration/schemas.py:1208 and api/routers/uploads.py:228 declare the same literal and are deliberately left alone — Step 0 established that no discovery extraction reaches them. [EXECUTING SESSION: re-confirm both anchors, and sweep for a fifth declaration. Four were found by sweep after v0.1 named two; a fifth is unlikely but the sweep is cheap and this count has been wrong once.]
The engine commit is separate from the surface work, per §2.
4.2 The render adapter — a new file in the Operator Layer's lib/api/. The wall does not constrain its name: the Step 0 read establishes that rendering is not a forbidden term and the room may be named for itself throughout. Add it to WIRE_BOUNDARY_FILES per the existing convention.
4.3 RenderingRoom.tsx — the Download control per D-4, and the recency display per D-3.
4.4 The strings for both, asserting the surface where no read stands behind them, per the governing rule.
lib/api/shape.ts and never shaping.ts — the wall reads import specifiers, so a room-named adapter trips every consumer. (Recorded here because it is the trap CR-2026-160 hit, and it is now pre-answered.)unread. It needs a perimeter call the fences forbid, and the defect's mechanism does not depend on it.fetchPlatformLevel rejections — build-list item B-34.Per-step commits. Two repositories, so two commit series — never one commit spanning both. Check the current branch before the first commit in each.
Step 0 — DONE. A resuming session does not repeat it.
> What Step 0 established, on main in both repositories with no branch created and no database connected:
>
> - Baselines. Operator Layer 630 passed / 0 failed / exit 1 / twelve fetchPlatformLevel rejections. Engine 1 failed / 3459 passed / 68 skipped. v0.4's 610→630 correction matched the observed run exactly.
> - Determination 1 — no engine route needs changing. All three download routes exist with their contracts read, including the format override. The auth dependency looked like a halt — all four render routes use get_contributing_contributor, a bearer-token path — but get_current_contributor accepts the session cookie with precedence, which is how the surface already calls the list route today.
> - Determination 3 — a discovery extraction never reaches the upload-side responses. _SKILL_SOURCE_MODE maps only to image, pdf, text and voice, returning None when unmapped, and the upload pipeline and the contribution endpoint use different registries. D-2's conditional resolves to two declarations, not four. Adding the member upload-side would declare a value that path cannot produce — the exact mirror of the text member this CR names as half of what made the defect possible.
> - Determination 2 — halted, and resolved at v0.5 by D-3.
>
> A resuming session re-confirms only: both HEADs, both tree states, and both baseline sets. Anything else diverging is an anomaly and halts.
Step 1 — B-28, engine repository. Two literals, per Step 0's determination 3 — api/schemas.py:2524 and :2806 only. The upload-side pair is not touched. Suite against the engine baseline.
Commit (engine): CR-2026-162 step 1: allow the discovery source mode
Step 2 — the render adapter, plus its WIRE_BOUNDARY_FILES entry.
Commit (OL): CR-2026-162 step 2: render download adapter
Step 3 — the Download control, per D-4.
Commit (OL): CR-2026-162 step 3: download control on populated renders
Step 4 — the recency display, per D-3. Not a currency display and not a current-marker.
Commit (OL): CR-2026-162 step 4: render recency display
Step 5 — tests. A test that a discovery contribution is accepted end to end; a test that the Download control is absent on failed and empty and present on populated; a test that the room asserts no currency — it fails if any render is marked, badged or labelled as the current one. Assert specific conditions, never a bare Exception.
Commits: per repository.
CHECKPOINT A — report, then proceed. Both baseline comparisons; the tests; a live pass on the dev server showing a Markdown contribution accepted, a render downloaded, and two renders of the same declared type side by side, each showing when it was produced and its sequence within that type, with neither presented as the current one. No Operator confirmation. Halt and queue on: any new failure or rejection; either determination coming back ambiguous; any charter §6 anomaly.
Step 6 — implementation notes, in both repositories, recording all three determinations.
CHECKPOINT B — merge and tag, separately per repository. --no-ff in each; tag the Operator Layer render-flow-v0_1 and the engine discovery-source-mode-v0_1. Push both. Authorized under R-2 including the pushes. Deployment is never autonomous (F-1).
source_mode declarations accept discovery. The two upload-side declarations are unchanged — excluded on Step 0's evidence, not overlooked. A sweep finds no fifth declaration.source_mode literals.populated only, and never as a disabled or inert control.display_number is never presented as ordering across declared types.WIRE_BOUNDARY_FILES; the vocabulary wall passes with no other new exemption.This block names the entry point and the fences. It restates nothing the body carries — not the steps, not the counts, not the file paths. (Structural change at v0.3. v0.1 and v0.2 restated facts here, and both drifted from the body when those facts changed — the kickoff said two literals in one module while §4.1 said two-or-four across three. This has happened before, and the executing session reads the kickoff. A block that points cannot drift from what it points at.)
CR-2026-162 — B-28 and B-7. Execution session.
CR: loomworks-record/change-requests/cr-2026-162-render-flow-v0_8.md
Confirm it exists, and that it is the highest version present — numeric sort.
Grounding, read before the CR:
inspection-briefs/loomworks-cr-c-step-0-findings-v0_1.md
Charter dunin7-standing-authorization-charter-v0_1 governs.
Read the CR in full before starting. It is the authority on WHAT changes and
WHERE — this block does not repeat any of it. Where this block and the CR
appear to differ, the CR is right and you halt rather than choosing.
Section 3 — the construction decisions and their reasoning
Section 4 — what changes, and the anchors
Section 5 — what is out of scope
Section 6 — the step sequence, both checkpoints, and their conditions
Section 7 — the acceptance gate
TWO REPOSITORIES — the CR's header names both targets and both baselines.
Separate branches, separate commit series, separate merges and tags. Never one
commit spanning both. Commit to a branch in each; check the current branch
before the first commit in each.
The engine is otherwise read-only: no route, no migration, no behaviour change.
If anything in the engine beyond what Section 4.1 names needs to change, halt —
that is a different change request.
playground_dev is the live production database and is not touched.
THIS IS A RESUME. Section 6 records what is already complete and where to
enter. Do not repeat completed work, and do not re-settle anything Section 6
records as settled.
NEITHER BASELINE IS GREEN in either repository. Section 6 carries both recorded
baseline sets — re-confirm them and compare against them. Exit 0 is not
reachable and is not the criterion.
Deployment is never yours.
Append the outcome to current-status/dunin7-status-brief at close.
DUNIN7 — Done In Seven LLC — Miami, Florida CR-2026-162 — B-28 and B-7: the lost contribution and the Rendering flow — v0.8 — 2026-08-01 Four declarations where two were named, one wire, and three fields already arriving unused.