diff --git a/changelog.d/add-model-diff-docs.added.md b/changelog.d/add-model-diff-docs.added.md new file mode 100644 index 0000000..ee5b549 --- /dev/null +++ b/changelog.d/add-model-diff-docs.added.md @@ -0,0 +1 @@ +Add documentation section explaining how PolicyEngine and TAXSIM outputs differ. Renders static output conventions (CTC/ACTC split, state EITC bundling, filing-status auto-detection, spouse income splitting, Additional Medicare Tax, non-refundable credit ordering) plus a live feed of GitHub issues labeled model-difference. diff --git a/dashboard/public/config-data.json b/dashboard/public/config-data.json index d424d0d..42bab55 100644 --- a/dashboard/public/config-data.json +++ b/dashboard/public/config-data.json @@ -280,5 +280,5 @@ } ] }, - "lastUpdated": "2026-03-24T15:14:08.434Z" + "lastUpdated": "2026-04-17T20:07:56.953Z" } \ No newline at end of file diff --git a/dashboard/src/components/DocumentationContent.jsx b/dashboard/src/components/DocumentationContent.jsx index 13261f4..8912ef5 100644 --- a/dashboard/src/components/DocumentationContent.jsx +++ b/dashboard/src/components/DocumentationContent.jsx @@ -16,6 +16,7 @@ import { import { highlightCode } from '../utils/codeHighlight'; import { loadConfigurationData } from '../utils/configLoader'; import LoadingSpinner from './common/LoadingSpinner'; +import ModelDifferences from './ModelDifferences'; import { OUTPUT_VARIABLES, INPUT_VARIABLE_CATEGORIES, @@ -465,6 +466,7 @@ policyengine_versions() { id: 'installation', label: 'Installation & Usage' }, { id: 'options', label: 'All Runners & CLI' }, { id: 'mappings', label: 'Variable Mappings' }, + { id: 'differences', label: 'Modeling Differences' }, { id: 'datasets', label: 'Sample Datasets' }, ].map(({ id, label }) => ( + {isExpanded && conv.detail && ( +
+

{conv.detail}

+
+ )} + + ); + })} + + + + {/* Dynamic issues */} +
+
+
+ +

+ Known differences under investigation +

+ + {loading ? '…' : issues.length} + +
+ + + View on GitHub + +
+

+ Issues tagged{' '} + + {MODEL_DIFFERENCE_LABEL} + {' '} + document current PolicyEngine vs. TAXSIM divergences and link to the + statute or form instructions for each case. They disappear from this + list when closed. +

+ + {loading && ( +
+
+ Loading… +
+ )} + + {error && ( +
+ {error} +
+ )} + + {!loading && !error && issues.length === 0 && ( +
+ No open model-difference issues. +
+ )} + + {!loading && !error && issues.length > 0 && ( +
+ {issues.map((issue) => ( +
+ + #{issue.number} {issue.title} + + +
+ + + {issue.author} + + + + {formatDate(issue.created_at)} + +
+ {issue.labels.length > 0 && ( +
+ + {issue.labels.map((label, index) => ( + + {label} + + ))} +
+ )} + {issue.body && ( +
+ {issue.body.length > 200 + ? `${issue.body.substring(0, 200)}…` + : issue.body} +
+ )} +
+ ))} +
+ )} +
+ + ); +}; + +export default ModelDifferences; diff --git a/dashboard/src/utils/githubApi.js b/dashboard/src/utils/githubApi.js index 99c84f8..650cfad 100644 --- a/dashboard/src/utils/githubApi.js +++ b/dashboard/src/utils/githubApi.js @@ -83,6 +83,15 @@ export const getIssuesForState = (issues, stateCode) => { }); }; +// Get issues with a specific label +export const getIssuesByLabel = (issues, labelName) => { + if (!labelName) return []; + + return issues.filter(issue => + issue.labels.some(label => label.name === labelName) + ); +}; + // Format issue data for display export const formatIssue = (issue) => { return {