Files
amethyst/quartz/plans/README.md
T
Claude 486e93f873 feat(marmot): add the lifecycle state machine and convergence branch selection
Stages 5 and 6, protocol cores.

The lifecycle model: six canonical states with their legal-transition table,
four derived convergence statuses with the legal-combination table, and the
durable local gates (Leaving, Disbanding, realized removal) that restrict
outbound work without being lifecycle states.

Two table entries are load-bearing rather than bookkeeping, and both have tests.
There is no Merging -> Recovering edge: a competing branch observed while
applying our own confirmed commit is retained, the merge completes to Stable,
and admission into a bounded pass then triggers Stable -> Recovering. Diverting
mid-merge would leave a half-applied epoch. And Disbanded has no outgoing edge
at all — no later branch supersedes a terminalized disband.

Branch selection replaces the superseded MIP-03 rule, which broke a same-epoch
tie on the outer Nostr created_at and then the event id. Both are transport
evidence: timestamps are chosen by senders, and each transport copy of one MLS
message carries a different event id. The replacement reads only authenticated
values.

Three details that decide whether two clients agree:

Byte ordering is unsigned. Account keys and SHA-256 digests are uniformly
distributed, so a signed comparison inverts roughly half of all final ties, and
two implementations would disagree that often.

raw_commit_depth gets no comparison step of its own — it is already inside
effective_commit_depth, so once effective depth and quorum status tie, a further
raw-depth comparison is necessarily tied too. A widely circulated write-up of
this algorithm lists raw depth as a step; the spec does not, and there is a test
that fails if it is added.

Witnesses count distinct sender ACCOUNTS per branch epoch, capped at the quorum
size, and epochs at or before fork_epoch do not count. Counting by account stops
a multi-device member counting twice; counting distinct senders stops one member
inflating a branch by sending a lot; the per-epoch cap stops one busy epoch
outweighing several quiet ones.

The policy constructor enforces max_witness_override_depth <= max_rewind_commits,
because without that bound app-payload traffic could push a branch past the
rollback horizon and beat an arbitrarily longer valid commit branch.

Twenty-five tests, including the worked example: a three-commit branch with
witness quorum ties a four-commit branch without one at effective depth four and
then wins on quorum, while a five-commit branch beats both because the boost is
capped at one. Selection is asserted invariant under input order, reversal,
shuffling and every rotation. Full quartz jvmTest: 4,582 tests, 0 failures.

Still open in these stages: the bounded pass scheduler and the candidate-graph
builder that replays MLS bytes against retained states, plus wiring the
lifecycle states into MlsGroup so they gate anything. CommitOrdering's
transport-metadata tiebreak therefore still stands — deleting it is only safe
once something replaces it end to end, and selection alone does not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kCuA6tc4JQzHPCDd39GHq
2026-09-08 16:50:47 +00:00

3.1 KiB

quartz plans

Audited 2026-09-08. 12 plans: 7 shipped (archived), 0 in-progress, 4 queued, 1 closed (negative result).

Queued

Plan Summary
2026-05-08-local-headers-explorer.md Headers-only Bitcoin P2P client to verify NIP-03 OTS attestations without a trusted block explorer.
2026-06-12-giftwrap-deletion-requests.md Let a recipient-authored kind-5 delete/block a gift wrap (kind 1059) addressed to them.
2026-07-03-incremental-negentropy-storage.md Always-current (created_at, id) index so cold NEG-OPENs stop paying a full scan + seal (~340 ms at 50k vs strfry's ~21 ms).
2026-07-04-small-req-floor.md Small-REQ dispatch floor: decomposed, inline fast path tried and reverted (no wire-level win); floor is transport-side.
2026-08-13-gpu-pow-mining.md GPU NIP-13 mining declined (ARMv8 has SHA-256 in silicon, mobile GPUs do not). Midstate is ~3x on JVM targets; Android hinges on Conscrypt per-digest JNI cost, still unmeasured. created_at refresh while mining shipped.
2026-09-08-marmot-spec-resync.md Marmot moved off the MIP-era spec (2026-07-02): group state split into app_data_dictionary components, account identity proof v2, and a convergence engine. Current MDK rejects our groups outright. Gap analysis + 8-stage plan; Stages 0-4 done (mdk interop reference, app_data_dictionary, identity proof v2, the six group components, transport corrections); lifecycle + branch selection landed.

Archived (shipped)

Plan Summary
archive/2026-06-03-fix-nip46-bunker-double-resume-plan.md Fix NIP-46 bunker double-resume crash and retry id-reuse races via Channel-per-request + fresh id per attempt.
archive/2026-06-04-auth-scope-vs-policy.md Move relay-server authenticated-identity state from the policy into the engine-owned connection scope.
archive/2026-06-09-clink.md Implement CLINK (Offers/Debits/Manage) Lightning-over-Nostr pointers, events, and client/server in Quartz.
archive/2026-06-11-runstr-interop.md RUNSTR kind-1301 workout events and supporting fitness kinds in Quartz plus Amethyst fitness screens.
archive/2026-06-19-napplet-nip5a-resolver.md Platform-agnostic NIP-5A static-site resolver verifying content-addressed Blossom blobs against signed manifests.
archive/2026-06-20-powr-interop.md Parse and render the POWR/NIP-101e kind-1301 strength-workout dialect alongside the existing RUNSTR dialect.
archive/2026-06-28-git-smart-http-browser.md Git smart-HTTP v2 client to browse NIP-34 repo file trees and render source from the clone URL.