DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path current-status/current-status-manifest-v0_72.md

Loomworks Current-Status Manifest — v0.72

Version: 0.72 Date: 2026-06-28 Status: Working draft. The entire Companion-surface arc is now MERGED to Operator-Layer main (3f2fca8, a --no-ff merge; 36 commits across nine pieces — CR-2026-125 focus, dev-env fixes, Companion surface integration, list-loading CR-2, voice panel + timestamps, add-side rework, mobile Companion, create-restore, seed viewer; all were already on origin/feat-companion-surface, nothing local-only). This SUPERSEDES the v0.69 §5 residue "OL Companion work on the feat branch only, no merge to main" — the merge v0.69 named as unscheduled is DONE; OL main advanced bafdb07 → 3f2fca8 and is in sync on origin. Merged-whole verification: tests 451/451 green, tsc clean of merge regressions (the 4 known pre-existing errors only — 3 TagChipArea + 1 RefreshFocusOnIntent — no new), vocabulary-wall green; lint red (25 errors / 14 warnings) — a standing repo condition, not merge breakage (pre-merge main already carried 15 lint errors; the merge added 10, all from feat's own new Companion-surface files; lint has never been this repo's push gate — tests/tsc/vocab are). Named as debt in §5. Three more pieces landed on top of the merge this session: the seed viewer (built, pushed, and LIVE-VERIFIED against E0007/Goosey's real seed — seed_version 9, all five commitments rendered from live data, no UUID leak, 403 error-path proven), create-restore (the create-engagement button restored to the lens-home, both layouts), and the scoped create-stage three-door design (Entry 116). Four CRs filed to the record this session (Entries 115–116). Engine main unchanged at 5ccc3d7; OL main 3f2fca8; record main 461f09a. Two Companion/Operator-Layer arcs absorbed in v0.69 (both shipped, SHAs verified against live repos): the add-side rework (Companion spoken-note capture) and the mobile Companion surface. Engine main at 5ccc3d7 (add-side Phases 1–4 merged; pushed, in sync). Operator Layer add-side half is the single commit 8bd73f2 (Phase 5 — held-card Dismiss), anchored by annotated tag add-side-rework-ol-v0_1, living on feat-companion-surface (not on main). The mobile Companion surface is on feat-companion-surface at dac9fec (pushed), built on top of 8bd73f2. Two residues named (§5): the add-side arc has no completion record; the OL add-side + mobile-Companion work is preserved on the feat branch only — no merge to main. Stele Phase 7 is CLOSED — P7-3 (ceremony lift + reference app + browser ceremony + config generator + docs, CR-2026-116) is LANDED. The add_passkey_ enrollment ceremony was lifted into stele.webauthn — a clean extraction (two trivial one-directional shared symbols, a thin wrapper over Stele's own WebAuthn primitives, only me_security calling it), not the feared persons/signup.py split — dissolving the P7-2 §4 asymmetry and collapsing the mount to two required slots (provide_db_session + provide_webauthn_config): the three ceremony/store injection slots are gone and the pending store is Stele-internal. The engine re-pointed its single consumer surface (me_security + deps.py + app.py) onto stele.webauthn, and persons/signup.py shrank to the intact signup flow; engine suite 2930/0/46 at every commit, playground_dev passkey-begin round-trip green. A runnable reference host (stele/examples/) mounts stele.router, composes signup + login host-side (login-TOTP composed host-side per §0.5; sign-in is WebAuthn discoverable-only — no email/username/"remember ID", the authenticator holds identity; no email as identity), demonstrates both delivery shapes (cookie + bearer over one minted token), names its own cookie, and is verified end-to-end against a real Postgres; a minimal browser WebAuthn front drives the real navigator.credentials ceremony; a config generator (generate_env.py, env-scaffolding only) scaffolds the env with a freshly generated Fernet STELE_SECRET_KEY; the adopter docs (standards/loomworks-stele-mount-contract-v0_1.{html,md}) write the mount contract down (HTML primary + MD source). §1.6 (neutralize the brand-leaked stele.session.COOKIE_NAME) was DEFERRED — the grounding grep (a guard written into the CR) found the engine consumes that constant as its live production session-cookie name at ~10 sites across 4 files (login.py/signup.py/me_reactivate.py/deps.py), so an in-place rename would change the engine's cookie on deploy and mass-logout every live session; parked as a properly-sequenced engine-decouple-then-neutralize sub-slice (harmless to clone-and-run adopters — the reference host names its own cookie). stele main 8246729 (pushed; §1 lift + §2–§4 examples); engine main 32c1a68 (pushed; re-pointed + signup shrank + mount test updated). Recorded in loomworks-stele-phase-7-p7-3-completion-record-v0_1 + cr-2026-116-stele-phase-7-p7-3-reference-app-and-ceremony-lift-v0_3 (the §9 asymmetry-dissolution forward-note pointing back to CR-115 §4, per the Operator's settled forward-note-not-115-amendment decision). Stele Phase 7 P7-2 (mountable router + SDK surface, CR-2026-115) is LANDED. stele now ships an HTTP surface of its own: a mountable FastAPI APIRouter (stele.router) carrying the 8 credential-backed primitive routes (passkey enrollment ×4, recovery codes ×2, TOTP rotation ×2), plus the SDK surface (stele/__init__.py — 65 primitives exported eager + FastAPI-free, a lazily-imported stele.router + the injection slots, the mount-contract docstring). A host mounts via include_router(stele.router, prefix=…) + app.dependency_overrides for the named injection contract (3 required slots / 5 defaulted / 2 host ceremony callables). Session delivery is host-pluggable — a neutral Authorization: Bearer default over the delivery-agnostic resolve_session, cookie is a host override; issuance stays mint-only (the router sets no cookie). The authorization boundary is stated: Stele authenticates (resolves who), the host authorizes (what-here) via the resolve_current_principal slot. The KEK no-arg fallback env-var was renamed LOOMWORKS_SECRET_KEYSTELE_SECRET_KEY — strictly Stele-internal (injectable path untouched; zero engine deployment change, since the engine reads its own LOOMWORKS_SECRET_KEY and injects). stele main 1077803 (pushed; §1 router + §3 SDK + §2 rename). The engine consumes it — its from stele. import … primitive paths are intact (identity-equal to the new top-level exports), and a committed mount-verify test (tests/test_stele_router_mount.py) proves a passkey-enrollment route resolves end-to-end through the engine's REAL dependency providers (not just stubs); no production mount, no auth-surface migration (the engine keeps its hand-rolled routers). engine main 08e89c5 (pushed), suite 2930/0/46. Five as-built resolutions (CR v0.2 §0): module-level stele.router + dependency_overrides (not a factory); narrow optional person_email (Stele depends on no host_account shape); lazy router import (library/ORM consumers stay framework-free); /auth/dev/issue-session omitted (the 8-route set, down from the candidate 9 — session-issue stays the stele.session.issue_session primitive); bearer-default delivery. Recorded in loomworks-stele-phase-7-p7-2-completion-record-v0_1 (phase folder) + cr-2026-115-stele-phase-7-p7-2-mountable-router-sdk-v0_2 (as-built §0). P7-3 has since LANDED — see the P7-3 block at the top of this status; Phase 7 is CLOSED. Stele Phase 7 P7-1 (packaging floor, CR-2026-114) is LANDED. The standalone DUNIN7/stele repo is live (private, main 0d5e265): the 9-module library + its own pinned dependency manifest + an independently-runnable consolidated migration baseline (one revision, down_revision=None) building the 3-table schema — principals / webauthn_credentials / recovery_codes, KEK-direct TOTP, no data_encryption_keys (Stele has one secret scope, so the engine's envelope/per-scope-DEK machinery is not lifted). The engine consumes stele as an editable path package (stele = { path = "../stele", editable = true }) and is re-pointed off its local loomworks.stele. copies — loomworks.stele.stele. across 185 .py, the 8 module copies removed, actor.py stays host-side (re-pointed to stele.registry); engine main ff0c4cf (pushed), suite 2928/0/46. §6 (TOTP envelope→KEK-direct re-wrap) resolved to a verified NO-OP — 38 TOTP secrets on playground_dev, 0 envelope-encrypted, all 38 already KEK-direct; the CR's "prevent lockout" premise was false against live data (the host's decrypt_value already dual-paths KEK-direct → no lockout window, and zero envelope secrets existed → nothing to convert). Walkable thread (not a P7-1 defect): the engine's intended TOTP envelope (SCOPE_TOTP) encryption was never actually in effect for this corpus — likely CR-2026-102's SCOPE_TOTP call-site repoint never landed, or the secrets are mirrored legacy values; orthogonal to Stele, worth confirming about CR-2026-102's true landed state. Deploy-time precondition: the ../stele relative-path editable dep means the engine needs stele co-located until the published-package slice replaces it with a version pin. Next: P7-2 — SDK surface + mountable primitive router (the me_security/auth_dev shape), CR-2026-115, drafted from the scoping note + the P7-1 completion record + the queued direction loomworks-queued-direction-p7-2-session-delivery-ui-vs-agent-v0_1 (cookie vs bearer over the same minted token) as its input. Recorded in cr-2026-114-stele-phase-7-p7-1-packaging-floor-v0_1 + loomworks-stele-phase-7-p7-1-completion-record-v0_1. Stele extraction: CR-B (host-FK re-target, mirror retire, persons drop, CR-2026-113) is COMPLETE, MERGED + PUSHED to engine main at fe7c3f1 (a --no-ff merge of cr-2026-113-stele-cr-b; 16 files, +359/-89; origin/main confirmed d0f302e pre-merge, no drift; branch retired local + origin). alembic 0090 → 0093. This is the last Stele arc before Phase 7 (packaging) and it clears the final persons coupling: all 11 host FKs now reference principals.id (each delete behavior preserved verbatim — 3 ON DELETE CASCADE on person_settings/saved_filters/workspaces, 8 NO ACTION; Migration A 0091 asserts persons.id ⊆ principals.id at build time), the reverse mirror trigger 0090 is retired (Migration B 0092), and the persons table is DROPPED (Migration C 0093) along with the 4 _PersonRow registration stubs. principals is the sole identity table with no persons shadow; it carries 15 inbound host/credential FKs (the 11 + 4 pre-existing). The 8 ORM ForeignKey("persons.id") declarations the stubs served are now DB-only → principals.id (the host_account.id → principals.id cross-base pattern). Suite 2928/46/0 at every commit; playground_dev verified end-to-end including the full chain down 0093→0090 (persons recreated + refilled from principals 41=41, trigger restored, FKs re-pointed) then re-up. Three of the build's five as-built deltas were grounding gaps — Step 0 inventoried FK references and ORM stubs exactly (zero drift) but missed (a) raw-SQL reads of persons (4 production sites, would have silently emptied approval-card recipient lists — falsifies the v0.1 §4 "the mirror's only job is the FKs" premise), (b) the 8 ORM FK strings* the stubs targeted (→ DB-only), and (c) the data half of Migration C's down-path (recreate-empty fails the chained FK re-point → refill from principals). Recorded in cr-2026-113-stele-extraction-cr-b-v0_2 (as-built §0; v0.1 preserved) and loomworks-stele-cr-b-completion-record-v0_1. The next Stele arc is Phase 7 (standalone repo, SDK surface, mountable router, reference app, clone-and-run bar) — CR-B was its last identity-side precondition. CR-C (CR-2026-112, the identity-table collapse) remains COMPLETE and merged at d0f302e (the prior live front; its detail follows immediately below). CR-C: COMPLETE and merged to engine main at d0f302e (a --no-ff merge; 82 files, +510/-390). 4 commits, alembic 0089 → 0090 (migration 0090 reverses the mirror trigger — see below). principals is now the canonical identity table — the sole identity read/write source; the app reads and writes the 7 identity columns directly via PrincipalRow. The mirror trigger was REVERSED, not retired: 0090 dropped the persons → principals trigger and installed a principals → persons trigger, so persons is now a standing mirror kept populated solely to feed the 11 host FKs that still reference persons.id. persons is not dropped — that, and the final trigger retirement, are CR-B. The PersonRow identity model is gone; a minimal id-only _PersonRow registration stub (now in persons/models.py) holds the persons table registration so the host FKs resolve. stele/models.py is now SteleBase-only (PrincipalRow + the two credential rows) — the Phase-7 standalone precondition, met cleanly. Suite 2928/46/0 at every commit and on merged main; playground_dev verified (a principals write mirror-populates persons; both the host_account.id → principals.id and person_settings.person_id → persons.id FK classes resolve). Recorded in cr-2026-112-stele-extraction-cr-c-v0_2 (as-built; v0.1 preserved as planned trajectory) and loomworks-stele-cr-c-completion-record-v0_1. CR-A (CR-2026-111, the host-side teardown) remains complete at bee2b4c (its detail is carried below). Carry-forward: Phase 7 (packaging) — the standalone repo, SDK surface, mountable router, reference app, and clone-and-run bar; CR-B cleared the last identity-side precondition (principals is now the sole identity table, no persons shadow). Otherwise carries v0.62 forward.

Phase 7 (packaging) — CLOSED: P7-1 + P7-2 + P7-3 all LANDED; the §E fork was resolved B-first (full P7-3 landing in the header status block). Step 0 (the accessor-class inventory + extraction-blocker triage) closed with the import-graph proven clean — Stele is a pure library today (10 .py files, no APIRouter of its own), and the Phase-4 mint↔onboard split already IS the Stele↔host cut line (mint_principal = Stele, onboard = host-pure), so no de-coupling sub-arc is needed. The Phase 7 scoping note (phases/stele-extraction-phase-7/loomworks-stele-phase-7-scoping-note-v0_1.{md,html}, record 4283c21) resolves the one open decision — the §E fork (does Stele own signup/login orchestration, or ship primitive-level routes only?) — as (B), primitives-only, for the first packaging arc. Stele packages its primitives + a thin primitive-level router (the me_security/auth_dev shape); signup/login orchestration stays a host composition over Stele primitives; the reference app demonstrates the wiring (ceremony → mint → session → onboard) and is a first-class deliverable under (B), since the headline flows live there rather than as package routes. Three settled-source reasons: architecture-spec v0.5's "the Engine is the product; the Companion is a subordinate access path" (Stele is a substrate primitive, not the product surface); smaller blast radius / no new seam ((A) would introduce a Stele→host onboard callback contract); and the cut line already exists (package along the boundary the code drew, don't reach across it). Fork (A) — Stele owning /auth/signup/ + /auth/login/ via a host-supplied onboard callback seam — is preserved as a named later arc, not built now. Seed-alignment checked clean: the seed commits to what the primitives are (UUID-as-identity, no email as identity, passkey/authenticator/recovery/org-SSO), not to who owns the orchestration routes. Deliverable set under (B) (standalone repo, own dependency manifest, own independently-runnable migration set, SDK surface, mountable primitive router, docs-with-runnable-examples, reference app, thin config generator) is sequenced as a recommended P7-1 → P7-2 → P7-3 sub-arc: P7-1 = repo + deps + migration extraction (the riskiest slice — Stele's revisions currently live in the engine's alembic chain); P7-2 = SDK surface + constructed mountable router + the session/config injection contract; P7-3 = reference app + docs + config generator + the WebAuthn-ceremony gap close (the full clone-and-run bar). Sequencing is a recommendation for CR drafting to absorb, not a settled partition. Phase 7 CLOSED: P7-1 + P7-2 + P7-3 all landed (CR-2026-114 + CR-2026-115 + CR-2026-116; engine 32c1a68 + DUNIN7/stele 8246729 — see the header status block). The full clone-and-run-and-use bar is met: a stranger clones the reference host at stele/examples/, runs the baseline migration + the app, and registers a real passkey in a browser that round-trips through stele.router. v0.71 (later same session): the create stage advanced from scoped to partly-shipped. The strip-it-down arc re-scoped doors 2 and 3 (door 2 is product-native — no marketing bridge, no credits/token; door 3 is the lightest door — the document→seed spine already exists), and the converged-spine discovery found all three doors are three text inputs to ONE compose→commit terminal (extract_seed_fields_from_text, which IS the create conversation's own commit step) — the create-stage spine was discovered, not designed. Door 1 is BUILT, LIVE-VERIFIED (headless, to the WebAuthn gate), and SHIPPED — the empty-create-conversation regression is RESOLVED; the create page greets on load (greeting render browser-confirmed by screenshot; the browser passkey-commit is the one pending acceptance step). Door 1 required two CRs (an OL frontend opening-turn + an engine cold-open), because the live check found the engine could not greet from an empty opener (it 400s — a system-only Anthropic call is impossible); the cold-open uses a templated greeting via the orient bypass pattern. Engine main advanced 5ccc3d7 → 5578a05 (--no-ff cold-open merge); OL main advanced 3f2fca8 → 132296f (--no-ff opening-turn merge). Eight CRs now filed for the create stage (the four in Entry 116 plus door-2, door-3, and the cold-open CRs; the withdrawn generator-bridge CR never reached the record). A methodology note filed (operations/loomworks-methodology-scoping-grounding-disciplines-v0_1) capturing two disciplines. See Entry 117 and the §5/§2 updates. v0.72 (later same session): the create stage is COMPLETE — all three doors shipped. Doors 2 and 3 joined door 1, each a thin engine seam over the untouched compose→commit spine plus its OL surface. Door 2 ("I'll tell you") — five foundation questions (incl. the voice) → a turn-writer seam (POST /me/engagements/seed-creation-conversation, batch-records the answers as creation-mode turns via the existing record_turn, no LLM, no commit) → the conversation opens populated → refine → commit through the existing terminal. Engine 5578a05 → 37a3be5; OL 132296f → 807ef8e (both --no-ff). Door 3 ("here's my specification") — upload a document → the existing /seed/extract pulls the five commitments (no commit) → review-and-adjust (one net-new editable field) → amend → commit via the existing /instantiate. Needed only a thin allocation seam (POST /me/engagements/draft-candidate, exposing the existing _allocate_candidate_engagement — a seedless candidate + operator membership). Engine 37a3be5 → 0b2c232; OL 807ef8e → b107290 (both --no-ff). Both live-verified to the WebAuthn gate (door 2: the seed carried all five incl. the voice; door 3: an adjusted voice value survived to commit — "ADJUSTED persisted: True"). Both CR scopes were corrected in-build (door 2 "frontend-only" → needed the seam; door 3 "heaviest door" → the smallest), recorded not smoothed. The create stage is three text inputs to one spine, complete. The browser passkey-commit remains the one pending step across all three doors (the passkey tap is the Operator's, unreachable headlessly). See Entry 118. Correction (2026-06-19): Architecture-spec authority pointer re-pointed v0.4 → v0.5 (architecture/loomworks-architecture-specification-v0_5.md, commit cc96036) — v0.5 landed 2026-06-10 outside the manifest fold-trail, so v0.59–v0.64 carried a stale pointer; corrected in-place as documentation hygiene, no version bump (the manifest stays v0.64). Purpose: To serve as a fresh chat's first orientation. The manifest is a current-status record, not a foundation. The foundation is what-dunin7-is-building-v0_20.md (2026-05-02). The manifest sits above it. Scope of absorption: v0.42 spans 13 days of accumulated state (2026-05-12 to 2026-05-25) — substantially more than the per-phase absorption cadence v0.31 through v0.41 used. See §1.D for the cadence shift and §2 for the consolidation-surface shift. Format note (v0.62). The standalone styled .html manifest convention lapsed after v0.51 (v0.52–v0.62 are Markdown-only); tools/build_site.py renders this .md into the served record-site HTML, which superseded the standalone artifact. v0.62 continues .md-only and flags the deferral here rather than hand-reconstructing a faithful styled standalone from the .md-only v0.52–v0.61 lineage; restoring the portable artifact is a mechanical re-style from the v0.51 template if wanted.


How to read this manifest

Before treating any document in project knowledge as authoritative, check this manifest first. Project knowledge may contain superseded framings, deferred-or-since-shipped predictions, or pre-cleanup-arc references. The manifest reflects current state.

Cross-document hierarchy. The architecture specification (architecture/loomworks-architecture-specification-v0_5.md) is the structural source. The methodology canon (operations/loomworks-methodology-canon-v0_1.html) is the methodology source. The development assessment (substrate/where-we-are-in-loomworks-development-assessment-v0_1.html) frames the Phase A/B/C horizons. The manifest cross-references all three rather than re-stating their content.

The manifest is the absorption layer; the methodology document is the consolidation layer. This separation from v0.41 holds — with one substantive structural shift. A separate consolidation surface emerged between v0.41 and v0.42: the methodology canon in operations/. The relationship between the canon and the anticipated what-dunin7-is-building v0.21 consolidation is an open question (see §3 below).

Repos. Three code repos plus marketing, all under DUNIN7/ on GitHub:

The record repo is DUNIN7/loomworks-record, served at record.dunin7.com via Cloudflare Pages.


Section 1 — Current document authority

Repo names

Unchanged from v0.41. Three code repos plus marketing, all under DUNIN7/. Path conventions as above.

Methodology document

Updated for v0.42 (structural shift). v0.41 named the methodology v0.21 consolidation as outstanding, with the backlog "compounding noticeably." v0.42 absorbs an additional body of methodology contributions from the cleanup arc — but four of those have already been canonized at operations/loomworks-methodology-canon-v0_1, bypassing the v0.21 path entirely.

The structural shift: methodology consolidation now happens on two surfaces:

The relationship between the two surfaces is an open question for the Operator to resolve when v0.21 is undertaken. Possibilities: v0.21 absorbs the canon by reference; v0.21 absorbs only what the canon hasn't taken; the canon eventually replaces the v0.21 consolidation cadence; they coexist permanently on different cadences. v0.42 records the question but does not resolve it.

The other accumulated candidates (Phase 49/50/51/52/53/54/55/56 build findings, plus the candidates surfaced during the cleanup arc that didn't reach canon threshold) remain v0.21 lift candidates.

Current live build front

The Stele extraction is the current live build front. Stele is the principal/identity layer — the fourth Loomworks product alongside OVA, FORAY, and Loomworks itself. The extraction gives the engine's scattered identity code a clean, named module boundary and a host-agnostic contract, moving in small reversible slices with no behaviour change. Phase 0 (complete, engine e4656b4) stood up the stele/ module and moved the three zero-caller-outside-identity files (recovery.py, webauthn.py, session.py) as pure renames. Phase 1 is complete and pushed (engine origin/main f1cf170): the remaining core identity pieces — PersonRow, the two credential row models, the registry (principal view), and credentials.py — moved into stele/ under a shared Base at loomworks.identity_base; four commits, all pure renames with selective per-symbol import repoints; suite green (2920/46/0); no schema change (alembic 0083 unchanged); real-database sign-in + credential read verified from stele/. The KEK did not move (top-level credentials/, untouched). The gating persons.id FK / Base decision was locked before execution: D1 = own-its-own-table (direction), D2 = Branch 1 (code-move now, physical split deferred to Phase 6). Phase 2 is complete and pushed (engine origin/main 677c46f): the two actor constructors (actor_from_personkind="person", actor_from_companionkind="companion" bound to person.id) moved out of orchestration/helpers.py into a new dedicated module stele/actor.py; the project-membership pieces (OperatorProjectNotFoundError, verify_project_membership) stayed in orchestration/ (a split, not a whole-file move); the ActorRef type was referenced, not moved (owned by the memory substrate). Four commits (Step 0 archive, v0.2 re-archive, the collapsed move-and-repoint, the comment/docstring sync); suite green (2920/46/0); no schema change (alembic 0083 unchanged); real-DB person-actor and companion-actor stamps verified from stele/. The CR was amended v0.1→v0.2 mid-flight: v0.1 split the move from the repoints and predicted a runnable suite minus 6 files, but removing module-top-imported constructors before repointing the production routers aborts collection (33 errors); the fix collapsed Steps 2.1–2.3 into one move-and-repoint commit, restoring the Phase 1 mechanic (each move bundled with its repoints, green at every commit). Completion record: loomworks-stele-phase-2-completion-record-v0_1. Phase 3 (get_current_person / session-resolution → Stele) is next — points the auth-path actor resolution (api/deps.py) under Stele; the ~119 session-resolution callers do not move. Halt-before-push; per-step commits; database-truth regression.

Phase 3 is complete and pushed (engine origin/main d3acd84): session→principal resolution moved into Stele as resolve_session in stele/session.py, returning a ResolvedSession(person, payload); all five decode-load sites in deps.py (get_current_person, get_current_person_optional, _resolve_optional_person, _resolve_cookie_actor, _resolve_cookie_contributor) now delegate to it — zero inline decode_session remain. The totp_verified/person-exists policy stays host-side, read off the carried payload; the person actor routes through stele.actor.actor_from_person; membership, can_commit, contributor-membership, and bearer/agent builds stay host-side (the seam: Stele resolves who, the host decides what-here). Four step-commits (3.1 add operation, 3.2 thin three person resolvers, 3.2b contributor seam inspect-first, 3.3 engagement seam + actor route); Step 3.4 verification-only; suite green at every commit (2920/46/0); no schema change (alembic 0083). The CR took three amendments before any code (v0.2 two-resolver finding; v0.3 ResolvedSession carries the payload so the second-factor gate isn't dropped; v0.4 grounding read found five decode-load sites not two), each driven by reading the real engine rather than a line-coordinate guess — the standing lesson: ground the design in a full read of the real code before drafting executable steps. One recorded minor behaviour change: distinct 401 detail strings collapsed to one None-case 401 (status codes preserved, no test affected). Completion record: loomworks-stele-phase-3-completion-record-v0_1. Phase 4 (the sign-up mint↔onboard split, approach B) is complete and merged (see below).

Phase 4 (the sign-up mint↔onboard split, approach B — two-phase) is complete and merged (engine origin/main 9be25fd; branch cr-2026-107-stele-extraction-phase-4 merged fast-forward and deleted local + remote). This is the first schema change in the extraction and the first real behaviour change (Phases 0–3 were schema-neutral pure-relocation slices). The fused complete_totp_verify split into mint_principal (Stele, stele/registry.py) and onboard (host, persons/onboard.py), committing separately: mint commits durably first, then onboard; the route owns both commits with the mint commit explicit and outside get_db_session's rollback scope (viable because the session factory uses expire_on_commit=False). A new onboarding_complete boolean (migration 0084, inverted backfill — existing rows true, new mints false) marks the minted-not-onboarded orphan state; _heal_if_orphaned (both login routes, after the account-status gate, before the cookie) runs onboard(claim_token=None) to complete an orphan on next sign-in. The credit-grant claim moved from the route into onboard; create_person kept separate (bare credential-less primitive, saved-filter tail stripped → relocated to onboard). Step series 4.1 (migration) → 4.2 (mint + strip) → 4.3a/b/c (onboard, two-phase route rewrite, new-semantics test re-points) → 4.4 (heal); suite green at every commit, final 2921/46/0; alembic 0084 on main/playground_dev/playground_test. The CR took **four versions, two corrections caught in build (v0.3 mint signature — sketched from the integration design's contract vocabulary rather than the real :255–284 body; v0.4 heal placement — "before issue_session" sat before the account-status gate, which would have onboarded a suspended/deleted orphan before denying it a session, fixed by moving heal post-gate with a new regression test). Standing lesson extended:** ground the design in the real code not just for which functions exist (Phase 3) but for what a signature is and where a placement sits — a signature is derived from the real body it relocates; a placement is checked against the real code at the placement site. Proven end-to-end in the real database, both halves (a forced onboard failure leaves a clean orphan; signing that same kept orphan back in heals it). Two logged limitations on the failed-signup-with-claim path (failed-signup UX gap; orphaned claim — both rooted in the pending record being discarded at mint-commit). Completion record: loomworks-stele-phase-4-completion-record-v0_1 (loomworks-record ae3775f); session handoff: loomworks-stele-phase-4-to-5-handoff-v0_1. Phase 5 is complete and merged (see below). A correction to the repo working-model recorded at Phase 4 close: engine origin/main sat at d3acd84 through all of Phase 4 — the bcb59f5 v0.2-archive commit lived only on local main and the branch until the Phase 4 merge fast-forwarded origin to 9be25fd; do not assume local main == origin/main between phases.

Phase 5 (credential lifecycle) is complete and merged (engine origin/main 8f2665a; branch cr-2026-108-stele-extraction-phase-5 held, not yet deleted — branch deletion is the Operator's separate step after the completion record files; fast-forward 9be25fd..8f2665a, 7 files / 918 insertions, no merge commit). No schema change — alembic stays 0084 (Phases 0–3 were schema-neutral; Phase 4 was the one schema change at 0084; Phase 5 adds routes and primitives only, the locked hard-delete decision deliberately avoiding a migration). Phase 5 built the two genuinely-missing credential-lifecycle operations and closed one gap on the already-built enrollment path. Grounding first established what was already there: second-passkey enrollment and recovery-code surfacing were already shipping (the latter via the §10.3 amendment — invalidated_at soft-invalidation, the /me/security/ router), so Phase 5 did not rebuild them; the real work was passkey-revoke, person-scoped TOTP-rotate, and the display_name gap. What shipped: (1) passkey-revokeDELETE /me/security/passkeys/{id} + a new Stele remove_credential primitive (the first delete idiom in stele/, hard-delete, flush-in-primitive/commit-in-route) carrying a last-passkey guard at the primitive/service layer (not the router, per the Phase-4 placement lesson); (2) person-scoped TOTP-rotate — a new Stele twin stele/person_totp.py (begin_totp_rotation returns secret + provisioning URI without writing; confirm_totp_rotation verifies the new secret in the primitive, re-encrypts onto PersonRow.totp_secret; no import of contributors/, so stele/ did not grow a dependency on contributors/ — the twin-over-generalize decision protecting the extraction's layering); (3) the display_name field threaded through the passkey-complete route into the existing add_credential call (substrate already accepted it; the route had omitted it). Cut order 5C → 5A → 5B; five commits (archive → 5C → .wrangler/ gitignore → 5A → 5B); suite green at every commit, final 2933/46/0; alembic 0084. The CR took two versions, one a correction caught at Step 0 grounding: the revoke guard predicate was corrected from the scoping note's "block iff passkey_count == 1 AND totp_secret IS NULL" (which treated TOTP as a fallback "way in") to "block the last passkey unconditionally, regardless of TOTP" — because the real production login is passkey-assertion → partial session → then TOTP/recovery, so TOTP cannot mint a session alone and removing a person's last passkey locks them out even with a TOTP secret (the v0.1 OR-predicate would have allowed exactly that). The other two decisions: hard-delete-over-soft-delete-column (stays at 0084), and person-scoped-twin-over-generalize. Two build deviations CC caught and resolved: (a) the prescribed git add -A swept a Cloudflare credential file (.wrangler/cache/wrangler-account.json) into the 5C commit — amended out before any push (nothing left the machine), .wrangler/ gitignored as its own commit, and explicit-path staging adopted from 5A onward (the class-fix, not just the instance-fix); (b) the hard-delete tripped the non-erasure architectural guard tests/test_no_delete_statements.py (R-A28/R-B21) — resolved the guard's designed way by adding credentials.py to the file-level allowlist with a rationale matching the six existing precedents and the sibling OVA-credentials module's documented discipline (a credential is operational auth, not a MemoryObject / event-log entry* — so the delete is outside the non-erasure invariant's domain, not an exception to it; Operator-reviewed verbatim against the precedents before push). Standing lesson extended again: grounding now covers **the architectural invariants that police the kind of change being made, not just function inventory (Phase 3) and signatures/placements (Phase 4) — the guard collision surfaced at build (5A) because Step 0 read the placement site and call-sites but not the repo-wide guard suite; the lesson was applied immediately in 5B (a read-only guard-suite scan before editing, which came back clean: rotate overwrites a column, no delete). Proven end-to-end in the real database — all six §7 cases on the real HTTP path through real get_db_session, only the WebAuthn crypto verify stubbed: the corrected guard refuses a last-passkey-with-TOTP revoke with a real 409, a two-passkey person revokes one and signs in with the other, a valid rotate makes the old TOTP code fail and the new one pass on a real sign-in, an invalid-code rotate leaves the old secret intact, and no person ends a revoke at zero passkeys. The SSO forward-dependency is recorded in the guard's code comment and the completion record: SSO is not built (a seed commitment ahead of the build, per Phase 14 Decision 7 / Phase 48 deferral); the guard counts passkeys only today, and when org-SSO lands the predicate widens to "last passkey AND no SSO binding." Completion record: loomworks-stele-phase-5-completion-record-v0_1; governing CR: cr-2026-108-stele-extraction-phase-5-v0_2. The next slice is the de-engine-ing toward the standalone repository (Phases 6–7); see the standalone-distribution milestone paragraph below.**

Phase 6a (the expand half of the physical persons split) is complete and merged (engine origin/main def8b04; branch cr-2026-109-stele-extraction-phase-6 held, not yet deleted; fast-forward 8f2665a..def8b04, 11 files / 1503 insertions, no merge commit). This is the slice the Phase-5 paragraph's "next is the de-engine-ing toward the standalone repository (Phases 6–7)" pointed at — and the manifest-vs-brief tension flagged there is now resolved by the work (see the standalone paragraph below). Second schema change in the extraction (migrations 0085/0086, alembic 0086), and the first to move existing data — expand-contract chosen for reversibility (the expand half lands the tables with both shapes live and nothing dropped; the contract — dropping persons's now-duplicate columns and retiring the triggers — is a separate later step). What landed: persons split into principals (Stele's own new Base stele/base.py; the 7 identity/auth columns; the 2 credential FKs re-pointed inward to principals.id; zero outward FK) and host_account (host Base; PK id = principal id via a DEFERRABLE deferred FK; the 16 host columns), sharing one id 1:1. persons keeps all 23 columns; two AFTER INSERT OR UPDATE mirror triggers keep principals and host_account in sync with every persons write — so the re-pointed credential FK resolves and the Phase-4 orphan/heal path works across two tables with no mint_principal change (the triggers are the writer-of-record for the new tables during expand). The build was two code commits (1.3 principals + credential moves + 0085; 2.1 host_account + 0086) plus the Base scaffold (1.2); Steps 3–6 produced no code — Step 3 records the deferred view-seam, Step 4 folds to a carry-forward (triggers cover the mint seam), Steps 5–6 are verification-only. Four inspections each changed the plan before damage (the richest correction trajectory in the extraction): Option B sequencing (1.2), the dual-write ordering bug + sync trigger (1.3), model-layer rename-to-find (Step 3 scoping), and the 6a/6b split when the Step 3.1 inspection found the Person view is fused. The host_account → principals FK is DEFERRABLE INITIALLY DEFERRED because the two triggers fire in name-sort order (host before principals), so the deferred check resolves at commit once both rows exist — proven on the real DB. Verified end-to-end on playground_dev (parity 41/41/41; both triggers mirror to the right table with clean separation; real HTTP signup creates all three rows; orphan heals across both tables). Suite 2933/46/0. Completion record: loomworks-stele-phase-6a-completion-record-v0_1; governing CR: cr-2026-109-stele-extraction-phase-6-v0_7. Carry-forwards: the Person-view split → CR 6b (the next slice — Stele's Person view carries six host columns and the ~150-site host blast radius flows through it; the split into a pure Principal view + host view, with the host-read re-home via model-layer rename-to-find, starts from the three stele sites registry.py Person view / get_person_by_email / actor.py actor_from_companion); the mint host-column cleanup and the 12 host-FK re-target and the ordered trigger-pair retirement → contract; the failed-signup HTTP-500 → the Phase-4 logged limitation, unchanged.

Phase 6b complete and merged (129d124, CR v0.7). Every host-field reader re-homed; Person name retired at the view and function layer; no twin reached main (verified on the merged tree). The contract arc that followed is now complete: CR-A (CR-2026-111, host-side teardown — persons reduced to principal-only, host_account sole host home) at bee2b4c; CR-C (CR-2026-112, identity-table collapse — principals canonical, mirror reversed) merged at d0f302e; CR-B (CR-2026-113, host-FK re-target + mirror retire + persons drop) merged to engine main at fe7c3f1 (branch cr-2026-113-stele-cr-b retired). With CR-B, persons is gone and identity is wholly on principals. Phase 7 scoping complete, fork resolved B-first, CR drafting next.

Standalone-distribution milestone (named v0.53; framed in brief v0.4). The Operator will take Stele to the Claude Code Miami group for independent testing — which requires Stele as a clone-and-run standalone repo (code + SDK + comprehensive documentation with runnable examples + a reference UI template), with no residual DUNIN7/Loomworks dependency. The persons.id FK on the credential/recovery rows was the gating design question: standalone Stele either owns its own principal table or defines the FK as a host-supplied contract. This is now locked AND, for the table split, executed: D1 = own-its-own-table; D2 = Branch 1 (code-move first, physical split in Phase 6). Phase 6a landed that physical splitprincipals is Stele's own table on Stele's own Base, the credential/recovery FKs point inward at it, and Stele's MetaData is now self-contained with zero outward FK (the structural precondition for the standalone repo). The Phase 1-era manifest-vs-brief tension is now resolved by the work: the manifest's "physical split deferred to Phase 6 (D2 = Branch 1)" and the brief's "Phase 6 = de-engine + packaging" are reconciled by the split-first decision and the 6a/6b split — Phase 6 = the physical split (6a, the table split, done; 6b complete); the contract phase and then Phase 7 (de-engine + packaging) are the remaining Stele slices. The two documents no longer disagree: the table split is a Phase-6 item (as the manifest's D2 said), done in-engine before packaging (as the split-first decision settled), and the brief's de-engine/packaging work is Phase 7. The Stele body-of-work brief v0.4 (loomworks-record main a7ed9e6) names the standalone repository as Stele's terminal form, frames the FK decision with both branches and their standalone consequences, folds the standalone deliverables into a re-sequenced phase plan, and names the Phase 0 WebAuthn-ceremony gap as closing at the reference UI (Phase 7). The Miami date is the Operator's to set against real phase progress.

Canonical documents on loomworks-record main (brief v0.4 at a7ed9e6; the others unchanged since 047d90a):

Locked decisions (do not relitigate): (1) contract surface approved, including the white-label hooks tenant_context + locale — Stele holds no brand, outcomes are structured codes hosts translate; (2) sign-up split = approach B (mint-then-onboard with a heal path) — Phase 4, not Phase 0; (3) move, not duplicate — one implementation throughout, safety from small reversible commits, not a parallel fallback. Detail lives in the three documents above; the manifest does not duplicate it.

A second active strand — the Companion / Operator-Layer surface — also carries unabsorbed-until-v0.69 work. Parallel to the Stele substrate extraction, the Companion surface advanced on feat-companion-surface: the add-side rework (spoken-note capture, engine Phases 1–4 merged to main at 5ccc3d7; OL Phase 5 at 8bd73f2, tagged add-side-rework-ol-v0_1) and today's mobile Companion surface (dac9fec). This strand is frontend-and-responder work on the Operator Layer; the Stele strand is substrate. They are independent. The mobile Companion surface resolved the build-queue-v0.3 open gap ("mobile in-engagement transcript — confirm intended end state") and is recorded in §3 Entry 114; the add-side arc is Entry 113. Update (2026-06-28, later session): this strand is now MERGED to OL main. The feat-companion-surface integration line — carrying the add-side OL half, the mobile Companion surface, and (added this session) create-restore and the seed viewer — merged to Operator-Layer main at 3f2fca8 (--no-ff, 36 commits, merged-whole suite green, lint red as standing baseline). The Companion surface and OL main no longer diverge. The feat-companion-surface branch is fully contained in main and retained pending a confirmation the merged main runs live (then retire-able). The Companion-surface work has additionally turned to the engagement create stage — the seed lifecycle's authoring step — now scoped as a three-door design (Entry 116); the seed viewer is its lifecycle sibling (view), the seed-editor CR (cr-seed-editor-v0_1) its edit sibling.

Loomworks engagement seed

Corrected at v0.52. Canonical seed is v0.12 (2026-06-07), not v0.9. The v0.42 deferral framing below is now stale: the seed bumps it named as candidate work have landed — v0.10 (Memory widened to N-scope), v0.11 (the Memory contribution/write-access axis), v0.12 (the two-tier sign-up posture: open signup with automatic commons membership, un-invited path volume-limited, authorized lift raises the ceiling, lift mechanism deferred to spec). The next seed bump, if warranted, is the one that absorbs the Stele/fourth-product framing — named as candidate work, not produced here.

Stale framing preserved per corrections-not-smoothed discipline: v0.41 said "defer the seed bump and revisit at manifest consolidation pace." v0.42 reassessed and named a v0.10 bump as warranted to capture the cleanup-arc framing shifts. That bump and two further bumps have since landed (see correction above).

Loomworks engagement state

Updated for v0.42. Engagement assertions accumulated through Phase 56 (E0001's Memory holds the build-up through "voice work discipline"); the cleanup arc's three CRs added implicit Memory state through the architecture spec v0.4 and methodology canon landings, but no engagement-level assertions for the cleanup arc itself were contributed. v0.42 notes this as a candidate Operator action — contribute assertions to E0001 capturing the cleanup arc's framing shifts.

Substrate state

Updated for v0.50 (engine + Operator Layer substrate-state refresh).

Engine: 2,930 tests collected / 2,884 passed at HEAD 56f2b6b (after CR-2026-099 orientation, CR-2026-100 personal recall, and the orient current-values + Path-A formatting enhancement all landed and tagged, 2026-06-10/11). Up from 2,829 at v0.49's 5472335. 46 skipped (calibration-gated and conditional tests, plus the new gated live-classifier tests for orient + personal recall). 0 failing on the 2026-06-11 full-suite run — the full suite is green; the four failures the v0.49 (2026-06-07) run recorded did not reproduce on this date (the two test_phase_44_evaluator dedup tests are the date-sensitive evaluator-dedup family — see below; test_api_assertion_retract and test_dismissal_patterns_cadence did not fail on current main at this run date).

Phase-44 flake characterization (carried from v0.49): the last two are not random flakes (both fail 3/3 deterministically in isolation) and not a fixed pair — they are a date-sensitive Phase-44 evaluator-dedup family (the dedup compares fixture timestamps against real now()), so which subset fails varies by run date. v0.42's "2 pre-existing failures" reflected its run date; on 2026-06-07 both dedup tests fail, at baseline and HEAD alike. Treat the pre-existing set as the whole dedup family, not a fixed count.

Alembic head: 0081 (was 0073 at v0.42, 0064 at v0.41). Migrations 0079–0081 — step-up auth (organizations + memberships + per-user presence; engagement always-tap override) — landed on main between v0.42 and now; CR-2026-097 itself added no migration (provenance rides the existing assertion metadata).

Substrate shape after the cleanup arc (replacing the three FORAY-shaped tables v0.41-era substrate carried):

New engine module: src/loomworks/foray/ with three files: __init__.py (re-exports), reserved_emit.py (no-op emitter), anchor_priority.py (19-entry registry). Sixteen reserved-location call sites across the engine: 3 audit + 1 memory + 12 credit. All carry # FORAY_RESERVED_LOCATION: <namespace>.<event_kind> grep markers.

Frontend state — Workshop (loomworks-ui): Unchanged from v0.41. HEAD remains at 7f35825 (2026-05-06, Phase 45 step 14). 282 vitest (29 files); eslint 0 errors / 1 pre-existing warning; tsc/build clean. Workshop is intentionally frozen at the Phase 45 four-room engine-internals shape. This is positioning, not neglect — active product development happens on the Operator Layer. The architecture spec v0.4 §10 makes this explicit; v0.42 inherits the framing.

Frontend state — Operator Layer (loomworks): Updated for v0.50. HEAD 4ffb3ff (2026-06-11, Path-A newline-honoring CSS for the navigation companion reply). Prior 4e43e9f = CR-2026-099 Step 4 (orientation surfaced on the in-engagement + navigation surfaces via SuggestedActions + the recogniser extension). Tag companion-orientation-discovery-v0_1 on OL at 4e43e9f; the Path-A CSS one-liner at 4ffb3ff is untagged. (Supersedes the stale 054b0c2 v0.42 snapshot — Entry 109 had already moved OL to a673524; the §1 block wasn't refreshed in step until now.) Earlier OL state carried forward: upload pathway operator-reachable end-to-end as of 2026-05-27 (OL 2186d13, untagged), engine writes UploadEventReceived events with provenance, assertion-drafting unbuilt (queued-directions v0.21 §15.3); voice modality matured (silence-submit threshold default 2.5s, recognizer E-prefix expansion, voice-provenance input_mode marker, in-engagement voice listening, brass microphone glyph on voice-origin turns). Updated for v0.70 (2026-06-28). OL main is now 3f2fca8 — the merged Companion-surface arc (see header status). Suite 451/451; tsc 4 known pre-existing errors (3 TagChipArea + 1 RefreshFocusOnIntent), no merge regressions; vocabulary-wall green; lint 25 errors / 14 warnings (standing baseline — see §5). The arc includes: CR-2026-125 focus/current-engagement, the Companion surface integration (mockups 1–4, in-engagement + lens-home), list-loading CR-2 (keyset pagination on rooms/lenses/conversation), voice panel + per-bubble timestamps, the add-side rework (Entry 113), the mobile Companion surface (Entry 114), create-restore (the lens-home create button), and the seed viewer (live-verified). Engine main unchanged at 5ccc3d7; alembic unchanged. Updated for v0.71 (2026-06-28): OL main advanced 3f2fca8132296f (door-1 opening-turn merge, --no-ff); engine main advanced 5ccc3d75578a05 (door-1 cold-open merge, --no-ff); alembic unchanged. Prior SHAs preserved as trajectory. (See header status + Entry 117.) Updated for v0.72 (2026-06-28): the create stage completed — doors 2 and 3 shipped. OL main advanced 132296f807ef8e (door-2 surface, --no-ff) → b107290 (door-3 surface, --no-ff); engine main advanced 5578a0537a3be5 (door-2 turn-writer seam, --no-ff) → 0b2c232 (door-3 allocation seam, --no-ff); alembic unchanged (both seams reuse existing helpers, no migration). Prior SHAs preserved as trajectory. (See header status + Entry 118.)

Marketing repo (loomworks-marketing): Updated for v0.42. HEAD at 0d86610 (2026-05-17, "Fix four-stage phrasing on home — Memory, Manifestation, Shaping, Rendering"). This commit appears to address one of v0.41's three held marketing-site content observations (the room-order rendering issue). Status of the other two observations — "Manifestation paired with 'ships into the world'" and "broader frame-level question about substrate vocabulary outward" — awaits Operator confirmation.

Phase CRs and tags

Updated for v0.42 (substantial). Tag history since v0.41 (chronological):

| Date | Tag | Type | What | |---|---|---|---| | 2026-05-14 | phase-58-upload-pathway | Numbered phase | Upload pathway substrate | | 2026-05-15 | phase-59-upload-pathway-completion | Numbered phase | Upload pathway completion | | 2026-05-18 | voice-listening-v0_1 | Named ship | Voice listening §A + §B (preference store + Companion tune_setting) | | 2026-05-19 | sign-out-v0_1 | Named ship | POST /auth/logout endpoint | | 2026-05-19 | in-engagement-surface-fill-in-v0_1 | Named ship | Conversation-history 404 fix | | 2026-05-19 | engagement-list-scoping-v0_1 | Named ship | GET /engagements scoped to caller's memberships | | 2026-05-19 | composer-placement-and-message-order-v0_1 | Named ship | Composer placement + message_order | | 2026-05-19 | foray-audit-for-settings-v0_1 | Named ship | The audit substrate later renamed by CR-A | | 2026-05-19 | voice-tryprompts-to-tooltip-v0_1 | Named ship | Voice try-prompts → tooltip (bundled commit) | | 2026-05-19 | top-bar-cleanup-v0_1 through _v0_3 | Named ships (×3) | Three tags on same substrate commit | | 2026-05-20 | voice-pill-padding-engagement-navigation-v0_1 | Named ship | Voice pill padding (bundled with voice-provenance) | | 2026-05-20 | voice-provenance-v0_1 | Named ship | input_mode column on conversation_turns | | 2026-05-20 | voice-recognizer-e-prefix-v0_1 | Named ship | Voice recognizer E-prefix expansion | | 2026-05-20 | voice-listening-silence-submit-v0_1 | Named ship | Voice listening silence-submit | | 2026-05-24 | phase-61-audit-cleanup | Numbered phase (CR-A) | Substrate hygiene cleanup arc, first sibling | | 2026-05-24 | phase-62-memory-events-cleanup | Numbered phase (CR-B) | Substrate hygiene cleanup arc, second sibling | | 2026-05-25 | phase-63-credit-substrate-cleanup | Numbered phase (CR-C) | Substrate hygiene cleanup arc, third sibling; closes Phase A | | 2026-06-10 | companion-orientation-discovery-v0_1 | Named ship | Companion orientation & discovery (capability ships) | | 2026-06-10 | companion-orientation-discovery-v0_2 | Named ship | Orientation composition fix (server-compose, fabrication-proof) | | 2026-06-11 | personal-recall-v0_1 | Named ship | First-class cross-engagement personal recall | | 2026-06-11 | companion-orientation-discovery-v0_3 | Named ship | Orientation current-values stated + Path-A list formatting |

(Note: the table has been a v0.42 snapshot since v0.43, with intervening landings recorded via §3 entries instead. These four rows are added for the session's tags; the authoritative landing record is the §3 entries below.)

Phase 57: no engine tag. Identifier was reassigned mid-flight. Local branch phase-57-marketing-engagement-creation exists on engine and Operator Layer but never produced a tag.

Phase 60: no engine tag. Phase 60 is Companion-as-Operator-system-interface, closed mid-May on the Operator Layer at tags phase-60-close-v0_1 (835936b, 2026-05-16) and phase-60-recovery-v0_1 (7868851, 2026-05-16); no engine tag because Phase 60 was Operator-Layer-only. The phase-60-operator-layer-upload-pathway-v1 branch name that v0.42 read as "in flight" was separate, mislabeled work — upload-pathway-v1 — and is now deleted from refs; the actual upload-pathway landing is untagged at OL 2186d13 (2026-05-27). See Entry 101 correction and §15.3 for the remaining engine-side upload work (assertion-drafting from UploadEventReceived).

Investigation documents

Updated for v0.42. New investigations and substrate documents in the record since v0.41:

Phase 58 implementation notes

New for v0.42. Upload pathway substrate. Engine repo 2a6a753. (Not landed as separate implementation notes in the record at this manifest's authoring; consider whether to lift if the Operator wants the trajectory persisted.)

Phase 59 implementation notes

New for v0.42. Upload pathway completion (CR-2026-092 v0.4). Engine side. (Same posture as Phase 58 notes.)

Phase 60 implementation notes

Not in the record at this version. Phase 60 (Companion-as-Operator-system-interface) closed mid-May without producing a record-resident implementation-notes artifact; the tune_setting handler is the first shipped instance per §2.B. Any implementation-notes write-up is identified-but-not-actioned work, alongside the broader numbering-reconciliation pass named in §5. See Entry 101 correction.

Phase 61 implementation notes

New for v0.42. phase-61-implementation-notes-v0_1.{md,html} at substrate/cleanup/. Captures the CR-A close: audit.foray_eventsaudit.events; foundation module src/loomworks/foray/ established with _foray_reserved_emit no-op; 3 reserved-emit call sites; reserved slot 1 of 2 consumed (FK deviation — orphan-row protection cost exceeded benefit given Loomworks' deletion semantics). Validates the per-call-site reserved emit pattern.

Phase 62 implementation notes

New for v0.42. phase-62-implementation-notes-v0_1.{md,html} at substrate/cleanup/. Captures the CR-B close: memory_events Phase 25 wiring cleanup. The attestation column renamed to commit_webauthn_attestation as a true Alembic rename (1 existing non-null row carrying real WebAuthn proof preserved). _ANCHOR_PRIORITY registry relocated to src/loomworks/foray/anchor_priority.py. Both reserved slots consumed (test scope expansion finding + raw-SQL INSERT helper discovery — informs canon Principle 4).

Phase 63 implementation notes

New for v0.42; closes the cleanup arc. phase-63-implementation-notes-v0_1.{md,html} at substrate/cleanup/. Captures the CR-C close: credit.foray_action_flowscredit.flows via in-place RENAME. Trigger continuity verified empirically (synthetic-INSERT test confirmed the trigger fires on the renamed table; the update_balance_on_flow trigger binds to table OID and follows the rename transparently). 12 reserved-emit call sites — validates the per-call-site discipline at scale. 9-value typed event_kind taxonomy added with legacy_unknown fallback.

Methodology canon v0.1 — new in record

New for v0.42. operations/loomworks-methodology-canon-v0_1.{md,html} (commit de23c31). The standing canon of methodology principles earned through execution evidence. Four principles in v0.1 (see §2.A below). Discovery-trajectory discipline applies — v0.2/v0.3 will land alongside v0.1 when consolidation continues.

Architecture specification v0.4 — new in record

New for v0.42. architecture/loomworks-architecture-specification-v0_4.{md,html} (commit 7da12f1). v0.3 preserved untouched at architecture/loomworks-architecture-specification-v0_3.html per discovery-trajectory discipline. v0.4 absorbs four substantive sets of changes since v0.3: FORAY reframing (load-bearing), methodology canon integration, voice modality maturation, Workshop framing made explicit. Superseded as authority by v0.5 (architecture/loomworks-architecture-specification-v0_5.{md,html}, commit cc96036, landed 2026-06-10) — a focused reconciliation bringing the Companion framing (§02, §08) into line with the Companion architecture foundation note v0.2: the Engine is the product and the authority, and the Companion is an optional access layer over the Engine's API (operational agency, never sovereign; Operator-direct and Companion-mediated both first-class). v0.4 preserved alongside per discovery-trajectory discipline. v0.5 is authoritative for current architectural framing. (Pointer corrected in-place 2026-06-19 — see the Correction note in the header; no version bump.)

Record-production-discipline note — new in record

New for v0.42. operations/record-production-discipline-v0_1.{md,html} (commit 73e947a, 2026-05-24). Establishes the direct-to-record production discipline: documents with discovery-record value land in the record automatically as part of producing them, not as a separate later step. Path A (Claude.ai → Downloads → Claude Code, for substantive new artifacts) and Path B (in-record editor at record.dunin7.com, for small edits) named. The Downloads-as-staging step retired for record-bound documents.

Session handoff

Updated for v0.42. The closing artifact of the substrate hygiene cleanup arc is the Phase 63 implementation notes at substrate/cleanup/phase-63-implementation-notes-v0_1.{md,html}. No standalone session handoff at v0.42; the cleanup arc's trajectory is preserved across the 14 documents in substrate/cleanup/.


Section 2 — Named principles and patterns

2.A Promotions to methodology canon v0.1

Four principles were lifted to canonical status at the cleanup arc's close (record commit de23c31). v0.42 records the promotions; the canon at operations/loomworks-methodology-canon-v0_1.html carries the authoritative statements, evidence bases, and boundary conditions. Brief summaries:

  1. Per-call-site reserved emit. When a code path is being prepared for future external integration, the reserved-location marker lives at each business-event site, not centralized in helper writers. Evidence: 3 / 1 / 12 sites across CR-A / CR-B / CR-C.
  1. Test-filename-to-current-substrate alignment. When a test's filename framing references a cleaned-up origin, rename to reflect current substrate or delete if functionality is gone. Four-instance evidence including a negative case at CR-C (zero renames needed because filenames were already accurate — validates the principle in its negative form).
  1. Migration strategy: rename when downstream bindings exist; recreate when independent. Choose by what binds, not by default preference. Evidence: CR-A drop-and-recreate (no bindings), CR-B column rename (ORM bindings followed), CR-C table rename (trigger and FK followed via table OID).
  1. Inventory enumeration vs cognitive density. Inventories enumerate references but undercount cognitive density per reference. Design steps should grep for assertion patterns and reader sites directly; per-test-function enumeration is more reliable than per-file enumeration. Evidence: CR-B's slot-1 finding (10 incidental files actually contained 4 directly-testing functions plus raw-SQL helpers), CR-C's per-file density finding (21 + 29 + 17 references in three files).

2.B New in v0.42 — from the cleanup arc

Substrate-friction-discipline-pattern (already named in v0.41 / earlier): the cleanup arc exercised this pattern across three sibling CRs. Reserved slots consumed cleanly within budget. The pattern continues to hold operationally.

Halt-and-surface beats absorb-silently (named; not yet canonized): every CR in the cleanup arc honored the Checkpoint A halt before merge. CR-B's slot 1 surfaced execution-time discoveries (4 additional test functions + raw-SQL INSERT helper); CR-C's slot 1 surfaced 4 more execution-time discoveries (multi-line JSONB predicate, UUID/str type comparison, two missed raw-SQL queries, mangled import). All surfaced cleanly through the halt-and-surface discipline rather than absorbed in CR execution.

Direct-to-record production discipline (now established as standing discipline): see operations/record-production-discipline-v0_1. The Downloads-as-staging step retired for record-bound documents. Documents land in the record automatically as part of producing them.

HTML-companion-as-part-of-producing-the-document discipline: every record document has both .md and .html with Loomworks letterpress styling. Established mid-session (commit 73e947a).

2.C Sharpening of existing principles — from the cleanup arc

Seam-and-stub progression sharpened to "reserved-location pattern." v0.41's framing of OVA integration via seam-and-stub generalized: the cleanup arc applied the same pattern at 16 sites for FORAY integration, with _foray_reserved_emit("<namespace>.<event_kind>", payload) calls at each call site plus # FORAY_RESERVED_LOCATION grep markers. The pattern is now Loomworks-wide; v0.4 of the architecture spec §09 carries the framing.

Discovery-record posture validated at scale. The cleanup arc's complete trajectory — scoping note v0.1 → inventory → scoping note v0.2 → three CR designs → three CR drafts → three implementation notes → methodology canon v0.1 → architecture spec v0.4 — lives in the record as a connected discovery sequence. Anyone reading the section indexes can follow the trajectory end-to-end. This is the strongest validation of the posture to date.

Companion-as-Operator-system-interface principle (post-Phase 60; named). The Companion is the primary surface for all Operator-system interaction including preferences, configuration, and policy — not just conversational work. Phase 60's tune_setting handler is the first instance. Listed in v0.4 architecture spec §12 as operative discipline; v0.42 records it here for absorption.

Guarantee-enforcement generalizes from composition to classification (new v0.50). The established principle — a correctness guarantee whose content is authoritative is enforced in code, not requested in a prompt, because soft guidance loses to a strong model prior under context pressure — now has its second strong instance, on a different surface. CR-2026-099's composition fix established it for replies (the orientation reply is a structural contract over generated registry data, so it is composed server-side, bypassing the responder LLM that otherwise fabricated under domain-context pressure). CR-2026-100's structural orient-guard establishes it for classification (a recall query must never land on the orientation bypass; soft classifier guidance lost to the "what can you ___" capability prior, so the guarantee is enforced by a deterministic post-classifier guard, not by classifier persuasion). The general statement: when correctness is a guarantee and the LLM holds a prior that pulls against it, enforce the guarantee deterministically in code — the prompt is where you state preferences, not where you secure invariants. Two instances across two surfaces (composition, classification); on the three-instance cadence this is a strong candidate for canon promotion at the next consolidation.

2.D Methodology candidates awaiting framing (v0.21 consolidation candidates)

Carried forward from v0.41 (still pending v0.21 consolidation pass):

New for v0.42 (cleanup-arc candidates that didn't reach canon threshold):

New for v0.62 (Stele contract-phase / CR-A lessons, flagged for the v0.21 consolidation pass — CR v0.3 §11):

New for v0.64 (Stele CR-B lessons; full statements in loomworks-stele-cr-b-completion-record-v0_1 §8):

New for v0.71 (create-stage scoping/grounding disciplines; full statements in operations/loomworks-methodology-scoping-grounding-disciplines-v0_1):

Structural shift in v0.42: The v0.21 path is no longer the only lift surface. Principles that earn three-instance evidence in a single arc may land in the methodology canon directly (consolidation-after-arc cadence). The relationship between the v0.21 path and the canon is an open question (see §1 above). Candidates listed here may, by the time of v0.21 consolidation, have been canonized via a different path.


Section 3 — Entries

Numbered phase entries follow the v0.41 convention: Provenance / Content / build summary / methodology contributions / trajectory / build-quantitative summary.

Earlier entries (Entry 1 through Entry 98 / Phase 56) carry forward by reference from v0.41 and prior manifests. v0.42 adds Entries 99 through 104.

Entry 99 — Phase 58: Upload pathway substrate (new v0.42)

Provenance. Tagged phase-58-upload-pathway on engine 2026-05-14. Substrate-only.

Content. Upload pathway substrate established. Foundational work for the in-engagement upload surface.

Trajectory worth recording. Phase 58 shipped before Phase 57 (Phase 57 was a reassigned identifier; see Entry 99-A note). Upload pathway became the natural next surface after the engagement-creation arc closed at Phase 56.

Build-quantitative summary. Substrate-only at Phase 58 close. Operator Layer surface-reachability landed separately, untagged, at OL 2186d13 (2026-05-27, /chat?project=<id> restoration); the in-engagement-composer upload-port (item 3, Shape 2) is identified-but-not-done. Phase identifier for the OL upload-pathway work is unreconciled (§5); this is not Phase 60's work (see Entry 101 correction).

Entry 99-A — note on Phase 57 reassignment

v0.41 anticipated Phase 57 as "Phase 32 marketing engagement" (strongest candidate), with alternates Option C (Discovery render specialists) and explain-affordance investigation. Reality: Phase 57 identifier was reassigned mid-flight. A phase-57-marketing-engagement-creation branch exists on engine and Operator Layer but never produced a tag. v0.42 records the prediction-vs-reality gap honestly — not because v0.41's selection criteria were wrong, but because the actual selection criteria turned out to be different (see §4 below for completion plan honesty).

Entry 100 — Phase 59: Upload pathway completion (new v0.42)

Provenance. Tagged phase-59-upload-pathway-completion on engine 2026-05-15. CR-2026-092 v0.4.

Content. Upload pathway completion on the engine side. The substrate is operationally complete; the Operator Layer surface-reachability landed separately at OL 2186d13 (2026-05-27, untagged), and is not Phase 60's work — Phase 60 is Companion-as-Operator-system-interface (see Entry 101 correction). The in-engagement-composer upload-port remains identified-but-not-done as item 3 (scoping note at change-requests/loomworks-composer-upload-port-scoping-note-v0_1).

Build-quantitative summary. Engine side complete. OL upload-surface reachability landed separately at 2186d13 (2026-05-27, untagged); the in-engagement-composer upload-port (item 3, Shape 2) remains identified-but-not-done. Phase identifier for the OL upload-pathway work is unreconciled (§5).

Entry 101 — Phase 60: Companion-as-Operator-system-interface (closed mid-May)

Correction note. v0.42 and earlier labeled Entry 101 "Phase 60: Upload pathway v1 (in flight)." That label was wrong. It keyed off the Operator Layer branch name phase-60-operator-layer-upload-pathway-v1, which is now deleted from refs and never produced a tag. Phase 60 in the record's canonical phases/ taxonomy is phase-60-companion-as-operator-system-interface, and this same manifest's §2.B already names Phase 60's first instance as the tune_setting handler — a Companion-as-interface deliverable, not upload work. The label is corrected here; the prior position is preserved in this note per corrections-preserved discipline.

Provenance. Operator Layer tags phase-60-close-v0_1 (835936b, 2026-05-16) and phase-60-recovery-v0_1 (7868851, 2026-05-16). No engine tag.

Content. Phase 60 is the Companion-as-Operator-system-interface work: the Companion as the primary surface for Operator-system interaction (preferences, configuration, policy), not only conversational work. The tune_setting handler is the first shipped instance. Closed mid-May.

The upload-pathway work that wore the Phase 60 branch name — landing identifier unresolved. Separate from Phase 60. The upload pathway is operator-reachable end-to-end as of 2026-05-27, restored at Operator Layer commit 2186d13 (the /chat?project=<id> route restoration), which is untagged. The engine writes UploadEventReceived Memory events with full provenance (verified 2026-05-28). The remaining engine-side gap — drafting held Assertions from those events — is tracked as queued-directions v0.21 §15.3. Which phase identifier this OL work belongs under is unreconciled; see Section 5.

Entry 105 — 2026-05-28 cleanup-and-scoping arc (new v0.43)

Content. A four-item session (plus one promoted item). Items closed: configuration-drift remediation (engine b793aef, 427c446.env.example reference checked in, RP-origin test decoupled) and the test-override audit (engine d5d57ee — two missed upload-test fixtures brought to the production session envelope; eight upload-test fixtures now uniform; conftest divergence recorded as load-bearing-by-design). Filed: queued-directions v0.21 §15.3 (upload content does not reach assertion grain; plus two independently-timed documentation corrections). In progress: item 3, file upload through the in-engagement composer — Shape 2 (shared upload hook) chosen; scoping note at change-requests/loomworks-composer-upload-port-scoping-note-v0_1 (.md/.html). Deferred: §13.3 Operator real-passkey registration (unsequenced).

Active work resumes at. Item 3's Change Request — the next artifact — beginning with the cross-layer-seam decision (composer upload direct-to-engine via existing postUpload, vs. an Operator Layer gateway route). See the scoping note's open question 1.

Detail lives in. Queued-directions v0.21 §15.3; the composer-upload-port scoping note v0.1; session handoff 2026-05-28 evening v0.1. This entry is a pointer, not a restatement.

Entry 106 — Source identification shipped and merged (2026-05-29)

What landed. Source identification — the first build on the Memory-completion path — shipped and merged to main on both code repositories. The work unifies conversation-turn provenance onto the existing ActorRef model, so conversation turns now record source the same honest, provenance-grounded way assertions always have, and the Operator Layer surface labels turns by their true source.

Governing document. Change Request CR-2026-094, document version 0.2, filed at change-requests/loomworks-source-identification-cr-v0_2.md (version 0.1 preserved alongside per the corrections-preserved discipline). Executes source-identification scoping note version 0.2 (decisions D1 through D5).

The capability, in plain terms.

Merged state (current baseline).

Baseline reconciliation (note, not a correction to earlier entries). Version 0.43 recorded the engine baseline as 573abe1. That figure is truthful-but-behind: 573abe1 (the Phase 63 credit-substrate-cleanup merge) is a clean ancestor of d5d57ee (the pre-source-identification main, three commits ahead — the 2026-05-28 cleanup arc Entry 105 records), which is in turn the parent line of the merged daee809. So the lineage is 573abe1d5d57eedaee809. The current engine main baseline is daee809 (alembic 0074). Earlier entries' 573abe1 lines are left as written; this entry states the current figure.

Acceptance. Engine suite 2687 passed / 2 pre-existing failures (unchanged by identity) / 0 errors; the migration applies and reverses cleanly. Operator Layer suite 412 passed; typecheck and lint at baseline. Live authenticated check against the running stack confirmed each source-kind renders its honest label end to end, including the additive Domain Expert marker and the Contributor-not-Operator fix. The conversation-turn path was treated as a Memory write path throughout — tested against production-session behaviour, not a green suite alone (the lesson from the upload-pathway arc, where a green suite masked a broken production path).

Tracked follow-ups (recorded, not blocking).

Position on the path. Source identification was step one of the Memory-completion path. The named next step is the four-room credit spend-gate (the major build that meters and gates the Memory → Manifestation → Shaping → Rendering pipeline before it is surfaced) — a horizon, not started. The branch merges close the development-database-ahead-of-main gap: engine main now carries migration 0074, so the next step can start from main with schema and code in agreement.

Entry 107 — Phase 64: Pipeline-Spend Credit Gate (new v0.45)

What landed. The prepaid hard-gated solvency control over the three model-rooms (Manifestation, Shaping, Rendering) — step two of the Memory-completion path, the "four-room credit spend-gate" Entry 106 named as the next horizon (and corrected in scope to three model-calling rooms; Memory writes no model). It is a solvency control, not a metering feature: the gate is primary and pre-spend, the database floor is its backstop, and reconciliation is corrective only.

Governing document. Change Request CR-2026-095 v0.1, archived in the engine repo at docs/phase-crs/phase-64-cr-pipeline-spend-credit-gate-v0_1.md; drawn from the pre-scoping document set in the record's scoping-notes/ (constraints note v0.1/v0.2, scoping note v0.2/v0.3, session handoff v0.1). Implementation notes at docs/phase-impl-notes/phase-64-implementation-notes-v0_1.md (engine repo).

Merged state (current baseline). Engine main at 95e072d, alembic head 0076 (migration 0075 adds credit.reservoir/lot/draw_down/engagement_spend_authorization + the BEFORE INSERT person-side floor trigger; 0076 adds the Operator-set refill_amount). Tag phase-64-pipeline-spend-credit-gate (annotated) at 95e072d. Fast-forward merge to main, working branch deleted (tag/branch name-collision resolved). Substrate-only — Operator Layer (1ce2542) and Workshop unchanged.

The capability, in plain terms.

Operator decisions settled during the build. Reservoir default lenient-until-provisioned; refill amount Operator-set (migration 0076, correcting an initial threshold-derived cut); gated-model = re-resolve the system key for the gated tier (the model called matches the credit debited; no stored plaintext key). Plus two execution-surfaced refinements worth carrying as methodology: the floor scoped to live spend (a naïve party-only floor would have blocked production reconciliation — surfaced because the floor's introduction broke 8 reconciliation tests), and a FIFO determinism fix (solvency FIFO must order on something monotonic; lots created in one transaction tie-broke on random UUID — grants arrive one-per-transaction).

Acceptance. Full suite 2,725 passed / 2 pre-existing pinned failures (unchanged) / 0 non-pinned; migrations 0075/0076 round-trip; floor / reservoir-refusal / authorization / FIFO invariants verified by live SQL beyond the suite. Steps 0–8 each full-suite-green at commit; +~3,550 lines / 39 files.

Tracked follow-up. No HTTP-level per-room metered-spend / 402-exhaustion end-to-end test — the gate/meter/refusal logic is unit-tested and the room wiring regression-covered (66 tests); the route-level e2e drive is the gap. (The two pinned failures and the conftest sequence-reset / TRUNCATE-deadlock infra items carry forward.)

Position on the path. Step two of the Memory-completion path is done. The §0 solvency invariant is true for the rooms (person-side gate + floor) and on the issuing side (funded reservoir). The hard precondition — the pipeline is not opened to other Operators until the prepaid gate is real — is now satisfiable.

Entry 108 — Phase 66: Spend Visibility and the Pause Preference — BUILT and merged (updated v0.47)

What landed. The Operator-facing surface Phase 64 deferred (Phase 64 was substrate-only — a pipeline run spent silently after a one-time up-front authorization). The Operator now sees spend on every metered room and approves async spend until they graduate themselves off. Built across five steps and merged to main on both code repos. (v0.46 recorded this entry as drafted/queued, not yet built; v0.47 flips it to built. The prior framing is preserved in v0.46 per corrections-preserved discipline.)

Governing document. Change Request CR-2026-096 v0.1, with scoping note v0.2 + CR-drafting handoff v0.2, all under phases/phase-66-spend-visibility-and-pause/ (record commits 9ad7bf8, f54ef55); each paired .md/.html.

Merged state (current baseline).

The capability, in plain terms (the five build steps).

  1. Spend visibility — every metered room. A new thin GET /me/spend read endpoint surfaces each recent run's actual per-run cost (the consumption_credit flow Phase 64 wrote but exposed nowhere); the Operator Layer Spend surface (/spend) shows actual cost + current balance. The scope adjustment found at drafting held — the cost figure was net-new substrate (only aggregate /me/credits existed).
  2. Spend-pause preference — default ON. persons.spend_pause (the teaching stance: a new Operator is taught the cost model by approving spend); PATCH /me/settings/spend-pause + the /me payload.
  3. Async park / resume — the load-bearing checkpoint. System-key async Shaping/Rendering spend now parks before debit (pending_approval) when pause is on, raising RoomSpendPauseRequired between the gate check and the model call; resume re-dispatches the job with re-cost (re-runs gate+model; actual debit ≤ the displayed cap, never the parked figure). Decline ends the run in declined with no debit.
  4. Approval card. action_type='spend_pause_approval' (Operator-direct), showing the cost cap ("up to N credits") with three actions — approve (resume) / decline / stop-pausing (flip the preference off and approve this run, the in-card graduation).
  5. Settings toggle + re-enable affordance. An on/off toggle mirroring ExhaustionPreferenceSection, plus a re-enable control on the visibility surface so an Operator who turned pause off from a card can turn it back on without hunting in settings.

Amendment during the build — distinct declined job state. The first cut reused the failed terminal (with a marker string) for Operator-declined spend; the Operator directed a distinct declined state so decline is not conflated with operational errors/refusals. Migration 0078 was amended in place (not released downstream), round-trip re-verified, and the full suite re-confirmed green before continuing.

Drafter decisions that held. Resume strategy = re-cost (re-dispatch on approval; the cap is a ceiling, not a commitment). Off-switch reach = all rooms, one preference. Phase 65 reserved for credit purchase; this work took 66.

Phase B — Manifestation pause — DEFERRED (unchanged). Pausing synchronous Manifestation spend stays out of scope: it runs inline in an HTTP request and cannot await an out-of-band Operator decision without a synchronous-request→job re-architecture. Phase A pauses only async Shaping/Rendering; the park branch is structurally gated to {shaping, rendering} and the settings help-text states the gap plainly ("the first drafting step always shows its spend and proceeds — it can't be paused yet"). Honest to "only show what is available": no Manifestation pause control is shown anywhere.

Acceptance. All 11 §21 acceptance criteria met (final-checkpoint walkthrough, every criterion mapped to a named test or surface). Suite state: engine 2,754 passed / 2 pinned pre-existing failures (unchanged) / 33 skipped; Operator Layer 430 passed, tsc 0 new errors (3 pre-existing in a tags test), vocabulary wall green. Migrations 0077/0078 round-trip. Per-step full-suite-green; five engine commits (Steps 1–4 + the declined amendment) + four OL commits (Steps 1, 2, 4, 5).

Known, decided behaviors (recorded, not gaps). (1) "Stop-pausing" is two sequential, non-transactional calls — PATCH spend_pause→off then approve; PATCH-first is the safe ordering (a failed approve leaves the run parked and re-approvable, never silently spent). (2) §21.1 "balance movement" is surfaced as current balance + per-run cost, not a per-run before→after delta (consistent with the CR's framing that balance is frontend-derivable and the cost figure is the net-new piece). (3) The cap's input estimate is chars/4 (no pre-call tokenizer on the hot path); it's a credible ceiling paired with max_tokens, with the actual figure shown post-run.

Position on the path. Phase 64 made spend real (substrate: gate, metering, FIFO draw-down); Phase 66 makes it visible and approvable (the Operator-facing surface). The spend loop is now closed for async rooms; Manifestation pause (Phase B) is the remaining completeness item.

Entry 109 — Axis 11: CenterPane conversation pagination — BUILT and merged (new v0.48)

What landed. The Operator can now load conversation turns older than the most recent fifty on the primary in-engagement surface (CenterPane), which was previously impossible — the surface fetched limit=50 once on mount and offered no way back. A "load earlier conversation" control, gated on the engine's existing has_more, pages back through history. Frontend only — no engine change, no Memory contact (pagination is a pure read of conversation history that already exists; it writes nothing, derives nothing, touches no provenance). This is a consumer/reader-surface capability at the Memory read boundary, not a four-room production change.

Governing document. Change Request phase-axis-11 change-request v0.2 (phases/phase-axis-11-conversation-pagination/loomworks-phase-axis-11-conversation-pagination-change-request-v0_2.{md,html}, record commit f5be7fd). Preceded by the scoping note v0.2 (record 9429b2a) and the CR-drafting handoff v0.1 (record 20bfdc1); the handoff's three-part Step 0 (0a fetch-code read, 0b live-browser scroll-model observation, 0c CenterPane-only target) was executed and Operator-accepted before the build, and the five-shape pre-flight (R1+R2) was folded into v0.2 before approval.

Merged state (current baseline).

The capability, in plain terms.

Known limitation (R2) — accepted, follow-on noted. The created_at-only, strict-< cursor can skip a turn that shares the exact boundary created_at and sorts later by id (engine ordering tiebreaks on id DESC). The dedup guard prevents duplicates but not this skip. The complete fix is an engine-side composite (created_at, id) cursor, out of this frontend-only phase's scope and recorded as a follow-on. Accepted because turns are written with distinct sub-second timestamps in practice (verified on live data: E0005's 96 turns paged as 50 + 46 with zero overlap and none lost).

Tests + acceptance. Operator Layer 438 frontend tests pass (8 new — the first CenterPane test file: has_more gating, before-cursor prepend, end-of-history, dedup, raw-oldest cursor, window-scroll mechanism, inert-effect gate, R1 staleness; jsdom has no layout engine, so the scroll test asserts the mechanism, not pixels). tsc clean (modulo the 3 pre-existing tags-test errors, unchanged); production build succeeds. Smoke test confirmed on live E0005 (Operator, 2026-05-31): loading earlier is stable (no jump), control placement reads correctly, no duplicate turns.

Position on the path. Closes the Axis 11 long-conversation-surface item the Phase-60 post-close diagnostic deferred (queued-directions §16.3, fix-shape (b) "client pagination via the existing before-cursor / has_more"). The remaining §16.3 long-conversation candidates — older-turn summarization, time-windowing, within-engagement room-segmentation — stay deferred (Memory-adjacent; out of this pure-read phase). The R2 composite-cursor follow-on is the one engine-side tail.

Entry 102 — Phase 61 (CR-A): Audit substrate cleanup (new v0.42; first sibling of the cleanup arc)

Provenance. Tagged phase-61-audit-cleanup on engine 2026-05-24. Merge commit 616bab9. First of three sibling CRs from substrate hygiene scoping note v0.2.

Content. audit.foray_eventsaudit.events. Established the src/loomworks/foray/ module foundation with the _foray_reserved_emit no-op emitter. Validated the per-call-site reserved emit pattern at 3 sites in the audit substrate.

Five methodology contributions for absorption:

  1. Per-call-site reserved emit validated (3 sites). Three near-identical 4-line emit blocks at three call sites were not awkward; preserved the business-event-vs-persistence distinction visibly. (Lifted to canon Principle 1 at the arc's close.)
  2. Test-filename-to-current-substrate alignment first application. Renamed test_voice_tune_setting_foray_audit.pytest_voice_tune_setting_audit.py. (Lifted to canon Principle 2.)
  3. Migration strategy: drop-and-recreate when no downstream bindings. audit.foray_events had no triggers, no FKs from other tables, no downstream readers. Drop-and-recreate worked cleanly. (Lifted to canon Principle 3.)
  4. Reserved-slot consumption: one slot for FK deviation (Decision 5 in the design). ORM-level FK declarations entangled the audit DeclarativeBase with persons metadata; dropping FKs from both ORM and DB was the right call given Loomworks' invariant that persons and engagements are never deleted.
  5. Halt-and-surface discipline at Checkpoint A worked cleanly; no merge without explicit Operator approval.

Trajectory worth recording. CR-A validated the reserved-location pattern at the smallest scope. The pattern then scaled cleanly through CR-B (1 site) and CR-C (12 sites).

Build-quantitative summary. ~2 hours CC execution time (under 4.5-6h estimate). Test count 2708 baseline → 2674 passed / 33 skipped / 2 pre-existing failures.

Entry 103 — Phase 62 (CR-B): memory_events Phase 25 wiring cleanup (new v0.42; second sibling of the cleanup arc)

Provenance. Tagged phase-62-memory-events-cleanup on engine 2026-05-24. Merge commit ead29a8. Second of three sibling CRs.

Content. Phase 25 readiness wiring on memory_events cleaned. The attestation column renamed to commit_webauthn_attestation as a true Alembic rename (preserving 1 existing non-null row carrying real WebAuthn proof). _ANCHOR_PRIORITY registry (19 entries) relocated from src/loomworks/memory/events.py to src/loomworks/foray/anchor_priority.py. The _foray namespace injection logic at events.py:209-220 removed. compute_content_hash function removed entirely (zero callers after column drop). content_hash and foray_tx_ref columns dropped.

Five methodology contributions for absorption:

  1. Per-call-site reserved emit scales both directions (1 site for CR-B vs 3 for CR-A). The pattern holds at fewer sites; the principle is "one emit per business event" not "centralize at the helper writer."
  2. Migration strategy: column rename when ORM bindings exist. True rename via op.alter_column(... new_column_name=...) preserved the WebAuthn row through the migration; round-trip verified.
  3. Reserved slot 1 consumed by test scope expansion finding — inventory said "10 incidental references"; execution found 4 additional phase-specific tests with test_foray_namespace_injected-style functions, 4 _ANCHOR_PRIORITY import sites, and 3 compute_content_hash import removals. (Lifted to canon Principle 4.)
  4. Reserved slot 2 consumed by raw-SQL INSERT helper findingtest_phase_48_reconciliation_evaluator.py:128 had a raw-SQL INSERT helper writing content_hash. Production paths were clean; test helpers bypass the ORM "single code path" claim from docstrings. (Reinforces canon Principle 4.)
  5. Test-filename-to-current-substrate alignment validated at second instance. Deleted test_phase_25_content_hash_and_foray.py entirely; renamed test_phase_25_commit_attestation.pytest_commit_webauthn_attestation.py. Three test functions deleted across three other phase test files. Validates the rename-or-delete distinction.

Trajectory worth recording. CR-B was the load-bearing safety operation of the arc — the 1 non-null attestation row had to survive the rename. Empirical verification: pre-migration query showed event_id 0673cfd7-354b-4e2a-8a33-9d7355ebf180's data; post-migration query under the new column name showed the same data, byte-for-byte. Round-trip preserved.

Build-quantitative summary. ~2.5 hours CC execution time (toward lower end of 3-5h estimate). Test count 2708 baseline → 2670 passed / 33 skipped / 2 pre-existing failures.

Entry 104 — Phase 63 (CR-C): Credit substrate cleanup (new v0.42; third sibling of the cleanup arc; closes Phase A)

Provenance. Tagged phase-63-credit-substrate-cleanup on engine 2026-05-25. Merge commit 573abe1. Third of three sibling CRs. Closes the substrate hygiene cleanup arc and Phase A of the development assessment.

Content. credit.foray_action_flowscredit.flows via in-place RENAME (preserving trigger + FK + indexes transparently). 9-value typed event_kind taxonomy added with legacy_unknown fallback for historical rows that don't fit the 9 patterns. Two new typed columns (turn_event_id, converted_person_id) replace JSONB-extract reader queries. Three downstream readers refactored to typed-column predicates (conversion observer, reconciliation evaluator, inline idempotency check inside write_referral_credit_flow). 12 reserved-emit call sites added across flows.py (11) and proposal_applier.py (1). metadataextra_metadata rename retires SQLAlchemy reserved-name workaround.

Five methodology contributions for absorption:

  1. Per-call-site reserved emit at scale (12 sites). The pattern is now validated across the full range Loomworks encounters: 1 → 3 → 12 sites. (Strengthens canon Principle 1.)
  2. Migration strategy: in-place RENAME when triggers and FKs bind. The credit.update_balance_on_flow trigger binds to table OID and follows ALTER TABLE ... RENAME transparently. Empirically verified — synthetic INSERT on the renamed table fires the trigger and produces the expected double-entry balance updates. (Strengthens canon Principle 3.)
  3. Inventory cognitive density per file (21 + 29 + 17 references in three test files). The 8-file inventory count was right; the per-file density was the finding. (Reinforces canon Principle 4 in a new direction — file-count accurate, cognitive density underestimated.)
  4. Test-filename-to-current-substrate alignment at fourth instance — negative case. Zero renames in CR-C because the credit test files (test_phase_47_credit_substrate.py, etc.) were named after their phase-origin rather than after the FORAY framing. The principle correctly predicted "no renames needed." (Validates canon Principle 2 in its negative form.)
  5. Three readers, not two. Inventory said 2 downstream readers; CC's design step found 3 (the inline idempotency check inside write_referral_credit_flow was the third). The design-time grep caught what the inventory missed — the principle works.

Trajectory worth recording. The PostgreSQL trigger was framed as "the main unknown going in" in the kickoff. In execution, the trigger turned out to be the smoothest piece — it binds to table OID, follows the rename, requires no DDL change. CR-C's load-bearing risk surface was the test-density work, not the trigger. The cleanup arc's overall finding: the highest-cost work was substantively cheaper than anticipated; the lowest-cost work (test sweep) absorbed the reserved-slot budget.

Build-quantitative summary. ~5 hours CC execution time (middle of 4-7h estimate). Test count 2708 collected → 2673 passed / 33 skipped / 2 pre-existing failures. Five commits on phase-63-credit-substrate-cleanup branch. Phase A complete.


Entry 110 — Companion orientation & discovery (new v0_50)

What landed. The Companion can now tell the Operator what they can do and what they can change, scoped to where they are, with current setting values, rendered as a scannable list. Asked "what can I do here?" / "what can I change?" / "I'm lost", it answers from the system's own registries (never hand-written), located lightly ("here" / "in voice listening"), with drive-it example chips. Engine + Operator Layer.

Governing document. CR-2026-099 v0.1 (capability) + v0.2 (composition fix), docs/phase-crs/phase-cr-companion-orientation-discovery-v0_{1,2}.md. Scoping note v0.1/v0.2 (scoping-notes/). Implementation notes v1.0 (phases/companion-orientation-discovery/). Current-values + Path-A formatting enhancement folded in (tag v0_3).

Merged state (current baseline). Engine: main 56f2b6b, tags companion-orientation-discovery-v0_1 (8aea79c, ship) / v0_2 (a41ebf5, composition fix) / v0_3 (56f2b6b, values + formatting). Operator Layer: main 4ffb3ff, tag companion-orientation-discovery-v0_1 (4e43e9f). Workshop: frozen, unchanged.

The capability, in plain terms.

Known limitation / follow-on. The list uses /newline, not true Markdown (Companion-turn Markdown is unbuilt — spec §10.2; see queued-directions §18.4). When Markdown rendering lands, the orient list can become true Markdown.

Tests + acceptance. Engine suite green; the orient reply is server-composed (fabrication structurally impossible — proven by a zero-character domain-injection test); live-classifier confirmed (orient classifies, no action-utterance theft); Operator browser review passed.

Position on the path. Closes the discoverability hole the Companion-as-interface standing note left open (a conversation shows nothing until asked). The composition fix (v0.2) established a methodology instance (§2.C). Deferred: the §6.4 Explain affordance (voice-calibration-gated); Markdown rendering.


Entry 111 — First-class personal recall (new v0_50)

What landed. The Companion now reliably recalls the Operator's personal memories — birthdays, preferences, who's who — from any engagement, returning the same answer wherever asked. Engine only.

Governing document. CR-2026-100, docs/phase-crs/phase-cr-personal-recall-v0_1.md. Scoping note v0.1 (scoping-notes/, edfb74a). Implementation notes v1.0 (phases/personal-recall/). Functional spec → v0.2 (§8.1, personal recall read side). Queued-directions → v0.26 (§18, follow-ons).

Merged state (current baseline). Engine: main 56f2b6b, tag personal-recall-v0_1 (ec0b383). Operator Layer: unchanged (engine-only fix). Workshop: frozen.

The capability, in plain terms.

Known limitation / follow-on. Wholesale, not topic-filtered (subset optimization deferred — §18.2). The "ask-first on genuinely ambiguous recall" clarification is deferred (§18.1); the safe-default-away-from-orient rule + structural guard handle ambiguity now.

Tests + acceptance. Engine suite green; gated live-classifier 13/13 (the bug case "birthdays" → recall_personal; the ambiguous "what can you remember for me" structurally redirected off the bypass; engagement recall and writes unaffected); Operator browser review passed in the previously-broken Fenwick engagement (E0060) — birthdays recalls identically to E0005.

Position on the path. Fixes the cross-engagement personal-recall reliability bug at the root (recall was emergent, not first-class). Advances the memory=recall reframe (§18.5) without performing it (decoupled — engineering consistency fix, not a seed change). Deferred follow-ons: queued-directions §18.1–18.5.


Entry 112 — Stele extraction: the fourth product, the live build front (new v0.52)

The current live build front (see §1 "Current live build front" for the canonical-document pointer and locked decisions). Stele — said "steel" — is the principal/identity layer: the part of Loomworks that establishes who a principal is (human or agent), authenticates by passkey + second factor, manages credentials, and produces the actor reference every recorded action is attributed to. It is the fourth product alongside OVA (authorisation), FORAY (transaction record), and Loomworks itself (governance) — the three of which all assume a principal exists and none of which creates one. Stele is what they were silently relying on, and it is what gives a Companion Agent a first-class identity to act under.

What the work is: mostly extraction, not invention — the identity code exists and works inside the engine; the work is giving it a clean module boundary and a host-agnostic contract, plus closing two real gaps the code scan exposed (passkey-revoke and person-TOTP-rotate, both absent today) and one real refactor (splitting the fused sign-up into Stele-mints-principal → host-onboards). The contract is defined complete (revoke/rotate included even where code lacks them) so the design leads the build.

Phase order (each halt-before-push, auth path tested against the database, not the suite alone): 0 — stand up the module, move the zero-caller pieces (this CR); 1 — identity records + registry; 2 — actor constructors; 3 — point session.resolve under the host's resolve-current-person dependency (the 119 callers don't move); 4 — the mint↔onboarding split (approach B); 5 — recovery-completeness + build the to-build operations; Later — agent identity (token-exchange standards) + the agent actor path.

Phase 0 is complete and pushed (engine origin/main e4656b4, 2026-06-14). Five commits: 60e7cfa (0.1 skeleton), 3d96508/e2ab1c6/3b2c585 (0.2 — move recovery.py/webauthn.py/session.py, repointing 8/20/85 importers as pure renames), e4656b4 (0.4 isolation harness). Suite 2920/46/0; real-database sign-in verified against playground_dev. Completion record: loomworks-stele-phase-0-completion-record-v0_1. Two boundary corrections happened mid-flight, both surfaced by tree-truth verification before any file moved and recorded in the CR amendment notes: (v0.1→v0.2) two of the five listed pieces were not separable files — the credential row models and credentials.py reassigned to Phase 1, the person-TOTP internals to Phases 3/4; (v0.2→v0.3) the three remaining files had ~113 importers including load-bearing modules — resolved by distinguishing forbidden logic edits from in-scope import repoints (a move's mechanical completion). The standing lesson: "zero external callers" means "zero outside the identity set"; "don't touch load-bearing code" means "don't change its behaviour," not "don't repoint its imports."

Named verification gap carried forward: a full cryptographic WebAuthn ceremony against the database was not exercised (needs a real browser/authenticator, infeasible headless). Acceptable for Phase 0 (the verify functions are byte-identical renames; the session path every request runs on got the full real-DB check); carried forward to the Claude Code Miami standalone-UI milestone, where a reference UI drives a real authenticator end to end.

Phase 1 is complete and pushed (engine origin/main f1cf170, 2026-06-14). Four commits: 6d45526 (1.1 — shared Baseloomworks.identity_base), 8f5c005 (1.2 — PersonRow + the two credential row models → stele/models.py, 18/44/0 importers, mixed lines split per-symbol), 83cd9b1 (1.3 — registry → stele/registry.py, 36/86/0), f1cf170 (1.4 — credentials.pystele/credentials.py, 5/8/0). Step 1.5 was verification-only (no commit). Suite 2920/46/0 (identical to post-Phase-0 baseline); real-database sign-in + credential read verified from stele/ against playground_dev. Completion record: loomworks-stele-phase-1-completion-record-v0_1. No schema or data change (Branch 1 invariant, confirmed three ways: empty migration diff, alembic 0083 unchanged on repo and live DB, moved table definitions byte-identical). The Person view moved verbatim — the integration-design §5.2 narrowing (dropping exhaustion_preference/spend_pause) is deferred to Phase 6, not done here.

Phase 1 gating decision — locked and recorded. The persons.id FK / Base decision (brief v0.4 §5B) was split into two and locked before any code moved: D1 = own-its-own-table (direction — standalone Stele ships its own principal table), D2 = Branch 1 (shared-Base code-move now under one MetaData, zero schema change; the physical persons → principals + host-account split deferred to Phase 6 where the standalone packaging is built). The alternative (Branch 2 — Stele-own-Base + physical split now) was set aside as the highest-risk option, correctly homed at Phase 6. The name-collision watch-item resolved clean: loomworks.stele.credentials (moved) is distinct from loomworks.credentials (KEK, untouched), proven by construction.

Two Phase 6 carry-forwards found this phase (deferred by design): (1) the engagements-stub thread — stele.models.PersonRow FKs engagements.id, whose stub stays in persons.models, so stele.models is not importable in true isolation without it; an outward-pointing FK the Phase 6 de-engine step cuts under D1 = own-table. (2) the Person-view narrowing (§5.2), held verbatim this phase, lands at Phase 6 with the physical split.

Phase 2 is complete and pushed (engine origin/main 677c46f, 2026-06-15). The two actor constructors moved out of orchestration/helpers.py into a new dedicated module stele/actor.py: actor_from_person (kind="person") and actor_from_companion (kind="companion", bound to person.id) — the integration design's actor.for_principal / actor.for_companion (the dotted names are contract vocabulary; the underscore names are the code symbols — there is no for_agent constructor, agent actors are 64 inline sites). A split, not a whole-file move: OperatorProjectNotFoundError + verify_project_membership stayed in orchestration/; the ActorRef type was referenced, not moved (owned by memory/base.py). Import partition: ActorRef + Person moved with the constructors, Person stayed on both sides (shared by the verifier), ActorRef audited out of helpers.py. Four commits (306b526 Step-0 archive, af10f6a v0.2 re-archive, 5c06423 collapsed move-and-repoint of all 7 importers, 677c46f comment/docstring sync); Step 2.5 verification-only. Suite 2920/46/0; no schema change (alembic 0083 unchanged on repo + live DB); real-DB person-actor and companion-actor stamps verified from stele/, staying verifier still resolves/raises correctly. Completion record: loomworks-stele-phase-2-completion-record-v0_1. Two findings recorded (corrections-not-smoothed): (1) the CR v0.1→v0.2 amendment — v0.1 split the move from the repoints and predicted a runnable suite minus 6 files; but removing the module-top-imported constructors before repointing the four production routers makes the app un-importable and pytest aborts at collection (33 import-path errors, zero tests run). Caught in execution, halted, amended: Steps 2.1–2.3 collapsed into one move-and-repoint commit, restoring the Phase 1 "bundle each move with its repoints" mechanic so the suite is green at every commit. The lesson: model import topology (module-top imports in collection-critical modules), not just importer count, when drafting per-step suite expectations. (2) the mixed-import-block finding — 4 of the 6 production importers pulled the actor constructor in a block shared with the staying project-membership symbols; handled by per-symbol splits (the Phase 1 mixed-line mechanic). Phase 3 (next) — get_current_person / session-resolution → Stele. Points the auth-path actor resolution in api/deps.py (get_resolved_actor, _resolve_cookie_actor, get_committing_resolved_actor) under Stele; the ~119 session-resolution callers do not move. Do not conflate with the actor constructors (Phase 2, done) or the sign-up split (Phase 4, approach B). Same move-not-duplicate discipline; bundle each move with its repoints; verify against the live tree at the current HEAD and against database truth.

Phase 3 is complete and pushed (engine origin/main d3acd84, 2026-06-15). Session→principal resolution moved into Stele as resolve_session (stele/session.py): resolve_session(token, , secret_key, now, db) -> ResolvedSession | None, where ResolvedSession carries .person + .payload; it catches SessionInvalid internally (returns None), never raises, never applies the totp_verified gate. All five decode-load sites in deps.py now delegate to it (get_current_person, get_current_person_optional, _resolve_optional_person, _resolve_cookie_actor, _resolve_cookie_contributor) — zero inline decode_session remain (the single decode-load chokepoint). Host seam held: the totp_verified/person-exists policy is read off the carried payload host-side; membership, can_commit, contributor-membership, the bearer/agent _ActorRef builds all stay in deps.py; the person _ActorRef routes through stele.actor.actor_from_person. Four step-commits (7d639c2 3.1 add operation, 3a3665c 3.2 thin three person resolvers, 088212b 3.2b contributor seam, d3acd84 3.3 engagement seam + actor route) plus three archive commits; Step 3.4 verification-only. Suite 2920/46/0 green at every commit; no schema change (alembic 0083 repo + live DB); DB-truth green (sign-in, totp-reject, both tolerant resolvers None/Person, engagement-scoped actor from stele.actor, contributor path unchanged). Completion record: loomworks-stele-phase-3-completion-record-v0_1. Trajectory recorded (three amendments before code): (1) v0.1→v0.2 — Step-0 found get_current_person is one of two* resolvers (_optional returns None, can't inherit a raising delegator); fix = return-based operation. (2) v0.2→v0.3 — bare Person | None discards the payload the totp_verified gate needs; fix = ResolvedSession(person, payload), a security-critical correction so the gate can't be silently dropped. (3) v0.3→v0.4 — a grounding read of every decode_session caller found five decode-load sites, not two (the missed _resolve_optional_person and _resolve_cookie_contributor); fix = seam all five, with the over-deferral correction (don't confuse the decode-load step, Phase 3's subject, with actor construction, which stays host-side). The standing lesson: ground the design in a full read of the real code before drafting executable steps — line-coordinate checks confirm what you look at, not what you didn't think to look for. One recorded minor behaviour change: distinct 401 detail strings collapsed to one None-case 401 (status codes preserved, no test asserts the strings). Phase 4 (next) — the sign-up mint↔onboard split (approach B). Stele-mints-principal → host-onboards, with a heal path.

Phase 4 is complete and merged (engine origin/main 9be25fd, 2026-06-15; branch merged fast-forward and deleted local + remote). The fused complete_totp_verify sign-up split into mint_principal (Stele, stele/registry.py — verbatim relocation of the live :255–284: internal TOTP encrypt, mint with onboarding_complete=False/first_login_at=now, add_credential, generate+store recovery, -> tuple[PersonRow, list[str]]; recovery_codes_count exposed as the one intentional knob) and onboard (host, persons/onboard.py — saved-filter seed + commons/E2E/org membership + personal engagement + credit claim + set flag, one atomic transaction). Two-commit route: mint_principal → db.commit() (durable, route-owned, outside the rollback scope) → discard pending → onboard → db.commit() → issue_session; viable via expire_on_commit=False. First schema change of the extraction: migration 0084, onboarding_complete boolean, inverted backfill (41 existing rows → true; new mints default false). Orphan = onboarding_complete=false ∧ personal_engagement_id=NULL; _heal_if_orphaned in both login routes after the account-status gate, before the cookie runs onboard(claim_token=None). create_person kept separate (saved-filter tail stripped → onboard). Commits: 51563ab 4.1 migration, fd8d626 4.2 mint+strip, d2d7994 4.3a onboard, b66e1d0 4.3b two-phase route, d2d54b4 4.3c new-semantics re-points, 258d056 4.4 heal (+ archive commits). Suite green at every commit, final 2921/46/0; alembic 0084 repo + playground_dev + playground_test. **Four-version CR, two corrections caught in build: (v0.3) the mint_principal signature was sketched from the integration design's contract vocabulary (totp_secret_ciphertext, -> PersonRow) and contradicted the real :255–284 body (which encrypts internally, returns recovery plaintext, carries email/mobile/first_login_at) — caught at Step 4.2 before any mint code; (v0.4) the heal placement "before issue_session" sat before the route-level account-status gate, which would onboard a suspended/deleted orphan before denying it a session — caught at Step 4.4, fixed by moving heal post-gate with a regression test (test_suspended_orphan_is_gated_not_healed). Standing lesson extended:** ground the design in the real code for what a signature is and where a placement sits, not just which functions exist — a signature is derived from the real body it relocates; a placement is checked against the real code at the placement site. Proven end-to-end in the real database both halves (forced onboard failure → clean orphan; same kept orphan signed back in → heal completes it, no auto-claim). Two logged limitations (failed-signup-with-claim path, both rooted in the pending record discarded at mint-commit): failed-signup UX gap (no session, no pending record, heal only on sign-in); orphaned claim (heal runs claim_token=None, auto-claim lost, grant survives unclaimed). Repo working-model correction: engine origin/main sat at d3acd84 through all of Phase 4 — bcb59f5 (v0.2 archive) lived only on local main/branch until the merge fast-forwarded origin to 9be25fd; do not assume local main == origin/main between phases. Completion record: loomworks-stele-phase-4-completion-record-v0_1; handoff: loomworks-stele-phase-4-to-5-handoff-v0_1. Phase 5 (next) — credential lifecycle (second-passkey enrollment, passkey-revoke, TOTP-rotate, recovery-code surfacing), scoped against the Companion-spec §10.3 account-recovery amendment already landed (/me/security/, OneTimeSecretsDisplay); first task = establish from real code what /me/security/ already provides vs. what the Phase 5 row still needs.

Phase 6b — the Person-view split (application-layer / expand half). Split the fused Person view into Principal (Stele) + HostAccount (host-side); stood up CurrentUser delivery host-side (two cached PK loads in expand, the contract reality regardless); established the HostAccount cascade thread and a shared test helper (tests/helpers/identity.py); stripped all six host fields; retired the Person name and the get_current_person shim via a token-level rename (not a regex, which would have corrupted title="Person" and string literals). Merged --no-ff at 129d124; suite 2933/46/0; no migration (0086). (Detail-block gap, pre-existing: this Entry still lags on Phase 5 — engine 8f2665a — and Phase 6a — engine def8b04 — whose per-phase paragraphs are to be folded in from their completion records, not from the §1 summary.)

Phase 6b → the contract phase (CR-2026-111 / CR-A): host-side teardown COMPLETE and merged (engine origin/main bee2b4c, --no-ff, 2026-06-18). The physical teardown 6a/6b deferred: re-home every host-column accessor to host_account, retire the host mirror trigger, drop the 16 host columns from persons. Staged C1 → M1 → C2 → M2 (a migration can't re-home application writers, so the code half and schema half can't be atomic), plus a discovered C1.5 (pre-M1 fixture re-home) and a follow-on 0089 (restore the host_account CHECKs). 11 commits, alembic 0086 → 0089; persons ends principal-only (7 cols); host_account is the sole host home (16 cols + 3 CHECKs + the new referred_by → principals FK); host mirror trigger gone, principals trigger live. Suite 2928/46/0 at every commit; boundary held. Four corrections recorded in CR v0.3 (close-out): (1) §4.5 — host_account creation is HOST-side (signup), not the Stele mint; (2) C1.5 — §7's test-surface missed the trigger-reliant fixture class that breaks at M1, not C2/M2 (per-fixture explicit sync; a conftest mirror listener implemented then rejected because it masks the missing-host-write failure mode the phase exists to remove); (3) the near_exhaustion firing gap — a 4th accessor class, dynamic getattr/setattr access, invisible to the by-column grep and the raw-SQL scan but caught loudly by the C2 model strip; (4) 0089 — the 3 persons CHECKs cascaded at M2 and host_account had none (6a was Pydantic-only), but C1/C2's raw-SQL re-homes added non-boundary write paths, so the CHECKs are restored at the schema level (parity over minimalism). Plus the 0087-only-validity framing: once C2 removed the dual-writes the code is valid only at 0087+, so M2's downgrade is schema+DATA restoration (lossless backfill from host_account, proven on dev with a distinctive 16-column row), not a live rollback. Record: cr-2026-111-stele-extraction-contract-phase-host-teardown-v0_3. CR-B and CR-C carry forward (see §1 status).

CR-A → CR-C (CR-2026-112): the identity-table collapse — COMPLETE and merged (engine origin/main d0f302e, --no-ff, 2026-06-18). CR-A made persons principal-only at the column level; CR-C made principals the canonical identity table — the app now reads and writes the 7 identity columns directly via PrincipalRow instead of through persons/PersonRow. The mirror trigger was reversed, not retired: migration 0090 dropped the persons → principals trigger and installed a principals → persons trigger, so persons becomes a standing mirror kept populated for the 11 host FKs still pointed at persons.id. 4 commits (271dcf2 5 pure reads; ee2c7c0 principals=write-source + the reversed trigger + 6 writes + the 2 coupled loads; a8fb53b PersonRow→id-only FK-target stub + test reads repointed; 73a1e94 relocate HostAccountRow + the stub → persons/models.py, stele/models.py now SteleBase-only). alembic 0089 → 0090; suite 2928/46/0 at every commit and on merged main; Phase-4 caution passed (origin/main confirmed bee2b4c before merge). playground_dev verified (rolled back). The CR was planned as 5 commits and built as 4; four as-built corrections, each caught at a halt point (recorded in CR v0.2 §0): (1) the reads/writes split breaks on load-then-mutate pairs — repointing the load silently moves the write, so 2 of the 7 reads moved to the write commit; (2) the 11 host FKs force the trigger to reverse rather than retire (the v0.1 plan's "retire the trigger" assumed persons was idle — it is not; onboarding writes to its FK-dependent tables on every signup), folding old Commits 2+3 into one; (3) PersonRow cannot be fully deleted — it also registered the persons table on the shared identity_base.Base where the host-FK tables live; deleting it broke configure_mappers (~414 tests), so it reduces to a 4th id-only _PersonRow stub; (4) "SteleBase-only" required moving two Base classes, not one — the new stub (added in Commit 3) also sat on the host Base, so both it and HostAccountRow moved out. Record: cr-2026-112-stele-extraction-cr-c-v0_2 (as-built; v0.1 preserved); completion record loomworks-stele-cr-c-completion-record-v0_1. Methodology banked (for v0.21): a reads-then-writes split breaks on load-then-mutate pairs; a test observing a column must move in the same commit as the write it observes; "retire the trigger" assumed an idle mirror — a table feeding live FKs cannot go idle until the FKs move; an ORM row class can do two jobs (identity model + table registration), and the registration must outlive the identity model while dependents remain; a "make the module clean" end-state must account for classes added to that module during the same CR. CR-B carries forward (see §1 status): the 11 host-FK re-targets off persons (with the open principals.id vs host_account.id target decision — Claude.ai, CC, and the strategic-direction record all lean principals.id; the CR-A handoff's literal wording said host_account.id; settle before scoping), then retire the reversed trigger, remove the 4 _PersonRow stubs, and drop the persons table.


Entry 113 — Companion add-side rework (new v0.69; arc shipped 2026-06-27/28, absorbed late)

Provenance. Engine main 5ccc3d7 ("Merge add-side rework Phase 4 into main"; local == origin, pushed, no tag on the merge). Operator Layer 8bd73f2 ("Add-side rework Phase 5 — held-card Dismiss (+ Confirm) wired to discard/commit"), on feat-companion-surface, anchored by annotated tag add-side-rework-ol-v0_1 (added 2026-06-28 at absorption time). Governing CR: change-requests/loomworks-cr-add-side-rework-v0_1 (only version; no v0.2). SHAs verified against the live repos at absorption, not from the session summary.

Content. A six-phase rework of how the Companion captures a spoken/typed personal note (the "add side," paired with the earlier "remove side" matcher work). The arc:

Also shipped in the same session and recorded here for completeness (they preceded the numbered phases): the Companion truthfulness fix (engine 41704ef — removal actually retracts now; the success line is server-composed and gated on the real retraction, out of the LLM's reach; the invented "permanent erasure in settings" promise deleted) and the removal matcher robustness work (engine ed5b2b4 — stem normalization so "remove parking" finds "Parked on Level 13"; candidate-surfacing on a near-miss instead of flat-deny; the Fix-1 number disambiguation + confirm-before-retract preserved).

Standing notes added this session (record them under §2 when the next consolidation runs; named here): "The Companion must not claim what the system did not do" (success language gated on the engine's confirmed result, not scripted on intent) and "Merged is not deployed — restart dev after a runtime-affecting merge" (prompts cache in-process at first read; a merge does not update a running server).

The disposal-of-never-committed decision (recorded). Dismissing a held draft that was never committed discards cleanly — no retraction/correction record — because corrections-preserved applies to things that were in the record; a mis-transcription that never committed is noise, not a superseded fact. This is the discarded terminal state (distinct from retracted). The confirm-back simplification scoping note (loomworks-voice-entry-confirm-back-simplification-scoping-note-v0_1) was folded into this CR (its lean (a)), and is preserved as the decision-trail, not as an open queue item.

Trajectory worth recording. The CR's lesson, consistent with the project's standing discipline: success language and authority gates are structural, not scripted — the truthfulness fix and the move of the commit gate onto the human held-card are both instances of "correctness in code, not in the prompt/surface."

Build-quantitative summary. Engine Phases 1–4 merged to main (5ccc3d7), pushed. OL Phase 5 (8bd73f2) on feat-companion-surface, tagged. Suite green at ship (per the session record; not independently re-run at absorption).

Two residues (see §5). (1) No completion record was written for this arc — every other phase arc in the project has one; this is owed work, deliberately not backfilled at absorption time to avoid reconstructing a completion record from a summary rather than the live build. (2) The OL half is on feat-companion-surface only — not merged to main — now anchored by the add-side-rework-ol-v0_1 tag so it survives any branch lifecycle.


Entry 114 — Mobile Companion surface (new v0.69; built and pushed 2026-06-28)

Provenance. Operator Layer feat-companion-surface at dac9fec (pushed; 8bd73f2..dac9fec). Governing CR: change-requests/cr-mobile-companion-surface-v0_1 (record loomworks-record, commit 891ef15). Frontend only — no engine change, no migration. No tag (lives on the feat branch under the same not-yet-merged-to-main condition as the add-side OL work).

Content. The Companion becomes a readable, persistent fifth surface in the mobile swipe plane — slot 0, the default landing on entering an engagement — alongside the four rooms (Memory / Manifestation / Shaping / Rendering). Before, mobile had no way to read the Companion conversation; replies only flashed for five seconds in the hint line. The transcript bubbles (Operator turns, Companion turns, the voice-origin microphone glyph, per-bubble timestamps, suggested-action chips, upload-result cards) were extracted from the desktop ConversationPane into a shared ConversationTranscript component that both surfaces render — so provenance display (the build-queue-v0.3 cross-cutting conformance requirement) carries to mobile identically, for free. Both surfaces drive the same useConversation instance, so transcript, paging ("load earlier"), and message order are the same on mobile as desktop. The five-second hint flash is unchanged.

The structural decision (recorded). The Companion is added as a surface-index layer local to MobileSurface (slot 0 = Companion, slots 1–4 = the four rooms), wrapping the room model — NOT as a fifth ROOMS entry and NOT by widening the parent's RoomKey-typed activeRoom state. The alternative (widen activeRoom to RoomKey | "companion" in InEngagementSurface) was set aside: it pushes a non-room value into a room-typed contract across every consumer, contradicts "the Companion is not a room," and has a larger blast radius. The local-index approach kept the parent untouched except for two new downward props (messageOrder, companionName).

Build. Five steps, suite green at each, halt-before-push:

Decisions made at drafting (recorded). heldCount NOT introduced to the mobile transcript (matches desktop, which also threads 0 today; the build queue lists "no shared held-count source" as an open gap — both surfaces get it together when a source lands). The transcript bubbles extracted, not reimplemented (provenance carries; no drift). The Companion slot keeps MobileSurface's existing bottom bar (no second composer).

Build-quantitative summary. Final suite 443 passed / 83 files; tsc clean on changed files; vocabulary-wall clean. Files: ConversationTranscript.tsx (new), ConversationPane.tsx, MobileSurface.tsx, InEngagementSurface.tsx, strings.ts, tests/components/engagement/MobileSurface.test.tsx.

Position. Resolves the build-queue-v0.3 open gap "mobile in-engagement transcript — confirm intended end state." The queue's gap entry should be marked resolved (see the paired queue update, loomworks-companion-build-queue-v0_4 if produced, or a note on v0.3). Shares the same not-merged-to-main condition as the add-side OL work (§5).


Entry 115 — Companion-surface arc merged to main; seed viewer + create-restore landed (new v0.70; 2026-06-28)

Provenance. OL main 3f2fca8 (--no-ff merge of feat-companion-surface; parents bafdb07 + 86663aa; 36 commits; 92 files +8,674/−7,715; origin/main in sync). Seed-viewer commits 30be73541ba22686663aa; create-restore 9667d60; both on the feat branch before the merge, now on main. SHAs verified against the live repos at absorption.

The merge. The whole Companion-surface arc consolidated onto main after the heaviest remaining piece (the seed editor) was CR'd — the deliberate "merge before the heaviest build" sequencing, so the editor builds on a clean main base. Merged-whole verification ran before the push (tests 451/451, tsc 4-known-only, vocab green, lint 25/14 standing — every gate that has been the gate is green; lint is named debt, §5). Nothing was local-only; every commit had already lived on origin/feat-companion-surface.

create-restore (9667d60, CR cr-restore-engagement-creation-affordance-v0_1). The create-engagement entry point was dropped in the lens-home rebuild (the page existed and worked; only the way in was missing). Restored as a shared CreateEngagementButton in both layouts (desktop lens-tab right cluster; mobile header), doing router.push("/operator/create-engagement") — the card-button idiom minus focus-set (no engagement to focus yet). The grounding corrected the scoping note's "try-prompt" assumption (the home's "open a project · what needs me" is static text, not an interactive prompt seam — so the affordance is a button, not a prompt). HOME.voiceHint dropped on desktop (no mic there → misleading), kept on mobile. Frontend-only; suite 445/83.

Seed viewer (30be735/41ba226/86663aa, CR cr-seed-viewer-v0_1). A read-only viewer of the committed seed (the five commitments + version), opened from the in-engagement header (IconFileText, desktop right cluster + mobile), rendered below the header via the VoiceListeningPanel panel precedent (no new overlay machinery). Frontend-only — the grounding found the engine route already exists (GET /engagements/{id}/seed, seed_view.py, returning a structured plain-terms SeedPayloadResponse with Operator-vocabulary labels, engagement-scoped auth via get_current_contributor). fetchSeed projects only the five rendered fields (no engagement_id/UUID — vocab-wall-clean by projection). DraftSpecification.tsx was NOT reused (create-bound blob renderer); a new structured field/value renderer was built. Suite 451/85. LIVE-VERIFIED: the real component fed E0007/Goosey's live seed (seed_version 9, all five commitments populated, no UUID in the DOM, deferred fields absent, 403 error-path proven through the catch). The one un-exercised link (a literal Chrome click of the header button) is covered by the surface open-the-viewer component test.

The seed lifecycle. The seed viewer is the view stage of a single object's lifecycle: create → view → edit. The seed editor (CR'd, cr-seed-editor-v0_1) is the edit stage; the create stage (Entry 116) is the author stage. The create conversation and the edit conversation are the same conversational mechanism (propose → Operator approves → commit → prior-preserved, via the considerations machinery) pointed at a forming vs. an existing seed. The moment a seed is committed it is official, and therefore viewable and editable — no limbo; "only show what's available" governs the lifecycle (view/edit affordances appear when a committed seed exists).


Entry 116 — CRs filed + the engagement create-stage three-door design (new v0.70; 2026-06-28)

Four CRs filed to loomworks-record this session (all .md, Claude-Code-facing; pushed):

The engagement create-stage three-door design (scoping-notes/loomworks-create-stage-three-doors-scoping-note-v0_1, record 461f09a). Began as "the create page doesn't invite activity" (a screenshot of the deprecated create page — old menu-bar shell, not the new lens-home chrome) and developed through correction into a settled design shape. Two Operator conditions govern it: (1) the paths in are identified clearly; (2) the path out is one merged resultant seed. Three doors, each matched to an Operator state, with the finishing step matched to the door:

All three converge on one merged resultant seed, Operator-committed, official-and-therefore-editable. The empty-create-conversation regression dissolves into door 1: the grounding found it's a frontend wiring gap over a ready engine (the create_engagement_entry template is built to speak first — greet + first elicitation question — but ChatView never fires the opening converse call on mount; the old Workshop surface's static greeting was also dropped in the rebuild). The conversation is the common finishing room doors 2/3 fall back to when a result is thin. Build staging (lean, per-CR to confirm): door-1 fix (fire the opening greeting) → door-2 bridge (carry the generator draft across the boundary into the create conversation) → door-3 converter (document upload + extraction + mapping-review surface). Each its own CR with its own Step-0 grounding.


Entry 117 — Create stage: strip-down, converged spine, door 1 shipped (new v0.71; 2026-06-28, same session as 115–116, later)

This entry substantially supersedes Entry 116's create-stage framing. Entry 116 recorded the first scoping (door 2 = the marketing Example Generator carried across a marketing→product boundary; door 3 = "the heaviest, newest capability," NET-NEW). The same session then stripped both down through Operator-driven correction. Entry 116 is preserved as the superseded trajectory; this entry is the corrected shape.

The strip-it-down arc (door 2). The Operator drove a sequence of strippings — "must we follow previous implementations?", "leave the Example Generator where it is, copy its intent", "why are we looking at credit mechanisms", "a generator that follows logic, no credits", "run it the same methodology as any AI logic in the Loomworks space", "the model should be the most appropriate for the task". Each removed imported machinery. Door 2 was first scoped (a withdrawn, never-filed cr-generator-create-bridge-v0_1) as routing the deployed anonymous marketing generator into the product — which imported an anonymous→authenticated boundary, a claim-token to cross it, a marketing→product crossing, the generator's infrastructure, and nearly a pinned model. All of it dissolved once the assumption was dropped: door 2 runs product-native for an already-signed-in Operator, asking the five foundation questions (incl. the voice the marketing generator omits), using the product's own AI-logic methodology with the task-appropriate model. The marketing Example Generator stays untouched on marketing; door 2 copies its intent, not its deployment. Scoping note: scoping-notes/loomworks-create-stage-door-2-scoping-note-v0_1.

The converged-spine discovery. Grounding me_create_engagement.py found it is the commit terminal of the create conversation itself — it reads the conversation transcript, runs extract_seed_fields_from_text (→ draft → induct → commit), and the conversational create flow (converse → create_engagement_commit) delegates into it. "Conversation-create" and "extract-create" are ONE converged spine; there is no second path. All three doors are three text inputs to that one spine (door 1 = conversation, door 2 = answers, door 3 = document). The create-stage spine was discovered, not designed — after nearly building three new copies of it. Consequence locked into the door-2 and door-3 CRs: no new engine extraction/create capability — the doors feed the existing spine. Door 3 re-scoped to its true size (scoping-notes/loomworks-create-stage-door-3-scoping-note-v0_1): the document→commitments path already exists (Phase 53 /seed/extract); door 3's real work is create-path upload + feeding the Operator's document to the existing extraction + a review surface (SeedViewer display + held-card confirm + ONE net-new editable-field component). The lightest door, not the heaviest.

Door 1 BUILT, LIVE-VERIFIED, SHIPPED — the empty-create-conversation regression RESOLVED. Door 1 turned out to need two CRs. The OL frontend (cr-create-conversation-opening-turn-v0_1) fires the opening converse call on create-mode mount (lazy-init thinking, openingFiredRef fire-once, zero new lint debt, standard mode untouched). But its live check failed: an empty opener 400s — generate_response unconditionally appends a {"role":"user","content": operator_message} turn, and the Anthropic Messages API rejects empty content; a system-only call is impossible. The greeting machinery greets in response to a non-empty opener; there was no cold-open path (the mocked tests passed precisely because they didn't exercise the real responder). So an engine cold-open CR (cr-create-entry-cold-open-v0_1) added a templated greeting via the orient bypass pattern (server-composed companion_message, no LLM call → no empty user turn → no 400, no fallback possible) plus skipping the empty-operator-turn record (which had poisoned subsequent converse with the same 400). Built as Option T (over Option S, LLM-with-synthetic-framing) — the cold open has no context for the LLM's warmth, so a fixed invitation is more correct; the LLM joins on turn two. Live-verified end to end against the real engine + real Anthropic: cold open → templated greeting (not the fallback, not a 400), active #1/#2 → real elicitation (the flagged leading-assistant-role property held), commit → real candidate engagement (E0078) up to the WebAuthn step-up gate (a pre-existing presence ceremony, satisfied by a passkey tap in the browser, unreachable headlessly). Live-test mutations cleaned. Shipped: engine main 5ccc3d7 → 5578a05 (--no-ff); OL main 3f2fca8 → 132296f (--no-ff); both serving processes restarted onto merged main. The create page greets live on load — "Let's set up a new project. To start, what's the work you have in mind?" — the greeting render is browser-confirmed (screenshot, 2026-06-28 10:54 PM, on the running surface). The full entry→active→commit sequence is live-verified HEADLESSLY (real engine + real Anthropic) up to the WebAuthn step-up gate; the browser passkey-commit step is still PENDING (the passkey tap is the Operator's, unreachable headlessly — a pre-existing presence ceremony unchanged by the cold-open). So: the greeting is verified live in the browser; the commit-with-tap is the one remaining acceptance step. The arc that began with "the create page doesn't invite activity" closes — to the headless ceiling plus a browser-confirmed greeting — with a page that opens by inviting it.

The eight create-stage CRs (all filed to loomworks-record change-requests/, pushed): cr-restore-engagement-creation-affordance-v0_1 (built, Entry 115), cr-seed-viewer-v0_1 (built, Entry 115), cr-reply-source-legibility-v0_1 (not built), cr-seed-editor-v0_1 (not built), cr-create-conversation-opening-turn-v0_1 (built+shipped — door 1 frontend), cr-create-stage-door-2-v0_1 (not built), cr-create-stage-door-3-v0_1 (not built), cr-create-entry-cold-open-v0_1 (built+shipped — door 1 engine). The withdrawn cr-generator-create-bridge-v0_1 never reached the record (its boundary-crossing machinery dissolved in the strip-down). Three scoping notes + the parent three-door note are filed. Door 2 and door 3 are CR'd and ready to build off merged main; both depend on door 1's now-shipped opening.


Entry 118 — Create stage COMPLETE: doors 2 and 3 shipped (new v0.72; 2026-06-28, same session as 115–117, later)

The create stage is complete — all three doors shipped, three text inputs to the one compose→commit spine, the spine itself untouched (the converged-spine discipline from Entry 117 held through both builds). Door 1 (Entry 117) shipped earlier this session; doors 2 and 3 follow here.

Door 2 — "I'll tell you" (shipped). For the articulable Operator who hasn't written it down: five foundation questions (incl. the voice the marketing generator omits), composed into the create conversation's opening state, then refine and commit. Step 0 corrected the CR's "frontend-only" lean (recorded, not smoothed): the commit terminal composes the seed from persisted DB turns (get_recent_turns → the creation-mode block), so client-side-only synthesized answers would render a populated opening but the commit would read an empty block and fail — the exists-vs-works trap, caught at the read level. The fix: a thin turn-writer seam POST /me/engagements/seed-creation-conversation that batch-records the answered questions as creation-mode conversation_turns via the existing record_turn (pure INSERT, no LLM, no commit) — a turn-writer, not a second spine; the compose→commit spine is untouched. ChatView fetches the just-seeded block to display (single source of truth — the display reads the same DB the commit reads, closing the drift trap). Live-verified (real engine + real Anthropic): seam → 11 turns recorded; the conversation opened populated with the faithful five Q&A from the DB (not the generic greeting, no immediate commit); commit read the seeded block, drafted a convergent seed (E0079) carrying all five commitments incl. the voice ("Plain, unsentimental, and factual — no marketing gloss, no hype"), to the WebAuthn gate. Engine feat-create-stage-door-2 f1b0d85main 37a3be5 (--no-ff); OL 97bcc9emain 807ef8e (--no-ff); engine suite 3049, OL 458, zero new lint debt. CR cr-create-stage-door-2-v0_1 (v0.1 scope corrected in-build).

Door 3 — "here's my specification" (shipped). For the already-documented Operator (PRD/brief/SOW): upload the document, the existing extraction pulls the five commitments, review-and-adjust the mapping (not a conversation — finished work gets reviewed), then commit. **Step 0 confirmed door 3 is the smallest door (correcting the CR's "heaviest" framing, recorded not smoothed): the document→commitments→commit path already exists end to end — upload (POST /engagements/{id}/uploads), extract-without-commit (POST …/seed/extract, returns the five commitments + drafts the candidate seed), amend (POST …/seed), commit (POST …/instantiate, the WebAuthn gate). The one real gap was pre-engagement upload: upload/extract are engagement-scoped, but create mode has no engagement yet, and allocating one via the public draft_engagement would require fabricated placeholder commitments (the orphaned-initial-Seed anti-pattern the engine explicitly designed around, and a truthfulness violation). The fix: a thin allocation seam** POST /me/engagements/draft-candidate exposing the existing internal _allocate_candidate_engagement (seedless candidate + operator membership) — pure reuse, no new extract/create capability. The one net-new UI piece: an editable-field component (adjust an extracted value before confirming), over the reused SeedViewer display + held-card confirm. Live-verified: draft-candidate → candidate; upload spec → file_id; /seed/extract → the five commitments (gap_fields empty, no commit); adjust the voice → amend → the seed carried the adjusted voice ("Terse and clinical — data only…"), NOT the extracted original ("ADJUSTED persisted: True" — the exists-vs-works proof that the commit reads the reviewed mapping); instantiate → the WebAuthn gate. Engine feat-create-stage-door-3 3e80e29main 0b2c232 (--no-ff); OL dcc32cdmain b107290 (--no-ff); engine suite 3050, OL 461, lint unchanged. CR cr-create-stage-door-3-v0_1 (v0.1 "heaviest door" framing corrected in-build). Two build-time branches not exercised live (the spec was complete): re-induct-after-amend (not needed for the convergent case — instantiate went straight to the gate; an amend that introduced a gap would re-induct or instantiate-divergent) and the gaps→conversation handoff (handled structurally via per-field gap markers + a done-state note that uncovered items fill in the door-1 conversation).

The pattern across all three doors. Each needed only a thin engine seam — greeting (door 1 cold-open), turn-writer (door 2), allocation (door 3) — over reused spine machinery, plus its OL surface; the compose→commit spine was never rebuilt. Each Step 0 corrected its CR's scope before code (door 1: speak-first isn't built for empty openers; door 2: not frontend-only; door 3: the smallest not the heaviest). Each was live-verified to the WebAuthn gate against the real engine + real Anthropic, distinguishing render/exists from commit/works. The one remaining real-world step across all three is the browser passkey-commit (the WebAuthn presence ceremony — the passkey tap is the Operator's, unreachable headlessly; pre-existing, unchanged by any door). The create stage that began with "the create page doesn't invite activity" is complete: three ways in (talk it through / answer the questions / hand over a document), one merged resultant seed.


4.A Carryover from v0.41

Methodology v0.21 consolidation outstanding. Pressure was named in v0.41 as "compounding noticeably." v0.42 absorbs the consolidation-surface shift (canon emerged) but the v0.21 path remains an open arc — the candidates listed in §2.D carry forward.

Phase 45 OVA-spec scope sharpening. Carried from v0.41. OVA remains parked (Kaspa vProgs not ready).

"Skills" terminology three-way distinction — SETTLED 2026-06-11. See standing note loomworks-standing-note-skill-method-vocabulary-v0_6 (supersedes v0_2). Three senses named: skill (bounded engine transform), skill file (Anthropic-platform SKILL.md, kept at arm's length), method (practitioner's encoded way of working). Customization layering settled: personal side is invariant (bound to person UUID, follows across every Companion); method is optional specialization over it; vertical is a method aimed at a domain and sold.

Cross-Operator stewardship of promoted fragments. Carried as open question.

Operator content authoring. Soft deadline before alpha exhaustion. Carried.

Voice tuning iterations ongoing. Updated for v0.42: substantial voice work shipped (14 ships across the absorption interval — silence-submit threshold, recognizer E-prefix expansion, voice provenance, voice-pill padding). The iteration cadence is operationally healthy; the underlying "voice tuning ongoing" framing carries forward as accurate.

Engineering capacity decision trigger. Carried as watch-this.

Engine deployment via M4 tunnel. Phase 52 gate 7 deferred until deployment. Carried.

Marketing-site content observations held — three items. Updated for v0.42. Marketing repo commit 0d86610 (2026-05-17, "Fix four-stage phrasing on home — Memory, Manifestation, Shaping, Rendering") appears to address the room-order rendering observation. Status of the other two — "Manifestation paired with 'ships into the world'" and "broader frame-level question about substrate vocabulary outward" — awaits Operator confirmation. v0.42 records one item likely-resolved and two items unverified.

phase-56-step-0 local branch. Step 0 branch lifecycle decision pending. Carried.

**7 stale origin/phase-* refs on engine origin.** Carried. Increased by 2 local non-main branches on engine (phase-57-marketing-engagement-creation, phase-58-upload-pathway) per CC's grounding observation. Engine's full stale-branch state: 2 local + 7 remote.

Queued Companion directions (filed 2026-06-27/28; scoping notes/investigation in loomworks-record). Four directions await deliberate pickup, none a loose end:

> Update (2026-06-28, later session). Conversation search remains queued (its mobile dependency cleared by Entry 114). Command/settings discoverability and recordable-facts/topic remain as filed. Added this session: > - The engagement create stage (loomworks-create-stage-three-doors-scoping-note-v0_1, Entry 116) — three doors to one seed, staged door-1 → door-2 → door-3. The parent design for the coming create CRs. The door-1 fix also closes the empty-create-conversation regression. > - Source-model legibility (cr-reply-source-legibility-v0_1, Entry 116) — gap 1 of the three-gap source model (structural reply source-marking; then gap 2 a content-origin provenance type; then gap 3 web egress). The CR's source enum is designed to extend (web slots in as a value). The recordable-facts/topic investigation converges here. > - Seed lifecycle (Entry 115) — view (built), edit (cr-seed-editor-v0_1, ready to build), author (the create stage). One object, three tools.

4.B Closures from v0.41

Substrate hygiene cleanup arc (Phase A of the development assessment) — closed across Phases 61-63. Three FORAY-shaped substrate surfaces replaced with Loomworks-native equivalents. Reserved-location pattern in place at 16 call sites. src/loomworks/foray/ module foundation established. Phase A is genuinely complete.

The "Phase 57 strongest candidate Phase 32 marketing engagement" prediction. Closed without execution — Phase 57 identifier got reassigned; the marketing engagement work did not become Phase 57; the cleanup arc emerged as a different selection. v0.42 records the prediction-vs-reality gap honestly (see Entry 99-A and §3 below).

The "FORAY substrate operating" framing. Closed by the cleanup arc. FORAY is now correctly framed as an external service Loomworks will call. v0.41's incidental FORAY-substrate mentions are superseded. Architecture spec v0.4 §09 carries the authoritative current framing.

4.C New in v0.42

The methodology canon emerged as a separate consolidation surface. Four principles canonized at operations/loomworks-methodology-canon-v0_1 through a consolidation-after-arc cadence. This is a structural shift from v0.41's anticipation that all methodology consolidation would happen via the v0.21 path. Both surfaces now coexist; relationship to v0.21 is an open question.

Phase numbering became less canonical. Numbered phases continue (58, 59, 61, 62, 63) but the universe of "how work lands" expanded: named ships (14 across 2026-05-18 through 2026-05-20), sibling CRs within an arc (61, 62, 63 as the cleanup arc), in-flight Operator Layer work without engine tags (60). v0.42 names this explicitly as a structural shift.

Direct-to-record production became the standing discipline. The Downloads-as-staging step retired for record-bound documents. Documents land in the record as part of producing them. See operations/record-production-discipline-v0_1.

HTML-companion-as-part-of-producing-the-document became standing. Every record document has both .md and .html with letterpress styling.

Direct-to-record-friction observation. Two grounding documents in this absorption — loomworks-current-state-grounding-v0_1 (for the architecture spec) and loomworks-manifest-absorption-grounding-v0_1 (this manifest) — landed at Downloads as operational scaffolding, not in the record. The discipline correctly distinguishes record-bound documents from operational scaffolding. Worth noting as a discipline working as intended.

Operational hygiene cluster (newly named as a coherent thing in architecture spec v0.4 §13). v0.42 inherits the framing: the cluster includes the stale manifest (now closed by v0.42 itself), the stale queued-directions document (v0.11; still pre-cleanup-arc), the stale branches across three code repos, the two pre-existing test failures, and the unverified marketing-site observations.

CR-2026-100 personal-recall follow-ons (new v0.50). Five adjacent directions deferred from the personal-recall CR, captured in queued-directions §18.1–18.5: ask-first-on-ambiguous-recall clarification affordance (§18.1); topic-filtered / relevance-ranked recall as a subset of the wholesale set (§18.2); the *_about_me write-family name being narrower than its scope (§18.3); the Companion-turn Markdown rendering gap (§18.4 — also tracked at spec §10.2); the memory=recall reframe this CR advances but does not perform (§18.5, seed-level, awaiting Operator commission). Identified and deferred; none blocking.

4.D Completion plan

v0.41's table predicted Phase 57; v0.42's table is honest about the reality that prediction surfaces have become harder. No firm next-phase prediction; multiple candidates.

| Phase / Arc | What | Status | |---|---|---| | Phase 60 (Companion-as-Operator-system-interface) | First shipped instance: tune_setting handler | Closed mid-May (OL tags phase-60-close-v0_1, phase-60-recovery-v0_1) | | Upload pathway assertion-drafting | Engine work — draft held Assertions from UploadEventReceived events | Open (queued-directions v0.21 §15.3) | | Manifest v0.42 absorption | This document | Closing with this version | | Queued directions document absorption | v0.12 absorbing the cleanup-arc + canon + spec-v0.4 + 14 named ships | Identified, not started | | Phase B start | KV unification, identifier scheme normalization, job table base | Identified, not started; Operator's choice when to begin | | Phase C start | Memory stewardship, multi-backing, multi-Operator scenarios | Identified, not started; depends on Phase B sequencing | | Operational hygiene cluster pass | Stale branches, pre-existing test failures, queued directions v0.12, marketing observations status | Identified, not started; small piece compared to Phases B and C | | Loomworks engagement seed v0.10 candidate | Capture cleanup-arc framing shifts in seed vocabulary | Identified candidate; bump deferred to its own commission | | Methodology v0.21 consolidation | Lift accumulated candidates (and possibly cross-reference the canon) | Identified arc; relationship to canon is open question | | Standing-note creation | Standing notes on FORAY-as-external-service, Companion-as-Operator-system-interface, Memory backings | Identified as candidate; not started | | Personal-recall follow-ons | Ask-first clarification, subset recall, *_about_me rename consideration, Companion-Markdown rendering, memory=recall reframe | Identified, deferred — queued-directions §18 |

Cadence note for subsequent manifests. v0.42 absorbed 13 days of state; this is arc-cadence absorption. Per-phase cadence (v0.31-v0.41 style) was a different shape. Recommended posture going forward: per-arc absorption rather than per-phase, given that work increasingly lands as arcs (cleanup arc, voice modality maturation, engagement creation arc) rather than as discrete phases. The Operator may choose otherwise; v0.42 names the recommendation but does not enforce it.


Section 5 — Open questions and known issues

The methodology canon vs what-dunin7-is-building v0.21 relationship. Open question. Possibilities: v0.21 absorbs the canon by reference; v0.21 absorbs only what the canon hasn't taken; the canon eventually replaces the v0.21 consolidation cadence; they coexist permanently on different cadences. Operator decision required when v0.21 is undertaken.

Upload-pathway phase-identifier reconciliation. The upload-pathway-v1 Operator Layer work landed untagged at 2186d13 (2026-05-27) and does not belong to Phase 60 (which is Companion-as-interface). Its correct phase identifier is unreconciled. A numbering-reconciliation pass (also covering the Entry 99-A Phase 57 reassignment) is the place to settle this; not attempted in v0.43.

The marketing-site observations status. Two of three observations are awaiting Operator confirmation (room-order issue likely resolved by 0d86610; the other two unverified).

The completion plan table's predictive value. v0.41's table predicted Phase 57 confidently. v0.42's table presents multiple candidates without firm prediction. Whether the predictive framing returns when work cadence settles, or whether the completion plan permanently shifts toward "multiple candidates" — open question.

The seed bump deferral. Recommended as warranted in v0.42 but not actioned. The Operator's commission to bump candidate seed v0.9 to v0.10 (or further) is identified work.

Add-side arc — no completion record. The Companion add-side rework (Entry 113) shipped — engine merged to main at 5ccc3d7, OL at 8bd73f2 (tagged) — but no completion record was written, where every other phase arc in the project has one. Owed work. Deliberately not backfilled at v0.69 absorption: a completion record written nine days late from the CR + session summary rather than the live build would reconstruct-from-summary, the exact thing the discipline warns against. If written, it should be grounded in the live engine/OL state, not the summary.

OL Companion work — MERGED to main (2026-06-28). [RESOLVED] The v0.69 residue named the feat→main merge as an unscheduled Operator decision. It was made: feat-companion-surface merged to OL main at 3f2fca8 (--no-ff, 36 commits, merged-whole suite green). OL main and the live Companion surface no longer diverge. The feat-companion-surface branch is fully contained in main, retained pending a live-run confirmation of merged main (then retire-able). Kept here as a resolved-residue record, not an open item.

OL lint debt on main (named 2026-06-28). The merged main carries 25 lint errors / 14 warnings, all react-hooks/react-compiler rules at severity=error (15× setState-in-effect, 6× refs-during-render, 2× components-during-render, 2× rules-of-hooks). This is a standing repo condition, not merge breakage: pre-merge main already carried 15 (in files the merge never touched — ChatView, security components, filters/page.tsx); the merge added 10, all from the arc's own new Companion-surface files (SeedViewer, MobileSurface, InEngagementSurface, ConversationPane, useConversation, Home, useHomeData, useVoiceListening, usePagedList, VoiceListeningPanel). Lint has never been this repo's push gate (tests/tsc/vocab are). Two deferred-work pieces: (a) the 10 new Companion-surface react-hooks errors — the arc's own debt, the most worth cleaning (these rules flag real render-bug patterns), a focused cleanup CR; (b) the 15 standing main errors — a broader repo-lint-health question, lower priority. Named, not absorbed silently.

Methodology note filed (2026-06-28). operations/loomworks-methodology-scoping-grounding-disciplines-v0_1.{md} — the two disciplines above (true-size grounding; exists-is-not-works), each with its create-stage evidence, candidate for the methodology canon at the next consolidation. Committed 2ca3dd4, pushed (after the committed-not-pushed catch above).

Browser passkey-commit pending across all three create-stage doors (2026-06-28). Doors 1–3 are shipped and live-verified to the WebAuthn step-up gate, but the final commit — the WebAuthn presence ceremony (a passkey tap) — is unreachable headlessly and remains the Operator's to perform in the browser. This is a pre-existing security control on all commits, unchanged by the create-stage work; it is the one real-world acceptance step still open on each door. Not a defect — the expected ceiling of headless verification. (The greeting render was browser-confirmed by screenshot for door 1; the door-2/3 surfaces were live-driven to the gate over HTTP.)

Push-confirmation discipline reinforced (2026-06-28). Twice this session a push Claude.ai authorized did not execute and surfaced later as "ahead of origin" (create-restore 9667d60; the create-stage scoping note 461f09a, where Claude.ai mis-stated an unexecuted push as landed). Both were caught by ground-truth checks before harm. Standing rule reaffirmed: a push is not done until origin is confirmed at the expected SHA — "I authorized it" and "it landed" are different facts; confirm the SHA, do not assume. A third instance surfaced at v0.71 absorption: the methodology note (operations/loomworks-methodology-scoping-grounding-disciplines-v0_1) was reported "committed and pushed" but was committed-not-pushed (2ca3dd4 local, ahead of origin) — caught by a ground-truth origin/main check at retrieval, then pushed. The pattern is now three-for-three this session: "committed" reported as "pushed." The discipline holds: confirm origin at the expected SHA before treating any push as done.


Changelog

Updates the §1 standalone-distribution-milestone paragraph (brief v0.4 now drafted and governs — names the standalone repository as Stele's terminal form, frames the persons.id FK decision for Phase 1, re-sequences the phase plan into Phases 6–7, names the WebAuthn-ceremony gap closing at the Phase 7 reference UI), the canonical-documents list (brief v0.3 → v0.4, v0.3 preserved beside it; integration-design note that v0.4 pulls the §5.2 table-split forward to Phase 1), and the §3 Entry 112 Phase-1 FK watch-item (points at brief v0.4 §5B). Pointer bump only — no phase, substrate, or other §-state change; v0.53's Phase-0-complete state carried forward. Records the v0.4 structural choice (re-sequence over parallel-track) and the surfaced-not-pre-decided FK recommendation (own-table). Updates §1 live-front and §3 Entry 112 to Phase-0-closed / Phase-1-next; records the five-commit series, the two mid-flight boundary corrections (CR v0.1→v0.2→v0.3), the isolation proof, the real-DB sign-in result, and the named WebAuthn-ceremony gap carried forward. Names the Claude Code Miami standalone-distribution milestone (clone-and-run repo + SDK + docs-with-runnable-examples + UI template) with the persons.id FK as the gating design question, landing in Phase 1. Points to the Phase 0 completion record loomworks-stele-phase-0-completion-record-v0_1. Otherwise carries v0.52 forward.


DUNIN7 — Done In Seven LLC — Miami, Florida Loomworks Current-Status Manifest — v0.72 — 2026-06-28 The manifest is the absorption layer; the foundation document is the consolidation layer.