DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path phases/companion-commit-affordance/loomworks-companion-commit-affordance-completion-record-v0_2.html

DUNIN7 · Loomworks · Completion Record

Companion Human Commit Affordance

Record version. v0.2
Date. 2026-06-24 (v0.1) · amended 2026-06-25 (v0.2)
Change Request. CR-2026-121 — Companion Human Commit Affordance — v0.1 (2026-06-24)
Status. Executed and pushed. Production database migration pending.
Executing agent. Claude Code on DUNIN7-M4, fresh execution session.
Operator. Marvin Percival.
Grounded by. Step 0 inspection companion-commit-step0-v0_1.md; seed-check against canonical seed v0.12.

Amendment — v0.2 (2026-06-25)

This record carries two corrections; the v0.1 body below is unchanged and preserved in full, with each correction added as a marked note beside the text it corrects. (1) Acceptance item #8 scope — corrected in the new section "Amendment — acceptance item #8 scope correction," after the acceptance gate; the conversational gap it understated was closed by CR-2026-122 (live at 59c8249). (2) Production migration status — corrected in a note appended to the "Production migration status" section: a 2026-06-25 read-only check established there is no production engine or database, so 0094 is not "pending a production deploy" — production deployment is unstarted. Per corrections-preserved discipline, both original claims stay visible alongside their corrections.

Plain-language summary

The Companion can now commit an Operator's held drafts without the Operator leaving the friendly surface. Before this change, knowledge added through the Companion landed as a held draft awaiting approval, but the only place to give that approval was the Workshop — the harder surface the Companion exists to replace. This change gives the Companion its own commit affordance two ways that share one numbering scheme: on the card surface the Operator can select held items and commit them, or commit all; by voice or text the Operator can say "commit held 3" or "commit all" and the Companion does it after confirming what it is about to commit.

Two correctness properties are built in and proven. Commit is recorded as the human Operator's act, never the Companion's — on both the card path and the voice path. And the Companion's language tells the truth about state: a held draft is "held, awaiting your commit," and only after commit is it "committed to the record."

The work is fully executed, both code repositories are merged to their main branches and pushed, and every test passes. One step remains before the feature is live for real users: the database migration that assigns the held numbers has run on the development and test databases but has not yet run in production. The code is on main; the schema and data change awaits the engine's deploy step.

What this completes

This is the keystone build of the Companion build order. Until commit worked on the Companion, nothing downstream — deriving a Manifestation, creating a Shape, producing a Render — could be reached or tested on the Companion surface, because each of those operates on committed knowledge. With commit now working on the Companion, the downstream build items become reachable.

The open loop named in the build map — Fenwick E0060's three held drafts with no Companion path to commit them — is closed. Those drafts now carry stable numbers and were committed by both the card and the voice path against the real engagement (then rolled back so the drafts stay held; the proof was non-destructive).

Seed alignment

The Change Request was checked against the canonical Loomworks candidate seed v0.12 before execution. No conflict. The build implements seed commitments rather than working against them:

Pre-flight verifications (V1–V7)

All seven passed. The two gated decisions (V1, V6) were cleared by the Operator before any code was written.

VerificationResult
V1 — commit-order dependency (gates D4)Pass, no dependency. list_assertions orders by created_at; every display_number site is a display label with a null-guard; no ORDER BY display_number, no "Nth committed", no monotonic-by-commit assumption anywhere. Operator cleared toward lifecycle-stable (D4).
V2 — held-number uniqueness scopePass. Held and committed numbers draw from the single per-engagement counter (engagements.next_display_number) under the engagement-row lock — no collision.
V3 — current held assertions carry no numberPass, with refinement. Fenwick E0060's three held assertions were display_number = None as predicted. Refinement surfaced: a revised-from-committed assertion is held while carrying its number forward (E0007 #14). The migration backfill therefore targets only state='held' AND display_number IS NULL, never overwriting an already-numbered held revision. This confirmed the lifecycle carry-forward already exists on the revise edge.
V4 — feed orderingPass. /me/dashboard/needs_you orders by surfaced_at DESC, item_id DESC; the held number travels in the payload as a dedicated field, decoupled from feed order (number stable, order cosmetic).
V5 — migration backfill determinismPass. Backfill draws from each engagement's counter, ordered by last_updated_at, scoped to the held-and-unnumbered predicate; reproducible and collision-free.
V6 — human actor on the converse path (gates D7)Pass, human actor reachable. The converse route authenticates the human principal; actor_from_person(person) builds the kind="person" actor (the analogue the cookie path uses); the data layer accepts a person actor and rejects only kind="agent". Operator cleared toward both paths — verbal commit ships, no deferral.
V7 — card path authorityPass. The card commit is a direct authenticated POST forwarding the human session, not a converse call; satisfies R-B20 with no special handling.

Gated decisions as resolved by the Operator:

What shipped

Per-step commits, suite green at each step, staged by explicit path.

loomworks-engine — 5 commits, merged to main

CommitChange
464dc28Migration 0094 — held-number backfill (run and reversible; dev and test at head 0094)
9b7c93cAdd-time held-number allocation (lifecycle-stable); commit adopts the existing number
48ef463 + e79dd71Feed enrichment (needs_you arm plus operator-dashboard / inbox translators)
40eff76commit_assertion converse intent — two-turn confirm-back, human authority, instruction template

Merged to main 0ae231b via --no-ff (08d0c0c..0ae231b), pushed to DUNIN7/loomworks-engine.

loomworks (Companion) — 1 commit, merged to main

CommitChange
e53080aActionable held card (held number, multi-select, "Commit selected" / "Commit all"), fidelity language, verbal path wired through the existing converse pipeline (no new client endpoint)

Merged to main bafdb07 via --no-ff (c17539a..bafdb07), pushed to DUNIN7/loomworks.

loomworks-ui (Workshop)

Untouched, as specified — it served as the port reference only.

Acceptance gate — all 10 items met

  1. V1–V7 verified — V1 and V6 cleared by the Operator; lifecycle-stable plus both commit paths.
  2. Held number visible and stable — the held card shows "Held N"; the number is durable from add time and does not change while held.
  3. Lifecycle-stable — the display_number is unchanged across the held-to-committed transition; confirmed on Fenwick and in tests.
  4. Card commit — selecting a held assertion and committing it records an assertion_committed event with the human as committing party (kind=person); the item leaves the held surface.
  5. Batch commit — "Commit selected" and "Commit all" commit each targeted assertion, one event per assertion.
  6. Verbal commit — "commit held N" produces a confirm-back naming the item and commits on confirmation as the human Operator; "commit all" works; an unknown number is declined without committing anything.
  7. Authority (R-B20) — no commit anywhere records the Companion as the committing party; every commit is the human Operator.
  8. Fidelity — held drafts are never described as "saved" or "in the record"; held and committed are named distinctly.
  9. Suites green — engine 2938 passed / 0 failed; Companion 470 passed / 0 failed; eslint clean. New tests cover held-number allocation at add, lifecycle carry-through at commit, feed emission of the held number, and the commit_assertion route (resolution, human authority, confirm-back, unknown-number rejection).
  10. Fenwick E0060 manual check — the three held drafts now carry stable numbers 1, 2, 3; both card and verbal paths were exercised against the real engagement as the human Operator (numbers preserved) and rolled back so the drafts stay held. The build-map open loop is closed.

Amendment — acceptance item #8 scope correction (v0.2, 2026-06-25)

Corrections-preserved — scope correction

The acceptance gate above lists item #8 as met, worded:

Fidelity — held drafts are never described as "saved" or "in the record"; held and committed are named distinctly.

That wording claims a property of the whole Companion. The v0.1 claim stands as a record of what was asserted at the time and is left unchanged above. The correction: what was actually built and tested under CR-2026-121 was narrower than the wording. The fidelity rule (D8) was scoped — per CR-2026-121 §5.2 — to the held card, the confirm-back, and the post-commit response only. Those are the two persona-bypassing surfaces: the server-composed commit replies and the static card copy. Both were brought under the rule and verified.

The Companion's conversational voice — free conversation through the responder LLM path, which loads companion_persona.md — was never under the fidelity rule. At the time this record was filed, that voice described held drafts as "saved" and "in the record," falsifying item #8 as worded. This was discovered on 2026-06-25 by live observation at engagement E0060: the Companion told the Operator a held draft was "saved" while three held assertions sat awaiting commit.

Root cause and fix are recorded in the conversational-fidelity scoping note (loomworks-record c60f565) and closed by CR-2026-122 — Conversational Fidelity, merged and pushed to loomworks-engine main at 59c8249. CR-2026-122's persona state-to-word mapping brings the conversational voice under the same honesty the card and commit surfaces already had, verified by deterministic tests and a live check against the original defect surface.

Net: item #8 held on the surfaces CR-2026-121 built and tested (card, commit replies). It did not hold on the conversational surface, which was outside CR-2026-121's scope and is now closed by CR-2026-122. The original wording overstated the scope; the trajectory — claim, discovery, correction, fix — is preserved here rather than smoothed.

A second conversational voice (the engagement-creation converse, seed_conversation.py / CREATION_CONVERSATION_PROMPT) is outside both CRs and may carry the same gap independently; it is recorded as standing note f9d182b for a possible follow-on.

Production migration status — pending

Outstanding for the feature to be live

This is the one step remaining for the feature to be live for real users.

  • Migration 0094 is a data backfill that draws held numbers from each engagement's next_display_number counter. It has run on development (playground_dev) and test (playground_test), both confirmed at head 0094.
  • It has not run in production (the api.loomworks.dunin7.com engine database). The push moved code only. The engine repository carries a single GitHub workflow (api-docs.yml, an API-docs freshness check) and no deploy or alembic-upgrade workflow, so merging to main does not touch the production database. This is consistent with the established "merge is not deploy" posture.
  • Consequence until it runs: in production, held assertions will not carry backfilled numbers and newly added held assertions will not be born with one — the code is live on main, the schema and data change is not yet applied. The held-commit feature is not fully functional in production until the migration runs.
  • When it runs: it should run as part of the same engine deploy that ships this code. Running it later is acceptable — the backfill is order-independent and idempotent on the display_number IS NULL predicate — but the feature is not complete in production until then.

Amendment to the above (v0.2, 2026-06-25) — there is no production engine

The v0.1 section above is preserved as written. Its framing — that 0094 is "pending a production deploy" and "has not run in production" — implies a production engine and database exist and await a migration step. A read-only check on 2026-06-25 established that they do not. api.loomworks.dunin7.com fails the TLS handshake and has no cloudflared ingress entry on DUNIN7-M4 (the tunnel serves only forge/workforce/foraychallenge; the engine runs only as a local dev process on :8000). This was re-verified after unrelated foraychallenge tunnel work, ruling out a transient disruption: the tunnel config is months old and was never restarted, and there was never a loomworks/engine ingress to be "down." Engine production deployment is a deferred, unstarted item — the M4-tunnel step (spine manifest) or the unbuilt fleet (Discovery-stage deployment-strategy doc).

Accurate statement: migration 0094 is live wherever a database exists — development and test. There is no production engine, no production database, and therefore no pending production migration. 0094 will run when production is stood up, as part of standing it up. The v0.1 "pending a production deploy" wording overstated how close production is; the held-commit feature is not "awaiting one migration" in production — production itself does not yet exist. Trajectory preserved: the original framing stays above, the correction sits here.

State at completion