src/programs/snap-negative/policy.ts
Linked repository file from this build.
import type { SnapReview, SuaType } from "./types";
import { RuleError } from "@/lib/errors";
/** Workbook snapshot for the synthetic sample only; not a current-policy certification. */
export const demoPolicy = {
id: "fs-negative-workbook-ffy2026-demo-v1",
effectiveFrom: "2025-10",
effectiveThrough: "2026-09",
source: "FS Negative Template Workbook.xlsm: AD65:AE72, V65:AA72, AB17:AC21, T89, W11, B55",
verification: "Workbook values transcribed; operational policy remains unverified.",
grossLimits: [2610, 3526, 4442, 5360, 6276, 7192, 8110, 9026],
netLimits: [1305, 1763, 2221, 2680, 3138, 3596, 4055, 4513],
standardDeductions: [209, 209, 209, 223, 261, 299, 299, 299],
allotments: [298, 546, 785, 994, 1183, 1421, 1571, 1789],
sua: { heating: 857, non_heating: 488, limited: 128, telephone: 107, none: 0 } satisfies Record<
SuaType,
number
>,
shelterCap: 744,
minimumBenefit: 24,
homelessDeduction: 199,
earnedDeductionPercent: 20,
} as const;
/** Full workbook table through household size 20. Values are transcribed, not extrapolated. */
export const expandedDemoPolicy = {
...demoPolicy,
id: "fs-negative-workbook-ffy2026-demo-v2",
source: "FS Negative Template Workbook.xlsm: AD65:AE84, V65:AA84, AB17:AC21, T89, W11, B55",
grossLimits: [
...demoPolicy.grossLimits,
9944,
10862,
11780,
12698,
13616,
14534,
15452,
16370,
17288,
18206,
19124,
20042,
],
netLimits: [
...demoPolicy.netLimits,
4972,
5434,
5893,
6352,
6811,
7270,
7729,
8188,
8647,
9106,
9565,
10024,
],
standardDeductions: [...demoPolicy.standardDeductions, ...Array<number>(12).fill(299)],
allotments: [
...demoPolicy.allotments,
2007,
2225,
2443,
2661,
2879,
3097,
3315,
3533,
3751,
3969,
4187,
4405,
],
} as const;
export interface SnapPolicy {
id: string;
effectiveFrom: string;
source: string;
verification: string;
grossLimits: readonly number[];
netLimits: readonly number[];
standardDeductions: readonly number[];
allotments: readonly number[];
sua: Record<SuaType, number>;
shelterCap: number;
shelterDeductionPercent: number;
minimumBenefit: number;
homelessDeduction: number;
earnedDeductionPercent: number;
farmExpenseAllowancePercent: number;
nonFarmExpenseAllowancePercent: number;
errorThreshold: number;
memoResponseDays: number | null;
}
/** Published FFY 2026 numbers. No FY 2027 amounts have been supplied. */
const { effectiveThrough: _effectiveThrough, ...initialAmounts } = expandedDemoPolicy;
export const initialPolicy: SnapPolicy = {
...initialAmounts,
id: "snap-negative-ffy2026-v1",
shelterDeductionPercent: 50,
farmExpenseAllowancePercent: 100,
nonFarmExpenseAllowancePercent: 100,
errorThreshold: 58,
memoResponseDays: null,
};
export function policyForMonth(sampleMonth: string, policies: readonly SnapPolicy[]): SnapPolicy {
if (!/^\d{4}-(0[1-9]|1[0-2])$/.test(sampleMonth))
throw new RuleError("Enter a valid sample month.");
const policy = policies
.filter((row) => row.effectiveFrom <= sampleMonth)
.reduce<SnapPolicy | undefined>(
(latest, row) => (!latest || row.effectiveFrom > latest.effectiveFrom ? row : latest),
undefined,
);
if (!policy) throw new RuleError("No published policy for this sample month.");
return policy;
}
/** Saved policy numbers remain fixed when a later table is published. */
export function resolveReviewPolicy(review: Pick<SnapReview, "policy" | "policyId">): SnapPolicy {
if (review.policy) {
if (review.policyId && review.policy.id !== review.policyId)
throw new RuleError("Review policy does not match its saved ID.");
return review.policy;
}
if (review.policyId && review.policyId !== initialPolicy.id)
throw new RuleError("The saved review policy is missing.");
return initialPolicy;
}