---
date: 2026-03-30
topic: "compass-trajectory-consistency"
status: draft
---

# Implementation Plan — Compass ↔ Trajectory Consistency

This plan implements the validated design (thoughts/shared/designs/2026-03-30-compass-trajectory-consistency-design.md) with the following firm constraints from the user:
- Use per-window MP-centroid party coordinates as the canonical source for components 1 & 2
- When a party has no MPs in a window, use the first chronological party vector as fallback
- **Update all callers** to the new explicit API; do NOT keep backward compatibility shims


## Goal

Make the political compass numeric values identical to trajectory centroids for SVD components 1 and 2 by passing explicit per-party (x,y) coordinates (computed from positions_by_window) to the compass renderer and updating all callers to use that API.


## Micro-tasks (ordered, small, actionable)

All tasks assume a development branch and running tests locally. Each task should be one commit.

1) Add explorer_helpers.py (pure helper)
- Create compute_party_coords(positions_by_window, party_map, window_id, fallback_party_scores=None)
- Returns (party_coords: Dict[str,(x,y)], fallback_used: Set[str])
- Unit tests: tests/test_explorer_helpers.py
- Estimate: 2.0h

2) Update explorer.py to the new strict API
- Replace _build_party_axis_figure to accept only explicit party_coords for comp_sel 1 & 2.
- Remove old polymorphic/legacy path; callers must pass party_coords or raise a clear error.
- Update rendering glue to call _build_party_axis_figure with explicit party_coords.
- Ensure hover text shows fallback notes for parties where fallback_used contains the party.
- Update/clean Streamlit caption behavior when no coords available.
- Tests: modify tests/test_explorer_chart.py to supply party_coords shape and assert behavior.
- Estimate: 4.5h

3) Update all callers across repo to pass explicit party_coords
- Grep for places that previously passed party vectors into _build_party_axis_figure or used load_party_axis_scores for compass rendering.
- Update each call site to compute party_coords via compute_party_coords, passing the fallback_party_scores (first-chronological vector) when needed.
- Caller list (non-exhaustive — verify with repo search):
  - explorer.build_svd_components_tab
  - explorer._render_party_axis_chart (if present)
  - any scripts or tests that directly call _build_party_axis_figure
- Update tests referencing legacy vector shape.
- Estimate: 3.0h

4) Add integration consistency test
- tests/test_compass_trajectory_consistency.py — synthetic positions_by_window and party_map to assert compute_party_coords equals centroid computations used by trajectories.
- Estimate: 1.0h

5) Run full test suite and fix regressions
- Run pytest; address failures introduced by strict API change.
- If other modules relied on old shape in ways not covered by tests, update them to use compute_party_coords.
- Estimate: 1.5h

6) Manual QA
- Run streamlit run explorer.py and visually verify compass tooltips and trajectories hover values match (comps 1 & 2) for several parties and windows.
- Verify fallback tooltip and logger WARN when a party uses fallback vector.
- Estimate: 1.0h

7) Commit and push (or open PR) with description:
"feat(explorer): use explicit per-party (x,y) coords from positions_by_window for compass (components 1 & 2); update callers and add tests"
- Estimate: 0.5h


## Verification commands

- Unit tests:
  - python -m pytest tests/test_explorer_helpers.py
  - python -m pytest tests/test_explorer_chart.py
  - python -m pytest tests/test_compass_trajectory_consistency.py
- Full test suite:
  - python -m pytest
- Manual UI:
  - streamlit run explorer.py


## Rollback and mitigation

- If the strict API uncovers many call sites, revert to a temporary feature branch, document call sites, and migrate them in smaller patches.
- Keep commits small and self-contained to ease review.


## Notes

- This plan follows the user's instruction to update all callers and to use the first chronological party vector as fallback.
- The helper is pure Python to keep tests simple; callers may cache if needed.
