Files
bitgate/tests/conformance/bitvid-fixtures.test.js
T
thePR0M3TH3AN 4f689184e2 feat(core): rebuild governance core to the plan's decision model
The evaluator was a skeleton with invented thresholds (5/3/10/5) and two
unimplemented branches. Rebuild it against the migration plan's spec and the
behavior characterized from the pinned reference commit.

Core:
- four independent decision dimensions (ranking, visibility, interaction,
  transaction) with severity ladders and max-merge composition
- stable reason identifiers replacing free-text strings
- structured evidence, redacted unless a profile opts in
- administrative-state reduction with capability filtering at merge time, so
  revoking a role drops that actor's entries immediately
- protected actors stripped from every denial set
- snapshot fingerprints for cache invalidation
- generic policy engine: applications supply profiles and category thresholds;
  the core carries none of its own

Characterization:
- 34 generated fixtures covering every behavior the plan's Phase 0 requires
- conformance suite that actually evaluates them, replacing a placeholder that
  asserted a list's length
- reference thresholds (3/3/20/5, 60-day mute window) live in bitvid-compat as
  an application profile, not as engine defaults

Fixes found while building:
- reduceAdminState accepted malformed target identifiers, because getTargetKey
  formats anything it is given
- community-user-deny fired for any contributor rather than only for
  community-curated sources

273 tests pass; typecheck and the reference-import guard are clean.
2026-08-09 17:33:41 -04:00

85 lines
3.3 KiB
JavaScript

// Conformance suite for the characterization corpus.
//
// Every fixture under fixtures/bitvid/cases is evaluated against the reference
// application profile. A change to a threshold, a precedence rule, or an effect
// ladder must show up here as a failing case.
import { readdirSync, readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
import { runConformanceCase } from "@nostr-governance/testing/conformance";
import { REFERENCE_POLICY } from "@nostr-governance/bitvid-compat/profile";
const ROOT = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
const CASES_DIR = join(ROOT, "fixtures", "bitvid", "cases");
const CASE_INDEX = join(ROOT, "fixtures", "bitvid", "characterization-cases.json");
const caseFiles = readdirSync(CASES_DIR).filter((name) => name.endsWith(".json")).sort();
const fixtures = caseFiles.map((name) => JSON.parse(readFileSync(join(CASES_DIR, name), "utf8")));
describe("characterization corpus", () => {
it("has fixtures on disk", () => {
expect(fixtures.length).toBeGreaterThanOrEqual(15);
});
it("index matches the files on disk", () => {
const index = JSON.parse(readFileSync(CASE_INDEX, "utf8"));
expect([...index].sort()).toEqual(fixtures.map((fixture) => fixture.name).sort());
});
it("covers every behavior the migration plan requires", () => {
const names = new Set(fixtures.map((fixture) => fixture.name));
const required = [
"trusted-report-threshold-reached",
"duplicate-reporter-dedupe",
"blocked-reporter-ignored",
"trusted-mute-below-threshold",
"trusted-mute-at-threshold",
"expired-trusted-mute",
"personal-block-precedence",
"admin-user-deny",
"admin-event-deny",
"community-blacklist-merge",
"moderator-trust-seed",
"viewer-override-softens-hide",
"author-override",
"home-hide-bypass",
"cache-fallback-effective",
];
for (const name of required) {
expect(names, `missing required characterization case: ${name}`).toContain(name);
}
});
});
describe.each(fixtures.map((fixture) => [fixture.name, fixture]))("%s", (_name, fixture) => {
it(fixture.description, () => {
const { passed, mismatches, decision } = runConformanceCase(fixture, REFERENCE_POLICY);
expect(passed, `${fixture.behavior}\n ${mismatches.join("\n ")}`).toBe(true);
expect(decision.policyProfile).toBe(fixture.profile);
expect(decision.policyVersion).toBe(REFERENCE_POLICY.version);
expect(decision.snapshotFingerprint).toMatch(/^[0-9a-f]{16}$/);
});
});
describe("evaluation determinism", () => {
it("produces identical decisions for identical snapshots", () => {
for (const fixture of fixtures) {
const first = runConformanceCase(fixture, REFERENCE_POLICY).decision;
const second = runConformanceCase(fixture, REFERENCE_POLICY).decision;
expect(second).toEqual(first);
expect(second.snapshotFingerprint).toBe(first.snapshotFingerprint);
}
});
it("does not mutate fixture inputs", () => {
for (const fixture of fixtures) {
const before = JSON.stringify(fixture);
runConformanceCase(fixture, REFERENCE_POLICY);
expect(JSON.stringify(fixture)).toBe(before);
}
});
});