DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path inspection-briefs/loomworks-walk-audit-report-v0_1.md

Loomworks — seed-to-render walk audit — report — v0.1

Version. 0.1 Date. 2026-07-29 Author. Claude Code, on DUNIN7-M4. Operator: Marvin Percival. Brief. loomworks-walk-audit-cc-brief-v0_1.md (v0.1, 2026-07-28), as amended by the Operator's direction of 2026-07-29 (isolated walk-audit stack). Synthetic engagement. WALK-AUDIT-2026-07-2889caf855-2955-4d8f-8030-fed4290b4a2d, left standing in playground_walkaudit.


0. Heads-up: the two things to read first

  1. Door 3 produces engagements that cannot reach Stage 2 at all. Every engagement created through the shipped door-3 path writes one discovery_to_seed_extracted Memory event, and that event type is not registered in the Memory registry. Manifestation derivation replays Memory, hits the unknown type, and 500s. The walk's own synthetic engagement is dead at Stage 2 and therefore at Stages 3 and 4. This is W-1, and it is the finding the walk exists to surface. Isolated by control test (§4).
  2. The Companion cannot reach Stages 2, 3, or 4 at all. The Manifestation and Shaping rooms in the Operator Layer are hardcoded empty placeholders, and the Companion's intent vocabulary has no production intents for manifestation, shaping, or rendering. The continuity number is 8 (§7).

1. Engine + OL SHAs, manifest, dev-stack state

1.1 Fronts

| Thing | Value | Note | |---|---|---| | Engine main HEAD (walked) | 1aac8154ca440b831f5ba2bd0fc02d6af890614d | 2026-07-24. Matches the front v0.75 records. Working tree clean but for M uv.lock. | | Operator Layer HEAD (walked) | 8c5ec15e3315de35c632c78894c4f4fe9e15c9cc | 2026-07-22, on branch feat/foray-sales-generator, 10 commits ahead of OL main 99f7f64. | | OL main | 99f7f64 | The front v0.75 records. Not what is checked out. | | Manifest read | v0.75~/loomworks-record/current-status/current-status-manifest-v0_75.md | Plus current-status-manifest-v0_75-amendment-v0_1.md. The brief grounded on v0.74; the brief instructed me to read the highest actually present, and v0.75 is it. |

Lane B caveat, load-bearing. The Operator Layer I drove is the working tree at 8c5ec15, on a feature branch 10 commits ahead of main. It contains the merged Companion-surface work (git merge-base --is-ancestor 3f2fca8 HEAD → true), so the Lane B findings below are valid for the Companion surface. But it also carries 10 unmerged foray-sales-generator commits. Any Lane B finding here should be re-confirmed against main before it is treated as a statement about the shipped product.

1.2 What changed from v0.74 to v0.75 (one paragraph, per the Operator's request)

v0.75 is record hygiene only — no build work. It does three things. First, it marks superseded, in place, the v0.69-era sentences still standing inside the v0.74 header and Entries 113/114 that claim the Companion-surface work lives on feat-companion-surface and was never merged to main; the repo is ground truth and contradicts them (git merge-base --is-ancestor feat-companion-surface main returns true, main..feat-companion-surface is 0 commits). Corrections-preserved: the sentences stay, markers are appended, nothing is deleted. Second, it records the repo-verified current fronts — OL main 99f7f64 (2026-07-19), engine main 1aac815. Third, it opens a new §5 residue naming the absorption gap those fronts expose: OL and engine work landed between 2026-06-28 and 2026-07-19/28 that no §3 entry records, including the OL "Item 7a" claim/credit merge and the engine advance 0b2c232 → 1aac815. The gap is named, not filled. Everything else carries v0.74 forward.

1.3 Dev-stack state as found — and why the brief's stack did not exist

This section is the environment-reality section the Operator asked for. Every line is evidence-cited.

What the brief assumed: a dev stack — engine on :8000, Operator Layer on :3001, a dev database that could safely gain a synthetic engagement.

What was actually running:

| Port | Process | Reality | |---|---|---| | :8000 | uvicorn loomworks.api.app:create_app from ~/loomworks-engine, launchd com.dunin7.loomworks-engine | The live production engine. ~/.cloudflared/config.yml routes api.dunin7.com127.0.0.1:8000. Posture LOOMWORKS_ENV=production; WEBAUTHN_RP_ORIGIN=https://app.dunin7.com. | | :3002 | next start from ~/loomworks, launchd com.dunin7.loomworks-operator-layer | The live production Operator Layer. Routes app.dunin7.com127.0.0.1:3002. The plist header says so: "Loomworks Operator Layer (production build) — dunin7.com perimeter, Stage 1." | | :3001 | nothing | The dev surface the brief targets. loomworks-dev.dunin7.com127.0.0.1:3001 returns 502. The OL plist records the intent: "the dev server keeps 3001 for loomworks-dev.dunin7.com, started by hand when wanted." | | :5432, :9000, :6379 | Postgres, MinIO, Redis | Shared services, launchd-managed. |

Three consequences that stopped the brief as written:

  1. playground_dev is the production database. ~/loomworks-engine/.env is the only env file, and WorkingDirectory in the engine plist is what makes it resolve. It sets DATABASE_URL=…/playground_dev and LOOMWORKS_ENV=production. The live perimeter runs on a database named playground_dev. Creating the synthetic engagement there — which the brief's "the dev database gains the synthetic engagement" would have meant — would have written audit data into the live record.
  2. The brief's dev-auth affordance was not mounted. POST /auth/dev/issue-session on :8000 returns 404. api/app.py:871 mounts that router only when loomworks_env is development or test; posture is production, so the route is absent by design. The affordance exists in the tree, not on the running engine.
  3. The CEILING could not have been taken in a browser either. WEBAUTHN_RP_ORIGIN=https://app.dunin7.com, so a passkey tap at localhost:3001 would fail origin validation regardless.

Standing Operator item — the playground_dev naming trap. The database backing the public perimeter at app.dunin7.com is named playground_dev. Every convention an operator, a script, or an agent brings to that name — "dev is safe to write to, safe to reset, safe to point a test at" — is wrong here, and nothing at the point of use says so. This audit was one instruction away from writing synthetic audit data into it, and stopped only because the cloudflared ingress was read before the first write. Flagging as a standing item, not resolving it.

1.4 The stack I built instead (Operator-directed, Option 1 amended)

| Component | Value | |---|---| | Database | playground_walkaudit, created fresh. playground_dev never written to. | | Dev engine | Second uvicorn from ~/loomworks-engine, 127.0.0.1:8001, inline env only~/loomworks-engine/.env not modified. LOOMWORKS_ENV=development, WEBAUTHN_RP_ID=localhost, WEBAUTHN_RP_ORIGIN=http://localhost:3005, isolated LOOMWORKS_DATA_DIR. Launcher: scratchpad/start-dev-engine.sh. | | Dev OL | next dev -H localhost -p 3005 from ~/loomworks, ENGINE_ORIGIN=http://127.0.0.1:8001. Port 3005 appears nowhere in ~/.cloudflared/config.yml (verified: grep -c 3005 → 0) and is localhost-bound, so nothing new became publicly reachable. | | Live processes | Untouched. No launchd job stopped, started, or reloaded. | | Auth | POST /auth/dev/issue-session on :8001 → 204, session valid (/me → 200). CEILING-BYPASSED-DEV. |

Bringing up a fresh Loomworks database is not a one-command operation. Three out-of-band steps were required that alembic upgrade head does not cover, and none are documented as a sequence:

  1. Migration 0034_phase_15_loomworks_engagement_induction.py:277 raises RuntimeError: administrative engagement not present. The administrative engagement is created by app startup (api/app.py:87, ensure_administrative_engagement), not by any migration. A fresh DB must therefore be migrated to 0033, have the app bootstrap run against it, then be migrated to head.
  2. Stele has a separate alembic chain (~/stele/src/stele/migrations, version table stele_alembic_version) that the engine chain does not include. Without it principals.totp_last_step is missing and any principal write fails with UndefinedColumnError. Its baseline 0001 also collides with the engine-created principals table and must be stamped, not run.
  3. There is no non-WebAuthn door to create the first identity. Provisioning used stele.registry.create_principal + a host_account insert + the product's own persons.onboard.onboard(). Legitimately a CEILING; noted because it means no scripted walk can start from an empty database without library access.

Also required before the walk could move, both through the product's own Operator-facing doors:

Second engagement, disclosed. Because W-1 kills Stage 2 on the synthetic engagement, Stages 2–4 could not be walked there at all. To answer whether those stages work at all — which the walk table, the continuity number and the provenance verdict all need — I built one clearly-labelled control, WALK-AUDIT-2026-07-28-CONTROL (5bbdd348-2b70-4772-b751-c0b8a5d62951), identical in content but created without the /seed/extract step. It is the isolation test for W-1 and the carrier for Stages 2–4. Both engagements are left standing. E0060, E0007, E0030 and E0006 were never touched; they do not exist in playground_walkaudit.


2. The walk table

Lane A = substrate over HTTP against the dev engine. Lane B = Companion conversation or Operator Layer surface. WA = the synthetic engagement, CTL = the control.

| # | Step | Lane A | Lane B | Evidence | |---|---|---|---|---| | 0.1 | Draft-candidate allocation | CLEAN | OPERATOR-VERIFY | POST /me/engagements/draft-candidate → 201. OL door picker at /operator/create-engagement is client-rendered; SSR HTML carries chrome only. | | 0.2 | Upload authored spec | CLEAN | OPERATOR-VERIFY | POST /engagements/{id}/files → 201, file_id, 5976 bytes, text/markdown. lib/api/door3.ts:51 is the matching client. | | 0.3 | Extract five commitments | CLEAN | OPERATOR-VERIFY | POST /seed/extract → 200 in 13.1 s against real Anthropic. All five commitments populated, gap_fields: [], induction converged cycle 1. Quality high. | | 0.4 | Adjust one extracted value | CLEAN | OPERATOR-VERIFY | POST /engagements/{id}/seed (partial amend) → 200, seed_version 1→2; read-back confirms the adjusted voice_of_the_work. | | 0.5 | Instantiate to the gate | CEILING-BYPASSED-DEV | CEILING | POST /instantiate → 401 step_up_required; /instantiate/challenge → 200 with rp_id: localhost, allow_credentials: []. Bypassed by stamping presence via the product's own record_presence_proof. Then → 200 state: active, attestation_recorded: false. | | 0.6 | Door 1 opens? | CLEAN (route live) | OPERATOR-VERIFY | POST /me/engagements/seed-creation-conversation → 422 (validation only, route alive); with real exchanges → 201 turns_recorded: 11. | | 0.7 | Door 2 opens? | BROKEN | BROKEN | Doors 1 and 2 share a terminal commit at POST /me/engagements/create-from-conversation, which returns 422 demanding a path parameter its own route does not declare. Uncallable with any body. → W-2 | | 1.1 | Text contribution via Companion | CLEAN | CLEAN | POST /operator/converse → held 1…4 with display numbers. Two facts in one message were held as one assertion (no data lost — verified full text). | | 1.2 | Structured contribution | CLEAN | LEAVES-COMPANION | POST /engagements/{id}/contributions → 201 display_number: 5. Attribution differs from 1.1 — see W-6. Reachable in the OL Memory room, not in the Companion. | | 1.3 | File contribution — Markdown | BROKEN | BROKEN | supported-types advertises text/markdown → mode discovery; the contribution 422s on response validation and the contribution is lost (assertion total stayed 5). → W-3 | | 1.3b | File contribution — PDF | LEAVES-COMPANION | LEAVES-COMPANION | → 201, but the whole document lands as one verbatim assertion, not extracted assertions. → W-7 | | 1.4a | Commit held assertions | CLEAN | CLEAN | Five commits → 200, version→2. Not step-up gated — no assert_fresh_presence in the assertions router or engagement/assertions.py; only engagement instantiate is gated. No CEILING here, contrary to the brief's expectation. | | 1.4b | Supersede with a correction | CLEAN | LEAVES-COMPANION | POST /revise → v3, was_revision_of_version: 2; /history returns v1, v2, v3 — corrections preserved. Trajectory is not walkable from any surface — see W-8. Revise itself is reachable conversationally (change_assertion). | | 1.4c | Redirect one | CLEAN | LEAVES-COMPANION | POST /redirect → 200, new assertion id in the target engagement. redirectAssertion exists in lib/api/assertions.ts:70; intent request_redirect exists. | | 1.4d | Retract one | CLEAN | BROKEN | POST /retract → 200, state: retracted. No retract action exists anywhere in Lane B — no client function, no Companion intent. → W-4 | | 1.5 | Ask about a committed contribution | CLEAN | BROKEN | Companion answered "three of the eleven branches… still waiting for your okay, not saved yet". Truth: v4, committed, "four". Wrong value and wrong lifecycle state. → W-5 | | 2 | Produce/refresh the Manifestation | BROKEN (WA) / CLEAN (CTL) | BROKEN | WA: derive and preview both 500, ValueError: Unknown object_type: discovery_to_seed_extracted. CTL: derive → 201. → W-1. Lane B: the Manifestation room is a hardcoded placeholder → W-9. | | 3.1 | Declare a shape type | CLEAN | BROKEN | POST /declared-shape-types → 201 (works even on WA — declaring does not replay Memory). Lane B: Shaping room is a hardcoded placeholder → W-9. | | 3.2 | Produce a shape | BROKEN (WA) / CLEAN (CTL) | BROKEN | shape-events requires manifestation_ref; WA has none (manifestationstotal_count: 0). CTL → 202 → completed, real 4-finding brief, correct "four of the eleven". Companion refuses: no delegation, and the phrasing it suggests does not grant it → W-10. | | 3.3 | Grammar/completeness behavior | CLEAN | n/a | Fired correctly: shape_incomplete, legal-document grammar, missing required structural elements, and offered completeness_override_rationale. Override accepted → v2 confirmed. Working as designed. | | 4.1 | Produce a Mode A render | CLEAN (CTL) | BROKEN | renders/ad-hoc → 202 → completed. No render-production trigger exists in Lane B — the Rendering room only lists, and no Companion intent produces. → W-11 | | 4.2 | Download the artifact | CLEAN (CTL) | LEAVES-COMPANION | /download → 200, 11 325 bytes, content-disposition: attachment; filename="meridian-onboarding-board-brief-walk-audit.html". Verified genuine: full HTML, correct facts. OL wires inline view only, not /downloadW-12. Companion's request_download returns raw UUIDsW-13. | | 4.3 | Incremental re-render | CLEAN (CTL) | BROKEN | Revised an assertion → re-derived → re-shaped → re-rendered; change surfaced correctly ("5 of the credit union's 11 branches", Doral noted). It is a full re-run of the chain, not an incremental delta. memory-status flags staleness well; downstream-impact lists downstream artifacts but marks none stale → W-14. Lane B cannot reach any step of it. | | 5.1 | Observability | LEAVES-COMPANION | LEAVES-COMPANION | activity-summary is an in-flight counter, all zeros after the walk. room-summary is counts. /me/dashboard/recent is the only history-shaped surface, and it shows download_url: null and labels both distinct renders #1 — html_document. → W-15 | | 5.3 | Provenance walk | CLEAN (with one gap) | BROKEN | Five hops all resolve over the API; at-version/2 faithfully returns the text that was rendered. The Manifestation hop cannot be version-pinned → W-16. No Lane B surface exposes any hop (at-version appears nowhere in the OL). |


3. The break list

Every non-CLEAN finding, numbered. "What fixed would mean" is stated as the observed gap, not as a proposed design.


W-1 — Door-3 engagements cannot derive a Manifestation

Stage 2 · Lane A and Lane B · BROKEN

POST /engagements/{id}/manifestations/derive and /preview both return 500 on the synthetic engagement:


ValueError: Unknown object_type: discovery_to_seed_extracted
  at src/loomworks/memory/registry.py:220  (deserialize_memory_object)
  via src/loomworks/memory/queries.py:92   (state_of_engagement_at_version)
  via src/loomworks/engagement/manifestation.py:213, :511
  via src/loomworks/api/routers/manifestations.py:432

The type is written by the door-3 extract path (api/routers/seed_extraction.py:240; model at engagement/discovery_to_seed.py:63) but is never registered: memory/registry.py registers Phases 2, 3, 4, 6, 7, 9, 10, 11, 31, 34, 37 and stops. grep -c "_register_phase_53\|_register_phase_54"0.

Isolated by control test. Synthetic engagement Memory contains exactly one such event (SELECT object_type, count(*) … GROUP BY 1assertion|15, relationship|2, seed|2, discovery_to_seed_extracted|1, engagement|1) and derive 500s. The control engagement, created without /seed/extract, has no such event and derives → 201. Same code, same database, same session.

Blast radius is confined to the Memory-replay path: assertions, memory-status, room-summary, activity-summary, shapings, renders, considerations, declared-shape-types, downstream-impact all return 200 on the broken engagement. It is derivation specifically — and derivation is the gate to Stages 3 and 4.

Fixed would mean: an engagement created through the shipped door-3 path can derive a Manifestation.


W-2 — Doors 1 and 2 cannot be committed; the terminal route is uncallable

Stage 0 · Lane A and Lane B · BROKEN

POST /me/engagements/create-from-conversation returns 422 for every request, including a well-formed one:


{"detail":[{"type":"missing","loc":["path","engagement_id"],"msg":"Field required","input":null}]}

The route (api/routers/me_create_engagement.py:553) declares no {engagement_id} path parameter, and its handler signature (:567) has none. The requirement arrives through the dependency chain: the handler depends on get_seed_induction_agent (api/deps.py:312), which depends on get_llm_client_with_engagement_fallback (api/deps.py:270), whose first parameter is engagement_id: UUID = Path(...) (api/deps.py:271) — a path-scoped dependency mounted on a route with no such path segment. FastAPI can never satisfy it.

Both doors 1 and 2 converge on this endpoint (module docstring, :4-18). The five-commitment conversation itself works (seed-creation-conversation → 201, turns_recorded: 11); it is the commit that cannot be reached.

Fixed would mean: a creation conversation can be committed into an engagement.


W-3 — Contributing a Markdown file 422s and loses the contribution

Stage 1.3 · Lane A and Lane B · BROKEN

GET /engagements/{id}/contributions/supported-types advertises:


{"pattern":"text/markdown","label":"Discovery document (Markdown)","mode":"discovery"}

POST /engagements/{id}/contributions with that file's file_id returns 422:


1 validation error for AssertionResponse
source_mode  Input should be 'text', 'voice', 'pdf' or 'image'
             [type=literal_error, input_value='discovery']

The skill sets source_mode="discovery" (skills/discovery_to_seed.py:159; registered mode="discovery" at skills/registry.py:205), and the response models forbid it: api/schemas.py:2524 and :2806 both declare Literal["text","voice","pdf","image"].

The contribution is lost, not merely unserializable — the assertion total stayed at 5 before and after.

Fixed would mean: a Markdown file offered by supported-types can be contributed without the contribution being discarded.


W-4 — Retract exists on the substrate and nowhere in the Operator's reach

Stage 1.4d · Lane B · BROKEN

POST /assertions/{id}/retract works (200, state: retracted, rationale recorded). In the Operator Layer there is no retract action at all: lib/api/assertions.ts exports commitAssertion, discardAssertion, redirectAssertion, storeVoiceRecording, addVoiceAssertion — no retract. retracted appears only as a state in lib/api/memory.ts:26-27, never as something the Operator can do. The Companion intent vocabulary has discard_held and change_assertion but no retract intent.

Retracting a committed assertion — withdrawing something from the durable record — is reachable only by direct API call.

Fixed would mean: an Operator can retract a committed assertion without leaving the Companion and the Operator Layer.


W-5 — Recall returns the superseded value and the wrong lifecycle state

Stage 1.5 · Lane B · BROKEN

Asked "How many of the eleven branches have instant-issue card capability?", the Companion (classified_intent: ask_about_past_input) replied:

> "Based on what you've told me, three of the eleven branches have instant-issue card capability — though that note is still waiting for your okay, not saved yet."

Truth at that moment, from GET /assertions/{id}: version: 4, state: committed, committed_at: 2026-07-29T14:56:54Z, content "…exists at four of the eleven branches (corrected from three…)". The answer is wrong on the value and on the state, and it is confidently phrased.

This is at a scale of six assertions. The brief directs that the known §18.2 wholesale-recall limit (v0.73: _PAST_INPUT_LIMIT = 50, no search index has ever existed) is cited context, not a finding to re-derive — and that what is being audited is whether the ask-path works at this scale. At this scale it does not: the failure here is not truncation but reading a superseded version and misreporting lifecycle. It is a distinct failure from the §18.2 limit and is not covered by the standing "no live recall demonstration in front of a prospect" conduct rule, which was written about the early-input case.

Fixed would mean: asking about a corrected, committed contribution returns the current committed text and the correct lifecycle state.


W-6 — The two contribution paths attribute differently

Stage 1.1 vs 1.2 · Lane A · LEAVES-COMPANION (provenance consequence)

Same person, same engagement, same minute:

| Path | contributed_by | |---|---| | Companion converse (1.1) | {"kind":"companion","id":"910c64ec…","display_name":"Companion"} | | Contribution surface (1.2) | {"kind":"person","id":"910c64ec…","display_name":"Walk Audit Operator"} |

The person id is identical; the kind and the human-readable name are not. A provenance walk that terminates in display_name (which is what a reader sees) lands on "Companion" for anything contributed by talking, and on the person's name for anything typed into the surface. The distinction is invisible to the Operator at contribution time.

Fixed would mean: the contributor a provenance walk reports does not depend on which path the same person used.


W-7 — PDF ingestion stores the document as one verbatim assertion

Stage 1.3b · Lane A and Lane B · LEAVES-COMPANION

Contributing a 15-line PDF produced one assertion whose content is the entire extracted text, newlines and all, with source_mode: "pdf". No decomposition into discrete assertions occurred. The brief asks to verify "extraction produced assertions (not just a stored file)" — what exists is closer to a stored file with the text lifted into a single record.

Tied, as the brief directs, to the already-recorded ingestion gap rather than re-derived: v0.73 §, "V2/V3 sharpened the ingestion gap (two upload pathways with inconsistent rules; spreadsheet/presentation absent with no extraction skill — the cap table, the model, the deck)". This walk adds that the pathway which is present also does not decompose.

Of the walk's own document types: the authored specification (text/markdown) is accepted by door 3's extract path but refused by the contribution path (W-3). A .docx, .csv or .xlsx version of the same brief would be refused outright — supported-types lists only application/pdf, text/markdown, audio/, image/.

Fixed would mean: contributing a document yields assertions a reader can commit, supersede and cite individually.


W-8 — A correction's trajectory is not walkable from any surface

Stage 1.4b · Lane B · LEAVES-COMPANION

The substrate preserves corrections properly: /history returns v1, v2, v3 with was_revision_of_version set, and /at-version/{v} returns any prior text. The brief asks specifically that "the superseded assertion remains and the trajectory is walkable from the surface, not only in the database."

It is not. at-version appears nowhere in the Operator Layer source. There is no history view, no version list, no "what did this say before" affordance. The superseded text is retained and unreachable except by API.

Fixed would mean: an Operator can see what an assertion said before it was corrected, from the surface.


W-9 — The Manifestation and Shaping rooms are placeholders

Stages 2 and 3 · Lane B · BROKEN

app/operator/engagement/[engagement_address]/RoomView.tsx dispatches four rooms. Two are live and two are not:


case "memory":    <MemoryRoom …/>          // live engine data
case "rendering": <RenderingRoom …/>       // live engine data
case "compose":   <EmptyRoom message={SURFACE.composeEmpty} …/>
case "shape":     <EmptyRoom message={SURFACE.shapeEmpty} …/>

(RoomView.tsx:43-66.) The file's own header states it: "Memory and Rendering are live engine data; the two rooms with no surface path yet show…". The copy is aspirational — strings.ts:1085-1086: "No shapes waiting on you yet. / Shapes appear here once there's settled memory to shape." — but there is settled memory on the control engagement, a derived Manifestation and two confirmed shapes, and the room still shows the empty state, because it is hardcoded.

Combined with the absent Companion intents (W-10, W-11), Stages 2 and 3 have no Operator-reachable surface of any kind.

Fixed would mean: the Manifestation and the shapes produced from it are visible and actionable in the Operator Layer.


W-10 — The Companion refuses to shape, and the remedy it offers does not work

Stage 3 · Lane B · BROKEN

Asked to produce a shape, the Companion classified request_draft and refused:

> "I don't have the authority to produce that draft on my own — no delegation has been granted… you can say something like 'you can draft specifications'… to give me standing authority."

Saying exactly that back to it was classified remember_about_me and stored as a personal-memory note:

> "Got it — 'Can draft board briefs for this engagement.', held."

side_effects: []. No delegation was granted. On retry the Companion still could not produce, and added a second problem:

> "I want to flag some vocabulary — 'shape' and 'Manifestation' are terms I don't use."

So the Companion refuses the action, suggests a phrasing that its own classifier routes to the wrong intent, and does not share the vocabulary of the pipeline stage the Operator is trying to reach.

Fixed would mean: the delegation the Companion asks for can be granted the way the Companion says to grant it.


W-11 — No render can be produced from Lane B

Stage 4.1 · Lane B · BROKEN

RenderingRoom.tsx fetches and lists renders (fetchRendersPage); it has no production action. The Companion intent enum has request_draft, approve_draft, request_revision, request_download — and nothing that produces a render. Producing the Mode A render required POST /renders/ad-hoc directly.

Fixed would mean: an Operator can cause a render to be produced without an API call.


W-12 — The render-download path is not wired into the Operator Layer

Stage 4.2 · Lane B · LEAVES-COMPANION

The engine's download route is correct and complete: GET /renders/{id}/download → 200, 11 325 bytes, content-disposition: attachment; filename="meridian-onboarding-board-brief-walk-audit.html", content-type: text/html. The file is the real render.

The Operator Layer does not call it. RenderingRoom.tsx:26-30 builds a client-side Blob from output.html and opens it in a new tab, and its header records the scope decision: "The action appears ONLY for outputs that are actually viewable right now (inline HTML documents) — no dead 'Download' button on outputs the surface can't yet open." So an HTML render can be viewed, nothing can be downloaded, and a PDF render offers no action at all.

Fixed would mean: a produced render can be downloaded from the surface, in the formats the engine can already emit.


W-13 — The Companion answers a download request with raw UUIDs

Stage 4.2 · Lane B · LEAVES-COMPANION

Asked "Can I download the finished Board brief for Meridian?" (classified_intent: request_download, request_action: None):

> "No artifact with a title matching 'Board brief' turned up in the search. There are two HTML documents saved to the project: > 1. 1bad53b2-ea8d-44c7-abc0-04f7e186493f > 2. 454edb9c-5e24-4d40-bef7-8c90d7d8f32d > Do either of those IDs mean anything to you…?"

The title was there to be found: the render record carries source_shape_title: "Meridian onboarding — Board brief (walk audit)". The Companion's search did not match it, returned no download affordance, and handed the Operator two UUIDs and a question. This is the brief's failure condition stated literally — the Operator stops being an Operator and becomes a mechanic.

Contributing cause: the shape-event's own title field is null. It was set at production ("Meridian onboarding — Board brief (walk audit)") and came back null after confirmation, while the render preserved it in source_shape_title. Titles are lost at the confirm step.

Fixed would mean: asking the Companion for a finished document by its name returns that document.


W-14 — Nothing marks a downstream artifact stale after Memory changes

Stage 4.3 · Lane A · LEAVES-COMPANION

memory-status does its job well after a committed revision: memory_has_changed: true, changes_since_derivation: {assertions_committed: 1, assertions_revised: 1, relationships_added: 3, total: 5}, manifestation_engagement_version: 9 vs current_engagement_version: 23.

downstream-impact lists the chain — Manifestation → Shaping → confirmed Shape → Render — and marks nothing stale (no key containing "stale"; summary reads "1 active Shaping ran against this Manifestation, producing 1 confirmed Shape and 1 Render"). The render on disk is now out of date and no surface says so. Re-rendering is a full manual re-run of derive → shape → confirm → render; there is no incremental path.

Fixed would mean: when Memory changes, the artifacts downstream of it are identifiable as out of date.


W-15 — No surface shows the walk as a coherent history

Stage 5.1 · Lane A and Lane B · LEAVES-COMPANION

After a complete seed→render walk, activity-summary reads {"shaping":{"running":0,"pending_confirmation":0},"rendering":{"running":0,"pending_action":0},"memory":{"pending_commit":0}} — it is a what-is-in-flight-now counter, structurally incapable of showing history. room-summary gives totals. /me/dashboard/recent is the only history-shaped surface and it has two defects: download_url: null on every item, and both distinct renders labelled identically #1 — html_document.

Fixed would mean: an Operator can see what happened in this engagement, in order, from one place.


W-16 — The Manifestation hop of a provenance walk cannot be version-pinned

Stage 5.3 · Lane A · LEAVES-COMPANION

Every other hop pins its version. The shape event records manifestation_object_id and manifestation_version: 1, but GET /engagements/{id}/manifestations/{manifestation_id} returns the current row — during the walk it returned version: 2, state: superseded, not the v1 the shape was built from. There is no at-version route for manifestations (routes are: manifestations, /derive, /preview, /{manifestation_id} — verified against the live OpenAPI document).

Assertions have /at-version/{version} and it works correctly; manifestations do not.

Fixed would mean: the Manifestation a shape was built from can be retrieved as it was at that version.


4. The continuity number and the provenance verdict

4.1 Companion continuity (Stage 5.2)

Definition used: a departure is a step in Stages 1–4 that cannot be completed from within the Companion conversation. This is the strict reading the brief's phrase "how many times the walk left the Companion" calls for; departures into another Operator-Layer surface and departures into a raw mechanism are marked separately, because the two are different sizes of problem.

| Stage step | Departure? | Where it goes | |---|---|---| | 1.1 Text contribution | — | Companion. | | 1.2 Structured contribution | 1 | OL Memory room. | | 1.3 File contribution | 2 | OL Memory room (Markdown path broken outright). | | 1.4a Commit | — | Companion (commit_assertion). | | 1.4b Supersede | — | Companion (change_assertion). | | 1.4b′ See the correction's trajectory | 3 | Raw mechanism — API only (W-8). | | 1.4c Redirect | — | Companion (request_redirect). | | 1.4d Retract | 4 | Raw mechanism — no surface, no intent (W-4). | | 1.5 Ask about a contribution | — | Companion (answers wrongly — W-5 — but does not force a departure). | | 2 Manifestation | 5 | Raw mechanism — placeholder room, no intent (W-1, W-9). | | 3 Shaping | 6 | Raw mechanism — placeholder room, delegation ungrantable (W-9, W-10). | | 4.1 Render production | 7 | Raw mechanism — no trigger anywhere (W-11). | | 4.2 Download | 8 | Raw mechanism/download unwired; Companion returns UUIDs (W-12, W-13). |

Companion continuity number: 8

Of which 6 are departures to a raw mechanism — curl or direct API — and 2 are Companion→Operator-Layer hops.

The shape of it matters more than the count. Stage 1 is largely continuous: the Companion can take a contribution, commit it, correct it and redirect it, and four of Stage 1's eight steps need no departure at all. Stages 2, 3 and 4 are continuous nowhere. Every step of the second half of the pipeline is a raw-mechanism departure. The thread does not fray evenly; it stops.

4.2 Provenance-walk verdict (Stage 5.3)

Walked backward from one rendered claim — "instant-issue card capability exists at four of the eleven branches" in render 454edb9c — on the control engagement.

| Hop | Result | |---|---| | Render → Shape | confirmed_shape_event_ref: {id: 9b671e59…, version: 2} ✅ | | Shape → Manifestation | manifestation_object_id: fb820ca5…, manifestation_version: 1 ✅ (pinned in the record; not retrievable at that version — W-16) | | Shape → Memory | selected_memory_refs: [5802b88f v1 (seed), 0c04d84f v2, 3a772bc5 v2, bcee7791 v2] ✅ | | Memory → Assertion text as rendered | GET /assertions/bcee7791…/at-version/2 → "…exists at four of the eleven branches" ✅ — faithful, though the assertion is now v3 ("five") | | Assertion → Contributor | {"kind":"person","id":"910c64ec…","display_name":"Walk Audit Operator"} ✅ |

Verdict: possible only via API/database — not reconstructable from surfaces.

The substrate's provenance is genuinely good, and the at-version fidelity is the strongest single result in this audit: the chain returns the text as it was rendered, not as it reads today, which is exactly what a provenance walk is for. Two qualifications: the Manifestation hop cannot be resolved at its pinned version (W-16), and the terminal contributor name depends on which contribution path was used (W-6).

Lane B cannot perform any hop. at-version appears nowhere in the Operator Layer; no surface exposes selected_memory_refs, confirmed_shape_event_ref, or a lineage view of any kind. An Operator asked "where did this sentence come from?" has no way to answer it from the product.


5. Observed but not anticipated by the brief

  1. The audit's target stack was the live perimeter. §1.3. The brief's "dev stack" description did not match anything running, and the database named playground_dev is what app.dunin7.com serves. This is the single most consequential thing found, and it was found before the first write only because the ingress config was read first.
  2. A fresh database cannot be brought up from the documented commands. §1.4 — three out-of-band steps, one of them a second alembic chain in a different repository, one of them a mid-chain application boot.
  3. The dev-auth affordance stops short of the create ceremony. /auth/dev/issue-session issues a session through the production code path but never stamps last_presence_proof_at, and is_presence_fresh fails closed. So the documented affordance for "smoke-test harnesses and dev tooling" cannot carry a scripted walk past POST /instantiate — the one step in the walk it most needs to. Bypassing it required calling record_presence_proof directly. Consider whether the dev affordance should reach the same ceiling it was built to bypass.
  4. attestation_recorded: false survives into the record. The instantiate response marks that no WebAuthn attestation backed the commit. It is a genuinely good property — the dev bypass is legible in the data rather than indistinguishable from a real tap.
  5. Committing memory is not step-up gated. Only engagement instantiate is (api/routers/engagements.py:606, :730). The brief expected a CEILING at Stage 1.4 and there is none. This is consistent with the already-recorded v0.74 V3 finding ("the commit check never compares committer to contributor — a member self-admits") and is noted, not re-derived.
  6. Shape titles are lost at confirmation. W-13's contributing cause: title set at production returns null after confirm, though the render preserves it as source_shape_title.
  7. The Companion's first turn on a new account is a credit wall. §1.4. Environment-conditioned, but it is what a genuinely new operator meets before anything else.
  8. The Companion disclaims the product's own vocabulary. W-10: "'shape' and 'Manifestation' are terms I don't use." The Operator Layer maintains a deliberate vocabulary wall (RoomView.tsx:3-6 refers to "the forbidden room-key literals"), so this is presumably intentional — but the effect is that an Operator who has read the manifest and speaks its language is told the Companion does not speak it.
  9. Extraction quality is high and worth saying so. Door 3's /seed/extract turned the two-page brief into all five commitments with no gaps, correctly separating scope exclusions and measurement caveats into additional_assertions, in 13 seconds. The shaping agent produced a genuinely readable four-finding board brief that expanded abbreviations as the voice commitment required. The parts of this pipeline that work, work well.

6. Disposition


DUNIN7 — Done In Seven LLC — Miami, Florida Loomworks — seed-to-render walk audit — report — v0.1 — 2026-07-29