Context
PolicyEngine apps are starting to duplicate household setup flows. Cliff Watch now has a local guided wizard; Coverage Compass has a household/coverage wizard; California Wealth Tax has reusable wizard patterns; app-v2 has the strongest household model and metadata-driven variable inputs, but its /households/create flow is a dense editor rather than a lightweight standalone-app wizard.
We should create shared infrastructure so PE apps collect households consistently without copying app-specific UI.
Problem
Household setup differs across apps in ways that affect results and UX:
- Some apps set default state or ages.
- County can be free text instead of a state-filtered dropdown.
- Some UIs ask tax filing status when users should be asked marital status.
- Disability, blindness, student, pregnancy, and care-needs fields are inconsistent.
- App-v2 has reusable household semantics, but standalone apps need a lighter guided flow.
Scope
V1 should be US-first. The generic wizard primitives can be country-neutral, but the first household module should explicitly target US household setup and PolicyEngine-US semantics.
Goals
- Add shared wizard primitives: step state, progress, Back/Continue, validation gating, review navigation.
- Add a shared US household draft contract with blank initial state: no default state, no default age, no default marital status.
- Ask marital status in UI; derive filing status only in app/model adapters.
- Support state-filtered county dropdowns with a decided metadata source before implementation.
- Support app-controlled person fields such as pregnancy, disabled, blind, student, and care-needs.
- Provide adapters rather than forcing one UI shell across apps.
- Validate app-v2 compatibility early with round-trip fixtures.
Non-goals
- Do not replace app-v2's full household editor in the first pass.
- Do not move Cliff Watch, Coverage Compass, or wealth-tax-specific fields into shared core.
- Do not migrate every PE app at once.
- Do not design a fake all-country abstraction while only implementing US behavior.
Phase 0: Decisions
- Choose package home and ownership: likely a new shared package, not model logic inside UI kit.
- Decide county metadata source, representation, update cadence, and fallback behavior.
- Define dependency direction so app-v2 and standalone apps can consume the package without circular coupling.
- Decide URL-state ownership: shared draft serialization or app-local serialization.
Phase 1: Audit and contract spike
- Build a field matrix for Cliff Watch, Coverage Compass, California Wealth Tax, app-v2, and other active household apps.
- Create app-v2 round-trip fixtures before locking the draft shape:
- Single adult.
- Married adults.
- Adult plus dependent child.
- Disabled person.
- Student.
- County/state case.
- Verify the draft can map to app-v2
Household groups, members, periods, variables, and entity relationships.
Phase 2: Wizard primitives
- Extract copy-neutral primitives:
useWizardSteps
WizardProgress
WizardNavigation
WizardOptionCard
WizardReviewList
- Test step validation, skipped/conditional steps, editing earlier answers, review navigation, and disabled states.
- Include accessibility criteria: focus movement, error announcement,
aria-current or equivalent step semantics, keyboard option cards, and mobile viewport checks.
Phase 3: US household builder
- Add
createBlankDraft, createDraftFromExisting, and normalizeLegacyDraft.
- Add explicit adapters:
validate
toPayload
fromPayload
renderExtraSteps
renderReviewItems
serialize / deserialize where needed
- Keep common flags metadata-backed where possible rather than hard-coded as universal booleans.
Phase 4: First consumers
- Migrate Cliff Watch first:
- Preserve wage-axis behavior.
- Preserve SSI/SSDI and fixed adult earnings.
- Preserve program take-up, costs, URL params, and payload parity.
- Migrate Coverage Compass second:
- Preserve ESI, coverage fields, pregnancy behavior, URL/share behavior, and calculation payload parity.
Acceptance criteria
- Shared wizard primitives work without household-specific code.
- Shared US household draft starts blank for state, ages, and marital status.
- County dropdown is filtered by selected state and has tested legacy normalization.
- Filing status is not user-facing in shared UI.
- App-v2 conversion tests pass before consumer migration.
- App-specific fields stay in adapters/slots.
- Cliff Watch and Coverage Compass retain calculation payload parity.
- Accessibility and responsive behavior are tested for the shared wizard pieces.
Context
PolicyEngine apps are starting to duplicate household setup flows. Cliff Watch now has a local guided wizard; Coverage Compass has a household/coverage wizard; California Wealth Tax has reusable wizard patterns; app-v2 has the strongest household model and metadata-driven variable inputs, but its
/households/createflow is a dense editor rather than a lightweight standalone-app wizard.We should create shared infrastructure so PE apps collect households consistently without copying app-specific UI.
Problem
Household setup differs across apps in ways that affect results and UX:
Scope
V1 should be US-first. The generic wizard primitives can be country-neutral, but the first household module should explicitly target US household setup and PolicyEngine-US semantics.
Goals
Non-goals
Phase 0: Decisions
Phase 1: Audit and contract spike
Householdgroups, members, periods, variables, and entity relationships.Phase 2: Wizard primitives
useWizardStepsWizardProgressWizardNavigationWizardOptionCardWizardReviewListaria-currentor equivalent step semantics, keyboard option cards, and mobile viewport checks.Phase 3: US household builder
createBlankDraft,createDraftFromExisting, andnormalizeLegacyDraft.validatetoPayloadfromPayloadrenderExtraStepsrenderReviewItemsserialize/deserializewhere neededPhase 4: First consumers
Acceptance criteria