Data-Flow Foundation F1+F2 — PR2: PWA repository + composition migration#131
Merged
Conversation
Implements the PwaHubRepository class skeleton that satisfies the full HubRepository interface from @variscout/core/persistence. The write path (dispatch) is fully wired (load → applyAction → save; throws on no-active-hub); applyAction is stubbed in a separate expansion-seam file (P3.2 fills it in). Grouped read APIs serve data from the single hub blob: hubs, outcomes, and canvasState are real; the remaining 7 entity groups return empty stubs with PWA-blob-only comments (F3 normalizes). Module-scoped singleton export matches the existing hubRepository pattern; composition-root decision deferred to P4.6. 33 new smoke tests; 222 passing (up from 189). Build + typecheck clean. Co-Authored-By: ruflo <ruv@ruv.net>
Implements applyAction(hub, action) as an exhaustive Immer switch over all HubAction kinds. Hub-resident actions (HUB_UPDATE_GOAL, HUB_UPDATE_ PRIMARY_SCOPE_DIMENSIONS, OUTCOME_ADD/UPDATE/ARCHIVE) produce real draft mutations; non-hub-resident actions (INVESTIGATION_*, FINDING_*, QUESTION_*, CAUSAL_LINK_*, SUSPECTED_CAUSE_*, EVIDENCE_*, EVIDENCE_SOURCE_*) are documented no-ops per the PWA blob constraint (F3 normalizes). Canvas actions (PLACE_CHIP_ON_STEP etc.) are no-ops because canvasStore is the canonical mutation surface; hub's canonicalProcessMap is overwritten via HUB_PERSIST_SNAPSHOT when the user saves. Exhaustiveness: TypeScript assertNever() default case verified — removing any case from the switch causes a compile error. Adds immer ^11.1.4 as explicit dep. Adds 46 new tests (268 total, 222 baseline); fake timers pin Date.now() for deterministic archive timestamps. Co-Authored-By: ruflo <ruv@ruv.net>
Replace stub helpers with real cascadeArchiveDescendantsInDraft that walks transitiveCascade(parentKind) and soft-marks descendants on the draft hub. On PWA blob, only hub→outcome yields observable mutations; all other parent kinds are structurally correct but no-op until F3 normalizes. Added 19 tests covering the hub→outcome cascade, idempotency, parentId mismatch, and all non-hub parent kinds as regression-proof no-ops. Co-Authored-By: ruflo <ruv@ruv.net>
Add 8 integration tests in a new `describe('dispatch end-to-end')` block that
prove the loadHub → applyAction → saveHub wiring is intact for each action
category: HUB_PERSIST_SNAPSHOT, HUB_UPDATE_GOAL, OUTCOME_ADD, OUTCOME_UPDATE,
OUTCOME_ARCHIVE (happy + idempotency with fake-timer advancement),
INVESTIGATION_ARCHIVE (documented no-op for PWA blob), and PLACE_CHIP_ON_STEP
(documented no-op per R15 canvas strategy).
Co-Authored-By: ruflo <ruv@ruv.net>
Replace direct hubRepository.saveHub calls in SaveToBrowserButton with
pwaHubRepository.dispatch({ kind: 'HUB_PERSIST_SNAPSHOT', hub }), so all
hub writes go through the single dispatch path.
Also fixes PwaHubRepository.dispatch to short-circuit on HUB_PERSIST_SNAPSHOT
— the bootstrap case where no hub exists yet (first "Save to this browser"
click) no longer throws. applyAction remains complete over HubAction for purity.
Co-Authored-By: ruflo <ruv@ruv.net>
Replace hubRepository.loadHub() with pwaHubRepository.hubs.list() in the Mode A.1 bootstrap effect. hubRepository.getOptInFlag() is kept as a direct call — no HubAction equivalent exists until F3 adds HubMetaAction. Co-Authored-By: ruflo <ruv@ruv.net>
Add dispatch(action: CanvasAction) entry point to canvasStore that switches on action.kind and delegates to the existing per-action methods. assertNever default enforces exhaustiveness at compile time. Per-action methods kept as transitional wrappers (PR3 removes them). Covers all 10 CanvasAction kinds; createStepFromChip and hydrateCanvasDocument remain method-only (not in CanvasAction union). Adds 11 tests (272 total). Co-Authored-By: ruflo <ruv@ruv.net>
Per F1+F2 plan §P4.6: - packages/stores/CLAUDE.md: dispatch boundary lives at app/UI composition root via pwaHubRepository (PWA) / azureHubRepository (Azure, PR3 pending); audit R14 (addHubComment network IO) + R15 (canvasStore.dispatch) exceptions documented; wallLayoutStore whitelist note (R12). - apps/pwa/CLAUDE.md: pwaHubRepository module-scoped singleton at apps/pwa/src/persistence/; HUB_PERSIST_SNAPSHOT is the bootstrap path; getOptInFlag/setOptInFlag remain the documented direct-access exception.
P4.8 review nit — replaces "P4.6 will lock this decision" with the shipped state pointer to apps/pwa/CLAUDE.md.
P4.9 final reviewer flagged that "(PR3 ESLint rule)" reads as live enforcement. Restated as "(F2 PR3 will enforce with an ESLint rule)".
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
jukka-matti
added a commit
that referenced
this pull request
May 6, 2026
…otocol for PR3 PR2 (PWA repository + composition migration) merged at 7fc1a36. Plan updated with Session 2 status block + revised Session 3 resume protocol (Phase P5-P8 sequence, fresh worktree at .worktrees/data-flow-foundation-pr3/, Sonnet workhorse + Opus for P8.1 final-branch review). Original Session 1 status preserved as PR1 history. Co-Authored-By: ruflo <ruv@ruv.net>
jukka-matti
added a commit
that referenced
this pull request
May 6, 2026
PR3 (Azure repository + ESLint guard) merged at 2490fc8, completing F1+F2 across all three squash commits on origin/main: - d2822ea PR #130 (F1 types) - 7fc1a36 PR #131 (F2 PWA) - 2490fc8 PR #132 (F2 Azure + ESLint guard) Plan updated with F1+F2 SHIPPED block + Session 3 closeout (P5-P8 delivered, plan-reality deltas, F-series forward, watchlist). Original Session 2 closeout preserved as PR2 history. Spec already flipped status: active → delivered as part of PR3 P8.2. Co-Authored-By: ruflo <ruv@ruv.net>
10 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 2 of the Data-Flow Foundation F1+F2 plan (
docs/superpowers/plans/2026-05-06-data-flow-foundation-f1-f2.md, §"Phase P3" + §"Phase P4"). Builds on PR1 (#130, types + interfaces).This PR moves PWA hub-blob persistence behind
pwaHubRepository, an implementation of@variscout/core/persistence#HubRepository. UI/composition-layer call sites (SaveToBrowserButton, App.tsx) now dispatchHUB_PERSIST_SNAPSHOTand otherHubActions instead of reaching forhubRepository.saveHub/loadHubdirectly.canvasStoregains a paralleldispatch(action: CanvasAction)entry per audit R15. F3 (PR7+) will normalize the PWA blob into per-table writes; PR2 deliberately delegates to existing storage per locked decision D-P2.apps/pwa/src/persistence/):PwaHubRepositoryclass implementingHubRepository; Immer-basedapplyActionwith exhaustivekindswitch +assertNeverdefault; cascade walkers viatransitiveCascade; module-scoped singleton at the composition root.HUB_PERSIST_SNAPSHOT; App.tsx loads viapwaHubRepository.hubs.list();canvasStore.dispatchdelegates to existing per-action methods (transitional wrapper, removed in PR3 cleanup);packages/stores/CLAUDE.mdandapps/pwa/CLAUDE.mddocument the dispatch boundary.Per audit revisions: R10 scoped P4 to UI/app files (domain stores never had Dexie calls); R15 kept canvasStore method-per-action API in PR2; R14 documented
addHubCommentnetwork IO as a deliberate exception.Stats
data-flow-foundation-pr2@variscout/pwa: 189 → 298 tests (+109)@variscout/stores: 261 → 272 tests (+11 fromcanvasStore.dispatch)bash scripts/pr-ready-check.shgreenReviews completed
47870af1f074d110Test plan
claude --chromewalk (P4.7, deferred from controller session — chrome_* tools unavailable):HUB_PERSIST_SNAPSHOTdispatch pathOut of scope (carried forward)
AzureHubRepository+ ESLint guard + final Opus review)🤖 Generated with Claude Code