Repository navigation
SunVox Studio saves renders and projects to Crow storage, composes with an arrangement, and the artifact CSP allows WASM in pages only - #525
Merged
Conversation
…ct CSP The design kit allows its WASM library (sunvox) in pages only, so slides, data and map no longer carry the WASM carve-out. Artifacts 0.6.3. Claude-Session: https://claude.ai/code/session_01N9fXzvNy8rCEArj1y5p6fp
…ment, song name and fuller info - sunvox_render and sunvox_compose save to Crow storage (storage key, a storage_files row, a 1-hour URL); reference_type blog_post makes a file playable on a song page. Optional Funkwhale upload (the Funkwhale add-on's own configuration, one origin, no redirects, rate-limited), a done notification and a 48 kHz output rate. - sunvox_compose: an arrangement (ordered, bounded timeline placements; repeats are clones), the song name, controller values checked against each controller's min/max, and a same-name composition is kept unless overwrite is true. The tempo goes into the pattern that plays first. - sunvox_info: format, project and engine version, module x/y/colour, pattern x/y. - spike/ leaves the bundle; the test fixture is now a short song composed by sunvox_compose from a fixed spec (scripts/sunvox-studio/make-fixture.mjs). - CI installs the bundle's deps with the installer's flags and requires the engine tests to run. sunvox-studio 0.2.0. Claude-Session: https://claude.ai/code/session_01N9fXzvNy8rCEArj1y5p6fp
…, tags for Funkwhale, budgets - The MCP child opens Nest-configured storage (storage.shared.* with sealed secrets) the way the gateway does, with the instance identity loaded only if it exists (new loadIdentityIfPresent, which never creates one); the MINIO_* env stays the fallback. envKeys now name the variables the s3-client reads. - mp3/ogg renders carry title/artist/album tags (a library import needs them). The Funkwhale push fits the 60 s tool-call budget (30 s upload, two short import checks), reports a failed import, and its import_reference is the content hash. - Storage keys get a random part (blog_post files are public). The work dir defaults to this instance's data dir and a '~/' setting expands. A same-name compose that lands first is never clobbered (wx). - The fixture test derives its expected values from the spec; CI installs ffmpeg and libasound and runs the mp3 cases; a guard ties the design kit's WASM libraries to the CSP rows that allow WASM. Claude-Session: https://claude.ai/code/session_01N9fXzvNy8rCEArj1y5p6fp
A render carries up to 2 s of effect tail after the song ends, so duration_s now reports the rendered audio and song_duration_s the song. Found by the live end-to-end check (a 10 s song rendered to 12.1 s). Claude-Session: https://claude.ai/code/session_01N9fXzvNy8rCEArj1y5p6fp
…ngement field Claude-Session: https://claude.ai/code/session_01N9fXzvNy8rCEArj1y5p6fp
…rage reads limited, one Funkwhale deadline - The MCP child opens the Nest storage settings, wipes the identity's key material at once and gives the s3-client only the opened config (new useStorageConfig); loadIdentityIfPresent reads the file without any create path. - storage_key reads only SunVox Studio's own files and blog media (never project files, attachments or private uploads), so a render cannot re-publish a private file at /blog/media. - The Funkwhale push has one 35 s deadline that caps every request, and refuses to upload unmetered when the database is missing. - 0.1.x installs that carry the old '~/.crow/data/sunvox-studio' default get their own instance's work dir. Storage keys carry 128 random bits; local render names a random suffix. Claude-Session: https://claude.ai/code/session_01N9fXzvNy8rCEArj1y5p6fp
…l call's start A render that already used most of the 60 s tool call skips the push (before any request or rate token) and says to upload later with fw_upload_track; otherwise the push gets what is left, at most 35 s. The Nest storage config is retried when its first load finds nothing, a trailing slash on the legacy work-dir value is ignored, and the comment on wiping the identity says what it does and does not protect. Claude-Session: https://claude.ai/code/session_01N9fXzvNy8rCEArj1y5p6fp
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.
Follow-up to #515. It completes the SunVox Studio MCP tools, fixes the minor points left open by its review, and narrows the artifact CSP.
What changes
sunvox_renderandsunvox_composesave to Crow storagesave_to_storage: if omitted, the file is saved whenever storage is available.truefails when storage is missing.falsekeeps only the local file.storage_filesrow, so it appears in Files. The rules matchcrow_upload_file: the sameMAX_UPLOAD_SIZEandSTORAGE_QUOTA_MBlimits, and the object is removed if its row cannot be written.sunvox-studio/<renders|projects>/<time>-<128 random bits>-<name>.reference_type: "blog_post"attaches the file to a post. The file then becomes public at/blog/media/<key>, which is where a song page's SunVox player fetches it. No other reference type is accepted, because those carry project access checks that a bundle must not bypass.storage.shared.*, with sealed secrets). Before this change it could not, so reading bystorage_keyfailed as well.loadIdentityIfPresent(), which never creates one.useStorageConfig(). The child never keeps the root seed.MINIO_*environment is the fallback.storage_keyis limited to SunVox Studio's own files (sunvox-studio/...) and blog media. Project files, attachments and private uploads are refused, so a render cannot re-publish a private file at/blog/media.funkwhale_library(a UUID or a library name) uploads an mp3 or ogg render to Funkwhale, sofw_playcan play it on the glasses.fw_upload_track.notify: trueraises a Crow notification when the render is done.sample_ratecan be 44100 or 48000. The library silently renders anything lower at 44100, so lower rates are refused.duration_sis now the length of the audio actually written. A render can run up to 2 s past the end of the song because of effect tails.song_duration_sgives the song's own length.sunvox_composearrangementplaces patterns on the timeline in order.xis missing, the pattern starts where the previous one ended. Ifyis missing, it is 0.namebecomes the song name.overwrite: trueis passed. The write is atomic, so a concurrent compose cannot clobber it.~/setting expands to the home dir.sunvox_infoReview minors from #515
spike/is no longer in the bundle. Installed copies used to ship it, including scripts that wrote to the live data dir.The test fixture is now a short song composed by
sunvox_composefrom a fixed spec (scripts/sunvox-studio/make-fixture.mjs). It reproduces byte for byte, and its expected values are derived from the spec. The upstream author's demo song has been removed from the repo.CI now runs the engine tests instead of skipping them:
suitejob installs the bundle's dependencies with the installer's flags, plus ffmpeg and libasound;CROW_REQUIRE_SUNVOX_ENGINE=1turns a missing engine into a failure.The job keys
suite,static-checksandauditare unchanged.Artifact CSP
'wasm-unsafe-eval'now appears on thepagerow only. The design kit allows its only WASM library (sunvox) in pages only.Versions
Testing
tests/sunvox-studio.test.js(33 cases);tests/sunvox-studio-outputs.test.js(18 cases, run against fakes with no services);tests/artifact-origin.test.js,tests/identity-load-if-present.test.jsandtests/s3-client-use-config.test.js;tests/typed-tool-schemas.test.js.storage.shared.*settings and no MinIO environment in the MCP child. The gateway was a scratch instance on loopback. 26 of 26 checks passed:blog_postand notify. Both files landed in storage withstorage_filesrows, a notification row was created, and the presigned URL served a decodable mp3.**SunVox:** storage:<key>was opened in headless Chrome and Play was pressed. The engine assets and the project loaded, the player showed "Ready" with the song name, and the transport advanced (line 0 → 9 in 1.5 s).funkwhale_libraryuploaded the render;fw_playtool returned a stream envelope that the glasses' envelope reader accepts;fw_play.Deploy
spike/keeps it, because the refresh only adds files. It is harmless, and reinstalling removes it.https://claude.ai/code/session_01N9fXzvNy8rCEArj1y5p6fp