- 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.
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.imight be rotation) confirmed false in one pass. - Verification comment added to
buildSetMeshcreates a permanent, documented decision trail. - Zero code churn. AC2 was correctly identified as N/A without second-guessing.
npm run lint→Checked 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:
buildReliefScenetraverses and disposes geometry beforeterrainGroup.clear()— not in the spec, found empirically, fixed correctly. Prevents silent GPU memory accumulation on repeateddrawRelief()calls. preloadTextures()moved intosetup()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/lastBuiltSetreset tonullinundrawRelief— prevents stale memoization aftergroup.clear().drawSvg(icons, parentEl)called for bothtype === "svg"andhasFallback === 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 attemptedvi.spyOn(globalThis, "requestAnimationFrame")which fails in node env. Self-corrected tovi.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.ibefore deciding whether to implement rotation - Story 2-2: confirmed
buildSetMeshfindings 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
- Verify-before-implement is official practice — every story where implementation could be skipped must confirm first
- Deferred tasks always annotate the receiving story ("Deferred to: Story X-Y")
- 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
doneOwner: Azgaar (Project Lead) -
Complete formal code review for Story 2-3 → mark
doneOwner: 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
- → Code review Stories 2-2 and 2-3 →
done(Azgaar) - → Create Story 3-1 with T11 items folded in (Bob SM)
- → 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
- Investigate-first discipline prevents phantom implementations. FR15 rotation was verified absent rather than implemented speculatively — saved real complexity.
- 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.
- Unscoped quality improvements happen when stories are well-understood. The GPU leak fix in
buildReliefScenewasn't specced — it was discovered and fixed correctly by an engaged developer. - 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
- Code review Stories 2-2 and 2-3 (Azgaar)
- Create Story 3-1 with T11 items (Bob SM — use
create-story) - Story 3-2 ready to kick off in parallel
- 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