Calls storytold/craft-common-actions/.github/workflows/sonarcloud.yml@main
with secrets: inherit. Adds SonarCloud badge to README where missing and
removes the redundant sonar-project.properties (config now passed by the
reusable workflow).
Adds .coderabbit.yaml so CodeRabbit no longer reviews or comments on PRs opened by dependabot[bot].
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Use the existing begin/merge history contract for character styles, isolating clip, layer and selected ranges. Cover actual pointer gestures, undo/redo, fresh gestures and invalid targets.
ItemId wraps a u64 (item_p parses the `item` param with u64_p), so
reading activeSequence with as_i64 would silently return None for
any id above i64::MAX and make document()'s sequence go null instead
of inspecting the valid id project.inspect reported. Switches to
as_u64 and adds a regression test for that boundary (proven to fail
against as_i64 first).
Addresses a CodeRabbit review comment on #2480.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
document() composed project.inspect and sequence.inspect as two
separate round trips to the app (two lock scopes in headless mode,
two TCP round trips in bridge mode). sequence.inspect with no `item`
answers for whichever sequence is active *now*, not the one
project.inspect just reported, so if the active sequence changes in
that window (another client, or the app's own UI, switching tabs)
the pair comes back inconsistent: project.activeSequence names one
sequence while sequence describes another.
Reproduced against a running bridge-mode app: a real MCP client
hammering doc_inspect while an independent connection flipped
sequence.open between two sequences mismatched on ~300/300 calls, so
this is a wide window, not a rare edge case.
Fix: read project.inspect's activeSequence id first, then pass it
explicitly as sequence.inspect's `item`, so the second call always
describes the sequence the first one named, regardless of what
becomes active afterward.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Found while testing crates/time/src/lib.rs:423 (format_time, TimeDisplay::Seconds)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/time/src/lib.rs:418 (format_time, TimeDisplay::AudioSamples)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/color/src/lut.rs:290 (Lut::to_cube, the `both` branch)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
With the playhead outside a clip the tab shows the clip's text at its
start, but the edit went to graphics.set without a time, which writes at
the playhead clamped into the clip (its last frame). For keyframed text
the shown value stayed and another keyframe changed. Each row now keeps
the time it read its text at and the edit is written there; a new test
covers keyframed text with the playhead past the clip.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The new stopwatches show for every animatable parameter of the layer's
definition, but effects.toggleAnimation only found parameters stored in
the instance, so a layer saved before a parameter existed answered "no
such param". The parameter is now created from its default first (an
existing one and its keyframes are left alone). Engine test included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>