Version. 0.1 Date. 2026-06-02 Provenance. Engine-source trace, Operator: Marvin Percival. A focused deep-dive into one finding from the seed-creation mechanism map: that there are three terminal commits to a structured Seed, and they diverge. Status. Investigation / analysis. Report-only — no design, no redesign, no fix proposed. Understanding-first. Reads with.
investigations/loomworks-seed-creation-mechanism-map-v0_1.md — the full mechanism map this deep-dive expands (its §5).investigations/loomworks-seed-creation-engine-contract-v0_1.md — the interface contract beneath this divergence.investigations/loomworks-engine-boundary-inventory-v0_1.md — the whole-engine boundary this is one instance of.standing-notes/loomworks-standing-note-engine-wrapper-boundary-v0_1.md — the engine/wrapper boundary lens both documents are measured against.
Code citations. engine: = the loomworks-engine repo at time of writing; line numbers indicative, names load-bearing.
The three terminal paths are not three peers designed together. They are two generations of conversational creation, the newer of which forked into two sub-paths. The divergence the map flags is real and is rooted in one mechanical fact: the two generations read from two different conversation stores, and only one of those stores carries the structured seed_fields. A seed created through the live operator-Companion path is therefore materially thinner at creation than one created through the older Phase 31/Workshop path — by necessity of the surface, not by a discard of available structure.
Path 1 — Phase 54 (commit_project_draft → POST /engagements/{eid}/seed/converse/commit). Built to close a gap in the older create_project lineage (Phase 31 dedicated seed-conversation + Phase 40 operator routing): Phase 31 produced a brief but never inducted. CR-2026-069 §1: "closes the Phase 31 induct-seed gap… Answer C — deliberate-but-amendable: the Phase 31 brief-stop is the deliberate default, AND the Operator wants the option to skip the manual amend step and go straight to induction." Designed as a thin rebinder — P54-D2: "No new LLM call needed inside the new endpoint — Phase 31 already does the LLM extraction; Phase 54's endpoint is a pure rebinder + caller."
Paths 2 & 3 — Phase 55 (create_engagement_commit → POST /me/engagements/create-from-conversation, output_path = brief | discovery_record). Built after Phase 54 as the product surface for new-engagement creation from the operator's main Companion. CR-2026-070 §1: "Phase 55 builds the conversational engagement creation surface that closes the engagement-creation-arc's product surface… at terminal turn asks 'Discovery record or brief?' The Operator picks." The two output paths are an intentional operator choice at the terminal turn (brief = quick/thin; discovery_record = structured Markdown → Phase 53 LLM extraction).
So the situation is intentional at the sub-fork level (Phase 55 deliberately offers brief vs discovery) and accretional at the generation level (Phase 54 and Phase 55 are terminals from two generations that now coexist). Current-status manifest v0.41 confirms both shipped, neither superseding: Phase 54 "engagement creation arc terminal symmetry," Phase 55 "product loop closed end-to-end."
Deep cause: two flows, two conversation stores, only one carrying structured fields.
create_project always carries a project_id; every turn delegates to _call_phase31_converse → converse_route (engine: router.py:_route_create_project:940), which writes **companion_turn Memory events carrying seed_fields (engine: seed_conversation.py:_append_companion_turn:466-472). At commit, Phase 54 reads those seed_fields off the latest ready_for_review event and adapts them (engine: seed_commit_from_brief.py:_adapt_seed_fields_for_draft_seed:97 — voice→voice_of_the_work, list/dict additional_assertions, R-A10 fill). Structure is there to reuse because the Phase 31 engine produced it.**create_engagement_active is project-less (project_id=None) and does not delegate to Phase 31 — engine: router.py:_route_create_engagement_active:1384: "signals the responder to load the active-flow instruction template; the recent turns… passed through to the responder via the standard prompt-assembly path." Those turns are Phase 42 relational ConverseTurn rows (get_recent_turns), carrying no seed_fields — the general responder is not running Phase 31's structured-extraction XML contract.
It does not discard structured fields — in the P55 surface they were never produced. The brief path's only raw material is the relational turn text, so _compose_brief_from_turns (engine: me_create_engagement.py:135) concatenates the operator's messages into what_the_work_is and draft_seeds with empty defaults for the other five fields (:374-385: who="", voice="", constraints=[], success="", additional={}). The docstring frames this as deliberate given that this surface has no structured fields: "The candidate Seed is intentionally thin; induct_seed surfaces findings the Operator addresses post-creation." (The map's v0.1 wording "ignores the seed_fields" was imprecise and is corrected in its §5 to match this.)
Fault-B is unrelated to thinness; it guards a re-extraction bug that the thin-composition approach creates. Comment at engine: me_create_engagement.py:574-588: "If the current creation block already drafted a candidate… commit THAT already-drafted candidate seed (the reviewed one) IN PLACE — do NOT re-extract. Without this, every commit turn re-allocated a fresh engagement + re-drafted a seed from the raw turns, so an override on the second turn committed a fresh degenerate transcript-dump seed and discarded the clean candidate the Operator reviewed." So Fault-B exists because re-composing from raw turns yields a "degenerate transcript-dump seed"; the guard ensures the reviewed first-turn candidate is what commits.
Yes, at the moment of creation, structurally.
SeedInductionAgent.examine against R-A5–R-A11 will (on a reasoned read of the code) produce findings on the empty who/voice/constraints/success fields → the seed does not converge on first pass → create_engagement_from_conversation early-returns state="candidate" with findings (engine: me_create_engagement.py:642-654), not an active engagement. (This convergence behaviour is inferred from the mechanism, not separately test-run.)They do not auto-converge to the same place: P54 lands a rich converged seed; P55-brief lands a thin non-converged candidate the operator must refine or commit-despite-findings (divergent); P55-discovery lands something richer than brief.
Phase 55 fires. The OL Companion frontend (loomworks/.../ChatView.tsx) drives creation with intent_hint: "create_engagement_entry" — the Phase 55 lineage (create_engagement_entry → _active → commit). The normal operator creating an engagement through the OL Companion hits /me/engagements/create-from-conversation and, at the terminal "Discovery record or brief?" turn, chooses brief or discovery_record (operator-selected; neither is a silent default).
Relative to that operator:
commit_project_draft) is the terminal of the older create_project/Phase 31 lineage. It is the live terminal for the Workshop's dedicated structured seed-conversation surface (/engagements/{id}/seed/converse), and remains classifier-reachable in the OL (vocabulary still includes create_project/commit_project_draft, engine: classifier.py:48-55), but it is not what the OL creation frontend drives — prior-generation from the OL operator's point of view.POST /engagements → instantiate, WebAuthn) is the Workshop's "I know what I need" Surface B — a separate front door, not the Companion path.Summary: Phase 55 (brief or discovery, operator's pick) is the live OL-Companion path; Phase 54 is live-but-belongs-to-the-Workshop/Phase-31 lineage; both operational, neither legacy-dead.
More than untidy; a real, bounded risk — partly masked because the thinness is "by design."
Where it's genuinely fine:
commit_engagement → _create_engagement core, so the committed object is structurally uniform regardless of path. No data-integrity divergence.me_create_engagement.py:642). The system is honest that a thin brief seed isn't done.Where the real risk sits:
seed_fields (it does in the Phase 31 lineage), but the live OL creation flow runs a conversation engine that doesn't — so the structured representation the operator could have isn't captured where they actually create. Same wire-flattening pattern the standing note names: structure exists in one engine path and is absent in the one the operator uses.Net read: not harmless-untidy, but not corrupting either. The committed object is always well-formed; the risk is seed thinness and routine divergence on the live OL-brief path, plus inconsistent seed quality across surfaces for the same input — and the deeper signal is that the live operator surface is the one path that can't reuse the structured representation the system is otherwise capable of producing. That is the thing to weigh before deciding anything. No fix is proposed here.
Investigation / deep-dive only. No engine or wrapper code changed. No mechanism redesigned or proposed. Filed in loomworks-record/investigations/. Pairs with investigations/loomworks-seed-creation-mechanism-map-v0_1.md (the map this expands), 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 standing-notes/loomworks-standing-note-engine-wrapper-boundary-v0_1.md (the lens).