Repository navigation
deck: decks with audio or video open - #511
Merged
Merged
Conversation
Approved by the maintainer (11 Oct 2026): a real 42 MB, 36-slide .pptx with one video wouldn't open, because the import guard refused every audio or video part (held:). Audit (deckcraft d0e57d7e): the decoders, deckcraft-media, are a dependency of the engine crate only (and the egui UI); pptx, format, render, anim and pdf don't depend on them. Inside the engine they are called from media.info and media.posterFrame (cmd/media.rs 100, 123) and from insert.audio and insert.video (cmd/insert.rs 450, 477), the four commands the door already holds back (#448). The package reader keeps a clip's bytes and its poster (pptx read/shapes.rs 259), the renderer draws the poster or a film or speaker glyph (render lib.rs 559-571), and the writers copy the bytes. No path the service runs reaches a decoder. - guard: audio and video parts pass like any other; the content-type, extension, signature and manifest checks go. Every bound stays (entries, names, sizes, totals, ratio, nesting outside ppt/embeddings/, parity), and a deck's media counts against the session's 128 MiB when it opens (too_large:) - tests: a deck with a video (red poster) and a sound opens from a package and a native file, draws the poster (and the glyphs without one), saves natively and reopens, exports a package with the clips' bytes unchanged, and a PDF; hostile clip bytes ride along on every path while the four media commands stay held; a deck past 128 MiB of media is too_large:; the old media-held tests turned around - docs: apps/AGENTS.md, both apps READMEs, ADR 0013's deck row in both languages Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since #511 a deck with audio or video opens; held: now means a zip inside the zip, or a part past the import guard's bounds (#448). Wording only, no layout change: - main.splash: the open view's explanation names a zip inside the presentation or parts larger or more unusual than Quick Deck takes, and says to save a simpler copy; the library card says "Can't open this file" - dev fixture: the held deck's refusal is the guard's nested-zip words - READMEs (both languages): the held state's description - model test: the held explanation names no media Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ymote
marked this pull request as ready for review
October 13, 2026 02:25
Review of #511 (minor): the 128 MiB media ceiling ran only after the engine read, on deck.open and deck.cover, and on deck.run only with commands; info, text, render and convert never checked it. The package reader copies each media part out, so the peak could be twice the media. - guard: before the engine reads, the declared total of a zip's binary parts (everything but its XML and relationship parts, and a native deck's manifest and mimetype) past 128 MiB is too_large:, in the session ceiling's words - read_guarded and read_deck: the deck's own media against the same ceiling right after the engine reads, so all seven paths answer alike (media_ceiling; media_over and too_large_deck give one set of words to the guard, the paths and the session's Held::over) - test: a native deck and a package just past 128 MiB are refused on all seven paths with no engine read; one just under opens on all seven Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Local CI passed on da0fcc5 ( GitHub would run for this PR: desktop.yml, phone.yml, apps.yml. Merged on this local pass (macOS runner queue); GitHub CI runs on the merge commit on main.
Skipped (these did NOT pass; (!) marks a skip that blocks tools/ci-local-merge.sh):
Notes:
|
This was referenced Oct 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The maintainer imported a real 42 MB, 36-slide
.pptxwith oneppt/media/media1.mp4, and Quick Deck couldn't open it: the import guard refused every audio or video part asheld:. They approved opening such decks (11 Oct 2026, "yes OK"). Media rides along as opaque bytes and nothing plays it.Audit: every call into the decoders, and what the service runs
Read at deckcraft
d0e57d7e. The decoders aredeckcraft-media: the symphonia audio decoder, plus the h264, hevc, av1, vp9, isobmff, matroska, ogg and opus crates. Per the crates'Cargo.tomls, onlyengineandui-eguidepend on it.pptx,format,render,anim,pdf,text,modelandfontsdon't, so none of them can call a decoder.deckcraft-mediaengine/src/cmd/media.rs:100,deckcraft_media::probemedia.infoonlyHELD_BACK, #448); no method builds itengine/src/cmd/media.rs:123,deckcraft_media::poster_pngmedia.posterFrame(media.rs:139) andinsert.video(insert.rs:477)engine/src/cmd/insert.rs:450,deckcraft_media::probeinsert.audioandinsert.video(insert.rs:511,514)engine/src/lib.rs:27,pub use deckcraft_media as mediazipcrate's directory readdeckcraft_pptx::import(read/shapes.rs:259stores the clip's bytes as aMediaClip, with the package's own poster picture), thendeckcraft_format::repairdeckcraft_format::load(each item's bytes frommedia/<id>)deck.cover,deck.view,deck.layouts, the images exportrender_slide,render_layoutandcmd::file::render_png(render/src/lib.rs:559-571: the poster is drawn as a picture, otherwise a film or speaker glyph)deck.view {step},deck.showshow_order,ShowState,Timeline::state), then the rendererdeck.slide,deck.slides,deck.format_state,deck.hitslide.inspect(inspect.rs:99reports a clip's id, video, autoplay and loop),document.inspect,format.state,Session::hit_test, model readssave_bytes(.., "deckcraft"), sodeckcraft_format::save: clip bytes are stored, video and audio not compressed again.pptxexportsave_bytes(.., "pptx"), so the pptx writer (write/shapes.rs:557: the media part and its relationships)cmd::file::pdf_bytes, so deckcraft-pdf, which uses the renderersave_bytes(.., "outline")/slides_to_outlineedit.undoandedit.redo(edit.rsrestore: a snapshot swap)edit.rs:57media_of_shapesonly lists a shape's media ids for the clipboarddeck.runWhat
src/guard.rs): audio and video parts pass like any other part. The checks by extension, by declared content type ([Content_Types].xml), by container signature, and by a native manifest'scontentTypeare gone. Every bound stays:ppt/embeddings/(held:) and the read-alike parity rule;mimetype) past the session's 128 MiB of media istoo_large:, in the session ceiling's words. The package reader copies each media part out, so the engine never takes in more than the ceiling;read_guarded(open, cover) andread_deck(info,text,render,convert,run) hold the deck's own media to the same ceiling, so all seven paths answer alike. One set of words (media_over,too_large_deck) serves the guard, the paths and the session'sHeld::over.The four media commands stay held.
held:now means a zip beyond the guard, or a command the door holds back (src/codes.rs).apps/AGENTS.md, the deck service paragraph in both apps READMEs, and ADR 0013's deck row in both languages.apps/quickdeck/design/SERVICE.md, its own commit). The import guard'sheld:list drops audio and video. A new "Audio and video" paragraph says they open, carried as bytes and never decoded, with the four media commands held andtoo_large:past 128 MiB of media. In the error table,held:becomes "its zip is beyond the import guard (Engine robustness gaps from the command-door caps review: deck media, cad DXF splines, film export memory, photo.run caps #448)". A line in "As built" notes deck: decks with audio or video open #511, which lifts decision 4's media refusal.held:now names a zip inside the presentation, or parts larger or more unusual than Quick Deck takes (Engine robustness gaps from the command-door caps review: deck media, cad DXF splines, film export memory, photo.run caps #448), and says to save a simpler copy;Tests
On the Linux build host (x86_64), at head
dab0c0e0on main37eb1e23:cargo test --locked -p octosense-deck-service -p octosense-engine-area: deck service lib 88 passed, 1 ignored (the timing test);first_call1 andskill1 passed; engine-area 28 passed.cargo clippy --locked -p octosense-deck-service -p octosense-engine-area --all-targets --no-deps: no findings.cargo test --locked -p octosense-shell quickdeck_model, from the root: 28 passed, including the newa_held_deck_is_explained_without_media. The whole shell lib suite from the root also passed: 1,050 passed.a_deck_with_video_and_sound_opens_draws_saves_and_exports. A deck holds a video with a red poster and a sound..pptxand a native file, with the clips' bytes intact in the open document.deck.viewworks with and without a step, and so doesdeck.cover..pptxwhose clips come back byte for byte, and which opens again, and a 3-page PDF.hostile_clip_bytes_are_carried_on_every_path_and_never_decoded. The clips are a hostile MP4 (boxes claiming 4 GiB and 16 EiB, four billion samples) and a WAV of 65,535 channels claiming 4 GiB.info,text,render,convertto every format,run,open,slides,slide,view(plain, with a step and in edit mode),hit,show,layouts,cover, an edit then undo and redo,save, and the.pptx, PDF, images and outline exports.media.info,media.posterFrame,insert.videoandinsert.audiostay held throughdeck.run.a_deck_past_the_media_ceiling_is_too_large_before_the_engine_reads. A native deck and a package whose binary parts declare just past 128 MiB (1,311 parts of 100 KiB, each inside every other bound, in files of a few hundred KB) answertoo_large:on all seven paths with no engine read. The read counter stays unchanged. One just under (1,310 parts) opens on all seven paths, with seven reads. The post-read check (media_ceiling) refuses and passes the same two decks in the same words.Also checked on the maintainer's Mac only: the maintainer's own deck. A throwaway check that wasn't committed opened it through the service and drew five slides. The file never left the Mac.
Not run: no shell or desktop run, and no Quick Deck UI.
apps/quickdeck/tests/ui.py(a hidden desktop shell) wasn't re-run, so its storeds3-heldevidence still shows the old card line. The design brief (design/BRIEF.md) keeps its original wording as a record.🤖 Generated with Claude Code