mirror of
https://github.com/calesthio/OpenMontage.git
synced 2026-08-25 09:34:21 +08:00
fix(backlot): surface approval artifacts before gates
This commit is contained in:
@@ -91,6 +91,9 @@ class TestBoardState:
|
||||
assert sc2["visual"]["exists"] is False # missing file flagged
|
||||
script_stage = next(x for x in s["stages"] if x["name"] == "script")
|
||||
assert script_stage["status"] == "completed"
|
||||
assert script_stage["produces"] == ["script"]
|
||||
proposal_stage = next(x for x in s["stages"] if x["name"] == "proposal")
|
||||
assert proposal_stage["produces"] == ["proposal_packet", "decision_log"]
|
||||
|
||||
def test_gate_skip_detection(self, projects_root):
|
||||
p = _make_project(projects_root, "sneaky")
|
||||
|
||||
@@ -10,16 +10,102 @@ import urllib.request
|
||||
|
||||
import pytest
|
||||
|
||||
from lib.checkpoint import init_project, write_checkpoint
|
||||
from scripts import backlot_screenshot_stage
|
||||
from tests.contracts.test_phase0_contracts import sample_artifact
|
||||
|
||||
|
||||
pytest.importorskip("playwright.sync_api")
|
||||
from playwright.sync_api import sync_playwright # noqa: E402
|
||||
|
||||
|
||||
APPROVAL_CASES = [
|
||||
("gate-research", "framework-smoke", "research", "research_brief", "Test Topic"),
|
||||
("gate-idea", "hybrid", "idea", "brief", "Did you know?"),
|
||||
("gate-proposal", "cinematic", "proposal", "proposal_packet", "The Surprising Truth About X"),
|
||||
("gate-script", "cinematic", "script", "script", "Hello world"),
|
||||
("gate-scene-plan", "cinematic", "scene_plan", "scene_plan", "Host on camera"),
|
||||
("gate-assets", "cinematic", "assets", "asset_manifest", "asset-1"),
|
||||
("gate-edit", "documentary-montage", "edit", "edit_decisions", "cut-1"),
|
||||
("gate-compose", "cinematic", "compose", "render_report", "renders/output.mp4"),
|
||||
("gate-publish", "cinematic", "publish", "publish_log", "youtube"),
|
||||
]
|
||||
|
||||
|
||||
def _build_approval_projects() -> None:
|
||||
root = backlot_screenshot_stage.STAGE_DIR
|
||||
for project_id, pipeline_type, stage, artifact_name, _visible_text in APPROVAL_CASES:
|
||||
artifact = sample_artifact(artifact_name)
|
||||
if artifact_name == "edit_decisions":
|
||||
artifact["render_runtime"] = "ffmpeg"
|
||||
review_summary = (
|
||||
{
|
||||
"critical": 0,
|
||||
"suggestions": 1,
|
||||
"nitpicks": 0,
|
||||
"review_focus_met": "9/9",
|
||||
"schema_validation": "proposal_packet PASS",
|
||||
}
|
||||
if stage == "proposal"
|
||||
else "Artifact is ready for human review."
|
||||
)
|
||||
init_project(
|
||||
project_id,
|
||||
title=f"Approval fixture: {stage}",
|
||||
pipeline_type=pipeline_type,
|
||||
pipeline_dir=root,
|
||||
)
|
||||
write_checkpoint(
|
||||
root,
|
||||
project_id,
|
||||
stage,
|
||||
"awaiting_human",
|
||||
{artifact_name: artifact},
|
||||
pipeline_type=pipeline_type,
|
||||
review={
|
||||
"round": 1,
|
||||
"decision": "pass",
|
||||
"critical": 0,
|
||||
"suggestions": 1,
|
||||
"nitpicks": 0,
|
||||
"summary": review_summary,
|
||||
},
|
||||
)
|
||||
|
||||
# A manifest-declared custom stage/artifact proves the fallback is driven
|
||||
# by the stage contract rather than a hardcoded canonical-stage list.
|
||||
init_project(
|
||||
"gate-character-design",
|
||||
title="Approval fixture: character design",
|
||||
pipeline_type="character-animation",
|
||||
pipeline_dir=root,
|
||||
)
|
||||
write_checkpoint(
|
||||
root,
|
||||
"gate-character-design",
|
||||
"character_design",
|
||||
"awaiting_human",
|
||||
{"character_design": {
|
||||
"version": "1.0",
|
||||
"characters": [{
|
||||
"id": "ada",
|
||||
"display_name": "Ada",
|
||||
"role": "explorer",
|
||||
"body_type": "round",
|
||||
"style": "flat graphic",
|
||||
"silhouette_notes": "Round explorer with a bright orange field jacket",
|
||||
"required_emotions": ["curious"],
|
||||
"required_actions": ["wave"],
|
||||
}],
|
||||
}},
|
||||
pipeline_type="character-animation",
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def staged_backlot_server():
|
||||
backlot_screenshot_stage.build_stage()
|
||||
_build_approval_projects()
|
||||
port = 4897
|
||||
env = dict(os.environ)
|
||||
env["OPENMONTAGE_PROJECTS_DIR"] = str(backlot_screenshot_stage.STAGE_DIR)
|
||||
@@ -57,6 +143,8 @@ def test_project_pages_fit_mobile_and_tablet_widths(staged_backlot_server):
|
||||
"/p/the-slow-orchard?static=1",
|
||||
"/p/the-last-lighthouse?static=1",
|
||||
"/p/paper-boats?static=1",
|
||||
"/p/gate-proposal?static=1",
|
||||
"/p/gate-character-design?static=1",
|
||||
]
|
||||
viewports = [
|
||||
{"width": 390, "height": 844},
|
||||
@@ -108,3 +196,69 @@ def test_static_navigation_invalid_route_and_active_takes(staged_backlot_server)
|
||||
assert page.locator(".takes .tk.active").count() >= 1
|
||||
finally:
|
||||
browser.close()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("project_id", "_pipeline_type", "stage", "artifact_name", "visible_text"),
|
||||
APPROVAL_CASES,
|
||||
)
|
||||
def test_every_canonical_gate_promotes_its_artifact_before_approval(
|
||||
staged_backlot_server,
|
||||
project_id,
|
||||
_pipeline_type,
|
||||
stage,
|
||||
artifact_name,
|
||||
visible_text,
|
||||
):
|
||||
with sync_playwright() as pw:
|
||||
browser = pw.chromium.launch(headless=True)
|
||||
page = browser.new_page(viewport={"width": 1280, "height": 900})
|
||||
try:
|
||||
page.goto(
|
||||
staged_backlot_server + f"/p/{project_id}?static=1",
|
||||
wait_until="networkidle",
|
||||
)
|
||||
review = page.locator(f'.approval-review[data-stage="{stage}"]')
|
||||
assert review.is_visible()
|
||||
assert review.get_by_text("PENDING APPROVAL", exact=True).is_visible()
|
||||
assert "[object Object]" not in review.inner_text()
|
||||
artifact = review.locator(f'[data-artifact="{artifact_name}"]')
|
||||
assert artifact.is_visible()
|
||||
assert visible_text in artifact.inner_text()
|
||||
|
||||
review.get_by_role("button", name="OPEN FULL ARTIFACT").click()
|
||||
assert page.locator(".drawer").is_visible()
|
||||
assert visible_text in page.locator(".drawer").inner_text()
|
||||
finally:
|
||||
browser.close()
|
||||
|
||||
|
||||
def test_script_gate_keeps_script_visible_and_marks_pending_approval(staged_backlot_server):
|
||||
with sync_playwright() as pw:
|
||||
browser = pw.chromium.launch(headless=True)
|
||||
page = browser.new_page(viewport={"width": 1280, "height": 900})
|
||||
try:
|
||||
page.goto(staged_backlot_server + "/p/gate-script?static=1", wait_until="networkidle")
|
||||
assert page.locator(".script-card").is_visible()
|
||||
assert page.locator(".script-pending").inner_text() == "PENDING APPROVAL"
|
||||
finally:
|
||||
browser.close()
|
||||
|
||||
|
||||
def test_manifest_declared_custom_gate_uses_generic_review_fallback(staged_backlot_server):
|
||||
with sync_playwright() as pw:
|
||||
browser = pw.chromium.launch(headless=True)
|
||||
page = browser.new_page(viewport={"width": 1280, "height": 900})
|
||||
try:
|
||||
page.goto(
|
||||
staged_backlot_server + "/p/gate-character-design?static=1",
|
||||
wait_until="networkidle",
|
||||
)
|
||||
review = page.locator('.approval-review[data-stage="character_design"]')
|
||||
assert review.is_visible()
|
||||
artifact = review.locator('[data-artifact="character_design"]')
|
||||
assert artifact.is_visible()
|
||||
assert "Ada" in artifact.inner_text()
|
||||
assert "Round explorer" in artifact.inner_text()
|
||||
finally:
|
||||
browser.close()
|
||||
|
||||
Reference in New Issue
Block a user