Several contracts existed and were tested in isolation while nothing actually
used them. Reported as complete previously; this corrects that.
- storage was injected and never referenced. Adds persist/hydrate, hydration
before querying relays, and last-known-good state with a stale flag when a
relay is unreachable, which is what makes the characterized cache-fallback
behavior real rather than reduction-level only
- signature verification existed as a tested helper the load path never called.
Now applied through an injected verifier before state becomes authoritative,
with rejection counts and an enabled/disabled readout in diagnostics
- trusted mute lists had no subscription flow, so the store never populated in
a real deployment. Subscribes by author, chunked
- community source references decoded but were never resolved. Curator lists
are now fetched and merged with a source marker, still capability-checked
- root-published policy was announced and discarded. Now applied, accepted only
from the root, and a malformed document leaves the working policy intact
- adds import/export and capability queries
Two design corrections found while wiring:
- the cache key hashed the entire roster, so it rotated whenever a moderator
was added and the cache was discarded. Now derived from root identity alone.
- the root administrator is a constructor option: it is deployment config, and
hydration could not otherwise find its own cache, since the key derives from
the very fingerprint the cache would have supplied.
634 tests; lint, typecheck, and the declaration build clean.
Stores (Phase 4): admin, trust graph, reports, trusted mutes, policy, and
overrides. Each owns one slice of state and emits only when effective state
changes, so a consumer can treat every emission as a real invalidation.
- report storage is keyed target -> reporter -> category, making deduplication
structural: relays redeliver constantly and a redelivery must not inflate a count
- contribution lists replace by (actor, kind) and ignore out-of-order older
documents, so a late delivery cannot resurrect removed entries
- mute lists prune against an injected clock
- viewer switching clears blocks, mutes, and overrides but keeps operator seeds,
which are configuration rather than viewer data
Runtime: event routing, chunked report subscriptions (200 per filter, not one
per target), viewer lifecycle, evaluation, diagnostics, idempotent teardown.
Transport, signer, and storage are injected; in-memory doubles ship for tests.
Commands (Phase 5): every mutation checks capability locally before the signer
is invoked, so an unauthorized actor cannot produce a signed event at all.
Protected actors are refused at the command boundary as well as during
reduction. Partial relay acceptance succeeds while keeping failures visible.
Also fixes the type build: every package's "types" field pointed at a path the
build never produced, so consumers got no types at all. Declarations now emit
per package and resolve.
103 runtime tests; 505 total.