Sprint: 10
Date: 2026-10-27
Facilitated by:scrum-master, per process/05_sprint_retrospective.mdInputs used:backlog/sprints/sprint-10.md, backlog/backlog.md (Sprint 10 refinement, planning, and Review outcome notes), backlog/epics/02_template_designer_gui_foundation.md, backlog/epics/04_live_preview_and_record_navigation.md, backlog/epics/06_layout_efficiency_and_operator_tooling.md, logs/technical_debt_log.md, logs/impediment_log.md, logs/process_improvement_log.md, backlog/sprints/sprint-9-retrospective.md (for follow-through check). This session had direct shell/build access throughout and ran dotnet test itself at every checkpoint.
Signals
Objective:
3/3 committed stories Done (13/13 points), sprint goal assessed “met in full” at Sprint Review (backlog/backlog.md, Sprint 10 Review outcome).
Test suite grew from 364/364 (Desktop.Tests, Sprint 9 close) to 388/388 across the sprint's three batches (+12 wrap/clip indicator tests, +12 multi-select tests, +12 alignment/distribution tests); CLI.Tests unaffected throughout at 124/124.
Two ad-hoc, non-committed items handled mid-sprint on live human product-owner feedback: (1) mid-Batch-1, adding Delete/Backspace support and correcting the resize handle to width-only; (2) between Batch 1 and Batch 2, a canvas click-smoothness regression, root-caused and fixed with disclosed before/after timing evidence (~50ms to 0.3ms per click).
Zero new impediments; the two pre-existing open ones (asset path strategy, UNC timeout/retry) remain non-blocking and untouched.
Two new technical debt items logged this sprint (both Low/Open/non-blocking): the pre-existing Address-Control-interaction-code testability gap grew further (now three features built on the untested WinForms-only side: rotation, multi-select, align/distribute); a pre-existing, unrelated GDI+ selection-highlight measurement quirk was found and disclosed rather than fixed in-scope.
Live verification spanned reflection-driven built-form harnesses with real screenshots for every GUI-touching item this sprint, including a fresh (not reused) full-form screenshot for Batch 3 per its own explicit AC.
Subjective:
The human product owner actively used the live built app between batches and surfaced two real issues immediately, both handled the same session rather than being logged for a later sprint — a fast, effective feedback loop, though it means the sprint's actual path diverged twice from its planned batch sequence.
The additive-layer design for multi-select (decided at story-writing time: extend CanvasElementEditor/TemplateCanvasControl's selection state rather than replace it) paid off exactly as intended — every pre-existing single-select code path needed zero changes, confirmed by the full test suite and live smoke passing unmodified.
Architecture reuse compounded well across the sprint: Batch 2's rotation-aware world-space AABB helper (built for rubber-band selection) was exposed and reused directly for Batch 3's alignment/distribution bounding boxes, rather than a second implementation.
When the click-smoothness regression was reported, the team went straight to direct temporary instrumentation (Stopwatch timers inserted into the suspect method, removed after) rather than reasoning from assumption — this disproved an initially plausible but wrong hypothesis (the new wrap/clip indicator's paint cost) with hard numbers before landing on the real cause.
What Went Well
Multi-select shipped as a genuinely additive layer, verified, not just designed that way on paper. The story's own conversation notes called for this explicitly; the full test suite (388/388) and live smoke both confirm every existing single-select interaction — properties panel, resize/rotate handles, address-line drill-in — works completely unchanged whenever 0 or 1 items are selected.
Root-cause-first debugging for the ad-hoc smoothness regression. Rather than guessing or re-applying the Sprint 8 fix's exact shape reflexively, the team measured first, found the initial hypothesis wrong, and kept measuring until the actual cause (an unconditional SelectionChanged raise) was confirmed with before/after numbers.
Consistent, compounding architecture reuse. The same rotation-aware bounding-box math served rubber-band selection (Batch 2) and alignment/distribution (Batch 3) without a second implementation — a direct payoff of exposing CanvasElementEditor.GetWorldBounds publicly rather than keeping it a private implementation detail of one feature.
Honest technical-debt logging continued under pressure to just move on. Two new gaps found during this sprint's own live verification — one architectural (Address-Control testability), one cosmetic (GDI+ measurement) — were logged with enough detail to act on later, rather than silently ignored or scope-crept into an unplanned fix.
What Didn't Go Well
The click-smoothness regression was, in shape, a repeat of a bug this team had already found and fixed once. Sprint 8 found and fixed “an expensive full-refresh runs on every tick of a hot mouse event” for ElementsChanged/mouse-move during a drag. This sprint's own SelectionChanged/mouse-down handler had the exact same shape of defect — an unconditional expensive refresh on a hot UI event — sitting in the very same file, and it wasn't caught by this team's own verification practices; it took the human product owner noticing a real hitch during actual use, two sprints after the sibling bug was fixed, before it was found. The fix itself was fast and well-verified once reported, but the team's own review/DoD process had no mechanism that would have caught this proactively by generalizing from the earlier, structurally identical fix.
Patterns / Insights (Prioritized)
(Team-level, real and actionable) When a performance bug is fixed because a UI event handler runs expensive work unconditionally on a hot event, check every sibling event handler on the same control for the identical shape of defect, not just re-verify the one specific gesture that was reported. Sprint 8 fixed this for OnMouseMove/ElementsChanged; the identical defect in OnMouseDown/SelectionChanged on the same control went unnoticed for two sprints until a human caught it live.
(Team-level, real and actionable) Direct temporary instrumentation (inline Stopwatch timers in the suspect method, removed once root-caused) is a fast, effective technique for a reported perf/smoothness regression — proved out this sprint after an initial plausible-sounding hypothesis was measured and disproved. Worth reaching for this before forming a hypothesis on the next such report, not only as a fallback once a first guess fails.
(Team-level, minor, tooling) A reflection-driven mouse-event harness that clicks exactly on an element's boundary corner (rather than a few points inside its box) can produce a false negative: pixel-truncation in the round-trip through integer mouse coordinates can land a fraction of a point outside a >=-style hit-test boundary. Worth a standing habit for future harness-writing: click safely inside an element's box, not on its exact edge.
Action Items (Add These To Sprint 11's Plan)
When fixing an expensive-refresh-on-a-hot-UI-event bug on any canvas control, audit every sibling event handler on that same control for the identical anti-pattern before considering the fix complete — owner: dev-team — due: ongoing, and explicitly re-checked the next time any TemplateCanvasControl mouse/key handler is touched.
When investigating a reported perf/smoothness regression, reach for direct temporary instrumentation (inline timers in the suspect code path) as a first step, not a fallback after a hypothesis fails — owner: dev-team — due: ongoing.
In reflection-driven mouse-event harnesses, click a few points inside an element's bounding box rather than exactly on its edge/corner, to avoid false negatives from pixel-truncation round-tripping — owner: dev-team — due: ongoing.
Escalate rather than defer again: actually extract TemplateCanvasControl's Address-Control-specific hit-test/drag/resize/multi-select/align state and math into a new AddressControlEditor (Desktop.Core), mirroring CanvasElementEditor's role for standalone elements. This has now been logged and consciously deferred across three features (rotation, multi-select, align/distribute) — recommend product-owner actually size and schedule this as its own story next time capacity allows, rather than continuing to note it and move on — owner: product-owner (to schedule) / dev-team (to size and build) — due: Sprint 11 backlog refinement, as a real candidate, not just a re-logged note.
Deferred / Lower-Priority Ideas
“Add an adjustable width and height with text wrapping to Address Control lines” (epic 4, 8 pts) remains the natural next epic-4 pull, deferred from Sprint 10 for exactly this reason.
“Warn on text overflow before render” (epic 4, provisional 5 pts) remains blocked on the Address Control wrap/clip story above landing first.
“Undo and redo layout changes” (epic 6, 13 pts) remains this backlog's highest-uncertainty estimate and the last story in epic 6 — a reasonable Sprint 11 candidate on its own, but not to be paired with another large/novel story per this team's established caution.
“Complete the first text-only operator workflow” (epic 1, 5 pts) remains flagged as a stale label needing re-verification before ever being pulled blind — carried forward unchanged for several sprints now.
Follow-Up On Previous Retro's Actions
All four of Sprint 9's retrospective action items, checked against backlog/sprints/sprint-10.md and backlog/backlog.md's Sprint 10 refinement/planning/review outcomes:
Treat a story's GUI-layer verification as equally load-bearing as any other check, not optional once a different check “feels sufficient” — Applied. Every GUI-touching item this sprint (the indicator, the delete/resize-handle correction, multi-select, align/distribute) got a real reflection-driven built-form smoke with a genuine screenshot; Batch 3 specifically captured a fresh screenshot rather than reusing Batch 2's, exactly matching this discipline's intent.
Re-confirm/re-size “Support rotated wrapped text and a live wrap/clip indicator for text elements” before it is committed — Applied, exactly as recommended, during Sprint 10 backlog refinement: renamed, re-sized from 8 to 3 points, confirmed via real code inspection and a licensed end-to-end test that rotation composition was already delivered as a Sprint 9 byproduct.
Apply the built-form-vs-canvas-only smoke rule per story when epic 6's multi-select/align pair is finally pulled — Applied, its trigger having finally occurred after being carried forward unchanged for two prior sprints. Batch 2 (multi-select, touches the properties panel) and Batch 3 (align/distribute, adds a new toolbar) each got their own full built-form smoke, with Batch 3's screenshot freshly captured rather than reused — no drop, and the multi-sprint carry finally resolved.
Evaluate extracting the pre-existing Sprint 6 Address Control interaction logic to a CanvasElementEditor-equivalent before/alongside the next story that deepens Address Control interaction — Triggered twice this sprint (both multi-select and align/distribute deepened Address Control interaction) but the actual extraction was, again, consciously deferred rather than done — correctly logged and disclosed both times rather than silently dropped, but this is now the second sprint in a row this exact trigger has fired without the refactor happening. Escalated above into its own concrete Sprint 11 action item rather than carried forward as a passive note a third time.
Three items show clean follow-through; one (item 4) is honestly flagged as acknowledged-but-deferred for a second consecutive occurrence, escalated rather than quietly re-carried — no silent drops.
Kit-Level Decision
No kit-level edit proposed this sprint. Both new insights (auditing sibling event handlers for a known anti-pattern; instrumentation-first perf debugging) are team coding/debugging practices, not gaps in the Scrum-kit process, templates, or agent files themselves — logged above as team action items rather than routed to logs/process_improvement_log.md. The Sprint 9 retrospective's own Proposed license-key-search-depth entry there remains awaiting a human product-owner decision on wording/placement; not revisited this sprint since nothing new changed its status.
Anti-Patterns Checked
No follow-through on prior retro actions: Ruled out; see “Follow-Up” above — three items show clean follow-through, one is honestly escalated rather than silently re-carried a third time.
Blame-focused discussion: Ruled out; the click-hitch regression and the recurring Address-Control-testability gap are both described as process/practice gaps to generalize a fix from, not attributed to a person or session.
Hidden mini-waterfall within the sprint: Ruled out; each of the three batches was designed, implemented, tested, documented, and live-verified within its own pass, consistent with every prior sprint's practice.
Avoiding an obvious known problem: Ruled out; the click-smoothness regression was investigated to a confirmed root cause and fixed with disclosed before/after evidence, not patched around or left as a caveat.
Status-theater: Ruled out; every claim this sprint is backed by a specific, checkable number or artifact — exact test counts at each batch boundary, a specific before/after timing measurement for the smoothness fix, and real screenshots for every GUI-touching change.
Review rubber-stamping (Sprint 3-named, resolved Sprint 4, checked at every sprint since): Ruled out. Sprint 10's review independently re-ran the full test suite and read the actual CanvasElementEditor/TemplateCanvasControl/AlignmentCalculator code directly, and explicitly assessed both ad-hoc items’ scoping rather than accepting dev-team's framing at face value.