Add Factory AI at Work Gate 1 production pack - #18
Conversation
There was a problem hiding this comment.
Sorry @OrionArchitekton, your pull request is larger than the review limit of 150000 diff characters
|
Warning Review limit reached
Next review available in: 8 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThe PR adds a Factory AI production pack with source-attested rendering, immutable output claiming and promotion, expanded provenance reports, stricter CLI validation, independent brand cards, and full-bleed geometry checks. ChangesFactory AI production workflow
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Sequence Diagram(s)sequenceDiagram
participant Operator
participant AttestedLauncher
participant CLI
participant runPipeline
participant Validators
participant Promotion
Operator->>AttestedLauncher: start pinned render
AttestedLauncher->>CLI: launch detached committed source
CLI->>runPipeline: pass attestation and fresh-output options
runPipeline->>Validators: produce provenance and media artifacts
Validators->>Promotion: approve receipt and artifact set
Promotion-->>Operator: publish sealed reviewed root
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Reviewer's GuideImplements a fail-closed, source-attested production lane for the Factory AI at Work Gate 1 episode, adding immutable output claiming, stronger geometry/provenance guards, CLI contract enforcement, and a reviewed-pack promoter around a new Factory-specific demo bundle. Sequence diagram for source-attested immutable render pipelinesequenceDiagram
actor Operator
participant Launcher as run_source_attested_render_sh
participant Cli as main
participant SourceBuild as attestSourceBuild
participant Pipeline as runPipeline
participant Provenance as buildRenderReport
participant Output as claimFreshOutputDir
Operator->>Launcher: invoke with repo_root, commit, node_bin, pnpm_cli, config_path
Launcher->>Launcher: verify_fixed_commit
Launcher->>Launcher: verify_snapshot_root
Launcher->>Launcher: frozen_pnpm_install
Launcher->>Cli: exec src_cli_ts with --attest-source-build
Cli->>Cli: parseCommand
Cli->>SourceBuild: attestSourceBuild
SourceBuild-->>Cli: SourceBuildSession
Cli->>Pipeline: runPipeline(config, { requireFreshOut, sourceBuild })
Pipeline->>SourceBuild: assertSourceBuildExecutionContext
Pipeline->>Output: claimFreshOutputDir
Output-->>Pipeline: FreshOutputClaim
Pipeline->>Pipeline: runPreflight
Pipeline->>Pipeline: digestPrebakedInputs
Pipeline->>Pipeline: renderVideo
Pipeline->>SourceBuild: assertSourceBuildUnchanged
Pipeline->>Provenance: buildRenderReport
Provenance-->>Pipeline: RenderReport
Pipeline->>Provenance: persistRenderReport(required=true)
Pipeline->>Output: publishFreshOutput
Output-->>Operator: final.mp4 and render_report.json in reviewed attempt
Flow diagram for Factory AI at Work Gate 1 production packflowchart LR
A[evidence_source_files] --> B[rehearsal_render_FAKE_TTS]
B --> C[real_captures_and_voice]
C --> D[source_attested_render_attempt]
D --> E[validate_factory_ai_at_work_inputs_ts]
E --> F[promote_factory_ai_at_work_attempt_sh]
F --> G[sealed_reviewed_pack_with_PRODUCTION_RECEIPT_sha256]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f20f4169e7
ℹ️ 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".
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (3)
scripts/validate-factory-ai-at-work-inputs.ts (1)
304-350: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winDeep-compare the report fields by canonical form, not by
JSON.stringifykey order.Line 304 uses
stableConfigJsonfor the config, which is the repository's canonical-serialization helper. Lines 310, 336, and 343 then compareclips,voice, andsourceBuildAttestationwith rawJSON.stringify. RawJSON.stringifyis sensitive to property insertion order.The comparison therefore depends on the key order that
src/provenance.tsandsrc/source-build.tshappen to use when they build these objects. A future reorder of{ shotId, sha256 }to{ sha256, shotId }breaks this validator and reports "input hashes do not match the archived config, script, and ordered clip bytes", which points at the wrong cause.The failure mode is a false rejection, not a false acceptance, so this is not urgent. Reuse the canonical serializer or a small deep-equal helper for these three comparisons.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/validate-factory-ai-at-work-inputs.ts` around lines 304 - 350, Replace the raw JSON.stringify comparisons for report.inputs.clips, report.voice, and report.sourceBuildAttestation with canonical-form deep comparisons using stableConfigJson or an equivalent shared deep-equality helper. Keep the existing validation semantics and failure messages unchanged, while preserving array ordering and value equality.src/cli.ts (1)
73-114: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract one value-taking helper for the string options.
Lines 59-114 repeat the same parse-and-validate structure four times, once per flag and once per syntax. The blocks differ only in the flag name, the noun in the message, and the assigned variable. One helper removes about 40 lines and makes the validation rule identical for every flag.
♻️ Proposed helper
const requireOnce = (flag: string) => { if (seenFlags.has(flag)) { throw new Error(`${flag} may be supplied once`); } seenFlags.add(flag); }; + const values = new Map<string, string>(); + const takeValue = (flag: string, noun: string, inline: string | undefined, next: string | undefined): number => { + requireOnce(flag); + const value = inline ?? next; + if (!value || value.startsWith("-")) { + throw new Error(`${flag} requires a non-empty ${noun} argument that does not start with '-'`); + } + values.set(flag, value); + return inline === undefined ? 1 : 0; + };Then drive the four options from one table of
flag → nounpairs and read the results fromvaluesafter the loop.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cli.ts` around lines 73 - 114, Extract the repeated value parsing and validation from the CLI argument loop into one helper for string options, parameterized by flag and its error-message noun. Define a table mapping --out, --clips-dir, --script, and the other string option to their nouns, use the helper for both separate-argument and --flag=value forms, and retrieve parsed values from a shared values object before assigning the corresponding variables.scripts/promote-factory-ai-at-work-attempt.sh (1)
56-127: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider collapsing the two entry-check helpers into one.
factory_require_exact_entriesandfactory_require_allowed_entriesare identical except for the entry-count check. A single helper with a mode argument removes about 30 duplicated lines and keeps the glob save/restore logic in one place.♻️ Suggested shape
+factory_require_entries() { + local mode="$1" # exact | allowed + local root="$2" + local label="$3" + shift 3 + # ... shared glob collection ... + if [ "$mode" = exact ] && [ "${`#entries`[@]}" -ne "$#" ]; then + echo "$label does not contain the exact required entry count" >&2 + return 1 + fi + # ... shared name membership loop ... +}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/promote-factory-ai-at-work-attempt.sh` around lines 56 - 127, Consolidate factory_require_exact_entries and factory_require_allowed_entries into one shared entry-validation helper, preserving the existing dotglob/nullglob save-and-restore behavior and unexpected-entry checks. Add a mode or optional argument to control whether the helper enforces an exact entry count, and update both callers to use the unified helper with the appropriate behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@demos/factory-ai-at-work/gate-01/CAPTURE_PLAN.md`:
- Line 43: Update the sentence in CAPTURE_PLAN.md to hyphenate the compound
modifier, changing “15 second disclosure card” to “15-second disclosure card.”
In `@scripts/validate-factory-ai-at-work-inputs.ts`:
- Around line 455-475: Update validateChapters to validate each chapter’s
duration from the masterReport timeline before comparing YOUTUBE_CHAPTERS.txt.
Ensure every chapter entry is at least 10 seconds long, using the next chapter’s
start time or the timeline’s ending duration for the final chapter, and fail
with a clear message identifying any shorter chapter; preserve the existing
duplicate, missing, and exact-content checks.
In `@src/cli.ts`:
- Around line 59-72: The CLI option parsing in src/cli.ts lines 59-72 and 73-114
duplicates validation and lets --render-host accept an empty space-form value.
Add a shared takeValue(flag, noun, inline, next) helper that calls requireOnce,
rejects empty values and values beginning with "-", then replace both
--render-host forms and the --out, --clips-dir, and --script parsing blocks with
it; specifically ensure the --render-host space form uses the same !next
validation.
- Around line 191-193: Unify relative-path handling for the --script and
--clips-dir overrides in the CLI configuration assignment block. Either validate
and require both options to be absolute in their help/validation, or resolve
both relative values against the same config directory before assigning
config.script and config.clipsDir; ensure subsequent readFileSync and
resolveClipPath calls use the intended common base.
In `@tests/factory-ai-at-work-pack.test.ts`:
- Around line 37-46: Avoid running the parent-commit lookup during module
evaluation: resolve OTHER_SOURCE_COMMIT lazily within the unrelated-commit
assertion, treating a failed HEAD^ lookup as unavailable and skipping that
assertion. Also defer SOURCE_BUILD_ATTESTATION creation until
writeProductionArtifacts or otherwise ensure its rejection is awaited and
reported as a test failure rather than becoming an unhandled rejection.
---
Nitpick comments:
In `@scripts/promote-factory-ai-at-work-attempt.sh`:
- Around line 56-127: Consolidate factory_require_exact_entries and
factory_require_allowed_entries into one shared entry-validation helper,
preserving the existing dotglob/nullglob save-and-restore behavior and
unexpected-entry checks. Add a mode or optional argument to control whether the
helper enforces an exact entry count, and update both callers to use the unified
helper with the appropriate behavior.
In `@scripts/validate-factory-ai-at-work-inputs.ts`:
- Around line 304-350: Replace the raw JSON.stringify comparisons for
report.inputs.clips, report.voice, and report.sourceBuildAttestation with
canonical-form deep comparisons using stableConfigJson or an equivalent shared
deep-equality helper. Keep the existing validation semantics and failure
messages unchanged, while preserving array ordering and value equality.
In `@src/cli.ts`:
- Around line 73-114: Extract the repeated value parsing and validation from the
CLI argument loop into one helper for string options, parameterized by flag and
its error-message noun. Define a table mapping --out, --clips-dir, --script, and
the other string option to their nouns, use the helper for both
separate-argument and --flag=value forms, and retrieve parsed values from a
shared values object before assigning the corresponding variables.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 862f0dc1-c59e-4753-9dc2-e8a4301d8e01
📒 Files selected for processing (45)
CHANGELOG.mdREADME.mddemos/factory-ai-at-work/gate-01/CAPTURE_PLAN.mddemos/factory-ai-at-work/gate-01/CLAIM_LEDGER.mddemos/factory-ai-at-work/gate-01/PRODUCTION_RECEIPT_TEMPLATE.mddemos/factory-ai-at-work/gate-01/PUBLISHING.mddemos/factory-ai-at-work/gate-01/README.mddemos/factory-ai-at-work/gate-01/cuts/cut-a/DEMO_SCRIPT.mddemos/factory-ai-at-work/gate-01/cuts/cut-a/demo.config.jsondemos/factory-ai-at-work/gate-01/cuts/cut-b/DEMO_SCRIPT.mddemos/factory-ai-at-work/gate-01/cuts/cut-b/demo.config.jsondemos/factory-ai-at-work/gate-01/cuts/cut-c/DEMO_SCRIPT.mddemos/factory-ai-at-work/gate-01/cuts/cut-c/demo.config.jsondemos/factory-ai-at-work/gate-01/master/DEMO_SCRIPT.mddemos/factory-ai-at-work/gate-01/master/demo.config.jsondocs/runbooks/factory-ai-at-work-gate-01-production.mdscripts/promote-factory-ai-at-work-attempt.shscripts/run-source-attested-render.shscripts/validate-factory-ai-at-work-inputs.tsscripts/validate-factory-ai-at-work-receipt.shspecs/factory-ai-at-work-gate-01-production-pack-spec.mdspecs/shorts-platform-profile-spec.mdsrc/cli.test.tssrc/cli.tssrc/config.test.tssrc/ffmpeg.test.tssrc/ffmpeg.tssrc/framing.test.tssrc/framing.tssrc/git-environment.tssrc/pipeline.tssrc/preflight.tssrc/provenance.test.tssrc/provenance.tssrc/render.tssrc/source-build.test.tssrc/source-build.tssrc/types.tstests/brand-card-selection.smoke.test.tstests/cli.test.tstests/factory-ai-at-work-pack.test.tstests/pipeline.smoke.test.tstests/prebaked-narration.smoke.test.tstests/preflight.smoke.test.tstests/render-aspect-guard.test.ts
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (6)
tests/prebaked-input-binding.test.ts (3)
857-860: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAssert the specific rejection reason for the trailing-slash symlink case.
expect(runRecovery).toThrow()accepts any failure, including a usage error. The script rejects a trailing slash at a dedicated guard with the message "render-input root must be one exact canonical directory path without a trailing slash". Match that text, so the test proves the trailing-slash guard fired and not some earlier check.♻️ Proposed assertion
- expect(runRecovery).toThrow(); + expect(runRecovery).toThrow(/without a trailing slash/);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/prebaked-input-binding.test.ts` around lines 857 - 860, Update the runRecovery assertion in the trailing-slash symlink test to match the exact rejection message “render-input root must be one exact canonical directory path without a trailing slash” instead of accepting any thrown error. Preserve the existing marker and outsideRoot assertions.
788-814: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThis test uses the shared
tmpdir()as--tmp-root.The script requires the temporary root to be root-owned with the sticky bit, or owned by the current user without group or world write. The shared
tmpdir()satisfies the first rule on a typical Linux host, but the test then depends on host/tmppermissions. Every other recovery test in this file creates a privatemkdtemproot and passes that. Use a private root here too, so the happy path does not depend on the host temporary-directory mode.♻️ Proposed change to use a private temporary root
- const staleRoot = await mkdtemp( - join( - tmpdir(), - `agent-demo-video-render-inputs-${DEAD_RECOVERY_PID}-`, - ), - ); + const selectedTmpRoot = await mkdtemp(join(tmpdir(), "prebaked-recovery-happy-")); + const staleRoot = await mkdtemp( + join( + selectedTmpRoot, + `agent-demo-video-render-inputs-${DEAD_RECOVERY_PID}-`, + ), + ); const recoveryScript = join( process.cwd(), "scripts/cleanup-stale-render-input-root.sh", ); await markPrivateInputRoot(staleRoot); const runRecovery = () => execFileSync( "/usr/bin/bash", [ "--noprofile", "--norc", "-p", recoveryScript, "--tmp-root", - tmpdir(), + selectedTmpRoot, "--older-than-seconds", "3600", staleRoot, ], { encoding: "utf8" }, );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/prebaked-input-binding.test.ts` around lines 788 - 814, Update the recovery test around “recovers only one explicitly named owned stale render-input root” to create a private temporary root with mkdtemp, pass that root to the script’s --tmp-root option, and create the stale input root beneath it. Keep the test’s existing recovery assertions and cleanup behavior unchanged.
38-56: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThe
await import("node:fs/promises")calls in cleanup blocks resolve to this mock, not to the real module.
vi.mockintercepts the specifier for dynamic imports too. Everyfinallyblock that calls(await import("node:fs/promises")).rm(...)therefore goes through the override at line 42. The tests pass today only because each fault-injecting test setscleanupFault.enabled = falsebefore itsrmcall. A future test that throws before resetting the flag will silently skip its own cleanup and leak a temporary directory.Capture the real
rmonce and use it in cleanup blocks, so cleanup never depends on the fault flag.♻️ Proposed helper for unmocked cleanup
vi.mock("node:fs/promises", async (importOriginal) => { const actual = await importOriginal<typeof import("node:fs/promises")>(); return { ...actual,Then add a helper near the top of the file and use it in every
finallyblock:const realFs = await vi.importActual<typeof import("node:fs/promises")>("node:fs/promises"); const removeTree = (path: string) => realFs.rm(path, { recursive: true, force: true });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/prebaked-input-binding.test.ts` around lines 38 - 56, Capture the unmocked fs/promises module once using vi.importActual and define a removeTree helper near the test setup that calls the real rm with recursive and force options. Update every finally-block cleanup in the tests to use removeTree instead of dynamically importing node:fs/promises, ensuring cleanup is independent of cleanupFault.enabled while preserving the existing fault-injection mock.scripts/promote-factory-ai-at-work-attempt.sh (1)
46-127: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
factory_require_node_binaryis maintained as two verbatim copies. Both scripts define the same 80-line Node admission function. The two copies must stay identical, because the promotion gate and the receipt gate are supposed to give the same guarantee about the interpreter that evaluates receipts. Nothing enforces that today, and the neighboring environment scrub lists already diverge: the receipt validator filtersRIPGREP_CONFIG_PATHand the promote script does not.
scripts/promote-factory-ai-at-work-attempt.sh#L46-L127: extract this definition into a shared helper that both scripts source from a path pinned relative to$0, or add a test that compares the two function bodies.scripts/validate-factory-ai-at-work-receipt.sh#L33-L114: replace this copy with the shared helper, and align the environment scrub list with the promote script in the same change.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/promote-factory-ai-at-work-attempt.sh` around lines 46 - 127, The duplicated factory_require_node_binary definitions must be maintained through one shared implementation. In scripts/promote-factory-ai-at-work-attempt.sh lines 46-127, extract the function into a shared helper sourced using a path pinned relative to $0; in scripts/validate-factory-ai-at-work-receipt.sh lines 33-114, remove the local copy and source that helper. Align the receipt validator’s environment scrub list with the promote script, including the RIPGREP_CONFIG_PATH handling.src/pipeline.ts (2)
328-331: 🩺 Stability & Availability | 🔵 TrivialDocument the temporary-root capacity requirement.
Every prebaked clip is copied into the binding root under
tmpdir(). On many hosts/tmpis a memory-backed tmpfs, so the Gate 1 master plus the three cuts require roughly the full size of all thirteen captures in RAM. If tmpfs runs out, binding fails with ENOSPC after the operator has already staged evidence.
trustedPrivateInputParentreadstmpdir(), soTMPDIRalready gives operators a disk-backed override. State the space requirement and theTMPDIRoverride in the runbook preconditions.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pipeline.ts` around lines 328 - 331, Update the runbook preconditions for the temporary binding root created after trustedPrivateInputParent to state that it must have capacity for roughly the full size of all thirteen captures, including the Gate 1 master and three cuts, and document TMPDIR as the operator override for selecting a disk-backed location instead of tmpdir().
111-119: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winConsider handling SIGHUP for the private binding root.
The handlers cover SIGINT and SIGTERM only. SIGHUP terminates the process by default, and it arrives whenever a controlling terminal or SSH session closes. In that case the binding root survives with full copies of the capture media, and recovery needs
scripts/cleanup-stale-render-input-root.sh. The attested launcher already treats HUP as a cleanup trigger, so adding it here restores parity.If you accept this change, update the SIGINT/SIGTERM wording in
docs/runbooks/factory-ai-at-work-gate-01-production.md(line 534) and inspecs/factory-ai-at-work-gate-01-production-pack-spec.md(AC8, line 143) as well.♻️ Proposed change
function removePrivateInputSignalHandlers(): void { process.removeListener("SIGINT", handlePrivateInputSignal); process.removeListener("SIGTERM", handlePrivateInputSignal); + process.removeListener("SIGHUP", handlePrivateInputSignal); } function addPrivateInputSignalHandlers(): void { process.prependListener("SIGINT", handlePrivateInputSignal); process.prependListener("SIGTERM", handlePrivateInputSignal); + process.prependListener("SIGHUP", handlePrivateInputSignal); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pipeline.ts` around lines 111 - 119, Extend addPrivateInputSignalHandlers and removePrivateInputSignalHandlers to register and remove handlePrivateInputSignal for SIGHUP alongside SIGINT and SIGTERM, preserving the existing listener behavior. Update the corresponding SIGINT/SIGTERM-only wording in the production runbook and production pack specification to include SIGHUP.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/runbooks/factory-ai-at-work-gate-01-production.md`:
- Around line 373-374: Update the Node probe block that writes
YOUTUBE_CHAPTERS.txt to emit its output to a temporary file first, such as
YOUTUBE_CHAPTERS.txt.tmp, so failures leave the existing destination unchanged.
Replace the final non-empty check to validate the temporary file, then move it
into YOUTUBE_CHAPTERS.txt only after validation succeeds.
In `@tests/prebaked-input-binding.test.ts`:
- Around line 800-814: Gate the stale-root recovery tests around runRecovery and
their related cases to Linux, or otherwise skip them on macOS and Windows before
invoking /usr/bin/bash. Document the Linux-only requirement for npm test if the
tests remain ungated, while preserving the existing recovery assertions on
Linux.
---
Nitpick comments:
In `@scripts/promote-factory-ai-at-work-attempt.sh`:
- Around line 46-127: The duplicated factory_require_node_binary definitions
must be maintained through one shared implementation. In
scripts/promote-factory-ai-at-work-attempt.sh lines 46-127, extract the function
into a shared helper sourced using a path pinned relative to $0; in
scripts/validate-factory-ai-at-work-receipt.sh lines 33-114, remove the local
copy and source that helper. Align the receipt validator’s environment scrub
list with the promote script, including the RIPGREP_CONFIG_PATH handling.
In `@src/pipeline.ts`:
- Around line 328-331: Update the runbook preconditions for the temporary
binding root created after trustedPrivateInputParent to state that it must have
capacity for roughly the full size of all thirteen captures, including the Gate
1 master and three cuts, and document TMPDIR as the operator override for
selecting a disk-backed location instead of tmpdir().
- Around line 111-119: Extend addPrivateInputSignalHandlers and
removePrivateInputSignalHandlers to register and remove handlePrivateInputSignal
for SIGHUP alongside SIGINT and SIGTERM, preserving the existing listener
behavior. Update the corresponding SIGINT/SIGTERM-only wording in the production
runbook and production pack specification to include SIGHUP.
In `@tests/prebaked-input-binding.test.ts`:
- Around line 857-860: Update the runRecovery assertion in the trailing-slash
symlink test to match the exact rejection message “render-input root must be one
exact canonical directory path without a trailing slash” instead of accepting
any thrown error. Preserve the existing marker and outsideRoot assertions.
- Around line 788-814: Update the recovery test around “recovers only one
explicitly named owned stale render-input root” to create a private temporary
root with mkdtemp, pass that root to the script’s --tmp-root option, and create
the stale input root beneath it. Keep the test’s existing recovery assertions
and cleanup behavior unchanged.
- Around line 38-56: Capture the unmocked fs/promises module once using
vi.importActual and define a removeTree helper near the test setup that calls
the real rm with recursive and force options. Update every finally-block cleanup
in the tests to use removeTree instead of dynamically importing
node:fs/promises, ensuring cleanup is independent of cleanupFault.enabled while
preserving the existing fault-injection mock.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: ccc34c4a-5fd1-4c77-bbad-9e1ad03fefcb
📒 Files selected for processing (16)
README.mddemos/factory-ai-at-work/gate-01/CAPTURE_PLAN.mddocs/runbooks/factory-ai-at-work-gate-01-production.mdscripts/cleanup-stale-render-input-root.shscripts/promote-factory-ai-at-work-attempt.shscripts/run-source-attested-render.shscripts/validate-factory-ai-at-work-inputs.tsscripts/validate-factory-ai-at-work-receipt.shspecs/factory-ai-at-work-gate-01-production-pack-spec.mdsrc/cli.test.tssrc/cli.tssrc/pipeline.tssrc/preflight.tstests/factory-ai-at-work-pack.test.tstests/prebaked-input-binding.test.tstests/preflight.smoke.test.ts
🚧 Files skipped from review as they are similar to previous changes (8)
- demos/factory-ai-at-work/gate-01/CAPTURE_PLAN.md
- README.md
- src/cli.test.ts
- tests/preflight.smoke.test.ts
- scripts/run-source-attested-render.sh
- tests/factory-ai-at-work-pack.test.ts
- src/preflight.ts
- scripts/validate-factory-ai-at-work-inputs.ts
Outcome
Turns the first Factory AI at Work episode from a script folder into a fail-closed production lane: one landscape master and three independent 9:16 cuts can be rendered from real evidence, reviewed against explicit claims, and promoted as an immutable closed set before an operator-authorized upload.
No media, credentials, publication approval, upload state, or channel-wide streak counter is committed. Real capture and paid voice rendering remain operator-gated.
Production flow
What changed
Verification
pnpm test: 40 files, 273 tests passedpnpm typecheck: passedpnpm build: local and remote entry builds passedbash -n: all changed shell entrypoints passedgitleaks detect --source . --no-banner --redact --exit-code 1: no leaks--verify-only: exact commit snapshot verifiedTrust boundaries and follow-ups
Summary by Sourcery
Introduce a fail-closed, production-ready pack for the first Factory AI at Work episode, adding source-attested rendering, immutable output claiming, enhanced clip and aspect validation, and a reviewed promotion workflow for one master and three portrait cuts.
New Features:
Enhancements:
Documentation:
--out,--clips-dir, and--scriptin production runs.Tests:
Chores:
Summary by CodeRabbit
New Features
Bug Fixes
Documentation