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.
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.
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 — Person → Principal — so no twin merges to main (the no-twin-on-main rule).
Unchanged from v0.4 — recorded there in full. Summary: M1 combined delivery (get_current_user → CurrentUser(.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).
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:
Person → Principal 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.get_current_person's ~78 Depends sites split into:Depends(get_current_user) (read user.host_account. / user.principal.),Depends(get_current_principal) (a thin identity-only dependency; e.g. the 5 me_security handlers left on get_current_person in 3.3 are identity-only).
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.
get_person_by_id → get_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.make_person_and_host rides the rename with the rest.PersonRow (ORM row) keeps its name — contract-phase.playground_dev, not the suite alone. Suite green. Commit. Halt.Step 3.8 — boundary + invariant verification.
stele/ imports nothing from persons/. No migration; triggers and DB columns untouched. Full suite green. Commit. Halt. Then merge to main, record, retire branch (6a close pattern).0085 → principals, 0086 → host_account).persons keeps all 23.stele/ imports nothing from persons/.playground_dev per touched route.Principal view (Stele); HostAccount view (host-side); all readers re-homed.Person name retired at view + function layer; no twin on main; shim (get_current_person/ResolvedSession.person) retired; ~78 Depends sites on get_current_user (host) / get_current_principal (identity); get_principal_by_id etc.PersonRow row name survives (contract-phase).playground_dev clean.main, recorded, branch retired.PersonRow host-side; drop persons host columns; re-target 12 host FKs to host_account; retire mirror triggers as an ordered pair.persons/host_account_view.py imports HostAccountRow from stele/models.py — resolves when the row relocates host-side.personal_engagement_id= kwarg to local builders without reading it back. Follow-on consolidation onto the shared helper — out of 6b scope.persons.personal_engagement_id → engagements FK isolation issue (passes once any engagement-loading module is in the run; full suite green). Pre-existing, not a 6b change. Relevant at contract phase when personal_engagement_id's FK is re-targeted — flagged so it is not rediscovered cold.personal_engagement_id classification — closed (confirmed host; v0.4 trajectory item 8).deps.py, not a generic resolve_session rewrite. Until profiled, the two-load shape stands.
DUNIN7 — Done In Seven LLC — Miami, Florida
CR-2026-110 — Stele Extraction Phase 6b — Person-view split — v0.5 — 2026-06-16