DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path phases/stele-extraction-cr-b/loomworks-stele-cr-b-cr-drafting-handoff-v0_1.md

Loomworks — Stele Extraction CR-B CR-Drafting Handoff — v0.1

Version. 0.1 Date. 2026-06-19 Author. Marvin Percival (DUNIN7 Operator) with Claude.ai (scoping) on DUNIN7-M4. For. A fresh Claude.ai chat — the CR-drafting role. Draft CR-2026-113 (Stele Extraction CR-B), the sole remaining Stele arc, from the seed, the Step 0 report, and the carry-forwards below. Status. CR-drafting handoff. The FK-target decision is settled (principals.id). Step 0 is done and its findings collapse the scope to less work than the inherited handoff feared. This handoff carries the firm scope and the three gotchas Step 0 surfaced. Markdown primary (technical consumer / next-session orientation).


Plain-language summary

What CR-B is. The last Stele arc before Phase 7 (packaging). After CR-C, principals is the canonical identity table and persons stands only as a reversed mirror feeding 11 host foreign keys. CR-B moves those 11 FKs onto principals.id, then removes everything that only existed to keep persons alive — the reversed trigger, the 4 registration stubs, and the persons table itself.

What's already settled (do not re-open). The FK target is principals.id — a UUID, the id of an authorized identity, per the seed's Identity section ("the UUID is the identity; it is what other Loomworks records reference"). The Operator settled it and grounded it against the seed. The CR drafts on this; it does not re-litigate it.

What Step 0 found (this is the firm scope). All 11 FK columns are already UUID — zero column-type migrations, all 11 are pure constraint re-points. Count is exactly 11, no drift. Plus three precise gotchas the drafter must carry (below).

What the CR drafter does. Draft CR-2026-113 v0.1 — the planned trajectory — as a migration arc with a tested down-path, the CR-A safety model. Per-step commits, suite green at each, halt before push, explicit-path staging. The as-built v0.2 with a §0 corrections section comes after execution (the standing CR discipline).


Read first (the drafter's orientation)

In order, from loomworks-record (behind Cloudflare Access — if unreachable, ask CC to fetch to Downloads):

  1. The seedcandidate-seeds/loomworks/loomworks-candidate-seed-v0_12.md (canonical). The Identity section (§Authentication framework → Identity) is the ground for the settled FK target: the UUID is the identity, held in the principal record, and it is what other Loomworks records reference.
  2. The Step 0 reportphases/stele-extraction-cr-b/loomworks-stele-cr-b-step-0-inspection-report-v0_1.md (filed by CC). The firm scope: the 11 FKs with exact column names and delete behaviors, the type confirmation, the 4 stubs, the trigger body, the migration shape. Draft from this report's facts, not the inherited handoff's shorthand.
  3. The Step 0 inspection briefphases/stele-extraction-cr-b/loomworks-stele-cr-b-step-0-inspection-brief-v0_1.md. What was asked, for context on what the report answers.
  4. The CR-C completion recordphases/stele-extraction-cr-c/loomworks-stele-cr-c-completion-record-v0_1.md. §5 end-state (where CR-B starts), §6 the four carry-forwards.
  5. CR-2026-112 v0.2change-requests/cr-2026-112-stele-extraction-cr-c-v0_2.md. The as-built shape to model CR-B's structure on; §0 shows the corrections-preserved discipline the CR-B as-built will follow.
  6. The CR-B opening handoffloomworks-stele-cr-b-opening-handoff-v0_1.md (Downloads, also in record). Context and standing disciplines — but the Step 0 report supersedes its FK-list shorthand and its "audit/credit" phrasing (see corrections below).

The settled decision (do not re-open)

FK target: principals.id. A UUID — the id of an authorized identity. Grounded against the seed's Identity section by the Operator. The Phase-7 boundary consideration the opening handoff flagged was resolved: the host already FK-references principals (via host_account.id → principals.id and the credential FKs), so pointing the 11 at principals.id makes them consistent with the coupling that already exists structurally — it introduces no new coupling kind. Settled.


The firm scope (from Step 0 — this supersedes the opening handoff's shorthand)

Four tasks, dependency order. Task 1 is settled; Tasks 2–4 are the build.

Task 1 — FK target — SETTLED

principals.id. No build step; the precondition, already met.

Task 2 — Re-target the 11 host FKs to principals.id

All 11 are pure constraint re-points — every column is already UUID, so no column-type migration on any. The 11, with the three gotchas Step 0 surfaced:

Gotcha 1 — 6 of 11 columns are NOT named person_id. The "11 × person_id" shorthand was wrong. The real column names (the migration must name each exactly, not pattern-match):

The drafter pulls the exact table→column pairing from the Step 0 report (it has the full mapping). Do not infer it.

Gotcha 2 — 3 carry ON DELETE CASCADE, the rest NO ACTION. CASCADE on person_settings, saved_filters, workspaces; NO ACTION on the other 8; ON UPDATE NO ACTION throughout. Each re-targeted constraint must preserve its own delete behavior verbatim. A CASCADE silently dropped or a NO ACTION silently turned to CASCADE is a real behavior change — call it out per-FK in the CR.

Gotcha 3 — one schema-qualified FK, not several. Only credit.credit_grant is non-public (schema credit). There is no audit FK — the inherited "audit/credit schemas" phrasing over-counted. The migration handles credit.credit_grant schema-qualified; the other 10 are public.

Populatability holds without backfill. 9 of the 11 are NOT NULL, but persons.id ⊆ principals.id via the reverse mirror, so the new target is already populatable for every existing row. Assert at build (verify the subset on playground_dev); no data backfill.

Task 3 — Retire the reversed mirror trigger (0090)

Once no FK references persons, the principals → persons mirror has no job. Drop trigger stele_principals_mirror_to_persons and function stele_mirror_principals_to_persons(). Step 0 captured the full function body verbatim — the down-path restores the trigger + function exactly (the created_at-immutable-on-conflict behavior included).

Task 4 — Remove the 4 _PersonRow stubs and drop persons

All 4 stubs are separate MetaData registrations of persons (files/models.py, notifications/models.py, orchestration/models.py, persons/models.py) — all id-only FK-target stubs, none an app model. All 4 removed at table-drop, token-level (NAME-token sweep, never a blanket \bPerson\b regex — the standing discipline, proven through 6b→CR-A→CR-C). Then DROP TABLE persons.


The one sequencing decision for the CR to settle

Are Tasks 3 and 4 one migration or two? Step 0 gives the input: the down-paths are distinct — Task 3's down restores the trigger + function verbatim; Task 4's down recreates persons (7 columns) + the 4 stubs. The drafter decides, informed by:

This is a CR-drafting call. State the choice and the reasoning in the CR; either is defensible. (Lean, not binding: two migrations — persons can't drop until the trigger is gone anyway, and single-purpose down-paths are easier to verify against playground_dev.)


Corrections to the inherited record (name, don't smooth — per Discovery discipline)

The CR-B opening handoff and the CR-C completion record both carried CR-C-era assumptions Step 0 corrected:

  1. "audit/credit schemas" → credit only. No audit FK exists. One schema-qualified FK (credit.credit_grant), not several. (Opening handoff §scope Task 2; CR-C record §6.)
  2. "11 × person_id" → 6 of 11 are differently named. The shorthand hid claimed_by_/added_by_/created_by_/owner_/uploaded_by_ prefixes. (Opening handoff §scope Task 2.)
  3. "remove the 4 stubs (incl. the new persons/models.py one)" → all 4 are equal-status separate registrations. None is privileged; all 4 drop together at table-drop. (CR-C record §6 carry-forward 3.)

The CR drafts on the corrected facts and records these corrections so the trajectory stays walkable.


CR structure to follow (model on CR-2026-112)


Standing disciplines to carry in


What CR-B unblocks

Phase 7 — de-engine completion + packaging. Once persons is gone and the 11 FKs anchor on principals.id, Stele's table set is clean for extraction: the standalone repo, Stele's own dependency manifest + migration set, the SDK surface, docs-with-runnable-examples, the reference app, the thin config generator — the clone-and-run repo for the Claude Code Miami independent-testing milestone. CR-C met the stele/models.py precondition; CR-B removes the last persons coupling.


Open methodology note (low priority, not for CR-B execution)

The manifest's §2.D methodology section was not updated with the 5 CR-C lessons (they live in Entry 112's prose). Rides along to the v0.21 consolidation; does not block CR-B.


DUNIN7 — Done In Seven LLC — Miami, Florida Loomworks — Stele Extraction CR-B CR-Drafting Handoff — v0.1 — 2026-06-19