DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Archived (read-only)
Path phases/phase-59-upload-pathway-completion/archive/phase-59-cr-upload-pathway-completion-v0_2.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.2 Date. 2026-05-14 Status. Drafted; awaiting Operator approval. Supersedes v0.1. Pre-flight Step 0 already run (unchanged from v0.1; V0–V11 evidence baseline holds); CC consumes this CR plus phase-59-step-0-findings-v0_1.md as the evidence baseline. Author. Claude.ai (CR re-drafter) on direction from Marvin Percival (DUNIN7 Operator). Companion documents.

Amendment record (v0.2; pre-execution). v0.2 absorbs 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 separates them: P59-D4 covers confidence-disambiguation only; new P59-D11 covers purpose-disambiguation. v0.2 of this CR carries the separation through: §3 expands to eleven P59-D rows; §14 sharpens its title and framing to confidence-disambiguation; new §15 (Sub-arc 2f) carries purpose-disambiguation; downstream sections renumber by +1; §19–§25 absorb test-count widening, halt-condition additions, acceptance-gate items, carry-forward additions, and methodology-candidate additions. The v0.1 CR is preserved alongside as superseded. Methodologically: v0.2 is 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. Phase 59 build runs against v0.2 of both scoping note and CR.


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 | Narration shaping. Multi-pathway restore; narration consumes both extraction result and accompanying Operator message. Empty accompanying-message path falls back to current isolation behavior — multi-pathway is additive. | Scoping v0.1 §Stage 2.2; drift verdict (restore multi-pathway) | | 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

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/. The Step 0 inspection brief (loomworks-phase-59-step-0-inspection-brief-v0_1.md) specified eleven verifications V0 through V11 covering: Phase 58 close baseline + Step 0 branch lifecycle accounting (V0); transformation skills enumeration (V1); image-skill dispatch precedence (V2 — settles P59-D6); ObjectStore put_blob method state (V3); credential-store abstraction state (V4); UploadEventReceived event class state (V5); rate-limit middleware state (V6); streaming-upload state (V7); detection registry state + classifier confidence model (V8); Companion narration current shape (V9); content-reliability surface absence (V10); CR §7.4 fallback affordance endpoint absence (V11).

This CR consumes the findings as evidence baseline. CC does not re-run Step 0 verifications V0 through V11; the build steps below cite Step 0 evidence by verification number where the implementation depends on a Step 0 finding. v0.2 adds no new Step 0 verifications — Sub-arc 2f consumes the same detection-registry dispatch surface V8 already covered. Per scoping v0.2 §Companion artifacts: "the existing evidence baseline holds; v0.2's additions don't require new Step 0 verifications (2f consumes the same detection-registry dispatch surface V8 already covered)."

Pre-flight (CR-execution time). Before Step 1 begins, CC archives this CR at engine repo docs/phase-crs/phase-59-cr-upload-pathway-completion-v0_2.md (preserves phase-59-cr-upload-pathway-completion-v0_1.md alongside as superseded per re-draft handoff §6 preservation principle). CC then runs a small CR-execution-time read confirming the substrate baseline hasn't shifted since Step 0 closure:

  1. CR registry. Confirm CR-2026-XXX (this CR's number) is the next available against engine repo docs/phase-crs/ directory listing; advance the number if taken. v0.2 note: if the v0.1 CR's number was already claimed at v0.1 archival, v0.2 reuses the same number (versioned filename, not re-numbered CR). If the v0.1 number was not claimed (e.g., v0.1 never reached archival), v0.2 takes the next available. CC consults engine repo docs/phase-crs/ for the v0.1 archival state.
  2. Baseline tag check. Confirm engine tag phase-58-upload-pathway still resolves at the commit Step 0 V0 recorded.
  3. Test-count baseline. Re-run .venv/bin/pytest -q against the engine repo's main branch; confirm count is within ±2 of the Step 0 V0 figure (allowing for any post-tag docs-on-main commits).
  4. Alembic head. Confirm 0064 still holds.
  5. Build branch creation. Create branch phase-59-upload-pathway-completion from main on engine repo. No OL branch — Phase 59 is engine-only per scoping v0.2.

If pre-flight reveals any drift greater than minor (e.g., test counts off by more than ±2; tag missing; Alembic head shifted), CC halts and surfaces; the CR re-drafter (Claude.ai) consumes the drift into a v0.3 of this CR rather than CC absorbing silently.


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 Memory event class (Sub-arc 1c)

9.1 What 1c delivers

A new typed MemoryObject subclass upload_event_received capturing the "an upload happened" Memory event Phase 58 deferred persisting. Schema, _ANCHOR_PRIORITY entry, no Alembic migration per the typed-MemoryObject-without-migration pattern (Phase 50/52/53 precedent inherited per P59-D7).

9.2 Schema

The UploadEventReceived class lives alongside recent typed MemoryObject classes per the Phase 50/52/53 placement convention (CC reads CRV-4 at execution time to identify the convention's current shape; locates the recent additions and matches their pattern). Schema fields:

9.3 _ANCHOR_PRIORITY entry

CC adds "upload_event_received": "standard" to the _ANCHOR_PRIORITY dict per CRV-3 (read at execution time per Phase 53 V7 evidence at events.py:112–130; placement convention follows whatever ordering the existing entries use — alphabetical, insertion-order, or grouped-by-domain). The "standard" priority value mirrors 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. The Phase 50/52/53 precedent: OBJECT_TYPE_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). The deferral preserves the typed-MemoryObject-without-migration pattern.

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.

Halt condition. If the event class's storage requirements force a schema change (e.g., a field type not representable in the existing content column), CC halts per §22. The pattern fails to compose; scoping v0.2 absorbs and Alembic head advances.

9.6 Step 0 evidence consumed

9.7 Acceptance for 1c


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. Narration multi-pathway restore (Sub-arc 2d)

13.1 What 2d delivers

The Companion narration of uploaded files restored to multi-pathway behavior. Phase 58 shipped narration in content-isolation mode (extraction result only). Sub-arc 2d restores the multi-pathway: narration consumes both the extraction result AND any accompanying Operator message that arrived with the upload. Empty accompanying-message path falls back to the current isolation behavior — multi-pathway is additive; the existing single-input shape is preserved as the empty-message degenerate case.

13.2 The framing per scoping v0.1 §Stage 2.2

Drift verdict (restore multi-pathway). Phase 58 collapsed narration to single-input because the upload pathway didn't yet thread accompanying messages through to the narration composer. The collapse was drift, not deliberate; restoring the multi-pathway recovers the design intent that the Companion's narration of an upload engages with the Operator's context for the upload, not just the artifact in isolation.

13.3 Substrate-level work

Per CRV-8 (read at execution time): the narration composition function lives engine-side (Step 0 V9 confirms HOLDS — narration takes extraction result only; no accompanying-message input). CC reads the composition function signature and identifies the addition point for the accompanying-message input.

The prompt template revision lives at src/loomworks/prompts/ (Phase 53 precedent for prompt-template placement; CC confirms exact path at execution per CRV-8). The revision adds an optional accompanying_message field to the template's input schema. When present, the message shapes the narration's focus — the Companion responds to both the artifact and the Operator's framing of why they uploaded it. When absent, the narration runs in the current single-input shape.

13.4 OL converse view shape preservation

A halt condition surfaces if the narration's output shape (the data the OL converse view consumes) needs to change to accommodate multi-pathway. The scoping note's envelope premise is that Phase 59 ships engine-only — any OL-side shape change defeats the envelope. If the output shape change is unavoidable, CC halts per §22; scoping v0.2 (or v0.3) absorbs the wider surface or splits Sub-arc (ii) across phases.

The expected case: the output shape stays the same. The narration prompt template changes its input; the output's narration text remains the same kind of text. OL converse view reads whatever the narration produces without caring whether the narration came from one-input or two-input composition.

13.5 Step 0 evidence consumed

13.6 Acceptance for 2d


13.7 Composition with Sub-arc 2f (purpose-disambiguation pre-emption) [NEW v0.2]

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).

Implementation: a disambiguation-check helper between detection and dispatch; the helper consults the accompanying message via the existing 2d input pathway. The check shape — keyword matching, schema check, or LLM call — lands at execution time per the existing 2d composition function's posture; CC selects the lower-friction path consistent with 2d's accompanying-message consumption (§13.3). If the check requires an LLM call and the LLM-call posture wasn't decided at scoping, CC halts per §22 — re-draft 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)

14.1 What 2e delivers

The detection registry's dispatch (per Step 0 V8 — single-skill commit today; no confidence output) extended with a confidence model. The dispatch returns a confidence score alongside the selected skill. Confidence below a threshold triggers a re-dispatch path that surfaces an "ask Operator to clarify" affordance.

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

Per CRV-7 (read at execution time): the detection registry's dispatch method signature. Sub-arc 2e extends the signature to return (SkillReference, confidence: float) rather than just SkillReference. The confidence score's range is 0.0 to 1.0; values close to 1.0 indicate high confidence in the dispatch (e.g., a .docx file matched to docx_extraction via MIME type — strong signal); values close to 0.5 or lower indicate uncertainty (e.g., an unknown content type matched only by a fallback heuristic).

The threshold value: CC selects at execution per defensible-default heuristics. A reasonable starting threshold is 0.7 — above it, dispatch proceeds; below it, the re-dispatch path engages. The threshold value documents in implementation notes for future-phase calibration.

The re-dispatch path: when confidence is below threshold, the dispatch returns an AskOperatorToClarify shape (a typed object describing the candidate skills and their confidence scores). The upload endpoint catches this shape and returns it in its response. Phase 60's OL surface consumes the response and renders the clarification affordance.

Composition with 2f (§15) at the substrate level. Per §15.3: 2f extends the same dispatch to support "return all candidates above threshold" semantics for the multi-valid case. The dispatch evolves to support both 2e's "best candidate with confidence" semantics and 2f's "all candidates above threshold" semantics — either one fires per upload, depending on the candidate landscape. CC implements both extensions in Sub-arc 2 build sequence (Step 2); ordering within the step lands at execution time. If the two semantics can't compose cleanly in the dispatch surface — e.g., the schema can't represent both result shapes — CC halts per §22.2.

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


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

15.1 What 2f delivers

Engine-side detection-time check: when the detection registry surfaces multiple registered skills matching the upload's content type at confidence above the P59-D4 threshold, the engine produces an 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 at the OL surface (Phase 60 renders).

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). Each fires at high confidence on its own — the engine isn't uncertain in the classification-accuracy sense (the 2e surface). The choice between them is the Operator's purpose: "transcribe text" or "describe content"? The engine asks; the Operator answers; dispatch proceeds.

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

Per CRV-7 (read at execution time): the detection registry's dispatch surface. 2f extends the dispatch to support "return all candidates above threshold" semantics alongside the existing "return best candidate" semantics that 2e (§14.3) provides. The two extensions compose in the same dispatch method — either result shape fires per upload depending on the candidate landscape:

The per-candidate purpose-framing strings live at the skill-registration layer (each transformation skill declares its purpose-framing at registration: e.g., image_vision_analysis declares "describe what's in the image"; image_ocr declares "transcribe the text in the image"). The declaration shape: CC selects at execution time per the existing skill-registration interface; the framing is a single short string per skill, surfaced through the registry-query path. If the existing skill-registration interface doesn't accept declarative metadata of this shape — e.g., it's a simple register(skill_name, skill_class) call with no metadata slot — CC halts per §22; re-draft handoff §7 names this as a halt-and-escalate signal.

The detection-time check fires after the dispatch returns; if multiple candidates are present 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_string, 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).

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.2) 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


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

Per CR drafting handoff §7 and scoping v0.2 §Test surface estimate, total new engine tests in the range ~26–41 always-run (v0.2 widens from v0.1's ~23–37 by +3–4 for Sub-arc 2f tests):

| Sub-arc | Component | Estimate | |---------|-----------|----------| | (i) | 1a credential-store consolidation | 1–2 | | (i) | 1b ObjectStore put_blob end-to-end | 2–3 | | (i) | 1c UploadEventReceived event class | 3–4 | | (i) | 1d rate-limit middleware | 2 | | (i) | 1e streaming-upload | 2–3 | | (ii) wiring | 2a/2b/2c API-key resolution | 3–6 | | (ii) wiring | 2d narration multi-pathway | 3 | | (ii) wiring | 2e classifier confidence model (confidence-disambiguation) | 3 | | (ii) wiring | 2f multi-valid-prompt-for-process (purpose-disambiguation) [NEW v0.2] | 3–5 | | (ii) quality | 3a OCR threshold model | 2–3 | | (ii) quality | 3b OCR class-aware parameters | 2–3 | | (ii) quality | 3c content-reliability warning surface | 3–4 | | (iii) engine | 4a fallback affordance endpoint | 3–5 |

Estimate range: 32–46 tests across the sub-arcs; the lower bound of the scoping note v0.2's 26–41 reflects natural absorption where components share test infrastructure (e.g., 2a/2b/2c may share fixtures; 2e/2f may share dispatch-surface fixtures; 3a/3b share the OCR fixture pipeline). The upper bound assumes minimal sharing.

Post-Phase-59 target: existing baseline (~2,146 always-run + 26 skipped per Phase 58 close) + ~26–41 new = ~2,172–2,187 always-run + 26+ skipped. (v0.2 widens from v0.1's ~2,169–2,183 by +3–4.)

20.2 Test grouping by build step

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 + build branch creation. CC archives this CR to engine repo docs/phase-crs/phase-59-cr-upload-pathway-completion-v0_2.md (preserves phase-59-cr-upload-pathway-completion-v0_1.md alongside as superseded per re-draft handoff §6 preservation principle). Runs the pre-flight reads per §4 (baseline tag check; test-count baseline; Alembic head; CR-registry confirmation). Creates branch phase-59-upload-pathway-completion from main on engine repo. (No OL branch — Phase 59 is engine-only per scoping v0.2.) Estimated wall-time: ~10 min.

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

The three-checkpoint structure follows the CR drafting handoff §6 — distinct from scoping v0.2 §Stage 3's two-checkpoint framing. 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.

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 1 halt conditions

22.2 Step 2 halt conditions

22.3 Step 3 halt conditions

22.4 Step 4 halt conditions

22.5 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); existing ~2,146 stay green; 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) 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 (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. The CR-drafting cycle is itself a Phase 59 trajectory event worth recording.
  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 (skill-registration vs. wherever); the 2d/2f composition check shape as-shipped (keyword-match, schema-check, or LLM call).
  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 adds 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) — worth recording explicitly because the discipline previously applied predominantly to build trajectory; v0.2 extends it to CR-drafting trajectory.

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 six candidates above plus any surfaced).


Document trailer

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