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 — a read-only inspection pass that grounds the P7-3 scoping note. CC inspects; CC decides nothing; CC reports facts and surfaces the two forks with the real picture so the Operator decides.
Status. Step 0 inspection brief. P7-2 (CR-2026-115) is landed and recorded across all three repos. This brief precedes the P7-3 scoping note + CR. Markdown primary (technical consumer).
Against. DUNIN7/stele main = 1077803, loomworks-engine main = 08e89c5, loomworks-record main = cb367ab (re-confirm at the top of the pass; record actual HEADs).
What P7-3 is. The final Phase 7 slice — the clone-and-run-and-use bar. A from-scratch standalone host app (NOT the engine) that mounts stele.router, wires the injection slots, and demonstrates real end-to-end use including the browser WebAuthn ceremony (a user registers a real passkey against the mounted package). Plus docs (the mount contract written down), a config generator (sized by this inspection), and the WebAuthn-ceremony-gap close. Both delivery shapes (cookie + bearer) demonstrated.
What this brief does. Grounds P7-3's scoping in the real post-P7-2 code, before any CR drafts. It has three jobs: (1) capture the live mount surface a stranger actually wires; (2) inspect the persons/signup.py tangle so the Operator can resolve the §4 ceremony fork on facts, not a guess; (3) report what a real mount actually requires so the config generator gets sized to fit. CC reports; the Operator decides both forks.
What this brief is NOT. Not a build. Not the scoping note (that follows, written against this brief's findings). No edits, no commits, no migrations — read-only throughout.
Fork 1 — the §4 ceremony. P7-2 left the add-passkey enrollment ceremony (persons.signup.add_passkey_begin / add_passkey_complete) host-side, wired into stele.router as an injection slot. Stele owns all other WebAuthn logic (stele.webauthn); this one enrollment ceremony is the exception, parked because persons/signup.py is doubly-bound (signup flow + me_security enrollment). P7-3's reference app must do something about this slot. Two paths:
add_passkey_* into stele.webauthn (dissolve the asymmetry). Move the ceremony into Stele next to the rest of the WebAuthn logic; the slot disappears; the reference app wires less. But** this reopens the parked persons/signup.py split (the engine module that the ceremony shares with the signup flow).
What CC must report for Fork 1: how tangled persons/signup.py actually is — whether lifting add_passkey_* is a clean extraction or a messy split. This fact is the whole decision. See §A.
Fork 2 — the config generator size. P7-3 includes a config generator, but its size is deliberately unset. It could be env-scaffolding-only (a .env template with STELE_SECRET_KEY / RP-ID / origin, secret pre-generated) or env-plus-a-runnable-mount-skeleton (a starter main.py with include_router(stele.router) and stubbed slots). The first is small and can't drift; the second is more useful but must track the mount shape.
What CC must report for Fork 2: what a real mount actually requires — the full set of config values and the full set of code-wiring a stranger writes to get a working mount. The size of that real surface decides whether a skeleton-file generator earns its keep or whether env-scaffolding is enough. See §C.
persons/signup.py tangle (Fork 1's deciding fact)
Inspect loomworks-engine/src/loomworks/persons/signup.py and report:
begin_signup, complete_passkey, complete_totp_verify, etc.), the me_security enrollment ceremony (add_passkey_begin, add_passkey_complete, the PendingAddPasskeyStore and AddPasskeyBeginResult types), and anything serving both.add_passkey_ share helpers, types, constants, or module-level state with the signup-flow functions? List every shared symbol. The question lifting turns on: can add_passkey_ (+ its private helpers + its types) be extracted into stele.webauthn without dragging signup-flow code, or are they entangled?add_passkey_* imports from stele.webauthn already.** If the ceremony is mostly a thin wrapper over existing stele.webauthn registration primitives, the lift is near-trivial (it's already calling the Stele functions; lifting moves the thin wrapper). If it holds substantial host-specific logic, the lift carries that logic across. Report which.add_passkey_*.** Confirm the only callers are me_security's enrollment routes (Step 0 of P7-2 found this; re-confirm against live). If a signup-flow path also calls them, the lift is more entangled.stele.webauthn landing site. If add_passkey_* were lifted, where in stele.webauthn would it land — does the module's existing shape have a natural home for an add-passkey ceremony, and would lifting require new Stele types (the PendingAddPasskeyStore / AddPasskeyBeginResult shapes — are these Stele-shaped or host-shaped)?Report, do not decide. Output a clean read of the tangle. The Operator resolves Fork 1 from it.
Inspect DUNIN7/stele/src/stele/api.py and src/stele/__init__.py (the P7-2 router + SDK) and report the mount surface as it exists, so the reference app builds against the real thing, not the CR's description:
api.py.)stele exposes at top level (the 65 primitives, the lazy stele.router, the slots), and the exact import paths a host uses.stele.router + app.dependency_overrides keyed on the exact slot objects). Report exactly what a host writes to override a slot (the app.dependency_overrides[slot] = provider form, with the real slot object names).extract_token (bearer default), how a host overrides it for cookie, and issue_session (mint-only). Report what a host writes for each of the two delivery shapes (cookie + bearer) so the reference app can demonstrate both.provide_webauthn_config must return (stele.webauthn.WebauthnConfig), and specifically what RP-ID / origin / RP-name fields it carries. This is the config the generator must scaffold (§C) and the ceremony needs (Fork 1).Synthesize §B into the concrete answer to "what does a stranger write to get a working mount":
navigator.credentials.create() / .get() calls, the RP-ID/origin binding) to drive a real passkey enrollment against the mounted router. This is the ceremony-gap-close surface; report what the reference app's browser front must do.So the scoping note builds the reference app against real constraints:
stele.router is a plain FastAPI APIRouter mountable in any FastAPI app, so the reference app is a minimal standalone FastAPI app (not the engine, not Next.js). Report any coupling that would complicate a bare-FastAPI mount.0001_baseline from P7-1) is what the reference app runs to stand up its DB, and whether a throwaway SQLite or a real Postgres is needed (the routes use AsyncSession; report what the primitives assume).navigator.credentials ceremony, the fetch calls to the mounted routes, the token handling for cookie vs bearer). Report the shape; the scoping note designs it.../stele editable dep stays; retiring it for a version pin is a parked thread, not P7-3. (But: if Fork 1 resolves toward lifting, note any interaction with the package path.)stele.router — not P7-3; the engine keeps its hand-rolled routers.
A Step 0 inspection report (loomworks-stele-phase-7-p7-3-step-0-inspection-report-v0_1.md, Markdown primary) carrying:
persons/signup.py tangle read (Fork 1's deciding fact).Then halt — the Operator resolves both forks, and the P7-3 scoping note is written against this report.
add_passkey and stop — trace what it shares with the signup flow, because the shared surface is what decides the lift, and shared helpers won't show up in a name-grep for the ceremony.DUNIN7 — Done In Seven LLC — Miami, Florida Loomworks — Stele Phase 7 P7-3 Step 0 Inspection Brief — v0.1 — 2026-06-19