Fix audited generation, Wizard, World3D and review integrations - #404
Conversation
PR Review — Loreframe StudioRisk: medium Automated review from Findings
Changed files
CONTRIBUTING checklist
Posted by the repo PR review workflow. Re-runs on each push to the PR. |
Code healthQuality score: 63.8/100Higher is better. The score is a trend dashboard; the independent ratchet below remains the CI gate.
Change vs PR base: +0.1 points.
Markdown, JSON catalogs and tests are out of this table. Only Most complex functions
Trend vs baseline
Warnings
Ratchet passed. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Review panel leaves dashboard stale
- After a successful review persist, the host now forwards the saved pipeline and DirectorDashboard updates dashboardSelectedPipeline so the clip grid, tags, and counts stay in sync.
Or push these changes by commenting:
@cursor push 17c8b80036
Preview (17c8b80036)
diff --git a/ui/src/components/DirectorDashboard/DirectorDashboard.tsx b/ui/src/components/DirectorDashboard/DirectorDashboard.tsx
--- a/ui/src/components/DirectorDashboard/DirectorDashboard.tsx
+++ b/ui/src/components/DirectorDashboard/DirectorDashboard.tsx
@@ -1157,7 +1157,11 @@
<details className="rounded-lg border border-border p-3">
<summary className="cursor-pointer text-sm">{reviewCopy().title}</summary>
- <ProductionReviewHost key={`${activeWorkspace}:${selectedPipeline.pipeline_id}`} pipeline={selectedPipeline} workspace={activeWorkspace} />
+ <ProductionReviewHost key={`${activeWorkspace}:${selectedPipeline.pipeline_id}`} pipeline={selectedPipeline} workspace={activeWorkspace} onChange={next => {
+ useStore.setState(s => s.dashboardSelectedPipeline?.pipeline_id === next.pipeline_id
+ ? { dashboardSelectedPipeline: next }
+ : {})
+ }} />
</details>
{/* LLM Log */}
<div className="bg-bg-secondary rounded-lg border border-border p-3">
diff --git a/ui/src/features/production-review/ProductionReviewHost.tsx b/ui/src/features/production-review/ProductionReviewHost.tsx
--- a/ui/src/features/production-review/ProductionReviewHost.tsx
+++ b/ui/src/features/production-review/ProductionReviewHost.tsx
@@ -6,7 +6,13 @@
import { exportReview, persistReview, regenerateReview, reviewFileUrl } from './runtime'
import { reviewCopy } from './copy'
-export function ProductionReviewHost({ pipeline, workspace }: { pipeline: SavedPipelineState; workspace: string }) {
+export function ProductionReviewHost({
+ pipeline, workspace, onChange,
+}: {
+ pipeline: SavedPipelineState
+ workspace: string
+ onChange?: (pipeline: SavedPipelineState) => void
+}) {
const desk = useMemo(() => projectReviewDesk({ pipeline: { ...pipeline, workspace } }), [pipeline, workspace])
const [job, setJob] = useState<VideoEditorExportJob | null>(null)
const [error, setError] = useState('')
@@ -23,7 +29,10 @@
}, [job])
return <div>
<ProductionReviewDesk desk={desk} onChange={() => undefined}
- onPersist={commands => persistReview(desk, commands)}
+ onPersist={async commands => {
+ const saved = await persistReview(desk, commands)
+ onChange?.(saved)
+ }}
onRegenerate={plan => regenerateReview(desk, plan)}
onExport={async selection => { setError(''); setJob(await exportReview(desk, selection)) }}
fileUrl={filename => reviewFileUrl(filename, workspace)} />
diff --git a/ui/src/features/production-review/runtime.ts b/ui/src/features/production-review/runtime.ts
--- a/ui/src/features/production-review/runtime.ts
+++ b/ui/src/features/production-review/runtime.ts
@@ -1,13 +1,14 @@
import { BASE } from '../../api/http'
import { fetchSavedPipeline, rerunClipVideo } from '../../api/director'
import { probeVideoEditorClip, startVideoEditorExport } from '../../api/video-editor'
+import type { SavedPipelineState } from '../../types'
import { projectReviewDesk } from './project'
import type { ExportSelection, PersistCommand, RegenOutcome, RegenPlan, ReviewDesk } from './types'
export const reviewFileUrl = (name: string, workspace: string) =>
`/api/v1/file/${encodeURIComponent(name)}?workspace=${encodeURIComponent(workspace)}`
-export async function persistReview(desk: ReviewDesk, commands: PersistCommand[]): Promise<void> {
+export async function persistReview(desk: ReviewDesk, commands: PersistCommand[]): Promise<SavedPipelineState> {
const decisions = commands.filter(command => command.type !== 'rerun_clip')
const response = await fetch(`${BASE}/api/v1/director/pipelines/${encodeURIComponent(desk.pipelineId)}/review`, {
method: 'PUT', headers: { 'Content-Type': 'application/json' },
@@ -17,6 +18,7 @@
const body = await response.json().catch(() => ({}))
throw new Error(body.detail || 'Could not save review')
}
+ return response.json()
}
export async function regenerateReview(desk: ReviewDesk, plan: RegenPlan): Promise<RegenOutcome[]> {
diff --git a/ui/tests/productionReviewRuntime.test.tsx b/ui/tests/productionReviewRuntime.test.tsx
--- a/ui/tests/productionReviewRuntime.test.tsx
+++ b/ui/tests/productionReviewRuntime.test.tsx
@@ -44,13 +44,16 @@
}
throw new Error(`Unexpected request: ${url}`)
})
- const view = (key: string) => <ProductionReviewHost key={key} workspace="original" pipeline={saved as SavedPipelineState} />
+ let notified: SavedPipelineState | null = null
+ const view = (key: string) => <ProductionReviewHost key={key} workspace="original" pipeline={saved as SavedPipelineState} onChange={next => { notified = next }} />
try {
const root = render(view('first'))
await act(async () => fireEvent.click(screen.getByRole('button', { name: 'old-id' })))
await act(async () => fireEvent.click(screen.getByRole('button', { name: 'Approve' })))
assert.equal(saved.clips[0].selected_video_filename, 'old.mp4')
assert.equal(saved.clips[0].tag, 'good')
+ assert.equal(notified?.clips[0].selected_video_filename, 'old.mp4')
+ assert.equal(notified?.clips[0].tag, 'good')
root.rerender(view('reload'))
assert.equal(screen.getByRole('button', { name: 'old-id' }).getAttribute('aria-pressed'), 'true')
await act(async () => fireEvent.click(screen.getByRole('button', { name: 'Export approved selection' })))You can send follow-ups to the cloud agent here.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 93c9982. Configure here.


Resumen ejecutivo
Qué cambia
Corrige los ocho fallos de integración de la auditoría: una intención remota no vuelve a ejecutar al proveedor al recuperar estado; Wizard continúa sin tener el navegador abierto; el render World3D funciona desde la aplicación compilada; el inspector y la revisión de producción ejecutan sus acciones reales.
Para qué sirve
Evita duplicar generaciones, perder borradores y presentar acciones como realizadas cuando solo cambiaba la interfaz. Por ejemplo, una imagen terminada continúa a upscale desde el servidor, y cambiar una toma guarda esa selección sin heredar la aprobación anterior.
Impacto para el usuario
Se recuperan los borradores sin guardar aunque se abran más de ocho documentos. Reanudar una tarea fallida crea un intento nuevo. Generar en el inspector devuelve una tarea verificable; Director permite guardar decisiones, regenerar tomas y descargar la selección aprobada. Los MP4 solicitados a 24 fps mantienen esa frecuencia.
Riesgo
Estado
Summary
Un único PR agrupa F1–F8 por petición expresa del usuario. Conserva los contratos de intención, workspace y provenance; conecta las superficies incompletas con los ejecutores existentes.
Overview
Las intenciones se admiten y despachan con identidad durable. El supervisor reconcilia workflows al arrancar y durante la vida del servidor. Los consumidores reciben tareas y errores reales. World3D monta un stage dedicado desde un entrypoint compilado y utiliza el mismo reloj y bloqueo de exportación del editor.
Detailed changes
Backend
interruptedy requiere una intención nueva; nunca se relanza automáticamente.executionKeyal reanudar tareas fallidas/canceladas/interrumpidas. Mantiene la lista de tareas anteriores./world3d-render.html, detección de renderer/browser y origen interno basado en el socket o configuración explícita. Plan y mux conservan 24/30/60 fps.PUT /api/v1/director/pipelines/{pid}/reviewguarda decisiones como un lote atómico con el bloqueo de Director, pertenencia al workspace y comprobación del archivo seleccionado. La selección actualiza el segmento H3 único y los outputs.UI and Wizard
ui/src/lib; Wizard conserva sus exports y el inspector accede porui/src/api.Data, provenance and compatibility
Sin migración de medios ni de identidades. Se preservan prompts literales, intentos históricos, archivos ajenos y workspace explícito. El inventario de rutas incorpora únicamente el nuevo PUT; se verificó que las rutas previas mantienen su orden relativo. Las tres suites Python nuevas forman parte del reparto de CI. No se modifican baselines de calidad.
Files and ownership
app/services/core_generation_commands.py,core_remote_image.py: despacho/recuperación remota.wizard_workflow_executor.py,wizard_workflow_supervisor.pyy montajes de runtime: continuación y reintentos.world3d_export.py,world3d_renderer_support.py,ownedRenderer.tsx, HTML/Vite: render compilado.generation-inspector, codec/API de vídeo: ejecución del inspector.production-review,director_review.py,DirectorDashboard: decisiones persistidas y acciones reales.documentHistory.ts: conservación de borradores.Validation
Corrección del CI y los dos avisos de revisión
Reproducido el agotamiento de heap del test de revisión: 30 ms de demora hacían que la comparación
HTMLElementcontranullformatease el grafo DOM/React. La aserción compara un booleano; se conserva la demora como regresión.npm testusa ahora dos procesos también en CI.El dashboard recibe el pipeline confirmado por el guardado y actualiza tomas, tags y contadores. No se aplica una respuesta tardía tras desmontar el panel ni a otro workspace/pipeline.
La comparación muestra metadata real de cada vídeo, o segundos/frames+fps propios de la toma. No atribuye la duración planificada del plano a todas sus versiones.
Regresiones:
NODE_OPTIONS=--max-old-space-size=256 ui/node_modules/.bin/tsx --tsconfig ui/tsconfig.app.json --import ./ui/tests/setupI18n.ts --test --test-concurrency=2 ui/tests/productionReviewUi.test.tsx ui/tests/productionReviewRuntime.test.tsx ui/tests/productionReview.test.ts: 20 passed. La reproducción anterior agotaba esos mismos 256 MiB.Añadida al inventario de arquitectura una entrada
behaviorpor la importación pública del store en el nuevo test del dashboard; ninguna entrada anterior alterada.pytest -q tests/test_architecture_contracts.py: 5 passed ypython scripts/architecture_contracts.py: correcto.Suite completa por
npm test: 1720 passed, 0 cancelled, 0 skipped (94,99 s); lint, build, presupuesto y ratchet correctos. Backend sin cambios en este commit.Date (UTC): 2026-09-12
Base SHA:
5f68eb124146c73cef8e5aeac33204aa07f2704eHead SHA:
5b55e550e36209f2a5cc20ceb205f6928bfb50e3Validation scope: suite completa por componentes y smoke real; proveedores simulados. La primera ejecución del wrapper no pasó y no se presenta como
--fullverde.python scripts/verify_clean_repo.py,python scripts/check_dependency_contract.py,python scripts/check_documentation_links.py,python scripts/check_brand_contract.py.python -m compileall -q app/services app/launch.py scripts.Regresión enfocada:
pytest -q tests/test_architecture_contracts.py tests/test_ci_shards.py tests/test_select_local_tests.py tests/test_quick_video_batches.py tests/test_integration_audit_regressions.py tests/test_director_review.py tests/test_core_runtime.py tests/test_world3d_export.py: 102 passed antes de las dos aserciones adicionales, incluidas en la suite final.OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 python -m pytest -q tests --durations=5: 3368 passed, 2 skipped, 139,54 s.cd ui && npm run i18n:check.UI:
cd ui && npm test(concurrencia de dos procesos en el propio script): 1720 passed, cero omitidas.cd ui && npm run lint -- --max-warnings=0,npm run build,npm run budget: entry JS 190565 / 327680 bytes gzip.git diff --checky ratchet contra la base de development.HOCUSPOCUS_E2E_PORT=42873 CI=1 npm run test:e2e: 36 passed y cuatro pruebas de habla no arrancaron al faltar Chrome en su ruta predeterminada. Repetidas las cuatro con el mismo spec y una configuración local temporal que apunta al Chrome ya instalado: 4 passed. Configuración temporal eliminada, sin debilitar tests.RUN_WORLD3D_RENDER_SMOKE=1 python -m pytest -q tests/test_world3d_owned_render_smoke.py: 1 passed, Chromium/FFmpeg reales, GLB cargado, movimiento entre frames, MP4 256×144, 12 frames a 24 fps durante 0,5 s, sin imports/src/.La primera pasada UI detectó la dependencia directa entre features, ya extraída al codec compartido, y una terminación de proceso bajo carga. La primera pasada Python detectó el inventario de rutas/reparto de tests pendiente de actualizar y una espera agotada de Quick Video. La pasada posterior detectó una espera incorrecta en el nuevo test del supervisor: esperaba la llamada al fake antes de que el recibo estuviera guardado. Ahora espera el estado público persistido. Todos estos casos se volvieron a comprobar.
Code quality
development, destino de este PR; no contramain.CI and review
InternalBugBotyFind critical bugs). Los dos hilos corregidos están resueltos. El check formalIndependent QApermanece neutral; no se cuenta como aprobación independiente.Coste de la tarea
Notes and limitations
t2v/t2v_1.3B; los demás modos conservan sus contratos actuales.Follow-up work
Revisión independiente/CI del HEAD y, fuera de estos ocho hallazgos, mezcla de audio en el renderer del servidor y validación artística con assets reales.
Checklist
Note
Medium Risk
Touches command dispatch, durable task state, and several user-facing execution paths (remote image, Wizard, World3D render, inspector submit, Director review persistence); regressions could affect billing, workflow continuity, or saved production state.
Overview
This PR bundles integration-audit fixes across generation, Wizard workflows, World3D server export, the generation inspector, and Director production review.
Remote image commands now use a persistent dispatch claim and job restore/sync callbacks so replaying an admitted intent does not silently re-call the provider; unknown outcomes surface as interrupted instead of a duplicate run.
Wizard image→upscale gets an app lifespan supervisor that reconciles all workspaces, serialized advance, and a fresh execution key when resuming a failed step so retries are new attempts, not rebinding the old task.
World3D export drives a compiled
world3d-render.htmlentry (__world3dExport) instead of dev/src/imports, validates renderer/browser readiness, binds app URL from the listening socket when unset, and keeps 24/30/60 fps through plan and mux.Director adds
PUT …/pipelines/{pid}/reviewfor atomic batch save of take selection, approval tags, and notes (with H3 segment/output updates and approval cleared on take change). The dashboard embeds a production review panel wired to persist, regenerate via existing rerun APIs, and export approved clips through video-editor.UI: the generation inspector submits real commands (including shared video codec in
lib+api), with busy/error states and receipt-based retry; Scene3D draft pruning keeps unsaved drafts past the cache cap.Reviewed by Cursor Bugbot for commit 5b55e55. Configure here.