DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path phases/phase-59-upload-pathway-completion/phase-59-cr-upload-pathway-completion-v0_4.md

Phase 59 Change Request — Upload Pathway v1 completion

CR identifier. CR-2026-XXX (next number in sequence; CR drafter confirms against engine repo docs/phase-crs/ listing before archival). Version. 0.4 Date. 2026-05-15 Status. Drafted; awaiting Operator approval. Supersedes v0.3, v0.2, v0.1 (all preserved alongside as superseded). Step 0 inspection brief V0–V11 executed cleanly by CC on 2026-05-15 per v0.3 §4.3 (Step 0a–0e green; halted at Step 0f for Operator confirmation). Three V findings drove this v0.4 amendment cycle: V9 NARRATION-LIVES-IN-OL (Sub-arc 2d reshape per Candidate C); V5 EVENT-EXISTS partial (Sub-arc 1c shrink); V8 ALREADY-HAS-CONFIDENCE heuristic (Sub-arcs 2e/2f reshape). v0.4 absorbs all three explicitly per Operator's Option 2 selection at the v0.4 amendment-scoping cycle. Author. Claude.ai (CR re-drafter, v0.4) on direction from Marvin Percival (DUNIN7 Operator). Companion documents.

Amendment record (v0.2; preserved per Discovery-record discipline). v0.2 absorbed a correction surfaced during CR drafting by Operator review (scoping v0.2 Move 5). v0.1 scoping note compressed two distinct Operator-engagement-at-dispatch surfaces — confidence-disambiguation (engine isn't sure it dispatched correctly) and purpose-disambiguation (multiple legitimate skills fire at high confidence; the choice is the Operator's purpose) — into one (the classifier confidence model at P59-D4). v0.2 of the scoping note separated them: P59-D4 covers confidence-disambiguation only; new P59-D11 covers purpose-disambiguation. v0.2 of this CR carried the separation through: §3 expanded to eleven P59-D rows; §14 sharpened its title and framing to confidence-disambiguation; new §15 (Sub-arc 2f) carried purpose-disambiguation; downstream sections renumbered by +1; §19–§25 absorbed test-count widening, halt-condition additions, acceptance-gate items, carry-forward additions, and methodology-candidate additions. Methodologically: v0.2 was the second-order evidence for v1-multi-pathway-collapses-inquiry-as-protocol — the inquiry, applied at scoping time, produced a compression that Operator review caught.

Amendment record (v0.3; this version). v0.3 absorbs a correction surfaced by CC's pre-flight halt on 2026-05-15 at the first Step 0 execution attempt against v0.2. The halt-surface note (phase-59-halt-surface-2026-05-15-step-0-pre-flight-baseline-drift-v0_1.md) recorded four divergences between v0.2's stated baseline and actual engine repo state: (a) main HEAD at be7fba5 (Phase 56 close) rather than at or near the Phase 58 tag; (b) phase-59-step-0 branch does not exist; (c) phase-59-step-0-findings-v0_1.md does not exist on any branch; (d) test count ~2,400 passed + 30 skipped + 2 pre-existing fails per Phase 58 implementation notes v0.2 §13, not ~2,146 passed + 26 skipped as v0.2 stated. Two confirmed: tag phase-58-upload-pathway at engine 15300fa; Alembic head 0064. Root cause: the v0.1 drafting handoff §2 stated "phase-59-step-0 branch exists" and provided pre-Phase-58 test counts without CC having actually run pre-flight; the assertion propagated through v0.1 scoping → v0.1 CR → v0.2 re-draft unchallenged. v0.3 absorbs the correction along three lines: (i) §4 substantially restructures to land Step 0 inspection brief execution inline at CC pre-flight rather than consuming a pre-existing findings doc; the phase-59-step-0 branch is created by CC at pre-flight, branching from phase-58-upload-pathway tag (not main); CC produces the findings doc as the first pre-flight output; (ii) baseline figures in §§4, 20, 23 update from ~2,146/26 to ~2,400/30+2 to match Phase 58 close state; (iii) §24.2 records two new methodology candidates surfaced by the halt — drafting-handoff-encodes-stated-state-without-verification and main-branch-drift-from-tag-history (the latter also queued at §24.3 as an operational-hygiene candidate beyond Phase 59 scope). Methodologically: v0.3 is third-order evidence for the inquiry-as-protocol's vulnerability — beyond the inquiry catching cross-phase inheritance compressions (Phase 58 four-instance evidence) and beyond catching scoping-time self-compressions (v0.2 Move 5), the inquiry needs a pre-flight-verification check against live-codebase state because drafting-handoff documents can encode imagined state factually. CC's halt-and-surface at pre-flight is the recovery mechanism. The v0.2 CR's framing of "Step 0 already ran" was preservation-principle-correct (v0.1 → v0.2 verbatim) but factually wrong; the re-draft handoff §6 preservation principle protected a stale assertion. v0.3 sharpens the principle: preservation requires the underlying assertions to verify against live state at scoping/drafting time. No P59-D decisions revisited; no architectural changes; §§5–19 carry verbatim from v0.2 (the framing-convention paragraph at §4.6 governs the twelve "Step 0 evidence consumed" subsections without per-subsection rewrites). Path A (in-chat v0.3 re-draft) selected over Paths B/B+/C per Operator decision; reasoning: §4 had a structural mistake (wrong branch source) that needed text-level absorption rather than session-level patch.

Amendment record (v0.4; this version). v0.4 absorbs CC's 2026-05-15 Step 0d V0–V11 inspection findings into the CR. Step 0a–0e executed cleanly per v0.3 §4.3 (CR archived as engine commit 6576085; halt-surface trajectory as 30e4d27; Step 0 findings as 0d442ba); CC halted at Step 0f for Operator confirmation; Operator selected the v0.4 amendment cycle per Path 3 (handoff §6) over Path 1 (in-flight conditional-branch absorption). Three material V-divergences absorb into v0.4 explicitly per Operator's Option 2 selection:

(a) V9 NARRATION-LIVES-IN-OL → Sub-arc 2d reshape (Candidate C per amendment-handoff §2). Engine produces structured ExecutorResult; the Companion's narration is OL-side composition; no engine-side narration template exists at src/loomworks/prompts/ or anywhere CC searched. Sub-arc 2d shrinks from "narration multi-pathway restore via prompt-template addition" to "engine ships accompanying_message field on ExecutorResult / PerFileUploadResponse so Phase 60 OL has the data needed to compose multi-pathway narration." P59-D3 amends accordingly. §13 substantively reshapes; §24.1 names the Phase 60 OL consumer explicitly per Candidate C's commitment to explicit Phase 60 naming. Step 2 still runs six components (2d kept at smaller scope, not removed).

(b) V5 EVENT-EXISTS (PARTIAL) → Sub-arc 1c reshape. Phase 58 already shipped UploadEventReceived(MemoryObject) at src/loomworks/uploads/upload_event.py:118 and the _ANCHOR_PRIORITY entry at src/loomworks/memory/events.py:157 ("upload_event_received": "standard"); the persistence call (append_event) is the deferred Wave 7 piece per uploads.py docstring (lines 17–25). Sub-arc 1c shrinks from "build the class + anchor + persistence call" to "wire the persistence call only." §9 substantively reshapes.

(c) V8 ALREADY-HAS-CONFIDENCE (HEURISTIC) → Sub-arcs 2e/2f reshape. Phase 58 already shipped a heuristic purpose-classifier (classify_purpose_for_chains at src/loomworks/uploads/executor.py:149; PurposeClassificationResult model at src/loomworks/uploads/upload_event.py:105 with confidence: float | None field; needs_clarification status with candidates: list[str] response shape). Sub-arc 2e extends the heuristic with classifier-backed confidence (P59-D4 reframes from "build threshold-driven re-dispatch" to "extend existing heuristic with classifier-backed confidence + AskOperatorToClarify shape extension on existing needs_clarification routing"). Sub-arc 2f extends the candidates: list[str] shape to AskOperatorForProcess with per-candidate purpose-framing strings (P59-D11 holds verbatim; the shape-extension is the work). §14 and §15 substantively reshape.

V0/V1/V2/V3/V4/V6/V7/V10/V11 verdicts came in clean. V0 HOLDS-WITH-DRIFT (drift = main-stale + 6 phase-* branches; both already-queued at v0.3 §24.3 and Step 5 close cleanup). V2 SCENARIO A VARIANT (two-registry split: Phase 16 image_description.py registered against image/ in ExtractionSkillRegistry at src/loomworks/skills/registry.py:191; Phase 58 image_vision_analysis.py + image_ocr.py registered into loomworks.uploads.detection_registry; settles P59-D6 with documentation noting the two-rail split). V1 NEW PROTOCOL TWO-RAIL SPLIT absorbs routinely under v0.3 §12.5 conditional fit — Sub-arcs 2a/2b/2c read against src/loomworks/uploads/skills/ family naming-only divergence absorbs in-flight; no §12 reshape required (Operator did not select Option 3 for v0.4; the __init__.py docstring at src/loomworks/uploads/skills/__init__.py:23–28 already documents the deliberate two-rail coexistence). V3/V4/V6/V7/V10/V11 HOLDS as expected modulo naming-only path correction (uploads.py is the Phase 58 endpoint; v0.3's references to files.py carry a Phase 16/53 framing absorbed in-flight per v0.3 §22.6's naming-only-absorbs language).

Test count and methodology updates. §20 estimate adjusts for all three reshapes (~24–39, was ~26–41 in v0.3; net delta is small because 1c shrinks ~2 tests, 2d shrinks ~2 tests, 2e/2f shape-extensions stay within their original ranges). §24.1 adds the Phase 60 carry-forward entry for V9 absorption (Candidate C's explicit naming commitment). §24.2 adds new methodology candidate (§4.6-framing-convention-tiering-needs-explicit-marker) for v0.21 — the §4.6 framing convention's first test under actual Step 0 execution surfaced that conditional branches don't tier between routine-absorption and halt-for-scoping. §25 records v0.3 → v0.4 cycle as the second amendment cycle within Phase 59 (v0.1 → v0.2 was the first; both fit within the four reserved slots P59-D9 allocates).

Methodologically: v0.4 is the first test of v0.3 §4.6's framing convention against actual Step 0 execution. The convention worked — three V divergences and three conditional-branch absorptions (or halts-then-amendment); no surprises about how the framing handles divergence. The convention's blind spot (no explicit tiering between routine and halt-worthy conditional branches) carries to v0.21 as a sharpening candidate. One P59-D revisitation: P59-D3 amends per V9 Candidate C absorption; D1, D2, D4, D5, D6, D7, D8, D9, D10, D11 hold verbatim. Path A (in-chat v0.4 amendment by fresh Claude.ai chat) selected over a separate scoping note per the combined-cadence reasoning in amendment-handoff §6.

This is the second amendment cycle within Phase 59 (v0.1 → v0.2 was the first; v0.3 → v0.4 is the second). The first cycle absorbed scoping-time compression (Move 5); the second absorbs Step 0 inspection findings (3 V divergences). Both fit within the four reserved slots P59-D9 allocates; reserved-slot count remains at 4.


Plain-language summary

Phase 59 finishes the v1 upload pathway that Phase 58 started. Engine work only — Phase 60 will carry the OL surfaces that consume Phase 59's contracts. The work spans four engine segments: (1) Wave 7 wiring — credential-store consolidation, ObjectStore put_blob end-to-end, UploadEventReceived persistence, rate-limit middleware, streaming-upload optimization. (2) Per-skill key resolution + accompanying-message threading + classifier confidence + multi-valid-prompt-for-process detection. (3) OCR threshold + class-aware refinement + content-reliability warning surface. (4) Engine half of the manual-content fallback affordance Phase 58 deferred.

This is v0.4 of CR-2026-092 — the second amendment cycle within Phase 59. v0.1 → v0.2 absorbed a scoping-time compression (Move 5: confidence-disambiguation and purpose-disambiguation collapsed into one surface; v0.2 separated as P59-D4 + P59-D11). v0.2 → v0.3 absorbed CC's 2026-05-15 pre-flight halt (main was two phases stale from the tag; Step 0 branch + findings doc didn't exist; test counts were rebased). v0.3 → v0.4 absorbs CC's 2026-05-15 Step 0 execution findings: three of twelve V verifications surfaced material divergences from what scoping anticipated.

The three v0.4 absorptions:

The other nine V findings absorbed routinely. V0 baseline confirms; V2 settles P59-D6 (two-registry split); V1 surfaces the two-rail-split structural pattern but Sub-arcs 2a/2b/2c read against the right family without §12 reshape; V3/V4/V6/V7/V10/V11 all HOLDS as scoping anticipated.

Phase 59 still ships the same five build steps + four reserved buffer slots + four halt points (Step 0f for findings confirmation; Checkpoints A/B/C for the build segments). Test envelope adjusts slightly downward (~24–39 new tests, was ~26–41 in v0.3). All eleven P59-D items hold (P59-D3 amends per Candidate C; ten others unchanged). Tag at completion: phase-59-upload-pathway-completion on engine repo only at Checkpoint C (final).

What v0.4 does NOT change: architectural shape; sub-arc count (still 12 components: 1a–1e + 2a–2f + 3a–3c + 4a — Step 2 still six because Candidate C keeps 2d at smaller scope); reserved-slot count (4); engine-only scope; no OL changes; no marketing changes; expected Alembic head 0064; no new dependencies; no P59-D revisitation beyond D3.

On resume: CC paused at Step 0f reviews v0.4; archives v0.4 to engine repo docs/phase-crs/phase-59-cr-upload-pathway-completion-v0_4.md (preserves v0.1, v0.2, v0.3 alongside as superseded); resumes Step 0f → Operator confirms Step 0 findings + v0.4 absorption → Step 0g (build branch creation from phase-59-step-0 HEAD 0d442ba) → Step 1+ proceeds per the v0.4-reshaped sub-arc decomposition.


1. Purpose

Phase 59 finishes the v1 upload pathway Phase 58 started. Three sub-arcs span four segments of engine-side work plus a fifth segment that moves to Phase 60 per the Stage 4 envelope split that the Phase 59 scoping conversation produced.

The phase's two outputs:

Substrate output. Wave 7 wiring complete: credential-store consolidation; ObjectStore put_blob end-to-end; UploadEventReceived persistence; rate-limit middleware on the upload endpoint; streaming-upload optimization. The v1-image-and-audio capabilities reach first-quality through the new pathway: API-key resolution for new-pathway audio/vision/OCR; narration shaping that consumes both extraction result and accompanying Operator message; classifier confidence model with threshold-driven re-dispatch (confidence-disambiguation); multi-valid-prompt-for-process detection (purpose-disambiguation); OCR threshold model refinement; OCR class-aware parameter refinement; content-reliability warning surface. Plus the engine half of the v1-unsupported-format pathway: the CR §7.4 fallback affordance endpoint Phase 58 deferred.

Methodology output. Phase 59 is the first phase running the v1-multi-pathway-collapses-to-single-pathway inquiry as a named protocol. Phase 58 surfaced the pattern with four-instance evidence within one phase (per phase-58-implementation-notes-v0_2.md); Phase 59 codifies the inquiry as a per-item scoping-time discipline. Implementation notes will record where the protocol fit cleanly under build pressure (deliberate verdicts matched build experience) and where it surfaced new shape (drift or anticipated-vs-surprising). This is the second-instance evidence that will inform whether the protocol promotes to a named principle at the what-dunin7-is-building v0.21 consolidation slotted between Phase 59 close and Phase 60 scoping.

Scoping v0.2 added a second-order evidence point worth recording in this Purpose paragraph rather than only in implementation notes. The inquiry-as-protocol, applied at scoping time, produced a compression that Operator review caught (Move 5: v0.1 compressed confidence-disambiguation and purpose-disambiguation into one surface; v0.2 separated them as orthogonal). The protocol's vulnerability to scoping-time self-compression — and Operator review as its recovery mechanism — is itself methodology evidence. The first-application phase has now surfaced two kinds of evidence: how the protocol fits per-item discipline, and how the protocol fails as a self-applied check at scoping time. Both feed v0.21.

The originally-planned thirteen-item single-phase scope that the Phase 59 entry handoff anticipated split at Stage 4 into Phase 59 (engine; segments 1–4) plus Phase 60 (Contribution composer completeness; OL-block). The split was not in the entry handoff's scoping space — it emerged from Stage 4 envelope analysis as the cleanest line through coherent phase identities. Phase 60 inherits Phase 59's engine-side contracts; the OL surface implements the consumption.


2. In-scope and out-of-scope

2.1 In-scope

Engine-side work only. Five sub-arc components map across four segments:

Each component is detailed below at §7 through §19.

2.2 Out-of-scope

The following do not ship in Phase 59:

If CC finds itself implementing any of the above, it has crossed a scope boundary — halt and surface.


3. Construction decisions

All eleven P59-D items closed at scoping v0.2 (ten from v0.1 plus new P59-D11). CC consumes them; does not relitigate.

| Item | Setting | Source | |------|---------|--------| | P59-D1 | Envelope split. Phase 59 = engine (Segments 1–4); Phase 60 = OL composer-completeness + folder filter. | Scoping v0.1 §Stage 4; emerged at Stage 4 envelope analysis | | P59-D2 | Credential-store coexistence. Accept multi-pattern; document the two scopes (system-level via app.state; engagement-level via credential-store). New-pathway transformation skills read from credential-store; Phase 16 voice-mode endpoint continues to read from app.state.openai_api_key. | Scoping v0.1 §Stage 2.1; settled by inheritance-audit drift verdict (accept multi-pattern) | | P59-D3 [AMENDED v0.4 per V9 Candidate C] | Accompanying-message data shape (Phase 59) + multi-pathway narration composition (Phase 60). Phase 59 ships accompanying_message: str \| None field on ExecutorResult / PerFileUploadResponse so OL has the data needed to compose multi-pathway narration. Phase 60 carries the actual narration composition change (engine has no narration template — V9 NARRATION-LIVES-IN-OL — so the multi-pathway restore lands at the OL render layer, not engine prompt layer). The two-pathway intent (Companion narration engages with both artifact and Operator's framing) is preserved; the locus shifts from engine-prompt-template (the v0.1/v0.2/v0.3 framing) to OL-narration-composition (v0.4 framing per V9). The accompanying-message-disambiguation pre-emption logic for Sub-arc 2f stays engine-side because the disambiguation check sits between detection and dispatch (§13.7 carries; only the post-dispatch narration consumption relocates). | Scoping v0.1 §Stage 2.2; drift verdict (restore multi-pathway). v0.4 amendment per V9 NARRATION-LIVES-IN-OL (engine produces structured ExecutorResult; OL renders narration); restore-multi-pathway intent preserved with composition-locus relocation to Phase 60. | | P59-D4 | Classifier confidence model (confidence-disambiguation). Threshold-driven re-dispatch on low confidence (ask Operator to clarify); not multi-skill comparison. Single-skill-commit dispatch is accepted as deliberate. v0.2 clarification: this decision covers the confidence-disambiguation surface only — engine uncertainty about classification accuracy. v0.2 adds P59-D11 for purpose-disambiguation as a distinct, orthogonal surface (multiple legitimate skills at high confidence; the choice is the Operator's purpose, not engine accuracy). | Scoping v0.1 §Stage 2.2 + v0.2 §Stage 2.2 clarification; drift-justified verdict (accept single-skill-commit; add threshold-driven re-dispatch) | | P59-D5 | Content-reliability surface. Three-state extraction result: succeeded / unreliable_succeeded / failed. The third state surfaces a warning alongside the assertion content; Phase 60's OL surface displays it. Assertion content persists in all three success cases (including unreliable); the warning is metadata, not a rejection. | Scoping v0.1 §Stage 2.2; drift verdict (restore three-state surface) | | P59-D6 | Image-skill dispatch precedence. Settled via Step 0 V2 (Scenario A or B per findings); documentation-only resolution. CC consults phase-59-step-0-findings-v0_1.md §V2 for the verdict; implementation captures the precedence (Scenario A: both Phase 16 stub and Phase 58 narrower-key registrations live with longest-match-wins; Scenario B: Phase 58 retired the Phase 16 registration; only new skills live). | Scoping v0.1 §Stage 2.2; documentation-only resolution per inheritance audit | | P59-D7 | UploadEventReceived registry posture. _ANCHOR_PRIORITY entry added per Phase 53 V7 evidence pattern; OBJECT_TYPE_REGISTRY entry deferred per Phase 50/52/53 precedent (typed-MemoryObject-without-migration pattern). No Alembic migration required. | Scoping v0.1 §Stage 2.1; Phase 50/52/53 precedent inherited | | P59-D8 | Rate-limit library. slowapi per Phase 50's resolution. Phase 50 wired slowapi to the public credit-request endpoint; Phase 59 mirrors the pattern on the upload endpoint with an upload-appropriate rate value (per-call cost is higher; per-minute rate is lower). | Scoping v0.1 §Stage 2.1; Phase 50 precedent inherited | | P59-D9 | Reserved-slot count. 4 slots; envelope-breach beyond reservation requires explicit Operator authorization per the Phase 58 v0.5 pattern. Per-segment risk allocation: 1 slot Sub-arc (i) (credential-store coexistence; streaming-upload async-context); 1 slot Sub-arc (ii) wiring (narration multi-pathway restore changes existing-output shape; v0.2: 2f's purpose-disambiguation surface adds an engine-side data shape Phase 60 must consume cleanly; same OL-contract-preservation risk family — single slot covers the 2e/2f cluster per v0.2 §Stage 4.2 reasoning); 1 slot Sub-arc (ii) quality (first-pass tuning surfacing); 1 slot standing reservation. Phase 58's two-slot reservation absorbed two routine cycles before fifth-cycle envelope-breach; Phase 59's count is doubled to anticipate new-protocol-first-application surfacing protocol shape + first-quality tuning surfacing calibration findings. v0.2 confirms slot count unchanged after 2f addition. | Scoping v0.1 §Stage 4.2 + v0.2 §4.2 reasoning | | P59-D10 | Methodology v0.21 slot. Between Phase 59 close and Phase 60 scoping. Composer-completeness ships afterward. The slot allows Phase 59's implementation notes (recording v1-multi-pathway-collapses inquiry's second-instance application evidence) to feed v0.21 before Phase 60 scoping consumes v0.21 as a baseline. | Scoping v0.1 §Stage 4.1 | | P59-D11 [NEW v0.2] | Multi-valid-prompt-for-process (purpose-disambiguation). When detection surfaces multiple registered skills matching at high confidence (i.e., not the P59-D4 low-confidence case; the confidence threshold is exceeded on multiple candidates), the engine emits AskOperatorForProcess shape rather than committing to a single skill. The shape carries per-candidate purpose-framing strings the Companion uses to compose an elicitation prompt. If Sub-arc 2d's accompanying-message input is present AND disambiguates purpose, 2f does not fire — the message answers the question pre-emptively. Phase 59 ships the engine-side data + contract; Phase 60 OL renders the elicitation affordance. Shape name resolved at this re-draft: AskOperatorForProcess — the existing AskOperatorToClarify shape (P59-D4 surface) establishes the "Ask Operator [preposition] [thing]" family in the codebase; AskOperatorForProcess extends that family while preserving the Operator's "prompt for process" phrasing. Considered and rejected: AskOperatorToChooseProcess (more grammatically parallel to ToClarify but loses the Operator's preposition); AskOperatorForPurpose (uses methodology vocabulary rather than Operator vocabulary — fails plain-terms-discipline since the shape name surfaces into engine-side data Phase 60 consumes). CRV-7 at execution time may surface a deeper codebase-naming-family divergence; per re-draft handoff §7 that's naming-only and absorbs in-flight unless architectural. | Scoping v0.2 §Open construction decisions; surfaced post-v0.1 by Operator review (Move 5); naming resolved at this re-draft |

All decisions traceable to scoping v0.2 (with the ten v0.1 items unchanged); no decision in this CR overrides or revises a P59-D item. If a v0.2 decision feels wrong during build, CC halts per scoping v0.2 §Halt conditions / handoff §11 — the chat doesn't override; it surfaces.


4. Pre-flight Step 0

4.1 What v0.3 restructures

v0.2's §4 framed Step 0 as already-run: "Step 0 already ran. CC produced phase-59-step-0-findings-v0_1.md on the phase-59-step-0 branch from main at engine repo docs/phase-impl-notes/." CC's pre-flight halt on 2026-05-15 surfaced this was factually wrong — the branch and findings doc don't exist; the assertion came from the v0.1 drafting handoff §2 and propagated unchallenged through v0.1 scoping, v0.1 CR, and v0.2 re-draft. v0.3 absorbs the correction: Step 0 inspection brief verifications V0–V11 execute inline at CC pre-flight rather than against a pre-existing findings doc. The inspection brief (loomworks-phase-59-step-0-inspection-brief-v0_1.md) is the authoritative source for what V0–V11 verify; §4.6 below describes how the "Step 0 evidence consumed" subsections in §§7–19 read against verifications that haven't yet run.

This is a process correction, not an architectural one. The V0–V11 verifications themselves are unchanged. What changes is when and by whom they execute.

4.2 Substrate baseline (corrected)

CC's pre-flight halt provided the actual baseline. v0.3 records:

Engine repo (DUNIN7/loomworks-engine):

Operator Layer repo (DUNIN7/loomworks):

Marketing repo (DUNIN7/loomworks-marketing):

4.3 Step 0 execution cadence

v0.3 introduces sub-step structure within Step 0 to absorb the inline brief execution. The sub-steps land in §21.1 Step 0 expanded structure; recorded here for §4 self-sufficiency.

Step 0a — CR archival. CC archives this CR to engine repo docs/phase-crs/phase-59-cr-upload-pathway-completion-v0_3.md (preserves v0.1 and v0.2 alongside as superseded per re-draft handoff §6 + v0.3 amendment-record discipline). CR registry: confirm CR-2026-XXX (this CR's number) is the next available against docs/phase-crs/ directory listing. v0.3 note: if v0.1 or v0.2 archival claimed a number, v0.3 reuses that number (versioned filename, not re-numbered CR).

Step 0b — Substrate baseline verification. CC runs the baseline checks per §4.2 against actuals at pre-flight time: tag resolves; test count within ±5 of the corrected ~2,400 (slightly wider than v0.2's ±2 because the figure itself is rebased and minor drift since 2026-05-15 is plausible); Alembic head 0064; working tree clean. Any divergence beyond tolerance halts before further work — phase-59-halt-surface-{timestamp}-v0_1.md filed.

Step 0c — phase-59-step-0 branch creation. CC creates phase-59-step-0 branch from phase-58-upload-pathway tag (i.e., from commit 15300fa). Not from main. This is the source-baseline correction v0.3 absorbs.

Step 0d — Inspection brief V0–V11 execution. CC reads loomworks-phase-59-step-0-inspection-brief-v0_1.md from project knowledge or wherever the brief is supplied at session open. CC runs each of V0 through V11 against the live engine repo at the phase-59-step-0 branch HEAD. Each verification produces a verdict per the brief's framing (HOLDS / DRIFT / BREAKS or analogous). Naming-only divergences absorb in-flight; architectural divergences halt.

Step 0e — Findings document filing. CC files phase-59-step-0-findings-v0_1.md at engine repo docs/phase-impl-notes/ on the phase-59-step-0 branch. The document records each V0–V11 verdict, evidence cited (file:line references; exact strings; signatures verified), and any divergence absorbed in-flight or surfaced as halt. Commit on the phase-59-step-0 branch.

Step 0f — Operator confirmation halt. CC halts after filing findings. Operator reviews phase-59-step-0-findings-v0_1.md and confirms the verdicts before CC proceeds to Step 0g. This is an additional halt point v0.3 introduces — v0.2 had Checkpoint A after Step 1; v0.3 adds a Step 0 confirmation halt because pre-flight is now substantive (not just baseline verification). Operator may approve the findings as-is, may request CC re-verify a specific V, or may halt the build for amendment scoping if findings reveal an architectural divergence v0.2 didn't anticipate.

Step 0g — Build branch creation. On Operator confirmation, CC creates phase-59-upload-pathway-completion branch from the phase-59-step-0 branch HEAD (so the build branch inherits the findings doc commit). All Step 1+ work commits on the build branch.

4.4 V0–V11 inline reference — which verification gates which sub-arc

The inspection brief is authoritative for V0–V11 content; this table maps each V to its CR consumer section so CC knows what each finding gates.

| V | What it verifies (per inspection brief) | Gates CR section | If divergence | |---|----------------------------------------|------------------|---------------| | V0 | Phase 58 close baseline + Step 0 branch lifecycle accounting | §4.2 baseline | §22 halt if test count, Alembic, tag diverge beyond tolerance | | V1 | Transformation skills enumeration | §12 (Sub-arcs 2a/2b/2c) | §12 conditional branches; halt if skill set differs from expectation | | V2 | Image-skill dispatch precedence | §3 P59-D6 settlement | Scenario A or B per findings; documentation-only resolution | | V3 | ObjectStore put_blob method state | §8 (Sub-arc 1b) | §8.4 conditional branches | | V4 | Credential-store abstraction state | §7 (Sub-arc 1a), §12 (Sub-arcs 2a/2b/2c) | §7.2, §12.5 conditional branches | | V5 | UploadEventReceived event class state | §9 (Sub-arc 1c) | §9.6 conditional branches | | V6 | Rate-limit middleware state | §10 (Sub-arc 1d) | §10.3 conditional branches | | V7 | Streaming-upload state | §11 (Sub-arc 1e) | §11.4 conditional branches | | V8 | Detection registry state + classifier confidence model | §14 (Sub-arc 2e), §15 (Sub-arc 2f) | §14.5, §15.6 conditional branches; load-bearing for both 2e AND 2f | | V9 | Companion narration current shape | §13 (Sub-arc 2d) | §13.5 conditional branches | | V10 | Content-reliability surface absence | §18 (Sub-arc 3c) | §18.4 conditional branches | | V11 | CR §7.4 fallback affordance endpoint absence | §19 (Sub-arc 4a) | §19.5 conditional branches |

4.5 CRV verifications stay distinct from Step 0 verifications

CR drafting handoff §9 enumerates eleven CRV verifications (CRV-1 through CRV-11). These are CR-execution-time reads CC runs against the live codebase during build steps (for exact strings, signatures, naming conventions that V0–V11 didn't enumerate). v0.3 does not change CRV mechanics. The distinction:

Both layers coexist. V0–V11 establish state; CRV-N confirm exact-string deltas at the moment of implementation.

4.6 Step 0 evidence subsection convention (v0.3 framing)

Each component section in §§7–19 includes a "Step 0 evidence consumed" subsection (§7.2, §8.4, §9.6, §10.3, §11.4, §12.5, §13.5, §14.5, §15.6, §16.4, §18.4, §19.5). These subsections were drafted at v0.2 with framing like "Per Step 0 V_N findings, [state X holds]" — written as if the verdict had already landed.

v0.3 reframes this convention without rewriting the twelve subsections. Read each subsection's first bullet as describing the expected verdict per the inspection brief, not as a confirmed-already verdict. CC produces the actual verdict at Step 0d–0e pre-flight execution. If the actual verdict matches the expected (HOLDS), the conditional branches' first arm applies and the sub-arc proceeds as drafted. If the actual verdict diverges (e.g., V4 returns ALREADY-WIRED instead of HOLDS), the subsection's conditional branches govern (e.g., §7.2 "If V4 returned ALREADY-WIRED. Sub-arc 1a shrinks to documentation-only"). If the actual verdict surfaces a case the conditional branches don't cover, CC halts per §22.

This convention shift is one-paragraph rather than twelve-subsection because each subsection already enumerates its conditional branches for divergent V verdicts. The subsections' "HOLDS verdict means Sub-arc X proceeds as specified" language reads correctly under v0.3 framing: "if HOLDS lands at pre-flight, Sub-arc X proceeds." The v0.2-era language "Per Step 0 V_N findings, [state X]" reads under v0.3 as "Per the inspection brief V_N (expected verdict at pre-flight), [state X]."

The trajectory record reading v0.3 in six months can reconstruct: v0.2 framing assumed findings doc existed; v0.3 framing acknowledges it doesn't yet exist and CC produces it.

4.7 Halt conditions specific to Step 0

In addition to §22 halt conditions, Step 0a–g introduces these:

4.8 Step 0 executed [NEW v0.4]

CC executed Step 0a–0e per §4.3 on 2026-05-15 against the substrate baseline at engine tag phase-58-upload-pathway (15300fa). Outcomes:

Three V findings drove v0.4 absorption per Operator's Option 2 selection: V9 (Sub-arc 2d reshape per Candidate C); V5 (Sub-arc 1c shrink); V8 (Sub-arcs 2e/2f reshape). Six V findings (V0/V2/V3/V4/V6/V7/V10/V11) HOLDS routinely. V1 absorbs naming-only divergence in-flight without §12 reshape.

On v0.4 approval at Step 0f resume: CC archives v0.4 to engine repo docs/phase-crs/phase-59-cr-upload-pathway-completion-v0_4.md (preserves v0.1, v0.2, v0.3 alongside as superseded); resumes Step 0g (build branch creation from phase-59-step-0 HEAD 0d442ba — so the build branch inherits the CR archive + halt-surface trajectory + Step 0 findings commits); proceeds to Step 1 per the v0.4-reshaped sub-arc decomposition.


5. Substrate scope

Engine repo only. DUNIN7/loomworks-engine at /Users/dunin7/loomworks-engine. All six sub-arc components (1a–1e; 2a–2f; 3a–3c; 4a) land in this repo.

No Operator Layer changes. DUNIN7/loomworks at /Users/dunin7/loomworks remains at the Phase 58 close state through Phase 59's life. Phase 60 carries OL-side work. Phase 59's engine-side contracts are designed to be consumed by Phase 60's OL surfaces but Phase 59 itself ships no OL code.

No marketing repo changes. Untouched in Phase 59.

No new dependencies in pyproject.toml. Step 0 V6 confirms slowapi is already a dependency from Phase 50. No new Python or system dependencies are introduced. (If V6 finding diverges — e.g., slowapi not present — CC halts per §22 below.)

Alembic head expected unchanged at 0064. The typed-MemoryObject-without-migration pattern (Phase 50/52/53 precedent) governs Sub-arc 1c's UploadEventReceived class addition. If the pattern fails to compose (e.g., the event class's storage shape requires a column-level change), CC halts per §22 — scoping v0.3 would absorb and Alembic head would advance from 0064 to 0065.


6. Sub-arc decomposition

Phase 59's engine-side work decomposes into three sub-arcs across four build segments. The decomposition mirrors the scoping note's Stage 2 per-item characterization tables, refined here for build sequencing.

Sub-arc (i) — Wave 7 engine substrate. Components 1a through 1e. Five wiring/persistence items the Phase 58 close handoff identified as deferred Wave 7 work. Lands in Build Step 1.

Sub-arc (ii) wiring half — API-key resolution + narration + confidence + prompt-for-process. Components 2a through 2f. The wiring side of v1-image-and-audio capability reaching first-quality through the new pathway: per-skill API-key resolution; narration shaping; classifier confidence model; multi-valid-prompt-for-process detection [NEW v0.2]. Mechanical wiring on top of Sub-arc (i)'s credential-store consolidation. Lands in Build Step 2.

Sub-arc 2f composes with 2e (both ship engine-side data-shape additions consumed by Phase 60 OL — AskOperatorToClarify and AskOperatorForProcess respectively) and with 2d (2d's accompanying-message input can pre-empt 2f's elicitation when the message disambiguates purpose; see §13 composition paragraph). 2e and 2f are orthogonal surfaces — engine certainty (2e) and Operator purpose (2f) — not alternatives.

Sub-arc (ii) quality half — OCR tuning + reliability surface. Components 3a through 3c. The Operator-judgment-shaped side: OCR threshold model refinement; OCR class-aware parameter refinement; content-reliability warning surface. First-pass tuning where calibration-shape findings are expected to surface. Lands in Build Step 3.

Sub-arc (iii) engine half — Fallback affordance endpoint. Component 4a. The engine half of the v1-unsupported-format pathway: the CR §7.4 fallback affordance endpoint Phase 58 deferred. Lands in Build Step 4.

The two intra-phase Operator checkpoints — Checkpoint A after Build Step 1 (Operator confirms Wave 7 wiring before Sub-arc (ii) wiring half begins) and Checkpoint B after Build Step 3 (Operator confirms quality work before Sub-arc (iii) begins) — separate mechanical wiring from Operator-judgment-shaped work, and quality tuning from the engine-half close. Checkpoint C is the final pre-tag checkpoint at Build Step 5.

Sub-arcs flow strictly in order: (i) → (ii) wiring → (ii) quality → (iii) engine half. The credential-store consolidation in 1a is a prerequisite for 2a/2b/2c (which read from it); the UploadEventReceived event in 1c is independent of subsequent sub-arcs but lands in Sub-arc (i) because it's substrate-shaped persistence work. The narration multi-pathway restore in 2d is independent of the credential-store work but groups with the wiring half because the engine-side classifier confidence model in 2e and the multi-valid-prompt-for-process detection in 2f are the cross-cutting wiring on top of which 3a–3c's quality tuning runs.


7. Credential-store multi-pattern documentation (Sub-arc 1a)

7.1 What 1a delivers

Documentation of the multi-pattern credential resolution shape that emerged from Phase 16 (system-level via app.state.openai_api_key) coexisting with Phase 58's credential-store abstraction (engagement-level resolution). Plus new-pathway transformation skills wired to read from the credential-store.

The framing per scoping v0.1 §Stage 2.1: the two patterns serve genuinely different scopes. Phase 16's voice-mode endpoint operates at the system level — one OpenAI key for the deployment's transcription work. Phase 58's credential-store operates at the engagement level — per-engagement keys keyed by credential type. Both are legitimate; neither retires the other.

The substrate-level work this sub-arc covers. Three things:

  1. Documentation site. A new document at docs/credential-resolution-v0_1.md (or analogous; CC selects placement per Phase 58 docs conventions; CRV-2 will surface the credential-store interface that anchors this) that explicitly records the two scopes and the resolution chain for new-pathway skills. The document is the source-of-truth for future-phase decisions on whether to retire one of the patterns or keep both indefinitely.
  1. New-pathway skill wiring. Sub-arcs 2a/2b/2c (audio/vision/OCR) read from the credential-store. Sub-arc 1a establishes the resolution helper or method on the credential-store interface that 2a/2b/2c will call. Step 0 V4 findings tell CC the credential-store's class location and key-resolution method signature; CRV-2 is the CR-execution-time re-confirmation of the signature.
  1. Phase 16 voice-mode endpoint preserved unchanged. No code change to transcribe_audio_skill or its app.state.openai_api_key reads. The multi-pattern coexistence is the point — Phase 59 does not migrate the Phase 16 surface to the credential-store.

7.2 Step 0 evidence consumed

7.3 CRV-2 confirmation at execution

CC reads the credential-store class definition and key-resolution method signature at execution time, verifying the call-site shape Sub-arc 2a/2b/2c's wiring lands on. Naming-only divergence (e.g., method named get_key instead of resolve) absorbs in-flight; architectural divergence (e.g., method signature requires fundamentally different arguments) halts.

7.4 Acceptance for 1a


8. ObjectStore put_blob end-to-end wiring (Sub-arc 1b)

8.1 What 1b delivers

The put_blob method exists on the ObjectStore class (per Step 0 V3 findings — Phase 58 shipped the abstraction; the method exists but isn't called end-to-end from the production upload endpoint flow). Sub-arc 1b wires put_blob into the upload endpoint's persistence path.

8.2 Substrate-level work

The upload endpoint at src/loomworks/api/routers/files.py (per Phase 53 V6 / Phase 59 Step 0 V7 evidence) currently reads the file body into memory and passes it forward. Sub-arc 1b replaces the in-memory persistence with an ObjectStore put_blob call that writes the file body to the underlying blob storage (MinIO local; S3-compatible production per Phase 58's ObjectStore abstraction).

The call-site shape per CRV-1 (read at execution time): the put_blob method signature determines the call. CC reads it verbatim from the ObjectStore class definition, identifies the bytes-input and metadata-input arguments, and wires the call into the upload endpoint flow at the appropriate point (after content-type detection has identified the artifact; before upload_event_received event persistence per Sub-arc 1c).

8.3 Ordering with streaming-upload (1e)

Sub-arc 1e (streaming-upload optimization) replaces whole-file read with chunked streaming. The streaming pattern must compose with put_blob: the streaming reader feeds chunks to put_blob rather than buffering the whole file in memory then calling put_blob once. The exact composition depends on put_blob's signature — whether it accepts a stream/generator or a bytes buffer. CC reads CRV-1 at execution time and decides:

8.4 Step 0 evidence consumed

8.5 Acceptance for 1b


9. UploadEventReceived persistence-call wiring (Sub-arc 1c) [RESHAPED v0.4 per V5]

9.1 What 1c delivers [v0.4 reshape]

v0.3 framing was: "build a new typed MemoryObject subclass upload_event_received." V5 evidence at Step 0 found Phase 58 already shipped the class + _ANCHOR_PRIORITY entry; only the persistence call (append_event) was deferred to Wave 7 per src/loomworks/api/routers/uploads.py docstring (lines 17–25): "UploadEventReceived MemoryObject append_event persistence (the endpoint returns the executor result + a generated upload_event_id without writing to memory_events)."

v0.4 framing: Sub-arc 1c shrinks to wire the persistence call. CC verifies the existing UploadEventReceived(MemoryObject) class at src/loomworks/uploads/upload_event.py:118 against §9.2's schema spec (any field-level divergence absorbs in-flight per CRV-3; architectural divergence halts per §22). CC verifies the _ANCHOR_PRIORITY entry at src/loomworks/memory/events.py:157 ("upload_event_received": "standard") is intact. CC then adds the append_event call in the upload endpoint at src/loomworks/api/routers/uploads.py after put_blob succeeds (Sub-arc 1b composition) and before response return.

9.2 Schema (verify; do not rebuild)

CC verifies the existing UploadEventReceived class at src/loomworks/uploads/upload_event.py:118 carries fields equivalent to the v0.3 schema spec (preserved here for verification reference):

Phase 58 may have shipped additional fields (e.g., purpose_classification_result: PurposeClassificationResult | None is present per V8 evidence; multi-file aggregation fields like folder_manifest; per-step provenance shape). These fields carry through Phase 59's persistence-call wiring without modification — CC populates them per the Sub-arc 1b/2e/2f composition without altering the schema. Field-level alignment between the existing class and Phase 59's persistence-call population logic verifies at execution time per CRV-3/CRV-4. Naming-only divergence (e.g., uploaded_by vs. actor_ref) absorbs in-flight; architectural divergence (e.g., the existing class's storage shape requires a column-level change to support v0.3's intended fields) halts per §22.

9.3 _ANCHOR_PRIORITY entry (verify; do not rebuild)

CC verifies "upload_event_received": "standard" is intact at src/loomworks/memory/events.py:157. Confirmed present per V5 evidence. CRV-3 reads the surrounding _ANCHOR_PRIORITY dict structure to confirm placement convention (no relocation needed; entry already correctly positioned per Phase 50/52/53 typed-MemoryObject additions).

9.4 OBJECT_TYPE_REGISTRY deferred

Per P59-D7, no OBJECT_TYPE_REGISTRY entry added in Phase 59. V5 evidence confirms no OBJECT_TYPE_REGISTRY exists in src/loomworks/memory/events.py — the typed-MemoryObject pattern doesn't require this registry. The Phase 50/52/53 precedent: registry entries are added when downstream consumers exist; Phase 59 doesn't ship a downstream consumer (Phase 60's OL surfaces will be the first consumer; a future phase adds the registry entry when the consumer integration lands).

9.5 No Alembic migration

The typed-MemoryObject pattern stores discriminated objects in the existing Memory event table's content column (per Phase 50/52/53 implementation). No schema change required. Alembic head stays at 0064. V5 evidence confirms the existing UploadEventReceived class follows this pattern (no migration was added when Phase 58 introduced it).

Halt condition. If the persistence-call wiring surfaces a storage requirement the existing class doesn't accommodate (e.g., the new persistence path requires a discriminated-object representation the content column can't hold), CC halts per §22. The pattern fails to compose; v0.5 absorbs and Alembic head advances.

9.6 Step 0 evidence consumed

9.7 Acceptance for 1c [v0.4 shrink]


10. Rate-limit middleware on upload endpoint (Sub-arc 1d)

10.1 What 1d delivers

slowapi rate-limit decorator on the upload endpoint at src/loomworks/api/routers/files.py. Per P59-D8: slowapi is the library (Step 0 V6 confirms slowapi is in pyproject.toml and integrated on Phase 50's public credit-request endpoint). Per the Phase 50 pattern, CC adds a @limiter.limit(...) decorator on the upload endpoint.

10.2 Rate value selection

CC reads CRV-5 at execution time: the verbatim @limiter.limit(...) decoration on Phase 50's public credit-request endpoint. The upload endpoint's rate value is set lower per-minute than the public credit-request endpoint's rate, because per-call cost on upload is higher (file persistence + skill dispatch + Memory event write). The exact value lands at CR drafting time as a placeholder pending CRV-5 confirmation — likely something on the order of 5–10 uploads per minute per engagement, with a daily ceiling for envelope-protection. CC selects a defensible value during execution; the value documents in implementation notes for future-phase calibration.

10.3 Step 0 evidence consumed

10.4 Acceptance for 1d


11. Streaming-upload optimization (Sub-arc 1e)

11.1 What 1e delivers

The upload endpoint's whole-file read pattern (per Step 0 V7 findings — await file.read() or equivalent that buffers the whole upload in memory) replaced with streaming. The streaming pattern reads the upload body in chunks; each chunk feeds forward to put_blob (Sub-arc 1b composition).

11.2 Chunking and size-limit enforcement

CC reads CRV-6 at execution time: existing streaming patterns in the codebase (other endpoints, ObjectStore implementations) for the chunking convention. The chunk size matches the codebase convention or, if no convention exists, lands at a default like 1 MB chunks (large enough to avoid syscall overhead; small enough to keep memory usage bounded).

The 50 MB size limit from Phase 16 still holds under streaming. Implementation: a running byte counter incremented on each chunk read; when the counter exceeds the limit, the upload aborts with the appropriate error response. The check fires per-chunk, not at completion — the limit cannot be bypassed by sending an oversized upload incrementally.

11.3 Composition with put_blob (1b)

See §8.3 for the 1b/1e composition discussion. The decision lands at execution time based on put_blob's signature (CRV-1).

11.4 Step 0 evidence consumed

11.5 Acceptance for 1e


12. API-key resolution for new-pathway skills (Sub-arcs 2a / 2b / 2c)

12.1 What 2a / 2b / 2c deliver

The three new-pathway transformation skills — audio_transcription, image_vision_analysis, image_ocr — wired to read API keys from the credential-store (Sub-arc 1a establishes the credential-store interface and resolution helper that these sub-arcs consume).

12.2 Sub-arc 2a — audio_transcription

The new-pathway audio skill (introduced at Phase 58 for the upload pathway; distinct from Phase 16's voice-mode transcribe_audio_skill) reads its OpenAI API key from the credential-store. Engagement-level resolution: if the engagement has a configured OpenAI key, use it. Fallback: system-level key via app.state.openai_api_key if no engagement-level key is configured. The fallback is the documented multi-pattern resolution chain per P59-D2.

12.3 Sub-arc 2b — image_vision_analysis

The new-pathway vision skill reads its Anthropic API key (Claude-with-vision is the model family; separate key family from OpenAI) from the credential-store. Engagement-level resolution: if the engagement has a configured Anthropic key, use it. Fallback: system-level if configured. If no system-level Anthropic key exists either, the skill fails with a credential-resolution error that surfaces meaningfully to the Operator (per the only-show-what-is-available principle — the failure must be honest).

12.4 Sub-arc 2c — image_ocr

The new-pathway OCR skill's API-key handling depends on the OCR backend Phase 58 chose. CC reads at execution time:

CC determines the OCR backend by reading the image_ocr skill module at execution time; the existing implementation will reveal whether external service is involved.

12.5 Step 0 evidence consumed

12.6 Acceptance for 2a / 2b / 2c


13. Accompanying-message field on upload response (Sub-arc 2d) [RESHAPED v0.4 per V9 Candidate C]

13.1 What 2d delivers [v0.4 reshape]

v0.3 framing was: "narration multi-pathway restore via engine-side prompt-template addition consuming accompanying message." V9 evidence at Step 0 found no engine-side narration composition function exists — engine produces structured ExecutorResult (status, selected_chain, provenance, content_summary, candidates, purpose_classification_result, error_message); the Companion's narration is OL-side composition of those fields. The src/loomworks/prompts/ directory contains only creation_conversation.py and discovery_to_seed_extraction.py; no upload-narration template exists. The "Companion narrates plainly" language scattered through src/loomworks/uploads/ modules (executor.py, detection_registry.py, upload_event.py, skills/base.py, skills/image_metadata.py, skills/image_ocr.py) refers to OL-side rendering of structured result fields, not to engine-side prompt composition.

v0.4 framing per Candidate C: Sub-arc 2d ships an accompanying_message: str | None field on ExecutorResult (and the upload endpoint's PerFileUploadResponse shape that wraps it) so Phase 60 OL has the data it needs to compose multi-pathway narration. Engine accepts the accompanying message at the upload endpoint (existing multipart form already supports it via additional form fields per FastAPI convention; CC verifies at CRV-8); threads it through execute_upload to ExecutorResult; surfaces it in PerFileUploadResponse. Phase 60's OL surface consumes the field at narration-render time per Phase 60 scoping.

Scope is small: field addition + wire-through + persistence to UploadEventReceived event (per the existing class's already-shipped fields per V5, or via a small field addition if the existing class doesn't carry it — CC verifies at CRV-3/CRV-4). No engine-side prompt template work. No engine-side LLM call. No narration text composition.

13.2 The framing per scoping v0.1/v0.2 §Stage 2.2 + v0.4 reshape per V9

Original drift verdict (v0.1/v0.2/v0.3). Phase 58 collapsed narration to single-input because the upload pathway didn't yet thread accompanying messages through. The collapse was drift; the restore-multi-pathway intent was right.

v0.4 reshape per V9. The intent (Companion narration engages with both artifact and Operator's framing) preserves; the locus of where multi-pathway composition happens shifts from engine-prompt-template (the v0.1/v0.2/v0.3 framing) to OL-narration-render (the v0.4 framing). Engine's job becomes "expose the data multi-pathway composition needs"; OL's job becomes "compose multi-pathway narration." This is symmetric with how 2e/2f surfaces (AskOperatorToClarify, AskOperatorForProcess) work: engine ships the data; OL renders the affordance.

The locus shift doesn't relitigate the drift verdict — multi-pathway restore is still the answer. It relocates the implementation from engine prompt to OL render. Phase 60 carries the OL render work per §24.1 carry-forward.

13.3 Substrate-level work [v0.4 shrink]

Per CRV-8 (read at execution time): the upload endpoint's multipart form parsing at src/loomworks/api/routers/uploads.py (POST at line 286) already accepts FastAPI form fields. CC reads the existing form-field handling and adds an optional accompanying_message: Annotated[str | None, Form(...)] = None parameter (or analogous per existing convention). The endpoint passes the value to execute_upload (executor.py:313 signature; existing api_key parameter is the precedent shape).

The ExecutorResult dataclass at src/loomworks/uploads/executor.py:92 extends with an optional accompanying_message: str | None = None field. The executor surfaces the field on every result variant (completed, detection_failed, transformation_failed, needs_clarification, in_progress) — the field is upload-input metadata, not result-state-specific.

The PerFileUploadResponse at src/loomworks/api/routers/uploads.py:109 (per V11 evidence at lines 109–125) extends with the same field — the wire shape mirrors the executor shape.

The UploadEventReceived event class at src/loomworks/uploads/upload_event.py:118 extends with the same field if it doesn't already carry it (CC verifies at CRV-3 — the existing class may already have it per Phase 58's purpose-classification fields work). The event persistence (Sub-arc 1c) populates the field.

No prompt template addition. No src/loomworks/prompts/upload_narration*.py file. No LLM call. The accompanying message rides on the response shape; OL composes narration text at render time.

13.4 OL contract preservation [v0.4 reshape]

The v0.3 §13.4 worried about narration output shape change defeating the engine-only envelope. v0.4 reframes: the engine-only envelope is preserved exactly because no engine-side narration composition exists to change. The wire-shape addition (one str | None field) is the engine-side commitment Phase 60 OL consumes. Phase 60's OL render work that uses the field is Phase 60 scope; Phase 59 does not pre-empt it.

v0.4 halt condition (replaces v0.3's). A halt condition fires (per §22.3) if the upload endpoint's multipart form-parsing surface can't accept the new optional field cleanly — e.g., the OL composer (the upload client) doesn't currently send anything that could populate it, and the server-side validation flags any unknown form field as an error. The expected case: the OL composer sends a composer_message or analogous field already (per Phase 58's "the bytes the Companion chat composer attachment affordance sends" framing in uploads.py docstring); CC verifies the actual wire-name at CRV-8 and matches it. If the OL composer sends nothing, the field defaults to None and Phase 60 OL plumbing adds the send-side wiring.

13.5 Step 0 evidence consumed

13.6 Acceptance for 2d [v0.4 shrink]


13.7 Composition with Sub-arc 2f (purpose-disambiguation pre-emption) [NEW v0.2; v0.4 light reframe per V9]

If the upload arrives with an accompanying message that disambiguates purpose between multiple candidate skills (e.g., "transcribe this contract" → OCR; "what's on this whiteboard" → vision-analysis), the engine consults the message at detection time before checking 2f's multi-valid-candidates condition. When the message disambiguates, dispatch proceeds to the matching skill and 2f does not fire. When the message does not disambiguate (empty message; off-topic message; or message that doesn't clarify purpose), 2f fires per its standard flow (§15).

v0.4 reframing: the disambiguation-check pre-emption logic stays engine-side because the check sits between detection and dispatch (engine territory; the dispatch decision needs to land before the executor invokes a skill). What v0.4 changes is upstream of the check — Sub-arc 2d ships the accompanying_message field on the upload endpoint's intake (§13.3) rather than threading the field into a (non-existent) engine narration template. The field is available to the disambiguation-check helper exactly because Sub-arc 2d ships it on the executor-input path. Downstream of the check (the narration consumption) is what relocates to OL per V9.

Implementation: a disambiguation-check helper between detection and dispatch; the helper consults the accompanying_message field Sub-arc 2d ships on the executor input. The check shape — keyword matching against the per-candidate purpose-framing strings 2f registers (§15.3), schema check on declarative metadata, or LLM call — lands at execution time per the simplest viable path consistent with the candidate set's purpose-framing strings. CC selects the lower-friction path; LLM call is the highest-friction option and absorbs only if keyword/schema can't disambiguate cleanly. If the check requires an LLM call and the LLM-call posture wasn't decided at scoping, CC halts per §22.3 — v0.4's amendment-handoff §7 names this as a halt-and-escalate signal.

Tests cover both the pre-emption case (accompanying message disambiguates; dispatch proceeds; 2f does not fire) and the message-doesn't-disambiguate case (accompanying message present but doesn't clarify purpose; 2f fires per standard flow). Counted in §15 acceptance, not §13's, to keep the 2f surface co-located.


14. Classifier confidence model (Sub-arc 2e — confidence-disambiguation) [RESHAPED v0.4 per V8]

14.1 What 2e delivers [v0.4 reshape]

v0.3 framing was: "extend the detection registry's dispatch (single-skill commit today; no confidence output) with a confidence model." V8 evidence at Step 0 found Phase 58 already shipped a heuristic purpose-classifier — classify_purpose_for_chains at src/loomworks/uploads/executor.py:149 produces a PurposeClassificationResult (model at src/loomworks/uploads/upload_event.py:105) with a confidence: float | None field, a default threshold of 0.6, and routes to needs_clarification status with a candidates: list[str] response shape when confidence falls below threshold. The threshold-driven re-dispatch logic exists; what doesn't yet exist is (a) a substantive classifier (the current model is keyword-counting on candidate-chain skills) and (b) the full AskOperatorToClarify shape extension (the current needs_clarification + candidates: list[str] is the bare-bones precursor).

v0.4 framing per V8: Sub-arc 2e extends the existing heuristic. Two pieces:

What 2e covers — and what it doesn't. 2e covers confidence-disambiguation: engine isn't sure it dispatched correctly. The shape it produces (AskOperatorToClarify) carries an accuracy-question: "I dispatched this to skill X with confidence Y; was that right?" The orthogonal surface — purpose-disambiguation, multiple legitimate skills firing at high confidence where the choice is the Operator's purpose, not engine accuracy — is covered by Sub-arc 2f (§15). See §15.2 for the framing distinction and §6 sub-arc decomposition for the 2e/2f composition.

Phase 59 ships the engine-side data + the contract for OL consumption. Phase 60 carries the OL surface that consumes the ask-Operator-to-clarify data.

14.2 The framing per scoping v0.2 §Stage 2.2

Drift-justified verdict. Single-skill-commit dispatch is accepted as deliberate — the engine commits to one transformation skill per upload, rather than running multiple skills and comparing outputs (which would multiply API costs and complicate Memory event semantics). The confidence model is additive: it adds threshold-driven re-dispatch (ask the Operator if uncertain), not multi-skill comparison.

The distinction matters. Multi-skill comparison was a candidate path the scoping conversation considered and rejected: it would treat low-confidence dispatch as a resource-allocation problem (try multiple skills; compare) rather than as an Operator-engagement problem (the engine doesn't know; ask). The Operator-engagement framing matches the only-show-what-is-available principle and the plain-English-communication-with-Operators principle — when the engine is uncertain, it says so and asks, rather than papering over uncertainty with comparison heuristics.

v0.2 sharpening on the framing. Scoping v0.1 compressed two distinct Operator-engagement-at-dispatch surfaces — confidence-disambiguation and purpose-disambiguation — into the single classifier confidence model. Operator review during CR drafting (Move 5) caught the compression. The two surfaces are genuinely distinct: engine certainty (am I dispatching correctly?) and Operator purpose (which legitimate skill do you want?). The engine can be very certain about classification while being entirely uncertain about purpose, and vice versa. v0.2 §Stage 2.2 separates them; this CR's §14 covers 2e (confidence-disambiguation only); §15 covers 2f (purpose-disambiguation). The compression v0.2 caught is second-order evidence for the v1-multi-pathway-collapses-inquiry-as-protocol candidate — the inquiry applied at scoping time can produce its own compressions (Operator review is the recovery mechanism). See §24.2 methodology candidates carry-forward.

14.3 Substrate-level work [v0.4 reshape]

Existing substrate per V8: classify_purpose_for_chains(...) at src/loomworks/uploads/executor.py:149 produces PurposeClassificationResult (upload_event.py:105) with confidence: float | None. Default threshold is 0.6. needs_clarification is one of ExecutorResult.status literals (executor.py:68). The executor at executor.py:357 invokes the classifier and routes to needs_clarification when below threshold. The response shape carries candidates: list[str] per PerFileUploadResponse (uploads.py:109–125).

Sub-arc 2e's two extensions:

  1. Classifier upgrade. Per CRV-7 (read at execution time): the existing keyword-counting heuristic in classify_purpose_for_chains (executor.py:149–223). Sub-arc 2e replaces or supplements with classifier-backed confidence. CC selects the classifier shape at execution per cost/latency tradeoffs and existing patterns:

CC selects the lowest-friction option that improves on the current heuristic measurably. If the LLM-call posture wasn't decided at scoping, CC halts per §22.3 — same halt-and-escalate signal as the 2d/2f composition LLM-call posture.

  1. Shape extension. The existing needs_clarification + candidates: list[str] becomes a richer AskOperatorToClarify shape (per-candidate metadata: skill reference, classifier confidence, accuracy-framing string). The shape lives on PurposeClassificationResult (extending the existing model) or alongside it on ExecutorResult (a new optional field). CC selects placement at CRV-7 per the existing model's extensibility shape; naming-only divergence absorbs in-flight; architectural divergence (e.g., the existing model is frozen=True and can't be extended without reshaping) halts per §22.

The threshold value: existing default is 0.6. CC re-evaluates at execution time per the new classifier's confidence-output range; if the upgraded classifier produces confidence on a different distribution, the threshold may shift. Documented in implementation notes for future-phase calibration.

The re-dispatch path: when confidence is below threshold, the dispatch produces the AskOperatorToClarify shape; the upload endpoint surfaces it in its response (the existing needs_clarification status routing carries; the response shape's candidates: list[str] field becomes the richer per-candidate-metadata shape). Phase 60's OL surface renders the clarification affordance.

Composition with 2f (§15) at the substrate level. Per §15.3: 2f extends the same dispatch surface to handle multi-candidate-above-threshold semantics. The dispatch (existing classify_purpose_for_chains extended per 2e) emits one of three states based on candidate landscape: single-above-threshold (standard dispatch), single-below-threshold (2e fires AskOperatorToClarify), multiple-above-threshold (2f fires AskOperatorForProcess). CC implements both extensions in Sub-arc 2 build sequence (Step 2); ordering within the step lands at execution time. If the three states can't compose cleanly in the existing classifier shape — e.g., the existing confidence: float | None field can't represent "multiple candidates equally confident" without losing information — CC halts per §22.3.3.

14.4 OL contract preservation

The OL contract per the envelope premise: Phase 59 ships the engine-side data shape; Phase 60 builds the OL surface that consumes it. CC sketches the expected OL consumer shape during CR execution and documents it in implementation notes for Phase 60's scoping. A halt condition fires (per §22) if the contract reveals OL-side constraints Phase 59 didn't anticipate — e.g., the OL surface needs more or different data than the engine's shape provides. In that case, scoping v0.3 or cross-phase scoping reshapes.

Phase 60 OL consumer of AskOperatorToClarify is anticipated to be similar to but distinct from the Phase 60 OL consumer of AskOperatorForProcess (§15.5). Different elicitation framings: accuracy-question (2e) vs. purpose-question (2f). Both consume from the same upload endpoint response slot — the shape returned alongside the upload acknowledgment.

14.5 Step 0 evidence consumed

14.6 Acceptance for 2e [v0.4 reframed]


15. Multi-valid-prompt-for-process (Sub-arc 2f — purpose-disambiguation) [NEW v0.2; RESHAPED v0.4 per V8]

15.1 What 2f delivers [v0.4 reshape]

v0.3 framing was: "engine produces an AskOperatorForProcess shape rather than committing to a single skill" — implying the detection-registry dispatch surface needed to learn multi-candidate-above-threshold semantics from scratch. V8 evidence at Step 0 found the multi-candidate surface partially exists already: DetectionMatched.candidate_chains: tuple[str, ...] (detection_registry.py:124) carries multiple candidates when multiple rules match; classify_purpose_for_chains at executor.py:149 narrows the chain set with confidence; tied-match (multiple chains with the same top score) routes to needs_clarification with bare candidates: list[str] per existing executor.py:212 logic. The semantic Phase 58 ships is "tied-match → ask"; Phase 59 sub-arc 2f ships "multiple-above-threshold → ask with richer per-candidate metadata."

v0.4 framing per V8: Sub-arc 2f extends the existing tied-match-routing into the full purpose-disambiguation surface. Two pieces:

Canonical example. An image upload triggers both image_vision_analysis (treat as photograph; describe what's in it) and image_ocr (treat as scanned document; extract the text). Per the existing detection registry, both rules register against image/* extensions and magic bytes; look_up() returns a DetectionMatched with candidate_chains=("image_vision_analysis", "image_ocr"). Per Phase 58's existing routing, the tied-match goes to needs_clarification with candidates: list[str]. Per Phase 59 2f: the routing produces AskOperatorForProcess with [{skill: "image_vision_analysis", purpose_framing: "describe what's in the image", confidence: 0.95}, {skill: "image_ocr", purpose_framing: "transcribe the text in the image", confidence: 0.95}].

Shape name resolution. AskOperatorForProcess — the existing AskOperatorToClarify shape (P59-D4 surface) establishes the "Ask Operator [preposition] [thing]" family in the codebase; AskOperatorForProcess extends that family while preserving the Operator's "prompt for process" phrasing. The name is settled at this re-draft per P59-D11 §3 resolution; final substrate naming lands per CRV-7 (read at execution time). Naming-only divergence from the codebase family absorbs in-flight; architectural divergence (e.g., the codebase favors Disambiguation or Elicitation prefixes for this shape family) halts per §22 — re-draft handoff §7 names this as a halt-and-escalate signal.

Phase 59 ships the engine-side data shape + the contract for OL consumption. Phase 60 carries the OL surface that consumes the prompt-for-process data with the per-candidate purpose-framing strings.

15.2 The framing per scoping v0.2 §Stage 2.2

Drift verdict, restore multi-pathway. Scoping v0.1 compressed confidence-disambiguation and purpose-disambiguation into a single classifier confidence model (P59-D4). The compression had two reinforcing causes (per scoping v0.2 §Move 5): the upload-pathway investigation that seeded Sub-arc (ii) framing named "when detection is ambiguous, the engine asks a purpose-shaped question" but didn't separate purpose-disambiguation from confidence-disambiguation; and scoping v0.1 was running the v1-multi-pathway-collapses inquiry on Phase 58's outputs and naturally surfaced the single-skill-commit vs. multi-skill comparison axis (which P59-D4 settled as accept-single-skill-commit). The two-distinct-surfaces axis was a different question — about what the Operator engages on, not about how the engine dispatches — and got compressed under the dispatch-posture decision.

v0.2 separates them. The two surfaces are orthogonal: engine certainty (am I dispatching correctly? — covered by 2e) and Operator purpose (which legitimate skill do you want? — covered by 2f). The engine can be very certain about classification while being entirely uncertain about purpose, and vice versa. Compressing them treats Operator-engagement-at-dispatch as a one-dimensional problem (engine certainty); the two-surface shape recognizes that engine certainty and Operator purpose are orthogonal concerns.

The two surfaces compose with Sub-arc 2d (§13.7): if the Operator provided an accompanying message that already disambiguates purpose ("scan the contract" or "what's on the whiteboard"), 2f's elicitation does not fire — the message answers the question pre-emptively. If no accompanying message OR the message doesn't disambiguate, 2f fires per its standard flow.

15.3 Substrate-level work [v0.4 reshape]

Existing substrate per V8: DetectionRule at src/loomworks/uploads/detection_registry.py:73 is a frozen dataclass with extensions: frozenset[str], magic_byte_signature: MagicByteSignature, candidate_chains: tuple[str, ...], content_type_hint: str | None, file_family: str. look_up(*, filename, content_head) -> DetectionMatched | DetectionFailed at detection_registry.py:214 returns matched chains. classify_purpose_for_chains at executor.py:149 narrows the chain set with confidence. The multi-candidate surface exists; per-candidate purpose-framing strings do not.

Sub-arc 2f's two pieces:

  1. Per-candidate purpose-framing-string declaration. Per CRV-7 (read at execution time): the existing DetectionRule frozen dataclass extends with a purpose_framing: str field (or analogous; CC matches naming convention at execution). Each transformation skill's register_detection_rule(...) call adds the purpose-framing argument: e.g., image_vision_analysis registers with purpose_framing="describe what's in the image"; image_ocr with purpose_framing="transcribe the text in the image". The framing is a single short string per skill, surfaced through registered_rules() (detection_registry.py:registered_rules) and joined in at dispatch time per the matched candidates. If the existing DetectionRule is frozen=True and adding a field would force a breaking change to existing registration call-sites — CC verifies at CRV-7 — CC selects between (a) adding the field with a default value (purpose_framing: str = "" so existing call-sites still work) and (b) requiring all skill modules update their registrations together (slightly larger surface but cleaner). CC selects the lower-friction option per backward-compat preference.
  1. Routing reshape. Phase 58's tied-match-routing in executor.py (lines 199–223) currently produces confidence=0.5 for tied matches, which routes to needs_clarification per the existing 0.6 threshold logic. Sub-arc 2f reshapes: when multiple candidates match above threshold (per the upgraded 2e classifier), route to a distinct AskOperatorForProcess path. The existing needs_clarification status either (a) carries one status with the response-shape discriminator (a discriminated union: AskOperatorToClarify | AskOperatorForProcess on the response field) or (b) splits into two sub-statuses (needs_purpose_clarification, needs_classification_clarification). CC selects (a) at execution per simpler-shape preference; (b) is the fallback if discriminated-union doesn't compose with existing OL-converse-view consumer expectations.

Dispatch state machine after 2e + 2f extensions:

The detection-time check fires after classify_purpose_for_chains returns; if multiple chains end up above threshold AND Sub-arc 2d's accompanying-message disambiguation pre-emption check (§13.7) does not fire, the engine produces the AskOperatorForProcess shape. The shape's payload: an array of {skill_reference, purpose_framing, confidence} tuples — one per above-threshold candidate. The upload endpoint catches the shape and returns it in its response slot (the same slot 2e's AskOperatorToClarify uses; only one of the two shapes fires per upload — discriminated union).

15.4 Composition with 2d, 2e, and 4a

15.5 OL contract preservation

Phase 60 OL consumer of AskOperatorForProcess is anticipated to be similar to but distinct from the AskOperatorToClarify consumer (§14.4). Both consume from the same upload endpoint response slot. The elicitation framing differs: AskOperatorForProcess frames as purpose-question ("you uploaded a file that could be processed two ways — which do you want?"); AskOperatorToClarify frames as accuracy-question ("I think this is X with confidence Y — is that right?"). The OL surface chrome may share components but the elicitation copy differs.

CR re-drafter sketches the expected Phase 60 consumer shape during CR execution; mid-Phase-59 surface that contradicts the sketch warrants halt per §22. The sketch lands in implementation notes for Phase 60's scoping input.

A halt condition fires (per §22.3) if AskOperatorForProcess and AskOperatorToClarify can't compose cleanly with the upload endpoint's response schema — e.g., both need to fire on the same response and the schema can't represent the union (this shouldn't happen because the candidate landscape is mutually exclusive, but the schema slot still needs to represent either shape). The expected case: the response slot is a discriminated union; either shape lands in it; neither fires when standard single-skill dispatch proceeds.

15.6 Step 0 evidence consumed

15.7 Acceptance for 2f [v0.4 reframed]


16. OCR threshold model refinement (Sub-arc 3a)

16.1 What 3a delivers

Refinement of the OCR's confidence-output-to-warning-decision mapping. The first-pass shipped at Phase 58 — OCR returns some confidence score; some mapping from confidence to "warn the Operator" decision exists. Phase 59 calibrates the mapping for first-quality.

16.2 Substrate-level work

CC reads the existing OCR threshold logic at execution time (the image_ocr skill module surface — file paths per Step 0 V1 evidence). The refinement specifies threshold values and the test fixtures that exercise them:

The threshold values document in implementation notes. The exact numbers depend on the OCR backend's confidence-output range (CC reads the backend's documentation at execution time).

16.3 Calibration-shape findings expected

Per scoping v0.1 §Stage 4.2 reserved-slot allocation, first-pass tuning is inherently surfacing. Phase 59 is the first phase where OCR threshold-model tuning runs against real image content; the calibration will reveal whether the scoping note's threshold-and-warning framing fits cleanly or surfaces new shape (e.g., per-character thresholding vs. document-level; per-image-class threshold variation per Sub-arc 3b).

The reserved-slot allocation explicitly anticipates this. If a calibration finding requires CR amendment scoping (e.g., the OCR backend doesn't surface the confidence output Phase 59 needs in a useful form), the mid-build amendment slot for Sub-arc (ii) quality engages per §22.

16.4 Step 0 evidence

V10 (content-reliability surface absence — Sub-arc 3c-relevant) and V8 (confidence model — Sub-arc 2e-relevant) together inform Sub-arc 3a indirectly. The OCR-specific evidence comes from CC reading the image_ocr skill module at execution time; Step 0 didn't enumerate the existing OCR threshold logic in detail.

16.5 Acceptance for 3a


17. OCR class-aware parameter refinement (Sub-arc 3b)

17.1 What 3b delivers

OCR parameter sets vary per image class (camera-captured vs. clean digital scan vs. low-quality scan). The classification logic — which image class an upload belongs to — is part of the OCR skill module (or a pre-step in the detection registry; CC selects at execution time per the existing module shape).

17.2 Substrate-level work

The image-class classifier looks at image properties (resolution, aspect ratio, color histogram, edge density, or similar heuristics; the exact signal set lands during construction) and identifies the class. The OCR engine then runs with the parameter set appropriate to the class:

The classifier's output also feeds the OCR threshold model in Sub-arc 3a — class-specific thresholds may differ.

17.3 Calibration-shape findings expected

Same reserved-slot allocation as 3a. First-pass tuning surfacing; calibration shape may diverge from scoping note expectations. Reserved slot engages if amendment is needed.

17.4 Acceptance for 3b


18. Content-reliability warning surface (Sub-arc 3c)

18.1 What 3c delivers

The ExtractionResult dataclass per CRV-9 (read at execution time per Step 0 V10 evidence) gains a reliability field with three values: succeeded, unreliable_succeeded, failed. The third state — unreliable_succeeded — surfaces a warning alongside the assertion content; Phase 60's OL surface displays the warning; Phase 59 ships the data shape and the engine-side classification of which extraction outcomes land in which state.

Critically: assertion content persists in all three success cases (including unreliable_succeeded). The warning is metadata, not a rejection. The Operator sees the assertion (content extracted by OCR or vision) AND the warning ("this extraction may not be reliable; review carefully"). The Operator can accept, edit, or reject the assertion; the engine does not pre-empt the decision.

18.2 The framing per scoping v0.1 §Stage 2.2

Drift verdict (restore multi-pathway). Phase 58 collapsed extraction outcomes to a two-state shape (succeeded / failed). The collapse was drift; the three-state surface restores the design intent that some extractions succeed-but-with-caveats — the assertion is good enough to surface but should carry an honest warning rather than be presented as if fully reliable.

This connects to the only-show-what-is-available and plain-English-communication-with-Operators principles. A two-state surface forces the engine to choose: either present unreliable extractions as fully reliable (dishonest) or reject them entirely (loses useful content). The three-state surface honors both — surface the content, name the unreliability.

18.3 Substrate-level work

Per CRV-9: read the ExtractionResult dataclass; add the reliability field as a three-value enum. The enum members are SUCCEEDED, UNRELIABLE_SUCCEEDED, FAILED (or whatever naming convention the codebase favors; CC matches existing enum conventions at execution time).

The classification logic — which extraction outcomes produce which reliability state — depends on the skill family. For OCR (Sub-arcs 3a/3b), the threshold mapping produces the state. For vision (image_vision_analysis), the confidence output from the Claude-with-vision API call produces the state (the API surfaces a confidence indicator on the vision response; CC verifies the surface at execution). For audio (audio_transcription), Whisper produces per-segment confidence; aggregate confidence below threshold maps to unreliable_succeeded.

The OL response shape carries the reliability state through. Phase 60 will read the field and render the warning surface.

18.4 Step 0 evidence consumed

18.5 Acceptance for 3c


19. Fallback affordance endpoint (Sub-arc 4a)

19.1 What 4a delivers

A new engine endpoint per Phase 58 CR §7.4: the manual-content-contribution fallback affordance for detection-failed cases. Operator-facing path: file uploaded successfully (200 from upload endpoint); detection-failed (no skill matched, or all matched skills returned FAILED reliability); Phase 60's OL surface lets Operator type content manually; the manual content posts to this fallback endpoint, which produces a Memory event and assertion the same way successful extraction would.

The candidate-landscape four-way distinction (per §15.4). Sub-arc 4a covers the zero-candidate case of the candidate-landscape space; 2e covers the one-candidate-low-confidence case; standard dispatch covers the one-candidate-high-confidence case; 2f covers the multi-candidate-above-threshold case. The four cases together exhaust the candidate-landscape space; 4a is the orthogonal complement to 2e and 2f, not an alternative to them. The 2d accompanying-message pre-emption (§13.7) sits one level up — it can convert a 2f case to a standard-dispatch case before 2f fires, but it does not interact with the 4a zero-candidate case (no candidate means there's nothing to disambiguate).

19.2 Endpoint contract

CC reads CRV-10 at execution time: existing endpoints in src/loomworks/api/routers/files.py per Step 0 V11 evidence. CC selects placement for the new endpoint following the convention (engagement-scoped per the universal convention from Phase 53 V10 / scoping v0.1 §Stage 2.3).

Proposed endpoint shape (CC confirms or adjusts at execution time):


POST /engagements/{engagement_id}/files/{file_id}/manual-content

Request body:


{
  "content": "<the Operator's typed text content>",
  "content_type": "text/markdown" | "text/plain"
}

Response: the Memory event reference + assertion reference produced by the manual contribution.

The endpoint behaves as a fallback for the upload_event_received event already persisted (Sub-arc 1c) — it doesn't create a new upload event; it adds a manual-contribution assertion attached to the existing file_id.

19.3 Memory event class

CC determines at execution time whether the fallback endpoint produces:

Either approach is acceptable; the choice depends on whether existing event classes fit naturally or would require force-fitting. CC selects the lower-friction option and documents the choice in implementation notes.

19.4 Authentication and scope

Engagement-scoped per the universal convention. The endpoint requires the same authentication the upload endpoint requires; the Operator is the actor on the resulting Memory event.

19.5 Step 0 evidence consumed

19.6 Phase 60 OL consumer shape preservation

A halt condition fires (per §22) if the endpoint contract reveals Phase 60-side constraints the scoping note didn't anticipate. CC sketches Phase 60's consumer shape during CR execution; mid-Phase-59 surface that contradicts the sketch warrants halt and cross-phase scoping.

19.7 Acceptance for 4a

20. Test strategy

20.1 Test surface estimate [v0.4 adjusts per V5/V8/V9 reshapes]

Per CR drafting handoff §7 and scoping v0.2 §Test surface estimate, refined at v0.4 for the three V-finding reshapes. Total new engine tests in the range ~24–39 always-run (v0.4 narrows from v0.3's ~26–41; net delta is small because 1c shrinks ~2 tests, 2d shrinks ~2 tests, 2e/2f shape-extensions stay within their original ranges):

| Sub-arc | Component | Estimate (v0.4) | Δ from v0.3 | Reason | |---------|-----------|----------|------------|--------| | (i) | 1a credential-store consolidation | 1–2 | unchanged | V4 HOLDS | | (i) | 1b ObjectStore put_blob end-to-end | 2–3 | unchanged | V3 HOLDS | | (i) | 1c UploadEventReceived persistence-call wiring [RESHAPED v0.4 per V5] | 1–2 | -2 (was 3–4) | V5 EVENT-EXISTS partial; class + anchor priority shipped; only persistence call to wire | | (i) | 1d rate-limit middleware | 2 | unchanged | V6 HOLDS | | (i) | 1e streaming-upload | 2–3 | unchanged | V7 HOLDS | | (ii) wiring | 2a/2b/2c API-key resolution | 3–6 | unchanged | V4 HOLDS; V1 absorbs naming-only | | (ii) wiring | 2d accompanying-message field on response [RESHAPED v0.4 per V9 Candidate C] | 1–2 | -1 to -2 (was 3) | V9 NARRATION-LIVES-IN-OL; small wire-through; OL composition is Phase 60 | | (ii) wiring | 2e classifier confidence + AskOperatorToClarify shape extension [RESHAPED v0.4 per V8] | 3 | unchanged count; character changes (extension not build) | V8 ALREADY-HAS-CONFIDENCE heuristic | | (ii) wiring | 2f multi-valid → AskOperatorForProcess shape + per-candidate framing strings [RESHAPED v0.4 per V8] | 3–5 | unchanged count; character changes (extension not build) | V8 ALREADY-HAS-CONFIDENCE; tied-match routing exists; 2f extends | | (ii) quality | 3a OCR threshold model | 2–3 | unchanged | V8/V10 inform indirectly | | (ii) quality | 3b OCR class-aware parameters | 2–3 | unchanged | reserved-slot inflows expected | | (ii) quality | 3c content-reliability warning surface | 3–4 | unchanged | V10 HOLDS | | (iii) engine | 4a fallback affordance endpoint | 3–5 | unchanged | V11 HOLDS |

Estimate range: 28–43 tests across the sub-arcs at minimum/maximum bounds; the lower bound of ~24–39 reflects natural absorption where components share test infrastructure (e.g., 2a/2b/2c may share fixtures; 2e/2f may share dispatch-surface fixtures including reuse of Phase 58's existing classify_purpose_for_chains test fixtures; 3a/3b share the OCR fixture pipeline; 1c may share the existing UploadEventReceived Phase 58 schema-validation tests). The upper bound assumes minimal sharing.

Post-Phase-59 target: existing baseline (~2,400 always-run + 30 skipped + 2 pre-existing fails per Phase 58 implementation notes v0.2 §13, confirmed by CC at Step 0b) + ~24–39 new = ~2,424–2,439 always-run + 30+ skipped + 2 pre-existing fails carrying through. The two pre-existing fails (test_api_assertion_retract.py::test_api_assertion_retract; test_phase_44_evaluator.py::test_concern_scan_does_not_re_fire_within_dedup_window) are not Phase 59 scope; if Phase 59 work converts a passing test to failing OR makes a pre-existing fail green, that's recorded in implementation notes per §25.

v0.4 widening of halt threshold. Per §22.6, test-count divergence from estimate >50% halts. The 50% buffer at v0.4's ~24–39 estimate accommodates routine surfacing during build (>36–58 new tests would halt; previously >39–62 at v0.3 estimate ranges). The buffer carries; the absolute halt threshold scales with the estimate.

20.2 Test grouping by build step [v0.4 adjusts]

Tests group per Build Step (§21):

20.3 Test posture

20.4 Operator Layer tests

Zero new OL vitest in Phase 59. Phase 60 carries OL-side tests. The existing 167 OL vitest stay green throughout Phase 59's life.

20.5 Alembic migration

Likely zero per typed-MemoryObject-without-migration pattern (P59-D7). CC confirms at execution; if migration becomes necessary, CC halts per §22 (the pattern fails to compose) and Alembic head advances from 0064 to 0065. The likelihood is low given Phase 50/52/53 precedent.

20.6 Test-count divergence as halt condition

Per §22, test-count divergence from estimate greater than 50% (i.e., >62 new tests across the phase, v0.2 widening from v0.1's >55) halts. The estimate's 50% buffer accommodates routine surfacing during build; beyond 50% the phase has changed shape and scoping should re-engage.


21. Build sequencing

21.1 Step structure

5 active steps + 4 reserved buffer slots = 9 slots total. Reserved-slot-as-halt-condition-pre-commitment per the methodology candidate from Phase 50 onward, refined at Phase 58 to allow envelope-breach with explicit Operator authorization.

Step 0 — Pre-flight + CR archival + Step 0 inspection brief execution + Operator confirmation halt + build branch creation. Seven sub-steps per §4.3 (v0.3 expansion from v0.2's three-action Step 0):

Estimated Step 0 wall-time: ~30–60 min (was ~10 min in v0.2; expansion absorbs inspection brief execution + findings filing + Operator confirmation wait).

Step 1 — Sub-arc (i) Wave 7 engine substrate. Components 1a through 1e in order: credential-store consolidation documentation (1a) → ObjectStore put_blob wiring (1b) → UploadEventReceived Memory event class + _ANCHOR_PRIORITY entry (1c) → rate-limit middleware (1d) → streaming-upload optimization (1e). Tests: ~10–14 new. Step 1 closes when all five components' acceptance criteria green per §7–§11.

Checkpoint A — Operator confirmation after Step 1. CC pauses; produces a step-summary; Operator confirms Wave 7 wiring on test cases before Step 2 (Sub-arc (ii) wiring half) begins. The checkpoint separates mechanical substrate work (Sub-arc (i)) from the wiring half (Sub-arc (ii)) that integrates with Phase 60's anticipated OL consumer shapes. v0.2: confirmation scope widens to include both 2e (confidence-disambiguation) and 2f (purpose-disambiguation) surfaces — Operator confirms both engine-side data shapes before Step 2's six components begin.

Step 2 — Sub-arc (ii) wiring half. Six components: 2a/2b/2c (per-skill API-key resolution; audio, vision, OCR), 2d (narration multi-pathway restore), 2e (classifier confidence model — confidence-disambiguation), 2f (multi-valid-prompt-for-process — purpose-disambiguation) [NEW v0.2]. Tests: ~12–17 new (v0.2 widens from v0.1's ~9–12 by +3–5 for 2f). Step 2 closes when components' acceptance criteria green per §12–§15.

Step 3 — Sub-arc (ii) quality half. Components 3a (OCR threshold model refinement), 3b (OCR class-aware parameter refinement), 3c (content-reliability warning surface). Tests: ~7–10 new. Step 3 closes when components' acceptance criteria green per §16–§18.

Checkpoint B — Operator confirmation after Step 3. CC pauses; produces a step-summary including any calibration-shape findings from 3a/3b tuning; Operator confirms quality work before Step 4 (Sub-arc (iii) engine half) begins. The checkpoint separates quality tuning (where first-pass surfacing is expected) from the engine-half close.

Step 4 — Sub-arc (iii) engine half. Component 4a (fallback affordance endpoint). Tests: ~3–5 new. Step 4 closes when 4a's acceptance criteria green per §19.

Step 5 — Close. CC produces implementation notes at engine repo docs/phase-impl-notes/phase-59-implementation-notes-v0_1.md per §25. Applies refined close protocol with explicit refspecs per the methodology candidate from Phase 56 (manifest v0.41 §2 named principle). Applies Step 0 branch lifecycle per Phase 57-established convention: deletes phase-59-step-0 locally after merging Step 0 findings into the build branch context. Retroactive cleanup of any Phase 58 Step 0 branches present per Phase 57 P57-D7 Option A precedent.

Checkpoint C — Final, before tagging. CC pauses; final implementation-notes review; Operator confirms close-protocol invocation before tag lands. Tag phase-59-upload-pathway-completion on engine repo only (no OL tag per scoping v0.2 §What Phase 59 delivers).

21.2 Reserved slots (6–9)

Per P59-D9, four reserved amendment slots. Per scoping v0.2 §Stage 4.2 allocation:

Reserved-not-skipped: unconsumed if no amendment arises; the buffer's value is its presence, not its consumption. Phase 50 left all three reserved slots unconsumed; Phase 51, 52, 53, 54, 55, 56 followed; Phase 57 consumed three of four through three amendment cycles; Phase 58 consumed both of its two slots and breached at v0.5 (fifth amendment cycle requiring explicit Operator authorization per the established pattern). Phase 59's four-slot allocation doubles Phase 58's reservation because (a) v1-multi-pathway-collapses-inquiry-as-protocol is in its first application and protocol-shape surfacing is anticipated; (b) first-quality tuning in Step 3 inherently surfaces calibration shape. v0.2 confirms the slot count unchanged after 2f's addition — 2f fits within the existing wiring-half slot (slot 7) per the OL-contract-preservation risk-family reasoning.

Envelope-breach beyond slot 9 requires explicit Operator authorization per the Phase 58 v0.5 pattern. Mid-build amendment scoping runs in a separate Claude.ai chat per standard pattern; CC produces a halt-surface note per §22 and the Operator opens the amendment scoping chat.

21.3 Auto-mode posture

Four halt points total in v0.3: Step 0f (findings confirmation; new), Checkpoint A (Wave 7 + wiring-half confirmation), Checkpoint B (quality confirmation), Checkpoint C (final pre-tag). v0.2 had three; v0.3 adds Step 0f because pre-flight is now substantive (Step 0 inspection brief execution + findings filing) rather than baseline-only.

The four-checkpoint structure follows the CR drafting handoff §6 + v0.3 expansion. The handoff added Checkpoint A (after Step 1 substrate work) because the Wave 7 substrate scope is large enough to warrant its own confirmation point before wiring half engages; v0.3 adds Step 0f for the analogous reason at pre-flight.

21.4 Tag pre-commitment

phase-59-upload-pathway-completion on engine repo only at Phase 59 close. No OL tag — Phase 59 has no OL work. OL tag returns at Phase 60 with phase-60-contribution-composer-completeness or analogous.


22. Halt conditions

CC halts and writes a halt-surface note at phase-59-halt-surface-{timestamp}-v0_1.md in engine repo docs/phase-impl-notes/ on any of the following. Mid-build amendment scoping then runs in a separate Claude.ai chat per the standard pattern; CC does not draft-and-hope.

22.1 Step 0 halt conditions [v0.3 expansion]

Per §4.7 (Step 0a–0g sub-steps); recorded here for §22 self-sufficiency.

22.2 Step 1 halt conditions

22.3 Step 2 halt conditions

22.4 Step 3 halt conditions

22.5 Step 4 halt conditions

22.6 Any-step halt conditions

In all cases, halt-and-surface is preferred to draft-and-hope. The amendment scoping path is established practice (Phase 49, 50, 51, 52, 53, 57, 58 all engaged it); engaging it is not failure.


23. Acceptance gates

Phase 59 closes when all of the following hold:

  1. Tag landed. phase-59-upload-pathway-completion on engine repo at Phase 59 close. Annotated tag. Pushed to origin via the refined close protocol's explicit refspec (per manifest v0.41 §2 named principle). No OL tag.
  1. All Step 1–4 deliverables shipped per §7–§19. Each sub-arc component meets its acceptance criteria. v0.2 expansion: includes Sub-arc 2f purpose-disambiguation surface (AskOperatorForProcess shape; per-candidate purpose-framing strings declared at registration; 2d pre-emption check; upload endpoint returns shape in response slot) alongside the existing list.
  1. Stage 2 verdicts documented in implementation notes per §25. Each per-item deliberate-vs-drift verdict carries from scoping v0.2 §Stage 2 into the implementation notes with a build-pressure annotation: anticipated-vs-surprising; protocol-fit-clean vs. protocol-surfaces-new-shape. This is the v1-multi-pathway-collapses-inquiry-as-protocol's first-application evidence. v0.2 adds the 2f verdict row (drift; restore multi-pathway; Move 5 second-order evidence for the inquiry-as-protocol candidate's scoping-time self-compression vulnerability).
  1. Test count delta within estimate envelope. ~26–41 new engine tests (v0.2 widens from v0.1's ~23–37; carries unchanged at v0.3); existing ~2,400 passed + 30 skipped + 2 pre-existing fails carry through Phase 59 (v0.3 baseline correction from v0.2's incorrect ~2,146/26); the two pre-existing fails are not Phase 59 scope; OL 167 vitest unchanged. If delta exceeds 50% of estimate (i.e., >62 new tests), halt-and-surface per §22 fired and was resolved through amendment.
  1. Alembic head check. Head at 0064 unless §22 halt fired for migration; in that case head at 0065 (or higher).
  1. No envelope-breach beyond 4 reserved slots without explicit Operator authorization. Reserved slots consumed track per §21.2. Phase 58 v0.5 envelope-breach pattern engaged only with explicit Operator OK.
  1. Implementation notes filed at engine repo docs/phase-impl-notes/phase-59-implementation-notes-v0_1.md per §25, capturing the trajectory, the Stage 2 verdicts under build pressure, reserved-slot consumption, methodology candidates for v0.21.
  1. Step 0 branch lifecycle applied. phase-59-step-0 deleted locally per Phase 57-established convention. Any Phase 58 Step 0 branches still present at execution time also cleaned up per P57-D7 Option A retroactive cleanup pattern.
  1. Refined close protocol invocation clean. Per CRV-11 (read at execution time per Phase 56's named principle in manifest v0.41 §2). Explicit refspec push for both branch and tag; local + remote build branch deletion via explicit refspecs.
  1. Operator confirmation at Checkpoints A, B, C. Each checkpoint produces a confirmation record in implementation notes. v0.2: Checkpoint A confirmation scope explicitly covers both 2e and 2f surfaces per §21.1.
  1. No silent shape changes to OL contracts. Phase 59's engine-side contracts that Phase 60 will consume preserved as drafted: classifier confidence model's AskOperatorToClarify shape; [NEW v0.2] multi-valid-prompt-for-process AskOperatorForProcess shape (with per-candidate purpose-framing strings); content-reliability three-state in ExtractionResult; fallback affordance endpoint response shape. Any drift surfaced per §22 and absorbed via amendment.
  1. Substrate-friction-discipline-pattern fired appropriately. If any halt-surface event occurred, the discipline pattern's resolution shape (note-first; halt-then-amendment; explicit reserved-slot consumption) was followed per Phase 58 implementation notes §11.1 pattern.

24. Carry-forward

24.1 To Phase 60 (engine-side contracts inherited)

Phase 60's OL surface implements consumption of Phase 59's engine-side contracts:

Phase 60 inherits Phase 59's contracts; the OL surface implements the consumption.

24.2 Methodology v0.21 consolidation (between Phase 59 close and Phase 60 scoping)

Per P59-D10. The v0.21 consolidation slot lives between Phase 59 close and Phase 60 scoping; runs parallel as a separate Claude.ai work session. Phase 59's implementation notes feed v0.21 with:

24.3 Items deferred past Phase 59

Per scoping v0.2 §What Phase 59 does NOT deliver, items deferred past Phase 59:

The queued-directions document (loomworks-queued-directions-and-deferred-work-v0_11.md at Phase 59 entry; will advance to v0.12 at Phase 59 close to absorb new candidates including v0.3's main-branch-drift investigation) carries these.

24.4 New candidates surfaced during Phase 59

To be recorded in implementation notes (§25) and absorbed at Phase 59 close into queued-directions v0.12 if applicable. The CR cannot pre-enumerate these — they surface during build.


25. Implementation notes pre-commitment

CC produces phase-59-implementation-notes-v0_1.md at engine repo docs/phase-impl-notes/ at Phase 59 close. The notes are the bridge from Phase 59 build determinations to manifest v0.42 absorption and v0.21 consolidation.

25.1 Required sections

  1. Trajectory. Phase 58 close state; Phase 59 entry; the five-segment build sequence as executed; checkpoint outcomes (Step 0f, A, B, C); any halt-surface events. v0.2 carry-forward: record the v0.1→v0.2 CR-re-draft cycle as part of the Phase 59 trajectory — v0.1 CR's compression of confidence/purpose surfaces, Move 5 Operator review, v0.2 scoping note + re-draft handoff + v0.2 CR. v0.3 carry-forward: record the v0.2→v0.3 CR-re-draft cycle as part of the Phase 59 trajectory — CC's 2026-05-15 pre-flight halt-surface note + four divergences (main behind tag, no Step 0 branch, no findings doc, test counts off) + Path A absorption + v0.3 CR with §4 restructure and baseline correction. v0.4 carry-forward: record the v0.3→v0.4 CR-re-draft cycle as the third trajectory-event-of-this-kind — CC's 2026-05-15 Step 0 execution outcomes (Step 0a–0e green; Step 0 findings doc filed at engine 0d442ba); Step 0f Operator confirmation halt; Operator's Path 3 selection (v0.4 amendment cycle) with Candidate C + Option 2 absorption decisions; v0.4 CR's three substantive section reshapes (§9 1c shrink for V5; §13 2d reshape per Candidate C for V9; §14/§15 2e/2f reshape for V8). The CR-drafting cycle is itself a Phase 59 trajectory event worth recording across all three: v0.2 (scoping-time compression caught at CR drafting); v0.3 (pre-flight execution caught at first CC attempt); v0.4 (Step 0 inspection findings absorbed via fresh-chat amendment cycle).
  1. Per-sub-arc implementation summaries. One subsection per sub-arc component (1a through 4a, including 2f [NEW v0.2]); for each: what shipped; tests added; any naming-only divergence from this CR absorbed in-flight; any architectural divergence that halted; how it was resolved. 2f-specific: record the AskOperatorForProcess name as-shipped (whether the CR's resolution held or CRV-7 surfaced a codebase-naming-family divergence); the per-candidate purpose-framing strings declaration layer as-shipped (extension to existing DetectionRule per v0.4 §15.3, or alternative); the 2d/2f composition check shape as-shipped (keyword-match against per-candidate purpose-framing strings, schema-check on declarative metadata, or LLM call).

[NEW v0.4] 1c-specific: record the persistence-call wiring as-shipped (where the append_event call lands in uploads.py; whether existing schema fields needed extension for the accompanying_message field per Sub-arc 2d; any field-level divergence from v0.4 §9.2 verification reference absorbed in-flight). [NEW v0.4] 2d-specific: record the accompanying_message field name as-shipped (whether v0.4's name held or CRV-8 surfaced a different OL composer convention); the wire-shape (placement on ExecutorResult vs. PerFileUploadResponse vs. both; persistence on UploadEventReceived); any need for OL composer-side wire-up that wasn't anticipated. [NEW v0.4] 2e-specific: record the classifier choice as-shipped (LLM call vs. embedding-based vs. heuristic refinement per v0.4 §14.3); the threshold value if changed from existing 0.6; the shape-extension placement (extending PurposeClassificationResult vs. new field on ExecutorResult).

  1. Stage 2 verdicts under build pressure. The v1-multi-pathway-collapses-inquiry-as-protocol's first-application evidence. Per scoping v0.2 §Stage 2 verdict (drift / standard scoping / accept), name what build pressure surfaced:
  1. Reserved-slot consumption. Each of slots 6–9 (per §21.2): consumed or unconsumed? If consumed, what amendment cycle drove the consumption; how the substrate-friction-discipline-pattern fired; what the resolution was.
  1. Methodology candidates for v0.21. The v0.21 consolidation slot per §24.2. Candidates to surface or sharpen:
  1. Phase 60 readiness check. Phase 59's engine-side contracts that Phase 60 will consume — list them; confirm each is in the expected shape per §24.1. v0.2 adds AskOperatorForProcess to the contract list.
  1. Close-protocol outcome. Refined close protocol's invocation at Step 5: refspec push results; branch deletions executed; Step 0 branch lifecycle outcomes; retroactive cleanup of any Phase 58 Step 0 branches that may have been present.
  1. Anything else worth recording for v0.42 manifest absorption.

25.2 Build-time discovery preservation

The Discovery-record discipline applies to implementation notes. Where build experience contradicts a scoping verdict, the notes preserve both — the prior verdict (scoping v0.2 position), the build-time finding (what surfaced), and the resolution (how the surface was reconciled). The same discipline applies to any reserved-slot consumption — the original v0.2 framing, the friction that surfaced, the amendment-cycle scoping outcome.

v0.2 added Move 5 as a recordable trajectory event itself. Implementation notes preserve: the v0.1 single-surface compression (confidence and purpose collapsed into the classifier confidence model); the v0.2 two-surface correction (P59-D4 covers confidence-disambiguation; P59-D11 adds purpose-disambiguation); the methodological lesson (the inquiry-as-protocol's vulnerability to scoping-time self-compression); and how build experience under v0.2's framing confirmed or refined the two-surface framing. This is the Phase 59-specific instance of the Discovery-record discipline applied to a CR-cycle event (not just a build-cycle event).

v0.3 adds the pre-flight-verification cycle as a recordable trajectory event itself. Implementation notes preserve: the v0.1 drafting handoff §2 stated assertions (phase-59-step-0 branch exists; ~2,146 tests); the v0.2 preservation of those assertions verbatim; CC's 2026-05-15 pre-flight halt-surface note + four divergences; v0.3's §4 restructure absorbing the corrections (branch from tag not main; Step 0 inline at pre-flight; ~2,400 baseline); and how Phase 59 build under v0.3's framing executed (Step 0 inspection brief V0–V11 outcomes; Step 0f Operator confirmation outcome; whether the build proceeded as expected or surfaced further corrections). The Discovery-record discipline now applies to three distinct cycle-types within Phase 59: build cycles, scoping-time CR cycles (Move 5), and pre-flight-time CR cycles (v0.3). Worth recording explicitly because the discipline previously applied predominantly to build trajectory; v0.2 extended it to CR-drafting trajectory (scoping-time); v0.3 extends it again to CR-drafting trajectory (pre-flight-time).

v0.4 adds the Step-0-execution-time CR cycle as a recordable trajectory event itself. Implementation notes preserve: CC's 2026-05-15 Step 0 execution outcomes (V0–V11 verdicts, with V5/V8/V9 surfacing material divergences); the Step 0 findings doc on phase-59-step-0 branch at 0d442ba as the evidence baseline; Step 0f Operator confirmation halt + Path 3 selection (v0.4 amendment cycle) + Candidate C + Option 2 absorption decisions; the v0.4 amendment-handoff document; the v0.4 fresh-chat scoping work that produced this CR; and how Phase 59 build under v0.4's reshaped framing executed (the 1c persistence-call wiring per §9; the 2d accompanying-message field per §13; the 2e classifier upgrade + shape extension per §14; the 2f routing-reshape + per-candidate framing per §15; their as-shipped capture per §25.1 item 2). The Discovery-record discipline now applies to four distinct cycle-types within Phase 59: build cycles, scoping-time CR cycles (Move 5; v0.2), pre-flight-time CR cycles (CC pre-flight halt; v0.3), and Step-0-execution-time CR cycles (CC Step 0 findings drove amendment cycle; v0.4). Worth recording explicitly because the discipline now spans the full phase-life arc — from scoping through CR drafting through pre-flight through Step 0 inspection through build — with CR amendment cycles available at any of those points without breaking phase coherence.

This makes implementation notes the input to v0.42 manifest absorption (Stage 2 verdicts; reserved-slot consumption; methodology candidates) and to v0.21 consolidation (the eight candidates above plus any surfaced).


Document trailer

DUNIN7 — Done In Seven LLC — Miami, Florida Phase 59 CR — Upload Pathway v1 completion — v0.4 — 2026-05-15 Supersedes v0.3, v0.2, v0.1 (all preserved alongside as superseded per re-draft handoff §6 + v0.3 amendment-record discipline + v0.4 amendment-handoff §6).