DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path session-handoffs/loomworks-recovery-completeness-handoff-v0_1.md

Handoff → Recovery completeness session — v0.1

Version. 0.1 Date. 2026-06-12 Purpose. Open a fresh, isolated session to complete account-recovery for Loomworks personal identity: make the seed's three committed recovery mechanisms real where they are not, carry the seed's positive recovery commitment forward into the Companion functional spec (which currently states recovery only negatively), and resolve the sign-in email-field question inside recovery rather than ahead of it. This is scoping-and-build-planning work, not a single CR drafted in flight. Paste or upload this on arrival.

Role of this session. Scope, decide, and produce CR-drafting handoff(s) and any seed/spec amendment for Operator approval. Extended-inquiry on the design questions; disciplined on the build. Treat as Discovery raw material — when a position is corrected, name the prior alongside the current.


1. Plain-language summary

The seed already designed recovery well — line 137 names three credential-based mechanisms and rejects email. The problem is not design; it is that the design is only partly built, the spec never carried the design forward, and a sign-in email-field divergence surfaced that turns out to be entangled with the recovery design. This session makes recovery whole: build what is missing, document what is undocumented, and settle the email field with the recovery picture in full view.


2. What this session must orient against first (session-start discipline)

This is authentication-framework work — seed territory, the highest-governance part of the project. Before any substantive work, have Claude Code (CC) surface from loomworks-record (highest-versioned present; do not assume from this handoff):

The seed governs the spec; where the seed is silent the comprehensive specification governs.


3. The findings this session inherits (verified 2026-06-12; verify still-current, do not re-derive blindly)

A smoke test of the local Companion pair on the M4 (Operator Layer :3001 ↔ engine :8000) and a read-only investigation produced these. They are the starting facts.

3.1 The seed's recovery design (sound — line 137, verbatim)

> Recovery uses credentials the user controls and that cannot be hijacked at an external provider. Recovery codes generated at sign-up, additional registered authenticators, or operator-mediated identity verification are the acceptable mechanisms. Email-based password reset is not a recovery mechanism in Loomworks.

Three committed mechanisms: (1) recovery codes at sign-up, (2) additional registered authenticators, (3) operator-mediated identity verification. The seed commits the posture and (per its style) leaves mechanism detail to the specification. This is a positive commitment — recovery is not defined only negatively.

3.2 The build state (one of three works; two do not)

| Seed mechanism (line 137) | Engine state | Detail | |---|---|---| | Recovery codes at sign-up | BUILT, working | persons/recovery.py (generate, bcrypt-hash, store, verify-and-consume); 10 codes generated and displayed once at sign-up (persons/signup.py); redeemed at POST /auth/login/recovery (persons/login.py:442). | | Additional registered authenticators | NOT usable (schema-only) | The data model is one-to-many (WebauthnCredentialRow, table webauthn_credentials, unique on credential_id not on person), so the schema allows multiple passkeys — but the only passkey-registration endpoint is POST /auth/signup/passkey. There is no endpoint to enroll a second/backup passkey for an existing user. So every user has exactly one passkey; this recovery path cannot be exercised today. | | Operator-mediated identity verification | NOT built | No personal-account operator-recovery endpoint. (/admin/ is credit/provisioning; POST /engagements/{id}/contributors/{cid}/totp/reset is an engagement-operator resetting a contributor's* engagement-scoped TOTP — a different concern from a person recovering their own lost authenticator.) |

3.3 The exposure, stated plainly

Today a user has exactly one passkey and one set of recovery codes, and nothing else. Recovery rests entirely on the codes. Lose the authenticator and the codes → permanently locked out; the other two seed-promised mechanisms do not exist in runnable form. This is the opposite failure shape from email: email recovery is too available (a backdoor); this is too unavailable (one working path, no redundancy). The seed correctly refused the over-available method; the under-availability is the unpaid cost.

Highest-value, lowest-cost fix: an endpoint to enroll a second passkey. The schema already supports it. A backup authenticator is a stronger recovery method than codes (not transcribable, not loseable-on-paper) and is the method serious passwordless systems lean on. This is a missing endpoint, not a missing design.

3.4 The spec gap

The Companion functional spec §10.3 states recovery only negatively ("recovery never uses email-based reset") and carries none of the seed's three positive mechanisms forward. No architecture/spec document in loomworks-record states a positive recovery mechanism. The positive commitment lives solely in the seed (line 137). The spec needs to carry the seed's positive commitment forward.


4. The email-field question — entangled with recovery, deliberately deferred into this session

4.1 What surfaced

The Operator Layer sign-in form presents an optional email field, made optional in the Phase-57 amendment, used as a passkey-discovery hint; identity and lookup are by credential_id, not email. This diverges from the seed's Sign-in clause (line 133, verbatim):

> Sign-in does not request an email address. Sign-in does not key user lookup on email. Sign-in does not offer an email-based account recovery path.

And from spec §10.3 (heading and body both bake in "never requests email").

4.2 The Operator decision already taken (2026-06-12)

The Operator chose to relax line 133 to permit a non-identity email hint, rather than remove the field. Recorded. The Operator's stated rule: "email and mobile number can be associated with a user, but never used as the identity for sign-in."

4.3 The tension that paused the amendment (drift-surface finding — must be resolved in this session)

The seed's Sign-in Path 1 already specifies the WebAuthn discoverable-credential mechanism for identifying the user:

> Path 1 — Passkey. The browser's native passkey prompt identifies the user (via the WebAuthn discoverable-credential mechanism) and authenticates them in a single step.

Discoverable credentials are exactly how a user with one-or-many passkeys signs in without naming themselves. So the email hint may be solving a problem the seed's own architecture already solves. Two honest readings, unresolved:

  1. Discoverable credentials suffice → the hint is redundant → remove the field instead of amending. The recovery finding (§3) strengthens this: the seed already commits to the discovery mechanism.
  2. The hint helps real cases discoverable credentials handle imperfectly (an authenticator holding many resident keys; weak platform passkey UI) → the amendment stands, but its honest justification is "smoothing an imperfect discoverable-credential flow," not "providing discovery the system otherwise lacks." If the amendment is written, it must not imply email does discovery that Path 1 already assigns to discoverable credentials — or the seed contradicts itself.

This session resolves which reading holds, with the recovery picture in full view, and only then finalizes either an amendment (v0.13) or a field-removal. The amendment was deliberately not drafted in the originating session because the recovery finding is material to it.

4.4 Why they belong in one session

The email field's justification (passkey discovery) and the recovery design (additional authenticators, discoverable-credential sign-in) share the same mechanism — discoverable credentials. Deciding the field without the recovery picture is what produced the tension in the first place. One session, one coherent authentication-framework pass.


5. The work this session should scope (not a fixed plan — the session decides)

Candidate scope, in rough priority. The session confirms, reorders, or amends.

  1. Second-passkey enrollment endpoint — the high-value, low-cost fix (§3.3). An endpoint letting an authenticated user register an additional passkey. Schema already supports it. Makes the seed's mechanism (2) real. Likely the spine of the session.
  2. Resolve and execute the email-field decision (§4) — either draft the v0.13 seed amendment (relaxing line 133, with the three protections held: optional/not-keyed/not-recovery, and honest about the discoverable-credential overlap) plus the spec §10.3 follow-on; or remove the field and conform the build. Decide reading 1 vs 2 first.
  3. Carry the seed's positive recovery commitment into the spec (§3.4) — amend §10.3 (or a better-placed section) to state what recovery is, not only what it is not.
  4. Operator-mediated recovery — the third seed mechanism, unbuilt. Scope whether it is needed now or deferred. Note: it fits the architecture's grain unusually well — "a governing human re-authorizes access, recorded as assertions" is the same source-supplies/Operator-governs shape recurring elsewhere (see §7). Provenance/OVA machinery is built for exactly this. May be a strong fit but larger; the session decides build-now vs scope-and-defer.
  5. Recovery-code surfacing — confirm the one working mechanism is actually reachable in the Operator Layer UI (the smoke test verified the engine path, not the frontend surface). If a user can't see/regenerate codes in the UI, the one working mechanism is functionally weak.

6. Discipline notes for this session


7. One principle worth carrying (cross-session)

Operator-mediated recovery (§5.4) is another instance of a principle that recurred four times in the originating session (the skill/method vocabulary work, standing note v0.6 §2.1/§5/§7/§9.4): the source is acknowledged / supplies; the authority is granted by the Operator. Recovery-as-Operator-re-authorization is that principle at the credential layer — a governing human deliberately re-authorizes access, recorded. This is a strong v0.21 methodology consolidation candidate (source-supplies / Operator-governs), already flagged in the manifest. Not this session's work to consolidate, but if operator-mediated recovery is designed here, it should be designed in that principle's shape.


8. What does NOT transfer

The skill/method/vertical vocabulary work from the originating session (standing note loomworks-standing-note-skill-method-vocabulary-v0_6, committed e04c222) is closed and unrelated. Its carried threads (personality/interaction domain; product-vs-service line; contract-proposal representation) are not this session's concern. The deployment question that started the originating thread (Companion live at dunin7.com) is deferred — the Operator confirmed local M4 access is sufficient for now; the Phase-52 engine-deployment gate remains deferred. Do not let either bleed in.


DUNIN7 — Done In Seven LLC — Miami, Florida Handoff → Recovery completeness session — v0.1 — 2026-06-12