fix: assemble jobs pin the project's first clip as their source asset

The claim path resolves the row's video_asset_id; NULL stranded every
assemble job as 'produce asset unavailable'.
This commit is contained in:
glass beadian 2026-10-16 21:42:32 +00:00
parent d8de9f5d82
commit 78d0d0c15e

View file

@ -1,4 +1,4 @@
import { Inject, Injectable, NotFoundException, Optional } from "@nestjs/common";
import { BadRequestException, Inject, Injectable, NotFoundException, Optional } from "@nestjs/common";
import type { PoolClient } from "pg";
import { appendTenantAudit, type AuditEvent } from "../audit/audit.service.js";
import { withTenant } from "../db/client.js";
@ -128,7 +128,7 @@ export class EdlService {
/**
* Queue the assemble lane: the job row carries the validated project so the
* worker re-validates exactly what the api persisted (044's claim picks the
* row up by kind 'assemble'). video_asset_id stays NULL — the produced
* row up by kind 'assemble'). video_asset_id pins the project's first
* output is a derived video_assets row written when the job completes.
*/
async render(workspaceId: string, id: string, lane: EdlLane | undefined, actorUserId: string): Promise<{ jobId: string }> {
@ -140,11 +140,17 @@ export class EdlService {
if (row === undefined) throw new NotFoundException(`EDL project ${id} not found`);
const project = row.project as EdlProject;
const input = { edlProjectId: id, project, ...(lane === undefined ? {} : { lane }) };
// The claim path resolves the row's source asset (the project's FIRST
// clip); the runner resolves the remaining clips through asset().
const firstClip = project.items.find((item) => item.kind === "clip");
if (firstClip === undefined || firstClip.kind !== "clip") {
throw new BadRequestException("project has no clip to render");
}
return client
.query(
`INSERT INTO video_processing_jobs (workspace_id, video_asset_id, kind, state, input_json)
VALUES ($1, NULL, 'assemble', 'queued', $2::jsonb) RETURNING id`,
[workspaceId, JSON.stringify(input)],
VALUES ($1, $3, 'assemble', 'queued', $2::jsonb) RETURNING id`,
[workspaceId, JSON.stringify(input), firstClip.assetId],
)
.then((jobResult) => {
const jobRow = jobResult.rows[0];