import {it,expect} from "vitest"; import {mkdtemp,rm,writeFile,readFile} from "node:fs/promises"; import {tmpdir,homedir} from "node:os"; import {join} from "node:path"; import {createHash} from "node:crypto"; import {EditorWorkflow} from "../src/media/editor-workflow.js"; import {SkillRunner} from "../src/media/skill-runner.js"; import {analysisFixture} from "./fixtures/editor-analysis.js"; import {planFixture} from "./fixtures/editor-plan.js"; import {mediaRuntime,runMedia} from "../src/media/media-worker.js"; it("requires source review before accepting a plan and never treats model PASS as human review",async()=>{ const root=await mkdtemp(join(tmpdir(),"workflow-")); try{ await writeFile(join(root,"target-drama-analysis.json"),JSON.stringify({withheld_information:["The answer"]})); const workflow=new EditorWorkflow({root,sessionId:"ses_test",jobId:"job_test",analysisId:"analysis_test",dramaId:"drama_test",sources:[{episodeId:"ep_test",episodeNo:1,source:join(root,"source.mp4"),duration:20,sha256:"abc",subtitle:"WEBVTT"}],runner:new SkillRunner({skillRoot:"/unused",pythonExecutable:"/unused"})}); await expect(workflow.submitPlan({},new AbortController().signal)).rejects.toMatchObject({code:"SELECTION_REVIEW_REQUIRED"}); const selected=await workflow.proposeSelection({segments:[{id:"one",episodeId:"ep_test",start:0,end:10,reason:"A complete question and reaction"}]}); expect(selected.selection?.reviewed).toBe(false); expect(JSON.stringify(selected)).not.toContain(root); await expect(workflow.review("selection",{planHash:selected.selection?.hash,pass:true})).rejects.toThrow(); await expect(workflow.render(new AbortController().signal)).rejects.toMatchObject({code:"PLAN_REVIEW_REQUIRED"}); await expect(workflow.proposeSelection({segments:[{id:"one",episodeId:"foreign",start:0,end:10,reason:"Invalid source"}]})).rejects.toMatchObject({code:"SELECTION_INVALID"}); }finally{await rm(root,{recursive:true,force:true});} }); it("binds human-reviewed selection to original validators and renders only a REVIEW artifact",async()=>{ const root=await mkdtemp(join(tmpdir(),"workflow-render-"));const signal=new AbortController().signal; try{ const runtime=await mediaRuntime();const source=join(root,"source.mp4"); await runMedia(runtime.ffmpeg,["-v","error","-f","lavfi","-i","testsrc2=size=180x320:rate=24","-f","lavfi","-i","sine=frequency=440:sample_rate=48000","-t","11","-c:v","libx264","-c:a","aac",source],root,signal); await writeFile(join(root,"target-drama-analysis.json"),JSON.stringify(analysisFixture())); const original=await readFile(source); const workflow=new EditorWorkflow({root,sessionId:"ses_test",jobId:"job_test",analysisId:"analysis_fixture",dramaId:"drama_fixture",sources:[{episodeId:"ep_test",episodeNo:1,source,duration:11,sha256:createHash("sha256").update(original).digest("hex"),subtitle:"WEBVTT\n\n00:00:01.000 --> 00:00:04.000\nSynthetic test caption.\n"}],runner:new SkillRunner({skillRoot:join(homedir(),".codex/skills/swads-short-drama-editor"),pythonExecutable:join(homedir(),".cache/codex-runtimes/codex-primary-runtime/dependencies/python/bin/python3")})}); const selected=await workflow.proposeSelection({segments:[{id:"one",episodeId:"ep_test",start:0,end:10,reason:"Synthetic complete test sequence"}]}); const evidence="Synthetic engineering review; not a licensed drama clearance."; await workflow.review("selection",{planHash:selected.selection!.hash,reviewer:"Test fixture",policyCheckedAt:new Date().toISOString(),policyPageUpdated:"Test fixture policy",pictureAudioReviewed:true,noUnresolvedFindings:true,segmentEvidence:[{segmentId:"one",pictureEvidence:evidence,audioEvidence:evidence,subtitleEvidence:evidence}]}); const unverified=planFixture();unverified.referenceCandidates.candidates[0]!.evidence.metrics={views:0,likes:0}; const pendingReference=await workflow.submitPlan(unverified,signal); expect(pendingReference.pass).toBe(true); await expect(workflow.review("plan",{planHash:workflow.view().plan!.hash,reviewer:"Test fixture",policyCheckedAt:new Date().toISOString(),pictureAudioReviewed:true,referenceReviewed:true,storyReviewed:true,packagingReviewed:true,noUnresolvedFindings:true,segmentEvidence:[{segmentId:"one",observation:evidence}]})).rejects.toMatchObject({code:"VERIFIED_REFERENCE_REQUIRED"}); const result=await workflow.submitPlan(planFixture(),signal); expect(result.pass).toBe(true); const plan=workflow.view().plan!; await expect(workflow.render(signal)).rejects.toMatchObject({code:"PLAN_REVIEW_REQUIRED"}); await workflow.review("plan",{planHash:plan.hash,reviewer:"Test fixture",policyCheckedAt:new Date().toISOString(),pictureAudioReviewed:true,referenceReviewed:true,storyReviewed:true,packagingReviewed:true,noUnresolvedFindings:true,segmentEvidence:[{segmentId:"one",observation:evidence}]}); await writeFile(source,"changed after review"); await expect(workflow.render(signal)).rejects.toMatchObject({code:"REVIEWED_SOURCE_CHANGED"}); await writeFile(source,original); const rendered=await workflow.render(signal); expect(rendered.preview?.duration).toBeCloseTo(10,1);expect(rendered.preview?.reviewStatus).toBe("REVIEW"); expect(JSON.stringify(rendered)).not.toContain(root); const bytes=await readFile(workflow.previewPath(plan.id));expect(bytes.byteLength).toBeGreaterThan(1000); expect(rendered.humanReviewPassed).toBe(false); }finally{await rm(root,{recursive:true,force:true});} },60_000);