Files
diariet/src/engine.test.ts

126 lines
5.1 KiB
TypeScript
Raw Normal View History

Initial commit: Diariet A bureaucratic horror game — five shifts processing incoming tips and incident reports for a municipal office that officially handles nuisance complaints and unofficially exists to keep Djupet's cult off the front page. Route each report: dismiss, file as known, flag for follow-up, or escalate and lose visibility into what happens next. Guidelines accumulate and contradict across shifts, same shape as Retur's regulation stack. Directly descended from Retur's engine (routeLetter/nextDay -> routeReport/nextShift, same 4-route-per-item structure) but with one real mechanical difference: escalating always costs Insyn (insight/ notice), whether or not it was the correct call — being right doesn't make you invisible. Several reports cite real events from Djupet's own event pool (the bleeding IKEA LACK table, Göran added to the cult's Discord by accident, the Värnhemstorget pigeons, Turning Torso rotating), reframed as outside tips from residents who saw a fragment of something they don't understand. Same universe, a level further from the truth, and the player is explicitly never given the full picture — that's the design, not a limitation. Shares djupet/retur's exact :root palette but its own accent (cold institutional cyan instead of Retur's stamp-red or Djupet's eldritch purple). Intro/win/loss screens use real generated desk photos (rotary phone, corkboard map with red string, a ceiling water stain shaped like a coastline that grows between screens), converted PNG->WebP. Verified: tsc clean, 9/9 vitest (data-integrity check that every report has real consequence text, and a locked-in test for the escalation-always-costs-insight mechanic), a real browser playthrough confirming the wrong+escalate cost stacks correctly (-1 trust, +2 insight), and all three ending states screenshotted via injected game state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:50:31 +02:00
import { describe, expect, it } from 'vitest';
import { buildRoster, createState, currentReport, reportsForDay, nextShift, routeReport, startGame, PER_DAY_COUNT, LAST_DAY } from './engine.ts';
Initial commit: Diariet A bureaucratic horror game — five shifts processing incoming tips and incident reports for a municipal office that officially handles nuisance complaints and unofficially exists to keep Djupet's cult off the front page. Route each report: dismiss, file as known, flag for follow-up, or escalate and lose visibility into what happens next. Guidelines accumulate and contradict across shifts, same shape as Retur's regulation stack. Directly descended from Retur's engine (routeLetter/nextDay -> routeReport/nextShift, same 4-route-per-item structure) but with one real mechanical difference: escalating always costs Insyn (insight/ notice), whether or not it was the correct call — being right doesn't make you invisible. Several reports cite real events from Djupet's own event pool (the bleeding IKEA LACK table, Göran added to the cult's Discord by accident, the Värnhemstorget pigeons, Turning Torso rotating), reframed as outside tips from residents who saw a fragment of something they don't understand. Same universe, a level further from the truth, and the player is explicitly never given the full picture — that's the design, not a limitation. Shares djupet/retur's exact :root palette but its own accent (cold institutional cyan instead of Retur's stamp-red or Djupet's eldritch purple). Intro/win/loss screens use real generated desk photos (rotary phone, corkboard map with red string, a ceiling water stain shaped like a coastline that grows between screens), converted PNG->WebP. Verified: tsc clean, 9/9 vitest (data-integrity check that every report has real consequence text, and a locked-in test for the escalation-always-costs-insight mechanic), a real browser playthrough confirming the wrong+escalate cost stacks correctly (-1 trust, +2 insight), and all three ending states screenshotted via injected game state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:50:31 +02:00
import { REPORTS } from './data/content.ts';
// A fixed sequence, not a real PRNG — deterministic and enough entropy to
// exercise the shuffle without pulling in a dependency for tests only.
function fakeRng(seed: number): () => number {
let s = seed;
return () => {
s = (s * 9301 + 49297) % 233280;
return s / 233280;
};
}
function stateWithRoster(roster: string[]) {
return { ...startGame(createState()), roster };
}
describe('buildRoster', () => {
it('draws exactly PER_DAY_COUNT reports per day from that day\'s pool', () => {
const roster = buildRoster(fakeRng(1));
expect(roster).toHaveLength(PER_DAY_COUNT * LAST_DAY);
for (let day = 1; day <= LAST_DAY; day++) {
const ids = roster.slice((day - 1) * PER_DAY_COUNT, day * PER_DAY_COUNT);
expect(ids).toHaveLength(PER_DAY_COUNT);
expect(new Set(ids).size).toBe(PER_DAY_COUNT); // no duplicates within a day
for (const id of ids) {
const report = REPORTS.find((r) => r.id === id);
expect(report, `roster id ${id} has no matching report`).toBeTruthy();
expect(report!.day).toBe(day);
}
}
});
it('each day\'s pool has more reports than get drawn, so variety is possible', () => {
for (let day = 1; day <= LAST_DAY; day++) {
const poolSize = REPORTS.filter((r) => r.day === day).length;
expect(poolSize).toBeGreaterThan(PER_DAY_COUNT);
}
});
it('different seeds produce different rosters', () => {
const a = buildRoster(fakeRng(1));
const b = buildRoster(fakeRng(99));
expect(a).not.toEqual(b);
});
});
Initial commit: Diariet A bureaucratic horror game — five shifts processing incoming tips and incident reports for a municipal office that officially handles nuisance complaints and unofficially exists to keep Djupet's cult off the front page. Route each report: dismiss, file as known, flag for follow-up, or escalate and lose visibility into what happens next. Guidelines accumulate and contradict across shifts, same shape as Retur's regulation stack. Directly descended from Retur's engine (routeLetter/nextDay -> routeReport/nextShift, same 4-route-per-item structure) but with one real mechanical difference: escalating always costs Insyn (insight/ notice), whether or not it was the correct call — being right doesn't make you invisible. Several reports cite real events from Djupet's own event pool (the bleeding IKEA LACK table, Göran added to the cult's Discord by accident, the Värnhemstorget pigeons, Turning Torso rotating), reframed as outside tips from residents who saw a fragment of something they don't understand. Same universe, a level further from the truth, and the player is explicitly never given the full picture — that's the design, not a limitation. Shares djupet/retur's exact :root palette but its own accent (cold institutional cyan instead of Retur's stamp-red or Djupet's eldritch purple). Intro/win/loss screens use real generated desk photos (rotary phone, corkboard map with red string, a ceiling water stain shaped like a coastline that grows between screens), converted PNG->WebP. Verified: tsc clean, 9/9 vitest (data-integrity check that every report has real consequence text, and a locked-in test for the escalation-always-costs-insight mechanic), a real browser playthrough confirming the wrong+escalate cost stacks correctly (-1 trust, +2 insight), and all three ending states screenshotted via injected game state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:50:31 +02:00
describe('routing engine', () => {
it('starts on a real report from shift one', () => {
Initial commit: Diariet A bureaucratic horror game — five shifts processing incoming tips and incident reports for a municipal office that officially handles nuisance complaints and unofficially exists to keep Djupet's cult off the front page. Route each report: dismiss, file as known, flag for follow-up, or escalate and lose visibility into what happens next. Guidelines accumulate and contradict across shifts, same shape as Retur's regulation stack. Directly descended from Retur's engine (routeLetter/nextDay -> routeReport/nextShift, same 4-route-per-item structure) but with one real mechanical difference: escalating always costs Insyn (insight/ notice), whether or not it was the correct call — being right doesn't make you invisible. Several reports cite real events from Djupet's own event pool (the bleeding IKEA LACK table, Göran added to the cult's Discord by accident, the Värnhemstorget pigeons, Turning Torso rotating), reframed as outside tips from residents who saw a fragment of something they don't understand. Same universe, a level further from the truth, and the player is explicitly never given the full picture — that's the design, not a limitation. Shares djupet/retur's exact :root palette but its own accent (cold institutional cyan instead of Retur's stamp-red or Djupet's eldritch purple). Intro/win/loss screens use real generated desk photos (rotary phone, corkboard map with red string, a ceiling water stain shaped like a coastline that grows between screens), converted PNG->WebP. Verified: tsc clean, 9/9 vitest (data-integrity check that every report has real consequence text, and a locked-in test for the escalation-always-costs-insight mechanic), a real browser playthrough confirming the wrong+escalate cost stacks correctly (-1 trust, +2 insight), and all three ending states screenshotted via injected game state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:50:31 +02:00
const state = startGame(createState());
const report = currentReport(state);
Initial commit: Diariet A bureaucratic horror game — five shifts processing incoming tips and incident reports for a municipal office that officially handles nuisance complaints and unofficially exists to keep Djupet's cult off the front page. Route each report: dismiss, file as known, flag for follow-up, or escalate and lose visibility into what happens next. Guidelines accumulate and contradict across shifts, same shape as Retur's regulation stack. Directly descended from Retur's engine (routeLetter/nextDay -> routeReport/nextShift, same 4-route-per-item structure) but with one real mechanical difference: escalating always costs Insyn (insight/ notice), whether or not it was the correct call — being right doesn't make you invisible. Several reports cite real events from Djupet's own event pool (the bleeding IKEA LACK table, Göran added to the cult's Discord by accident, the Värnhemstorget pigeons, Turning Torso rotating), reframed as outside tips from residents who saw a fragment of something they don't understand. Same universe, a level further from the truth, and the player is explicitly never given the full picture — that's the design, not a limitation. Shares djupet/retur's exact :root palette but its own accent (cold institutional cyan instead of Retur's stamp-red or Djupet's eldritch purple). Intro/win/loss screens use real generated desk photos (rotary phone, corkboard map with red string, a ceiling water stain shaped like a coastline that grows between screens), converted PNG->WebP. Verified: tsc clean, 9/9 vitest (data-integrity check that every report has real consequence text, and a locked-in test for the escalation-always-costs-insight mechanic), a real browser playthrough confirming the wrong+escalate cost stacks correctly (-1 trust, +2 insight), and all three ending states screenshotted via injected game state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:50:31 +02:00
expect(state.phase).toBe('playing');
expect(report).toBeTruthy();
expect(report!.day).toBe(1);
Initial commit: Diariet A bureaucratic horror game — five shifts processing incoming tips and incident reports for a municipal office that officially handles nuisance complaints and unofficially exists to keep Djupet's cult off the front page. Route each report: dismiss, file as known, flag for follow-up, or escalate and lose visibility into what happens next. Guidelines accumulate and contradict across shifts, same shape as Retur's regulation stack. Directly descended from Retur's engine (routeLetter/nextDay -> routeReport/nextShift, same 4-route-per-item structure) but with one real mechanical difference: escalating always costs Insyn (insight/ notice), whether or not it was the correct call — being right doesn't make you invisible. Several reports cite real events from Djupet's own event pool (the bleeding IKEA LACK table, Göran added to the cult's Discord by accident, the Värnhemstorget pigeons, Turning Torso rotating), reframed as outside tips from residents who saw a fragment of something they don't understand. Same universe, a level further from the truth, and the player is explicitly never given the full picture — that's the design, not a limitation. Shares djupet/retur's exact :root palette but its own accent (cold institutional cyan instead of Retur's stamp-red or Djupet's eldritch purple). Intro/win/loss screens use real generated desk photos (rotary phone, corkboard map with red string, a ceiling water stain shaped like a coastline that grows between screens), converted PNG->WebP. Verified: tsc clean, 9/9 vitest (data-integrity check that every report has real consequence text, and a locked-in test for the escalation-always-costs-insight mechanic), a real browser playthrough confirming the wrong+escalate cost stacks correctly (-1 trust, +2 insight), and all three ending states screenshotted via injected game state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:50:31 +02:00
});
it('advances and records a correct route', () => {
const before = startGame(createState());
const report = currentReport(before)!;
const state = routeReport(before, report.correctRoute);
Initial commit: Diariet A bureaucratic horror game — five shifts processing incoming tips and incident reports for a municipal office that officially handles nuisance complaints and unofficially exists to keep Djupet's cult off the front page. Route each report: dismiss, file as known, flag for follow-up, or escalate and lose visibility into what happens next. Guidelines accumulate and contradict across shifts, same shape as Retur's regulation stack. Directly descended from Retur's engine (routeLetter/nextDay -> routeReport/nextShift, same 4-route-per-item structure) but with one real mechanical difference: escalating always costs Insyn (insight/ notice), whether or not it was the correct call — being right doesn't make you invisible. Several reports cite real events from Djupet's own event pool (the bleeding IKEA LACK table, Göran added to the cult's Discord by accident, the Värnhemstorget pigeons, Turning Torso rotating), reframed as outside tips from residents who saw a fragment of something they don't understand. Same universe, a level further from the truth, and the player is explicitly never given the full picture — that's the design, not a limitation. Shares djupet/retur's exact :root palette but its own accent (cold institutional cyan instead of Retur's stamp-red or Djupet's eldritch purple). Intro/win/loss screens use real generated desk photos (rotary phone, corkboard map with red string, a ceiling water stain shaped like a coastline that grows between screens), converted PNG->WebP. Verified: tsc clean, 9/9 vitest (data-integrity check that every report has real consequence text, and a locked-in test for the escalation-always-costs-insight mechanic), a real browser playthrough confirming the wrong+escalate cost stacks correctly (-1 trust, +2 insight), and all three ending states screenshotted via injected game state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:50:31 +02:00
expect(state.reportIndex).toBe(1);
expect(state.decisions[0].correct).toBe(true);
expect(state.trust).toBe(3);
});
it('penalizes an incorrect route', () => {
const before = startGame(createState());
const report = currentReport(before)!;
const wrongRoute = (['avfarda', 'arkivera', 'utred', 'eskalera'] as const).find((r) => r !== report.correctRoute)!;
const state = routeReport(before, wrongRoute);
Initial commit: Diariet A bureaucratic horror game — five shifts processing incoming tips and incident reports for a municipal office that officially handles nuisance complaints and unofficially exists to keep Djupet's cult off the front page. Route each report: dismiss, file as known, flag for follow-up, or escalate and lose visibility into what happens next. Guidelines accumulate and contradict across shifts, same shape as Retur's regulation stack. Directly descended from Retur's engine (routeLetter/nextDay -> routeReport/nextShift, same 4-route-per-item structure) but with one real mechanical difference: escalating always costs Insyn (insight/ notice), whether or not it was the correct call — being right doesn't make you invisible. Several reports cite real events from Djupet's own event pool (the bleeding IKEA LACK table, Göran added to the cult's Discord by accident, the Värnhemstorget pigeons, Turning Torso rotating), reframed as outside tips from residents who saw a fragment of something they don't understand. Same universe, a level further from the truth, and the player is explicitly never given the full picture — that's the design, not a limitation. Shares djupet/retur's exact :root palette but its own accent (cold institutional cyan instead of Retur's stamp-red or Djupet's eldritch purple). Intro/win/loss screens use real generated desk photos (rotary phone, corkboard map with red string, a ceiling water stain shaped like a coastline that grows between screens), converted PNG->WebP. Verified: tsc clean, 9/9 vitest (data-integrity check that every report has real consequence text, and a locked-in test for the escalation-always-costs-insight mechanic), a real browser playthrough confirming the wrong+escalate cost stacks correctly (-1 trust, +2 insight), and all three ending states screenshotted via injected game state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:50:31 +02:00
expect(state.decisions[0].correct).toBe(false);
expect(state.trust).toBeLessThan(3);
expect(state.insight).toBeGreaterThan(0);
Initial commit: Diariet A bureaucratic horror game — five shifts processing incoming tips and incident reports for a municipal office that officially handles nuisance complaints and unofficially exists to keep Djupet's cult off the front page. Route each report: dismiss, file as known, flag for follow-up, or escalate and lose visibility into what happens next. Guidelines accumulate and contradict across shifts, same shape as Retur's regulation stack. Directly descended from Retur's engine (routeLetter/nextDay -> routeReport/nextShift, same 4-route-per-item structure) but with one real mechanical difference: escalating always costs Insyn (insight/ notice), whether or not it was the correct call — being right doesn't make you invisible. Several reports cite real events from Djupet's own event pool (the bleeding IKEA LACK table, Göran added to the cult's Discord by accident, the Värnhemstorget pigeons, Turning Torso rotating), reframed as outside tips from residents who saw a fragment of something they don't understand. Same universe, a level further from the truth, and the player is explicitly never given the full picture — that's the design, not a limitation. Shares djupet/retur's exact :root palette but its own accent (cold institutional cyan instead of Retur's stamp-red or Djupet's eldritch purple). Intro/win/loss screens use real generated desk photos (rotary phone, corkboard map with red string, a ceiling water stain shaped like a coastline that grows between screens), converted PNG->WebP. Verified: tsc clean, 9/9 vitest (data-integrity check that every report has real consequence text, and a locked-in test for the escalation-always-costs-insight mechanic), a real browser playthrough confirming the wrong+escalate cost stacks correctly (-1 trust, +2 insight), and all three ending states screenshotted via injected game state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:50:31 +02:00
});
it('escalating costs insight even when it is the correct route (d04, hand-picked into the roster)', () => {
const roster = ['d01', 'd02', 'd03', 'd04', 'd05', ...buildRoster(fakeRng(2)).slice(PER_DAY_COUNT)];
let state = stateWithRoster(roster);
Initial commit: Diariet A bureaucratic horror game — five shifts processing incoming tips and incident reports for a municipal office that officially handles nuisance complaints and unofficially exists to keep Djupet's cult off the front page. Route each report: dismiss, file as known, flag for follow-up, or escalate and lose visibility into what happens next. Guidelines accumulate and contradict across shifts, same shape as Retur's regulation stack. Directly descended from Retur's engine (routeLetter/nextDay -> routeReport/nextShift, same 4-route-per-item structure) but with one real mechanical difference: escalating always costs Insyn (insight/ notice), whether or not it was the correct call — being right doesn't make you invisible. Several reports cite real events from Djupet's own event pool (the bleeding IKEA LACK table, Göran added to the cult's Discord by accident, the Värnhemstorget pigeons, Turning Torso rotating), reframed as outside tips from residents who saw a fragment of something they don't understand. Same universe, a level further from the truth, and the player is explicitly never given the full picture — that's the design, not a limitation. Shares djupet/retur's exact :root palette but its own accent (cold institutional cyan instead of Retur's stamp-red or Djupet's eldritch purple). Intro/win/loss screens use real generated desk photos (rotary phone, corkboard map with red string, a ceiling water stain shaped like a coastline that grows between screens), converted PNG->WebP. Verified: tsc clean, 9/9 vitest (data-integrity check that every report has real consequence text, and a locked-in test for the escalation-always-costs-insight mechanic), a real browser playthrough confirming the wrong+escalate cost stacks correctly (-1 trust, +2 insight), and all three ending states screenshotted via injected game state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:50:31 +02:00
for (const route of ['avfarda', 'arkivera', 'utred'] as const) state = routeReport(state, route);
expect(currentReport(state)?.id).toBe('d04');
state = routeReport(state, 'eskalera');
expect(state.lastDecision?.correct).toBe(true);
expect(state.lastDecision?.trustCost).toBe(0);
expect(state.lastDecision?.insightCost).toBe(1);
});
it('escalating a wrong report stacks the escalation cost on top of the wrong-route cost', () => {
const roster = ['d01', 'd02', 'd03', 'd04', 'd05', ...buildRoster(fakeRng(3)).slice(PER_DAY_COUNT)];
let state = stateWithRoster(roster);
Initial commit: Diariet A bureaucratic horror game — five shifts processing incoming tips and incident reports for a municipal office that officially handles nuisance complaints and unofficially exists to keep Djupet's cult off the front page. Route each report: dismiss, file as known, flag for follow-up, or escalate and lose visibility into what happens next. Guidelines accumulate and contradict across shifts, same shape as Retur's regulation stack. Directly descended from Retur's engine (routeLetter/nextDay -> routeReport/nextShift, same 4-route-per-item structure) but with one real mechanical difference: escalating always costs Insyn (insight/ notice), whether or not it was the correct call — being right doesn't make you invisible. Several reports cite real events from Djupet's own event pool (the bleeding IKEA LACK table, Göran added to the cult's Discord by accident, the Värnhemstorget pigeons, Turning Torso rotating), reframed as outside tips from residents who saw a fragment of something they don't understand. Same universe, a level further from the truth, and the player is explicitly never given the full picture — that's the design, not a limitation. Shares djupet/retur's exact :root palette but its own accent (cold institutional cyan instead of Retur's stamp-red or Djupet's eldritch purple). Intro/win/loss screens use real generated desk photos (rotary phone, corkboard map with red string, a ceiling water stain shaped like a coastline that grows between screens), converted PNG->WebP. Verified: tsc clean, 9/9 vitest (data-integrity check that every report has real consequence text, and a locked-in test for the escalation-always-costs-insight mechanic), a real browser playthrough confirming the wrong+escalate cost stacks correctly (-1 trust, +2 insight), and all three ending states screenshotted via injected game state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:50:31 +02:00
// d01's correct route is avfarda; eskalera is wrong here.
state = routeReport(state, 'eskalera');
expect(state.lastDecision?.correct).toBe(false);
expect(state.lastDecision?.insightCost).toBe(2); // 1 for wrong + 1 for escalating
});
it('ends a shift and restores one trust point for the next', () => {
let state = startGame(createState());
const routes = reportsForDay(state, 1).map((report) => report.correctRoute);
for (const route of routes) state = routeReport(state, route);
Initial commit: Diariet A bureaucratic horror game — five shifts processing incoming tips and incident reports for a municipal office that officially handles nuisance complaints and unofficially exists to keep Djupet's cult off the front page. Route each report: dismiss, file as known, flag for follow-up, or escalate and lose visibility into what happens next. Guidelines accumulate and contradict across shifts, same shape as Retur's regulation stack. Directly descended from Retur's engine (routeLetter/nextDay -> routeReport/nextShift, same 4-route-per-item structure) but with one real mechanical difference: escalating always costs Insyn (insight/ notice), whether or not it was the correct call — being right doesn't make you invisible. Several reports cite real events from Djupet's own event pool (the bleeding IKEA LACK table, Göran added to the cult's Discord by accident, the Värnhemstorget pigeons, Turning Torso rotating), reframed as outside tips from residents who saw a fragment of something they don't understand. Same universe, a level further from the truth, and the player is explicitly never given the full picture — that's the design, not a limitation. Shares djupet/retur's exact :root palette but its own accent (cold institutional cyan instead of Retur's stamp-red or Djupet's eldritch purple). Intro/win/loss screens use real generated desk photos (rotary phone, corkboard map with red string, a ceiling water stain shaped like a coastline that grows between screens), converted PNG->WebP. Verified: tsc clean, 9/9 vitest (data-integrity check that every report has real consequence text, and a locked-in test for the escalation-always-costs-insight mechanic), a real browser playthrough confirming the wrong+escalate cost stacks correctly (-1 trust, +2 insight), and all three ending states screenshotted via injected game state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:50:31 +02:00
expect(state.phase).toBe('shift-end');
state = nextShift(state);
expect(state.day).toBe(2);
expect(state.trust).toBe(3);
});
it('has PER_DAY_COUNT reports available in every shift', () => {
const state = startGame(createState());
for (let day = 1; day <= LAST_DAY; day += 1) expect(reportsForDay(state, day)).toHaveLength(PER_DAY_COUNT);
Initial commit: Diariet A bureaucratic horror game — five shifts processing incoming tips and incident reports for a municipal office that officially handles nuisance complaints and unofficially exists to keep Djupet's cult off the front page. Route each report: dismiss, file as known, flag for follow-up, or escalate and lose visibility into what happens next. Guidelines accumulate and contradict across shifts, same shape as Retur's regulation stack. Directly descended from Retur's engine (routeLetter/nextDay -> routeReport/nextShift, same 4-route-per-item structure) but with one real mechanical difference: escalating always costs Insyn (insight/ notice), whether or not it was the correct call — being right doesn't make you invisible. Several reports cite real events from Djupet's own event pool (the bleeding IKEA LACK table, Göran added to the cult's Discord by accident, the Värnhemstorget pigeons, Turning Torso rotating), reframed as outside tips from residents who saw a fragment of something they don't understand. Same universe, a level further from the truth, and the player is explicitly never given the full picture — that's the design, not a limitation. Shares djupet/retur's exact :root palette but its own accent (cold institutional cyan instead of Retur's stamp-red or Djupet's eldritch purple). Intro/win/loss screens use real generated desk photos (rotary phone, corkboard map with red string, a ceiling water stain shaped like a coastline that grows between screens), converted PNG->WebP. Verified: tsc clean, 9/9 vitest (data-integrity check that every report has real consequence text, and a locked-in test for the escalation-always-costs-insight mechanic), a real browser playthrough confirming the wrong+escalate cost stacks correctly (-1 trust, +2 insight), and all three ending states screenshotted via injected game state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 19:50:31 +02:00
});
it('every report has its own correct-route consequence', () => {
for (const report of REPORTS) {
expect(report.correctConsequence, `${report.id} is missing a correctConsequence`).toBeTruthy();
}
});
it('loses on insight reaching the cap even with trust intact', () => {
let state = startGame(createState());
// Escalate every report regardless of correctness to ramp insight fast.
for (let i = 0; i < 10 && state.phase === 'playing'; i++) state = routeReport(state, 'eskalera');
expect(state.phase).toBe('lost');
expect(state.insight).toBeGreaterThanOrEqual(5);
});
});