Skip to main content

H-phase — post-G-board enhancements (implementer brief)

Scoped on feat/mvp1-personas-authz @ 8850b13 (= main). Binding spec: docs/decisions/2026-07-02-h-phase-enhancements.md. G-2 account switcher is shipped (docs/decisions/2026-07-03-account-switcher.md); H-5 may consume its substrate. Build loop: TDD vertical slices (one behavior → failing test → minimal impl → green).

Terminology (owner-stated, from spec): “kids” = the member role only. Restrictions are role-based (member vs admin/helper), not member-kind-based.

Working copy: .superpowers/sdd/h-phase-plan.md mirrors this file for the autonomous controller.


OrderItemWhy
1H-1No migration; unblocks step presentation everywhere (Today + editor + later print).
2H-4No migration; fixes broken room print (placeId never written) + adds steps to PDF. Pairs with H-1 icons.
3H-3Reuses H-1 step editor atoms; self-scoped write on existing stepsPerMember column.
4H-5Hard-depends on G-2 (satisfied); folds G-2 keyboard-focus a11y debt. Presentation-heavy.
5H-2New persistence + request→approve lifecycle (largest SDK/schema slice).
6H-6IA restructure — biggest UX shift; consumes shipped E-6 earn + G-8 spend surfaces. Do last.

Cross-cutting invariants (from controller prompt)

  • One data path: Bloc → Repository → Client → Service → Adapter.
  • Dual gate on privileged mutations (service + RLS).
  • viewingAs is presentation-only — never actingMemberId (app/test/unit/authz_invariant_test.dart).
  • TDD: vertical red→green slices; flow tests mock repositories (app/test/README.md).
  • Suite baselines at last deploy: app 406 pass, SDK 864 pass — counts must not drop.

H-1 — Subtask icons + prominent visibility

Current state (verified)

LayerLocationFinding
Modelpackages/client_sdk/lib/src/models/subtask.dart:14-22icon field exists (String? icon key). Stored in chore subtasks JSONB — no migration.
Schemainfra/supabase/migrations/20260612000002_tier0_domain.sqlsubtasks jsonb not null default '[]'.
Today UIapp/lib/inside/routes/authenticated/home/widgets/today_chore_row.dart:219-229Steps render as • ${step.name} bullets — never reads step.icon.
Chore editorapp/lib/inside/routes/authenticated/chore_editor/widgets/chore_editor_body.dart:576-580New steps created with id + name + sortOrder onlyno icon. No icon picker UI.
DS pickerpackages/design_system/lib/src/molecules/ds_emoji_picker.dartShipped (Twemoji font + curated grid). Generic household emoji — not the POC subtask catalog.
POC parityChore_app/packages/client_sdk/lib/src/models/sdk/subtask_icons.dartCurated SubtaskIconCategory list (~hundreds of emoji + labels + search tags). Port this catalog.

Verdict

SDKMigrationAuthorizerSize
Optional (port catalog as pure-Dart data in client_sdk or design_system)NoNo new capabilityM

Slices (TDD)

SliceSizeContentGate
H1-S1: catalog + renderSPort POC subtaskIconCategories (+ searchSubtaskIcons) into rewhaven (prefer design_system data-only module — model-agnostic). Unit test: search returns expected emoji for a tag.DS tests green
H1-S2: Today shows iconsStoday_chore_row.dart + timer row: when step.icon set, render emoji via Twemoji/DS typography (same path as chore emoji). TDD: widget/golden test with one subtask carrying icon key.app green
H1-S3: editor pickerMExtend _MemberStepsEditor: icon chip per step → opens curated subtask icon sheet (keyword search like POC; can reuse DsEmojiPicker shell with subtask dataset OR dedicated DsSubtaskIconPicker). Persist Subtask.icon on save (already serializes). Flow test: admin adds step with icon → Today shows it.app green + deploy
H1-S4: default/shared subtasksSWire icon picker for shared subtasks list (not only stepsPerMember overrides) if editor supports shared steps today — verify and close gap.app green

Test sketch

  • DS: catalog search, emoji renders in golden.
  • App unit: step list widget shows emoji when icon non-null.
  • Flow: chore editor save → Today row shows icon (headless screenshot optional).

POC adopt/adapt

Adopt curated catalog + search UX from POC subtask_icons.dart. Adapt to DsSheet/DsEmojiPicker patterns already in rewhaven DS.


H-4 — Print review (rooms + steps)

Current state (verified)

LayerLocationFinding
Print engineapp/lib/inside/print/printable_chore_list.dartMember + place list selection works. PDF _choreRow prints chore name onlyno subtasks, explicit comment that emoji omitted (:136-138).
Place filterapp/lib/inside/print/printable_chore_list.dart:38-39choresForPlace filters on Chore.placeIdcorrect IF placeId populated.
placeId write pathapp/lib/inside/blocs/chore_editor/bloc.dart:319-365createChore / updateChore never pass placeId. Editor has per-room member overrides (roomAssignees) but no primary room tag.
Schemainfra/supabase/migrations/20260612000011_chore_place.sqlplace_id uuid column exists on chores. Drift mirrors it.
Print UIapp/lib/inside/routes/authenticated/home/widgets/print_menu.dartRoom picker + buildPlaceList wired — room lists empty in practice because placeId always null.
POC parityChore_app/app/lib/inside/routes/authenticated/chores/widgets/chore_print_sheet.dartScope (kid/room/all), _includeSubtasks toggle, today/week range, subtasks under chore rows in PDF.

Verdict

SDKMigrationAuthorizerSize
No (optional: expose placeId on create/update if not already on repository signature)NoNoM

Slices (TDD)

SliceSizeContentGate
H4-S1: placeId on choresMAdd room/place picker to chore editor (reuse app/lib/inside/routes/authenticated/shared/room_picker.dart); thread placeId through bloc → repository → SDK. TDD: save chore with place → getChores() returns matching placeId; place print list non-empty.app + SDK green
H4-S2: steps in PDFMExtend _buildPdf / _choreRow to indent subtasks under each chore (text labels; optional icon as Unicode if font supports, else name-only per current B&W policy). Resolve steps via same stepsForMember logic as Today. Unit test in printable_chore_list_test.dart.app green
H4-S3: room grouping in member printSOptional POC parity: group member list by room when placeId set (or separate section headers).app green + deploy

Test sketch

  • Unit: choresForPlace returns chores after H4-S1 seed.
  • Unit: PDF bytes contain subtask names when chore has steps.
  • Flow: print menu → room list → triggers print with count > 0.

H-3 — Self-scoped step customization

Current state (verified)

LayerLocationFinding
ModelChore.stepsPerMember + editorMap memberId → List<Subtask>already persisted (infra/supabase/migrations/20260612000014_chore_steps_per_member.sql).
Admin editorapp/lib/inside/routes/authenticated/chore_editor/widgets/chore_editor_body.dart:259-278Parents edit any member's steps.
Member pathNo member-facing step editor today.
Precedentapp/lib/inside/blocs/self_profile/bloc.dartSelf-pin at save — edits authenticated member only (G-4 pattern).

Verdict

SDKMigrationAuthorizerSize
Yes — guarded updateStepsForMember(choreId, memberId, steps) or narrow updateChore patchNoSelf-scoped: member may write only stepsPerMember[actingMemberId]; admin override unchangedM

Slices (TDD)

SliceSizeContentGate
H3-S1: SDK guardMService method: reject if memberId != actingMemberId unless actor holds admin chore-edit capability. RLS: chore row update policy must allow member to patch own steps JSON only (may need migration if RLS blocks member writes today — verify live policy before assuming no migration).SDK green
H3-S2: member UIMToday chore drill-down or profile path: member edits own steps only (reuse H-1 step row + picker). Cannot touch default subtasks or sibling keys.app green + deploy

Stop-and-ask

If Postgres RLS currently denies member UPDATE on chores, H3-S1 needs a narrow RLS policy (additive migration) — scoper could not confirm without live policy read; implementer must check infra/supabase/migrations/*chores* policies before slice commit.


H-5 — Today page rework (viewing-as)

Current state (verified)

LayerLocationFinding
G-2 substrateapp/lib/outside/repositories/selected_member/selected_member_repository.dartShipped. Catalog already consumes it.
Todayapp/lib/inside/routes/authenticated/home/page.dartMaster view — all members' chores; approvals block always rendered for parental viewer (:463+). Does not read SelectedMemberRepository.
Deferred question.superpowers/sdd/g2-plan.md §7Lens-vs-subject: parent viewing-as-child — master-with-preview vs child-limited surface. Must decide in H5-S1.
Carried debtaccount-switcher.mdSwitcher keyboard-focus a11y (focus ring, trapped menu, announce) — not built. Fold into H5 or touch switcher in same deploy.

Verdict

SDKMigrationAuthorizerSize
Unlikely (presentation filter)NoApprovals visibility = display predicate on Authorizer.can(selectedMember, helper) — hide only, never grantL

Slices (TDD)

SliceSizeContentGate
H5-S0: product decisionOwner picks lens semantics (recommend: tailored view — selected member sees only their items; parent-as-self keeps master view). Record in ADR appendix.decision logged
H5-S1: Today filters by viewingAsMTodayChoresBloc / page consumes SelectedMemberRepository; when viewingAs ≠ self and viewer has viewHouseholdAll, filter groups to selected member. Flow test: switcher → Today shows one kid.app green
H5-S2: approvals gateSHide approvals section unless selected identity has helper (or authenticated viewer is parental and viewing self — preserve master oversight).app green
H5-S3: switcher a11y debtMFocus ring + keyboard nav on AccountSwitcherChip sheet per g2-plan §3.4.app green + deploy

Test sketch

  • Flow: account switcher select child → Today lists only that child's chores.
  • Unit: approvals widget absent when viewingAs = member without helper.

H-2 — Members recommend/request chores

Current state (verified)

LayerLocationFinding
SpecH-2Member cannot create chores; can request → admin approves → real chore. Mirror goal-request lifecycle.
Goal precedentpackages/client_sdk/lib/src/services/economy_service.dart requestGoalStatus transition + Capability.requestGoal / approveGoalRequest.
Stub modelspackages/client_sdk/lib/src/models/chore_suggestion.dartEphemeral AI suggest shape — not a persisted member request.
UI stubapp/lib/inside/routes/authenticated/catalog/widgets/recommend_sheet.dartCatalog “recommend” UX — not the H-2 approval queue.
POCGrep Chore_appNo chore-request table precedent found — greenfield lifecycle (like goal requests in rewhaven).

Verdict

SDKMigrationAuthorizerSize
YesChoreRequest aggregate + requestChore / approveChoreRequest / rejectChoreRequestYes — new table + RLS + status enumNew capabilities: requestChore, approveChoreRequest (mirror goals)L

Slices (TDD) — high level

SliceSizeContent
H2-S1: schema + modelMMigration chore_requests (household-scoped, status, payload fields, append-only audit). Drift + cloud adapter.
H2-S2: service + authzMService guards + RLS dual gate; Authorizer capabilities. SDK tests with MockClient.
H2-S3: member request UIMRequest form (member role); no create chore button.
H2-S4: admin approve UIMApprovals or Admin queue → promotes to createChore. Flow test end-to-end. Deploy.

Detailed slice breakdown deferred to H-2 implementer dispatch (after H-1/H-4/H-3/H-5 land).


H-6 — IA restructure (Earn + Rewards tabs; Catalog removed)

Current state (verified)

LayerLocationFinding
Shellapp/lib/inside/routes/router.dart:111-123Tabs: Home / Catalog / Household / More.
E-6 earnapp/lib/inside/routes/authenticated/catalog/page.dartUnified earn list (chores + bounties) with filters — in Catalog today.
G-8 spendapp/lib/inside/routes/authenticated/catalog/page.dart + rewards/activities routesActivities + rewards with spend gates (app/lib/inside/routes/authenticated/spend_gates/spend_gates_sheet.dart) — partially split (admin editors separate).
SpecH-6New Earn tab (chores+bounties), Rewards tab (activities+rewards), remove Catalog; admin-only editing with deep links; extract SpendGatesRepository.

Verdict

SDKMigrationAuthorizerSize
Minimal (mostly routing/repos)NoAdmin-only edit affordances — existing manageCatalog / admin guardsXL

Slices (TDD) — phased

SliceSizeContent
H6-S1: SpendGatesRepository extractionMMove spend-gate reads behind repository (per spec); no UX change.
H6-S2: Earn tab routeLNew shell tab; migrate catalog earn half; deep links; flow tests.
H6-S3: Rewards tab routeLMigrate spend half; retire catalog spend UI.
H6-S4: Remove Catalog + redirectMDelete CatalogRoute; guards + bookmarks redirect; admin edit deep links. Deploy.

Do not start H-6 until H-1/H-4/H-5 stabilize Today + print + viewing-as — IA shift deletes the catalog surface users know today.


Stop-and-ask (owner)

  1. H5 lens semantics (H5-S0): tailored child-only Today vs master-with-highlight when viewing-as child? Recommendation: tailored (matches spec bullet “only THEIR items”).
  2. H3 RLS: confirm whether members can PATCH chore rows today — may add a migration slice.
  3. H4 print icons: B&W PDF with emoji vs text-only subtasks? Recommendation: text + optional Unicode (match current printable_chore_list.dart comment policy unless owner wants emoji font embedding).

Commits / docs map

DocRole
2026-07-02-h-phase-enhancements.mdProduct spec (committed)
This fileImplementer brief (committed)
.superpowers/sdd/h-phase-plan.mdController working copy (gitignored)
Per-slice ADRsAdd under docs/decisions/ when a slice changes load-bearing behavior

Unverified claims — re-verification summary

Claim (lost scoping session)Verdict
H-1/H-4 need no migrationConfirmed for H-1 and H-4 core work. H-3 may need RLS migration — TBD. H-2 needs migration.
Subtask.icon never writtenConfirmed — field exists, editor omits it.
Today uses plain bulletsConfirmedtoday_chore_row.dart:229.
placeId dead in editorConfirmed — bloc save path omits placeId; schema column exists.
Print omits steps/roomsConfirmed — room path empty; PDF has no subtask rows.