Files
bitgate/docs/checkpoints.md
thePR0M3TH3AN adeba151b8 feat: rename to BitGate and close the drop-in gap
Renames the project and makes it as easy to adopt as BitLogin, which was the
stated bar and which it did not previously meet.

Rename (ADR 0005): @nostr-governance/* -> @bitgate/*, governance-* elements ->
bitgate-*, createGovernanceRuntime -> createBitGate. "Governance" reads as DAO
voting to this audience and named a category rather than a product; BitGate
names the benefit and joins the bit- family that BitVid and BitRoad compose
with. Domain types keep their names — the product is BitGate, the subject
matter is still governance. The migration plan is left as written; this ADR
records the change rather than rewriting history.

Drop-in distribution (ADR 0006): adopting BitGate meant supplying a transport,
authoring a policy, and wiring every element in JavaScript. Now:

- createRelayTransport(urls) — WebSocket transport with reconnection, backoff,
  subscription replay, and cross-relay dedupe
- policy presets (social, commerce, admin-only) addressable by name; the engine
  still carries no thresholds of its own
- <bitgate-provider> — configuration in markup, with descendants finding the
  runtime through a bubbling context event rather than DOM walking, which
  breaks across shadow boundaries
- npm run build:widget — a self-contained dist/bitgate.js

That last one came from running it in a browser rather than from a test. Bare
specifiers resolve in Node and vitest but not in a browser, so the widget
source worked everywhere except a plain static page — the one place it exists
to serve. The bundle is not committed: consumers build from reviewed source.

Also found by running it: the provider's ready event fires during element
upgrade, before a page that defines elements after parsing can attach a
listener, so it now exposes `ready` as a promise too.

Four bugs fixed along the way, three found by new tests and one by the browser:
admin state stayed silent when a roster change altered capabilities but no
denials; the relay transport sent every subscription twice on connect; the
commerce preset computed a meaningless visibility verdict at checkout and could
hide a listing from its own seller; <bitgate-status> threw on an unusable
decision.

759 tests; lint, typecheck, and both builds clean.
2026-08-09 19:58:45 -04:00

175 lines
7.7 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.
# Checkpoints
Scope note: this repository is the SDK. Migration-plan Phases 6–11 (BitVid
shadow mode, cutovers, and duplicate removal) modify the consumer repositories
and are tracked there, not here.
## Checkpoint 0 — Repo skeleton (completed)
Delivered: npm workspaces monorepo, Node 22 + ESM, Vitest, JSDoc typecheck,
GitHub Actions CI, reference import guard, provenance docs.
Later additions: GPL-3.0-or-later `LICENSE`, `CHANGELOG.md`, architecture
decision records under `docs/adr/`, and a working per-package type build. The
`types` fields previously pointed at paths the build never produced, so
consumers received no declarations; declarations now emit into each package.
## Checkpoint 1 — Characterization corpus (completed)
Delivered:
- 34 fixtures under `fixtures/bitvid/cases/`, generated by
`scripts/build-characterization-corpus.mjs`
- conformance harness (`packages/testing/src/conformance.js`) that builds a
snapshot, evaluates it, and diffs against a partial expectation
- conformance suite (`tests/conformance/bitvid-fixtures.test.js`) asserting
every required behavior, determinism, and input immutability
Characterized values, read from the pinned reference commit and cross-checked
against the migration plan's baseline section:
```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 live in `@bitgate/bitvid-compat` as one application's profile,
not as engine defaults.
Provenance: fixtures are authored from the reference source and its documented
configuration, not captured from a live relay. They pin the behavior the
extraction must reproduce; they are not a recording of production traffic.
## Checkpoint 2 — Pure core (completed)
Delivered: identifiers, targets, authority, administrative-state reduction,
reasons, evidence, policy engine, fingerprints, evaluator, adapter contract.
Acceptance:
- identical snapshots produce identical decisions (asserted per fixture)
- evaluation performs no I/O and reads an injected clock
- evaluation mutates no input (asserted per fixture)
- the core imports no browser globals and has no dependencies
- the core contains no application-specific terms or thresholds
## Checkpoint 3 — Nostr codecs (completed)
Delivered: bech32/NIP-19 (verified against the NIP-19 test vector), canonical v1
on `kind:30078`, NIP-56 reports, NIP-51 mute lists, legacy administrative lists
covering all five migration stages, replaceable selection with a deterministic
same-timestamp tiebreak, injected signature verification.
## Checkpoint 4 — Runtime stores (completed)
Delivered: `GovernanceAdminStore`, `TrustGraphStore`, `ReportStore`,
`TrustedMuteStore`, `PolicyStore`, `OverrideStore`, `GovernanceRuntime`.
Acceptance: injected transport, storage, and clock; change-only emission; viewer
switching clears viewer-scoped state while keeping operator seeds; subscriptions
close on destroy; report subscriptions are chunked (200 per filter) rather than
opened per target; author evidence is queryable in batches; expired mute lists
prune against the injected clock.
### Correction
An earlier revision of this file claimed storage acceptance that was not met:
storage was injected and then never used, so nothing persisted or hydrated and
the characterized cache-fallback behavior existed only at the reduction level.
Closed in Checkpoint 8.
## Checkpoint 5 — Public commands (completed)
Delivered: contribution, role, policy, community-source, report, and override
commands with stable error codes.
Acceptance: every command checks capability locally before the signer is
invoked, so an unauthorized actor cannot produce a signed mutation; revoked
actors' contributions stop affecting effective state; protected actors are
refused at the command boundary; first relay acceptance completes the command
while remaining relay results stay observable.
## Checkpoint 6 — Reusability proof (completed)
Delivered: `examples/commerce`, a marketplace built entirely on the public API,
covering the ten proof-of-fit behaviors the migration plan requires — including
that no core change was needed. Plus `README.md`, `docs/integration-guide.md`,
and `examples/commerce/README.md`.
## Checkpoint 7 — Performance and security fixtures (completed)
Delivered:
- `tests/performance/large-feed.test.js` — 5,000 targets, 500 authors, 100
trusted muters per author, multiple report categories and administrative
contributors, viewer switching, and roster changes
- `tests/security/requirements.test.js` — one case per enumerated security
requirement testable at this layer
Acceptance:
- `evaluateMany(5,000)` performs no network access
- report subscriptions are chunked, never one per card
- updating one report invalidates only that target's decisions
- updating one author's mute state invalidates only that author's targets
- changing policy, roster, or viewer invalidates everything
- destroy leaves no subscriptions or cached decisions
This fixture found a real defect: evaluation was quadratic in state size,
because the snapshot and its fingerprint were rebuilt per target. A
5,000-target pass took ~47 seconds. After memoizing both, the same pass takes
~85ms cold and ~6ms warm.
Requirements 15 and 16 (never export signer secrets, avoid shared moderator
keys) are properties of the injected signer and of operational practice rather
than of this code; the root-authorized contributor model is what removes the
need for a shared moderator key.
## Checkpoint 8 — Runtime wiring (completed)
Closes the gaps between interfaces that existed and pipelines that used them.
Delivered:
- **Storage**: `persist()` / `hydrate()`, hydrate-before-query on load, and
last-known-good state retained with a `stale` flag when relays fail. Cache
keys are namespaced by root identity — not by the full roster, which would
rotate the key every time a moderator was added.
- **Signature verification** wired into the load path through an injected
verifier, with rejected counts in diagnostics and an explicit
`signatureVerification: enabled|disabled` readout.
- **Trusted mute-list subscriptions** by author, chunked. Without this the
trusted-mute store never populated in a real deployment.
- **Community source resolution**: curator lists are fetched and merged with a
source marker, still subject to the curator's capabilities.
- **Root policy application**: policy documents are now applied rather than
merely announced, accepted only from the root, and a malformed document
leaves the working policy in place.
- **Import/export** (§10.14) exporting contributions rather than conclusions,
so an import re-derives effective state against the importing roster.
- **Capability queries** (§10.8): `can()`, `capabilitiesOf()`,
`viewerCapabilities()`.
Design note: the root administrator is now a constructor option, because it is
deployment configuration rather than discovered state. Hydration could not
otherwise find its own cache — the key derives from the root fingerprint the
cache itself would have had to supply.
## Status
CI gates green: reference guard, typecheck, 634 tests, per-package type build.
Typecheck and the declaration build both pass from a cold checkout with no
`dist/` present.
## Not done here
Migration-plan Phases 6–11 operate on BitVid and BitRoad:
- Phase 6 — BitVid compatibility facade and shadow mode
- Phase 7 — cut over BitVid administrative state
- Phase 8 — cut over BitVid reports and trust
- Phase 9 — cut over BitVid policy
- Phase 10 — validate through BitRoad itself
- Phase 11 — remove duplicated BitVid logic
The commerce example stands in for Phase 10's API-shape validation without
touching the BitRoad repository.