Version. 0.1 Date. 2026-06-19 Author. Marvin Percival (DUNIN7 Operator) with Claude.ai (scoping) on DUNIN7-M4. For. Claude Code (CC) on DUNIN7-M4. Read-only inspection. No edits, no commits, no migrations. Produce a report; file it. Status. Step 0 inspection brief — the grounding pass that precedes the Phase 7 (packaging) scoping note. Markdown primary (technical consumer — CC execution).
Grounding line. engine main at fe7c3f1 (CR-B merge), alembic head 0093, suite 2928/0/46. If main is not at fe7c3f1, stop and report drift — do not inspect against a different tree.
What this is. The read-only grounding pass for Stele Phase 7 — the arc that extracts Stele from the engine monorepo into a standalone, mountable, clone-and-run plugin. Before any extraction CR is drafted, CC inventories every way the engine and Stele reach across each other, organized by accessor class, and triages each finding as a hard extraction blocker or a mechanical repoint.
Why it's shaped this way. CR-B's Step 0 swept FK references and ORM stubs with zero drift — and was still blind to three other ways code reached persons: raw-SQL reads, the ORM FK strings the stubs targeted, and the down-path's data dimension. Those surfaced at execution, not grounding, and one (empty recipient lists) would have been a silent production break. The lesson: an inventory's lenses define its blind spots. This brief fixes that by naming the accessor classes explicitly as separate categories — each reported even when empty, so the blind spots are chosen, not inherited.
What CC produces. One report, loomworks-stele-phase-7-step-0-inspection-report-v0_1.md, with one section per accessor class (1–7 below), each carrying findings + a blocker/mechanical triage column, plus a synthesis section (§8) that answers the one question that decides the CR shape: is the import-graph clean enough to extract in one CR, or does it need a de-coupling sub-arc first?
What CC does NOT do. No edits. No commits. No migrations run. No create_all. Read-only inspection only — grep, git, file reads, and read-only DB introspection against playground_dev. If any step would mutate state, stop and report instead.
Enumerate accessor classes explicitly. A "zero references" result under one lens does not clear the others. CR-B's FK lens was exact and still missed raw-SQL reads. Report every category below even when it is empty — an empty category is a finding ("no raw-SQL reads of Stele tables exist"), not an absence to skip.
Triage every finding. For each finding, mark it:
Direction matters. For import-graph and migration coupling especially, record the direction of every dependency. Engine → Stele is expected and fine (the engine consumes Stele). Stele → engine is the extraction blocker (a mountable plugin cannot import upward from the host it mounts into). State the direction on every edge.
Report, don't fix. Where CC sees an obvious repoint, name it in the triage column — do not perform it. This is grounding, not building.
Establish the exact target set first, from the real tree — do not work from this list, confirm and correct it:
SteleBase MetaData. Per CR-B end-state: principals, plus the credential/recovery tables (webauthn_credential, recovery_code — confirm exact table names from stele/models.py). Report the full authoritative list as found.stele/ package (confirm path — expected src/loomworks/stele/ or similar; the CR-B migration-path delta proved repo-root assumptions can be wrong). Report the real path and the module inventory.For every Stele table and every Stele module/surface, report each category below. Each section: the findings (file:line, the reaching construct, the direction), then the triage (BLOCKER / MECHANICAL / OPEN) with a one-line WHY.
Classes, relationship() objects, and ForeignKey objects (not strings — those are category 2) in engine code that point at Stele tables or import Stele model classes.
relationship(...) targeting Stele classes; ForeignKey(SteleClass.col) object form.relationship()s back to an engine class is a BLOCKER (upward coupling).
ForeignKey("stele_table.col") string targets that resolve in-metadata. CR-B Delta 3: removing the persons stubs stranded 8 of these; they converted DB-only because principals is on a separate MetaData.
ForeignKey("...") string whose target is a Stele table, across the whole engine.relationship() that needs in-metadata resolution.
text() queries, raw SELECT/INSERT/UPDATE/JOIN that name Stele tables directly by string. This is the lens CR-B's Step 0 missed (4 production sites reading persons).
FROM principals, JOIN principals, INSERT INTO principals, etc.). Search the table names as string literals, not just the ORM classes.Where Stele's migrations interleave with engine migrations, and what an independent Stele migration set requires. CR-B Delta 4: a down-path that re-points FKs needs the target table populated, not just schema-present.
migrations/versions/ are Stele-owned (create/alter Stele tables) vs engine-owned; the dependency edges between them (does an engine migration depend on a Stele revision, or vice-versa?); whether any Stele migration references an engine table.down_revision, and every cross-edge (Stele-rev depended on by engine-rev = expected; Stele-rev depending on engine-rev = BLOCKER for an independent set).down_revision is an engine rev) is BLOCKER-shaped — name the exact interleave points.What the engine imports from Stele (expected) and what Stele imports from the engine (the extraction blocker).
import and from … import inside the stele/ package that resolves to an engine module (config, db session, models, utils, settings — anything outside stele/).How Stele currently receives its DB session and config (session-injected, config-injected per the manifest), and what a mountable router needs instead.
stele/ gets its Session/engine (passed in? imported from an engine module? a global?); how it gets settings/config (e.g. loomworks_secret_key — the ExtractionSkill test pattern reads a per-engagement key; confirm how Stele reads its own config).Which engine routes are actually Stele's, what mounting them as a router requires, and what auth/middleware they assume from the engine.
stele/ ownership, not by name guessing); for each, the auth dependency, middleware, and any engine-context it assumes (current-principal resolution, etc.).After the seven sections, a synthesis section answering, in plain terms:
Is the import-graph clean enough to extract Stele in a single CR, or does extraction need a de-coupling sub-arc first?
Also report, for the scoping note's sequencing:
stele/ package, how many engine call-sites consume Stele.git -C <engine> rev-parse HEAD = fe7c3f1; git -C <engine> status clean; alembic head 0093. If not, stop and report.stele/ — categories 1–3 are about engine code reaching into Stele.playground_dev for the FK/constraint truth (the inbound-FK-on-principals set, the Stele table list) — \d+ / catalog queries, no mutation.
loomworks-stele-phase-7-step-0-inspection-report-v0_1.md — Markdown primary, filed to loomworks-record at phases/stele-extraction-phase-7/. Sections 1–7 (one per accessor class, findings + triage), section 8 (synthesis + deliverable-set sizing). Grounding line at top: engine main at the confirmed HEAD, alembic head, suite count.
DUNIN7 — Done In Seven LLC — Miami, Florida Loomworks — Stele Phase 7 Step 0 Inspection Brief — v0.1 — 2026-06-19