Files
bitgate/Nostr Governance Extraction and Multi-App Integration Plan.md
2026-07-26 16:38:44 -04:00

2812 lines
62 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Nostr Governance Extraction and Multi-App Integration Plan
**Source application:** BitVid
**First consumer:** BitVid
**Second validation consumer:** BitRoad
**Target repository:** `PR0M3TH3AN/nostr-governance`
**Implementation style:** ESM JavaScript with strict JSDoc and generated type declarations
**Migration strategy:** Characterize → extract → shadow → cut over → validate in BitRoad
**Status:** Proposed master development plan
**Baseline reviewed:** BitVid `4525c1c`; BitRoad `bcd6c8e`
---
# 1. Executive Summary
BitVid currently contains a substantial reusable governance system:
* User allowlists
* User denylists
* Event denylists
* Super-admin authority
* Delegated moderators
* Community-curated blacklists
* NIP-56 report aggregation
* NIP-51 trusted-mute aggregation
* Web-of-trust scoring
* Adjustable moderation thresholds
* Viewer blocks and overrides
* Anonymous-user trust seeds
* Nostr-backed administration
* Cached fallback state
* Batched subscriptions and evaluation
These capabilities should be extracted into a standalone, headless repository named:
```text
nostr-governance
```
The repository should become a reusable governance SDK for Nostr applications. It will determine:
* Who is authorized to administer an application
* Which users or events are allowed or denied
* Which community actors may contribute moderation lists
* Which reports and mutes are trusted
* Which policy effects apply to a target
* Why a decision was made
It will not determine:
* How a warning looks
* Whether a BitVid thumbnail is blurred
* How a BitRoad product card is styled
* Which modal opens
* Which toast appears
* How a feed or marketplace rerenders
* What application-specific wording is shown
The fundamental division is:
```text
Nostr Governance
decides:
"This target is downranked, restricted, hidden, or denied."
Consuming application
decides:
"This means blur the thumbnail, disable checkout,
collapse the post, or hide the product."
```
BitVid will be the first consumer because its existing behavior provides the reference implementation and conformance suite.
BitRoad will be the second consumer because its sellers, storefronts, products, reviews, and checkout surfaces exercise the generic user, event, and addressable-target model. BitRoad currently uses `kind:30078` parameterized-replaceable events for storefronts and products, making address-level governance especially valuable.
---
# 2. Current System Baseline
## 2.1 Current BitVid behavior
BitVid is follow-centric and performs client-side, user-controlled moderation with optional administrative lists. Its documentation explicitly separates creator access controls from trust-graph moderation.
The current system includes:
* NIP-56 reports
* NIP-51 mute lists
* Administrative user lists
* Administrative event lists
* Viewer blocks
* Trusted contacts
* Default trust seeds
* Threshold-based policy decisions
* Viewer overrides
* Feed-specific enforcement exceptions
### Current default thresholds
The reviewed BitVid configuration uses:
```text
Trusted report blur threshold: 3
Trusted report autoplay threshold: 3
Trusted mute hide threshold: 20
Trusted spam-report hide threshold: 5
Trusted mute validity window: 60 days
```
These values are BitVid defaults, not universal governance defaults. The extracted system must let each application provide its own policy.
## 2.2 Current trusted-mute behavior
Trusted mutes below the hide threshold are ranking signals only.
A trusted mute below the threshold must:
* Downrank the author
* Not blur content
* Not block playback
* Not produce a public warning badge
* Not be interpreted as an administrative denial
At the trusted-mute threshold, the decision escalates to a reversible hide. This recent distinction must be preserved during extraction.
## 2.3 Current report behavior
Trusted reports are counted from the viewer’s trusted graph. Report thresholds can:
* Blur content
* Prevent automatic interaction
* Hide content at a higher threshold
* Produce evidence explaining the decision
Reports must be deduplicated by reporter, and reports from muted or blocked reporters must not count.
## 2.4 Current trust seeds
For anonymous or default visitors, BitVid derives trust seeds from:
* The super admin
* Active moderators
Static configured seeds are fallback values when the live administrative state cannot be loaded. Changes to moderators or the blacklist cause the trusted-seed state to be reapplied.
## 2.5 Current community blacklist federation
BitVid supports community-curated blacklist sources without granting those curators full moderator authority.
The super admin publishes references to curator lists. BitVid fetches those lists, merges the entries, removes duplicates, and protects administrators from being added to the effective blacklist.
This distinction should become a formal capability in the extracted authority model:
```text
Curator:
can contribute a limited list
Moderator:
can perform application-approved governance actions
Super admin:
can grant roles and change policy
```
## 2.6 Current performance behavior
The extraction must preserve recent BitVid performance improvements:
* NIP-56 reports are fetched through batched active-event subscriptions.
* Large event sets are divided into bounded filter chunks.
* Author moderation information is evaluated in batches.
* Trusted-contact changes emit only when the graph actually changes.
* Community list references are retrieved in a batch.
BitVid currently chunks report targets in groups of 200 rather than opening one subscription per video.
The batch-author optimization previously reduced a large-feed moderation benchmark by approximately 50%, so the extracted runtime must not regress to per-item store lookups.
## 2.7 Current policy duplication
Policy is currently calculated in more than one BitVid layer.
`createModerationStage()` determines:
* Trusted report counts
* Trusted mute counts
* Viewer blocks
* Administrative status
* Hide thresholds
* Feed-policy bypasses
* Overrides
* Blur state
* Interaction restrictions
`ModerationDecorator` then performs overlapping calculations while decorating video objects.
The extracted system must establish one canonical policy evaluator.
The feed stage and decorator must consume its decision rather than reimplementing policy.
---
# 3. Goals
The extracted repository must:
1. Preserve current BitVid behavior during migration.
2. Support other Nostr applications without importing BitVid concepts.
3. Treat users, immutable events, and addressable events as first-class targets.
4. Provide deterministic and explainable governance decisions.
5. Formalize super-admin, moderator, and curator authority.
6. Support capability-based delegation.
7. Support arbitrary application report categories.
8. Support adjustable, application-defined policies.
9. Support multiple policy profiles within one application.
10. Keep Nostr transport and signing injectable.
11. Keep storage injectable.
12. Work in browsers, workers, Node.js, and tests.
13. Support anonymous and authenticated viewers.
14. Support personal blocks and viewer overrides.
15. Support batched evaluation and bounded subscriptions.
16. Preserve legacy BitVid events during migration.
17. Provide a stable public SDK for BitVid, BitRoad, and future consumers.
18. Permit an optional hosted HTTP adapter without requiring one.
---
# 4. Non-Goals
The initial extraction will not include:
* BitVid CSS
* BitVid design tokens
* Video-card components
* Thumbnail blur implementation
* Playback controls
* Profile-modal UI
* DOM event dispatch
* Toast messages
* Feed rendering
* BitRoad product-card components
* BitRoad checkout UI
* Storefront themes
* Framework-specific React, Vue, or web components
* A mandatory hosted moderation server
* Appeals or dispute-resolution policy
* Enforcement outside compatible clients
The project is a governance engine and synchronization SDK, not a complete moderation product.
---
# 5. Resolved Architectural Decisions
## 5.1 Repository name
Use:
```text
PR0M3TH3AN/nostr-governance
```
The name is broad enough for:
* Moderation
* Access control
* Trust
* Delegation
* Administrative policy
* Community curation
* Commerce restrictions
## 5.2 Headless first
The first stable release contains no UI components.
Optional UI-controller or component packages may be considered after BitVid and BitRoad both consume the headless runtime successfully.
## 5.3 JavaScript before TypeScript conversion
Begin with:
* ESM JavaScript
* Strict JSDoc
* Type checking
* Generated `.d.ts` declarations
Do not combine behavioral extraction with a complete TypeScript rewrite. A TypeScript conversion can occur after parity is established.
## 5.4 SDK before HTTP
The primary interface is a JavaScript SDK.
An HTTP or Cloudflare Worker adapter may be added later using the same SDK internally.
## 5.5 Capability-based authority
Applications check capabilities, not hardcoded role names.
Do not expose a universal method such as:
```js
isAdminEditor()
```
as the principal authority model.
Expose:
```js
governance.can(actorPubkey, capability, target);
```
## 5.6 Addressable targets are mandatory
A governance system for BitRoad cannot rely only on immutable event IDs.
BitRoad products and storefronts can be replaced while retaining their address coordinate. A blocked product must not evade governance merely by publishing a new revision.
## 5.7 One canonical evaluator
All policy effects must be produced by one pure evaluator.
Application adapters may translate a decision, but they may not recalculate the underlying policy.
## 5.8 Wire schema and package version are separate
A package update must not silently change which Nostr events are authoritative.
Track separately:
```text
Package version: 0.4.2
Event schema version: 1
Policy version: bitvid-2026-07
```
---
# 6. Target Repository Structure
```text
nostr-governance/
├── package.json
├── packages/
│ ├── core/
│ │ ├── src/
│ │ │ ├── targets.js
│ │ │ ├── identifiers.js
│ │ │ ├── authority.js
│ │ │ ├── policy.js
│ │ │ ├── evaluator.js
│ │ │ ├── decisions.js
│ │ │ └── snapshots.js
│ │ └── package.json
│ │
│ ├── nostr/
│ │ ├── src/
│ │ │ ├── transport.js
│ │ │ ├── signer.js
│ │ │ ├── codecs/
│ │ │ │ ├── canonical-v1.js
│ │ │ │ ├── bitvid-legacy.js
│ │ │ │ ├── nip51.js
│ │ │ │ └── nip56.js
│ │ │ ├── event-selection.js
│ │ │ └── verification.js
│ │ └── package.json
│ │
│ ├── runtime/
│ │ ├── src/
│ │ │ ├── GovernanceRuntime.js
│ │ │ ├── GovernanceAdminStore.js
│ │ │ ├── TrustGraphStore.js
│ │ │ ├── ReportStore.js
│ │ │ ├── TrustedMuteStore.js
│ │ │ ├── PolicyStore.js
│ │ │ ├── OverrideStore.js
│ │ │ └── commands/
│ │ └── package.json
│ │
│ ├── storage/
│ │ ├── src/
│ │ │ ├── memory.js
│ │ │ ├── localStorage.js
│ │ │ └── indexedDb.js
│ │ └── package.json
│ │
│ ├── bitvid-compat/
│ │ ├── src/
│ │ │ ├── accessControlFacade.js
│ │ │ ├── moderationServiceFacade.js
│ │ │ ├── legacyCache.js
│ │ │ └── videoDecisionAdapter.js
│ │ └── package.json
│ │
│ └── testing/
│ ├── src/
│ │ ├── FakeTransport.js
│ │ ├── FakeSigner.js
│ │ ├── FakeStorage.js
│ │ ├── FakeClock.js
│ │ └── fixtures/
│ └── package.json
│
├── examples/
│ ├── vanilla-browser/
│ ├── node-runtime/
│ ├── bitvid-adapter/
│ └── bitroad-adapter/
│
├── docs/
│ ├── architecture.md
│ ├── authority-model.md
│ ├── event-schema-v1.md
│ ├── policy-guide.md
│ ├── migration-from-bitvid.md
│ └── consumer-integration.md
│
└── .github/workflows/
```
Recommended package names:
```text
@nostr-governance/core
@nostr-governance/nostr
@nostr-governance/runtime
@nostr-governance/storage
@nostr-governance/bitvid-compat
@nostr-governance/testing
```
Do not create a BitRoad-specific package initially. Build the first BitRoad adapter inside BitRoad or as an example. Only create `@nostr-governance/bitroad` if multiple applications later need the exact same commerce mappings.
---
# 7. Domain Model
## 7.1 Governance targets
```ts
type GovernanceTarget =
| {
type: "user";
pubkey: string;
}
| {
type: "event";
eventId: string;
author?: string;
kind?: number;
}
| {
type: "address";
coordinate: string;
author?: string;
kind?: number;
};
```
### User target
Used for:
* BitVid creators
* BitRoad sellers
* Review authors
* Community curators
* Reporters
### Event target
Used for:
* One exact video note
* One exact report
* One immutable review
* One event that should remain denied regardless of its author
### Address target
Used for:
* A replaceable BitVid video coordinate
* A BitRoad product across revisions
* A BitRoad storefront
* An article
* A playlist
* An application-specific object identified through an `a` coordinate
## 7.2 Target keys
```ts
function governanceTargetKey(target): string;
```
Canonical forms:
```text
user:<hex-pubkey>
event:<hex-event-id>
address:<kind>:<hex-pubkey>:<d-tag>
```
Every cache, override, evidence record, and decision must use a canonical target key.
## 7.3 Policy decision
```ts
interface GovernanceDecision {
target: GovernanceTarget;
key: string;
ranking: {
effect: "normal" | "downrank";
weight: number;
};
visibility: {
effect: "allow" | "warn" | "restrict" | "hide" | "deny";
overridable: boolean;
};
interaction: {
effect:
| "allow"
| "require-explicit-action"
| "deny";
};
transaction?: {
effect:
| "allow"
| "require-review"
| "deny";
};
reasons: GovernanceReason[];
evidence: GovernanceEvidence;
policyProfile: string;
policyVersion: string;
snapshotFingerprint: string;
evaluatedAt: number;
}
```
The optional `transaction` dimension is useful for commerce applications.
A product may be:
* Visible
* Inspectable
* Downranked
* Prevented from checkout
without conflating all of those states into one `hidden` boolean.
## 7.4 Stable reason identifiers
```text
viewer-block
viewer-mute
viewer-override
admin-user-deny
admin-event-deny
admin-address-deny
community-user-deny
trusted-report
trusted-report-threshold
trusted-mute
trusted-mute-threshold
allowlist-miss
protected-target
surface-policy-bypass
policy-disabled
```
Applications map these identifiers to their own wording.
## 7.5 Governance evidence
```ts
interface GovernanceEvidence {
trustedReportTotal: number;
trustedReportsByCategory: Record<string, number>;
trustedReporterPubkeys: string[];
trustedMuteTotal: number;
trustedMutesByCategory: Record<string, number>;
trustedMuterPubkeys: string[];
personalBlock: boolean;
personalMute: boolean;
userDenied: boolean;
eventDenied: boolean;
addressDenied: boolean;
userAllowed: boolean;
protectedTarget: boolean;
thresholds: {
warn?: number;
restrict?: number;
hide?: number;
deny?: number;
};
}
```
Sensitive evidence such as reporter names should not be included automatically. Applications may resolve public profile display names separately.
---
# 8. Authority and Delegation Model
## 8.1 Current BitVid authority mismatch
BitVid currently allows moderators to invoke list mutations through `canEditAdminLists()`, but its canonical list loader scopes core list retrieval to the super-admin author. Persistence then signs with the currently active signer.
This creates an apparent distinction between:
* Being permitted by the client to request a mutation
* Being accepted as an authoritative publisher by the loader
The new repository must resolve this explicitly rather than reproducing the ambiguity.
## 8.2 Root-authorized contributor model
Use:
1. Root-signed role state
2. Actor-signed contribution lists
3. Capability-based list acceptance
The root administrator publishes the authoritative role roster.
Each authorized actor publishes their own contribution list under their own key.
The runtime:
1. Loads root role state.
2. Resolves actor capabilities.
3. Loads contributions from authorized actors.
4. Ignores contributions that exceed the actor’s capabilities.
5. Merges valid contributions.
6. Stops accepting an actor’s contributions immediately after revocation.
No moderator needs access to a shared super-admin private key.
## 8.3 Roles
Default roles:
```text
super_admin
moderator
curator
reviewer
```
Roles are convenience bundles. Capabilities remain authoritative.
## 8.4 Capabilities
```ts
type GovernanceCapability =
| "manage-roles"
| "manage-policy"
| "manage-community-sources"
| "contribute-user-allow"
| "contribute-user-deny"
| "contribute-event-deny"
| "contribute-address-deny"
| "contribute-trust-seed"
| "review-evidence";
```
Default role mapping:
```js
const defaultRoleCapabilities = {
super_admin: [
"manage-roles",
"manage-policy",
"manage-community-sources",
"contribute-user-allow",
"contribute-user-deny",
"contribute-event-deny",
"contribute-address-deny",
"contribute-trust-seed",
"review-evidence",
],
moderator: [
"contribute-user-deny",
"contribute-event-deny",
"contribute-address-deny",
"contribute-trust-seed",
"review-evidence",
],
curator: [
"contribute-user-deny",
],
reviewer: [
"review-evidence",
],
};
```
Applications may define additional roles:
```text
seller_moderator
listing_moderator
video_moderator
review_moderator
```
## 8.5 Protected actors
The runtime must protect:
* Root administrators
* Optionally selected system accounts
* Optionally application infrastructure keys
Protected actors cannot be denied through contributor lists.
Only an authorized root-policy change may change protected status.
## 8.6 Merge policy
| State | Authority | Merge behavior |
| ----------------- | --------------------------- | ---------------------------- |
| Roles | Root only | Latest valid root event |
| Policy | Root only | Latest valid root event |
| Community sources | Root or capability holder | Latest accepted source state |
| User allowlist | Root by default | Configurable |
| User denylist | Authorized contributors | Union |
| Event denylist | Authorized contributors | Union |
| Address denylist | Authorized contributors | Union |
| Trust seeds | Root plus authorized actors | Union |
| Viewer overrides | Local viewer | Viewer-local |
| Personal blocks | Viewer | Viewer-local |
---
# 9. Canonical Nostr Event Schema
## 9.1 General approach
The repository must use codecs so event formats remain replaceable.
The core runtime must not know:
* Which Nostr kind stores roles
* Which `d` identifier is used
* Whether entries appear in tags or content
* How a legacy BitVid event is represented
These details belong to codecs.
## 9.2 Canonical v1 kind
Use `kind:30078` for canonical governance application-data documents.
Reasons:
* Parameterized-replaceable
* Suitable for application-specific state
* Supports namespaced `d` identifiers
* Can carry structured content
* Avoids overloading a people-list kind for policies and role documents
* Already supported broadly by the user’s application stack
Legacy BitVid `kind:30000` events remain supported through the compatibility codec.
## 9.3 Canonical identifiers
```text
<namespace>:governance:roles:v1
<namespace>:governance:policy:v1
<namespace>:governance:user-allow:v1
<namespace>:governance:user-deny:v1
<namespace>:governance:event-deny:v1
<namespace>:governance:address-deny:v1
<namespace>:governance:community-sources:v1
```
Examples:
```text
bitvid:governance:roles:v1
bitvid:governance:user-deny:v1
bitroad:governance:address-deny:v1
```
## 9.4 Common tags
```json
[
["d", "bitroad:governance:address-deny:v1"],
["v", "1"],
["client", "nostr-governance"],
["scope", "address-deny"]
]
```
## 9.5 Role event
Published by a root administrator:
```json
{
"kind": 30078,
"content": "",
"tags": [
["d", "bitroad:governance:roles:v1"],
["v", "1"],
["p", "<moderator-pubkey>", "moderator"],
["cap", "<moderator-pubkey>", "contribute-user-deny"],
["cap", "<moderator-pubkey>", "contribute-address-deny"],
["p", "<curator-pubkey>", "curator"],
["cap", "<curator-pubkey>", "contribute-user-deny"]
]
}
```
The exact tag layout should be finalized through test vectors before release, but it must support:
* Role labels
* Explicit capabilities
* Root protection
* Schema version
* Future extension without changing the kind
## 9.6 User contribution lists
```json
{
"kind": 30078,
"content": "",
"tags": [
["d", "bitroad:governance:user-deny:v1"],
["v", "1"],
["p", "<seller-pubkey>", "scam"],
["p", "<seller-pubkey-2>", "malware"]
]
}
```
## 9.7 Event contribution lists
```json
{
"kind": 30078,
"content": "",
"tags": [
["d", "bitvid:governance:event-deny:v1"],
["v", "1"],
["e", "<event-id>", "illegal"]
]
}
```
## 9.8 Address contribution lists
```json
{
"kind": 30078,
"content": "",
"tags": [
["d", "bitroad:governance:address-deny:v1"],
["v", "1"],
["a", "30078:<seller-pubkey>:bitroad:product:sku-001", "malware"]
]
}
```
## 9.9 Policy event
```json
{
"kind": 30078,
"tags": [
["d", "bitroad:governance:policy:v1"],
["v", "1"]
],
"content": "{\"policyVersion\":\"bitroad-1\",\"profiles\":{...}}"
}
```
Policy content must be schema-validated and size-bounded.
## 9.10 Legacy BitVid compatibility
The compatibility codec must continue reading:
```text
bitvid:admin:editors
bitvid:admin:whitelist
bitvid:admin:blacklist
bitvid:admin:event-blacklist
```
It must also read existing community blacklist source references.
Migration behavior:
```text
Stage 1: read legacy, write legacy
Stage 2: read both, write legacy
Stage 3: read both, dual-write
Stage 4: read both, write canonical
Stage 5: retain legacy reading for compatibility
```
Do not perform a destructive migration.
---
# 10. Public SDK
## 10.1 Runtime creation
```ts
createGovernanceRuntime(options): GovernanceRuntime;
```
```ts
interface CreateGovernanceRuntimeOptions {
applicationId: string;
namespace: string;
rootPubkeys: string[];
transport: GovernanceTransport;
storage: GovernanceStorage;
policy: GovernancePolicy;
signer?: GovernanceSigner;
clock?: GovernanceClock;
codecs?: GovernanceCodec[];
logger?: GovernanceLogger;
cachePolicy?: GovernanceCachePolicy;
reputationSource?: GovernanceReputationSource;
}
```
Example:
```js
const governance = createGovernanceRuntime({
applicationId: "bitroad",
namespace: "bitroad",
rootPubkeys: [operatorPubkey],
transport,
signer,
storage,
policy: bitRoadPolicy,
codecs: [
createCanonicalGovernanceCodec({ version: 1 }),
],
});
```
## 10.2 Lifecycle
```ts
governance.initialize(): Promise<GovernanceSnapshot>;
governance.destroy(): Promise<void>;
```
`destroy()` must:
* Close subscriptions
* Cancel supported requests
* Clear timers
* Remove listeners
* Release viewer-sensitive state
* Clear active targets
## 10.3 Viewer state
```ts
governance.setViewer(viewer): Promise<void>;
governance.clearViewer(): Promise<void>;
```
```ts
interface GovernanceViewer {
pubkey?: string;
follows?: Iterable<string>;
blockedPubkeys?: Iterable<string>;
mutedPubkeys?: Iterable<string>;
}
```
Anonymous sessions omit `pubkey` and rely on configured trust seeds.
## 10.4 Active-target management
```ts
governance.setActiveTargets(targets): Promise<void>;
governance.addActiveTargets(targets): Promise<void>;
governance.removeActiveTargets(targetsOrKeys): Promise<void>;
governance.clearActiveTargets(): Promise<void>;
```
This API allows:
* BitVid to register videos visible in the active feed
* BitRoad to register products in the current marketplace page
* A product page to register its reviews
* An application to remove targets when a view is closed
The runtime must batch active-target report subscriptions.
## 10.5 Evaluation
```ts
governance.evaluate(
target,
context?
): GovernanceDecision;
```
```ts
governance.evaluateMany(
targets,
context?
): Map<string, GovernanceDecision>;
```
`evaluateMany()` is required for:
* Feeds
* Search results
* Marketplace grids
* Storefront catalogs
* Review lists
* Admin dashboards
Evaluation must be synchronous after runtime state has been loaded. Relay access must not occur inside an individual evaluation call.
## 10.6 Evaluation context
```ts
interface GovernanceEvaluationContext {
surface?: string;
policyProfile?: string;
viewerPubkey?: string;
enforcement?: {
hardHide?: boolean;
allowOverrides?: boolean;
requireExplicitAction?: boolean;
};
metadata?: Record<string, unknown>;
}
```
## 10.7 Snapshot queries
```ts
governance.getSnapshot(): GovernanceSnapshot;
governance.getRoles(): GovernanceRoleSnapshot;
governance.getPolicy(): GovernancePolicySnapshot;
governance.getAdministrativeState(): GovernanceAdministrativeSnapshot;
governance.getEvidence(target): GovernanceEvidence;
governance.getUserStatus(pubkey): GovernanceUserStatus;
governance.getTargetStatus(target): GovernanceTargetStatus;
```
Returned values must be immutable snapshots or defensive copies.
Consumers must never receive internal mutable maps.
## 10.8 Capability queries
```ts
governance.can(
actorPubkey,
capability,
target?
): boolean;
```
```ts
governance.getCapabilities(
actorPubkey
): GovernanceCapability[];
```
UI may use these methods to decide which controls to show.
Commands must independently repeat authority validation before signing.
## 10.9 Administrative commands
```ts
governance.commands.grantRole(input);
governance.commands.revokeRole(input);
governance.commands.setCapabilities(input);
governance.commands.addUserAllow(input);
governance.commands.removeUserAllow(input);
governance.commands.addUserDeny(input);
governance.commands.removeUserDeny(input);
governance.commands.addEventDeny(input);
governance.commands.removeEventDeny(input);
governance.commands.addAddressDeny(input);
governance.commands.removeAddressDeny(input);
governance.commands.addCommunitySource(input);
governance.commands.removeCommunitySource(input);
governance.commands.publishPolicy(input);
```
Example:
```js
await governance.commands.addAddressDeny({
target: productTarget,
category: "malware",
reason: "Download contained a malicious executable.",
metadata: {
storefrontAddress: product.storefrontAddress,
},
});
```
## 10.10 Command result
```ts
interface GovernanceCommandResult {
ok: boolean;
commandId?: string;
publishedEventIds?: string[];
acceptedRelays?: string[];
stateChanged?: boolean;
error?: {
code: GovernanceErrorCode;
message: string;
};
}
```
Stable error codes:
```text
forbidden
invalid-target
invalid-pubkey
invalid-event-id
invalid-address
protected-target
signer-unavailable
signature-failed
publish-failed
transport-unavailable
stale-state
conflict
```
## 10.11 Viewer overrides
```ts
governance.overrides.set(input): Promise<void>;
governance.overrides.clear(input): Promise<void>;
governance.overrides.clearAll(): Promise<void>;
governance.overrides.has(target): boolean;
governance.overrides.get(target): GovernanceOverride | null;
```
Supported scopes:
```text
target
author
category
```
Administrative transaction denials should not be viewer-overridable unless the application policy explicitly permits it.
## 10.12 Reports
```ts
governance.reports.create(input): Promise<GovernanceCommandResult>;
governance.reports.getSummary(target): GovernanceReportSummary;
governance.reports.getTrustedReporters(
target,
category?
): GovernanceReporterEvidence[];
```
The core accepts arbitrary normalized categories.
BitVid examples:
```text
nudity
spam
illegal
impersonation
malware
profanity
other
```
BitRoad examples:
```text
scam
malware
impersonation
counterfeit
non-delivery
misleading
prohibited
spam
other
```
## 10.13 Subscriptions
```ts
governance.subscribe(listener): () => void;
governance.subscribeToTarget(target, listener): () => void;
governance.subscribeToRoles(listener): () => void;
governance.subscribeToPolicy(listener): () => void;
governance.subscribeToAdministrativeState(listener): () => void;
governance.subscribeToViewerState(listener): () => void;
```
Semantic change types:
```text
initialized
viewer-changed
roles-changed
policy-changed
administrative-state-changed
trust-graph-changed
report-summary-changed
trusted-mute-state-changed
target-decision-changed
override-changed
transport-status-changed
```
Notifications must include a state fingerprint or revision so consumers can ignore duplicates.
## 10.14 Import and export
```ts
governance.exportSnapshot(options?): GovernancePortableSnapshot;
governance.importSnapshot(
snapshot,
options?
): Promise<GovernanceImportResult>;
```
Import modes:
```text
preview
merge
replace-local-cache
publish-authoritative-state
```
Signer secrets must never be exported.
## 10.15 Diagnostics
```ts
governance.diagnostics.getStatus(): GovernanceRuntimeStatus;
governance.diagnostics.explain(
target,
context?
): GovernanceDecisionTrace;
```
Example trace:
```text
viewer block: no
admin user deny: no
admin address deny: no
trusted scam reports: 2 / restrict threshold 3
trusted mute count: 1 / hide threshold 20
result: downrank
```
Sensitive relationship evidence must be restricted or omitted in production diagnostics.
---
# 11. Transport, Signer, and Storage Interfaces
## 11.1 Transport
```ts
interface GovernanceTransport {
list(
filters: object[],
options?: GovernanceListOptions
): Promise<NostrEvent[]>;
subscribe(
filters: object[],
handlers: GovernanceSubscriptionHandlers,
options?: GovernanceSubscribeOptions
): GovernanceSubscription;
publish(
event: NostrEvent,
options?: GovernancePublishOptions
): Promise<GovernancePublishResult>;
}
```
The package must not depend directly on:
* BitVid’s relay pool
* BitRoad’s `queryRelays()`
* NDK
* nostr-tools
* A particular SubscriptionManager
Each consumer provides an adapter.
## 11.2 Signer
```ts
interface GovernanceSigner {
getPublicKey(): Promise<string>;
signEvent(event: UnsignedNostrEvent): Promise<NostrEvent>;
}
```
This aligns with both applications’ need to support multiple signer methods.
BitRoad already separates its active signer and NIP-07, nsec, and BitLogin implementations.
## 11.3 Storage
```ts
interface GovernanceStorage {
read(key: string): Promise<unknown>;
write(key: string, value: unknown): Promise<void>;
remove(key: string): Promise<void>;
}
```
Storage keys must be namespaced by:
```text
application ID
governance namespace
root-authority fingerprint
schema version
viewer pubkey, when viewer-specific
```
Example:
```text
nostr-governance:bitroad:bitroad:<root-fingerprint>:v1:admin
```
This prevents state from one deployment or viewer leaking into another.
---
# 12. Policy Engine
## 12.1 Policy pipeline
Canonical evaluation order:
```text
1. Validate and normalize target
2. Resolve protected-target status
3. Apply viewer personal block
4. Apply administrative user denial
5. Apply administrative event denial
6. Apply administrative address denial
7. Apply access allowlist policy
8. Apply viewer override where permitted
9. Aggregate trusted mute evidence
10. Aggregate trusted report evidence
11. Apply category thresholds
12. Apply optional reputation signal
13. Apply surface policy profile
14. Return decision and explanation
```
## 12.2 Separation of access and trust
Allowlists must remain separate from the trust graph.
Being allowed to publish or appear in an application does not make someone:
* A trusted reporter
* A moderator
* A trust seed
* Immune to moderation
* Exempt from personal blocks
This preserves BitVid’s existing separation between creator access and trust-based moderation.
## 12.3 Policy profiles
One application may enforce the same evidence differently by surface.
Example BitRoad profiles:
```js
const bitRoadPolicyProfiles = {
"public-marketplace": {
administrativeDeny: {
visibility: "hide",
transaction: "deny",
},
trustedSignals: {
default: "downrank",
},
allowViewerOverride: false,
},
"product-detail": {
administrativeDeny: {
visibility: "restrict",
transaction: "deny",
},
trustedSignals: {
default: "warn",
},
allowViewerOverride: true,
},
"checkout": {
administrativeDeny: {
visibility: "allow",
transaction: "deny",
},
trustedSignals: {
scam: "require-review",
malware: "deny",
},
allowViewerOverride: false,
},
"seller-dashboard": {
administrativeDeny: {
visibility: "warn",
transaction: "deny",
},
exposeEvidence: true,
allowViewerOverride: false,
},
};
```
A denied product can therefore:
* Disappear from public discovery
* Remain visible to its seller
* Be inspectable in an appeals screen
* Be blocked from checkout
## 12.4 Trusted-mute policy
Trusted mutes must support:
* Ranking effect below threshold
* Configurable validity window
* Category-specific counts
* Category-specific escalation thresholds
* Unique muter counting
* Blocked-reporter exclusion
* Optional decay behavior
The default generic engine should not blur, hide, or deny merely because one trusted account muted another.
## 12.5 Report policy
Applications define category thresholds:
```js
const bitRoadReportPolicy = {
scam: {
warn: 2,
restrict: 3,
hide: 5,
transactionDeny: 3,
},
malware: {
warn: 1,
restrict: 1,
hide: 2,
transactionDeny: 1,
},
misleading: {
warn: 3,
restrict: 5,
hide: 8,
},
spam: {
downrank: 2,
hide: 8,
},
};
```
These are illustrative values, not required defaults.
---
# 13. Runtime Store Architecture
## 13.1 `GovernanceAdminStore`
Responsible for:
* Root state
* Roles
* Capabilities
* User allow contributions
* User deny contributions
* Event deny contributions
* Address deny contributions
* Community sources
* Protected actors
* Effective merged state
## 13.2 `TrustGraphStore`
Responsible for:
* Viewer follows
* Operator trust seeds
* Moderator trust seeds
* Viewer blocks
* Viewer mutes
* Trusted-set calculation
* Trust-set change notifications
## 13.3 `ReportStore`
Responsible for:
* NIP-56 event ingestion
* Target association
* Category normalization
* Unique reporter aggregation
* Trusted/untrusted separation
* Active-target subscriptions
* Report summary snapshots
## 13.4 `TrustedMuteStore`
Responsible for:
* NIP-51 mute lists
* Replaceable-list selection
* Validity windows
* Author aggregation
* Category aggregation
* Batch author queries
* Expired-list pruning
## 13.5 `PolicyStore`
Responsible for:
* Default policy
* Root-published policy
* Local application policy
* Policy-profile selection
* Policy schema validation
* Policy versioning
## 13.6 `OverrideStore`
Responsible for:
* Per-target overrides
* Per-author overrides
* Per-category overrides
* Viewer-scoped persistence
* Override expiry if configured
## 13.7 `GovernanceRuntime`
Responsible for:
* Store lifecycle
* Transport orchestration
* Viewer changes
* Active-target changes
* Evaluation
* Commands
* Subscription fan-out
* Snapshot creation
* Diagnostics
---
# 14. Application Adapter Contract
Each application defines how its objects become governance targets and how decisions map back into application behavior.
```ts
interface GovernanceApplicationAdapter<TObject> {
applicationId: string;
toTargets(object: TObject): GovernanceTarget[];
getPrimaryTargetKey(object: TObject): string;
applyDecision?(
object: TObject,
decision: GovernanceDecision
): TObject;
}
```
Some objects should map to multiple targets.
A BitRoad product may be affected by:
* Seller user status
* Exact event status
* Address status
```js
function bitRoadProductTargets(product) {
return [
{
type: "user",
pubkey: product.pubkey,
},
{
type: "event",
eventId: product.id,
author: product.pubkey,
kind: 30078,
},
{
type: "address",
coordinate: product.address,
author: product.pubkey,
kind: 30078,
},
];
}
```
The runtime or adapter then composes those decisions using an explicit application rule.
---
# 15. BitVid Extraction Map
## 15.1 Move or rewrite into `nostr-governance`
Reusable logic currently found in:
```text
js/services/moderationUtils.js
js/services/moderationService.js
js/accessControl.js
js/adminListStore.js
js/adminListBatch.js
js/adminEventBlacklistHelpers.js
js/services/trustBootstrap.js
admin-related parts of js/nostrEventSchemas.js
```
Extract:
* Identifier normalization
* Report parsing
* Report aggregation
* Trusted-mute aggregation
* Decay-window handling
* Administrative list parsing
* Community source parsing
* Role resolution
* Capability checks
* Protected-actor rules
* Nostr persistence
* Cached fallback
* Active-target subscriptions
* Batched author evidence
* Policy decisions
* Decision explanations
## 15.2 Remain in BitVid
```text
js/app/moderationActionController.js
js/app/moderationCoordinator.js
js/ui/components/VideoCard.js
profile/admin modal controllers
video modal controls
playback coordinators
BitVid CSS and design tokens
feed refresh orchestration
```
`ModerationActionController` remains in BitVid because it currently understands videos, cards, playback resumption, feed refreshes, status messages, and DOM events.
## 15.3 Convert to thin BitVid adapters
### Feed stage
Current:
```text
load evidence
calculate thresholds
apply precedence
calculate hide state
calculate blur state
apply feed bypass
mutate video
```
Target:
```text
collect targets
evaluateMany()
attach decisions
filter items according to feed profile
```
### Moderation decorator
Current:
```text
recalculates moderation policy
```
Target:
```text
maps a GovernanceDecision to video.moderation
```
Example:
```js
function applyGovernanceDecisionToVideo(video, decision) {
const restricted =
decision.visibility.effect === "restrict" ||
decision.visibility.effect === "hide" ||
decision.visibility.effect === "deny";
video.moderation = {
...video.moderation,
governanceDecision: decision,
hidden:
decision.visibility.effect === "hide" ||
decision.visibility.effect === "deny",
blurThumbnail: restricted,
blockAutoplay:
decision.interaction.effect !== "allow",
reasons: decision.reasons,
evidence: decision.evidence,
};
return video;
}
```
### Compatibility facade
Temporarily preserve existing BitVid calls:
```text
isSuperAdmin
isAdminEditor
canEditAdminLists
canAccess
isBlacklisted
isEventBlacklisted
getWhitelist
getBlacklist
getEditors
```
Internally, these become wrappers over the governance runtime.
---
# 16. BitRoad Integration Reference
## 16.1 Why BitRoad is the validation consumer
BitRoad has:
* Sellers
* Storefronts
* Products
* Reviews
* Public marketplace discovery
* Seller dashboards
* Checkout
* Nostr signer abstractions
* Nostr relay abstractions
Its public listing and private purchase architecture is already separated conceptually, and products/storefronts are represented as addressable `kind:30078` events.
Its main application module already consumes separate modules for:
* Product parsing
* Review parsing
* Storefront parsing
* Marketplace filtering and sorting
* Product rendering
* Relay access
* Signer access
This provides natural integration seams.
## 16.2 BitRoad targets
| Object | Targets |
| ---------------- | ---------------------------------------------------------- |
| Seller | User |
| Storefront | User + address + exact event |
| Product | Seller user + product address + exact event |
| Review | Reviewer user + exact review event |
| Store catalog | Storefront address |
| Imported product | No governance until published, unless local policy applies |
## 16.3 Marketplace pipeline
Current conceptual flow:
```text
relay events
↓
parseProductFeed()
↓
filterMarketplaceListings()
↓
sortMarketplaceListings()
↓
renderMarketplaceGrid()
```
Target flow:
```text
relay events
↓
parseProductFeed()
↓
create governance targets
↓
governance.evaluateMany()
↓
apply visibility and rank effects
↓
filterMarketplaceListings()
↓
sortMarketplaceListings()
↓
renderMarketplaceGrid()
```
## 16.4 Checkout enforcement
Governance must be evaluated again immediately before checkout.
```js
function assertProductCheckoutAllowed(product) {
const targets = bitRoadProductTargets(product);
const decisions = governance.evaluateMany(targets, {
surface: "checkout",
policyProfile: "commerce-transaction",
enforcement: {
hardHide: true,
allowOverrides: false,
},
});
const composed = composeBitRoadProductDecision(decisions);
if (
composed.transaction?.effect === "deny" ||
composed.interaction.effect === "deny"
) {
throw new Error("This listing is unavailable for purchase.");
}
return composed;
}
```
This prevents a product page opened before a newer governance update from initiating checkout using stale state.
## 16.5 Suggested BitRoad effects
```text
normal
downrank in marketplace
show warning
hide from marketplace
disable checkout
deny seller onboarding
deny new publication
hide storefront
suppress review
```
## 16.6 Suggested BitRoad moderator roles
```js
const bitRoadRoles = {
listing_moderator: [
"contribute-event-deny",
"contribute-address-deny",
"review-evidence",
],
seller_moderator: [
"contribute-user-deny",
"review-evidence",
],
community_curator: [
"contribute-user-deny",
],
};
```
## 16.7 BitRoad proof-of-concept
Before `nostr-governance` reaches `1.0.0`, BitRoad should demonstrate:
1. Seller allowlist mode
2. Administrative seller denial
3. Product-address denial
4. Exact-event denial
5. Trusted scam-report downranking
6. Malware-based checkout denial
7. Moderator capability checks
8. Community curator ingestion
9. Seller-dashboard explanation
10. No changes to the generic core
The purpose is not to ship all BitRoad moderation immediately. It is to prove the extracted API does not accidentally remain video-specific.
---
# 17. Migration Plan
## Phase 0 — Characterize current BitVid behavior
### Work
* Pin the BitVid baseline commit.
* Reconcile documentation with current code.
* Inventory list identifiers.
* Inventory storage keys.
* Inventory event kinds.
* Inventory public service methods.
* Document decision precedence.
* Document feed exceptions.
* Document overrides.
* Record relay-request and feed-evaluation performance.
* Add missing characterization tests.
* Resolve delegated-authority behavior.
### Required tests
* Trusted report threshold
* Duplicate reporter
* Blocked reporter
* Trusted mute below threshold
* Trusted mute at threshold
* Expired trusted mute
* Personal block precedence
* Administrative blacklist
* Event blacklist
* Community blacklist
* Moderator trust seed
* Viewer override
* Author override
* Home/Recent hide bypass
* Cache fallback
### Acceptance
* The current behavior is reproducible from fixtures.
* Intentional policy changes cause test failures.
* Tests read defaults from configuration instead of duplicating values.
---
## Phase 1 — Create the repository
### Work
* Create npm workspace.
* Configure Node.js 22.
* Configure ESM.
* Add linting.
* Add test runner.
* Add JSDoc type checking.
* Generate type declarations.
* Add changelog.
* Add architecture-decision records.
* Add GPL-compatible license.
BitVid currently declares GPL-3.0-or-later, so directly extracted code should retain compatible licensing unless an independently implemented clean rewrite is performed.
### Acceptance
* Packages build independently.
* Core imports no browser globals.
* CI runs unit and contract tests.
* Empty runtime initializes with fake dependencies.
---
## Phase 2 — Implement the pure core
### Work
Implement:
* Target normalization
* Strict pubkey normalization
* Strict event-ID normalization
* Address parsing
* Role resolution
* Capability resolution
* Administrative-state reduction
* Policy schema
* Policy normalization
* Pure evaluator
* Decision composition
* Explanation traces
* Snapshot fingerprints
### Acceptance
* Identical snapshots produce identical decisions.
* Evaluation performs no I/O.
* Evaluation mutates no input.
* Core can run in Node without browser polyfills.
* Core contains no BitVid or BitRoad terms.
---
## Phase 3 — Implement codecs
### Work
Implement:
* Canonical v1 codec
* BitVid legacy admin codec
* Existing BitVid event-blacklist codec
* Existing BitVid community-source codec
* NIP-56 codec
* NIP-51 codec
* Replaceable-event selection
* Signature-verification hooks
### Acceptance
* Existing BitVid fixtures parse correctly.
* Malformed tags are ignored safely.
* Npub and hex inputs normalize consistently.
* Latest-event selection matches current BitVid behavior.
* Same-timestamp ties are deterministic.
* Legacy state can be represented as a normalized snapshot.
---
## Phase 4 — Implement runtime stores
### Work
Build:
* `GovernanceAdminStore`
* `TrustGraphStore`
* `ReportStore`
* `TrustedMuteStore`
* `PolicyStore`
* `OverrideStore`
* `GovernanceRuntime`
### Acceptance
* Stores use injected transport.
* Stores use injected storage.
* Stores emit only on actual changes.
* Viewer switching clears viewer-specific state.
* Subscriptions close on destroy.
* Report subscriptions remain batched.
* Author evidence can be queried in batches.
* Expired trusted mutes are pruned with an injected clock.
---
## Phase 5 — Implement public commands
### Work
Implement:
* Role commands
* Capability commands
* User list commands
* Event list commands
* Address list commands
* Community source commands
* Policy commands
* Report publishing
* Partial relay acceptance
* Stable error codes
### Acceptance
* Every command checks authority.
* Unauthorized actors cannot sign an accepted mutation.
* Revoked actors’ contributions stop affecting effective state.
* Protected actors cannot be denied.
* First relay acceptance may complete the command.
* Remaining relay results remain observable for diagnostics.
---
## Phase 6 — Add BitVid compatibility layer
### Work
Build facades matching current BitVid service methods.
Add:
```text
FEATURE_EXTERNAL_GOVERNANCE_SHADOW
```
For each BitVid target:
1. Evaluate with current BitVid implementation.
2. Evaluate with external runtime.
3. Normalize both outputs.
4. Log differences in development.
5. Continue rendering from current BitVid output.
### Mismatch record
```js
{
targetKey,
author,
currentDecision,
externalDecision,
policyFingerprint,
trustFingerprint,
adminFingerprint,
}
```
### Acceptance
* No production-visible changes.
* Characterization fixtures show zero unexplained mismatches.
* Live-feed sampling reveals no systematic mismatch.
* Shadow mode does not materially regress feed performance.
---
## Phase 7 — Cut over BitVid administrative state
### Work
Replace:
* Admin-list loading
* Admin-list caching
* Community-source merging
* Role checks
* User allow/deny state
* Event deny state
Keep the old BitVid public facade temporarily.
### Acceptance
* Existing lists remain effective.
* Cached fallback remains effective.
* Community-curated lists remain effective.
* Administrator protection remains effective.
* Moderators have cryptographically defined authority.
* Existing admin UI continues working.
---
## Phase 8 — Cut over BitVid reports and trust
### Work
Replace:
* Trusted-contact state
* Trust-seed state
* Report aggregation
* Trusted-mute aggregation
* Decay handling
* Active-target subscriptions
* Author evidence batching
### Acceptance
* Trusted mutes remain ranking-only below threshold.
* Current report thresholds remain unchanged.
* Current hide thresholds remain unchanged.
* Blocked reporters remain excluded.
* Anonymous trust seeds remain functional.
* Moderator changes update trust seeds.
* No relay-request regression occurs.
---
## Phase 9 — Cut over BitVid policy
### Work
* Make `evaluateMany()` authoritative.
* Reduce the feed stage to target collection and decision application.
* Reduce `ModerationDecorator` to presentation mapping.
* Preserve BitVid policy profiles for Home, Recent, Discovery, and playback.
* Preserve existing overrides.
* Preserve UI behavior.
Add:
```text
FEATURE_EXTERNAL_GOVERNANCE
```
Keep old policy behind a rollback flag for one stabilization cycle.
### Acceptance
* One canonical evaluator remains.
* Existing unit tests pass.
* Existing visual moderation tests pass.
* Override restoration works.
* Home and Recent behavior remains correct.
* Playback behavior remains correct.
* The old evaluator can be disabled without UI changes.
---
## Phase 10 — Validate through BitRoad
### Work
Implement inside BitRoad:
```text
src/governance/runtime.mjs
src/governance/transportAdapter.mjs
src/governance/signerAdapter.mjs
src/governance/productAdapter.mjs
src/governance/storefrontAdapter.mjs
src/governance/reviewAdapter.mjs
src/governance/policy.mjs
```
Integrate into:
* Marketplace loading
* Product detail
* Storefront catalogs
* Reviews
* Checkout
* Seller dashboard
### Acceptance
* Product-address denial persists across revisions.
* Seller denial affects all seller products.
* Exact-event denial affects only the selected event.
* Trusted reports can downrank marketplace items.
* Checkout performs a fresh governance check.
* Seller dashboard can explain restrictions.
* No core package changes are required for BitRoad.
---
## Phase 11 — Remove duplicated BitVid logic
### Work
Delete:
* Duplicate threshold calculation
* Duplicate target normalization
* Duplicate list parsing
* Duplicate report aggregation
* Duplicate trusted-mute aggregation
* Duplicate authority checks
* Direct relay access from removed services
Retain:
* BitVid policy configuration
* BitVid adapter
* BitVid UI
* BitVid action controller
* BitVid orchestration
### Acceptance
* Removing old services does not change behavior.
* BitVid imports only documented public package APIs.
* No consumer imports package-internal paths.
---
# 18. Testing Strategy
## 18.1 Core policy tests
Cover:
* Personal block precedence
* Personal mute
* User denial
* Event denial
* Address denial
* Allowlist miss
* Trusted mute below threshold
* Trusted mute at threshold
* Trusted reports by category
* Viewer override
* Policy profile differences
* Protected target
* Transaction denial
* Deterministic explanation trace
## 18.2 Authority tests
Cover:
* Root grants role
* Root revokes role
* Moderator cannot manage roles
* Curator can contribute only allowed lists
* Removed moderator contribution is ignored
* Unknown capability is ignored
* Actor cannot self-escalate
* Protected root cannot be denied
* Invalid root signature is rejected
## 18.3 Trust tests
Cover:
* F1 reports count
* Non-F1 reports do not count
* Trust seeds count
* Duplicate reports count once
* Blocked reporters do not count
* Muted reporters do not count
* Trust changes recompute summaries
* Anonymous and authenticated trust differ correctly
## 18.4 Trusted-mute tests
Cover:
* Rolling validity window
* Expired lists
* New list replacement
* Category metadata
* Total counts
* Category counts
* Batch author lookup
* Ranking-only behavior below threshold
* Hide behavior at threshold
## 18.5 Transport tests
Cover:
* Relay timeout
* Partial acceptance
* No relay acceptance
* Out-of-order events
* Duplicate events
* Same-timestamp replacement
* Subscription closure
* Active-target changes
* Large filter chunking
* Reconnection
* Cached fallback
## 18.6 Storage contract tests
Every storage adapter must pass one shared suite:
* Missing key
* Read/write
* Remove
* Invalid data
* Version migration
* Viewer separation
* Root-authority separation
* Schema-version separation
## 18.7 BitVid integration tests
Retain and expand:
* Trusted-report tests
* Trusted-mute tests
* Admin-list-store tests
* Trust-seed tests
* Moderation-stage tests
* Moderation-decorator tests
* Override tests
* Visual moderation tests
* Admin UI tests
BitVid’s existing QA plan already identifies the principal trusted-report, hide, override, muted-reporter, and visual scenarios that should seed the package conformance suite.
## 18.8 BitRoad integration tests
Cover:
* Denied seller removed from marketplace
* Denied seller still sees dashboard explanation
* Product address denial survives replacement
* Exact event denial does not deny a different address revision unless policy composes it
* Checkout denial occurs before invoice creation
* Marketplace downranking preserves stable sorting
* Review-author denial suppresses reviews
* Anonymous marketplace uses trust seeds
* Signed-in buyer uses personal trust graph
* Viewer state does not leak between accounts
---
# 19. Security Requirements
The repository must:
1. Verify signatures before accepting authoritative state.
2. Validate authority independently of UI state.
3. Use strict 64-character pubkey and event-ID validation.
4. Validate address coordinates.
5. Bound list sizes.
6. Bound reference counts.
7. Bound policy content size.
8. Ignore unknown capabilities.
9. Ignore unauthorized contributor events.
10. Protect root and configured system accounts.
11. Deduplicate reports by reporter, target, and category.
12. Apply configurable mute-list expiry.
13. Namespace caches correctly.
14. Prevent viewer-state leakage.
15. Never export signer secrets.
16. Avoid shared moderator keys.
17. Treat relays as transport rather than authority.
18. Preserve the last-known valid state during transient relay failure.
19. Mark stale state in diagnostics.
20. Fail closed for administrative commands when authority cannot be confirmed.
21. Permit policy-configured fail-open behavior for public viewing where appropriate.
---
# 20. Performance Requirements
## 20.1 Required characteristics
* No subscription per card
* No async evaluation per item
* One logical subscription per active signal class
* Bounded `#e` and `#a` filter chunks
* Batched author evidence lookup
* Decision caching by target and state fingerprint
* Incremental invalidation
* Emit only on actual state changes
* Cancel obsolete active-target work
* Close subscriptions on view changes
* No repeated full-list parsing during individual evaluations
## 20.2 Performance fixture
Include:
```text
5,000 targets
500 authors
100 trusted muters per author
multiple report categories
multiple administrative contributors
multiple policy profiles
viewer switching
moderator roster changes
relay reconnect
```
## 20.3 Performance acceptance
* `evaluateMany(5,000)` performs no network access.
* Batch evaluation does not regress below the current BitVid baseline.
* Updating one report invalidates only affected target decisions.
* Updating one author mute state invalidates only that author’s targets.
* Changing policy may intentionally invalidate all decisions.
* Destroy leaves no active timers or subscriptions.
---
# 21. Optional HTTP and Cloudflare Adapter
The headless SDK does not require a server.
A later package may provide:
```text
@nostr-governance/http
@nostr-governance/cloudflare-worker
```
Suggested routes:
```text
POST /v1/evaluate
POST /v1/evaluate-many
GET /v1/users/:pubkey/status
POST /v1/targets/status
GET /v1/policy
GET /v1/roles
POST /v1/commands/user-deny
POST /v1/commands/event-deny
POST /v1/commands/address-deny
POST /v1/reports
```
Rules:
* The HTTP adapter must call the SDK.
* It must not contain a second evaluator.
* Administrative requests require cryptographic authentication.
* Public evaluation responses must avoid leaking sensitive trust-graph details.
* BitVid and BitRoad must remain capable of using the SDK directly.
---
# 22. Versioning and Releases
## 22.1 Proposed releases
```text
0.1.x
Core targets, authority, policy, evaluator, fixtures
0.2.x
Nostr codecs and storage contracts
0.3.x
Runtime stores, subscriptions, commands
0.4.x
BitVid compatibility and shadow mode
0.5.x
BitVid administrative cutover
0.6.x
BitVid trust and policy cutover
0.7.x
BitRoad proof-of-concept
0.8–0.9.x
API stabilization, security audit, documentation
1.0.0
Stable SDK and canonical schema v1
```
## 22.2 Versioning rules
* Use semantic versioning.
* Version event schemas separately.
* Do not remove legacy codecs in a minor release.
* Document policy-output changes prominently.
* Include decision fixtures in breaking-change reviews.
* Pin exact package versions during pre-1.0 BitVid migration.
* Add automated dependency updates after API stabilization.
## 22.3 Consumer contract tests
The governance repository should expose:
```text
npm run test:consumer:bitvid
npm run test:consumer:bitroad
```
Each consumer should run governance conformance fixtures before dependency updates are merged.
---
# 23. Risks and Mitigations
## Risk: Extracting BitVid assumptions into the core
**Mitigation:** Require BitRoad proof-of-concept before `1.0.0`.
## Risk: Policy logic remains duplicated in BitVid
**Mitigation:** Enforce one evaluator and prohibit adapters from calculating thresholds.
## Risk: Delegated moderation is only a UI permission
**Mitigation:** Root-authorized contributor model with signature and capability verification.
## Risk: Product bans are bypassed through replacement events
**Mitigation:** First-class address targets.
## Risk: Relay outages erase administrative state
**Mitigation:** Last-known valid cached snapshots with stale-state diagnostics.
## Risk: Community curators gain excess authority
**Mitigation:** Curator-specific capabilities and list-type validation.
## Risk: Viewer overrides bypass transactional safety
**Mitigation:** Policy profiles independently control visibility, interaction, and transaction effects.
## Risk: Extraction causes feed-performance regression
**Mitigation:** Preserve active-target batching, author batching, and benchmark gates.
## Risk: Legacy BitVid state is lost
**Mitigation:** Compatibility codec, read-both migration, optional dual-write.
## Risk: Package and event-schema upgrades become coupled
**Mitigation:** Independent schema, policy, and package versions.
---
# 24. Definition of Done
The project is complete when:
* BitVid imports the external governance runtime.
* BitVid’s existing administrative lists still work.
* BitVid’s community curators still work.
* BitVid’s trust seeds still work.
* BitVid’s reports and trusted mutes retain current behavior.
* Trusted mutes remain ranking-only below threshold.
* BitVid policy is calculated in one place.
* BitVid UI remains owned by BitVid.
* BitRoad can consume the same runtime without core modifications.
* BitRoad can govern sellers, exact product events, and product addresses.
* BitRoad checks governance before checkout.
* Delegated authority is cryptographically verifiable.
* Core packages contain no video, card, modal, marketplace, or checkout UI concepts.
* No package consumer imports internal source paths.
* Transport, signer, and storage are injected.
* Unit, integration, visual, security, and performance tests pass.
* Shadow mode produces no unexplained BitVid differences.
* The original duplicate BitVid governance code can be removed.
* Canonical schema v1 is documented.
* Public SDK methods are documented.
* Consumer integration examples are functional.
---
# 25. Recommended PR Sequence
## Repository PRs
1. Create workspace and CI.
2. Add identifiers and target model.
3. Port BitVid fixtures into conformance tests.
4. Implement authority and capability resolution.
5. Implement policy schema and pure evaluator.
6. Implement canonical v1 codec.
7. Implement BitVid legacy codecs.
8. Add fake transport, signer, storage, and clock.
9. Implement administrative store.
10. Implement trust graph.
11. Implement report store.
12. Implement trusted-mute store.
13. Implement runtime lifecycle.
14. Implement commands.
15. Implement public diagnostics.
16. Publish `0.3.0`.
## BitVid PRs
17. Add package and compatibility facade.
18. Add shadow evaluation.
19. Resolve decision mismatches.
20. Cut over administrative state.
21. Cut over trust and reports.
22. Cut over policy evaluation.
23. Remove duplicate policy from decorator.
24. Remove legacy internal services.
25. Enable external governance by default.
## BitRoad PRs
26. Add governance transport and signer adapters.
27. Add seller, product, storefront, and review target adapters.
28. Add marketplace evaluation.
29. Add product-detail warnings.
30. Add checkout enforcement.
31. Add administrator capability checks.
32. Add seller-dashboard explanations.
33. Add BitRoad consumer contract tests.
## Stabilization PRs
34. Security review.
35. Performance review.
36. Event-schema documentation.
37. Migration documentation.
38. Public API freeze.
39. Publish `1.0.0`.
---
# 26. First Build Milestone
The first meaningful milestone should not be a UI or a complete runtime.
Build this vertical slice:
```text
BitVid fixture events
↓
BitVid legacy codec
↓
normalized governance snapshot
↓
pure evaluator
↓
generic GovernanceDecision
↓
BitVid decision adapter
```
The milestone is successful when the package can take existing BitVid moderation fixtures and produce decisions equivalent to the current implementation without importing BitVid application code.
That establishes the durable core around which transport, storage, commands, shadow mode, and BitRoad integration can be built.