3.0 cyberspace!#12
Merged
Merged
Conversation
3f6a530 to
e497c47
Compare
DATA_NODE_SLICE objective kind with cross-validated requiresCyberspace/count params, cyber-data-spike recipe gated on Act 2+ with a living Decker (availableWhen filter across all three generation paths), Campaign hasLivingDecker getter + loud deploy gate, and NEEDS DECKER row gating in the briefing crew list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
JackInPoint interactable (Ω) placed for data-node-slice contracts: Decker-only capability sniff, linked latch with logged (never thrown) redundant input, one-shot EVENT.JACK_IN emit. Run latches a dormant cyberspace state machine at briefing; snapshot/restore enforce the block ⇔ cyber-contract invariant and throw on unknown phases, dormant payload smuggling, or missing linked state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Records the four scope decisions, S1/S2 implementation notes (shipped), approved architecture for S3-S7, and verified research notes so the Cyberspace effort can resume cold at S3. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
S3 of the cyberspace slice plan. The digital layer exists and round-trips:
- cyberMapBuild: deterministic node-lattice generator (spanning random walk
over a 4×2 cell lattice, rooms + L-corridors, FLOOR/WALL only), seeded
from the contract via Rng.fork('cyberspace') so layout is independent of
jack-in turn. Connectivity flood-validated; unreachable port/node throws.
- CyberAvatar (Entity subclass): maxHp = Decker RAM, damageReduction = ICE
resistance, carries intrusionStrength + callsign, baseHitChance 0.8,
isCyberAvatar capability flag.
- EntryPort interactable: avatar-only interact emits JACK_OUT (resolve
latch lives on Run.cyberspace, not the port).
- CyberspaceLayer: own bus + World, build/restore ctors, onTurnEnded AP
refresh + alarm tick driven by the single meat TurnQueue, mapSeen.
- Run: CyberspaceState active/resolved phases, cyberActive/activeWorld/
activeActor accessors, jackIn/jackOut with throw-on-illegal-phase,
cyber ENTITY_DAMAGED listener (avatar death → RESULT/DEATH flatline),
snapshot block for all three phases.
- persistence: restoreCyberspace with full adversarial throw matrix
(allowed-keys per phase, grid/tile validation, exactly-one avatar/port,
bounds checks against the cyber grid); Decker cyber stats persist via
both crew paths (campaign snapshot + run-entity extra), absent → base
defaults, partial → throw.
- Decker: ram/intrusionStrength/iceResistance fields with ctor validation
and DECKER_BASE_* constants (scope decision #4 — named stats, real
effects).
49 new tests under tests/unit/game/cyber/ (failing-first verified).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
S4 of the cyberspace slice plan. The layer now has a reason to exist: - DataNode interactable (glyph ◈): interact adds the actor's intrusionStrength to sliceProgress; sliced at sliceDifficulty (2/3/4 by contract difficulty). Avatar-only via the isCyberAvatar sniff — the Decker body also carries intrusionStrength, so the stat is not the capability. Slicing is silent; ICE detection (S6) owns the cyber alarm. Progress is raw (never clamped) so persisted state loses nothing. - CyberspaceLayer.build gains required nodeCount (the contract objective's count — required, not defaulted, so a divergence can't silently corrupt the objective) and spawns nodes on the farthest node anchors from entry, Chebyshev-sorted stable over the deterministic generator order. - Run: ObjectiveState.cyber tally threaded per phase (live count while active, the resolved latch after jack-out, zero while dormant); DATA_NODE_SLICE satisfaction counts sliced >= required; jackOut latches objectiveComplete from the real tally — jacking out early leaves the objective permanently unsatisfiable and extraction gated through the existing abort-confirm flow (zero new extraction code). - objectiveProgress: dataNodeProgress helper + NODES HUD chip; the chip pipeline is kind-generic so no shell changes needed. - persistence: data-node entity codec (label/sliceDifficulty/sliceProgress, malformed throws); active cyberspace blocks must carry exactly the contract's node count (nodes never despawn — any drift is corruption). 25 new tests (dataNode.test.ts, dataNodeObjective.test.ts; failing-first verified), suite at 1629 green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The P3.M4.6 pull-forward (scope decision #2), completing what S3/S4 started (resolve latch, teardown, autosave, objective tally): - JackInPoint gains the `burned` latch: `Run.jackOut()` burns the meat-side port when the avatar routes out, so re-jack-in is refused with dedicated flavor (`link-burned` / "LINK BURNED — the connection is dead") instead of the redundant-input 'already-linked'. `burn()` on an unlinked port throws (corrupt state), as does constructing one. - Snapshot extra carries `burned`; pre-S5 records restore unburned (legacy normalization), non-boolean or burned-without-linked throws. - Coverage audit of the planned S5 matrix: jackOut from dormant / on a non-cyber contract throws (new); resolved latching both ways, post-jack- out round-trip, and resolved-block smuggling were already locked by S3/S4 tests. 8 new tests (jackOut.test.ts; failing-first verified), suite at 1637 green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
S6 of the cyberspace slice plan:
- ProbeIce (glyph ¶, displayName Probe) extends PatrolHostile: explicit
small stats (hp 3, melee dmg 1, sight 6 — ICE scaling is its own axis,
resolveEnemyStats tiers deliberately unused). EngageSteps = trace flare
then Guard-style close-and-strike: raiseAlarm({repPenalty: false}) on
the *cyber* world self-gates while ALERT, so the 'trace-alarm' step
fires once per alarm window; probes listen for alarms (PatrolHostile
default, unlike the Lookout) so one flare converges the pack.
- CyberspaceLayer.build spawns one probe per patrol ring at a seed-picked
ring tile (pure function of the contract seed) and binds it to the
layer bus; the restore path was already re-binding PatrolHostiles.
- Registry plumbing: 'probe-ice' joins PATROL_ARCHETYPE_IDS (shares the
generic patrol snapshot/restore machinery wholesale), archetypeOf,
SNAPSHOT_EXTRACTORS, ARCHETYPE_FACTORY, kindFromId; 'trace-alarm' step
type + corp-turn status copy line.
- Death paths proven through the real combat pipeline (no synthetic
emits): probe melee on a 1-hp avatar → RESULT/DEATH with cause; avatar
killing a probe counts in run telemetry. ICE resistance mitigation
locked to the min-1 rule (dmg 1 vs resist 1 → 1).
- Cyber alarm verified decoupled from Meatspace (no ALARM on the meat
bus, meat latch untouched) and ticking on meat round advances.
9 new tests (ProbeIce.test.ts; failing-first verified), suite 1646 green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cyber tileset axis in palette (glyphForTile tileset param, throws on unknown), buildFrame/AsciiRenderer threading, RAM-labeled avatar HUD, // THE GRID // location line, active-view seam (run.activeWorld / activeActor) through applyIntent + look/describe + vision, and the chained dual-phase corp turn (meat hostiles, then ICE) locked by dualPhaseTurn.test.ts shared-rng order assertions. kaizen.md: index.ts complexity findings recorded for post-M3 cleanup (ShellScene casts, statusLine extraction, listener rewire dedupe, bus listener-order coupling, active-view seam enforcement). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
buildScoreContract now emits kind DATA_NODE_SLICE with
{requiresCyberspace: true, count: 1} (Rylee's call: the Score always
has a Cyberspace component, for now). P3.M1.7 tests deploy the
Decker through the living-Decker gate and lock the objective shape.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An incomplete jack-out is irreversible (LINK BURNED + objective latched
unsatisfiable) but resolved with zero warning. Run.jackOut now defers to
onJackOutRequested when the objective is incomplete (mirror of the
onAbortRequested seam; no callback → resolve immediately, same harness
posture); run.confirmJackOut() finalizes, throwing on illegal states —
unlike confirmAbort there is no legal request-voiding race, so a stale
confirm is a wiring bug. A complete jack-out never asks.
Shell: confirmation modal context 'jack-out-early' with link-burn copy;
JACK_OUT bus handler skips the Meatspace swap while the layer is still
live (deferred); completeJackOutShellSwap shared by both resolve paths.
wireRunConfirmations extracted and now also called on campaign resume —
restored runs previously lost onAbortRequested entirely, silently
skipping the abort-extraction confirm after any mid-run reload.
EntryPort success copy neutralized ("routing out…") since the port no
longer knows whether the link actually dropped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Whew, this turned out to be pretty chunky