Files
jhonny-editor/code/tests/tools/structural-verification.test.ts
João Henrique 1249b3aeb7 feat: alinhada a remoção da engine Python ao fluxo ripple do execu
- alinhada a remoção da engine Python ao fluxo ripple do executor CEP para cortar vídeo e áudio
- criada remoção atômica para manter vídeo e áudio vinculados sincronizados
- criada aba de configuração de legendas offline e inclusão das preferências no pacote para a IA
- criado gerador offline de blocos de legenda sincronizados com palavras da transcrição e cortes aprovados
- criada uma versão base portátil da skill edit-video-by-voice para testes em outros agentes de IA
- incorporado perfil editorial opcional à skill portátil para orientar decisões de edição

Resumo:
- 14 arquivos alterados
- 4 novos
- 10 modificados
- 0 removidos

 10 files changed, 278 insertions(+), 33 deletions(-)

Arquivos:
  - code/cep-plugin/index.html
  - code/cep-plugin/main.js
  - code/docs/supported-actions.md
  - code/engine/editor/aplicador_de_plano_de_edicao.py
  - code/engine/editor/escrita/escrita_no_editor.py
  - code/engine/testes/duplos_de_premiere.py
  - code/engine/testes/test_aplicador_de_plano_de_edicao.py
  - code/src/tools/timeline.ts
  - code/tests/tools/structural-verification.test.ts
  - code/tests/tools/tool-modules.test.ts
  - code/engine/arquitetura/legendas.md
  - code/engine/editor/legendas/
  - code/engine/testes/test_gerador_de_legendas.py
  - skills/
2026-09-09 13:05:07 -04:00

396 lines
17 KiB
TypeScript
Executable File

import { beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("../../src/bridge/file-bridge.js", () => ({
sendCommand: vi.fn().mockResolvedValue({ success: true, data: {} }),
}));
import { sendCommand } from "../../src/bridge/file-bridge.js";
import { getTimelineTools } from "../../src/tools/timeline.js";
import { getTrackTargetingTools } from "../../src/tools/track-targeting.js";
import { getAdvancedTools } from "../../src/tools/advanced.js";
import { getTrackTools } from "../../src/tools/tracks.js";
const mockedSendCommand = vi.mocked(sendCommand);
const bridgeOptions = { tempDir: "/tmp/test", timeoutMs: 1000 };
const timeline = getTimelineTools(bridgeOptions);
const trackTargeting = getTrackTargetingTools(bridgeOptions);
const advanced = getAdvancedTools(bridgeOptions);
const tracks = getTrackTools(bridgeOptions);
beforeEach(() => vi.clearAllMocks());
describe("trim_clip verification", () => {
it("requires exactly one edit point instead of reporting a no-op or multi-write as success", async () => {
const result = await timeline.trim_clip.handler({ node_id: "abc" });
expect(result.success).toBe(false);
expect(result.error).toContain("new_in_seconds");
// The bridge must not be touched at all — there is nothing to apply.
expect(mockedSendCommand).not.toHaveBeenCalled();
const multiple = await timeline.trim_clip.handler({
node_id: "abc",
new_in_seconds: 2,
new_out_seconds: 8,
});
expect(multiple.success).toBe(false);
expect(mockedSendCommand).not.toHaveBeenCalled();
});
it("compares the read-back in point against the requested value", async () => {
await timeline.trim_clip.handler({ node_id: "abc", new_in_seconds: 2 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("var actualIn = after.inPoint");
expect(script).toContain("Math.abs(actualIn - 2) > tolerance");
expect(script).toContain("did not apply a verified timeline trim");
expect(script).toContain("verified: true");
});
it("compares the read-back out point against the requested value", async () => {
await timeline.trim_clip.handler({ node_id: "abc", new_out_seconds: 8 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("Math.abs(actualOut - 8) > tolerance");
});
it("only writes the edge that was actually requested", async () => {
await timeline.trim_clip.handler({ node_id: "abc", new_in_seconds: 2 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("clip.inPoint = __secondsToTicks(2).toString();");
expect(script).not.toContain("clip.outPoint = __secondsToTicks(2).toString();");
});
it("derives its tolerance from the sequence timebase so frame snapping is not a failure", async () => {
await timeline.trim_clip.handler({ node_id: "abc", new_in_seconds: 2 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("seq.timebase");
expect(script).toContain("TICKS_PER_SECOND / 24");
expect(script).toContain("var tolerance = __ticksToSeconds(frameTicks)");
});
it("refuses invalid numeric edit points before contacting Premiere", async () => {
const result = await timeline.trim_clip.handler({
node_id: "abc",
new_out_seconds: Number.NaN,
});
expect(result.success).toBe(false);
expect(result.error).toContain("finite");
expect(mockedSendCommand).not.toHaveBeenCalled();
});
it("verifies the visible timeline geometry as well as source metadata", async () => {
await timeline.trim_clip.handler({ node_id: "abc", new_out_seconds: 8 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("var afterResult = __findClip(\"abc\")");
expect(script).toContain("var expectedStart = before.start");
expect(script).toContain("var expectedEnd = before.end + (actualOut - before.outPoint)");
expect(script).toContain("visible timeline duration does not match the applied source range");
expect(script).toContain("source metadata may have changed, but this is not reported as success");
});
it("fails closed for retimed clips and unhandled out-of-range keyframes", async () => {
await timeline.trim_clip.handler({ node_id: "abc", new_out_seconds: 8 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("does not support retimed or otherwise non-1x clips");
expect(script).toContain("__findOutOfRangeKeyframes");
expect(script).toContain("keyframe_policy: preserve");
expect(script).toContain("keyframesOutsideVisibleRange");
});
it("allows explicit keyframe preservation while reporting that it was not fully verified", async () => {
await timeline.trim_clip.handler({
node_id: "abc",
new_out_seconds: 8,
keyframe_policy: "preserve",
});
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain('keyframePolicy: "preserve"');
expect(script).toContain("keyframesVerified:");
});
});
describe("split_clip verification", () => {
it("refuses invalid local arguments before contacting Premiere", async () => {
const invalidTime = await timeline.split_clip.handler({ time_seconds: -1 });
expect(invalidTime.success).toBe(false);
expect(mockedSendCommand).not.toHaveBeenCalled();
const invalidTrack = await timeline.split_clip.handler({
time_seconds: 4,
track_index: 1.5,
});
expect(invalidTrack.success).toBe(false);
expect(mockedSendCommand).not.toHaveBeenCalled();
});
it("requires a clip to span the requested cut before attempting QE razor", async () => {
await timeline.split_clip.handler({ time_seconds: 4, track_type: "audio" });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("function __eligibleClips");
expect(script).toContain("if (!eligibleBefore.length)");
expect(script).toContain("no razor was attempted");
});
it("verifies each left and right segment, not only a count increase", async () => {
await timeline.split_clip.handler({ time_seconds: 4 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("var expectedClipCount = clipCountBefore + eligibleBefore.length");
expect(script).toContain("function __hasSegment");
expect(script).toContain("left segment");
expect(script).toContain("right segment");
expect(script).toContain('keyframeSemantics: "unverified"');
});
});
describe("remove_linked_from_timeline", () => {
it("valida dois IDs e remove os dois clipes no mesmo script", async () => {
const invalid = await timeline.remove_linked_from_timeline.handler({ node_ids: ["video"] });
expect(invalid.success).toBe(false);
expect(mockedSendCommand).not.toHaveBeenCalled();
await timeline.remove_linked_from_timeline.handler({ node_ids: ["video", "audio"] });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain('var primeiro = __findClip("video")');
expect(script).toContain('var segundo = __findClip("audio")');
expect(script).toContain("primeiro.clip.remove(true, false)");
expect(script).toContain("segundo.clip.remove(true, false)");
expect(script).toContain("O Premiere não confirmou a remoção dos dois clipes vinculados");
});
});
describe("move_clip verification", () => {
it("re-finds the clip after the move rather than trusting a stale reference", async () => {
await timeline.move_clip.handler({ node_id: "abc", new_start_seconds: 5 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain('var after = __findClip("abc")');
expect(script).toContain("Math.abs(actualStart - 5) > tolerance");
expect(script).toContain("verified: true");
});
it("rejects an out-of-range track index instead of silently skipping the move", async () => {
await timeline.move_clip.handler({
node_id: "abc",
new_start_seconds: 5,
new_track_index: 99,
});
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("is out of range");
expect(script).toContain("targetTracks.numTracks");
});
it("attempts the track change before writing the start time, so a failure leaves no partial edit", async () => {
await timeline.move_clip.handler({
node_id: "abc",
new_start_seconds: 5,
new_track_index: 1,
});
const script = mockedSendCommand.mock.calls[0][0];
const trackMoveAt = script.indexOf("qeClip.moveToTrack");
const startWriteAt = script.indexOf("clip.start = __secondsToTicks");
expect(trackMoveAt).toBeGreaterThan(-1);
expect(startWriteAt).toBeGreaterThan(-1);
expect(trackMoveAt).toBeLessThan(startWriteAt);
});
it("matches the QE clip by start time because QE item indices include gaps", async () => {
await timeline.move_clip.handler({
node_id: "abc",
new_start_seconds: 5,
new_track_index: 1,
});
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain('String(cand.type) !== "Clip"');
expect(script).not.toContain("getItemAt(result.clipIndex)");
});
it("verifies the clip actually landed on the requested track", async () => {
await timeline.move_clip.handler({
node_id: "abc",
new_start_seconds: 5,
new_track_index: 1,
});
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("after.trackIndex !== 1");
});
it("does not emit any track-move code when no track change was requested", async () => {
await timeline.move_clip.handler({ node_id: "abc", new_start_seconds: 5 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).not.toContain("moveToTrack");
expect(script).not.toContain("after.trackIndex !==");
});
});
describe("razor_all_tracks verification", () => {
it("counts tracks whose clip count actually changed, not razor attempts", async () => {
await trackTargeting.razor_all_tracks.handler({ time_seconds: 7 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("domTrack.clips.numItems > before");
expect(script).toContain("verified: true");
});
it("treats only tracks with a clip spanning the cut point as eligible", async () => {
await trackTargeting.razor_all_tracks.handler({ time_seconds: 7 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("function __spansPoint");
expect(script).toContain("if (v > s && v < e) return true");
expect(script).toContain("if (wasEligible) eligible++");
});
it("errors when any eligible track did not split", async () => {
await trackTargeting.razor_all_tracks.handler({ time_seconds: 7 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("eligible > 0 && razored < eligible");
expect(script).toContain("only partially applied");
expect(script).toContain("no-op on some Premiere Pro 26.x");
});
it("surfaces per-track razor exceptions rather than swallowing them", async () => {
await trackTargeting.razor_all_tracks.handler({ time_seconds: 7 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("failures.push");
expect(script).toContain("failures: failures");
});
});
describe("move_clip_to_track verification", () => {
it("matches the QE clip by start time instead of the DOM clip index", async () => {
// getItemAt(result.clipIndex) returns an "Empty" gap on any track with a
// leading gap, which is what made this fail with a misleading error.
await advanced.move_clip_to_track.handler({
node_id: "abc",
target_track_index: 1,
});
const script = mockedSendCommand.mock.calls[0][0];
expect(script).not.toContain("getItemAt(result.clipIndex)");
expect(script).toContain('String(cand.type) !== "Clip"');
expect(script).toContain("Math.abs(parseFloat(cand.start.ticks) - wantStart) < 1");
});
it("rejects an out-of-range target track", async () => {
await advanced.move_clip_to_track.handler({
node_id: "abc",
target_track_index: 99,
});
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("is out of range");
expect(script).toContain("targetTracks.numTracks");
});
it("short-circuits when the clip is already on the requested track", async () => {
await advanced.move_clip_to_track.handler({
node_id: "abc",
target_track_index: 1,
});
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("alreadyOnTrack: true");
});
it("confirms against the DOM rather than trusting the QE call", async () => {
await advanced.move_clip_to_track.handler({
node_id: "abc",
target_track_index: 1,
});
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain('var after = __findClip("abc")');
expect(script).toContain("after.trackIndex !== 1");
expect(script).toContain("verified: true");
});
it("explains the QE rejection instead of surfacing a raw parameter error", async () => {
await advanced.move_clip_to_track.handler({
node_id: "abc",
target_track_index: 1,
});
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("catch (moveErr)");
expect(script).toContain("The clip was left untouched");
expect(script).toContain("overwriteClip");
});
});
describe("track creation verification", () => {
it("rejects invalid add_track requests locally instead of generating unsafe host code", async () => {
const result = await tracks.add_track.handler({ track_type: "audio", count: 0 });
expect(result.success).toBe(false);
expect(result.error).toContain("positive integer");
expect(mockedSendCommand).not.toHaveBeenCalled();
});
it("uses a bounded QE fallback only after a public add_track failure with no mutation", async () => {
await tracks.add_track.handler({ track_type: "audio", count: 2 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain('typeof seq.insertAudioTrackAt !== "function"');
expect(script).toContain("afterPublic !== expected && afterPublic !== before");
expect(script).toContain("qeSeq.addTracks(0, 2, 0, 0)");
expect(script).toContain("if (after !== expected)");
expect(script).toContain("verified: true");
});
it("does not report QE add_tracks success until exact video and audio count readback", async () => {
await advanced.add_tracks.handler({
video_tracks: 1,
audio_tracks: 2,
audio_mono_tracks: 1,
audio_51_tracks: 1,
});
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("var beforeVideo = seq.videoTracks.numTracks");
expect(script).toContain("var expectedAudio = beforeAudio + 4");
expect(script).toContain("typeof qeSeq.addTracks !== \"function\"");
expect(script).toContain("afterVideo !== expectedVideo || afterAudio !== expectedAudio");
expect(script).toContain("verified: true");
});
it("rejects an empty add_tracks request locally rather than returning a successful no-op", async () => {
const result = await advanced.add_tracks.handler({});
expect(result.success).toBe(false);
expect(result.error).toContain("at least one");
expect(mockedSendCommand).not.toHaveBeenCalled();
});
});
describe("overwrite_clip verification", () => {
it("rejects invalid indices locally before they can be interpolated into ExtendScript", async () => {
const result = await advanced.overwrite_clip.handler({
item_id: "source-1",
audio_track_index: -1,
});
expect(result.success).toBe(false);
expect(result.error).toContain("audio_track_index");
expect(mockedSendCommand).not.toHaveBeenCalled();
});
it("checks both target tracks and host capability before calling overwriteClip", async () => {
await advanced.overwrite_clip.handler({
item_id: "source-1",
track_index: 1,
audio_track_index: 2,
start_seconds: 5,
});
const script = mockedSendCommand.mock.calls[0][0];
const videoCheck = script.indexOf("Video track index 1 is out of range");
const audioCheck = script.indexOf("Audio track index 2 is out of range");
const call = script.indexOf("seq.overwriteClip(item");
expect(videoCheck).toBeGreaterThan(-1);
expect(audioCheck).toBeGreaterThan(-1);
expect(call).toBeGreaterThan(audioCheck);
expect(script).toContain('typeof seq.overwriteClip !== "function"');
});
it("proves the requested source landed on a target track and errors on no new placement", async () => {
await advanced.overwrite_clip.handler({ item_id: "source-1", start_seconds: 5 });
const script = mockedSendCommand.mock.calls[0][0];
expect(script).toContain("clip.projectItem ? String(clip.projectItem.nodeId)");
expect(script).toContain("Math.abs(actualStartTicks - wantedStartTicks) <= frameTicks");
expect(script).toContain("if (!videoPlaced && !audioPlaced)");
expect(script).toContain("produced no verifiable new placement");
expect(script).toContain("verified: true");
});
});