Version. 0.2 (v0.1 added the upload→held-assertion wire; v0.2 adds the source-file view at the confirm step — see Part below) Date. 2026-07-01 Status. Drafted, not executed. Completes Room 1 (Memory) intake. Base: main @ 2abcfd1 (post-CR-2026-129). Number 130 confirmed free (staged d1fecfb). Grounded on: seed v0_12 (§Memory line 43 — intake commitment, incl. lineage to source file), manifest v0_72, upload-pathway ground-truth v0_1 (loomworks-record 7138184).
You can upload files and images today — they store, and images are even interpreted by the vision skill. But the interpretation gets dropped: it never becomes a Memory assertion, so you can't confirm it, recall it, or reason over it. An uploaded photo of Fenwick's leaf produces a description that goes nowhere.
This CR wires the last connection: an uploaded image's description (and a document's extracted content) becomes a held assertion you confirm — flowing through the same capture→confirm→commit grammar as a spoken note. Upload a photo → the machine describes it → proposes it as a held note ("I see a Monstera with a new fenestrated leaf — save this?") → your confirm commits it to Memory. The file is stored AND its content becomes recallable memory.
This completes Room 1's intake: Memory can now take in what you hand it, not only what you speak.
Seed §Memory line 43: a contribution carries how it arrived — "typed, spoken, extracted from a document, described from an image." The seed already names described-from-image and extracted-from-document as first-class contribution kinds with automatic lineage. Line 45: "A correction is a contribution. A retraction is a contribution. Both are preserved" — the append-only assertion model.
So this CR does NOT introduce a new commitment — it closes the gap between the seed's standing commitment (intake includes described-from-image / extracted-from-document, as contributions) and the current Rail-B code (which interprets but drops the result at event grain). We make the code honor what the seed already says. No seed conflict; the seed mandates the target.
The mechanism (how extraction/description becomes a held assertion, the routing, storage) is specification-level, governed by the comprehensive specification — this CR builds the mechanism for the seed's commitment.
Wire Rail B's interpretation output → held assertion. Today uploads.py:661 hardcodes assertions_drafted=[], and no consumer converts the interpretation into an assertion — the description lives only as an object-store blob + an upload_event_received row, unreachable by recall (recall reads committed assertions only).
The fix: when an upload is interpreted (vision describes an image, extraction summarizes a document), call add_assertion with the interpretation as content, producing a held assertion with provenance recording the "how" (described-from-image / extracted-from-document, per seed §Memory line 43) and lineage to the source file. It enters the capture→confirm→commit loop: proposed as held, the Operator confirms (machine describes → proposes → human approves — Operator-authority). Mirror Rail A (image_description.py / contributions.py:280) as the reference implementation.
Why: the confirm gate is "machine describes → Operator approves." The Operator cannot honestly approve a description of a file they cannot see. If an uploaded image produces "I see a Monstera with a new fenestrated leaf — save this?", the Operator must be able to look at the actual image to confirm the interpretation is right. Same for a document — confirming an extracted summary requires being able to open the source. Confirming blind is not confirming.
What: every uploaded file gets a view option at the point of confirmation (and on the held card in the Memory panel). The held assertion already carries lineage to its source file (per seed §Memory line 43 — the provenance connection exists); this surfaces that link in the UI.
Scope note: this adds a frontend dimension the v0.1 CR did not have — the held card / Memory panel needs a control to open the stored file from its object-store blob. Requires an engine route to serve/stream the stored blob for viewing (authenticated, scoped to the engagement) plus the frontend view/preview control. Bounded, but real added surface beyond the v0.1 engine wire.
system_config.loomworks_llm_key / engagement key), not an env var. Confirm it's populated so vision can run in dev; if absent, the failure must surface truthfully (transformation_failed with a clear message), NOT silently produce no description. (Truthfulness — same discipline as Finding 3.)An uploaded image or file becomes a held assertion (machine describes → proposes → Operator confirms) that is recallable Memory, with provenance recording it as described-from-image / extracted-from-document. The file is also stored, and the Operator can VIEW the source file at the confirm step (preview in place where the type supports it, download link otherwise) — so the confirmation is eyes-on-the-source, not blind. Failures surface truthfully. Verified at runtime by uploading a real image, viewing it, confirming it enters the held tray, commits on confirm, and recalls. Suite green.
Room 1's intake works: Memory takes in files, folders, and images (with interpreted descriptions), not only spoken/typed notes. Combined with the four conformance findings (120/127/128/129), the Memory room does its full job — accumulate with provenance, from every intake path — and is genuinely done.
Then the queue (unchanged): semantic-meaning foundation (recall + correction-recognition + routing substrate), content-to-engagement routing consistency, held-tray robustness edges (incl. dismiss-verb/number-resolution, over-eager-capture), wide-net reduction, boundaries arc.