Skip to content

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
tamashi095 merged 17 commits into
mainfrom
codex/controls-batch-13a
Oct 15, 2026
Merged

tamashi095 merged 17 commits into
mainfrom
codex/controls-batch-13a

Conversation

@tamashi095

@tamashi095 tamashi095 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

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

  • Keep a one-shot spectrum window out of the continuous stream #1616 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.
  • Refuse a source with more than two channels #1681 One validator rule: Source::channels is 1 or 2, with the new typed code source.channels.unsupported, at load and in every structural edit, on both hosts. session::SOURCE_CHANNELS_LAUNCH_MAXIMUM = 2 is the one limit. The browser staging, the C ABI's plane bound and the SDK (new ABI-layout constant maximumSourceChannels) 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 now RESULT_INVALID_ARGUMENT at the boundary.
  • Expose the armed tap mask from host-core #1679 EffectObservationHandle carries armed_taps, which the core sets exactly when the lane armed a tap. The browser's build_plan_shape copies it, and its duplicate binding match is deleted.
  • Boot an empty session on both hosts #1682 An empty session (no source, track or route) boots on the core, the C ABI and the browser, and grows and shrinks by structural transactions. The one refusal on the path (EmptySources in prepare_graph_source_set) is deleted. HostPrepareCaps::maximum_source_channels is 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.
  • Run the automation row rule when a row's activity changes #1631 The classifier re-runs automation_diagnostics when controls::activity_changed holds (strip set or order, or a matrix_or_pan variant change), not only when the automation table changes. So a mode switch that strands a stored pan entry is refused control.inactive before any commit.
  • Make a send's follows_mute and a strip's matrix_mode non-automatable #1632 The follows_mute and matrix_mode rows declare an AutomationRule::Excluded with a reason and a reopen condition, and they are refused control.automation.target on both hosts. The SDK tables and the control-list fixture follow.

Evidence

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:

Departures recorded in the specs

Issues filed from this batch's specs

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

tamashi095 and others added 17 commits October 15, 2026 12:50
…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>
…ment

The #1632 list test asserts that an excluded row carries a reason and a
reopen condition, not their wording. The #1616 continuous read's comment
names both writers of the epoch and why one load still covers the loop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tamashi095
tamashi095 merged commit f0611aa into main Oct 15, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant