chore: fold the v0.2.0 release-audit follow-ups into the release#33
Merged
yultyyev merged 4 commits intoJun 18, 2026
Merged
Conversation
…orkspace resolveInWorkspace checked containment on the lexically-resolved path, so an in-workspace symlink pointing out of the tree was followed at FFmpeg-open time — the boundary it exists to enforce (AGENTS.md non-negotiable #3) leaked. Canonicalize both the workspace and the resolved path before comparing: walk the existing prefix with lstat, follow symlinks explicitly (so a DANGLING in-workspace link resolves toward its real, possibly out-of-tree, target instead of looking like an in-workspace leaf), and treat only a genuine ENOENT as a not-yet-created tail — EACCES / symlink loops fail closed. A symlinked workspace root (macOS /var -> /private/var) is collapsed too, so legitimate paths aren't rejected. The lexical resolved path is still returned, so an in-workspace symlink to an in-workspace target keeps working. Residual (documented): an open-time TOCTOU race needs O_NOFOLLOW at the open site, out of scope here.
applyVerbs re-lowers and retries on a CompositionConflictError (the optimistic expectedBaseRev guard) but capped the loop at a hardcoded 4, while the inner commit loop allows MAX_COMMIT_ATTEMPTS (8). A burst of >4 concurrent edits against the same base rev therefore dropped its tail: the 5th+ writer exhausted its retries and lost the edit. Align the cap to MAX_COMMIT_ATTEMPTS so each concurrent edit re-lowers against fresh state and lands. Latent today (the shipping UI has no concurrent caller of the verbs path), but closed before the API gains one. expectedBaseRev stays load-bearing — the guard is what forces the re-lower. Adds a deterministic regression test that races a burst through a barrier so each writer needs an increasing attempt count.
A per-clip fadeIn/fadeOut on the same cut as a transition double-darkened (the xfade already blends that window). Suppress the fade on a transition boundary so the xfade owns the blend — but only when the fold actually emits an xfade there. A transition keyed to the LAST clip (e.g. left dangling after the next clip was removed) blends nothing, so gate fadeOut suppression on a following clip existing; otherwise a fade-to-black at the timeline end was silently dropped to a hard cut. Outer-boundary fades and fades on plain cuts are untouched. Adds regression tests for the matched-boundary case and the dangling-transition (last-clip) case.
- Document the `clip timeline` composition workflow (new → add-media → transition → show → export, with undo/redo and read-only show/at/frame) in README, SKILL.md, and the top-level `clip --help` (it was reachable but unlisted). - Reframe the source-of-truth narrative: the Composition document is canonical for assembled edits; session.json is the append-only op log of tool calls (was "the session is the source of truth", which contradicted the code and AGENTS.md non-negotiable #2). - Refresh the stale "356 tests" claim to 539 (README badge + FAQ, llms.txt). - Remove competitor brand names from the TransitionKind JSDoc (it ships in dist/index.d.ts); the README/llms comparison prose keeps its intentional naming. - Drop the hand-maintained, drifting SKILL.md frontmatter version field.
|
🎉 This PR is included in version 0.2.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
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.
Folds all 7 follow-ups from the pre-release audit into v0.2.0 so the release ships complete, rather than tracking them for v0.2.1. Three are correctness fixes with regression tests; the rest are docs/cleanup. Stacked on the integration branch; merge before
phase0 → main.Code fixes (with regression tests)
fix(timeline): follow symlinks when confining agent/UI paths.resolveInWorkspacechecked containment on the lexical path, so an in-workspace symlink pointing out of the tree was followed at FFmpeg-open time. Now canonicalizes both sides via anlstatwalk that follows symlinks explicitly (incl. dangling links → their real out-of-tree target) and fails closed onEACCES/symlink-loops; only a genuineENOENTis a not-yet-created tail. A symlinked workspace root (macOS/var→/private/var) is collapsed so legit paths aren't rejected. Residual (documented): open-time TOCTOU needsO_NOFOLLOW, out of scope.fix(timeline): widen theapplyVerbsretry toMAX_COMMIT_ATTEMPTS. The re-lower loop was capped at a hardcoded 4 while the inner commit loop allows 8, so a burst of >4 concurrent edits dropped its tail. Latent today (no concurrent caller of the verbs path ships), closed before the API gains one.expectedBaseRevstays load-bearing. Deterministic barrier-based race test added.fix(timeline): drop per-clip fades only on real transition boundaries. Suppressing a per-clip fade on a transition cut (to avoid double-darkening) over-fired on a transition keyed to the last clip — which the fold never xfades — silently dropping a fade-to-black to a hard cut (reachable byremoveClipon the final clip). Now gated on a following clip existing.Docs / cleanup
clip timelineworkflow in README, SKILL.md, and the top-levelclip --help(it was reachable but unlisted).session.jsonis the op log (was "the session is the source of truth", contradicting the code + AGENTS.md feat: walking skeleton — clip CLI + Claude Code skill (trim tool) #2).TransitionKindJSDoc (it ships indist/index.d.ts); the README/llms comparison prose keeps its intentional naming.versionfield.Verification
These fixes were found by an adversarial review of the first cut of this branch (each finding double-verified by reproduce + refute lenses); all three confirmed findings are fixed here and covered by new tests.
Gate green:
pnpm type-check,pnpm test(539 pass),pnpm lint(7 pre-existing warnings only),pnpm build;npm packsurface re-checked brand-free.🤖 Generated with Claude Code