morphit/docs/adr/0005-phase3-subphase-split.md

164 lines
7.1 KiB
Markdown

# ADR-0005: Split Phase 3 into three subphases
**Status:** Accepted
> **2026-05-07 forward note:** the "3-minute replace-window
> enforcement" line items below describe the value as
> originally implemented. Updated to **15 minutes** in Part
> 70; see ADR-0001 Amendment 2026-05-07 for the rationale.
> **2026-05-12 forward note (Part 120 audit):** the
> "Go service" / "Go relay" / "Go indexer" framing below
> describes the original Phase 3a/3b implementation plan.
> Both shipped as **Node.js/TypeScript** services (`tsx` as
> the runtime). The rationale for choosing TypeScript over
> Go is captured in ADR-0008 §"Writing the indexer in Go
> instead of Node.js/TypeScript" (no actively-maintained Go
> library for Blurt signature verification means we'd
> re-implement; `@beblurt/dblurt` gives us the full verify
> path in TS). This ADR is preserved with the original Go
> framing intact for historical accuracy.
**Date:** 2026-04-18
**Deciders:** project maintainer
**Supersedes:** Plan v1.3 §348 description of Phase 3 as a single phase
## Context
Plan v1.3 described Phase 3 as a single deliverable covering: posting
relay, account creation UI, indexer, peer gossip, REST + RSS,
order browse + filter UI, 3-minute replace-window enforcement, sybil
fee logic, and self-trade detection.
After completing Phases 1 and 2, several properties of that original
scope became clear:
1. **Scope is large.** Each bullet above is at least one development
session of focused work, several are two or three. A single-tarball
phase would mean 10+ turns between testable deliverables.
2. **Infrastructure precedes feature work.** The relay and indexer
are Go services, new to the repo; they need scaffolding (module
layout, Postgres schema, build system, deployment scripts)
before feature code can land. Without a mid-phase checkpoint,
the user has to accept a long stretch of "trust me, this is all
necessary" work before anything is visible.
3. **Each bullet has distinct value on its own.** Account creation
works without the orderbook UI. Orderbook browse works before
posting is wired. Each slice is individually shippable to a
staging environment, which means the user can poke at real
services and report issues mid-phase rather than at the end.
4. **The operator has now completed the Blurt account registration
prerequisites.** `morphit` and `morphit-relay` exist on-chain as
of 2026-04-18. This unblocks the relay subphase specifically —
we can start it immediately rather than gate it behind user
action.
## Decision
Phase 3 is split into three subphases, each producing a standalone
tarball:
- **Phase 3a — Relay + account creation.** Go relay service that
accepts signed `account_create_with_delegation` ops from users and
pays the Blurt RC cost. Client-side account-registration UI that
collects a chosen Blurt account name, signs locally with the user's
owner key via `useOwnerKey()`, hands the op to the relay, and
activates the user's display-name broadcast flow. Exit criterion:
a first-time user can onboard end-to-end and end up with a real
Blurt account without Morphit ever holding their keys.
- **Phase 3b — Indexer + orderbook read.** Go indexer service that
streams the Blurt chain and materializes Morphit ops into a
queryable Postgres database. REST + RSS endpoints with the full
filter set promised in the `rss_feeds` FAQ entry. SvelteKit
orderbook route wired to live data. Peer-to-peer gossip between
indexer instances (so the user's app has more than one data
source). Exit criterion: a visitor can browse live orders on
morphit.io, filter them, and subscribe to an RSS feed of
matching orders — even before any orders exist to browse.
- **Phase 3c — Order posting + enforcement.** Client-side compose UI
for new orders. `morphit_order_v1` + `morphit_order_replace_v1`
ops with on-chain signing via `useActiveKey()` for BLURT fee
payments. 3-minute replace-window enforcement at the indexer
(per ADR-0001). Sybil fee logic (escalating-per-24h). Self-trade
detection. Optional featured-slot auction. Exit criterion: a user
can post an order and another user can see it; the fee path works
for all three fee currencies (BTC / XMR / BLURT).
## Alternatives considered
### Single monolithic Phase 3
- **Pros:** less ADR bookkeeping; one tarball to track.
- **Cons:** no intermediate testability; 10+ turns of work with no
user-facing deliverable until the end; any scope creep pushes the
whole phase out; harder to roll back a problematic piece without
unpicking unrelated work.
- **Rejected.**
### Split into two subphases (relay+account vs indexer+orderbook+post)
- **Pros:** only one mid-phase checkpoint to manage.
- **Cons:** the indexer-plus-post bundle is still 6+ turns and
inherits the same "no intermediate testability" problem between
them. Also conflates "read path works" with "write path works,"
which are genuinely separate engineering concerns worth isolating.
- **Rejected.**
### Four+ subphases
- **Pros:** even finer granularity.
- **Cons:** diminishing returns. Relay and account-creation really
do belong together (the relay exists to serve the account-creation
flow and little else for now). Similarly, order posting and its
enforcement/anti-abuse logic belong together — shipping posting
without enforcement would be a live abuse vector on mainnet Blurt.
- **Rejected.**
## Consequences
### Positive
- Each subphase ends with a testable deliverable on staging.
- Scope creep in one subphase doesn't block the others from shipping.
- The user gets three opportunities to redirect the design mid-phase
rather than one opportunity at the end.
- Go infrastructure scaffolding (module layout, Postgres wiring,
build system) lands in 3a and is amortized across 3b and 3c.
### Negative
- Three tarball handoffs instead of one. Each has its own
extract-and-review overhead for the user.
- Two `REVIEW-PHASE3a.md` / `REVIEW-PHASE3b.md` / `REVIEW-PHASE3c.md`
documents instead of one. Disciplined but not hard.
- Subphase boundaries may need to move as reality pushes back.
E.g., if the relay ends up smaller than expected, we might pull
some indexer scaffolding into 3a. The three-phase structure is
the plan, not a contract — an ADR-0006 can re-draw the lines if
needed.
### Follow-up work
- `REVIEW-PHASE2.md` entries P2-1 (Blurt account registration)
and the operator-action-items section in PLAN.md are now
marked complete; 3a can reference those as done rather than
blocking on them.
- Carry-forward item #11 from Phase 1 (self-hosting docs) lands
in 3b, when the indexer is the first Go service users might
want to self-host.
- Carry-forward items #16 (WhaleVault / Gravity) and the posting
relay's owner-key-never-in-browser invariant interact in
Phase 3a; the relay protocol must accept an externally-signed
transaction blob so extension-based signing works out of the box.
## References
- Plan v1.3 §348 — original Phase 3 single-phase definition.
- ADR-0001 — `custom_json` replacement ops (3c enforcement).
- ADR-0002 — live keys policy (3a `useOwnerKey()` pattern).
- REVIEW-PHASE2.md — Phase-1/2 carry-forward items that land in
each subphase.