import { describe, test } from "node:test"; import assert from "node:assert/strict"; import { KORTFORM_WEIGHTS, LONG_FORM_WEIGHTS, composite, band, triage, requiredDimensions, scoreEnvelope, } from "../src/score.js"; const r1 = (x: number) => Math.round(x * 10) / 10; const sum = (o: Record) => Object.values(o).reduce((a, b) => a + b, 0); describe("trends scorer (RE-R1 / B2)", () => { // SSOT: references/trend-scoring-modes.md — weights, band thresholds, and action // strings are pinned here so silent drift in any of them fails loudly. describe("pinned weights (SSOT)", () => { test("kortform weights match the SSOT and sum to 1.0", () => { assert.equal(KORTFORM_WEIGHTS.pillar, 0.3); assert.equal(KORTFORM_WEIGHTS.audience, 0.25); assert.equal(KORTFORM_WEIGHTS.timing, 0.2); assert.equal(KORTFORM_WEIGHTS.angle, 0.15); assert.equal(KORTFORM_WEIGHTS.authority, 0.1); assert.equal(r1(sum(KORTFORM_WEIGHTS)), 1.0); }); test("long-form weights match the SSOT and sum to 1.0", () => { assert.equal(LONG_FORM_WEIGHTS.pillar, 0.3); assert.equal(LONG_FORM_WEIGHTS.depth, 0.25); assert.equal(LONG_FORM_WEIGHTS.angle, 0.2); assert.equal(LONG_FORM_WEIGHTS.authority, 0.15); assert.equal(LONG_FORM_WEIGHTS.currency, 0.1); assert.equal(r1(sum(LONG_FORM_WEIGHTS)), 1.0); }); }); describe("composite", () => { test("all-tens -> exactly 10.0 (proves Sigma weights = 1.0) for both modes", () => { const kort = { pillar: 10, audience: 10, timing: 10, angle: 10, authority: 10 }; const long = { pillar: 10, depth: 10, angle: 10, authority: 10, currency: 10 }; assert.equal(composite(kort, "kortform"), 10.0); assert.equal(composite(long, "long-form"), 10.0); }); test("asymmetric golden vector {10,8,6,4,2} in dimension order -> 7.0 for both modes", () => { // 10*.30 + 8*.25 + 6*.20 + 4*.15 + 2*.10 = 3.0 + 2.0 + 1.2 + 0.6 + 0.2 = 7.0 const kort = { pillar: 10, audience: 8, timing: 6, angle: 4, authority: 2 }; const long = { pillar: 10, depth: 8, angle: 6, authority: 4, currency: 2 }; assert.equal(composite(kort, "kortform"), 7.0); assert.equal(composite(long, "long-form"), 7.0); }); test("a dimension below 1 throws", () => { const kort = { pillar: 0, audience: 5, timing: 5, angle: 5, authority: 5 }; assert.throws(() => composite(kort, "kortform"), /range|1.*10|dimension/i); }); test("a dimension above 10 throws", () => { const kort = { pillar: 11, audience: 5, timing: 5, angle: 5, authority: 5 }; assert.throws(() => composite(kort, "kortform")); }); test("a missing dimension throws", () => { const kort = { pillar: 5, audience: 5, timing: 5, angle: 5 }; // authority missing assert.throws(() => composite(kort as Record, "kortform")); }); }); describe("band — boundaries + exact SSOT action strings", () => { test("8.0 -> Immediate", () => { const b = band(8.0); assert.equal(b.priority, "Immediate"); assert.equal(b.kortformAction, "Draft within 24h"); assert.equal(b.longformAction, "Promote to the edition backlog now"); }); test("6.0 -> High", () => { const b = band(6.0); assert.equal(b.priority, "High"); assert.equal(b.kortformAction, "Publish within 48–72h"); assert.equal(b.longformAction, "Strong edition candidate — schedule it"); }); test("4.0 -> Medium", () => { const b = band(4.0); assert.equal(b.priority, "Medium"); assert.equal(b.kortformAction, "Add to this week's calendar"); assert.equal(b.longformAction, "Hold as a backlog candidate, revisit"); }); test("2.0 -> Low", () => { const b = band(2.0); assert.equal(b.priority, "Low"); assert.equal(b.kortformAction, "Note, skip for now"); assert.equal(b.longformAction, "Park unless the angle sharpens"); }); test("below 2.0 -> Skip", () => { const b = band(1.9); assert.equal(b.priority, "Skip"); assert.equal(b.kortformAction, "Off positioning"); assert.equal(b.longformAction, "Off positioning"); }); test("just below a boundary lands in the lower band (7.9->High, 5.9->Medium, 3.9->Low)", () => { assert.equal(band(7.9).priority, "High"); assert.equal(band(5.9).priority, "Medium"); assert.equal(band(3.9).priority, "Low"); }); }); describe("triage", () => { const candidates = [ { id: "low", scores: { pillar: 2, audience: 2, timing: 2, angle: 2, authority: 2 } }, // 2.0 { id: "high", scores: { pillar: 8, audience: 8, timing: 8, angle: 8, authority: 8 } }, // 8.0 { id: "mid", scores: { pillar: 5, audience: 5, timing: 5, angle: 5, authority: 5 } }, // 5.0 { id: "below", scores: { pillar: 3, audience: 3, timing: 3, angle: 3, authority: 3 } }, // 3.0 ]; test("keeps composite >= threshold, drops below, ranks kept composite-desc, annotates", () => { const { kept, dropped } = triage(candidates, { mode: "kortform", threshold: 4.0 }); assert.deepEqual( kept.map((k) => k.id), ["high", "mid"], ); // 8.0, 5.0 desc; both >= 4.0 assert.deepEqual( dropped.map((d) => d.id).sort(), ["below", "low"], ); // 3.0, 2.0 < 4.0 assert.equal(kept[0].composite, 8.0); assert.equal(kept[0].band.priority, "Immediate"); assert.equal(kept[1].composite, 5.0); assert.equal(kept[1].band.priority, "Medium"); }); test("threshold is inclusive (composite == threshold is kept)", () => { const { kept } = triage(candidates, { mode: "kortform", threshold: 5.0 }); assert.deepEqual( kept.map((k) => k.id), ["high", "mid"], ); // mid == 5.0 kept }); test("an empty candidate list -> empty kept/dropped", () => { const { kept, dropped } = triage([], { mode: "kortform", threshold: 4.0 }); assert.deepEqual(kept, []); assert.deepEqual(dropped, []); }); }); describe("requiredDimensions (RE-R3a / SC1)", () => { test("kortform -> the five keys in SSOT weight order", () => { assert.deepEqual(requiredDimensions("kortform"), ["pillar", "audience", "timing", "angle", "authority"]); }); test("long-form -> the five keys in SSOT weight order", () => { assert.deepEqual(requiredDimensions("long-form"), ["pillar", "depth", "angle", "authority", "currency"]); }); test("order is pinned to the SSOT weight literals (a silent reorder fails)", () => { assert.deepEqual(requiredDimensions("kortform"), Object.keys(KORTFORM_WEIGHTS)); assert.deepEqual(requiredDimensions("long-form"), Object.keys(LONG_FORM_WEIGHTS)); }); }); describe("scoreEnvelope (RE-R3a / SC1)", () => { test("composes composite()+band() — composite/priority equal the existing functions (one owner)", () => { const dims = { pillar: 8, audience: 7, timing: 9, angle: 6, authority: 5 }; const env = scoreEnvelope("kortform", dims); assert.equal(env.mode, "kortform"); assert.deepEqual(env.dimensions, dims); assert.equal(env.composite, composite(dims, "kortform")); assert.equal(env.priority, band(composite(dims, "kortform")).priority); }); test("long-form envelope composes the long-form composite/band", () => { const dims = { pillar: 9, depth: 8, angle: 7, authority: 6, currency: 5 }; const env = scoreEnvelope("long-form", dims); assert.equal(env.composite, composite(dims, "long-form")); assert.equal(env.priority, band(composite(dims, "long-form")).priority); }); test("a bad dimension makes scoreEnvelope throw (via composite — defense-in-depth contract)", () => { const dims = { pillar: 8, audience: 7, timing: 99, angle: 6, authority: 5 }; assert.throws(() => scoreEnvelope("kortform", dims)); }); }); });