src/programs/snap-negative/seed-generator-support.test.ts
Linked repository file from this build.
import { expect, test } from "bun:test";
import { assertSummaryRelease, transmittalEligible } from "@/features/reviews/downstream";
import { policySchema } from "@/features/policy/schema";
import { generateSeedBatch } from "./seed-generator";
import { initialPolicy, policyForMonth } from "./policy";
import { CURRENT_CALC_VERSION, CURRENT_CHECK_VERSION } from "./rule-versions";
import { selectFinal } from "./calculation";
import { alignIncomeRows, scenarioForColumn } from "@/features/reviews/computation-grid.helpers";
import { buildDiscrepancies } from "@/features/reviews/computation-discrepancies";
import { fiscalYear, reviewKey } from "@/features/reviews/review-key";
test("fiscal-year support data is deterministic, dated and frozen on each review", () => {
const options = { ffyFrom: 2025, ffyTo: 2027, perMonth: 2, seed: 42, preserveReviewNumbers: [] };
const batch = generateSeedBatch(options);
expect(JSON.stringify(generateSeedBatch(options))).toBe(JSON.stringify(batch));
expect(batch.asOf).toBe("2027-09-30T12:00:00.000Z");
expect(batch.reviews).toHaveLength(144);
expect(new Set(batch.reviews.map(reviewKey)).size).toBe(144);
expect(batch.reviews.filter((review) => review.reviewNumber === "60001")).toHaveLength(3);
expect(new Set(batch.reviews.map((review) => review.id)).size).toBe(144);
const incomeIds = batch.reviews.flatMap((review) =>
Object.values(review.facts.scenarios).flatMap((scenario) =>
scenario.income.map((row) => row.id),
),
);
expect(new Set(incomeIds).size).toBe(incomeIds.length);
expect(batch.policies.map((policy) => policy.effectiveFrom)).toEqual([
"2024-10",
"2025-10",
"2026-10",
]);
expect(batch.policies[1]).toEqual(initialPolicy);
for (const policy of batch.policies) expect(policySchema.safeParse(policy).success).toBe(true);
for (const policy of [batch.policies[0]!, batch.policies[2]!])
expect(policy.verification).toContain("Synthetic test data only");
for (const review of batch.reviews) {
const policy = policyForMonth(review.sampleMonth, batch.policies);
expect(review.policyId).toBe(policy.id);
expect(review.policy).toEqual(policy);
expect(review.policy).not.toBe(policy);
expect(review.calcVersion).toBe(CURRENT_CALC_VERSION);
expect(review.checkVersion).toBe(CURRENT_CHECK_VERSION);
expect(review.lineage![0]!.rawText.split("|")).toHaveLength(42);
expect(review.lineage![0]!.rowNumber).toBeGreaterThanOrEqual(3);
if (review.facts.final) expect(review.facts.final).toEqual(selectFinal(review));
}
const review = batch.reviews[0]!;
const oldLimit = review.policy!.grossLimits[0];
batch.policies[0]!.grossLimits = [];
expect(review.policy!.grossLimits[0]).toBe(oldLimit);
});
test("seed income rows have unique grid keys with current and legacy IDs, including Final and discrepancies", () => {
const batch = generateSeedBatch({ ffyFrom: 2026, ffyTo: 2026, perMonth: 2, seed: 7 });
let legacyCollisions = 0;
for (const review of batch.reviews) {
const lists = [
...Object.values(review.facts.scenarios).map((scenario) => scenario.income),
scenarioForColumn(review, "final", {}).income,
...buildDiscrepancies(review).map((item) => item.scenario.income),
];
const legacy = lists.map((list) =>
list.map((row, index) => ({ ...row, id: `income-${index + 1}` })),
);
for (const columns of [lists, legacy]) {
const groups = alignIncomeRows(columns);
expect(new Set(groups.map((group) => group.key)).size).toBe(groups.length);
for (let column = 0; column < columns.length; column++) {
const rows = groups.flatMap((group) => (group.rows[column] ? [group.rows[column]!] : []));
expect(new Set(rows)).toEqual(new Set(columns[column]));
}
}
const oldKeys = alignIncomeRows(legacy).map((group) => group.rows.find(Boolean)?.id);
if (new Set(oldKeys).size !== oldKeys.length) legacyCollisions++;
}
expect(legacyCollisions).toBeGreaterThan(0);
});
test("a full FFY covers the current workflow with consistent flags and supporting facts", () => {
const batch = generateSeedBatch({
ffyFrom: 2026,
ffyTo: 2026,
perMonth: 50,
seed: 42,
preserveReviewNumbers: [],
});
expect(batch.reviews).toHaveLength(1200);
expect([...new Set(batch.reviews.map((review) => review.state))].sort()).toEqual([
"awaiting_cao_response",
"awaiting_manager",
"awaiting_pec_approval",
"awaiting_review",
"dropped",
"needs_changes",
"new_active",
"released_to_reporting",
]);
const dropKinds = new Set<string>();
const memoTypes = new Set<string>();
const responses = new Set<string>();
const businesses = new Set<string>();
for (const review of batch.reviews) {
const snapshots = review.receivedSnapshots!;
expect(snapshots.examiner).toBeDefined();
expect(snapshots.examiner!.facts).not.toBe(review.facts);
expect(snapshots.examiner!.facts.final).toBeUndefined();
expect(snapshots.examiner!.facts.members).toEqual([]);
expect(snapshots.examiner!.outcome).toBe("");
expect(snapshots.supervisor !== undefined).toBe(review.state !== "new_active");
expect(review.facts.answers.variances.length).toBeLessThanOrEqual(1);
expect(Number.isInteger(review.facts.caoIssuedBenefitCents)).toBe(true);
for (const scenario of Object.values(review.facts.scenarios)) {
for (const income of scenario.income) {
expect(review.facts.members.some((member) => member.id === income.memberId)).toBe(true);
if (income.category === "self_employment")
businesses.add(
`${income.selfEmploymentKind}:${income.amountCents > income.expensesCents ? "profit" : "loss"}`,
);
}
}
const senior = !["new_active", "needs_changes", "awaiting_review"].includes(review.state);
expect(Boolean(review.supervisorApproved)).toBe(senior);
expect(Boolean(review.pecApproved)).toBe(
senior && review.outcome !== "drop" && review.state !== "awaiting_pec_approval",
);
expect(Boolean(review.memoApproved)).toBe(
["awaiting_cao_response", "released_to_reporting"].includes(review.state),
);
expect(Boolean(review.errorSummaryReleased)).toBe(review.state === "released_to_reporting");
expect(Boolean(review.dropApproved)).toBe(review.state === "dropped");
expect(transmittalEligible(review)).toBe(
["released_to_reporting", "dropped"].includes(review.state),
);
expect(Boolean(snapshots.program_manager)).toBe(
Boolean(review.pecApproved) || (senior && review.outcome === "drop"),
);
for (const flag of [
review.supervisorApproved,
review.pecApproved,
review.memoApproved,
review.dropApproved,
review.errorSummaryReleased,
]) {
if (flag) {
expect(flag.actor.staffId).toBeTruthy();
expect(flag.at <= batch.asOf).toBe(true);
}
}
if (review.state === "needs_changes") {
expect(review.notes[0]!.actor.staffId).toBe(review.supervisor);
expect(review.notes[0]!.fieldLink).toBe("recordedReason");
expect(review.activity[0]!.noteId).toBe(review.notes[0]!.id);
}
if (review.dropKind) dropKinds.add(review.dropKind);
if (review.outcome === "drop") {
expect(review.dropKind).toBeDefined();
expect(review.memos).toBeUndefined();
expect(review.caoResponse).toBeUndefined();
}
if (review.pecApproved) {
expect(review.pecDecision?.actor.role).toBe("pec");
expect(review.memos?.[0]?.body).toContain("SYNTHETIC TEST LETTER");
}
if (review.memos?.[0]?.type) memoTypes.add(review.memos[0].type);
if (review.caoResponse) responses.add(review.caoResponse.status);
if (review.memoApproved) {
expect(review.memos![0]!.outboundAt).toBe(review.memoApproved.at);
expect(review.caoResponseDeadline).toBeTruthy();
}
if (review.errorSummaryReleased)
expect(() =>
assertSummaryRelease({ ...review, state: "awaiting_cao_response" }, batch.asOf),
).not.toThrow();
}
expect([...dropKinds].sort()).toEqual([
"failure_to_comply",
"not_subject_to_review",
"refusal_to_comply",
]);
expect(memoTypes.size).toBe(5);
expect([...responses].sort()).toEqual(["agree", "dispute", "no_response"]);
expect([...businesses].sort()).toEqual([
"farm:loss",
"farm:profit",
"non_farm:loss",
"non_farm:profit",
]);
});
test("yearly numbering and random streams are independent of other generated fiscal years", () => {
const options = {
ffyFrom: 2023,
ffyTo: 2026,
perMonth: 2,
seed: 42,
asOf: new Date("2026-09-01T12:00:00Z"),
};
const batch = generateSeedBatch(options);
expect(batch.reviews).toHaveLength(192);
expect(new Set(batch.reviews.map(reviewKey)).size).toBe(192);
for (const year of [2023, 2024, 2025, 2026]) {
const reviews = batch.reviews.filter((review) => fiscalYear(review.sampleMonth) === year);
expect(reviews.map((review) => review.reviewNumber)).toEqual([
...Array.from({ length: 24 }, (_, index) => String(60001 + index)),
...Array.from({ length: 24 }, (_, index) => String(650001 + index)),
]);
const alone = generateSeedBatch({ ...options, ffyFrom: year, ffyTo: year });
// Source line numbers describe the combined fixture file, so compare case facts separately.
expect(reviews.map(({ lineage: _lineage, ...review }) => review)).toEqual(
alone.reviews.map(({ lineage: _lineage, ...review }) => review),
);
}
});
test("explicit dates and sample-month sets have stable behavior", () => {
const options = {
ffyFrom: 2026,
ffyTo: 2026,
perMonth: 1,
asOf: new Date("2026-09-08T12:00:00Z"),
};
expect(
generateSeedBatch({ ...options, sampleMonths: ["2026-09", "2026-08", "2026-09"] }),
).toEqual(generateSeedBatch({ ...options, sampleMonths: ["2026-08", "2026-09"] }));
expect(() => generateSeedBatch({ ...options, perMonth: 0 })).toThrow();
expect(() => generateSeedBatch({ ...options, asOf: new Date("invalid") })).toThrow();
const future = generateSeedBatch({ ...options, sampleMonths: ["2026-10"] });
expect(future.reviews.every((review) => review.state === "new_active")).toBe(true);
});