IM-4c: unified Wall layout authority + Focus lens + propose-hypothesis-from-finding#258
Merged
Conversation
…thesis-from-finding The remainder of IM-4 spec §8.6 (deferred from PR #257's IM-4b sub-slice): one Wall coordinate space via a single computeWallLayout authority (kills the 3x duplicated Minimap/pan-to-node math), the Focus lens (degree-of-interest dimming pinned to viewStore), an orphan-finding home + the descoped createHubFromFinding CTA, and the setHubStatus orphan deletion (§10). Bakes in the anti-green-but-dead seam-test discipline from the IM-4b trial. Linked from the master plan IM-4 section. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Single deterministic source of truth for hub / finding / factor positions + tethers on the Investigation Wall, in the fixed 2000x1400 user-space. Lifts the inline placement math out of WallCanvas verbatim (linear + tributary hub rows, support/counter chip columns at hubX+/-130, scope anchor, factor band) and adds a left-gutter orphan lane for findings linked to no hub. Minimap + both apps' pan-to-node will consume this in later tasks (kills the 3x duplicated math). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tion authority) WallCanvas now derives hub anchors, evidence-chip columns, the orphan-finding lane, and tether endpoints from computeWallLayout instead of inline math — killing the source-of-truth duplication that let Minimap + pan-to-node drift. Each node carries data-wall-node-id + data-x/data-y so consumers + seam tests read the SAME coordinates the DOM rendered. Adds the WallCanvas.layout seam test pinning hub/orphan positions + the LOUD counts-against guard + tether-to-anchor guard. FindingChip gains the (Task-4-wired) onProposeHypothesis affordance, shown only on orphan chips. All 357 AnalyzeWall tests stay green (collab seam included). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds buildWallLayoutArgs — the single owner of the tributary-bucketing rule (mirrors WallCanvas's tributaryGroups memo) — so WallCanvas, Minimap, and both apps' pan-to-node all feed the SAME inputs into computeWallLayout. Minimap now positions its dots from the authority (correct under tributary grouping, where the old linear-row duplicate silently drifted off the cards); both apps' command- palette pan-to-node centers on the authority hub position. Minimap seam test proves dot x === authority x under tributary grouping and != the linear column. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eateHubFromFinding) wiring Orphan findings (linked to no hub) get a home on the Wall: a left-gutter lane that keeps the SVG body mounted even with zero hubs (EmptyState now only shows when there are neither hubs NOR orphans). FindingChip renders the 'Propose suspected mechanism from this finding' affordance on orphan chips. createHubFromFinding trap — wired per app's rendered-hubs source of truth: - Azure renders hypothesesState.hubs (useHypotheses hook) → propose routes through createHub + connectFinding on that hook (NOT analyzeStore, a different collection that would not re-render the Wall). - PWA renders useAnalyzeStore.hypotheses reactively → propose calls createHubFromFinding, which re-renders the Wall directly. Seam tests: WallCanvas.proposeHypothesis.seam proves render-through (a NEW hub card appears via a stateful harness mirroring the apps); the ideasSection descope guard is FLIPPED to the positive assertion; AnalyzeWorkspace.mapwall proves the Azure wiring hits createHub + connectFinding, not a bare store call. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds viewStore.focusedWallEntityId (+ setFocusedWallEntity) as the SINGLE focus source (ADR-086 — WallCanvas AND Minimap read this one field, no per-renderer useState). New pure wallFocus.ts: wallDegreeOfInterest = undirected BFS over the WallLayout tethers (focused=0, adjacent=1, distant>=2; null focus = 0 = no dimming), focusOpacity maps distance to vivid/mid/dim tiers. WallCanvas applies the opacity + data-doi to every hub/finding/orphan node, focuses on node click, clears on empty-canvas click (a back rect). Minimap dims its dots from the SAME store field + the same authority edges. Focus is dimming ONLY — never touches CanvasLevel/LOD (spec §9). Focus seam test asserts real opacity + click gestures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
setHubStatus had zero production callers and no action/interface definition anywhere in packages/ or apps/ (spec §10 #1 — a manual status override contradicts the derived-status model). Removed the stale comment reference that implied the action still existed on main; the comment now documents that status is derived via deriveHypothesisStatus + the disconfirmation gesture, with the stored-vs-derived reader migration deferred to IM-6. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…butaries The PWA threads groupByTributary=Boolean(processMap && wallGroupByTributary), and some fixtures supply a processMap with no `tributaries` array. The Minimap's new computeWallLayout call then hit `processMap.tributaries.map` on undefined. Guard with Array.isArray so a tributaries-less processMap falls back to the linear layout instead of throwing. Surfaced by AnalyzeView.mapwall. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The plan committed in 68c0608 lacked the SDD frontmatter block, failing pnpm docs:check (and pr-ready-check) on main + every branch off it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…model-builder is V-next
Captures the settled factor-cause model from the IM-4c design conversation
(two grounded 5-lens explorations):
- A cause's factors = a DERIVED projection (deriveBranchColumns ∪ findings'
columns ∪ CausalLink), never a stored Hypothesis.factorIds field. Factors are
scope-level; the finding is the bridge.
- The typed factor→hypothesis bipartite edge is deferred (CausalLink stays
factor→factor); the Evidence Map stays the separate cross-scope overview.
- The parsimony engine (computeBestSubsets) already exists; the vital-few
model-builder (R²adj + p only, full analyst control with snap-back) is a
~90%-UI V-next increment. Selection-stability bootstrap deferred one increment.
- Focus lens never moves the model metrics ("in the model" ≠ "is the cause").
Amends ADR-086 (records the original heavier bipartite reading as superseded)
+ pins a Replayed-Decision in the log so the next implementer doesn't add a
stored factor field. IM-4c merges as the scope-band Wall.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lder hook computeWallLayout positions factors + emits factor edges, but WallCanvas does not pass `factors` in V1 (the band still renders via TributaryFooter), so factorPositions is intentionally empty in production. Comment points to the ADR-086 Amendment + decision-log so the empty map reads as a deferred hook, not a bug — factors stay scope-level; a cause's factors are derived, never stored. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eWall modules Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
IM-4c — the last layout half of IM-4 §8.6
Plan:
docs/superpowers/plans/2026-05-31-im-4c-unified-wall-layout-focus-lens.md.Spec:
docs/superpowers/specs/2026-05-30-investigation-wall-unified-canvas-design.md§8.6.Follows IM-4a (#256) + IM-4b (#257). After this, only IM-6 remains.
Single-Opus implementer (per the IM-4b TDD-pipeline trial verdict — integration-heavy UI needs one implementer that wires through the production seam + runs real builds).
What ships
computeWallLayout— one position authority. Pure/deterministic; returns hub/finding/factor positions + scope anchor + edges. WallCanvas renders from it (data-wall-node-id/data-x/data-y); the old inline hub/finding math is gone.buildWallLayoutArgs) — the 3× duplicated layout formula is killed.FindingChipgainsonProposeHypothesis. Wired per-app through the rendered-hubs path (Azure →hypothesesState.createHub+connectFinding; PWA →createHubFromFinding) — verified render-through, not a store-call spy.viewStore.focusedWallEntityId(read by WallCanvas AND Minimap); click-to-focus / empty-canvas-clear; purewallDegreeOfInterestBFS. Dimming only — never touchesCanvasLevel/LOD.setHubStatusorphan documented/removed (spec §10 chore(deps): bump pnpm/action-setup from 4.1.0 to 4.4.0 #1 — status is derived).Factor model (settled this PR's design conversation)
Factors render as the scope-level contributing-factors band (correct for V1). A cause's factors are a derived projection, never stored — the adversarial review's "factors aren't coordinate-space nodes" is by design; the
computeWallLayoutfactor-positioning is the forward hook for the V-next model-builder (vital-few best-subset UX, R²adj + p, full analyst control). Pinned in ADR-086 Amendment (2026-05-31) + the decision-log. The Focus lens never moves model metrics ("in the model" ≠ "is the cause").Verification
bash scripts/pr-ready-check.sh) green: full turbo test, lint, level-boundaries, both app vite builds + dist-integrity. (Earlier run's only red was a missing-frontmatter docs:check on the plan doc — fixed on main.)data-*/opacity/positions). Its two "majors" both resolved: factors-as-band is the settled V1 model (deferred per ADR amendment); the active-IP-scope render-through limitation is pre-existing (mirrors the existing create-hub composer) — logged, not introduced here.🤖 Generated with Claude Code