# Engine Escape Audit

When real production work runs **outside** the `vclaw` engine — in hand-written
`.mjs` harness scripts with hardcoded paths — it loses every guarantee the engine
provides (path portability, tested behavior, no-footgun live pages, consistent
artifacts). Every recurring operational bug we have hit traces back to work that
escaped the engine. This doc inventories that escaped work and prioritizes which
patterns to absorb into tested CLI commands.

> Methodology: grep `~/.videoclaw-*/**/*.mjs` for hardcoded
> `/Users/.../​.videoclaw-*` and `/Users/.../Documents/GitHub/videoclaw*` paths,
> read representative scripts, classify by recurring shape. (2026-06-18 sweep:
> **31 hardcoded paths across 20 scripts**.)

## The five patterns

| # | Pattern | Scripts | Engine coverage today | Verdict |
|---|---------|---------|-----------------------|---------|
| 1 | **Status/review dashboard generator** (live HTML + lightbox, run-status-gen.mjs) | 1 | `status`/`execute-status` are read-only JSON; no live-refresh HTML | **Leave** (served via run-server.mjs; portal covers polished surfaces) |
| 2 | **Resumable per-scene/per-beat render loop** with retry+fallback (voice-render.mjs, chain.mjs, round3.mjs, fix-clips.mjs) | 4 | `produce`/`execute` render per-scene but NOT resumable retry/fallback ladders or continuation chaining | **ABSORB** (Tier 1) |
| 3 | **Concurrency pool driver** (max-concurrent, auto-refill, poll, pool-driver.mjs, poll-pending.mjs) | 3 | `produce` has no max-concurrent control / auto-refill loop | **ABSORB** (Tier 1) |
| 4 | **I2V multi-engine submit harness** (engine select, upload/poll/download, upscale, i2v.mjs) | 2 | `produce` + `--veo-model` covers engine choice; i2v adds upscale/per-engine tuning | **Leave** (self-contained, reads only `.env.local`) |
| 5 | **Matrix/moderation-retry test rigs** (harness.mjs, model-matrix.mjs) | 2 | dev/QA tooling, not production | **Leave** (test rigs; hardcoded paths acceptable) |

## Tier-1 recommendations (absorb)

### `vclaw video render-scenes` — productize the resumable render loop (Pattern 2)
- **Why:** voice-render.mjs / chain.mjs are bespoke per project; the resumable
  retry+fallback ladder and continuation chaining are genuinely missing from the
  engine and are re-implemented (slightly differently, with bugs) each time.
- **Shape:** `vclaw video render-scenes --project <slug> [--continue-from <i>] [--fallback-chain] [--method <route>]`
- **Reuse:** the existing per-scene `executeProject` + `runAutoChain` engine;
  add a resume cursor persisted to `state/` and a fallback-route ladder.
- **Test:** `--continue-from` skips done scenes; a rejected scene escalates the
  fallback ladder; state persists across a simulated crash (injected runner).

### `vclaw video pool` — productize the concurrency pool driver (Pattern 3)
- **Why:** pool-driver.mjs maintains N-in-flight Runway-explore renders with
  auto-refill; it is the single most-copied operator loop (cartoon gens 3–6,
  DHUAAN chain). Hardcodes a disposable worktree `dist` path that breaks on GC.
- **Shape:** `vclaw video pool --project <slug> --scenes <list> --max-concurrent <N> [--until-complete]`
- **Reuse:** the native route transports + their job-state; the pool is a
  scheduler over `executeProject` submit + `refreshExecutionStatus` poll.
- **Test:** assert exactly N in-flight, auto-refill on completion, skip already-done,
  bounded retries; machine-readable `state.jsonl` + `progress.json` output.

## Cross-cutting fix for ALL escaped scripts
Every harness hardcodes the repo `.env.local` and a `dist` path. Independent of
productizing: standardize on `VCLAW_ENV_FILE` (cred source) and ship the migrated
projects' harness consts re-pointed to `~/videoclaw` + the stable repo `dist`, so
the remaining operator scripts survive a workspace move. `vclaw video verify-env`
surfaces mismatches.

## Not now
Patterns 1/4/5 stay as operator scripts; productizing them is lower ROI than the
Tier-1 loops. Whisper-based content QC is also deferred (motion-overlay already
has Gemini STT; the QC seam is `assemble/media-qc.ts` + `verify-final`).

## Resolved — `pool` is now parallel-safe (DONE)
`vclaw video pool` runs **in parallel** again (`--max-concurrent` defaults to 2;
the `>1` gate is removed). The historical blocker was that `executeProject`
(`execute.ts`) — plus `refreshExecutionStatus` and the candidate-select — did an
**unlocked read-modify-write** of the whole-project `scene-candidates.json` /
`scene-selection.json`. Two scenes rendering concurrently could clobber each
other's candidate/selection (lost update), leaving a scene "pending" on the next
resume so it RE-RENDERED — a double-spend on a paid route. (Sequential drivers —
`--auto-chain`, `render-scenes` — were always immune; only parallel `pool` exposed
it. An adversarial review caught it; the scheduler's own unit tests missed it
because they stub the runner.)

**Fix (landed):** all four write points — the `execute.ts` candidate ingest, the
two `execution-status.ts` poll-update sections, and the candidate-select in
`handlers/execution.ts` — now run their read-modify-write under a single
per-project artifact lock via `withSceneArtifactsLock` (in
`scene-candidate-store.ts`, built on the existing `acquireSceneCandidatesLock`).
One lock guards BOTH `scene-candidates.json` and `scene-selection.json`. The
pattern is **lock → re-read the CURRENT on-disk state → apply MY deltas to the
fresh current → write**, so a concurrent writer's update is never lost; the slow
provider submit/poll stays OUTSIDE the lock so concurrency is preserved. A
NON-stubbed concurrency test (`scene-artifact-concurrency.test.ts`) fires 8 scenes
through the real locked ingest with `Promise.all` and asserts every scene lands a
candidate + a pending selection (zero lost updates), with a second test proving
the harness genuinely races (the old unlocked path drops at least one scene). The
`--max-concurrent > 1` gate in `handleVideoPool` is lifted. The pure scheduler
(`execute-pool.ts`) was already correct + adversarially tested.
