Phase 0: critical-path risk reduction (tracking)
closedPurpose
Overarching tracker for Phase 0 — critical-path risk reduction: build the thinnest possible walking skeleton through the three riskiest integrations first, so unknown unknowns surface in week one rather than after months of feature work:
- Control plane ↔ Stalwart deployment integration (Registry API over real deployment)
- Credential model: how the control plane is authorized to act on behalf of arbitrary users (masquerade/impersonation)
- atproto OAuth flow for authn/authz against a user’s PDS at signup
Design basis: docs/00-overview.md … docs/09-open-questions.md (decisions locked 2026-08-24).
Child issues & dependency graph
| ID | Issue | Depends on |
|---|---|---|
ccd3c37 |
[C1] Deployment harness: local Stalwart OSS + Postgres + spaces-alpha PDS | — |
24dcaa6 |
[C2] stalwartsync: Registry-client spike — schema, object lifecycle, two-phase reload | C1 |
3541d85 |
[C3] Control-plane credential & impersonation model (masquerade as any user) | C1 |
a589d34 |
[C4] OAuth broker walking skeleton — indigo ClientApp vs live PDS | C1 |
c1c7e19 |
[C5] OIDC issuer → Stalwart OpenId directory wiring + app-password round-trip | C2, C3, C4 |
0d541aa |
[C6] End-to-end risk probe: signup→login→read-mailbox + failure injection | C1–C5 |
ccd3c37 ──► 24dcaa6 ─┐
├──► 3541d85 ├─► c1c7e19 ──► 0d541aa
└──► a589d34 ─┘
C2/C3/C4 are parallelizable once C1 lands.
Phase exit criteria
0d541aapasses end-to-end against real Stalwart + real PDS containers, including one injected failure per dependency.- Every surprise discovered during C1–C6 is recorded as a new bug issue (link from the discovering issue) and triaged into later phases.
- Decision records exist for: impersonation mechanism (
3541d85ADR) and any deviation from design docs.
6 Comments
Scope change on C1 (ccd3c37) — 2026-08-24
Per design review, C1 was revised before implementation:
modernc.org/sqlite); Stalwart data store = SQLite configured at bootstrap. Docs 01 §2/§8, 07, 09-Q7 updated.../rtw/servicespattern (dockerTools.buildLayeredImage via nix/lib.nix mkImage; packages under nix/pkgs; entrypoints under nix/scripts). Stalwart is built from source @ rev 2add611e withenterprisefeature OFF — nixpkgs’ stalwart-mail (0.15.5) predates the Registry architecture the whole plan depends on.devenv uporchestrates bring-up via process-compose processes (no Justfile for lifecycle).Status: all Nix/devenv/script code written; git-dep outputHashes resolved; full Stalwart rust build running. One manual blocker for the Nix-built PDS: npm package-lock generation fails silently in this environment and npm is outside agent permissions — documented manual step in ccd3c37; devenv falls back to upstream alpha image until it lands.
Design-status note — 2026-08-24
Owner is reconsidering where data lives (on-protocol in users’ PDS repos vs. Stalwart stores) as Phase 0 progresses. Consequences for how we work until that settles:
C2 (
24dcaa6) complete — 2026-08-25Child issue C2 (stalwartsync Registry-client spike) is implemented and green against the live C1 harness; see its findings comment (2644d5c) for the full record. Summary for the tracker:
internal/stalwart(merged JMAP+Registry client, one constructor, no env side-effects), record packagestenant/domain/account/settingswith required tenancy (ADR-0004), integration journey test proving the signup story end-to-end. All three acceptance criteria met live (lifecycle green, replay-idempotency, masked-password proof).objectIsLinked, unindexed tenant name,calculateTotalgating, omission-based secret preservation,/api/discover= OIDC doc. All recorded on24dcaa6and corrected in code + docs/05.c1c7e19) depends on C2’saccount.IssuePassword/Updateand the verified app-password auth path; C3 (3541d85) benefits from the confirmed recovery-admin +Impersonatemechanics. C2’sstalwart.Clientis the shared seam C5/C6 build on.Follow-up issues filed: pagination/O(n) tenant lookup, and the DKIM-task orphan edge (links below).
New child issue + design revision
b5a31bd[C7]: domain ownership verification + readiness probes (internal/domain) — implements the two-gate proof (TXT challenge + apex-handle piggyback) from ADR-0005. Depends on C2 (Stalwart lifecycle ininternal/domain) and feeds C6 (signup journey gate).claimed → verifying → verified → active(ownership gate before any Stalwart provisioning); new §4a + docs/adr/0005-domain-ownership-verification.md. Docs/01/02 touched to match.Design decision landed — ADR-0006 (2026-08-28)
The data-location question tracked since 2026-08-24 (comment f89287c) is resolved. New ADR supersedes the affected docs:
Effect on C6
0d541aare-scoped (comment 09d75f4): happy path no longer publishes a public claim or consumes jetstream for signup.New child issues (Phase 1, post-C6)
f6192a1a472ea3ee2256b12ce549f15633ab04aeb99185c91Phase 0 exit met — 2026-09-08
All Phase-0 child issues are closed and the exit gate passed:
ccd3c3724dcaa63541d85a589d34c1c7e190d541aab5a31bdThe risky seams (Registry integration, impersonation, OAuth, OIDC translation) are proven against a live harness. Nothing in Phase 0 blocks the next step.
Path forward
New tracker
70790ed(“PoC: minimal live deployment”) carries the thin-PoC plan. Scope is deliberately thin: control plane + Stalwart on a live server, app-password read-mail proof. The on-protocol ADR-0006/0007 work (postmaster, spaces, reconciler, webmail) is deferred until after the thin PoC deploys.Storage/failover decision landed as ADR-0008: Stalwart store = FoundationDB in prod (SQLite in dev), app DB = SQLite everywhere, failover = active/passive + VIP + FDB lease fence (active/active coordinator deferred to Q8).
docs/deployment.mdupdated to match.Tracker-lag note
The tracker lags the code in two places worth recording: -
f6192a1(lexicons) is effectively done in code (lexicons/at/sovrn/*+ generatedapi/sovrntypes incl.tenant.detail/domain.detail/mail.account/mail.service); only network publication (sovrn.at_lexiconTXT) remains. -f15633a(reconciler) is ~half done: app-view XRPC, SQLite store (TID↔StalwartID), DNS gate, and background verifier exist; themailbox_claimsstate machine, spaceproj publisher, and three-way sweep do not.