festifun/plan/status/lane-B.md
m3ultra bb542960c2 Lane B (M2 + M8 geometry): COLMAP reconstruction, geometry math, graceful degradation
Implements spec M2 (frame sampling, COLMAP orchestration, TXT-model parsing, scene
normalization, pose interpolation, PLY + DB export) and the M8 geometry functions.

geometry.py (M8): slerp_pose (shortest-arc, double-cover), ray_from_pixel (COLMAP
+y-down back-projection), triangulate_rays (closest-point + parallel guard),
nearest_point_on_ray (in-front radius cylinder). Frozen colmap_to_threejs untouched.

frames.py (M2): variance-of-Laplacian sharpness + windowed sharpest-frame sampling.

sfm.py (M2): hand-written COLMAP images/cameras/points3D parsers; normalize_scene
(centroid->0, camera sphere r->10, up->+Y) as one similarity transform over points+poses;
interpolate_poses (slerp+lerp, no extrapolation); build-aware COLMAP CLI orchestration
(3.x/4.x option detection, CPU SIFT, single-camera-per-folder, undistort->TXT, largest
component by images.bin header count); run_reconstruct with full graceful degradation
(COLMAP absent / <60% / <2 videos / no frames / missing files -> poses left untouched).

Tests: 61 pass (24 foundation + 37 lane-B) with independent oracles (scipy Slerp,
projection-inverse, closed-form geometry) and every degradation/DB-safety branch covered.
Validated end-to-end against real COLMAP 4.1.0 (6 components, largest selected, weak ->
graceful degradation, exit 0).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 08:40:46 +10:00

4.4 KiB

Status — lane-B

Round 0 — 2026-07-16 — STATUS: ready_to_merge

Directives acknowledged: round 0 of plan/DIRECTIVES.md (run order C→A→D→B; merge when acceptance passes, don't wait on siblings; maintain this status file; evidence discipline).

Environment: COLMAP 4.1.0 (CPU-only) + ffmpeg both installed, so the pipeline was exercised against real COLMAP end-to-end, not just the synthetic export path.

Isolation note (see blocker): worked in a dedicated git worktree (/Users/m3ultra/Documents/festifun-laneB on lane/b-recon) because all lane agents were sharing one working directory. Only the 6 lane-B-owned files were touched.

Acceptance checklist (spec M2 + M8 geometry + lane brief) — all pass:

  • geometry.py M8 stubs implemented: slerp_pose (shortest-arc, double-cover), ray_from_pixel (COLMAP +y-down back-projection), triangulate_rays (closest-point + parallel guard), nearest_point_on_ray (in-front radius cylinder). Frozen colmap_to_threejs/quat_to_mat/ mat_to_quat and the 3 frozen POSE_TEST_VECTORS untouched (git diff 5fa7301 shows 0 removed lines in test_geometry.py; the frozen funcs are unchanged).
  • frames.py: sharpness (variance of Laplacian) + windowed sharpest-frame sample_frames.
  • COLMAP TXT parsers (images/cameras/points3D) with hand-written-snippet tests + a truncated-PARAMS guard (clean ValueError).
  • normalize_scene: centroid≈0, camera-sphere radius≈10, up≈+Y — verified by test_normalize_scene_invariants and a projection-invariance test (test_normalize_scene_preserves_projection).
  • pose interpolation (slerp+lerp, registered=False, NO extrapolation past first/last registered) — both guard directions tested.
  • PLY export via frozen synthetic.write_ply; poses written via atomic db.set_poses.
  • graceful degradation: COLMAP absent / <60% frames / <2 videos / no frames / missing files → diagnostic, existing poses UNTOUCHED, DB uncorrupted. Mixed-subset case (some videos registered, others kept) tested for the DB-safety invariant.
  • real end-to-end: syntheticreconstruct ran the full COLMAP CLI (feature_extractor → exhaustive_matcher → mapper → image_undistorter → model_converter → my parsers), produced 6 components (2/15/11/16/17/37 imgs), correctly selected the largest by images.bin header count, judged 37/120 (31%) weak, degraded gracefully, left all 41 synthetic poses/video untouched, exit 0.
  • pytest green — 61 passed (24 foundation + 37 lane-B; test_geometry.py + test_sfm.py).
  • no edits outside owned files (git diff 5fa7301 --name-only = frames/geometry/sfm/test_geometry only; untracked: test_sfm.py, this status file); no new deps.

Bugs found & fixed while validating on real COLMAP:

  • COLMAP 4.x renamed SiftExtraction/SiftMatchingFeatureExtraction/FeatureMatching; option detected from --help (which COLMAP prints to stderr) so the pipeline runs on 3.x and 4.x.
  • _largest_model_dir ranked binary models by file size (tracks keypoints, not image count) → now reads the exact registered-image count from the images.bin uint64 header (validated on the real 6-component run).
  • workspace cleared before each run so a stale database.db can't fail reruns.

Adversarial review: 5-lens review + verify pass (23 agents) → 18 raw findings, 5 CONFIRMED (2 code, 3 test-coverage), all applied; 13 refuted (incl. triangulate/nearest-point "behind origin" — correct-as-written).

Blockers / questions for coordinator:

  • Shared working tree collision. All four lane agents are operating in the same working directory (/Users/m3ultra/Documents/festifun), not separate clones/worktrees as plan/README.md requires. Mid-session the shared branch was switched to lane/d-events and the tree accumulated uncommitted edits from lanes A/B/C/D at once. I isolated lane B in its own worktree so nothing is clobbered. Recommend the coordinator have each lane use git worktree/separate clones, and adjudicate merges centrally, since a naive git branch -f main from any lane could silently drop a sibling's merge. I did NOT auto-merge to main for this reason — lane B is ready and awaiting a safe merge.

Next: commit lane B to lane/b-recon; coordinator to merge to main (safely, given the shared-tree issue).