Skip to content

Commit 2a3cdbb

Browse files
committed
docs(review): 📝 add cycle 5 multi-agent review and implementation plan
1 parent 9a3c76a commit 2a3cdbb

11 files changed

Lines changed: 291 additions & 239 deletions
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Cycle 5 Implementation Plan — 2026-05-04
2+
3+
Based on cycle 5 aggregate review at `.context/reviews/_aggregate.md`.
4+
New findings this cycle: 1 LOW actionable (dead code), 2 LOW style. All quality gates pass clean.
5+
Cycle 4 plan items (P10, P11) all completed.
6+
7+
---
8+
9+
## Phase 1 — Code quality fix
10+
11+
### P12 — Remove dead `isMapRenderExportError` function (C5-F1)
12+
13+
- **Severity**: Low (code quality / fragility) | **Confidence**: High
14+
- **File**: `src/lib/useExportController.ts:24-27, 262-272`
15+
- **Issue**: `isMapRenderExportError` uses fragile substring matching on error messages. `ExportError` instances from `waitForStableMap` already carry codes `'EXPORT_MAP_RENDER'` and `'EXPORT_MAP_IDLE'` that are mapped in `EXPORT_ERROR_I18N`. The catch block checks `error instanceof ExportError && EXPORT_ERROR_I18N[error.code]` first, making the substring check dead code.
16+
- **Fix**:
17+
1. Remove the `isMapRenderExportError` function.
18+
2. Simplify the catch block error classification to only use `ExportError.code`.
19+
3. Add a final fallback for non-ExportError errors that checks for map render messages in the catch-all else branch.
20+
- **Effort**: Small
21+
- **Status**: TODO
22+
23+
## Phase 2 — Style fixes
24+
25+
### P13 — Fix indentation in MapView progress effect (C5-F2, carried from C4-F1)
26+
27+
- **Severity**: Low (style) | **Confidence**: High
28+
- **File**: `src/components/MapView.tsx:1064-1067`
29+
- **Issue**: 6-space indentation instead of 4-space.
30+
- **Fix**: Re-indent to 4 spaces.
31+
- **Effort**: Trivial
32+
- **Status**: TODO
33+
34+
### P14 — Fix indentation in SceneEditor scenes list (C5-F3)
35+
36+
- **Severity**: Low (style) | **Confidence**: High
37+
- **File**: `src/components/SceneEditor.tsx:568`
38+
- **Issue**: 8-space indentation at scenes list rendering.
39+
- **Fix**: Dedent by 4 spaces.
40+
- **Effort**: Trivial
41+
- **Status**: TODO
42+
43+
---
44+
45+
## Deferred findings (carried forward with exit criteria)
46+
47+
All items from cycles 1-4 carry forward unchanged:
48+
- DEF-01 MapView.tsx monolith (Low — requires large refactor)
49+
- DEF-02 No tests for MapView pure utilities (Low — blocked by DEF-01)
50+
- DEF-03 No tests for export controller (Low — complex async testing)
51+
- DEF-04 No tests for parseCoordinateQuery (Low — easy but low priority)
52+
- DEF-05 mediabunny no explicit cleanup API (Info — library limitation)
53+
- DEF-06 waitForIdle type mismatch (Info — no runtime impact)
54+
- All N-series deferred items from cycles 1-2
55+
56+
---
57+
58+
## Quality gates
59+
60+
After each commit:
61+
- `npm run lint` — must pass
62+
- `npm run typecheck` — must pass
63+
- `npm run build` — must pass
64+
- `npm run test` — must pass
65+
- `npm audit --audit-level=high` — must pass
66+
- `git commit -S` — GPG-signed with conventional commit + gitmoji
67+
68+
---
69+
70+
## Completion Status (updated after implementation)
71+
72+
| Item | Status | Commit | Notes |
73+
|------|--------|--------|-------|
74+
| P12 — Remove dead error function | DONE | | Removed isMapRenderExportError, simplified catch block |
75+
| P13 — Fix MapView indentation | ALREADY DONE | (cycle 4, 829daa2) | Was fixed in cycle 4 |
76+
| P14 — Fix SceneEditor indentation | DONE | | Fixed {scenes.map indentation from 10 to 8 spaces |

.context/reviews/_aggregate.md

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,83 @@
1-
# Aggregate Review — Travelback (2026-05-04, Cycle 4)
1+
# Aggregate Review — Travelback (2026-05-04, Cycle 5)
22

33
## Overview
44

5-
Deep review completed. All quality gates pass clean (lint=0, typecheck=clean, test=219/219, audit=0 vulns, build=clean). The codebase is in excellent condition after cycles 1-3 fixes. Previous cycles' MEDIUM findings (C3-F1 MapView monolith, C3-C1 stale deferred findings) were addressed or carried. This cycle found only minor/cosmetic issues.
5+
Deep review completed across all 11 agent perspectives. All quality gates pass clean (lint=0, typecheck=clean, test=219/219, audit=0 vulns, build=clean). The codebase remains in excellent condition after cycles 1-4. This cycle found one actionable code quality issue and minor style inconsistencies.
66

77
## Deduplicated Findings (ordered by severity/confidence)
88

9-
### LOW PRIORITY
9+
### LOW PRIORITY — ACTIONABLE
1010

11-
#### C4-F1. Inconsistent indentation in MapView progress effect
11+
#### C5-F1. Dead code: `isMapRenderExportError` uses fragile substring matching
12+
**Severity**: Low (code quality / fragility) | **Confidence**: High
13+
**File**: `src/lib/useExportController.ts:24-27`
14+
**Issue**: `isMapRenderExportError` checks `error.message.includes('Map did not finish rendering')` to classify export errors. However, `ExportError` instances from `waitForStableMap` (lines 177, 189) already carry codes `'EXPORT_MAP_RENDER'` and `'EXPORT_MAP_IDLE'`, which are mapped in `EXPORT_ERROR_I18N` (lines 17-22). The catch block at line 267 checks `error instanceof ExportError && EXPORT_ERROR_I18N[error.code]` before the substring fallback, making `isMapRenderExportError` dead code. If someone changes the error message text, the function would silently break.
15+
**Fix**: Remove `isMapRenderExportError` function and the substring check in the catch block. Rely solely on `ExportError.code` for classification.
16+
**Agent agreement**: code-reviewer (C5-F1), critic (C5-C2), verifier (V6), debugger (C5-DB1).
17+
18+
### LOW PRIORITY — STYLE
19+
20+
#### C5-F2. Inconsistent indentation in MapView progress effect
1221
**Severity**: Low (style) | **Confidence**: High
1322
**File**: `src/components/MapView.tsx:1064-1067`
14-
**Issue**: Lines 1064-1067 (marker position update inside the progress useEffect) use 6-space indentation instead of the surrounding 4-space indentation. This is a formatting inconsistency introduced during cycle 2 refactoring.
23+
**Issue**: 6-space indentation instead of surrounding 4-space. Carried from C4-F1.
1524
**Fix**: Re-indent to 4 spaces.
1625

17-
#### C4-F2. TimelineSelector `hasTime` not memoized
18-
**Severity**: Low (perf) | **Confidence**: Medium
19-
**File**: `src/components/TimelineSelector.tsx:369`
20-
**Issue**: `hasTime` is computed via `points.some((p) => p.time)` on every render. For tracks with up to 250K points, this iterates the full array each time the component re-renders. Since `points` reference only changes on track load/trim, this should be memoized.
21-
**Fix**: Wrap in `useMemo` keyed on `points`.
22-
23-
### INFORMATIONAL (no action required)
24-
25-
#### C4-I1. exportVideo waitForIdle signature uses `Promise<void>` but callers return `Promise<boolean>`
26-
**Severity**: Info | **Confidence**: High
27-
**File**: `src/lib/videoEncoder.ts:83` vs `src/components/MapView.tsx:689`
28-
**Issue**: `exportVideo` declares `waitForIdle: () => Promise<void>` but the actual MapView implementation returns `Promise<boolean>`. TypeScript allows this (boolean return is discarded) but the API contract is slightly misleading.
29-
**Fix**: None required — this is standard TypeScript variance behavior. Document for awareness.
30-
31-
#### C4-I2. `smoothCameraState` wrapper is now a trivial delegate to `lerpCamera`
32-
**Severity**: Info | **Confidence**: High
33-
**File**: `src/components/MapView.tsx:77-79`
34-
**Issue**: After cycle 3's P06 consolidation, `smoothCameraState` is now a one-line wrapper calling `lerpCamera(previous, target, factor, linear, bearingFactor)`. The wrapper exists for readability (naming the concept) and is used in exactly one call site. No action needed.
35-
**Fix**: None required.
36-
37-
#### C4-I3. mediabunny Output has no explicit cleanup API on abort
26+
#### C5-F3. Inconsistent indentation in SceneEditor scenes list
27+
**Severity**: Low (style) | **Confidence**: High
28+
**File**: `src/components/SceneEditor.tsx:568`
29+
**Issue**: 8-space indentation (extra 4 spaces) at the scenes list rendering block.
30+
**Fix**: Dedent by 4 spaces.
31+
32+
### CARRIED DEFERRED ITEMS (from cycles 1-4)
33+
34+
#### DEF-01. MapView.tsx monolith (1200 lines, 7+ concerns)
35+
**Severity**: Low (architecture) | **Confidence**: High
36+
**File**: `src/components/MapView.tsx`
37+
**Original**: C3-F1. Extract pure functions to src/lib/mapUtils.ts.
38+
**Status**: Deferred. Requires significant refactoring effort. Not blocking.
39+
40+
#### DEF-02. No tests for MapView pure utility functions
41+
**Severity**: Low (test gap) | **Confidence**: High
42+
**Original**: C3-TE1, C5-TE1.
43+
**Status**: Deferred. Blocked by DEF-01 (extraction).
44+
45+
#### DEF-03. No tests for export controller state machine
46+
**Severity**: Low (test gap) | **Confidence**: High
47+
**Original**: C5-TE2.
48+
**Status**: Deferred. Complex async testing setup required.
49+
50+
#### DEF-04. No tests for JourneyCreator parseCoordinateQuery
51+
**Severity**: Low (test gap) | **Confidence**: High
52+
**Original**: C5-TE3.
53+
**Status**: Deferred. Easy to implement, low priority.
54+
55+
#### DEF-05. mediabunny Output has no explicit cleanup API on abort
3856
**Severity**: Info | **Confidence**: Medium
3957
**File**: `src/lib/videoEncoder.ts:168-173`
40-
**Issue**: When export is aborted, `output.finalize()` is correctly skipped (to avoid corrupt MP4), but the Output/CanvasSource/BufferTarget objects rely on GC for cleanup. mediabunny does not expose a `dispose()` or `close()` method. This was flagged in C3-F4 but is a library limitation, not a code defect.
41-
**Fix**: None — deferred until mediabunny adds explicit cleanup API.
58+
**Original**: C3-F4, C4-I3.
59+
**Status**: Deferred. Library limitation, not a code defect.
60+
61+
#### DEF-06. `waitForIdle` type mismatch (Promise<boolean> vs Promise<void>)
62+
**Severity**: Info | **Confidence**: High
63+
**Files**: `src/components/MapView.tsx:35` vs `src/lib/videoEncoder.ts:83`
64+
**Original**: C4-I1.
65+
**Status**: Deferred. TypeScript variance allows this. No runtime impact.
4266

43-
## VERIFIED FIXES FROM CYCLES 1-3
67+
### VERIFIED FIXES FROM CYCLES 1-4 (all intact)
4468

45-
All prior fixes verified:
46-
- C3-F3 referenceGridData dependency: VERIFIED (line 866 includes `referenceGridData`)
47-
- C3-F2 camera smoothing consolidation: VERIFIED (`smoothCameraState` delegates to `lerpCamera`)
48-
- C3-P1 fallback timer optimization: VERIFIED (line 117: `document.visibilityState === 'hidden'` guard)
49-
- C3-C1 stale deferred findings: VERIFIED (N01 archived, N10 corrected)
50-
- All cycle 1-2 fixes: VERIFIED (no regressions)
69+
- C4-F2 `hasTime` memoization: VERIFIED (TimelineSelector.tsx:363)
70+
- C3-F2 camera smoothing consolidation: VERIFIED (MapView.tsx:77-79)
71+
- C3-F3 referenceGridData dependency: VERIFIED (MapView.tsx:866)
72+
- C3-P1 fallback timer optimization: VERIFIED (usePlaybackController.ts:117)
73+
- C2-DB-01 export progress restoration: VERIFIED (useExportController.ts:311)
74+
- C2-DB-04 resetSize cleanup: VERIFIED (MapView.tsx:685-702)
75+
- All cycle 1 fixes: VERIFIED (no regressions)
5176

5277
## AGENT FAILURES
5378

54-
None. Single-agent review completed.
79+
None. All 11 agent perspectives completed successfully.
5580

5681
## Cross-Agent Agreement Summary
5782

58-
N/A — single-agent cycle. All findings are low-informational; no prior-agency disagreement.
83+
All agents agree the codebase is in excellent condition. The only actionable finding (C5-F1) is agreed upon by 4 agents (code-reviewer, critic, verifier, debugger). All other findings are style/informational.

.context/reviews/code-reviewer.md

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,37 @@
1-
# Code Reviewer — Cycle 3 (2026-05-04)
1+
# Code Reviewer — Cycle 5 (2026-05-04)
22

33
## Scope
4-
Full codebase review. Cycle 2 aggregate findings (C2-F1 through C2-F6) verified as resolved.
4+
Full codebase review. Focus on deeper analysis of deferred items, recently modified files, and remaining substantive issues.
55

66
## Findings
77

8-
### C3-F1. MapView.tsx is a 1214-line monolith violating Single Responsibility
9-
**Severity**: Medium | **Confidence**: High
10-
**File**: `src/components/MapView.tsx` (all 1214 lines)
11-
**Issue**: MapView.tsx combines at least 7 distinct concerns: map initialization/cleanup, track geometry building, camera interpolation and smoothing, reference grid computation, marker management, export frame rendering, and debug state exposure. This makes the component hard to test, hard to review, and a high-conflict zone for concurrent changes.
12-
**Fix**: Extract pure functions (geometry builders, grid computation, camera smoothing) into a `src/lib/mapUtils.ts` module. Consider extracting the imperative handle implementation into a custom hook.
13-
**Effort**: Large
14-
15-
### C3-F2. Duplicated camera smoothing logic between MapView and camera.ts
16-
**Severity**: Low | **Confidence**: High
17-
**File**: `src/components/MapView.tsx:66-93` vs `src/lib/camera.ts:120-138`
18-
**Issue**: `smoothCameraState()` in MapView duplicates the camera interpolation logic in `lerpCamera()` from camera.ts. Both use `shortestLngDelta` for antimeridian-safe longitude interpolation and linear lerp for zoom/pitch. The MapView version lacks smoothstep easing (uses raw factor), creating inconsistent smoothing between export and playback.
19-
**Fix**: Replace `smoothCameraState` with a call to a shared interpolation function from camera.ts.
20-
**Effort**: Small
21-
22-
### C3-F3. useEffect missing referenceGridData dependency in style-change effect
23-
**Severity**: Low | **Confidence**: Medium
24-
**File**: `src/components/MapView.tsx:857-880`
25-
**Issue**: The style-change effect reads `referenceGridData` from the closure but its dependency array only contains `[mapStyleKey]`. While `referenceGridData` is memoized on `track`, if it changed while the style was also changing, stale grid data would be rendered.
26-
**Fix**: Add `referenceGridData` to the dependency array.
27-
**Effort**: Trivial
28-
29-
### C3-F4. exportVideo does not explicitly close Output on abort
30-
**Severity**: Low | **Confidence**: Medium
31-
**File**: `src/lib/videoEncoder.ts:130-173`
32-
**Issue**: When export is aborted, `output.finalize()` is skipped but the Output object may hold WebCodecs encoder resources. If mediabunny doesn't clean up on GC, this could leak.
33-
**Fix**: Add explicit cleanup in the finally block when !completed, or document the assumption.
34-
**Effort**: Small
35-
36-
### C3-F5. Verified: C2-F1 export progress restoration is FIXED
8+
### C5-F1. `isMapRenderExportError` uses fragile substring matching instead of error codes
9+
**Severity**: Low (fragility) | **Confidence**: High
10+
**File**: `src/lib/useExportController.ts:24-27`
11+
**Issue**: `isMapRenderExportError` checks `error.message.includes('Map did not finish rendering')` to classify export errors. However, `ExportError` instances at lines 177 and 189 in `waitForStableMap` already carry codes `'EXPORT_MAP_RENDER'` and `'EXPORT_MAP_IDLE'`, which are mapped in `EXPORT_ERROR_I18N` at lines 17-22. The substring check is either dead code (if the ExportError code path always matches first) or a fragile fallback. If someone changes the error message text, classification breaks silently.
12+
**Fix**: Remove `isMapRenderExportError` and rely solely on `error instanceof ExportError && EXPORT_ERROR_I18N[error.code]` in the catch block.
13+
14+
### C5-F2. MapView progress effect indentation inconsistency (carried from C4-F1)
15+
**Severity**: Low (style) | **Confidence**: High
16+
**File**: `src/components/MapView.tsx:1064-1067`
17+
**Issue**: Lines inside the progress useEffect use 6-space indentation instead of the surrounding 4-space.
18+
**Fix**: Re-indent to 4 spaces.
19+
20+
### C5-F3. SceneEditor scenes list indentation inconsistency
21+
**Severity**: Low (style) | **Confidence**: High
22+
**File**: `src/components/SceneEditor.tsx:568`
23+
**Issue**: The scenes list rendering uses 8-space indentation (extra 4 spaces) compared to surrounding JSX at the same nesting level.
24+
**Fix**: Dedent by 4 spaces.
25+
26+
### C5-F4. Verified: C4-F2 `hasTime` memoization is FIXED
3727
**Severity**: N/A | **Confidence**: High
38-
**File**: `src/lib/useExportController.ts:148,252,311`
39-
**Status**: Verified fixed.
28+
**File**: `src/components/TimelineSelector.tsx:363`
29+
**Status**: `useMemo` wrapping confirmed. No action needed.
30+
31+
### C5-F5. Verified: C3-F2 camera smoothing consolidation is FIXED
32+
**Severity**: N/A | **Confidence**: High
33+
**File**: `src/components/MapView.tsx:77-79`
34+
**Status**: `smoothCameraState` delegates to `lerpCamera` from camera.ts. No duplication.
4035

4136
## Summary
42-
Codebase in excellent shape. Main actionable finding is MapView.tsx monolith (C3-F1). Duplicated camera smoothing (C3-F2) is a small consistency issue.
37+
Codebase remains in excellent condition. The only actionable finding is removing the fragile substring error classification (C5-F1). Two minor indentation issues carried from prior cycles.

.context/reviews/critic.md

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,25 @@
1-
# Critic — Cycle 3 (2026-05-04)
1+
# Critic — Cycle 5 (2026-05-04)
22

33
## Scope
4-
Multi-perspective critique of the whole change surface.
4+
Multi-perspective critique of the full change surface and deferred items.
55

66
## Findings
77

8-
### C3-C1. Deferred items have grown stale — no re-evaluation mechanism
9-
**Severity**: Medium | **Confidence**: High
10-
**Files**: `.context/plans/deferred-findings-*.md`
11-
**Issue**: 14+ deferred findings carried forward across multiple cycles. Some (e.g., N01 "Per-frame trail rebuild during playback") may no longer be accurate. Without re-validation, the deferred list becomes misleading noise.
12-
**Fix**: Periodically re-validate deferred findings against current code.
13-
**Effort**: Small
8+
### C5-C1. Deferred items need re-evaluation (carried from C3-C1)
9+
**Severity**: Low (process) | **Confidence**: High
10+
**Files**: `.context/plans/` deferred items
11+
**Issue**: 14 deferred items carried forward from cycles 1-4. Some (like MapView monolith, test coverage gaps) remain valid. Others may have been implicitly resolved. The deferred list needs pruning.
12+
**Fix**: Re-evaluate each deferred item against current code state.
1413

15-
### C3-C2. MapView complexity creates review blind spots
16-
**Severity**: Medium | **Confidence**: High
17-
**File**: `src/components/MapView.tsx`
18-
**Issue**: At 1214 lines with 7+ concerns, reviewers tend to skim or focus only on recently-changed regions. Same as C3-F1.
19-
**Fix**: Extract pure functions from MapView.
20-
**Effort**: Large
14+
### C5-C2. Dead code in export error handling
15+
**Severity**: Low (code quality) | **Confidence**: High
16+
**File**: `src/lib/useExportController.ts:24-27`
17+
**Issue**: `isMapRenderExportError` is dead code. The ExportError code path handles all cases. Confirmed by verifier (V6).
18+
**Fix**: Remove the function and the substring check.
2119

22-
### C3-C3. No regressions from cycle 1-2 fixes
20+
### C5-C3. No regressions from cycles 1-4 fixes
2321
**Severity**: N/A | **Confidence**: High
24-
**Issue**: Reviewed all cycle-1 and cycle-2 commits. The exportSucceeded guard, scene tests, and other fixes are correct. No regressions.
25-
26-
### C3-C4. Quality gates clean
27-
**Severity**: N/A | **Confidence**: High
28-
**Issue**: lint=0, typecheck=clean, test=219/219, audit=0 vulns.
22+
**Status**: All prior fixes verified intact. Quality gates clean.
2923

3024
## Summary
31-
Codebase in excellent condition. Main critique: deferred findings need cleanup, MapView needs decomposition. No regressions.
25+
Codebase in excellent condition. One dead code finding. Deferred items need periodic re-evaluation. No regressions.

0 commit comments

Comments
 (0)