Skip to content

feat(map-inset): render and composite a route inset per regular LF - #109

Merged
joepetjr merged 6 commits into
mainfrom
feat/map-inset-render
Oct 28, 2026
Merged

joepetjr merged 6 commits into
mainfrom
feat/map-inset-render

Conversation

@joepetjr

@joepetjr joepetjr commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

What

  • day_pipeline: when config.drive.map_inset == "route", each regular long-form video gets a route-only map inset. map_inset.render_route_inset renders it, and ost_applier.apply_ost(map_inset=...) composites it in the existing OST encode, placed at the receipt's inset_rect.
  • Timeline: extract_and_concat_segments(receipt_sidecar=True) saves the keycut receipt validated in chore(deps): pin keycut v0.2.0 and validate its live assembly receipt #108 beside the concat as <concat>.receipt.json. It writes to a temporary name and renames, and removes the file before each cut and on every failure. The inset uses EditTimeline.from_receipt(..., inserts=[Insert(0, probed montage lead)]). A concat that has no receipt is cut again, and if the receipt is still missing the render stops.
  • route_claims.map_inset_inputs refuses before the day master is encoded and lists every problem: no bundle, or a bundle that fails verify_bundle; a start or end trim that is not above 0 m (the output is public, so an untrimmed route would show where the drive began or ended); an unparsable privacy zone; no usable GPS for the day. Route points are the day's GPS in master-video seconds, split at GPS gaps.
  • If the renderer refuses one video (for example, too little route coverage), the run stops and names that video. No video ships without the map it was asked for.
  • Resume: the OST fingerprint takes in a signature built from the bundle manifest hash, the trim, the zones, the layout and the route, so turning the inset on or changing any of those forces a re-burn. When the inset is off the fingerprint is byte-identical to today's (tested).
  • The inset receipt is recorded in state["regular_lf_map_inset"], and the clip is purged with the other per-video work files.
  • Photo and clip inserts do not block an inset. They are spliced in after the burn, so the map stays on its own frames and the inserted stills carry none.

Why

Plan unit Q5a-3: the drive wiring for the opt-in map inset. #106 added the overlay and #107 the renderer. No config can turn this on yet; the --map-inset flags come in the follow-up PR, so this one changes nothing for existing renders.

Tests

  • New tests/test_regular_lf_map_inset.py. It covers: off behaves like a config written before the flag existed, for both the apply_ost kwargs and the fingerprint; every pre-encode refusal fires before the encode is called; the clip is placed at the receipt rect; the timeline is shifted by the montage lead; route points are in master seconds; the receipt file is written and removed; a missing receipt triggers a second cut; a per-video refusal stops the render; inserts keep the inset; and a real-ffmpeg composite whose output pix_fmt is yuv420p10le.
  • Local run on this branch, 12 files (this test file plus map_inset, ost overlay, keycut live receipt, segment extractor, resume correctness, lf work retention, day_pipeline, config defaults, inserts, flag registry and gps captions): 279 passed.
  • ruff check and ruff format are clean on the changed files, and tools/check_public_tree.py passes.

Move the keycut pin from v0.1.0 to v0.2.0. The day-master cut
(extract_and_concat_segments) now calls keycut's
extract_and_concat_ranges_with_receipt and checks the receipt it returns
with our own load_receipt. If the receipt does not validate, the function
logs an error naming the failing field and returns None, because an
output-to-source time map built from a bad receipt would be wrong. The
signature and return type are unchanged.

keycut 0.1.2 changed the re-encode fallback to seek on the input side
(-ss S -i master -ss 0 -t D). montage_builder.reencode_range_argv mirrors
that argv, so it follows; the lead-seam cut gives the same frames without
decoding from the start of the file. keycut 0.2.0 also probes piece and
output durations for the receipt, so the clean-run command count in the
resume test goes from 4 to 7.

Add a real-ffmpeg test that runs keycut on a synthetic master, loads the
live receipt, maps output time back to source time, and compares the
receipt's keys with the frozen assembly_receipt_v1.json fixture.
# Conflicts:
#	gomoveshift/pipeline/montage_builder.py
#	pyproject.toml
What: when a drive config selects map_inset="route", each regular
long-form video gets a route-only map inset rendered from an offline
bundle and composited inside the existing OST encode. The LF cut now
keeps its keycut receipt beside the concat (opt-in sidecar), the inset
timeline is built from it shifted by the real montage lead, the inset
options and route are folded into the LF OST fingerprint, and the inset
receipt is recorded in drive state.

Refusals happen before the day master is encoded and list every
problem in one error: no bundle or a bundle that fails verification,
either trim not above zero, an unparsable privacy zone, no usable day
GPS trace, or photo/clip inserts on the day. A per-LF renderer refusal
stops the run, naming the LF.

Why: an LF must never silently ship without the map it was asked for,
nor with a partial overlay. With the option off the path is unchanged.
The CLI flags and config fields follow in the next commit; until then
this is unreachable from a real config.
Stills are spliced into the burned LF, so the map stays on its own frames and the inserted stills carry none.
# Conflicts:
#	gomoveshift/pipeline/day_pipeline.py
@joepetjr joepetjr added the needs-operator Autoland hard-denied this PR; human merge required label Oct 28, 2026
@joepetjr

Copy link
Copy Markdown
Contributor Author

Unclassified (unclassified) and ready to merge -- all checks green.

Offending paths:

  • gomoveshift/pipeline/cleanup.py
  • gomoveshift/pipeline/day_pipeline.py
  • gomoveshift/pipeline/drive_state_model.py
  • gomoveshift/pipeline/route_claims.py

Human merge (all 3 ready hard-denied PRs in Back-Road-Creative/framegrade):
sudo gh-merge-batch Back-Road-Creative/framegrade 54 79 109 --wait --yes

This PR alone:
sudo gh-merge-approved 109 --repo Back-Road-Creative/framegrade --wait --yes

@joepetjr
joepetjr merged commit b62c027 into main Oct 28, 2026
13 checks passed
@joepetjr
joepetjr deleted the feat/map-inset-render branch October 28, 2026 11:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-operator Autoland hard-denied this PR; human merge required

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant