# Comic Outline Creator

> Phase-1 Layer-2 of a comic — turn a LOCKED skeleton (intent_spec + the pre-locked beat/shot list) into an approved outline_spec: a 6-column beat table that binds every ARIS capability to a STORY COST, plus the continuity-motif contract the storyboard layer will be held to. NOT free creation — editorial adaptation of a pre-locked skeleton via 3 parallel lenses → cross-model (Codex) synthesis → a density/restructure pass → a USER-approval HARD GATE. Cross-model synthesis is part of authoring here, not post-review. Author the comic.json downstream with comic-storyboard-creator + comic-blueprint-author; this skill only produces the outline + motif contract.

- Skill: `wanshuiyin/comic-outline-creator` (Agent Skill)
- Install (CLI): `npx skillmds@latest add wanshuiyin/comic-outline-creator`
- Raw SKILL.md: https://api.skillmd.com/api/skills/wanshuiyin/comic-outline-creator/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: wanshuiyin (https://skillmd.com/u/wanshuiyin)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/wanshuiyin/comic-outline-creator

---


# comic-outline-creator — the Outline + Motif Contract (Phase 1, Layer 2)

The **middle-left of Figure 1**: take a locked `intent_spec` (+ the pre-locked beat/shot skeleton it
carries — OR, for an **idea-first comic with NO pre-locked skeleton**, the 3 lenses first **synthesize** a beat
skeleton from the intent's `logline` / `subjects` / `constraints` / `format`, then adapt it the same way; the
synthesized skeleton is recorded so the deltas-vs-skeleton discipline still applies) and produce a single
**approved `outline_spec`** — the 6-column beat table that drives the
storyboard, and the continuity-motif arcs that become the storyboard's checkable contract. This is the
comic twin of aris_movie's `movie-outline-creator` (a Layer-2 authoring-time **plan gate** before any
pixels), specialized for our image-comic route: the deliverable is a *plan*, never a frame.

Two things are simultaneously true, and the whole skill is built around them:
**(a)** the outline is NOT a free brainstorm — it is an **editorial adaptation of a pre-locked skeleton**
(N beats / M shots, beat boundaries fixed), so every candidate must self-report its **deltas vs the
skeleton**; **(b)** an unbounded "ARIS capability showcase" silently rots into a **product manual** unless
every capability is bound to a concrete **story cost** and skill-name tags are banned from the 画面. The
3-lens → Codex-synthesis → density-pass → user-approval loop turns (a) into a faithful, debated outline and
the 侧栏讲解铁律 + the gate catch (b) every round.

```text
  intent_spec (logline + tagline + dual-identity + LOCKED skeleton)
        │
        ▼  ① FAN-OUT: 3 parallel named lenses over the SAME skeleton (faithful ∥ comicnative ∥ clarity)
        │     each ends with a self-authored "through-line + deltas vs the skeleton" section
        ▼
  ② SYNTHESIZE — Codex (different model family) reconciles the 3 → OUTLINE v2
        ▼
  ③ DENSITY/DESIGN pass — Codex MAY restructure panel count (e.g. centerpiece 4→5 pages, +mid-act page)
        │     AUTHORS the 侧栏讲解铁律 (anti "product manual" guard)
        ▼
  ④ Emit the 6-column BEAT TABLE + the centerpiece sub-plan + the 5 motif arcs (exact per-shot values)
        ▼
  ⑤ READINESS gate (PRE-user, cross-model, blind to orchestrator prose) — scores ONLY the author-controllable
        │   dims; EXCLUDES user_decision_record + the unresolved-questions veto (those are not yet satisfiable).
        │   Two-step (never cold): write review:* nodes + `reviews` edges → THEN comic-cross-layer-gate <id> --gate outline
        ▼ readiness:advance
  ⑥ USER APPROVAL = HARD GATE — present; record ✅ APPROVED + fill 已定决策 + EMPTY 待确认 block
        │   THEN the FINAL gate (now user_decision_record==5 IS satisfiable) → write outline_spec node (locked)
        │ revise ─▶ ② (bounded: MAX_OUTLINE_REVISIONS=3 → auto-abandon → failure_mode node)
        ▼ approve + signed
  outline_spec (locked) → SOURCE OF TRUTH for the storyboard layer
        │
        ▼  (much later, orchestrator-owned) OUTLINE_FINAL_LOCK — after the asset layer locks, a cheap
           re-check that the locked assets still match this approved outline (N1 two-stage; §EXACT gate)
```

## Constants
- **LENS_COUNT** = **3, mandatory** (`faithful`, `comicnative`, `clarity`) — Tier-1 Workflow fan-out
  ([`fan-out-pattern`](../../protocols/fan-out-pattern.md)). Fewer than 3 lenses is a hard veto.
- **SYNTHESIZER** = `mcp__codex__codex`, `model_reasoning_effort: xhigh` — a **different model family** from
  the Claude lens authors. Codex both *reconciles* the 3 candidates AND runs the density/restructure pass;
  the outline layer is itself a cross-model artifact (executor ≠ reviewer, [`reviewer-independence`](../../protocols/reviewer-independence.md)).
- **GATE REVIEWERS** = `mcp__codex__codex` (NO model pin — follows the local codex config, currently
  `gpt-5.6-sol` — at `xhigh`) ‖ Gemini (`auto-gemini-3`, readability dims) — each
  sees ONLY `outline_spec.json` + `intent_spec.json` (the skeleton) + the lens files, never Claude's prose. They
  do **not** acquit; they each persist a `review:<slug>` node (payload `{target_node_id, reviewer, gate_kind:
  "outline", review_scores:{...}}`) with a `reviews` edge `review:<slug> → <outline_id>`, and the SOLE acquittal
  organ [`comic-cross-layer-gate`](../comic-cross-layer-gate/SKILL.md) `--gate outline` then **fuses** those
  score-nodes (D4: never invoke the gate cold — write the reviews FIRST, then call the gate).
- **THE GATE IS RUN TWICE BY THIS SKILL** (the user-approval deadlock fix): a **READINESS** pass BEFORE user
  approval (scores only the author-controllable dims; the gate's own `user_decision_record == 5` floor and the
  unresolved-questions veto are **not yet satisfiable**, so the readiness reviewers explicitly omit them), then
  the **FINAL** pass AFTER the user signs + the `待确认` block is emptied (now `user_decision_record == 5` IS
  satisfiable). See §EXACT gate. A THIRD, later touch — **OUTLINE_FINAL_LOCK** — is owned by the orchestrator,
  not this skill: after the asset layer locks (provisional storyboard → asset gen/review), a cheap re-check
  that the locked assets still match the approved outline (§EXACT gate → the N1 two-stage contract).
- **MAX_OUTLINE_REVISIONS** = 3, then auto-abandon → write a `failure_mode` node so a re-run must diverge. Its
  payload is **exactly** what `validate_wiki.py` PAYLOAD_REQUIRED demands for `failure_mode`: `{"layer":
  "outline", "affected_shot_ids": [<the abandoned skeleton shots, e.g. all S01..SMM>], "active": true}`
  (node_id `fail:<slug>`, node_type `failure_mode`, status `active`). There is **NO `encoding_style` field** in
  the schema — carry the "a re-run must diverge" positive-invariant in `title` or a non-required note, never a
  fabricated required-looking key; the node must pass `cli/validate_wiki.py`.
- **MAX_DRAFT_ATTEMPTS** = 3 — schema-repair loop for the `outline_spec` node; on each fail, `codex-reply`
  quoting the validator errors **verbatim**. Never silently coerce a value to pass schema (change the
  narrative + document it, or surface to the user).
- **TARGET_PAGE_CEILING** (soft cap, exceed ⇒ Codex must justify in `rationale.beat_count_justification`,
  not a hard stop): `mvp=2`, `demo=6`, `longform=12` beats per tier (ported from `MAX_BEATS_PER_TIER`).
- **MIN_CAST_PER_BEAT** = every beat names **≥1 world/scene + the cast in it** (text-panel beats: a
  text-panel scene + its world). Ported from aris_movie's `MIN_ASSETS_PER_BEAT=2`; a structural check
  JSON-Schema can't express.
- **NODE** = `outline_spec` (this skill **reads** `intent_spec`, **writes** one `outline_spec`). See §Node.
- **APPROVAL IS NON-AUTOMATABLE** — the loop can DRIVE to a clean gate, but **only the user ACQUITS** the
  outline ([`acceptance-gate`](../../protocols/acceptance-gate.md)). Nothing proceeds to the storyboard
  layer until the user signs off, recorded inline.

## Input contract — what this skill reads, what it must not invent
The contract boundary is the **`intent_spec` node** ([§Node](#node)) — produced upstream by
`comic-intent-parser`, carrying: the **logline** (a single sentence whose climax may be an editorial
inversion — e.g. *"the climax is NOT winning — it's that ARIS didn't let itself off the hook"*); the
**tagline**; the **`dual_identity`** constraint (*"an emotional story of honest research + an ARIS capability
showcase"*) the whole debate optimizes against; and the **`source_skeleton`** — the pre-locked beat list
(`B01…BNN`), shot list (`S01…SMM`), and beat boundaries. **The skeleton is LOCKED; this skill ADAPTS it,
never re-derives it.**

This skill is **plan + verify**: it **never bakes a pixel** (image gen is `comic-director` / Phase 2-3) and
**never invents a beat boundary or a shot**. Adding a *page* (a density-pass split) is allowed and must be
accounted for in the deltas; **moving a beat boundary or dropping a shot is a delta that must be justified +
surfaced to the user**. If `intent.status != locked` → **REFUSE** (the upstream hand-off token is `locked` =
approved + frozen; an `under_review`/`draft` intent is not ready — re-run `comic-intent-parser` to its user
gate). If the skeleton is missing → **REFUSE and ESCALATE** (do not fabricate one).

## Procedure (an agent can execute this step by step)

### 0. Load + refuse-guard
Snapshot the `intent_spec` node. Pull cumulative wiki context: prior LOCKED assets (for reuse-over-invention),
and `failure_mode` nodes with `layer="outline"` (rejected/superseded outlines — a re-run must diverge from
them). Refuse if `intent.status != locked` (the upstream author-node hand-off token is `locked`, not `active`).
Checkpoint an `OUTLINE_STATE.json` (resumable —
[`resumable-runs`](../../protocols/resumable-runs.md)).

### 1. FAN-OUT — write 3 parallel candidate LENSES over the SAME locked skeleton
This is **Tier-1 Workflow fan-out** ([`fan-out-pattern`](../../protocols/fan-out-pattern.md)): three
independent passes, each a *named lens* over the identical skeleton, NOT three free drafts. Write each to its
own file (`story/outline_candidate_{faithful,comicnative,clarity}.md`). The three lenses are fixed:

- **`faithful`** — one-to-one fidelity: **M shots → M panels, no cut / merge / add**, beat boundaries
  `B01…BNN` preserved exactly. The conservative anchor (palette grammar + stamp mirrors live here).
- **`comicnative`** — comic-as-a-medium: **collapse runtime / motion shots into static-friendly pages**
  (in our run `S07-S09 → one 2×2 page`; `22 shots → 12 panels`); choose a `full-bleed / 2-up / 2×2`
  page-rhythm for scroll-reading.
- **`clarity`** — legibility for a **non-ML reader**: foreground the through-line so the headline number-arc
  (in our run `+6.2 → +1.4`) is readable via **one concrete physical prop** (the `Tok|yo` broken-JSON
  evidence) + **one wordless emotional gauge** (executor bounce height).

**Each candidate MUST end with a self-authored section: `## through-line + deltas vs the skeleton`** stating
exactly what it **merged / added / kept** and **why** (e.g. *"merged S07-S09 → one 2×2 page (motion is
redundant in a static page); kept all 13 beats; moved Tok|yo's first plant earlier to B06-S09 as a
re-pointable物证"*). A candidate with **no deltas section is a hard veto** — delta-accounting is the
discipline that proves it is an adaptation, not a guess.

### 2. SYNTHESIZE — Codex reconciles the 3 → OUTLINE v2
Call the **SYNTHESIZER** (different model family). Feed it the three lens files + the `intent_spec` +
`schemas/node_schema.json`'s `outline_spec` shape, inside a demarcated `=== EXTERNAL CONTEXT (advisory) ===`
fence; Claude's prose lives ONLY in that fence ([`reviewer-independence`](../../protocols/reviewer-independence.md)).
The synthesis takes the **best of each lens** — in our run: `faithful`'s two-world WARM/DARK palette grammar
+ the REJECT↔ACCEPT mirror, `comicnative`'s page-rhythm, `clarity`'s motif arcs + countdown spine. Emit
`{outline, rationale}`.

### 3. DENSITY / DESIGN pass — Codex MAY restructure panel count
Codex then does a **density / design pass** that may materially change panel count where the read demands it
(in our run: the centerpiece B08 went **4 panels → 5 single-read pages** by adding an "audit entry" panel,
with the 2×2 kept only as recap/hero/GitHub-screenshot; and a **new mid-act page** `B09.5` "research
star-map / wiki" was added *after the audit, before the paper* — flagged as *"the most powerful position"*;
panel count moved `22 → ~24`). This pass also **AUTHORS the 侧栏讲解铁律** (step 6). Adding pages is fine;
account for every one in the deltas.

### 4. Emit the 6-column BEAT TABLE
Emit the canonical table — **fixed columns, in this order**:

| Beat (zh/en) | Panels | 布局/layout | 世界/world | 内容 + 台词 gist | ARIS 特性（绑剧情）|

- **Beat** — bilingual id + name (`**B01 卧室·倒计时**`).
- **Panels** — the shot ids it OWNS (`S01` · `S07,S08,S09大` · `S12-15 + 新增 S12a`).
- **布局/layout** token ∈ {`full-bleed`, `split`, `2-up`, `1-panel`, `竖排3`, `5单张页(默认)/2×2 recap`}.
- **世界/world** token ∈ {`暖/WARM`, `暗/DARK`, `seam`, `暗·星空/starfield`} — human beats warm, ARIS beats
  dark-cyber, **explicit seam panels** at hand-off / payoff. (The warm/cold split is **by-design** — the
  downstream gate must never flag it as drift.)
- **内容 + 台词 gist** — panel action + baked-dialogue gist + a one-line side-narration (旁白).
- **ARIS 特性（绑剧情）** — the bound capability, **phrased as a STORY COST, never a feature name**
  (✅ `experiment-bridge（证据是暂定的）` · `honest re-run（自纠 overclaim）` · `auto-review-loop（对抗审）`;
  ❌ `experiment-audit`, `novelty-check` as bare tags). A bare feature name here is a hard veto.

### 5. Centerpiece sub-plan (the densest beat)
For the centerpiece beat, emit a sub-table `| 页/page | 画面/image | 侧栏（先讲发生了什么，再点能力）|` with the
verbatim **70/30 composition rule**:
> 每页：技术主画面 70% + 角色情绪 30%（右下角蓝 exec bounce 当体温计）+ 侧栏讲解。

Each row's 侧栏 puts the **event-sentence first**, then `· *trait: <skill>*` second (so the side-narration
reads as story, then footnotes the capability).

### 6. Embed VERBATIM the 侧栏讲解铁律 (the anti "product-manual" guard)
This block is **load-bearing** — copy it verbatim into the outline (it is what stops a capability showcase
from rotting into a product manual):
> 🎙️ 侧栏讲解铁律（防止"能力展示"变产品手册 —— codex）
> - 每条能力必须绑一个剧情代价：不写"ARIS has experiment-audit"，写"executor 的庆祝被审计打断，所以 ARIS 没撒谎"。
> - 侧栏第一句永远讲发生了什么；第二句才点能力名。
> - 每个能力都改变角色状态（bounce 高低 / 咖啡冷掉 / 红队介入 / claim 被降级）。
> - 画面里不堆 skill 名标签；skill 名只作侧栏小字或 hover/click metadata。

### 7. Lock the continuity-motif arcs AT OUTLINE TIME (exact per-shot values)
The outline **doubles as the continuity contract** — the storyboard's motif-state table and the
panel/assembly gates will be checked against these arcs, so they must carry **exact per-shot values now**.
Lock the 5 arcs (our run's values, as the worked pattern):
- **mug heat**: `STEAMING(S01) → fading(S03) → COLD(S20)` — B01/B12 bookend.
- **executor bounce** (wordless emotion thermometer): `MAX(S02) → HIGH(S09) → DROP(S11) → ZERO/SILENT(S12–S15,
  arc low point) → tempered-return(S16) → smallest-warm(S21)`. (Storyboard will add the uniqueness
  invariant *"S02 是全片唯一 MAX"*; no post-fall peak.)
- **Tok|yo broken-JSON evidence**: `born/first-plant(B06-S09) → smoking-gun(B08) → clean footnote(S17) →
  faint constellation star(S22)`.
- **DDL countdown spine**: `24:00:00 → ~19:00 → 00:42` — strictly **monotonically non-increasing** across
  the whole film (storyboard enforces; never rewinds).
- **REJECT(S11) ↔ ACCEPT(S16)**: deliberate **mirror stamps** so the centerpiece audit reads as the hinge
  between them.

### 8. Write the 6-column table + sub-plan + 铁律 + motif arcs to `story/OUTLINE_DRAFT.md`
Add a top-of-file `Logline + Tagline + 双重身份` block (mirroring the intent), an empty `## ✅ 已定决策` block,
and an `## ⚠️ 待你确认` block listing every open design question (e.g. *centerpiece 5-page split OK? new
mid-act wiki page OK? 侧栏铁律 OK?*).

### 9. READINESS gate — PRE-user, cross-model, blind (NOT the final gate)
This is the **author-controllable** gate, run **before** the user has decided anything. By construction the
artifact from step 8 has an **empty `已定决策`** + a **non-empty `⚠️ 待确认`** block and **no user sign-off** —
so the FINAL gate's `user_decision_record == 5` floor and its "open questions unresolved but advancing" veto
are **not yet satisfiable**. Applying the full conjunctive APPROVE rule here would deadlock a fresh agent
(stall, or fabricate a user approval). So the readiness pass scores **only** the dims the author controls and
**explicitly EXCLUDES** `user_decision_record` + the unresolved-questions veto (see §EXACT gate → READINESS).

Run it as a **two-step gate invocation (D4 — never call the gate cold)**:
1. **Fan out the GATE REVIEWERS** (Codex at `xhigh`, no model pin ‖ Gemini `auto-gemini-3`) on the files only
   (`outline_spec.json` + `intent_spec.json` + the lens files, inside the advisory fence — no orchestrator
   prose). **Persist EACH as a `review` node:** `node_id review:<slug>` (e.g. `review:outline_codex_r1`),
   node_type `review`, payload **required** `{target_node_id: <outline_id>, reviewer: "codex"|"gemini",
   gate_kind: "outline", review_scores:{skeleton_fidelity:…, delta_accounting:…, coverage:…,
   page_rhythm_readability:…, story_cost_binding:…, motif_contract_completeness:…, safety_ip:…}}` — and write a
   `reviews` edge `{src: review:<slug>, dst: <outline_id>, type: "reviews"}` (the gate walks `reviews` edges in;
   `reviewed_by` is the wrong direction and the fuser won't find it).
2. **THEN** invoke `comic-cross-layer-gate <outline_id> --gate outline` to fuse the score-nodes + adjudicate.
   (This is the OUTLINE_DRAFT_VALID stage: on a fresh outline `identity_lock_feasibility` /
   `scene_lock_feasibility` are unscorable — no assets exist — so the reviewers leave them `null` and the gate
   SKIPs them, never 0-substitutes; the effective draft floor is `coverage ≥ 4 AND safety_ip ≥ 4`. The
   readiness reviewers likewise leave `user_decision_record` unscored. What IS checked here: every referenced
   `asset_id` is DECLARED with a complete, generatable request — `locked` is NOT required until
   OUTLINE_FINAL_LOCK, after the asset layer.) On a FAIL verdict, fold the blockers and loop back to step 2
   (bounded by `MAX_OUTLINE_REVISIONS`); on a clean readiness verdict, proceed to step 10.

**Then schema-validate the (still-`under_review`) `outline_spec` node** payload (`cli/validate_wiki.py` mirrors
`node_schema.json`); on a schema error, run the `MAX_DRAFT_ATTEMPTS` repair loop with `codex-reply` quoting the
errors verbatim. **Also run the 2 structural checks JSON-Schema can't express:** (i) **coverage** — every
`intent.dual_identity` "must-land" item and every skeleton beat maps to ≥1 table row; (ii) **MIN_CAST_PER_BEAT**
— every beat names ≥1 world + its cast. Do **not** flip to `locked` yet — that needs the user sign-off (step 10).

### 10. USER APPROVAL = HARD GATE → FINAL gate → then lock
Present the readiness-clean outline to the user. **Nothing proceeds until they sign off.** On approval:
- record inline `✅ APPROVED by user <date>` (with their words, e.g. `("都可以")`),
- fill the `## ✅ 已定决策（用户 <date>）` block — **every resolved open question becomes a recorded decision
  node** (our run: `B06-S09 → big panel`; `Tok|yo pre-plant → very small, narration does NOT spell it out`;
  `B13 constellation → pure glowing star-points, NO labels`),
- empty the `## ⚠️ 待你确认` block (every open question is now in `已定决策`).

Now — and **only** now — run the **FINAL gate** (D4 two-step again): re-fan the GATE REVIEWERS on the
now-complete artifact, persist fresh `review:<slug>` nodes (this round CAN score `user_decision_record`,
since the sign-off + `已定决策` block + emptied `待确认` block exist) with `reviews` edges, then call
`comic-cross-layer-gate <outline_id> --gate outline`. The FINAL gate applies the full conjunctive APPROVE rule
(§EXACT gate → FINAL) including `user_decision_record == 5`, now satisfiable. On the gate's `approve`:
- the gate itself **mints the `decision` node** (`node_id decision:outline_<slug>`, payload **required**
  `{target_node_id: <outline_id>, verdict: "approve", gate_kind: "outline"}`) + the `decides` edge and **flips
  the `outline_spec` node `status: locked`** — that FLIP is the gate's job, not this skill's. (Never write
  `status: locked` by hand without the gate's `approve` verdict node **and** the inline user sign-off.)
- declare the file **"SOURCE OF TRUTH for the storyboard layer."**

Then hand off to `comic-storyboard-creator` for its PROVISIONAL structural pass (it inherits the locked beats
+ the motif arcs as its continuity ledger). Asset generation/review, OUTLINE_FINAL_LOCK, and the storyboard's
FINAL asset-resolution validation follow — [`comic-author`](../comic-author/SKILL.md) steps 4–6b.

## EXACT gate — this skill's PRE-gate rubric, fused by `comic-cross-layer-gate --gate outline`
**Authority note (D3) — the N1 TWO-STAGE contract:** the canonical APPROVE predicate + the status FLIP for the
`outline` gate are owned by [`comic-cross-layer-gate`](../comic-cross-layer-gate/SKILL.md) `--gate outline`,
and under the N1 DAG that gate runs in **two stages**:
- **OUTLINE_DRAFT_VALID** (this skill's readiness + final passes) — validates **narrative + continuity +
  safety only**. It does **NOT** require any referenced asset to be `locked` (on a fresh project assets don't
  exist yet); it requires every referenced `asset_id` to be **DECLARED with a complete, generatable request**.
  Because no locked assets exist, the gate-floor dims `identity_lock_feasibility` / `scene_lock_feasibility`
  are **unscorable at draft time**: the reviewers leave them `null`, the fuser SKIPs them (never
  0-substitutes), and **the effective draft floor reduces to `coverage ≥ 4 AND safety_ip ≥ 4`** — this is the
  explicit resolution of the dim-vocabulary gap (the reviewers here never score those two dims; nobody does
  until assets exist).
- **OUTLINE_FINAL_LOCK** (orchestrator-owned — [`comic-author`](../comic-author/SKILL.md) step 6a, AFTER the
  asset layer locks) — a cheap re-check that the now-locked assets still match the approved outline;
  `identity_lock_feasibility` / `scene_lock_feasibility` ARE scored here, against real locked assets. The hard
  locked-asset barrier itself stays downstream, before blueprint authoring (comic-author steps 6b–7).
This replaces the deadlocked single-stage contract (an outline gate demanding locked assets that depend on a
storyboard that depends on a locked outline). The dims + verdict rules below are **THIS skill's pre-gate
routing** (step 9 step-1 fan-out): the rubric the GATE REVIEWERS score into their `review:<slug>` nodes, and
the local stop-rule this skill uses to loop/abandon **before** deferring to the fuser. They are not a
competing gate — the cross-layer-gate fuses these score-nodes and makes the final call.

Each GATE REVIEWER scores these dims **0–5** seeing ONLY `outline_spec.json` + `intent_spec.json` (the
skeleton) + the lens files — **no orchestrator prose**:

- **`skeleton_fidelity`** — beats / shots / beat boundaries from the locked skeleton are preserved or every
  change is an accounted delta (no silent re-derivation).
- **`delta_accounting`** — every candidate has a `deltas vs the skeleton` section; the synthesized outline's
  added/merged pages are all listed and justified.
- **`coverage`** — every `intent.dual_identity` must-land item + every skeleton beat maps to ≥1 table row
  with the right cast in `must_show` (the comic analog of aris_movie's `coverage` dim).
- **`page_rhythm_readability`** — layout tokens give a real scroll-read rhythm; the centerpiece is single-read
  paced; non-ML reader can follow the headline arc (readability — Gemini co-scores).
- **`story_cost_binding`** — **every** `ARIS 特性` cell is phrased as a story cost that changes a character
  state, **never** a bare feature name.
- **`motif_contract_completeness`** — all motif arcs are locked with **exact per-shot values** (not "a
  recurring mug"); REJECT↔ACCEPT mirror + monotonic DDL declared.
- **`safety_ip`** — no celebrity likeness / copyrighted character / trademarked logo / off-policy content;
  anti-IP `must_avoid` carried into the style bible (HIGHER = better).
- **`user_decision_record`** — the `✅ APPROVED` stamp + `已定决策` block (resolved questions as decision
  nodes) + an EMPTY `⚠️ 待确认` block are all present and consistent. **Scored in the FINAL round ONLY** — at
  step 9 it is not yet satisfiable, so the READINESS reviewers leave it `null` (the fuser SKIPs a `null` dim,
  it does **not** 0-substitute).

### READINESS verdict rule (step 9 — PRE-user; EXCLUDES the user dim + the unresolved-questions veto)
The author-controllable stop-rule the readiness fan-out routes on (this is what makes step 9 actually passable
before the user has decided anything):
```
skeleton_fidelity >= 4 AND delta_accounting >= 4 AND coverage >= 4
AND story_cost_binding >= 4 AND motif_contract_completeness >= 4 AND safety_ip >= 4
```
`user_decision_record` is **NOT** evaluated here, and the **"open questions unresolved but advancing" veto does
NOT apply** at readiness (the `⚠️ 待确认` block is *expected* to be non-empty pre-user). Readiness-clean ⇒
present to the user (step 10).

### FINAL verdict rule (step 10 — POST-user; the full conjunctive rule, now satisfiable)
```
skeleton_fidelity >= 4 AND delta_accounting >= 4 AND coverage >= 4
AND story_cost_binding >= 4 AND motif_contract_completeness >= 4
AND safety_ip >= 4 AND user_decision_record == 5
```
**revise** ⇐ any blocking dim `< 4` but recoverable (loop to step 2, bounded by `MAX_OUTLINE_REVISIONS=3`).
**abandon** ⇐ `safety_ip < 3` **OR** three consecutive `revise` rounds with the **same root cause** →
auto-abandon → write a `failure_mode` node whose payload is **exactly** the validator-required shape `{"layer":
"outline", "affected_shot_ids": [<abandoned skeleton shots>], "active": true}` (node_id `fail:<slug>`, status
`active`; no `encoding_style` key — that is not a schema field).

**Hard veto (any one → not APPROVE, regardless of scores):**
- fewer than **3 lenses**;
- any candidate with **no `deltas vs the skeleton`** section;
- any `ARIS 特性` cell written as a **product-manual feature name** instead of a character cost;
- a **skill-name in a 画面 main label** (skill names allowed ONLY in side-narration small-text / hover
  metadata);
- **open questions unresolved but advancing** (FINAL round only — the `⚠️ 待确认` block must be emptied into
  `已定决策` before the user can lock; this veto is intentionally OFF at readiness, see above);
- **motif arcs not locked** at outline time (no exact per-shot values).

> The loop can DRIVE to a clean gate, but **the gate cannot ACQUIT — only the user can**
> ([`acceptance-gate`](../../protocols/acceptance-gate.md)). A clean cross-model readiness gate is necessary,
> the signed user approval is sufficient; both are required, and the FINAL gate is what mints the `approve`
> decision + flips `outline_spec` to `locked`.

## Node — reads `intent_spec`, writes `outline_spec`
Per [`../../schemas/node_schema.json`](../../schemas/node_schema.json) (`schema_version node/comic/3.0`).

**Reads** `intent_spec` (`node_id intent:<slug>`) — payload required (verbatim from `validate_wiki.py`
PAYLOAD_REQUIRED): `raw_input_refs, user_goal, audience, format, constraints, subjects, source_skeleton,
dual_identity, uncertainties, confidence`. **Refuse unless its `status == locked`** (the author-node hand-off
token is `locked` = approved + frozen, NOT `active`; `comic-intent-parser`'s user gate is what flips it).

**Writes one** `outline_spec` (`node_id outline:<slug>` — matches the schema node_id pattern). Payload
**required fields** — every one of these (verbatim from `validate_wiki.py` PAYLOAD_REQUIRED for `outline_spec`)
must be present: `source_intent_id, title, logline, tagline, design_constraint, target_page_count,
narrative_beats, beat_table, motif_arcs, character_asset_ids, scene_asset_ids, prop_asset_ids,
global_style_bible, budget`:
- `source_intent_id` — the `intent:<slug>` it adapts. Also write the provenance edge `{src: outline:<slug>,
  dst: intent:<slug>, type: "derived_from"}` (the author-layer "this node was authored/derived from that node"
  verb — `derived_from` is in `validate_wiki.py` EDGE_TYPES; `generated_from` is NOT and would FAIL the
  validator). **The edge record itself must pass `cli/validate_wiki.py`** (both endpoints resolve to real
  node_ids; the type is in EDGE_TYPES).
- `title`, `logline`, `tagline`, `design_constraint` — carried from intent (the dual-identity constraint).
- `target_page_count` — within `TARGET_PAGE_CEILING` for the tier, or justified in `rationale`.
- `narrative_beats` — the beat list with each beat's `must_show` (cast/world per beat — enforces
  `MIN_CAST_PER_BEAT`).
- `beat_table` — the 6-column table (the canonical render-source for the storyboard).
- `motif_arcs` — the 5 arcs with **exact per-shot values** (the continuity contract).
- `character_asset_ids`, `scene_asset_ids`, `prop_asset_ids` — flat lists of asset node_ids: **prior LOCKED
  assets** when one matches (reuse over invention), else **newly DECLARED ids** whose complete, generatable
  request the storyboard layer will consolidate (`locked` is NOT required at the draft gate — the N1 two-stage
  contract; OUTLINE_FINAL_LOCK re-checks once they lock). **Emit no new asset node here** — that is the asset
  layer's job, where `reuse_of` lives. (There is no `reuse_of` field on `outline_spec` — the asset references
  are these three flat id-lists; don't carry the movie source's `asset_plan[].reuse_of` here.)
- `global_style_bible` — pointer to the locked `ART_BIBLE.md` / `style_anchor` nodes (incl. the warm/dark
  two-world palette + the anti-IP `must_avoid`).
- `budget` — page/asset budget for the downstream layers.

Status lifecycle: `draft → under_review → locked` — `locked` flipped by the FINAL `comic-cross-layer-gate
--gate outline` `approve` (after the inline user sign-off), or `rejected` / `superseded`. (`active` is a RUNTIME
status, never this author node's hand-off token.)
**Fail-closed:** never write `status: locked` without the gate's `decision` node `verdict="approve"` **and** the
inline user sign-off; never silently coerce a value to pass schema.

## Two engine contracts the outline must SET UP (fail-closed, downstream)
The outline does not author blueprints, but it **must make them authorable** — so the centerpiece sub-plan
and any figure-bearing beat are spec'd so the downstream layers can satisfy these without re-litigating. (The
runtime field names below are the **`comic.json` panel** fields the engine reads — `condition.content_svg` /
`condition.expected_literals` — the *only* artifact that uses the `condition.` prefix; do not conflate with the
wiki nodes the downstream layers write, where the field is `blueprint.payload.content_svg` (top-level) and
`panel_spec.payload.content_blueprint` — there is **no** `content_svg` on a panel_spec.)
1. **Every panel will need a `condition.content_svg`** (a deterministic blueprint — figure or layout; the
   engine rejects `condition.content_svg: null`, never write it null). So every figure-bearing beat in the
   table must name **what the blueprint depicts** (the curve, the gauge, the broken-JSON chip), not just "a
   screen" — the storyboard / blueprint authors instantiate the SVG, but the outline owes them a concrete
   subject.
2. **A `text_mode:"baked"` figure-panel will need `condition.expected_literals`** (exact numbers/keys,
   ascii-tokenizable, verbatim) — or the bake is refused. So every beat whose number is the point (`+6.2`,
   `+1.4`, `0.60→0.71`, `REJECT`, `T-00:42`) must surface that **exact literal in the table's gist** as the
   to-be-gated token; a beat with no audited number → its panel becomes `text_mode: "html"` downstream. The
   motif arcs (DDL, exact_parse, claim_delta) are precisely the literal source the gate will token-diff later.

## Worked example
A converged, **user-approved** outline ships in
[`examples/comic_m3_audit/story/`](../../examples/comic_m3_audit/story/) — the ARIS-Movie comic *"我把那 24
小时交出去了 / I Handed Over Those 24 Hours"*. The exact files to copy the shape from:

- **The 3 lenses** —
  [`outline_candidate_faithful.md`](../../examples/comic_m3_audit/story/outline_candidate_faithful.md) (22
  shots → 22 panels, beat boundaries preserved, ends with *"Through-line + deltas: one-to-one fidelity, …"*),
  [`outline_candidate_comicnative.md`](../../examples/comic_m3_audit/story/outline_candidate_comicnative.md)
  (S07-S09 → one 2×2 page P06; 22 → 12 panels; full-bleed / 2-up / 2×2 rhythm), and
  [`outline_candidate_clarity.md`](../../examples/comic_m3_audit/story/outline_candidate_clarity.md) (Tok|yo
  prop + bounce gauge carry the +6.2→+1.4 story for a non-ML reader). **Copy the pattern:** three named
  lenses over the *same* skeleton, each closing with an explicit `deltas vs the skeleton` section.
- **The approved outline** —
  [`OUTLINE_DRAFT.md`](../../examples/comic_m3_audit/story/OUTLINE_DRAFT.md). Copy its **exact** shape:
  - header provenance line: *"OUTLINE v2 — 3-lens debate → codex synthesis → codex design pass (B08 density +
    wiki) → user decisions. … ✅ APPROVED by user 2026-06-10 ('都可以') … Now the SOURCE OF TRUTH for the
    storyboard layer."* — the whole lifecycle is recorded in one line;
  - the `## ✅ 已定决策（用户 2026-06-10）` block (3 resolved open questions as decision nodes: S09 big /
    Tok|yo tiny, narration doesn't spell it out / B13 unlabeled glowing star-points);
  - the verbatim `## 🎙️ 侧栏讲解铁律` block;
  - the 13-row **6-column beat table** (every `ARIS 特性` cell is a story cost, e.g.
    `experiment-bridge（证据是暂定的）`);
  - the **B08 5-page sub-plan** with the 70/30 rule + event-first / trait-second 侧栏;
  - the `## vs v1 的增量` deltas (`22 → ~24` panels, +S12a +S16b) and the `## ⚠️ 待你确认` block.

Copy its shape; swap in your own logline / skeleton / cast.

## Hard do / don't (earned lessons)
- **DO** treat the skeleton as **locked** and make every candidate self-report its `deltas vs the skeleton` —
  adapt, never re-derive; a candidate with no deltas section is a veto.
- **DO** write **3** lenses (faithful ∥ comicnative ∥ clarity) and let **Codex (a different model family)**
  synthesize + run the density pass — the outline layer is a cross-model artifact, not a solo draft.
- **DO** bind **every** capability to a **story cost** and **embed the 侧栏讲解铁律 verbatim** — this is the
  guard that stops a capability showcase from rotting into a product manual.
- **DO** lock the **motif arcs with exact per-shot values at outline time** — the outline is the storyboard's
  continuity contract; vague motifs make the downstream gate uncheckable.
- **DON'T** put a **skill name in a 画面 main label** — skill names live ONLY in side-narration small-text /
  hover metadata.
- **DON'T** advance to the storyboard with **open questions unresolved** — empty the `⚠️ 待确认` block into
  `已定决策` first; resolved questions are recorded decision nodes.
- **DON'T** **batch** ahead, and **never draft (or proceed) without explicit user story approval** — the user
  is the only acquitter; record `✅ APPROVED <date>` inline before locking. (Memory: *never draft
  outline/storyboard without explicit user story approval; confirm intent → outline → storyboard layer by
  layer.*)
- **DON'T** bake or invent — this skill produces a *plan*; pixels are `comic-director`'s job, and a missing
  beat/shot is an **ESCALATE**, not a fabrication.
- **DON'T** silently coerce a value to pass schema or to pass the gate — change the narrative + document it,
  or surface to the user.

## Protocols (governance contracts this skill honors)
- [`reviewer-independence`](../../protocols/reviewer-independence.md) — the Codex synthesizer + the gate
  reviewer get the lens files + `intent_spec` + schema inside an `=== EXTERNAL CONTEXT (advisory) ===` fence,
  never the author's interpretation; the Claude lens authors ≠ the Codex synthesizer/judge.
- [`acceptance-gate`](../../protocols/acceptance-gate.md) — the loop can DRIVE to a clean cross-model gate but
  cannot ACQUIT; **USER approval is the hard gate** for the outline (never proceed without it), recorded
  inline as `✅ APPROVED <date>` + the `已定决策` decision block.
- [`fan-out-pattern`](../../protocols/fan-out-pattern.md) — the 3 lenses are **Tier-1 Workflow fan-out**
  (faithful ∥ comicnative ∥ clarity), all reconciled at the single Codex synthesis seat; `<3` lenses is a
  veto.
- [`reviewer-routing`](../../protocols/reviewer-routing.md) — Codex at `xhigh` (synthesizer + gate; NO model
  pin — it follows the local codex config, currently `gpt-5.6-sol`); Gemini `auto-gemini-3` (optional
  readability co-reviewer); never downgrade the effort tier.
- [`review-tracing`](../../protocols/review-tracing.md) — every gate round's reviewer verdict + the user
  decision are logged as `review` / `decision` nodes so each verdict is auditable.
- [`output-versioning`](../../protocols/output-versioning.md) · [`resumable-runs`](../../protocols/resumable-runs.md)
  — version the outline (`_v{N}` + `supersedes`); `OUTLINE_STATE.json` makes the loop resumable.

