Repository navigation
Controls batch 13a: mono/stereo sources only, empty sessions boot, automation row fixes, spectrum one-shot fix (#1681, #1682, #1631, #1632, #1616, #1679) - #1684
Merged
Conversation
…ces are mono or stereo; TBD30 an empty session boots on both hosts) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The continuous read discards any popped record whose stream epoch is not the current one, inside its bounded pop loop, so a one-shot record that lands after a mode switch's drain is never returned as a continuous window; the #1609 single-record invalidation flag it supersedes is deleted. A loom case explores the race. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner answer 2026-10-15: sources are mono or stereo. One session-validator rule refuses 0 or more than 2 channels with source.channels.unsupported, at load and in a structural edit; session::SOURCE_CHANNELS_LAUNCH_MAXIMUM = 2 is the one limit the browser staging, the C ABI and the SDK (generated ABI constant) read. Browser source staging back to 1,024 bytes; retained ceilings re-pinned from measurements. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
EffectObservationHandle carries the armed tap mask its prepared arm set (armed_taps), and the browser's build_plan_shape copies it; the duplicate binding match in host-web is deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner answer 2026-10-15: an app opens an empty mixer and adds stems by structural edits. The source graph no longer refuses a session with no source (SourceGraphSourceSetError::EmptySources deleted); an empty session prepares, renders silence with zero render allocations, and a structural transaction adds the first stereo stem and its track, which is heard. TBD29 follow-up: HostPrepareCaps::maximum_source_channels (always None) is deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
controls::activity_changed holds when the strip set or a strip's pan/matrix form changes; the classifier then runs the stored-automation row rule, so a live switch that would strand an automation entry is refused control.inactive before any commit on both hosts (parity test), and a switch that strands nothing stays live. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An empty session's meter lease follows the configured window (not the strip meters), its master-window ring is sized when no strip meter exists, and poll_meters publishes master windows alone with trackCount 0. A parity row boots empty on both hosts, adds the first stereo stem and track by one structural transaction and renders identical bits at four rates; the browser qualification gains an empty-boot leg in three browsers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ter boot (from TBD30) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1632) The control registry declares an automation rule per row; follows_mute (a routing setting) and matrix_mode (a mode) declare an exclusion with its reason and reopen condition (root, 2026-10-14; owner-revisitable), so the one row rule refuses a stored automation on either as control.automation.target on both hosts. The SDK tables and the control-list fixture follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # hosts/host-web/tests/control_parity.rs
…ter #1632 check-browser-expected-resources measured the simd128 initial and before-dispose memoryBytes at 2,818,048 (was 2,883,584, one 64 KiB page less). Bisected to 167fc10 (#1632); the stream did not run this gate. The set-control timeline row stays 2,883,584. A smaller boot is benign; re-pinned from the measurement. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Controls batch 13a: an app can open an empty mixer and add stems by structural edits on both hosts, and sources are mono or stereo only (owner answers of 2026-10-15). The batch also keeps a one-shot spectrum window out of the continuous stream, copies a successor's armed taps from the core's mask, re-runs the automation row rule when a row's activity changes, and makes two rows non-automatable.
Closes #1616
Closes #1679
Closes #1631
Closes #1632
Closes #1681
Closes #1682
What changed
try_read_continuous_record(crates/host-core/src/spectrum.rs) loads the stream epoch once before its bounded pop loop and discards every record of another epoch. So a one-shot window that render pushes between the switch's drain and its mode store is never read as a continuous window. Make the spectrum one-shot handoff safe across threads #1609's one-record invalidation rule is subsumed and deleted, so render does two fewer atomic stores on a failure.Source::channelsis 1 or 2, with the new typed codesource.channels.unsupported, at load and in every structural edit, on both hosts.session::SOURCE_CHANNELS_LAUNCH_MAXIMUM = 2is the one limit. The browser staging, the C ABI's plane bound and the SDK (new ABI-layout constantmaximumSourceChannels) read it. The browser's source PCM staging falls from 130,560 to 1,024 bytes. On the C ABI, a chunk of three or more planes is nowRESULT_INVALID_ARGUMENTat the boundary.EffectObservationHandlecarriesarmed_taps, which the core sets exactly when the lane armed a tap. The browser'sbuild_plan_shapecopies it, and its duplicate binding match is deleted.EmptySourcesinprepare_graph_source_set) is deleted.HostPrepareCaps::maximum_source_channelsis deleted, because the validator is the one limit. The browser fixes two sizes at zero: the meter lease reads the configured window instead of the strip meters, and the master ring is sized when no strip meter exists. On an empty mixer the meters publish the master's own windows. A boot that designates a master strip over an empty session is still refused (host.observation.master_track); see Designate the browser master strip after boot #1683.automation_diagnosticswhencontrols::activity_changedholds (strip set or order, or amatrix_or_panvariant change), not only when the automation table changes. So a mode switch that strands a stored pan entry is refusedcontrol.inactivebefore any commit.follows_muteandmatrix_moderows declare anAutomationRule::Excludedwith a reason and a reopen condition, and they are refusedcontrol.automation.targeton both hosts. The SDK tables and the control-list fixture follow.Evidence
batch-gates.sh: fmt, bench and realtime policies, the host-core feature matrix and loom, clippy, the workspace tests, the doc job, allcheck-*scripts, the cross targets, the web build, the SDK headless suite with 551 passing, and the fuzz check) passes on the integrated tree. The first run was cut short when the disk filled; the rerun passes.--check-matrix --self-test-mutationson the integrated tree: each prints "all qualification gates passed", including Boot an empty session on both hosts #1682's newempty-boot-*gates. Render allocations are 0 in every row,empty-bootandempty-boot-first-stemamong them.hosts/host-web/tests/control_parity.rs: Refuse a source with more than two channels #1681 (a three-channel source is refused alike at load and by structural edit, four rates); Boot an empty session on both hosts #1682 (empty boot, identical silence, list, state and snapshot bytes, then the first stem added by one transaction and heard bit for bit alike, four rates); Run the automation row rule when a row's activity changes #1631 (a mode switch under a stored pan entry is refused alike, four rates).crates/host-core/tests/empty_boot.rs,crates/capi/tests/empty_boot.rs(at 44.1, 48, 88.2 and 96 kHz) andhosts/host-web/tests/empty_boot.rs(render-locked allocator).audit capi:pcm_digestbf7dcedd1d92621f(unchanged), 0 allocations. Browser boot high-water growth 20,447,232 bytes (unchanged).sourcePcmStagingBytes130,560 to 1,024; thebridgeRetainedBytesceiling 1,812,352 to 1,667,648; the simd128memoryBytes3,014,656 to 2,883,584.check-browser-expected-resourcesmeasured the simd128 initial and before-disposememoryBytesat 2,818,048, one 64 KiB page less than 2,883,584. I bisected this to 167fc10 (Make a send's follows_mute and a strip's matrix_mode non-automatable #1632); the stream did not run this gate. A smaller boot is benign, so it is re-pinned from the measurement in 8fa4543. The set-control timeline row stays 2,883,584.control_commandpeak heap past Shrink the peak heap of a live-only commit #1615's 78,000 ceiling (81,451). The reference gives a 77,347 first peak and 72,588 steady.Review
One opus-high review of the 13a diff (origin/main...8fa4543, plus the numbering commit): PASS with findings, no BLOCKER or MAJOR. The reviewer ran the focused tests and the #1616 loom model, and proved the #1616 epoch arm and the #1631 classifier step red on revert. No ack precedes a drop: #1631 and #1681 refuse before commit, and #1616 discards only records that are not windows of the current stream. Folded in 9d12d49:
Recorded, no change:
RESULT_INVALID_ARGUMENTwith no last-error diagnostic.session-validatorcodes share one check rather than having a new test.Departures recorded in the specs
RESULT_INVALID_ARGUMENTwith no last-error diagnostic.crates/capi/tests/empty_boot.rsjoins the realtime policy's unsafe allowlist, like every capi test binary that calls the C entries.Issues filed from this batch's specs
refuse-a-source-with-more-than-two-channels(implemented here; closes with this PR).boot-an-empty-session-on-both-hosts(implemented here; closes with this PR).designate-the-browser-master-strip-after-boot(successor of Boot an empty session on both hosts #1682; stays open). Since an empty session boots, a master strip cannot be named at boot; Designate the browser master strip after boot #1683 makes the master designation something the app sets or changes after boot, through the one core path.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.