Problem
Conversations resolve, but the substrate has no way to say so. A decision thread reaches its conclusion and then accretes drive-by replies for weeks, each one reopening a question that was already answered. Clients improvise with ✅ emoji conventions — nothing enforces them, and nothing records who decided the matter was closed.
The gap is real in the current kind registry: kind:46030/46031 record a single approver's judgment and have no consequence outside workflow execution. There's no threshold semantic and no notion of finality anywhere in the tree (no VISION doc, NIP, or open issue mentions sealing or quorum — happy to be corrected).
Proposal (one paragraph)
Threads can be sealed: a kind:46040 seal request names a thread root, a threshold k, and an explicit approver set (relay-validated against channel membership, snapshotted at request time). Approvers publish individually signed kind:46041 approvals bound to the request id, so consent is bound to exact parameters. When the relay observes the k-th valid approval, it marks the thread sealed and emits a relay-signed, channel-scoped kind:8004 delta naming every counted approver — any client can re-verify the quorum from the signed approvals. Once enforced, the relay rejects new writes into the sealed reply tree (sealed: OK message). Unsealing is the same grammar in reverse, permanently exempt from the write-block (following the moderation Phase 1 precedent that restriction-lifting paths must never be blockable), with unseal quorum ≥ seal quorum and the unseal approver set drawn from the original approvers ∪ admins. Admin single-approver thread locking is the k=1 degenerate case, not a separate feature.
State model
OPEN ──(46040 accepted)──▶ OPEN + PENDING_SEAL
OPEN + PENDING_SEAL ──(k-th 46041 accepted)──▶ SEALED
OPEN + PENDING_SEAL ──(lapse/expiry)──▶ OPEN
SEALED ──(46043 accepted)──▶ SEALED + PENDING_UNSEAL
SEALED + PENDING_UNSEAL ──(k'-th 46041 accepted)──▶ OPEN
SEALED + PENDING_UNSEAL ──(lapse/expiry)──▶ SEALED
PENDING_UNSEAL is a sub-state of SEALED — the write-block never loosens while an unseal quorum accumulates. History is append-only; seal → unseal → seal cycles are legal and fully attributed.
Why this mechanism
Every team already trusts it daily: GitHub branch protection is relay-enforced quorum — individually attributed approvals, counted by the forge, gating an irreversible-ish action. Deliberately no threshold cryptography: a threshold signature proves that k participants consented while erasing which k, and the audit question is always "who authorized closing this?" — the answer must be names. The relay is trusted for enforcement, not for attribution: every counted approval is independently verifiable from its signature.
Precedents followed
- Handler shape: structural sibling of
handlers/identity_archive.rs (user-signed request → relay validation → state table → relay-signed deltas in the 8xxx range)
- Write-block placement: adjacent to the ban/timeout gate in ingest, including its key edge case — the lifting path stays writable
- Kinds at 46040–46043 in the workflow range; deltas carry
h and follow the subject channel's read controls
- Phased rollout with a numbered-decisions plan doc, mirroring Community Moderation Phase 1: Phase 1 records seals (state + deltas, no enforcement — "recorded, not enforced" per the draft's conformance section), Phase 2 enforces (the ingest write-block, with an explicit by-kind enforcement matrix keyed on resolved thread ancestry, not raw
e tags)
Deliberately deferred
Channel/community sealing, role-scoped and predicate quorums (cardinality is framed as the minimal quorum predicate so richer predicates are an extension, not a redesign), a soft "checkpoint" tier, blocking objections (deny votes), and a transparency log. None are blocked or foreclosed by this design.
Status
Full NIP draft (wire format, validation rules, trust model, invariants, concurrency edge cases) and a design-decisions doc with anticipated Q&A are written and have been through several adversarial review passes — see gist below. If the approach has support, I'll open them as a docs-only RFC PR for detailed review before any implementation.
Related: #54 (these kinds extend the 46xxx approval vocabulary that workflow support established).
Feedback especially wanted on:
- Is thread-root the right first subject, or would maintainers rather see this land against a different scope?
- The Phase 1/Phase 2 split — is "record first, enforce second" the right rollout, or should enforcement ship in one PR?
- Kind number placement (46040–46043 + 8004/8005 following NIP-IA's delta convention) — any collisions with unpublished plans?
Attachments
Gist (both docs): https://gist.github.com/AaronGoldsmith/dbaf3382815b2f10f33b0ef9b0b34f5d
NIP-SL.md — full protocol draft
THREAD_SEALING_PLAN.md — design decisions + Q&A + phased checklist
Problem
Conversations resolve, but the substrate has no way to say so. A decision thread reaches its conclusion and then accretes drive-by replies for weeks, each one reopening a question that was already answered. Clients improvise with ✅ emoji conventions — nothing enforces them, and nothing records who decided the matter was closed.
The gap is real in the current kind registry:
kind:46030/46031record a single approver's judgment and have no consequence outside workflow execution. There's no threshold semantic and no notion of finality anywhere in the tree (no VISION doc, NIP, or open issue mentions sealing or quorum — happy to be corrected).Proposal (one paragraph)
Threads can be sealed: a
kind:46040seal request names a thread root, a threshold k, and an explicit approver set (relay-validated against channel membership, snapshotted at request time). Approvers publish individually signedkind:46041approvals bound to the request id, so consent is bound to exact parameters. When the relay observes the k-th valid approval, it marks the thread sealed and emits a relay-signed, channel-scopedkind:8004delta naming every counted approver — any client can re-verify the quorum from the signed approvals. Once enforced, the relay rejects new writes into the sealed reply tree (sealed:OK message). Unsealing is the same grammar in reverse, permanently exempt from the write-block (following the moderation Phase 1 precedent that restriction-lifting paths must never be blockable), with unseal quorum ≥ seal quorum and the unseal approver set drawn from the original approvers ∪ admins. Admin single-approver thread locking is the k=1 degenerate case, not a separate feature.State model
PENDING_UNSEAL is a sub-state of SEALED — the write-block never loosens while an unseal quorum accumulates. History is append-only; seal → unseal → seal cycles are legal and fully attributed.
Why this mechanism
Every team already trusts it daily: GitHub branch protection is relay-enforced quorum — individually attributed approvals, counted by the forge, gating an irreversible-ish action. Deliberately no threshold cryptography: a threshold signature proves that k participants consented while erasing which k, and the audit question is always "who authorized closing this?" — the answer must be names. The relay is trusted for enforcement, not for attribution: every counted approval is independently verifiable from its signature.
Precedents followed
handlers/identity_archive.rs(user-signed request → relay validation → state table → relay-signed deltas in the 8xxx range)hand follow the subject channel's read controlsetags)Deliberately deferred
Channel/community sealing, role-scoped and predicate quorums (cardinality is framed as the minimal quorum predicate so richer predicates are an extension, not a redesign), a soft "checkpoint" tier, blocking objections (deny votes), and a transparency log. None are blocked or foreclosed by this design.
Status
Full NIP draft (wire format, validation rules, trust model, invariants, concurrency edge cases) and a design-decisions doc with anticipated Q&A are written and have been through several adversarial review passes — see gist below. If the approach has support, I'll open them as a docs-only RFC PR for detailed review before any implementation.
Related: #54 (these kinds extend the 46xxx approval vocabulary that workflow support established).
Feedback especially wanted on:
Attachments
Gist (both docs): https://gist.github.com/AaronGoldsmith/dbaf3382815b2f10f33b0ef9b0b34f5d
NIP-SL.md— full protocol draftTHREAD_SEALING_PLAN.md— design decisions + Q&A + phased checklist