mirror of
https://github.com/PR0M3TH3AN/bitgate.git
synced 2026-11-05 21:11:00 +00:00
feat: adapter contract, commerce proof-of-fit, and reusability docs
Proves the engine did not stay video-specific during extraction. - application adapter contract in core (createApplicationAdapter, evaluateObject, collectTargets): an object names the targets that govern it and the strictest verdict reaching any of them wins, so denying a seller takes their whole catalogue down with no cascade logic in the application - examples/commerce: a marketplace on the public API covering all ten proof-of-fit behaviors the plan requires, including that no core change was needed. One product, one snapshot, four surfaces, four different verdicts. - README, integration guide, per-example README, CHANGELOG, four ADRs, and GPL-3.0-or-later LICENSE (the license was listed in Phase 1 but missing) - checkpoints rewritten to reflect actual state and to say plainly which migration-plan phases belong to the consumer repos rather than here Fixes a real gap found by the proof-of-fit: composeDecisions kept only the first decision's evidence, so an object governed by several targets lost the evidence that drove its verdict. Evidence now merges — counts summed, contributor lists unioned, flags or-ed. 556 tests; lint, typecheck, and per-package type build clean.
This commit is contained in:
1 parent
4d460c12fe
commit
2beb7a7bb5
24 files changed
+2732
-48
No files matched your search
@@ -0,0 +1,158 @@
|
||||
# nostr-governance
|
||||
|
||||
A headless, application-agnostic governance engine for Nostr: moderation,
|
||||
access control, and trust-graph policy, with no opinion about what your
|
||||
application is.
|
||||
|
||||
The engine carries **no thresholds of its own**. Applications supply a policy
|
||||
definition; the engine supplies precedence, aggregation, composition, and
|
||||
explanation. That separation is what lets one engine serve a video app and a
|
||||
marketplace without either leaking into the other.
|
||||
|
||||
## Why it looks like this
|
||||
|
||||
**Four independent decision dimensions.** A governance decision is not a
|
||||
`hidden` boolean. It is four answers:
|
||||
|
||||
| Dimension | Values |
|
||||
| --- | --- |
|
||||
| `ranking` | `normal` → `downrank` (with weight) |
|
||||
| `visibility` | `allow` → `warn` → `restrict` → `hide` → `deny` |
|
||||
| `interaction` | `allow` → `require-explicit-action` → `deny` |
|
||||
| `transaction` | `allow` → `require-review` → `deny` |
|
||||
|
||||
A marketplace listing can be visible to its seller, downranked in discovery,
|
||||
inspectable behind a warning on its detail page, and blocked at checkout — all
|
||||
from one evaluation. Collapsing that into one boolean is what forces
|
||||
applications to reimplement policy.
|
||||
|
||||
**Composition is ladder-maximum per dimension**, which makes it commutative and
|
||||
associative: the order decisions arrive in cannot change the result.
|
||||
|
||||
**Capabilities resolve at merge time, not ingest time.** Revoking a moderator's
|
||||
role drops their contributions from effective state immediately, without
|
||||
replaying or rewriting anything.
|
||||
|
||||
**Trust seeds are a fallback, not an addition.** Once a viewer has real
|
||||
contacts, configured seeds stop contributing — following nobody must not be
|
||||
equivalent to following the operator's seed list.
|
||||
|
||||
## Packages
|
||||
|
||||
| Package | Purpose |
|
||||
| --- | --- |
|
||||
| `@nostr-governance/core` | Pure evaluation. No I/O, no browser globals, no dependencies. |
|
||||
| `@nostr-governance/nostr` | Codecs: canonical v1, NIP-56, NIP-51, legacy lists, bech32. |
|
||||
| `@nostr-governance/runtime` | Stores, transport orchestration, commands. |
|
||||
| `@nostr-governance/testing` | Conformance harness. |
|
||||
| `@nostr-governance/bitvid-compat` | Reference application profile for the characterization corpus. |
|
||||
|
||||
## Quick start
|
||||
|
||||
```js
|
||||
import { createPolicyDefinition, evaluateTarget } from "@nostr-governance/core";
|
||||
import { createGovernanceRuntime, createMemoryTransport } from "@nostr-governance/runtime";
|
||||
|
||||
const policy = createPolicyDefinition({
|
||||
id: "my-app",
|
||||
version: "1.0.0",
|
||||
defaultProfile: "feed",
|
||||
profiles: {
|
||||
feed: {
|
||||
name: "feed",
|
||||
administrativeDeny: { visibility: "hide", interaction: "deny" },
|
||||
reports: {
|
||||
spam: { downrank: 1, restrict: 3, hide: 8 },
|
||||
malware: { hide: 1, interactionDeny: 1 },
|
||||
},
|
||||
mutes: { default: { downrank: 1, hide: 20 } },
|
||||
muteWindowSeconds: 60 * 24 * 60 * 60,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const runtime = createGovernanceRuntime({
|
||||
applicationId: "my-app",
|
||||
namespace: "myapp",
|
||||
transport: myRelayAdapter,
|
||||
policy,
|
||||
now: () => Math.floor(Date.now() / 1000),
|
||||
});
|
||||
|
||||
runtime.setViewer(viewerPubkey);
|
||||
runtime.trust.setContacts(followList);
|
||||
await runtime.loadAdministrativeState();
|
||||
|
||||
const decision = runtime.evaluate({ type: "user", pubkey: authorPubkey }, { profile: "feed" });
|
||||
if (decision.visibility.effect === "hide") return null;
|
||||
```
|
||||
|
||||
## Extending to a new application
|
||||
|
||||
Write an adapter saying what your object is in governance terms, and a policy
|
||||
saying what the evidence means to you. Nothing else.
|
||||
|
||||
```js
|
||||
import { createApplicationAdapter, evaluateObject } from "@nostr-governance/core";
|
||||
|
||||
const productAdapter = createApplicationAdapter({
|
||||
applicationId: "my-shop",
|
||||
toTargets: (product) => [
|
||||
{ type: "user", pubkey: product.sellerPubkey },
|
||||
{ type: "event", id: product.id, author: product.sellerPubkey },
|
||||
{ type: "address", kind: "30078", pubkey: product.sellerPubkey, identifier: product.sku },
|
||||
],
|
||||
getPrimaryTargetKey: (product) => `address:30078:${product.sellerPubkey}:${product.sku}`,
|
||||
});
|
||||
|
||||
const decision = evaluateObject(product, productAdapter, (target) =>
|
||||
runtime.evaluate(target, { profile: "checkout" }),
|
||||
);
|
||||
```
|
||||
|
||||
A worked example lives in [`examples/commerce`](examples/commerce) — a
|
||||
marketplace built entirely on the public API, demonstrating seller allowlists,
|
||||
address denial that survives republication, malware-driven checkout blocking,
|
||||
capability-scoped moderator roles, community curator ingestion, and
|
||||
seller-facing explanations. See [`docs/integration-guide.md`](docs/integration-guide.md).
|
||||
|
||||
## Authority model
|
||||
|
||||
Root-authorized contributors: the root publishes the role roster, each actor
|
||||
publishes contributions under their own key, and a contribution is accepted only
|
||||
if the signing actor holds the matching capability.
|
||||
|
||||
```
|
||||
manage-roles manage-policy manage-community-sources
|
||||
contribute-user-allow contribute-user-deny contribute-event-deny
|
||||
contribute-address-deny contribute-trust-seed review-evidence
|
||||
```
|
||||
|
||||
Roles are convenience bundles over these; applications define their own
|
||||
(`listing_moderator`, `seller_moderator`, …). No moderator ever needs the root
|
||||
key. Protected actors cannot be denied by any contributor list, however many
|
||||
curators list them.
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run lint # reference guard + typecheck
|
||||
npm test # unit + conformance
|
||||
npm run build:types # per-package .d.ts
|
||||
```
|
||||
|
||||
BitVid and BitRoad are **read-only reference repositories**, pinned by commit in
|
||||
[`docs/reference-map.md`](docs/reference-map.md). Behavior is copied via fixtures
|
||||
and characterization tests, never by importing their source;
|
||||
`npm run check:references` fails the build if anything does.
|
||||
|
||||
Regenerate the characterization corpus with:
|
||||
|
||||
```bash
|
||||
node scripts/build-characterization-corpus.mjs
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
GPL-3.0-or-later. See [`docs/license-and-provenance.md`](docs/license-and-provenance.md).
|
||||
Reference in new issue
Block a user