guts/docs/LANES/LANE_C_NOTES.md
type-two a318cf09f7 [lane B+C+F] The Appendix Sovereign: the secret boss, and a reputation you cannot fake
Two boss specs written to C's format (LANE_C_NOTES §Boss specs, round 3 additions) and the
first of them built. Both extend the roster along C's own law — one boss, one pressure — onto
the two axes the game had systems for and no boss pointed at: reputation (§4 Sovereign) and
restraint (§5 Mast Cell, specced only).

THE SOVEREIGN. The appendix is not vestigial: it is a biofilm reservoir where the gut's flora
shelter and re-seed the colon after a purge, and the whole fight is that fact. It is the only
boss whose existence is decided before you arrive — read once on entry:
  karma >= 70  THE COMMUNION — no fight at all. Full coat, a permanent phage escort. The
               reward for five levels of restraint is being spared a boss.
  karma >= 30  THE TOLL — P1 only.
  below        THE SOVEREIGN — three phases. P1's matrix is immune to the cannon and only the
               antacid torpedo disperses it (a mature biofilm's whole defining trait); P2 is a
               quorum bloom that re-armours when the room gets crowded; P3 is a 20s reseed run.
And the mechanic that makes it this boss: the lair is seeded with YOUR OWN FLORA, and it feeds
on dysbiosis — every commensal your stray fire kills re-armours a plate, live, mid-fight.

KARMA vs STANDING — a real bug found in testing, and worth the extra number. `standing` is a
SPENDABLE meter: a full bar is consumed to bud an ally, dropping to a 50 floor. That meant a
perfect player could never HOLD >= 70, so the Communion was almost unreachable — verified: a
symbiotic pilot showed standing 50 and was demoted to "toll". `karma` is the same inputs with
nothing spending it. The Sovereign's tier and gates' `secretTo` branches read karma; E's bar
still reads standing.

Also: boss.js generalised to a registry, which was the claim its header made — the Sovereign
needed zero changes to enemies.js. LS_appendix (3 segments, 800 units, 16 events), reached from
L4's ileocecal valve via `secretTo`/`secretNeed` — anatomically exact, the appendix hangs off
the cecum right past that valve. The secret is hidden behind conduct, not behind a wall.

C's selfcheck caught par.time as a free medal and the fix improved the design: par 160 sits
under the timid traversal, so only a Communion run (which has no fight) can beat it. The time
medal rewards the same conduct the level is about.

Verified: all three tiers branch correctly (communion = 0 nodes + 4 phages; toll = 1 phase;
full = 3 phases, 4 armoured); killing a commensal mid-fight re-armours a plate (reason
"dysbiosis"); the valve routes karma 100 -> LS_appendix and karma 0 -> L5. Levels 5/5 valid.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 23:25:36 +10:00

36 KiB
Raw Blame History

LANE C — NOTES (Levels & Encounters)

Round 1 · 2026-07-16 · all numbers below are measured with node web/js/levels/index.js --sim unless flagged otherwise. Read §→ Lane X for anything addressed to you.


What landed (round 1)

file what
web/js/levels/index.js registry + loader + schema selfcheck (qa gate) + pacing simulator
web/js/levels/enemies.js enemy catalogue (fiction id → archetype), pickup + hazard vocabularies
web/js/levels/difficulty.js the single difficulty table + applyDifficulty()
web/js/levels/L2_esophagus.json the vertical slice — complete: 3600 units, 7 beats, 65 enemies, 47 events
web/js/levels/L1_mouth.json skeleton (shape only)
web/js/levels/L3_stomach.json skeleton (shape only)
docs/TECH.md §Level schema ratified v1 (was v0)
docs/GDD.md per-level time targets, esophagus roster, L2 setpieces (bannered)
web/js/stub/world_stub.js STUB_LEVEL synced to v1 (authorised by ROUND1 §Lane C.1 — only that const)

node web/js/levels/index.js --selfcheck3/3 valid, exit 0. qa.sh green.


Schema v1 — what changed from v0, and why

Ratified in TECH.md. All additive; every v0 level still parses. I own it from here.

added why it was needed
schema so a level and its loader can disagree loudly instead of silently
theta / rho v0 could only place content along the canal. A wall-mounted turret and a "visible-but-costly" sample are both statements about the cross-section. rho is a fraction of the safe radius, never a distance — radius varies with s, so a fraction is the only placement that cannot end up inside a wall.
spread count: 6 at a single s is a pile, not a field
span hazards have extent (a 400-unit squeeze zone), not just a trigger point
par medals need thresholds; GDD §Scoring had nowhere to live
pickup, gate types the pickup economy and the level→level seam were undefined in v0
segment name the anatomy, separated from the biome (see below)
next campaign order belonged in data, not in code

The one real design decision in v1: biome ≠ anatomy. Lane A's registry has six canonical ids (oral · esophagus · stomach · small_intestine · large_intestine · appendix). I had authored mouth/pharynx/cardia/pylorus and the selfcheck rejected all four against A's live registry. A is right and I conformed — biome is the tissue/look family, segments[].name carries the anatomy. There is no cardia biome and there should not be one.

That turned out to be a gift rather than a compromise, because it lets colour do the wayfinding:

  • L1's oropharynx wears the esophagus palette — the tube goes teal 200 units before the epiglottis, so you read the transition in the walls before any HUD tells you.
  • L3's cardia keeps the esophagus palette — you arrive in teal and the world turns orange the moment the fundus opens. The acid sea reveals itself. Spending a biome id on the cardia would have thrown that reveal away.

L2_esophagus — the vertical slice

Identity: the sprint. The purest tube in the body, one biome, no arenas, everything readable at 1420 u/s. Par 3:30; measured speedrun 2:47, timid run 4:22.

Scale, stated honestly: cross-sections are anatomically true (radius 1012 units ≈ a 2 cm lumen at 1 unit : 1 mm). Lengths are dilated ~14× — the real esophagus is 25 cm, this level is 3600 units. The canal is proportioned, not measured. I would rather say that out loud once than have five lanes quietly assume different scales.

Anatomy is the level designer. The esophagus has three real constrictions (cricopharyngeal, broncho-aortic, diaphragmatic hiatus). They are the level's three setpieces, in the real order. Deviations I chose, on purpose:

  • The broncho-aortic constriction is a single ~2 cm feature in life; L2 dilates it into two beats (aortic at 1100, bronchial at 2000) because one is a spike and one is a ramp.
  • In life the cricopharyngeal narrowing is the tightest of the three. L2 makes the hiatus tightest instead, because the level needs to escalate and beat 1 is the tutorial.

Measured pacing (--sim L2_esophagus)

  beat                        s-range      len flow  en  dens  tight haz   PRESSURE  clear   t     cum
  Upper Esophageal Sphincter    0- 400   400   12   1  0.25  1.09 1.00   0.27 ..........  6.63   29s  0:29
  Cervical Esophagus          400-1100   700   14  15  2.14  1.00 1.00   2.14 ###.......  6.79   43s  1:12
  Aortic Constriction        1100-1500   400   16   9  2.25  1.33 1.45   4.35 #######...  2.88   22s  1:34
  Thoracic Esophagus         1500-2000   500   14   3  0.60  1.00 1.15   0.69 #.........  6.55   31s  2:05
  Bronchial Narrowing        2000-2600   600   16  17  2.83  1.20 1.33   4.53 #######...  4.45   33s  2:38
  Diaphragmatic Hiatus       2600-3000   400   18   9  2.25  1.76 1.60   6.35 ##########  2.73   19s  2:57
  Abdominal Esophagus        3000-3600   600   20  11  1.83  1.33 1.80   4.40 #######...  4.15   22s  3:19

pressure = density × tightness × hazard — density alone is a lie in a tube, because 9 enemies in a 6.8-unit hole is not 9 enemies in a 12-unit hole.

The curve: 0.27 → 2.14 → 4.35 → 0.69 → 4.53 → 6.35 → 4.40. Breather → pressure → SPIKE → breather → pressure → SPIKE → finale. Two waves, escalating (4.35 → 4.53 → peak 6.35).

The finale is not the pressure peak, and that is deliberate. You cannot sustain maximum dodge-density at maximum speed and call it fair. The finale's intensity is stakes, not density: it is the only place in L2 where a mistake is fatal rather than expensive. The pressure index cannot see that — it is a relative index, not a fun-meter. Flagging it so nobody "fixes" beat 7 by piling enemies into it.

Honesty about this evidence: the sim is a kinematic model, not a playtest. It assumes a constant throttle and no combat slowdown (fair-ish in tube mode: the current carries you and you cannot stop). Times are lower bounds on a real run. It cannot tell me whether the hiatus feels good — only that it is flyable, paced, and survivable. Verdict on feel needs A's world + B's controller in round 2. See §Why no in-engine flythrough.

Teach-then-test ledger

Every mechanic appears safe before it appears lethal. This is the law I checked the level against:

mechanic taught (safe) tested
the flow itself b1, s 0400 — slowest flow, straightest tube, one lazy chunk the whole level
bolus chunk s 240 — one, slow, unmissable s 1260, in a 9-unit tube that pulses
eosinophil swarm s 620 — three, open water, nothing else happening s 2880, chasing you through the hiatus gate
candida bloom s 760 — one, straight wall, 200-unit sightline s 1180, in the squeeze that pushes you at it
ring gate s 2100 — open 67% of the time s 2800 — open 40%, in the tightest tube
reflux surge s 1700 — the "burp": 16 u/s vs 14 flow, non-lethal s 3000 — 21 u/s, lethal, 600 units

The burp is the most important event in the level. When the real surge arrives 1300 units later, the player already knows the verb.

One deliberate exception: aortic_squeeze (s 1100) is first met as the spike. It gets away with it because it is non-lethal (graze damage) and 400 units long, so its first two pulses teach it inside its own zone. If B makes squeeze contact lethal, this breaks — tell me.

Checkpoints — death costs ≤ 30 s (measured, at par throttle)

10 checkpoints, sphincter-themed where anatomy allows. Max gap 28.8 s (the opening breather, where you are least likely to die). Every gap is enforced by the selfcheck, so this cannot silently rot.

  20 ->  420  400u  28.8s   420 ->  860  440u  27.3s   860 -> 1080  220u  13.7s
1080 -> 1520  440u  24.2s  1520 -> 1680  160u   9.9s  1680 -> 2000  320u  19.9s
2000 -> 2280  280u  15.2s  2280 -> 2580  300u  16.3s  2580 -> 2980  400u  19.4s
2980 -> 3600  620u  23.2s

Checkpoints sit before hazard zones, never inside them (1080 precedes the squeeze at 1100; 2980 precedes the surge at 3000). Respawning a player inside a squeeze is a bug.

The three biopsy samples — visible-but-costly, three different costs

Never on the racing line, always in plain sight. The cost is what differs:

# s cost
1 700, θ=π, ρ=0.92 proximity — pinned to the far wall in the tail of the bolus field: wall-hug (graze) while chunks tumble past
2 1300, θ=π/2, ρ=0.90 timing — against the wall inside the squeeze zone: eat a pulse, or thread it between beats
3 3200, θ=3π/2, ρ=0.85 the chase — ~1.5 s off-line with an acid wall ~5 s behind you. The only one that is a real decision at full speed.

The finale, tuned

Surge 21 u/s spawning 40 units behind you, chasing 600 units. Segment flow is 20, throttle range ×0.61.4 ⇒ 1228 u/s. So: throttle 1.05+ outruns it; dawdling at 12 u/s kills you. Par pace (~26 u/s) finishes ~5 s clear. The level's last instruction is "do not dawdle".

The antacid torpedo is the skill expression: B's balance.js gives it neutralizeRadius: 14, neutralizeDuration: 10, so fired backward it stalls the surge ~10 s. L2 hands you 2 antacid at s 2300 and 1 at s 3080, never explains this, and rewards you for noticing. On hard, difficulty.js puts the surge at 23.1 u/s and the chase stops being a sprint and becomes a route-planning problem.

L2 roster — all three are real esophageal pathology

fiction archetype real thing
bolus_chunk floater swallowed food debris in the swallow
eosinophil_swarm seeker eosinophilic esophagitis — immune cells that mistake ENDO-1 for the parasite they were built for
candida_bloom turret candida esophagitis — white plaque colonies anchored to the mucosa

Reality is weirder and better than invention (charter). All three fell out of "what actually goes wrong in an esophagus", and each one maps to a different archetype B already built.


Why there is no in-engine flythrough this round

My charter says to fly each level on the stub (?lvl=L2_esophagus&stub=1). That flag combination does not exist yetboot.js hardcodes STUB_LEVEL on the ?stub=1 path and never reads flags.lvl. Snippet offered in §→ Lane F.

Worth saying plainly: even with that wiring, the stub could not validate L2's pacing. The stub is single-segment (levelData.segments[0]), so it would render beat 1 and nothing else. L2's whole design is the sequence of 7 beats. The real flythrough needs Lane A's world and Lane B's controller, which is exactly the round-2 integration.

So round 1's evidence is the pacing sim — which is the right instrument for a data lane, and is stronger than eyeballing one beat: it checks all 10 checkpoint gaps, all 7 clearances and the par against three throttle profiles, on every qa run, forever. What it cannot do is tell me the hiatus feels good. That claim I am not making.


Boss specs

One-pager each: phases → telegraphs → windows → failure pressure. Written now so A can shape lairs and D can concept hero meshes in round 2. Numbers are design intent, not measured — they need B's framework to tune against.

The roster's shape: one boss, one pressure. Guardian = a coat race (positional attrition). Tapeworm = a distance race (a chase you can lose without dying). Blockage = a hull race + doom timer (darkness and risk/reward). If they all became DPS checks we would have built one boss three times.

Round 3 extends the roster along the same law, onto the two axes the game had systems for and no boss pointed at: Appendix Sovereign = a reputation race (§4) and the Mast Cell = a restraint test (§5). Five bosses, five pressures, no repeats.

1. Pyloric Guardian — L3 exit, arena (arenas[2], s 2350, radius 70)

The pyloric sphincter itself: a muscular iris, hypertrophied and colonised. It periodically opens to pass chyme — that cycle is the whole fight, because the nodes are only exposed when the ring relaxes. The arena churns throughout, pushing you at the walls.

phase hp the loop window
P1 Peristaltic Cycle 100→66% iris opens 2.5 s every 8 s; 4 mucosal nodes glow at the rim, vulnerable only while open. 3 fixed vents spit acid on a 3 s cycle. 2.5 s / 8 s (31%)
P2 Reflux Fury 66→33% cycle tightens to 1.8 s every 5 s. Between openings it vomits bolus chunks + pepsin swarms into the arena. 2 of the 4 regrown nodes are armored — antacid strips them. Churn ×1.5. 1.8 s / 5 s (36%)
P3 Death Grip 33→0% it stops opening and tries to seal permanently — 25 s doom timer. The core is exposed only when it spasms. Acid vents become a rotating sweep. 1.2 s every ~4 s, ×5 hits
  • Telegraphs: a deep gulp 2 s before every open · nodes amber → white-hot when vulnerable · vents dribble 0.8 s before spitting · P3's window = the whole arena flashes and the churn reverses for 1.2 s (you feel the tell in the controls, not just the eyes).
  • Failure pressure: stomach coat-drain is continuous, so this is a race against your coat, not its hp. Mucus shallows on the greater curvature pause the drain but are far from the iris — the risk/reward is positional. P3 adds the doom timer.
  • Scaling: difficulty.window multiplies every window; doom timer 25 s × (1.3 / 1.0 / 0.85).

2. Tapeworm — L4 miniboss, tube chase

Taenia solium, metres long, coiled through the ileum. It does not fight you — it runs, and the canal is its body. A chase at high flow through the villi forest, which occludes sightlines and keeps making it vanish.

phase hp the loop window
P1 The Tail 100→70% you catch the tail. 6 proglottids, each with a pale weak point — a genital pore, which real proglottids actually have — on one face only. It rolls on a 4 s period; shoot the pore as it comes round. Killed segments detach and become obstacles. ~1.8 s of every 4 s roll
P2 Constriction 70→40% it coils around the lumen into 3 rotating rings you thread. Weak points move to the ring joints. 1.5 s per joint pass
P3 The Scolex 40→0% it turns to face you: four suckers and a rostellum of hooks, charging head-on. Hooks fire as projectiles. Weak point = the suckers, exposed as it lunges. 1.4 s per lunge
  • Telegraphs: pore-glow ~1.2 s before it is shootable · a grinding drone that rises as you close (distance made audible — the villi hide it visually) · hook volleys pre-flash · the scolex rears with a wet inhale 1.2 s before each lunge.
  • Failure pressure: it is a chase — you can lose without dying. Fall behind and it escapes: soft fail, level continues, medal gone, and it reappears in L5 as a hazard. A consequence the player earned is worth more than a retry screen.

3. The Blockage — L5 final boss, tube→arena, in the dark

A fecalith the size of the lumen: compacted mass, colonised, embedded with antibody turrets and gas pockets. The colon behind it has been distending for the whole level. Darkness is the medium — the gas pockets are the light source, which is the whole look of the fight.

phase hp the loop window
P1 The Face 100→60% 5 armored plates (3 hits each). Turrets fire homing darts from between them. Gas pockets bulge between plates: shoot one and it detonates, destroying adjacent plates outright — and hurting you inside ~15 units. Optimal play = detonate 23 from max range. continuous; the pockets are the timer
P2 Fragmentation 60→30% the mass breaks into 4 tumbling chunks, each with a turret, orbiting the arena. Gas vents fire jets that shove you into them. Core opens intermittently. 2 s every 6 s
P3 The Push 30→0% the colon begins the final peristaltic push: the arena contracts on a 5 s beat and drives the Blockage toward the exit with you behind it. 30 s doom timer — if it plugs the rectum, you lose. Core exposed on each contraction. 1.6 s every 5 s
  • Finale: it blows, and the canal expels you both. (GDD: triumphant ejection.)
  • Telegraphs: pockets glow — in the dark they are the brightest thing in the room, so the risk telegraphs itself · plate cracks show damage state · a full-canal groan 1.5 s before each contraction · turret pre-fire flash.
  • Failure pressure: hull attrition, inverting the Guardian. Colon coat-drain is mild, but gas blasts and darts hit the hull, and hull is pickup-only. Plus the P3 doom timer.

Boss specs — round 3 additions

Same law as the roster above: a boss earns its place by attacking a resource nothing else attacks. The three originals take coat, distance and hull. These two take the two axes the game built systems for and then never pointed a boss at — your reputation and your trigger finger. Neither needs a new archetype; both are schedules over what exists (combat/boss.js is a state machine, not an entity system — see its header).

4. The Appendix Sovereign — LS secret, arena (the cul-de-sac off the cecum)

The appendix is not vestigial, and this fight is the game finally saying so: it is a biofilm reservoir, a dead-end where the gut's own flora shelter from the torrent and re-seed the colon after a purge. The Sovereign is that mat, matured — a layered dome carrying the lineage of every colony you have flown past since the esophagus.

It is the only boss whose existence is decided before you arrive. BIOME STANDING is read on entry and the encounter branches:

standing what happens
≥ 70 — symbiotic The Communion. Not a fight. The mat opens, re-seeds your coat to full and sends a permanent phage escort out with you. ~30 s of spectacle and a gift. The reward for five levels of restraint is being spared a boss.
3069 — neutral The Toll. It does not know you. P1 only, softened — prove yourself and it opens.
< 30 — dysbiotic The Sovereign. The mat has turned. Full three-phase fight, the hardest in the game.

The dysbiotic fight, which is the one worth speccing:

phase hp the loop window
P1 The Matrix 100→60% The dome is sheathed in extracellular matrix and the cannon does nothing to it — that is not a gimmick, it is what a biofilm IS (a mature one is orders of magnitude more drug-resistant than free bacteria). Only the antacid torpedo disperses matrix, exposing feeding channels beneath. Nutrient orbs bloom around the lair to fund the ammo. continuous, gated by ammo, not by time
P2 Quorum Bloom 60→30% Channels exposed, it calls — quorum sensing, for real: it floods the lair with virions and spore pods and re-armours a matrix plate every time the population crosses its threshold. Hold the count DOWN with sustained fire while hitting the channels. Let it bloom and you are back in P1. continuous, gated by heat
P3 The Reseed 30→0% It will not die in a cul-de-sac: it tries to flush itself into the colon to survive, and the lair drains toward the cecum. 20 s doom timer — if it reaches the exit it lives, the secret is lost, and the run ends without it. Core exposed while it swims. ~2 s per surge, ×4
  • The mechanic that makes it this boss and not another: the lair is full of your own flora. Cyan colonies drift between you and the dome for the whole fight, and the Sovereign feeds on dysbiosis — every commensal your stray fire kills drops your standing and buffs it in real time (a plate regrows, a bloom comes early). It is the only fight in GUTS where the right move is regularly to stop shooting, under maximum pressure, with a boss in your face.
  • Telegraphs: the dome glows brighter and redder as your standing falls — the boss wears your conduct as its skin · matrix plates crack white where a torpedo landed · a rising chorus 1.5 s before a quorum bloom · P3 = the whole lair's fog streams toward the exit.
  • Failure pressure: reputation, live. Every other boss takes a resource off your ship. This one takes your difficulty dial and hands it to your trigger discipline. A player who sprays makes the fight unwinnable by their own hand, which is the thesis of the game stated as a boss.
  • Why a secret boss may borrow every pressure: the roster law says one pressure per boss so we do not build one boss three times. An optional superboss at the end of a hidden branch is the exam, and an exam is allowed to be cumulative — ammo (P1), heat (P2), distance (P3). Its OWN pressure, the one no other boss has, is the flora law running underneath all three.
  • Scaling: difficulty.window; the branch thresholds shift (easy 60/25 · normal 70/30 · hard 80/40), so mercy is easier to earn on easy and must be deliberate on hard.

5. The Mast Cell — L1 oral cavity, arena (the tutorial's centrepiece)

A sentinel immune cell on patrol in the oral mucosa, packed with granules of histamine. It is not hostile. It has no attack, it does not chase, and its aura is harmless. It is also hair-trigger, and the entire encounter is built on one question: will you shoot it?

The GDD's fiction has said from day one that the enemy is "an infestation + an immune system that can't tell you're friendly". Every boss so far fights that second clause. This one lets you decline.

phase hp the loop window
P1 Patrol It drifts a slow circuit of the cavity, granules glowing cyan — the flora colour, doing narrative work: the readability law is telling you this is not your enemy and the level is watching whether you believe it. Thread past it and the encounter simply ends. There is no fight. the whole beat
P2 Degranulation 100→40% Triggered by any damage you deal it. It turns amber and dumps histamine: the cavity's walls swell inward (playable radius drops ~30%), coat drain doubles, and amylase droplets pour in. It still does not chase you — the level is now the enemy, and you did that. continuous
P3 Anaphylaxis 40→0% Past a second damage threshold the cascade goes systemic: the lumen constricts toward lethal and a 25 s doom timer starts — the airway is closing. Reaching the epiglottis is now a race you started for no reason. continuous
  • Telegraphs: cyan granules while calm · a visible ripple through its membrane if your reticle lingers on it — the game warning you off before you ever pull · the first hit turns it amber and the comms crew break protocol to shout · the walls visibly swell on every plume.
  • Failure pressure: restraint, and nothing else. The pacifist route has no coat race, no hull race and no timer. All the pressure is psychological: five minutes of tutorial have trained the reflex "amber thing → shoot", the game hands you a thing that is not amber, and the punishment for the reflex is not damage — it is the level getting worse and staying worse. Best-case and worst-case are separated entirely by what the player chose.
  • Why it belongs in L1: a tutorial teaches verbs. This one teaches the game's thesis — that the body is weather and not all of it is your enemy — and it teaches it in the only way that sticks, by letting you get it wrong and live in the consequence. It also arms the flora law before L2 ever shows a cyan colony.
  • Scaling: difficulty sets the anaphylaxis doom timer (32 / 25 / 20 s) and whether P2 has a grace hit (easy forgives one; hard triggers on a graze).

→ Lane B

Four things, in priority order. (1) is the only one that blocks you consuming my levels.

1. Resolve fiction ids → archetypes. Your pools are keyed by archetype; my levels name enemies in fiction. One line in combat/index.js:

import { getEnemy } from '../levels/index.js';
// ...inside the level:event handler, replacing enemies.spawn(ev.enemy, ...):
const spec = getEnemy(ev.enemy);
enemies.spawn(spec?.archetype ?? ev.enemy, { s: ..., theta: ..., rho: ... });

?? ev.enemy keeps bare archetype names working, and enemies.js has passthrough entries for floater/seeker/turret, so this is backward compatible and STUB_LEVEL still works unchanged — I deliberately did not rename the stub's enemies out from under your harness.

2. theta may be an array (one per instance) for wall-mounted groups — theta: [1.05, 4.19] with count: 2. Your loop currently passes ev.theta whole to every instance. Needs:

theta: Array.isArray(ev.theta) ? ev.theta[i % ev.theta.length] : ev.theta ?? null,

Until that lands I have kept STUB_LEVEL on scalar thetas so nothing breaks. L2 uses arrays.

3. spread (units along s a group occupies) — you currently hardcode i * 3.5. L2 tunes this per encounter (60 = a wall of traffic in the hiatus; 200 = strung out along the chase):

const spread = ev.spread ?? (3.5 * ((ev.count ?? 1) - 1));
const s = (ev.s ?? 0) + (ev.count > 1 ? (i / (ev.count - 1)) * spread : 0);

4. Heads-up — your tuning.js header is stale. It documents wallRho = radius waveAmp(0.9) skin(0.6) => ~7.0..10.0 playable disc. Lane A has since measured the esophagus at amp 1.4 (+ breathe 0.15, and A's waveMaxAt subtracts both). Your real envelope in a radius-10 tube is now ~6.35..9.35, and your disc top speed / graze tuning was sized against the old number. Not my call to change — flagging it because it moved under both of us. My selfcheck reads A's registry live, which is how I caught it.

Balance ownership — agreed, and I removed my duplicate. You own mechanics (hp, radius, speed, damage, fire rate, score), keyed by archetype, in balance.js. I own composition (which fiction, how many, where, in what order). My first cut of enemies.js restated hp/size/speed/score; that was over-reach — an hp: 2 here and an hp: 24 there (against damage: 12) is the same number twice. levels/enemies.js is now a join table only, and levels/index.js reads your scores via scoreFor() to compute the score budget: L2 par.score 9000 of a 9400 kill budget = 95%, computed from your numbers, not mine. If you retune scores, my par re-checks itself on the next qa run.

Hazards I placed that are yours: reflux_surge (see HAZARDS in levels/enemies.js for params). L2 has a non-lethal one at s 1700 and the lethal finale at s 3000. They are inert data until you implement them — that is by design (charter: stub it in data first), not a bug. Also: if aortic_squeeze contact ever becomes lethal rather than graze, tell me — L2's teach-then-test ledger depends on it being survivable.

→ Lane A

1. Biome conformance — done, no action needed. I had authored mouth/pharynx/cardia/ pylorus; your registry rejected all four and your design is right. biome = look, segments[].name = anatomy. You do not need to add biome ids for C. Your six cover the campaign, and I made the constraint pay for itself (see §Schema v1 — the cardia keeping the esophagus palette is why the acid sea gets to reveal itself).

2. Your amp 0.9 → 1.4 landed mid-session and cost me 0.5 units of flyable radius. No complaint — your reasoning (B cannot surf a crest the player cannot see) is better than my tube. The diaphragmatic hiatus went unflyable at base 6.5 and I widened it to 6.8 (free radius 2.73, against my 2.5 floor). This is working as intended: my selfcheck reads wave.amp + wave.breathe from your registry live, so if you retune again, my levels fail qa and I re-tune them. Please keep changing it if it looks better — just expect a red qa.

3. Request (round 2): per-segment wave override. Anatomically the hiatus is a fixed muscular ring held by the diaphragm crura — it does not have big peristaltic waves; the esophagus above it does. Right now one amp applies to the whole biome, so the level's tightest hole gets the level's biggest wave, which is both wrong and the thing squeezing my design. I have not added it to the schema unilaterally. Proposed: segments[].wave: { amp: 0.6 } overriding the biome, waveMaxAt(s) preferring the segment. Your call — say yes in NOTES and I will spec it into v2 and re-tune.

4. Do segments blend radius at boundaries? L2 steps 12 → 9 (s 1100) and 10 → 6.8 (s 2600). C's design assumes a smooth blend over ~4060 units, not a cliff — a hard radius step would read as a wall and the constrictions are supposed to feel like the body narrowing, not like a level seam. If your tube hard-steps, tell me and I will author explicit taper segments instead. This is my biggest open dependency on you.

5. Arena semantics — ratified in TECH v1 as I read your arenaSpatial: a sphere of radius centred on the centreline at at, spanning [at-radius, at+radius], modeAt'arena' inside. Problem for L3: the stomach body is not a sphere. L3_stomach.json currently fakes it with one radius-180 sphere and that is flagged PROVISIONAL in the file. It needs either a capsule/blob primitive or chained overlapping spheres. Not urgent (L3 is round 3+), but it will decide how I author the acid sea, so I would like your read early.

6. Hazards that are yours: aortic_squeeze and ring_gate (params + rationale in HAZARDS, levels/enemies.js). Both are inert data until you build them — fine by me. The important one: aortic_squeeze is directional (one-sided) on purpose. It presses from theta and the opposite arc stays clear. A symmetric squeeze would be an untimeable toll, because in a flow-locked tube the player cannot stop and would eat all ~10 pulses of a 400-unit zone. Directional turns it into a positioning verb — and it is also what the aorta actually does. ring_gate is the opposite: a point, therefore timeable, because the player can modulate throttle on approach to arrive on an open beat. Two hazards, two verbs.

→ Lane D

  • Concept these three for L2 (round 2 hero-ish props, ART_BIBLE emissive law): bolus_chunk (tumbling debris, amber 0xd98a3a), eosinophil_swarm (small fast, red 0xff4d3d), candida_bloom (wall-mounted white plaque colony, 0xffd166). Tints in levels/enemies.js are advisory — yours to make beautiful.
  • Boss specs are ready above (§Boss specs) — phases and silhouettes are stable enough to concept the Pyloric Guardian (a muscular iris with 4 rim nodes) and the Tapeworm (segmented body + a 4-sucker scolex). The Blockage is a mass of plates + glowing gas pockets.
  • The candida_bloom is the interesting modelling problem: it is flat against a curved wall, not a free-floating prop. Might be a decal/plane rather than a GLB.
  • L2 needs your esophagus wall pack — already on your round-1 list, nothing extra from me.

→ Lane E

1. Bus events I need (F referees the names — proposing here):

  • hazard:warn { kind, s, eta } — fires warn seconds before a hazard (my events carry warn, default 2.5 s). Drives your HUD ping + audio:cue.
  • hazard:proximity { kind, distance }the reflux surge chases you from behind. This is a forward-facing game; without a rear indicator the finale is unfair rather than tense. This is the single most important UI request I have. A rear-distance bar, a rising audio bed, screen-edge acid creep — your call, but the player must feel 5 s of margin shrink.

2. Gut-map — L2 is 3600 units, 7 named segments, 10 checkpoints. Segment names are authored for exactly this (Upper Esophageal Sphincter, Aortic Constriction, Diaphragmatic Hiatus…). listLevels() in levels/index.js gives you { id, name, tagline, length, par, skeleton } for menus; getLevel(id) gives the rest.

3. Telegraph budget: L2 is flown at 1420 u/s (up to 28 in the finale). Anything lethal telegraphs ≥ 2 s = 4056 units upstream. My selfcheck warns if I author a lethal hazard with warn < 2.

→ Lane F

1. ?stub=1&lvl=<id> does not compose. boot.js pickWorld() hardcodes STUB_LEVEL on the stub path and never reads flags.lvl — so the flag table's C-owned ?lvl=<id> row does not work with ?stub=1, which is the combination my charter tells lanes to verify levels with. Offered (your file, your call):

async function pickWorld() {
  const level = await loadLevel(flags.lvl).catch(() => null);   // C's registry, when present
  if (!flags.stub) {
    try {
      const mod = await import('./world/index.js');
      const lv = level ?? STUB_LEVEL;
      return mod.createWorld(lv, { rng: createRng(flags.seed ?? lv.seed) });
    } catch (e) {
      console.info('[boot] Lane A world not available, using stub —', e.message);
    }
  }
  const lv = level ?? STUB_LEVEL;                                // ?stub=1&lvl=L2 => C's data
  return createStubWorld(lv, { rng: createRng(flags.seed ?? lv.seed) });
}

Caveat so nobody expects too much: the stub is single-segment, so ?stub=1&lvl=L2_esophagus renders beat 1 only. Still useful (it proves the data path end-to-end); it is not a flythrough. The real one is round 2 on A's world.

2. getLevel() defaults to L2_esophagus (DEFAULT_LEVEL in levels/index.js) — booting with no ?lvl gives you the vertical slice. Change it if you would rather it be L1.

3. Bus table (TECH §Bus events) — please referee hazard:warn {kind,s,eta} and hazard:proximity {kind,distance} (rationale in §→ Lane E). Also note B is already emitting level:neutralize, which isn't in the table yet.

4. Schema v1 is ratified in TECH.md §Level data schema — I rewrote that section only. I also touched exactly one const in your world_stub.js (STUB_LEVEL, per ROUND1 §Lane C.1) and left the geometry untouched, so your round-0 screenshot still stands.

5. qa.sh, minor: the web/js/levels/*.json loop asserts id/seed/segments on every JSON in that directory. No collision today (my catalogue and difficulty table are .js), but it means C can never put a non-level JSON there. Fine by me — noting it so it is a decision rather than a trap.


Open questions

  1. Segment radius blending (A) — biggest one. If the tube hard-steps at segment boundaries, L2's constrictions read as seams and I re-author with taper segments.
  2. Per-segment wave override (A) — would let the hiatus be tight and calm, which is both better design and better anatomy.
  3. Ship radius 0.9 (B) — I took it from flight/tuning.js (ship.radius, the collision sphere, vs a hull that "reads ~1.9 long, 1.2 wide"). My MIN_CLEARANCE of 2.5 is ~2.8× it. If the effective collision radius is really the visual 1.2, my two spikes lose 0.3 and the hiatus goes under the floor.
  4. Is MIN_CLEARANCE = 2.5 right? It is my judgement call, unvalidated by anything except arithmetic. It is the number that decides whether L2's setpieces are exciting or miserable, and only B's controller in a real tube can settle it. If one thing from this round gets playtested in round 2, make it the hiatus at s 26003000.
  5. Par time 3:30 vs the GDD's old flat "610 min/level" — I refined the GDD to per-level targets rather than pad L2. A flow-locked tube bounds its own length: a timid run is 4:22 and there is no way to dawdle further. F to sign off.

Next round (C)

  • Fly L2 on A's world + B's controller. Replace the sim's numbers with real ones, and finally answer whether the hiatus feels good.
  • L1 encounter pass (tutorial beats, molar crush-cycles, saliva tides, the epiglottis exam) — needs B's arena controller.
  • L3 encounter pass + the acid sea's mucus-shallow lanes — needs A's arena decision (§→ A.5).
  • levels/bosses/pyloric_guardian.js — the phase state machine, once B's enemy framework has a boss hook. Spec is above and stable.
  • Fold the boss specs into the GDD proper once F signs them off.
  • Tune difficulty.js against real play (the table is authored, not validated).