Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions desktop/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1995,14 +1995,14 @@ function App() {
setAgentStates(INITIAL_AGENT_STATES);
updateWorkflowMessage(workflowId, {
status: "blocked",
phase: "Transcription approval required",
phase: "Local catalog required",
progress: 100,
detail: result.message || "ReelBrain cannot begin grounded editing until a transcript is authorized.",
detail: result.message || "ReelBrain cannot begin grounded editing until a local catalog is available.",
videoChanged: false,
});
setMessages((current) => [
...current,
{ id: crypto.randomUUID(), role: "system", text: result.message || "Transcription approval is required before fan-out.", time: nowLabel() },
{ id: crypto.randomUUID(), role: "system", text: result.message || "A local transcript and candidate catalog are required before fan-out.", time: nowLabel() },
]);
} else {
updateWorkflowMessage(workflowId, {
Expand Down
2 changes: 2 additions & 0 deletions desktop/src/services/reelbrain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ export async function startEditorialFanout(input: {
agentResults: (raw.agentResults ?? raw.agent_results) as unknown[] | undefined,
requiresCreatorApproval: (raw.requiresCreatorApproval ?? raw.requires_creator_approval) as boolean | undefined,
requiredEffect: (raw.requiredEffect ?? raw.required_effect) as string | undefined,
catalogSearchPath: (raw.catalogSearchPath ?? raw.catalog_search_path) as string | undefined,
requiredCatalogFiles: (raw.requiredCatalogFiles ?? raw.required_catalog_files) as string[] | undefined,
message: raw.message as string | undefined,
};
}
Expand Down
2 changes: 2 additions & 0 deletions desktop/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ export type FanoutResult = {
agentResults?: unknown[];
requiresCreatorApproval?: boolean;
requiredEffect?: string;
catalogSearchPath?: string;
requiredCatalogFiles?: string[];
message?: string;
};

Expand Down
25 changes: 24 additions & 1 deletion reelbrain/fanout.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,13 +223,36 @@ def plan(self, request: dict[str, object]) -> dict[str, object]:
raise FanoutError("source_digest_mismatch")
catalog = self._find_catalog(source_sha256)
if catalog is None:
catalog_search_path = (
self.workspace
/ ".reelbrain"
/ "dogfood"
/ "*"
/ "run"
/ "source_inventory.json"
)
required_catalog_files = [
"source_inventory.json",
"<source_id>/editorial_plan.json",
"<source_id>/bilingual_transcript.json",
]
return {
"status": "TRANSCRIPT_REQUIRED",
"source_path": str(source_path),
"source_sha256": source_sha256,
"requires_creator_approval": True,
"required_effect": "transcribe_and_build_candidate_catalog",
"message": "This source has no canonical transcript/catalog yet. Approve transcription before starting the editorial agents.",
"catalog_search_path": str(catalog_search_path),
"required_catalog_files": required_catalog_files,
"message": (
"No canonical catalog matched this source SHA-256. ReelBrain searched "
f"{catalog_search_path} and requires source_inventory.json plus "
"<source_id>/editorial_plan.json and "
"<source_id>/bilingual_transcript.json. Files elsewhere are not "
"imported automatically. No agents ran, no video changed, and no "
"provider spend was authorized. Prepare or import the catalog into "
"the app workspace, then choose New edit again."
),
}
memory = DesktopMemoryService(self.workspace, creator_id).inspect()
current_steering = str(request.get("current_steering") or "").strip() or None
Expand Down
12 changes: 12 additions & 0 deletions tests/test_desktop_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,18 @@ def test_unprepared_source_requires_transcription_approval(tmp_path: Path) -> No
)
assert result["status"] == "TRANSCRIPT_REQUIRED"
assert result["requires_creator_approval"] is True
assert result["catalog_search_path"] == str(
tmp_path / ".reelbrain" / "dogfood" / "*" / "run" / "source_inventory.json"
)
assert result["required_catalog_files"] == [
"source_inventory.json",
"<source_id>/editorial_plan.json",
"<source_id>/bilingual_transcript.json",
]
assert "Files elsewhere are not imported automatically" in result["message"]
assert "No agents ran, no video changed, and no provider spend was authorized" in result[
"message"
]


def test_creator_review_actions_never_imply_publish_ready(tmp_path: Path) -> None:
Expand Down