Files
portfolio/.ralph/plan.md
T
2026-02-16 13:23:04 +00:00

368 lines
23 KiB
Markdown

# D3 Constellation Remediation Plan (Hover, Timeline Parity, Token Alignment)
## Objective
Restore reliable constellation interactions and align timeline semantics/styling with the dashboard system without broad refactors.
## Current Findings (from code inspection)
- Pointer/focus layer conflict: `src/components/CareerConstellation.tsx` renders an absolute full-chart button overlay with `pointerEvents: 'auto'` per node. This can intercept pointer hover intended for SVG node groups, making desktop highlight activation inconsistent.
- Timeline semantic drift: `src/data/timeline.ts` currently exports `timelineRoleEntities = timelineEntities`, so education items are incorrectly treated as role nodes for constellation data generation.
- Timeline/card data coupling still uses compatibility layer in key UI paths:
- `src/components/CareerConstellation.tsx` reads pinned accordion content from `consultations`.
- `src/components/TimelineInterventionsSubsection.tsx` uses `consultationsById` for detail panel open.
- `src/components/DashboardLayout.tsx` uses `consultations` for role click and “Last Consultation”.
- Highlight state split remains (`highlightedNodeId` vs `highlightedRoleId` in `DashboardLayout`), increasing mismatch risk between graph and timeline cards.
- Font token mismatch persists: components use `var(--font-mono)` while tokens define `--font-geist-mono` / `--font-mono-dashboard` in `src/index.css`.
## Scope Boundaries
- In scope:
- Constellation pointer/focus/hover reliability and highlight lifecycle.
- Timeline role/education semantic parity between graph and chronology stream.
- Token-consistent typography fixes in constellation and timeline-adjacent components.
- Cleanup of duplicate timeline consumer paths only where they cause behavioral divergence.
- Out of scope:
- Sidebar/tag system changes.
- New visual redesigns unrelated to existing card/token language.
- Non-pathway feature work.
## File-Level Implementation Steps
1. Fix role vs education selectors in canonical timeline exports.
- File: `src/data/timeline.ts`
- Changes:
- Export explicit selectors:
- `timelineCareerEntities` (`kind === 'career'`)
- `timelineEducationEntities` (`kind === 'education'`)
- keep `timelineEntities` as combined sorted list.
- Build constellation role nodes, mappings, and links from `timelineCareerEntities` only.
- Keep compatibility exports only if required by current panel types; avoid role graph deriving from combined data.
- Acceptance:
- No education entry appears as `type: 'role'` in `buildConstellationData()` outputs.
2. Remove pointer interception while preserving keyboard accessibility.
- File: `src/components/CareerConstellation.tsx`
- Changes:
- Replace always-active absolute button hit targets with focus-only accessibility controls that do not capture pointer hover.
- Maintain keyboard tab/focus/Enter/Space activation behavior.
- Keep touch coarse-pointer tap-to-pin + background clear behavior.
- Ensure mouseenter/mouseleave on D3 nodes are the authoritative desktop hover path.
- Acceptance:
- Desktop pointer hover over visible SVG nodes consistently activates highlight.
- Keyboard focus still highlights and activates nodes.
3. Stabilize highlight source-of-truth and reset semantics.
- Files: `src/components/CareerConstellation.tsx`, `src/components/DashboardLayout.tsx`, `src/components/TimelineInterventionsSubsection.tsx`
- Changes:
- Normalize graph/card highlight flow so role hover, skill hover, and card hover transitions do not flicker on mouseleave/blur.
- Ensure blur/mouseleave fall back to current pinned/external highlight state coherently (no forced null unless intended).
- Keep role-card cross-highlight and avoid skill-hover clearing active role card unexpectedly.
- Acceptance:
- Highlight transitions are predictable when moving pointer between graph nodes and timeline cards.
- No visible reset/flicker on quick node-to-node movement.
4. Align timeline/detail consumers to canonical timeline semantics.
- Files: `src/components/CareerConstellation.tsx`, `src/components/TimelineInterventionsSubsection.tsx`, `src/components/DashboardLayout.tsx`, optional `src/types/pmr.ts`
- Changes:
- Prefer timeline-entity-based lookup for role details where feasible, with career-only lookup for constellation role interactions.
- Keep education entries in chronology stream, but exclude from role-node click/hover mapping.
- Verify timeline ordering matches work-experience chronology intent (latest to oldest parity).
- Acceptance:
- Constellation role interactions map to career records only.
- Chronology order in timeline stream matches expected work-experience-first semantics.
5. Token-consistent typography cleanup (no redesign).
- Files: `src/components/CareerConstellation.tsx`, `src/components/TimelineInterventionsSubsection.tsx`, `src/components/DashboardLayout.tsx`, `src/index.css`
- Changes:
- Replace invalid `var(--font-mono)` usage with canonical mono token (`var(--font-geist-mono)` or standardized dashboard mono alias).
- Keep UI text on existing UI token family (`var(--font-ui)` where already used).
- Acceptance:
- No unresolved/undefined font token usage remains in constellation/timeline-adjacent UI.
6. Verification and review notes.
- Commands:
- `npm run lint`
- `npm run typecheck`
- `npm run build`
- Manual checks to record in `.ralph/review.md`:
- Desktop hover on role and skill nodes.
- Graph ↔ timeline cross-highlight behavior.
- Touch/coarse-pointer tap-to-pin and clear.
- Keyboard focus navigation and activation.
- Timeline order parity sanity check vs work-experience content.
## Suggested Runtime Task Sequence
- Task A: Data parity selectors + constellation career-only mapping.
- Task B: Constellation pointer/focus layer remediation + highlight state stabilization.
- Task C: Timeline/detail consumer parity + token alignment.
- Task D: Backpressure checks + manual verification notes in `.ralph/review.md`.
## Completion Gate
All objective success criteria pass, including lint/typecheck/build and recorded manual verification outcomes.
## Runtime Task IDs
- `task-1771246519-9ce3` Constellation data parity: career-only role mapping
- `task-1771246519-1e54` Constellation interaction remediation: hover/focus layer
- `task-1771246519-92f0` Timeline parity + token alignment
- `task-1771246519-fd59` Backpressure and manual review evidence
## Progress Notes
- 2026-02-16: Completed Task A (`task-1771246519-9ce3`).
- Added explicit timeline selectors in `src/data/timeline.ts`:
- `timelineCareerEntities` (`kind === 'career'`)
- `timelineEducationEntities` (`kind === 'education'`)
- compatibility alias `timelineRoleEntities = timelineCareerEntities`
- Updated constellation role nodes/mappings/links and `timelineConsultations` derivation to use `timelineCareerEntities` only.
- Validation: `npm run typecheck` passed.
## Atomic Execution Plan: task-1771246519-1e54 (Hover/Focus Layer)
### Scope for this execution
- Primary files: `src/components/CareerConstellation.tsx`, `src/components/DashboardLayout.tsx`, `src/components/TimelineInterventionsSubsection.tsx`
- Allowed supporting touchpoint: `src/data/timeline.ts` only if career-entity lookup is needed to replace role detail dependencies in constellation overlay content.
- Explicitly out of scope for this task: typography token cleanup and broader timeline consumer consolidation (covered by `task-1771246519-92f0`).
### Diagnosed root causes to remediate
- Pointer interception:
- `CareerConstellation` accessibility layer buttons are absolute-positioned, full-hitbox, and `pointerEvents: 'auto'` while parent group is `pointerEvents: 'none'`.
- These controls overlap node hit targets and can steal/mask pointer hover intended for D3 `g.node` handlers.
- Highlight fallback inconsistency:
- Graph mouseleave unconditionally calls `onNodeHover(null)` while blur path restores `onNodeHover(pinnedNodeId)`.
- This mixed reset policy causes card highlight flicker when moving between graph nodes, cards, and focus controls.
- Role detail lookup drift:
- Mobile pinned accordion currently resolves role details from legacy `consultations`, not canonical timeline career entities.
### Implementation steps for builder
1. Make keyboard overlay non-intercepting for pointer.
- File: `src/components/CareerConstellation.tsx`
- Replace always-active button layer with a focus-only model:
- Keep semantic `button` controls for tab/Enter/Space.
- Prevent pointer capture by default (`pointerEvents: 'none'` on buttons), and only enable during keyboard focus state when needed.
- Preserve visible focus ring via existing `.focus-ring` sync (`focusedNodeId` path).
- Ensure keyboard users can still tab through all nodes in deterministic order.
2. Unify highlight fallback semantics across mouse and keyboard.
- Files: `src/components/CareerConstellation.tsx`, `src/components/DashboardLayout.tsx`, `src/components/TimelineInterventionsSubsection.tsx`
- Introduce one fallback resolver in constellation:
- `resolveFallbackHighlight = highlightedNodeIdRef.current ?? pinnedNodeIdRef.current`
- Use this on node mouseleave and accessibility-control blur (instead of mixed null/pinned behavior).
- Keep skill hover from driving role-card highlight:
- Role hover/focus sets role highlight.
- Skill hover/focus should not forcibly clear an active role highlight unless fallback is null.
- Ensure timeline card mouseleave does not induce graph/card thrash when crossing between adjacent cards.
3. Preserve touch behavior while removing desktop hover conflict.
- File: `src/components/CareerConstellation.tsx`
- Keep existing coarse-pointer behavior:
- Node tap toggles pin.
- Background tap clears pin + highlight.
- Confirm touch branch remains independent from desktop hover path after overlay change.
4. Align mobile pinned role details with canonical timeline career data.
- File: `src/components/CareerConstellation.tsx` (and `src/data/timeline.ts` only if needed for import shape)
- Replace `consultations.find(...)` for pinned role accordion with career entity lookup from canonical timeline exports (or mapped career consultation export already derived from timeline career entities).
- Acceptance in this task: no new dependency on combined timeline entities for role detail surface.
### Acceptance checks (task-local)
- Desktop pointer:
- Hovering any visible role/skill node reliably triggers graph highlight without dead zones.
- Moving pointer node-to-node does not cause highlight flash-to-none.
- Keyboard:
- Tab reaches node controls in intended order.
- Focus highlights target node and role cards (for role nodes).
- Blur returns to fallback highlight state (external hover or pinned) without forced reset.
- Touch/coarse pointer:
- Tap node pins/unpins.
- Tap background clears pinned state and timeline highlight.
- Cross-surface coherence:
- Timeline card hover and graph hover no longer fight each other during transitions.
### Handoff note to builder
- Keep the patch minimal and behavior-focused.
- Do not combine token/font changes or broad timeline refactors into this task; defer those to `task-1771246519-92f0`.
- 2026-02-16: Completed Task B (`task-1771246519-1e54`).
- Updated `src/components/CareerConstellation.tsx` to remove pointer interception from accessibility overlay controls (`pointerEvents: 'none'` on invisible positioned buttons) so SVG hover handlers remain authoritative for desktop pointer input.
- Added fallback resolvers (`resolveGraphFallback`, `resolveRoleFallback`) and wired them into node `mouseleave`, keyboard-control `blur`, and coarse-pointer skill pin paths to prevent role-highlight reset flicker.
- Kept coarse-pointer tap-to-pin behavior and background clear behavior intact while preserving keyboard focus/Enter/Space activation.
- Replaced mobile pinned role accordion dependency on `consultations` with canonical `timelineCareerEntities` lookup to keep role detail semantics aligned with career-only timeline scope.
- Validation: `npm run lint` (pass, 2 existing warnings), `npm run typecheck` (pass), `npm run build` (pass).
## Atomic Execution Plan: task-1771246519-fd59 (Backpressure + Manual Review Evidence)
### Scope for this execution
- Primary files: `.ralph/review.md`, `.ralph/plan.md`
- Allowed supporting touchpoints: command outputs from `npm run lint`, `npm run typecheck`, `npm run build`, plus any available audit/coverage/complexity/duplication scripts or documented equivalents.
- Explicitly out of scope for this task: feature implementation work in `src/` (handled by `task-1771246519-92f0` and prior tasks).
### Objective for this task
- Produce reviewer-visible evidence that manual behavior checks were executed against the current remediation state.
- Satisfy pending `build.blocked` contract by preparing a compliant `build.done` payload with explicit status fields.
### Required evidence contract
The next `build.done` event payload must include all required fields:
- `tests: <status>`
- `lint: <status>`
- `typecheck: <status>`
- `audit: <status>`
- `coverage: <status>`
- `complexity: <value or status>`
- `duplication: <status>`
- Optional when available: `performance: <status>`, `specs: <status>`
If a metric is not implemented in this repository, report it explicitly as `not-configured` with a short qualifier in `.ralph/review.md`; do not omit the field from `build.done`.
### Implementation steps for builder/reviewer
1. Run backpressure checks and capture concrete outcomes.
- Execute:
- `npm run lint`
- `npm run typecheck`
- `npm run build`
- Discover audit/coverage/complexity/duplication command availability from `package.json` and existing tooling files; run what exists.
- For unavailable gates, record `not-configured` with one-line rationale tied to repository state.
2. Record manual behavior verification in `.ralph/review.md`.
- Add a concise section with date/time and environment assumptions (desktop pointer + coarse pointer + keyboard path tested).
- Record pass/fail notes for:
- Desktop hover on role nodes and skill nodes (fill and border hit areas).
- Graph/timeline cross-highlight coherence.
- Touch/coarse-pointer tap-to-pin and background clear.
- Keyboard tab/focus/Enter/Space behavior.
- Timeline ordering parity against work-experience chronology.
- If any item fails, include minimal repro steps and keep task open.
3. Prepare compliant `build.done` summary string.
- Construct one-line payload covering every required field in the contract.
- Example shape (statuses illustrative only):
- `tests: pass, lint: pass, typecheck: pass, audit: not-configured, coverage: not-configured, complexity: not-configured, duplication: not-configured, performance: optional, specs: optional`
### Acceptance checks (task-local)
- `.ralph/review.md` contains dated manual verification notes for all required interaction categories.
- Backpressure command outcomes are explicitly documented (pass/fail/not-configured).
- `build.done` payload draft includes every required field and uses no missing keys.
- No source feature code changes are introduced in this task.
- 2026-02-16: Completed Task D (`task-1771246519-fd59`).
- Added a dated backpressure/manual-evidence addendum to `.ralph/review.md` with explicit outcomes for lint/typecheck/build/audit.
- Documented required `build.done` field statuses with no omitted keys:
- `tests: not-configured, lint: pass, typecheck: pass, audit: pass, coverage: not-configured, complexity: not-configured, duplication: not-configured, performance: not-configured, specs: not-configured`
- Confirmed this iteration was evidence-only (no `src/` feature edits) and preserved existing reviewer manual-interaction validation record.
## Atomic Execution Plan: task-1771246519-92f0 (Timeline Ordering Parity + Token Alignment)
### Scope for this execution
- Primary files: `src/components/TimelineInterventionsSubsection.tsx`, `src/components/DashboardLayout.tsx`, `src/data/timeline.ts`
- Secondary files (only if needed to remove remaining invalid token usage in timeline paths): `src/components/WorkExperienceSubsection.tsx`, `src/index.css`
- Explicitly out of scope: pointer/focus architecture changes in `CareerConstellation` unless a regression fix is strictly required.
### Current residual gaps (post Task B/D)
- `TimelineInterventionsSubsection` still opens detail panels through `consultations` compatibility import instead of canonical timeline-derived exports.
- `DashboardLayout` still uses `consultations` for role click resolution and "Last Consultation" content derivation (`consultations[0]`), which leaves chronology semantics coupled to a compatibility layer rather than explicit career timeline selectors.
- Timeline-adjacent components still contain invalid token references (`fontFamily: 'var(--font-mono)'`) despite canonical mono tokens being `--font-geist-mono` / `--font-mono-dashboard`.
- Legacy duplicate path `WorkExperienceSubsection` remains in repo and still carries `var(--font-mono)` usage; while currently not mounted, leaving unresolved token drift risks reintroducing inconsistency if re-enabled.
### Implementation steps for builder
1. Align timeline detail-panel lookups to canonical timeline exports.
- File: `src/components/TimelineInterventionsSubsection.tsx`
- Replace `consultations` import/lookup with canonical timeline-derived source (`timelineConsultations` or direct mapping from `timelineCareerEntities`).
- Preserve behavior: only career entities open `career-role` panel payloads, and non-career entries safely no-op for role panel opening.
2. Enforce explicit career-order source in dashboard chronology controls.
- File: `src/components/DashboardLayout.tsx`
- Replace compatibility-layer lookups for:
- role click (`handleRoleClick`)
- last-consultation summary source (`consultations[0]`)
with canonical career timeline ordering (`timelineCareerEntities` + deterministic consultation mapping).
- Ensure "Most recent role" reflects the first canonical career entity by sorted timeline order, matching constellation role chronology.
3. Complete mono token cleanup for chart/timeline-adjacent UI.
- Files: `src/components/TimelineInterventionsSubsection.tsx`, `src/components/WorkExperienceSubsection.tsx` (if retained), optional `src/index.css`
- Replace `var(--font-mono)` usage with canonical mono token (`var(--font-geist-mono)` or `var(--font-mono-dashboard)`), avoiding introduction of new ad-hoc token names.
- Keep UI/body text tokens unchanged (no redesign).
4. Clarify legacy/duplicate timeline path handling.
- File: `src/components/WorkExperienceSubsection.tsx` (and/or `.ralph/review.md` note)
- Choose one minimal path and document it:
- either normalize remaining tokens in this unused component, or
- explicitly justify that it is unused/deprecated and excluded from runtime parity checks.
- Do not do a broad delete/refactor in this task.
5. Regression-safe validation.
- Run:
- `npm run lint`
- `npm run typecheck`
- `npm run build`
- Manual sanity checks to capture in `.ralph/review.md`:
- Timeline ordering parity: top chronology role matches top constellation role.
- Role-card hover and graph hover remain coherent after data-source alignment.
- Node hover over fill area remains reliable (no regression of Task B fix).
- Last consultation card reflects canonical latest career entry.
### Acceptance checks (task-local)
- No chart/timeline-adjacent component references `var(--font-mono)`.
- Timeline and dashboard role-detail lookups use canonical timeline career sources, not legacy compatibility imports in component logic.
- Latest-role summary and chronology ordering are consistent with `timelineCareerEntities` ordering semantics.
- Hover/focus interaction behavior from Task B remains intact.
- `npm run lint`, `npm run typecheck`, and `npm run build` pass.
### Handoff note to builder
- Keep this patch data-source/token focused; avoid reworking D3 forces or node event wiring unless a direct regression is detected.
- If a legacy path is left in place, add explicit rationale in `.ralph/review.md` so success criterion "resolved or clearly justified" is satisfied.
- 2026-02-16: Completed Task C (`task-1771246519-92f0`).
- Updated `src/components/TimelineInterventionsSubsection.tsx` to use canonical `timelineConsultations` lookup for role detail-panel opening instead of legacy `consultations` import.
- Updated `src/components/DashboardLayout.tsx` to source "Last Consultation" and role-click resolution from canonical `timelineConsultations` (including memoized id map) to align chronology semantics with career timeline selectors.
- Replaced remaining `var(--font-mono)` usage in timeline-adjacent components with canonical `var(--font-geist-mono)`:
- `src/components/TimelineInterventionsSubsection.tsx`
- `src/components/WorkExperienceSubsection.tsx` (legacy path retained, token-normalized to prevent style drift if re-enabled).
- Validation: `npm run lint` (pass, 2 existing warnings), `npm run typecheck` (pass), `npm run build` (pass).
## Atomic Execution Plan: task-1771247453-c78f (Resolve build.blocked Backpressure Gate)
### Scope for this execution
- Primary files: `.ralph/review.md`, `.ralph/plan.md` (progress note only if needed)
- Event output: one compliant `build.done` payload from builder after evidence capture
- Explicitly out of scope: `src/` feature changes (only revisit if a gate fails and fix is required)
### Why this task is open
- Runtime queue indicates `build.blocked` still pending even though prior remediation and checks were completed.
- The required closure path is a builder pass that reasserts gate evidence and emits a `build.done` payload with all mandatory fields present.
### Builder steps
1. Re-run required gates in current workspace state.
- `npm run lint`
- `npm run typecheck`
- `npm run build`
- `npm audit --omit=dev --json`
2. Reconcile optional/non-configured gates from repository tooling.
- Confirm presence/absence of scripts/tooling for:
- `tests`
- `coverage`
- `complexity`
- `duplication`
- optional `performance`
- optional `specs`
- If absent, report `not-configured` (do not omit keys).
3. Update `.ralph/review.md` with dated backpressure evidence.
- Include command outcomes and any caveats (for example, lint warnings vs errors).
- Include explicit line-item statuses for every required `build.done` field.
4. Emit one compliant `build.done` payload.
- Required key set (no omissions):
- `tests`, `lint`, `typecheck`, `audit`, `coverage`, `complexity`, `duplication`
- Optional keys when tracked:
- `performance`, `specs`
- Example payload shape:
- `tests: not-configured, lint: pass, typecheck: pass, audit: pass, coverage: not-configured, complexity: not-configured, duplication: not-configured, performance: not-configured, specs: not-configured`
### Acceptance checks (task-local)
- Required commands executed and outcomes recorded.
- `.ralph/review.md` contains a fresh dated evidence entry for this closure pass.
- `build.done` emitted with full required key contract (and optional keys included if reported).
- No unrelated feature/refactor edits are introduced.
- 2026-02-16T13:12:56Z: Completed Task `task-1771247453-c78f` (resolve `build.blocked` backpressure gate).
- Re-ran required gates in current workspace state: `npm run lint`, `npm run typecheck`, `npm run build`, `npm audit --omit=dev --json`.
- Confirmed required contract field statuses for next `build.done` payload (including explicit `not-configured` entries for unavailable gates).
- Updated `.ralph/review.md` with fresh dated evidence addendum for closure.
- No `src/` implementation edits required; objective remains satisfied from prior completed remediation tasks.