1
0
Fork 0
polaris-task-force/tests/int/operation-territory.int.spec.ts
Z8MB1E 3c70160dfc feat(operations): readiness and zone pressure aggregates
Deterministic, explainable, advisory readiness aggregates per subject behind a permission gate, and mission-scoped zone pressure with read-time decay yielding route-risk and yield multipliers.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-20 02:43:53 -04:00

258 lines
9 KiB
TypeScript

import { getPayload, Payload } from "payload";
import config from "@/payload.config";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { applyZonePressure, computeZoneState, PRESSURE_OUTCOME_DELTAS } from "@/lib/operations/territory";
let payload: Payload;
const RUN = `terr-${Date.now().toString(36)}`;
const DAY = 86_400_000;
// ---------------------------------------------------------------------------
// Fixture tracking for cleanup
// ---------------------------------------------------------------------------
const syncEventIds: number[] = [];
const opEventIds: number[] = [];
const opEffectIds: number[] = [];
const zoneIds: number[] = [];
const pressureRowIds: number[] = [];
const userIds: number[] = [];
let factionId: number;
let mapId: number;
let serverId: number;
let zoneAId: number;
let zoneBId: number;
let zoneCId: number;
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
/** Full hook chain: raw op.end sync event -> validated event -> effect ->
* settlement (handleOperationEnd) -> one attributed pressure delta. */
async function endOperation(label: string, outcome: string, zoneId: number): Promise<number> {
const sync = await payload.create({
collection: "arma-sync-events",
data: {
eventId: `${RUN}-${label}`,
server: serverId,
type: "operation.end",
occurredAt: new Date().toISOString(),
payload: { operationId: RUN, version: 1, outcome, zoneId, factionId, actorId: userIds[0] },
},
overrideAccess: true,
depth: 0,
});
syncEventIds.push(sync.id);
const events = await payload.find({
collection: "operation-events",
where: { sourceEvent: { equals: sync.id } },
limit: 1,
depth: 0,
overrideAccess: true,
});
expect(events.docs).toHaveLength(1);
opEventIds.push(events.docs[0].id);
const effects = await payload.find({
collection: "operation-effects",
where: { operationEvent: { equals: events.docs[0].id } },
limit: 1,
depth: 0,
overrideAccess: true,
});
expect(effects.docs).toHaveLength(1);
opEffectIds.push(effects.docs[0].id);
return effects.docs[0].id;
}
async function pressureRowCount(zoneId: number): Promise<number> {
const rows = await payload.find({
collection: "zone-pressure",
where: { zone: { equals: zoneId } },
limit: 100,
depth: 0,
overrideAccess: true,
});
return rows.docs.length;
}
// ---------------------------------------------------------------------------
// Setup / teardown
// ---------------------------------------------------------------------------
beforeAll(async () => {
const payloadConfig = await config;
payload = await getPayload({ config: payloadConfig });
const actor = await payload.create({
collection: "users",
data: {
username: `${RUN}-actor`,
discordUsername: `${RUN}-actor-discord`,
displayName: `${RUN} Actor`,
steamId: `${RUN}-steam-actor`,
password: "Test1234",
},
overrideAccess: true,
depth: 0,
});
userIds.push(actor.id);
const faction = await payload.create({
collection: "factions",
data: { name: `${RUN} Hostiles`, type: "majorFaction" },
overrideAccess: true,
depth: 0,
});
factionId = faction.id;
const server = await payload.create({
collection: "game-servers",
data: { serverId: `${RUN}-srv`, name: `${RUN} Server`, status: "online" },
overrideAccess: true,
depth: 0,
});
serverId = server.id;
const map = await payload.create({
collection: "maps",
data: { name: `${RUN} Map`, worldSizeWidth: 8192, worldSizeHeight: 8192, basemapMode: "image" },
overrideAccess: true,
depth: 0,
});
mapId = map.id;
for (const label of ["alpha", "bravo", "charlie"] as const) {
const zone = await payload.create({
collection: "map-zones",
data: {
name: `${RUN} Zone ${label.toUpperCase()}`,
map: mapId,
type: "territory",
points: [
[0, 0],
[100, 0],
[100, 100],
[0, 100],
],
},
overrideAccess: true,
depth: 0,
});
zoneIds.push(zone.id);
if (label === "alpha") zoneAId = zone.id;
if (label === "bravo") zoneBId = zone.id;
if (label === "charlie") zoneCId = zone.id;
}
});
afterAll(async () => {
if (!payload) return;
const pressureRows = await payload.find({
collection: "zone-pressure",
where: { operationId: { equals: RUN } },
limit: 100,
depth: 0,
overrideAccess: true,
});
for (const row of pressureRows.docs) {
await payload.delete({ collection: "zone-pressure", id: row.id, overrideAccess: true }).catch(() => {});
}
for (const id of opEffectIds) {
await payload.delete({ collection: "operation-effects", id, overrideAccess: true }).catch(() => {});
}
for (const id of opEventIds) {
await payload.delete({ collection: "operation-events", id, overrideAccess: true }).catch(() => {});
}
for (const id of syncEventIds) {
await payload.delete({ collection: "arma-sync-events", id, overrideAccess: true }).catch(() => {});
}
for (const id of zoneIds) {
await payload.delete({ collection: "map-zones", id, overrideAccess: true }).catch(() => {});
}
await payload.delete({ collection: "maps", id: mapId, overrideAccess: true }).catch(() => {});
await payload.delete({ collection: "factions", id: factionId, overrideAccess: true }).catch(() => {});
await payload.delete({ collection: "game-servers", id: serverId, overrideAccess: true }).catch(() => {});
for (const id of userIds) {
await payload.delete({ collection: "users", id, overrideAccess: true }).catch(() => {});
}
});
// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
describe("Zone pressure (task 7)", () => {
it("applies hostile pressure once for a failed operation and replays as a no-op", async () => {
const effectId = await endOperation("fail-1", "failed", zoneAId);
const state = await computeZoneState(payload, zoneAId);
expect(state.pressure).toBe(PRESSURE_OUTCOME_DELTAS.failure);
expect(state.state).toBe("contested");
expect(state.routeRiskMultiplier).toBe(1.25);
expect(state.yieldMultiplier).toBe(0.9);
expect(state.activeRows).toBe(1);
const replay = await applyZonePressure(payload, {
zoneId: zoneAId,
factionId,
operationId: RUN,
sourceEffectId: effectId,
delta: PRESSURE_OUTCOME_DELTAS.failure,
});
expect(replay.created).toBe(false);
expect(await pressureRowCount(zoneAId)).toBe(1);
});
it("walks the full arc: contested after failure, recovering after a successful push", async () => {
await endOperation("fail-b", "failed", zoneBId);
const contested = await computeZoneState(payload, zoneBId);
expect(contested.state).toBe("contested");
await endOperation("success-b", "success", zoneBId);
const recovering = await computeZoneState(payload, zoneBId);
expect(recovering.pressure).toBe(15);
expect(recovering.state).toBe("recovering");
expect(recovering.routeRiskMultiplier).toBe(1);
expect(recovering.yieldMultiplier).toBe(1);
});
it("reaches hostile control at the documented threshold", async () => {
await endOperation("fail-2", "failed", zoneAId);
const controlled = await computeZoneState(payload, zoneAId);
expect(controlled.pressure).toBe(80);
expect(controlled.state).toBe("controlled");
expect(controlled.routeRiskMultiplier).toBe(1.5);
expect(controlled.yieldMultiplier).toBe(0.75);
});
it("decays deterministically, halving per elapsed period", async () => {
const now = Date.now();
const plusOnePeriod = await computeZoneState(payload, zoneAId, new Date(now + 7 * DAY + 3_600_000));
expect(plusOnePeriod.pressure).toBe(40);
expect(plusOnePeriod.state).toBe("contested");
const plusTwoPeriods = await computeZoneState(payload, zoneAId, new Date(now + 14 * DAY + 3_600_000));
expect(plusTwoPeriods.pressure).toBe(20);
expect(plusTwoPeriods.state).toBe("recovering");
const plusTenPeriods = await computeZoneState(payload, zoneAId, new Date(now + 70 * DAY + 3_600_000));
expect(plusTenPeriods.pressure).toBeLessThan(1);
expect(plusTenPeriods.state).toBe("neutral");
});
it("never touches zones the operation did not declare", async () => {
const untouched = await computeZoneState(payload, zoneCId);
expect(untouched.pressure).toBe(0);
expect(untouched.state).toBe("neutral");
expect(untouched.activeRows).toBe(0);
expect(await pressureRowCount(zoneCId)).toBe(0);
});
it("keeps placement semantics independent of pressure (pure helpers only)", () => {
// Placement rules live in src/lib/map/placement.ts (terrain + resources),
// which pressure never imports or mutates. This assertion documents the
// boundary: state thresholds are the ONLY pressure inputs to downstream
// multipliers.
expect(PRESSURE_OUTCOME_DELTAS.failure).toBe(40);
expect(PRESSURE_OUTCOME_DELTAS.success).toBe(-25);
});
});