Skip to content

feat(m12): generator spike — grow a playable planet from the pair's rhythm - #23

Closed
ksdisch wants to merge 1 commit into
mainfrom
claude/project-status-review-p6ske4
Closed

feat(m12): generator spike — grow a playable planet from the pair's rhythm#23
ksdisch wants to merge 1 commit into
mainfrom
claude/project-status-review-p6ske4

Conversation

@ksdisch

@ksdisch ksdisch commented Jul 9, 2026

Copy link
Copy Markdown
Owner

What & why

The next step of the project's boldest vision, "The Planet That Knows You Two": stop hand-authoring planets and grow one from a recorded portrait of how this specific pair plays. M10 shipped the de-risked wedge (schema-v2 per-role solve telemetry + the read-only portrait card); nothing yet consumed that telemetry. This spike closes that gap — telemetry → a PlanetConfig you can actually play.

The honest risk the vision doc names is that a generator "dynamites the rigid PlanetConfig" the codebase's safety rests on — "one bad planet ruins the evening." So the crux deliverable here isn't a generated planet, it's a proof the generator can never emit an unplayable one.

Changes

  • New src/game/planets/generate.ts (pure, deterministic):
    • deriveProfile(telemetry)RhythmProfile — aggregates the pair's recorded rhythm (solve speed, respawn history, explore-vs-solve split) into normalized 0..1 signals + a stable seed. Never throws; empty/solo/corrupt telemetry → a neutral default.
    • generatePlanet(profile)PlanetConfig — maps those signals to geometry knobs, each clamped to a band proven valid against the shared reach budget, so the output is always clearable. Seeded mulberry32 for within-band variety (no Date.now/Math.random, per the Vitest determinism guards). Themeless (default textures, zero Boot churn); planet-3 gate template (Freeze corridor → Phase Dash curtain → Illuminate finale).
  • New src/game/planets/generate.test.ts — the safety proof: a property sweep of 1000 configs (profile grid × seeds) plus corrupt/extreme inputs, asserting every generated config satisfies the same invariants planet3.test.ts encodes (full-height curtain, Illuminate finale reach math, in-canvas keypoints, degenerate-or-≥260 pit); determinism; and deriveProfile never throwing on a hostile blob.
  • src/game/scenes/Hub.ts — a "✦ Grow a planet" node derives from loadProgress().telemetry and launches the generated config via scene-data (Planet.init takes a raw config, so no registry mutation, no progression coupling).
  • src/game/testBridge.ts — adds startGeneratedPlanet() so a headless driver can clear a grown planet through the usual getState/cast/input loop.

Verification

  • npm run typecheck ✓ · npm run test 168 passed (+12 new) ✓ · npm run build ✓ · npm run smoke:relay
  • Headless full clear of a generated planet (pre-installed Chromium, ?solo=1&test=1): startGeneratedPlanet() → boots into the Planet scene → Freeze freezes the sentry → Phase Dash crosses the curtain → Illuminate reveals the ledge → reaches the goal. won=true, 0 respawns, win cue fired, telemetry recorded (attempts:1, lastClearMs:4881).

Deliberate spike cuts

  • Themeless — theme selection needs Boot preload textures; noted follow-up.
  • One gate template (planet-3's) — proving the pipeline, not a template library.
  • Not a registry/progression node — a launch target only; it doesn't record telemetry back (keeps the spike one-way: telemetry → planet).
  • No protocol/relay/src/shared/phone/dependency changes.

Does the grown planet feel like ours? That's the human gate the vision doc names — the spike earns the right to ask it, it can't self-answer it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Pm5HnAqLxtzGYMo6cFxRrt


Generated by Claude Code

…hythm

The next step of "The Planet That Knows You Two" (docs/ideas): consume the
M10 telemetry wedge to grow a PlanetConfig from how this pair actually plays.

- New pure src/game/planets/generate.ts: deriveProfile(telemetry) -> RhythmProfile
  and generatePlanet(profile) -> PlanetConfig. Deterministic (seeded mulberry32;
  no Date.now/Math.random). Every geometry knob is clamped to a band proven valid
  against the shared reach budget, so the output is ALWAYS playable for any input.
  Themeless (default textures, zero Boot churn); planet-3 gate template
  (Freeze corridor -> Phase Dash curtain -> Illuminate finale).
- New generate.test.ts: the safety proof — a property sweep (1000 configs over a
  profile grid x seeds, plus corrupt/extreme inputs) asserting every generated
  config satisfies the SAME invariants planet3.test.ts encodes; determinism; and
  deriveProfile never throws on a hostile telemetry blob.
- Hub: a "Grow a planet" node derives from loadProgress().telemetry and launches
  the generated config via scene-data (Planet.init takes a raw config — no registry
  mutation). testBridge gains startGeneratedPlanet() for headless verification.

Gated on typecheck + 168 Vitest (+12) + build + smoke:relay. Headless-verified on
the pre-installed Chromium: startGeneratedPlanet() -> full clear (freeze -> phase ->
illuminate -> goal), won=true, 0 respawns, win cue + telemetry recorded.

Deliberate spike cuts: themeless (theme selection needs Boot preload textures);
one gate template; not a registry/progression node; no protocol/relay/shared/phone/
dependency changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pm5HnAqLxtzGYMo6cFxRrt
@ksdisch

ksdisch commented Aug 1, 2026

Copy link
Copy Markdown
Owner Author

Closing per 2026-08-01 PR triage: M12 generator spike idle since 2026-07-12, mergeable state unknown. The spike's value is the recorded design in the PR body, which survives closure. The branch survives if this is ever picked back up.

@ksdisch ksdisch closed this Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants