R2D2-MERIDIAN/docs/AGENTS.md
Joshua Belke 051cd966b0
Some checks failed
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Meridian Harness / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Meridian Harness / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Meridian Harness / Publish rolling release (push) Has been cancelled
Meridian Harness / Publish tagged release (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Isolated DB Gate (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Admin Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Server Cross-Compile (push) Has been cancelled
CI / Server Cross-Compile-1 (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
docs(mips): adopt MIP-RT and withdraw the on-chain payments scope
Protocol council, 2026-08-20, parallel mode, five seats — Protocol Steward
(chair), Interop Skeptic, Enforcement Auditor, plus Revocation Guardian and
Second-Node Skeptic borrowed at the charter cap of two. Each seat received
only its charter row, the decision sentence and the evidence. Call: approve
with conditions, 5/5 concurring, no seat blocking at close.

**Withdrawn, not deferred — and none of the prior call's conditions fired.**
`meridian-ded` approved on-chain payments on 2026-08-02 against three
reversal conditions: a competing upstream payments NIP merging, a measured
fake-claim burden, and an upstream x402 Kaspa scheme. All three verified
NOT fired. The reversal proceeds on different grounds and the record says
so plainly: the requirement was never present, rather than refuted — no
counterparty outside the issuing community, no reachable public chain from
an exercise network. A scope held "deferred" on conditions that never fired
is inventory with no owner or expiry, and it keeps a chain-settled second
system of record alive as a live option.

The chair initially **blocked** the withdrawal limb, because "withdrawn"
was being chosen blind to the one trigger the prior council said would
point the other way: the NIPs mirror was pinned at `8228afb5`, dated
2026-07-31 — *before* the call being reversed. Lifted only after fetching
refs (working tree still pinned, confirmed by `rev-parse`) and re-running
the sweep: `origin/master` = `656cecc7` (2026-08-08), delta two commits
touching only `29.md` and `47.md`, zero hits tree-wide for
`x402|kaspa|erc-20|eip-681|eip-3009|stablecoin`. `git ls-remote` returned
the same head on 2026-08-20, so the twelve-day gap is upstream quiet, not
stale data.

That check also revealed it is a **weaker instrument than it looks**, which
is why `docs/AGENTS.md` now carries the rule rather than the anecdote:
upstream `c538775` moved NIP-47's authorization models and wallet
extensions out of `nostr-protocol/nips` entirely, into
`nostr-wallet-connect/nwc` — 332 of 351 changed lines — behind an open
numeric `extensions` namespace that nothing here mirrors. A future payment
scheme can now merge upstream without ever appearing in the grep that just
cleared this decision. So a scan record must state the mirror's commit hash
*and* its commit date separately from the scan date, and name the surface it
actually covered; the mirror is merged-state only and cannot see an open PR.

Three amendments the council made to the spec, all at DRAFT deliberately
because deferring any of them forces a renumber:

- **Kind `50416`, a consumer-signed spend hold**, accepted before serving.
  Without it `50412` is a post-hoc self-report by the party that gained the
  resource, and ingest rejects an overdraft only after the GPU-seconds are
  already gone.
- **The epoch rule is rewritten.** Wire `epoch` is advisory and ignored on
  input; the relay assigns it per `(community, holder, class)`; it is
  absorbing at *any* epoch, following the MIP-MS pattern, resolved
  fail-closed. Without this a peer transfer at `epoch n+1` reinstates a
  holder reclaimed at `epoch n` — the monotonic-revocation law, live on one
  relay today.
- **The arbiter is registered at scaling axis A1**, with `SELECT … FOR
  UPDATE` in the same transaction as the ledger append.

MIP-RT is a **non-monetary internal resource instrument, not a payment
rail**, and the support matrix now says exactly that: nine payment rows keep
`Reject` with strengthened rationale, an MIP-RT row is added, and there is
**no NIP-CP row** — that was the withdrawn bead's ask.

The register row cites `meridian-8t6h` (Phase 1), not the closing Phase 0
bead: `just check-mips` requires a non-terminal row to name a live bead, so
pointing it at `meridian-yzr6` would turn the gate red the moment that bead
closed. Bead created and row repointed before closing, not after.

Verified: `check-mips`, `check-architecture-map`, `check-kinds`,
`check-feature-specs`, `check-external-copy` all exit 0. `check-stellar` and
`check-gauntlet` exit 1, both pre-existing and provably not from this work —
`check-stellar`'s findings are byte-identical to a baseline captured before
any edit, and `check-gauntlet` fails on F001/F003 marked open against beads
already closed in the committed export at HEAD.

Beads: meridian-yzr6 (Phase 0), meridian-grxu (minutes), meridian-8t6h (Phase 1)
Signed-off-by: Joshua Belke <joshua@innovationhub-act.org>
2026-08-20 18:34:48 -04:00

10 KiB
Raw Permalink Blame History

docs/ — Protocol Specs & Operator Guides

Purpose

Durable reference material: the repo-local NIP extensions that define wire protocol, machine-checked formal specs, deployment/operations guides, troubleshooting playbooks, and audience-orientation guides — documents that teach an incoming contributor a whole surface from one file, bound to the code by a provenance table. Not a changelog and not a design diary — top-level VISION*.md files hold direction, CHANGELOG.md holds history.

Ownership

Path Owns
nips/ Repo-local NIP extensions: NIP-AA, AB, AE, AM, AO, AP, CW, DV, ER, GC, GS, IA, OA, PL, RS, WF, WP — the normative wire contracts. GC (git collaboration) and WF (channel workflows) are profiles: they restrict and pin down kinds defined upstream (NIP-34) or already shipped, rather than adding new ones
mips/ Meridian Implementation Possibilities — repo-local proposals documenting what Meridian-compatible relay and client software may implement, under the two-letter scheme, with README.md as the register and lifecycle. Register rows without a file are specified in TASKS.md § 5 and migrate here under MRDN-201. DRONE-PROTOCOL-COVERAGE.md is the ETL coverage register behind the vehicle-protocol profiles — a coverage map, never a commitment schedule. ENFORCED is the only state that permits NIP-11 advertisement
spec/ Machine-checked models: MultiTenantRelay.tla/.cfg, GitOnObjectStore.tla/.cfg (TLA+), MultiTenantAuth.spthy, NIP-AB.spthy (Tamarin)
formal/ STATEFUL_GATEWAY.md and nip-pl/ — executable acceptance + mutation tests in Python (acceptance.py, delivery.py, *_mutation.py, mutation_test.py, NOTE.md)
admin/ Operator dashboard guide
Orientation ux-end-to-end-workflow.md — the end-to-end user journey for an incoming UI/UX designer: acts 1–3 in depth, act 4 indexed, with the surface map, the port map, required-versus-optional user input, and a provenance table binding every claim to its source file. Its §8 platform table states reachability on a stock install (preview flags default off), not module existence
Loose guides multi-tenant-relay.md, multi-tenant-conformance.md, push-gateway-deployment.md, control-plane-deployment.md, community-registration-launch-policy.md, git-on-object-storage.md, meridian-shared-compute-dev.md, bridge-channel-window.md, nostr-nip-support-matrix.md, linux-rendering-troubleshooting.md, welcome-kickoff-silent-failures.md, workflow-variables.md, projects-qa-runbook.md, MCP_DRIVEN_HOOKS.md
plans/ Dated closeout and hardening plans for completed programs — a record of what was done, not a live queue
benchmarks/ Measured performance records and the capacity contract they hold the relay to (relay-capacity-contract.md), with raw runs under data/
runbooks/ Executable operator diagnosis, containment, recovery, rollback, and verification procedures for relay and control-plane alerts, backup/restore, and network isolation
assets/ Images referenced by docs (screenshots/, icons)

Local Contracts

  • A NIP in nips/ is normative. It follows upstream NIP format: title, one-line summary, status line (draft / optional / relay), Motivation, then the kind and tag definitions. Implementation must match the document; if they diverge, one of them is a bug — say which in the change.
  • A new event kind that other clients must understand gets a written spec, and its integer goes in crates/meridian-core/src/kind.rs. A kind with no written contract cannot be implemented by a second client. Whether that spec is a NIP or a MIP is decided by the constituency rule below — not by how important the kind is, and not by which directory is closer to hand.
  • Constituency decides NIP vs MIP, and it is the first question, not the last. A NIP is a proposal to the Nostr commons: if anyone outside this deployment would want it, it is a NIP and belongs upstream. If the only constituency is this deployment, it is a MIP and lives in mips/. Calling a deployment-specific spec a NIP pollutes both namespaces and implies an upstream ambition we do not have; the precedent is SLIPs to BIPs. Deconfliction is not theoretical — upstream already uses two-letter suffixes (A0, A4, B0, B7, BE, C0, C7, CC, EE, F4, 5A, 7D) expanding into exactly our space, and NIP-SF/FP/GR/KB are all plausible upstream names for other things. Before minting either, check whether an upstream NIP already covers the behaviour — profiling one spends no letter and gets third-party interoperation for free. That is the cheapest of the three outcomes and the most commonly missed.
  • The repo-local NIPs in nips/ are being migrated, not grandfathered. MRDN-201 (TASKS.md § 5.1) is a P0 story: every repo-local proposal becomes MIP-XX and moves to mips/, leaving nips/ for profiles of genuinely upstream NIPs. Until it runs, an existing NIP-XX here is a legacy name and never evidence that a new repo-local spec may be filed as a NIP. (The count of those files is stated and CI-guarded in the root AGENTS.md; it is deliberately not repeated here, because a second hand-maintained number is the failure that law names.) NIP-ER is the one that cannot be renamed silently. It is the only house name on the wire — SUPPORTED_EXTENSIONS in crates/meridian-relay/src/nip11.rs is ["nip-er"], and ENFORCED_MIPS is empty — so every other rename is invisible to clients, and this one is not. Clients feature-detect that string. Advertise both names through a deprecation window, or keep nip-er permanently as an alias; do not swap it. The failure is already on this repo's record in the opposite direction: NIP-17 was advertised while kind:10050 was rejected, and conformant clients detected support and then failed silently.
  • nips/ is the only place a repo-local NIP may live — never beside the crate that implements it, and the row above must list it. NIP-AB spent time under crates/meridian-core/src/pairing/: complete, Tamarin-modelled, and invisible to anyone following this file. Any kind-vs-spec audit reported kind:24134 as unspecified, because a spec off the documented path is indistinguishable from a missing one.
  • Never renumber or repurpose a published NIP letter or kind. Supersede with a new document and mark the old one.
  • A kind collision scan carries the limits of the instrument that produced it. Record the mirror's commit hash and its commit date, separately from the date you scanned — they are routinely weeks apart, and a scan run against a mirror pinned before the decision it justifies proves nothing. Two limits are structural and must be written into the scan record rather than assumed away: the mirror is merged-state only, so it cannot see an open upstream PR claiming a number; and since upstream commit c538775 (2026-08-08), nostr-protocol/nips no longer covers payment-scheme vocabulary — NIP-47's authorization models and wallet extensions moved out to github.com/nostr-wallet-connect/nwc, behind an open numeric extensions namespace that nothing here mirrors. A grep over the NIPs mirror is therefore a narrower instrument than it looks, and a clean result states which surface it actually covered. Advance the pin and re-run before any constant lands.
  • A MIP in mips/ carries its lifecycle state on the status line and its row in mips/README.md, and the two must agree. A profile MIP adds no mechanism — it binds an existing envelope, payload schema, and link profile to one real feed. The enforcement obligation is staged with the lifecycle, because a MIP whose wire format is not yet frozen can only name speculative checks: a DRAFT owes a § Enforcement point naming who refuses a non-conforming frame; from IMPLEMENTABLE it owes a § Enforcement points table naming a check that fails for every normative MUST. just check-mips enforces the staging, the register/file state agreement, and that each row names a live bead; a MIP whose vocabulary nothing reads also fails just check-kinds. Neither waits for an audit.
  • spec/ models are checked, not decorative. If a change alters relay admission, replay ordering, or object-store semantics, update the model and the tracers in crates/meridian-relay/src/conformance/ — crates/meridian-conformance replays runtime traces against MultiTenantRelay.tla.
  • formal/nip-pl/ mutation tests must keep failing on mutants. A mutation that the acceptance suite accepts means the suite lost its teeth — fix the suite, not the mutant.
  • Operator guides state the current deployment, not history. Delete superseded procedure rather than annotating it.
  • Upstream NIPs are referenced, never copied: https://github.com/nostr-protocol/nips.

Work Guidance

  • Put implementation-adjacent rules in the owning AGENTS.md (they must be read before editing code); put protocol contracts and operator procedure here.
  • Reference docs from code with a path, and keep the path true when files move — a stale docs/ reference in a //! comment is a silent dead end.

Verification

cargo test -p meridian-conformance
cargo test -p meridian-test-client --test conformance_multitenant

cd docs/formal/nip-pl                # models run from their own directory
python3 acceptance.py && python3 mutation_test.py
python3 delivery.py && python3 delivery_mutation.py
python3 fixed_payload.py && python3 fixed_payload_mutation.py

docs/formal/nip-pl/NOTE.md states the run order and the models' honest limits — they enumerate bounded abstract transitions, not SQL schedules or network behavior. TLA+/Tamarin models are checked with their own tools (TLC, Tamarin); see the header of each model file.

Child STELLAR Index

None — docs/ is governed by this file, including nips/, spec/, formal/, and admin/.