Skip to content

feat(drift): rigid drift correction — first feature mined from the quarry - #130

Draft
CSSFrancis wants to merge 6 commits into
mainfrom
feat/drift-rigid
Draft

feat(drift): rigid drift correction — first feature mined from the quarry#130
CSSFrancis wants to merge 6 commits into
mainfrom
feat/drift-rigid

Conversation

@CSSFrancis

Copy link
Copy Markdown
Owner

Landing-order step 2: RIGID drift correction extracted from the quarry (feat/seg-fast-engine) by the quarry rules — tests pulled first as the behavioral spec, then only the code that makes them pass, file-level pulls only, everything trimmed. Non-rigid stays behind for its own PR (nonrigid.py, test_drift_nonrigid.py, its benchmark and scripts).

What landed: spyde/drift/ (frames/model/translation/warp — streaming solvers, small DriftModel output, corrected movie as a LAZY per-frame view; nothing materialises the stack), the Drift Correction wizard (drift_action.py + DriftWizard.tsx + caret wiring, nonrigid branches stripped: METHODS, models, DEFAULTS/schema keys, run branch), the 7 staged-verb registry entries + toolbars.yaml (signal_types: [insitu]), the synthetic particle_movie fixture with stamped drift ground truth (identity shared with the future seg PR), protocol/renderer wiring, and the quarry's ResizeObserver caret-placement fix (pulled because the pruned wizard's e2e reproduced the stale-placement no-op click for real).

Measured contracts kept as docstrings (the category that survives the no-narrative rule): the Tukey-not-Hann taper with the 25 px failure mode, _PHASE_FLOOR / _REJECT_FRACTION measurements, ROI-off-by-default, trace-batching flush.

Evidence:

  • Numba check clean — FFT/scipy/optional-torch only, none of the miscompiled kernel class.
  • test_drift_translation.py 49/49, test_drift_wizard.py 57/57 (3 nonrigid tests pruned, named in the extraction log); full migrated suite 2757 passed / 0 failed (10m28s).
  • e2e drift_wizard.spec.ts 4/4 in 33.2s (below the SLOW_SPECS bar); caret payload↔DEFAULTS↔schema verified 1:1 both directions, every setter has a caller.
  • Screenshots reviewed at electron/drift_wizard_shots/01–09 (caret face, Advanced with Rigid+Affine locked + backend reason, mid-fill dy/dx curve with Stop, final curve matching the fixture's 6.0 px ground truth, corrected sum visibly sharper: "1.9x sharper"). Built + headless-tested + screenshots reviewed — maintainer's eyes are the final gate on the wizard.

Size, flagged honestly: 4,940 insertions over 21 files — over the 1–2k guideline. 1,573 of it is the ported tests+spec (the audited behavioral spec), 279 fixture+icon, ~3.1k production dominated by contract docstrings. If you'd rather review it in two sittings, say the word and I'll split compute (spyde/drift/ + translation tests) from wizard (action/TSX/e2e) — the seam is clean.

Pulled from feat/seg-fast-engine (PR #122) at file level; these are the
behavioral spec for the rigid drift PR. test_drift_wizard.py is pruned of
its non-rigid coverage (three TestMethodStubs tests: nonrigid selectable,
nonrigid field parameterisation, unknown-field fallback) -- non-rigid
lands in its own later PR. test_drift_translation.py is rigid-only and
comes over verbatim.
…izard

Pulled file-level from feat/seg-fast-engine (PR #122) and trimmed to the
rigid surface:

- spyde/drift/{frames,translation,warp}.py verbatim (all rigid): streaming
  frame source, FFT phase correlation with running Fourier reference +
  Guizar-Sicairos sub-pixel refinement, per-frame NaN-padded warp. The
  measured contracts stay as docstrings (Tukey-not-Hann taper, the phase
  magnitude floor, outlier rejection thresholds).
- model.py: DriftModel without the nonrigid 'extra' carrier and the
  uncalled shift_at accessor.
- __init__.py: no nonrigid re-exports.
- drift_action.py: METHODS drops 'nonrigid'; NONRIGID_MODELS, the
  decimated-stack reader, the nonrigid fit step, its DEFAULTS/schema/
  _coerce keys and the drift_run nonrigid branch are all gone. Non-rigid
  arrives in its own PR.

No numba anywhere in the package (FFT/scipy/optional torch only).
…cle-movie fixture

- registry: the seven drift_* staged handlers + the 'drift' wizard-schema
  entry (DriftWizard.parameters is the one source of truth).
- toolbars.yaml: the Drift Correction toggle, gated signal_types [insitu]
  (the rigid solver needs a 1-D navigation axis -- the same gate
  Play/Fast-Forward use).
- data/synthetic.py: the particle_movie generator with stamped per-frame
  drift ground truth (also carries the particle event table the later
  segmentation PR asserts against -- the fixture is shared, its identity
  must not fork between the two PRs).
- test harness: load_test_data_particles, lazy at one frame per chunk like
  a real .mrc movie. The seg-only 'noise' payload knob stays behind.
… real pixels

drift_wizard.spec.ts pulled from the quarry and pruned of its non-rigid
stages (the 'nonrigid selectable/field controls' and 'nonrigid solve runs
the fit' tests). DriftWizard.tsx pruned to the rigid tabs -- METHODS,
DEFAULTS and the params() payload mirror drift_action 1:1. Wiring:
FloatingToolbar mounts the caret for the Drift Correction toggle;
SpyDEContext re-broadcasts the five drift_* messages as CustomEvents;
protocol.ts types them.
The drift caret's Advanced disclosure changes the caret's height without
re-rendering FloatingToolbar (a child's state update does not re-render
its parent), so the placement went stale and the caret JUMPED on the next
unrelated render -- a jump between mousedown and mouseup lands the two on
different elements and the browser emits no click at all, which is how
closing Advanced silently no-opped in the e2e. A ResizeObserver on the
caret's box re-runs placement when its content changes; the measured
width is mirrored into state so the side placements clamp into the MDI
area instead of walking off the app edge. Pulled from the quarry's
FloatingToolbar (minus its Segment brush strip).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant