framing-layer V1 slice 2 — close-the-loop on Mode B#122
Merged
Conversation
… (slice-2 Task A)
Replace the legacy (outcome, factors, specs) onConfirm signature with
ColumnMappingConfirmPayload. Stage 3 now renders OutcomeCandidateRow for
multi-select, PrimaryScopeDimensionsSelector for scope dimensions, and
OutcomeNoMatchBanner when all candidates score below threshold.
Key changes:
- onConfirm emits { outcomes: OutcomeSpec[], primaryScopeDimensions, ...legacy compat }
- Multi-outcome selection via parent-held Set state + OutcomeCandidateRow
- PrimaryScopeDimensionsSelector replaces standalone factor-picker in setup mode
- OutcomeNoMatchBanner surfaces when all candidates score below noMatchThreshold
- mode='edit': preloads initialOutcomes + initialPrimaryScopeDimensions
- Inline specs per row (OutcomeCandidateRow already has spec inputs when selected)
- Legacy compat fields (payload.outcome, payload.factors, payload.specs) kept for
importFlow compatibility; clearly documented for removal in future slice
- No σ-based LSL/USL suggestions (spec §3.3 invariant preserved)
- CharacteristicType ambiguity resolved: processHub type vs legacy types.ts type
Co-Authored-By: ruflo <ruv@ruv.net>
…+ update tests Atomic migration: all three render sites and their tests updated in one commit so the build never breaks (per feedback_no_backcompat_clean_architecture). Sites migrated: - apps/pwa/src/App.tsx:886 (handleMappingConfirmWithGoal) — adopts ColumnMappingConfirmPayload; resolves slice-1 TODO by populating sessionHub.outcomes + sessionHub.primaryScopeDimensions - apps/azure/src/pages/Editor.tsx:1310 + :1672 (handleMappingConfirmWithCategories) — adopts payload shape; persists outcomes + primaryScopeDimensions to active Hub via saveProcessHub when processContext.processHubId is available Tests updated: - packages/ui/src/components/ColumnMapping/__tests__/ColumnMapping.test.tsx — rewritten for new multi-outcome, scope-dim, no-match, and edit-mode API - apps/azure/src/pages/__tests__/Editor.test.tsx — mocked ColumnMapping updated to emit new ColumnMappingConfirmPayload shape E2E helper updated: - apps/azure/e2e/helpers.ts confirmColumnMapping() — drives new OutcomeCandidateRow UI; accepts optional outcomeName param; fix pre-existing __dirname lint error Co-Authored-By: ruflo <ruv@ruv.net>
…guard Returns true only when a ProcessHub carries a non-empty processGoal AND at least one OutcomeSpec with a non-empty columnName. Used by Mode A.1 reopen path to decide canvas-first-paint vs framing flow. primaryScopeDimensions intentionally not required (skip path is valid). Exported from both the root barrel and the /processHub sub-path. Co-Authored-By: ruflo <ruv@ruv.net>
…utton, VrsExportButton, Edit framing) Adds the canvas framing toolbar that appears after data is loaded: - OutcomePin for the first Hub outcome (mean ± σ + n fallback when no specs) - SaveToBrowserButton for opt-in IndexedDB persistence - VrsExportButton for .vrs file download - "Edit framing" button that re-opens ColumnMapping in edit mode - GoalBanner now wired with onChange to persist goal edits to sessionHub Co-Authored-By: ruflo <ruv@ruv.net>
Adds onImportVrs prop to HomeScreen which renders a VrsImportButton when provided. The handler in App.tsx restores hub + raw data from the .vrs file, seeds outcome and primaryScopeDimensions, and lands directly on the canvas — no framing flow re-run needed for previously-packaged training scenarios. Co-Authored-By: ruflo <ruv@ruv.net>
…seNewHubProvision) Adds FSD hubCreation feature slice: - HubCreationFlow: Stage 1 (HubGoalForm) → Stage 3 (ColumnMapping) router; Stage 1 is skipped on re-edit or when a processHubId already exists - useNewHubProvision: creates and persists a new ProcessHub from a goal narrative via saveProcessHub; fires onCreated callback for Editor wiring - Index barrel exporting both - 5 tests for useNewHubProvision covering creation, skip-path, and onCreated Co-Authored-By: ruflo <ruv@ruv.net>
Adds optional onNewHub prop to ProjectDashboard. When provided, renders a 'New Hub' button in the Quick Actions panel that calls the handler. Absent means the button is hidden (e.g. contexts that don't yet expose Mode B entry). 3 new tests covering render, hide, and click behavior. Co-Authored-By: ruflo <ruv@ruv.net>
…hange wiring - Add isProcessHubComplete import; compute hubIsComplete on render - Add onHubGoalChange prop: wires GoalBanner onChange so inline goal edits persist back to the hub via the parent handler - Add onEditFraming prop: renders amber framing-prompt banner with "Add framing" CTA when hub is incomplete and handler is provided; banner hidden when hub is complete or handler is absent - 5 new tests: onChange wiring, prompt visible/hidden (complete hub, absent handler), CTA fires onEditFraming with correct hubId Co-Authored-By: ruflo <ruv@ruv.net>
Editor.tsx: - Replace both ColumnMapping render sites with HubCreationFlow so new investigations gate behind Stage 1 (HubGoalForm) before ColumnMapping - Add handleNewHub: 'New Hub' from Dashboard opens paste → framing flow - Add handleHubCreated: Stage 1 callback syncs new hub into processContext and processHubs list so Stage 3 can persist outcomes to it - Remove unused ColumnMapping import (now internal to HubCreationFlow) - Mock HubCreationFlow in Editor.test.tsx to preserve existing routing test semantics (data-testid="column-mapping") HubCreationFlow.test.tsx (10 new tests): - Stage 1 gate: shown for new investigation - Skip Stage 1 on isMappingReEdit or existing processHubId - Confirm/skip advance to ColumnMapping with correct goalContext - saveProcessHub called with goal narrative (confirm path) and empty goal (skip path → Untitled hub) - onHubCreated fires with created hub - onConfirm called when ColumnMapping confirms Co-Authored-By: ruflo <ruv@ruv.net>
…inding 1) Drop the legacy outcome/factors/specs fields from ColumnMappingConfirmPayload; derive them at call-sites in PWA App.tsx and Azure Editor.tsx from the Hub-shaped outcomes[0] / primaryScopeDimensions. Tests updated to assert shim fields absent. Co-Authored-By: ruflo <ruv@ruv.net>
save() now returns early when draft.trim() === '' so clicking Save with an empty text field does not invoke onChange and leaves the banner in edit mode. Test added to verify the guard. Co-Authored-By: ruflo <ruv@ruv.net>
handleHubGoalChange persists inline goal edits via saveProcessHub and propagates into processHubs state. handleEditFraming navigates to the hub's framing flow. Both handlers are passed to ProcessHubView. Tests added for goal-change persistence and framing-prompt visibility. Co-Authored-By: ruflo <ruv@ruv.net>
When isProcessHubComplete() is true and hub.outcomes is non-empty, render one OutcomePin per outcome inside a data-testid=outcome-pin-row wrapper. Stats fall back to 0 / rowCount until live analysis is wired. Tests assert the row is absent for incomplete hubs and present with N pins for a hub with N outcomes. Co-Authored-By: ruflo <ruv@ruv.net>
App.tsx framing toolbar maps sessionHub.outcomes to one OutcomePin each (was outcomes[0] only). Removed the stats && guard so pins render in the zero-stats fallback state before first analysis completes. outcomePinMulti.test.tsx: seeds 1-outcome and 2-outcome hubs, asserts correct pin counts via data-testid=outcome-pin. Co-Authored-By: ruflo <ruv@ruv.net>
…port Four Playwright tests covering the deferred Mode B scenarios from slice 1: paste → HubGoalForm → ColumnMapping → GoalBanner + OutcomePin + framing-toolbar; reload restores Mode A.1 GoalBanner; all-text CSV triggers OutcomeNoMatchBanner; .vrs fixture import shows GoalBanner + OutcomePin. Adds data-testid to SaveToBrowserButton (save-to-browser-button/saved) and VrsImportButton (vrs-import-button) for stable E2E selectors. Co-Authored-By: ruflo <ruv@ruv.net>
Two passing Playwright tests for the deferred Azure Mode B scenarios from slice 1: (1) Editor paste → HubGoalForm Stage 1 → ColumnMapping → I-chart; (3) load sample → Overview tab → action-new-hub → paste replaces data (window.confirm accepted via page.once handler) → Stage 1 → ColumnMapping → I-chart. Tests 2 and 4 skip gracefully when portfolio is unavailable in a clean context. Adds MODE_B_CSV, pasteDataAndAnalyze, completeStage1 helpers to e2e/helpers.ts. Co-Authored-By: ruflo <ruv@ruv.net>
…cal #1) Pass initialOutcomes + initialPrimaryScopeDimensions from the active Hub to ColumnMapping at all three render sites so edit-framing no longer silently drops outcomes 2..N. - apps/pwa/src/App.tsx: pass sessionHub.outcomes / .primaryScopeDimensions when isMappingReEdit - apps/azure/src/features/hubCreation/HubCreationFlow.tsx: add initialOutcomes + initialPrimaryScopeDimensions props; forward to ColumnMapping when isMappingReEdit === true - apps/azure/src/pages/Editor.tsx: derive activeHub from processHubs and pass its outcomes/primaryScopeDimensions at both HubCreationFlow sites - ColumnMapping.test.tsx: add regression test 'edit-mode roundtrip preserves all initialOutcomes (multi-outcome)' Co-Authored-By: ruflo <ruv@ruv.net>
…tical #2) Multi-select semantics require checkbox, not radio. This was a semantic mismatch — radio implies single-select in HTML. - OutcomeCandidateRow.tsx: type="radio" → type="checkbox" - OutcomeCandidateRow.test.tsx: getByRole('radio') → getByRole('checkbox') - ColumnMapping.test.tsx: all getAllByRole('radio') → getAllByRole('checkbox') (already committed in Critical #1 batch but note here for clarity) - apps/azure/e2e/helpers.ts: confirmColumnMapping selector updated from input[type="radio"] to input[type="checkbox"] - apps/pwa/e2e/modeB.e2e.spec.ts: weight_g selector updated; adds multi-outcome E2E test (select 2 checkboxes → assert 2 OutcomePins) Co-Authored-By: ruflo <ruv@ruv.net>
…Important #3) Previously all three handlers were no-ops. Now they do something: - onSkip: clears selectedOutcomeSpecs (Start Analysis becomes disabled — canvas will show all-unclassified columns per §3.3 skip-spec path) - onExpectedChange: stores the analyst note in local state and includes it in the ColumnMappingConfirmPayload as expectedOutcomeNote - onRename(oldName, newName): delegates to parent's onColumnRename callback (sets a display alias for the column) Adds ColumnMappingConfirmPayload.expectedOutcomeNote field (optional string). ProcessHub has no home for it yet — downstream handlers currently ignore it; logged as carry-forward in decision-log. New ColumnMapping tests: - 'Skip CTA clears selected outcomes' — disables Start Analysis after skip - 'expectedOutcomeNote is included in payload after onExpectedChange' Co-Authored-By: ruflo <ruv@ruv.net>
…ovision (Important #5) The bespoke handleCreateHub in pages/Dashboard.tsx used inline crypto.randomUUID() + saveProcessHub with a hardcoded 'New Hub' name, bypassing extractHubName. Replaced with useNewHubProvision which: - calls extractHubName(narrative) — falls back to 'Untitled hub' for empty - uses the canonical persistence path (saveProcessHub via useStorage) - fires onCreated callback so processHubs state + selectedHubId update atomically Updated Dashboard.processHub.test.tsx to assert 'Untitled hub' instead of 'New Hub' and updated the test description to reflect canonical path. Co-Authored-By: ruflo <ruv@ruv.net>
…ine-panel decision 2026-05-04 entry documents why slice 2 shipped the amber-CTA → redirect-to-Editor-paste-flow path instead of the inline-panel design from the plan. Also documents the expectedOutcomeNote carry-forward. Co-Authored-By: ruflo <ruv@ruv.net>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Merged
16 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
Closes the Mode B loop end-to-end. Both apps now let a first-time user paste a CSV, state a process goal, multi-select outcomes with inline specs, pick scope dimensions, and land on a workspace with a goal banner + outcome pin per outcome. Save-to-browser,
.vrsround-trip, and edit-framing affordances all live.Builds on slice 1 (#121, foundation only — types + 8 unmounted components). Slice 2 mounts and wires what slice 1 built, plus the Azure
features/hubCreation/slice that didn't exist.Plan:
~/.claude/plans/lets-do-slice-2-synchronous-sonnet.md(approved 2026-05-04).Spec:
docs/superpowers/specs/2026-05-03-framing-layer-design.md§16 acceptance.What's in scope
ColumnMappingrefactor to canonical Hub-level mapper. NewonConfirmpayload{ outcomes: OutcomeSpec[]; primaryScopeDimensions: string[]; ... }. All 3 call sites migrated atomically (PWAApp.tsx, AzureEditor.tsx× 2). No compat shim. Perfeedback_no_backcompat_clean_architecture+feedback_type_separation_vs_component_separation.OutcomeCandidateRow(now<input type="checkbox">, was radio — caught in final review).PrimaryScopeDimensionsSelectorsub-step + auto-suggest viasuggestPrimaryDimensions().OutcomeNoMatchBannerwith functional rename / skip / expected-outcome-note CTAs.features/hubCreation/slice:HubCreationFlow(Stage 1 → 2 → 3 inline orchestrator),useNewHubProvision(canonical hub creator withextractHubName).ProjectDashboard+ Dashboard+ New Hubroutes throughuseNewHubProvision(replaceswindow.prompt).ProcessHubView:isProcessHubComplete()gate, "Add framing" CTA → Editor paste flow, editableGoalBanner(onChangewired throughDashboard.handleHubGoalChange→saveProcessHub), "Edit framing" affordance,OutcomePinrow (one per outcome).App.tsxframing toolbar:OutcomePinper outcome,SaveToBrowserButton(contextual chip),VrsExportButton, edit-framing re-entry.HomeScreen:+ Import .vrs filesecondary action.packages/core:isProcessHubComplete()helper.GoalBanner: non-empty validation on Save.What's out of scope (carried forward)
Per spec §15 V1 phasing — this slice ships the close-the-loop scope only:
Process
Subagent-driven dispatch per
feedback_subagent_driven_default:bash scripts/pr-ready-check.shgreen throughout.Test plan
bash scripts/pr-ready-check.sh— green (tests + lint + docs:check + dist integrity).pnpm --filter @variscout/ui build— green perfeedback_ui_build_before_merge..vrsImport).claude --chromewalk in both PWA + Azure (perfeedback_verify_before_push):OutcomeNoMatchBannerSkip path🤖 Generated with ruflo