Commit Graph

4 Commits

Author SHA1 Message Date
type-two
7455c03ae3 [lane B+C+E+F] Playtest blockers: the game never taught its controls, deleted bosses on death, and shipped an unwinnable tutorial
A five-way audit of the shipped build found the first thirty seconds are broken in three
independent ways. All three are verified, not inferred.

1. THE CONTROLS WERE NEVER STATED. The title said "press any key", and aim + fire are both gated
   on pointer lock (input.js:45 onMouseMove early-returns unlocked; input.js:50 the first
   mousedown only REQUESTS the lock) — so a player who dismissed with a key got no mouse look and
   a cannon that silently did nothing. Worse: in an ARENA the forward axis belongs solely to
   intent.throttle (player.js), so an untaught player coasts to a dead stop in front of L1's Mast
   Cell and reasonably concludes the game is broken. Six arenas across L1/L3/L5/LS are the same
   trap. The card now says CLICK TO FLY, takes the pointer lock on any dismissal, and prints the
   legend that has existed — written and styled — in flight/dev.html since round 1, visible only
   to whoever was running Lane B's harness.

2. DYING DELETED THE BOSS. boot's pump advanced `_ei` monotonically and never rewound. That
   reasoning is right for `spawn` and `pickup` (re-firing double-spawns survivors and resurrects
   banked pickups) but it silently applied to `boss` as well: die to any of the five, respawn,
   fly through an empty lair, cross the gate, and collect a graded medal for a fight that never
   happened. Dying was the fastest route past every boss in the game. Now a REARM set ({boss,
   acid}) re-fires on respawn while everything else is retired into `_spent`. Verified by event
   trace: start:mast_cell -> end:wipe -> start:mast_cell. Also despawns the sentinel's body on a
   wipe, which the fix exposed as a duplicate (1 -> 2 Mast Cells per death).

3. L1'S TIDE WAS UNWINNABLE, AND MINE. I authored it this morning at speed 5 in a flow-2 segment,
   reasoning "5 against 2 catches a dawdler". The player ceiling there is 2.8 u/s sustained
   (throttleMax 1.4 x flow 2); boost peaks 5.2 for 0.55s on a 2.4s cooldown. C's own --sim prints
   the verdict in plain text — "required 2.50x UNWINNABLE" — and I never ran it. Because
   hazards.js grazes on gap<=catchRadius and the gap stays negative once passed, it was a ~74 dps
   loop back onto the s=475 checkpoint: a brand-new player, in the default level, hard-stopped
   three minutes in. Retuned to 2.4 (required 1.20x — the same shape as L2's teaching burp).

   The validator was exempting it: `if (!c.lethal) continue` in levels/index.js meant qa.sh went
   green over a death loop. An unwinnable chase is a design failure whatever its lethality — a
   non-lethal one you cannot outrun is a continuous-damage trap. That exemption is gone, and all
   six levels still validate.

Also: DEFAULT_LEVEL was still 'L2_esophagus' from when L2 was the only finished level, so every
new player skipped the tutorial entirely and started mid-campaign. LANE_C_NOTES §→ Lane F #2
said "change it if you would rather it be L1". It is L1 now.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 19:04:25 +10:00
type-two
f9aeaf259f [lane B+C] L1 Oral Cavity: the tutorial, and the Mast Cell — the boss you win by not shooting
L1 has been a 2-event skeleton since round 1, waiting (in its own status field) on "Lane B's
arena-mode controller". That exists now, so C's round2_plan is built as written: molar
crush-cycles, the saliva tide, amylase droplets, the three samples exactly where C put them
(behind the molars / under the tongue / a tonsillar crypt), and the epiglottis exam. 24 events.

The teaching order is the level: move (orbs, no current) -> LOOK (the arena opens and you can
stop, which no other level allows) -> shoot (one droplet, then two) -> coat (the molar ring
grazes you, mucin is right there) -> RESTRAINT -> flow returns (the tide, the funnel) -> the
exam. Every verb alone, in the calmest room in the game, before anything is asked of it. Two
hazards are deliberately re-used rather than invented: the molar crush IS a ring_gate and the
saliva tide IS a non-lethal surge, so L2's gates and its reflux finale become callbacks instead
of new ideas.

THE MAST CELL (LANE_C_NOTES §Boss specs 5) sits at the exact midpoint. A sentinel immune cell:
cyan, no attack, no chase, inert aura (auraDps 0 — it shares the floater's drift branch and its
aura does literally nothing). Fly past and the encounter just ends. Shoot it and it degranulates
— droplets close in from the walls (which is how "the cavity swells shut" is expressed, because
a runtime tube radius is not in Lane A's contract), the coat bleeds, and past half health the
airway closes on a 25s timer. You always get through. The only question is what you get through.

It needed a new boss `kind: 'sentinel'` with its own update path, because forcing a thing with
no rings and no windows through the phase machine would have been worse than a branch. Damage is
the failure state, so every number describes a consequence rather than a fight.

Verified, all three player choices: SPARE -> "spared", coat untouched at 100, karma +25, score 0.
SHOOT -> "degranulated", coat 100->56. KILL -> "anaphylaxis-survived", coat 100->6. Score is 0 in
every case: shooting it buys literally nothing, so no medal can ever reward the mistake.

Two bugs the testing paid for: `def.phases[0]` crashed on a boss that has no phases, and the
first degranulation drain (5/s) was UNDER the player's 8/s coat regen — measured coat going
80 -> 100 during a histamine cascade, i.e. the punishment was healing you. Now 14 and 22, which
are net -6/s and -14/s against regen.

L1 is no longer a skeleton: its checkpoint-gap and zero-samples warnings are gone, and the
campaign now opens on a real tutorial instead of an empty mouth with a gate at the end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 00:13:52 +10:00
jing
2e85ec0622 [lane C] Round 2 WIP (session cut off): schema v2, surf-aware pacing, chase analysis, --probe
Landed before the cut: schema v2 (segments[].wave.amp override, validated — breathe stays
biome-owned); hiatus re-authored tight AND calm (radius back to 6.5, amp 0.6, 3.3u steady
clearance); par 210 -> 180 with full rationale (below throttle-only par-pace, above a surf
run — the medal teaches the mechanic); finale surge 21 -> 24 so surfing is the stylish
escape (required 1.20x); surf profile reads A's live CREST_FACTOR; chaseAnalysis() +
escapability laws in validate; NEW --probe builds A's real canal and measures clearance
against the model (all L2 segments clear the 2.5 floor, hiatus 3.75); isMain guard +
importSpline shim — fixes A's selfcheck process.exit killing C's mid-run (qa.sh had been
green on one level out of three).

Cut off before: fly-through of the integrated build (blocked on B), pickup economy handover
(B proposed numbers in balance.js meanwhile — reconcile), L1 encounter design doc, GDD boss
folding, NOTES. Committed by F to protect the shared tree; levels selfcheck 3/3 GREEN.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:26:42 +10:00
jing
1b5ec767cd [lane C] Round 1: schema v1, levels registry + selfcheck + pacing sim, L2 vertical slice
Data spine:
- Schema v1 ratified (TECH.md, C-owned). Additive over v0: schema/par/next, segment
  name, cross-section placement (theta/rho as a FRACTION of safe radius), spread, span,
  pickup+gate event types, hazard params. STUB_LEVEL synced (that const only, per
  ROUND1 §Lane C.1) — world.hash() unchanged (1bdf001), geometry provably untouched.
- levels/index.js: registry + loader (node+browser, no THREE), real schema selfcheck
  (qa's --selfcheck hook is now live) and a pacing simulator (--sim). Consumes the other
  lanes' contracts live rather than restating them: A's biomes.js for ids and
  wave.amp+breathe, A's SKIN, B's tuning.js hull radius, B's balance.js for scores.
- levels/enemies.js (fiction id -> archetype join table), levels/difficulty.js.

L2_esophagus — the vertical slice, complete: 3600 units, 7 beats, 47 events, 65 enemies,
10 checkpoints, 3 samples, reflux-surge finale. L1/L3 skeletons (shape only).
Anatomy is the level designer: the three real esophageal constrictions are the three
setpieces, and all three enemies are real esophageal pathology (bolus chunk, eosinophilic
esophagitis, candida esophagitis).

Measured (node web/js/levels/index.js --selfcheck|--sim; qa GREEN):
- selfcheck 3/3 valid, exit 0.
- pressure curve 0.27 -> 2.14 -> 4.35 -> 0.69 -> 4.53 -> 6.35 -> 4.40 (breather/pressure/
  spike/breather/pressure/peak/finale).
- par 3:30 vs measured 2:47 speedrun / 3:19 par-pace / 4:22 timid; par.score 9000 of a
  9400 kill budget (95%), computed from B's scores.
- all 10 checkpoint gaps within the <=30s death-cost law (max 28.8s); min clearance 2.73.

Two contract collisions found and resolved (LANE_C_NOTES):
- Biome ids: authored mouth/pharynx/cardia/pylorus; A's registry has six canonical ids and
  rejected all four. A is right — biome = look, segments[].name = anatomy. Conformed.
- Balance: my first enemies.js restated hp/size/speed/score that B owns in balance.js.
  Cut to a join table; index.js reads B's scores via scoreFor().

Caught live: A raised esophagus wave.amp 0.9 -> 1.4 mid-session, making the diaphragmatic
hiatus unflyable (2.33 vs the 2.5 floor). Widened 6.5 -> 6.8. The invariant also failed my
own aortic constriction's first draft (radius 7, symmetric squeeze) -> radius 9, directional.

No in-engine flythrough: ?stub=1&lvl= does not compose (snippet offered to F) and the stub
is single-segment, so it could only render beat 1. The pacing evidence is a kinematic model,
not a playtest — it proves L2 is flyable, paced and survivable, not that it feels good.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 08:53:34 +10:00