Skip to content

Staging - Add, bpm management - #350

Merged
Sportinger merged 52 commits into
masterfrom
staging
Jul 28, 2026
Merged

Staging - Add, bpm management#350
Sportinger merged 52 commits into
masterfrom
staging

Conversation

@kfxs

@kfxs kfxs commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Sportinger and others added 30 commits July 24, 2026 08:46
Pure computeTimelineOccupancy over clips/tracks: occupied span vs
clip-duration-sum (distinct numbers), per-track and global gaps/overlaps,
MIDI stack tracks never report overlaps, unassigned-track bucket,
deterministic ordering, 1e-6 epsilon. First consumer of the single
duration semantics; existing 14 ad-hoc computations migrate later.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
withTimelineRevision wraps the store creator: one atomic increment per
set/setState call whose watched keys (clips, tracks, clipKeyframes,
markers, masterAudioState) change identity. Covers all 52 direct setState
sites and history restores without per-action edits. Monotonic within a
session; revision-only writes never self-bump. getTimelineRevision()
exposes the counter for stale-plan detection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cancelBatch() gives historyStore a real abort (restore pre-batch snapshot,
stacks untouched). beginAgentTransaction/commit/abort wrap tool-call
groups: one transaction per chat turn instead of one undo entry per tool,
inner calls suppressed, executeBatch paths only close batches they own,
revisions captured via getTimelineRevision. Thrown errors roll back.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… (WP2-D)

Additive occupancy block from computeTimelineOccupancy plus the central
timelineRevision. First bridge-visible consumer of the canonical
semantics; also the calibration surface for the agent-kernel adapter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
youtube/localImport append points now use computeTimelineOccupancy; export.ts documented as state.duration-based (semantics preserved).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rnel adapter calibration)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
split/splitEvenly/splitAtTimes/cutRanges/trim additively report
entities.created/updated/deleted (clip refs incl. linked audio) and
stateRevisionBefore/After. Kills the model-copied-ID-list problem at the
source: dependent edits can consume returned identities directly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rage

startBatch flushes pending debounced captures (user edits become their own
undo entry, never swallowed into an AI batch); cancelBatch drops pending
timers (no redo-clearing no-op entries). Grouped tool execution aborts on
any failed mutating result instead of committing partials; suppressHistory
honored; transaction ownership verified at commit/abort. Revision watches
duration/in-out/tempo fields, skips store cloning for unwatched patches,
and the bridge occupancy block reads revision from its own snapshot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dits (WP2-FIX2)

Monotonic batch counter replaces Date.now collisions; beginAgentTransaction re-reads batch state after the pre-start flush; audits complete after group outcome with rolledBack markers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…led (WP2-FIX3)

startBatch returns {opened,batchId}; transactions never adopt foreign batches as owned. Rolled-back mutations audit as success:false partialTransaction with the original result preserved.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nel WP7)

Store-agnostic timeline checks (counts, gaps, overlaps, order, AV-link, occupancy) with a registry; guided validation delegates without behavior change. One verification core, no parallel systems.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, move/reorder/speed (WP4)

Shared mutationEntityResults helper; additive entities+revision blocks on nine more mutating handlers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ng locked (agent-kernel WP3)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… WP11 prep)

Typed HTTP client for run/validate/manifests/runs/amend/health; no kernel logic, structural types only, per plan 21.1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…11 slice 1)

The in-app chat tries the kernel service before the legacy provider loop
(strangler pattern). Default OFF via localStorage flag; not-mechanical,
service-down, and network errors fall through untouched; succeeded runs
answer with a Kernel-verified summary and fingerprint. Zero behavior
change when disabled.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Packets 1 and 4 of the BPM management plan.

Packet 1 — tempo editing core:
- new pure src/timeline/tempo/tempoEdits.ts owning every invariant (sort,
  dedupe by time, pinned first event, clamps, id backfill/repair)
- TempoEvent.id, required at runtime and optional in the project tier;
  normalizeRulerLaneState now normalizes instead of passing through, so
  pre-#299 projects gain ids at the single load seam
- editable BPM range [20, 999] — deliberately NOT the 60/200 detection bins
  from beatGridEstimation, which would reject 40 and 240 BPM
- new tempoSlice (setProjectTempo / add / update / removeTempoChange),
  capturing history AFTER the mutation like midiClipSlice
- tempoMap threaded through all 12 history sites; restore falls back to the
  live map so a pre-#299 entry cannot clobber it on undo

Packet 4 — tempo-driven body grid and snapping:
- new pure src/timeline/tempo/barsGrid.ts: explicit bar/beat/subdivision line
  times plus the pixel thresholds the bars ruler also uses, so ruler ticks and
  grid lines can never disagree
- an ENABLED Bars+Beats ruler lane wins the grid (not activeRulerLaneId, which
  is retired as a grid seam); bars replace the time/frame grid
- grid snapping in both snap paths with a pixel-derived threshold, since a
  1/16 at 120 BPM is narrower than the fixed 0.15 s window
- timelineGridSubdivision view preference (localStorage) with the picker in
  the Rulers menu

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Completes commit 41c8929, which referenced this export from
registrySnapshot.ts while the export itself was left uncommitted.
Build verified green at HEAD+fix in a clean worktree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Packet 2 of the BPM management plan, plus a Rulers menu UX fix.

Content follows tempo:
- new pure src/timeline/tempo/tempoRemap.ts — remapAcrossMaps,
  trackFollowsTempo, remapMidiClip, remapTimelineClipsForTempo
- MIDI clips, notes and the four CC automation lanes are remapped through
  old map -> bar/beat -> new map; video/audio/image clips keep their seconds
  and their object identity
- durations are never scaled by a factor: ends are remapped and the remapped
  start subtracted, which is the only correct answer across a tempo boundary
- everything is anchored on the clip's content origin, so noteAbsoluteStart
  stays exact and the window cannot drift from its notes
- tempoSlice commits the remapped clips and the new map in one set under one
  snapshot, so a single undo reverts tempo and notes together

TempoMap fix:
- barBeatToSeconds now extrapolates through segment 0 below the first
  segment. With more than one segment every range test failed and it fell
  through to the LAST segment, returning nonsense for bar <= 0 — reachable
  through a left-extended MIDI clip's negative inPoint
- new barBeatToSecondsAt object wrapper

Rulers menu:
- clicking a lane row toggles the lane again (checkmark + highlight); the
  grid resolution moved behind a + expander on the Bars + Beats row and is
  indented under it, so one click never means two things

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e/transform tools (agent-kernel WP4)

Shared helper consolidation replaces three private snapshot helpers;
entity kind union extended to the kernel contract vocabulary
(mediaItem/composition/folder).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…proper media entity kinds (agent-kernel WP4)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…y (agent-kernel WP2)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ings expose mediaId (agent-kernel WP4/WP2 calibration)

Restores the kernel adapter contract after envelope consolidation and
gives linked A/V pairs a shared source identity in tool listings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…c (agent-kernel WP15 app side)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ion core (agent-kernel WP7/WP11)

New-tool integration touched exactly: one definition group, one policy
entry, handler + dispatch, tests - the WP11 tool-addition evidence.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Packet 3 plus two model fixes found while testing it in the app.

Tempo lane (Rulers -> Tempo, stacked under Bars + Beats, never selectable as
the active lane):
- flags read "4/4 - BPM = 120"; editing swaps only the value being changed for
  a field, so the rest of the label stays readable
- right-click the lane: Add tempo change / Add time signature change, inserted
  at the nearest bar with the relevant editor already armed and selected
- right-click a flag: Change tempo / Change time signature / Ramp toggle /
  Delete (Delete disabled on the project tempo)
- drag to move, snapped to bars, Alt for free placement; one undo per gesture
- the menu portals to document.body: the lane lives inside .time-ruler, which
  has a transform and two overflow:hidden wrappers, so a fixed-position menu
  was being positioned against the wrong box and clipped away
- dismissal listens in the CAPTURE phase, since the flags themselves stop
  mousedown propagation and a bubble listener never fired

Ramps (plan 3.3 said out of scope; now supported):
- TempoEvent.curve = 'jump' | 'ramp'; 'ramp' reaches the tempo by interpolating
  from the previous event across the interval leading into it
- TempoMap integrates a linearly varying tempo: elapsed beats are quadratic in
  time and the inverse solves that quadratic in closed form, so 60 -> 120 over
  8 s covers 12 beats (the average), not 8
- dashed sloped indicator across the ramped interval plus an arrow on the flag

Model fixes:
- content is anchored to its QUARTER-NOTE position, not to (bar, beat). Bar and
  beat made a pure meter change (4/4 -> 3/4 at the same BPM) drag every note
  sideways even though no note's duration changed
- tempo marks are re-anchored on every edit so they stay on their BAR. They are
  stored in seconds, so a ramp changing the length of the preceding interval
  used to slide a flag placed on bar 11 to bar 11.5. An explicitly set position
  (insert or drag) still wins, so a dragged flag lands where it was dropped

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…mark passes report cancelled

- deleteMediaItem test expects the WP4 envelope
- OCR gate fixtures carry the new baseline identity fields
- legacy artifact events include camera-motion
- precise type-module imports keep the foundation barrel budget
- localBenchmarkRunner: warm-cache blocking applies to completed runs only

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
kfxs and others added 12 commits July 27, 2026 16:45
A read-only mirror of the timeline's tempo lane, stacked between the Time and
Bars rulers so tempo sits directly above the bars it drives.

- follows the timeline's Rulers -> Tempo toggle, so one setting drives both
  views instead of a second hidden one (and it is already project-persisted
  through rulerLanes, from #257)
- same labels, ramp arrow and dashed sloped indicator as the timeline lane;
  flags are pointer-events:none so they never swallow ruler scrubbing
- built as a separate inline-styled renderer rather than reusing
  TempoRulerLane: the piano roll is a detached popup, and in dev the app CSS is
  injected as <style> tags that are not mirrored into it, so Timeline.css
  classes do not exist there
- PIANO_ROLL_RULER_H replaced by pianoRollRulerHeight(laneCount), since the
  ruler is no longer a fixed two lanes

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Selecting a MIDI track defaulted to Track controls. The instrument is what you
actually reach for on a MIDI track — volume/pan already live in the mixer — so
it now opens there. Audio tracks still open on Track effects and every other
track type on Track controls.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…P11 deletion item)

Plan authorizes absorb-or-retire; the kernel path replaces the
options-preflight prototype. FlashBoardChatOptionsPlanner (general
provider/model logic) stays.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ion local execution, fingerprint completion (agent-kernel WP11)

Default-on when kernel url+token are configured; v1 run-string gateway
test retired in favor of the cutover suite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Packets 5 and 6 of the BPM management plan.

Engine:
- src/engine/audio/metronomeVoice.ts — one oscillator + gain with a ~40 ms
  exponential decay; 1000 Hz at full level on the downbeat, 800 Hz at 0.7
  otherwise. No assets, no sample loading. A click whose time has already
  passed fires immediately rather than being dropped
- src/services/audio/metronomeScheduler.ts — the look-ahead pattern from
  midiPlaybackScheduler: 25 ms timer, 0.12 s window, timeline<->context anchor,
  re-anchor on a >0.25 s seek, silence at non-1x speed, dedup so a beat inside
  two windows fires once
- beat times come from iterateBarBeatLines, so the click tracks meter, mid-window
  tempo changes and RAMPS with no new math
- routing per plan 3.4: its own GainNode straight to AudioContext.destination,
  never a registered node route, so it cannot reach master metering, the
  FX/limiter chain or an export; an isExporting guard sits on top

UI:
- MetronomeButton after the Rulers menu: the button toggles, a separate caret
  opens a popover with volume and Every beat / Bars only
- metronomeEnabled / metronomeVolume / metronomeMode are per-user localStorage
  view state like snappingEnabled, never project content (plan 3.6). Pulled
  forward from Packet 6 into Packet 5 because the engine needs something to read

Count-in is deliberately NOT included. A real pre-count sounds the click for N
bars while content stays silent, which needs a new transport phase rather than
a playhead roll-back; play() has nowhere for "running but not advancing". The
plan allows shipping the toggle and volume first rather than bending playback.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…nel WP11)

Bridge and in-app audits now see kernel-first turns; verified E2E:
in-app sentence -> /kernel/compile -> one local transaction ->
fingerprint-complete -> Kernel-verifiziert with runId reference.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…call; deferred rollback never falls back silently

Sequential per-call execution builds the sim-to-real binding from the
split segments payload; abortNoop transactions report honest failure
instead of double-editing via legacy fallback. Live E2E: split+shuffle
kernel-verified (20+20, non-monotonic order, fingerprint match).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Packet 7, plus three architecture-ratchet fixes the full chain surfaced from the
metronome packets (which were fast-committed without checks).

Docs:
- new docs/Features/Tempo-And-Metronome.md — what you can do, then the three
  ideas the feature rests on, each written around WHY, since each was wrong at
  least once while building: BPM sets duration while the meter only groups; MIDI
  is musical and media is linear; a tempo mark is a musical object
- Timeline-Rulers.md gets a superseded-in-part banner and its two now-false
  claims corrected in place: it no longer "ships no grid/snap behavior", and the
  click-to-select active-lane seam was retired in favour of "an enabled bars
  lane wins the grid"
- Features/README.md indexes the new page; ongoing/README.md marks the plan
  complete
- the plan doc gains per-packet landing notes and a new section 11 recording
  where the shipped feature diverges from it (ramps, quarter-note anchoring,
  musical re-anchoring, the smaller deviations, and the two bugs that
  mutation-testing our own tests caught)

Ratchet fixes:
- the metronome bootstrap moved from useLayerSync (which is under a hard LOC
  cap it pushed over) into editorBoot, where the other app-wide services start.
  A global audio service was never part of layer sync
- metronomeScheduler registered in the getState access policy at 4 hits, the
  same class as midiPlaybackScheduler; baselines bumped with the reason
- kept the registry file inside its own 300-line budget

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The architecture registry budget test measures split(/\r?\n/).length, so a
newline-terminated file scores content lines + 1. Both staging and this
branch sat at 299 content lines = exactly 300, so the merge of the two
(staging's muscriptor adapter grant + this branch's metronomeScheduler
entry) scored 301 and failed CI, even though neither branch fails alone.

Drop the per-packet bookkeeping comments left over from the closed
Complete Refactor (packets 231/267/291/306/307/342/343/345, the
dockStore-folder note, and the multi-line ratchet log in the baselines);
that history lives in git and in docs/completed/refactor/. No entries,
paths or baseline numbers change, so the file is 281 lines with real
headroom instead of zero.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Conflict in src/architecture/getStateAccessPolicy.ts resolved by keeping
this branch's trimmed baseline block and combining both sides' numbers:
staging's allowedAdapterPathCount 26 (muscriptor adapter grant) plus this
branch's metronomeScheduler entry on top of staging's ledger
(237 -> 238 files, 674 -> 678 hits).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 27, 2026

Copy link
Copy Markdown

Deploying masterselects with  Cloudflare Pages  Cloudflare Pages

Latest commit: 63b7e93
Status: ✅  Deploy successful!
Preview URL: https://fedb4755.masterselects.pages.dev
Branch Preview URL: https://staging.masterselects.pages.dev

View logs

Sportinger and others added 10 commits July 27, 2026 20:43
…ecise type-module imports

kernelChatGateway builds its snapshot through executeAIToolCalls instead
of reading the store (getState access policy, plan 8.3); two BPM-PR
barrel imports narrowed to types/timeline (foundation type budget).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ry section replaces stale 86-tool count

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nel gateway (agent-kernel story cutover, app side)

Moments are built on-device from getClipTranscript pages (text+timings
only, 400-word cap) and sent solely to the configured kernel service;
story compiles create/open the target composition inside the same agent
transaction before executing resolved calls.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pile timeout, Logger-visible fallback reasons

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Transcripts are persisted on the media file, but agent-facing reads
(getClipTranscript, findSilentSections, listings, clip details) only saw
the clip-instance copy, so re-added or restored clips reported
hasTranscript while returning no words. All reads now go through
resolveClipTranscriptWords: clip words win, media-file words are the
fallback; hasTranscript is computed from the same resolver.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Matches the kernel-side rename; keeps kernel-internal vocabulary out of
the public client per the isolation test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…properties panel falls back to media transcript

History edit states only carry transcriptStatus, so undo/redo and
history-mediated rebuilds produced clips with status ready but no words.
Restore now reuses the live clip words or re-derives them from the media
store, and the properties panel transcript tab reads through the same
media-anchored resolver.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ent schema

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tures use storySummary

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Sportinger
Sportinger merged commit 6d6d968 into master Jul 28, 2026
7 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

Development

Successfully merging this pull request may close these issues.

2 participants