feat: laat video en audio meereizen naar een git-repository #540

Merged
brenno merged 1 commit from feat/git-media into main 2026-07-22 11:31:23 +00:00
Owner

Summary

If you keep presentations in git, the media belongs there too. Warning about it is a courtesy, not a substitute for supporting it.

Part of #515 — media only. Sidecars are split off (see below).

What I got wrong first

I told the maintainer this needed a design decision before building. It did not: D5 already decided it — partial clone plus a size warning, explicitly no hard cap, because "telling a presentation author their video is too large is a bad answer from a tool that supports video". I should have read the design before saying it needed input.

What genuinely was undesigned is the way back, now recorded as D12.

The way back (D12)

Media cannot return the way an image does. WebAssetStore is a Map<String, Uint8List> — fine for a picture, wrong for the 1 GiB maxMediaBytes allows. So a repo: media reference resolves to:

  • a staged file on a platform with a filesystem (AssetStaging.stageBytes), so the player reads from disk exactly as it does for a deck opened from a folder;
  • mem: on web, within a browser-sized cap.

Validation is symmetric with images: a forge is untrusted (P5), so bytes must sniff as a known container (mediaMimeFromBytes) and stay inside the cap — the same shape as looksLikeImage.

Changes

  • deck_repo_serializer.dartpoolImage was never image-specific (only its mem-path fallback name was); renamed poolAsset, and videoPath/audioPath now go through it and are rewritten to repo: refs.
  • repo_asset_resolver.dart — the media read path via staging, with container sniffing.
  • GitDeckOmissions loses videoSlides/audioSlides, and the pre-commit warning loses those two lines. A warning that is untrue teaches people to dismiss the whole dialog — including the parts that are still true.
  • docs/design/GIT_STORAGE.md — D12 added, D5 annotated with the confirmation and its date.
  • CHANGELOG under Added.

Verification

Six tests in test/git_media_roundtrip_test.dart, including that two slides using the same film produce one blob — the property that keeps history from growing on every commit — and that unreadable media is reported rather than silently dropped, which is the exact failure mode the issue describes.

Mutation-checked: removing the pooling call makes three of the six fail. The test measures something.

make check, make check-secrets, make sast all green.

Deliberately not in scope

The sidecars — .ink.json, .user-notes.json, .seal.json — still do not travel, and the warning still says so. They are a different data class, and the ink half needs the merge driver from D7 (union of stroke sets), which depends on per-stroke identity in the annotation format. Filed separately rather than bolted on here.

Principles

Touches storage, so weighed: the deck stays plain Marp Markdown, media lands in the shared content-addressed pool that images already use, and nothing new becomes unreadable outside OciDeck. It makes the user's copy more complete, which is the direction that matters — a deck you cannot take with you is the failure this project exists to avoid.

## Summary If you keep presentations in git, the media belongs there too. Warning about it is a courtesy, not a substitute for supporting it. Part of #515 — media only. Sidecars are split off (see below). ## What I got wrong first I told the maintainer this needed a design decision before building. It did not: **D5 already decided it** — partial clone plus a size warning, explicitly *no* hard cap, because "telling a presentation author their video is too large is a bad answer from a tool that supports video". I should have read the design before saying it needed input. What genuinely *was* undesigned is the way back, now recorded as **D12**. ## The way back (D12) Media cannot return the way an image does. `WebAssetStore` is a `Map<String, Uint8List>` — fine for a picture, wrong for the 1 GiB `maxMediaBytes` allows. So a `repo:` media reference resolves to: - **a staged file** on a platform with a filesystem (`AssetStaging.stageBytes`), so the player reads from disk exactly as it does for a deck opened from a folder; - **`mem:`** on web, within a browser-sized cap. Validation is symmetric with images: a forge is untrusted (P5), so bytes must sniff as a known container (`mediaMimeFromBytes`) and stay inside the cap — the same shape as `looksLikeImage`. ## Changes - `deck_repo_serializer.dart` — `poolImage` was never image-specific (only its mem-path fallback name was); renamed `poolAsset`, and `videoPath`/`audioPath` now go through it and are rewritten to `repo:` refs. - `repo_asset_resolver.dart` — the media read path via staging, with container sniffing. - `GitDeckOmissions` loses `videoSlides`/`audioSlides`, and the pre-commit warning loses those two lines. **A warning that is untrue teaches people to dismiss the whole dialog** — including the parts that are still true. - `docs/design/GIT_STORAGE.md` — D12 added, D5 annotated with the confirmation and its date. - CHANGELOG under Added. ## Verification Six tests in `test/git_media_roundtrip_test.dart`, including that two slides using the same film produce **one** blob — the property that keeps history from growing on every commit — and that unreadable media is *reported* rather than silently dropped, which is the exact failure mode the issue describes. **Mutation-checked:** removing the pooling call makes three of the six fail. The test measures something. `make check`, `make check-secrets`, `make sast` all green. ## Deliberately not in scope The sidecars — `.ink.json`, `.user-notes.json`, `.seal.json` — still do not travel, and the warning still says so. They are a different data class, and the ink half needs the merge driver from D7 (union of stroke sets), which depends on per-stroke identity in the annotation format. Filed separately rather than bolted on here. ## Principles Touches storage, so weighed: the deck stays plain Marp Markdown, media lands in the shared content-addressed pool that images already use, and nothing new becomes unreadable outside OciDeck. It makes the *user's* copy more complete, which is the direction that matters — a deck you cannot take with you is the failure this project exists to avoid.
feat(git): laat video en audio meereizen naar de repo
Some checks failed
CI / Gate (Linux) · Format · Analyze · Coverage (pull_request) Has been cancelled
CI / Test (macos-latest) (pull_request) Has been cancelled
CI / Test (windows-latest) (pull_request) Has been cancelled
CI / Web hardening (pull_request) Has been cancelled
CI / Docs links (pull_request) Has been cancelled
CI / Supply-chain (Trivy · advisory) (pull_request) Has been cancelled
CI / Gate (Linux) · Format · Analyze · Coverage (push) Has been cancelled
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Web hardening (push) Has been cancelled
CI / Docs links (push) Has been cancelled
CI / Supply-chain (Trivy · advisory) (push) Has been cancelled
1d11ad6d86
Wie presentaties in git bewaart, hoort zijn media daar te vinden. Een deck
zonder de film is geen kopie maar een fragment, en waarschuwen is een
beleefdheid, geen vervanging voor ondersteuning. Dat was al besloten (D5:
partial clone plus een waarschuwing, géén harde grens) maar niet gebouwd.

Media gaat door dezelfde content-geadresseerde pool als afbeeldingen.
poolImage heette al ten onrechte zo — hij is niet beeldspecifiek, alleen
de naamval bij een mem:-pad was dat.

De terugweg was het ontbrekende ontwerp, nu vastgelegd als D12: een
repo:-mediaverwijzing wordt op een platform mét bestandssysteem een
gestaged bestand, niet een mem:-pad. WebAssetStore is een Map in het
geheugen — prima voor een plaatje, verkeerd voor de gigabyte die
maxMediaBytes toestaat. Validatie is symmetrisch met beeld: een forge is
onvertrouwd (P5), dus de bytes moeten als bekende container snuiven.

De omissiewaarschuwing verliest video en audio. Een waarschuwing die
onwaar is, leert de gebruiker de hele melding weg te klikken.

De sidecars (.ink.json, .user-notes.json, .seal.json) reizen nog niet
mee; die blijven in de waarschuwing staan en krijgen een eigen issue.

Getoetst met een mutatie: het poolen weghalen laat drie van de zes tests
vallen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
brenno merged commit 1bb0e28746 into main 2026-07-22 11:31:23 +00:00
brenno deleted branch feat/git-media 2026-07-22 11:31:23 +00:00
Sign in to join this conversation.
No description provided.