- Synced 14 capability delta specs to main specs - Created 6 new main specs: api-authentication, error-boundary, input-validation, security-headers, shared-types - Updated 8 existing specs with security, validation, and performance requirements - Archived change to openspec/changes/archive/2026-02-20-code-review-fix/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2.4 KiB
ADDED Requirements
Requirement: Keyboard handler uses stable selectedSpanId
The SpanAnnotationManager keyboard handler SHALL use a useRef for selectedSpanId to prevent stale closure reads. The handleDeleteSpan function SHALL be wrapped in useCallback with proper dependencies.
Scenario: Delete correct span via keyboard
- WHEN user selects span A, then selects span B, then presses Delete
- THEN span B is deleted (not span A from a stale closure)
Requirement: Preview primitive uses ref instead of state
The SpanAnnotationManager preview primitive (shown during span drawing on mouse move) SHALL use a useRef instead of useState to avoid a state/effect feedback loop and unnecessary re-renders.
Scenario: Mouse move during drawing does not cause re-render cascade
- WHEN the user moves the mouse while drawing a span annotation
- THEN the preview primitive updates via ref mutation without triggering a React re-render
Requirement: Preview primitive cleanup on unmount
The SpanAnnotationManager SHALL detach the preview primitive in the useEffect cleanup function when the component unmounts, preventing a leaked canvas primitive.
Scenario: Component unmounts during drawing
- WHEN the user navigates away while mid-draw
- THEN the preview primitive is detached from the chart
Requirement: fitContent not called on every span change
The SpanAnnotationManager reconciliation effect SHALL NOT call chart.timeScale().fitContent() on every span annotation change. fitContent() SHALL only be called on initial chart load.
Scenario: Span annotation added preserves zoom
- WHEN the user adds a new span annotation
- THEN the chart maintains the current scroll position and zoom level (no fitContent reset)
Requirement: Incremental primitive updates
The SpanAnnotationManager SHALL update only the selection state of existing primitives on selection change instead of detaching all and re-attaching all. Full recreation SHALL only occur when the annotation list itself changes (add/remove/edit).
Scenario: Selection change is O(1)
- WHEN the user clicks a different span annotation
- THEN only the previously selected and newly selected primitives are updated (not all N primitives)
Scenario: Annotation add triggers full reconciliation
- WHEN a new span annotation is added
- THEN the primitive list is reconciled (new primitive added, existing ones kept)