MeridiansMeridians

Budgeted fate exploration — scouting timelines worth producing

Source path: knowledge-base/specs/fate-exploration/README.md

# Budgeted fate exploration — scouting timelines worth producing

Status: **rough spec (direction).** Not an implementation contract; nothing here ships until scheduled.

This is the spec closest to the product's identity: Meridians is **the causal exploration of fate and
possibility**, and exploration is what makes that literal rather than a slogan. The branches a reader
chooses between are *found* — searched out of the world's own causal structure and priced — not authored
in advance. Everything downstream (the fork, the routes, the endings, the assets) is the residue of a
search that happened here. This is also why Meridians is a **causal simulator** and not a story
generator: the pathways a person rehearses were searched and priced from the world's causal structure, and
completing this scout into Meridians World Search (MWS) ([branch refinement](../branch-refinement/README.md)) is the first
priority among the specs ([specs map](../README.md#priorities-2026-09-21)).

One boundary governs everything below and is not negotiable at any budget: **exploration proposes; it
never commits.** Will is injected from outside the simulation — a reader at a fork, a seat at the card
table, a Director steering the run, or an agent through MCP — and the world computes the consequence. A
scout may cut a fan of futures, price each one, and stage what a branch would look like if taken; the act
of *taking* it belongs to someone outside the engine, and the record keeps who they were and from what
vantage they moved. An autonomous run that quietly selects on a participant's behalf has not explored
faster, it has erased the authorship that makes a branch a parallel world rather than a model's
continuation. Where a run must proceed unattended, the Director's `autoExecute` mandate is the injected
Will, and it is attributable to them.

This specification owns one thing: **how the instrument spends money to discover which futures are worth
reading, and how a discovered future earns production.** It is the supply side of the
[visual-novel delivery](../visual-novel/README.md), which owns the demand side (what a reader-paced
Episode is and what a commitment means). Neither spec introduces a second generator, pricer, or writer. The
[branch structures](../visual-novel/branching.md) spec owns the structural target that shapes promotion.
In roadmap terms, Fate Exploration is the **generative scout**: it maps causal terrain and production
demand; the [Factory](../visual-novel/production.md#12-factory--the-production-control-surface) makes the
reusable coverage for the few promoted routes.

Its integration order is deliberately split. Structural scouting, budget bounds, fatefulness, and
orthogonality can advance before the Experience reader. The production hand-off cannot: it waits for
Factory's rebuildable coverage projection, then emits demand rather than media. The sequenced gates are
owned by the [World roadmap](../world/README.md#roadmap--scout-make-read-wander-learn), grounded in the
[current VN experiment audit](../../sources/research/2026-09-02-2026-09-02-vn-experiment-audit.md).

Authority is unchanged:

```text
Domain defines. Branch preserves. Scenario resolves. Episode embodies. World inherits and lives.
```

Read first: [visual-novel delivery](../visual-novel/README.md) (§3 commitment contract, §7 preparation),
[visual-novel branching](../visual-novel/branching.md) (the Reading as the branch instrument),
[visual-novel production](../visual-novel/production.md) (the asset inventory, style lock, and production
costs),
[unit economics](../../knowledge/product/economics/UNIT_ECONOMICS.md) (the cost lanes and the ceilings),
[narrative convention](../../knowledge/conventions/NARRATIVE_CONVENTION.md) (scene classes, beat mechanisms),
[World concept contract](../world/README.md) (what happens to a mature branch).
The [branch refinement](../branch-refinement/README.md) spec extends this policy into an opt-out MCTS loop
over the existing branch tree.

The subsystems it reads: `src/types/domain/settings.ts` (`AutoConfig`, `AutoEndCondition`, `AutoRunState`),
`src/types/domain/futures.ts` (`Future` / `FutureRun` / `FuturesConfig` — the sister continuations and their
`priorLogit`), `src/types/domain/scene.ts` (`WorldExpansion` deltas), `src/lib/core/forces/thread-market.ts`
(stance movement, entropy, closure tests), `src/lib/core/kernel/api-logger.ts` (`calculateApiCost` — the only
pricer), `src/lib/engine/image/generate.ts` (the single Replicate seam), `src/lib/core/constants/scale.ts`
(`SCENES_PER_ARC`, the prose grain envelope).

> **The claim.** Exploration is cheap and production is expensive — by roughly a factor of forty per arc
> (§3). So the instrument should *look* far more than it *builds*: fan out many structurally divergent
> continuations at scout depth, score them with free deterministic derivations, and spend the illustrated,
> voiced, reader-paced budget only on the few timelines that move the world. Exploration is bounded by
> money, not by a scene count, because money is the thing that actually runs out.

---

## 1. Exploration is not auto mode

Auto mode advances **one** branch: `AutoConfig.endConditions` stop it at a scene count, an arc count,
planning-complete, all-threads-resolved, or a manual stop, and `AutoRunState` counts cycles as it goes. That
is a *depth* instrument — it makes one timeline longer.

Exploration is a *breadth* instrument: from one fork, several continuations are generated **so that they
diverge**, and the divergence is the product. The substrate already exists — `Future` carries the variables,
`considered` (the rejected option space), `breaks` (the falsifying condition), `opens` (what it primes) and a
`priorLogit`; a `FuturesRunState` batch runs sisters off one arc under bounded concurrency and commits one.
What is missing is the loop *around* that batch: a policy that decides where to fan next, a score that says
which results were worth having, and a budget that stops the whole thing.

| | Auto mode (shipped) | Exploration (this spec) |
|---|---|---|
| Shape | one branch, deeper | a fan of sisters off many forks |
| Unit of progress | a scene, an arc | a *scouted candidate* — a structural continuation with deltas and no prose |
| Bound | scene / arc count | **spend**, in dollars (§2) |
| Success | the story continued | the fan contains something fateful and orthogonal (§4) |
| Output | accepted branch material | ranked candidates, most of them never produced |

Both remain end conditions on the same run object: a spend bound belongs to auto mode too (a long
single-branch run is exactly as capable of eating a ceiling), which is why §2 adds it to `AutoEndCondition`
rather than inventing a parallel config.

---

## 2. The budget is the bound

Add one variant to the existing union in `src/types/domain/settings.ts`:

```ts
export type AutoEndCondition =
  | { type: "scene_count"; target: number }
  | { type: "arc_count"; target: number }
  | { type: "all_threads_resolved" }
  | { type: "planning_complete" }
  | { type: "manual_stop" }
  | { type: "spend"; budgetUsd: number };   // new
```

Rules, all of which follow the shipped spend model rather than extending it:

- **One pricer.** Spend accrued by a run is the sum of `calculateApiCost` over the api-log entries
  attributed to that run — the same function the Usage screen and the ceilings use. No estimator, no second
  ledger, no per-run price table.
- **The run needs an attribution key.** Today entries carry caller + model + domain; a run-scoped tag (an
  exploration-run id) is the one field this spec asks for, because "what did this fan cost" is otherwise
  unanswerable and the whole spec depends on answering it.
- **Checked before each cycle, not after.** A cycle is refused when `spent + estimatedCycleCost > budgetUsd`,
  where the estimate is the median measured cost of the last N cycles of that same stage (fall back to the
  §3 table for a cold start). Refusing *after* the overspend is how a $5 budget becomes $8.
- **A run budget is not a ceiling.** The instance and per-domain ceilings still apply and still win; the run
  budget is the Director saying "this exploration gets $5", not "this exploration may exceed my week".
  Autonomous exploration continues to fail closed.
- **Exhaustion is a completion, not a failure.** The run stops at `budget_exhausted`, keeps every scouted
  candidate and its score, and reports what the money bought: candidates scouted, forks touched, best score
  found, cost per candidate. A budget that ends the run with nothing promotable is a legitimate and
  reportable result.
- **The remaining budget is visible while it burns.** Same posture as the spend gauges: a run shows spent,
  remaining, and cost-per-candidate live. An exploration whose cost per candidate is climbing is a
  configuration problem the Director should see at cycle three, not in the bill.

---

## 3. What things actually cost

Unit costs at the shipped default allocation (`balanced-smart`: `generate` → `google/gemini-3.7-flash`,
`write` / `plan` / `intuition` → `google/gemini-2.5-flash`), priced with `MODEL_PRICING`,
`IMAGE_FLAT_RATE_USD`, and `TTS_PRICING` as they stand. **Token volumes are engineering estimates, not
measurements** — the api-log in a working record is the source that should replace them, and until it does,
treat every figure below as an order of magnitude and the *ratios* as the finding.

One arc = `SCENES_PER_ARC` (4) scenes; one scene at the default `balanced` prose grain = 750 words.

| Stage | Per unit | Per 4-scene arc | Note |
|---|---|---|---|
| **Scout** — structure + deltas, no prose | ~$0.014 / candidate arc | ~$0.014 | `generate`, ~12k in / ~5k out |
| Prose | ~$0.005 / scene | ~$0.02 | `write`, 750 words out |
| Script composition (tableaux) | ~$0.009 / scene | ~$0.04 | `write` at `MAX_TOKENS_LARGE`; output-heavy |
| Image prompt | ~$0.001 / image | — | `intuition`, capped at `MAX_TOKENS_IMAGE_PROMPT` |
| **Image** | **$0.04 / output image** | ~$0.24 (6 new entities) | Seedream 4.5 is $0.04 per *output image* — our flat rate is correct per image (§9 for the per-call caveat) |
| Matte (background removal) | ~$0.0005 / image | — | a second, time-billed Replicate model; ~80× cheaper than a generation |
| **Voice** (`tts-1`) | ~$0.065 / scene | ~$0.26 | 750 words ≈ 4.3k characters at $15/1M |
| Embedding (novelty scoring) | ~$0.00002 / 1k tokens | negligible | `text-embedding-3-small`, input-only |
| Scoring (§4) | **$0** | $0 | deterministic core derivations, no model call |

Two consequences, and they are the whole economic argument:

1. **A scouted candidate costs about 2.5% of a produced one** (~$0.014 vs ~$0.56 for a fully illustrated,
   voiced 4-scene arc). A $5 exploration budget buys ~350 structural candidates *or* ~9 produced arcs. Fan
   wide at scout depth; that is where the information per dollar is.
2. **Production cost is voice (~46%) and images (~43%), not text (~11%).** So the levers that matter are:
   voice opt-in and cached per line version; images per *entity*, produced once, reused across every branch
   and route (§7). Getting the text tier cheaper is rearranging the last tenth.

The cost of *not* scoring for free is worth stating: an LLM judge over 350 candidates at ~$0.005 each is
~$1.75 — a third of the exploration budget spent on opinions about the exploration. §4 keeps scoring free.

---

## 4. What "fateful" and "orthogonal" mean, measurably

Scoring must be **deterministic, free, and derived from state** — never a model asked "is this
interesting?". Every input below already exists.

**Fatefulness** — how much of the world this candidate moves. From the candidate's `WorldExpansion` deltas
and `src/lib/core/forces/thread-market.ts`:

- *Stance movement*: summed absolute `outcomeProbabilityDeltas` across touched threads. A candidate that
  moves no thread's stance is, by the instrument's own model, inconsequential.
- *Closure and rupture*: threads crossing into `isNearClosed` / `isThreadClosed`, or into
  `isThreadAbandoned`. Resolution and abandonment are the two most fateful events a thread has.
- *Entropy collapse*: fall in `normalizedEntropy` over a thread's outcome distribution — the candidate
  decided something the domain was genuinely unsure about. Weight by the pre-candidate entropy, so
  collapsing a coin-flip counts and confirming a foregone conclusion does not.
- *Structural change*: presence of `systemDeltas` / `ownershipDeltas`. Rules and ownership changing is a
  different order of consequence from actors reacting.
- *Cascade*: `opens` non-empty — the candidate primes threads for the arc after next.
- *Falsifiability*: `breaks` non-empty and specific. A direction that cannot be wrong is not a direction.

**Orthogonality** — how much this candidate differs *in mechanism* from its sisters and from what the branch
tree already holds:

- *Delta-set divergence*: Jaccard distance between the sets of entities/threads each sister touches. Two
  candidates that move the same threads in the same direction are one candidate.
- *Direction disagreement*: opposed signs on the same thread's stance delta — the strongest form of
  orthogonality, and the only one that guarantees §3 of the VN spec will present a real fork.
- *Option-space distance*: sisters whose `considered` sets overlap heavily explored the same neighbourhood.
- *Prose distance*, from `src/lib/core/search/embeddings.ts` cosine similarity, **as a tiebreak only.**
  Semantic distance is a soft geometric approximation of difference; it is not causality, and a score that
  leans on it will happily reward candidates that say new words about the same world.

Two hard rules:

- **Delta-gated, like the fork itself.** A candidate whose deltas are empty or duplicate a sister's is not a
  low-scoring candidate; it is *not a candidate*, and it must never reach the reader as a choice
  ([visual-novel](../visual-novel/README.md) §3). Prose-only divergence is a version.
- **The score is a readout, never a training target.** It selects what to *produce*; it must not be fed back
  into prompts as "write me a high-fatefulness arc", and it must never be tuned to make the numbers rise.
  That is the same Goodhart posture verification already holds: measure the output, never optimise the
  measure. If exploration starts producing world-shattering nonsense, the score is doing its job and the
  generator is not.

---

## 5. The exploration policy — where to fan next

Given a budget, a domain, and a set of forks (any arc terminal with fewer than *k* accepted continuations),
each cycle:

1. **Choose a fork.** Rank by expected information per dollar: thread entropy at that fork (unsure ⇒ worth
   exploring), few sisters so far, and — where reader telemetry exists — reader traffic (§10). An
   upper-confidence rule is the honest shape: value plus an uncertainty term that decays with each sister
   already scouted there, so a promising fork gets deepened without starving the rest of the tree.
2. **Fan with mandated divergence.** Generate *n* sisters (2–4; the existing batch runner already bounds
   concurrency) whose `Future` variables are chosen to be *opposed*, not merely different — and pass each
   sister the others' directions as `considered`, which the shipped prompt already steers against. Divergence
   is a generation instruction, not a hope.
3. **Score, free** (§4). Discard duplicates by delta-set identity before scoring; they cost nothing more.
4. **Keep everything, produce nothing.** A scouted candidate is retained as a candidate with its score and
   its cost — cheap to keep, and the corpus of rejected candidates is itself the record of what the domain
   was capable of. Retention is bounded per fork (keep the top *m* plus every candidate any reader has
   visited) so the tree does not grow without limit.
5. **Stop** on budget exhaustion (§2), no fork above an information floor, or a manual stop.

Explosion control, since "endlessly grow" is the stated goal and unbounded fanning is how it dies:

- Fan width is bounded per fork; depth beyond a fork requires that fork's best candidate to clear the
  promotion floor. Breadth is cheap, but *unbounded* breadth at every node is the combinatorial trap.
- A candidate that never scores above the floor and that no reader ever visits is prunable. Nothing is
  deleted while a save, route, or produced asset references it.

---

## 6. Promotion — how a timeline earns production

Production is a **ladder**, and each rung is a separate spend decision with its own estimate. Nothing
descends the ladder implicitly.

What a rung is *bought with* is the product's value proposition, so the ladder is also the order in which
a candidate earns each of the four: prose buys **consequence** (the deltas differ and can be pointed at)
and the beginnings of **meaning** (a recurrence the record can support); composition and POV buy
**perspective** (what this seat could know at this moment); assets and voice buy **immersion**. A rung
that buys none of them is decoration and should be refused however cheap it looks.

One more thing a promoted timeline is bought for, and the scout should weigh it: **re-entry**. A route
worth producing is one a reader will want to come back to from another seat, or one that leaves the world
in a state worth wandering or worth testing a policy against. Scouting for the second seat and the kept
state is how exploration serves the three forms the roadmap is pointed at
([World roadmap](../world/README.md#what-the-gates-are-for--three-forms-one-substrate)); scouting for the
single most dramatic branch serves a film.

```text
scouted  →  prose  →  composed (tableaux)  →  illustrated  →  voiced  →  published reading
 $0.014     +$0.02      +$0.04                 +$0.24*        +$0.26      export
                                               (* new entities only, once, reused forever)
```

- **Rung 1 → 2 (prose).** Gate: fatefulness above the floor *and* orthogonality against accepted siblings.
  This is the cheapest rung and the one that can be automatic within a run budget.
- **Rung 2 → 3 (composition).** Gate: the candidate is part of a route a reader can actually reach — it
  hangs off an accepted branch, and its fork qualifies as a choice under the commitment contract.
- **Rung 3 → 4 (assets).** Gate: emit a Factory coverage manifest, reuse approved lineages, then require
  **explicit Director confirmation with a stated estimate** for the missing or incompatible coverage.
  Autonomous work does not climb this rung; the VN spec already holds that preparation is reader- or
  Director-initiated.
- **Rung 4 → 5 (voice).** Opt-in per production, cached per exact line version, stable voice per character.
  This is the single most expensive rung; it should be the last and the most deliberate.
- **Rung 5 → published.** Export through the existing seam (`src/lib/core/io/script-export.ts`), catch-up
  only, publish sanitisation applies.

Because assets attach to **entities**, the ladder gets cheaper as the domain matures: the second production
in a well-illustrated world pays for prose, composition, and voice only. A domain's first production is its
expensive one — worth saying out loud to the Director rather than letting them infer it from the bill.

### The Factory handoff

Promotion maps more than missing images. It declares the terrain a production must cover:

- entities and identity lineages appearing on the promoted route;
- locations, maps, artifacts, effects, sound, and motion required by its Scripts;
- branch/time-valid appearance changes earned by accepted deltas;
- expression and performance families suggested by the active Entity Interpretation Graph bindings and their
  Behaviour Readings;
- consumable moment assets justified by irreversible deltas;
- exact reuse, missing coverage, incompatible style or lineage, and the estimated cost to repair it.

That manifest is a proposal. Factory may generate drafts and the scout lane may produce disposable
thumbnails, but only approved production renditions become dependencies of an Experience or World origin.
An asset request is not evidence about a character, and exploration may not alter a latent graph merely to
reduce the production bill.

---

## 7. Sprites on location plates — the Replicate approach

Today one seam generates every image: `renderToUrl` in `src/lib/engine/image/generate.ts`, one
prompt + `aspect_ratio` per prediction against Seedream 4.5, with per-kind composition prompts and aspect
ratios already tuned — `location` 16:9 (wide establishing shot), `character` / `unit` 3:4 (portrait), and
`artifact` 1:1. That is already the right decomposition for a visual novel: **the location is the plate, the
character is the figure, and the composite is free.**

The recommendation, in order of confidence:

- **Composite at render time, never at generation time.** A figure drawn *into* a location bakes a
  (character × location × pose × expression) product into paid images; the same figure drawn once and placed
  over the plate by the renderer costs nothing per combination and is exactly what `ScriptCastMember.slot` /
  `facing` / `state` already describe. Generating in-situ art is a per-scene cost multiplied by the
  branching factor — the failure the VN spec already forbids.
- **Figures need a matte.** Seedream returns no alpha. Two options, and this is the main open technical
  question: (a) a second Replicate call to a background remover — measured at ~$0.0005 p50, i.e. ~1% of the
  generation, so effectively free per figure and produced once per entity; or (b) prompt a flat, uniform
  backdrop and key it locally at import. (a) is more robust, (b) adds no provider. Either way the matte is
  produced **once per figure asset**, not per scene.
- **Expression variants, reference-conditioned.** Seedream 4.5 accepts reference images (`image_input`) and
  is built for subject consistency across generations. So a character's canonical 3:4 portrait becomes the
  reference for a small variant set — neutral / intent / recoil is enough (VN spec §6) — instead of
  re-rolling the character and getting a different face. Three variants per *speaking* character, not per
  character: a figure that never speaks needs one image.
- **Batching is a real lever with an accounting bug in front of it.** The model also takes
  `sequential_image_generation` + `max_images`, so a consistent variant set can come back from one
  prediction. Do not use it until §9 is fixed: our pricer charges per *call*, so a 3-image prediction would
  log $0.04 instead of $0.12 and the ceilings would quietly under-count.
- **Style coherence is a domain-level property.** The style directive already threads through
  `buildImageDescriptionSystem`; a production must pin the directive it used, because a re-generated figure
  in a drifted style is worse than a flat one.

What this buys: a produced arc's asset cost is *new entities only*. A four-scene arc in an established
domain that introduces one location and one speaking character costs $0.04 (plate) + $0.04 (figure) +
3 × $0.04 (variants) + two mattes ≈ $0.20 once, then zero for every re-read, every route through it, and
every sister branch that visits the same place.

---

## 8. The image model is a tier choice, not a constant

Seedream 4.5 at $0.04/image is the *production* rate, and the seam is currently pinned to it:
`REPLICATE_URL` in `src/lib/engine/image/generate.ts` is one hardcoded model URL. The LLM lane solved this
years of design earlier — `modelFor(category)` resolves a category to a model through the active allocation —
and the image lane needs the same shape: **an image tier resolved per purpose**, not a constant.

Live Replicate list prices (per output image, fetched 2026-08-31; the per-second figures are the compute
component and the per-image price is what an official model actually bills):

| Model | $/image | Reference input | Where it belongs |
|---|---|---|---|
| `black-forest-labs/flux-schnell` | **$0.003** | `input_image`, `num_outputs` | **scout tier** — draft plates, figure roughs, style tests, flowchart thumbnails |
| `google/imagen-4-fast` | $0.02 | — | mid tier — good plates when the domain's look is undemanding |
| `black-forest-labs/flux-dev` · `qwen/qwen-image` | $0.025 | `input_image` (kontext-dev) | mid tier |
| `bytedance/seedream-3` · `ideogram-ai/ideogram-v3-turbo` | $0.03 | — | mid tier |
| `google/nano-banana` | $0.039 | yes (editing model) | production alternative — no saving over Seedream, pick on quality |
| `black-forest-labs/flux-kontext-pro` · `recraft-ai/recraft-v3` | $0.04 | `input_image` (kontext) | production alternative |
| **`bytedance/seedream-4.5`** (today) | $0.04 | `image_input`, `max_images` | **production tier** — subject consistency, spatial reasoning |
| `851-labs/background-remover` | ~$0.0005 | — | matte, every tier |

What the spread is worth: **flux-schnell is ~13× cheaper than the current model.** A fresh domain's first
production needing 6 new entity images is $0.24 at production tier and ~$0.018 at scout tier. So:

- **Scout tier for anything disposable.** A candidate being *evaluated* does not need a $0.04 plate; it needs
  a thumbnail. Exploration should be able to look illustrated at ~1% of the asset budget, and a promoted
  candidate regenerates its assets at production tier — the draft was never the artifact.
- **Production tier for canonical entity assets**, where consistency is the whole requirement. This is where
  the $0.04 buys something: a figure that survives re-generation with the same face, and reference
  conditioning (`image_input`) for the variant set.
- **One model per domain per published production.** Mixing tiers inside one reading is visible — a
  flux-schnell plate behind a Seedream figure reads as an error. The tier is a property of the *production*,
  and the style directive it used must be pinned alongside it.
- **Cheaper does not mean cheap enough to be careless.** At $0.003 an image, the temptation is per-scene art;
  the (character × location × pose) product still multiplies faster than the price falls. §7's rule holds at
  every tier.

The blocker is accounting, not capability: the pricer's flat $0.04 is **model-blind** (§9), so switching to
flux-schnell today would show *no saving at all* in the gauges or against the ceilings — the run would be
priced 13× its cost and a budget bound (§2) built on it would refuse cycles that cost a quarter of a cent.
Per-model image pricing is a prerequisite for the tier, not a follow-up.

---

## 9. Three accounting defects to fix before the asset lane grows

All three are in `src/lib/core/kernel/api-logger.ts`, and all three are load-bearing for §2 — a budget bound
is only as honest as the pricer under it.

- **The rate is model-blind.** Every `replicate/` entry prices at `IMAGE_FLAT_RATE_USD` regardless of which
  model ran, so the §8 tier is unobservable: a $0.003 flux-schnell image and a $0.04 Seedream image cost the
  same in the gauges. A per-model image rate table — the mirror of `MODEL_PRICING` — is the fix, with the
  flat rate demoted to the unknown-model fallback (same posture as `DEFAULT_PRICING`).

  ```ts
  // today: one rate for every Replicate model, checked before the stamped cost
  if (isImageGenCall(entry)) return IMAGE_FLAT_RATE_USD;

  // wanted: stamped cost wins; otherwise price by model × outputs; flat rate is the fallback
  if (entry.costUsd != null) return entry.costUsd;
  if (isImageGenCall(entry))
    return (IMAGE_PRICING[entry.model] ?? IMAGE_FLAT_RATE_USD) * (entry.outputCount ?? 1);
  ```

- **The image rate is per call, not per output image.** `isImageGenCall` matches any `replicate/` model (or a
  `generateImage` caller) and returns `IMAGE_FLAT_RATE_USD` ($0.04). That is exactly right for one Seedream
  4.5 output image (verified: $0.04 per output image), and wrong the moment a prediction returns several —
  which is precisely what §7's batching wants. The cost should scale with outputs returned.
- **The flat rate outranks a stamped cost.** `calculateApiCost` checks `isImageGenCall` *before*
  `entry.costUsd`, so a cheap `replicate/` call — a background remover at ~$0.0005 — prices as $0.04, ~80×
  its real cost. A stamped `costUsd` should win over a category default; the flat rate is the fallback for
  the call that cannot report its own price.

None of the three is a crisis today (one model, one output per call), and all three become systematic error
the week the sprite lane or the §8 tier ships. Fixing them is a small change to one function, one rate table,
and a guard test.

---

## 10. Playthroughs as evidence — without a second writer

"The more playthroughs, the more informed the branching" is the right instinct and the easiest place in this
whole design to break the architecture. The constraint from the VN spec is absolute: **reading writes nothing
to canon.** So:

- Reader traversal — forks presented, commitments taken, where a reader stopped, what they re-read — is
  **reading telemetry**: per-reader, disposable, held in client/aux state, in the shape the record already
  has for non-canonical stores (`AUX_STORES`, alongside the logs). Losing it loses a statistic, never
  content.
- Exploration may read that telemetry as an **exploration prior only** (§5.1: which forks get scouted next).
  It may never be an input to what is *true*: not to thread stances, not to priors, not to `WorldExpansion`
  deltas. Readers voting a thread's stance would be a second writer wearing a survey's clothes.
- **Autonomous playthroughs are a measurement instrument, not an audience.** A machine walk of a route is a
  legitimate way to check that a route is traversable, that every fork qualifies, and that no dead option is
  presented — and it costs nothing beyond the walk, because the material is already produced. What it must
  never do is stand in for reader interest: synthetic traversal counts fed into an exploration prior are the
  model grading its own homework, and the aggregate must keep human and machine walks distinguishable.
- **Explicit judgement stays explicit.** A Director's assessment of a branch is a governed action with
  provenance, not a by-product of having read it. The two must not be conflated: one is evidence, the other
  is traffic.

The honest summary of what telemetry can do: it tells you **where to look next**, never **what is true**.

---

## 11. The honest ledger

| Requirement | State | Where |
|---|---|---|
| Sister continuations with variables, `considered`, `breaks`, `opens`, priors | **shipped** | `Future` / `FutureRun` |
| Batch runner with bounded concurrency and commit-one | **shipped** | `futures-engine.ts` |
| Structure-then-prose generation split | **shipped** | `generateScenes` + prose lane |
| Deterministic thread/stance derivations (movement, entropy, closure, abandonment) | **shipped** | `forces/thread-market.ts` |
| One pricer across every paid lane; instance + per-domain ceilings on actual trailing spend | **shipped** | `api-logger.ts`, spend ceilings |
| Single Replicate seam with per-kind aspect + composition | **shipped** | `image/generate.ts` |
| **Image tier resolved per purpose (scout vs production model), mirroring `modelFor`** | **build** | extends `image/generate.ts` (§8) |
| Auto mode with scene/arc/threads end conditions | **shipped** | `AutoConfig` |
| **Spend end condition + pre-cycle refusal + live run readout** | **build** | extends `AutoEndCondition` |
| **Run-scoped cost attribution (an exploration-run id on log entries)** | **build** | extends the api-log entry |
| **Fatefulness + orthogonality score** | **build** | new pure derivation in `core` |
| **Exploration policy (fork selection, mandated divergence, retention, pruning)** | **build** | new, around the shipped batch runner |
| **Promotion ladder with per-rung estimate and Director confirmation** | **build** | new surface over the shipped pricer |
| **Factory coverage manifest for promoted routes** | **build** | derived from route Scripts, deltas, Acting bindings, and approved asset lineages |
| **Figure mattes + reference-conditioned expression variants** | **build** | extends `image/generate.ts` |
| **Per-model + per-output image pricing; stamped cost beating the flat rate** | **build** | fixes in `api-logger.ts` (§9) |
| **Reading telemetry as an aux store, read-only to exploration** | **build** | new aux store |

---

## 12. Risks, and the test that would falsify this

- **Combinatorial explosion.** The obvious failure: fanning at every node until the tree is unreadable and
  unpayable. Held by the budget bound (§2), bounded fan width, and promotion floors (§5) — and the budget is
  the one that actually holds, because it cannot be argued with.
- **Novelty mistaken for consequence.** A score that leans on prose embeddings rewards new words about the
  same world. Held by delta-gating and by keeping semantic distance a tiebreak (§4).
- **Goodharting the score.** The score becoming a generation target, and the generator learning to move many
  threads a little. Held by §4's readout rule, and detectable: fatefulness rising while reader-observed
  consequence does not is the signature.
- **Mispriced spend.** A budget bound resting on a pricer that is model-blind and per-call rather than
  per-image (§9) — it both under-counts batches and hides every saving the §8 tier would buy. The one defect
  class that makes every other number in this spec a lie.
- **Telemetry becoming canon.** The subtlest risk, and the one worth an enforcing test rather than
  discipline (§10).
- **A second generator.** An "exploration engine" growing beside the futures batch runner. Held by scope:
  this spec adds a policy, a score, and a bound around the shipped runner, and nothing else.
- **Scout becoming producer.** Cheap exploration silently creating or replacing protected identity assets.
  Held by the Factory handoff: scouting emits coverage demand; Director-approved production creates the
  reusable artifact.

**The falsifiable test.** Take one domain with a mature branching arc. Run exploration under a fixed budget
— say $5 — and record: candidates scouted, how many cleared the delta gate, how many cleared the promotion
floor, and the cost per promotable candidate. Then have a reader walk the two highest-scoring promoted routes
and the highest-*prior* route, blind to the scores, and say which forks felt consequential and which felt
weightless. If the score's ranking does not correlate with the reader's, the score is measuring the wrong
thing and §4 is wrong — the interesting outcome either way, and cheap to run because scouting is 2.5% of
production.

---

## 13. Open decisions

1. **Does exploration ever run autonomously?** Scouting is cheap enough to be a background posture, and the
   spend model says autonomous work fails closed. A nightly $1 scout that never climbs past rung 2 is
   defensible; the question is whether the Director wants their world growing while they sleep.
2. **One budget, or a budget per rung?** A single run budget is simpler; separate scout and production
   budgets stop a cheap exploration from being swallowed by one expensive production.
3. **How aggressively to prune.** Keeping every scouted candidate forever is a record-size decision, not a
   cost decision, and it affects what the flowchart can honestly show as "unexplored".
4. **Who sets the promotion floor** — a fixed threshold, a per-domain setting, or "top *k* this week".
5. **Whether machine playthroughs may inform exploration priors at all** (§10), or only validate routes.
Open on GitHub

Raw Markdown source