Fantasy-Map-Generator/_bmad-output/implementation-artifacts/epic-2-retro-2026-03-12.md
Azgaar 1c1d97b8e2 feat: Update sprint status and complete Epic 2 tasks
- Mark Epic 2 as done and update related stories to reflect completion.
- Add Epic 2 retrospective document detailing team performance, metrics, and insights.
- Enhance draw-relief-icons.ts to include parentEl parameter in drawRelief function.
- Introduce performance measurement scripts for WebGL and SVG rendering comparisons.
- Add benchmarks for geometry building in draw-relief-icons.
2026-03-12 15:43:19 +01:00

15 KiB

Epic 2 Retrospective — Relief Icons Layer Migration

Date: 2026-03-12 Facilitator: Bob 🏃 (Scrum Master) Project Lead: Azgaar Epic: 2 — Relief Icons Layer Migration Status at Retro: 1/3 stories formally done; 2/3 in review (dev complete, code review pending)


Team Participants

Agent Role
Bob 🏃 Scrum Master (facilitating)
Amelia 💻 Developer (Claude Sonnet 4.5 / 4.6)
Quinn 🧪 QA Engineer
Winston 🏗️ Architect
Alice 📊 Product Owner
Azgaar Project Lead

Epic 2 Summary

Delivery Metrics

Metric Value
Stories completed (formally done) 1/3
Stories dev-complete (in review) 2/3 — 2-2, 2-3
Blockers encountered 0
Production incidents 0
Technical debt items 1 — T11 manual smoke test deferred from Story 2-2
Test coverage at epic end 88.51% (was 85.13% entering epic)
Total tests at epic end 43 (was 34 entering epic)
Lint errors 0 across all three stories

FRs Addressed

FR Description Status
FR12 Instanced relief rendering in single GPU draw call Story 2-2
FR13 Position icons at SVG-space terrain cell coordinates Story 2-2
FR14 Scale icons by zoom level and user scale setting Story 2-2
FR15 Per-icon rotation from terrain dataset Story 2-1 (verified: no rotation field; zero rotation is correct)
FR16 Configurable opacity Story 2-2
FR17 Re-render on terrain dataset change Story 2-2
FR18 WebGL2 detection and automatic SVG fallback Stories 2-2, 2-3
FR19 SVG fallback visual parity Story 2-3 (structural verification)
FR20 No WebGL canvas intercepting pointer events Epic 1 / Story 2-2
FR21 Existing Layers panel controls unchanged Story 2-2

NFRs Addressed

NFR Description Status
NFR-B1 Named Three.js imports only Story 2-2
NFR-M5 ≥80% Vitest coverage 88.51%
NFR-C1 WebGL2 sole gating check Story 2-3
NFR-C4 Hardware acceleration disabled = SVG fallback Story 2-3
NFR-P1 <16ms render (1,000 icons) ⚠️ Implemented; browser measurement deferred to Story 3-1
NFR-P2 <100ms render (10,000 icons) ⚠️ Implemented; browser measurement deferred to Story 3-1

Story-by-Story Analysis

Story 2-1: Verify and Implement Per-Icon Rotation in buildSetMesh

Agent: Claude Sonnet 4.5 Status: done Pattern: Investigation-first story — verify before coding

What went well:

  • Perfect execution of the investigate-first pattern. Hypothesis (r.i might be rotation) confirmed false in one pass.
  • Verification comment added to buildSetMesh creates a permanent, documented decision trail.
  • Zero code churn. AC2 was correctly identified as N/A without second-guessing.
  • npm run lintChecked 80 files in 98ms. No fixes applied.

No struggles: Clean from start to finish.

Key artifact: FR15 verification comment in buildSetMesh documenting that r.i is a sequential index, not a rotation angle, and that both WebGL and SVG paths produce unrotated icons — visual parity confirmed by shared code path.


Story 2-2: Refactor draw-relief-icons.ts to Use Framework

Agent: Claude Sonnet 4.6 Status: review (dev complete)

What went well:

  • Biome import ordering auto-fix was handled correctly — recognized as cosmetic-only, not flagged as a bug.
  • Discovery of GPU leak pattern: buildReliefScene traverses and disposes geometry before terrainGroup.clear() — not in the spec, found empirically, fixed correctly. Prevents silent GPU memory accumulation on repeated drawRelief() calls.
  • preloadTextures() moved into setup() callback — arguably more correct than module-load-time preloading (textures load when the framework is ready, not at import).
  • Anisotropy line removal was clean — explanatory comment documents the renderer ownership transfer.
  • All 34 existing framework tests pass unaffected

Struggles:

  • None during implementation. One optional item (T11) was deferred.

Technical debt incurred:

  • T11 (medium priority, HIGH impact on Epic 3): Browser smoke test — load map, render relief icons, toggle layer, pan/zoom, measure render time. Deferred as "optional" in Story 2-2. This is the prerequisite for Story 3-1's benchmarking.

Key decisions:

  • lastBuiltIcons/lastBuiltSet reset to null in undrawRelief — prevents stale memoization after group.clear().
  • drawSvg(icons, parentEl) called for both type === "svg" and hasFallback === true — same code path, guaranteed visual parity.

Story 2-3: WebGL2 Fallback Integration Verification

Agent: Claude Sonnet 4.6 Status: review (dev complete)

What went well:

  • No duplication of existing tests — developer read the test file before writing new ones. All 9 new tests are genuinely novel.
  • Node env constraint correctly identified and handled: vi.stubGlobal("requestAnimationFrame", vi.fn()) pattern discovered independently (same pattern used in Story 1.3).
  • Coverage increase from 85.13% → 88.51% (+3.38%) from fallback branch coverage.
  • AC4 visual parity verified structurally with sound reasoning: drawSvg() is unchanged; same code path = identical output.

Struggles:

  • Initial requestRender() test attempted vi.spyOn(globalThis, "requestAnimationFrame") which fails in node env. Self-corrected to vi.stubGlobal. Good problem-solving.

Deferred (T5): Integration test for window.drawRelief() SVG output when hasFallback=true — skipped due to node env (pack globals, DOM requirements). Documented with clear rationale.

Final counts: 43 tests total (+9 new), 88.51% statement coverage.


Cross-Story Patterns

Pattern 1 — Investigation-before-implementation (All 3 stories)

Every story began by reading existing code before writing new code:

  • Story 2-1: verified r.i before deciding whether to implement rotation
  • Story 2-2: confirmed buildSetMesh findings from 2-1 still held before proceeding
  • Story 2-3: read full test file before writing any new tests

Team verdict: This is a strength. Official team practice going forward.

⚠️ Pattern 2 — Node-only Vitest environment as recurring constraint (Stories 2-2, 2-3)

Both stories deferred important verification because the unit test environment has no DOM, no pack globals, and no real WebGL context. Story 3-1 is a browser-only story — this pattern will surface again.

Team verdict: Known constraint, documented. Story 3-1 scope includes browser harness decision.

Pattern 3 — Transparent documentation of deferred work (Both deferring stories)

Both deferrals (T11 in 2-2, T5 in 2-3) are clearly documented with explicit reasoning in completion notes. No hidden debt.

Team verdict: Healthy habit. Explicit "deferred to story X" annotation should be formalized.


Previous Epic Retrospective

No Epic 1 retrospective exists. This is the first retrospective for the Fantasy-Map-Generator project.

Note: Epic 1's retrospective status in sprint-status.yaml remains optional. If desired, a retro for Epic 1 can be run separately.


Next Epic Preview: Epic 3 — Quality & Bundle Integrity

Stories: 3-1 Performance Benchmarking, 3-2 Bundle Size Audit (both ready-for-dev)

Dependencies on Epic 2

Epic 3 Story Depends On Status
3-1 Performance Benchmarking Relief layer rendering in browser from 2-2 ⚠️ T11 smoke test pending
3-1 Performance Benchmarking window.drawRelief() callable 2-2 complete
3-2 Bundle Size Audit Named Three.js imports from 2-2 2-2 complete
3-2 Bundle Size Audit vite build clean lint passes

Key Insight

Story 2-2's deferred T11 (browser smoke test) and Story 3-1's benchmarking overlap naturally. Story 3-1 should begin with the T11 verification items as pre-benchmark confirmation steps.

Story 3-2 Independence

Story 3-2 (Bundle Size Audit) has no dependency on Story 3-1 or on T11. It can begin immediately once Stories 2-2 and 2-3 code reviews are complete.


Significant Discovery Assessment

No significant discoveries requiring Epic 3 plan changes. The architecture is sound, the named import refactor (NFR-B1) is done, fallback is tested, and Epic 3's premise is validated.

The only course-correction needed is scoping: Story 3-1 should explicitly include T11 smoke test items.


Action Items

Process Improvements

# Action Owner Success Criteria
P1 Update story template: deferred tasks must annotate "Deferred to: [story X]" Bob 🏃 (SM) Template updated before creating Story 3-1
P2 Document known node-env Vitest constraint in story template dev notes section Paige 📚 (Tech Writer) One-line note: "Vitest: no DOM, no pack globals, no real WebGL"

Technical Debt

# Item Owner Priority
D1 T11 browser smoke test from Story 2-2 — manual verification of icons render, layer toggle, pan/zoom Amelia 💻 HIGH — subsumed into Story 3-1 scope

Team Agreements

  1. Verify-before-implement is official practice — every story where implementation could be skipped must confirm first
  2. Deferred tasks always annotate the receiving story ("Deferred to: Story X-Y")
  3. Node env constraint is documented once in the story template — not re-discovered per story

Epic 3 Preparation Tasks

Critical (block Epic 3 start)

  • Complete formal code review for Story 2-2 → mark done Owner: Azgaar (Project Lead)

  • Complete formal code review for Story 2-3 → mark done Owner: Azgaar (Project Lead)

  • Determine Story 3-1 browser test approach: Playwright (existing config at playwright.config.ts) vs. manual DevTools Owner: Quinn 🧪 (QA)

Parallel (can start now)

  • Story 3-2 (Bundle Size Audit) — no blocking dependencies Owner: Amelia 💻

Story 3-1 Scope Enhancement (SM action when creating story)

  • Add T11 items from Story 2-2 to Story 3-1 as pre-benchmark verification steps Owner: Bob 🏃 (SM — add when creating Story 3-1)

Critical Path

  1. → Code review Stories 2-2 and 2-3 → done (Azgaar)
  2. → Create Story 3-1 with T11 items folded in (Bob SM)
  3. → Story 3-2 runs in parallel (Amelia Dev)

Readiness Assessment

Dimension Status Notes
Testing & Quality Green 43 tests, 88.51% coverage, lint clean
Browser Verification ⚠️ Pending T11 smoke test — folded into Story 3-1
Deployment N/A Development project
Stakeholder Acceptance Single-developer project — retrospective is acceptance
Technical Health 🟢 Clean Named imports, GPU leak fixed, fallback tested
Unresolved Blockers None Code review is a process gate, not a blocker

Key Takeaways

  1. Investigate-first discipline prevents phantom implementations. FR15 rotation was verified absent rather than implemented speculatively — saved real complexity.
  2. The node-only test environment is a known, documented constraint — not a surprise, not a failure. Epic 3 Story 3-1 is the natural home for browser-level verification.
  3. Unscoped quality improvements happen when stories are well-understood. The GPU leak fix in buildReliefScene wasn't specced — it was discovered and fixed correctly by an engaged developer.
  4. Transparent deferral documentation is the team's strongest quality habit. Nothing was buried.

Commitments

  • Action Items: 2
  • Preparation Tasks: 3 critical, 2 parallel
  • Critical Path Items: 2 code reviews
  • Team Agreements: 3

Next Steps

  1. Code review Stories 2-2 and 2-3 (Azgaar)
  2. Create Story 3-1 with T11 items (Bob SM — use create-story)
  3. Story 3-2 ready to kick off in parallel
  4. No Epic 3 plan changes required — proceed when code reviews are done

Retrospective facilitated by Bob 🏃 (Scrum Master) · Fantasy-Map-Generator Project · 2026-03-12