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

DUNIN7 · Loomworks · Completion Record

Current-engagement spine

Record version. v0.1
Date. 2026-06-26
Change Request. CR-2026-123 — Current-engagement spine — v0.3 (supersedes v0.1/v0.2)
Status. Executed on branch cr-2026-123-current-engagement-spine through Step 6; suite green at every step; 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; scoping note …spine-scoping-note-v0_2; architecture spec v0.6 §08; the Step-4 match-policy findings; 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 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 sibling CR-2026-124.

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" 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/…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 are settled, grounded decisions (exact / case-insensitive / person-scoped; duplicate title = ask-don't-guess; "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.

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

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

CommitStepChange
0b1279e0Archive CR v0.2 as branch base (baseline main 59c8249, suite 2940/46, alembic 0094).
c88b30c1host_account.current_engagement_id — nullable FK clone of personal_engagement_id; migration 0095 (down_revision 0094); up adds column + FK, down drops both; up/down/up clean.
419b1802Converse scope defaults to focus when project_id omitted; threaded through verify/context/history/classifier/route. Null boundary asks; no Personal fallback. current_engagement_id on the HostAccount view. +3 tests.
000396e3PUT /me/current-engagement set/clear + set_current_engagement seam; reuses verify_project_membership; close (null) clears. +4 tests.
99e5d89Archive CR v0.3 (Step 4 re-scope) onto the branch.
1f972304handle_resolver.py resolve_engagement_handle — delegate Personal/"0"/E####/UUID to resolve_engagement_address first, then bare-int → number lookup (person-scoped), else name lookup (exact / case-insensitive / person-scoped). Duplicate title → AmbiguousEngagementHandleError with candidates. Wired into the endpoint (handle precedence; 404 unknown; 409 ambiguous). +16 tests.
05e33925GET /me/current-engagement — "where am I": name + per-Operator number + E####; null focus → not-in-an-engagement, 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) → 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 — PASS
  6. "where am I" → name "Goosey" + number 7 + E-label — PASS
  7. clear (close) → focus null → omitted-project_id default None (asks, no Personal fallback) — PASS
  8. explicit project_id → wins over focus — PASS

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

Open after this record

Halt before push — Operator authorization required

The branch (7 commits, 0b1279e..05e3392) is not pushed. On the Operator's review and explicit authorization, push CR-2026-123 (merge --no-ff to engine main per convention). Until then nothing is on origin.

State at completion