Comic cross layer gate
Skill wanshuiyin/ARIS-Movie-Director/skills/comic-cross-layer-gate
The ONE parameterized score-fuser for EVERY comic-author authoring gate — `--gate intent|outline|asset|storyboard|blueprint|continuity|p0_proof|compile`. A single fuser (not a per-layer split) prevents drift. It NEVER re-runs a reviewer; it collects the reviewer score-nodes already on the wiki (via `reviews` edges), fuses them deterministically (min-fuse per dim, max for inverted dims, SKIP missing dims — never substitute 0), then a Codex xhigh adjudicator (NO model pin — follows the local codex config) that sees ONLY structured inputs (scores + tags + raw artifact PATHS + verbatim source context + verbatim rubric — NEVER reviewer prose) makes an asymmetric call (threshold HARD-vetoes "advance"; Codex SOFT-vetoes everything else). The `--gate p0_proof` mode is the zero-credit pre-production proof: a text-only cross-model adversarial review of the pipeline's CODE + IR-CONTRACT + ENGINE state-machine that MUST clear all blockers in BOTH non-author families and then MINT the digest-bound decision:p0_proof certificate via scripts/run_p0_proof.py BEFORE a single metered image-generation credit is spent. Use when a sibling step (intent-parser, outline-creator, asset-review-loop, storyboard-creator, blueprint-author, continuity-audit, json-compiler) defers its acquittal to "the gate", or the user says "过 gate", "cross-layer gate", "审这一层", "p0 proof", "证明流水线再花钱".From its SKILL.md
npx -y skills add wanshuiyin/ARIS-Movie-Director --skill comic-cross-layer-gateAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- runs commandsInstructs the agent to run 1 command, including `scripts/run_p0_proof.py`.
SKILL.md
45.3 KB, ~11.7k tokens by cl100k_base, as published. Nobody here has run it
comic-cross-layer-gate — the Universal Authoring Score-Fuser + the Zero-Credit P0 Proof (Phase 1)
The acquittal organ of the comic-author suite. Every authoring step
(intent → style → outline → asset → storyboard → blueprint → continuity → the compiled comic.json) is a
generator; none of them acquits itself. They each emit their node(s), fan out independent reviewers, and
then defer to this one skill to fuse the scores into a verdict, mint the audit trail, and flip the target's
status. It is the image-comic port of aris_movie's 6-gate adversarial decision skill — but folded into one
parameterized fuser (Codex's single-fuser design, against the per-layer split that drifts: six near-copies
diverge, one fuser stays honest). The downstream per-panel panel_gate / page assembly_gate are NOT this
skill — those live in packages/core/spiral_engine.js and run at bake
time; this skill is the authoring-side, pre-bake gate that decides whether a spec may advance.
Cardinal lesson, landed as a guard not prose: identical scores across rounds = the judge is broken — audit the rubric, do not regenerate the artifact (memory:
feedback_gate_identical_scores_judge_broken). Concretely: this gate carries a_score_fingerprintin everydecisionnode; if round N's fused per-dim vector equals round N−1's after the artifact changed, the gate HALTS and flagsjudge_suspect— the rubric (this skill), not the spec, is the suspect. A gate that emits the same verdict regardless of the work is worse than no gate.
upstream step emits node(s) + fans out independent reviewers (writes review:* score-nodes + `reviews` edges)
│
comic-cross-layer-gate <target_node_id> --gate <kind>
▼
⓪ PRE-CHECK structural facts the GATE computes (asset-resolve / policy / count-band / continuity) — RAW, not opinion
▼
① COLLECT reviewer score-nodes via `reviews` edges — NEVER re-run a reviewer; hard-fail if none
▼
② THRESHOLD per-dim min-fuse (max for inverted dims); SKIP missing dims (NEVER 0-substitute); per-gate floor → threshold_verdict
▼
③ ADJUDICATE Codex xhigh (no model pin — local codex config) — sees ONLY {scores + failure_mode tags + threshold_block + raw PATHS + ≤200w verbatim source + verbatim rubric}
▼ (NEVER reviewer prose / notes / overall — that is the contamination vector)
④ ASYMMETRIC threshold HARD-VETO over "advance"; Codex SOFT-VETO over everything else
▼
⑤ WRITE decision node (full audit) + (on FAIL only) a positive-invariant failure_mode the NEXT step preloads as a banlist
▼
⑥ FLIP target status → locked (advance) · under_review (needs-work) · rejected (terminal) ; stdout last line: VERDICT=<v> GATE=<kind> TARGET=<id>
The --gate p0_proof branch is a different shape (a text-only adversarial review of the pipeline machinery,
not a score-fuse over a spec) — it is documented in its own section below. It is the single most important
contract this skill owns: it runs AFTER comic-json-compiler and
BEFORE any metered image bake (the agent mcp__codex__codex sidecar), costs zero generation credits,
and must clear all blockers in BOTH non-author families and then MINT the digest-bound decision:p0_proof_*
certificate via scripts/run_p0_proof.py — or the spiral is forbidden to spend a
credit.
Constants
- GATE KINDS =
intent | outline | asset | storyboard | blueprint | continuity | p0_proof | compile. The legal verdict set is per-gate (below) and enforced — a verdict outside a gate's set is a hard error (theintentgate can never emitkeep; theassetgate can emitlocked, theintentgate cannot). The legal nodestatustokens a FLIP may write are ONLY{draft, pending, under_review, locked, rejected, superseded, active, complete, final}(schema enum) — a verdict (revise/regenerate/fallback) is never a status. - REVIEWERS (collected, never re-run here): the Codex CLI at
model_reasoning_effort: xhighwith NO model pin — it follows the local codex config (currentlygpt-5.6-sol) — for every gate's ambiguity / correctness / logic pass; Geminiauto-gemini-3wherever a second family or a visual read is needed (image inputs, UX/design). Never downgrade the effort tier (reviewer-routing). (The one place a model IS pinned is the metered BAKE, not this skill:gpt-5.5+xhighas the single compat default inrun_comic.get_bake_plan()— config-driven override plumbing is planned, not yet implemented.) - ADJUDICATOR = the Codex CLI at
xhigh(same no-model-pin rule — local codex config), fed ONLY structured inputs (§③). Its effort is always xhigh — effort widens fan-out, it never weakens the judge. (run_comic.pyexposes only--review-effort; there is no--effortflag.) - FUSE RULE = min per dimension (most-pessimistic), EXCEPT inverted dims (
artifact_severity,*_severity, anything where higher = worse) use max; SKIP a dim no reviewer scored (filter thenulls) — NEVER substitute 0 (the v1.0 bug: a lite reviewer leaving a dim unscored must neither slip an advance nor force a fail). - ASYMMETRIC TRUST = the deterministic threshold has HARD VETO over "advance" (Codex cannot overrule
approve/lockedif the deterministic floor failed); Codex has SOFT VETO over everything else (a Codexreviseoverrules a thresholdapprove). Structural facts (§⓪) also hard-veto advance. - CAPS —
MAX_ASSET_REGEN = 4then escalate the asset gate to the outline gate (abandon_shot); re-gate (re-vote) caps fold into the calling step's attempt budget. The准 ×3convention (asset gate, owned bycomic-asset-review-loop): alockedverdict requires cross-model UNANIMITY in the SAME round — CC and Gemini and Codex all approve the asset that round (≥3 distinct reviewer families lock-pass together). Fewer than 3 families approving →regenerate --another-voter(re-vote to reach the third family, not re-bake); a family's hard-fail → re-bake. (NOT "three consecutive rounds" — that aris_movie video port is wrong for this repo; the owner is same-round unanimity.) - P0 GATE THRESHOLD =
blockers.length == 0in BOTH non-author families{openai, google}on the SAMEcomic_sha, then the certificate is MINTED byscripts/run_p0_proof.py— a HARD HALT until the digest-bounddecision:p0_proof_*node exists (a timed-out/missing family does NOT count toward quorum; quorum unmet = no certificate = baking stays blocked). Zero image-generation credits are spent before the mint. The review is deliberately text-only → not rate-limited → free. - CODEX UNAVAILABLE → emit the threshold-only provisional verdict with
_confidence: "low", exit code 2, and skipfailure_modecompilation. Malformed adjudicator JSON →codex-replyretry ×2, then fall back to threshold-only. - OUTPUT — a
decisionnode inwiki/nodes/, thedecidesedge, areview-tracingentry per collected reviewer + the adjudicator, and (on a FAIL verdict only) afailure_modenode. Final stdout line is EXACTLYVERDICT=<v> GATE=<kind> TARGET=<id>for the caller to parse.
Input contract — what the gate is given, what it refuses
The direct input is a target_node_id + a --gate <kind>. The gate reads from the wiki, it is not
handed prose:
- It NEVER re-runs a reviewer. The upstream step already fanned out and wrote
review:*score-nodes withreviewsedges → the target. The gate collects those nodes; if zero reviews are attached, it hard-fails (no reviews — gate is a score-fuser, not a reviewer). This is the load-bearing separation: the executor that authored the spec must not also be the one whose read of it acquits it. - The adjudicator sees scores + failure-mode tags + raw artifact PATHS + a ≤200-word VERBATIM source slice +
the VERBATIM rubric — and NOTHING else. It never sees a reviewer's prose,
notes,evidence,overall_assessment, orrationale(reviewer-independence). Reviewer prose is the contamination vector; forwarding it re-introduces the correlated blind spot cross-model review exists to break. (Structural facts in §⓪ are an exception — they are RAW artifacts the gate itself computed, not reviewer opinion, so forwarding them does not violate independence.) - The upstream gate state machine is
verdict ∈ {approve, locked, revise, regenerate, fallback}(plus the asset-gate-onlyabandon_shot). Each reviewer call that feeds this gate gets file paths + an explicit=== EXTERNAL CONTEXT (advisory) ===fence around any cross-cutting context — never the author's interpretation. The fence is what keeps "here is the situation" from becoming "here is what to conclude".
The universal architecture (every --gate except p0_proof — which has its OWN write path, the deterministic minter, §p0_proof below)
Ported verbatim from the aris_movie 6-gate skill; the deterministic-JS fuse pattern is the same one the engine
already proves in packages/core/spiral_engine.js:59 (panelVerdict).
Honesty note: the six universal score-fuse gates ship NO runner today — the agent executes this SOP directly (collect → fuse → adjudicate → write → flip, by hand, per the steps below); a parameterized
run_gate.pyis planned, not shipped. The only executables this skill owns/shells today arescripts/run_p0_proof.py(the p0 certificate minter) and the deterministic--gate compilescripts. The worked-example workflows below are the pattern to copy.
⓪ Pre-check — the structural facts the gate computes
Before touching reviewers, compute the raw artifacts (filesystem facts, not opinions) the gate hard-vetoes
on. These differ per gate (see each rubric) but the shape is constant: resolve every referenced asset_id,
every asset is status: locked, policy fields match expected, count in band, continuity links
well-formed (no dangling / out-of-order / cycle). Any non-empty violation set → revise regardless of
reviewer scores OR Codex ("structural failures cannot be voted-around"). Record each as
_unresolved_asset_refs / _policy_violations / _count_band / _continuity_breaks in the decision audit.
① Collect — reviewer score-nodes, never re-run
Walk reviews edges into target_node_id; load each review:* node's payload.review_scores. Build
per_reviewer = {reviewer: {dim: score, ...}, failure_mode_tags: [...]}. Hard-fail if the set is empty.
② Threshold — deterministic per-dim fuse
For each rubric dimension, fuse across reviewers with min (or max for an inverted dim), skipping
any reviewer that left it null. Apply the per-gate floor (each rubric below). Yield threshold_verdict ∈ {advance, revise} + a _cited_dimensions map of every fused value. This is mechanical and reproducible — a
fresh reviewer can re-derive it from the table alone.
③ Adjudicate — Codex, structured inputs only
Call the Codex CLI at xhigh (no model pin — local codex config) with EXACTLY: per_reviewer scores, failure_mode_tags, the threshold_block
(the fused values + the floor), the raw artifact PATHS, a ≤200-word verbatim slice of the source node
(not a summary — a literal excerpt), and the verbatim rubric for this gate. Ask for a verdict in this
gate's legal set + a one-line confidence + the single most important fix. Trace the call
(review-tracing).
④ Asymmetric cross-check
threshold_verdict == revise→ the final verdict is a FAIL verdict no matter what Codex said (threshold hard-vetoes advance).threshold_verdict == advanceAND Codex returns a FAIL verdict → Codex's FAIL wins (Codex soft-vetoes advance).threshold_verdict == advanceAND Codex advances → ADVANCE (approve/locked, per gate).- Record
_threshold_verdict,_codex_verdict,_disagreement(bool),_confidence.
⑤ Write — decision + (on FAIL only) a positive-invariant failure_mode
Write a decision node (full audit). On any FAIL verdict, compile one failure_mode node whose
repair_pattern is a POSITIVE INVARIANT ("force a status:locked ref for every must_show asset", NOT "no
draft assets") — diffusion and the next authoring step focus on what you mention, so state the desired
target, not the ban (negative patterns are only for explicit banlists). Default scope is movie-local;
engine-global needs explicit grounding (an over-broad failure_mode poisons cross-project banlists). The
next authoring step preloads this node as its banlist — the spiral's learning loop.
⑥ Flip + emit
Flip target.status (locked on advance for asset/storyboard/etc.; leave/rejected on a terminal fail).
Exception: a PROVISIONAL-stage storyboard approve never flips — the node stays under_review (see --gate storyboard). Append the decides edge. Print the parse line.
EXACT gates (dimensions · thresholds · vetoes) — ported from the aris_movie source
Every reviewer scores each dim 0–5. "ADVANCE" verdict in CAPS. Advisory dims do NOT block advance; they ride into the decision audit and the adjudicator's context.
--gate intent → verdicts {approve, revise}
- ADVANCE (
APPROVE) iffcompleteness ≥ 4ANDsafety_flag_coverage ≥ 4. - Advisory:
clarity,scope_feasibility. - EXTRA veto: if the
intent_spec.payload.confidence < 0.6, OR any unresolved high-impact uncertainty remains, downgradeapprove → reviseeven when both floor dims pass (low-confidence / unresolved intent must not lock silently). This is the EXACT predicatecomic-intent-parsermust quote — no0.5/0.6drift between the parser's stated gate and the gate that actually runs. - Note: the user-approval gate for intent is a separate HARD human gate owned by
comic-intent-parserstep ⑥ — this gate is the cross-model adjudication, not the human sign-off.
--gate outline → verdicts {approve, revise} — two checkpoints: OUTLINE_DRAFT_VALID, then OUTLINE_FINAL_LOCK
The outline acquittal is deliberately split in two. A single-stage "outline needs locked assets" contract
deadlocks a fresh project: assets are produced from the storyboard's consolidated_asset_requests, the
storyboard needs an approved outline, so the outline can never see a locked asset first. The Phase-1 DAG is:
OUTLINE_DRAFT_VALID → human outline approval → provisional storyboard (structural pass, may
reference draft assets) → consolidated_asset_requests → asset generation + review → assets LOCKED →
OUTLINE_FINAL_LOCK (cheap re-check) → storyboard FINAL asset-resolution validation → blueprints
- OUTLINE_DRAFT_VALID (this gate, pre-assets): validates NARRATIVE + CONTINUITY + safety only — it does
NOT require any referenced asset to be locked.
- Pre-check (HARD): every referenced
asset_id(scene / character / prop / must_show in the*_asset_idslists) must be DECLARED with a complete, generatable request (enough spec for the asset pipeline to produce it), else hard-fail with the missing-declaration list. Declared-but-draft is fine; undeclared or unrequestable is not. - ADVANCE (
APPROVE) iffcoverage ≥ 4ANDsafety_ip ≥ 4. - Advisory:
asset_promptability,audio_plan.
- Pre-check (HARD): every referenced
- OUTLINE_FINAL_LOCK (after assets lock): the cheap re-check that the now-locked assets still match the
approved outline — this is where
identity_lock_feasibility ≥ 4andscene_lock_feasibility ≥ 4are scored (they are meaningless before real locked refs exist). The hard locked-asset barrier lives at the storyboard FINAL asset-resolution validation + theblueprintgate, before blueprint authoring — not at the draft outline.
--gate asset → verdicts {approve, regenerate, locked, abandon_shot}
- LOCK (
LOCKED) iffidentity_lock_satisfied ≥ 4ANDref_quality ≥ 4ANDbg_isolation ≥ 4ANDsafety_ip ≥ 4— and the准 ×3rule holds (cross-model unanimity in the SAME round: CC AND Gemini AND Codex all lock-pass that round; fewer than 3 families approving →regenerate --another-voter= re-vote to reach the third family, not re-bake; a family's hard-fail → re-bake). See Constants. - Advisory:
reuse_readiness. - Cross-check (RAW):
output_refexists on disk AND itssha256matches the node AND thedata_urlis non-empty — any mismatch hard-vetoes lock. - Cap:
MAX_ASSET_REGEN = 4→ escalate to the outline gate (abandon_shot).
--gate storyboard → verdicts {approve, revise} — STRUCTURAL, CC-only (no visual reviewer; no pixels yet)
This is the comic.json structural validator (it supersedes the lone check_asset_collisions.py) — and
it is a TWO-STAGE contract: the gate runs TWICE per storyboard (the N1 DAG under --gate outline;
comic-storyboard-creator ⑨.0 quotes this same ordering):
- PROVISIONAL stage (right after authoring, pre asset-lock): structural pass only — declared-but-draft
assets are allowed;
panel_assets_referenceableis unscorable, leftnull, and the fuser SKIPs it (the verdict rides on the other three dims; only an UNDECLARED ref — no whitelist entry, no completeasset_request— vetoes). A provisionalapprovedoes NOT lock the storyboard node — no ⑥ FLIP; it staysunder_review. - FINAL stage (after the asset layer locks everything + OUTLINE_FINAL_LOCK): all four dims scorable — the
full asset-resolution predicate applies (every panel asset ref resolves AND is
locked; an un-locked ref hard-vetoes via_unresolved_asset_refs), andapproveflips the storyboard tolockedon advance.
The four structural dims are FILE-SYSTEM FACTS the gate computes, not reviewer opinion:
panel_assets_referenceable— every asset ref in each panel resolves and islocked. (Scored at the FINAL stage only — the storyboard's FINAL asset-resolution validation, the hard locked-asset barrier of the Phase-1 DAG; at the PROVISIONAL stage it isnull/SKIPped and the declared-check applies instead.)global_policies_valid—global_policiesfields match expected (e.g. text-mode rules present; mirror-lock policy present; page-order authority declared).panel_count_band_aligned— panels-per-page in band per target tier{mvp:(2,2), demo:(4,6), longform:(10,12)}(in-range = 5, off-by-one = 3, further = ≤2), AND theTOTALSline reconciles (Σ panels-per-page == panel count; NEW + reused == total).continuity_chain_well_formed— the MOTIF STATE TABLE has one row per panel; links have no dangling / out-of-order / cycle; every per-panelmotifsfield agrees with its table row.- ADVANCE (
APPROVE) iff ALL FOUR ≥ 4 — at the PROVISIONAL stage, all scorable dims (panel_assets_referenceableis SKIPped, never substituted with 0). - STRUCTURAL HARD VETO: any non-empty
_unresolved_asset_refs(FINAL stage; at the PROVISIONAL stage declared-but-unlocked refs are expected — only an UNDECLARED ref vetoes) /_policy_violations/_continuity_breaks, or an out-of-band_panel_count_band, forcesreviseregardless of reviewer scores OR Codex. (Plus the comic-specific structural vetoes the storyboard step also asks for: DDL non-monotonic; bounce-uniqueness broken; the two metric columns co-mingling; a DONE panel retro-edited; the storyboard page order disagreeing with the compiledcomic.jsonpage order — the storyboard is the authority.)
--gate blueprint (the IMAGE analog of aris_movie's frame_condition gate) → verdicts {approve, revise, fallback}
aris_movie's frame_condition gate is VIDEO-flavored (action_freeze, harmonization); the IMAGE analog
drops the motion dims and asks instead: "is this panel's condition.content_svg + identity_ref + scene
buildable?"
- ADVANCE (
APPROVE) iffrefs_present ≥ 4ANDspatial_correctness ≥ 4ANDblueprint_renders ≥ 4(the SVG rasterizes to a non-empty PNG — a RAW pre-check, not a vote). text_preservationrequired only when the panel has whitelisted baked text.safezone_quality(html panels) < 3 while the floor otherwise passes →fallback= route the panel's text to the HTML overlay (a route switch, not a regen).- Cap:
MAX_BLUEPRINT_REGEN = 3→ escalate to rewrite the panel_spec.
--gate continuity → verdicts {approve, revise}
Adjudicates the comic-continuity-audit read against the
motif_ledger. Dims (all ≥ 4 to ADVANCE):
ledger_row_complete— one MOTIF-table row per panel; no missing variable.invariants_hold— the declarative predicates verify against the table:ddl_monotonic_non_increasing,bounce_single_max(S02 = the film's ONLY MAX; no post-fall peak),metric_columns_disjoint(noclaim_deltavalue in theexact_parsecolumn or vice-versa).mirror_locks_paired— each paired constraint (REJECT ↔ ACCEPT same stamp geometry; S02-MAX ↔ S21-smallest; S16b labeled star-map ↔ S22 wordless twin from the same node JSON,禁目测) is present and consistent.design_aware— MOTIF-vs-ENV disambiguation is honored: only continuity-bearing instances are tracked; an intended absence / a taggedenvprop is not flagged as drift (absence ≠ drift).- Structural HARD VETO: any invariant violation forces
revise(invariants are machine-checkable predicates, not vibes).
--gate compile → verdicts {approve, revise} — DETERMINISTIC (no reviewer fan-out; the scripts ARE the judge)
The compiled-comic.json acquittal that comic-json-compiler defers to.
Unlike every other gate this one is purely deterministic — NO review:* nodes, NO Codex adjudication, so
§① (collect) is skipped and the "hard-fail if zero reviews" rule does NOT apply. It PASSES (approve) iff
both real scripts exit 0, else revise carrying their stderr as the blocker list:
python3 skills/comic-director/scripts/run_comic.py --project <dir> --page <P> --panels <ids> --dry-run— validates the comic.json shape, that everytext_mode:"baked"figure-panel carries asciicondition.expected_literals, and prints each concrete bake prompt (no placeholders).--panelsis required byrun_comic.py(argparserequired=True), so run this once per page inpages[]with that page's panel ids — omitting--panelsexits non-zero (a false blocker).python3 cli/validate_wiki.py <dir>— node/edge/payload/privacy/node_id conformance againstnode_schema.json. There is noreconcile_pages.py(it never existed) — these on-disk scripts are the entire deterministic core. PASS (approve) iff EVERY per-pagerun_comic.pyANDvalidate_wiki.pyexit 0. Record all exit codes + any stderr in the decision audit. The §⑥ FLIP target is the schema-validdecision:compile_<slug>wiki node this gate writes (status: final) — NOTcomic.json, which is a file, not a wiki node (it has no legal node_id prefix, carries nowiki_node_id, and can never be an edge endpoint).
--gate p0_proof → verdict {advance} — MINTED, never hand-written
The one gate whose decision node comes from a script: scripts/run_p0_proof.py
mints verdict: advance after verifying the two-family same-digest quorum itself (full contract in the
dedicated section below). Its target_node_id is the compile/intent anchor NODE (e.g.
decision:compile_<slug>) — never comic.json, which is a file, not a wiki node.
The bake-time
panel_gate(spiral_engine.jspanelVerdict: KEEP iffnarr ≥ 4 AND minIdent ≥ 4 AND styleOK AND compOK AND NOT artifactBad AND textOK AND NOT anatomyDefect AND disagree < 2, wherenarr = min(narrative_beat_fidelity, composition_story),artifactBadis corroborated — both visual reviewers must flag it, a lone pixel-purist cannot single-veto — anddisagreeis the two visual reviewers' identity-score gap) and the pageassembly_gateare NOT re-implemented here — they run at bake time insidepackages/core/spiral_engine.js. (Provenance note: the engine's narrative "cc" reviewer slot currently shells the codex CLI and is honestly recorded asopenaiin the wiki; a configurable--narrative-revieweris planned, not yet implemented — cross-family acquittal vs the Claude author still holds via gemini + codex.) This skill is the authoring-side gate; the engine is the artifact-side gate. They share the same fuse discipline.
--gate p0_proof — the zero-credit code proof + the digest-bound spending certificate
Runs AFTER comic-json-compiler, BEFORE any metered image
generation. It is a text-only cross-model adversarial review of the pipeline machinery the executor
authored solo — distinct from experiment-integrity (audits results after the fact) and from the per-unit
panel gate (audits generated artifacts). It is a pre-production correctness proof that is deliberately
free (text review, not image generation → not rate-limited). The fan-out shape is ported from
examples/comic_m3_audit/workflows/p0-review.js; the
certificate is minted by the shipped deterministic scripts/run_p0_proof.py — the
agent never hand-writes the decision node.
Step 1 — compute the digest, fan out. comic_sha = sha256(<project>/comic.json BYTES). Fan out 3
watchdog-bounded CLI reviewers, each cat'ing the REAL files into its prompt (never a Claude summary), each
a DIFFERENT model family from the Claude author — and inject the comic_sha digest into every reviewer
prompt with the instruction to echo it back in the review output; the echo is what binds each review to the
exact compiled version it read:
codexon CODE — the build script + the viewer: base64 inlining,</escaping in the JSON-in-<script>blob, missing-image handling, path resolution, the locale (T()) toggle, bubble positioning, XSS viainnerHTMLofT(),?p=bounds.codexon ENGINE LOGIC —spiral_engine.js: thepanelVerdictformula (deadlock / wrong-keep / skip-missing-dim / disagree gate), the retry/rollback/caps state machine (infinite-loop risk, rollback target math,kept[]filtering,localByPanelreset),generatePanel's bake seam + thegen_failed/rate-limit path, the gate prompts eliciting parseable JSON, theREPO + "/" + REPOpath hack,Promise.allraces.geminion DESIGN / CONTRACT / UX — isART_BIBLE.mdan executable convergence target for the panel_gate? Does thecomic.jsonIR scale to 24 panels + bilingual + 3text_modes? The viewer reading experience? Drift from the design doc? (This google-family review may come from the legacygeminiCLI OR from Antigravity via the shipped shim,cli/gemini_agy_shim.py— the shim pins a Gemini model, so the family recorded staysgoogleeither way.)
Gate schema FIND (required [reviewer, blockers, should_fix, overall]): blockers[] and should_fix[]
are arrays of {file, issue, fix} — all three required per item (a blocker with no concrete fix is not a
blocker, it is a complaint); plus nice[] and a one-line overall. Synthesis dedups, drops invalid/duplicate
points (noting the drop), orders BLOCKER > SHOULD > NICE, adds blocker_count / should_count, and
returns the single-most-important fix.
Step 2 — write one review JSON per family. From the CLEARED fan-out (every blocker fixed and re-reviewed)
the agent writes ≥2 review files, one per non-author family — e.g. p0_codex.json for openai,
p0_gemini.json for google — each carrying {family, verdict, blockers, comic_sha} (extra fields are
tolerated; these four are what the minter checks). A review COUNTS toward quorum only if family ∈ {openai, google, anthropic}, blockers == [] (the literal empty list), verdict ∈ {pass, clean, approve, advance}, AND its comic_sha equals the digest of the CURRENT comic.json. Parseable alone is NOT
quorum — a review that acquitted a different comic.json version, a non-empty blocker list, a missing file
(reviewer timeout/skip) or unparseable JSON simply does not count. NEVER proceed on timeout: for this
gate a timed-out family means quorum unmet, which means NO certificate, which means baking stays BLOCKED
— fail-closed. ("Note the timeout and proceed" is legal ONLY for ADVISORY fan-outs, e.g. the pivot-design
consult — never for the spending gate.)
Step 3 — MINT the certificate (deterministic, fail-closed).
python3 skills/comic-cross-layer-gate/scripts/run_p0_proof.py \
--project <dir> --target <anchor_node_id> --reviews p0_codex.json p0_gemini.json
The minter re-verifies everything itself (it never trusts the agent's account of the fan-out): it recomputes
comic_sha from the comic.json BYTES, computes bake_plan_sha = pickup_image.bake_plan_digest(run_comic.get_bake_plan()) (the resolved bakereq/v1 spend plan —
model/effort/include_image_gen_tool/sandbox/min_bytes/aspect/bake_timeout), discards every review that does
not count (stderr notes why), and requires BOTH non-author families {openai, google} among the counted
reviews — the Claude author family can drive, never acquit. Any violation → clear stderr reason + exit 1 +
no node. On success it atomically writes wiki/nodes/decision_p0_proof_<slug>_<utcstamp>.json:
node_id decision:p0_proof_<slug>_<utcstamp> (slug from comic.json comic_id), node_type: decision,
status: final, real-UTC created_at, payload {gate_kind: p0_proof, verdict: advance, target_node_id, comic_sha, bake_plan_sha, reviewer_quorum, review_files}.
The legal p0_proof verdict is advance — minted by the script, never hand-written. What
run_comic.py's _p0_clean() preflight then verifies before spending a credit: a decision:p0_proof_* node
with gate_kind == p0_proof and an accepted status/verdict, AND payload.comic_sha == sha256 of the
CURRENT comic.json AND payload.bake_plan_sha == the digest of get_bake_plan(args). Edit comic.json
after minting and the cert is stale → REJECTED (the log points back at run_p0_proof.py); the mint binds
the argparse-DEFAULT plan, so a run with non-default --min-bytes/--bake-timeout also needs a fresh cert.
This kills the "a certificate once existed somewhere in this directory" hole: the cert acquits ONLY the exact
bytes + spend plan it audited.
(Operational hardening kept from the source: MCP is forbidden inside this fan-out — an unbounded hang
would freeze it — so every external call is a watchdog-bounded CLI: codex sleep 540-600s, gemini sleep 300-360s, kill -9 on timeout, unique temp file per branch. A killed reviewer simply produces no counted
review file — see step 2: no quorum, no cert, no spending.)
Two engine contracts the gate enforces (fail-closed)
These mirror the engine's own fail-closed checks — cfgUsable (~L422) and generatePanel's content_svg
shell-safety guard (~L273) in packages/core/spiral_engine.js — the
gate refuses to ADVANCE a spec that would later make the engine refuse to run:
- Every panel needs a blueprint SVG — but the field name differs by artifact (do NOT conflate them):
the wiki
blueprint.payload.content_svg(top-level on the payload), thepanel_spec.payload.content_blueprint(the panel_spec's own field — there is NOcontent_svgon a panel_spec), and thecomic.jsonpanel'scondition.content_svg(the RUNTIME field the engine reads atspiral_engine.js.condition.content_svg). Any of thesenull/ empty / not a project-relative*.svgis a structural hard-veto at theblueprintandstoryboardgates (the engine rejectscondition.content_svg: nullin comic.json outright). Do not let a planned panel through with no blueprint. - A baked figure-panel MUST declare
expected_literals(exact numbers / keys, verbatim, ASCII- tokenizable). The engine'scfgUsablerefuses to run an ungated baked figure (a bakedcontent_svgwith an emptyexpected_literalsis a fail-closed refusal). So thestoryboard/blueprintgate hard-vetoes atext_mode: "baked"figure-panel that carries noexpected_literals; a scene panel with no audited numbers must betext_mode: "html"(its text moves to the overlay). This is the plausible-unsupported- success guard — a beautiful panel with a WRONG number must never keep, so the gate must be able to token-diff it later, which requires the literals authored now.
Node it reads / writes (schemas/node_schema.json)
Reads:
- The
target_node_id— one ofintent_spec/outline_spec/asset/storyboard_spec/blueprint/ (forcontinuity)motif_ledger/ (forp0_proof) the compiledcomic.json+ pipeline files. Read its required payload (per the schema) — and a ≤200-word verbatim slice is the only source text the adjudicator sees. - Every
reviewnode attached via areviewsedge → the target. Required payloadtarget_node_id, reviewer, gate_kind; the per-dim scores live in the optionalreview_scoresmap this skill fuses. (Edgereviewsmay carry the optionalreviewer ∈ {cc, codex, gemini}+weight.) - The wiki banlist of prior
failure_modenodes (so the adjudicator's context includes what already failed at this layer).
Writes (one JSON file each under wiki/nodes/, created_at ISO-8601):
decision(node_iddecision:<gate>_<slug>) — payload requiredtarget_node_id, verdict, gate_kind; this skill additionally writes the audit fields_threshold_verdict, _codex_verdict, _disagreement, _confidence, _cited_dimensions, _score_fingerprint(+ the structural sets_unresolved_asset_refs / _policy_violations / _count_band / _continuity_breakswhen computed).status: "final". Append adecidesedge (decision → target, optionalverdicton the edge).- EXCEPTION —
p0_proofdecisions are never hand-written:scripts/run_p0_proof.pymintsdecision:p0_proof_<slug>_<utcstamp>(verdictadvance,status: final, payload addscomic_sha, bake_plan_sha, reviewer_quorum, review_files) atomically, fail-closed, after verifying the two-family same-digest quorum itself. Every OTHER gate's decision node is written by the agent per this section. failure_mode(node_idfail:<gate>_<slug>) — only on a FAIL verdict. Payload requiredlayer, affected_shot_ids, active;repair_patternis the positive invariant; default scope movie-local.status: "active". Append afailure_ofedge (failure_mode → target).- No
failure_modeon an advance verdict, and none when Codex was unavailable (provisional verdict).
Worked example (the pattern to copy)
The canonical exhibits are the three historical orchestration scripts + the engine that ground this skill:
-
The P0 proof —
examples/comic_m3_audit/workflows/p0-review.js. Copy theFINDschema (required: ['reviewer','blockers','should_fix','overall'], each blocker/ should_fix item{file, issue, fix}— all three required), the 3-reviewer fan-out (codexReview('code', [BUILDER, TEMPLATE], …)‖codexReview('engine', [ENGINE], …)‖ the inlinegeminidesign reviewer), thecat-the-real-file rule (files.map(f => 'echo "===== ${f} ====="; cat "${f}"')— never a summary), and the synthesis reducer that dedups → orders BLOCKER>SHOULD>NICE → returnsblocker_count/should_count. Its watchdog hardening (codex … & P=$!; ( sleep 540; kill -9 $P ) & WD=$!; wait $P; kill $WD) is exactly the MCP-forbidden discipline — but note where the LIVE contract diverges from the exhibit: p0-review.js noted a timeout and proceeded; the shipped minter makes a timed-out family not count toward quorum, so the spending gate stays blocked. The contract isblockers.length == 0in both non-author families on the samecomic_sha, then therun_p0_proof.pymint, before any credit. -
The cross-model adjudication shape —
examples/comic_m3_audit/workflows/pivot-design.js. Copy the typed gate schemas that force the gate to be real:DESIGN_SCHEMA(required: ['recommendation','codex_take','gemini_take','open_decisions']— a branch cannot claim a cross-model review it did not do, thecodex_take/gemini_takefields are the evidence), andCRITIQUE_SCHEMA(required: ['model','biggest_flaws','missing','risks','verdict'], prompt forbids softening: "pass through the sharpest valid points"). The "form your OWN take FIRST → get codex → get gemini → reconcile/judge → surface only genuine human forks" loop is the adjudicator discipline; the unique temp file per branch + note-a-timeout-and-proceed is the operational guard — legal here because this consult is ADVISORY; the p0_proof spending gate must fail-closed on timeout instead. -
The deterministic fuse —
packages/core/spiral_engine.js:59(panelVerdict). This is the exact min-fuse / skip-missing / max-for-inverted / single-vote-veto pattern to port into §②:idents = [gem?..., cdx?...].filter(x => x != null); minIdent = idents.length ? Math.min(...idents) : 0(skip-missing, never 0-substitute when some reviewer scored it);artifactBad = (gemArt >= 4 && cdxArt >= 3) || …(inverted dim, corroborated — a lone pixel-purist can't single-veto a by-design background glow);anatomyDefect = … === true(a single-vote veto for a clear defect the literal-diff is blind to); and the fail-closed guardif (![gem,cdx].every(r => visCore(r).every(x => x != null))) return retry(a reviewer that returned incomplete core scores must not slip an advance). The authoring gate inherits this verbatim so reviewer-independence + min-fuse + positive-invariant failure_modes come for free.
Hard do / don't (earned lessons)
- DO treat this gate as a score-fuser, never a reviewer — collect the
review:*nodes the upstream step already wrote; hard-fail if there are none. Re-running a reviewer here would make the gate part of the thing it judges. - DO feed the adjudicator scores + tags + raw PATHS + ≤200-word verbatim source + verbatim rubric and
NOTHING ELSE. Forwarding any reviewer prose/notes/overall is a CRITICAL independence violation
(
reviewer-independence). - DO
SKIPa dim no reviewer scored — NEVER substitute 0. (The v1.0 bug: a lite reviewer's blank dim must neither slip an advance nor force a fail.) - DO keep the trust asymmetric: the deterministic threshold (and the structural facts) hard-veto advance; Codex soft-vetoes everything else. Codex can never overrule a failed floor into an advance.
- DO run
--gate p0_prooftoblockers.length == 0in BOTH non-author families AND mint the cert viascripts/run_p0_proof.pyBEFORE the first metered bake. It is free, andrun_comic.pyfail-closes without the digest-bound node. Skipping it to "save a step" trades zero-cost text review for credit-cost regeneration. - DON'T regenerate the artifact when scores are identical across rounds — that means the judge is
broken, not the spec. HALT and flag
judge_suspect; audit this rubric (memory:feedback_gate_identical_scores_judge_broken). A gate that scores the same regardless of the work is broken. - DON'T let an authoring step acquit itself — the gate (a different model family) acquits; the loop can
DRIVE but it cannot ACQUIT (
acceptance-gate). - DON'T flag an intended design variation as drift — the warm/dark two-world split, a disjoint cast on a
2-up, a tagged
envprop, a deliberate absence are design, not drift. The gate is design-aware. - DON'T emit a verdict outside a gate's legal set (the
intentgate cannot saykeep; only theassetgate can saylocked/abandon_shot) — it is a hard error. - DON'T mint a
failure_modeon an advance, or when Codex was unavailable (the provisional verdict is_confidence: low, exit 2 — fix and re-gate, don't poison the banlist). - DON'T call MCP inside the
p0_prooffan-out — watchdog-bounded CLI only. And DON'T treat a p0 timeout as skippable: a timed-out family does not count toward quorum → no certificate → baking stays blocked (fail-closed). Note-a-timeout-and-proceed is for ADVISORY fan-outs only.
Protocols (governance contracts this skill honors)
reviewer-independence— the adjudicator sees scores + tags + raw PATHS + a ≤200-word verbatim source slice + the verbatim rubric only; never reviewer prose/notes/ overall. The p0_proof reviewers eachcatthe real files, never a Claude summary. The=== EXTERNAL CONTEXT (advisory) ===fence keeps cross-cutting context from becoming a conclusion.acceptance-gate— this skill IS the acquittal: a generating step can DRIVE toward a locked spec but cannot ACQUIT it; a different model family (Codex adjudicator) + the deterministic threshold do. Identical-scores-across-rounds → the judge is suspect, not the artifact.review-tracing— every collected reviewer + the adjudicator call + the p0_proof fan-out is traced (prompt + response +threadId+ verdict) so each acquittal is auditable and the independence claim is checkable after the fact.reviewer-routing— the Codex CLI atxhighwith no model pin (it follows the local codex config, currentlygpt-5.6-sol) for the adjudicator and every correctness/logic reviewer; Geminiauto-gemini-3for the visual/design family; the metered bake alone pinsgpt-5.5+xhighinrun_comic.get_bake_plan()(single compat default; config-driven override is planned). Never downgrade the effort tier (effort widens fan-out, never weakens the judge).artifact-integrity— structural facts (asset-resolve / policy / count-band / continuity / sha-match / blueprint-renders) are RAW artifacts the gate computes and hard-vetoes on; they are verified, never originated, and forwarding them to Codex is not an independence breach.fan-out-pattern— the p0_proof 3-reviewer fan-out and the per-gate multi-reviewer collection are Tier-1/Tier-2 fan-outs that converge on this one cross-model adjudication bench.injection-hygiene— all node ids / paths flowing into the watchdog CLI prompts are whitelisted ([A-Za-z0-9_-]ids, absolute metachar-free paths) before interpolation, exactly as the engine validates them.
What ships with it: 1 file
9.4 KB alongside SKILL.md, 1 of them executable
scripts/
- run_p0_proof.pyruns9.4 KB