DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path phases/current-engagement-spine/loomworks-current-engagement-spine-completion-record-v0_1.md

Completion Record — Current-engagement spine (CR-2026-123 v0.3)

Record version. v0.1 Date. 2026-06-26 Change Request. CR-2026-123 — Current-engagement spine — v0.3 (2026-06-26; supersedes v0.1/v0.2). Status. Executed on branch cr-2026-123-current-engagement-spine through Step 6; suite green at every step; the 8-step database-truth walk passed. NOT pushed — halt before push, awaiting Operator authorization. Executing agent. Claude Code on DUNIN7-M4. Operator. Marvin Percival. Grounded by. CR-2026-123 v0.3 (docs/phase-crs/ on the branch); scoping note loomworks-current-engagement-spine-scoping-note-v0_2; architecture spec v0.6 §08 (the spine reconciliation); the Step-4 name-resolver match-policy findings (read-only, 2026-06-26); Step 0 re-confirmation against engine 59c8249.


Plain-language summary

The Companion now has a server-side memory of "the engagement you're in right now." Each person's small record (host_account) gained one line — current_engagement_id — beside the "Personal engagement" line that already worked the same way. The conversation path reads it: when a turn names no project, the scope defaults to the focused engagement; when nothing is focused and nothing is named, the Companion asks rather than guessing Personal. A focus-set operation writes it on "open X," a unified resolver turns any handle (your number for it, its name, its E-label, a UUID, or "Personal") into the engagement, and a "where am I" read says where you are by name + your number + E-label.

This CR was re-scoped once, mid-build, and the re-scope is recorded here rather than smoothed. v0.2 framed Step 4 as "only the number lookup is new — reuse an existing name resolver and an existing 'open X' handler." Execution found that false: the cited name resolver runs the wrong direction (id→name), and there is no "open X" intent in the Companion to wire into. The build halted, the Operator chose pause-and-revise, and the work split: v0.3 (this record) builds the engine handle-resolution and the spine; the spoken "open X" classifier intent is the sibling CR-2026-124. v0.3 alone delivers handle resolution at the endpoint, tested and usable; v0.3 + CR-2026-124 stacked is the full voice "open X."


The v0.2 → v0.3 re-scope (recorded, not smoothed)

At Step 4 the v0.2 plan met the codebase and two of its three "reuse" claims were false against engine 59c8249:

  1. Name→id resolution did not exist. v0.2 cited engagement/redirect.py:103 _resolve_engagement_name as reusable name resolution. That function is id→name — it reads the Seed's engagement name to label a cross-engagement redirect. "open Goosey" needs name→id, which existed nowhere.
  2. There was no "open X" intent to wire into. IntentLabel carried 23 intents, none open/navigate/switch. The only by-number "open" was a frontend list-expansion shorthand with no engine path.

So two of three handles were new construction, not reuse — the "imagined state encoded as fact" the CR's own Finding ② warns against, surfacing one step late. The build halted at the Step 4 boundary (Steps 1–3 already committed and green). A redraft handoff was filed (cr-drafting-handoffs/loomworks-cr-2026-123-step-4-redraft-handoff-v0_1.md), the match-policy questions were answered against live data, and CR v0.3 re-scoped Step 4 to engine resolution only, splitting the spoken intent to sibling CR-2026-124. All name-match and collision policies in v0.3 are settled decisions grounded in the live findings (name match = exact, case-insensitive, person-scoped; duplicate title = ask-don't-guess with candidates; "open 0" = Personal).


Seed and spec alignment

Cleared against candidate seed v0.12 (silent on current-engagement focus / converse-path addressing) and architecture spec v0.6 (the §08 spine reconciliation: surface signals posture when a surface signals; the carried current engagement supplies scope when none does; ask-don't-guess at the null boundary). The authentication framework is untouched — current_engagement_id is a focus pointer, resolution never keys on email. Addressing vocabulary (name + per-Operator number + E####; UUID invisible) follows the engagement-identity record and does not reopen it.


What shipped (per-step commits; suite green at each)

Branch cr-2026-123-current-engagement-spine off engine main 59c8249. Not pushed.

| Commit | Step | Change | |---|---|---| | 0b1279e | 0 | Archive CR v0.2 as branch base (baseline: main 59c8249, suite 2940/46, alembic 0094). | | c88b30c | 1 | host_account.current_engagement_id — nullable FK clone of personal_engagement_id; migration 0095 (down_revision 0094), up adds column + FK host_account_current_engagement_id_fkey, down drops both; up/down/up clean. | | 419b180 | 2 | Converse scope defaults to focus when project_id omitted (engagement_id = body.project_id or host_account.current_engagement_id), threaded through membership-verify/context/history/classifier/route. Null boundary asks; no Personal fallback. current_engagement_id added to the HostAccount view. +3 tests. | | 000396e | 3 | PUT /me/current-engagement set/clear + set_current_engagement write seam; reuses verify_project_membership; close (null) clears. +4 tests. | | 99e5d89 | — | Archive CR v0.3 (Step 4 re-scope) onto the branch. | | 1f97230 | 4 | api/handle_resolver.py resolve_engagement_handle — delegate Personal/"0"/E####/UUID to resolve_engagement_address first, then bare-int → number lookup (memberships.operator_sequence_number, person-scoped), else name lookup (exact, case-insensitive, person-scoped). Duplicate title → AmbiguousEngagementHandleError with candidates. Wired into the endpoint (handle precedence; unknown → 404; ambiguous → 409 with candidates). +16 tests. | | 05e3392 | 5 | GET /me/current-engagement — "where am I": name + per-Operator number + E#### (UUID out of labels); null focus → in_engagement false, no guessed Personal. +3 tests. |

Suite trajectory: baseline 2940 → Step 2 2943 → Step 3 2947 → Step 4 2963 → Step 5 2966 passed, 0 failed, 46 skipped. API docs regenerated at Steps 3/4/5; freshness CI guard green at each. Every commit lands green; per-step reversibility holds.


Report (CR §6)

8-step database-truth walk (CR §4 Step 6) — playground_dev, non-destructive (rolled back)

All eight passed, exercised at the resolution + endpoint level (the spoken "open X" utterance walk belongs to CR-2026-124):

  1. name "Goosey" → resolve → set → focus == Goosey — PASS
  2. E-label (delegated to resolve_engagement_address) → Goosey — PASS
  3. number "7" → engagement at this person's sequence 7 — PASS
  4. "0" and "Personal" → both Personal (number path does not steal "0") — PASS
  5. duplicate title "Dup" → ambiguous error carrying both candidates (no silent first-match) — PASS
  6. "where am I" → name "Goosey" + number 7 + E-label — PASS
  7. clear (close) → focus null → omitted-project_id default is None (asks, no Personal fallback) — PASS
  8. explicit project_id → wins over focus (focus ignored) — PASS

(The converse-default halves of steps 1/7/8 are also pinned by the committed Step 2 integration tests, green against playground_test.)


Acceptance — met (v0.3 scope)


Open after this record


State at completion


DUNIN7 — Done In Seven LLC — Miami, Florida Completion Record — Current-engagement spine — v0.1 — 2026-06-26 CR-2026-123 v0.3