DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path phases/phase-53-discovery-to-seed-skill/phase-53-cr-discovery-to-seed-skill-v0_1.md

DUNIN7-M4 — INFRASTRUCTURE CHANGE REQUEST

CR-2026-068 — Phase 53: Discovery-to-Seed Skill (v0.1)

Version. v0.1 Date. 2026-05-10 Author. Claude (drafting) / Marvin Percival (approving). Target. /Users/dunin7/loomworks-engine on DUNIN7-M4 (MacMini M4). No work in loomworks (Operator Layer) or loomworks-marketing repos by default. Baseline reference. Tag phase-52-jurisdiction-routing:

Phase 52 close per Step 0 findings: 2,137 substrate tests passed, 25 skipped, Alembic head 0064_phase_49_persons_columns_and_thresholds.py, working tree clean (engine); 139 vitest passed, 11 prerendered routes, eslint/tsc/build clean (Operator Layer, unchanged from Phase 50 baseline per Phase 51 V7 / Phase 52 P52-D4).

Priority. Standard. Confidential. Internal DUNIN7. Supersedes. No prior Phase 53 CR — v0.1 is the first. CR number. CR-2026-068 is the expected value if Phase 52 was CR-2026-067. [CC verifies at Step 0 pre-flight item 1] against engine repo docs/phase-crs/ directory listing; advance if taken. Companion to. loomworks-phase-53-scoping-note-v0_2.md (authoritative scope; absorbs Step 0 findings); loomworks-phase-53-cr-drafting-handoff-v0_1.md (drafting instructions for this CR); phase-53-step-0-findings-v0_1.md (engine repo docs/phase-impl-notes/; verified live-codebase state, absorbed into scoping v0.2 with one open FORAY question settled by this CR as P53-D12); phase-52-cr-jurisdiction-routing-v0_1.md (structural template); phase-50-cr-companion-as-authority-and-public-form-v0_1.md §10 (Memory event registration parallel); phase-31-cr-conversational-engagement-creation-v0_1.md (prompt template convention; Phase 31 backward-compat baseline); Phase 25 CR + Phase 25 FORAY amendment (induct_seed invocation pattern; _ANCHOR_PRIORITY seed-family precedent); Phase 16 CR + Phase 16 addendum (upload pipeline; _ACCEPTED extension point); current-status-manifest-v0_37.md. Status. Pre-execution CR. Ready for Operator review and approval. Step 0 pre-flight runs against this version.


Contents


1. Executive summary

Phase 53 opens the engagement creation arc — the second of the two architectural arcs left open after the credit / form-flow / marketing arc reached natural stabilization at Phase 52. The arc itself spans multiple phases; Phase 53 lays the foundational substrate so subsequent phases can build the Discovery-assistance product surface (queued directions §1.1), the Operator Layer integration, and ultimately the deferred Phase 32 marketing engagement on top. Phase 53 kickoff posture mirrors Phase 47 in the credit arc: open the arc with the load-bearing substrate primitive, defer the surface and methodology consolidation to subsequent phases.

Sub-arc 1 — Substrate (engine). Phase 53 lands the Discovery-to-seed skill as the engagement creation arc's foundational primitive — an LLM-assisted bounded transformation that takes a Discovery document landed in Memory via Phase 16's upload pipeline and produces a structured candidate Seed conforming to R-A5–R-A11. Four substantive surfaces ship together as sub-arc 1:

Sub-arc 2 — Operator Layer. Empty by default per P53-D4. Phase 51 V7 and Phase 52 P52-D4 precedent. The Operator Layer's existing Phase 31 conversational creation surface (five engagement-scoped endpoints per V5; produces a string brief, does NOT call induct_seed) remains unchanged. Phase 54+ may add an Operator Layer surface that exposes the Discovery-to-seed skill once the Discovery-assistance arc (queued directions §1.1) defines the upstream surface.

Sub-arc 3 — Marketing site. Empty. Phase 53 doesn't touch the marketing repo.

By the close of Phase 53, the Operator can upload a Markdown Discovery document to an engagement, invoke the Discovery-to-seed endpoint, and receive a candidate Seed that flows through the Phase 25 induction loop unchanged. The skill produces seeds from heterogeneous Discovery shapes via LLM-assisted bounded contract (P53-D1) — V8's evidence of 6+ organizing schemes across project-knowledge Discovery records made purely-declarative extraction architecturally unsuitable.

Tag at completion: phase-53-discovery-to-seed-skill on engine repo only.

Build-time estimate: 2–2.5 hours total (substrate sub-arc 1 only). Test count delta: ~20–30 over the Phase 52 close baseline of 2,137. No Alembic migration. Per V7's typed-MemoryObject-without-migration pattern.


2. In-scope and out-of-scope

2.1 In-scope

Per scoping note v0.2 §3, fully transposed:

2.2 Out-of-scope (per scoping v0.2 §4 / handoff §6)

These items are explicitly deferred to Phase 54+ inside the engagement creation arc, deferred-pending-trigger, or out of Phase 53 entirely:

2.3 No voice content shipping

Phase 53 ships no Companion-rendered prose. The skill produces a structured Seed; the Memory event records a substrate fact; no voice surface. The CR has no §7-equivalent voice-template section. Same posture as Phase 52 §2.3.


3. Prerequisites

3.1 Baseline at Phase 53 Step 0

If the baseline diverges (substrate test count off by more than ±2 routine noise, Alembic head different, working tree dirty, tag missing on engine, marketing site not live), CC stops at the start of Step 0 and reports before running any pre-flight items.

3.2 Step 0 verifications absorbed in scoping v0.2

The scoping note v0.2 absorbed ten verifications run by CC against the live codebase, recorded in phase-53-step-0-findings-v0_1.md at engine repo docs/phase-impl-notes/. Consolidated state per the brief's framework: State 2 — one BREAKS plus enumeration findings; v0.2 is the architectural-amendment absorption. The CR proceeds against v0.2 with P53-D12 settling the FORAY question that v0.2 left open between its §3.5 schema framing and §6 V7 row.

| # | Verification | Verdict | Where absorbed | |---|--------------|---------|----------------| | V1 | ExtractionSkill family location, protocol, registration call-sites | HOLDS | scoping v0.2 §3 V1; §4 P53-D3 confirms candidate (i); §5.1, §5.2 | | V2 | Materializer registry identity | HOLDS as distinct surface | scoping v0.2 §3 V2; §4 P53-D3 narrows by elimination (retires candidate (iii)) | | V3 | Phase 38 declare-and-register pattern | HOLDS as sibling-but-distinct | scoping v0.2 §3 V3; §4 P53-D3 narrows by elimination (retires candidate (ii)-via-grammar) | | V4 | Seed schema + R-A5–R-A11 mapping | HOLDS with naming-only divergence | scoping v0.2 §3 V4; §4 P53-D5 sharpened; §3.2 / §11 schema | | V5 | Phase 31 conversational creation surface | HOLDS with minor drift + functional gap | scoping v0.2 §3 V5; §4 P53-D5 sharpened; §4 P53-D11 new; §3.7 backward-compat tests | | V6 | Phase 16 upload pipeline (Markdown) | BREAKS | scoping v0.2 §3 V6; §4 P53-D6 amended; §3.1 amendment slice | | V7 | Memory event registration pattern (Phase 50/52) | HOLDS with minor convention drift | scoping v0.2 §3 V7; §4 P53-D9 confirmed; v0.2 noted open FORAY question — settled at this CR by P53-D12 | | V8 | Discovery records as test fixture inventory | PARTIALLY HOLDS | scoping v0.2 §3 V8; §4 P53-D1 validated; §3.7 test fixtures tightened | | V9 | FORAY attestation seam | HOLDS | scoping v0.2 §3 V9; §10 schema; P53-D12 settles _ANCHOR_PRIORITY entry per V9 mechanics | | V10 | Endpoint surface naming convention | HOLDS via in-convention | scoping v0.2 §3 V10; §4 P53-D10 new (settles /seed/extract) |

These ten verifications are not re-run at CR-execution time. The pre-flight Step 0 list in §3.3 covers CR-time deltas — exact strings, line numbers, module paths that the CR drafter specified against Step 0 evidence but where placement decisions or convention-fit questions remain.

3.3 Pre-flight Step 0 (CR-time)

Before Step 1 begins, CC archives this CR at docs/phase-crs/phase-53-cr-discovery-to-seed-skill-v0_1.md in the engine repo and runs the following pre-flight reads. Step 0 findings absorbed most exact-string verifications; this pre-flight list covers the few remaining placement / convention-fit confirmations.

  1. CR registry. Confirm CR-2026-068 is the next available CR number against engine repo docs/phase-crs/ directory listing; advance if taken.
  1. _ACCEPTED exact line and adjacent test coverage. Per V6 evidence: _ACCEPTED = _ACCEPTED_AUDIO | _ACCEPTED_PDF | _ACCEPTED_IMAGE at src/loomworks/api/routers/files.py:102. Confirm the union expression line and locate any existing test that validates accepted / rejected types (likely in tests/test_phase_16_*.py) so §7's amendment to _ACCEPTED and the test addition at §17 land cleanly. If existing tests parametrize over _ACCEPTED, the new text/markdown member needs no further test scaffolding; if they enumerate explicitly, §17's smoke test adds the member.
  1. New skill module placement convention. v0.2 §3.2 sketches src/loomworks/skills/discovery_to_seed.py; V1 confirmed the skills directory is src/loomworks/skills/ containing __init__.py, image_description.py, pdf_extraction.py, registry.py, transcription.py. Confirm the new module lands as a sibling at the same level (no subdirectory needed) and the naming convention (snake_case, no _skill suffix per V1's sibling listing).
  1. New prompt template module placement convention. v0.2 §3.2 sketches src/loomworks/prompts/discovery_to_seed_extraction.py. V5 confirmed Phase 31's template at src/loomworks/prompts/creation_conversation.py (with PROMPT_VERSION = "1.0", CONVERSATION_MODEL = "claude-sonnet-4-6", CREATION_CONVERSATION_PROMPT, __all__ exports per lines 21, 23, 26, 200–203). Confirm the prompts directory layout and the convention (module-level constants exported via __all__).
  1. Skill registration insertion point. Per V1 evidence: build_default_registry() at src/loomworks/skills/registry.py:165–195, with three registration calls at lines 177, 183, 189. §9's new fourth registration lands as a sibling — confirm the insertion site (ordering convention: by Content-Type family alphabetically, or by introduction order, or some other ordering; the CR specifies one but [CC verifies] against the existing call ordering).
  1. _ANCHOR_PRIORITY insertion point + seed-family proximity. Per V7 evidence: _ANCHOR_PRIORITY dict at src/loomworks/memory/events.py:112–130 with 14 current entries including seed_drafted, seed_amended, finding_produced, finding_addressed, induction_cycle_recorded. §10's new entry "discovery_to_seed_extracted": "standard" lands alongside the seed-family per P53-D12. Confirm the exact placement convention (insertion order: by phase, by family, alphabetical, or otherwise) so §10's amendment respects local ordering.
  1. Memory event module placement. Phase 50 used src/loomworks/credit/grant_request.py and Phase 52 used src/loomworks/credit/jurisdiction_routing.py per V7 evidence — both credit-family events. Phase 53's discovery_to_seed_extracted is a seed-family event, not credit-family. Confirm placement convention: natural location is src/loomworks/engagement/discovery_to_seed.py (a new engagement-family file co-located with src/loomworks/engagement/creation.py which hosts draft_seed and induct_seed) or potentially in src/loomworks/skills/discovery_to_seed.py (co-located with the skill itself, though this mixes substrate concerns). Pre-flight selects placement; CR's §10 specifies loomworks/engagement/discovery_to_seed.py as default with [CC verifies at Step 0 pre-flight item 7] for the engagement-family placement question.
  1. New /seed/extract route placement. Per V10 evidence: 10 /seed* routes across 3 modules — engagements.py (5 routes: 215, 297, 343, 425, 822), seed_view.py (1 route: 34), seed_conversation.py (5 routes: 491, 813, 857, 877, 938). The closest sibling for /seed/extract is /seed/induct at engagements.py:343 (verb-aligned, lifecycle-action, post-seed-creation). Pre-flight confirms placement: extend engagements.py with the new route (default) or create new module src/loomworks/api/routers/seed_extraction.py if scope of orchestration warrants separation.
  1. induct_seed exact signature and call shape. Per V5 evidence: defined at src/loomworks/engagement/creation.py:409 (async def induct_seed(...)); two production callers at src/loomworks/engagement/seed_amendment.py:133 (outcome = await induct_seed(...)) and src/loomworks/api/routers/engagements.py:361 (same shape). §11 specifies the third invocation against verbatim sibling pattern — CC reads the full signature and one or both call shapes so the endpoint's hand-off lands exact.
  1. compute_content_hash exact import and _foray injection alignment. Per V9 evidence: compute_content_hash at src/loomworks/memory/events.py:133–145; _foray injection at events.py:209–220; columns at 102–104 (content_hash, attestation, foray_tx_ref). §10 specifies discovery_to_seed_extracted carries the full _foray namespace per P53-D12; CC confirms the append_event(event_kind="discovery_to_seed_extracted", payload=...) call site automatically picks up the _ANCHOR_PRIORITY entry and injects _foray per the existing mechanism. No new FORAY plumbing needed.
  1. LLM client / key resolution convention. §8 specifies a system-level key via system_config (mirroring V5's Phase 31 evidence — migrations/versions/0048_phase_31_system_config.py schema; helpers in src/loomworks/system_config/store.py:71,124,150). Confirm the canonical key name to use for the extraction model's API key — likely anthropic_api_key or a parallel new key — against existing system_config rows. If a new key is needed, §8 adds a row insertion via the existing set_system_config helper at deploy time; not via Alembic migration.

If any of items 1–11 reveal architectural divergence (not just naming or exact-string placement), CC halts and surfaces — does not draft and hope. Naming-only divergences absorb in-flight per the standard discipline.

3.4 CR archival

Archive this CR at:


/Users/dunin7/loomworks-engine/docs/phase-crs/phase-53-cr-discovery-to-seed-skill-v0_1.md

before Step 1 begins. Per Phase 47 / 48 / 49 / 50 / 51 / 52 standard pattern.


4. Construction decisions this CR closes

Twelve decisions settled in scoping note v0.2 §5 plus P53-D12 settled at this CR (the FORAY question v0.2 left open between its §3.5 schema framing and §6 V7 row). CC executes against them; does not re-decide. No decisions remain [Operator confirms] at CR-execution time.

P53-D1. LLM-assisted bounded skill. Per V8 evidence (~12 Discovery records across 6+ distinct organizing schemes — Decision-list, Thread-list, Numbered-position, Field-list R-A-aligned, Discovery-trajectory, Programme-shaped). Purely-declarative extraction would over-fit to one scheme; the LLM does real interpretation work to map heterogeneous Discovery shapes onto R-A5–R-A11. The discipline is bounded contract, not no LLM. Single-shot LLM call wrapped by strict input/output contract: no conversation, no multi-turn, no retry-on-clarification.

P53-D2. Free-form Markdown Discovery documents with recognized section headers (path (a)). Phase 53 consumes the kind of Discovery records already produced in chat. Phase 54+ may add a structured Memory-shape Discovery input (path (b)) as an alternative; not Phase 53 scope.

P53-D3. Skill registers in ExtractionSkillRegistry at src/loomworks/skills/registry.py (V1 confirmed location). Settled by elimination: V2 retired the materializer-registry candidate (render-output-side, distinct surface); V3 retired GRAMMAR_REGISTRY (shape-declarative not callable, raises on duplicate). The skill conforms to the ExtractionSkill Protocol exactly as V1 confirmed; registration adds a fourth entry in build_default_registry() alongside the three existing (audio, PDF, image).

P53-D4. Operator Layer sub-arc 2 empty by default. Per Phase 51 V7 / Phase 52 P52-D4 precedent. The Operator Layer's existing Phase 31 conversational creation surface (5 engagement-scoped endpoints per V5) remains unchanged. Phase 54+ may add an Operator Layer surface that exposes the Discovery-to-seed skill.

P53-D5. Phase 31 and Phase 53 coexist as truly distinct paths. V4 + V5 revealed deeper divergence than v0.1 anticipated: Phase 31 produces a string brief (stored on companion_turn events at seed_conversation.py:468, 842, 850); Phase 53 produces a structured Seed payload directly. Phase 31 does NOT call induct_seed (V5 confirmed only 2 production callers, neither in seed_conversation.py); Phase 53 does (becomes the third caller). They share the /engagements/{eid}/seed/* URL family (V10) but produce different artifacts and follow different downstream pipelines. Coexistence holds.

P53-D6. Phase 16 upload-pipeline as Discovery-document Memory location, via additive text/markdown MIME-type extension. V6 BREAKS: _ACCEPTED (at files.py:102) does NOT currently include text/markdown; Markdown uploads 415-reject at the upload boundary. Smallest-amendment path per V6 implication option (1): extend _ACCEPTED to include text/markdown; UTF-8 text-decoding happens inside the skill body. No rebuild of Phase 16's pipeline; no breaking change to existing uploaders. The alternative (V6 option (2) — Discovery-record-as-Memory-shape upstream substrate) is held for Phase 54+.

P53-D7. Tag name: phase-53-discovery-to-seed-skill on engine repo only. No tags on Operator Layer or marketing repos by default — Phase 53 has no work in those repos. If sub-arc 2 lands actual work via Phase 54 surface design lifting forward, marker tag follows Phase 51 V7 precedent (Operator Layer tag lands on the Phase 51 commit as a marker).

P53-D8. Engagement creation arc as explicit multi-phase trajectory. Phase 53 = kickoff (substrate primitive). Phase 54+ candidates listed in §18: Discovery-assistance flow (queued directions §1.1); Discovery-trajectory + Discovery-record specialists; Operator Layer engagement-creation surface; Phase 31 induct-seed gap clarification (P53-D11); Phase 31/53 unification or deprecation; eventual Phase 32 marketing engagement. Each phase scoped independently when it opens; arc framing in scoping language only, not commitment.

P53-D9. Memory event kind: discovery_to_seed_extracted. Typed MemoryObject subclass; Literal["discovery_to_seed_extracted"] object_type; schema per §10.3. Mirrors Phase 25's seed-family naming and structural pattern. OBJECT_TYPE_REGISTRY entry deferred per Phase 50/52 precedent (V7) — substrate event functions without explicit registration; Phase 54+ adds when downstream consumers need deserialize_memory_object("discovery_to_seed_extracted", payload). For the FORAY question, see P53-D12 below.

P53-D10. Endpoint name: POST /engagements/{eid}/seed/extract. Per V10's tighter-alternative recommendation. The endpoint is an ExtractionSkill invocation surface; the URL reflects the family. Verb-aligned with /seed/induct per V10's lifecycle-action convention. Engagement-scoped per V10's universal /seed* family pattern (10 routes enumerated, all engagement-scoped, no system-scoped sibling family).

P53-D11. Phase 31 induct-seed gap deferred to Phase 54+ for Operator clarification. V5 found Phase 31 produces a seed_document: str brief stored on companion_turn events and does NOT call induct_seed; entering the Phase 25 induction loop from Phase 31 currently requires a separate Phase 25 amend step (the Operator extracts structured fields from the brief and POSTs to /engagements/{eid}/seed). Whether this is deliberate design (string-brief flow is its own completion path) or incompleteness (Phase 31 should call induct_seed but doesn't) is not a Phase 53 question. Phase 53 carry-forward records the open question; no Phase 31 amendment in Phase 53.

P53-D12. discovery_to_seed_extracted added to _ANCHOR_PRIORITY at priority "standard". Settled at this CR; not in v0.2. The scoping note v0.2 left an internal mechanical contradiction between its §3.5 schema framing ("_foray namespace + content_hash (per V9 canonical pattern)") and its §6 V7 row ("Defer OBJECT_TYPE_REGISTRY + _ANCHOR_PRIORITY per Phase 50/52"). Per V9 evidence (events.py:209–220), _foray is injected into the event payload only when _ANCHOR_PRIORITY.get(event_kind) is not None. The two readings are mechanically irreconcilable: either Phase 53 mirrors Phase 50/52 (defer entry, no _foray namespace, just column-level content_hash) or it mirrors Phase 25's seed-family (seed_drafted, seed_amended already in _ANCHOR_PRIORITY per V7 — entry present, full _foray namespace injection). Settled: mirror Phase 25's seed-family. discovery_to_seed_extracted is a seed-lineage event the way seed_drafted and seed_amended are, not an authority/credit event the way grant_request_received and jurisdiction_routing_decided are. The §3.5 schema framing is the operative commitment; the §6 V7 row's "Phase 50/52 precedent" framing pattern-matched on the wrong cousin (V7 findings flagged exactly this). Add "discovery_to_seed_extracted": "standard" to _ANCHOR_PRIORITY at events.py:112–130. OBJECT_TYPE_REGISTRY remains deferred separately per P53-D9 (those are independent registrations per V7's clarification).


5. Migration

No Alembic migration. Per V7 evidence: Phase 50 and Phase 52 both added typed MemoryObject subclasses (with Literal[...] object_type and field definitions) without introducing a migration. The substrate's memory_events table already carries content_hash, attestation, foray_tx_ref columns per V9 evidence at src/loomworks/memory/events.py:102–104. Phase 53's discovery_to_seed_extracted event lands in the same column shape.

Alembic head remains 0064_phase_49_persons_columns_and_thresholds.py at Phase 53 close.

P53-D12's _ANCHOR_PRIORITY entry is a code-only addition to a module-level dict at events.py:112–130; no schema implications.

The system_config row for the LLM API key (if needed per §8 / pre-flight item 11) is a row insertion via the existing set_system_config helper, not a migration.


6. Backend modules and changes (sub-arc 1)

High-level summary; full specs in §§7–11. All changes in DUNIN7/loomworks-engine only.

| # | What | Path | Per §§ | |---|------|------|--------| | 1 | Phase 16 _ACCEPTED MIME-type extension (additive) | src/loomworks/api/routers/files.py:102 | §7 | | 2 | Discovery-to-seed skill module (new) | src/loomworks/skills/discovery_to_seed.py | §8 | | 3 | Prompt template module (new) | src/loomworks/prompts/discovery_to_seed_extraction.py | §8 | | 4 | Skill registration in build_default_registry() | src/loomworks/skills/registry.py:165–195 | §9 | | 5 | discovery_to_seed_extracted Memory event class (new) | src/loomworks/engagement/discovery_to_seed.py [CC verifies placement at Step 0 pre-flight item 7] | §10 | | 6 | _ANCHOR_PRIORITY entry addition | src/loomworks/memory/events.py:112–130 | §10.4 | | 7 | POST /engagements/{eid}/seed/extract endpoint | src/loomworks/api/routers/engagements.py [CC verifies placement at Step 0 pre-flight item 8] | §11 |

No Operator Layer changes (§12). No marketing repo changes (§13).


7. Phase 16 _ACCEPTED MIME-type extension

7.1 What

Extend _ACCEPTED at src/loomworks/api/routers/files.py:102 to include text/markdown. Single-line additive change per P53-D6 / V6.

7.2 Current state per V6 evidence

V6 enumerated the current accepted-set composition:

text/markdown, text/plain, text/x-markdown are NOT in _ACCEPTED. Markdown Discovery uploads via POST /engagements/{engagement_id}/files currently 415-reject at the upload boundary.

7.3 Amendment

Two approaches — naming-only choice for the CR drafter; CC selects at Step 1 per local convention:

Option (i) — Extend the union directly.


# src/loomworks/api/routers/files.py:102 — current
_ACCEPTED = _ACCEPTED_AUDIO | _ACCEPTED_PDF | _ACCEPTED_IMAGE

# Phase 53 amendment — option (i)
_ACCEPTED_MARKDOWN = {"text/markdown"}  # NEW IN PHASE 53 — P53-D6 / V6
_ACCEPTED = _ACCEPTED_AUDIO | _ACCEPTED_PDF | _ACCEPTED_IMAGE | _ACCEPTED_MARKDOWN

Option (ii) — Inline literal in the union.


# Phase 53 amendment — option (ii)
_ACCEPTED = _ACCEPTED_AUDIO | _ACCEPTED_PDF | _ACCEPTED_IMAGE | {"text/markdown"}

Option (i) is the more conventional style given the existing _ACCEPTED_AUDIO / _ACCEPTED_PDF / _ACCEPTED_IMAGE named constants — symmetry suggests _ACCEPTED_MARKDOWN. Option (ii) is tighter for a single-element set but loses the named-constant symmetry. Default: Option (i). CC selects at Step 1 per local convention.

7.4 Phase 53 scope: text/markdown only

Not text/plain, not text/x-markdown, not other text types. Per scoping v0.2 §3.1: smallest additive change to unblock Discovery-document upload. Phase 54+ can extend further if needed.

The skill at §8 declares its accepted content type as text/markdown exactly (matching the _ACCEPTED member); the skill's registration in §9 uses the same string as the content-type-pattern key.

7.5 Backward-compat semantics

The amendment is purely additive — existing MIME types continue to be accepted; existing reject behavior preserved for non-_ACCEPTED types. The error message at lines 191–201 lists the allowed set verbatim; after Phase 53, the message includes text/markdown in the listing automatically (it's the same set being listed). No callers of the upload endpoint need updating; the change is invisible to them.

7.6 Test coverage

One additive smoke test in §17 confirms text/markdown upload returns 201 and produces an UploadedFileRow referenceable from §11's endpoint. Existing test coverage of _ACCEPTED reject behavior continues unchanged (those tests assert specific non-_ACCEPTED types reject; text/markdown is no longer one of them).

7.7 No Memory event from upload

Per V6 evidence: the upload endpoint persists bytes and an UploadedFileRow metadata row; no Memory event is written by the upload endpoint itself. The two-step pattern per the route docstring (files.py:173–181): upload stages the file, then a separate contribution / extraction endpoint references the file_id and dispatches downstream. Phase 53 follows this exactly — §11's endpoint is the "second step" that references the Phase 16-staged file_id.


8. Discovery-to-seed skill module

8.1 What

New file src/loomworks/skills/discovery_to_seed.py hosting the LLM-assisted bounded skill that transforms a Markdown Discovery document into a structured candidate Seed payload. Conforms to the ExtractionSkill Protocol per V1 evidence.

8.2 ExtractionSkill Protocol conformance

Per V1 evidence at src/loomworks/skills/registry.py:64–90, the Protocol is:


class ExtractionSkill(Protocol):
    async def __call__(
        self,
        *,
        file_path: Path,
        engagement_id: UUID,
        db: AsyncSession,
        secret_key: str | None = None,
        person_id: UUID | None = None,
    ) -> ExtractionResult: ...

The Phase 53 skill conforms to this signature exactly. Input is file_path: Path, not pre-decoded text — UTF-8 decoding happens inside the skill body. (The scoping note v0.2 §3.2 described the input as discovery_document_text: str; the protocol-conforming shape is file_path: Path with internal decoding. Decoding-at-the-skill matches the convention of the existing skills — PDF, image, audio — which all read their content from the provided file path.)

8.3 ExtractionResult return shape

Per V1 evidence at src/loomworks/skills/registry.py:28–61:


@dataclass(frozen=True)
class ExtractionResult:
    text: str
    method: str
    source_mode: str
    key_source: Literal["operator", "person", "system"] | None = None
    extra_metadata: dict[str, object] | None = None

The Phase 53 skill returns:

The structured draft_seed payload in extra_metadata is the canonical Phase 53 output. §11's endpoint reads extra_metadata["draft_seed"] and uses it to drive Memory event write + induct_seed hand-off.

8.4 Skill body sequence


1. Open file_path; read bytes; UTF-8 decode → discovery_document_text: str.
2. Resolve LLM API key: secret_key kwarg if provided; otherwise system-level
   key via get_system_config(...) per §8.7.
3. Build prompt: format EXTRACTION_PROMPT with discovery_document_text
   substitution.
4. Single-shot LLM call (no conversation; no retry-on-clarification):
   model=EXTRACTION_MODEL, structured-output instructions targeting
   R-A5–R-A9 + R-A11 fields per Seed schema (V4 evidence).
5. Parse LLM response; validate against Seed payload schema; identify
   gap_fields (any R-A targeted field the LLM left blank or marked
   "[not extractable from this Discovery]").
6. Construct ExtractionResult(text=<summary>, method="...", source_mode="markdown",
   key_source="system", extra_metadata={...}).
7. Return.

8.5 R-A targeting per V4 evidence

Per V4 evidence: canonical Seed model (src/loomworks/engagement/models.py or per V4's Seed definition site) has fields:

The LLM extraction targets six fields: what_the_work_is, who_consumes_the_work, voice_of_the_work, constraints, success_conditions, additional_assertions. Each field's prompt instruction describes the R-A requirement (per Phase 25 §S2 wording and the structured-input-template.md guidance) and asks for the LLM to extract from the Discovery document or leave with an explicit gap marker.

[CC verifies at Step 0 pre-flight] exact Seed field names against V4 evidence (V4 confirmed naming-only divergence; CR uses verbatim field names).

8.6 R-A10 endpoint-derived, not LLM-extracted

Per Phase 25 §S2 evidence: "R-A10 (initial contributors and agents) is not a form field. The creating person is the initial contributor. Agents are auto-registered at commit time. R-A10 content is derived, not authored."

Phase 53 inherits this convention: the skill does NOT extract initial_contributors or initial_agents from the Discovery document. The skill's draft_seed payload leaves these fields empty ([]); §11's endpoint fills them at hand-off time:

8.7 LLM client + key resolution

Per V5 evidence: Phase 31's conversational creation uses system_config for the LLM API key (migrations/versions/0048_phase_31_system_config.py schema; set_system_config / get_system_config / delete_system_config helpers at src/loomworks/system_config/store.py:71,124,150). Phase 53 follows the same convention.

The skill resolves the LLM key by:

  1. If the secret_key kwarg is non-None (as provided by the ExtractionSkillRegistry dispatch path with a per-engagement key per V1's protocol), the skill uses it. (This path is not exercised by §11's endpoint — see below — but the skill remains protocol-conformant for hypothetical contribution-pipeline invocations.)
  2. Otherwise, the skill calls get_system_config(db, key_name=<canonical_key>) to fetch the system-level LLM API key. [CC verifies at Step 0 pre-flight item 11] the canonical key name in current system_config table (likely anthropic_api_key or parallel; mirror Phase 31's convention).

§11's endpoint always invokes the skill with secret_key=None, triggering the system-level resolution path. This is the canonical Phase 53 invocation; the protocol-conformant per-engagement path exists for future flexibility but is not exercised in Phase 53 production code.

8.8 Prompt template module

New file src/loomworks/prompts/discovery_to_seed_extraction.py, parallel to V5's Phase 31 creation_conversation.py.

Module-level constants (mirroring Phase 31's convention per V5 evidence — PROMPT_VERSION = "1.0", CONVERSATION_MODEL = "claude-sonnet-4-6", CREATION_CONVERSATION_PROMPT defined inline, __all__ exports):


# src/loomworks/prompts/discovery_to_seed_extraction.py

PROMPT_VERSION = "1.0"
EXTRACTION_MODEL = "claude-sonnet-4-6"  # [CC verifies against Phase 31 convention at Step 0 pre-flight item 4]

EXTRACTION_PROMPT = """\
... (multi-line literal: instructions for the LLM to extract R-A5–R-A9 + R-A11
from a Markdown Discovery document, with structured-output JSON shape, gap
markers for non-extractable fields, and explicit anti-hallucination guidance) ...
"""

__all__ = ["EXTRACTION_MODEL", "EXTRACTION_PROMPT", "PROMPT_VERSION"]

The prompt content itself is voice-shaped at draft time; the CR specifies the structural commitments (R-A5–R-A9 + R-A11 fields targeted; explicit gap markers; anti-hallucination instructions) but the literal prose is built at Step 2.

8.9 Bounded contract semantics

Per P53-D1: single-shot LLM call; no conversation; no multi-turn; no retry-on-clarification. If the input Discovery document is too sparse for a high-quality Seed, the induction loop catches the gaps (Phase 25 §R-A14 — "Each finding produced by the seed-induction agent MUST name the requirement not met, the location in the seed where the gap was detected, and a suggestion (not a decision) about what would satisfy the requirement").

The skill leaves fields gap-marked rather than fabricating. Test 4c (§17) asserts this behavior on a Discovery record that doesn't have content for a specific field.

8.10 Versioning

PROMPT_VERSION = "1.0" per Phase 31's convention. Future prompt iterations bump the version; the version is captured on each Memory event write per §10.3 (skill_version field). Phase 25's induction-loop history reads seed_requirements_engagement_version_at_induction; Phase 53's audit trail reads skill_version for prompt-version provenance.


9. Skill registration in build_default_registry()

9.1 What

Add a fourth registration call to build_default_registry() at src/loomworks/skills/registry.py:165–195 per V1 evidence. The new skill registers under content-type-pattern "text/markdown".

9.2 Existing registrations per V1 evidence

Three production registrations in build_default_registry() (per V1 evidence enumerating call-sites at registry.py:177, 183, 189):

  1. registry.register("audio/", transcribe_audio_skill, label="Audio (voice recording or upload)", mode="voice") at line 177.
  2. registry.register("application/pdf", extract_pdf_skill, label="PDF document", mode="pdf") at line 183.
  3. registry.register("image/", describe_image_skill, label="Image (photo, diagram, screenshot)", mode="image") at line 189.

9.3 Phase 53 registration


# src/loomworks/skills/registry.py — inside build_default_registry()
# Insertion point: alongside the three existing calls; ordering convention
# [CC verifies at Step 0 pre-flight item 5].

from loomworks.skills.discovery_to_seed import extract_discovery_to_seed

registry.register(
    "text/markdown",
    extract_discovery_to_seed,
    label="Discovery document (Markdown)",
    mode="discovery",
)  # NEW IN PHASE 53 — P53-D3 / V1

Per V1's content-type-pattern keying: "text/markdown" matches uploads with that exact content type (per the canonicalization at files.py:105–119 — strips ; codec=... parameters, lowercases). The registry's longest-match-wins resolution (per V1 evidence at registry.py:119–145) means "text/markdown" resolves cleanly against the canonicalized upload content type.

Exact placement: [CC verifies at Step 0 pre-flight item 5]. Naming-only divergences (e.g., parameter ordering, mode-string convention) absorb in-flight per the standard discipline.

9.4 Registry-vs-endpoint invocation paths

The registration creates a content-type-based dispatch hook: a POST to /engagements/{eid}/contributions referencing a file_id with content type text/markdown would route through ExtractionSkillRegistry.resolve("text/markdown") to the new skill per V6 evidence (src/loomworks/api/routers/contributions.py:97 dispatches via the resolved skill).

Phase 53's primary invocation path is §11's dedicated /seed/extract endpoint, not the contribution endpoint. The endpoint imports and invokes extract_discovery_to_seed directly. The registry-based dispatch path exists for hypothetical future use and remains protocol-conformant; if exercised at runtime (e.g., by an Operator POSTing a Markdown file to the contribution endpoint instead of the extract endpoint), the result lands as a standard contribution (text content stored per Phase 16's contribution flow), without the Phase 53 downstream pipeline (Memory event write + induct_seed hand-off). The contribution-pipeline-as-side-door is acceptable alpha posture; Phase 54+ can decide whether to special-case it or leave as-is.

9.5 Test coverage

§17 test 2a asserts the registration is present (build_default_registry().resolve("text/markdown") returns a RegisteredSkill with the correct skill function).


10. Memory event registration — discovery_to_seed_extracted

10.1 What

Register a new typed MemoryObject subclass for the discovery_to_seed_extracted event, mirroring Phase 25's seed-family structural pattern with full FORAY namespace injection per P53-D12. Module placement: src/loomworks/engagement/discovery_to_seed.py (engagement-family co-located with Phase 25's creation.py; [CC verifies at Step 0 pre-flight item 7]).

10.2 Mirror to Phase 25 seed-family + Phase 50/52 typed-subclass pattern

V7 confirmed the typed-MemoryObject-subclass-without-migration pattern from Phase 50/52. Phase 53's class structure follows that pattern verbatim. Where Phase 53 diverges from Phase 50/52 — and follows Phase 25's seed-family instead — is in the _ANCHOR_PRIORITY entry: included per P53-D12, not deferred. (V7 itself flagged this as the open question; P53-D12 settles to inclusion per V9 mechanics and seed-family precedent.)

The mirror covers four elements:

  1. Typed MemoryObject subclassDiscoveryToSeedExtracted(MemoryObject) with explicit fields per §10.3.
  2. Literal[...] object_typeLiteral["discovery_to_seed_extracted"] matching the event-kind literal.
  3. append_event(event_kind="discovery_to_seed_extracted") call site in the endpoint at §11.4.
  4. _ANCHOR_PRIORITY entry"discovery_to_seed_extracted": "standard" added to the dict at events.py:112–130 per P53-D12; this triggers _foray namespace injection per V9 mechanics at events.py:209–220.
  5. OBJECT_TYPE_REGISTRY entry deferred per Phase 50/52 precedent (V7) — the typed shape exists for write-time validation and read-time clarity; explicit registration is deferred until a downstream consumer needs deserialize_memory_object on it.

10.3 Schema


# src/loomworks/engagement/discovery_to_seed.py
# [CC verifies module placement at Step 0 pre-flight item 7]

from datetime import datetime
from typing import Literal
from loomworks.memory.base import MemoryObject
# [CC verifies exact import path at Step 0 pre-flight item 7]


class DiscoveryToSeedExtracted(MemoryObject):
    """
    Memory event recording an LLM-assisted extraction of a candidate Seed
    from a Markdown Discovery document via Phase 53's discovery-to-seed
    skill.

    Mirrors Phase 25's seed-family structural pattern (typed MemoryObject
    subclass; Literal[...] object_type; full FORAY namespace via
    _ANCHOR_PRIORITY entry per P53-D12). OBJECT_TYPE_REGISTRY entry
    deferred per Phase 50/52 precedent (V7).
    """
    object_type: Literal["discovery_to_seed_extracted"] = "discovery_to_seed_extracted"

    # The Phase 16 UploadedFileRow that holds the source Discovery document
    discovery_document_ref: str        # file_id (UUID as string)
    discovery_document_filename: str   # original_filename from UploadedFileRow

    # The structured Seed payload the skill produced (dict serialization of
    # Seed fields per V4 evidence; not a Seed instance because R-A10 fields
    # are filled by the endpoint at hand-off time, not by the skill)
    extracted_seed_payload: dict       # {what_the_work_is, who_consumes_the_work, ...}

    # Provenance of the extraction
    skill_version: str                 # e.g., "1.0" per §8.10
    prompt_version: str                # e.g., "1.0" per Phase 31 PROMPT_VERSION convention
    extraction_model: str              # e.g., "claude-sonnet-4-6" per §8.8

    # Gap markers: R-A identifiers the skill left empty / explicitly gap-marked
    gap_fields: list[str]              # e.g., ["R-A8", "R-A11"]

    extracted_at: datetime

Exact field-order convention, base-class import path, frozen / mutable posture, datetime tz handling: [CC verifies at Step 0 pre-flight item 7] against Phase 25's seed-family classes and against Phase 50's GrantRequestReceived / Phase 52's JurisdictionRoutingDecided. Naming-only divergences from convention absorb in-flight.

10.4 _ANCHOR_PRIORITY entry per P53-D12

Per P53-D12 and V9 evidence (events.py:209–220 — _foray injection triggered by _ANCHOR_PRIORITY.get(event_kind) is not None):


# src/loomworks/memory/events.py:112–130 — current
# Per V7 evidence: 14 entries including seed_drafted, seed_amended,
# finding_produced, finding_addressed, induction_cycle_recorded, etc.

_ANCHOR_PRIORITY: dict[str, str] = {
    "engagement_committed": "critical",
    "engagement_committed_divergent": "critical",
    "membership_created": "high",
    # ... existing seed-family entries ...
    "seed_drafted": "standard",
    "seed_amended": "standard",
    "finding_produced": "standard",
    "finding_addressed": "standard",
    "induction_cycle_recorded": "standard",
    # ... etc ...
    "discovery_to_seed_extracted": "standard",  # NEW IN PHASE 53 — P53-D12 / V9
}

[CC verifies exact ordering at Step 0 pre-flight item 6] — placement alongside the existing seed-family entries per local ordering convention.

The "standard" priority mirrors seed_drafted and seed_amended. _foray namespace injection happens automatically per the existing mechanism at events.py:209–220 — no new FORAY plumbing.

10.5 No OBJECT_TYPE_REGISTRY entry (deferred per P53-D9)

Per V7 evidence at src/loomworks/memory/registry.py:7–9, the registry currently holds:


OBJECT_TYPE_REGISTRY: dict[str, type[MemoryObject]] = {"generic": GenericMemoryObject}

with helper functions _register_phase_2_types through _register_phase_37_types registering Phase 2/3/4/6/7/9/10/11/31/34/37 types at module import. Phase 41+ types (including Phase 50/52) are NOT registered — V7 evidence confirmed Phase 50 and Phase 52 explicitly deferred registry inclusion per the "typed shape exists for write-time validation and read-time clarity; explicit OBJECT_TYPE_REGISTRY registration is deferred until a downstream consumer needs deserialize_memory_object" rationale.

Phase 53 follows the same deferral per P53-D9. The Phase 53 DiscoveryToSeedExtracted class exists; it functions for write-time event construction; the registry omission means deserialize_memory_object("discovery_to_seed_extracted", payload) returns the generic MemoryObject shape rather than the typed subclass — acceptable because no Phase 53 consumer needs the typed deserialization. Phase 54+ adds the registry entry if a downstream Discovery-trajectory specialist or Operator Layer surface needs typed deserialization.

10.6 Event-kind literal canonicalization

The event-kind literal "discovery_to_seed_extracted" follows the snake_case past-tense convention from Phase 25's seed-family (seed_drafted, seed_amended, finding_produced) and from Phase 50/52 (grant_request_received, jurisdiction_routing_decided). [CC verifies convention at Step 0 pre-flight item 7] — if a different canonical form is in use elsewhere (e.g., a string-constant module enumerating event kinds), the literal lands in that location alongside Phase 25's existing entries.

10.7 No migration

Memory event registration is a code-only addition. The events themselves are appended to the existing event log via append_event (§11.4). No new tables, no new columns, no Alembic migration. Per §5.

The _ANCHOR_PRIORITY entry addition is also code-only — a dict mutation at module load.

10.8 FORAY hook coverage

Per V9 evidence: content_hash is written unconditionally to the memory_events.content_hash column on every event (events.py:236). The _foray namespace injection at events.py:209–220 happens for any event kind in _ANCHOR_PRIORITY. Phase 53's entry in _ANCHOR_PRIORITY (per §10.4 / P53-D12) ensures discovery_to_seed_extracted events get:

§17 test 5 covers FORAY-hook assertion mirroring tests/test_phase_25_content_hash_and_foray.py (V9 canonical fixture).


11. Endpoint — POST /engagements/{eid}/seed/extract

This is the substantive substrate section. Per scoping v0.2 §3.4 and P53-D10 / V10.

11.1 Architectural shape

The endpoint is a synchronous orchestrator that bridges a Phase 16-uploaded Discovery document into the Phase 25 induction loop. Distinguishing characteristics:

This is architecturally distinct from Phase 25's /engagements/{eid}/seed/induct (which inducts an already-drafted seed from form fields) and from Phase 31's conversational flow (which produces a string brief, not a structured Seed — V4 + V5). Phase 53's endpoint produces a new candidate seed from a Discovery document, then immediately inducts it.

11.2 Route placement

Per V10 evidence: 10 /seed* routes across 3 modules. The closest sibling for /seed/extract is /seed/induct at src/loomworks/api/routers/engagements.py:343 (engagements.py hosts 5 of the 10 routes; verb-aligned; lifecycle-action; post-seed-creation).

Default placement: extend src/loomworks/api/routers/engagements.py with the new route, positioned after the /seed/induct route handler. [CC verifies at Step 0 pre-flight item 8] — if engagements.py is already large (V10 enumerated routes at lines 215, 297, 343, 425, 822 — spread across 600+ lines), or if the orchestration logic warrants module separation, create new module src/loomworks/api/routers/seed_extraction.py with the single route. Default = engagements.py.

11.3 Request and response shapes


# Request body
class ExtractSeedRequest(BaseModel):
    file_id: UUID                 # references UploadedFileRow from Phase 16 upload
    # Optional: future amendments (e.g., extraction-specific prompts) land
    # additively without breaking signature.


# Response body
class ExtractSeedResponse(BaseModel):
    extracted_seed_payload: dict  # the Seed-shaped dict the skill produced
    seed_id: UUID                 # the inducted seed's ID after induct_seed hand-off
    induction_outcome: dict       # the InductionOutcome shape from induct_seed
    discovery_to_seed_event_id: UUID  # the discovery_to_seed_extracted Memory event ID
    gap_fields: list[str]         # R-A identifiers left gap-marked

[CC verifies at Step 0 pre-flight item 9] — exact InductionOutcome / induct_seed return shape against src/loomworks/engagement/creation.py:409 definition; the response body adopts the verbatim downstream shape.

11.4 Endpoint orchestration sequence


1. Auth: resolve actor via Depends(get_resolved_actor) per existing convention
   (matches Phase 16 upload endpoint at files.py:140 and engagement endpoints).
   Confirm actor has the right designation to invoke seed extraction on this
   engagement [CC verifies designation requirement at Step 0 pre-flight item 8
   against /seed/induct's auth posture].

2. Load UploadedFileRow by file_id from the request body. Confirm row exists
   and belongs to the path-parameter engagement_id (file_id-engagement_id
   binding check per Phase 16 convention). 404 if not found; 403 if cross-
   engagement.

3. Read the file path from row.storage_path. Confirm content_type ==
   "text/markdown" (defensive against future _ACCEPTED extension to other
   text types; Phase 53 scope is markdown only per P53-D6). 415 if not
   markdown.

4. Invoke the skill directly:
       result = await extract_discovery_to_seed(
           file_path=Path(row.storage_path),
           engagement_id=engagement_id,
           db=db,
           secret_key=None,   # triggers system-level key resolution per §8.7
           person_id=actor.person_id,
       )
   The skill returns ExtractionResult; the structured payload lives in
   result.extra_metadata["draft_seed"].

5. Extract the draft_seed payload:
       draft_seed_payload = result.extra_metadata["draft_seed"]
       gap_fields = result.extra_metadata.get("gap_fields", [])

6. Fill R-A10 fields at hand-off (R-A10 is endpoint-derived, not LLM-extracted
   per §8.6):
       draft_seed_payload["initial_contributors"] = [actor.person_id]
       draft_seed_payload["initial_agents"] = <default registered agents>
   [CC verifies at Step 0 pre-flight item 9] — default-agent-resolution
   helper used by Phase 25's commit path.

7. Write the discovery_to_seed_extracted Memory event:
       await append_event(
           db=db,
           engagement_id=engagement_id,
           event_kind="discovery_to_seed_extracted",
           payload={
               "discovery_document_ref": str(file_id),
               "discovery_document_filename": row.original_filename,
               "extracted_seed_payload": draft_seed_payload,
               "skill_version": "1.0",
               "prompt_version": PROMPT_VERSION,
               "extraction_model": EXTRACTION_MODEL,
               "gap_fields": gap_fields,
               "extracted_at": <now()>,
           },
           actor=actor,
       )
   FORAY hooks fire automatically per §10.8.

8. Construct the Seed and call induct_seed (becomes the third production
   caller per V5):
       seed = await draft_seed(
           db=db,
           engagement_id=engagement_id,
           seed_fields=draft_seed_payload,
           actor=actor,
       )
       outcome = await induct_seed(
           db=db,
           engagement_id=engagement_id,
           seed_id=seed.id,
           actor=actor,
       )
   [CC verifies at Step 0 pre-flight item 9] — exact draft_seed / induct_seed
   signatures and call shapes from the two existing production sites
   (seed_amendment.py:133 and engagements.py:361).

9. Construct ExtractSeedResponse and return 200.

Exact shape: [CC verifies at Step 0 pre-flight items 7, 8, 9, 10]. The implementation lands as a single route handler in engagements.py (or a new seed_extraction.py module); no Phase 25 / Phase 31 code is restructured.

11.5 Error-recovery semantics

Five failure modes:

  1. file_id not found in UploadedFileRow. 404 Not Found. Standard FastAPI dep / lookup pattern.
  1. file_id exists but belongs to a different engagement. 403 Forbidden. Cross-engagement access denial.
  1. content_type != "text/markdown". 415 Unsupported Media Type. Defensive; Phase 53 scope is markdown only.
  1. LLM call raises (network, auth, rate-limit, etc.). The skill propagates the exception; the endpoint returns 502 Bad Gateway with structured error. The discovery_to_seed_extracted Memory event is NOT written (no partial-success state); induct_seed is NOT called. The Operator can retry by POSTing again; per P53-D1's no-retry-on-clarification, the skill itself does not auto-retry — the Operator decides.
  1. induct_seed raises (transaction error, state-invalid, etc.). Halt-and-surface at runtime per the same convention as the other two production callers. The discovery_to_seed_extracted Memory event IS written (step 7 completed before step 8); the induction outcome is recorded as a failure. The Operator can retry induct_seed via the existing /engagements/{eid}/seed/induct endpoint or via amendment. Phase 53 alpha posture: no retry / fallback inside the endpoint.

11.6 No batch / async / streaming variants

Phase 53 scope: single-document, single-call, synchronous endpoint. Batch-extract (multiple documents → single seed), async / Celery / background-task variants, and streaming-LLM-response variants are all out of scope. Phase 54+ candidates if needed.

11.7 Backward-compat with Phase 25 and Phase 31

The endpoint is purely additive — no existing route signatures change; no existing route handlers are touched. Phase 25's five /engagements/{eid}/seed* routes (V10 enumeration: lines 215, 297, 343, 425, 822 in engagements.py + the route in seed_view.py at 34) continue to function identically. Phase 31's five seed_conversation.py routes (V5 enumeration: lines 491, 813, 857, 877, 938) continue to function identically.

induct_seed's two existing production callers (seed_amendment.py:133, engagements.py:361 per V5) are unchanged; the third caller (this endpoint) joins them without disturbing the function signature.

§17 includes explicit backward-compat smoke tests for Phase 25 (form-submission path produces identical output and identical induct_seed invocation) and Phase 31 (conversational path produces identical string-brief output, identical five engagement-scoped endpoint shapes, and continues to NOT call induct_seed — the V5 gap is preserved deliberately per P53-D11).


12. Frontend changes (Operator Layer)

Empty by default per P53-D4.

The Operator Layer's existing Phase 31 conversational creation flow remains unchanged (V5 confirmed the five engagement-scoped endpoints intact). Phase 54+ adds the Discovery-assistance surface once queued directions §1.1 design lands.

This section exists for symmetry with Phase 52's §12 frontend section and to mark the absence explicitly; it is not a placeholder for unbuilt work.

Operator Layer baseline at Phase 53 close: 139 vitest passed, 11 prerendered routes, eslint/tsc/build clean. Marker tag phase-51-marketing-site-and-companion-email at frontend e4c09e0 remains in place; Phase 53 does not advance a marker.


13. Marketing site

Empty. Phase 53 doesn't touch the marketing repo.

The marketing site (DUNIN7/loomworks-marketing, live at https://loomworks.doneinseven.com per Phase 51 / 52 close) is unrelated to engagement creation flow — its form is the public grant-request entry point for the credit / form-flow / marketing arc, not the engagement creation arc Phase 53 opens.

This section exists for symmetry with Phase 52's §13 marketing-site section and to mark the absence explicitly; it is not a placeholder for unbuilt work.


14. Build steps

Seven slots: 4 active + 3 reserved buffer per scoping v0.2 §7. Two checkpoints (A and B). Inverted-pyramid ordering: smallest independent slice first (Phase 16 extension); skill module + registration next; orchestration on top; full test sweep last.

Step 1 — Phase 16 _ACCEPTED MIME-type extension (engine)

What. The smallest independent change: extend _ACCEPTED at src/loomworks/api/routers/files.py:102 to include text/markdown per §7 / P53-D6 / V6. Land green against a single smoke test confirming text/markdown upload succeeds.

Step 0 inspection. Before implementing, CC reads:

Build. Per §7. Choose option (i) (named _ACCEPTED_MARKDOWN constant) or option (ii) (inline literal) per local convention. Add the constant / inline literal; update _ACCEPTED union.

Tests. 1–2 tests:

Acceptance gate. Step 1 tests pass; existing Phase 16 reject-behavior tests pass unchanged.

Halt threshold. Per §16 step-specific: Phase 16 _ACCEPTED extension surfaces unexpected interactions with existing MIME-type filters (e.g., the union expression has cascade effects through a security validator that depends on the closed list; or downstream code in contributions.py:97 branches on specific known MIME types). >30 tests touched.

Mode posture. Auto-mode-proceed.

Step 2 — Discovery-to-seed skill module + prompt template + registration (engine)

What. The skill substrate. New skill module per §8; new prompt template per §8.8; registration in build_default_registry() per §9. Tests run against mocked LLM responses (per drafting handoff §5 LLM-mocking discipline).

Step 0 inspection. Before implementing, CC reads:

Build. Per §8 (skill module body) + §8.8 (prompt template) + §9 (registration). Skill conforms to ExtractionSkill Protocol; UTF-8 decoding internal; single-shot LLM call; structured-output parsing; ExtractionResult return with draft_seed in extra_metadata. Prompt template module mirrors Phase 31's creation_conversation.py shape.

Tests. ~6–10 tests:

Acceptance gate. All Step 2 tests pass; registration present; skill conformant; full-fit and 2+ partial-fit fixtures extract per expected payloads; gap-marker behavior verified; hallucination-resistance verified.

Halt threshold. Per §16 step-specific: ExtractionSkill Protocol surface differs from V1's read (e.g., the secret_key kwarg is positional not keyword; the return is not ExtractionResult but a different dataclass; the protocol requires a method the skill can't naturally provide). LLM client / key resolution convention doesn't match Phase 31's system_config pattern. Prompt template structural convention differs from Phase 31's creation_conversation.py enough that __all__ exports don't fit.

Mode posture. Auto-mode-proceed.

Checkpoint A — skill substrate complete

CC produces implementation notes draft at /Users/dunin7/loomworks-engine/docs/phase-impl-notes/phase-53-implementation-notes-v0_1.md. Records build summary across Steps 1–2; any in-flight resolutions (naming-only divergences absorbed); test count delta. Operator confirms before Step 3.

Acceptance gate (Checkpoint A).

Step 3 — Memory event registration + endpoint + FORAY hooks + induct_seed hand-off (engine)

What. Wire the skill substrate into the endpoint orchestration. New discovery_to_seed_extracted Memory event class per §10; _ANCHOR_PRIORITY entry per §10.4 / P53-D12; new POST /engagements/{eid}/seed/extract endpoint per §11.

Step 0 inspection. Before implementing, CC reads:

Build. Per §10 (Memory event class + _ANCHOR_PRIORITY entry) + §11 (endpoint orchestration). The Memory event class lands as a new file src/loomworks/engagement/discovery_to_seed.py (per pre-flight item 7); the _ANCHOR_PRIORITY entry adds at events.py:112–130; the endpoint extends engagements.py (per pre-flight item 8 default).

Tests. ~6–10 tests:

Acceptance gate. All Step 3 tests pass; Memory event class registers cleanly; _ANCHOR_PRIORITY entry present and produces _foray injection; endpoint orchestrates the five-step flow correctly; induct_seed becomes the third production caller; R-A10 endpoint-fill works.

Halt threshold. Per §16 step-specific: induct_seed hand-off contract differs from V5's implication (e.g., requires Phase 31-style string brief rather than structured Seed; requires async context the endpoint can't provide). _ANCHOR_PRIORITY insertion produces cascade effects (e.g., existing tests that assert specific _ANCHOR_PRIORITY contents now fail). New Memory event module placement conflicts with existing imports / circular dependencies.

Mode posture. Auto-mode-proceed.

Step 4 — Test sweep (engine)

What. Full fixture and integration test sweep. Backward-compat smoke tests for Phase 25 and Phase 31. Per scoping v0.2 §3.7.

Step 0 inspection. Before implementing, CC reads:

Build. New test file tests/test_phase_53_discovery_to_seed.py. Land the broader integration and backward-compat tests not covered in Steps 1–3.

Tests. ~7–10 tests:

Acceptance gate. All Step 4 tests pass; total test count delta within ~20–30 over Phase 52 baseline (target: 2,157–2,167 substrate tests); Phase 25, Phase 31, Phase 16 backward-compat smoke green.

Halt threshold. Per §16 step-specific: any backward-compat regression on Phase 25 (form-submission path produces different output; induct_seed invocation changes) or Phase 31 (any of the five endpoints fails; string-brief output changes; Phase 31 now calls induct_seed despite P53-D11 saying gap is preserved) or Phase 16 (existing MIME types no longer upload; _ACCEPTED reject behavior regresses). >30 tests touched by a single change.

Mode posture. Auto-mode-proceed.

Checkpoint B — final, before tagging

CC produces implementation notes v0.2 (or higher if amendments consumed reserved slots) at /Users/dunin7/loomworks-engine/docs/phase-impl-notes/phase-53-implementation-notes-v0_2.md. Records build summary across all Steps; any in-flight resolutions; methodology findings (lens-bounded scoping evidence cascade second-instance evidence per scoping v0.2 §10.3 — V4/V5/V10 enumeration discrepancies; bounded-contract-not-no-LLM crystallization; engagement-scoped URL family universality; Phase 16 additive MIME extension precedent; P53-D12 settlement of v0.2 FORAY contradiction).

Acceptance gate (Checkpoint B). Per §15.

Tag. phase-53-discovery-to-seed-skill on DUNIN7/loomworks-engine at the post-Step-4 engine commit. Annotated tag. Pushed to origin.

No tags on Operator Layer or marketing repos by default per P53-D7. If sub-arc 2 lands actual work via mid-build amendment, marker tag follows Phase 51 V7 precedent.

Step 5 — Reserved buffer

(reserved — buffer for amendments arising from steps 1–4)

Unconsumed if no amendment arises. Phase 50 left all three reserved slots unconsumed; Phase 51 left all three reserved slots unconsumed; Phase 52 left all three reserved slots unconsumed per the Phase 52 §14 carry. Phase 53 expects similar posture given Step 0 absorbed ten verifications including the one BREAKS (V6) reshaped at v0.2 and the FORAY contradiction settled at this CR by P53-D12.

Step 6 — Reserved buffer

(reserved — buffer)

Step 7 — Reserved buffer

(reserved — buffer)


15. Acceptance gates

Twelve items per scoping v0.2 §8. Mirrors the Phase 52 v0.1 8-item shape, scaled up for Phase 53's larger scope (Phase 16 amendment + skill module + prompt template + Memory event + _ANCHOR_PRIORITY entry + endpoint + tests).

| # | Gate | Where verified | |---|------|---------------| | 1 | All Step 1 tests pass; Phase 16 _ACCEPTED extended to include text/markdown; Markdown upload succeeds with 201; existing MIME types continue to work; existing 415-reject behavior preserved for non-_ACCEPTED types. | Step 1 | | 2 | All Step 2 tests pass; skill module exists at src/loomworks/skills/discovery_to_seed.py; conforms to ExtractionSkill Protocol per V1; registered as fourth skill in build_default_registry(). | Step 2 | | 3 | All Step 3 tests pass; DiscoveryToSeedExtracted MemoryObject class registers cleanly; _ANCHOR_PRIORITY entry present and produces _foray injection per P53-D12 / V9. | Step 3 | | 4 | All Step 4 tests pass; full-fit and 2+ partial-fit fixtures extract per expected payloads. | Step 4 | | 5 | Endpoint POST /engagements/{eid}/seed/extract orchestrates the five-step flow correctly: file load → skill invocation → R-A10 fill → Memory event write with FORAY → induct_seed hand-off → response. | Step 3 / cross-cutting | | 6 | Candidate Seed reaches induct_seed per Phase 25 canonical path; induction loop runs unchanged. The endpoint becomes the third production caller alongside seed_amendment.py:133 and engagements.py:361. | Step 3 / cross-cutting | | 7 | discovery_to_seed_extracted Memory event written with full FORAY namespace per P53-D12 / V9: _foray block present with anchor_priority == "standard", anchorable == True, content_hash matching computed hash; content_hash column populated. | Step 3 / Step 4 cross-cutting | | 8 | Skill produces Seeds from at least three project-knowledge Discovery records (full-fit + 2 partial-fit fixtures per V8); hallucination-resistance test passes (skill leaves fields gap-marked rather than fabricating). | Step 2 / Step 4 cross-cutting | | 9 | Phase 25 form-submission path unchanged (backward-compat verified): existing POST /engagementsPOST /engagements/{eid}/seed/induct produces identical Seed shape; induct_seed invocation identical; both existing production callers preserved. | Step 4 / cross-cutting | | 10 | Phase 31 conversational-creation path unchanged (backward-compat verified): five engagement-scoped endpoints per V5 function identically; string-brief output unchanged; Phase 31 continues to NOT call induct_seed (the V5 gap is preserved deliberately per P53-D11). | Step 4 / cross-cutting | | 11 | Lint + tsc + build clean on Operator Layer (sub-arc 2 empty per P53-D4); no changes to Operator Layer repo. | Cross-cutting | | 12 | Working tree clean on main for engine repo before tag; tag phase-53-discovery-to-seed-skill lands as annotated tag at post-Step-4 commit; pushed to origin. Operator Layer and marketing repos: untouched (no tags, no commits per P53-D7 default). | Checkpoint B |


16. Halt conditions per build step

Per scoping v0.2 §9 and Phase 49 / 50 / 51 / 52 substrate-friction-discipline-pattern. Mid-build friction at any of these thresholds halts the build and surfaces for Operator-elective amendment scoping. Phase 53 thresholds are tightened against Step 0 findings absorbed in scoping v0.2 plus the FORAY question settled at this CR by P53-D12.

General (any step).

Step-specific.

In all cases, halt-and-surface is preferred to draft-and-hope. Reserved buffer slots 5–7 absorb amendment scoping if needed; if no amendment arises, slots stay unconsumed per Phase 50 / 51 / 52 precedent.


17. Test list

Total substrate: ~20–30 new tests across Steps 1–4. Operator Layer: 0 by default per P53-D4. Marketing site: 0.

| Step | Substrate | Frontend (Operator Layer) | Marketing | |------|-----------|---------------------------|-----------| | Step 1 | 1–2 (Phase 16 extension smoke) | — | — | | Step 2 | 6–10 (skill + prompt template + registration; fixtures) | — | — | | Step 3 | 6–10 (Memory event + endpoint + FORAY + induct_seed hand-off) | — | — | | Step 4 | 7–10 (integration + backward-compat smoke) | — | — | | Total | ~20–30 | 0 | 0 |

Build time estimate: 2–2.5 hours total per scoping v0.2 §7. Test count delta target: ~20–30 over the Phase 52 close baseline of 2,137.

The tests follow the green-against-mocked-LLM posture across Steps 2–3 (LLM responses mocked at the fixture level per drafting handoff §5 LLM-mocking discipline); Step 4 exercises the integration path against real Phase 16 + Phase 25 substrate with mocked LLM responses for the extraction step.

LLM-mocking discipline carries forward as Phase 54+ candidate: a separate non-CI test (or quarterly verification cadence) can run against live LLM to confirm prompt-extraction quality on the V8 fixtures. Phase 53 ships with mocked LLM only; the live-LLM cadence is opportunistic Phase 54+ work.

Compared to Phase 52's ~6–9 substrate / 0 frontend, Phase 53 is ~3–5x larger in test surface — proportionate to the substrate scope (4 substantive surfaces vs Phase 52's 4 narrower surfaces) and the integration-heavy nature of LLM-assisted skill testing.


18. Carry-forward to Phase 54

Items intentionally not built in Phase 53, recorded for Phase 54 scoping. Mirrors Phase 50 / 51 / 52 §18 explicit-list shape.

18.1 Phase 54+ candidates surfaced by Phase 53 work (engagement creation arc)

  1. Discovery-assistance flow as product feature (queued directions §1.1; per P53-D8 arc trajectory). Capturing what conversational assistance during Discovery looks like — the Companion guides Discovery-trajectory exploration, surfaces alternatives considered and set aside, captures crystallizations as they happen, produces the Discovery record that Phase 53's skill then transforms.
  1. Discovery-trajectory shape specialist + Discovery-record render specialist. Both declared in candidate seed v0.8 but Phase 9 / Phase 10 did not land specialists. The specialists would format Discovery records consistently for downstream Phase 53 skill consumption (reducing the V8-observed organizing-scheme variance) and render them readably.
  1. Operator Layer surface for Discovery → seed → induction (per P53-D4 deferral). Phase 53 ships substrate without an Operator Layer entry point beyond direct API call. Phase 54+ adds the Operator Layer UI surface once Discovery-assistance flow design lands.
  1. Phase 31 induct-seed gap clarification (P53-D11 carry from this CR). Operator-clarification-needed: deliberate string-brief design (Phase 31 produces a brief for human review before structured-field amendment) vs incompleteness (Phase 31 should auto-call induct_seed like Phase 53). If incompleteness, Phase 31 amendment lands at Phase 54+; closing the gap by calling draft_seed + induct_seed from seed_conversation.py:468 natural extension.
  1. Phase 31 / Phase 53 unification or deprecation (carried from v0.1 §11.1 item 4 via scoping v0.2). Two paths producing candidate seeds from natural-language input — Phase 31 conversational, Phase 53 Discovery-document-based. Phase 54+ may unify (one shared underlying skill family with two front-ends), deprecate one in favor of the other, or maintain both as distinct user-facing flows.
  1. Phase 53 OBJECT_TYPE_REGISTRY entry for discovery_to_seed_extracted (deferred per P53-D9 / Phase 50/52 precedent). Phase 54+ adds when downstream consumers built that need deserialize_memory_object("discovery_to_seed_extracted", payload) — likely the Discovery-trajectory specialist (item 2) or the Operator Layer surface (item 3).
  1. Structured Memory-shape Discovery input (P53-D2 path (b) deferred from scoping v0.2). Phase 53 reads free-form Markdown only; Phase 54+ may add a structured Memory-shape Discovery input as an alternative path.
  1. Live-LLM end-to-end integration test cadence (Phase 53 ships with mocked LLM only). A separate non-CI test (quarterly verification cadence?) can run against live LLM to confirm prompt-extraction quality on the V8 fixtures. Methodology absorption candidate; not yet phase-shaped.
  1. Phase 32 (marketing engagement through conversational creation) (deferred phase per queued directions §2.2). The eventual application of the engagement creation arc to the marketing-site engagement itself. Phase 54+ scoping; Phase 53 enables but doesn't deliver.

18.2 Carried from Phase 52 §18 — deferred-pending-trigger

  1. Modify-the-email-body extension (Phase 51 §19 item 1 / Phase 52 §18 item 4). Conditional. Unchanged carry from Phase 52.
  1. CORS wildcard / regex pattern support in loomworks_cors_origins (Phase 51 §19 item 2 / Phase 52 §18 item 5). Conditional. Unchanged carry.
  1. Threading additional fields onto held-proposal metadata at _author_proposal_assertion (Phase 52 V2 set-aside option (b) / Phase 52 §18 item 3). Available if a future phase introduces a need; unchanged carry.

18.3 Carried from Phase 52 §18 — conditional or speculative

  1. Multi-instance fleet groundwork (Phase 52 §18 item 1). Phase 52 shipped single-instance default with multi-instance scaffolding via the routing-skill primitive; the fleet build-out is still Phase 53+ candidate work. Phase 53 didn't surface anything that changes its readiness.
  1. Captcha for the public form (Phase 51 §19 item 4 / Phase 52 §18 item 6). Conditional on abuse signals.
  1. Threshold-driven Companion autonomy for grant decisions (Phase 51 §19 item 5 / Phase 52 §18 item 7). Gated on Operator content authoring being mature.
  1. Modify-the-proposal action on <GrantDecisionApprovalCard> (Phase 51 §19 item 6 / Phase 52 §18 item 8). Opportunistic.
  1. Multi-Companion-instance cross-checking on grant decisions (Phase 51 §19 item 7 / Phase 52 §18 item 9). Speculative future work.
  1. Real-LLM end-to-end spike test cadence formalization (Phase 51 §19 item 8 / Phase 52 §18 item 10). Combines with item 8 above as Phase 53 generalizes the LLM-mocking-vs-live tension.

18.4 Continuing parallel work

  1. Operator content authoring (continuation) (Phase 51 §19 item 9 / Phase 52 §18 item 11). Continuing parallel work, not phase-shaped.
  1. Voice tuning iterations on grant_proposal.md and grant_email.md (Phase 51 §19 item 10 / Phase 52 §18 item 12). Continuing parallel work.

18.5 Substrate-gap-dependent or deferred

  1. Phase 42 conversation_turns reconciler coverage (Phase 51 §19 item 11 / Phase 52 §18 item 13). Substrate-gap-dependent; future Phase 42 amendment.
  1. Reactivation in-session chrome (Phase 51 §19 item 12 / Phase 52 §18 item 14). Conditional.

18.6 Methodology consolidation

  1. Methodology v0.21 consolidation (Phase 51 §19 item 13 / Phase 52 §18 item 15). Continuing parallel work, runs separately. Phase 53 contributes per scoping v0.2 §10.3:

These contributions land in Phase 53 implementation notes during construction and feed the next manifest update (v0.38) / methodology consolidation pass.


19. Kickoff prompt for CC

Paste-ready. Mirrors the Phase 52 §19 kickoff shape, adapted for Phase 53's four-active-step / engine-only / larger-scope shape. Run on DUNIN7-M4 in a fresh Claude Code session against the engine repo at /Users/dunin7/loomworks-engine.


> Read the Change Request document at the path I supply below. This is
> CR-2026-068 v0.1, the Phase 53 Change Request (first version; no prior
> Phase 53 CR exists). You are the executing agent named in the CR.
>
> CR path: ~/Downloads/phase-53-cr-discovery-to-seed-skill-v0_1.md
> (confirm the latest approved version if more than one is present in
> Downloads).
>
> v0.1 drafts against:
>   - loomworks-phase-53-scoping-note-v0_2.md (authoritative scope; absorbs
>     Step 0 findings)
>   - phase-53-step-0-findings-v0_1.md (engine repo
>     docs/phase-impl-notes/; verified live-codebase state, absorbed into
>     scoping v0.2; FORAY question left open in v0.2 settled at this CR
>     by P53-D12)
>   - loomworks-phase-53-cr-drafting-handoff-v0_1.md (drafting handoff)
>
> Code baseline:
>   - engine: tag phase-52-jurisdiction-routing at 69aecdc (annotated tag
>     object f11e41a); main HEAD = 69aecdc (the tag commit per Step 0
>     findings baseline check; brief's phrasing of "one commit ahead at
>     14e5a7f" inverted parent/child — 14e5a7f is the parent of 69aecdc).
>     2,137 tests passed, 25 skipped, Alembic head 0064, working tree
>     clean.
>   - Operator Layer (DUNIN7/loomworks): marker tag
>     phase-51-marketing-site-and-companion-email at e4c09e0 (Phase 50
>     commit, sub-arc 2 has been empty across Phases 51 and 52). 139
>     vitest passed, 11 prerendered routes, eslint/tsc/build clean. NOT
>     IN PHASE 53 SCOPE BY DEFAULT per P53-D4.
>   - Marketing (DUNIN7/loomworks-marketing): tag at bf2f694 (annotated
>     tag object 76071b0); main one commit ahead at 78c26fa. Live at
>     https://loomworks.doneinseven.com. NOT IN PHASE 53 SCOPE.
>
> Per CR §3.4: archive this CR to
> docs/phase-crs/phase-53-cr-discovery-to-seed-skill-v0_1.md
> at Step 0 before Step 1 begins.
>
> Per CR §3.3: run pre-flight Step 0 (11 items). The ten scoping-time
> verifications absorbed into v0.2 (V1–V10) are not re-run; the pre-flight
> items here are CR-time deltas — placement convention confirmations,
> exact strings, module paths, ordering conventions that the CR drafter
> specified against Step 0 evidence but where local convention selection
> remains. Naming-only divergences absorb in-flight per the standard
> discipline; architectural divergences halt and surface (see CR §16
> halt conditions).
>
> Per CR §14: four active build steps + three reserved buffer slots
> (Steps 5–7 reserved-not-skipped per scoping v0.2 §7 reserved-slot
> convention). Two checkpoints — Checkpoint A after Step 2, Checkpoint B
> after Step 4 (final, before tagging). Standard auto-mode posture:
> Steps 1–2 accept auto-mode-proceed; Checkpoint A halts until Operator
> confirms; Steps 3–4 auto; Checkpoint B (final) halts for tagging.
>
> Per CR §4: twelve construction decisions (P53-D1 through P53-D12) are
> settled. CC executes against them; does not re-decide. P53-D12 in
> particular settles the FORAY question scoping v0.2 left open between
> its §3.5 schema framing and §6 V7 row — Phase 53 mirrors Phase 25's
> seed-family (add discovery_to_seed_extracted to _ANCHOR_PRIORITY at
> priority "standard"), not Phase 50/52's deferral. No decisions remain
> [Operator confirms].
>
> Per CR §16: halt-and-surface is preferred to draft-and-hope. Halt
> thresholds include: substrate-friction-discipline-pattern; any
> divergence from v0.2 scoping decisions or this CR's P53-D12; >30 tests
> touched by a single change; any count discrepancy emerges against
> Step 0's enumerations (V1: 3 production registrations + 18+ test
> modules; V4: 7 production Seed-construction sites + 33 test sites; V5:
> 5 Phase 31 endpoints + 2 induct_seed production callers; V10: 10
> /seed* routes across 3 modules) — third-instance lens-bounded scoping
> evidence cascade would itself be methodology contribution worth
> preserving; ExtractionSkill Protocol surface differs from V1 read;
> induct_seed signature contradicts V5; _ANCHOR_PRIORITY insertion
> produces cascade effects; any backward-compat regression on Phase 25,
> Phase 31, or Phase 16.
>
> Implementation notes at Checkpoints A and B:
> docs/phase-impl-notes/phase-53-implementation-notes-v0_1.md (and
> v0_2.md if revised at Checkpoint B). Records build summary for each
> step, in-flight resolutions, methodology findings (lens-bounded
> scoping evidence cascade second-instance evidence per scoping v0.2
> §10.3 — V4/V5/V10 enumeration discrepancies; bounded-contract-not-
> no-LLM crystallization; engagement-scoped URL family universality;
> Phase 16 additive MIME extension precedent; P53-D12 settlement-of-
> scoping-contradiction-at-CR-drafting as new methodology candidate).
>
> Tag at completion: phase-53-discovery-to-seed-skill
> (annotated, on engine repo only per P53-D7). No tags on Operator
> Layer or marketing repos by default — Phase 53 has no work in those
> repos. If sub-arc 2 lands actual work via mid-build amendment,
> marker tag follows Phase 51 V7 precedent.
> Push tag after Checkpoint B.

After CC reports build summary at completion, a fresh scoping chat opens for Phase 54 with the carry-forward from §18 as relevant.

If a mid-build amendment surfaces (Phase 49 Finding 6 trajectory — Operator-elective amendment scoping), the discipline is established: build doesn't halt on naming-only items; Operator decides architecturally with options + halt-threshold review; sub-step lands before continuing. Phase 49's phase-49-step-4-amendment-scoping-v0_1.md is the canonical instance; Phase 50 / 51 / 52 each left all three reserved slots unconsumed. Phase 53's most likely mid-build amendment triggers are LLM-mocking-discipline failure at Step 2's fixture level (Discovery records produce wildly variable outcomes the mock can't deterministically represent) and any Step 3 backward-compat surface change (_ANCHOR_PRIORITY cascade effects on existing tests; new endpoint placement conflict).


DUNIN7 — Done In Seven LLC — Miami, Florida Phase 53: Discovery-to-Seed Skill — CR v0.1 — 2026-05-10