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>
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.pyM8 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). Frozencolmap_to_threejs/quat_to_mat/mat_to_quatand the 3 frozen POSE_TEST_VECTORS untouched (git diff 5fa7301shows 0 removed lines in test_geometry.py; the frozen funcs are unchanged).frames.py:sharpness(variance of Laplacian) + windowed sharpest-framesample_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 bytest_normalize_scene_invariantsand 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 atomicdb.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:
synthetic→reconstructran 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 byimages.binheader count, judged 37/120 (31%) weak, degraded gracefully, left all 41 synthetic poses/video untouched, exit 0. pytestgreen — 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/SiftMatching→FeatureExtraction/FeatureMatching; option detected from--help(which COLMAP prints to stderr) so the pipeline runs on 3.x and 4.x. _largest_model_dirranked binary models by file size (tracks keypoints, not image count) → now reads the exact registered-image count from theimages.binuint64 header (validated on the real 6-component run).- workspace cleared before each run so a stale
database.dbcan'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 asplan/README.mdrequires. Mid-session the shared branch was switched tolane/d-eventsand 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 usegit worktree/separate clones, and adjudicate merges centrally, since a naivegit branch -f mainfrom any lane could silently drop a sibling's merge. I did NOT auto-merge tomainfor 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).