AgentStack
SKILL verified MIT Self-run

Comic Blind Comparison Review

skill-wanshuiyin-aris-movie-director-comic-blind-comparison-review · by wanshuiyin

Phase-1 comic-author step (post-final eval) — a DOUBLE-BLIND A/B of two FINAL whole comics: our cross-model-audited progressive render (the comic-author + comic-director output) vs a naive single-shot baseline. A single sealed coin-flip hides which is which; two cross-model reviewers (Codex + Gemini) score both on a fixed rubric reading only a SHARED blind spec (intent + ART_BIBLE); only AFTER bo…

No reviews yet
0 installs
10 views
0.0% view→install

Install

$ agentstack add skill-wanshuiyin-aris-movie-director-comic-blind-comparison-review

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Comic Blind Comparison Review? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

comic-blind-comparison-review — Double-Blind A/B of Two Finished Comics (Phase 1, step S12, post-final)

The "vs baseline" capability the comic side otherwise lacks. The per-panel [comic-director](../comic-director/SKILL.md) panel_gate and the cross-panel assembly_gate operate during production on single units; this skill operates after production, on two complete works — our cross-model-audited progressive comic (authored by the [comic-author](../comic-author/SKILL.md) suite, baked by [comic-director](../comic-director/SKILL.md)) vs a naive single-prompt one-shot baseline — and proves the spiral pipeline beats the one-shot, under a blind so neither reviewer can favor the home team. It is a direct, faithful port of aris_movie's blind-comparison-review from video to a whole-comic A/B (outputs/aris_movie_progressive.mp4 vs outputs/baseline_sd2_naive.mp4 → two rendered comic page sets), and it is an evaluation skill, not an authoring one: it never edits a comic, it judges two finished ones.

> Cardinal lesson baked in as a gate, not prose: the order of operations IS the integrity guarantee. > A single coin-flip seals .ab_mapping.json and chmod 600s it before any reviewer is invoked; the > seal's mtime MUST precede both reviews; from seal-time until UNSEAL the orchestrator (Claude) may not read > or quote the mapping; any home-team token in a reviewer prompt is a HARD-ABORT, not a warning. If the > orchestrator reads the mapping before both reviews land, it may subconsciously phrase the synthesis to favor > the home team — so the timestamp ordering is the audit trail, and "blinding integrity" is REPORTED, never > assumed.

  progressive comic  ┐                                            ┌─▶ comparison.md (Chinese deliverable)
  (our audited)      ├─▶ ⓪ SEAL .ab_mapping.json (1 coin-flip,    │
  baseline comic     ┘       chmod 600, mtime BEFORE any reviewer) │
  (naive one-shot)   │            ▼                                │
                     │      ① STAGE pages → A/ and B/ (sealed ids) │
                     │            ▼                                │
                     │      ② CODEX blind review (xhigh, RO)  ─────┤  (no home-team token; reads SHARED
                     │            ▼                                │   blind spec = intent + ART_BIBLE only)
                     │      ③ GEMINI blind review (per-page + ─────┤
                     │            synthesis, auto-gemini-3)        │
                     │            ▼                                │
                     └─▶  ④ UNSEAL (verify seal_ts /dev/null 2>&1 \
      || { echo "HALT: screenshot of page $i failed"; exit 2; }
  done
  echo "$2: rasterized $3 pages from the viewer"
}
# e.g.  rasterize_viewer "$PROG_PATH" "$PROG" "$NPAGES"   (NPAGES = len(comic.json pages[]))

If neither pre-rendered PNGs nor a headless renderer is available → HALT with that message; never feed the reviewers a partial or wrong-DPI rasterize (a corrupted page set makes the A/B score garbage).

Stage dispatch — the actual control flow (picks the form per artifact; never calls stage() blindly).

stage_any() {  # $1=artifact (a DIR of pre-rendered *_pNN.png / a comic.json / a single-file .html viewer)   $2=sealed letter
  case "$1" in
    *.html)  # the SINGLE-FILE viewer (the common ship form, NO sibling comic.json): rasterize whole-page PNGs.
             # derive NPAGES from the viewer's EMBEDDED JSON island (the build inlines comic.json into a ).
      NP=$(python3 - "$1" ]*>\s*(\{.*?\})\s*', html, re.S):   # the inlined comic-IR island
    try:
        d = json.loads(blob)
        if isinstance(d.get("pages"), list): n = len(d["pages"]); break
    except Exception:
        pass
print(n)
PY
)
      [ -n "$NP" ] || { echo "HALT: cannot read page count from the viewer's embedded JSON island in $1"; exit 2; } ;
      rasterize_viewer "$1" "$2" "$NP" ;;
    *)
      if [ -d "$1" ] && ls "$1"/*_p[0-9]*.png >/dev/null 2>&1; then   # a DIR of pre-rendered whole-page PNGs
        mkdir -p "outputs/comparison-pages/$2"; i=0
        for f in $(ls "$1"/*_p[0-9]*.png | sort); do i=$((i+1)); cp "$f" "outputs/comparison-pages/$2/$2_p$(printf '%02d' "$i").png"; done
        echo "$2: staged $i pre-rendered page PNGs"
      else
        stage "$1" "$2"   # a comic.json file or a project dir — stage() normalizes + requires page-level renders
      fi ;;
  esac
}
stage_any "$PROG_PATH" "$PROG"   # route by the SEALED letter; no read of the seal file → blind holds until ④
stage_any "$BASE_PATH" "$BASE"

Page-count parity gate (fail-closed). After staging both sides, assert A and B staged the same number of pages — an unequal A/B is not a fair head-to-head:

nA=$(ls outputs/comparison-pages/A/*.png 2>/dev/null | wc -l | tr -d ' ')
nB=$(ls outputs/comparison-pages/B/*.png 2>/dev/null | wc -l | tr -d ' ')
[ "$nA" -gt 0 ] && [ "$nA" = "$nB" ] || { echo "HALT: page-count parity failed (A=$nA B=$nB) — not a fair A/B"; exit 2; }

Page filenames embed only the sealed letter + a page index (A_p03.png) so reviewers cite by page, never by home-team identity.

② CODEX blind review (read-only, xhigh)

A fresh mcp__codex__codex call (NOT codex-reply), config {"model_reasoning_effort":"xhigh"}, sandbox: "read-only". It sees the two page dirs (comparison-pages/A, comparison-pages/B) + the SHARED blind spec (the identity-stripped intent + ART_BIBLE.md). Scrub the prompt with the banned-token scan (Constants) BEFORE submission. The prompt asks Codex to read the pages itself and score each comic 0–5 on every A/B rubric dimension, cite page filenames as evidence, and output JSON only. Save verbatim to outputs/blind_review_codex_raw.json. Required JSON shape:

{"comic_A": {"": {"score": 0-5, "evidence": "...cites A_p0X.png..."}, ...},
 "comic_B": {"": {"score": 0-5, "evidence": "...cites B_p0X.png..."}, ...},
 "overall_winner": "comic_A|comic_B|tie", "confidence": 0.0-1.0, "rationale": "..."}

If Codex returns non-JSON → retry once, stricter; still non-JSON → write a {"parse_failed": true} stub and continue Gemini-only, noting the degradation in comparison.md.

③ GEMINI blind review (independent, same blind rules)

3.1 per-pagemcp__gemini__analyzeFile, model auto-gemini-3, one call per image (every page in A/ and B/), each page NOT seeing the other comic. Per-page JSON {label, page_filename, character_appearance ≤150, scene_signature ≤80, style_features ≤80, artifact_severity_0_to_5 (int, 0=clean 5=catastrophic), notable_anomalies[]}; persist to outputs/gemini_perpage.json. 3.2 synthesismcp__gemini-cli__ask-gemini (text-only), fed both per-page observation lists + the blind spec summaries (≤1000 chars each), scoring the same 0–5 A/B rubric, JSON only. Save verbatim to outputs/blind_review_gemini_raw.json. Gemini is always auto-gemini-3. Fail fast if fewer than the staged pages succeed per comic (the video floor was ) or an outlinespec node (nodeid outline:) for the progressive comic, the caller passes that node_id as TARGETNODEID and the A/B nodes point there (this is the cleanest "the whole comic" anchor; it must be a real node in wiki/nodes/`).

  1. Else, the progressive comic's FIRST panel anchor — a panel: that exists as a

comic.json panels[*].wiki_node_id (e.g. the worked example has panel:s01_aris_comic_v1). This is the pragmatic fallback the slim schema supports today: it resolves via the comic.json panel-anchor union, so the edges validate. Record in the decision payload that the anchor is the first-panel proxy (the A/B is about the whole comic; the panel is just the schema-valid attachment point). Whichever you choose, the chosen id MUST already be a resolvable endpoint — verify with python3 cli/validate_wiki.py BEFORE declaring done; if it doesn't resolve, the skill HALTs rather than write a dangling edge.

EXACT gate (A/B rubric) — dimensions, scoring, the wedge, vetoes

Ported from the aris_movie blind-comparison-review rubric, adapted from video to comic (the video skill's narration_sync dimension is dropped and folded into overlay_readability = caption/bubble↔panel reading-order alignment, which the assembly_gate already scores). Each reviewer scores each comic 0–5 on all six dimensions — there is no numeric pass threshold; the verdict is the comparative overall_winner

  • confidence, and the consensus across the two families.
  • story_comprehension — can the reader follow the through-line end to end (the comic's logline lands)

from the pages alone? (video: scene_jumps coherent vs abrupt unexplained jumps.)

  • visual_consistency — character identity (face/clothes/age) + palette/render stable across pages vs

drifting. Design-aware: the two-world warm/dark split is by-design, not drift (ARTBIBLE §0.5); a reviewer must only flag miscolored worlds, never the split itself. (video: characterconsistency + style_drift.)

  • overlay_readability — bubbles/captions legible, correctly ordered, aligned to the right panel; no

garble; bilingual text fits. (replaces the video narration_sync dimension.)

  • editability_traceabilityTHE STRUCTURAL WEDGE. Could a human editor patch a bad page *without a

full re-gen, and is each failure localizable*? 5 = a single panel + its local prompt is the minimum patch unit and every panel traces to its panel_attempt/review/decision/failure_mode wiki nodes; 0 = the whole comic is one indivisible bake with no trace, so any defect forces a total re-gen. This is where the pipeline's contribution shows even when the baseline's one-shot output is visually strong — it is an architectural FACT (wiki-backed traceability), not a pixel measurement, so it can WIN the A/B even while the baseline ties or beats on polish. (video: editability_proxy.)

  • reproducibility — can the artifact be re-derived? (re-run the comic.json + content-SVG blueprints +

the audited spiral → the same comic) vs a one-shot whose exact output is unrecoverable. (video: deterministic re-render of cached frames.)

  • polish — raw aesthetic finish / artifact floor (the dimension the naive one-shot can plausibly win).

(video: artifactfloor / artifactseverity.)

Veto / hard-abort rules (the load-bearing rigor — abort beats taint):

  1. MAPPING_FILE referenced in ANY reviewer prompt → HARD-ABORT `"Blinding compromised — fix prompt

template and re-run"`. Better to abort than ship a tainted A/B.

  1. Any home-team token (progressive/baseline/ARIS/SD2/naive/one-shot/spiral/our system/

system under test, or a rhetorical "show that A is better") in a reviewer prompt → the prompt is REJECTED before submission by the banned-token scan.

  1. Reviewer raw files predate MAPPING_FILEblinding_integrity = "compromised", flag prominently in

comparison.md, never silently elide.

  1. Codex non-JSON → retry once stricter; else {"parse_failed": true} stub + continue Gemini-only, noted

in the md.

  1. Fewer than the staged pages return from a reviewer → re-run the missing page once, then fail fast.

Invariants (REPORTED, not assumed): seal written before any reviewer AND seal_ts **Schema note (read this — it is the orphan-panel-class discipline).** The aris_movie source describes a > single rich comparison node with baselinefor / comparedagainst edges. The SLIM comic > nodeschema.json (v3.0) has **no comparison node_type and no baselinefor/comparedagainst edge > types**; the canonical edge form is **{src, dst, type}** (NEVER from/to/edgetype) with type ∈ > {attemptof, reviews, decides, failureof, rollback_of, supersedes}. So this post-final A/B is recorded > with the schema's existing verdict vocabulary: **two review nodes** (one per reviewer) **+ one decision > node** (the consensus). The rich aris_movie comparison payload (per-dim scores, blinding audit) is carried > as the decision node's payload — the schema is additionalProperties: true`, so extra fields validate.

Reads — two finished comics (the progressive comic.json / rendered pages + the baseline rendered pages) and the SHARED blind spec (the intent_spec's logline/narrative_beats + ART_BIBLE.md). It does not mutate any upstream authoring node.

Writes (status complete for the reviews, final for the decision — the runtime canon). The exact PAYLOAD_REQUIRED from cli/validate_wiki.py is review["target_node_id","reviewer","gate_kind"] and decision["target_node_id","verdict","gate_kind"]; node_id must match the schema pattern ^(…|review|decision|…):[a-z0-9_-]+$ (lowercase + _/- only — cmp_… is fine, `` is digits):

  • review × 2 (node_id review:cmp__) — payload required (all three): target_node_id

(the resolved anchor from ⑥ — the caller's intent_spec/outline_spec id, or the first-panel proxy panel:; NEVER an id that doesn't resolve), reviewer (codex | gemini), gate_kind ("blind_comparison"). Recommended optional fields (validate under additionalProperties): raw_path (the verbatim blind_review_*_raw.json, project-RELATIVE — see the path rule below), winner (progressive|baseline|tie, after unseal), confidence, per_dim_scores (the unblinded 0–5 per-dimension scores for both artifacts). The raw reviews live in files; the node only summarizes (no separate "review-node per dimension").

  • decision × 1 (node_id decision:cmp_progressive_vs_baseline_) — payload required (all

three): target_node_id (the SAME resolved anchor), verdict (the consensus "progressive"|"baseline"|"tie"|"disagree"), gate_kind ("blind_comparison"). Recommended optional: progressive_path, baseline_path, comparison_md_path (all project-RELATIVE, see below), codex_winner, gemini_winner, anchor_kind ("author" | "first_panel_proxy" — record which ⑥ option was used), blinding_audit{sealed_at, first_review_started, last_review_completed, integrity, leakage_reason}. This is the single authoritative A/B record (the aris_movie comparison node's role).

> Path fields MUST be project-relative (release-gate rule). cli/validate_wiki.py runs abs_path_leaks() > over EVERY wiki/nodes/*.json payload and hard-fails (sys.exit 1) on any string containing /Users/ or > /home/. The only in-skill source of these paths is the seal, which stored them via os.path.abspath(...) > — so before writing the nodes you MUST relativize: progressive_path, baseline_path, comparison_md_path, > and any raw_path = os.path.relpath(p, PROJECT_DIR) (or just the outputs/… tail). Add a one-line guard > mirroring the validator before writing each node — fail fast rather than emit an invalid node: > ``python > import json > for s in (json.dumps(review_payload), json.dumps(decision_payload)): > assert "/Users/" not in s and "/home/" not in s, "HALT: payload has an absolute path; relativize before writing" > ` > (The outputs/.ab_mapping.json seal itself keeps os.path.abspath and is fine — the validator never scans it, > only wiki/nodes/`.)

Edges (canonical {src, dst, type} only; typevalidate_wiki.py EDGE_TYPES). The dst is the resolved target_node_id from ⑥ (the caller's intent_spec/outline_spec id, or the first-panel proxy panel: — an id that already resolves; **never the literal string `**): review:cmpcodex… --reviews--> and review:cmpgemini… --reviews--> (each with the optional reviewer + verdict edge fields); decision:cmp… --decides--> (with the optional verdict field). reviews/decides are both legal EDGETYPES` and exactly the verbs the example wi

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.