Version. 0.1
Date. 2026-08-07
Author. Claude Code (Wave 0 session). Operator: Marvin Percival.
Charter. standing-notes/dunin7-standing-authorization-charter-v0_1.
Scope. Wave 0 investigation 0.4 of standing-notes/loomworks-development-schedule-v0_1. Read-only. No code changed.
Read against. Engine loomworks-engine at afdeff5; surface loomworks at baec093. Both clean.
Reads with. investigations/loomworks-upload-pathway-investigation-v0_1 (the architectural commitments); investigations/loomworks-upload-pathway-ground-truth-v0_1 (partly stale — its headline "Rail B never lands in Memory" was closed by CR-2026-130).
The routing question is already answered by the existing convention — Markdown routes correctly today and needs no change. B-40 as literally posed ("where should it route") is a non-issue. But the investigation surfaced a real collision the item did not name: the same .md file means two incompatible things depending on which of two live rails it arrives through. That collision is the decision worth making, and it is the one this note recommends taking to a CR.
Rail B (the live upload pathway). POST /engagements/{id}/uploads detects by filename extension plus magic bytes, never MIME. .md has its own registered rule (uploads/skills/text_extraction.py:109) whose only difference from the .txt rule is a content_type_hint="text/markdown" string. Both route to the identical text_extraction skill, which is a UTF-8 decode and hardcodes output_content_type="text/plain" (:85). The module docstring says so outright (:15). Result: one held assertion, grammar_element="definition", source_mode="text" — indistinguishable in Memory from a typed note.
This is exactly what the convention prescribes. Every other type does the same thing: one file → at most one held assertion, content flattened to text, provenance in metadata, Operator commits. summarization.py:13 records single-assertion-per-file as a deliberate scope decision. So "consistent with existing conventions" means: change nothing about the routing.
A second live rail gives .md an entirely different meaning. src/loomworks/skills/registry.py:201–206 registers:
registry.register("text/markdown", extract_discovery_to_seed_skill,
label="Discovery document (Markdown)", mode="discovery")
POST /contributions resolves its skill by MIME content-type (api/routers/contributions.py:202). So a Markdown file contributed through Rail A runs a single-shot LLM seed extraction, yielding source_mode="discovery", an assertion whose content is a summary rather than the document, and a draft_seed payload in metadata.
The registration's own comment says it "supports content-type-based dispatch through the existing contribution pipeline" — so this is intended to fire, not vestigial. It was registered for Phase 53 Discovery documents specifically.
Two rails, one file type, two incompatible meanings. Rail A treats every Markdown file as a discovery document to extract a seed from; Rail B treats it as text to remember. Which one a contributor gets depends on which endpoint the client happens to call. This is the real B-40 decision, and it is a correctness question, not a filing-convention question.
Recommended resolution: Rail A's blanket text/markdown → discovery registration is too broad. Discovery extraction is a purpose, not a format — which is precisely the "operation-not-format granularity" commitment at §2.5 of the upload-pathway investigation. The canonical Phase 53 path is already the dedicated /seed/extract endpoint (api/routers/seed_extraction.py:155 requires content_type == "text/markdown" explicitly). The general contribution pipeline should route Markdown the way Rail B does. Narrow or remove the Rail A registration; keep /seed/extract as the deliberate discovery door.
(a) A one-line gap between surface and engine. The surface's document-create flow accepts .markdown (DocumentCreateFlow.tsx:258, accept=".md,.markdown,.txt,…"), but the engine registers only .md (text_extraction.py:111 — verified, .markdown appears nowhere). A .markdown file offered by the UI fails detection. One-line fix, independent of every other decision here.
(b) File length silently decides how Markdown is treated. Under 2000 chars (summarization.py:32) the held assertion carries the raw Markdown source verbatim — # headings, bullets, tables, fences — sitting in an assertion body. Over the threshold, the summarizer runs a prompt that says "Write plain prose, no preamble, no markdown formatting" (:41), deliberately destroying the structure. Neither branch is Markdown-aware; which one a contributor gets depends on file size. Worth a deliberate decision even if the answer is "accept it."
(c) The text/markdown hint dies at the skill boundary. It survives to the upload event's content_type_observed but is never copied into the assertion metadata (uploads.py:895–904). The docstring's promised "downstream consumers" do not exist on the assertion side. If Markdown-ness should ever be recoverable from Memory, this is the one-line place to thread it.
Should Markdown's structure be preserved into Memory? Markdown is the only supported format where structure survives extraction for free — the transform is a byte decode. Every other type flattens by necessity (docx headings are detected at docx_extraction.py:94 then dropped at uploads.py:956; PDF loses layout; HTML loses tags). So Markdown is where "one file = one flat assertion" is most visibly lossy: a .md with ten ## sections is ten distinguishable claims arriving as one.
This is not a B-40 decision and should not be smuggled into one. Preserving structure would make Markdown the first type to break the one-file-one-assertion convention, and that is exactly the multi-output granularity question the upload-pathway investigation filed as open at §6.5 on 2026-05-08 and never resolved. Nothing in the engine parses Markdown today (the only markdown library use runs the opposite direction, HTML→PDF for the Manifestation room), so this would be net-new machinery. Recommend it stay parked as its own question, and that B-40's CR explicitly say it is not answering it.
One small CR, no multi-option decision needed:
text/markdown → discovery registration (§2) — the correctness fix..markdown alongside .md (§3a) — one line.No option table is offered because the existing convention makes items 1–2 obvious. Manufacturing alternatives here would be false balance.
DUNIN7 — Done In Seven LLC — Miami, Florida Loomworks — B-40 scoping note — v0.1 — 2026-08-07