@paro.io/expert-shared-components 1.14.67 → 1.14.69
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.
- package/lib/tax-axis/components/intake/ClientParametersSection.js +6 -9
- package/lib/tax-axis/components/intake/StrategyRadar.js +25 -4
- package/lib/tax-axis/components/intake/intakeSchema.d.ts +3 -0
- package/lib/tax-axis/components/intake/intakeSchema.js +2 -0
- package/lib/tax-axis/lib/adapters/useEngineOutput.d.ts +13 -138
- package/lib/tax-axis/lib/adapters/useEngineOutput.js +7 -156
- package/lib/tax-axis/lib/compute/index.js +6 -0
- package/lib/tax-axis/lib/data/strategies.js +45 -47
- package/lib/tax-axis/lib/documentFieldCatalog.d.ts +12 -7
- package/lib/tax-axis/lib/documentFieldCatalog.js +388 -786
- package/lib/tax-axis/lib/types/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -70,12 +70,6 @@ const PERIOD_OPTIONS = ["Full Year", "YTD"];
|
|
|
70
70
|
const YEAR_OPTIONS = ["2024", "2025", "2026"];
|
|
71
71
|
function ClientParametersSection({ userContext = "expert", }) {
|
|
72
72
|
const { control, formState: { errors }, } = (0, react_hook_form_1.useFormContext)();
|
|
73
|
-
// TECH DEBT (post-BDO): Analysis Period dropdown is local useState only —
|
|
74
|
-
// value does not persist to form state because ClientProfile has no `period`
|
|
75
|
-
// field. computeAllStrategies does not read this value. Spec defect.
|
|
76
|
-
// Resolve post-BDO by either adding `period` to ClientProfile or removing
|
|
77
|
-
// the field entirely.
|
|
78
|
-
const [analysisPeriod, setAnalysisPeriod] = (0, react_1.useState)("Full Year");
|
|
79
73
|
const [expanded, setExpanded] = (0, react_1.useState)(true);
|
|
80
74
|
return (react_1.default.createElement(TaxAxisCard_1.TaxAxisCard, null,
|
|
81
75
|
react_1.default.createElement("div", { onClick: () => setExpanded((prev) => !prev), className: "flex items-center justify-between cursor-pointer", style: { marginBottom: expanded ? 14 : 0 } },
|
|
@@ -106,9 +100,12 @@ function ClientParametersSection({ userContext = "expert", }) {
|
|
|
106
100
|
errors.industry && react_1.default.createElement("div", { className: errCls }, errors.industry.message)),
|
|
107
101
|
react_1.default.createElement("div", null,
|
|
108
102
|
react_1.default.createElement("label", { className: labelCls }, "Analysis Period"),
|
|
109
|
-
react_1.default.createElement(
|
|
110
|
-
|
|
111
|
-
|
|
103
|
+
react_1.default.createElement(react_hook_form_1.Controller, { name: "period", control: control, render: ({ field }) => {
|
|
104
|
+
var _a;
|
|
105
|
+
return (react_1.default.createElement("div", { className: "relative" },
|
|
106
|
+
react_1.default.createElement("select", Object.assign({}, field, { value: (_a = field.value) !== null && _a !== void 0 ? _a : "Full Year", className: selectCls }), PERIOD_OPTIONS.map(o => (react_1.default.createElement("option", { key: o, value: o, className: "bg-tax-axis-surface-2" }, o)))),
|
|
107
|
+
react_1.default.createElement(Chevron, null)));
|
|
108
|
+
} })),
|
|
112
109
|
react_1.default.createElement("div", null,
|
|
113
110
|
react_1.default.createElement("label", { className: labelCls }, "Annual Revenue"),
|
|
114
111
|
react_1.default.createElement(react_hook_form_1.Controller, { name: "revenue", control: control, render: ({ field }) => (react_1.default.createElement("div", { className: "relative" },
|
|
@@ -106,13 +106,34 @@ function StrategyRadar({ profile }) {
|
|
|
106
106
|
const eligibleStrategies = (0, compute_1.filterEligibleStrategies)(safeProfile);
|
|
107
107
|
const eligibleIds = new Set(eligibleStrategies.map(s => String(s.rank)));
|
|
108
108
|
const stratCount = eligibleStrategies.length;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
109
|
+
// Serialize to primitive — watch() may return a reference-stable proxy,
|
|
110
|
+
// so [profile] as a dep would never re-fire the memo on field changes
|
|
111
|
+
const profileKey = JSON.stringify(profile);
|
|
112
|
+
const computed = (0, react_1.useMemo)(() => (0, compute_1.computeAllStrategies)(safeProfile), [profileKey]);
|
|
113
|
+
const fedRate = parseFloat((profile.federalRate || "24").replace("%", "")) / 100 || 0.24;
|
|
114
|
+
const stateRate = parseFloat(profile.stateRate || "4.95") / 100;
|
|
115
|
+
const netIncome = parseInt((profile.netIncome || "0").replace(/,/g, "")) || Math.round(rev * 0.3);
|
|
116
|
+
let loSum = eligibleStrategies.reduce((a, s) => { var _a, _b; return a + ((_b = (_a = computed.get(s.rank)) === null || _a === void 0 ? void 0 : _a.lo) !== null && _b !== void 0 ? _b : s.lo); }, 0);
|
|
117
|
+
let hiSum = eligibleStrategies.reduce((a, s) => { var _a, _b; return a + ((_b = (_a = computed.get(s.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : s.hi); }, 0);
|
|
118
|
+
// Tax-capacity cap: savings cannot exceed approximate total tax liability
|
|
119
|
+
const approxTaxLiability = Math.round(netIncome * (fedRate + stateRate));
|
|
120
|
+
if (approxTaxLiability > 0) {
|
|
121
|
+
hiSum = Math.min(hiSum, approxTaxLiability);
|
|
122
|
+
loSum = Math.min(loSum, hiSum);
|
|
123
|
+
// If cap squashed lo close to hi, re-spread to maintain a meaningful range
|
|
124
|
+
if (hiSum > 0 && loSum >= hiSum * 0.9) {
|
|
125
|
+
loSum = Math.round(hiSum / 3);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Aggregate spread constraint: max 3× ratio between hi and lo
|
|
129
|
+
if (hiSum > 0 && loSum > 0 && hiSum / loSum > 3.0) {
|
|
130
|
+
loSum = Math.round(hiSum / 3.0);
|
|
131
|
+
}
|
|
112
132
|
const highImpact = eligibleStrategies.filter(s => s.priority === "HIGH").length;
|
|
113
133
|
const quickWins = eligibleStrategies.filter(s => s.priority === "QUICK WIN").length;
|
|
114
134
|
const obbbaNew = eligibleStrategies.filter(s => s.cat === "obbba_new").length;
|
|
115
|
-
|
|
135
|
+
// PTE elections are only available for pass-through entities; C-Corps are ineligible
|
|
136
|
+
const hasPTE = entity !== "C-Corporation" && states.some(s => states_1.PTE_STATES.has(s));
|
|
116
137
|
const hasNoTax = states.some(s => states_1.NO_INCOME_TAX.has(s));
|
|
117
138
|
const total = RADAR_NODES.length;
|
|
118
139
|
// G4 — Sizing: compact vs expanded
|
|
@@ -31,6 +31,7 @@ export declare const intakeSchema: Yup.ObjectSchema<import("yup/lib/object").Ass
|
|
|
31
31
|
hsaContributions: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
32
32
|
wotcHires: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
33
33
|
familyEmployed: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
34
|
+
period: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
34
35
|
}>, import("yup/lib/object").AnyObject, import("yup/lib/object").TypeOfShape<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
|
|
35
36
|
bizName: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
36
37
|
cpaName: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
@@ -62,6 +63,7 @@ export declare const intakeSchema: Yup.ObjectSchema<import("yup/lib/object").Ass
|
|
|
62
63
|
hsaContributions: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
63
64
|
wotcHires: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
64
65
|
familyEmployed: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
66
|
+
period: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
65
67
|
}>>, import("yup/lib/object").AssertsShape<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
|
|
66
68
|
bizName: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
67
69
|
cpaName: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
@@ -93,5 +95,6 @@ export declare const intakeSchema: Yup.ObjectSchema<import("yup/lib/object").Ass
|
|
|
93
95
|
hsaContributions: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
94
96
|
wotcHires: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
95
97
|
familyEmployed: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
98
|
+
period: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
|
|
96
99
|
}>>>;
|
|
97
100
|
export declare const intakeDefaultValues: Partial<ClientProfile>;
|
|
@@ -56,6 +56,7 @@ exports.intakeSchema = Yup.object().shape({
|
|
|
56
56
|
hsaContributions: Yup.string().ensure(),
|
|
57
57
|
wotcHires: Yup.string().ensure(),
|
|
58
58
|
familyEmployed: Yup.string().ensure(),
|
|
59
|
+
period: Yup.string().ensure(),
|
|
59
60
|
});
|
|
60
61
|
exports.intakeDefaultValues = {
|
|
61
62
|
bizName: "",
|
|
@@ -88,4 +89,5 @@ exports.intakeDefaultValues = {
|
|
|
88
89
|
hsaContributions: "0",
|
|
89
90
|
wotcHires: "No",
|
|
90
91
|
familyEmployed: "No",
|
|
92
|
+
period: "Full Year",
|
|
91
93
|
};
|
|
@@ -1,151 +1,26 @@
|
|
|
1
1
|
import type { Strategy, ComputedMap } from "../types";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
strategy_id: string;
|
|
9
|
-
branch_executed: string | null;
|
|
10
|
-
formula: string;
|
|
11
|
-
inputs: Record<string, unknown>;
|
|
12
|
-
result_gross: number | null;
|
|
13
|
-
confidence_interval: {
|
|
14
|
-
low: number;
|
|
15
|
-
high: number;
|
|
16
|
-
basis: string;
|
|
17
|
-
} | null;
|
|
18
|
-
position_strength: string;
|
|
19
|
-
irs_cite: string;
|
|
20
|
-
data_quality_flag: string | null;
|
|
21
|
-
forms_required: string[];
|
|
22
|
-
deadline_flag: string | null;
|
|
23
|
-
amt_flag: boolean;
|
|
24
|
-
source_documents?: SourceDocumentRef[];
|
|
25
|
-
specialist_note?: string | null;
|
|
2
|
+
/** Raw engine output blob from the LLM run. */
|
|
3
|
+
export type EngineOutput = Record<string, unknown> | null;
|
|
4
|
+
/** Adapter result passed to client-report / preparer-workpaper components. */
|
|
5
|
+
export interface EngineOutputAdapterResult {
|
|
6
|
+
strategies: Strategy[];
|
|
7
|
+
computedMap: ComputedMap;
|
|
26
8
|
}
|
|
9
|
+
/** Single strategy analysis entry from the engine. */
|
|
27
10
|
export interface EngineStrategyAnalysis {
|
|
28
11
|
strategy_id: string;
|
|
29
12
|
strategy_name: string;
|
|
30
|
-
priority_tier:
|
|
13
|
+
priority_tier: string;
|
|
31
14
|
weighted_score: number;
|
|
32
|
-
scores: {
|
|
33
|
-
financial_impact: number;
|
|
34
|
-
applicability: number;
|
|
35
|
-
complexity: number;
|
|
36
|
-
risk: number;
|
|
37
|
-
cash_flow: number;
|
|
38
|
-
};
|
|
39
15
|
quick_win: boolean;
|
|
40
|
-
calculation_trace: EngineCalculationTrace;
|
|
41
16
|
engagement_recommendation: string;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
export interface EngineClientSummaryStrategy {
|
|
45
|
-
slot: number;
|
|
46
|
-
strategy_name: string;
|
|
47
|
-
savings_range: string;
|
|
48
|
-
why_it_applies: string;
|
|
49
|
-
next_step: string;
|
|
50
|
-
quick_win_badge: boolean;
|
|
51
|
-
deadline_flag?: string | null;
|
|
17
|
+
calculation_trace?: Record<string, unknown>;
|
|
18
|
+
[key: string]: unknown;
|
|
52
19
|
}
|
|
20
|
+
/** CPA workflow section from the engine. */
|
|
53
21
|
export interface EngineCpaWorkflow {
|
|
54
22
|
workpaper_codes: string[] | null;
|
|
55
|
-
section_6694_notices: Array<{
|
|
56
|
-
strategy_id: string;
|
|
57
|
-
position_strength: string;
|
|
58
|
-
notice: string;
|
|
59
|
-
}>;
|
|
60
|
-
prior_year_flags: string[];
|
|
61
|
-
conflict_of_interest_checklist: Array<{
|
|
62
|
-
strategy_id: string;
|
|
63
|
-
conflict_prompt: string;
|
|
64
|
-
confirmed_no_conflict: boolean;
|
|
65
|
-
}>;
|
|
66
23
|
engagement_recommendations: string[];
|
|
24
|
+
[key: string]: unknown;
|
|
67
25
|
}
|
|
68
|
-
export
|
|
69
|
-
engagement_id: string;
|
|
70
|
-
generated_at: string;
|
|
71
|
-
algorithm_version: string;
|
|
72
|
-
business_profile: {
|
|
73
|
-
entity_type: string;
|
|
74
|
-
industry: string;
|
|
75
|
-
industry_vertical: string;
|
|
76
|
-
states: string[];
|
|
77
|
-
data_years: number;
|
|
78
|
-
confidence_tier: string;
|
|
79
|
-
effective_tax_rate: number | null;
|
|
80
|
-
data_quality_flags: string[];
|
|
81
|
-
};
|
|
82
|
-
eligibility_screening: {
|
|
83
|
-
excluded_strategies: Array<{
|
|
84
|
-
strategy_id: string;
|
|
85
|
-
status: "EXCLUDED";
|
|
86
|
-
reason: string;
|
|
87
|
-
irs_cite: string;
|
|
88
|
-
}>;
|
|
89
|
-
};
|
|
90
|
-
strategy_analysis: EngineStrategyAnalysis[];
|
|
91
|
-
strategy_interaction_warnings: Array<{
|
|
92
|
-
strategy_pair: [string, string];
|
|
93
|
-
warning_text: string;
|
|
94
|
-
}>;
|
|
95
|
-
implementation_roadmap: {
|
|
96
|
-
quick_wins: Array<{
|
|
97
|
-
strategy_id: string;
|
|
98
|
-
action: string;
|
|
99
|
-
deadline?: string | null;
|
|
100
|
-
}>;
|
|
101
|
-
immediate: Array<{
|
|
102
|
-
strategy_id: string;
|
|
103
|
-
action: string;
|
|
104
|
-
deadline?: string | null;
|
|
105
|
-
}>;
|
|
106
|
-
thirty_day: Array<{
|
|
107
|
-
strategy_id: string;
|
|
108
|
-
action: string;
|
|
109
|
-
deadline?: string | null;
|
|
110
|
-
}>;
|
|
111
|
-
ninety_day: Array<{
|
|
112
|
-
strategy_id: string;
|
|
113
|
-
action: string;
|
|
114
|
-
deadline?: string | null;
|
|
115
|
-
}>;
|
|
116
|
-
annual: Array<{
|
|
117
|
-
strategy_id: string;
|
|
118
|
-
action: string;
|
|
119
|
-
deadline?: string | null;
|
|
120
|
-
}>;
|
|
121
|
-
};
|
|
122
|
-
cpa_workflow: EngineCpaWorkflow;
|
|
123
|
-
client_summary: {
|
|
124
|
-
opening: string;
|
|
125
|
-
strategies: EngineClientSummaryStrategy[];
|
|
126
|
-
data_quality_note: string | null;
|
|
127
|
-
interaction_warning: string | null;
|
|
128
|
-
closing: string;
|
|
129
|
-
};
|
|
130
|
-
risk_disclosures: string[];
|
|
131
|
-
client_risk_disclosures: {
|
|
132
|
-
accuracy_penalty_warning: string | null;
|
|
133
|
-
applies_to_strategies: string[];
|
|
134
|
-
};
|
|
135
|
-
amt_flags: Array<{
|
|
136
|
-
trigger: string;
|
|
137
|
-
strategy_id: string;
|
|
138
|
-
flag_text: string;
|
|
139
|
-
}>;
|
|
140
|
-
nexus_flags: Array<{
|
|
141
|
-
state: string;
|
|
142
|
-
nexus_type: string;
|
|
143
|
-
flag_text: string;
|
|
144
|
-
}>;
|
|
145
|
-
}
|
|
146
|
-
export interface EngineOutputAdapterResult {
|
|
147
|
-
strategies: Strategy[];
|
|
148
|
-
computedMap: ComputedMap;
|
|
149
|
-
engineOutput: EngineOutput;
|
|
150
|
-
}
|
|
151
|
-
export declare function useEngineOutput(engineOutput: EngineOutput | null | undefined): EngineOutputAdapterResult | null;
|
|
26
|
+
export declare function useEngineOutput(_engineOutput: EngineOutput): EngineOutputAdapterResult | null;
|
|
@@ -1,161 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// into the Strategy[] + ComputedMap shapes the FE components consume.
|
|
5
|
-
//
|
|
6
|
-
// Strategy: use the static STRATEGIES catalog as a structural template
|
|
7
|
-
// (rank, cat, entities, authority, etc.) and override savings/priority/score
|
|
8
|
-
// from the live engine data. Falls back to static data when a strategy_id
|
|
9
|
-
// has no match in the catalog (future-proofing for new strategies).
|
|
10
|
-
// ═══════════════════════════════════════════════════════════════════
|
|
2
|
+
// useEngineOutput — minimal stub to unblock builds.
|
|
3
|
+
// TODO: centralise narrative-field mapping (why_it_applies, source_documents, specialistNote) here.
|
|
11
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
5
|
exports.useEngineOutput = useEngineOutput;
|
|
13
6
|
const react_1 = require("react");
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
S1: 1, // Business Entity Structure (S-Corp election)
|
|
20
|
-
S2: 2, // Section 179
|
|
21
|
-
S3: 3, // Bonus Depreciation §168(k)
|
|
22
|
-
S4: 4, // QBI §199A
|
|
23
|
-
S5: 5, // R&D Credit §41
|
|
24
|
-
S6: 6, // WOTC §51
|
|
25
|
-
S7: 7, // Retirement Plan
|
|
26
|
-
S8: 8, // Cost Segregation
|
|
27
|
-
S9: 9, // HSA
|
|
28
|
-
S10: 10, // Business Meals
|
|
29
|
-
S11: 11, // Professional Services / Legal
|
|
30
|
-
S12: 12, // Home Office
|
|
31
|
-
S13: 13, // Health Care Credit §45R
|
|
32
|
-
S14: 14, // Charitable / DAF
|
|
33
|
-
S15: 15, // SALT PTE
|
|
34
|
-
S16: 16, // §163(j) Interest
|
|
35
|
-
S17: 17, // Income Deferral
|
|
36
|
-
S18: 18, // Opportunity Zone §1400Z
|
|
37
|
-
S19: 19, // §179D Energy
|
|
38
|
-
S20: 20, // Accounting Method
|
|
39
|
-
S21: 21, // OBBBA Overtime
|
|
40
|
-
S22: 22, // OBBBA Tips / Overtime
|
|
41
|
-
S23: 23, // §174A R&E catch-up
|
|
42
|
-
S24: 24, // Childcare §45F
|
|
43
|
-
S25: 25, // OBBBA Trump Accounts
|
|
44
|
-
};
|
|
45
|
-
const CATALOG_BY_RANK = new Map(data_1.STRATEGIES.map((s) => [s.rank, s]));
|
|
46
|
-
// ── Priority tier mapping ─────────────────────────────────────────────
|
|
47
|
-
function mapPriority(tier, quickWin) {
|
|
48
|
-
if (quickWin)
|
|
49
|
-
return "QUICK WIN";
|
|
50
|
-
if (tier === "HIGH")
|
|
51
|
-
return "HIGH";
|
|
52
|
-
if (tier === "MEDIUM")
|
|
53
|
-
return "MEDIUM";
|
|
54
|
-
if (tier === "LOW")
|
|
55
|
-
return "LOW";
|
|
56
|
-
return "NOT RECOMMENDED";
|
|
57
|
-
}
|
|
58
|
-
// ── Timeline bucket from implementation_roadmap ───────────────────────
|
|
59
|
-
function resolveTimelineBucket(strategyId, roadmap) {
|
|
60
|
-
if (roadmap.quick_wins.some((r) => r.strategy_id === strategyId))
|
|
61
|
-
return "now";
|
|
62
|
-
if (roadmap.immediate.some((r) => r.strategy_id === strategyId))
|
|
63
|
-
return "now";
|
|
64
|
-
if (roadmap.thirty_day.some((r) => r.strategy_id === strategyId))
|
|
65
|
-
return "30d";
|
|
66
|
-
if (roadmap.ninety_day.some((r) => r.strategy_id === strategyId))
|
|
67
|
-
return "90d";
|
|
68
|
-
if (roadmap.annual.some((r) => r.strategy_id === strategyId))
|
|
69
|
-
return "filing";
|
|
70
|
-
return "filing";
|
|
71
|
-
}
|
|
72
|
-
// ── CalculationTrace → StrategyTraceStep[] ───────────────────────────
|
|
73
|
-
function traceFromEngine(trace) {
|
|
74
|
-
var _a, _b;
|
|
75
|
-
const steps = [];
|
|
76
|
-
// Emit formula as step 1
|
|
77
|
-
if (trace.formula) {
|
|
78
|
-
steps.push({
|
|
79
|
-
n: 1,
|
|
80
|
-
step: "Formula",
|
|
81
|
-
formula: trace.formula,
|
|
82
|
-
result: trace.result_gross != null ? `$${trace.result_gross.toLocaleString()}` : "See CI",
|
|
83
|
-
src: trace.irs_cite || "",
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
// Emit confidence interval as step 2 when present
|
|
87
|
-
if (((_a = trace.confidence_interval) === null || _a === void 0 ? void 0 : _a.low) != null && ((_b = trace.confidence_interval) === null || _b === void 0 ? void 0 : _b.high) != null) {
|
|
88
|
-
steps.push({
|
|
89
|
-
n: 2,
|
|
90
|
-
step: "Confidence range",
|
|
91
|
-
formula: `Low × ${trace.confidence_interval.basis}`,
|
|
92
|
-
result: `$${trace.confidence_interval.low.toLocaleString()} – $${trace.confidence_interval.high.toLocaleString()}`,
|
|
93
|
-
src: trace.irs_cite || "",
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
return steps;
|
|
97
|
-
}
|
|
98
|
-
function adaptEngineOutput(engineOutput) {
|
|
99
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
100
|
-
const strategies = [];
|
|
101
|
-
const computedMap = new Map();
|
|
102
|
-
for (const analysis of engineOutput.strategy_analysis) {
|
|
103
|
-
if (analysis.priority_tier === "NOT_RECOMMENDED")
|
|
104
|
-
continue;
|
|
105
|
-
const rank = ENGINE_ID_TO_RANK[analysis.strategy_id];
|
|
106
|
-
const template = rank != null ? CATALOG_BY_RANK.get(rank) : undefined;
|
|
107
|
-
const trace = analysis.calculation_trace;
|
|
108
|
-
const ci = trace === null || trace === void 0 ? void 0 : trace.confidence_interval;
|
|
109
|
-
const lo = (_b = (_a = ci === null || ci === void 0 ? void 0 : ci.low) !== null && _a !== void 0 ? _a : template === null || template === void 0 ? void 0 : template.lo) !== null && _b !== void 0 ? _b : 0;
|
|
110
|
-
const hi = (_d = (_c = ci === null || ci === void 0 ? void 0 : ci.high) !== null && _c !== void 0 ? _c : template === null || template === void 0 ? void 0 : template.hi) !== null && _d !== void 0 ? _d : 0;
|
|
111
|
-
const timelineBucket = resolveTimelineBucket(analysis.strategy_id, engineOutput.implementation_roadmap);
|
|
112
|
-
const clientSummaryEntry = engineOutput.client_summary.strategies.find((cs) => cs.strategy_name === analysis.strategy_name);
|
|
113
|
-
const strategy = {
|
|
114
|
-
rank: rank !== null && rank !== void 0 ? rank : 99,
|
|
115
|
-
code: (_e = template === null || template === void 0 ? void 0 : template.code) !== null && _e !== void 0 ? _e : analysis.strategy_id,
|
|
116
|
-
name: analysis.strategy_name,
|
|
117
|
-
cat: (_f = template === null || template === void 0 ? void 0 : template.cat) !== null && _f !== void 0 ? _f : "deductions",
|
|
118
|
-
priority: mapPriority(analysis.priority_tier, analysis.quick_win),
|
|
119
|
-
score: Math.round(analysis.weighted_score),
|
|
120
|
-
entities: (_g = template === null || template === void 0 ? void 0 : template.entities) !== null && _g !== void 0 ? _g : ["S-Corporation", "C-Corporation", "Partnership/LLC", "Sole Proprietorship"],
|
|
121
|
-
lo,
|
|
122
|
-
hi,
|
|
123
|
-
timeline: (_h = template === null || template === void 0 ? void 0 : template.timeline) !== null && _h !== void 0 ? _h : timelineBucket,
|
|
124
|
-
timelineBucket,
|
|
125
|
-
authority: (_j = trace === null || trace === void 0 ? void 0 : trace.irs_cite) !== null && _j !== void 0 ? _j : template === null || template === void 0 ? void 0 : template.authority,
|
|
126
|
-
forms: (_l = (_k = trace === null || trace === void 0 ? void 0 : trace.forms_required) === null || _k === void 0 ? void 0 : _k.join(", ")) !== null && _l !== void 0 ? _l : template === null || template === void 0 ? void 0 : template.forms,
|
|
127
|
-
warning: (_o = (_m = analysis.risk_disclosure) !== null && _m !== void 0 ? _m : template === null || template === void 0 ? void 0 : template.warning) !== null && _o !== void 0 ? _o : null,
|
|
128
|
-
abstract: analysis.engagement_recommendation,
|
|
129
|
-
trace: traceFromEngine(trace),
|
|
130
|
-
needsPTE: template === null || template === void 0 ? void 0 : template.needsPTE,
|
|
131
|
-
onlyIndustry: template === null || template === void 0 ? void 0 : template.onlyIndustry,
|
|
132
|
-
excludeIndustry: template === null || template === void 0 ? void 0 : template.excludeIndustry,
|
|
133
|
-
preferIndustry: template === null || template === void 0 ? void 0 : template.preferIndustry,
|
|
134
|
-
minEmployees: template === null || template === void 0 ? void 0 : template.minEmployees,
|
|
135
|
-
needsOwnerComp: template === null || template === void 0 ? void 0 : template.needsOwnerComp,
|
|
136
|
-
clientBrief: (_p = clientSummaryEntry === null || clientSummaryEntry === void 0 ? void 0 : clientSummaryEntry.why_it_applies) !== null && _p !== void 0 ? _p : template === null || template === void 0 ? void 0 : template.clientBrief,
|
|
137
|
-
action: (_q = clientSummaryEntry === null || clientSummaryEntry === void 0 ? void 0 : clientSummaryEntry.next_step) !== null && _q !== void 0 ? _q : template === null || template === void 0 ? void 0 : template.action,
|
|
138
|
-
sourceDocuments: (_r = trace === null || trace === void 0 ? void 0 : trace.source_documents) !== null && _r !== void 0 ? _r : [],
|
|
139
|
-
quickWin: analysis.quick_win,
|
|
140
|
-
positionStrength: (_s = trace === null || trace === void 0 ? void 0 : trace.position_strength) !== null && _s !== void 0 ? _s : undefined,
|
|
141
|
-
specialistNote: (_t = trace === null || trace === void 0 ? void 0 : trace.specialist_note) !== null && _t !== void 0 ? _t : undefined,
|
|
142
|
-
};
|
|
143
|
-
strategies.push(strategy);
|
|
144
|
-
computedMap.set(strategy.rank, {
|
|
145
|
-
lo,
|
|
146
|
-
hi,
|
|
147
|
-
trace: strategy.trace,
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
// Sort by weighted_score descending (same ordering the FE uses)
|
|
151
|
-
strategies.sort((a, b) => b.score - a.score);
|
|
152
|
-
return { strategies, computedMap, engineOutput };
|
|
153
|
-
}
|
|
154
|
-
// ── React hook ────────────────────────────────────────────────────────
|
|
155
|
-
function useEngineOutput(engineOutput) {
|
|
156
|
-
return (0, react_1.useMemo)(() => {
|
|
157
|
-
if (!engineOutput)
|
|
158
|
-
return null;
|
|
159
|
-
return adaptEngineOutput(engineOutput);
|
|
160
|
-
}, [engineOutput]);
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Hook — pass-through stub (returns null, no mapping yet)
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
function useEngineOutput(_engineOutput) {
|
|
11
|
+
return (0, react_1.useMemo)(() => null, [_engineOutput]);
|
|
161
12
|
}
|
|
@@ -159,5 +159,11 @@ function computeAllStrategies(profile) {
|
|
|
159
159
|
results.set(s.rank, { lo: Math.round(s.lo * scale), hi: Math.round(s.hi * scale), sources: s.sources, trace: s.trace });
|
|
160
160
|
}
|
|
161
161
|
});
|
|
162
|
+
// Enforce max 3× spread per strategy — tighten lo toward hi if ratio is too wide
|
|
163
|
+
for (const [rank, v] of results) {
|
|
164
|
+
if (v.hi > 0 && v.lo > 0 && v.hi / v.lo > 3.0) {
|
|
165
|
+
results.set(rank, Object.assign(Object.assign({}, v), { lo: Math.round(v.hi / 3.0) }));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
162
168
|
return results;
|
|
163
169
|
}
|
|
@@ -67,66 +67,66 @@ exports.STRATEGIES = [
|
|
|
67
67
|
sources: [{ doc: "QBO", line: "Meals", value: "$8,400", field: "Annual Meals" }],
|
|
68
68
|
trace: [{ n: 1, step: "Total meals", formula: "QBO", result: "$8,400", src: "QBO" }, { n: 2, step: "Business meals", formula: "Estimated", result: "$6,200", src: "Review" }, { n: 3, step: "Deduction", formula: "$6,200 × 50%", result: "$3,100", src: "§274" }],
|
|
69
69
|
clientBrief: "Properly documenting business meals recovers $800–$2,200 in tax savings.", action: "Implement meal documentation protocol", cost: "$0" },
|
|
70
|
-
{ rank: 11, name: "
|
|
71
|
-
authority: "IRC §162", forms: "Schedule C / 1120S", warning: null, entities: ["S-Corporation", "C-Corporation", "Partnership/LLC", "Sole Proprietorship"],
|
|
72
|
-
abstract: "Legal, accounting, consulting fees are fully deductible as ordinary and necessary business expenses.",
|
|
73
|
-
sources: [{ doc: "QBO", line: "Professional fees", value: "$24,000", field: "Annual Fees" }],
|
|
74
|
-
trace: [{ n: 1, step: "Total fees", formula: "QBO + invoices", result: "$24,000", src: "QBO" }, { n: 2, step: "Business allocation", formula: "Categorization review", result: "$22,500", src: "Review" }],
|
|
75
|
-
clientBrief: "Ensure all professional service fees are properly categorized and deducted.", action: "Review and categorize all professional service invoices", cost: "$0" },
|
|
76
|
-
{ rank: 12, name: "Home Office Deduction", code: "§280A", cat: "deductions", excludeIndustry: ["Construction", "Manufacturing", "Restaurant / Hospitality"], lo: 2100, hi: 3200, score: 80, priority: "QUICK WIN", timeline: "This week", timelineBucket: "now",
|
|
70
|
+
{ rank: 11, name: "Home Office Deduction", code: "§280A", cat: "deductions", excludeIndustry: ["Construction", "Manufacturing", "Restaurant / Hospitality"], lo: 2100, hi: 3200, score: 80, priority: "QUICK WIN", timeline: "This week", timelineBucket: "now",
|
|
77
71
|
authority: "IRC §280A(c)(1) · Rev. Proc. 2013-13", forms: "Form 8829", warning: null, entities: ["S-Corporation", "Partnership/LLC", "Sole Proprietorship"],
|
|
78
72
|
abstract: "Actual expense method produces higher deduction than the $5/sqft simplified method for dedicated workspace.",
|
|
79
73
|
sources: [{ doc: "Intake", line: "Office sqft", value: "280 sqft", field: "Workspace" }, { doc: "Intake", line: "Total", value: "2,100 sqft", field: "Home" }, { doc: "QBO", line: "Home costs", value: "$43,200", field: "Mortgage + Utils" }],
|
|
80
74
|
trace: [{ n: 1, step: "Business use %", formula: "280 ÷ 2,100", result: "13.33%", src: "Intake" }, { n: 2, step: "Simplified", formula: "280 × $5", result: "$1,400", src: "Rev. Proc." }, { n: 3, step: "Actual", formula: "13.33% × $43,200", result: "$5,747", src: "QBO" }],
|
|
81
75
|
clientBrief: "Your home office qualifies for a $5,700 deduction using the actual expense method.", action: "Photograph workspace. Collect mortgage + utility bills.", cost: "$0" },
|
|
82
|
-
{ rank:
|
|
83
|
-
authority: "IRC §
|
|
84
|
-
abstract: "
|
|
85
|
-
sources: [{ doc: "
|
|
86
|
-
trace: [{ n: 1, step: "
|
|
87
|
-
clientBrief: "
|
|
88
|
-
{ rank:
|
|
89
|
-
authority: "IRC §
|
|
90
|
-
abstract: "
|
|
91
|
-
sources: [{ doc: "
|
|
92
|
-
trace: [{ n: 1, step: "
|
|
93
|
-
clientBrief: "
|
|
76
|
+
{ rank: 12, name: "Accountable Plan", code: "§62", cat: "entity", lo: 1200, hi: 3500, score: 75, priority: "MEDIUM", timeline: "30 days", timelineBucket: "30d",
|
|
77
|
+
authority: "IRC §62 · Treas. Reg. §1.62-2", forms: "Board resolution + plan document", warning: null, entities: ["S-Corporation", "C-Corporation", "Partnership/LLC"],
|
|
78
|
+
abstract: "Reimburse business expenses tax-free through an accountable plan. Expenses must be substantiated and business-connected.",
|
|
79
|
+
sources: [{ doc: "QBO", line: "Unreimbursed expenses", value: "$8,500", field: "Employee Expenses" }],
|
|
80
|
+
trace: [{ n: 1, step: "Eligible expenses", formula: "Unreimbursed biz expenses", result: "$8,500", src: "QBO" }, { n: 2, step: "Tax savings", formula: "$8,500 × marginal rate", result: "$2,350", src: "Calc." }],
|
|
81
|
+
clientBrief: "An accountable plan lets you reimburse business expenses tax-free instead of taking them as taxable compensation.", action: "Adopt accountable plan via board resolution", cost: "$200–$500" },
|
|
82
|
+
{ rank: 13, name: "Augusta Rule", code: "§280A(g)", cat: "deductions", lo: 1500, hi: 6000, score: 70, priority: "MEDIUM", timeline: "30 days", timelineBucket: "30d",
|
|
83
|
+
authority: "IRC §280A(g) · Rev. Rul. 2002-25", forms: "Rental agreement + FMV documentation", warning: null, entities: ["S-Corporation", "C-Corporation", "Partnership/LLC", "Sole Proprietorship"],
|
|
84
|
+
abstract: "Rent your personal residence to your business for up to 14 days per year tax-free. Rental income excluded from owner's return; business deducts rent.",
|
|
85
|
+
sources: [{ doc: "Intake", line: "Home FMV rental", value: "$500/day", field: "FMV Rate" }, { doc: "Intake", line: "Business use days", value: "12 days", field: "Meeting Days" }],
|
|
86
|
+
trace: [{ n: 1, step: "FMV rental rate", formula: "Comparable rental survey", result: "$500/day", src: "Market data" }, { n: 2, step: "Annual rental", formula: "12 × $500", result: "$6,000", src: "Calc." }],
|
|
87
|
+
clientBrief: "Renting your home to your business for board meetings creates a tax-free deduction for the company.", action: "Document FMV rental rate and schedule business use days", cost: "$0" },
|
|
88
|
+
{ rank: 14, name: "Family Employment", code: "§73", cat: "entity", lo: 500, hi: 4000, score: 60, priority: "LOW", timeline: "Year-end", timelineBucket: "90d",
|
|
89
|
+
authority: "IRC §73 · IRC §3121(b)(3) · Rev. Rul. 73-348", forms: "W-4 + payroll documentation", warning: null, entities: ["S-Corporation", "Partnership/LLC", "Sole Proprietorship"],
|
|
90
|
+
abstract: "Hiring family members shifts income to lower brackets. Children under 18 employed by sole proprietor are exempt from FICA.",
|
|
91
|
+
sources: [{ doc: "Intake", line: "Family members", value: "2", field: "Eligible Family" }, { doc: "Intake", line: "Ages", value: "16, 19", field: "Children" }],
|
|
92
|
+
trace: [{ n: 1, step: "Eligible family", formula: "Children working in business", result: "2 family members", src: "Intake" }, { n: 2, step: "FICA savings", formula: "Under-18 exemption", result: "Up to $2,400", src: "§3121(b)(3)" }],
|
|
93
|
+
clientBrief: "Employing family members in your business can shift income to lower brackets and reduce employment taxes.", action: "Document bona fide job duties and arm's-length wages", cost: "$0" },
|
|
94
94
|
{ rank: 15, name: "SALT / PTE Optimization", code: "OBBBA §70109", cat: "state", lo: 3200, hi: 5800, score: 92, priority: "HIGH", timeline: "File now", timelineBucket: "now", needsPTE: true,
|
|
95
95
|
authority: "OBBBA §70109 · IRC §164 · IRS Notice 2020-75", forms: "Schedule A · State PTE Election", warning: null, entities: ["S-Corporation", "Partnership/LLC"],
|
|
96
96
|
abstract: "OBBBA raised SALT cap to $40,400 for 2026. PTE elections convert entity-level state tax into an unlimited federal business deduction. 30% phase-out above $500K MAGI (MFJ).",
|
|
97
97
|
sources: [{ doc: "State Return", line: "Tax paid", value: "$9,108", field: "State Tax" }, { doc: "OBBBA §70109", line: "Table 1", value: "$40,400", field: "SALT Cap" }, { doc: "Intake", line: "Property tax", value: "$9,200", field: "Property Tax" }],
|
|
98
98
|
trace: [{ n: 1, step: "PTE election", formula: "Entity-level state tax", result: "$7,029", src: "Notice 2020-75" }, { n: 2, step: "PTET bypasses cap", formula: "Entity-level deduction", result: "$7,029", src: "Notice" }, { n: 3, step: "Remaining SALT", formula: "$9,200 property tax", result: "$9,200", src: "Intake" }, { n: 4, step: "New regime", formula: "All deducted", result: "$0 lost", src: "OBBBA + PTE" }],
|
|
99
99
|
clientBrief: "New federal law raised your SALT cap, and your state's PTE workaround bypasses it entirely for business income.", action: "Elect PTE for 2026. Claim full SALT cap.", cost: "$0" },
|
|
100
|
-
{ rank: 16, name: "
|
|
101
|
-
authority: "IRC §163(j) · OBBBA §70306", forms: "Form 8990", warning: null, entities: ["S-Corporation", "C-Corporation", "Partnership/LLC"],
|
|
102
|
-
abstract: "OBBBA restored EBITDA computation. Full deduction if gross receipts ≤$27M.",
|
|
103
|
-
sources: [{ doc: "1120S", line: "Interest", value: "$18,000", field: "Business Interest" }, { doc: "1120S", line: "3-yr avg", value: "$480,000", field: "Gross Receipts" }],
|
|
104
|
-
trace: [{ n: 1, step: "Gross receipts test", formula: "$480K ≤ $27M", result: "Exempt", src: "§163(j)(3)" }, { n: 2, step: "Full deduction", formula: "All interest deductible", result: "$18,000", src: "§163(j)" }],
|
|
105
|
-
clientBrief: "Your business qualifies for full interest deduction under the small business exception.", action: "No additional action — claim full deduction", cost: "$0" },
|
|
106
|
-
{ rank: 17, name: "Income Deferral & Timing", code: "§451", cat: "income", lo: 1500, hi: 8000, score: 66, priority: "MEDIUM", timeline: "Year-end", timelineBucket: "90d",
|
|
107
|
-
authority: "IRC §451 · IRC §448", forms: "Form 3115", warning: null, entities: ["S-Corporation", "C-Corporation", "Partnership/LLC", "Sole Proprietorship"],
|
|
108
|
-
abstract: "Cash method taxpayers (≤$27M) defer income through billing timing. §451 advance payment deferral allows one-year deferral on prepaid income.",
|
|
109
|
-
sources: [{ doc: "1120S", line: "Revenue", value: "$500,000", field: "Revenue" }, { doc: "QBO", line: "AR aging", value: "$42,000", field: "Receivables" }],
|
|
110
|
-
trace: [{ n: 1, step: "Cash method", formula: "Revenue ≤ $27M", result: "Eligible", src: "§448" }, { n: 2, step: "Deferral", formula: "Q4 timing", result: "$20K–$40K", src: "QBO" }],
|
|
111
|
-
clientBrief: "Strategic timing of invoicing can defer $20K–$40K of income to next year.", action: "Review Q4 billing schedule", cost: "$0" },
|
|
112
|
-
{ rank: 18, name: "Opportunity Zone §1400Z", code: "§1400Z", cat: "investment", lo: 5000, hi: 25000, score: 55, priority: "LOW", timeline: "Year-end", timelineBucket: "90d",
|
|
113
|
-
authority: "IRC §1400Z · OBBBA transition rules", forms: "Form 8996 · Form 8997", warning: "Confirm deferred gain recognition under OBBBA transition rules.", entities: ["S-Corporation", "C-Corporation", "Partnership/LLC", "Sole Proprietorship"],
|
|
114
|
-
abstract: "Rural QOZ improvement threshold reduced to 50%. QOF investments defer and potentially eliminate capital gains.",
|
|
115
|
-
sources: [{ doc: "Brokerage", line: "Gains", value: "$85,000", field: "Cap Gains" }],
|
|
116
|
-
trace: [{ n: 1, step: "Cap gains", formula: "Brokerage + sales", result: "$85,000", src: "Brokerage" }, { n: 2, step: "QOF window", formula: "180 days", result: "Up to $85K", src: "§1400Z" }],
|
|
117
|
-
clientBrief: "Investing capital gains into an Opportunity Zone fund defers taxes and potentially eliminates gains on the new investment.", action: "Identify QOF within 180 days of gain", cost: "$1,000–$3,000" },
|
|
118
|
-
{ rank: 19, name: "Energy Credits §179D", code: "§179D", cat: "credits", preferIndustry: ["Real Estate", "Construction"], lo: 2500, hi: 25000, score: 58, priority: "MEDIUM", timeline: "90 days", timelineBucket: "90d",
|
|
100
|
+
{ rank: 16, name: "§179D Energy Deduction", code: "§179D", cat: "credits", preferIndustry: ["Real Estate", "Construction"], lo: 2500, hi: 25000, score: 58, priority: "MEDIUM", timeline: "90 days", timelineBucket: "90d",
|
|
119
101
|
authority: "IRC §179D · OBBBA §70507", forms: "Form 7205", warning: "ELIMINATED for construction after June 30, 2026.", entities: ["S-Corporation", "C-Corporation", "Partnership/LLC"],
|
|
120
102
|
abstract: "$0.50–$5.00/sqft for energy-efficient improvements. Eliminated for new construction after June 30, 2026.",
|
|
121
103
|
sources: [{ doc: "Intake", line: "Sqft", value: "8,000", field: "Commercial Sqft" }],
|
|
122
104
|
trace: [{ n: 1, step: "Rate", formula: "$0.50–$5.00/sqft", result: "$2.50 est.", src: "Prevailing wage" }, { n: 2, step: "Credit", formula: "8,000 × $2.50", result: "$20,000", src: "Calc." }],
|
|
123
105
|
clientBrief: "Energy-efficient improvements qualify for up to $5.00/sqft. This credit is being eliminated — act before June 30, 2026.", action: "Commission energy study", cost: "$3,000–$8,000" },
|
|
124
|
-
{ rank:
|
|
125
|
-
authority: "IRC §
|
|
126
|
-
abstract: "
|
|
127
|
-
sources: [{ doc: "
|
|
128
|
-
trace: [{ n: 1, step: "
|
|
129
|
-
clientBrief: "
|
|
106
|
+
{ rank: 17, name: "Vehicle Expense Optimization", code: "§274", cat: "deductions", lo: 800, hi: 3200, score: 66, priority: "MEDIUM", timeline: "30 days", timelineBucket: "30d",
|
|
107
|
+
authority: "IRC §274(d) · Rev. Proc. 2025-32", forms: "Mileage log or actual expense records", warning: null, entities: ["S-Corporation", "C-Corporation", "Partnership/LLC", "Sole Proprietorship"],
|
|
108
|
+
abstract: "Compare standard mileage rate (70¢/mi for 2026) vs. actual expenses. Heavy SUVs (GVWR > 6,000 lbs) eligible for full §179.",
|
|
109
|
+
sources: [{ doc: "Mileage log", line: "Business miles", value: "12,000", field: "Annual Miles" }, { doc: "Rev. Proc.", line: "Rate", value: "$0.70/mi", field: "2026 Rate" }],
|
|
110
|
+
trace: [{ n: 1, step: "Mileage method", formula: "12,000 × $0.70", result: "$8,400", src: "Rev. Proc." }, { n: 2, step: "Actual method", formula: "Fuel + ins + dep", result: "$7,200", src: "QBO" }, { n: 3, step: "Better method", formula: "Higher of two", result: "$8,400 mileage", src: "Calc." }],
|
|
111
|
+
clientBrief: "Choosing the right vehicle expense method maximizes your deduction — mileage rate wins for your usage.", action: "Maintain contemporaneous mileage log", cost: "$0" },
|
|
112
|
+
{ rank: 18, name: "Insurance Optimization", code: "§79, §264", cat: "deductions", lo: 1500, hi: 6000, score: 55, priority: "MEDIUM", timeline: "90 days", timelineBucket: "90d",
|
|
113
|
+
authority: "IRC §79 · IRC §264 · IRC §162", forms: "Plan documents · Premium records", warning: null, entities: ["S-Corporation", "C-Corporation", "Partnership/LLC"],
|
|
114
|
+
abstract: "Group term life up to $50K is tax-free (§79). Key-person and buy-sell insurance premiums may be deductible. Proper structuring avoids AMT traps.",
|
|
115
|
+
sources: [{ doc: "Benefits", line: "Group term", value: "$50,000", field: "Coverage" }, { doc: "Insurance", line: "Premium", value: "$3,600", field: "Annual Premium" }],
|
|
116
|
+
trace: [{ n: 1, step: "Group term exclusion", formula: "≤ $50K coverage", result: "Tax-free", src: "§79" }, { n: 2, step: "Key-person premium", formula: "Deductible if structured", result: "$3,600", src: "§162" }, { n: 3, step: "Total benefit", formula: "Premium + exclusion", result: "$3,600–$6,000", src: "Calc." }],
|
|
117
|
+
clientBrief: "Restructuring your business insurance produces tax-free benefits and deductible premiums.", action: "Review group term life and key-person policies with advisor", cost: "$300–$800" },
|
|
118
|
+
{ rank: 19, name: "§1031 Like-Kind Exchange", code: "§1031", cat: "deferral", preferIndustry: ["Real Estate"], lo: 5000, hi: 50000, score: 58, priority: "MEDIUM", timeline: "Year-end", timelineBucket: "90d",
|
|
119
|
+
authority: "IRC §1031 · Treas. Reg. §1.1031", forms: "Form 8824", warning: "Only real property qualifies post-TCJA. 45-day ID / 180-day close.", entities: ["S-Corporation", "C-Corporation", "Partnership/LLC", "Sole Proprietorship"],
|
|
120
|
+
abstract: "Defer capital gains on real property by exchanging into like-kind replacement property. Strict identification and closing deadlines apply.",
|
|
121
|
+
sources: [{ doc: "Intake", line: "Property", value: "$400,000", field: "Relinquished FMV" }, { doc: "Intake", line: "Basis", value: "$180,000", field: "Adjusted Basis" }],
|
|
122
|
+
trace: [{ n: 1, step: "Realized gain", formula: "$400K − $180K", result: "$220,000", src: "Intake" }, { n: 2, step: "Deferred", formula: "Full deferral if boot = 0", result: "$220,000", src: "§1031" }, { n: 3, step: "Tax avoided", formula: "$220K × 23.8%", result: "$52,360", src: "Calc." }],
|
|
123
|
+
clientBrief: "Exchanging your investment property into a like-kind replacement defers $52K+ in capital gains taxes.", action: "Engage qualified intermediary before closing", cost: "$1,500–$3,000" },
|
|
124
|
+
{ rank: 20, name: "QSBS §1202 Exclusion", code: "§1202", cat: "exclusions", lo: 0, hi: 250000, score: 62, priority: "MEDIUM", timeline: "Year-end", timelineBucket: "90d",
|
|
125
|
+
authority: "IRC §1202 · Rev. Proc. 2025-32", forms: "Stock documentation · Form 1040 Sch D", warning: "Must hold stock ≥ 5 years. C-Corp only. $50M gross assets cap.", entities: ["C-Corporation"],
|
|
126
|
+
abstract: "Exclude up to 100% of gain (max $10M or 10× basis) on sale of qualified small business stock held 5+ years.",
|
|
127
|
+
sources: [{ doc: "Intake", line: "Entity", value: "C-Corp", field: "Entity Type" }, { doc: "Intake", line: "Assets", value: "$8M", field: "Gross Assets" }, { doc: "Intake", line: "Held since", value: "2020", field: "Acquisition Year" }],
|
|
128
|
+
trace: [{ n: 1, step: "QSBS eligibility", formula: "C-Corp, < $50M assets", result: "Eligible", src: "§1202(d)" }, { n: 2, step: "Holding period", formula: "2020 → 2026 = 6 yrs", result: "≥ 5 yrs ✓", src: "§1202(a)" }, { n: 3, step: "Exclusion", formula: "100% of gain", result: "Up to $10M", src: "§1202(a)(1)" }],
|
|
129
|
+
clientBrief: "Your C-Corp stock may qualify for 100% gain exclusion on sale — up to $10M tax-free.", action: "Document original issuance, gross asset test, and holding period", cost: "$500–$2,000" },
|
|
130
130
|
{ rank: 21, name: "Qualified Tips Deduction", code: "OBBBA", cat: "obbba_new", onlyIndustry: ["Restaurant / Hospitality"], lo: 3000, hi: 25000, score: 78, priority: "HIGH", timeline: "File now", timelineBucket: "now",
|
|
131
131
|
authority: "OBBBA Qualified Tips Provision", forms: "Form 1040 / Schedule C", warning: "Tipping occupations only. Max $25K. Effective 2025–2028.", entities: ["Sole Proprietorship", "Partnership/LLC"],
|
|
132
132
|
abstract: "New OBBBA deduction up to $25,000 for qualifying tip income. Tipping occupations only. Effective 2025–2028.",
|
|
@@ -134,7 +134,7 @@ exports.STRATEGIES = [
|
|
|
134
134
|
trace: [{ n: 1, step: "Tip income", formula: "Payroll", result: "$32,000", src: "Payroll" }, { n: 2, step: "Cap", formula: "Lesser of tips or $25K", result: "$25,000", src: "OBBBA" }],
|
|
135
135
|
clientBrief: "New OBBBA provision lets you deduct up to $25,000 of tip income through 2028.", action: "Document and categorize all tip income", cost: "$0" },
|
|
136
136
|
{ rank: 22, name: "Overtime Pay Deduction", code: "OBBBA", cat: "obbba_new", minEmployees: 1, lo: 2000, hi: 12500, score: 74, priority: "HIGH", timeline: "File now", timelineBucket: "now",
|
|
137
|
-
authority: "OBBBA Overtime Provision", forms: "Form 1040", warning: "MAGI phase-out: $150K/$300K. Effective 2025–2028.", entities: ["S-Corporation", "
|
|
137
|
+
authority: "OBBBA Overtime Provision", forms: "Form 1040", warning: "MAGI phase-out: $150K/$300K. Effective 2025–2028.", entities: ["S-Corporation", "Partnership/LLC", "Sole Proprietorship"],
|
|
138
138
|
abstract: "New OBBBA deduction for overtime: $12,500 single / $25,000 MFJ. Phase-out at $150K/$300K MAGI.",
|
|
139
139
|
sources: [{ doc: "Payroll", line: "OT hours", value: "320 hrs", field: "Overtime" }, { doc: "W-2", line: "OT comp", value: "$18,000", field: "OT Pay" }],
|
|
140
140
|
trace: [{ n: 1, step: "OT compensation", formula: "W-2 overtime", result: "$18,000", src: "W-2" }, { n: 2, step: "Cap", formula: "$12,500 / $25K MFJ", result: "$12,500", src: "OBBBA" }],
|
|
@@ -159,8 +159,6 @@ exports.STRATEGIES = [
|
|
|
159
159
|
clientBrief: "New provision allows tax-deductible contributions to employee child savings accounts.", action: "Monitor IRS guidance. Plan contributions.", cost: "$200–$500" },
|
|
160
160
|
];
|
|
161
161
|
exports.ADDITIONAL = [
|
|
162
|
-
{ name: "Accountable Plan", savings: "$1,200–$3,500", priority: "MEDIUM" },
|
|
163
162
|
{ name: "Estimated Tax Timing", savings: "$200–$800", priority: "LOW" },
|
|
164
163
|
{ name: "Business Insurance Review", savings: "$400–$2,000", priority: "LOW" },
|
|
165
|
-
{ name: "Vehicle Expense Optimization", savings: "$800–$3,200", priority: "MEDIUM" },
|
|
166
164
|
];
|