DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path investigations/loomworks-seed-creation-mechanism-map-v0_1.md

Loomworks — Seed-creation mechanism map (as built)

Version. 0.1 Date. 2026-06-02 Provenance. Engine-source trace, Operator: Marvin Percival. Consolidates seed-creation material previously scattered across the seed-investigation reports into one map. Status. Investigation / map of what exists today. Not a design and not a build. No mechanism change is proposed here. This is the artifact future seed-creation decisions are made against; it is measured by accuracy, not brevity. Lens. Read alongside standing-notes/loomworks-standing-note-engine-wrapper-boundary-v0_1.md. §6 marks engine-vs-wrapper per that note, and flags where the boundary is already not clean. Companion deep-dive. The three-terminal-paths divergence (§5) is analysed in depth — why each path exists, which fires for the live operator, and whether it is a problem — in investigations/loomworks-seed-creation-three-paths-deep-dive-v0_1.md. Code citations. All engine: references are to the loomworks-engine repo at the time of writing. Line numbers are indicative; function/file names are load-bearing.


0. Orientation — the one-paragraph shape

There is one shared engine core for committing a seed (draft_seedinduct_seedcommit_engagement_create_engagement), and several front-ends that reach it. The structured six-field Seed is the engine's truth; it lives in the administrative engagement's event log and is pointed to by a candidate engagement row's candidate_seed_id. The form path authors the six fields directly. The conversational path runs a Companion conversation that produces a prose brief + a structured seed_fields blob on conversation-turn events only (no Seed object yet), and then a terminal step turns that conversation into a real Seed and inducts it. The boundary between "conversation, no Seed object" (Sub-phase A) and "Seed object exists, induction with findings" (Sub-phase B) is the first draft_seed call. Everything converges on commit_engagement.


1. The full sequence — draft → induct → converge → terminal → instantiate

Engine-core functions (engine: src/loomworks/engagement/creation.py):

Step 1 — draft_seed (creation.py:82)

Step 1′ — amend_candidate_seed (creation.py:145) (pre-instantiation refinement)

Step 2 — induct_seed (creation.py:409) — one cycle per call

Step 3 — commit_engagement (creation.py:681) / commit_engagement_divergent (creation.py:725)

Step 4 — _create_engagement (creation.py:847) — the convergence point

(Post-commit amendment — out of creation scope but for completeness: revise_seed (creation.py:229) is the Phase 6 consideration-anchored amendment, paired with revise_engagement (creation.py:764) to advance seed_ref. That path is governance-bearing; it is not part of creation.)


2. The A/B seam — exactly where the structured Seed first exists

The transition is the first draft_seed call. Before it: a conversation. After it: a structured Seed object plus induction.

Sub-phase A — conversation, NO Seed object

The line

Sub-phase B — Seed object exists, induction with findings


3. Where the operator touches it today

| Moment | Operator touch-point | Mechanism behind it | |---|---|---| | Start (conversational) | Types/speaks an idea; answers the Companion's questions | POST …/seed/converse turns (Sub-phase A) | | Reads the brief | Sees prose "brief"; in the OL it's the read-only DraftSpecification on /chat | seed_document on each companion_turn; OL via draft_specification | | Ready signal | Companion says "take a look — does this capture it?" | LLM sets status="ready_for_review" (prompt, creation_conversation.py:148-153) | | Start (form) | Fills six plain-language fields; Submit for review | POST /engagementsdraft_engagement (Sub-phase A skipped entirely) | | Refine (form) | Edits fields; Submit amendment and re-induct; sees finding cards under fields | amend_candidate_seed_route + induct_engagement_seed | | Commit ceremony | Commit this engagement → WebAuthn; or Commit despite findings → rationale modal | instantiate_challenge + instantiate_engagement / …/divergent | | Title | (today) post-commit rename only | PUT /engagements/{eid}/title (metadata-only) |

The conversational operator never edits fields or the brief directly — input is always a conversational message (text or voice via …/seed/converse/transcribe).


4. State & records — what persists, when it first exists, and its weight

Recorded on the candidate engagement id (Sub-phase A conversation) — engine: seed_conversation.py:

Recorded under ADMINISTRATIVE_ENGAGEMENT_ID (the Seed's home) — engine: creation.py:

On the engagements row (engine: DB):

Recorded on the new engagement id at commit:

Weight ladder: conversation turns (persisted, no seed/engagement weight) → candidate Seed versions (versioned, pre-instantiation, freely discardable, not governance-bearing) → committed Engagement + post-commit revise_seed (governance-bearing, consideration-anchored). The "edits are free pre-commit" property holds throughout A and B in the governance sense (no Engagement), but in B the Seed is versioned (not literally silent).


5. The two front-end paths — and the THREE terminal commits

Form path (Workshop "Surface B")

POST /engagements (draft_engagement, engagements.py:220) → POST …/seed (amend_candidate_seed_route, :301) → POST …/seed/induct (induct_engagement_seed, :347) → GET …/seed/findings (:429) → POST …/instantiate/challenge (:653) → POST …/instantiate (instantiate_engagement, :467, WebAuthn via get_committing_contributor + challenge store) → commit_engagement. Authors the six fields directly; enters at Sub-phase B immediately (no conversation).

Conversational path (Companion "Surface A")

Operator-layer POST /operator/converse (engine: src/loomworks/orchestration/routers/converse.py, operator_converse, registered as /converse at :1094) classifies intent (or honours intent_hint) and delegates:

The three terminal commits to a structured Seed — and how they DIFFER (important)

  1. Phase 54POST /engagements/{eid}/seed/converse/commit (engine: src/loomworks/api/routers/seed_commit_from_brief.py:224). Reads the LLM-emitted seed_fields off the latest ready_for_review companion_turn (_load_latest_ready_for_review_companion_turn, :159), adapts it (_adapt_seed_fields_for_draft_seed, :97 — maps voicevoice_of_the_work, list/dict additional_assertions, fills R-A10), calls draft_seed, wires candidate_seed_id, writes seed_committed_from_brief event, then induct_seed. Uses the structured representation the conversation produced.
  2. Phase 55 brief pathPOST /me/engagements/create-from-conversation (engine: src/loomworks/api/routers/me_create_engagement.py:482) → _execute_brief_path (:345). It composes from raw turns: _compose_brief_from_turns builds only what_the_work_is and draft_seeds with empty defaults for the other five fields (me_create_engagement.py:374-385), then inline induct_seed. Writes terminal engagement_created_from_assistance on the personal engagement; has a Fault-B resume-and-commit guard (:574-604) so committing a reviewed candidate doesn't re-extract a degenerate transcript-dump seed.

Correction (verified — see the deep-dive): this path does NOT "ignore" structured seed_fields. Its conversation surface never produces them. Phase 55's create_engagement_active flow is project-less and does not delegate to Phase 31 (router.py:_route_create_engagement_active:1384 — it runs the general responder over Phase 42 relational ConverseTurn rows, which carry no seed_fields, under no Phase 31 structured-extraction XML contract). So compose-from-turns is a necessity of this surface's conversation store, not a discard of available structure. Contrast Phase 54, whose create_project flow always carries a project_id and delegates every turn to Phase 31 (_call_phase31_converse), which does write seed_fields onto companion_turn Memory events — which is why Phase 54 can reuse them.

  1. Phase 55 discovery_record path_execute_discovery_record_path (me_create_engagement.py:399): composes a Markdown discovery record from turns → Phase 16 upload → Phase 53 extract_seed_from_discovery (LLM extraction) → induct_seed.

All three (and the form path) converge on commit_engagement_create_engagement. They diverge on how the structured Seed is first produced: form fields, vs. the LLM seed_fields (Phase 54), vs. thin compose-from-turns (Phase 55 brief), vs. discovery extraction (Phase 55 discovery). This is the single most scattered part of the mechanism — the same operator idea becomes a Seed in at least three different ways. The root cause is that the two conversational generations read from two different conversation stores: the Phase 31/Phase 54 lineage runs the structured-extraction engine over Memory-event companion_turns (which carry seed_fields), while the Phase 55 lineage runs the general responder over relational ConverseTurn rows (which do not). Phase 54 reuses structure because its surface produces it; Phase 55-brief composes from raw turns because its surface never does. Phase 55-discovery re-derives structure via a separate Phase 53 LLM extraction. The full why-each-exists / which-fires-today / is-it-a-problem analysis is in the companion deep-dive (see Lens).


6. Engine vs. wrapper — and where the boundary is already not clean

Engine mechanism (must survive any wrapper):

Current-Companion-specific wrapper behavior:

Boundary-not-clean flags (engine mechanism that currently ASSUMES the Companion):

  1. The conversation endpoint lives engine-side and bakes in the Companion's prompt. api/routers/seed_conversation.py calls CREATION_CONVERSATION_PROMPT directly. The whole conversational-creation surface — a Companion artifact — sits inside the engine's API layer rather than in a wrapper talking through a boundary. A different wrapper inherits this prompt and its exact XML output contract.
  2. Phase 54's commit reads seed_fields off a companion_turn event in the Companion's emission shape. seed_commit_from_brief.py + _adapt_seed_fields_for_draft_seed exist specifically to translate the Phase 31 LLM's output (voice key, list/dict additional_assertions). The engine commit path is coupled to how this Companion emits structure.
  3. Phase 55 terminal paths read the Companion's conversation table. _compose_brief_from_turns / _compose_markdown_discovery_record (me_create_engagement.py) consume ConverseTurn rows and the creation-mode-turn filter — engine terminal logic reaching into the Companion's conversation store and its turn semantics (incl. the Fault-B resume heuristic).
  4. _create_engagement derives the title from additional_assertions.engagement_name (creation.py:862) — an operator/Companion naming convention embedded in the engine's title derivation.
  5. draft_engagement materializes operator membership "so the creator can complete the conversational-path setup (key prompt → first turn)" (engagements.py:239-251) — the engine row-creation accommodating a Companion-flow detail.
  6. The translator drops the structured representation at the wire (flag 2's mirror on the read side): the engine produces seed_fields + completion, and the operator-layer boundary discards them, so the OL can only ever see prose. Per the standing note this should be the wrapper choosing prose, exposed as a deliberate boundary offering both — today it is a fixed flattening.

These six are the places where, if the Companion were replaced, engine code would have to change — i.e. where the boundary is not yet clean. They are recorded here as observations, not defects to fix in this artifact.


7. One-screen mechanism diagram (textual)


CONVERSATIONAL (Surface A)                          FORM (Surface B)
  POST /operator/converse  (wrapper: classify+route)
     │  create_project / a turn                        POST /engagements
     ▼                                                   (draft_engagement)
  POST …/seed/converse  ── Sub-phase A ──┐                 │  allocate row + draft_seed + wire candidate_seed_id
   operator_turn / companion_turn        │                 │
   {seed_fields, brief, completion,      │                 ▼  ── enters Sub-phase B directly ──
    status} on the turn event            │           POST …/seed (amend_candidate_seed) ⇄ POST …/seed/induct
   NO Seed object yet                    │                 │       (loop: findings ↔ amend)
        │ status→ready_for_review        │                 │
        ▼                                │                 │
  ┌─ commit_project_draft ──────────────┐│                 │
  │  POST …/seed/converse/commit (P54)  ││                 │
  │   reads LLM seed_fields → draft_seed││                 │
  └─────────────────────────────────────┘│                 │
  ┌─ create_engagement_commit ──────────┐│                 │
  │  POST /me/…/create-from-conversation ││                │
  │   (P55) brief: compose-from-turns    ││                │
  │         OR discovery: extract        ││                │
  │   → draft_seed                       ││                │
  └─────────────────────────────────────┘│                 │
        │  ===== A→B boundary: first draft_seed =====       │
        ▼                                                   ▼
                    induct_seed  (cycles, findings, convergence/divergence)
                                   │ converged + human actor
                                   ▼
        commit_engagement / _divergent  →  _create_engagement
          (row → active, candidate_seed_id=NULL, Engagement v1, seed_ref, wasDerivedFrom)
                                   ▼
                            ENGAGEMENT ACTIVE

Investigation / map only. No engine or wrapper code changed. No mechanism redesigned or proposed. Filed in loomworks-record/investigations/. Pairs with standing-notes/loomworks-standing-note-engine-wrapper-boundary-v0_1.md (the lens), investigations/loomworks-seed-creation-three-paths-deep-dive-v0_1.md (the §5 deep-dive), investigations/loomworks-seed-creation-engine-contract-v0_1.md (the interface contract), investigations/loomworks-engine-boundary-inventory-v0_1.md (the whole-engine boundary), and investigations/loomworks-title-review-at-induction-design-v0_1.md.