Skip to content

feat(movie): support native Windows PowerShell and Git Bash - #2275

Merged
arittr merged 24 commits into
import/proving-it-works-skillfrom
feat/movie-os-compatibility
Sep 12, 2026
Merged

arittr merged 24 commits into
import/proving-it-works-skillfrom
feat/movie-os-compatibility

Conversation

@arittr

@arittr arittr commented Sep 10, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #2214. This PR targets import/proving-it-works-skill, mirrored at the exact #2214 head f6617db1517488d4a8b66925519d5ffbeef965b3, so the diff contains only the Windows work above the original import. The stack's ultimate target is dev. Merge #2214 first, then retarget this layer onto dev. GitHub's native Stack UI cannot include #2214 because its head is in the ada-sen/superpowers fork, so this is a branch-based stack with an explicit dependency; the mirrored base must be updated if #2214 changes.

Draft for Drew's review. Full-desktop application capture is unverified on the tested host; window-title capture works.

Who is submitting this PR? (required)

Field Value
Your model + version Media-tool fixes and instructions: OpenAI Codex gpt-6-astra at medium reasoning, with an initial gpt-5.6-luna worker. Scope reduction, the terminal recorder rewrite, and test cleanup: Claude Fable 5.1 (claude-fable-5-1).
Harness + version Codex CLI 0.153.4 through Paseo 0.8.0-beta.1 on macOS for the media work; Claude Code for the recorder rewrite and cleanup. Native instruction evaluations: Claude Code 2.1.267 on Windows.
All plugins installed Codex sessions: superpowers@superpowers-dev 6.3.0, stream-deck-agents-codex@drew-local, deep-research-work 0.1.15, plugin-management 0.1.0. Claude Code session: superpowers, superpowers-chrome, episodic-memory, decision-log, linear, primeradiant-ops, cloud-build, iterative-development, elements-of-style. The Windows evaluations loaded the candidate Superpowers plugin and its bootstrap.
Human partner who reviewed this diff Drew Ritter directed the work, reviewed the spec, asked for the diff against #2214, asked for the branch to be cut down and the recorder simplified, and requested this draft to review it. Complete human diff review is pending.

What problem are you trying to solve?

Drew asked what Windows support looked like for #2214 and requested native Git Bash and PowerShell support. Actual Windows runs of the imported skill failed: FFmpeg's glob input is unsupported on Windows, the subtitle filter misreads C:\ paths, text files were read in the cp1252 locale so UTF-8 and BOM input broke, browser discovery only knew Mac and Linux paths, and the narration verifier spawned python3, which does not exist on Windows, so --verify on silently passed without transcribing. The terminal recipe depends on tmux, which Windows does not have, and the docs had no PowerShell or Git Bash commands.

Before the doc changes, a native PowerShell agent had to infer the recorder interface from source and broke on special-path quoting and BOM-bearing JSON. A Git Bash agent passed /c/... to native Python and got a C:\c\... file-not-found error.

What does this PR change?

  • The five tools read and write explicit UTF-8, accept BOM and CRLF input, stage frame sequences instead of relying on globs, escape ffconcat entries, copy the SRT to a safe basename before the subtitle filter, find Chrome or Edge on Windows, and run local transcription through an isolated uv-managed Python. --verify on now transcribes cached clips too and fails when the transcriber is unavailable. Two small helpers, browser_tools.py and media_paths.py, are shared by the tools.
  • A terminal recorder that stands in for tmux, examples/film-terminal.py, keeps the Unix route's shape: serve starts ttyd on the chosen shell and a headless Chrome or Edge page showing it, keeps both alive in a background task, and logs the terminal output. run, key, watch, and close are one-shot CDP calls against that browser, so the shell and its state persist across tool calls. The installed prompt reports each command's status through the window title, invisible in the picture, and run prints it. Frames are screenshots at 5 fps in a fixed 1600×900 viewport. Cleanup is taskkill /T.
  • Windows sections in SKILL.md, assembling.md, narrating.md, recording-a-terminal.md, and recording-motion.md give copyable PowerShell and Git Bash sequences.
  • A Python regression suite replaces the three shell tests from feat(skills): import proving-it-works-with-a-movie skill #2214 with the same assertions plus coverage for each fix above. The shell versions are removed so there is one suite that runs on all three platforms. The recorder's session tests run anywhere ttyd and a Chrome-family browser exist, including macOS.
  • One design doc under docs/superpowers/specs/.

Is this change appropriate for the core library?

It extends the general-purpose movie skill being imported by #2214 to the Windows shells Superpowers already supports. It preserves the five CLI interfaces and the Unix tmux recipe. The recorder needs ttyd and a script-local websocket-client dependency; no global install dependency or paid service is introduced. Those workflow dependencies belong in the same conversation as #2214's existing FFmpeg and browser requirements.

What alternatives did you consider?

  • WSL-only support would not exercise native PowerShell or Git Bash.
  • Separate media pipelines per shell would duplicate the Python tools; both shells now call the same uv run --script commands.
  • A broader multi-OS rollout was started, stopped, and replaced by this Windows-only scope. Its probe, plans, and evidence drivers were removed from the branch.
  • An earlier recorder design was a daemon with a file-based request protocol, request IDs, and a Win32 Job Object module. It worked but was 1,700 lines across code, tests, and docs; it was replaced by the current one-shot-command design at about a third of that.

Does this PR contain multiple unrelated changes?

No. The tool fixes, the recorder, the instructions, and their tests all serve the one Windows workflow.

Existing PRs

Environment tested

Harness (e.g. Claude Code, Cursor) Harness version Model Model version/ID
Claude Code, native PowerShell tool 2.1.267 Sonnet claude-sonnet-5, low effort
Claude Code, native Git Bash tool 2.1.267 Sonnet claude-sonnet-5, low effort
Codex through Paseo, and Claude Code, driving native and portable test runs 0.153.4 / 0.8.0-beta.1 GPT-6 Astra, GPT-5.6 Luna, Claude Fable 5.1 gpt-6-astra, gpt-5.6-luna, claude-fable-5-1

Native host: Windows 11 build 26200, x64, Python 3.12.14, uv 0.12.12, FFmpeg 9.0.1 with libass, ttyd 1.7.7, PowerShell 5.1.26100.9168, PowerShell 7.6.6, Git Bash 5.3.9. No WSL, administrator rights, cloud key, or machine settings changes were needed; the final Windows run was made as an ordinary user with a Medium integrity token.

New harness support (required if this PR adds a new harness)

Not applicable.

Evaluation

Four instruction sessions with one fixed Windows scenario, same product code, model, and caches; only the docs changed between baseline and candidate. They ran against the earlier recorder design; the recorder's command surface has since been simplified and its documentation rewritten, and those sessions were not repeated.

Session Result
PowerShell baseline Inferred the recorder interface from source; failed on quoting and BOM JSON. Stopped at the documentation gap.
Git Bash baseline Passed /c/... to native Python; failed before repair. Stopped at the gap.
PowerShell candidate Followed the documented workflow end to end. Partial: skipped transcribing the rendered final audio.
Git Bash candidate Built the movie and ran the media, checker, and evidence steps. Incomplete: hit the harness turn cap before final-audio transcription.

Transcripts are retained locally and are not in this PR.

Rigor

  • Used superpowers:writing-skills for the doc changes with the four before/after sessions above.
  • Tested adversarially: observed Windows failures plus controlled failure paths (bad browser override, browser timeout, missing libass, unavailable or malformed transcription for fresh and cached clips, missing cwd, a command still running at the deadline, and process-tree cleanup with an unrelated sentinel process).
  • Did not modify Red Flags, rationalization, or human-partner language.

Validation of the current head:

  • Windows 11, as an ordinary user: the recorder's nine session tests pass for PowerShell 5.1, PowerShell 7, and Git Bash, covering status reporting and exit codes, state persisting across separate calls, a TUI filmed across two takes with its three states in order in the automatic frames, a long command spanning calls, and cleanup of a three-deep process tree. The browser suite passes with Chrome and with Edge.
  • macOS: 44 portable tests pass with zero skips, including the same session tests against a real ttyd, and a filmed take assembles and runs through the checker.
  • The media tools were validated at 8a31ffc3 with three complete native movies, one per shell: all five tools, contact-sheet and hard-caption inspection, final rendered narration transcription, and source-audio checks. The media code is unchanged since, apart from the card renderer's cleanup path, which the Windows browser suite covers.
  • Named-window gdigrab capture produced readable application pixels. Full-desktop capture returned zero with only wallpaper and remains unverified.
  • One Windows quirk is handled in code: Git Bash under ConPTY can lose the first keystroke of a session, so serve spends it on a bare Enter before installing the prompt.

Reproduction entry point: tests/proving-it-works-with-a-movie/README.md.

Human review

  • A human has reviewed the COMPLETE proposed diff before submission.

Drew asked for this draft so he can do that review. The unchecked box is deliberate.

@arittr
arittr marked this pull request as ready for review September 10, 2026 05:40
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

arittr and others added 3 commits September 9, 2026 22:53
The first, broader OS-compatibility rollout was stopped and replaced by the
narrower Windows completion. Its feasibility probe, probe cleanup test,
design, review, 12-task plan, results report, and the completion plan and
review record were internal execution artifacts with machine-specific paths.
The one probe-derived test list is inlined into the terminal suite.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Python suite ported the three shell tests' assertions so they run on
Windows; both copies were kept and the README mapped one to the other. Keep
the portable suite. Drop the one-shot Windows acceptance driver and its
browser fixture, which produced evidence rather than regressions, and the
never-implemented reserved suite names.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Remove generic shell exit-status recipes and a stills wrapper that the card
scene already covers. Keep the gdigrab commands and the verify-on notes
short. Reduce the spec to the design: drop execution logistics, host names,
and references to deleted files.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@arittr
arittr marked this pull request as draft September 10, 2026 05:54
arittr and others added 2 commits September 9, 2026 22:56
The in-process narration and subtitle tests let the tools' stdout and
stderr through to the runner. Capture both and assert the expected
diagnostics.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…watch/close

Windows has no tmux, so the recorder had grown into a 738-line daemon with a
file-based request protocol, request IDs, wait-only result retrieval, and a
Win32 Job Object module. Replace it with the Unix route's shape: serve keeps
ttyd and a headless browser alive and logs the terminal's output; run, key,
watch, and close are one-shot CDP calls against that browser. The installed
prompt reports each command's status through the window title, so run can
print it without any visible marker.

Process cleanup uses taskkill /T (a pgrep walk on Unix) instead of Job
Objects, which also simplifies the card renderer. The session tests run on
macOS too, since nothing in the script is Windows-specific.

Verified: 9 session tests per shell on Windows 11 for PowerShell 5.1,
PowerShell 7, and Git Bash; the browser suite with Chrome and Edge; 44
portable tests on macOS against a real ttyd session.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@arittr
arittr marked this pull request as ready for review September 11, 2026 23:21
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-12T00:18:02.878719Z 9fe81b4 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 26c44ceee0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.10"
# dependencies = ["websocket-client==1.9.0", "pillow"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove the new third-party WebSocket dependency

The new recorder requires websocket-client, and the test runner additionally declares websockets, even though this change explicitly is not new harness support. Script-local installation does not avoid the repository's prohibition on optional or required third-party dependencies, so this implementation must use the existing dependency-free surface or live outside core.

AGENTS.md reference: AGENTS.md:L36-L38

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Retain the recorder's used websocket-client dependency with Drew's explicit approval. 4d4ede29 removes unused websockets from the test runner.

The scoped dependency approval is recorded in the repair plan.

Comment on lines +9 to +13
Windows has no tmux, so the example script holds the session instead. `serve`
starts ttyd on the shell you name and a headless Chrome or Edge page showing
it, keeps both alive, and appends the raw terminal output to
`SESSION/terminal.log`. Every other verb is one short call against that
browser. Run `serve` in a background task your harness keeps alive, the way

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Re-run evaluations against the rewritten workflow

The commit's Evaluation section says all four instruction sessions exercised the earlier recorder design and were not repeated after this command surface and documentation were rewritten. Consequently there is no before/after or adversarial behavioral evidence for the instructions that will actually ship; repeat the sessions on this exact workflow and report those results before landing the skill change.

AGENTS.md reference: AGENTS.md:L93-L100

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fresh-reader baseline: Git Bash stops on the copied PowerShell & syntax; PowerShell 7 succeeds from a new directory. Final recipes in 9fe81b48 passed native PowerShell 5.1, PowerShell 7, and Git Bash trials covering readiness, echo, persistent shell state, interactive key continuation, long-command watch continuation, and close. Full transcripts and detailed reports (candidate-ps-report.md and candidate-bash-report.md) are retained locally; old recorder trials are not presented as evidence for this interface. These trials do not establish general skill auto-triggering or movie acceptance.

Committed results and evidence limits. The implementation worker accidentally ran a temporary-frame integration assertion before stopping; Drew was informed, and that run is excluded from acceptance evidence. The requested review videos were not opened.

Comment on lines +144 to +145
out.mkdir(parents=True, exist_ok=True)
start, index, last, stop = clock(), -1, None, None

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Clear stale frames before recording a replacement take

When a failed or unsatisfactory take is retried with the same --record directory, film() overwrites only the frame indexes reached by the new run and leaves any higher-numbered PNGs from the previous run. The assembler later consumes every PNG in that directory, so a shorter retry silently ends with footage from the old take; remove existing frame-pattern files or require an empty output directory before capture.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4d4ede29 refuses a nonempty take before run/key/watch session side effects and before direct capture. Existing frames and unrelated sentinel bytes are preserved. Choose a new or empty take directory.

Comment on lines +34 to +35
From Git Bash the commands are the same with `skill=$(cygpath -m ...)` and
`work=$(cygpath -m ...)`, as in assembling.md.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Provide commands that are valid in Git Bash

For a user invoking the recorder from Git Bash, these lines say to reuse the PowerShell commands, but those commands begin with PowerShell's & uv call operator; Bash reports a syntax error when & prefixes a command. This leaves the advertised Git Bash terminal workflow without a runnable sequence, so document an actual Bash version, including how the blocking serve process is kept alive.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9fe81b48 replaces the PowerShell shorthand with actual Git Bash blocks, native path conversion, background-task lifetime, bounded readiness, run/key/watch/close, and expected exit-2 handling. The final native Git Bash trial completed successfully. Two preliminary outer driver launch failures were preserved separately; they occurred before the recorder ran.


```powershell
$skill = 'C:/path/to/skills/proving-it-works-with-a-movie'
$work = "$HOME/movie O'Brien λ & [take]"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Create the PowerShell work directory before serving

On a fresh recording, assigning $work does not create that directory, while serve() explicitly exits when --cwd is not already a directory. Copying this documented PowerShell sequence therefore fails before ttyd or the browser starts unless some unrelated prior step happened to create the path; create $work before invoking serve.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not reproduced for the documented recipe. serve creates $work/session with parents before checking $work, so the fresh cwd exists by validation time. A fresh-reader native PowerShell 7 baseline completed setup, persistent state, running status, and close without pre-creating $work. The earlier isolated reproduction placed the session outside cwd and did not match the documented layout. Explicit directory creation in the updated example is clarity, not a required runtime fix.

return True

stdout, stderr = io.StringIO(), io.StringIO()
with patch.object(sys, "argv", ["burn-subtitles", str(movie), str(subs), str(output)]), patch.object(module, "has_libass", return_value=True), patch.object(module, "run", side_effect=fake_run), redirect_stdout(stdout), redirect_stderr(stderr):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip subtitle tests when FFmpeg is unavailable

In an environment without FFmpeg, these ostensibly mocked unit tests still call burn-subtitles.main(), whose initial shutil.which("ffmpeg") check raises SystemExit before the mocked has_libass or run functions are reached; the integration test also calls has_libass() directly and raises FileNotFoundError. Thus the default portable suite fails rather than reporting the unavailable capability as a skip as its README promises; mock the availability check in unit tests and guard the integration test.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4d4ede29 mocks executable discovery in subtitle unit tests and checks real integration prerequisites before probing libass. With only uv on PATH: four tests pass, one capability test skips, ordinary mode returns 0 and strict mode returns 1.

Prevent failed narration scenes from entering the cache manifest, while leaving their generated WAV files available as failure evidence. Add filesystem-backed regressions covering repeated rejected chat synthesis, accepted-scene reuse, and strict ASR rejection of cached audio.

Refuse nonempty recording directories both before CLI session side effects and at the direct film boundary. The regression preserves existing numbered frames and a sentinel byte-for-byte across run, key, watch, and direct film refusal.

Make subtitle capability tests independent of the host FFmpeg installation, skip the real pixel test before probing unavailable tools, retain strict skipped-capability rejection, and remove only the unused websockets runner dependency.
Replace the Git Bash PowerShell shorthand with complete native commands,
explicit path conversion, a kept-alive serve task, bounded readiness, and
run/key/watch/close examples. Use native input and sleep commands so the
recipe works without a sample app. Explain empty take directories and
PowerShell 5.1 embedded-quote escaping observed in native trials.

The original PowerShell missing-cwd finding does not reproduce when the
session is nested under the working directory; retain the successful
baseline and describe explicit directory creation as setup clarity.

Fresh readers exercised the final recipes on native PowerShell 5.1,
PowerShell 7, and Git Bash. Preserve the failed first candidate and driver
setup failures, distinguish instruction trials from full skill evaluation,
and keep movie acceptance with Drew. Record Drew's approval of the normal
workflow dependencies and the bounded repair plan.
@arittr
arittr merged commit c3116b2 into import/proving-it-works-skill Sep 12, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9fe81b48a2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

def _descendants(pid: int) -> list[int]:
pids, index = [pid], 0
while index < len(pids):
listed = subprocess.run(["pgrep", "-P", str(pids[index])], capture_output=True, text=True).stdout

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid requiring pgrep for process cleanup

On Unix installations without the optional pgrep utility, every cleanup attempt raises FileNotFoundError; render_card() therefore turns a successful screenshot into an assembly failure, while recorder cleanup can abort before killing either process. Use a dependency-free process-group or platform API, or provide a fallback when pgrep is absent.

AGENTS.md reference: AGENTS.md:L36-L38

Useful? React with 👍 / 👎.

Comment on lines +290 to +294
processes = [
subprocess.Popen(ttyd_argv, cwd=cwd, stdin=subprocess.DEVNULL, stdout=logs[0],
stderr=subprocess.STDOUT, start_new_session=unix),
subprocess.Popen(browser_argv, cwd=directory, stdin=subprocess.DEVNULL, stdout=logs[1],
stderr=subprocess.STDOUT, start_new_session=unix),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clean up ttyd when browser launch fails

If ttyd starts successfully but the browser Popen fails—for example because the selected executable becomes unavailable or Windows rejects its launch—the list construction raises before entering the later try/finally, leaving ttyd and its shell tree running and the log handles open. Start both processes inside a guarded block that terminates any process already launched on partial failure.

Useful? React with 👍 / 👎.

browser_argv = [browser, "--headless=new", "--no-first-run", "--no-default-browser-check",
"--use-gl=angle", "--use-angle=swiftshader", "--enable-unsafe-swiftshader",
"--disable-background-networking", "--remote-debugging-address=127.0.0.1",
f"--remote-debugging-port={debug_port}", f"--user-data-dir={directory / 'profile'}",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve the browser profile path before changing cwd

When SESSION is relative, the browser receives a relative --user-data-dir=SESSION/profile while its working directory is already SESSION, so it creates SESSION/SESSION/profile. close() only removes SESSION/profile, leaving the real browser profile and cache behind; resolve the session directory first or pass a profile path relative to the browser's chosen cwd.

Useful? React with 👍 / 👎.

arittr added a commit to ada-sen/superpowers that referenced this pull request Sep 12, 2026
Address the fresh review on PR obra#2214 after the obra#2275 integration. Drew approved fixing the two reproduced bugs and keeping the specified auto/on/off verification semantics.

Cache accepted narration by normalized text plus effective engine, voice, and synthesis model. Resolve voice defaults before rendering, invalidate entries without settings, and retain requested ASR checks on cache hits. Exclude rejected clips as before.

Treat manual subtitle offsets as start-time overrides. Only assembly offsets JSON selects scenes in the cut, including when manual timing overrides are also supplied. Empty narrated cuts write an empty SRT without crashing.

Make the gated Unix example pass --verify on and document the actual local ASR modes. Auto remains permissive if ASR is unavailable; on remains strict.

Validation: observed the new cache and subtitle regressions fail before the fixes; all 23 focused narration and subtitle-text tests now pass. Synthesis, duration probing, and ASR are mocked. No media inspection or live ASR was performed; Drew retains final video acceptance.
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.

1 participant