Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/feedthejoe / test/core.test.js |
| Date | Not specified in source |
| Repository | Janady13/feedthejoe |
| Revision | 0e608a2b515a959bf35d2783428766624400ca3c |
| Branch | main |
| Path or archive member | test/core.test.js |
| Original SHA-256 | d8d551b758e71f24951aab3dab9477d43a42e14a3e5c34cf1deaa79aa17ddea8 |
| Git blob SHA | d8039302f6d13077c95ad5b1dd512fd91ea8a52a |
| Reading-copy SHA-256 | d8d551b758e71f24951aab3dab9477d43a42e14a3e5c34cf1deaa79aa17ddea8 |
Recovered source transcript
Download complete source text ↓293 lines · 11.8 KB
import test from 'node:test';
import assert from 'node:assert/strict';
import { mulberry32, betaSample, gammaSample, seedFrom } from '../src/core/rank/random.js';
import { cosine, normalize, emaToward, centroid } from '../src/core/vector/vector.js';
import { completionRatio, weightOf, Signal, estimatedReadSeconds } from '../src/core/signal/signals.js';
import { fatigue, freshness } from '../src/core/rank/score.js';
import { rank, applyEvent, recordImpressions, initialState, DEFAULT_CONFIG } from '../src/core/rank/rank.js';
const DIM = 8;
const NOW = 1757260800000; // fixed clock; never Date.now() in a test
/** Deterministic unit vector pointing in a named "direction". */
function vec(seed) {
const r = mulberry32(seed);
const v = new Float32Array(DIM);
for (let i = 0; i < DIM; i += 1) v[i] = r() * 2 - 1;
return normalize(v);
}
/** Synthetic corpus: 3 topics x 8 items, each topic clustered around a centroid. */
function makeCorpus() {
const topics = ['engineering', 'writing', 'service'];
const items = [];
topics.forEach((topic, t) => {
const base = vec(1000 + t);
for (let i = 0; i < 8; i += 1) {
// Perturb the topic centroid slightly so members are near but not identical.
const jitter = vec(2000 + t * 100 + i);
const e = new Float32Array(DIM);
for (let d = 0; d < DIM; d += 1) e[d] = base[d] * 0.9 + jitter[d] * 0.1;
items.push({
id: `${topic}-${i}`,
topic,
embedding: normalize(e),
publishedMs: NOW - i * 30 * 86400000,
wordCount: 400,
});
}
});
return items;
}
const CORPUS = makeCorpus();
const INDEX = Object.fromEntries(CORPUS.map((i) => [i.id, i]));
// ---------------------------------------------------------------------------
test('PRNG is deterministic and stays in [0,1)', () => {
const a = mulberry32(42);
const b = mulberry32(42);
for (let i = 0; i < 1000; i += 1) {
const x = a();
assert.equal(x, b(), 'same seed must produce same stream');
assert.ok(x >= 0 && x < 1, `out of range: ${x}`);
}
});
test('seedFrom is stable and collision-free across the corpus', () => {
assert.equal(seedFrom('engineering-0'), seedFrom('engineering-0'));
const seeds = new Set(CORPUS.map((i) => seedFrom(i.id)));
assert.equal(seeds.size, CORPUS.length, 'item ids must not collide');
});
test('Gamma draws are positive and mean ~= shape', () => {
const rng = mulberry32(7);
for (const shape of [0.4, 1, 2.5, 9]) {
let sum = 0;
const N = 20000;
for (let i = 0; i < N; i += 1) {
const g = gammaSample(rng, shape);
assert.ok(g > 0, 'gamma must be positive');
sum += g;
}
const mean = sum / N;
assert.ok(Math.abs(mean - shape) < shape * 0.05,
`Gamma(${shape}) mean ${mean.toFixed(3)} should approx ${shape}`);
}
});
test('Beta draws converge to alpha/(alpha+beta)', () => {
const rng = mulberry32(11);
const cases = [[1, 1, 0.5], [8, 2, 0.8], [2, 8, 0.2], [1, 3, 0.25]];
for (const [a, b, expected] of cases) {
let sum = 0;
const N = 20000;
for (let i = 0; i < N; i += 1) {
const x = betaSample(rng, a, b);
assert.ok(x >= 0 && x <= 1, `beta out of range: ${x}`);
sum += x;
}
const mean = sum / N;
assert.ok(Math.abs(mean - expected) < 0.02,
`Beta(${a},${b}) mean ${mean.toFixed(4)} should approx ${expected}`);
}
});
test('wide posterior explores more than a narrow one with the same mean', () => {
const rng = mulberry32(3);
const spread = (a, b) => {
const xs = Array.from({ length: 5000 }, () => betaSample(rng, a, b));
const m = xs.reduce((s, x) => s + x, 0) / xs.length;
return Math.sqrt(xs.reduce((s, x) => s + (x - m) ** 2, 0) / xs.length);
};
// Beta(1,1) and Beta(50,50) share mean 0.5; only the first should explore.
assert.ok(spread(1, 1) > spread(50, 50) * 3,
'an uninformed posterior must produce far wider draws');
});
// ---------------------------------------------------------------------------
test('cosine: identical=1, opposite=-1, zero vector=0', () => {
const v = vec(5);
assert.ok(Math.abs(cosine(v, v) - 1) < 1e-6);
const neg = new Float32Array(v.map((x) => -x));
assert.ok(Math.abs(cosine(v, neg) + 1) < 1e-6);
assert.equal(cosine(v, new Float32Array(DIM)), 0);
});
test('cosine rejects dimension mismatch instead of returning a plausible number', () => {
assert.throws(() => cosine(new Float32Array(4), new Float32Array(8)), RangeError);
});
test('emaToward moves toward a positive target and away from a negative one', () => {
const start = vec(21);
const target = vec(22);
const toward = emaToward(start, target, 0.5, 1);
const away = emaToward(start, target, 0.5, -1);
assert.ok(cosine(toward, target) > cosine(start, target),
'positive weight must increase similarity to the target');
assert.ok(cosine(away, target) < cosine(start, target),
'negative weight must decrease similarity — skips have to actually teach');
});
test('emaToward always returns a unit vector', () => {
let v = vec(31);
for (let i = 0; i < 50; i += 1) {
v = emaToward(v, vec(40 + i), 0.3, i % 3 === 0 ? -1 : 1);
const len = Math.sqrt(v.reduce((s, x) => s + x * x, 0));
assert.ok(Math.abs(len - 1) < 1e-5, `drifted off the unit sphere: ${len}`);
}
});
test('centroid of a cluster is closer to its members than another cluster is', () => {
const eng = CORPUS.filter((i) => i.topic === 'engineering');
const wri = CORPUS.filter((i) => i.topic === 'writing');
const c = normalize(centroid(eng.map((i) => i.embedding)));
const inSim = eng.reduce((s, i) => s + cosine(c, i.embedding), 0) / eng.length;
const outSim = wri.reduce((s, i) => s + cosine(c, i.embedding), 0) / wri.length;
assert.ok(inSim > outSim, 'topic clusters must actually be clusters');
});
// ---------------------------------------------------------------------------
test('completion is a ratio against read time, not raw seconds', () => {
// A 100-word item and a 2000-word item, both dwelled on for 25s.
const short = completionRatio(25, 100);
const long = completionRatio(25, 2000);
assert.ok(short > long, 'the same dwell must mean more on a shorter piece');
assert.equal(completionRatio(9999, 400), 1, 'completion is capped at 1');
assert.equal(completionRatio(0, 400), 0);
assert.equal(completionRatio(-5, 400), 0, 'negative dwell is not evidence');
});
test('a one-line item cannot be completed by a glance', () => {
assert.ok(estimatedReadSeconds(1) >= 3);
assert.ok(completionRatio(0.5, 1) < 0.2);
});
test('signal weights: skip is negative, contact is strongest, unknown is inert', () => {
assert.ok(weightOf({ kind: Signal.SKIP }) < 0);
assert.ok(weightOf({ kind: Signal.CONTACT }) > weightOf({ kind: Signal.COMPLETION, completion: 1 }));
assert.ok(weightOf({ kind: Signal.COMPLETION, completion: 1 }) > weightOf({ kind: Signal.SAVE }));
assert.equal(weightOf({ kind: 'nonsense-from-the-dom' }), 0);
assert.equal(weightOf({ kind: Signal.COMPLETION }), 0, 'completion with no ratio is no evidence');
});
test('fatigue and freshness are bounded and monotonic', () => {
let prev = -1;
for (let n = 0; n < 100; n += 1) {
const f = fatigue(n);
assert.ok(f >= 0 && f < 1);
assert.ok(f > prev);
prev = f;
}
assert.equal(freshness(NOW, NOW, 240), 1);
assert.ok(Math.abs(freshness(NOW - 240 * 86400000, NOW, 240) - 0.5) < 1e-9);
assert.ok(freshness(NOW + 999e9, NOW, 240) <= 1, 'a future date must not exceed 1');
});
// ---------------------------------------------------------------------------
test('rank is deterministic: identical inputs give an identical order', () => {
const s = initialState(DIM);
const opts = { nowMs: NOW, seed: 99, round: 0, limit: 10 };
const a = rank(CORPUS, s, opts).map((r) => r.item.id);
const b = rank(CORPUS, s, opts).map((r) => r.item.id);
assert.deepEqual(a, b);
});
test('rank changes between rounds — the feed is allowed to move', () => {
const s = initialState(DIM);
const a = rank(CORPUS, s, { nowMs: NOW, seed: 99, round: 0, limit: 10 }).map((r) => r.item.id);
const b = rank(CORPUS, s, { nowMs: NOW, seed: 99, round: 1, limit: 10 }).map((r) => r.item.id);
assert.notDeepEqual(a, b);
});
test('rank respects exclude and limit', () => {
const s = initialState(DIM);
const skip = new Set(['engineering-0', 'writing-3']);
const out = rank(CORPUS, s, { nowMs: NOW, seed: 5, limit: 6, exclude: skip });
assert.equal(out.length, 6);
for (const r of out) assert.ok(!skip.has(r.item.id));
});
test('MMR prevents topic collapse even when one topic is strongly preferred', () => {
// Teach the model to love engineering, hard.
let s = initialState(DIM);
for (let i = 0; i < 8; i += 1) {
s = applyEvent(s, { kind: Signal.COMPLETION, itemId: `engineering-${i}`, completion: 1 }, INDEX);
}
const top = rank(CORPUS, s, { nowMs: NOW, seed: 4, limit: 8 });
const topics = new Set(top.map((r) => r.item.topic));
assert.ok(topics.size >= 2,
`a confident model still must not return a single topic; got ${[...topics]}`);
// And it should still lean engineering — diversity must not become randomness.
const engCount = top.filter((r) => r.item.topic === 'engineering').length;
assert.ok(engCount >= 3, `preference must survive diversification; got ${engCount}/8`);
});
test('a skip teaches: repeated skips demote that topic', () => {
let s = initialState(DIM);
const rankOf = (st, topic) => {
const out = rank(CORPUS, st, { nowMs: NOW, seed: 8, round: 0 });
return out.findIndex((r) => r.item.topic === topic);
};
const before = rankOf(s, 'service');
for (let i = 0; i < 8; i += 1) {
s = applyEvent(s, { kind: Signal.SKIP, itemId: `service-${i}` }, INDEX);
}
const after = rankOf(s, 'service');
assert.ok(after > before,
`skipped topic must sink: first service item went ${before} -> ${after}`);
});
test('impressions are not feedback — recording them does not move the posterior', () => {
const s0 = initialState(DIM);
const s1 = recordImpressions(s0, ['engineering-0', 'engineering-0', 'writing-1']);
assert.deepEqual(s1.topics, {}, 'showing an item must never look like approval');
assert.equal(s1.impressions['engineering-0'], 2);
assert.equal(s1.impressions['writing-1'], 1);
});
test('state updates are immutable', () => {
const s0 = initialState(DIM);
const snapshot = JSON.stringify({ t: s0.topics, i: s0.impressions });
applyEvent(s0, { kind: Signal.COMPLETION, itemId: 'writing-0', completion: 1 }, INDEX);
recordImpressions(s0, ['writing-0']);
assert.equal(JSON.stringify({ t: s0.topics, i: s0.impressions }), snapshot,
'original state must be untouched');
});
test('applyEvent ignores unknown items and inert signals', () => {
const s = initialState(DIM);
assert.equal(applyEvent(s, { kind: Signal.COMPLETION, itemId: 'does-not-exist', completion: 1 }, INDEX), s);
assert.equal(applyEvent(s, { kind: 'bogus', itemId: 'writing-0' }, INDEX), s);
});
test('cold start ladder: every item surfaces within a bounded number of rounds', () => {
// The promotion ladder's promise is coverage — no item may be starved.
let s = initialState(DIM);
const seen = new Set();
for (let round = 0; round < 12; round += 1) {
const page = rank(CORPUS, s, { nowMs: NOW, seed: 77, round, limit: 6 });
const ids = page.map((r) => r.item.id);
ids.forEach((id) => seen.add(id));
s = recordImpressions(s, ids);
}
assert.equal(seen.size, CORPUS.length,
`every one of ${CORPUS.length} items must appear; saw ${seen.size}`);
});
test('score parts are exposed for inspection and are finite', () => {
const s = initialState(DIM);
for (const r of rank(CORPUS, s, { nowMs: NOW, seed: 2, limit: 5 })) {
for (const [k, v] of Object.entries(r.parts)) {
if (typeof v === 'number') assert.ok(Number.isFinite(v), `${k} was ${v}`);
}
assert.ok(Number.isFinite(r.score));
}
});
test('config is frozen — tuning must be explicit, not accidental', () => {
assert.throws(() => { DEFAULT_CONFIG.weights.semantic = 99; }, TypeError);
});