Problem
We hit a stale computed bug where selection bounds kept showing the previous rectangle because the bounds computed called a snapshot-style helper that used peek() internally. The computed did not subscribe to selection.stateCell, so it only refreshed when some unrelated dependency caused it to rerun.
This is easy to miss when a computed uses helpers that hide whether they read reactive values or snapshots.
Direction
Prefer explicit invalidation reads when a computed/effect needs a signal only as a dependency:
computed(() => {
track(editor.selection.stateCell);
return editor.selectionBounds();
});
Use .value only when the value is actually consumed in that scope. If the value is not consumed, use track(cell) so the dependency is visually obvious.
Tasks
- Audit computed/effect/render props code for
.value reads whose value is not directly used.
- Replace invalidation-only
.value reads with track(cell).
- Check computed helpers that call snapshot APIs (
peek(), snapshot getters, imperative helpers) and add explicit track(...) at the computed boundary.
- Consider adding an oxlint rule that flags unused
.value reads and suggests track(cell).
Acceptance criteria
- Invalidation-only signal dependencies use
track(cell).
- Computeds that rely on snapshot-style helpers explicitly track their source cells.
- The selection-bounds stale-rect class of bug is covered by either a regression test or lintable pattern.
Problem
We hit a stale computed bug where selection bounds kept showing the previous rectangle because the bounds computed called a snapshot-style helper that used
peek()internally. The computed did not subscribe toselection.stateCell, so it only refreshed when some unrelated dependency caused it to rerun.This is easy to miss when a computed uses helpers that hide whether they read reactive values or snapshots.
Direction
Prefer explicit invalidation reads when a computed/effect needs a signal only as a dependency:
Use
.valueonly when the value is actually consumed in that scope. If the value is not consumed, usetrack(cell)so the dependency is visually obvious.Tasks
.valuereads whose value is not directly used..valuereads withtrack(cell).peek(), snapshot getters, imperative helpers) and add explicittrack(...)at the computed boundary..valuereads and suggeststrack(cell).Acceptance criteria
track(cell).