Files
bitgate/packages/core/test/policy.test.js
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

319 lines
10 KiB
JavaScript

import { describe, expect, it } from "vitest";
import {
INTERACTION_LADDER,
NEUTRAL_POLICY,
RANKING_LADDER,
TRANSACTION_LADDER,
VISIBILITY_LADDER,
applyEffects,
applyThresholds,
composeDecisions,
createNeutralDecision,
createPolicyDefinition,
effectSeverity,
maxEffect,
normalizeCategoryThresholds,
normalizeDimensionEffects,
normalizePolicyDefinition,
resolveProfile,
resolveThresholds,
} from "../src/policy.js";
import { createReason } from "../src/reasons.js";
describe("effect ladders", () => {
it("orders visibility from permissive to severe", () => {
expect(VISIBILITY_LADDER).toEqual(["allow", "warn", "restrict", "hide", "deny"]);
});
it("orders the remaining dimensions", () => {
expect(RANKING_LADDER).toEqual(["normal", "downrank"]);
expect(INTERACTION_LADDER).toEqual(["allow", "require-explicit-action", "deny"]);
expect(TRANSACTION_LADDER).toEqual(["allow", "require-review", "deny"]);
});
it("ranks effects by severity", () => {
expect(effectSeverity("visibility", "allow")).toBeLessThan(effectSeverity("visibility", "hide"));
expect(effectSeverity("visibility", "hide")).toBeLessThan(effectSeverity("visibility", "deny"));
});
it("returns -1 for effects outside the ladder", () => {
expect(effectSeverity("visibility", "banish")).toBe(-1);
});
it("throws for an unknown dimension", () => {
expect(() => effectSeverity(/** @type {any} */ ("vibes"), "allow")).toThrow(/Unknown decision dimension/);
});
it("keeps the more severe effect", () => {
expect(maxEffect("visibility", "allow", "hide")).toBe("hide");
expect(maxEffect("visibility", "deny", "warn")).toBe("deny");
expect(maxEffect("interaction", "allow", "require-explicit-action")).toBe("require-explicit-action");
});
it("falls back to the valid effect when one side is unknown", () => {
expect(maxEffect("visibility", "nonsense", "warn")).toBe("warn");
expect(maxEffect("visibility", "warn", "nonsense")).toBe("warn");
});
});
describe("normalizeDimensionEffects", () => {
it("passes valid effects through", () => {
expect(normalizeDimensionEffects({ visibility: "hide", interaction: "deny" })).toEqual({
visibility: "hide",
interaction: "deny",
});
});
it("rejects an effect from the wrong ladder", () => {
expect(() => normalizeDimensionEffects({ interaction: /** @type {any} */ ("hide") })).toThrow(
/invalid interaction effect/,
);
});
it("returns an empty object for missing input", () => {
expect(normalizeDimensionEffects(/** @type {any} */ (undefined))).toEqual({});
});
});
describe("normalizeCategoryThresholds", () => {
it("lowercases categories and floors values", () => {
expect(normalizeCategoryThresholds({ SPAM: { hide: 5.7 } })).toEqual({ spam: { hide: 5 } });
});
it("drops non-numeric gates", () => {
expect(normalizeCategoryThresholds({ spam: { hide: /** @type {any} */ ("many") } })).toEqual({
spam: {},
});
});
it("rejects negative thresholds", () => {
expect(() => normalizeCategoryThresholds({ spam: { hide: -1 } })).toThrow(/must be >= 0/);
});
});
describe("normalizePolicyDefinition", () => {
const valid = {
id: "app",
version: "1.0.0",
profiles: { feed: { name: "feed" } },
};
it("normalizes a minimal policy", () => {
const policy = normalizePolicyDefinition(valid);
expect(policy.id).toBe("app");
expect(policy.defaultProfile).toBe("feed");
expect(policy.profiles.feed.allowViewerOverride).toBe(true);
});
it("requires an id and a version", () => {
expect(() => normalizePolicyDefinition({ ...valid, id: "" })).toThrow(/non-empty id/);
expect(() => normalizePolicyDefinition({ ...valid, version: "" })).toThrow(/version string/);
});
it("requires at least one profile", () => {
expect(() => normalizePolicyDefinition({ ...valid, profiles: {} })).toThrow(/at least one profile/);
});
it("rejects a default profile that does not exist", () => {
expect(() => normalizePolicyDefinition({ ...valid, defaultProfile: "nope" })).toThrow(
/is not defined/,
);
});
it("names a profile from its map key when the profile omits a name", () => {
const policy = normalizePolicyDefinition({
...valid,
profiles: { checkout: /** @type {any} */ ({}) },
});
expect(policy.profiles.checkout.name).toBe("checkout");
});
it("defaults the hide ceiling when bypassHide is set", () => {
const policy = normalizePolicyDefinition({
...valid,
profiles: { feed: { name: "feed", bypassHide: true } },
});
expect(policy.profiles.feed.bypassHideCeiling).toBe("restrict");
});
it("rejects a negative mute window", () => {
expect(() =>
normalizePolicyDefinition({
...valid,
profiles: { feed: { name: "feed", muteWindowSeconds: -5 } },
}),
).toThrow(/muteWindowSeconds/);
});
it("is exposed as createPolicyDefinition", () => {
expect(createPolicyDefinition(valid).id).toBe("app");
});
});
describe("resolveProfile", () => {
const policy = createPolicyDefinition({
id: "app",
version: "1.0.0",
defaultProfile: "feed",
profiles: { feed: { name: "feed" }, checkout: { name: "checkout" } },
});
it("returns the requested profile", () => {
expect(resolveProfile(policy, { surface: "x", policyProfile: "checkout" }).name).toBe("checkout");
});
it("falls back to the default profile", () => {
expect(resolveProfile(policy, { surface: "x" }).name).toBe("feed");
});
it("throws for an unknown profile rather than silently falling back", () => {
expect(() => resolveProfile(policy, { surface: "x", policyProfile: "ghost" })).toThrow(
/Unknown policy profile/,
);
});
});
describe("resolveThresholds", () => {
const table = { spam: { hide: 5 }, default: { restrict: 3 } };
it("prefers an exact category match", () => {
expect(resolveThresholds(table, "spam")).toEqual({ hide: 5 });
});
it("falls back to the default entry", () => {
expect(resolveThresholds(table, "nudity")).toEqual({ restrict: 3 });
});
it("returns an empty object when nothing matches", () => {
expect(resolveThresholds({ spam: { hide: 5 } }, "nudity")).toEqual({});
expect(resolveThresholds(undefined, "spam")).toEqual({});
});
});
describe("applyThresholds", () => {
it("fires gates at or above the threshold", () => {
const { effects } = applyThresholds(3, { restrict: 3 });
expect(effects.visibility).toBe("restrict");
});
it("does not fire below the threshold", () => {
const { effects, firedGates } = applyThresholds(2, { restrict: 3 });
expect(effects).toEqual({});
expect(firedGates).toEqual([]);
});
it("keeps the most severe gate when several fire", () => {
const { effects } = applyThresholds(10, { warn: 1, restrict: 3, hide: 5 });
expect(effects.visibility).toBe("hide");
});
it("treats a zero threshold as disabled rather than always-on", () => {
const { effects } = applyThresholds(5, { hide: 0 });
expect(effects).toEqual({});
});
it("ignores non-positive counts", () => {
expect(applyThresholds(0, { warn: 1 }).effects).toEqual({});
expect(applyThresholds(Number.NaN, { warn: 1 }).effects).toEqual({});
});
it("maps gates onto their own dimensions", () => {
const { effects } = applyThresholds(5, {
downrank: 1,
restrict: 2,
requireExplicitAction: 3,
transactionDeny: 4,
});
expect(effects).toEqual({
ranking: "downrank",
visibility: "restrict",
interaction: "require-explicit-action",
transaction: "deny",
});
});
});
describe("applyEffects", () => {
it("escalates but never softens", () => {
const decision = createNeutralDecision();
applyEffects(decision, { visibility: "hide" });
applyEffects(decision, { visibility: "warn" });
expect(decision.visibility.effect).toBe("hide");
});
it("accumulates downrank weight", () => {
const decision = createNeutralDecision();
applyEffects(decision, { ranking: "downrank" });
applyEffects(decision, { ranking: "downrank" });
expect(decision.ranking.weight).toBe(2);
expect(decision.ranking.effect).toBe("downrank");
});
it("creates the transaction dimension on demand", () => {
const decision = createNeutralDecision();
expect(decision.transaction).toBeUndefined();
applyEffects(decision, { transaction: "deny" });
expect(decision.transaction).toEqual({ effect: "deny" });
});
it("deduplicates reasons", () => {
const decision = createNeutralDecision();
applyEffects(decision, {}, [createReason("viewer-block"), createReason("viewer-block")]);
expect(decision.reasons).toHaveLength(1);
});
});
describe("composeDecisions", () => {
const withVisibility = (effect, weight = 0) => {
const decision = createNeutralDecision();
decision.visibility.effect = effect;
decision.ranking.weight = weight;
return decision;
};
it("returns a neutral decision for an empty list", () => {
const composed = composeDecisions([]);
expect(composed.visibility.effect).toBe("allow");
});
it("keeps the most severe effect", () => {
expect(composeDecisions([withVisibility("warn"), withVisibility("hide")]).visibility.effect).toBe(
"hide",
);
});
it("is order-independent", () => {
const a = composeDecisions([withVisibility("warn"), withVisibility("hide")]);
const b = composeDecisions([withVisibility("hide"), withVisibility("warn")]);
expect(a.visibility.effect).toBe(b.visibility.effect);
});
it("sums ranking weight", () => {
expect(composeDecisions([withVisibility("allow", 2), withVisibility("allow", 3)]).ranking.weight).toBe(5);
});
it("makes a decision non-overridable if any input was", () => {
const locked = createNeutralDecision();
locked.visibility.overridable = false;
expect(composeDecisions([createNeutralDecision(), locked]).visibility.overridable).toBe(false);
});
it("does not mutate its inputs", () => {
const first = withVisibility("warn");
composeDecisions([first, withVisibility("deny")]);
expect(first.visibility.effect).toBe("warn");
});
});
describe("NEUTRAL_POLICY", () => {
it("enforces administrative denial", () => {
expect(NEUTRAL_POLICY.profiles.default.administrativeDeny?.visibility).toBe("hide");
});
it("applies no trust thresholds of its own", () => {
expect(NEUTRAL_POLICY.profiles.default.reports).toEqual({});
expect(NEUTRAL_POLICY.profiles.default.mutes).toEqual({});
});
});