mirror of
https://github.com/PR0M3TH3AN/bitgate.git
synced 2026-10-27 16:41:03 +00:00
BitGate read standard events but published a private vocabulary, making it an
island. NIP-32 (kind 1985) is the shared moderation vocabulary; BitGate now
reads and writes it. See ADR 0007.
The design keeps flexibility central, since the goal is a reusable building
block. A label is (namespace, value, target) and carries no built-in meaning —
"deny", "nsfw", and "MIT" are the same kind of object. What a label means is a
policy decision an application supplies via labelMapping { namespace,
denyValues, allowValues }. The codec itself is vocabulary-free; decodeLabels
returns every label regardless of namespace for generic use.
A matching label becomes a contribution authored by the labeller, gated
identically: it denies someone only if the labeller holds the capability in the
roster, exactly like a community source. An untrusted labeller's deny does
nothing, and labels fail closed without verification like any administrative
event.
- consume: ingestEvent maps kind 1985; loadLabels(labellers) fetches them
- emit: commands.publishLabel(target, value), gated by the same capability as
denying, so the shared form is no weaker than the private one
- the widget bundle re-exports the label API for the drop-in path
Validated against 40 real kind:1985 events from public relays (ISO-639-1
language labels among them): all decoded with targets and namespaces, zero
throws. 897 tests; cold gates green; audit clean.
57 lines
3.3 KiB
Markdown
57 lines
3.3 KiB
Markdown
# Nostr spec coverage
|
|
|
|
What BitGate implements, what it deliberately does not, and where the gaps are.
|
|
Verified against the NIPs repository; specs move, so re-check before relying on
|
|
this table for anything load-bearing.
|
|
|
|
## Implemented
|
|
|
|
| NIP | Kind | How BitGate uses it |
|
|
| --- | --- | --- |
|
|
| **NIP-01** | — | Event shape, replaceable selection with a deterministic same-timestamp tiebreak, and signature verification via `@bitgate/verify` (id recomputed, then schnorr-checked) |
|
|
| **NIP-02** | 3 | The viewer's follow list *is* the trust graph. Relay hints in the third tag position are captured as an outbox fallback. |
|
|
| **NIP-19** | — | bech32 `npub`/`note` decoding at the codec edge, so the core stays hex-only |
|
|
| **NIP-32** | 1985 | Labels, both directions. Consumed as capability-gated contributions via a configurable namespace/vocabulary; emitted with `publishLabel`. See [ADR 0007](adr/0007-nip32-labelling.md). |
|
|
| **NIP-51** | 10000 | Mute lists. Public `p` entries always; the viewer's *own* private entries decrypted through their signer. |
|
|
| **NIP-44** | — | Decryption of the viewer's own private mute entries, delegated to the signer |
|
|
| **NIP-56** | 1984 | Reports. The report type is read from the 3rd tag position, with fallbacks for clients that place it elsewhere. |
|
|
| **NIP-65** | 10002 | Outbox model: each contact's mute list is fetched from *their* write relays |
|
|
| **NIP-78** | 30078 | Canonical governance documents — roles, policy, and contribution lists — under namespaced `d` identifiers |
|
|
|
|
## Deliberate choices
|
|
|
|
**The viewer's private mutes are decrypted; nobody else's are.** Another
|
|
account's private list is none of our business, and the check lives at the
|
|
codec boundary rather than relying on callers to behave. A user who mutes
|
|
privately should still have their mutes take effect — ignoring them reads as
|
|
the product being broken.
|
|
|
|
**Report categories follow NIP-56 exactly** in the social preset. Declaring a
|
|
threshold for a category no standard client emits is dead configuration.
|
|
|
|
**Commerce categories are non-standard on purpose.** `scam`, `counterfeit`, and
|
|
`not-as-described` have no NIP-56 equivalent. Reports from generic clients
|
|
arrive as `other` and fall through to a `default` threshold, so they are never
|
|
silently ignored — including at checkout, where an unclassified complaint earns
|
|
review rather than an automatic denial.
|
|
|
|
**Relays are transport, never authority.** Signatures are verified through an
|
|
injected verifier before anything authoritative is accepted.
|
|
|
|
## Known gaps
|
|
|
|
**Trust is binary.** `resolveTrustSet` is "in the viewer's follows, or not".
|
|
Most things called web-of-trust weight by hop distance — follows-of-follows at
|
|
reduced weight. Adding depth naively would be wrong: a two-hop reporter would
|
|
count the same as someone the viewer actually follows. It needs hop-weighted
|
|
counting, which is a change to aggregation, not just to the set.
|
|
|
|
**NIP-72 / NIP-29 communities.** The role roster is a parallel invention to
|
|
NIP-72's moderator `p` tags. Note NIP-72 is now marked *"unrecommended: try
|
|
NIP-29 instead"*, so a compat codec is only worth building against a specific
|
|
target application.
|
|
|
|
**NIP-86 relay management, NIP-70 protected events.** Relay-side moderation is
|
|
a different layer and out of scope; BitGate governs what a client shows, not
|
|
what a relay stores.
|