@invaro/opentax 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/bundle/http.js +2546 -1359
  2. package/bundle/index.js +2540 -1353
  3. package/bundle/main.js +1520 -164
  4. package/package.json +5 -5
package/bundle/main.js CHANGED
@@ -13337,45 +13337,45 @@ function generateCustomRefineCheck(doc, ctx, check2, accessor) {
13337
13337
  throw new ZodCompileUnsupportedError("custom check without a predicate or check function");
13338
13338
  }
13339
13339
  function generateStringFormatCheck(doc, ctx, def, accessor, needsValue = true) {
13340
- const fmt3 = def.format;
13341
- if (fmt3 === "base64") {
13340
+ const fmt4 = def.format;
13341
+ if (fmt4 === "base64") {
13342
13342
  const validator = addConstant(ctx, isValidBase64);
13343
13343
  doc.write(`if (!${validator}(${accessor})) return INVALID;`);
13344
13344
  return accessor;
13345
13345
  }
13346
- if (fmt3 === "base64url") {
13346
+ if (fmt4 === "base64url") {
13347
13347
  const validator = addConstant(ctx, isValidBase64URL);
13348
13348
  doc.write(`if (!${validator}(${accessor})) return INVALID;`);
13349
13349
  return accessor;
13350
13350
  }
13351
- if (fmt3 === "jwt") {
13351
+ if (fmt4 === "jwt") {
13352
13352
  const validator = addConstant(ctx, isValidJWT);
13353
13353
  const alg = addConstant(ctx, def.alg ?? null);
13354
13354
  doc.write(`if (!${validator}(${accessor}, ${alg})) return INVALID;`);
13355
13355
  return accessor;
13356
13356
  }
13357
- if (fmt3 === "ipv6") {
13357
+ if (fmt4 === "ipv6") {
13358
13358
  const validator = addConstant(ctx, isValidIPv6);
13359
13359
  doc.write(`if (!${validator}(${accessor})) return INVALID;`);
13360
13360
  return accessor;
13361
13361
  }
13362
- if (fmt3 === "cidrv6") {
13362
+ if (fmt4 === "cidrv6") {
13363
13363
  const validator = addConstant(ctx, isValidCIDRv6);
13364
13364
  doc.write(`if (!${validator}(${accessor})) return INVALID;`);
13365
13365
  return accessor;
13366
13366
  }
13367
- if (fmt3 === "credit_card") {
13367
+ if (fmt4 === "credit_card") {
13368
13368
  const validator = addConstant(ctx, isValidCreditCard);
13369
13369
  doc.write(`if (!${validator}(${accessor})) return INVALID;`);
13370
13370
  return accessor;
13371
13371
  }
13372
- if (fmt3 === "iban") {
13372
+ if (fmt4 === "iban") {
13373
13373
  const validator = addConstant(ctx, isValidIBAN);
13374
13374
  doc.write(`if (!${validator}(${accessor})) return INVALID;`);
13375
13375
  return accessor;
13376
13376
  }
13377
13377
  const formatDef = def;
13378
- if (fmt3 === "url" || fmt3 === "httpurl" || formatDef.normalize || formatDef.hostname !== void 0 || formatDef.protocol !== void 0) {
13378
+ if (fmt4 === "url" || fmt4 === "httpurl" || formatDef.normalize || formatDef.hostname !== void 0 || formatDef.protocol !== void 0) {
13379
13379
  const parseConst = addConstant(ctx, validateURL);
13380
13380
  const defConst = addConstant(ctx, def);
13381
13381
  const trimVar = newVar(ctx);
@@ -13401,12 +13401,12 @@ function generateStringFormatCheck(doc, ctx, def, accessor, needsValue = true) {
13401
13401
  const customFn = def.fn;
13402
13402
  if (customFn) {
13403
13403
  if (isAsyncFunction(customFn))
13404
- throw new ZodCompileUnsupportedError(`async string format ${fmt3}`);
13404
+ throw new ZodCompileUnsupportedError(`async string format ${fmt4}`);
13405
13405
  const fnConst = addConstant(ctx, customFn);
13406
13406
  doc.write(`if (!${fnConst}(${accessor})) return INVALID;`);
13407
13407
  return accessor;
13408
13408
  }
13409
- if (PATTERN_IS_COMPLETE.has(fmt3) && def.pattern) {
13409
+ if (PATTERN_IS_COMPLETE.has(fmt4) && def.pattern) {
13410
13410
  const patternConst = addConstant(ctx, def.pattern);
13411
13411
  doc.write(`${patternConst}.lastIndex = 0;`);
13412
13412
  doc.write(`if (!${patternConst}.test(${accessor})) return INVALID;`);
@@ -19924,21 +19924,21 @@ function visit(schema, fnOrHandlers) {
19924
19924
  const h = fnOrHandlers[node2._zod.def.type];
19925
19925
  return h ? h(node2, rewritten) : node2;
19926
19926
  };
19927
- const cache = /* @__PURE__ */ new Map();
19927
+ const cache2 = /* @__PURE__ */ new Map();
19928
19928
  function run(s) {
19929
- const cached3 = cache.get(s);
19929
+ const cached3 = cache2.get(s);
19930
19930
  if (cached3 === RESOLVING) {
19931
19931
  return new $ZodLazy({
19932
19932
  type: "lazy",
19933
- getter: () => cache.get(s)
19933
+ getter: () => cache2.get(s)
19934
19934
  });
19935
19935
  }
19936
19936
  if (cached3 !== void 0)
19937
19937
  return cached3;
19938
- cache.set(s, RESOLVING);
19938
+ cache2.set(s, RESOLVING);
19939
19939
  const inner = mapInner(s);
19940
19940
  const mapped = fn(inner, inner !== s);
19941
- cache.set(s, mapped);
19941
+ cache2.set(s, mapped);
19942
19942
  return mapped;
19943
19943
  }
19944
19944
  function mapInner(s) {
@@ -23069,18 +23069,18 @@ var require_suggestSimilar = __commonJS({
23069
23069
  }
23070
23070
  return d3[a.length][b.length];
23071
23071
  }
23072
- function suggestSimilar(word, candidates) {
23073
- if (!candidates || candidates.length === 0) return "";
23074
- candidates = Array.from(new Set(candidates));
23072
+ function suggestSimilar(word, candidates2) {
23073
+ if (!candidates2 || candidates2.length === 0) return "";
23074
+ candidates2 = Array.from(new Set(candidates2));
23075
23075
  const searchingOptions = word.startsWith("--");
23076
23076
  if (searchingOptions) {
23077
23077
  word = word.slice(2);
23078
- candidates = candidates.map((candidate) => candidate.slice(2));
23078
+ candidates2 = candidates2.map((candidate) => candidate.slice(2));
23079
23079
  }
23080
23080
  let similar = [];
23081
23081
  let bestDistance = maxDistance;
23082
23082
  const minSimilarity = 0.4;
23083
- candidates.forEach((candidate) => {
23083
+ candidates2.forEach((candidate) => {
23084
23084
  if (candidate.length <= 1) return;
23085
23085
  const distance = editDistance(word, candidate);
23086
23086
  const length = Math.max(word.length, candidate.length);
@@ -26209,29 +26209,29 @@ function evalRule(ruleId, ctx) {
26209
26209
  const base = selectVersion(ctx.corpus, ruleId, ctx.asOf);
26210
26210
  const overs = selectOverriders(ctx.corpus, ruleId, ctx.asOf);
26211
26211
  const children = [];
26212
- const candidates = [];
26212
+ const candidates2 = [];
26213
26213
  let winner = null;
26214
26214
  let poisoned = false;
26215
26215
  for (const cand of overs) {
26216
26216
  const guard = evalExpr(cand.applicability, cand, ctx, children);
26217
26217
  if (guard === POISON) {
26218
- candidates.push(candidateEntry(cand, "unknown"));
26218
+ candidates2.push(candidateEntry(cand, "unknown"));
26219
26219
  poisoned = true;
26220
26220
  break;
26221
26221
  }
26222
26222
  expectType(guard, "bool", cand, "applicability");
26223
26223
  if (guard.value) {
26224
- candidates.push(candidateEntry(cand, true));
26224
+ candidates2.push(candidateEntry(cand, true));
26225
26225
  winner = cand;
26226
26226
  break;
26227
26227
  }
26228
- candidates.push(candidateEntry(cand, false));
26228
+ candidates2.push(candidateEntry(cand, false));
26229
26229
  }
26230
26230
  if (!winner && !poisoned) {
26231
26231
  if (base.applicability) {
26232
26232
  const guard = evalExpr(base.applicability, base, ctx, children);
26233
26233
  if (guard === POISON) {
26234
- candidates.push({ ...candidateEntry(base, "unknown"), priority: 0 });
26234
+ candidates2.push({ ...candidateEntry(base, "unknown"), priority: 0 });
26235
26235
  poisoned = true;
26236
26236
  } else {
26237
26237
  expectType(guard, "bool", base, "applicability");
@@ -26244,12 +26244,12 @@ function evalRule(ruleId, ctx) {
26244
26244
  }
26245
26245
  ]);
26246
26246
  }
26247
- candidates.push({ ...candidateEntry(base, true), priority: 0 });
26247
+ candidates2.push({ ...candidateEntry(base, true), priority: 0 });
26248
26248
  winner = base;
26249
26249
  }
26250
26250
  } else {
26251
26251
  if (overs.length > 0) {
26252
- candidates.push({ ...candidateEntry(base, true), priority: 0 });
26252
+ candidates2.push({ ...candidateEntry(base, true), priority: 0 });
26253
26253
  }
26254
26254
  winner = base;
26255
26255
  }
@@ -26299,7 +26299,7 @@ function evalRule(ruleId, ctx) {
26299
26299
  title: winner.title,
26300
26300
  citation: winner.citation,
26301
26301
  ...winner.id !== ruleId ? { resolvedFrom: ruleId } : {},
26302
- ...overs.length > 0 ? { candidatesConsidered: candidates } : {},
26302
+ ...overs.length > 0 ? { candidatesConsidered: candidates2 } : {},
26303
26303
  ...contributions.length > 0 ? { contributions } : {},
26304
26304
  ...ctx.excluded.size > 0 ? { excluding: [...ctx.excluded].sort() } : {},
26305
26305
  inputs,
@@ -56546,6 +56546,433 @@ var init_tips_overtime = __esm({
56546
56546
  }
56547
56547
  });
56548
56548
 
56549
+ // ../corpus-us-federal/dist/projection-spec.js
56550
+ var PROJECTION_PARAMS, CG, derived2, eitc, pctSteps, TAX_TABLE, FIXED_LITERALS, gt011, NOT_PROJECTED;
56551
+ var init_projection_spec = __esm({
56552
+ "../corpus-us-federal/dist/projection-spec.js"() {
56553
+ "use strict";
56554
+ PROJECTION_PARAMS = [
56555
+ { "kind": "indexed", "id": "brackets.single.12_bracket_start", "label": "brackets.single.12% bracket start (10% end)", "statute": "\xA7 1(j)(2)(C), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "952500", "ratio": ["2011421", "1495923"] }], "roundCents": "2500", "roundMode": "down", "on": "increase", "published2027": "1280000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["single"] }, { "id": "us.federal.kiddie_tax", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["single"] }] },
56556
+ { "kind": "indexed", "id": "brackets.single.22_bracket_start", "label": "brackets.single.22% bracket start (12% end)", "statute": "\xA7 1(j)(2)(C), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "3870000", "ratio": ["2011421", "1495923"] }], "roundCents": "2500", "roundMode": "down", "on": "increase", "published2027": "5202500", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["single"] }, { "id": "us.federal.kiddie_tax", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["single"] }] },
56557
+ { "kind": "indexed", "id": "brackets.single.24_bracket_start", "label": "brackets.single.24% bracket start", "statute": "\xA7 1(j)(2)(C), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "8250000", "ratio": ["8045684", "6082417"] }], "roundCents": "2500", "roundMode": "down", "on": "increase", "published2027": "10912500", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["single"] }, { "id": "us.federal.kiddie_tax", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["single"] }] },
56558
+ { "kind": "indexed", "id": "brackets.single.32_bracket_start", "label": "brackets.single.32% bracket start", "statute": "\xA7 1(j)(2)(C), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "15750000", "ratio": ["8045684", "6082417"] }], "roundCents": "2500", "roundMode": "down", "on": "increase", "published2027": "20832500", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["single"] }, { "id": "us.federal.kiddie_tax", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["single"] }] },
56559
+ { "kind": "indexed", "id": "brackets.single.35_bracket_start", "label": "brackets.single.35% bracket start", "statute": "\xA7 1(j)(2)(C), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "20000000", "ratio": ["8045684", "6082417"] }], "roundCents": "2500", "roundMode": "down", "on": "increase", "published2027": "26455000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["single"] }, { "id": "us.federal.kiddie_tax", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["single"] }] },
56560
+ { "kind": "indexed", "id": "brackets.single.37_bracket_start", "label": "brackets.single.37% bracket start", "statute": "\xA7 1(j)(2)(C), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "50000000", "ratio": ["8045684", "6082417"] }], "roundCents": "2500", "roundMode": "down", "on": "increase", "published2027": "66137500", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["single"] }, { "id": "us.federal.kiddie_tax", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["single"] }, { "id": "us.federal.itemized_deductions", "statuses": ["single"] }] },
56561
+ { "kind": "indexed", "id": "brackets.mfj.12_bracket_start", "label": "brackets.mfj.12% bracket start (10% end)", "statute": "\xA7 1(j)(2)(A), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "1905000", "ratio": ["2011421", "1495923"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "2560000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfj", "qss"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfj", "qss"] }] },
56562
+ { "kind": "indexed", "id": "brackets.mfj.22_bracket_start", "label": "brackets.mfj.22% bracket start (12% end)", "statute": "\xA7 1(j)(2)(A), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "7740000", "ratio": ["2011421", "1495923"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "10405000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfj", "qss"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfj", "qss"] }] },
56563
+ { "kind": "indexed", "id": "brackets.mfj.24_bracket_start", "label": "brackets.mfj.24% bracket start", "statute": "\xA7 1(j)(2)(A), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "16500000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "21825000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfj", "qss"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfj", "qss"] }] },
56564
+ { "kind": "indexed", "id": "brackets.mfj.32_bracket_start", "label": "brackets.mfj.32% bracket start", "statute": "\xA7 1(j)(2)(A), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "31500000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "41665000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfj", "qss"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfj", "qss"] }] },
56565
+ { "kind": "indexed", "id": "brackets.mfj.35_bracket_start", "label": "brackets.mfj.35% bracket start", "statute": "\xA7 1(j)(2)(A), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "40000000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "52910000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfj", "qss"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfj", "qss"] }] },
56566
+ { "kind": "indexed", "id": "brackets.mfj.37_bracket_start", "label": "brackets.mfj.37% bracket start", "statute": "\xA7 1(j)(2)(A), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "60000000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "79365000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfj", "qss"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfj", "qss"] }, { "id": "us.federal.itemized_deductions", "statuses": ["mfj", "qss"] }] },
56567
+ { "kind": "indexed", "id": "brackets.hoh.12_bracket_start", "label": "brackets.hoh.12% bracket start (10% end)", "statute": "\xA7 1(j)(2)(B), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "1360000", "ratio": ["2011421", "1495923"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "1825000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["hoh"] }, { "id": "us.federal.kiddie_tax", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["hoh"] }] },
56568
+ { "kind": "indexed", "id": "brackets.hoh.22_bracket_start", "label": "brackets.hoh.22% bracket start (12% end)", "statute": "\xA7 1(j)(2)(B), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "5180000", "ratio": ["2011421", "1495923"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "6965000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["hoh"] }, { "id": "us.federal.kiddie_tax", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["hoh"] }] },
56569
+ { "kind": "indexed", "id": "brackets.hoh.24_bracket_start", "label": "brackets.hoh.24% bracket start", "statute": "\xA7 1(j)(2)(B), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "8250000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "10910000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["hoh"] }, { "id": "us.federal.kiddie_tax", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["hoh"] }] },
56570
+ { "kind": "indexed", "id": "brackets.hoh.32_bracket_start", "label": "brackets.hoh.32% bracket start", "statute": "\xA7 1(j)(2)(B), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "15750000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "20830000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["hoh"] }, { "id": "us.federal.kiddie_tax", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["hoh"] }] },
56571
+ { "kind": "indexed", "id": "brackets.hoh.35_bracket_start", "label": "brackets.hoh.35% bracket start", "statute": "\xA7 1(j)(2)(B), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "20000000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "26455000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["hoh"] }, { "id": "us.federal.kiddie_tax", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["hoh"] }] },
56572
+ { "kind": "indexed", "id": "brackets.hoh.37_bracket_start", "label": "brackets.hoh.37% bracket start", "statute": "\xA7 1(j)(2)(B), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "50000000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "66135000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["hoh"] }, { "id": "us.federal.kiddie_tax", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["hoh"] }, { "id": "us.federal.itemized_deductions", "statuses": ["hoh"] }] },
56573
+ { "kind": "indexed", "id": "brackets.mfs.12_bracket_start", "label": "brackets.mfs.12% bracket start (10% end)", "statute": "\xA7 1(j)(2)(D), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "952500", "ratio": ["2011421", "1495923"] }], "roundCents": "2500", "roundMode": "down", "on": "increase", "published2027": "1280000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfs"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfs"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfs"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfs"] }] },
56574
+ { "kind": "indexed", "id": "brackets.mfs.22_bracket_start", "label": "brackets.mfs.22% bracket start (12% end)", "statute": "\xA7 1(j)(2)(D), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "3870000", "ratio": ["2011421", "1495923"] }], "roundCents": "2500", "roundMode": "down", "on": "increase", "published2027": "5202500", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfs"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfs"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfs"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfs"] }] },
56575
+ { "kind": "indexed", "id": "brackets.mfs.24_bracket_start", "label": "brackets.mfs.24% bracket start", "statute": "\xA7 1(j)(2)(D), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "8250000", "ratio": ["8045684", "6082417"] }], "roundCents": "2500", "roundMode": "down", "on": "increase", "published2027": "10912500", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfs"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfs"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfs"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfs"] }] },
56576
+ { "kind": "indexed", "id": "brackets.mfs.32_bracket_start", "label": "brackets.mfs.32% bracket start", "statute": "\xA7 1(j)(2)(D), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "15750000", "ratio": ["8045684", "6082417"] }], "roundCents": "2500", "roundMode": "down", "on": "increase", "published2027": "20832500", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfs"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfs"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfs"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfs"] }] },
56577
+ { "kind": "indexed", "id": "brackets.mfs.35_bracket_start", "label": "brackets.mfs.35% bracket start", "statute": "\xA7 1(j)(2)(D), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "20000000", "ratio": ["8045684", "6082417"] }], "roundCents": "2500", "roundMode": "down", "on": "increase", "published2027": "26455000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfs"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfs"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfs"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfs"] }] },
56578
+ { "kind": "indexed", "id": "brackets.mfs.37_bracket_start", "label": "brackets.mfs.37% bracket start", "statute": "\xA7 1(j)(2)(D), (j)(3)(B); \xA7 1(f)(3), (f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "30000000", "ratio": ["8045684", "6082417"] }], "roundCents": "2500", "roundMode": "down", "on": "increase", "published2027": "39682500", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfs"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfs"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfs"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfs"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfs"] }, { "id": "us.federal.itemized_deductions", "statuses": ["mfs"] }] },
56579
+ { "kind": "indexed", "id": "brackets.estate.24_start", "label": "brackets.estate.24% start (10% end)", "statute": "\xA7 1(j)(2)(E), (j)(3)(B); \xA7 1(f)(7)(A)", "index": "c-cpi-u", "comps": [{ "baseCents": "255000", "ratio": ["2011421", "1495923"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "340000", "rules": [{ "id": "us.federal.fiduciary.income_tax" }] },
56580
+ { "kind": "indexed", "id": "brackets.estate.35_start", "label": "brackets.estate.35% start", "statute": "\xA7 1(j)(2)(E), (j)(3)(B); \xA7 1(f)(7)(A)", "index": "c-cpi-u", "comps": [{ "baseCents": "915000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "1210000", "rules": [{ "id": "us.federal.fiduciary.income_tax" }] },
56581
+ { "kind": "indexed", "id": "brackets.estate.37_start", "label": "brackets.estate.37% start", "statute": "\xA7 1(j)(2)(E), (j)(3)(B); \xA7 1(f)(7)(A)", "index": "c-cpi-u", "comps": [{ "baseCents": "1250000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "1650000", "rules": [{ "id": "us.federal.fiduciary.income_tax" }] },
56582
+ { "kind": "indexed", "id": "capgains.mfj.zero", "label": "capgains.mfj.zero", "statute": "\xA7 1(j)(5)(B), (C)", "index": "c-cpi-u", "comps": [{ "baseCents": "7720000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "10210000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfj", "qss"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfj", "qss"] }, { "id": "us.federal.amt.tentative_minimum_tax", "statuses": ["mfj", "qss"] }] },
56583
+ { "kind": "indexed", "id": "capgains.hoh.zero", "label": "capgains.hoh.zero", "statute": "\xA7 1(j)(5)(B), (C)", "index": "c-cpi-u", "comps": [{ "baseCents": "5170000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "6835000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["hoh"] }, { "id": "us.federal.kiddie_tax", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["hoh"] }, { "id": "us.federal.amt.tentative_minimum_tax", "statuses": ["hoh"] }] },
56584
+ { "kind": "indexed", "id": "capgains.estate.zero", "label": "capgains.estate.zero", "statute": "\xA7 1(j)(5)(B), (C)", "index": "c-cpi-u", "comps": [{ "baseCents": "260000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "340000", "rules": [] },
56585
+ { "kind": "indexed", "id": "capgains.mfj.fifteen", "label": "capgains.mfj.fifteen", "statute": "\xA7 1(j)(5)(B), (C)", "index": "c-cpi-u", "comps": [{ "baseCents": "47900000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "63360000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["mfj", "qss"] }, { "id": "us.federal.kiddie_tax", "statuses": ["mfj", "qss"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["mfj", "qss"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["mfj", "qss"] }, { "id": "us.federal.amt.tentative_minimum_tax", "statuses": ["mfj", "qss"] }] },
56586
+ { "kind": "indexed", "id": "capgains.hoh.fifteen", "label": "capgains.hoh.fifteen", "statute": "\xA7 1(j)(5)(B), (C)", "index": "c-cpi-u", "comps": [{ "baseCents": "45240000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "59840000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["hoh"] }, { "id": "us.federal.kiddie_tax", "statuses": ["hoh"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["hoh"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["hoh"] }, { "id": "us.federal.amt.tentative_minimum_tax", "statuses": ["hoh"] }] },
56587
+ { "kind": "indexed", "id": "capgains.single.fifteen", "label": "capgains.single.fifteen", "statute": "\xA7 1(j)(5)(B), (C)", "index": "c-cpi-u", "comps": [{ "baseCents": "42580000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "56320000", "rules": [{ "id": "us.federal.income_tax_before_credits", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.tax_table", "statuses": ["single"] }, { "id": "us.federal.kiddie_tax", "statuses": ["single"] }, { "id": "us.federal.income_tax_before_credits.feie", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q1", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q2", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q3", "statuses": ["single"] }, { "id": "us.federal.estimated.annualized_installment_q4", "statuses": ["single"] }, { "id": "us.federal.amt.tentative_minimum_tax", "statuses": ["single"] }] },
56588
+ { "kind": "indexed", "id": "capgains.estate.fifteen", "label": "capgains.estate.fifteen", "statute": "\xA7 1(j)(5)(B), (C)", "index": "c-cpi-u", "comps": [{ "baseCents": "1270000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "1675000", "rules": [] },
56589
+ { "kind": "indexed", "id": "standardDeduction.single", "label": "standardDeduction.single (MFS same; MFJ/QSS = 200%)", "statute": "\xA7 63(c)(2)(C), (c)(7)(A)(ii), (c)(7)(B)(ii)", "index": "c-cpi-u", "comps": [{ "baseCents": "1575000", "ratio": ["12068526", "11419045"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "1660000", "rules": [{ "id": "us.federal.standard_deduction.base_amount", "statuses": ["single", "mfs"] }] },
56590
+ { "kind": "indexed", "id": "standardDeduction.hoh", "label": "standardDeduction.hoh", "statute": "\xA7 63(c)(2)(B), (c)(7)(A)(i), (c)(7)(B)(ii)", "index": "c-cpi-u", "comps": [{ "baseCents": "2362500", "ratio": ["12068526", "11419045"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "2492500", "rules": [{ "id": "us.federal.standard_deduction.base_amount", "statuses": ["hoh"] }] },
56591
+ { "kind": "indexed", "id": "dependentStdDed.floor", "label": "dependentStdDed.floor ($500) [= \xA7 1(g)(4)(A)(ii)(I) kiddie amount]", "statute": "\xA7 63(c)(5)(A), (c)(4)(B)(i); \xA7 1(f)(7)(A)", "index": "c-cpi-u", "comps": [{ "baseCents": "50000", "ratio": ["480023610229", "167518443950"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "140000", "rules": [{ "id": "us.federal.standard_deduction.dependent_limit" }, { "id": "us.federal.kiddie_tax" }] },
56592
+ { "kind": "indexed", "id": "dependentStdDed.earnedIncomeAddOn", "label": "dependentStdDed.earnedIncomeAddOn ($250)", "statute": "\xA7 63(c)(5)(B), (c)(4)(B)(ii)", "index": "c-cpi-u", "comps": [{ "baseCents": "25000", "ratio": ["480023610229", "238587252475"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "50000", "rules": [{ "id": "us.federal.standard_deduction.dependent_limit" }] },
56593
+ { "kind": "indexed", "id": "additionalStdDed.married", "label": "additionalStdDed.married (aged/blind)", "statute": "\xA7 63(f)(1),(2), (c)(4)(B)(i)", "index": "c-cpi-u", "comps": [{ "baseCents": "60000", "ratio": ["480023610229", "167518443950"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "170000", "rules": [{ "id": "us.federal.standard_deduction.additional", "path": "\\.parameters\\.amountMarried$" }] },
56594
+ { "kind": "indexed", "id": "additionalStdDed.unmarried", "label": "additionalStdDed.unmarried", "statute": "\xA7 63(f)(3), (c)(4)(B)(i)", "index": "c-cpi-u", "comps": [{ "baseCents": "75000", "ratio": ["480023610229", "167518443950"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "210000", "rules": [{ "id": "us.federal.standard_deduction.additional", "path": "\\.parameters\\.amountUnmarried$" }] },
56595
+ { "kind": "indexed", "id": "amt.exemption.joint", "label": "amt.exemption.joint (MFS = 50%)", "statute": "\xA7 55(d)(1)(A), (d)(4)(A)(i)(I), (d)(4)(B)", "index": "c-cpi-u", "comps": [{ "baseCents": "10940000", "ratio": ["8045684", "6082417"] }], "roundCents": "10000", "roundMode": "nearest", "on": "amount", "published2027": "14470000", "rules": [{ "id": "us.federal.amt.exemption", "path": "\\.parameters\\.exemptJoint$" }] },
56596
+ { "kind": "indexed", "id": "amt.exemption.unmarried", "label": "amt.exemption.unmarried", "statute": "\xA7 55(d)(1)(B), (d)(4)(A)(i)(II), (d)(4)(B)", "index": "c-cpi-u", "comps": [{ "baseCents": "7030000", "ratio": ["8045684", "6082417"] }], "roundCents": "10000", "roundMode": "nearest", "on": "amount", "published2027": "9300000", "rules": [{ "id": "us.federal.amt.exemption", "path": "\\.parameters\\.exemptSingle$" }] },
56597
+ { "kind": "indexed", "id": "amt.phaseoutThreshold.joint", "label": "amt.phaseoutThreshold.joint (single/MFS = 50%)", "statute": "\xA7 55(d)(2)(A), (d)(4)(A)(ii)(I), (d)(4)(B)(i)(II)(2)", "index": "c-cpi-u", "comps": [{ "baseCents": "100000000", "ratio": ["12068526", "11695585"] }], "roundCents": "10000", "roundMode": "nearest", "on": "amount", "published2027": "103190000", "rules": [{ "id": "us.federal.amt.exemption", "path": "\\.parameters\\.threshJoint$" }] },
56598
+ { "kind": "indexed", "id": "amt.break28", "label": "amt.break28 (MFS = 50%)", "statute": "\xA7 55(b)(1)(A)(iii), (d)(3)", "index": "c-cpi-u", "comps": [{ "baseCents": "17500000", "ratio": ["960047220458", "665483785395"] }], "roundCents": "10000", "roundMode": "nearest", "on": "amount", "published2027": "25250000", "rules": [{ "id": "us.federal.amt.tentative_minimum_tax", "path": "\\.parameters\\.break28$" }] },
56599
+ { "kind": "indexed", "id": "eitc.earnedIncomeAmount.0kids", "label": "eitc.earnedIncomeAmount.0kids", "statute": "\xA7 32(b)(2)(A), (j)(1)(B)(i), (j)(2)(A)", "index": "c-cpi-u", "comps": [{ "baseCents": "422000", "ratio": ["480023610229", "225996567225"] }], "roundCents": "1000", "roundMode": "nearest", "on": "amount", "published2027": "896000", "rules": [{ "id": "us.federal.eitc", "path": "\\.parameters\\.eia0$" }, { "id": "us.federal.eitc_no_age_gate", "path": "\\.parameters\\.eia0$" }] },
56600
+ { "kind": "indexed", "id": "eitc.earnedIncomeAmount.1kid", "label": "eitc.earnedIncomeAmount.1kid", "statute": "\xA7 32(b)(2)(A), (j)(1)(B)(i), (j)(2)(A)", "index": "c-cpi-u", "comps": [{ "baseCents": "633000", "ratio": ["480023610229", "225996567225"] }], "roundCents": "1000", "roundMode": "nearest", "on": "amount", "published2027": "1345000", "rules": [{ "id": "us.federal.eitc", "path": "\\.parameters\\.eia1$" }, { "id": "us.federal.eitc_no_age_gate", "path": "\\.parameters\\.eia1$" }] },
56601
+ { "kind": "indexed", "id": "eitc.earnedIncomeAmount.2_kids", "label": "eitc.earnedIncomeAmount.2+kids", "statute": "\xA7 32(b)(2)(A), (j)(1)(B)(i), (j)(2)(A)", "index": "c-cpi-u", "comps": [{ "baseCents": "889000", "ratio": ["480023610229", "225996567225"] }], "roundCents": "1000", "roundMode": "nearest", "on": "amount", "published2027": "1888000", "rules": [{ "id": "us.federal.eitc", "path": "\\.parameters\\.eia[23]$" }, { "id": "us.federal.eitc_no_age_gate", "path": "\\.parameters\\.eia[23]$" }] },
56602
+ { "kind": "indexed", "id": "eitc.phaseoutThreshold.0kids.other", "label": "eitc.phaseoutThreshold.0kids.other", "statute": "\xA7 32(b)(2)(A), (j)(1)(B)(i), (j)(2)(A)", "index": "c-cpi-u", "comps": [{ "baseCents": "528000", "ratio": ["480023610229", "225996567225"] }], "roundCents": "1000", "roundMode": "nearest", "on": "amount", "published2027": "1121000", "rules": [{ "id": "us.federal.eitc", "path": "\\.parameters\\.thresholdOther0$" }, { "id": "us.federal.eitc_no_age_gate", "path": "\\.parameters\\.thresholdOther0$" }] },
56603
+ { "kind": "indexed", "id": "eitc.phaseoutThreshold.kids.other", "label": "eitc.phaseoutThreshold.kids.other", "statute": "\xA7 32(b)(2)(A), (j)(1)(B)(i), (j)(2)(A)", "index": "c-cpi-u", "comps": [{ "baseCents": "1161000", "ratio": ["480023610229", "225996567225"] }], "roundCents": "1000", "roundMode": "nearest", "on": "amount", "published2027": "2466000", "rules": [{ "id": "us.federal.eitc", "path": "\\.parameters\\.thresholdOtherKids$" }, { "id": "us.federal.eitc_no_age_gate", "path": "\\.parameters\\.thresholdOtherKids$" }] },
56604
+ { "kind": "indexed", "id": "eitc.phaseoutThreshold.0kids.mfj", "label": "eitc.phaseoutThreshold.0kids.mfj", "statute": "\xA7 32(b)(2)(A)+(B), (j)(1)(B)(i),(ii), (j)(2)(A)", "index": "c-cpi-u", "comps": [{ "baseCents": "528000", "ratio": ["480023610229", "225996567225"] }, { "baseCents": "500000", "ratio": ["480023610229", "319536632415"] }], "roundCents": "1000", "roundMode": "nearest", "on": "amount", "published2027": "1873000", "rules": [{ "id": "us.federal.eitc", "path": "\\.parameters\\.thresholdMFJ0$" }, { "id": "us.federal.eitc_no_age_gate", "path": "\\.parameters\\.thresholdMFJ0$" }] },
56605
+ { "kind": "indexed", "id": "eitc.phaseoutThreshold.kids.mfj", "label": "eitc.phaseoutThreshold.kids.mfj", "statute": "\xA7 32(b)(2)(A)+(B), (j)(1)(B)(i),(ii), (j)(2)(A)", "index": "c-cpi-u", "comps": [{ "baseCents": "1161000", "ratio": ["480023610229", "225996567225"] }, { "baseCents": "500000", "ratio": ["480023610229", "319536632415"] }], "roundCents": "1000", "roundMode": "nearest", "on": "amount", "published2027": "3217000", "rules": [{ "id": "us.federal.eitc", "path": "\\.parameters\\.thresholdMFJKids$" }, { "id": "us.federal.eitc_no_age_gate", "path": "\\.parameters\\.thresholdMFJKids$" }] },
56606
+ { "kind": "indexed", "id": "eitc.investmentIncomeLimit", "label": "eitc.investmentIncomeLimit", "statute": "\xA7 32(i)(1), (j)(1)(B)(iii), (j)(2)(B)", "index": "c-cpi-u", "comps": [{ "baseCents": "1000000", "ratio": ["24137052", "19115459"] }], "roundCents": "5000", "roundMode": "down", "on": "amount", "published2027": "1260000", "rules": [{ "id": "us.federal.eitc", "path": "\\.parameters\\.investmentLimit$" }, { "id": "us.federal.eitc_no_age_gate", "path": "\\.parameters\\.investmentLimit$" }] },
56607
+ { "kind": "indexed", "id": "ctc.perChild", "label": "ctc.perChild", "statute": "\xA7 24(h)(2), (i)(2), (i)(3)", "index": "c-cpi-u", "comps": [{ "baseCents": "220000", "ratio": ["12068526", "11419045"] }], "roundCents": "10000", "roundMode": "down", "on": "increase", "published2027": "230000", "rules": [{ "id": "us.federal.ctc.tentative" }] },
56608
+ { "kind": "indexed", "id": "actc.refundableCapPerChild", "label": "actc.refundableCapPerChild", "statute": "\xA7 24(h)(5), (i)(1), (i)(3)", "index": "c-cpi-u", "comps": [{ "baseCents": "140000", "ratio": ["8045684", "6082417"] }], "roundCents": "10000", "roundMode": "down", "on": "increase", "published2027": "180000", "rules": [{ "id": "us.federal.actc" }, { "id": "us.federal.actc.maximum" }] },
56609
+ { "kind": "indexed", "id": "adoption.maxCredit", "label": "adoption.maxCredit (and special-needs amount)", "statute": "\xA7 23(a)(3), (b)(1), (h)(1),(2)", "index": "c-cpi-u", "comps": [{ "baseCents": "1000000", "ratio": ["480023610229", "263095457625"] }], "roundCents": "1000", "roundMode": "nearest", "on": "amount", "published2027": "1825000", "rules": [{ "id": "us.federal.adoption.allowed" }] },
56610
+ { "kind": "indexed", "id": "adoption.phaseoutStart", "label": "adoption.phaseoutStart", "statute": "\xA7 23(b)(2)(A)(i), (h)(1),(2)", "index": "c-cpi-u", "comps": [{ "baseCents": "15000000", "ratio": ["480023610229", "263095457625"] }], "roundCents": "1000", "roundMode": "nearest", "on": "amount", "published2027": "27368000", "rules": [{ "id": "us.federal.adoption.allowed" }] },
56611
+ { "kind": "indexed", "id": "adoption.refundableCap", "label": "adoption.refundableCap", "statute": "\xA7 23(a)(4), (h)(3)", "index": "c-cpi-u", "comps": [{ "baseCents": "500000", "ratio": ["12068526", "11419045"] }], "roundCents": "1000", "roundMode": "nearest", "on": "amount", "published2027": "528000", "rules": [{ "id": "us.federal.adoption.refundable" }] },
56612
+ { "kind": "indexed", "id": "qbi.threshold.other", "label": "qbi.threshold.other (MFJ = 200%)", "statute": "\xA7 199A(e)(2)(A),(B); \xA7 1(f)(7)", "index": "c-cpi-u", "comps": [{ "baseCents": "15750000", "ratio": ["8045684", "6082417"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "20830000", "rules": [{ "id": "us.federal.qbi.threshold", "statuses": ["single", "hoh", "qss"] }] },
56613
+ { "kind": "indexed", "id": "qbi.threshold.mfs", "label": "qbi.threshold.mfs", "statute": "\xA7 199A(e)(2); \xA7 1(f)(7)(B)", "index": "c-cpi-u", "comps": [{ "baseCents": "15750000", "ratio": ["8045684", "6082417"] }], "roundCents": "2500", "roundMode": "down", "on": "increase", "published2027": "20832500", "rules": [{ "id": "us.federal.qbi.threshold", "statuses": ["mfs"] }] },
56614
+ { "kind": "indexed", "id": "qbi.minDeduction", "label": "qbi.minDeduction", "statute": "\xA7 199A(i)(1)(B), (i)(3)", "index": "c-cpi-u", "comps": [{ "baseCents": "40000", "ratio": ["12068526", "11695585"] }], "roundCents": "500", "roundMode": "nearest", "on": "increase", "published2027": "41500", "rules": [{ "id": "us.federal.qbi_deduction" }, { "id": "us.federal.estimated.annualized_installment_q1" }, { "id": "us.federal.estimated.annualized_installment_q2" }, { "id": "us.federal.estimated.annualized_installment_q3" }, { "id": "us.federal.estimated.annualized_installment_q4" }] },
56615
+ { "kind": "indexed", "id": "qbi.minQbiFloor", "label": "qbi.minQbiFloor", "statute": "\xA7 199A(i)(2)(A), (i)(3)", "index": "c-cpi-u", "comps": [{ "baseCents": "100000", "ratio": ["12068526", "11695585"] }], "roundCents": "500", "roundMode": "nearest", "on": "increase", "published2027": "103000", "rules": [{ "id": "us.federal.qbi_deduction" }, { "id": "us.federal.estimated.annualized_installment_q1" }, { "id": "us.federal.estimated.annualized_installment_q2" }, { "id": "us.federal.estimated.annualized_installment_q3" }, { "id": "us.federal.estimated.annualized_installment_q4" }] },
56616
+ { "kind": "indexed", "id": "studentLoan.phaseoutStart.other", "label": "studentLoan.phaseoutStart.other", "statute": "\xA7 221(b)(2)(B), (f)", "index": "c-cpi-u", "comps": [{ "baseCents": "5000000", "ratio": ["480023610229", "263095457625"] }], "roundCents": "500000", "roundMode": "down", "on": "amount", "published2027": "9000000", "rules": [{ "id": "us.federal.student_loan_interest_deduction", "path": "\\.parameters\\.threshold$" }] },
56617
+ { "kind": "indexed", "id": "studentLoan.phaseoutStart.joint", "label": "studentLoan.phaseoutStart.joint", "statute": "\xA7 221(b)(2)(B), (f)", "index": "c-cpi-u", "comps": [{ "baseCents": "10000000", "ratio": ["480023610229", "263095457625"] }], "roundCents": "500000", "roundMode": "down", "on": "amount", "published2027": "18000000", "rules": [{ "id": "us.federal.student_loan_interest_deduction", "path": "\\.parameters\\.thresholdJoint$" }] },
56618
+ { "kind": "indexed", "id": "educatorCap", "label": "educatorCap", "statute": "\xA7 62(a)(2)(D), (d)(3)", "index": "c-cpi-u", "comps": [{ "baseCents": "25000", "ratio": ["480023610229", "352566612255"] }], "roundCents": "5000", "roundMode": "nearest", "on": "increase", "published2027": "35000", "rules": [{ "id": "us.federal.above_the_line_adjustments" }] },
56619
+ { "kind": "indexed", "id": "feie.exclusion", "label": "feie.exclusion", "statute": "\xA7 911(b)(2)(D)", "index": "c-cpi-u", "comps": [{ "baseCents": "8000000", "ratio": ["480023610229", "279675270875"] }], "roundCents": "10000", "roundMode": "down", "on": "increase", "published2027": "13730000", "rules": [{ "id": "us.federal.feie.exclusion" }, { "id": "us.federal.income_tax_before_credits.feie" }] },
56620
+ { "kind": "indexed", "id": "qsbs.capNew", "label": "qsbs.capNew", "statute": "\xA7 1202(b)(4)(B), (b)(5)", "index": "c-cpi-u", "comps": [{ "baseCents": "1500000000", "ratio": ["12068526", "11695585"] }], "roundCents": "1000000", "roundMode": "nearest", "on": "increase", "published2027": "1548000000", "rules": [{ "id": "us.federal.qsbs_exclusion", "path": "\\.parameters\\.capNew$" }] },
56621
+ { "kind": "indexed", "id": "section179.limit", "label": "section179.limit", "statute": "\xA7 179(b)(1), (b)(6)(A)(ii)(I), (b)(6)(B)", "index": "c-cpi-u", "comps": [{ "baseCents": "250000000", "ratio": ["12068526", "11419045"] }], "roundCents": "1000000", "roundMode": "nearest", "on": "increase", "published2027": "264000000", "rules": [{ "id": "us.federal.corp.section179_deduction" }, { "id": "us.federal.corp.section179_carryforward" }] },
56622
+ { "kind": "indexed", "id": "section179.phaseoutThreshold", "label": "section179.phaseoutThreshold", "statute": "\xA7 179(b)(2), (b)(6)", "index": "c-cpi-u", "comps": [{ "baseCents": "400000000", "ratio": ["12068526", "11419045"] }], "roundCents": "1000000", "roundMode": "nearest", "on": "increase", "published2027": "423000000", "rules": [{ "id": "us.federal.corp.section179_deduction" }, { "id": "us.federal.corp.section179_carryforward" }] },
56623
+ { "kind": "indexed", "id": "section179.suvLimit", "label": "section179.suvLimit", "statute": "\xA7 179(b)(5)(A), (b)(6)(A)(ii)(II)", "index": "c-cpi-u", "comps": [{ "baseCents": "2500000", "ratio": ["8045684", "6082417"] }], "roundCents": "10000", "roundMode": "nearest", "on": "increase", "published2027": "3310000", "rules": [] },
56624
+ { "kind": "indexed", "id": "grossReceiptsTest", "label": "grossReceiptsTest", "statute": "\xA7 448(c)(1), (c)(4)", "index": "c-cpi-u", "comps": [{ "baseCents": "2500000000", "ratio": ["8045684", "6082417"] }], "roundCents": "100000000", "roundMode": "nearest", "on": "amount", "published2027": "3300000000", "rules": [{ "id": "us.federal.corp.interest_deduction" }] },
56625
+ { "kind": "indexed", "id": "ebl.threshold", "label": "ebl.threshold (joint = 200%)", "statute": "\xA7 461(l)(3)(A)(ii)(II), (l)(3)(C)", "index": "c-cpi-u", "comps": [{ "baseCents": "25000000", "ratio": ["12068526", "11419045"] }], "roundCents": "100000", "roundMode": "nearest", "on": "amount", "published2027": "26400000", "rules": [{ "id": "us.federal.excess_business_loss_disallowed", "path": "\\.parameters\\.threshold$" }] },
56626
+ { "kind": "indexed", "id": "qualifyingRelative.grossIncomeLimit", "label": "qualifyingRelative.grossIncomeLimit", "statute": "\xA7 152(d)(1)(B); \xA7 151(d)(1),(d)(4),(d)(5)(B); \xA7 1(f)(7)(A)", "index": "c-cpi-u", "comps": [{ "baseCents": "200000", "ratio": ["480023610229", "174449553850"] }], "roundCents": "5000", "roundMode": "down", "on": "increase", "published2027": "550000", "rules": [{ "id": "us.federal.dependent.qualifying_relative" }, { "id": "us.federal.dependent.qualifying_relative.multiple_support" }] },
56627
+ { "kind": "indexed", "id": "hsa.limitSelf", "label": "hsa.limitSelf", "statute": "\xA7 223(b)(2), (g)(1)", "index": "c-cpi-u", "comps": [{ "baseCents": "225000", "ratio": ["472164898659", "236343367975"] }], "roundCents": "5000", "roundMode": "nearest", "on": "increase", "published2027": "450000", "rules": [{ "id": "us.federal.hsa_deduction", "path": "\\.parameters\\.limitSelf$" }] },
56628
+ { "kind": "indexed", "id": "hsa.limitFamily", "label": "hsa.limitFamily", "statute": "\xA7 223(b)(2), (g)(1)", "index": "c-cpi-u", "comps": [{ "baseCents": "450000", "ratio": ["472164898659", "236343367975"] }], "roundCents": "5000", "roundMode": "nearest", "on": "increase", "published2027": "900000", "rules": [{ "id": "us.federal.hsa_deduction", "path": "\\.parameters\\.limitFamily$" }] },
56629
+ { "kind": "indexed", "id": "ssWageBase", "label": "social security wage base", "statute": "\xA7 3121(a)(1), \xA7 1402(b)(1); Social Security Act \xA7 230(b)", "index": "awi", "comps": [{ "baseCents": "6060000", "ratio": ["7280033", "2293542"] }], "roundCents": "30000", "roundMode": "nearest", "on": "amount", "published2027": "19230000", "rules": [{ "id": "us.federal.employer.payroll_tax" }, { "id": "us.federal.se_tax.taxpayer" }, { "id": "us.federal.se_tax.spouse" }, { "id": "us.federal.estimated.annualized_installment_q4" }], "neverDecreases": true },
56630
+ { "kind": "indexed", "id": "householdEmployeeThreshold", "label": "domestic employee coverage threshold", "statute": "\xA7 3121(x), (a)(7)(B); Social Security Act \xA7 215(a)(1)(B)(ii)", "index": "awi", "comps": [{ "baseCents": "100000", "ratio": ["7280033", "2313267"] }], "roundCents": "10000", "roundMode": "down", "on": "amount", "published2027": "310000", "rules": [{ "id": "us.federal.household_employment_taxes", "path": "\\.parameters\\.ficaThreshold$" }] }
56631
+ ];
56632
+ CG = [
56633
+ "us.federal.income_tax_before_credits",
56634
+ "us.federal.income_tax_before_credits.tax_table",
56635
+ "us.federal.kiddie_tax",
56636
+ "us.federal.income_tax_before_credits.feie",
56637
+ "us.federal.estimated.annualized_installment_q1",
56638
+ "us.federal.estimated.annualized_installment_q2",
56639
+ "us.federal.estimated.annualized_installment_q3",
56640
+ "us.federal.estimated.annualized_installment_q4",
56641
+ "us.federal.amt.tentative_minimum_tax"
56642
+ ];
56643
+ derived2 = (id2, label, statute, terms, published2027, rules, roundCents = "1", roundMode = "nearest") => ({
56644
+ kind: "derived",
56645
+ id: id2,
56646
+ label,
56647
+ statute,
56648
+ terms: terms.map(([param28, num, den]) => ({ param: param28, num: String(num), den: String(den) })),
56649
+ roundCents,
56650
+ roundMode,
56651
+ published2027,
56652
+ rules
56653
+ });
56654
+ eitc = (path) => ["us.federal.eitc", "us.federal.eitc_no_age_gate"].map((id2) => ({ id: id2, path }));
56655
+ PROJECTION_PARAMS.push(derived2("standardDeduction.joint", "standard deduction, joint (200% of single)", "\xA7 63(c)(2)(A)", [["standardDeduction.single", 2, 1]], "3320000", [{ id: "us.federal.standard_deduction.base_amount", statuses: ["mfj", "qss"] }]), derived2("capgains.single.zero", "0% capital gain bracket end, single/MFS (\xBD of joint)", "\xA7 1(j)(5)(B)(i)(III)", [["capgains.mfj.zero", 1, 2]], "5105000", CG.map((id2) => ({ id: id2, statuses: ["single", "mfs"] }))), derived2("capgains.mfs.fifteen", "15% capital gain bracket end, MFS (\xBD of joint)", "\xA7 1(j)(5)(B)(ii)(I)", [["capgains.mfj.fifteen", 1, 2]], "31680000", CG.map((id2) => ({ id: id2, statuses: ["mfs"] }))), derived2("amt.exemption.mfs", "AMT exemption, MFS (50% of joint)", "\xA7 55(d)(1)(C)", [["amt.exemption.joint", 1, 2]], "7235000", [
56656
+ { id: "us.federal.amt.exemption", path: "\\.parameters\\.exemptMfs$" },
56657
+ { id: "us.federal.amt.amti", path: "\\.parameters\\.exemptMfs$" }
56658
+ ]), derived2("amt.phaseoutThreshold.unmarried", "AMT phase-out threshold, single and MFS (50% of joint)", "\xA7 55(d)(2)", [["amt.phaseoutThreshold.joint", 1, 2]], "51595000", [{ id: "us.federal.amt.exemption", path: "\\.parameters\\.thresh(Single|Mfs)$" }]), derived2("amt.mfsZeroAt", "AMTI at which the MFS exemption is fully phased out (threshold + 2 \xD7 exemption)", "\xA7 55(d)(1)(C), (d)(2)", [["amt.phaseoutThreshold.joint", 1, 2], ["amt.exemption.joint", 1, 1]], "66065000", [{ id: "us.federal.amt.amti", path: "\\.parameters\\.mfsZeroAt$" }]), derived2("amt.break28.mfs", "AMT 28% break, MFS (50%)", "\xA7 55(b)(1)(A)(iii)", [["amt.break28", 1, 2]], "12625000", [{ id: "us.federal.amt.tentative_minimum_tax", path: "\\.parameters\\.break28Mfs$" }]), derived2("amt.sub28", "2% of the AMT 28% break", "\xA7 55(b)(1)(A)(i)(II)", [["amt.break28", 2, 100]], "505000", [{ id: "us.federal.amt.tentative_minimum_tax", path: "\\.parameters\\.sub28$" }]), derived2("amt.sub28.mfs", "2% of the MFS AMT 28% break", "\xA7 55(b)(1)(A)(i)(II)", [["amt.break28", 1, 100]], "252500", [{ id: "us.federal.amt.tentative_minimum_tax", path: "\\.parameters\\.sub28Mfs$" }]), derived2("eitc.max0", "EITC maximum, no children (7.65% \xD7 earned income amount)", "\xA7 32(b)(1)", [["eitc.earnedIncomeAmount.0kids", 765, 1e4]], "68500", eitc("\\.parameters\\.max0$"), "100"), derived2("eitc.max1", "EITC maximum, one child (34%)", "\xA7 32(b)(1)", [["eitc.earnedIncomeAmount.1kid", 34, 100]], "457300", eitc("\\.parameters\\.max1$"), "100"), derived2("eitc.max2", "EITC maximum, two children (40%)", "\xA7 32(b)(1)", [["eitc.earnedIncomeAmount.2_kids", 40, 100]], "755200", eitc("\\.parameters\\.max2$"), "100"), derived2("eitc.max3", "EITC maximum, three or more children (45%)", "\xA7 32(b)(1)", [["eitc.earnedIncomeAmount.2_kids", 45, 100]], "849600", eitc("\\.parameters\\.max3$"), "100"), derived2("eitc.completedOther0", "EITC completed phase-out, no children (threshold + maximum \xF7 7.65%)", "\xA7 32(a)(2), (b)", [["eitc.phaseoutThreshold.0kids.other", 1, 1], ["eitc.max0", 1e4, 765]], "2016400", eitc("\\.parameters\\.completedOther0$"), "100"), derived2("eitc.completedMFJ0", "EITC completed phase-out, no children, joint", "\xA7 32(a)(2), (b)", [["eitc.phaseoutThreshold.0kids.mfj", 1, 1], ["eitc.max0", 1e4, 765]], "2768400", eitc("\\.parameters\\.completedMFJ0$"), "100"), derived2("kiddie.threshold", "kiddie tax threshold (2 \xD7 the \xA7 63(c)(5)(A) amount)", "\xA7 1(g)(4)(A)(ii)", [["dependentStdDed.floor", 2, 1]], "280000", [{ id: "us.federal.kiddie.net_unearned_income" }, { id: "us.federal.kiddie_tax" }]), derived2("qbi.threshold.joint", "QBI threshold, joint (200%)", "\xA7 199A(e)(2)(A)", [["qbi.threshold.other", 2, 1]], "41660000", [{ id: "us.federal.qbi.threshold", statuses: ["mfj"] }]), derived2("ebl.threshold.joint", "\xA7 461(l) threshold, joint (200%)", "\xA7 461(l)(3)(A)(ii)", [["ebl.threshold", 2, 1]], "52800000", [{ id: "us.federal.excess_business_loss_disallowed", path: "\\.parameters\\.thresholdJoint$" }]), derived2("ssWageBase.q1", "Schedule AI line 29 prorated limit, column (a) (\xBC of the wage base)", "Form 2210 Schedule AI line 29", [["ssWageBase", 1, 4]], "4807500", [{ id: "us.federal.estimated.annualized_installment_q1" }]), derived2("ssWageBase.q2", "Schedule AI line 29 prorated limit, column (b) (5/12)", "Form 2210 Schedule AI line 29", [["ssWageBase", 5, 12]], "8012500", [{ id: "us.federal.estimated.annualized_installment_q2" }]), derived2("ssWageBase.q3", "Schedule AI line 29 prorated limit, column (c) (2/3)", "Form 2210 Schedule AI line 29", [["ssWageBase", 2, 3]], "12820000", [{ id: "us.federal.estimated.annualized_installment_q3" }]));
56659
+ pctSteps = (start, from, year, lastYear) => {
56660
+ let v = start;
56661
+ for (let y = from + 1; y <= Math.min(year, lastYear); y++)
56662
+ v = (v * 101n * 2n + 100n) / 200n;
56663
+ return v;
56664
+ };
56665
+ PROJECTION_PARAMS.push({
56666
+ kind: "law",
56667
+ id: "salt.cap",
56668
+ label: "SALT limitation",
56669
+ statute: "\xA7 164(b)(7)(A)(ii), (b)(6)(B) (OBBBA \xA7 70120)",
56670
+ published2027: "4080400",
56671
+ byYear: (y) => y >= 2030 ? "1000000" : pctSteps(4080400n, 2027, y, 2029).toString(),
56672
+ rules: [{ id: "us.federal.salt_deduction", path: "\\.parameters\\.cap$" }]
56673
+ }, {
56674
+ kind: "law",
56675
+ id: "salt.threshold",
56676
+ label: "SALT phase-down threshold",
56677
+ statute: "\xA7 164(b)(7)(B)",
56678
+ published2027: "51005000",
56679
+ byYear: (y) => pctSteps(51005000n, 2027, y, 2029).toString(),
56680
+ rules: [{ id: "us.federal.salt_deduction", path: "\\.parameters\\.threshold$" }]
56681
+ }, {
56682
+ kind: "law",
56683
+ id: "salt.threshold.mfs",
56684
+ label: "SALT phase-down threshold, MFS (half)",
56685
+ statute: "\xA7 164(b)(7)(B)",
56686
+ published2027: "25502500",
56687
+ byYear: (y) => ((pctSteps(51005000n, 2027, y, 2029) + 1n) / 2n).toString(),
56688
+ rules: [{ id: "us.federal.salt_deduction", path: "\\.parameters\\.thresholdMfs$" }]
56689
+ });
56690
+ TAX_TABLE = ["250", "500", "1000", "1250", "1500", "2000", "2500", "5000", "300000", "10000000"];
56691
+ FIXED_LITERALS = {
56692
+ "us.federal.income_tax_before_credits": TAX_TABLE,
56693
+ "us.federal.income_tax_before_credits.tax_table": TAX_TABLE,
56694
+ "us.federal.income_tax_before_credits.feie": TAX_TABLE,
56695
+ "us.federal.kiddie_tax": TAX_TABLE,
56696
+ // Schedule AI: the Tax Table, and the ½-SE deduction's annualization factor written as den / (2 × num)
56697
+ "us.federal.estimated.annualized_installment_q1": [...TAX_TABLE, "1", "8"],
56698
+ "us.federal.estimated.annualized_installment_q2": [...TAX_TABLE, "5", "24"],
56699
+ "us.federal.estimated.annualized_installment_q3": [...TAX_TABLE, "2", "6"],
56700
+ "us.federal.estimated.annualized_installment_q4": [...TAX_TABLE, "1", "2"],
56701
+ "us.federal.qsbs_exclusion": ["1000000000"],
56702
+ // § 1202(b)(1)(A) $10,000,000 (only the § 1202(b)(4) $15M is indexed)
56703
+ "us.federal.salt_deduction": ["1000000"],
56704
+ // § 164(b)(7)(B) $10,000 floor
56705
+ "us.federal.ctc.tentative": ["50000"],
56706
+ // § 24(h)(4) $500 other-dependent credit, not indexed
56707
+ "us.federal.actc": ["250000"],
56708
+ // § 24(d)(1)(B)(i) $2,500 earned income floor
56709
+ "us.federal.actc.maximum": ["250000"],
56710
+ // § 21 as amended by OBBBA § 70405: $3,000/$6,000, 50%→35%→20%, $15,000 / $75,000 / $150,000 steps — none indexed
56711
+ "us.federal.cdcc.tentative": ["1", "20", "35", "50", "100", "300000", "600000", "1500000", "7500000", "15000000"],
56712
+ "us.federal.adoption.allowed": ["4000000"],
56713
+ // § 23(b)(2)(A)(ii) $40,000 phase-out range
56714
+ "us.federal.fiduciary.income_tax": ["10000", "30000", "60000"],
56715
+ // § 642(b) $600 / $300 / $100 exemptions
56716
+ "us.federal.household_employment_taxes": ["700000"],
56717
+ // § 3306(b)(1) $7,000 FUTA wage base
56718
+ "us.federal.employer.payroll_tax": ["700000"],
56719
+ "us.federal.eitc": ["2500", "5000"],
56720
+ // the printed EIC Table's $25 / $50 rows
56721
+ "us.federal.eitc_no_age_gate": ["2500", "5000"],
56722
+ "us.federal.se_tax.taxpayer": ["40000"],
56723
+ // § 6017 / § 1402(b) $400
56724
+ "us.federal.se_tax.spouse": ["40000"],
56725
+ "us.federal.hsa_deduction": ["100000"],
56726
+ // § 223(b)(3)(B) $1,000 catch-up
56727
+ "us.federal.student_loan_interest_deduction": ["250000", "1500000", "3000000"],
56728
+ // § 221(b)(1) $2,500; § 221(b)(2)(B) $15,000 / $30,000 ranges
56729
+ "us.federal.qbi.phase_in_range": ["7500000", "15000000"]
56730
+ // § 199A(b)(3)(B) as amended by OBBBA § 70105: $75,000 / $150,000
56731
+ };
56732
+ gt011 = (factId) => ({ kind: "cmp", op: "gt", left: { kind: "fact", factId }, right: { kind: "money", cents: "0" } });
56733
+ NOT_PROJECTED = {
56734
+ "us.federal.ptc": {
56735
+ usedWhen: { kind: "or", args: [gt011("marketplacePremiumsPaid"), gt011("advancePTC"), gt011("slcspAnnualPremium")] },
56736
+ reason: "the premium tax credit's applicable percentages are indexed to premium growth over income growth (\xA7 36B(b)(3)(A)(ii)) and its poverty line to HHS guidelines, neither of which is a price index the projection can carry forward"
56737
+ }
56738
+ };
56739
+ }
56740
+ });
56741
+
56742
+ // ../corpus-us-federal/dist/projection.js
56743
+ function percentToRational(p, label) {
56744
+ const m = /^(-?)(\d{1,2})(?:\.(\d{1,4}))?$/.exec(p.trim());
56745
+ if (!m)
56746
+ throw new Error(`${label}: expected a percent like 2.5 (at most 4 decimals), got "${p}"`);
56747
+ const frac = m[3] ?? "";
56748
+ const den = 100n * 10n ** BigInt(frac.length);
56749
+ const num = BigInt(m[2] + frac) * (m[1] ? -1n : 1n);
56750
+ if (num * 100n < -10n * den || num * 100n > 25n * den)
56751
+ throw new Error(`${label}: ${p}% is outside -10% to 25%`);
56752
+ return { num, den };
56753
+ }
56754
+ function roundTo(x, multiple, mode) {
56755
+ if (x.n < 0n)
56756
+ throw new Error("projection: negative amount");
56757
+ const d3 = x.d * multiple;
56758
+ const q = mode === "down" ? x.n / d3 : (2n * x.n + d3) / (2n * d3);
56759
+ return q * multiple;
56760
+ }
56761
+ function projectedValue(p, year, opts) {
56762
+ if (p.kind === "law")
56763
+ return BigInt(p.byYear(year));
56764
+ if (p.kind === "derived") {
56765
+ let sum = { n: 0n, d: 1n };
56766
+ for (const t of p.terms) {
56767
+ const q = PARAM_BY_ID.get(t.param);
56768
+ if (!q)
56769
+ throw new Error(`projection spec: unknown parameter ${t.param}`);
56770
+ const v2 = projectedValue(q, year, opts);
56771
+ const term = { n: v2 * BigInt(t.num), d: BigInt(t.den) };
56772
+ sum = { n: sum.n * term.d + term.n * sum.d, d: sum.d * term.d };
56773
+ }
56774
+ return roundTo(sum, BigInt(p.roundCents), p.roundMode);
56775
+ }
56776
+ const growth = percentToRational(p.index === "awi" ? opts.wageGrowthPercent ?? opts.inflationPercent : opts.inflationPercent, p.index === "awi" ? "wageGrowthPercent" : "inflationPercent");
56777
+ const g = { n: growth.den + growth.num, d: growth.den };
56778
+ const at = (y) => {
56779
+ const k = y - LAST_PUBLISHED_YEAR;
56780
+ let raw = { n: 0n, d: 1n };
56781
+ let base = 0n;
56782
+ for (const c2 of p.comps) {
56783
+ const term = mul({ n: BigInt(c2.baseCents), d: 1n }, mul({ n: BigInt(c2.ratio[0]), d: BigInt(c2.ratio[1]) }, pow(g, k)));
56784
+ raw = { n: raw.n * term.d + term.n * raw.d, d: raw.d * term.d };
56785
+ base += BigInt(c2.baseCents);
56786
+ }
56787
+ if (raw.n < base * raw.d)
56788
+ raw = { n: base, d: 1n };
56789
+ if (p.on === "amount")
56790
+ return roundTo(raw, BigInt(p.roundCents), p.roundMode);
56791
+ return base + roundTo({ n: raw.n - base * raw.d, d: raw.d }, BigInt(p.roundCents), p.roundMode);
56792
+ };
56793
+ let v = at(year);
56794
+ if (p.neverDecreases) {
56795
+ for (let y = LAST_PUBLISHED_YEAR; y < year; y++)
56796
+ if (at(y) > v)
56797
+ v = at(y);
56798
+ }
56799
+ return v;
56800
+ }
56801
+ function moneySlots(rule2) {
56802
+ const out = [];
56803
+ const walk = (x, path) => {
56804
+ if (Array.isArray(x))
56805
+ return x.forEach((v, i) => walk(v, `${path}[${i}]`));
56806
+ if (!x || typeof x !== "object")
56807
+ return;
56808
+ const o = x;
56809
+ if (o.kind === "money" && typeof o.cents === "string")
56810
+ out.push({ path, get: () => o.cents, set: (v) => o.cents = v });
56811
+ if (o.kind === "brackets" && Array.isArray(o.table))
56812
+ o.table.forEach((row2, i) => out.push({ path: `${path}.table[${i}]`, get: () => row2.threshold, set: (v) => row2.threshold = v }));
56813
+ if (o.type === "money" && typeof o.value === "string" && !("kind" in o))
56814
+ out.push({ path, get: () => o.value, set: (v) => o.value = v });
56815
+ for (const [k, v] of Object.entries(o)) {
56816
+ if (k === "citation")
56817
+ continue;
56818
+ if (k === "cases" && Array.isArray(v))
56819
+ v.forEach((c2, i) => walk(c2, `${path}.cases[${c2.when ?? i}]`));
56820
+ else
56821
+ walk(v, `${path}.${k}`);
56822
+ }
56823
+ };
56824
+ walk({ formula: rule2.formula, applicability: rule2.applicability, parameters: rule2.parameters }, "");
56825
+ return out;
56826
+ }
56827
+ function rulesEndingWith2027(base) {
56828
+ return base.rules.filter((r) => r.jurisdiction === "us.federal" && inWindow(r, `${LAST_PUBLISHED_YEAR}-06-30`) && r.effectiveTo === `${LAST_PUBLISHED_YEAR + 1}-01-01`);
56829
+ }
56830
+ function candidates(ruleId, cents2, path) {
56831
+ const cases = [...path.matchAll(/cases\[([^\]]+)\]/g)];
56832
+ const status = cases.length ? cases[cases.length - 1][1] : void 0;
56833
+ return PROJECTION_PARAMS.filter((p) => p.published2027 === cents2 && p.rules.some((r) => r.id === ruleId && (r.statuses === void 0 || status !== void 0 && r.statuses.includes(status)) && (r.path === void 0 || new RegExp(r.path).test(path))));
56834
+ }
56835
+ function classifyLiterals(base) {
56836
+ const out = [];
56837
+ for (const r of rulesEndingWith2027(base)) {
56838
+ if (NOT_PROJECTED[r.id])
56839
+ continue;
56840
+ for (const s of moneySlots(r)) {
56841
+ const cents2 = s.get();
56842
+ const c2 = candidates(r.id, cents2, s.path);
56843
+ const fixed = FIXED_LITERALS[r.id]?.includes(cents2) || cents2 === "0";
56844
+ if (c2.length === 1)
56845
+ out.push({ ruleId: r.id, path: s.path, cents: cents2, param: c2[0].id });
56846
+ else if (c2.length > 1)
56847
+ out.push({ ruleId: r.id, path: s.path, cents: cents2, error: `ambiguous: ${c2.map((p) => p.id).join(", ")}` });
56848
+ else if (fixed)
56849
+ out.push({ ruleId: r.id, path: s.path, cents: cents2, fixed: true });
56850
+ else
56851
+ out.push({ ruleId: r.id, path: s.path, cents: cents2, error: "neither an indexed parameter nor a declared fixed amount" });
56852
+ }
56853
+ }
56854
+ return out;
56855
+ }
56856
+ function projectCorpusInput(base, opts) {
56857
+ const { year } = opts;
56858
+ if (!Number.isInteger(year) || year <= LAST_PUBLISHED_YEAR || year > PROJECTION_HORIZON)
56859
+ throw new Error(`projection covers tax years ${LAST_PUBLISHED_YEAR + 1}\u2013${PROJECTION_HORIZON}; ${year} is published law or beyond the horizon`);
56860
+ const r = percentToRational(opts.inflationPercent, "inflationPercent");
56861
+ const w = opts.wageGrowthPercent === void 0 ? r : percentToRational(opts.wageGrowthPercent, "wageGrowthPercent");
56862
+ const fmtPct = (x) => {
56863
+ const scale = x.den / 100n;
56864
+ const neg3 = x.num < 0n;
56865
+ const a = neg3 ? -x.num : x.num;
56866
+ const digits = scale.toString().length - 1;
56867
+ const whole = (a / scale).toString();
56868
+ const frac = digits ? (a % scale).toString().padStart(digits, "0").replace(/0+$/, "") : "";
56869
+ return `${neg3 ? "-" : ""}${whole}${frac ? "." + frac : ""}`;
56870
+ };
56871
+ const tag = `projected.${year}.cpi-${fmtPct(r)}.awi-${fmtPct(w)}`;
56872
+ const from = `${year}-01-01`;
56873
+ const to = `${year + 1}-01-01`;
56874
+ const errors = classifyLiterals(base).filter((x) => x.error);
56875
+ if (errors.length)
56876
+ throw new Error(`projection spec is incomplete: ${errors.slice(0, 5).map((e) => `${e.ruleId} ${e.path} ${e.cents}: ${e.error}`).join("; ")}`);
56877
+ const added = [];
56878
+ for (const rule2 of rulesEndingWith2027(base)) {
56879
+ const clone2 = structuredClone(rule2);
56880
+ clone2.version = rule2.version + 1e3 * (year - LAST_PUBLISHED_YEAR);
56881
+ clone2.effectiveFrom = from;
56882
+ clone2.effectiveTo = to;
56883
+ const changed = [];
56884
+ if (NOT_PROJECTED[rule2.id]) {
56885
+ const np = NOT_PROJECTED[rule2.id];
56886
+ clone2.formula = { kind: "if", cond: np.usedWhen, then: { kind: "unsupported", reason: `${year} is a projection: ${np.reason}` }, else: clone2.formula };
56887
+ changed.push(`refuses when used \u2014 ${np.reason}`);
56888
+ } else {
56889
+ for (const s of moneySlots(clone2)) {
56890
+ const c2 = candidates(rule2.id, s.get(), s.path);
56891
+ if (c2.length !== 1)
56892
+ continue;
56893
+ const v = projectedValue(c2[0], year, opts).toString();
56894
+ if (v !== s.get())
56895
+ changed.push(`${c2[0].label}: ${s.get()} \u2192 ${v}`);
56896
+ s.set(v);
56897
+ }
56898
+ }
56899
+ clone2.title = `${rule2.title} \u2014 PROJECTED ${year}`;
56900
+ clone2.citation = {
56901
+ ...rule2.citation,
56902
+ source: `PROJECTION, NOT PUBLISHED LAW (${year}; C-CPI-U +${fmtPct(r)}%/yr, average wage index +${fmtPct(w)}%/yr assumed after the indexes used for 2027): ${rule2.citation.source}`,
56903
+ excerpt: `${rule2.citation.excerpt} [Projected from 2027 by each amount's statutory indexing formula at the assumed rates. Projected amounts: ${changed.length ? [...new Set(changed)].join("; ") : "none in this rule"}.]`
56904
+ };
56905
+ added.push(clone2);
56906
+ }
56907
+ if (year > 2028) {
56908
+ for (const [id2, cite] of Object.entries(SUNSET_AFTER_2028)) {
56909
+ const last = base.rules.filter((r2) => r2.id === id2).sort((a, b) => b.version - a.version)[0];
56910
+ if (!last)
56911
+ continue;
56912
+ added.push({
56913
+ id: id2,
56914
+ version: last.version + 1e3 * (year - LAST_PUBLISHED_YEAR),
56915
+ jurisdiction: last.jurisdiction,
56916
+ title: `${last.title} \u2014 ended after 2028`,
56917
+ citation: { source: cite, section: last.citation.section, url: last.citation.url, excerpt: `The provision does not apply to ${year}: ${cite}.` },
56918
+ effectiveFrom: from,
56919
+ effectiveTo: to,
56920
+ output: last.output,
56921
+ formula: last.output.type === "bool" ? { kind: "bool", value: false } : { kind: "money", cents: "0" }
56922
+ });
56923
+ }
56924
+ }
56925
+ const covered = new Set([...base.rules.filter((r2) => inWindow(r2, `${year}-06-30`)), ...added].map((r2) => r2.id));
56926
+ const missing = [...new Set(base.rules.filter((r2) => r2.jurisdiction === "us.federal" && inWindow(r2, `${LAST_PUBLISHED_YEAR}-06-30`)).map((r2) => r2.id))].filter((id2) => !covered.has(id2));
56927
+ if (missing.length)
56928
+ throw new Error(`projection has no ${year} version of: ${missing.join(", ")}`);
56929
+ return { name: base.name, version: `${base.version}+${tag}`, rules: [...base.rules, ...added], facts: base.facts };
56930
+ }
56931
+ function getProjectedCorpus(base, opts) {
56932
+ const key = JSON.stringify([base.version, opts.year, opts.inflationPercent, opts.wageGrowthPercent ?? null]);
56933
+ let c2 = cache.get(key);
56934
+ if (!c2) {
56935
+ c2 = loadCorpus(projectCorpusInput(base, opts));
56936
+ if (cache.size > 32)
56937
+ cache.clear();
56938
+ cache.set(key, c2);
56939
+ }
56940
+ return c2;
56941
+ }
56942
+ function projectionFromVersion(version2) {
56943
+ const m = /\+projected\.(\d{4})\.cpi-(-?[\d.]+)\.awi-(-?[\d.]+)$/.exec(version2);
56944
+ return m ? { year: Number(m[1]), inflationPercent: m[2], wageGrowthPercent: m[3] } : null;
56945
+ }
56946
+ var LAST_PUBLISHED_YEAR, PROJECTION_HORIZON, mul, pow, PARAM_BY_ID, inWindow, SUNSET_AFTER_2028, cache;
56947
+ var init_projection = __esm({
56948
+ "../corpus-us-federal/dist/projection.js"() {
56949
+ "use strict";
56950
+ init_dist();
56951
+ init_projection_spec();
56952
+ LAST_PUBLISHED_YEAR = 2027;
56953
+ PROJECTION_HORIZON = 2035;
56954
+ mul = (a, b) => ({ n: a.n * b.n, d: a.d * b.d });
56955
+ pow = (a, k) => {
56956
+ let r = { n: 1n, d: 1n };
56957
+ for (let i = 0; i < k; i++)
56958
+ r = mul(r, a);
56959
+ return r;
56960
+ };
56961
+ PARAM_BY_ID = new Map(PROJECTION_PARAMS.map((p) => [p.id, p]));
56962
+ inWindow = (r, d3) => r.effectiveFrom <= d3 && (r.effectiveTo === void 0 || d3 < r.effectiveTo);
56963
+ SUNSET_AFTER_2028 = {
56964
+ "us.federal.tips_deduction": "26 U.S.C. \xA7 224(h) (OBBBA \xA7 70201): no deduction for taxable years beginning after December 31, 2028",
56965
+ "us.federal.eligible.tips_deduction": "26 U.S.C. \xA7 224(h) (OBBBA \xA7 70201): no deduction for taxable years beginning after December 31, 2028",
56966
+ "us.federal.eligible.tips_occupation": "26 U.S.C. \xA7 224(h) (OBBBA \xA7 70201): no deduction for taxable years beginning after December 31, 2028",
56967
+ "us.federal.overtime_deduction": "26 U.S.C. \xA7 225(e) (OBBBA \xA7 70202): no deduction for taxable years beginning after December 31, 2028",
56968
+ "us.federal.car_loan_interest_deduction": "26 U.S.C. \xA7 163(h)(4)(D) (OBBBA \xA7 70203): applies only to taxable years beginning before January 1, 2029",
56969
+ "us.federal.senior_deduction": "26 U.S.C. \xA7 151(f)(4) (OBBBA \xA7 70103): applies only to taxable years beginning before January 1, 2029",
56970
+ "us.federal.senior_deduction.magi_threshold": "26 U.S.C. \xA7 151(f)(4) (OBBBA \xA7 70103): applies only to taxable years beginning before January 1, 2029"
56971
+ };
56972
+ cache = /* @__PURE__ */ new Map();
56973
+ }
56974
+ });
56975
+
56549
56976
  // ../corpus-us-federal/dist/extend.js
56550
56977
  var init_extend = __esm({
56551
56978
  "../corpus-us-federal/dist/extend.js"() {
@@ -56568,6 +56995,13 @@ function getCorpus() {
56568
56995
  cached2 = loadCorpus(corpusInput);
56569
56996
  return cached2;
56570
56997
  }
56998
+ function getProjectedFederalCorpus(opts) {
56999
+ return getProjectedCorpus(corpusInput, opts);
57000
+ }
57001
+ function corpusForVersion(version2) {
57002
+ const p = projectionFromVersion(version2);
57003
+ return p ? getProjectedFederalCorpus(p) : getCorpus();
57004
+ }
56571
57005
  var corpusInput, cached2, DEFAULT_TARGET;
56572
57006
  var init_dist2 = __esm({
56573
57007
  "../corpus-us-federal/dist/index.js"() {
@@ -56620,13 +57054,15 @@ var init_dist2 = __esm({
56620
57054
  init_standard_deduction();
56621
57055
  init_tips_eligibility();
56622
57056
  init_tips_overtime();
57057
+ init_projection();
56623
57058
  init_facts();
56624
57059
  init_extend();
56625
57060
  init_staleness();
56626
57061
  init_occupations();
57062
+ init_projection();
56627
57063
  corpusInput = {
56628
57064
  name: "@invaro/opentax-corpus-us-federal",
56629
- version: "0.44.0",
57065
+ version: "0.46.0",
56630
57066
  rules: [
56631
57067
  ...corporateRules,
56632
57068
  ...corporate1120Rules,
@@ -60274,26 +60710,26 @@ function composeAR(input2, evalStateTax, notes) {
60274
60710
  regular.notes.push(`AR line 26: Regular Income Tax Table kept \u2014 tax ${fmtD(regular.tax)} (net ${fmtD(regular.netTax)}) vs ${fmtD(lowOk.tax)} (net ${fmtD(lowOk.netTax)}) on the Low Income Tax Table (pass arUseLowIncomeTable: true to override)`);
60275
60711
  return regular;
60276
60712
  };
60277
- const candidates = [];
60713
+ const candidates2 = [];
60278
60714
  if (married && input2.arStatus4 !== false && (input2.arStatus4 === true || spouseGiven)) {
60279
60715
  if (!spouseGiven)
60280
60716
  notes.push("AR filing status 4: arSpouseIncome not given \u2014 the spouse's column B carries only line 18B (pass arSpouseIncome = the spouse's share of lines 8-22 and arSpouseAdjustments)");
60281
60717
  const s4 = best(true);
60282
60718
  if (s4)
60283
- candidates.push(s4);
60719
+ candidates2.push(s4);
60284
60720
  }
60285
- if (!(married && input2.arStatus4 === true) || candidates.length === 0) {
60721
+ if (!(married && input2.arStatus4 === true) || candidates2.length === 0) {
60286
60722
  const s2 = best(false);
60287
60723
  if (s2)
60288
- candidates.push(s2);
60724
+ candidates2.push(s2);
60289
60725
  }
60290
- let chosen = candidates[0];
60291
- for (const cand of candidates)
60726
+ let chosen = candidates2[0];
60727
+ for (const cand of candidates2)
60292
60728
  if (cand.netTax < chosen.netTax)
60293
60729
  chosen = cand;
60294
- if (candidates.length === 2) {
60295
- const s4 = candidates.find((x) => x.status4);
60296
- const s2 = candidates.find((x) => !x.status4);
60730
+ if (candidates2.length === 2) {
60731
+ const s4 = candidates2.find((x) => x.status4);
60732
+ const s2 = candidates2.find((x) => !x.status4);
60297
60733
  notes.push(`AR filing status: married filing separately on the same return (status 4) nets ${fmtD(s4.netTax)}; married filing joint (status 2) nets ${fmtD(s2.netTax)} \u2014 status ${chosen.status4 ? "4" : "2"} composed ('Use the method that suits you best'; pass arStatus4 to force)`);
60298
60734
  } else if (married && input2.arStatus4 === void 0 && !spouseGiven)
60299
60735
  notes.push("AR filing status 2 (joint) composed \u2014 Arkansas has ONE rate table for every status, so a two-income couple usually saves with status 4 (separately on the same return); pass arSpouseIncome (the spouse's share of lines 8-22) to compare");
@@ -61453,12 +61889,12 @@ function composeME(input2, evalStateTax, notes) {
61453
61889
  }
61454
61890
  const fedEic = D6(input2.federalEITC);
61455
61891
  const hasQc = input2.meHasQualifyingChild === true;
61456
- const eitc = fedEic > 0n ? rd25(evalStateTax("us.me.eitc", 0n, { meFederalEic: fedEic, meHasQualifyingChild: hasQc })) : 0n;
61457
- if (eitc > 0n)
61458
- notes.push(`ME Schedule A line 4: earned income tax credit ${fmtD(eitc)} = ${hasQc ? "25%" : "50% (no qualifying child)"} of the ${fmtD(fedEic)} federal EIC; refundable${!hasQc && deps > 0 && input2.meHasQualifyingChild === void 0 ? " \u2014 pass meHasQualifyingChild if a dependent is an EIC qualifying child (25%)" : ""}`);
61892
+ const eitc2 = fedEic > 0n ? rd25(evalStateTax("us.me.eitc", 0n, { meFederalEic: fedEic, meHasQualifyingChild: hasQc })) : 0n;
61893
+ if (eitc2 > 0n)
61894
+ notes.push(`ME Schedule A line 4: earned income tax credit ${fmtD(eitc2)} = ${hasQc ? "25%" : "50% (no qualifying child)"} of the ${fmtD(fedEic)} federal EIC; refundable${!hasQc && deps > 0 && input2.meHasQualifyingChild === void 0 ? " \u2014 pass meHasQualifyingChild if a dependent is an EIC qualifying child (25%)" : ""}`);
61459
61895
  const studentLoan = min22(D6(input2.meStudentLoanCredit), 250000n);
61460
61896
  const otherRef = D6(input2.refundableCredits);
61461
- const l25c = depCredit + ccRefundable + adcRefundable + eitc + studentLoan + otherRef;
61897
+ const l25c = depCredit + ccRefundable + adcRefundable + eitc2 + studentLoan + otherRef;
61462
61898
  const totalIncomeGiven = typeof input2.meTotalIncome === "number";
61463
61899
  const totalIncome = totalIncomeGiven ? rd25(c(input2.meTotalIncome)) : l14;
61464
61900
  let l25d = 0n;
@@ -61536,7 +61972,7 @@ function composeME(input2, evalStateTax, notes) {
61536
61972
  ...put("A1_dependent_exemption_credit", depCredit),
61537
61973
  ...put("A2_child_care_refundable", ccRefundable),
61538
61974
  ...put("A3_adult_care_refundable", adcRefundable),
61539
- ...put("A4_earned_income_credit", eitc),
61975
+ ...put("A4_earned_income_credit", eitc2),
61540
61976
  ...put("A5_student_loan_credit", studentLoan),
61541
61977
  ...put("25c_refundable_credits", l25c),
61542
61978
  ...put("25d_property_tax_fairness_credit", l25d),
@@ -62615,17 +63051,17 @@ function composeVT(input2, evalStateTax, notes) {
62615
63051
  const kids = Math.max(0, input2.vtChildrenSixOrUnder ?? 0);
62616
63052
  const ctc = kids > 0 ? tryEval("us.vt.child_tax_credit", 0n, { ...agiFacts, vtChildrenSixOrUnder: kids }, "Schedule IN-112 line 4 (child tax credit)") ?? 0n : 0n;
62617
63053
  const fedEic = D11(input2.federalEITC);
62618
- const eitc = fedEic > 0n ? tryEval("us.vt.eitc", 0n, { vtFederalEic: fedEic, vtEitcQualifyingChildren: Math.max(0, input2.vtEitcQualifyingChildren ?? 0) }, "Schedule IN-112 line 7 (earned income credit)") ?? 0n : 0n;
63054
+ const eitc2 = fedEic > 0n ? tryEval("us.vt.eitc", 0n, { vtFederalEic: fedEic, vtEitcQualifyingChildren: Math.max(0, input2.vtEitcQualifyingChildren ?? 0) }, "Schedule IN-112 line 7 (earned income credit)") ?? 0n : 0n;
62619
63055
  const veteran = input2.vtVeteranDischargeRecord === true ? tryEval("us.vt.veteran_credit", 0n, { ...agiFacts, vtVeteranDischargeRecord: true }, "Schedule IN-112 line 12 (veteran credit)") ?? 0n : 0n;
62620
63056
  if (cdcc > 0n)
62621
63057
  notes.push(`VT Schedule IN-112 line 2: child and dependent care credit ${fmtD(cdcc)} \u2014 72% of the federal credit, REFUNDABLE (\xA7 5828c)`);
62622
63058
  if (kids > 0)
62623
63059
  notes.push(ctc > 0n ? `VT Schedule IN-112 line 4: child tax credit ${fmtD(ctc)} for ${kids} child(ren) six or younger \u2014 $1,000 each less $20 per $1,000 or fraction of federal AGI over $125,000 regardless of filing status, REFUNDABLE (\xA7 5830f; 2025 Act 71 raised the age from five to six)` : `VT Schedule IN-112 line 4: no child tax credit \u2014 federal AGI ${fmtD(l1)} is above $174,000, where the $20-per-$1,000 reduction exhausts the $1,000`);
62624
63060
  if (fedEic > 0n)
62625
- notes.push(`VT Schedule IN-112 line 7: earned income credit ${fmtD(eitc)} \u2014 ${input2.vtEitcQualifyingChildren > 0 ? "38% of the federal credit with qualifying children" : "100% of the federal credit with NO qualifying children (2025 Act 71 \xA7 2, up from 38%)"}, REFUNDABLE`);
63061
+ notes.push(`VT Schedule IN-112 line 7: earned income credit ${fmtD(eitc2)} \u2014 ${input2.vtEitcQualifyingChildren > 0 ? "38% of the federal credit with qualifying children" : "100% of the federal credit with NO qualifying children (2025 Act 71 \xA7 2, up from 38%)"}, REFUNDABLE`);
62626
63062
  if (input2.vtVeteranDischargeRecord === true)
62627
63063
  notes.push(veteran > 0n ? `VT Schedule IN-112 line 12: veteran tax credit ${fmtD(veteran)} \u2014 $250 less $5 per full $100 of federal AGI over $25,000, REFUNDABLE (\xA7 5830g, new for 2025)` : `VT Schedule IN-112 line 12: no veteran credit \u2014 federal AGI ${fmtD(l1)} is $30,000 or more`);
62628
- const l26c = cdcc + ctc + eitc + veteran + D11(input2.refundableCredits);
63064
+ const l26c = cdcc + ctc + eitc2 + veteran + D11(input2.refundableCredits);
62629
63065
  const l26d = D11(input2.vtRealEstateWithholding);
62630
63066
  const l26e = D11(input2.vtNonresidentEstimatedPayments);
62631
63067
  const l26f = l26a + l26b + l26c + l26d + l26e;
@@ -62691,7 +63127,7 @@ function composeVT(input2, evalStateTax, notes) {
62691
63127
  "26b_estimated_and_extension_payments": fmtD(l26b),
62692
63128
  "IN112_II_2_child_dependent_care_credit": fmtD(cdcc),
62693
63129
  "IN112_II_4_child_tax_credit": fmtD(ctc),
62694
- "IN112_II_7_earned_income_credit": fmtD(eitc),
63130
+ "IN112_II_7_earned_income_credit": fmtD(eitc2),
62695
63131
  "IN112_II_12_veteran_credit": fmtD(veteran),
62696
63132
  "IN112_II_13_total_refundable_credits": fmtD(l26c),
62697
63133
  "26c_refundable_credits": fmtD(l26c),
@@ -62906,11 +63342,11 @@ function composeHI(input2, evalStateTax, notes) {
62906
63342
  if (l31 > 0n)
62907
63343
  notes.push("HI line 31: $25 child passenger restraint system credit (\xA7 235-15; attach the invoice)");
62908
63344
  const fedEic = D12(input2.federalEITC);
62909
- const eitc = fedEic > 0n ? rd25(evalStateTax("us.hi.eitc", 0n, { hiFederalEic: fedEic })) : 0n;
62910
- if (eitc > 0n)
62911
- notes.push(`HI Schedule CR line 8 (Form N-356): earned income tax credit ${fmtD(eitc)} = 40% of the ${fmtD(fedEic)} federal EIC; refundable (same filing status and dependents as the federal return${mfs ? " \u2014 a separate filer qualifies only when the federal EIC was allowed under \xA7 32(d)(2)" : ""})`);
63345
+ const eitc2 = fedEic > 0n ? rd25(evalStateTax("us.hi.eitc", 0n, { hiFederalEic: fedEic })) : 0n;
63346
+ if (eitc2 > 0n)
63347
+ notes.push(`HI Schedule CR line 8 (Form N-356): earned income tax credit ${fmtD(eitc2)} = 40% of the ${fmtD(fedEic)} federal EIC; refundable (same filing status and dependents as the federal return${mfs ? " \u2014 a separate filer qualifies only when the federal EIC was allowed under \xA7 32(d)(2)" : ""})`);
62912
63348
  const otherRef = D12(input2.refundableCredits);
62913
- const l32 = eitc + otherRef;
63349
+ const l32 = eitc2 + otherRef;
62914
63350
  const l33 = l28 + l29 + l30 + l31 + l32;
62915
63351
  const l34 = l27 - l33;
62916
63352
  let osc = 0n;
@@ -62986,7 +63422,7 @@ function composeHI(input2, evalStateTax, notes) {
62986
63422
  ...put("29_renters_credit", l29),
62987
63423
  ...put("30_child_dependent_care_credit", l30),
62988
63424
  ...put("31_child_passenger_restraint_credit", l31),
62989
- ...put("CR8_earned_income_credit", eitc),
63425
+ ...put("CR8_earned_income_credit", eitc2),
62990
63426
  ...put("32_schedule_cr_refundable_credits", l32),
62991
63427
  "33_total_refundable_credits": fmtD(l33),
62992
63428
  "34_adjusted_tax_liability": fmtD(l34),
@@ -64600,6 +65036,703 @@ var init_shape = __esm({
64600
65036
  }
64601
65037
  });
64602
65038
 
65039
+ // ../compose/dist/form2210.js
65040
+ function scopeFlags(facts2) {
65041
+ const out = [];
65042
+ const b = (id2) => facts2[id2]?.type === "bool" && facts2[id2].value === true;
65043
+ if (b("isClaimedAsDependent"))
65044
+ out.push("a dependent's standard deduction depends on the year's earned income (\xA7 63(c)(5)); line 7 takes the deduction in full, which the period's annualized earned income would change");
65045
+ if (b("isSubjectToKiddieTax"))
65046
+ out.push("Form 8615 uses the parent's annual taxable income");
65047
+ const month = facts2.rentalPlacedInServiceMonth;
65048
+ if (month && month.type === "int" && BigInt(month.value) > 0n && money43(facts2, "rentalDepreciableBasis") > 0n)
65049
+ out.push("rental property placed in service this year: its first-year depreciation depends on the month (Pub. 946 Table A-6), not on an annualized period");
65050
+ return out;
65051
+ }
65052
+ function nthWeekday(y, m, weekday, n) {
65053
+ const first = Date.UTC(y, m - 1, 1) / 864e5;
65054
+ const dow = new Date(first * 864e5).getUTCDay();
65055
+ return first + (weekday - dow + 7) % 7 + (n - 1) * 7;
65056
+ }
65057
+ function observed(y, m, d3) {
65058
+ const n = Date.UTC(y, m - 1, d3) / 864e5;
65059
+ const dow = new Date(n * 864e5).getUTCDay();
65060
+ return dow === 6 ? n - 1 : dow === 0 ? n + 1 : n;
65061
+ }
65062
+ function isLegalHoliday(n) {
65063
+ const y = Number(isoOf(n).slice(0, 4));
65064
+ return [
65065
+ observed(y, 1, 1),
65066
+ observed(y + 1, 1, 1),
65067
+ nthWeekday(y, 1, 1, 3),
65068
+ observed(y, 4, 16),
65069
+ observed(y, 6, 19),
65070
+ nthWeekday(y, 9, 1, 1)
65071
+ ].includes(n);
65072
+ }
65073
+ function nextBusinessDay(n) {
65074
+ let d3 = n;
65075
+ for (; ; ) {
65076
+ const dow = new Date(d3 * 864e5).getUTCDay();
65077
+ if (dow !== 0 && dow !== 6 && !isLegalHoliday(d3))
65078
+ return d3;
65079
+ d3 += 1;
65080
+ }
65081
+ }
65082
+ function ratePeriods(year) {
65083
+ const q = (y2, n, from, to) => ({
65084
+ from: dayNum(from),
65085
+ to: dayNum(to),
65086
+ quarter: `${y2}-Q${n}`,
65087
+ divisor: isLeap(y2) ? 366 : 365
65088
+ });
65089
+ const y = year;
65090
+ return [
65091
+ q(y, 2, `${y}-04-16`, `${y}-06-30`),
65092
+ q(y, 3, `${y}-07-01`, `${y}-09-30`),
65093
+ q(y, 4, `${y}-10-01`, `${y}-12-31`),
65094
+ q(y + 1, 1, `${y + 1}-01-01`, `${y + 1}-03-31`),
65095
+ q(y + 1, 2, `${y + 1}-04-01`, `${y + 1}-04-15`)
65096
+ ];
65097
+ }
65098
+ function composeForm2210(input2, run) {
65099
+ const { facts: facts2, taxYear: year } = input2;
65100
+ if (![2025, 2026, 2027].includes(year))
65101
+ throw new Error(`Form 2210 is composed for tax years 2025, 2026 and 2027, not ${year}`);
65102
+ const notes = [];
65103
+ const boxes = [];
65104
+ const get = (target) => run(facts2, target);
65105
+ const line1 = rd26(get("us.federal.income_tax_after_credits"));
65106
+ let other = get("us.federal.other_taxes");
65107
+ const withheld = money43(facts2, "federalTaxWithheld");
65108
+ const household = get("us.federal.household_employment_taxes");
65109
+ const line32 = rd26(get("us.federal.refundable_credits"));
65110
+ if (household > 0n && withheld === 0n && line1 + rd26(other - household) - line32 < 100000n) {
65111
+ other -= household;
65112
+ notes.push("line 2 leaves out the household employment taxes: no income tax was withheld and, without them, the year's tax is under $1,000 (Instructions for Form 2210, line 2)");
65113
+ }
65114
+ const line2 = rd26(other);
65115
+ const line4 = line1 + line2 - line32;
65116
+ const line5 = mulRate2(line4, 90n, 100n);
65117
+ const line6 = rd26(withheld);
65118
+ const line72 = line4 - line6;
65119
+ const partI = {
65120
+ "1_tax_after_credits": fmt2(line1),
65121
+ "2_other_taxes": fmt2(line2),
65122
+ "3_refundable_credits": fmt2(line32),
65123
+ "4_current_year_tax": fmt2(line4)
65124
+ };
65125
+ const result = { taxYear: year, partI, boxes, notes };
65126
+ if (line4 < 100000n) {
65127
+ result.noPenalty = "line 4 is less than $1,000: no penalty (\xA7 6654(e)(1))";
65128
+ return result;
65129
+ }
65130
+ partI["5_90_percent_of_line_4"] = fmt2(rd26(line5));
65131
+ partI["6_withholding"] = fmt2(line6);
65132
+ partI["7_line_4_minus_line_6"] = fmt2(line72);
65133
+ if (line72 < 100000n) {
65134
+ result.noPenalty = "line 7 is less than $1,000: no penalty (\xA7 6654(e)(1))";
65135
+ return result;
65136
+ }
65137
+ let line92;
65138
+ if (input2.noPriorYearReturn) {
65139
+ line92 = rd26(line5);
65140
+ partI["8_prior_year_tax"] = "not applicable (no prior-year return, or it covered under 12 months)";
65141
+ } else {
65142
+ const prior = facts2.priorYearTax;
65143
+ const priorAgi = facts2.priorYearAGI;
65144
+ if (!prior || prior.type !== "money")
65145
+ throw new MissingInput(["priorYearTax"]);
65146
+ if (!priorAgi || priorAgi.type !== "money")
65147
+ throw new MissingInput(["priorYearAGI"]);
65148
+ const mfs = facts2.filingStatus?.type === "enum" && facts2.filingStatus.value === "mfs";
65149
+ const high = BigInt(priorAgi.value) > (mfs ? 7500000n : 15000000n);
65150
+ const line8 = rd26(mulRate2(BigInt(prior.value), high ? 110n : 100n, 100n));
65151
+ partI["8_prior_year_tax"] = fmt2(line8) + (high ? ` (110% \u2014 prior-year AGI over ${mfs ? "$75,000" : "$150,000"})` : "");
65152
+ line92 = minC(rd26(line5), line8);
65153
+ }
65154
+ partI["9_required_annual_payment"] = fmt2(line92);
65155
+ if (line6 >= line92) {
65156
+ result.noPenalty = "line 6 (withholding) is at least line 9 (the required annual payment): no penalty";
65157
+ return result;
65158
+ }
65159
+ let annualized;
65160
+ if (input2.periods) {
65161
+ const ai = scheduleAI(input2, run, line92, notes);
65162
+ if ("refused" in ai)
65163
+ result.scheduleAI = ai;
65164
+ else {
65165
+ result.scheduleAI = { columns: ai.columns };
65166
+ annualized = ai.installments;
65167
+ }
65168
+ }
65169
+ const installments = [{ m: "regular", line10: Array(4).fill(rd26(mulRate2(line92, 25n, 100n))) }];
65170
+ if (annualized)
65171
+ installments.push({ m: "annualized", line10: annualized });
65172
+ const modes = input2.withholdingByDate ? ["even", "actual"] : ["even"];
65173
+ const runs = modes.map((w) => ({ w, notes: [], res: {} }));
65174
+ for (const r of runs)
65175
+ for (const { m, line10 } of installments)
65176
+ r.res[m] = partIII(input2, line10, r.notes, r.w, line4);
65177
+ const all = runs.flatMap((r) => installments.map(({ m }) => ({ w: r.w, m, r: r.res[m], run: r })));
65178
+ const unpriced = all.find((x) => x.r.penaltyCents === void 0);
65179
+ let chosen = runs[0];
65180
+ if (unpriced) {
65181
+ result.penalty = { refused: `${unpriced.m} method${modes.length > 1 ? `, withholding ${unpriced.w === "even" ? "spread evenly" : "on its actual dates"}` : ""}: ${unpriced.r.refused}` };
65182
+ } else {
65183
+ const best = all.reduce((a, b) => BigInt(b.r.penaltyCents) < BigInt(a.r.penaltyCents) ? b : a);
65184
+ chosen = best.run;
65185
+ result.penalty = { method: best.m, amount: best.r.penalty, amountCents: best.r.penaltyCents };
65186
+ if (best.m === "annualized")
65187
+ boxes.push("C");
65188
+ if (best.w === "actual")
65189
+ boxes.push("D");
65190
+ if (modes.length > 1)
65191
+ notes.push(best.w === "actual" ? "box D: treating withholding as paid on the dates it was actually withheld gives the lower penalty" : "withholding is treated as paid one-fourth on each due date: the actual withholding dates (box D) would not lower the penalty");
65192
+ }
65193
+ result.partIII = chosen.res;
65194
+ notes.push(...chosen.notes);
65195
+ result.notes = [...new Set(notes)];
65196
+ return result;
65197
+ }
65198
+ function scheduleAI(input2, run, line92, notes) {
65199
+ const { facts: facts2 } = input2;
65200
+ const periods = input2.periods;
65201
+ const refused = [];
65202
+ for (const [id2, kind] of Object.entries(SCHEDULE_AI_FACTS)) {
65203
+ if (typeof kind === "object" && money43(facts2, id2) !== 0n)
65204
+ refused.push(`${id2}: ${kind.refuse}`);
65205
+ }
65206
+ refused.push(...scopeFlags(facts2));
65207
+ if (refused.length)
65208
+ return { refused };
65209
+ const cols = [periods.mar31, periods.may31, periods.aug31];
65210
+ const names = ["mar31", "may31", "aug31"];
65211
+ const missing = [];
65212
+ cols.forEach((p, i) => {
65213
+ for (const id2 of Object.keys(p)) {
65214
+ const kind = SCHEDULE_AI_FACTS[id2];
65215
+ if (kind === void 0)
65216
+ throw new Error(`periods.${names[i]}.${id2}: not a fact Schedule AI reads`);
65217
+ if (kind !== "annualize")
65218
+ throw new Error(`periods.${names[i]}.${id2}: not a period amount (${kind === "keep" ? "it is used as is in every column" : "out of scope"})`);
65219
+ if (p[id2].type !== "money")
65220
+ throw new Error(`periods.${names[i]}.${id2}: must be money`);
65221
+ }
65222
+ for (const [id2, kind] of Object.entries(SCHEDULE_AI_FACTS)) {
65223
+ if (kind === "annualize" && money43(facts2, id2) !== 0n && p[id2] === void 0)
65224
+ missing.push(`periods.${names[i]}.${id2}`);
65225
+ }
65226
+ });
65227
+ if (missing.length)
65228
+ throw new MissingInput(missing);
65229
+ const columns = [];
65230
+ const installments = [];
65231
+ let prior27 = 0n;
65232
+ let prior26minus27 = 0n;
65233
+ const line24 = rd26(mulRate2(line92, 25n, 100n));
65234
+ for (let i = 0; i < 4; i++) {
65235
+ const a = ANNUALIZATION[i];
65236
+ const colFacts = { ...facts2 };
65237
+ if (i < 3) {
65238
+ for (const [id2, kind] of Object.entries(SCHEDULE_AI_FACTS)) {
65239
+ if (kind !== "annualize")
65240
+ continue;
65241
+ const period = cols[i][id2];
65242
+ const v = period && period.type === "money" ? BigInt(period.value) : 0n;
65243
+ if (v === 0n && colFacts[id2] === void 0)
65244
+ continue;
65245
+ colFacts[id2] = { type: "money", value: mulRate2(v, a.num, a.den).toString() };
65246
+ }
65247
+ for (const id2 of ["selfEmploymentNetProfit", "spouseSelfEmploymentNetProfit"]) {
65248
+ const p = cols[i][id2];
65249
+ const ne = p && p.type === "money" ? mulRate2(BigInt(p.value), 9235n, 10000n) : 0n;
65250
+ if (ne > 0n && ne < 40000n)
65251
+ return {
65252
+ refused: [
65253
+ `periods.${names[i]}.${id2}: the period's net earnings from self-employment are under $400, which Part II line 28 enters as zero while the period's income still counts on line 1 \u2014 not modeled`
65254
+ ]
65255
+ };
65256
+ }
65257
+ }
65258
+ const g = (t) => run(colFacts, t);
65259
+ const saltPaid = money43(colFacts, "stateAndLocalTaxesPaid");
65260
+ if (i < 3 && saltPaid > 0n && g("us.federal.salt_deduction") < saltPaid && g("us.federal.itemized_deductions") >= g("us.federal.standard_deduction"))
65261
+ return {
65262
+ refused: [
65263
+ `column (${"abcd"[i]}): the annualized state and local taxes exceed the year's SALT limit, and the instructions don't say whether the period's itemized deductions (line 4) are limited before or after line 5's annualization`
65264
+ ]
65265
+ };
65266
+ const agi2 = g("us.federal.agi");
65267
+ const deduction = g("us.federal.deduction_election");
65268
+ const ti = g("us.federal.taxable_income");
65269
+ const line14 = g("us.federal.income_tax_before_credits");
65270
+ const se = g("us.federal.se_tax");
65271
+ const amt = g("us.federal.amt");
65272
+ const otherTaxes = g("us.federal.other_taxes");
65273
+ const beforeNonref = g("us.federal.tax_before_nonrefundable_credits");
65274
+ const afterCredits = g("us.federal.income_tax_after_credits");
65275
+ const refundable = g("us.federal.refundable_credits");
65276
+ const line16 = amt + otherTaxes - se;
65277
+ const line17 = rd26(line14) + rd26(se) + rd26(line16);
65278
+ const line18 = rd26(beforeNonref - afterCredits) + rd26(refundable);
65279
+ const line19 = max029(line17 - line18);
65280
+ const line21 = rd26(mulRate2(line19, a.pct[0], a.pct[1]));
65281
+ const line22 = prior27;
65282
+ const line23 = max029(line21 - line22);
65283
+ const line25 = i === 0 ? 0n : prior26minus27;
65284
+ const line26 = line24 + line25;
65285
+ const line27 = minC(line23, line26);
65286
+ columns.push({
65287
+ column: `(${"abcd"[i]}) ${["1/1\u20133/31", "1/1\u20135/31", "1/1\u20138/31", "1/1\u201312/31"][i]}`,
65288
+ "2_annualization": a.label,
65289
+ "3_annualized_agi": D13(agi2),
65290
+ "8_deduction": D13(deduction),
65291
+ "13_annualized_taxable_income": D13(ti),
65292
+ "14_tax": D13(line14),
65293
+ "15_se_tax": D13(se),
65294
+ "16_other_taxes_incl_amt": D13(line16),
65295
+ "17_total_tax": fmt2(line17),
65296
+ "18_credits": fmt2(line18),
65297
+ "19_net": fmt2(line19),
65298
+ "20_applicable_percentage": `${Number(a.pct[0]) / (Number(a.pct[1]) / 100)}%`,
65299
+ "21": fmt2(line21),
65300
+ "22": fmt2(line22),
65301
+ "23": fmt2(line23),
65302
+ "24": fmt2(line24),
65303
+ ...i > 0 ? { "25": fmt2(line25) } : {},
65304
+ "26": fmt2(line26),
65305
+ "27_required_installment": fmt2(line27)
65306
+ });
65307
+ installments.push(line27);
65308
+ prior27 += line27;
65309
+ prior26minus27 = line26 - line27;
65310
+ }
65311
+ notes.push("Schedule AI: each column is the full return evaluated on the period's cumulative amounts \xD7 the annualization amount (line 2), with the standard deduction in full (line 7); lines 14\u201319 are that evaluation's tax, self-employment tax, other taxes including AMT, and credits");
65312
+ return { columns, installments };
65313
+ }
65314
+ function partIII(input2, line10, notes, withholdingDates, line4) {
65315
+ const year = input2.taxYear;
65316
+ const printed = [`${year}-04-15`, `${year}-06-15`, `${year}-09-15`, `${year + 1}-01-15`].map(dayNum);
65317
+ const effective = printed.map(nextBusinessDay);
65318
+ const dueLabels = printed.map((n, i) => isoOf(n) + (effective[i] !== n ? ` (payable ${isoOf(effective[i])}, \xA7 7503)` : ""));
65319
+ const jan31 = dayNum(`${year + 1}-01-31`);
65320
+ const filedBy = input2.filedAndPaidInFullOn ? dayNum(input2.filedAndPaidInFullOn) : void 0;
65321
+ const section6654h = filedBy !== void 0 && filedBy <= jan31;
65322
+ const asMade = (day) => {
65323
+ for (let i = 0; i < 4; i++)
65324
+ if (day > printed[i] && day <= effective[i])
65325
+ return printed[i];
65326
+ return day;
65327
+ };
65328
+ const estimated = input2.payments.map((p) => ({ day: asMade(dayNum(p.date)), amount: p.amount })).filter((p) => {
65329
+ if (p.amount < 0n)
65330
+ throw new Error("a payment amount can't be negative");
65331
+ return p.amount > 0n;
65332
+ });
65333
+ let withholding;
65334
+ if (withholdingDates === "actual") {
65335
+ const list = input2.withholdingByDate;
65336
+ const total2 = list.reduce((t, p) => t + p.amount, 0n);
65337
+ if (total2 !== money43(input2.facts, "federalTaxWithheld"))
65338
+ throw new Error(`withholdingByDate totals ${fmt2(total2, true)} but federalTaxWithheld is ${fmt2(money43(input2.facts, "federalTaxWithheld"), true)} \u2014 they must agree`);
65339
+ withholding = list.map((p) => ({ day: asMade(dayNum(p.date)), amount: p.amount })).filter((p) => p.amount > 0n);
65340
+ } else {
65341
+ const w = money43(input2.facts, "federalTaxWithheld");
65342
+ const quarter = w / 4n;
65343
+ withholding = printed.map((day, i) => ({ day, amount: i < 3 ? quarter : w - 3n * quarter })).filter((p) => p.amount > 0n);
65344
+ }
65345
+ const windowOf = (day) => {
65346
+ for (let i = 0; i < 4; i++)
65347
+ if (day <= effective[i])
65348
+ return i;
65349
+ return section6654h && day <= filedBy ? 3 : 4;
65350
+ };
65351
+ const line112 = [0n, 0n, 0n, 0n];
65352
+ for (const p of [...estimated, ...withholding]) {
65353
+ const w = windowOf(p.day);
65354
+ if (w < 4)
65355
+ line112[w] += p.amount;
65356
+ }
65357
+ if (section6654h) {
65358
+ const paidByFiling = [...estimated, ...withholding].filter((p) => p.day <= filedBy).reduce((t, p) => t + p.amount, 0n);
65359
+ if (paidByFiling < line4)
65360
+ throw new Error(`filedAndPaidInFullOn: \xA7 6654(h) needs the tax paid in full by ${input2.filedAndPaidInFullOn}, but the payments and withholding through that date total ${fmt2(paidByFiling, true)}, less than line 4 (${fmt2(line4)}) \u2014 list the payment made with the return in payments`);
65361
+ }
65362
+ const L11 = line112.map(rd26);
65363
+ const A = { "10": line10, "11": L11, "12": [], "13": [], "14": [], "15": [], "16": [], "17": [], "18": [] };
65364
+ let prev18 = 0n;
65365
+ let prev16plus17 = 0n;
65366
+ for (let i = 0; i < 4; i++) {
65367
+ const l12 = i === 0 ? 0n : prev18;
65368
+ const l13 = L11[i] + l12;
65369
+ const l14 = i === 0 ? 0n : prev16plus17;
65370
+ const l15 = i === 0 ? L11[0] : max029(l13 - l14);
65371
+ const l16 = i === 0 ? 0n : l15 === 0n ? l14 - l13 : 0n;
65372
+ const l17 = line10[i] >= l15 ? line10[i] - l15 : 0n;
65373
+ const l18 = l15 > line10[i] ? l15 - line10[i] : 0n;
65374
+ A["12"].push(l12);
65375
+ A["13"].push(l13);
65376
+ A["14"].push(l14);
65377
+ A["15"].push(l15);
65378
+ A["16"].push(l16);
65379
+ A["17"].push(l17);
65380
+ A["18"].push(l18);
65381
+ prev18 = l18;
65382
+ prev16plus17 = l16 + l17;
65383
+ }
65384
+ const sectionA = Object.fromEntries(Object.entries(A).map(([k, v]) => [k, v.map((c2) => fmt2(c2))]));
65385
+ const out = { dueDates: dueLabels, sectionA, worksheet: [] };
65386
+ const under = [...A["17"]];
65387
+ if (section6654h) {
65388
+ if (under[3] > 0n)
65389
+ notes.push("\xA7 6654(h): the return was filed and the tax paid in full by January 31, so there's no penalty on the January 15 installment");
65390
+ under[3] = 0n;
65391
+ }
65392
+ const end = dayNum(`${year + 1}-04-15`);
65393
+ const balances = under.map((u, i) => ({ col: i, left: u }));
65394
+ const chunks = [];
65395
+ const all = [...estimated, ...withholding].sort((x, y) => x.day - y.day);
65396
+ for (const p of all) {
65397
+ let rest = p.amount;
65398
+ for (const b of balances) {
65399
+ if (rest === 0n)
65400
+ break;
65401
+ if (b.left === 0n || p.day <= effective[b.col])
65402
+ continue;
65403
+ const use = minC(rest, b.left);
65404
+ chunks.push({ col: b.col, amount: use, paid: Math.min(p.day, end) });
65405
+ b.left -= use;
65406
+ rest -= use;
65407
+ }
65408
+ }
65409
+ for (const b of balances)
65410
+ if (b.left > 0n)
65411
+ chunks.push({ col: b.col, amount: b.left, paid: end });
65412
+ const merged = /* @__PURE__ */ new Map();
65413
+ for (const ch of chunks) {
65414
+ const key = `${ch.col}|${ch.paid}`;
65415
+ const m = merged.get(key);
65416
+ if (m)
65417
+ m.amount += ch.amount;
65418
+ else
65419
+ merged.set(key, { ...ch });
65420
+ }
65421
+ const periods = ratePeriods(year);
65422
+ let total = 0n;
65423
+ let missingRate;
65424
+ for (const ch of [...merged.values()].sort((x, y) => x.col - y.col || x.paid - y.paid)) {
65425
+ if (ch.paid <= printed[ch.col])
65426
+ continue;
65427
+ for (const rp of periods) {
65428
+ const start = Math.max(printed[ch.col], rp.from - 1);
65429
+ const stop = Math.min(ch.paid, rp.to);
65430
+ const days = stop - start;
65431
+ if (days <= 0)
65432
+ continue;
65433
+ const rate2 = UNDERPAYMENT_RATES[rp.quarter];
65434
+ if (!rate2) {
65435
+ missingRate ??= rp.quarter;
65436
+ continue;
65437
+ }
65438
+ const num = ch.amount * BigInt(Math.round(rate2.percent * 100)) * BigInt(days);
65439
+ const den = 10000n * BigInt(rp.divisor);
65440
+ const cents2 = (num * 2n + den) / (2n * den);
65441
+ total += cents2;
65442
+ out.worksheet.push({
65443
+ column: "abcd"[ch.col],
65444
+ amount: fmt2(ch.amount, true),
65445
+ from: isoOf(start),
65446
+ paidOn: isoOf(ch.paid),
65447
+ days,
65448
+ ratePercent: rate2.percent,
65449
+ quarter: rp.quarter,
65450
+ penalty: fmt2(cents2, true)
65451
+ });
65452
+ }
65453
+ }
65454
+ if (missingRate) {
65455
+ out.refused = `the underpayment rate for ${missingRate} hasn't been announced (\xA7 6621(a)(2) rates are set each quarter); the underpayments in Section A are final, the penalty isn't`;
65456
+ return out;
65457
+ }
65458
+ if (year === 2025 && out.worksheet.some((w) => w.quarter === "2026-Q2"))
65459
+ notes.push(`the printed 2025 penalty worksheet applies 7% through April 15, 2026, but the \xA7 6621 rate for April 1\u201315, 2026 is 6% (Rev. Rul. 2026-5); the penalty here uses each quarter's actual rate, which the instructions allow ("You don't have to use the method used on Form 2210 as long as you enter the correct penalty amount")`);
65460
+ out.penalty = fmt2(total, true);
65461
+ out.penaltyCents = total.toString();
65462
+ return out;
65463
+ }
65464
+ function dollarsToCents(v, path) {
65465
+ const s = typeof v === "number" ? Number.isFinite(v) ? String(v) : "" : typeof v === "string" ? v.replace(/[$,\s]/g, "") : "";
65466
+ const m = /^(-?)(\d+)(?:\.(\d{1,2}))?$/.exec(s);
65467
+ if (!m)
65468
+ throw new Error(`${path}: expected a dollar amount like 1234.56, got ${JSON.stringify(v)}`);
65469
+ const cents2 = BigInt(m[2]) * 100n + BigInt((m[3] ?? "").padEnd(2, "0"));
65470
+ return m[1] ? -cents2 : cents2;
65471
+ }
65472
+ function parsePayments(raw, path) {
65473
+ if (!Array.isArray(raw))
65474
+ throw new Error(`${path}: expected an array of { date, amount }`);
65475
+ return raw.map((p, i) => {
65476
+ if (!isObj(p))
65477
+ throw new Error(`${path}[${i}]: expected { date, amount }`);
65478
+ const extra = Object.keys(p).filter((k) => k !== "date" && k !== "amount");
65479
+ if (extra.length)
65480
+ throw new Error(`${path}[${i}]: unknown key(s) ${extra.join(", ")}`);
65481
+ if (typeof p.date !== "string")
65482
+ throw new Error(`${path}[${i}].date: expected YYYY-MM-DD`);
65483
+ dayNum(p.date);
65484
+ const amount = dollarsToCents(p.amount, `${path}[${i}].amount`);
65485
+ if (amount < 0n)
65486
+ throw new Error(`${path}[${i}].amount: can't be negative`);
65487
+ return { date: p.date, amount };
65488
+ });
65489
+ }
65490
+ function form2210InputFromArgs(args, taxYear, facts2, coerce) {
65491
+ const known = /* @__PURE__ */ new Set(["payments", "periods", "withholdingByDate", "noPriorYearReturn", "filedAndPaidInFullOn"]);
65492
+ const unknown2 = Object.keys(args).filter((k) => !known.has(k));
65493
+ if (unknown2.length)
65494
+ throw new Error(`unknown Form 2210 option(s): ${unknown2.join(", ")}`);
65495
+ if (args.payments === void 0)
65496
+ throw new Error("payments is required: every estimated tax payment for the year with its date (an empty array if none) \u2014 the penalty depends on when each was paid");
65497
+ const input2 = { taxYear, facts: facts2, payments: parsePayments(args.payments, "payments") };
65498
+ if (args.withholdingByDate !== void 0)
65499
+ input2.withholdingByDate = parsePayments(args.withholdingByDate, "withholdingByDate");
65500
+ if (args.noPriorYearReturn !== void 0) {
65501
+ if (typeof args.noPriorYearReturn !== "boolean")
65502
+ throw new Error("noPriorYearReturn: expected true or false");
65503
+ input2.noPriorYearReturn = args.noPriorYearReturn;
65504
+ }
65505
+ if (args.filedAndPaidInFullOn !== void 0) {
65506
+ if (typeof args.filedAndPaidInFullOn !== "string")
65507
+ throw new Error("filedAndPaidInFullOn: expected YYYY-MM-DD");
65508
+ dayNum(args.filedAndPaidInFullOn);
65509
+ input2.filedAndPaidInFullOn = args.filedAndPaidInFullOn;
65510
+ }
65511
+ if (args.periods !== void 0) {
65512
+ const p = args.periods;
65513
+ if (!isObj(p))
65514
+ throw new Error("periods: expected { mar31, may31, aug31 }");
65515
+ const keys = ["mar31", "may31", "aug31"];
65516
+ const extra = Object.keys(p).filter((k) => !keys.includes(k));
65517
+ if (extra.length)
65518
+ throw new Error(`periods: unknown key(s) ${extra.join(", ")} (use mar31, may31, aug31)`);
65519
+ const out = {};
65520
+ for (const k of keys) {
65521
+ const v = p[k];
65522
+ if (!isObj(v))
65523
+ throw new Error(`periods.${k}: expected an object of cumulative amounts from January 1 (e.g. { "wages": 15000 })`);
65524
+ for (const [id2] of Object.entries(v)) {
65525
+ const kind = SCHEDULE_AI_FACTS[id2];
65526
+ if (kind !== "annualize")
65527
+ throw new Error(`periods.${k}.${id2}: ${kind === void 0 ? "not an amount Schedule AI annualizes" : kind === "keep" ? "used as is in every column, not a period amount" : "out of scope for Schedule AI"}`);
65528
+ }
65529
+ out[k] = coerce(v);
65530
+ }
65531
+ input2.periods = out;
65532
+ }
65533
+ return input2;
65534
+ }
65535
+ var SCHEDULE_AI_FACTS, money43, dayNum, isoOf, isLeap, UNDERPAYMENT_RATES, rd26, max029, minC, fmt2, D13, mulRate2, ANNUALIZATION, MissingInput, isObj;
65536
+ var init_form2210 = __esm({
65537
+ "../compose/dist/form2210.js"() {
65538
+ "use strict";
65539
+ SCHEDULE_AI_FACTS = {
65540
+ // income
65541
+ wages: "annualize",
65542
+ taxableInterest: "annualize",
65543
+ taxExemptInterest: "annualize",
65544
+ ordinaryDividends: "annualize",
65545
+ qualifiedDividends: "annualize",
65546
+ shortTermCapitalGains: "annualize",
65547
+ shortTermCapitalLoss: "annualize",
65548
+ longTermCapitalGains: "annualize",
65549
+ longTermCapitalLoss: "annualize",
65550
+ netCapitalLoss: "annualize",
65551
+ selfEmploymentNetProfit: "annualize",
65552
+ spouseSelfEmploymentNetProfit: "annualize",
65553
+ scheduleCNetLoss: "annualize",
65554
+ k1OrdinaryBusinessIncome: "annualize",
65555
+ taxableIraDistributions: "annualize",
65556
+ taxablePensionsAndAnnuities: "annualize",
65557
+ unemploymentCompensation: "annualize",
65558
+ otherOrdinaryIncome: "annualize",
65559
+ alimonyReceivedPre2019: "annualize",
65560
+ hsaDistributions: "annualize",
65561
+ hsaQualifiedMedicalExpenses: "annualize",
65562
+ scheduleENetIncome: "annualize",
65563
+ rentalIncomeBeforeDepreciation: "annualize",
65564
+ nonpassiveScheduleELoss: "annualize",
65565
+ socialSecurityBenefits: "annualize",
65566
+ socialSecurityWages: "annualize",
65567
+ spouseSocialSecurityWages: "annualize",
65568
+ medicareWages: "annualize",
65569
+ gamblingWinnings: "annualize",
65570
+ qualifiedTips: "annualize",
65571
+ qualifiedOvertimePremium: "annualize",
65572
+ scheduleRDisabilityIncome: "annualize",
65573
+ nontaxableBenefitsForScheduleR: "annualize",
65574
+ earlyDistributionSubjectToPenalty: "annualize",
65575
+ amtIsoExerciseSpread: "annualize",
65576
+ amtOtherPreferences: "annualize",
65577
+ // QBI (the businesses' income and W-2 wages are the period's; UBIA is basis)
65578
+ qbiBusiness2Income: "annualize",
65579
+ qbiBusiness3Income: "annualize",
65580
+ qbiBusiness4Income: "annualize",
65581
+ qbiBusiness5Income: "annualize",
65582
+ qbiBusiness6Income: "annualize",
65583
+ qbiLossOffset: "annualize",
65584
+ qbiW2Wages: "annualize",
65585
+ spouseQbiW2Wages: "annualize",
65586
+ qbiBusiness2W2Wages: "annualize",
65587
+ qbiBusiness3W2Wages: "annualize",
65588
+ qbiBusiness4W2Wages: "annualize",
65589
+ qbiBusiness5W2Wages: "annualize",
65590
+ qbiBusiness6W2Wages: "annualize",
65591
+ qbiUBIA: "keep",
65592
+ spouseQbiUBIA: "keep",
65593
+ qbiBusiness2UBIA: "keep",
65594
+ qbiBusiness3UBIA: "keep",
65595
+ qbiBusiness4UBIA: "keep",
65596
+ qbiBusiness5UBIA: "keep",
65597
+ qbiBusiness6UBIA: "keep",
65598
+ // adjustments
65599
+ hsaContribution: "annualize",
65600
+ sepContribution: "annualize",
65601
+ selfEmployedHealthPremiums: "annualize",
65602
+ educatorExpenses: "annualize",
65603
+ spouseEducatorExpenses: "annualize",
65604
+ earlyWithdrawalPenaltyPaid: "annualize",
65605
+ alimonyPaidPre2019: "annualize",
65606
+ otherAdjustments: "annualize",
65607
+ iraContribution: "annualize",
65608
+ studentLoanInterest: "annualize",
65609
+ // itemized and Schedule 1-A deductions
65610
+ stateAndLocalTaxesPaid: "annualize",
65611
+ mortgageInterestPaid: "annualize",
65612
+ mortgageAverageBalance: "keep",
65613
+ charitableCashContributions: "annualize",
65614
+ noncashCharitableContributions: "annualize",
65615
+ medicalExpenses: "annualize",
65616
+ casualtyFederalDisasterLosses: "annualize",
65617
+ casualtyQualifiedDisasterLosses: "annualize",
65618
+ investmentInterestDeduction: "annualize",
65619
+ gamblingLossesItemized: "annualize",
65620
+ otherItemizedDeductions: "annualize",
65621
+ carLoanInterest: "annualize",
65622
+ niitInvestmentExpenses: "annualize",
65623
+ // credits (Schedule AI line 18: the items used to figure each credit are annualized)
65624
+ dependentCareExpenses: "annualize",
65625
+ secondaryEarnedIncome: "annualize",
65626
+ aotcExpensesStudent1: "annualize",
65627
+ aotcExpensesStudent2: "annualize",
65628
+ aotcExpensesStudent3: "annualize",
65629
+ llcQualifiedExpenses: "annualize",
65630
+ saversContributions: "annualize",
65631
+ saversContributionsSpouse: "annualize",
65632
+ qualifiedAdoptionExpenses: "annualize",
65633
+ insulationAirSealingCosts: "annualize",
65634
+ exteriorDoorMostExpensiveCost: "annualize",
65635
+ exteriorDoorOtherCosts: "annualize",
65636
+ windowsSkylightsCosts: "annualize",
65637
+ centralAirConditionerCosts: "annualize",
65638
+ gasOilWaterHeaterCosts: "annualize",
65639
+ gasOilFurnaceBoilerCosts: "annualize",
65640
+ electricalPanelCosts: "annualize",
65641
+ homeEnergyAuditCosts: "annualize",
65642
+ heatPumpBiomassCosts: "annualize",
65643
+ solarElectricCosts: "annualize",
65644
+ solarWaterHeatingCosts: "annualize",
65645
+ smallWindEnergyCosts: "annualize",
65646
+ geothermalHeatPumpCosts: "annualize",
65647
+ batteryStorageCosts: "annualize",
65648
+ fuelCellPropertyCosts: "annualize",
65649
+ // bases and balances
65650
+ pensionCostBasis: "keep",
65651
+ pensionBasisPreviouslyRecovered: "keep",
65652
+ rentalDepreciableBasis: "keep",
65653
+ // payments are Part III inputs, never income
65654
+ federalTaxWithheld: "keep",
65655
+ federalEstimatedPayments: "keep",
65656
+ federalExtensionPayment: "keep",
65657
+ priorYearTax: "keep",
65658
+ priorYearAGI: "keep",
65659
+ // out of scope: the form or the statute treats these differently by period
65660
+ foreignEarnedIncome: { refuse: "the foreign earned income exclusion is prorated by qualifying days (\xA7 911(b)(2)(A)), which Schedule AI does not annualize by a single factor" },
65661
+ priorYearShortTermCapitalLossCarryover: { refuse: "a prior-year capital loss carryover is not an amount of the period; neither the form nor the instructions say whether it is annualized" },
65662
+ priorYearLongTermCapitalLossCarryover: { refuse: "a prior-year capital loss carryover is not an amount of the period; neither the form nor the instructions say whether it is annualized" },
65663
+ qbiLossCarryforward: { refuse: "a prior-year qualified business loss carryforward is not an amount of the period; the instructions don't say whether it is annualized" },
65664
+ residentialCleanEnergyCarryforward: { refuse: "a prior-year credit carryforward is not an amount of the period" },
65665
+ advancePTC: { refuse: "the premium tax credit is reconciled by coverage month (\xA7 36B(b)(2)), not by annualizing a period" },
65666
+ slcspAnnualPremium: { refuse: "the premium tax credit is reconciled by coverage month (\xA7 36B(b)(2)), not by annualizing a period" },
65667
+ marketplacePremiumsPaid: { refuse: "the premium tax credit is reconciled by coverage month (\xA7 36B(b)(2)), not by annualizing a period" },
65668
+ parentTaxableIncome: { refuse: "Form 8615 uses the parent's annual taxable income" },
65669
+ pensionGrossPayments: { refuse: "the simplified method's tax-free part is a per-payment amount (\xA7 72(d)), not an annualized one \u2014 enter taxablePensionsAndAnnuities instead" },
65670
+ householdEmployeeCashWages: { refuse: "Schedule H thresholds apply to the calendar year's wages (\xA7 3121(x)), and the instructions give no period method" }
65671
+ };
65672
+ money43 = (facts2, id2) => {
65673
+ const f = facts2[id2];
65674
+ return f && f.type === "money" ? BigInt(f.value) : 0n;
65675
+ };
65676
+ dayNum = (iso) => {
65677
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(iso))
65678
+ throw new Error(`invalid date "${iso}" (use YYYY-MM-DD)`);
65679
+ const t = Date.UTC(Number(iso.slice(0, 4)), Number(iso.slice(5, 7)) - 1, Number(iso.slice(8, 10)));
65680
+ const d3 = new Date(t);
65681
+ if (d3.toISOString().slice(0, 10) !== iso)
65682
+ throw new Error(`invalid date "${iso}"`);
65683
+ return Math.round(t / 864e5);
65684
+ };
65685
+ isoOf = (n) => new Date(n * 864e5).toISOString().slice(0, 10);
65686
+ isLeap = (y) => y % 4 === 0 && y % 100 !== 0 || y % 400 === 0;
65687
+ UNDERPAYMENT_RATES = {
65688
+ "2025-Q2": { percent: 7, source: "Rev. Rul. 2025-7, I.R.B. 2025-13 (IR-2025-29)" },
65689
+ "2025-Q3": { percent: 7, source: "Rev. Rul. 2025-11, I.R.B. 2025-23 (IR-2025-59)" },
65690
+ "2025-Q4": { percent: 7, source: "Rev. Rul. 2025-18, I.R.B. 2025-37 (IR-2025-87)" },
65691
+ "2026-Q1": { percent: 7, source: "Rev. Rul. 2025-22, I.R.B. 2025-48 (IR-2025-112)" },
65692
+ "2026-Q2": { percent: 6, source: "Rev. Rul. 2026-5, I.R.B. 2026-8" },
65693
+ "2026-Q3": { percent: 7, source: "Rev. Rul. 2026-10, I.R.B. 2026-22" },
65694
+ "2026-Q4": { percent: 7, source: "Rev. Rul. 2026-15, I.R.B. 2026-36 (IR-2026-98)" }
65695
+ };
65696
+ rd26 = (x) => {
65697
+ const neg3 = x < 0n;
65698
+ const a = neg3 ? -x : x;
65699
+ const r = (a + 50n) / 100n * 100n;
65700
+ return neg3 ? -r : r;
65701
+ };
65702
+ max029 = (x) => x > 0n ? x : 0n;
65703
+ minC = (a, b) => a < b ? a : b;
65704
+ fmt2 = (cents2, withCents = false) => {
65705
+ const neg3 = cents2 < 0n;
65706
+ const a = neg3 ? -cents2 : cents2;
65707
+ const dollars6 = (a / 100n).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
65708
+ return `${neg3 ? "-" : ""}$${dollars6}${withCents ? "." + (a % 100n).toString().padStart(2, "0") : ""}`;
65709
+ };
65710
+ D13 = (c2) => fmt2(rd26(c2));
65711
+ mulRate2 = (c2, num, den) => {
65712
+ const p = c2 * num;
65713
+ const neg3 = p < 0n;
65714
+ const a = neg3 ? -p : p;
65715
+ const q = (a * 2n + den) / (2n * den);
65716
+ return neg3 ? -q : q;
65717
+ };
65718
+ ANNUALIZATION = [
65719
+ { num: 4n, den: 1n, label: "4", pct: [225n, 1000n] },
65720
+ { num: 12n, den: 5n, label: "2.4", pct: [45n, 100n] },
65721
+ { num: 3n, den: 2n, label: "1.5", pct: [675n, 1000n] },
65722
+ { num: 1n, den: 1n, label: "1", pct: [90n, 100n] }
65723
+ ];
65724
+ MissingInput = class extends Error {
65725
+ missing;
65726
+ constructor(missing) {
65727
+ super(`Form 2210 needs: ${missing.join(", ")}`);
65728
+ this.missing = missing;
65729
+ this.name = "MissingInput";
65730
+ }
65731
+ };
65732
+ isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
65733
+ }
65734
+ });
65735
+
64603
65736
  // ../compose/dist/index.js
64604
65737
  function makeStateTaxEvaluator(runTarget, input2) {
64605
65738
  return (target, stateTaxableIncomeCents, extraFacts) => {
@@ -64733,6 +65866,7 @@ var init_dist4 = __esm({
64733
65866
  init_va();
64734
65867
  init_shape();
64735
65868
  init_incomplete();
65869
+ init_form2210();
64736
65870
  }
64737
65871
  });
64738
65872
 
@@ -64741,7 +65875,7 @@ var COMPOSER_VERSION;
64741
65875
  var init_version = __esm({
64742
65876
  "dist/version.js"() {
64743
65877
  "use strict";
64744
- COMPOSER_VERSION = "0.11.0";
65878
+ COMPOSER_VERSION = "0.12.0";
64745
65879
  }
64746
65880
  });
64747
65881
 
@@ -75192,8 +76326,8 @@ var require_utils = __commonJS({
75192
76326
  if (separator === -1) return void 0;
75193
76327
  const address = host.slice(0, separator);
75194
76328
  const escaped = address + "%25" + zone;
75195
- const derived2 = normalizeIPv6("[" + escaped + "]");
75196
- if (derived2.isIPV6 === true && derived2.host === host) {
76329
+ const derived3 = normalizeIPv6("[" + escaped + "]");
76330
+ if (derived3.isIPV6 === true && derived3.host === host) {
75197
76331
  return "[" + escaped + "]";
75198
76332
  }
75199
76333
  return void 0;
@@ -78425,11 +79559,11 @@ var require_format = __commonJS({
78425
79559
  }
78426
79560
  function getFormat(fmtDef) {
78427
79561
  const code = fmtDef instanceof RegExp ? (0, codegen_1.regexpCode)(fmtDef) : opts.code.formats ? (0, codegen_1._)`${opts.code.formats}${(0, codegen_1.getProperty)(schema)}` : void 0;
78428
- const fmt3 = gen.scopeValue("formats", { key: schema, ref: fmtDef, code });
79562
+ const fmt4 = gen.scopeValue("formats", { key: schema, ref: fmtDef, code });
78429
79563
  if (typeof fmtDef == "object" && !(fmtDef instanceof RegExp)) {
78430
- return [fmtDef.type || "string", fmtDef.validate, (0, codegen_1._)`${fmt3}.validate`];
79564
+ return [fmtDef.type || "string", fmtDef.validate, (0, codegen_1._)`${fmt4}.validate`];
78431
79565
  }
78432
- return ["string", fmtDef, fmt3];
79566
+ return ["string", fmtDef, fmt4];
78433
79567
  }
78434
79568
  function validCondition() {
78435
79569
  if (typeof formatDef == "object" && !(formatDef instanceof RegExp) && formatDef.async) {
@@ -79091,8 +80225,8 @@ var require_limit = __commonJS({
79091
80225
  ref: self.formats,
79092
80226
  code: opts.code.formats
79093
80227
  });
79094
- const fmt3 = gen.const("fmt", (0, codegen_1._)`${fmts}[${fCxt.schemaCode}]`);
79095
- cxt.fail$data((0, codegen_1.or)((0, codegen_1._)`typeof ${fmt3} != "object"`, (0, codegen_1._)`${fmt3} instanceof RegExp`, (0, codegen_1._)`typeof ${fmt3}.compare != "function"`, compareCode(fmt3)));
80228
+ const fmt4 = gen.const("fmt", (0, codegen_1._)`${fmts}[${fCxt.schemaCode}]`);
80229
+ cxt.fail$data((0, codegen_1.or)((0, codegen_1._)`typeof ${fmt4} != "object"`, (0, codegen_1._)`${fmt4} instanceof RegExp`, (0, codegen_1._)`typeof ${fmt4}.compare != "function"`, compareCode(fmt4)));
79096
80230
  }
79097
80231
  function validateFormat() {
79098
80232
  const format = fCxt.schema;
@@ -79102,15 +80236,15 @@ var require_limit = __commonJS({
79102
80236
  if (typeof fmtDef != "object" || fmtDef instanceof RegExp || typeof fmtDef.compare != "function") {
79103
80237
  throw new Error(`"${keyword}": format "${format}" does not define "compare" function`);
79104
80238
  }
79105
- const fmt3 = gen.scopeValue("formats", {
80239
+ const fmt4 = gen.scopeValue("formats", {
79106
80240
  key: format,
79107
80241
  ref: fmtDef,
79108
80242
  code: opts.code.formats ? (0, codegen_1._)`${opts.code.formats}${(0, codegen_1.getProperty)(format)}` : void 0
79109
80243
  });
79110
- cxt.fail$data(compareCode(fmt3));
80244
+ cxt.fail$data(compareCode(fmt4));
79111
80245
  }
79112
- function compareCode(fmt3) {
79113
- return (0, codegen_1._)`${fmt3}.compare(${data}, ${schemaCode}) ${KWDs[keyword].fail} 0`;
80246
+ function compareCode(fmt4) {
80247
+ return (0, codegen_1._)`${fmt4}.compare(${data}, ${schemaCode}) ${KWDs[keyword].fail} 0`;
79114
80248
  }
79115
80249
  },
79116
80250
  dependencies: ["format"]
@@ -81377,7 +82511,7 @@ function zodForFact(f) {
81377
82511
  }
81378
82512
  switch (f.type) {
81379
82513
  case "money":
81380
- return money43.describe(f.description);
82514
+ return money44.describe(f.description);
81381
82515
  case "bool":
81382
82516
  return external_exports.boolean().describe(f.description);
81383
82517
  case "int":
@@ -81410,6 +82544,14 @@ function shapeFor(ids) {
81410
82544
  function factIdsForDomain(domain2) {
81411
82545
  return corpus.facts.filter((f) => domainOf(f.id) === domain2).map((f) => f.id);
81412
82546
  }
82547
+ function corpusFor(asOf, projection) {
82548
+ const year = Number(asOf.slice(0, 4));
82549
+ if (year > LAST_PUBLISHED_YEAR && projection)
82550
+ return getProjectedFederalCorpus({ year, inflationPercent: projection.inflationPercent, wageGrowthPercent: projection.wageGrowthPercent });
82551
+ if (projection)
82552
+ throw new Error(`projection is for tax years after ${LAST_PUBLISHED_YEAR}; ${year} is published law \u2014 drop projection`);
82553
+ return corpus;
82554
+ }
81413
82555
  function flattenFactsArg(input2) {
81414
82556
  const flat = {};
81415
82557
  const put = (key, value, from) => {
@@ -81478,6 +82620,17 @@ function buildFactsValidated(factsArg, defaultTarget) {
81478
82620
  };
81479
82621
  delete input2.refuseDefaults;
81480
82622
  delete input2.allowDefaults;
82623
+ let projection;
82624
+ if (input2.projection !== void 0) {
82625
+ const parsedProjection = projectionParam.safeParse(input2.projection);
82626
+ if (!parsedProjection.success || !parsedProjection.data)
82627
+ throw new Error("projection: expected { inflationPercent, wageGrowthPercent? }");
82628
+ projection = {
82629
+ inflationPercent: String(parsedProjection.data.inflationPercent),
82630
+ ...parsedProjection.data.wageGrowthPercent !== void 0 ? { wageGrowthPercent: String(parsedProjection.data.wageGrowthPercent) } : {}
82631
+ };
82632
+ }
82633
+ delete input2.projection;
81481
82634
  const flat = flattenFactsArg(input2);
81482
82635
  if (docsRaw !== void 0) {
81483
82636
  const parsedDocs = documentsShape.safeParse(docsRaw);
@@ -81538,10 +82691,11 @@ function buildFactsValidated(factsArg, defaultTarget) {
81538
82691
  documentMissing,
81539
82692
  documentUnsupported,
81540
82693
  ...w2Box1Cents !== void 0 ? { w2Box1Cents } : {},
81541
- defaults
82694
+ defaults,
82695
+ ...projection ? { projection } : {}
81542
82696
  };
81543
82697
  }
81544
- var corpus, money43, targetParam, asOfParam, BUSINESS_EXTRAS, DEPENDENT_EXTRAS, INDIVIDUAL_GROUPS, GROUP_NAMES, factById, GROUP_DESCRIPTIONS, OTHER_EARNED_INCOME, strictParam, refuseDefaultsParam, allowDefaultsParam, includeProofParam, individualNestedShape, businessShape, fiduciaryShape, dependentShape, FACT_SHAPE, STRICT_FLAT, factsObjectParam, INT_FACTS;
82698
+ var corpus, money44, targetParam, asOfParam, BUSINESS_EXTRAS, DEPENDENT_EXTRAS, INDIVIDUAL_GROUPS, GROUP_NAMES, factById, GROUP_DESCRIPTIONS, OTHER_EARNED_INCOME, strictParam, refuseDefaultsParam, allowDefaultsParam, includeProofParam, projectionParam, individualNestedShape, businessShape, fiduciaryShape, dependentShape, FACT_SHAPE, STRICT_FLAT, factsObjectParam, INT_FACTS;
81545
82699
  var init_schema = __esm({
81546
82700
  "dist/schema.js"() {
81547
82701
  "use strict";
@@ -81550,7 +82704,7 @@ var init_schema = __esm({
81550
82704
  init_dist2();
81551
82705
  init_documents();
81552
82706
  corpus = getCorpus();
81553
- money43 = external_exports.union([external_exports.number(), external_exports.string()]).describe('dollars, e.g. 50000 or "1234.56"');
82707
+ money44 = external_exports.union([external_exports.number(), external_exports.string()]).describe('dollars, e.g. 50000 or "1234.56"');
81554
82708
  targetParam = (defaultLabel, determinations) => external_exports.string().optional().describe(`rule to derive (default: ${defaultLabel}).${determinations ? ` ${determinations}` : ""}`);
81555
82709
  asOfParam = external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe(`REQUIRED for computation: the law-in-force date \u2014 use the intended tax year's year-end (e.g. "2025-12-31" for TY2025). Omitting it is an error, never a default.`);
81556
82710
  BUSINESS_EXTRAS = /* @__PURE__ */ new Set([
@@ -82374,6 +83528,10 @@ var init_schema = __esm({
82374
83528
  refuseDefaultsParam = external_exports.boolean().optional().describe("refuse defaults: every fact the answer needs must be given explicitly. A fact left out refuses with NEEDS_FACTS even when it has a documented default; each entry in error.data.missing carries that `default` so you can pass the value or accept it via allowDefaults. A missing enum can hide the facts behind it, so a second call may list more. Default false: defaults apply and are listed under assumptions.");
82375
83529
  allowDefaultsParam = external_exports.array(external_exports.string().max(80)).max(300).optional().describe("with refuseDefaults: fact ids whose documented defaults you accept (they still appear under assumptions)");
82376
83530
  includeProofParam = external_exports.boolean().optional().describe("include the full proof artifact in the response as `proof` (PROOF-FORMAT v2: every applied rule, input, assumption and rounding, verifiable offline against corpusMerkleRoot; ~200 KB). Default false \u2014 the hashes alone are returned.");
83531
+ projectionParam = external_exports.object({
83532
+ inflationPercent: external_exports.union([external_exports.number(), external_exports.string()]).describe("assumed annual C-CPI-U growth after the index the IRS used for 2027, in percent (e.g. 2.5)"),
83533
+ wageGrowthPercent: external_exports.union([external_exports.number(), external_exports.string()]).optional().describe("assumed annual growth of the national average wage index (social security wage base), in percent; defaults to inflationPercent")
83534
+ }).strict().optional().describe("PROJECTION for tax years 2028-2035 (asOf in that year): every inflation-indexed amount is projected from 2027 by its own statutory indexing formula at these ASSUMED rates; known law (the SALT limit's 101% steps and 2030 return to $10,000, the end of the tips/overtime/car-loan/senior deductions after 2028) is applied as law. The result is labeled projected and its proof cites the assumption. Omit for 2025-2027 (published law).");
82377
83535
  individualNestedShape = (() => {
82378
83536
  const shape = {};
82379
83537
  for (const [group, ids] of Object.entries(INDIVIDUAL_GROUPS)) {
@@ -82386,6 +83544,7 @@ var init_schema = __esm({
82386
83544
  shape.includeProof = includeProofParam;
82387
83545
  shape.refuseDefaults = refuseDefaultsParam;
82388
83546
  shape.allowDefaults = allowDefaultsParam;
83547
+ shape.projection = projectionParam;
82389
83548
  return shape;
82390
83549
  })();
82391
83550
  businessShape = (() => {
@@ -82424,6 +83583,15 @@ var init_schema = __esm({
82424
83583
  });
82425
83584
 
82426
83585
  // dist/server.js
83586
+ function projectedLabel(asOf, projection, corpusVersion) {
83587
+ return {
83588
+ taxYear: Number(asOf.slice(0, 4)),
83589
+ inflationPercent: projection.inflationPercent,
83590
+ wageGrowthPercent: projection.wageGrowthPercent ?? projection.inflationPercent,
83591
+ corpusVersion,
83592
+ warning: "PROJECTED, NOT PUBLISHED LAW: every inflation-indexed amount is the 2027 amount carried forward by its statutory indexing formula at the assumed rates; tell the user these are assumptions. Known law after 2027 (the SALT limit's steps, the end of the tips/overtime/car-loan/senior deductions after 2028) is applied as law."
83593
+ };
83594
+ }
82427
83595
  function versions() {
82428
83596
  return {
82429
83597
  engine: ENGINE.version,
@@ -82471,14 +83639,14 @@ function composeForm5695(facts2, asOf, get) {
82471
83639
  });
82472
83640
  if (!present)
82473
83641
  return null;
82474
- const rd26 = (c2) => {
83642
+ const rd27 = (c2) => {
82475
83643
  const neg3 = c2 < 0n;
82476
83644
  const abs = neg3 ? -c2 : c2;
82477
83645
  const r = (abs + 50n) / 100n * 100n;
82478
83646
  return neg3 ? -r : r;
82479
83647
  };
82480
- const d3 = (c2) => fmt2(rd26(c2));
82481
- const money44 = (id2) => {
83648
+ const d3 = (c2) => fmt3(rd27(c2));
83649
+ const money45 = (id2) => {
82482
83650
  const f = facts2[id2];
82483
83651
  return f && f.type === "money" ? BigInt(String(f.value)) : 0n;
82484
83652
  };
@@ -82489,7 +83657,7 @@ function composeForm5695(facts2, asOf, get) {
82489
83657
  for (const id2 of FORM_5695_FACTS) {
82490
83658
  if (id2 === "fuelCellHalfKilowatts" || id2 === "residentialCleanEnergyCarryforward")
82491
83659
  continue;
82492
- const c2 = money44(id2);
83660
+ const c2 = money45(id2);
82493
83661
  if (c2 !== 0n)
82494
83662
  costs[id2] = d3(c2);
82495
83663
  }
@@ -82505,14 +83673,14 @@ function composeForm5695(facts2, asOf, get) {
82505
83673
  };
82506
83674
  }
82507
83675
  return {
82508
- "1_solar_electric": d3(money44("solarElectricCosts")),
82509
- "2_solar_water_heating": d3(money44("solarWaterHeatingCosts")),
82510
- "3_small_wind": d3(money44("smallWindEnergyCosts")),
82511
- "4_geothermal_heat_pump": d3(money44("geothermalHeatPumpCosts")),
82512
- "5b_battery_storage": d3(money44("batteryStorageCosts")),
83676
+ "1_solar_electric": d3(money45("solarElectricCosts")),
83677
+ "2_solar_water_heating": d3(money45("solarWaterHeatingCosts")),
83678
+ "3_small_wind": d3(money45("smallWindEnergyCosts")),
83679
+ "4_geothermal_heat_pump": d3(money45("geothermalHeatPumpCosts")),
83680
+ "5b_battery_storage": d3(money45("batteryStorageCosts")),
82513
83681
  "6a_total": d3(E("clean.line6a")),
82514
83682
  "6b_30_percent": d3(E("clean.line6b")),
82515
- "8_fuel_cell_costs": d3(money44("fuelCellPropertyCosts")),
83683
+ "8_fuel_cell_costs": d3(money45("fuelCellPropertyCosts")),
82516
83684
  "9_30_percent": d3(E("clean.line9")),
82517
83685
  "10_kilowatt_capacity_x_1000": d3(E("clean.line10")),
82518
83686
  "11_smaller_of_9_or_10": d3(E("clean.line11")),
@@ -82521,28 +83689,28 @@ function composeForm5695(facts2, asOf, get) {
82521
83689
  "14_limitation": d3(E("clean.line14")),
82522
83690
  "15_residential_clean_energy_credit": d3(E("clean_energy_credit")),
82523
83691
  "16_carryforward_to_next_year": d3(E("clean.carryforward")),
82524
- "18a_insulation_air_sealing": d3(money44("insulationAirSealingCosts")),
83692
+ "18a_insulation_air_sealing": d3(money45("insulationAirSealingCosts")),
82525
83693
  "18b_30_percent_max_1200": d3(E("improvement.line18b")),
82526
- "19a_most_expensive_door": d3(money44("exteriorDoorMostExpensiveCost")),
83694
+ "19a_most_expensive_door": d3(money45("exteriorDoorMostExpensiveCost")),
82527
83695
  "19c_30_percent_max_250": d3(E("improvement.line19c")),
82528
- "19f_other_doors": d3(money44("exteriorDoorOtherCosts")),
83696
+ "19f_other_doors": d3(money45("exteriorDoorOtherCosts")),
82529
83697
  "19g_30_percent": d3(E("improvement.line19g")),
82530
83698
  "19h_doors_max_500": d3(E("improvement.line19h")),
82531
- "20c_windows_skylights": d3(money44("windowsSkylightsCosts")),
83699
+ "20c_windows_skylights": d3(money45("windowsSkylightsCosts")),
82532
83700
  "20d_30_percent_max_600": d3(E("improvement.line20d")),
82533
- "22c_central_air_conditioners": d3(money44("centralAirConditionerCosts")),
83701
+ "22c_central_air_conditioners": d3(money45("centralAirConditionerCosts")),
82534
83702
  "22d_30_percent_max_600": d3(E("improvement.line22d")),
82535
- "23c_gas_oil_water_heaters": d3(money44("gasOilWaterHeaterCosts")),
83703
+ "23c_gas_oil_water_heaters": d3(money45("gasOilWaterHeaterCosts")),
82536
83704
  "23d_30_percent_max_600": d3(E("improvement.line23d")),
82537
- "24c_gas_oil_furnaces_boilers": d3(money44("gasOilFurnaceBoilerCosts")),
83705
+ "24c_gas_oil_furnaces_boilers": d3(money45("gasOilFurnaceBoilerCosts")),
82538
83706
  "24d_30_percent_max_600": d3(E("improvement.line24d")),
82539
- "25c_enabling_property": d3(money44("electricalPanelCosts")),
83707
+ "25c_enabling_property": d3(money45("electricalPanelCosts")),
82540
83708
  "25e_30_percent_max_600": d3(E("improvement.line25e")),
82541
- "26b_home_energy_audit": d3(money44("homeEnergyAuditCosts")),
83709
+ "26b_home_energy_audit": d3(money45("homeEnergyAuditCosts")),
82542
83710
  "26c_30_percent_max_150": d3(E("improvement.line26c")),
82543
83711
  "27_total": d3(E("improvement.line27")),
82544
83712
  "28_smaller_of_27_or_1200": d3(E("improvement.line28")),
82545
- "29g_heat_pumps_biomass": d3(money44("heatPumpBiomassCosts")),
83713
+ "29g_heat_pumps_biomass": d3(money45("heatPumpBiomassCosts")),
82546
83714
  "29h_30_percent_max_2000": d3(E("improvement.line29h")),
82547
83715
  "30_total": d3(E("improvement.line30")),
82548
83716
  "31_limitation": d3(E("improvement.line31")),
@@ -82576,18 +83744,19 @@ function createServer(options = {}) {
82576
83744
  inputSchema: legacyJsonSchema(external_exports.object(individualNestedShape).strict())
82577
83745
  }, async (args) => {
82578
83746
  try {
82579
- const { facts: facts2, asOf, target, documentNotes, defaults } = buildFactsValidated(args);
82580
- const { value, proof } = evaluate(corpus, facts2, { asOf, target, ...defaults });
83747
+ const { facts: facts2, asOf, target, documentNotes, defaults, projection } = buildFactsValidated(args);
83748
+ const { value, proof } = evaluate(corpusFor(asOf, projection), facts2, { asOf, target, ...defaults });
82581
83749
  const cents2 = value.type === "money" ? value.cents : 0n;
82582
83750
  return ok({
82583
83751
  ok: true,
82584
83752
  target,
82585
83753
  asOf,
82586
- answer: fmt2(cents2),
83754
+ answer: fmt3(cents2),
82587
83755
  valueCents: cents2.toString(),
82588
83756
  ...documentNotes.length ? { documentNotes } : {},
82589
83757
  meaning: target === "us.federal.balance_due" ? cents2 < 0n ? "refund expected at filing" : "balance due at filing" : cents2 < 0n ? "net refund (refundable credits exceed tax)" : "net federal income tax",
82590
83758
  assumptions: proof.assumptions,
83759
+ ...projection ? { projected: projectedLabel(asOf, projection, proof.corpus.version) } : {},
82591
83760
  corpusMerkleRoot: proof.corpus.merkleRoot,
82592
83761
  artifactHash: proof.artifactHash,
82593
83762
  ...args.includeProof === true ? { proof } : {},
@@ -82609,7 +83778,7 @@ function createServer(options = {}) {
82609
83778
  ok: true,
82610
83779
  target,
82611
83780
  asOf,
82612
- answer: fmt2(cents2),
83781
+ answer: fmt3(cents2),
82613
83782
  valueCents: cents2.toString(),
82614
83783
  assumptions: proof.assumptions,
82615
83784
  corpusMerkleRoot: proof.corpus.merkleRoot,
@@ -82633,7 +83802,7 @@ function createServer(options = {}) {
82633
83802
  ok: true,
82634
83803
  target,
82635
83804
  asOf,
82636
- answer: fmt2(cents2),
83805
+ answer: fmt3(cents2),
82637
83806
  valueCents: cents2.toString(),
82638
83807
  assumptions: proof.assumptions,
82639
83808
  corpusMerkleRoot: proof.corpus.merkleRoot,
@@ -82652,7 +83821,7 @@ function createServer(options = {}) {
82652
83821
  try {
82653
83822
  const { facts: facts2, asOf, target } = buildFactsValidated(args, "us.federal.dependent.is_dependent");
82654
83823
  const { value, proof } = evaluate(corpus, facts2, { asOf, target });
82655
- const answer = value.type === "bool" ? value.value ? "yes" : "no" : fmt2(value.type === "money" ? value.cents : 0n);
83824
+ const answer = value.type === "bool" ? value.value ? "yes" : "no" : fmt3(value.type === "money" ? value.cents : 0n);
82656
83825
  return ok({
82657
83826
  ok: true,
82658
83827
  target,
@@ -82713,7 +83882,7 @@ function createServer(options = {}) {
82713
83882
  const incomplete = built.documentUnsupported;
82714
83883
  if (args.strict === true && incomplete.length)
82715
83884
  throw new IncompleteReturnError(incomplete);
82716
- const rd26 = (c2) => {
83885
+ const rd27 = (c2) => {
82717
83886
  const neg3 = c2 < 0n;
82718
83887
  const abs = neg3 ? -c2 : c2;
82719
83888
  const r = (abs + 50n) / 100n * 100n;
@@ -82724,20 +83893,21 @@ function createServer(options = {}) {
82724
83893
  for (const [id2, v] of Object.entries(built.facts)) {
82725
83894
  if (v.type === "money") {
82726
83895
  const cents2 = BigInt(v.value);
82727
- const r = rd26(cents2);
83896
+ const r = rd27(cents2);
82728
83897
  if (r !== cents2)
82729
83898
  roundedInputs += 1;
82730
83899
  facts2[id2] = { type: "money", value: r.toString() };
82731
83900
  } else
82732
83901
  facts2[id2] = v;
82733
83902
  }
82734
- const w2Box1Cents = built.w2Box1Cents === void 0 ? void 0 : rd26(built.w2Box1Cents);
83903
+ const w2Box1Cents = built.w2Box1Cents === void 0 ? void 0 : rd27(built.w2Box1Cents);
82735
83904
  if (roundedInputs > 0) {
82736
83905
  documentNotes.push(`whole-dollar rounding: ${roundedInputs} money input(s) rounded to the nearest dollar (50 cents up) after summing documents, before computation \u2014 Form 1040 instructions, Rounding Off to Whole Dollars`);
82737
83906
  }
82738
- const { proof } = evaluate(corpus, facts2, { asOf, target: "us.federal.net_tax", ...built.defaults });
83907
+ const returnCorpus = corpusFor(asOf, built.projection);
83908
+ const { proof } = evaluate(returnCorpus, facts2, { asOf, target: "us.federal.net_tax", ...built.defaults });
82739
83909
  const get = (target) => {
82740
- const { value } = evaluate(corpus, facts2, { asOf, target, ...built.defaults });
83910
+ const { value } = evaluate(returnCorpus, facts2, { asOf, target, ...built.defaults });
82741
83911
  return value.type === "money" ? value.cents : 0n;
82742
83912
  };
82743
83913
  const gross = get("us.federal.gross_income");
@@ -82750,7 +83920,7 @@ function createServer(options = {}) {
82750
83920
  const ctc = get("us.federal.ctc");
82751
83921
  const after = get("us.federal.income_tax_after_credits");
82752
83922
  const other = get("us.federal.other_taxes");
82753
- const eitc = get("us.federal.eitc");
83923
+ const eitc2 = get("us.federal.eitc");
82754
83924
  const actc = get("us.federal.actc");
82755
83925
  const aotcRef = get("us.federal.education.aotc_refundable");
82756
83926
  const refundable = get("us.federal.refundable_credits");
@@ -82773,10 +83943,10 @@ function createServer(options = {}) {
82773
83943
  const extension = extFact && extFact.type === "money" ? BigInt(extFact.value) : 0n;
82774
83944
  const estFact = facts2.federalEstimatedPayments;
82775
83945
  const estimated = estFact && estFact.type === "money" ? BigInt(estFact.value) : 0n;
82776
- const total24 = rd26(after) + rd26(other);
82777
- const payments = rd26(withheld) + rd26(refundable) + rd26(extension) + rd26(estimated);
83946
+ const total24 = rd27(after) + rd27(other);
83947
+ const payments = rd27(withheld) + rd27(refundable) + rd27(extension) + rd27(estimated);
82778
83948
  const balance = payments - total24;
82779
- const d3 = (c2) => fmt2(rd26(c2));
83949
+ const d3 = (c2) => fmt3(rd27(c2));
82780
83950
  return ok({
82781
83951
  ok: true,
82782
83952
  asOf,
@@ -82801,21 +83971,22 @@ function createServer(options = {}) {
82801
83971
  "20_other_nonrefundable_credits": d3(line20),
82802
83972
  "22_tax_after_credits": d3(after),
82803
83973
  "23_other_taxes": d3(other),
82804
- "24_total_tax": fmt2(total24),
83974
+ "24_total_tax": fmt3(total24),
82805
83975
  "25d_withholding": d3(withheld),
82806
83976
  "26_estimated_payments": d3(estimated),
82807
- "27a_eitc": d3(eitc),
83977
+ "27a_eitc": d3(eitc2),
82808
83978
  "28_actc": d3(actc),
82809
83979
  "29_aotc_refundable": d3(aotcRef),
82810
83980
  "32_refundable_credits": d3(refundable),
82811
- ...extension > 0n ? { "31_other_payments_incl_extension": fmt2(rd26(extension)) } : {},
82812
- "33_total_payments": fmt2(payments),
82813
- "34_refund_or_37_owed": balance >= 0n ? `refund ${fmt2(balance)}` : `owed ${fmt2(-balance)}`
83981
+ ...extension > 0n ? { "31_other_payments_incl_extension": fmt3(rd27(extension)) } : {},
83982
+ "33_total_payments": fmt3(payments),
83983
+ "34_refund_or_37_owed": balance >= 0n ? `refund ${fmt3(balance)}` : `owed ${fmt3(-balance)}`
82814
83984
  },
82815
83985
  schedule3: Object.fromEntries(Object.entries(sched3).map(([k, v]) => [k, d3(v)])),
82816
83986
  ...form5695 ? { forms: { "5695": form5695 } } : {},
82817
83987
  note: "Lines 9-37 are engine-computed and whole-dollar rounded; senior/tips/overtime/QBI deductions sit between 12e and 15 (lines 13-14). Line 1a is W-2 box 1 ONLY (Form 1040); non-W-2 earned income (e.g. pre-retirement disability) is line 1h. Gross document lines (4a/5a/6a) come from your transcription. Line 20 is the sum of the modeled Schedule 3 nonrefundable credits (schedule3); when any Form 5695 input is given, forms['5695'] carries that form's printed lines. Report these numbers as-is.",
82818
83988
  assumptions: proof.assumptions,
83989
+ ...built.projection ? { projected: projectedLabel(asOf, built.projection, proof.corpus.version) } : {},
82819
83990
  corpusMerkleRoot: proof.corpus.merkleRoot,
82820
83991
  artifactHash: proof.artifactHash,
82821
83992
  proofScope: "the proof artifact covers the us.federal.net_tax derivation (lines 9-24); other lines are separate cited targets evaluated on the same rounded facts \u2014 request each with calculate_tax + includeProof for its own tree",
@@ -82825,27 +83996,72 @@ function createServer(options = {}) {
82825
83996
  return fail(err);
82826
83997
  }
82827
83998
  });
83999
+ server.registerTool("compute_form_2210", {
84000
+ description: "Form 2210 \u2014 the estimated tax underpayment penalty (26 U.S.C. \xA7 6654) for tax years 2025-2027, composed from the printed form: Part I (the required annual payment: 90% of this year's tax, or 100% / 110% of last year's \u2014 pass priorYearTax and priorYearAGI in facts, or noPriorYearReturn), Part III Section A (underpayment per installment) and the Section B penalty worksheet (payments applied to the earliest underpayment first; each quarter's \xA7 6621 underpayment rate, by days). Pass `payments`: EVERY estimated tax payment with its date (include last year's overpayment applied to this year, dated April 15, and any payment with the return, dated the earlier of filing and April 15); withholding (facts.federalTaxWithheld) is treated as paid one-fourth on each due date unless you pass `withholdingByDate` (box D). Pass `periods` to also run Schedule AI, the annualized income installment method (box C): the CUMULATIVE amounts from January 1 through March 31, May 31 and August 31 for every income, deduction and credit amount that is nonzero for the year (same fact ids as facts; the tool lists any it needs). Each Schedule AI column is the whole return computed on the period's amounts \xD7 4, 2.4, 1.5 and 1, with the standard deduction in full, so every income type, deduction and credit the engine models is annualized; the columns refuse, with the reason, where the form doesn't settle the period treatment (foreign earned income exclusion, prior-year carryovers, premium tax credit, kiddie tax, household employment taxes, a dependent filer, the SALT cap binding in a period). The tool reports both methods and the lower penalty. A penalty that would run into a quarter whose rate the IRS hasn't announced is refused, with Section A still shown. Report the lines and notes verbatim.",
84001
+ inputSchema: legacyJsonSchema(external_exports.object({
84002
+ facts: factsObjectParam,
84003
+ payments: external_exports.array(external_exports.object({ date: external_exports.string(), amount: external_exports.union([external_exports.number(), external_exports.string()]) }).strict()).describe("every estimated tax payment for the year: { date: 'YYYY-MM-DD', amount: dollars } (an empty array if none)"),
84004
+ periods: external_exports.object({
84005
+ mar31: external_exports.record(external_exports.string(), external_exports.union([external_exports.number(), external_exports.string()])),
84006
+ may31: external_exports.record(external_exports.string(), external_exports.union([external_exports.number(), external_exports.string()])),
84007
+ aug31: external_exports.record(external_exports.string(), external_exports.union([external_exports.number(), external_exports.string()]))
84008
+ }).strict().optional().describe("Schedule AI: cumulative amounts from January 1 through each date, keyed by fact id, in dollars"),
84009
+ withholdingByDate: external_exports.array(external_exports.object({ date: external_exports.string(), amount: external_exports.union([external_exports.number(), external_exports.string()]) }).strict()).optional().describe("box D: withholding by the date actually withheld; must total facts.federalTaxWithheld"),
84010
+ noPriorYearReturn: external_exports.boolean().optional().describe("no return for the prior year, or it covered under 12 months: line 9 is line 5"),
84011
+ filedAndPaidInFullOn: external_exports.string().optional().describe("\xA7 6654(h): the date the return was filed and the tax paid in full, when by January 31")
84012
+ }).strict())
84013
+ }, async (args) => {
84014
+ try {
84015
+ const { facts: factArgs, ...options2 } = args;
84016
+ const built = buildFactsValidated(factArgs);
84017
+ const { asOf, defaults } = built;
84018
+ if (built.projection)
84019
+ throw new Error("Form 2210 is composed for the published tax years 2025-2027; drop projection");
84020
+ const run = (f, target) => {
84021
+ const { value } = evaluate(corpus, f, { asOf, target, ...defaults });
84022
+ return value.type === "money" ? value.cents : 0n;
84023
+ };
84024
+ const input2 = form2210InputFromArgs(options2, Number(asOf.slice(0, 4)), built.facts, (plain) => coerceFacts(corpus, plain));
84025
+ const form = composeForm2210(input2, run);
84026
+ if (form.penalty && "refused" in form.penalty) {
84027
+ return {
84028
+ content: [{ type: "text", text: JSON.stringify({ ok: false, error: { code: "NOT_MODELED", message: `Form 2210 penalty refused: ${form.penalty.refused}`, data: { form: { asOf, ...form } } } }, null, 2) }],
84029
+ isError: true
84030
+ };
84031
+ }
84032
+ return ok({ ok: true, asOf, form: "2210", ...form, corpusMerkleRoot: corpus.merkleRoot });
84033
+ } catch (err) {
84034
+ if (err instanceof MissingInput)
84035
+ return fail(new NeedsFactsError(err.missing.map((id2) => ({
84036
+ factId: id2,
84037
+ type: "money",
84038
+ description: id2.startsWith("periods.") ? "Schedule AI: the cumulative amount from January 1 through the period end (0 if none)" : "Form 2210 Part I line 8 needs it (or pass noPriorYearReturn)"
84039
+ }))));
84040
+ return fail(err);
84041
+ }
84042
+ });
82828
84043
  server.registerTool("verify_tax_claim", {
82829
84044
  description: `Verify a claimed tax amount (yours, a user's, or another tool's) against the law. Returns verdict 'verified' or 'refuted' with the correct value. Use this as a self-check before presenting any tax number. Put asOf (and target, if any) INSIDE the facts object \u2014 e.g. facts: {..., "asOf": "2025-12-31"} \u2014 otherwise the claim is checked under today's law.`,
82830
84045
  inputSchema: legacyJsonSchema(external_exports.object({
82831
84046
  facts: factsObjectParam,
82832
- claimedAmount: money43.describe("the amount to verify (negative = refund)"),
84047
+ claimedAmount: money44.describe("the amount to verify (negative = refund)"),
82833
84048
  toleranceDollars: external_exports.number().min(0).optional().describe("default 1")
82834
84049
  }).strict())
82835
84050
  }, async (args) => {
82836
84051
  try {
82837
- const { facts: facts2, asOf, target } = buildFactsValidated(args.facts);
82838
- const { value, proof } = evaluate(corpus, facts2, { asOf, target });
84052
+ const { facts: facts2, asOf, target, projection } = buildFactsValidated(args.facts);
84053
+ const { value, proof } = evaluate(corpusFor(asOf, projection), facts2, { asOf, target });
82839
84054
  const actual = value.type === "money" ? value.cents : 0n;
82840
84055
  const claimed = parseDollars(args.claimedAmount);
82841
84056
  const tolerance = BigInt(Math.round((args.toleranceDollars ?? 1) * 100));
82842
84057
  const diff = actual - claimed;
82843
84058
  const abs = diff < 0n ? -diff : diff;
82844
84059
  return ok({
84060
+ ...projection ? { projected: projectedLabel(asOf, projection, corpusFor(asOf, projection).version) } : {},
82845
84061
  ok: true,
82846
84062
  verdict: abs <= tolerance ? "verified" : "refuted",
82847
- claimed: fmt2(claimed),
82848
- correct: fmt2(actual),
84063
+ claimed: fmt3(claimed),
84064
+ correct: fmt3(actual),
82849
84065
  differenceCents: diff.toString(),
82850
84066
  assumptions: proof.assumptions,
82851
84067
  corpusMerkleRoot: proof.corpus.merkleRoot
@@ -82921,8 +84137,8 @@ function createServer(options = {}) {
82921
84137
  }).strict())
82922
84138
  }, async (args) => {
82923
84139
  try {
82924
- const { facts: facts2, asOf, target } = buildFactsValidated(args.facts);
82925
- const result = findCliffs(corpus, facts2, {
84140
+ const { facts: facts2, asOf, target, projection } = buildFactsValidated(args.facts);
84141
+ const result = findCliffs(corpusFor(asOf, projection), facts2, {
82926
84142
  vary: args.vary,
82927
84143
  fromCents: BigInt(Math.round(args.fromDollars * 100)),
82928
84144
  toCents: BigInt(Math.round(args.toDollars * 100)),
@@ -82932,10 +84148,11 @@ function createServer(options = {}) {
82932
84148
  ...options.hosted ? { limits: HOSTED_CLIFF_LIMITS } : {}
82933
84149
  });
82934
84150
  return ok({
84151
+ ...projection ? { projected: projectedLabel(asOf, projection, corpusFor(asOf, projection).version) } : {},
82935
84152
  ok: true,
82936
84153
  cliffs: result.cliffs.map((c2) => ({
82937
- at: fmt2(c2.atCents),
82938
- oneMoreCentCosts: fmt2(c2.jumpCents)
84154
+ at: fmt3(c2.atCents),
84155
+ oneMoreCentCosts: fmt3(c2.jumpCents)
82939
84156
  })),
82940
84157
  ...result.truncated ? { truncated: true, note: "stopped early: the scan hit its evaluation or cliff budget; narrow the range or raise the step" } : {},
82941
84158
  corpusMerkleRoot: result.corpusMerkleRoot
@@ -82949,15 +84166,16 @@ function createServer(options = {}) {
82949
84166
  inputSchema: legacyJsonSchema(external_exports.object({ facts: factsObjectParam }).strict())
82950
84167
  }, async (args) => {
82951
84168
  try {
82952
- const { facts: facts2, asOf, target } = buildFactsValidated(args.facts);
82953
- const result = compareAcross(corpus, facts2, {
84169
+ const { facts: facts2, asOf, target, projection } = buildFactsValidated(args.facts);
84170
+ const result = compareAcross(corpusFor(asOf, projection), facts2, {
82954
84171
  vary: "filingStatus",
82955
84172
  asOf,
82956
84173
  target
82957
84174
  });
82958
84175
  return ok({
84176
+ ...projection ? { projected: projectedLabel(asOf, projection, corpusFor(asOf, projection).version) } : {},
82959
84177
  ok: true,
82960
- scenarios: result.scenarios.map((s) => s.ok ? { filingStatus: s.value, result: fmt2(s.valueCents) } : { filingStatus: s.value, error: s.errorCode, message: s.errorMessage }),
84178
+ scenarios: result.scenarios.map((s) => s.ok ? { filingStatus: s.value, result: fmt3(s.valueCents) } : { filingStatus: s.value, error: s.errorCode, message: s.errorMessage }),
82961
84179
  corpusMerkleRoot: result.corpusMerkleRoot
82962
84180
  });
82963
84181
  } catch (err) {
@@ -82982,8 +84200,8 @@ function createServer(options = {}) {
82982
84200
  title: h.title,
82983
84201
  citation: h.citation,
82984
84202
  effective: `[${h.effectiveFrom}, ${h.effectiveTo ?? "open"})`,
82985
- byFilingStatus: Object.fromEntries(Object.entries(h.byFilingStatus).map(([k, v]) => [k, fmt2(BigInt(v))])),
82986
- parameters: Object.fromEntries(Object.entries(h.parameters).map(([k, v]) => [k, fmt2(BigInt(v))]))
84203
+ byFilingStatus: Object.fromEntries(Object.entries(h.byFilingStatus).map(([k, v]) => [k, fmt3(BigInt(v))])),
84204
+ parameters: Object.fromEntries(Object.entries(h.parameters).map(([k, v]) => [k, fmt3(BigInt(v))]))
82987
84205
  })),
82988
84206
  corpusMerkleRoot: corpus.merkleRoot
82989
84207
  });
@@ -83018,7 +84236,7 @@ function createServer(options = {}) {
83018
84236
  description: "Fact-check a claimed dollar amount about tax law ('the 2026 MFJ standard deduction is $32,200', 'CTC is $2,000 per child') against the corpus. Returns verified / refuted (with the correct value and citation) / unknown. Never states a verdict it cannot ground.",
83019
84237
  inputSchema: legacyJsonSchema(external_exports.object({
83020
84238
  query: external_exports.string().max(2e3).describe("what the amount is, e.g. 'standard deduction'"),
83021
- claimedAmount: money43,
84239
+ claimedAmount: money44,
83022
84240
  filingStatus: external_exports.enum(["single", "mfj", "mfs", "hoh", "qss"]).optional(),
83023
84241
  asOf: external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional()
83024
84242
  }).strict())
@@ -83033,7 +84251,7 @@ function createServer(options = {}) {
83033
84251
  return ok({
83034
84252
  ok: true,
83035
84253
  verdict: "verified",
83036
- claimed: fmt2(BigInt(result.claimedCents)),
84254
+ claimed: fmt3(BigInt(result.claimedCents)),
83037
84255
  rule: result.matchedRuleId,
83038
84256
  field: result.matchedField,
83039
84257
  citation: result.citation,
@@ -83042,24 +84260,24 @@ function createServer(options = {}) {
83042
84260
  });
83043
84261
  }
83044
84262
  const nearby = [
83045
- { rule: result.matchedRuleId, field: result.matchedField, value: fmt2(BigInt(result.actualCents)) },
84263
+ { rule: result.matchedRuleId, field: result.matchedField, value: fmt3(BigInt(result.actualCents)) },
83046
84264
  ...result.alternatives.flatMap((h) => [
83047
84265
  ...Object.entries(h.byFilingStatus).map(([k, v]) => ({
83048
84266
  rule: h.ruleId,
83049
84267
  field: k,
83050
- value: fmt2(BigInt(v))
84268
+ value: fmt3(BigInt(v))
83051
84269
  })),
83052
84270
  ...Object.entries(h.parameters).map(([k, v]) => ({
83053
84271
  rule: h.ruleId,
83054
84272
  field: k,
83055
- value: fmt2(BigInt(v))
84273
+ value: fmt3(BigInt(v))
83056
84274
  }))
83057
84275
  ])
83058
84276
  ].slice(0, 8);
83059
84277
  return ok({
83060
84278
  ok: true,
83061
84279
  verdict: "refuted",
83062
- claimed: fmt2(BigInt(result.claimedCents)),
84280
+ claimed: fmt3(BigInt(result.claimedCents)),
83063
84281
  message: "no corpus value near this query equals the claim \u2014 the actual values are listed below",
83064
84282
  nearbyValues: nearby,
83065
84283
  citation: result.citation,
@@ -83105,7 +84323,7 @@ function createServer(options = {}) {
83105
84323
  });
83106
84324
  return server;
83107
84325
  }
83108
- var fmt2, FORM_5695_FACTS;
84326
+ var fmt3, FORM_5695_FACTS;
83109
84327
  var init_server3 = __esm({
83110
84328
  "dist/server.js"() {
83111
84329
  "use strict";
@@ -83119,7 +84337,7 @@ var init_server3 = __esm({
83119
84337
  init_dist4();
83120
84338
  init_dist2();
83121
84339
  init_schema();
83122
- fmt2 = (cents2) => {
84340
+ fmt3 = (cents2) => {
83123
84341
  const sign = cents2 < 0n ? "-" : "";
83124
84342
  const abs = cents2 < 0n ? -cents2 : cents2;
83125
84343
  const digits = (abs / 100n).toString();
@@ -83700,8 +84918,8 @@ var init_dist5 = __esm({
83700
84918
  #body;
83701
84919
  #init;
83702
84920
  [getResponseCache]() {
83703
- const cache = this[cacheKey];
83704
- const liveHeaders = cache && cache[2] instanceof Headers ? cache[2] : void 0;
84921
+ const cache2 = this[cacheKey];
84922
+ const liveHeaders = cache2 && cache2[2] instanceof Headers ? cache2[2] : void 0;
83705
84923
  delete this[cacheKey];
83706
84924
  return this[responseCache] ||= new GlobalResponse(this.#body, liveHeaders ? {
83707
84925
  status: this.#init?.status,
@@ -83730,10 +84948,10 @@ var init_dist5 = __esm({
83730
84948
  ];
83731
84949
  }
83732
84950
  get headers() {
83733
- const cache = this[cacheKey];
83734
- if (cache) {
83735
- if (!(cache[2] instanceof Headers)) cache[2] = new Headers(cache[2] || (cache[1] === null ? void 0 : { "content-type": defaultContentType }));
83736
- return cache[2];
84951
+ const cache2 = this[cacheKey];
84952
+ if (cache2) {
84953
+ if (!(cache2[2] instanceof Headers)) cache2[2] = new Headers(cache2[2] || (cache2[1] === null ? void 0 : { "content-type": defaultContentType }));
84954
+ return cache2[2];
83737
84955
  }
83738
84956
  return this[getResponseCache]().headers;
83739
84957
  }
@@ -85516,6 +86734,35 @@ init_dist();
85516
86734
  init_dist2();
85517
86735
  import { readFileSync, writeFileSync } from "node:fs";
85518
86736
 
86737
+ // ../cli/dist/projection.js
86738
+ init_dist2();
86739
+ function corpusForFlags(asOf, flags) {
86740
+ const year = Number(asOf.slice(0, 4));
86741
+ if (flags.projectInflation === void 0) {
86742
+ if (flags.projectWageGrowth !== void 0)
86743
+ throw new Error("--project-wage-growth needs --project-inflation");
86744
+ return getCorpus();
86745
+ }
86746
+ if (year <= LAST_PUBLISHED_YEAR)
86747
+ throw new Error(`--project-inflation is for tax years after ${LAST_PUBLISHED_YEAR}; ${year} is published law \u2014 drop the flag`);
86748
+ return getProjectedFederalCorpus({ year, inflationPercent: String(flags.projectInflation), wageGrowthPercent: flags.projectWageGrowth });
86749
+ }
86750
+ function projectionLabel(asOf, flags, corpus2) {
86751
+ if (flags.projectInflation === void 0)
86752
+ return void 0;
86753
+ return {
86754
+ taxYear: Number(asOf.slice(0, 4)),
86755
+ inflationPercent: String(flags.projectInflation),
86756
+ wageGrowthPercent: String(flags.projectWageGrowth ?? flags.projectInflation),
86757
+ corpusVersion: corpus2.version,
86758
+ warning: "PROJECTED, NOT PUBLISHED LAW: every inflation-indexed amount is the 2027 amount carried forward by its statutory indexing formula at the assumed rates"
86759
+ };
86760
+ }
86761
+ var PROJECTION_HELP = {
86762
+ inflation: "project a tax year after 2027: assumed annual C-CPI-U growth in percent (e.g. 2.5); the answer is labeled projected",
86763
+ wage: "with --project-inflation: assumed annual average wage index growth in percent (social security wage base); default: the inflation rate"
86764
+ };
86765
+
85519
86766
  // ../cli/dist/flags.js
85520
86767
  init_dist();
85521
86768
  init_dist2();
@@ -91794,8 +93041,14 @@ function print(obj) {
91794
93041
 
91795
93042
  // ../cli/dist/commands/check.js
91796
93043
  function runCheck(flags) {
91797
- const corpus2 = getCorpus();
91798
93044
  const asOf = flags.asOf ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
93045
+ let corpus2;
93046
+ try {
93047
+ corpus2 = corpusForFlags(asOf, flags);
93048
+ } catch (err) {
93049
+ return emitError(err, flags.json);
93050
+ }
93051
+ const projected = projectionLabel(asOf, flags, corpus2);
91799
93052
  let plain = {};
91800
93053
  if (flags.facts) {
91801
93054
  try {
@@ -91839,6 +93092,7 @@ function runCheck(flags) {
91839
93092
  differenceCents: diff.toString(),
91840
93093
  toleranceCents: tolerance.toString(),
91841
93094
  assumptions: proof.assumptions,
93095
+ ...projected ? { projected } : {},
91842
93096
  corpusMerkleRoot: proof.corpus.merkleRoot,
91843
93097
  artifactHash: proof.artifactHash
91844
93098
  });
@@ -92004,25 +93258,25 @@ function renderSummary(proof) {
92004
93258
  const statusNode = findNode(root, "us.federal.income_tax_before_credits");
92005
93259
  const statusTag = statusNode?.inputs?.filingStatus?.value !== void 0 ? STATUS_LABEL[String(statusNode.inputs.filingStatus.value)] : null;
92006
93260
  const year = proof.asOf.slice(0, 4);
92007
- const money44 = (c2) => formatMoney(c2).padStart(14);
93261
+ const money45 = (c2) => formatMoney(c2).padStart(14);
92008
93262
  const lines = [];
92009
93263
  lines.push(import_picocolors4.default.bold(`${statusTag ?? "Taxpayer"} \xB7 tax year ${year}`));
92010
93264
  lines.push("");
92011
- lines.push(` Income ${money44(agi2)}`);
92012
- lines.push(` \u2212 Deductions ${money44(deductions)}${dedParts.length ? import_picocolors4.default.dim(` (${dedParts.join(" + ")})`) : ""}`);
92013
- lines.push(` = Taxable income ${money44(taxable2)}`);
92014
- lines.push(` Tax before credits ${money44(before)}`);
93265
+ lines.push(` Income ${money45(agi2)}`);
93266
+ lines.push(` \u2212 Deductions ${money45(deductions)}${dedParts.length ? import_picocolors4.default.dim(` (${dedParts.join(" + ")})`) : ""}`);
93267
+ lines.push(` = Taxable income ${money45(taxable2)}`);
93268
+ lines.push(` Tax before credits ${money45(before)}`);
92015
93269
  if (amt > 0n) {
92016
- lines.push(` + Alternative min tax${money44(amt)}${import_picocolors4.default.dim(" (Form 6251)")}`);
93270
+ lines.push(` + Alternative min tax${money45(amt)}${import_picocolors4.default.dim(" (Form 6251)")}`);
92017
93271
  }
92018
93272
  if (aptcRepayment > 0n) {
92019
- lines.push(` + Excess APTC ${money44(aptcRepayment)}${import_picocolors4.default.dim(" (Form 8962 repayment)")}`);
93273
+ lines.push(` + Excess APTC ${money45(aptcRepayment)}${import_picocolors4.default.dim(" (Form 8962 repayment)")}`);
92020
93274
  }
92021
- lines.push(` \u2212 Credits ${money44(education + ctc + refundable)}${creditParts.length ? import_picocolors4.default.dim(` (${creditParts.join(" + ")})`) : ""}`);
93275
+ lines.push(` \u2212 Credits ${money45(education + ctc + refundable)}${creditParts.length ? import_picocolors4.default.dim(` (${creditParts.join(" + ")})`) : ""}`);
92022
93276
  if (otherTaxes > 0n) {
92023
- lines.push(` + Other taxes ${money44(otherTaxes)}${import_picocolors4.default.dim(" (SE tax / Add'l Medicare / NIIT)")}`);
93277
+ lines.push(` + Other taxes ${money45(otherTaxes)}${import_picocolors4.default.dim(" (SE tax / Add'l Medicare / NIIT)")}`);
92024
93278
  }
92025
- const row2 = (label, amount, paint = (s) => s) => ` ${paint(label.padEnd(21))}${paint(money44(amount))}`;
93279
+ const row2 = (label, amount, paint = (s) => s) => ` ${paint(label.padEnd(21))}${paint(money45(amount))}`;
92026
93280
  lines.push(import_picocolors4.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
92027
93281
  if (net < 0n) {
92028
93282
  lines.push(row2("Your refund", -net, (s) => import_picocolors4.default.bold(import_picocolors4.default.green(s))));
@@ -92110,8 +93364,14 @@ function renderNode(node2, prefix, isLast, lines, seen) {
92110
93364
 
92111
93365
  // ../cli/dist/commands/eval.js
92112
93366
  function runEval(flags) {
92113
- const corpus2 = getCorpus();
92114
93367
  const asOf = flags.asOf ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
93368
+ let corpus2;
93369
+ try {
93370
+ corpus2 = corpusForFlags(asOf, flags);
93371
+ } catch (err) {
93372
+ return emitError(err, flags.json);
93373
+ }
93374
+ const projected = projectionLabel(asOf, flags, corpus2);
92115
93375
  let plain = {};
92116
93376
  if (flags.facts) {
92117
93377
  try {
@@ -92141,6 +93401,7 @@ function runEval(flags) {
92141
93401
  value: proof.root.value,
92142
93402
  formatted: formatValue(proof.root.value),
92143
93403
  assumptions: proof.assumptions,
93404
+ ...projected ? { projected } : {},
92144
93405
  corpusMerkleRoot: proof.corpus.merkleRoot,
92145
93406
  artifactHash: proof.artifactHash,
92146
93407
  proof
@@ -92148,6 +93409,8 @@ function runEval(flags) {
92148
93409
  } else {
92149
93410
  const summary = renderSummary(proof);
92150
93411
  console.log();
93412
+ if (projected)
93413
+ console.log(import_picocolors6.default.yellow(import_picocolors6.default.bold(`PROJECTED ${projected.taxYear} \u2014 not published law (C-CPI-U +${projected.inflationPercent}%/yr, wages +${projected.wageGrowthPercent}%/yr assumed)`)) + "\n");
92151
93414
  if (summary) {
92152
93415
  console.log(summary);
92153
93416
  console.log();
@@ -92475,7 +93738,8 @@ init_dist3();
92475
93738
  init_dist2();
92476
93739
  import { readFileSync as readFileSync3 } from "node:fs";
92477
93740
  function setup(flags) {
92478
- const corpus2 = getCorpus();
93741
+ const asOf = flags.asOf ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
93742
+ const corpus2 = corpusForFlags(asOf, flags);
92479
93743
  let plain = {};
92480
93744
  if (flags.facts)
92481
93745
  plain = JSON.parse(readFileSync3(flags.facts, "utf8"));
@@ -92485,7 +93749,7 @@ function setup(flags) {
92485
93749
  corpus: corpus2,
92486
93750
  base,
92487
93751
  vary: flags.vary ?? "wages",
92488
- asOf: flags.asOf ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
93752
+ asOf,
92489
93753
  target: flags.target ?? DEFAULT_TARGET
92490
93754
  };
92491
93755
  }
@@ -92793,21 +94057,110 @@ function runState(flags) {
92793
94057
  }
92794
94058
  }
92795
94059
 
92796
- // ../cli/dist/commands/verify.js
94060
+ // ../cli/dist/commands/form2210.js
92797
94061
  var import_picocolors15 = __toESM(require_picocolors(), 1);
92798
94062
  init_dist();
92799
94063
  init_dist2();
94064
+ init_dist4();
92800
94065
  import { readFileSync as readFileSync5 } from "node:fs";
94066
+ function runForm2210(flags) {
94067
+ const corpus2 = getCorpus();
94068
+ let args;
94069
+ try {
94070
+ args = JSON.parse(readFileSync5(flags.facts, "utf8"));
94071
+ if (!args || typeof args !== "object" || Array.isArray(args))
94072
+ throw new Error("expected a JSON object");
94073
+ } catch (err) {
94074
+ return emitError(new Error(`cannot read ${flags.facts}: ${err.message}`), flags.json);
94075
+ }
94076
+ const asOf = flags.asOf ?? (typeof args.asOf === "string" ? args.asOf : void 0);
94077
+ if (!asOf) {
94078
+ return emitError(new Error(`--as-of is required (the tax year's year-end, e.g. 2025-12-31), or put "asOf" in the file`), flags.json);
94079
+ }
94080
+ try {
94081
+ const { facts: plainFacts, asOf: _ignored, ...options } = args;
94082
+ const facts2 = coerceFacts(corpus2, plainFacts ?? {});
94083
+ const run = (f, target) => {
94084
+ const { value } = evaluate(corpus2, f, { asOf, target });
94085
+ return value.type === "money" ? value.cents : 0n;
94086
+ };
94087
+ const input2 = form2210InputFromArgs(options, Number(asOf.slice(0, 4)), facts2, (plain) => coerceFacts(corpus2, plain));
94088
+ const form = composeForm2210(input2, run);
94089
+ const refused = form.penalty && "refused" in form.penalty ? form.penalty.refused : void 0;
94090
+ if (flags.json && refused) {
94091
+ print({ ok: false, error: { code: "NOT_MODELED", message: `Form 2210 penalty refused: ${refused}`, data: { form: { asOf, ...form } } } });
94092
+ return EXIT.NOT_COVERED;
94093
+ }
94094
+ if (flags.json) {
94095
+ print({ ok: true, asOf, form: "2210", ...form, corpusMerkleRoot: corpus2.merkleRoot });
94096
+ return EXIT.OK;
94097
+ }
94098
+ const section = (title, lines) => {
94099
+ console.log(import_picocolors15.default.bold(title));
94100
+ const width = Math.max(...Object.keys(lines).map((k) => k.length)) + 2;
94101
+ for (const [k, v] of Object.entries(lines))
94102
+ console.log(` ${k.padEnd(width)}${v}`);
94103
+ console.log();
94104
+ };
94105
+ console.log();
94106
+ section(`Form 2210 (${form.taxYear}) \u2014 Part I`, form.partI);
94107
+ if (form.noPenalty)
94108
+ console.log(import_picocolors15.default.green(` ${form.noPenalty}
94109
+ `));
94110
+ if (form.scheduleAI && "columns" in form.scheduleAI) {
94111
+ for (const col of form.scheduleAI.columns)
94112
+ section(`Schedule AI ${col.column}`, Object.fromEntries(Object.entries(col).filter(([k]) => k !== "column")));
94113
+ } else if (form.scheduleAI) {
94114
+ console.log(import_picocolors15.default.yellow("Schedule AI refused:"));
94115
+ for (const r of form.scheduleAI.refused)
94116
+ console.log(import_picocolors15.default.yellow(` ${r}`));
94117
+ console.log();
94118
+ }
94119
+ for (const m of ["regular", "annualized"]) {
94120
+ const p = form.partIII?.[m];
94121
+ if (!p)
94122
+ continue;
94123
+ console.log(import_picocolors15.default.bold(`Part III \u2014 ${m === "regular" ? "regular installments" : "annualized (Schedule AI) installments"}`));
94124
+ console.log(` due dates ${p.dueDates.join(" ")}`);
94125
+ for (const [line2, cols] of Object.entries(p.sectionA))
94126
+ console.log(` line ${line2.padEnd(4)}${cols.map((c2) => c2.padStart(12)).join("")}`);
94127
+ for (const w of p.worksheet)
94128
+ console.log(import_picocolors15.default.dim(` (${w.column}) ${w.amount} from ${w.from} to ${w.paidOn}: ${w.days} days at ${w.ratePercent}% = ${w.penalty}`));
94129
+ console.log(p.penalty ? ` penalty: ${import_picocolors15.default.bold(p.penalty)}` : import_picocolors15.default.yellow(` ${p.refused}`));
94130
+ console.log();
94131
+ }
94132
+ if (form.penalty) {
94133
+ console.log("method" in form.penalty ? import_picocolors15.default.bold(`Line 19 penalty: ${form.penalty.amount} (${form.penalty.method} method${form.boxes.length ? `; box ${form.boxes.join(", ")}` : ""})`) : import_picocolors15.default.yellow(form.penalty.refused));
94134
+ console.log();
94135
+ }
94136
+ for (const n of form.notes)
94137
+ console.log(import_picocolors15.default.dim(` ${n}`));
94138
+ if (form.notes.length)
94139
+ console.log();
94140
+ return refused ? EXIT.NOT_COVERED : EXIT.OK;
94141
+ } catch (err) {
94142
+ if (err instanceof MissingInput) {
94143
+ return emitError(new NeedsFactsError(err.missing.map((id2) => ({ factId: id2, type: "money", description: "Form 2210 needs this amount" }))), flags.json);
94144
+ }
94145
+ return emitError(err, flags.json);
94146
+ }
94147
+ }
94148
+
94149
+ // ../cli/dist/commands/verify.js
94150
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
94151
+ init_dist();
94152
+ init_dist2();
94153
+ import { readFileSync as readFileSync6 } from "node:fs";
92801
94154
  function runVerify(proofPath, flags) {
92802
94155
  let artifact;
92803
94156
  try {
92804
- artifact = JSON.parse(readFileSync5(proofPath, "utf8"));
94157
+ artifact = JSON.parse(readFileSync6(proofPath, "utf8"));
92805
94158
  } catch (err) {
92806
94159
  return emitError(new Error(`cannot read proof ${proofPath}: ${err.message}`), flags.json);
92807
94160
  }
92808
94161
  let result;
92809
94162
  try {
92810
- result = verifyProof(artifact, getCorpus());
94163
+ result = verifyProof(artifact, corpusForVersion(String(artifact?.corpus?.version ?? "")));
92811
94164
  } catch (err) {
92812
94165
  return emitError(err, flags.json);
92813
94166
  }
@@ -92844,19 +94197,19 @@ function runVerify(proofPath, flags) {
92844
94197
  }
92845
94198
  if (result.ok) {
92846
94199
  console.log();
92847
- console.log(`${import_picocolors15.default.green("\u2713 VERIFIED")} ${import_picocolors15.default.bold(artifact.target)}`);
92848
- console.log(` value ${import_picocolors15.default.green(formatValue(artifact.root.value))} (as of ${artifact.asOf})`);
94200
+ console.log(`${import_picocolors16.default.green("\u2713 VERIFIED")} ${import_picocolors16.default.bold(artifact.target)}`);
94201
+ console.log(` value ${import_picocolors16.default.green(formatValue(artifact.root.value))} (as of ${artifact.asOf})`);
92849
94202
  console.log(` corpus ${result.corpusMerkleRoot}`);
92850
94203
  console.log(` artifact ${artifact.artifactHash}`);
92851
- console.log(import_picocolors15.default.dim(" independently re-derived from the corpus; every node matches the recorded derivation"));
94204
+ console.log(import_picocolors16.default.dim(" independently re-derived from the corpus; every node matches the recorded derivation"));
92852
94205
  console.log();
92853
94206
  return EXIT.OK;
92854
94207
  }
92855
94208
  console.error();
92856
- console.error(`${import_picocolors15.default.red("\u2717 VERIFICATION FAILED")} (${result.reason})`);
94209
+ console.error(`${import_picocolors16.default.red("\u2717 VERIFICATION FAILED")} (${result.reason})`);
92857
94210
  console.error(` ${result.message}`);
92858
94211
  if (result.path)
92859
- console.error(` divergence at: ${import_picocolors15.default.bold(result.path)}`);
94212
+ console.error(` divergence at: ${import_picocolors16.default.bold(result.path)}`);
92860
94213
  if (result.expected)
92861
94214
  console.error(` expected: ${result.expected}`);
92862
94215
  if (result.actual)
@@ -92901,12 +94254,12 @@ Every command accepts --json (single JSON object on stdout, ok: true|false).
92901
94254
  Exit codes: 0 ok \xB7 2 needs more facts (retry with them) \xB7 3 not covered by the corpus (don't retry) \xB7 1 other error.`).version("0.1.0");
92902
94255
  var evalCmd = program2.command("eval").description("compute a tax answer and print its proof tree").option("--facts <file>", "JSON facts file (inline flags below override it)");
92903
94256
  registerFactFlags(evalCmd);
92904
- evalCmd.option("--as-of <date>", "evaluate rules as of this ISO date (default: today)").option("--target <ruleId>", "rule to derive (default: income tax after credits)").option("--proof <file>", "write the proof artifact JSON to this file").option("--brief", "plain-English summary only (skip the proof tree)").option("--assumptions", "list every default the engine relied on (folded by default)").option("--json", "print the proof artifact JSON instead of the tree").option("--refuse-defaults", "refuse instead of assuming: any fact not given exits 2 (NEEDS_FACTS), defaults included").option("--allow-default <factIds...>", "with --refuse-defaults: fact ids whose defaults you accept").action((flags) => {
94257
+ evalCmd.option("--as-of <date>", "evaluate rules as of this ISO date (default: today)").option("--target <ruleId>", "rule to derive (default: income tax after credits)").option("--proof <file>", "write the proof artifact JSON to this file").option("--brief", "plain-English summary only (skip the proof tree)").option("--assumptions", "list every default the engine relied on (folded by default)").option("--json", "print the proof artifact JSON instead of the tree").option("--refuse-defaults", "refuse instead of assuming: any fact not given exits 2 (NEEDS_FACTS), defaults included").option("--project-inflation <percent>", PROJECTION_HELP.inflation).option("--project-wage-growth <percent>", PROJECTION_HELP.wage).option("--allow-default <factIds...>", "with --refuse-defaults: fact ids whose defaults you accept").action((flags) => {
92905
94258
  process.exitCode = runEval(flags);
92906
94259
  });
92907
94260
  var checkCmd = program2.command("check").description("verify a claimed tax amount (e.g. an AI agent's answer) against the law \u2014 exit 0 verified, 1 refuted").option("--facts <file>", "JSON facts file (inline flags below override it)");
92908
94261
  registerFactFlags(checkCmd);
92909
- checkCmd.requiredOption("--expect <dollars>", "the claimed amount to verify (negative = refund)").option("--tolerance <dollars>", "allowed absolute difference", "1").option("--as-of <date>", "evaluate rules as of this ISO date (default: today)").option("--target <ruleId>", "rule to check (default: net tax; balance due if --withheld)").option("--proof <file>", "write the proof artifact JSON to this file").option("--json", "machine-readable verdict").option("--refuse-defaults", "refuse instead of assuming: any fact not given exits 2 (NEEDS_FACTS), defaults included").option("--allow-default <factIds...>", "with --refuse-defaults: fact ids whose defaults you accept").action((flags) => {
94262
+ checkCmd.requiredOption("--expect <dollars>", "the claimed amount to verify (negative = refund)").option("--tolerance <dollars>", "allowed absolute difference", "1").option("--as-of <date>", "evaluate rules as of this ISO date (default: today)").option("--target <ruleId>", "rule to check (default: net tax; balance due if --withheld)").option("--proof <file>", "write the proof artifact JSON to this file").option("--json", "machine-readable verdict").option("--refuse-defaults", "refuse instead of assuming: any fact not given exits 2 (NEEDS_FACTS), defaults included").option("--project-inflation <percent>", PROJECTION_HELP.inflation).option("--project-wage-growth <percent>", PROJECTION_HELP.wage).option("--allow-default <factIds...>", "with --refuse-defaults: fact ids whose defaults you accept").action((flags) => {
92910
94263
  process.exitCode = runCheck(flags);
92911
94264
  });
92912
94265
  program2.command("facts").description("list every input fact the corpus understands").option("--json", "machine-readable output").action((flags) => {
@@ -92954,6 +94307,9 @@ program2.command("occupation").description("is this a \xA7 224 tipped occupation
92954
94307
  program2.command("state").description("compose a state return (IL-1040, VA 760, CA 540, NY IT-201, PA-40, NJ-1040, OH IT 1040, NC D-400, GA 500, MD 502, MO-1040, WI Form 1, MN M1, SC1040, AL Form 40, OR-40, OK Form 511, CT-1040, KS K-40, AR AR1000F, NM PIT-1, NE 1040N, ID Form 40, WV IT-140, ME 1040ME) from a composer-facts JSON file").requiredOption("--facts <file>", "composer facts JSON (same shape as the MCP compute_state_return tool)").option("--as-of <date>", "law in force on this ISO date (default: today)").option("--json", "machine-readable output").action((flags) => {
92955
94308
  process.exitCode = runState({ facts: flags.facts, asOf: flags.asOf, json: flags.json });
92956
94309
  });
94310
+ program2.command("form2210").description("Form 2210: the estimated tax underpayment penalty (\xA7 6654), with Schedule AI (the annualized income installment method), from a JSON file").requiredOption("--facts <file>", "JSON: { facts, payments, periods?, withholdingByDate?, noPriorYearReturn?, filedAndPaidInFullOn? } (same shape as the MCP compute_form_2210 tool)").option("--as-of <date>", "the tax year's rules (e.g. 2025-12-31); required unless the file has asOf").option("--json", "machine-readable output").action((flags) => {
94311
+ process.exitCode = runForm2210({ facts: flags.facts, asOf: flags.asOf, json: flags.json });
94312
+ });
92957
94313
  program2.command("signup").description("get OpenTax updates by email (new features and other things worth knowing)").argument("<email>", "your email address").option("--json", "machine-readable output").action(async (email3, flags) => {
92958
94314
  process.exitCode = await runSignup(email3, { json: flags.json });
92959
94315
  });
@@ -92967,7 +94323,7 @@ function solverCommand(name, description) {
92967
94323
  const cmd = program2.command(name).description(description);
92968
94324
  cmd.option("--facts <file>", "JSON facts file (inline flags below override it)");
92969
94325
  registerFactFlags(cmd);
92970
- cmd.option("--vary <factId>", "fact to vary", "wages").option("--as-of <date>", "evaluate rules as of this ISO date (default: today)").option("--target <ruleId>", "rule to derive (default: net tax)").option("--json", "machine-readable output");
94326
+ cmd.option("--vary <factId>", "fact to vary", "wages").option("--as-of <date>", "evaluate rules as of this ISO date (default: today)").option("--target <ruleId>", "rule to derive (default: net tax)").option("--project-inflation <percent>", PROJECTION_HELP.inflation).option("--project-wage-growth <percent>", PROJECTION_HELP.wage).option("--json", "machine-readable output");
92971
94327
  return cmd;
92972
94328
  }
92973
94329
  solverCommand("sweep", "evaluate the target across a range of one input").requiredOption("--from <dollars>", "range start").requiredOption("--to <dollars>", "range end").option("--step <dollars>", "step size", "1000").option("--csv", "CSV output").action((flags) => {
@@ -93001,7 +94357,7 @@ function runCli(argv) {
93001
94357
 
93002
94358
  // dist/phone-home.js
93003
94359
  init_version();
93004
- import { mkdirSync, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "node:fs";
94360
+ import { mkdirSync, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "node:fs";
93005
94361
  import { homedir } from "node:os";
93006
94362
  import { join } from "node:path";
93007
94363
  var ENDPOINT = "https://opentax.invaro.ai/api/t";
@@ -93013,7 +94369,7 @@ function firstRunNotice() {
93013
94369
  const dir = join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "opentax");
93014
94370
  const flag = join(dir, "notice-shown");
93015
94371
  try {
93016
- readFileSync6(flag);
94372
+ readFileSync7(flag);
93017
94373
  return false;
93018
94374
  } catch {
93019
94375
  }