@markcolabs/mcp 0.1.0 → 0.3.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 (88) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSE-API.md +111 -0
  3. package/README.md +128 -205
  4. package/dist/engines/compoundInterest.d.ts +8 -6
  5. package/dist/engines/compoundInterest.d.ts.map +1 -1
  6. package/dist/engines/compoundInterest.js +8 -6
  7. package/dist/engines/compoundInterest.js.map +1 -1
  8. package/dist/engines/data/irs2026.d.ts +110 -3
  9. package/dist/engines/data/irs2026.d.ts.map +1 -1
  10. package/dist/engines/data/irs2026.js +86 -3
  11. package/dist/engines/data/irs2026.js.map +1 -1
  12. package/dist/engines/data/rmd2026.d.ts +59 -0
  13. package/dist/engines/data/rmd2026.d.ts.map +1 -0
  14. package/dist/engines/data/rmd2026.js +75 -0
  15. package/dist/engines/data/rmd2026.js.map +1 -0
  16. package/dist/engines/data/stateTax2026.d.ts +114 -0
  17. package/dist/engines/data/stateTax2026.d.ts.map +1 -0
  18. package/dist/engines/data/stateTax2026.js +348 -0
  19. package/dist/engines/data/stateTax2026.js.map +1 -0
  20. package/dist/engines/hsa.d.ts +110 -0
  21. package/dist/engines/hsa.d.ts.map +1 -0
  22. package/dist/engines/hsa.js +83 -0
  23. package/dist/engines/hsa.js.map +1 -0
  24. package/dist/engines/ira.d.ts +115 -0
  25. package/dist/engines/ira.d.ts.map +1 -0
  26. package/dist/engines/ira.js +127 -0
  27. package/dist/engines/ira.js.map +1 -0
  28. package/dist/engines/mortgage.d.ts +7 -6
  29. package/dist/engines/mortgage.d.ts.map +1 -1
  30. package/dist/engines/mortgage.js +7 -6
  31. package/dist/engines/mortgage.js.map +1 -1
  32. package/dist/engines/paycheck.d.ts +57 -18
  33. package/dist/engines/paycheck.d.ts.map +1 -1
  34. package/dist/engines/paycheck.js +59 -26
  35. package/dist/engines/paycheck.js.map +1 -1
  36. package/dist/engines/retirement401k.d.ts +7 -3
  37. package/dist/engines/retirement401k.d.ts.map +1 -1
  38. package/dist/engines/retirement401k.js +7 -3
  39. package/dist/engines/retirement401k.js.map +1 -1
  40. package/dist/engines/rmd.d.ts +107 -0
  41. package/dist/engines/rmd.d.ts.map +1 -0
  42. package/dist/engines/rmd.js +109 -0
  43. package/dist/engines/rmd.js.map +1 -0
  44. package/dist/engines/rothConversion.d.ts +124 -0
  45. package/dist/engines/rothConversion.d.ts.map +1 -0
  46. package/dist/engines/rothConversion.js +145 -0
  47. package/dist/engines/rothConversion.js.map +1 -0
  48. package/dist/engines/socialSecurity.d.ts +7 -3
  49. package/dist/engines/socialSecurity.d.ts.map +1 -1
  50. package/dist/engines/socialSecurity.js +7 -3
  51. package/dist/engines/socialSecurity.js.map +1 -1
  52. package/dist/index.d.ts +21 -9
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +109 -11
  55. package/dist/index.js.map +1 -1
  56. package/dist/shared/bounds.d.ts +50 -0
  57. package/dist/shared/bounds.d.ts.map +1 -1
  58. package/dist/shared/bounds.js +85 -0
  59. package/dist/shared/bounds.js.map +1 -1
  60. package/dist/tools/hsa.d.ts +58 -0
  61. package/dist/tools/hsa.d.ts.map +1 -0
  62. package/dist/tools/hsa.js +129 -0
  63. package/dist/tools/hsa.js.map +1 -0
  64. package/dist/tools/ira.d.ts +55 -0
  65. package/dist/tools/ira.d.ts.map +1 -0
  66. package/dist/tools/ira.js +117 -0
  67. package/dist/tools/ira.js.map +1 -0
  68. package/dist/tools/paycheck.d.ts +14 -7
  69. package/dist/tools/paycheck.d.ts.map +1 -1
  70. package/dist/tools/paycheck.js +24 -11
  71. package/dist/tools/paycheck.js.map +1 -1
  72. package/dist/tools/retirement401k.d.ts +3 -3
  73. package/dist/tools/retirement401k.d.ts.map +1 -1
  74. package/dist/tools/retirement401k.js +3 -3
  75. package/dist/tools/retirement401k.js.map +1 -1
  76. package/dist/tools/rmd.d.ts +60 -0
  77. package/dist/tools/rmd.d.ts.map +1 -0
  78. package/dist/tools/rmd.js +130 -0
  79. package/dist/tools/rmd.js.map +1 -0
  80. package/dist/tools/rothConversion.d.ts +66 -0
  81. package/dist/tools/rothConversion.d.ts.map +1 -0
  82. package/dist/tools/rothConversion.js +141 -0
  83. package/dist/tools/rothConversion.js.map +1 -0
  84. package/dist/tools/socialSecurity.d.ts +3 -3
  85. package/dist/tools/socialSecurity.d.ts.map +1 -1
  86. package/dist/tools/socialSecurity.js +3 -3
  87. package/dist/tools/socialSecurity.js.map +1 -1
  88. package/package.json +19 -5
@@ -0,0 +1,115 @@
1
+ /**
2
+ * IRA contribution-limit engine — lifted from
3
+ * site/src/utils/ira-limits.js (functions `getContributionLimit`,
4
+ * `isCatchUpEligible`, `getRothContributionLimit`).
5
+ *
6
+ * Per ADR-0039 § 5: pure synchronous function, ENGINE_VERSION constant,
7
+ * parity test against the site source as the gate.
8
+ *
9
+ * Scope (S141 Wave 1A Item #2): MAGI + age + filing status → eligible Roth /
10
+ * Traditional contribution + phase-out reduction. Catch-up eligibility for
11
+ * age ≥ 50. Does NOT compute future-value projection or tax-deduction
12
+ * reinvestment side-account math — those stay in the calculator UI / a future
13
+ * tool. This is a contribution-LIMIT tool, not a projection tool.
14
+ *
15
+ * Math reference (Roth, per IRC §408A(c)(3)):
16
+ * baseCap = age ≥ 50 ? standard + catchUp : standard
17
+ * if MAGI ≤ phaseOut.start → eligible = baseCap
18
+ * if MAGI ≥ phaseOut.end → eligible = 0
19
+ * else:
20
+ * reductionRatio = (MAGI − phaseOut.start) / (phaseOut.end − phaseOut.start)
21
+ * reduced = baseCap × (1 − reductionRatio)
22
+ * eligible = max(round_to_$10(reduced), reduced > 0 ? $200 : 0)
23
+ *
24
+ * Math reference (Traditional, per IRC §219(b) + §219(g)):
25
+ * eligible = baseCap (Traditional CONTRIBUTION is not MAGI-limited;
26
+ * only the DEDUCTION is, via §219(g) phase-out.
27
+ * The contributionLimit tool reports the
28
+ * contribution; the deduction phase-out is
29
+ * surfaced as a separate field for clients that
30
+ * need it.)
31
+ *
32
+ * Source: IRS Notice 2025-67 (2026 retirement plan limits) +
33
+ * SECURE 2.0 Act §107 (catch-up indexing).
34
+ */
35
+ /**
36
+ * SemVer of the IRA engine. Per ADR-0039 § 5 (reaffirmed in ADR-0041 Position #4a):
37
+ * major bump = math change; minor = additive output; patch = numerical correction.
38
+ * NOT bumped for cosmetic refactors.
39
+ * - 1.0.0: initial v1 lift from ira-limits.js (S141 Wave 1A).
40
+ */
41
+ export declare const ENGINE_VERSION = "1.0.0";
42
+ /** Filing status (camelCase, matches the MCP package's federalTax convention). */
43
+ export type IraFilingStatus = "single" | "marriedFilingJointly" | "marriedFilingSeparately" | "headOfHousehold";
44
+ /** IRA type — drives Roth vs Traditional phase-out semantics. */
45
+ export type IraType = "traditional" | "roth";
46
+ /** Inputs to the IRA contribution-limit engine. */
47
+ export interface IraContributionLimitInput {
48
+ /** Current age (used for catch-up eligibility). */
49
+ age: number;
50
+ /** Federal filing status. */
51
+ filingStatus: IraFilingStatus;
52
+ /**
53
+ * Modified Adjusted Gross Income (MAGI), USD. Drives Roth phase-out and
54
+ * is reported alongside the Traditional deduction-phase-out signal.
55
+ */
56
+ magi: number;
57
+ /** Whether to compute the limit for Traditional or Roth. */
58
+ type: IraType;
59
+ }
60
+ /** Result payload returned by the engine. */
61
+ export interface IraContributionLimitResult {
62
+ /** User's max eligible contribution after phase-out, USD. */
63
+ eligibleContribution: number;
64
+ /** Base IRA limit (before catch-up), USD. Same for Traditional and Roth. */
65
+ traditionalCap: number;
66
+ /** Base Roth IRA limit (before catch-up), USD. Same number as traditionalCap. */
67
+ rothCap: number;
68
+ /** Catch-up contribution if age ≥ 50, else 0, USD. */
69
+ catchUp: number;
70
+ /**
71
+ * Reduction applied due to MAGI phase-out (Roth only, USD).
72
+ * For Traditional this is always 0 because contributionLimit is not
73
+ * MAGI-gated (the DEDUCTION is, surfaced separately).
74
+ */
75
+ phaseOutReduction: number;
76
+ /**
77
+ * Whether the user is in the catch-up window (age ≥ catchUpAge).
78
+ * Set independent of `type` so clients can advertise the catch-up regardless
79
+ * of which IRA type they're querying.
80
+ */
81
+ catchUpEligible: boolean;
82
+ /**
83
+ * Traditional IRA deduction phase-out signal (informational; does not
84
+ * affect `eligibleContribution`). Useful for clients that want to advise
85
+ * users their Traditional contribution may be non-deductible at high MAGI.
86
+ * - "fullyDeductible" — MAGI ≤ traditionalPhaseOut.start
87
+ * - "partiallyDeductible" — MAGI within phase-out range
88
+ * - "notDeductible" — MAGI ≥ traditionalPhaseOut.end
89
+ *
90
+ * Assumes the contributor (or spouse) IS covered by a workplace plan; if
91
+ * neither is covered, full deduction applies regardless of MAGI.
92
+ */
93
+ traditionalDeductionStatus: "fullyDeductible" | "partiallyDeductible" | "notDeductible";
94
+ /** Provenance metadata. */
95
+ meta: {
96
+ /** IRS tax year these limits apply to. */
97
+ tableYear: number;
98
+ /** Source authority (IRS notice / IRC citation). */
99
+ source: string;
100
+ };
101
+ }
102
+ /**
103
+ * Compute IRA contribution limit + phase-out reduction for the given inputs.
104
+ *
105
+ * 1-to-1 logic port of site/src/utils/ira-limits.js `getContributionLimit` +
106
+ * `isCatchUpEligible` + `getRothContributionLimit` (the contribution-limit
107
+ * portion; future-value projection is out of scope per S141 Wave 1A).
108
+ *
109
+ * Filing-status key mapping vs. site (which uses 'single' / 'mfj' / 'mfs'):
110
+ * the MCP camelCase keys ('single' / 'marriedFilingJointly' /
111
+ * 'marriedFilingSeparately' / 'headOfHousehold') resolve to the same numeric
112
+ * phase-out thresholds — see ROTH_PHASE_OUT_2026 in data/irs2026.ts.
113
+ */
114
+ export declare function contributionLimit(input: IraContributionLimitInput): IraContributionLimitResult;
115
+ //# sourceMappingURL=ira.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ira.d.ts","sourceRoot":"","sources":["../../src/engines/ira.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAQH;;;;;GAKG;AACH,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,kFAAkF;AAClF,MAAM,MAAM,eAAe,GACvB,QAAQ,GACR,sBAAsB,GACtB,yBAAyB,GACzB,iBAAiB,CAAC;AAEtB,iEAAiE;AACjE,MAAM,MAAM,OAAO,GAAG,aAAa,GAAG,MAAM,CAAC;AAE7C,mDAAmD;AACnD,MAAM,WAAW,yBAAyB;IACxC,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,6BAA6B;IAC7B,YAAY,EAAE,eAAe,CAAC;IAC9B;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,IAAI,EAAE,OAAO,CAAC;CACf;AAED,6CAA6C;AAC7C,MAAM,WAAW,0BAA0B;IACzC,6DAA6D;IAC7D,oBAAoB,EAAE,MAAM,CAAC;IAC7B,4EAA4E;IAC5E,cAAc,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;IACzB;;;;;;;;;;OAUG;IACH,0BAA0B,EACtB,iBAAiB,GACjB,qBAAqB,GACrB,eAAe,CAAC;IACpB,2BAA2B;IAC3B,IAAI,EAAE;QACJ,0CAA0C;QAC1C,SAAS,EAAE,MAAM,CAAC;QAClB,oDAAoD;QACpD,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAYD;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,yBAAyB,GAC/B,0BAA0B,CAgE5B"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * IRA contribution-limit engine — lifted from
3
+ * site/src/utils/ira-limits.js (functions `getContributionLimit`,
4
+ * `isCatchUpEligible`, `getRothContributionLimit`).
5
+ *
6
+ * Per ADR-0039 § 5: pure synchronous function, ENGINE_VERSION constant,
7
+ * parity test against the site source as the gate.
8
+ *
9
+ * Scope (S141 Wave 1A Item #2): MAGI + age + filing status → eligible Roth /
10
+ * Traditional contribution + phase-out reduction. Catch-up eligibility for
11
+ * age ≥ 50. Does NOT compute future-value projection or tax-deduction
12
+ * reinvestment side-account math — those stay in the calculator UI / a future
13
+ * tool. This is a contribution-LIMIT tool, not a projection tool.
14
+ *
15
+ * Math reference (Roth, per IRC §408A(c)(3)):
16
+ * baseCap = age ≥ 50 ? standard + catchUp : standard
17
+ * if MAGI ≤ phaseOut.start → eligible = baseCap
18
+ * if MAGI ≥ phaseOut.end → eligible = 0
19
+ * else:
20
+ * reductionRatio = (MAGI − phaseOut.start) / (phaseOut.end − phaseOut.start)
21
+ * reduced = baseCap × (1 − reductionRatio)
22
+ * eligible = max(round_to_$10(reduced), reduced > 0 ? $200 : 0)
23
+ *
24
+ * Math reference (Traditional, per IRC §219(b) + §219(g)):
25
+ * eligible = baseCap (Traditional CONTRIBUTION is not MAGI-limited;
26
+ * only the DEDUCTION is, via §219(g) phase-out.
27
+ * The contributionLimit tool reports the
28
+ * contribution; the deduction phase-out is
29
+ * surfaced as a separate field for clients that
30
+ * need it.)
31
+ *
32
+ * Source: IRS Notice 2025-67 (2026 retirement plan limits) +
33
+ * SECURE 2.0 Act §107 (catch-up indexing).
34
+ */
35
+ import { LIMITS_IRA_2026, ROTH_PHASE_OUT_2026, TRADITIONAL_PHASE_OUT_2026, } from "./data/irs2026.js";
36
+ /**
37
+ * SemVer of the IRA engine. Per ADR-0039 § 5 (reaffirmed in ADR-0041 Position #4a):
38
+ * major bump = math change; minor = additive output; patch = numerical correction.
39
+ * NOT bumped for cosmetic refactors.
40
+ * - 1.0.0: initial v1 lift from ira-limits.js (S141 Wave 1A).
41
+ */
42
+ export const ENGINE_VERSION = "1.0.0";
43
+ /**
44
+ * IRS rounding rule for phase-out reductions: round to nearest $10, minimum
45
+ * $200 if any contribution is allowed. Per IRC §408A(c)(3)(B)(ii).
46
+ */
47
+ function roundPhaseOutReduction(reduced) {
48
+ if (reduced <= 0)
49
+ return 0;
50
+ const rounded = Math.round(reduced / 10) * 10;
51
+ return Math.max(rounded, 200);
52
+ }
53
+ /**
54
+ * Compute IRA contribution limit + phase-out reduction for the given inputs.
55
+ *
56
+ * 1-to-1 logic port of site/src/utils/ira-limits.js `getContributionLimit` +
57
+ * `isCatchUpEligible` + `getRothContributionLimit` (the contribution-limit
58
+ * portion; future-value projection is out of scope per S141 Wave 1A).
59
+ *
60
+ * Filing-status key mapping vs. site (which uses 'single' / 'mfj' / 'mfs'):
61
+ * the MCP camelCase keys ('single' / 'marriedFilingJointly' /
62
+ * 'marriedFilingSeparately' / 'headOfHousehold') resolve to the same numeric
63
+ * phase-out thresholds — see ROTH_PHASE_OUT_2026 in data/irs2026.ts.
64
+ */
65
+ export function contributionLimit(input) {
66
+ const { age, filingStatus, magi, type } = input;
67
+ // Base cap (Traditional and Roth share the same base contribution limit).
68
+ const baseCap = LIMITS_IRA_2026.standard;
69
+ const catchUpEligible = age >= LIMITS_IRA_2026.catchUpAge;
70
+ const catchUp = catchUpEligible ? LIMITS_IRA_2026.catchUp : 0;
71
+ const fullCap = baseCap + catchUp;
72
+ // --- Roth phase-out (eligibility-gated) ---
73
+ // The Roth contribution itself is phased out at high MAGI. Traditional
74
+ // contribution is NOT (only its deductibility is — surfaced separately).
75
+ let eligibleContribution;
76
+ let phaseOutReduction;
77
+ if (type === "roth") {
78
+ const phaseOut = ROTH_PHASE_OUT_2026[filingStatus];
79
+ if (magi <= phaseOut.start) {
80
+ eligibleContribution = fullCap;
81
+ phaseOutReduction = 0;
82
+ }
83
+ else if (magi >= phaseOut.end) {
84
+ eligibleContribution = 0;
85
+ phaseOutReduction = fullCap;
86
+ }
87
+ else {
88
+ const range = phaseOut.end - phaseOut.start;
89
+ const overStart = magi - phaseOut.start;
90
+ const reductionRatio = overStart / range;
91
+ const reducedRaw = fullCap * (1 - reductionRatio);
92
+ eligibleContribution = roundPhaseOutReduction(reducedRaw);
93
+ phaseOutReduction = fullCap - eligibleContribution;
94
+ }
95
+ }
96
+ else {
97
+ // Traditional: contribution is never MAGI-phased-out, only deduction is.
98
+ eligibleContribution = fullCap;
99
+ phaseOutReduction = 0;
100
+ }
101
+ // --- Traditional deduction-phase-out signal (informational, always reported) ---
102
+ const tradPhaseOut = TRADITIONAL_PHASE_OUT_2026[filingStatus];
103
+ let traditionalDeductionStatus;
104
+ if (magi <= tradPhaseOut.start) {
105
+ traditionalDeductionStatus = "fullyDeductible";
106
+ }
107
+ else if (magi >= tradPhaseOut.end) {
108
+ traditionalDeductionStatus = "notDeductible";
109
+ }
110
+ else {
111
+ traditionalDeductionStatus = "partiallyDeductible";
112
+ }
113
+ return {
114
+ eligibleContribution,
115
+ traditionalCap: baseCap,
116
+ rothCap: baseCap,
117
+ catchUp,
118
+ phaseOutReduction,
119
+ catchUpEligible,
120
+ traditionalDeductionStatus,
121
+ meta: {
122
+ tableYear: 2026,
123
+ source: "IRS Notice 2025-67",
124
+ },
125
+ };
126
+ }
127
+ //# sourceMappingURL=ira.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ira.js","sourceRoot":"","sources":["../../src/engines/ira.ts"],"names":[],"mappings":"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"}
@@ -19,14 +19,15 @@
19
19
  * For 0% rate the formula reduces to: M = P / n
20
20
  */
21
21
  /**
22
- * SemVer of the mortgage engine math. Bumps when math changes OR when the
23
- * package's overall surface area changes meaningfully (S136 batch bump).
22
+ * SemVer of the mortgage engine math. Per ADR-0039 § 5 (reaffirmed in
23
+ * ADR-0041 Position #4a): major bump = math change; minor = additive output;
24
+ * patch = numerical correction. NOT bumped for cosmetic refactors.
24
25
  * - 0.1.0: initial v1 lift from mortgage-calculator.js (Sprint 135 Item 5).
25
- * - 0.2.0: minor batch bump on S136 (no math change here, but package adds
26
- * 3 new engines; bump keeps cross-engine ENGINE_VERSION values aligned for
27
- * the v0.1.0 npm publish surface).
26
+ * - 0.2.0 (v0.1.0 publish): out-of-policy package-surface bump superseded.
27
+ * - 1.0.0 (v0.2.0 publish): one-time reset to align with ADR-0039 § 5 semantics
28
+ * per ADR-0041 D4a. Math is unchanged from 0.1.0 / 0.2.0.
28
29
  */
29
- export declare const ENGINE_VERSION = "0.2.0";
30
+ export declare const ENGINE_VERSION = "1.0.0";
30
31
  /**
31
32
  * Inputs to the mortgage monthly-payment engine.
32
33
  *
@@ -1 +1 @@
1
- {"version":3,"file":"mortgage.d.ts","sourceRoot":"","sources":["../../src/engines/mortgage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,2BAA2B;IAC1C,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,oDAAoD;IACpD,cAAc,EAAE,MAAM,CAAC;IACvB,6DAA6D;IAC7D,aAAa,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,2BAA2B,GACjC,4BAA4B,CAwB9B"}
1
+ {"version":3,"file":"mortgage.d.ts","sourceRoot":"","sources":["../../src/engines/mortgage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,2BAA2B;IAC1C,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,oDAAoD;IACpD,cAAc,EAAE,MAAM,CAAC;IACvB,6DAA6D;IAC7D,aAAa,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,2BAA2B,GACjC,4BAA4B,CAwB9B"}
@@ -19,14 +19,15 @@
19
19
  * For 0% rate the formula reduces to: M = P / n
20
20
  */
21
21
  /**
22
- * SemVer of the mortgage engine math. Bumps when math changes OR when the
23
- * package's overall surface area changes meaningfully (S136 batch bump).
22
+ * SemVer of the mortgage engine math. Per ADR-0039 § 5 (reaffirmed in
23
+ * ADR-0041 Position #4a): major bump = math change; minor = additive output;
24
+ * patch = numerical correction. NOT bumped for cosmetic refactors.
24
25
  * - 0.1.0: initial v1 lift from mortgage-calculator.js (Sprint 135 Item 5).
25
- * - 0.2.0: minor batch bump on S136 (no math change here, but package adds
26
- * 3 new engines; bump keeps cross-engine ENGINE_VERSION values aligned for
27
- * the v0.1.0 npm publish surface).
26
+ * - 0.2.0 (v0.1.0 publish): out-of-policy package-surface bump superseded.
27
+ * - 1.0.0 (v0.2.0 publish): one-time reset to align with ADR-0039 § 5 semantics
28
+ * per ADR-0041 D4a. Math is unchanged from 0.1.0 / 0.2.0.
28
29
  */
29
- export const ENGINE_VERSION = "0.2.0";
30
+ export const ENGINE_VERSION = "1.0.0";
30
31
  /**
31
32
  * Compute the monthly principal & interest payment.
32
33
  *
@@ -1 +1 @@
1
- {"version":3,"file":"mortgage.js","sourceRoot":"","sources":["../../src/engines/mortgage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAmCtC;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAkC;IAElC,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAE1D,MAAM,WAAW,GAAG,iBAAiB,GAAG,GAAG,GAAG,EAAE,CAAC;IACjD,MAAM,WAAW,GAAG,SAAS,GAAG,EAAE,CAAC;IAEnC,IAAI,OAAe,CAAC;IACpB,IAAI,iBAAiB,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,GAAG,SAAS,GAAG,WAAW,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,OAAO;YACL,SAAS;gBACT,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,WAAW,EAAE,WAAW,CAAC,CAAC;oBACrD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,GAAG,WAAW,CAAC;IACxC,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,CAAC;IAE5C,OAAO;QACL,cAAc,EAAE,OAAO;QACvB,aAAa;QACb,SAAS;KACV,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"mortgage.js","sourceRoot":"","sources":["../../src/engines/mortgage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAmCtC;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAkC;IAElC,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAE1D,MAAM,WAAW,GAAG,iBAAiB,GAAG,GAAG,GAAG,EAAE,CAAC;IACjD,MAAM,WAAW,GAAG,SAAS,GAAG,EAAE,CAAC;IAEnC,IAAI,OAAe,CAAC;IACpB,IAAI,iBAAiB,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,GAAG,SAAS,GAAG,WAAW,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,OAAO;YACL,SAAS;gBACT,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,WAAW,EAAE,WAAW,CAAC,CAAC;oBACrD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,GAAG,WAAW,CAAC;IACxC,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,CAAC;IAE5C,OAAO;QACL,cAAc,EAAE,OAAO;QACvB,aAAa;QACb,SAAS;KACV,CAAC;AACJ,CAAC"}
@@ -6,34 +6,55 @@
6
6
  * Per ADR-0039 § 5: pure synchronous functions, ENGINE_VERSION constant,
7
7
  * parity test against the site source as the gate.
8
8
  *
9
- * MCP-side scope decision (S136): the site engine includes per-state tax
10
- * tables loaded async via fetch(), SDI, NYC local tax, hourly-mode handling,
11
- * and YTD wage tracking. None of those fit a synchronous, self-contained
12
- * MCP tool. The v0.2.0 paycheck engine therefore covers:
13
- * - Federal income-tax withholding (Percentage Method, IRS Pub 15-T 2026)
14
- * - FICA (SS 6.2% + Medicare 1.45% + Additional Medicare 0.9%)
15
- * - State estimate: $0 for no-tax states, otherwise a flat 5% estimate
16
- * (clearly disclaimed as an approximation pending a future stateful tool).
17
- * - Pre-tax + post-tax deductions on an annualized basis
9
+ * ## v0.3.0 changes (S141 Item #5)
18
10
  *
19
- * The state-tax limitation is documented in the tool envelope and disclaimer.
11
+ * Two YMYL-grade corrections vs v1.0.0:
20
12
  *
21
- * Math reference (annualized):
13
+ * 1. **MCP-AUDIT-011 — State-aware tax estimate.** The v1.0.0 flat 5% state
14
+ * estimate is replaced with a state-aware effective-rate lookup using
15
+ * marginal-bracket simplification (see `engines/data/stateTax2026.ts`).
16
+ * Rates sourced from the Tax Foundation 2026 State Individual Income Tax
17
+ * Rates report. No-tax states still return $0.
18
+ *
19
+ * 2. **MCP-AUDIT-012 — Additional Medicare base.** The 0.9% Additional
20
+ * Medicare tax now correctly uses the FICA wages base
21
+ * (gross − pre-tax cafeteria-plan deductions: 401k/HSA/dep-care/FSA),
22
+ * not raw gross. Matches the IRS § 3101(b)(2) rule.
23
+ *
24
+ * Engine version bumped 1.0.0 → 1.1.0 (additive: new `state` semantics +
25
+ * new result fields). Math output differs in two ways: state tax becomes
26
+ * state-correct, and Additional Medicare correctly excludes pre-tax
27
+ * deductions. Per ADR-0039 § 5 / ADR-0041 D4a, a math fix is a patch bump
28
+ * if not breaking the public surface; we're using a MINOR bump because we
29
+ * add new result fields (`stateTaxSource`, `stateTaxNotes`,
30
+ * `stateEffectiveRate`).
31
+ *
32
+ * Math reference (annualized) — v0.3.0:
22
33
  * federalTaxableIncome = max(0, grossAnnual − preTaxAnnual − stdDeduction)
23
34
  * federalTax = bracketsLookup(federalTaxableIncome, brackets[filingStatus])
24
- * ssTax = min(grossAnnual − preTaxAnnual, ssWageBase) * 0.062
25
- * medicare = (grossAnnual − preTaxAnnual) * 0.0145
26
- * addlMed = max(0, grossAnnual − addlMedThreshold[filingStatus]) * 0.009
27
- * stateTax = noTaxState ? 0 : (grossAnnual preTaxAnnual − stdDeduction) * 0.05
35
+ * ficaWages = max(0, grossAnnual − preTaxAnnual) // pre-tax deductions reduce FICA base
36
+ * ssTax = min(ficaWages, ssWageBase) * 0.062
37
+ * medicare = ficaWages * 0.0145
38
+ * addlMed = max(0, ficaWagesaddlMedThreshold[filingStatus]) * 0.009
39
+ * stateTax = noTaxState ? 0 : federalTaxableIncome * stateEffectiveRate(state, federalTaxableIncome)
28
40
  * netAnnual = grossAnnual − preTaxAnnual − federalTax − ficaTax − stateTax − postTaxAnnual
29
41
  * per-paycheck values = annual / payPeriodsPerYear
30
42
  */
31
43
  import { type FilingStatus, type PayFrequencyLabel } from "./data/federalTax.js";
32
44
  /**
33
- * SemVer of the paycheck engine.
34
- * - 0.2.0: initial port (S136). Co-incident with the package-wide S136 batch bump.
45
+ * SemVer of the paycheck engine. Per ADR-0039 § 5 (reaffirmed in ADR-0041 Position #4a):
46
+ * major bump = math change; minor = additive output; patch = numerical correction.
47
+ * NOT bumped for cosmetic refactors.
48
+ * - 0.2.0 (v0.1.0 publish): initial port (S136), shipped under out-of-policy package-surface version.
49
+ * - 1.0.0 (v0.2.0 publish): one-time reset to align with ADR-0039 § 5 per ADR-0041 D4a.
50
+ * Math unchanged.
51
+ * - 1.1.0 (v0.3.0 publish, S141 Item #5): state-aware tax (MCP-AUDIT-011) +
52
+ * Additional Medicare on FICA wages (MCP-AUDIT-012). Additive output fields:
53
+ * stateTaxSource, stateTaxNotes, stateEffectiveRate. Per-state math differs
54
+ * vs 1.0.0 for non-no-tax states; Additional Medicare differs for high
55
+ * earners with pre-tax deductions.
35
56
  */
36
- export declare const ENGINE_VERSION = "0.2.0";
57
+ export declare const ENGINE_VERSION = "1.1.0";
37
58
  /** Inputs to the paycheck net-pay engine. */
38
59
  export interface PaycheckNetPayInput {
39
60
  /** Gross annual salary, USD. */
@@ -75,6 +96,24 @@ export interface PaycheckNetPayResult {
75
96
  netPayAnnual: number;
76
97
  /** Whether the state has no income tax. */
77
98
  noStateIncomeTax: boolean;
99
+ /**
100
+ * v1.1.0 additive — citable source for the state-tax effective rate used.
101
+ * Same Tax Foundation 2026 report regardless of state; included for caller
102
+ * provenance.
103
+ */
104
+ stateTaxSource: string;
105
+ /**
106
+ * v1.1.0 additive — state-specific caveats (e.g., "Excludes NYC local tax",
107
+ * "Local municipal EIT NOT included"). Empty string when no caveats apply
108
+ * (no-tax states, flat-rate states with no local-tax overlay, etc.).
109
+ */
110
+ stateTaxNotes: string;
111
+ /**
112
+ * v1.1.0 additive — the effective rate (decimal, 0.093 = 9.3%) the engine
113
+ * applied to taxable income for the state-tax estimate. 0 for no-tax states
114
+ * and for state codes not modeled in our table.
115
+ */
116
+ stateEffectiveRate: number;
78
117
  }
79
118
  /**
80
119
  * Compute net pay (and the annualized + per-paycheck breakdown).
@@ -1 +1 @@
1
- {"version":3,"file":"paycheck.d.ts","sourceRoot":"","sources":["../../src/engines/paycheck.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAQL,KAAK,YAAY,EACjB,KAAK,iBAAiB,EAEvB,MAAM,sBAAsB,CAAC;AAE9B;;;GAGG;AACH,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,6CAA6C;AAC7C,MAAM,WAAW,mBAAmB;IAClC,gCAAgC;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qBAAqB;IACrB,YAAY,EAAE,iBAAiB,CAAC;IAChC,kEAAkE;IAClE,mBAAmB,EAAE,YAAY,CAAC;IAClC,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,sBAAsB,EAAE,MAAM,CAAC;IAC/B,wFAAwF;IACxF,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED,6CAA6C;AAC7C,MAAM,WAAW,oBAAoB;IACnC,mCAAmC;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mCAAmC;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,4BAA4B;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,cAAc,EAAE,MAAM,CAAC;IACvB,+BAA+B;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAmBD;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,mBAAmB,GAAG,oBAAoB,CAoEvE"}
1
+ {"version":3,"file":"paycheck.d.ts","sourceRoot":"","sources":["../../src/engines/paycheck.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,EAQL,KAAK,YAAY,EACjB,KAAK,iBAAiB,EAEvB,MAAM,sBAAsB,CAAC;AAO9B;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,6CAA6C;AAC7C,MAAM,WAAW,mBAAmB;IAClC,gCAAgC;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qBAAqB;IACrB,YAAY,EAAE,iBAAiB,CAAC;IAChC,kEAAkE;IAClE,mBAAmB,EAAE,YAAY,CAAC;IAClC,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,sBAAsB,EAAE,MAAM,CAAC;IAC/B,wFAAwF;IACxF,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED,6CAA6C;AAC7C,MAAM,WAAW,oBAAoB;IACnC,mCAAmC;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mCAAmC;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,4BAA4B;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,cAAc,EAAE,MAAM,CAAC;IACvB,+BAA+B;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,gBAAgB,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAmBD;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,mBAAmB,GAAG,oBAAoB,CA+EvE"}
@@ -6,34 +6,56 @@
6
6
  * Per ADR-0039 § 5: pure synchronous functions, ENGINE_VERSION constant,
7
7
  * parity test against the site source as the gate.
8
8
  *
9
- * MCP-side scope decision (S136): the site engine includes per-state tax
10
- * tables loaded async via fetch(), SDI, NYC local tax, hourly-mode handling,
11
- * and YTD wage tracking. None of those fit a synchronous, self-contained
12
- * MCP tool. The v0.2.0 paycheck engine therefore covers:
13
- * - Federal income-tax withholding (Percentage Method, IRS Pub 15-T 2026)
14
- * - FICA (SS 6.2% + Medicare 1.45% + Additional Medicare 0.9%)
15
- * - State estimate: $0 for no-tax states, otherwise a flat 5% estimate
16
- * (clearly disclaimed as an approximation pending a future stateful tool).
17
- * - Pre-tax + post-tax deductions on an annualized basis
9
+ * ## v0.3.0 changes (S141 Item #5)
18
10
  *
19
- * The state-tax limitation is documented in the tool envelope and disclaimer.
11
+ * Two YMYL-grade corrections vs v1.0.0:
20
12
  *
21
- * Math reference (annualized):
13
+ * 1. **MCP-AUDIT-011 — State-aware tax estimate.** The v1.0.0 flat 5% state
14
+ * estimate is replaced with a state-aware effective-rate lookup using
15
+ * marginal-bracket simplification (see `engines/data/stateTax2026.ts`).
16
+ * Rates sourced from the Tax Foundation 2026 State Individual Income Tax
17
+ * Rates report. No-tax states still return $0.
18
+ *
19
+ * 2. **MCP-AUDIT-012 — Additional Medicare base.** The 0.9% Additional
20
+ * Medicare tax now correctly uses the FICA wages base
21
+ * (gross − pre-tax cafeteria-plan deductions: 401k/HSA/dep-care/FSA),
22
+ * not raw gross. Matches the IRS § 3101(b)(2) rule.
23
+ *
24
+ * Engine version bumped 1.0.0 → 1.1.0 (additive: new `state` semantics +
25
+ * new result fields). Math output differs in two ways: state tax becomes
26
+ * state-correct, and Additional Medicare correctly excludes pre-tax
27
+ * deductions. Per ADR-0039 § 5 / ADR-0041 D4a, a math fix is a patch bump
28
+ * if not breaking the public surface; we're using a MINOR bump because we
29
+ * add new result fields (`stateTaxSource`, `stateTaxNotes`,
30
+ * `stateEffectiveRate`).
31
+ *
32
+ * Math reference (annualized) — v0.3.0:
22
33
  * federalTaxableIncome = max(0, grossAnnual − preTaxAnnual − stdDeduction)
23
34
  * federalTax = bracketsLookup(federalTaxableIncome, brackets[filingStatus])
24
- * ssTax = min(grossAnnual − preTaxAnnual, ssWageBase) * 0.062
25
- * medicare = (grossAnnual − preTaxAnnual) * 0.0145
26
- * addlMed = max(0, grossAnnual − addlMedThreshold[filingStatus]) * 0.009
27
- * stateTax = noTaxState ? 0 : (grossAnnual preTaxAnnual − stdDeduction) * 0.05
35
+ * ficaWages = max(0, grossAnnual − preTaxAnnual) // pre-tax deductions reduce FICA base
36
+ * ssTax = min(ficaWages, ssWageBase) * 0.062
37
+ * medicare = ficaWages * 0.0145
38
+ * addlMed = max(0, ficaWagesaddlMedThreshold[filingStatus]) * 0.009
39
+ * stateTax = noTaxState ? 0 : federalTaxableIncome * stateEffectiveRate(state, federalTaxableIncome)
28
40
  * netAnnual = grossAnnual − preTaxAnnual − federalTax − ficaTax − stateTax − postTaxAnnual
29
41
  * per-paycheck values = annual / payPeriodsPerYear
30
42
  */
31
43
  import { FEDERAL_TAX_BRACKETS_2026, STANDARD_DEDUCTIONS_2026, ADDITIONAL_MEDICARE_THRESHOLDS_2026, FICA_RATES, SS_WAGE_BASE, PAY_PERIODS_PER_YEAR, NO_TAX_STATES, } from "./data/federalTax.js";
44
+ import { getStateEffectiveRate, getStateEntry, STATE_TAX_2026_META, } from "./data/stateTax2026.js";
32
45
  /**
33
- * SemVer of the paycheck engine.
34
- * - 0.2.0: initial port (S136). Co-incident with the package-wide S136 batch bump.
46
+ * SemVer of the paycheck engine. Per ADR-0039 § 5 (reaffirmed in ADR-0041 Position #4a):
47
+ * major bump = math change; minor = additive output; patch = numerical correction.
48
+ * NOT bumped for cosmetic refactors.
49
+ * - 0.2.0 (v0.1.0 publish): initial port (S136), shipped under out-of-policy package-surface version.
50
+ * - 1.0.0 (v0.2.0 publish): one-time reset to align with ADR-0039 § 5 per ADR-0041 D4a.
51
+ * Math unchanged.
52
+ * - 1.1.0 (v0.3.0 publish, S141 Item #5): state-aware tax (MCP-AUDIT-011) +
53
+ * Additional Medicare on FICA wages (MCP-AUDIT-012). Additive output fields:
54
+ * stateTaxSource, stateTaxNotes, stateEffectiveRate. Per-state math differs
55
+ * vs 1.0.0 for non-no-tax states; Additional Medicare differs for high
56
+ * earners with pre-tax deductions.
35
57
  */
36
- export const ENGINE_VERSION = "0.2.0";
58
+ export const ENGINE_VERSION = "1.1.0";
37
59
  const ROUND = (v) => Math.round(v * 100) / 100;
38
60
  /**
39
61
  * Progressive bracket lookup — verbatim port of site `calculateBracketTax`.
@@ -68,23 +90,31 @@ export function netPay(input) {
68
90
  const stdDeduction = STANDARD_DEDUCTIONS_2026[federalFilingStatus];
69
91
  const federalTaxable = Math.max(0, adjustedAnnual - stdDeduction);
70
92
  const federalTaxAnnual = bracketTax(federalTaxable, FEDERAL_TAX_BRACKETS_2026[federalFilingStatus]);
71
- // FICA on gross (less pre-tax cafeteria plan deductions; we conservatively
72
- // apply pre-tax deductions to FICA since the kickoff input doesn't split
73
- // 401k vs cafeteria-plan deductions — matches the more lenient employee view).
93
+ // FICA on gross less pre-tax cafeteria-plan deductions; we conservatively
94
+ // apply all pre-tax deductions to FICA since the input doesn't split 401k
95
+ // vs cafeteria-plan deductions — matches the more lenient employee view.
74
96
  const ficaWages = adjustedAnnual;
75
97
  const ssWageBase = SS_WAGE_BASE[2026] ?? SS_WAGE_BASE[2025];
76
98
  const ssTaxAnnual = Math.min(ficaWages, ssWageBase) * FICA_RATES.socialSecurityRate;
77
99
  const medicareAnnual = ficaWages * FICA_RATES.medicareRate;
78
100
  const addlMedThreshold = ADDITIONAL_MEDICARE_THRESHOLDS_2026[federalFilingStatus];
79
- const addlMedAnnual = grossAnnualSalary > addlMedThreshold
80
- ? (grossAnnualSalary - addlMedThreshold) * FICA_RATES.additionalMedicareRate
101
+ // MCP-AUDIT-012 fix (v1.1.0): Additional Medicare uses FICA wages base,
102
+ // not raw gross. Matches IRS § 3101(b)(2) / Form 8959 rule. Pre-tax
103
+ // health/HSA/dep-care deductions DO reduce the Additional Medicare base.
104
+ const addlMedAnnual = ficaWages > addlMedThreshold
105
+ ? (ficaWages - addlMedThreshold) * FICA_RATES.additionalMedicareRate
81
106
  : 0;
82
107
  const ficaTaxAnnual = ssTaxAnnual + medicareAnnual + addlMedAnnual;
83
- // State tax: no-tax states explicit zero; everyone else gets a flat 5%
84
- // estimate over taxable income (clearly disclaimed in the envelope).
108
+ // State tax: no-tax states explicit zero; everyone else uses state-aware
109
+ // effective-rate lookup (MCP-AUDIT-011 fix, v1.1.0). See stateTax2026.ts.
85
110
  const stateUpper = state.trim().toUpperCase();
86
111
  const noStateIncomeTax = NO_TAX_STATES.includes(stateUpper);
87
- const stateTaxAnnual = noStateIncomeTax ? 0 : federalTaxable * 0.05;
112
+ const stateEffectiveRate = noStateIncomeTax
113
+ ? 0
114
+ : getStateEffectiveRate(stateUpper, federalTaxable);
115
+ const stateTaxAnnual = federalTaxable * stateEffectiveRate;
116
+ const stateEntry = noStateIncomeTax ? undefined : getStateEntry(stateUpper);
117
+ const stateTaxNotes = stateEntry?.notes ?? "";
88
118
  // Net annual + per-paycheck.
89
119
  const netPayAnnual = grossAnnualSalary -
90
120
  preTaxDeductionsAnnual -
@@ -104,6 +134,9 @@ export function netPay(input) {
104
134
  stateTaxAnnual: ROUND(stateTaxAnnual),
105
135
  netPayAnnual: ROUND(netPayAnnual),
106
136
  noStateIncomeTax,
137
+ stateTaxSource: STATE_TAX_2026_META.source,
138
+ stateTaxNotes,
139
+ stateEffectiveRate,
107
140
  };
108
141
  }
109
142
  //# sourceMappingURL=paycheck.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"paycheck.js","sourceRoot":"","sources":["../../src/engines/paycheck.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"paycheck.js","sourceRoot":"","sources":["../../src/engines/paycheck.ts"],"names":[],"mappings":"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"}
@@ -28,10 +28,14 @@
28
28
  * IRS limits: per IRS Notice 2025-67 (2026) — see engines/data/irs2026.ts.
29
29
  */
30
30
  /**
31
- * SemVer of the 401(k) projection engine.
32
- * - 0.2.0: initial port (S136). Co-incident with the package-wide S136 batch bump.
31
+ * SemVer of the 401(k) projection engine. Per ADR-0039 § 5 (reaffirmed in
32
+ * ADR-0041 Position #4a): major bump = math change; minor = additive output;
33
+ * patch = numerical correction. NOT bumped for cosmetic refactors.
34
+ * - 0.2.0 (v0.1.0 publish): initial port (S136), shipped under out-of-policy package-surface version.
35
+ * - 1.0.0 (v0.2.0 publish): one-time reset to align with ADR-0039 § 5 per ADR-0041 D4a.
36
+ * Math unchanged.
33
37
  */
34
- export declare const ENGINE_VERSION = "0.2.0";
38
+ export declare const ENGINE_VERSION = "1.0.0";
35
39
  /** Inputs to the 401(k) projection engine. */
36
40
  export interface Retirement401kProjectionInput {
37
41
  /** Current 401(k) balance, USD. */
@@ -1 +1 @@
1
- {"version":3,"file":"retirement401k.d.ts","sourceRoot":"","sources":["../../src/engines/retirement401k.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH;;;GAGG;AACH,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,8CAA8C;AAC9C,MAAM,WAAW,6BAA6B;IAC5C,mCAAmC;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,wCAAwC;IACxC,YAAY,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,yBAAyB,EAAE,MAAM,CAAC;IAClC,yFAAyF;IACzF,yBAAyB,EAAE,MAAM,CAAC;IAClC,+CAA+C;IAC/C,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,oDAAoD;AACpD,MAAM,WAAW,qBAAqB;IACpC,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,4DAA4D;IAC5D,oBAAoB,EAAE,MAAM,CAAC;IAC7B,qCAAqC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,6CAA6C;AAC7C,MAAM,WAAW,8BAA8B;IAC7C,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oFAAoF;IACpF,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,UAAU,EAAE,qBAAqB,EAAE,CAAC;CACrC;AA4CD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,6BAA6B,GACnC,8BAA8B,CA2EhC"}
1
+ {"version":3,"file":"retirement401k.d.ts","sourceRoot":"","sources":["../../src/engines/retirement401k.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,8CAA8C;AAC9C,MAAM,WAAW,6BAA6B;IAC5C,mCAAmC;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,wCAAwC;IACxC,YAAY,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,yBAAyB,EAAE,MAAM,CAAC;IAClC,yFAAyF;IACzF,yBAAyB,EAAE,MAAM,CAAC;IAClC,+CAA+C;IAC/C,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,oDAAoD;AACpD,MAAM,WAAW,qBAAqB;IACpC,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,4DAA4D;IAC5D,oBAAoB,EAAE,MAAM,CAAC;IAC7B,qCAAqC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,6CAA6C;AAC7C,MAAM,WAAW,8BAA8B;IAC7C,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oFAAoF;IACpF,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,UAAU,EAAE,qBAAqB,EAAE,CAAC;CACrC;AA4CD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,6BAA6B,GACnC,8BAA8B,CA2EhC"}
@@ -29,10 +29,14 @@
29
29
  */
30
30
  import { LIMITS_401K_2026 } from "./data/irs2026.js";
31
31
  /**
32
- * SemVer of the 401(k) projection engine.
33
- * - 0.2.0: initial port (S136). Co-incident with the package-wide S136 batch bump.
32
+ * SemVer of the 401(k) projection engine. Per ADR-0039 § 5 (reaffirmed in
33
+ * ADR-0041 Position #4a): major bump = math change; minor = additive output;
34
+ * patch = numerical correction. NOT bumped for cosmetic refactors.
35
+ * - 0.2.0 (v0.1.0 publish): initial port (S136), shipped under out-of-policy package-surface version.
36
+ * - 1.0.0 (v0.2.0 publish): one-time reset to align with ADR-0039 § 5 per ADR-0041 D4a.
37
+ * Math unchanged.
34
38
  */
35
- export const ENGINE_VERSION = "0.2.0";
39
+ export const ENGINE_VERSION = "1.0.0";
36
40
  const ROUND = (v) => Math.round(v * 100) / 100;
37
41
  /**
38
42
  * IRS contribution cap for a given age, mirroring `getIRSLimit` in the site engine.
@@ -1 +1 @@
1
- {"version":3,"file":"retirement401k.js","sourceRoot":"","sources":["../../src/engines/retirement401k.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"retirement401k.js","sourceRoot":"","sources":["../../src/engines/retirement401k.ts"],"names":[],"mappings":"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"}