MeridiansMeridians

Budgeted fate exploration — scouting timelines worth producing

From the Meridians Wiki · Public · Maintained · human-contract

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) is the first priority among the specs (specs map).

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, 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 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 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, grounded in the current VN experiment audit 🔒.

Authority is unchanged:

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

Read first: visual-novel delivery (§3 commitment contract, §7 preparation), visual-novel branching (the Reading as the branch instrument), visual-novel production (the asset inventory, style lock, and production costs), unit economics (the cost lanes and the ceilings), narrative convention (scene classes, beat mechanisms), World concept contract (what happens to a mature branch). The branch refinement 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)
Shapeone branch, deepera fan of sisters off many forks
Unit of progressa scene, an arca scouted candidate — a structural continuation with deltas and no prose
Boundscene / arc countspend, in dollars (§2)
Successthe story continuedthe fan contains something fateful and orthogonal (§4)
Outputaccepted branch materialranked 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:

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: generategoogle/gemini-3.7-flash, write / plan / intuitiongoogle/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.

StagePer unitPer 4-scene arcNote
Scout — structure + deltas, no prose~$0.014 / candidate arc~$0.014generate, ~12k in / ~5k out
Prose~$0.005 / scene~$0.02write, 750 words out
Script composition (tableaux)~$0.009 / scene~$0.04write at MAX_TOKENS_LARGE; output-heavy
Image prompt~$0.001 / imageintuition, 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 / imagea second, time-billed Replicate model; ~80× cheaper than a generation
Voice (tts-1)~$0.065 / scene~$0.26750 words ≈ 4.3k characters at $15/1M
Embedding (novelty scoring)~$0.00002 / 1k tokensnegligibletext-embedding-3-small, input-only
Scoring (§4)$0$0deterministic 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 §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); scouting for the single most dramatic branch serves a film.

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

    // 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

RequirementStateWhere
Sister continuations with variables, considered, breaks, opens, priorsshippedFuture / FutureRun
Batch runner with bounded concurrency and commit-oneshippedfutures-engine.ts
Structure-then-prose generation splitshippedgenerateScenes + prose lane
Deterministic thread/stance derivations (movement, entropy, closure, abandonment)shippedforces/thread-market.ts
One pricer across every paid lane; instance + per-domain ceilings on actual trailing spendshippedapi-logger.ts, spend ceilings
Single Replicate seam with per-kind aspect + compositionshippedimage/generate.ts
Image tier resolved per purpose (scout vs production model), mirroring modelForbuildextends image/generate.ts (§8)
Auto mode with scene/arc/threads end conditionsshippedAutoConfig
Spend end condition + pre-cycle refusal + live run readoutbuildextends AutoEndCondition
Run-scoped cost attribution (an exploration-run id on log entries)buildextends the api-log entry
Fatefulness + orthogonality scorebuildnew pure derivation in core
Exploration policy (fork selection, mandated divergence, retention, pruning)buildnew, around the shipped batch runner
Promotion ladder with per-rung estimate and Director confirmationbuildnew surface over the shipped pricer
Factory coverage manifest for promoted routesbuildderived from route Scripts, deltas, Acting bindings, and approved asset lineages
Figure mattes + reference-conditioned expression variantsbuildextends image/generate.ts
Per-model + per-output image pricing; stamped cost beating the flat ratebuildfixes in api-logger.ts (§9)
Reading telemetry as an aux store, read-only to explorationbuildnew 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.