DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path change-requests/cr-2026-110-stele-extraction-phase-6b-v0_5.md

CR-2026-110 — Stele Extraction Phase 6b — Person-view split — v0.5

Version. 0.5 Date. 2026-06-16 Author. Marvin Percival (DUNIN7 Operator) with Claude.ai (scoping) on DUNIN7-M4. Status. Steps 1–3.3 built, pushed, green on branch stele-phase-6b-person-view-split (b83deea). The field-stripping phase is complete — the Person view is now identity-only and field-equal to Principal. This version records that milestone and scopes the remaining work: 3.7 (shim retirement + name collapse) and 3.8 (boundary verification). Markdown primary (technical consumer: CC executes). Against. branch stele-phase-6b-person-view-split b83deea. Base was engine main def8b04. Suite 2933 / 46 / 0.


Plain-language summary

What this does. Splits Stele's fused Person read view into a pure Principal view (identity/auth) and a host-side HostAccount view (host account state), re-homes every reader, and retires the Person name. As of b83deea, all host fields are off the Person view; what remains is retiring the now-redundant Person name and the get_current_person shim.

What changed from v0.4. v0.4 recorded the proven Step 3 method and listed the four remaining fields as mechanical riders. They are done (Step 3.3, one commit). The Person view is now identity-only — id, display_name, first_login_at, last_presence_proof_at, created_at, updated_at — and field-equal to Principal. The two are now shape-identical twins; Person survives only as the get_current_person shim. v0.5 confirms this and scopes 3.7's collapse.

Decision needed. None outstanding. 3.7 is the last view-layer step; its one care-point (per-site host-vs-identity classification of the ~78 shim consumers) is flagged below for inspect-first, not a decision.

Out of scope (contract phase, separate CR). Drop persons host columns · re-target the 12 host FKs · retire the mirror triggers as an ordered pair · rename PersonRow.


Build state (as of b83deea)

| Step | Commit | State | |---|---|---| | 1 | (in branch) | Principal + HostAccount views authored | | 2 | 23d4bb5 | stele host-reads re-homed | | 3.0 | 73846d4 | CurrentUser delivery path stood up (additive) | | 3.1 | 1396552 | companion_name stripped; HostAccount cascade thread established | | 3.2 | f49c63f | personal_engagement_id stripped; shared tests/helpers/identity.py authored + proven; host classification confirmed | | 3.3 | b83deea | email/mobile/exhaustion_preference/spend_pause stripped — strip phase complete |

Person view now carries: identity only (id, display_name, first_login_at, last_presence_proof_at, created_at, updated_at) — field-equal to Principal. Every host column is re-homed onto the host_account path. Person survives solely as the get_current_person shim. Suite green and playground_dev-verified at every step.

The twin state (on the branch, never to reach main): Person (identity-only) and Principal (identity-only) are now shape-identical. 3.7 collapses them — PersonPrincipal — so no twin merges to main (the no-twin-on-main rule).


Settled Step 3 method (proven across 3.0–3.3)

Unchanged from v0.4 — recorded there in full. Summary: M1 combined delivery (get_current_userCurrentUser(.principal, .host_account), two cached PK loads, host-assembled in deps.py). M2 reader re-home by site class (leaf → get_current_user; hub → keep person + in-body host load; helper → host value as param). M3 the HostAccount cascade thread (one param through route_intent_route_*). M4 shared test helper tests/helpers/identity.py. M5 builder↔view anti-drift (drop a field from the builder's Person in the same commit it leaves the view). M6 per-field commit discipline relaxes once machinery exists (3.3 stripped four fields in one commit, 2-edit break-wall). M7 API shape constant (/me dict migrated in 3.1, keys preserved).


Remaining build steps

Step 3.7 — retire the Person name and the get_current_person shim.

The last view-layer step. Mechanical, not decision-bearing — every host-reader is already migrated — but the largest single touch in 6b (~177 type-annotation sites + ~78 Depends sites). Two cares:

  1. Collapse the twin. PersonPrincipal across the ~177 annotation sites; the Step-1 Principal view and the now-identity-only Person become one (Principal). No twin reaches main. Because they are field-equal (confirmed at 3.3), the collapse is a clean rename — no field reconciliation.
  2. Retire the shim, with per-site classification (the one care-point — INSPECT FIRST). get_current_person's ~78 Depends sites split into:

This split must be classified per site, not swept uniformly — sweeping a host-needing handler to get_current_principal would strip its host access. Most are expected identity-only (the host-readers were migrated in 3.1–3.3), so most go to get_current_principal; the few remaining host-readers go to get_current_user. Inspect-and-report the split before the sweep.

  1. Function renames (~4 sites): get_person_by_idget_principal_by_id; get_person_by_email/create_person renamed/re-typed; _row_to_person_row_to_principal (exists). get_principal_and_person_by_id (the combined projector added in 3.0 because Person couldn't derive Principal) collapses to principal-only.
  2. The shared test helper's make_person_and_host rides the rename with the rest.
  3. PersonRow (ORM row) keeps its name — contract-phase.
  4. Verify against playground_dev, not the suite alone. Suite green. Commit. Halt.

Step 3.8 — boundary + invariant verification.


Invariants (hold throughout)


Definition of done


Carry-forwards to contract phase


DUNIN7 — Done In Seven LLC — Miami, Florida CR-2026-110 — Stele Extraction Phase 6b — Person-view split — v0.5 — 2026-06-16