@paro.io/expert-shared-components 1.14.71 → 1.14.72

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.
@@ -7,12 +7,14 @@ interface ExecutiveSummaryProps {
7
7
  computed: ComputedMap;
8
8
  totalLo: number;
9
9
  totalHi: number;
10
- nowCount: number;
10
+ leadCount: number;
11
+ leadMidK: number;
12
+ leadLabel: string;
11
13
  top3: Strategy[];
12
14
  palette: Palette;
13
15
  effectiveTaxRate?: number;
14
16
  confidenceTier?: string;
15
17
  dataYears?: number;
16
18
  }
17
- export declare function ExecutiveSummary({ profile, eligible, computed, totalLo, totalHi, nowCount, top3, palette, effectiveTaxRate, confidenceTier, dataYears }: ExecutiveSummaryProps): React.JSX.Element;
19
+ export declare function ExecutiveSummary({ profile, eligible, computed, totalLo, totalHi, leadCount, leadMidK, leadLabel, top3, palette, effectiveTaxRate, confidenceTier, dataYears }: ExecutiveSummaryProps): React.JSX.Element;
18
20
  export {};
@@ -10,16 +10,18 @@ const SectionOpener_1 = require("./SectionOpener");
10
10
  const ETRChart_1 = require("./ETRChart");
11
11
  // Format K values: >= 1000K -> "$X.XM", otherwise "$XK"
12
12
  const fmtKRange = (k) => k >= 1000 ? "$" + (k / 1000).toFixed(1) + "M" : "$" + k + "K";
13
- function ExecutiveSummary({ profile, eligible, computed, totalLo, totalHi, nowCount, top3, palette, effectiveTaxRate, confidenceTier, dataYears }) {
13
+ function ExecutiveSummary({ profile, eligible, computed, totalLo, totalHi, leadCount, leadMidK, leadLabel, top3, palette, effectiveTaxRate, confidenceTier, dataYears }) {
14
+ const actionLabel = leadLabel === "this week" ? "Immediate Actions"
15
+ : leadLabel === "within 30 days" ? "30-Day Actions"
16
+ : leadLabel === "within 90 days" ? "90-Day Actions"
17
+ : "Planned Actions";
14
18
  const bizName = profile.bizName || "Client";
15
19
  const rev = parseInt((profile.revenue || "0").replace(/,/g, "")) || 500000;
16
20
  const dataYearsLabel = dataYears ? `${dataYears} year${dataYears > 1 ? "s" : ""}` : (profile.taxDataYears || "1 year");
17
21
  return (react_1.default.createElement(react_1.default.Fragment, null,
18
22
  react_1.default.createElement(SectionOpener_1.SectionOpener, { number: "01", eyebrow: "EXECUTIVE SUMMARY", headline: "Where " + bizName + "'s tax dollars are going \u2014 and where they don't have to.", bullets: [
19
23
  eligible.length + " strategies apply to your current profile, with combined estimated savings of " + fmtKRange(totalLo) + "\u2013" + fmtKRange(totalHi) + " annually.",
20
- nowCount > 0
21
- ? nowCount + " can be initiated this week without any structural changes to your business."
22
- : "Implementation timeline spans the current tax year with no structural changes required.",
24
+ leadCount + " " + (leadCount === 1 ? "strategy" : "strategies") + " can be initiated " + leadLabel + ", representing roughly $" + leadMidK + "K of the midpoint savings estimate.",
23
25
  "Analysis is based on " + dataYearsLabel + " of financial data and current law as of April 2026, including OBBBA provisions.",
24
26
  ], palette: palette }),
25
27
  react_1.default.createElement("div", { style: { marginBottom: 28 } },
@@ -28,7 +30,7 @@ function ExecutiveSummary({ profile, eligible, computed, totalLo, totalHi, nowCo
28
30
  react_1.default.createElement("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr", gap: 16 } }, [
29
31
  { v: fmtKRange(totalLo) + "\u2013" + fmtKRange(totalHi), l: "Est. Annual Savings" },
30
32
  { v: String(eligible.length), l: "Strategies Identified" },
31
- { v: String(nowCount), l: "Immediate Actions" },
33
+ { v: String(leadCount), l: actionLabel },
32
34
  { v: String(top3.length), l: "Priority Recommendations" },
33
35
  ].map(({ v, l }) => (react_1.default.createElement("div", { key: l },
34
36
  react_1.default.createElement("div", { style: { fontSize: 22, fontWeight: 800, color: palette.teal, fontFamily: palette.head, lineHeight: 1.2, marginBottom: 4 } }, v),
@@ -46,7 +48,7 @@ function ExecutiveSummary({ profile, eligible, computed, totalLo, totalHi, nowCo
46
48
  react_1.default.createElement("div", { style: { fontSize: 14, color: palette.gray700, lineHeight: 1.8, fontFamily: palette.body, marginBottom: 16 } },
47
49
  top3.length,
48
50
  " strategies represent the highest-impact opportunities and are detailed below. ",
49
- nowCount > 0 ? "Of these and the broader eligible set, " + nowCount + " can be initiated this week with no structural changes to your business." : "",
51
+ "Of these and the broader eligible set, " + leadCount + " can be initiated " + leadLabel + ".",
50
52
  " Savings estimates reflect your current revenue of ",
51
53
  rev >= 1000000 ? "$" + (rev / 1000000).toFixed(1) + "M" : "$" + Math.round(rev / 1000) + "K",
52
54
  ", an effective tax rate of ",
@@ -15,13 +15,14 @@ interface ImplementationRoadmapProps {
15
15
  eligible: Strategy[];
16
16
  computed: ComputedMap;
17
17
  top3: Strategy[];
18
- nowCount: number;
19
- nowMidK: number;
18
+ leadCount: number;
19
+ leadMidK: number;
20
+ leadLabel: string;
20
21
  bucketDefs: BucketDef[];
21
22
  bucketTotals: Record<string, BucketTotal>;
22
23
  activeBuckets: BucketDef[];
23
24
  palette: Palette;
24
25
  taxYear?: string;
25
26
  }
26
- export declare function ImplementationRoadmap({ eligible, computed, top3, nowCount, nowMidK, bucketDefs, bucketTotals, activeBuckets, palette, taxYear, }: ImplementationRoadmapProps): React.JSX.Element;
27
+ export declare function ImplementationRoadmap({ eligible, computed, top3, leadCount, leadMidK, leadLabel, bucketDefs, bucketTotals, activeBuckets, palette, taxYear, }: ImplementationRoadmapProps): React.JSX.Element;
27
28
  export {};
@@ -9,7 +9,7 @@ const data_1 = require("../../lib/data");
9
9
  const SectionOpener_1 = require("./SectionOpener");
10
10
  const QuarterlyCashChart_1 = require("./QuarterlyCashChart");
11
11
  const ImplementationTimelineChart_1 = require("./ImplementationTimelineChart");
12
- function ImplementationRoadmap({ eligible, computed, top3, nowCount, nowMidK, bucketDefs, bucketTotals, activeBuckets, palette, taxYear, }) {
12
+ function ImplementationRoadmap({ eligible, computed, top3, leadCount, leadMidK, leadLabel, bucketDefs, bucketTotals, activeBuckets, palette, taxYear, }) {
13
13
  const card = {
14
14
  background: palette.white,
15
15
  border: "1px solid " + palette.gray200,
@@ -27,7 +27,7 @@ function ImplementationRoadmap({ eligible, computed, top3, nowCount, nowMidK, bu
27
27
  };
28
28
  return (react_1.default.createElement(react_1.default.Fragment, null,
29
29
  react_1.default.createElement(SectionOpener_1.SectionOpener, { number: "03", eyebrow: "IMPLEMENTATION ROADMAP", headline: "Most savings can be locked in within the current quarter.", bullets: [
30
- nowCount + " eligible strategies can be initiated this week, representing roughly $" + nowMidK + "K of the midpoint savings estimate.",
30
+ leadCount + " eligible " + (leadCount === 1 ? "strategy" : "strategies") + " can be initiated " + leadLabel + ", representing roughly $" + leadMidK + "K of the midpoint savings estimate.",
31
31
  "Time-sensitive elections and filings have firm deadlines noted in each strategy detail above.",
32
32
  "Year-end planning items will be reviewed in a coordinated session before December 31.",
33
33
  ], palette: palette }),
@@ -35,7 +35,7 @@ const RecommendedStrategies_1 = require("./RecommendedStrategies");
35
35
  const ImplementationRoadmap_1 = require("./ImplementationRoadmap");
36
36
  const Methodology_1 = require("./Methodology");
37
37
  function TaxAxisClientReport({ profile, onBack, onNavigatePreparer, liveStrategies, liveComputedMap, engineRawOutput }) {
38
- var _a, _b, _c, _d, _e, _f;
38
+ var _a, _b, _c;
39
39
  const [view, setView] = (0, react_1.useState)("client");
40
40
  const staticEligible = (0, react_1.useMemo)(() => (0, compute_1.filterEligibleStrategies)(profile), [profile]);
41
41
  const staticComputed = (0, react_1.useMemo)(() => (0, compute_1.computeAllStrategies)(profile), [profile]);
@@ -68,8 +68,17 @@ function TaxAxisClientReport({ profile, onBack, onNavigatePreparer, liveStrategi
68
68
  bucketTotals[b.key] = { strategies, lo, hi };
69
69
  });
70
70
  const activeBuckets = bucketDefs.filter(b => bucketTotals[b.key].strategies.length > 0);
71
- const nowCount = ((_a = bucketTotals.now) === null || _a === void 0 ? void 0 : _a.strategies.length) || 0;
72
- const nowMidK = Math.round(((((_b = bucketTotals.now) === null || _b === void 0 ? void 0 : _b.lo) || 0) + (((_c = bucketTotals.now) === null || _c === void 0 ? void 0 : _c.hi) || 0)) / 2 / 1000);
71
+ // Lead bucket: first non-empty bucket for AT A GLANCE summaries
72
+ const leadBucket = activeBuckets[0];
73
+ const leadBt = leadBucket ? bucketTotals[leadBucket.key] : undefined;
74
+ const leadCount = (leadBt === null || leadBt === void 0 ? void 0 : leadBt.strategies.length) || 0;
75
+ const leadMidK = Math.round((((leadBt === null || leadBt === void 0 ? void 0 : leadBt.lo) || 0) + ((leadBt === null || leadBt === void 0 ? void 0 : leadBt.hi) || 0)) / 2 / 1000);
76
+ const leadLabel = leadBucket
77
+ ? leadBucket.key === "now" ? "this week"
78
+ : leadBucket.key === "30d" ? "within 30 days"
79
+ : leadBucket.key === "90d" ? "within 90 days"
80
+ : "before year-end"
81
+ : "this quarter";
73
82
  const handleToggle = (v) => {
74
83
  if (v === "preparer" && onNavigatePreparer) {
75
84
  onNavigatePreparer();
@@ -117,12 +126,12 @@ function TaxAxisClientReport({ profile, onBack, onNavigatePreparer, liveStrategi
117
126
  react_1.default.createElement("div", { style: { maxWidth: 680, margin: "0 auto", padding: "32px 20px 60px" } },
118
127
  react_1.default.createElement(ClientReportCover_1.ClientReportCover, { profile: profile, palette: palette_1.P }),
119
128
  react_1.default.createElement(ClientReportTOC_1.ClientReportTOC, { bizName: bizName, palette: palette_1.P }),
120
- react_1.default.createElement(ExecutiveSummary_1.ExecutiveSummary, { profile: profile, eligible: eligible, computed: computed, totalLo: totalLo, totalHi: totalHi, nowCount: nowCount, top3: top3, palette: palette_1.P, effectiveTaxRate: (_d = engineRawOutput === null || engineRawOutput === void 0 ? void 0 : engineRawOutput.business_profile) === null || _d === void 0 ? void 0 : _d.effective_tax_rate, confidenceTier: (_e = engineRawOutput === null || engineRawOutput === void 0 ? void 0 : engineRawOutput.business_profile) === null || _e === void 0 ? void 0 : _e.confidence_tier, dataYears: (_f = engineRawOutput === null || engineRawOutput === void 0 ? void 0 : engineRawOutput.business_profile) === null || _f === void 0 ? void 0 : _f.data_years }),
129
+ react_1.default.createElement(ExecutiveSummary_1.ExecutiveSummary, { profile: profile, eligible: eligible, computed: computed, totalLo: totalLo, totalHi: totalHi, leadCount: leadCount, leadMidK: leadMidK, leadLabel: leadLabel, top3: top3, palette: palette_1.P, effectiveTaxRate: (_a = engineRawOutput === null || engineRawOutput === void 0 ? void 0 : engineRawOutput.business_profile) === null || _a === void 0 ? void 0 : _a.effective_tax_rate, confidenceTier: (_b = engineRawOutput === null || engineRawOutput === void 0 ? void 0 : engineRawOutput.business_profile) === null || _b === void 0 ? void 0 : _b.confidence_tier, dataYears: (_c = engineRawOutput === null || engineRawOutput === void 0 ? void 0 : engineRawOutput.business_profile) === null || _c === void 0 ? void 0 : _c.data_years }),
121
130
  react_1.default.createElement("div", { style: { background: palette_1.P.gray50, borderLeft: "3px solid " + palette_1.P.gray300, borderRadius: "0 8px 8px 0", padding: "14px 20px", marginBottom: 20, fontSize: 11, color: palette_1.P.gray500, lineHeight: 1.7, fontFamily: palette_1.P.body } },
122
131
  "This summary was prepared using TaxAxis, Paro's AI-powered tax analysis engine. Savings estimates are based on financial data provided for tax year " + profile.year + " (" + (profile.taxDataYears || "1 year") + " of data). All figures are estimates. Your tax preparer has reviewed these recommendations.",
123
132
  hasOBBBA && " Some strategies reference provisions from the One Big Beautiful Bill Act (OBBBA), signed July 4, 2025, with limited IRS guidance."),
124
133
  react_1.default.createElement(RecommendedStrategies_1.RecommendedStrategies, { profile: profile, eligible: eligible, computed: computed, top3: top3, hasOBBBA: hasOBBBA, palette: palette_1.P, interactionWarnings: engineRawOutput === null || engineRawOutput === void 0 ? void 0 : engineRawOutput.strategy_interaction_warnings }),
125
- react_1.default.createElement(ImplementationRoadmap_1.ImplementationRoadmap, { eligible: eligible, computed: computed, top3: top3, nowCount: nowCount, nowMidK: nowMidK, bucketDefs: bucketDefs, bucketTotals: bucketTotals, activeBuckets: activeBuckets, palette: palette_1.P, taxYear: profile.year }),
134
+ react_1.default.createElement(ImplementationRoadmap_1.ImplementationRoadmap, { eligible: eligible, computed: computed, top3: top3, leadCount: leadCount, leadMidK: leadMidK, leadLabel: leadLabel, bucketDefs: bucketDefs, bucketTotals: bucketTotals, activeBuckets: activeBuckets, palette: palette_1.P, taxYear: profile.year }),
126
135
  react_1.default.createElement(Methodology_1.Methodology, { profile: profile, eligible: eligible, palette: palette_1.P }),
127
136
  react_1.default.createElement("div", { style: { padding: "16px 20px", marginBottom: 16, fontSize: 10, color: palette_1.P.gray400, lineHeight: 1.7, fontFamily: palette_1.P.body } }, "This summary was generated by TaxAxis, an AI-powered analysis tool by Paro. Recommendations are based on financial data provided and current tax law as of April 2026, including OBBBA provisions. These are estimates, not guarantees. Consult your tax preparer before implementing any strategy. This is not legal or financial advice."),
128
137
  react_1.default.createElement("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", padding: "12px 0", borderTop: "1px solid " + palette_1.P.gray200, fontSize: 10, color: palette_1.P.gray400, fontFamily: palette_1.P.mono } },
@@ -25,6 +25,42 @@ for (const s of data_1.STRATEGIES) {
25
25
  CATEGORY_BY_RANK.set(s.rank, s.cat);
26
26
  CODE_BY_RANK.set(s.rank, s.code);
27
27
  }
28
+ // Deterministic timeline bucket assignment by strategy number.
29
+ // Overrides LLM-assigned buckets to ensure consistent reports across runs.
30
+ // Bucket assignment logic:
31
+ // now: CPA can action in <2 hours, no external coordination needed
32
+ // 30d: Requires professional setup, plan changes, or payroll adjustments
33
+ // 90d: Requires specialist studies, amended returns, or multi-party coordination
34
+ const TIMELINE_BUCKET_BY_STRATEGY = {
35
+ // --- THIS WEEK: Documentation, reclassification, simple calculations ---
36
+ 10: "now", // S10 Business Meals §274 — reclassify existing expenses
37
+ 11: "now", // S11 Home Office §280A — calculate deduction, measure space
38
+ 13: "now", // S13 Augusta Rule §280A(g) — document rental days
39
+ 17: "now", // S17 Vehicle Expense §274 — review mileage logs, elect method
40
+ // --- WITHIN 30 DAYS: Professional action, plan setup, payroll changes ---
41
+ 1: "30d", // S1 S-Corp Salary §3121 — BLS benchmarking memo, payroll adjustment
42
+ 2: "30d", // S2 Section 179 — asset purchase timing, election
43
+ 3: "30d", // S3 Bonus Depreciation §168(k) — election decision
44
+ 7: "30d", // S7 Retirement §401(k) — plan design review, contribution change
45
+ 9: "30d", // S9 HSA §223 — enrollment, contribution adjustment
46
+ 12: "30d", // S12 Accountable Plan §62 — establish/update plan document
47
+ 14: "30d", // S14 Family Employment §73 — payroll onboarding, age verification
48
+ 21: "30d", // S21 Tips Deduction (OBBBA) — payroll system update
49
+ 22: "30d", // S22 Overtime Deduction (OBBBA) — payroll system update
50
+ 25: "30d", // S25 Trump Accounts (OBBBA) — account establishment
51
+ // --- WITHIN 90 DAYS: Specialist study, amended returns, multi-party coordination ---
52
+ 4: "90d", // S4 QBI §199A — SSTB analysis, entity structure review
53
+ 5: "90d", // S5 R&D Credit §41 — specialist study, Form 6765 prep
54
+ 6: "90d", // S6 WOTC §51 — certification process, hiring program setup
55
+ 8: "90d", // S8 Cost Segregation §168 — engineering study required
56
+ 15: "90d", // S15 PTE/SALT — state election filing, deadline coordination
57
+ 16: "90d", // S16 §179D Energy — energy efficiency certification required
58
+ 18: "90d", // S18 Insurance §79/§264 — carrier coordination, policy restructuring
59
+ 19: "90d", // S19 §1031 Like-Kind — qualified intermediary, identification periods
60
+ 20: "90d", // S20 QSBS §1202 — stock qualification analysis, holding period review
61
+ 23: "90d", // S23 §174A R&E Catch-Up — amended returns for 2022-2024
62
+ 24: "90d", // S24 Childcare §45F — facility/program establishment
63
+ };
28
64
  // ---------------------------------------------------------------------------
29
65
  // Core mapping — engine strategy_analysis entry -> canonical Strategy
30
66
  // ---------------------------------------------------------------------------
@@ -48,9 +84,9 @@ function mapAnalysisToStrategy(sa, idx, pc) {
48
84
  const formsFromTrace = Array.isArray(ct.forms_required)
49
85
  ? ct.forms_required.join(", ")
50
86
  : undefined;
51
- // Timeline bucket: derive from priority as a reasonable default
52
87
  const priority = (sa.priority_tier || "MEDIUM").toUpperCase();
53
- const timelineBucket = sa.quick_win ? "now" : priority === "HIGH" ? "now" : priority === "MEDIUM" ? "30d" : "90d";
88
+ // Deterministic bucket from static map; falls back to "30d" for unknown strategies.
89
+ const timelineBucket = TIMELINE_BUCKET_BY_STRATEGY[strategyNumber !== null && strategyNumber !== void 0 ? strategyNumber : 0] || "30d";
54
90
  return {
55
91
  rank: idx + 1,
56
92
  strategyNumber: strategyNumber !== null && strategyNumber !== void 0 ? strategyNumber : undefined,
@@ -64,7 +100,7 @@ function mapAnalysisToStrategy(sa, idx, pc) {
64
100
  entities: [],
65
101
  lo,
66
102
  hi,
67
- timeline: timelineBucket === "now" ? "Act now" : timelineBucket === "30d" ? "Within 30 days" : "Within 90 days",
103
+ timeline: timelineBucket === "now" ? "This week" : timelineBucket === "30d" ? "Within 30 days" : timelineBucket === "filing" ? "At filing" : "Within 90 days",
68
104
  timelineBucket,
69
105
  abstract: sa.engagement_recommendation || "",
70
106
  warning: (_j = sa.risk_disclosure) !== null && _j !== void 0 ? _j : null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paro.io/expert-shared-components",
3
- "version": "1.14.71",
3
+ "version": "1.14.72",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {