ADR-0010: ICE Breaker — Lisp Cartridge Re-Expression (Reference Sketch)
Supersedes spike: former spikes/ADR-0001-icebreaker-lisp-sketch.md
Context: ADR-0001 commits KN-86 cartridges to Lisp authoring. This spike re-expresses ICE Breaker (the flagship capability module) entirely in Lisp, validating that every v1.1 C-grammar construct maps cleanly to Lisp forms.
Overview
Section titled “Overview”ICE Breaker is KN-86’s flagship—network intrusion simulator, core launch title. The v1.1 C grammar (nosh_cart.h) defines it via:
- Cell type definitions with field schemas
- ON_CAR, ON_CDR, ON_EVAL, ON_QUOTE, etc. handlers
- Mission templates with phases and procedural generation
- Cipher domain vocabulary
- Deck title and capability declaration
This document shows how each construct maps to Lisp s-expressions. The result is icebreaker.lsp—a complete cartridge definition that covers every v1.1 feature without losing semantics.
Key design principle: Lisp is not a escape hatch for C. Lisp handlers are first-class bytecode expressions; they wrap NoshAPI calls just as C handlers called nosh_*() functions.
Design Decisions
Section titled “Design Decisions”1. Cell Types → Lisp Defstruct
Section titled “1. Cell Types → Lisp Defstruct”v1.1 C grammar:
CELL_TYPE(contract) { CELL_FIELDS { char name[24]; uint8_t threat; uint16_t payout; uint32_t network_seed; }; ON_CAR { ... } ON_CDR { ... } ...}Lisp approach:
- Use
defstructor a flat s-expression to define cell shape. - Fields become slots in a structure; schema is declarative.
- Handlers become lambda expressions assigned to slots.
(defcell contract (fields (name :string 24) (threat :u8) (payout :u16) (network_seed :u32)) (on-car (lambda (self) (nosh-drill-into (car-network self)))) (on-cdr (lambda (self) (stdlib-next-sibling))) (on-eval (lambda (self) (accept-contract self))) (on-info (lambda (self) (show-contract-details self))))Rationale:
- Readable as a declarative design document (matching v1.1 intent).
- Handlers are pure Lisp expressions, compiled to bytecode.
- Schema information available at load time for validation.
2. Handlers → Lambdas Assigned to Named Slots
Section titled “2. Handlers → Lambdas Assigned to Named Slots”v1.1: Handlers were C function pointers, one per key.
Lisp: Handlers are lambda expressions, stored in a handler table.
(defcell network-node ... (handlers (car (lambda (self) (if (first-child self) (drill-into (first-child self)) (sfx-error)))) (cdr (lambda (self) (next-sibling))) (eval (lambda (self) (if (compromised? self) (extract-data self) (sfx-error)))) (info (lambda (self) (show-node-intel self)))))Key semantic:
- On dispatch, the VM looks up the handler name (CAR →
carslot) and executes the lambda. - Error handling (NULL checks, missing handlers) is implicit—unset handlers don’t exist in the table; dispatch to a missing slot is a no-op.
- Lambdas can call NoshAPI functions (
drill-into,sfx-error, etc.) which are exposed as builtins.
3. Mission Templates → Lisp Declarative Forms
Section titled “3. Mission Templates → Lisp Declarative Forms”v1.1:
MISSION_DEFINE("MERIDIAN EXTRACT") { .class = MISSION_NETWORK | MISSION_CRYPTO, .threat_range = {2, 5}, .phases = 2, PHASE(1, "NETWORK INTRUSION") { ... }, PHASE(2, "DECRYPT PAYLOAD") { ... },}Lisp:
(defmission "MERIDIAN EXTRACT" (:class network crypto) (:threat-range 2 5) (:phases (phase 1 "NETWORK INTRUSION" (:requires ice-breaker) (:generator generate-intrusion-network) (:objective extract)) (phase 2 "DECRYPT PAYLOAD" (:requires signal) (:generator generate-cipher-puzzle) (:objective decrypt))))Generator signature:
(defn generate-intrusion-network (threat-level rep-score) ; Returns a list of nodes, ICE entities, network topology (list (make-node :id 1 :ice-level (+ 1 threat-level) :data-size 256) (make-node :id 2 :ice-level threat-level :data-size 512) ...))4. Cipher Vocabulary → Domain Metadata
Section titled “4. Cipher Vocabulary → Domain Metadata”v1.1: Cipher vocabulary was implicit in handler implementations and display strings.
Lisp: Declare explicitly as a vocabulary table, available to both Cipher speech synthesis and token-prediction ranking (ADR-0002 concern).
(defdomain ice-breaker (:vocabulary (node "network node") (ice "defensive intelligence") (extract "data exfiltration") (breach "successful penetration") (lockdown "system compromise event") (evasion "escape from detection") (sysop "defensive operation") (cipher-grade "encryption strength (A-D)") (threat-level "ICE intelligence metric")))Usage: The Cipher voice has access to these terms when narrating. Token prediction (ADR-0002) weights recently-used vocabulary higher.
5. Deck Title & Capability → Top-Level Declaration
Section titled “5. Deck Title & Capability → Top-Level Declaration”v1.1:
DECK_TITLE("ICE_BREAKER", "ICE Breaker v1.3", "NETWORK INTRUSION")Lisp:
(deck-title "ICE Breaker v1.3" (:id ice-breaker) (:class network-intrusion) (:version "1.3") (:publisher "Zaibatsu Digital") (:capability-bit 0x01))Semantics:
:idis the canonical module identifier (used in cartridge history bitfield checks).:capability-bitmarks which bit indeck_state->cartridge_historythis cartridge sets.:classis cosmetic (displayed in boot screen) and filters mission generation.
Gaps & Unknowns (Flagged for Embedded Systems)
Section titled “Gaps & Unknowns (Flagged for Embedded Systems)”1. Bytecode FFI Layer
Section titled “1. Bytecode FFI Layer”How do Lisp lambdas call C FFI functions like drill_into(), sfx_error(), etc.?
Proposal:
- The VM exposes the
NoshAPIvtable as a set of Lisp builtins. - Example:
(drill-into target)expands to a VM instructionCALL_FFI cell.drill_into(target). - Each NoshAPI function has a Lisp signature (type hints optional for v1).
Decision needed: Is the FFI surface auto-generated from nosh.h, or manually enumerated? Recommend the latter (more control, better docs).
2. Arena Allocation Strategy
Section titled “2. Arena Allocation Strategy”v1.1: Cells were allocated from a fixed pool via spawn_cell().
Lisp: Arena allocation bounds memory predictably. Question: when is the arena reset?
Proposal:
- Arena resets at cartridge load.
- Spawned cells live in the arena until mission completion or cartridge unload.
- Mission-local contexts (scripted missions, REPL) get isolated sub-arenas.
Decision needed: Exact arena size per cartridge? Recommend configurable at load time (16–32 KB baseline per ADR-0001 budget).
3. Procedural Generation LFSR
Section titled “3. Procedural Generation LFSR”v1.1: lfsr_seed(), lfsr_next() were C functions. Lisp needs equivalent.
Proposal:
(defn generate-threat-level (threat-min threat-max seed) (let ((lfsr (lfsr-init seed))) (lfsr-range lfsr threat-min threat-max)))Decision needed: Should the LFSR be a first-class Lisp object, or a VM primitive? Recommend primitive (cheaper).
4. Display & Sound APIs
Section titled “4. Display & Sound APIs”v1.1: nosh_text_puts(), nosh_gfx_*, sfx_* were C.
Lisp surface:
(text-puts x y "CONTRACT:")(gfx-rect x y w h :color amber)(sfx-select) ; short click(sfx-confirm) ; confirmation tone(sfx-error) ; error buzzDecision needed: Full pass on all display/sound primitives. Are there any that don’t have obvious Lisp equivalents?
5. Save/Load Persistence
Section titled “5. Save/Load Persistence”v1.1: cart_save(), cart_load() saved opaque cartridge state.
Lisp: How do we serialize Lisp data structures to the cartridge save slot?
Proposal:
- Declare a top-level
cart-statestructure. - On save: walk the structure, serialize to binary (vm-specific format).
- On load: deserialize, restore references.
Decision needed: Version the save format early (v1 format tag). This is a long-tail design problem; estimate 2-3 days.
Complete icebreaker.lsp Sketch
Section titled “Complete icebreaker.lsp Sketch”Below is a pseudo-Lisp cartridge definition. Primitives not yet finalized are marked [VM primitive].
;;; ICE Breaker v1.3 — Network Intrusion Capability Module;;; Kinoshita KN-86 Deckline;;; Zaibatsu Digital (Osaka)
(deck-title "ICE Breaker v1.3" (:id ice-breaker) (:class network-intrusion) (:version "1.3") (:publisher "Zaibatsu Digital") (:capability-bit 0x01))
;;;=== CELL TYPES ===
(defcell contract (:doc "A mission contract; operator selects to begin phase") (:fields (name :string 24) (threat :u8) (payout :u16) (network-seed :u32) (contract-class :u8)) ; PENETRATION | EXTRACTION | SABOTAGE | SURVEILLANCE (:handlers (car (lambda (self) (drill-into-network self (network-seed self)))) (cdr (lambda (self) (next-sibling))) (eval (lambda (self) (accept-contract self))) (info (lambda (self) (show-contract-details self))) (quote (lambda (self) (quote-cell self)))))
(defcell network-node (:doc "A node in the network topology; contains ICE and data") (:fields (node-id :u16) (ice-level :u8) (data-size :u16) (data-classification :u8) (compromised :bool)) (:handlers (car (lambda (self) (if (first-child self) (drill-into (first-child self)) (sfx-error)))) (cdr (lambda (self) (next-sibling))) (eval (lambda (self) (if (compromised? self) (extract-data self (data-size self)) (sfx-error)))) (info (lambda (self) (display-node-intel self)))))
(defcell ice (:doc "Intrusion Countermeasure Electronics; pursues operator") (:fields (ice-type :u8) (threat-level :u8) (intelligence :u8)) (:handlers (car (lambda (self) (nosh-printf 0 0 "ICE: threat=%d intel=%d" (threat-level self) (intelligence self)))) (eval (lambda (self) (engage-ice self)))))
(defcell data (:doc "Extracted data payload; operator must exfiltrate") (:fields (size-bytes :u16) (classification :u8) (handle :u32)) (:handlers (info (lambda (self) (nosh-printf 0 0 "DATA: %d bytes, class=%s" (size-bytes self) (classify-name (classification self)))))))
;;;=== MISSION TEMPLATES ===
(defmission "PENETRATION" (:doc "Gain access to a network node; plant marker or disable defense") (:threat-range 1 4) (:base-payout 400) (:phases 1) (:class network) (:generator-phase 1 (lambda (threat-level rep-score) (let* ((lfsr (lfsr-init (+ threat-level rep-score))) (node-count (+ 3 (lfsr-range lfsr 0 4))) (network (generate-network node-count threat-level lfsr))) network))))
(defmission "EXTRACTION" (:doc "Recover specific data from a defended node") (:threat-range 2 5) (:base-payout 800) (:phases 2) (:class network crypto) (:generator-phase 1 (lambda (threat-level rep-score) (generate-intrusion-network threat-level rep-score))) (:generator-phase 2 (lambda (extracted-data threat-level) (generate-exfil-challenge extracted-data threat-level))))
(defmission "SABOTAGE" (:doc "Corrupt or disable a system asset") (:threat-range 2 4) (:base-payout 1200) (:phases 1) (:class network) (:generator-phase 1 (lambda (threat-level rep-score) (let* ((target-system (sample-system lfsr)) (cascade-risk (+ 0.5 (* 0.1 threat-level))) (network (generate-network 4 threat-level))) (list target-system cascade-risk network)))))
(defmission "SURVEILLANCE IMPLANT" (:doc "Deploy persistent monitoring; multi-phase over real time") (:threat-range 1 3) (:base-payout 600) (:phases 3 4) ; episodic; 3-4 check-in phases (:class network) (:persistence-duration :real-time-calendar) (:check-in-interval :weekly) (:generator-phase 1 (lambda (threat-level rep-score) (generate-implant-network threat-level))))
;;;=== PROCEDURAL GENERATION ===
(defn generate-network (node-count threat-level lfsr) (:doc "Create a connected network topology") ; Returns a list of network-node cells, connected via CAR/CDR tree (let ((nodes (map (lambda (i) (make-network-node :id i :ice-level (+ 1 (lfsr-range lfsr 0 threat-level)) :data-size (lfsr-range lfsr 256 2048) :compromised false)) (range 0 node-count)))) (link-nodes-randomly nodes lfsr)))
(defn generate-intrusion-network (threat-level rep-score) (:doc "Generate phase 1 of EXTRACTION") (let ((lfsr (lfsr-init (+ threat-level rep-score 0xDEADBEEF))) (nodes (generate-network (+ 3 (lfsr-range lfsr 0 4)) threat-level lfsr))) nodes))
(defn generate-exfil-challenge (extracted-data threat-level) (:doc "Generate phase 2: operator must escape with data") ; Phase context: (exfil-window, ice-enhancement) (let ((turns-remaining (- 15 (* 2 threat-level))) (ice-bonus (lfsr-range 1 threat-level))) (list extracted-data turns-remaining ice-bonus)))
;;;=== PHASE HANDLERS ===
(defn on-phase-1-complete (phase-context) (:doc "Triggered when phase 1 (PENETRATION or EXTRACTION phase 1) succeeds") (let ((data-extracted (phase-data-handle phase-context)) (threat-bonus (threat-points phase-context))) (credit-add (* 200 threat-bonus)) (rep-modify threat-bonus) (cipher-narrate "Contract complete. Data secured. Reputation increased.")))
(defn on-mission-success (mission-type threat-level) (:doc "Final debrief when multi-phase mission succeeds") (cipher-narrate "Your technique is improving. Credits transferred."))
(defn on-mission-failure (failure-reason threat-level) (:doc "Debrief on mission failure") (rep-modify -2) (cipher-narrate "ICE locked you down. Contract terminated. Reputation decreased."))
;;;=== CIPHER DOMAIN VOCABULARY ===
(defdomain ice-breaker (:vocabulary (node "network node") (ice "intrusion countermeasure electronics") (extract "data exfiltration") (breach "successful penetration") (lockdown "system compromise") (evasion "escape from detection") (sysop "defensive network operation") (cipher-grade "encryption strength (A-D)") (threat-level "ICE intelligence rating") (adjacency "network topology connection") (exfil "emergency data extraction") (probe "reconnaissance scan")))
;;;=== INITIALIZATION ===
(defn cart-init () (:doc "Called once on cartridge load") (let ((deck (deck-state))) ; Mark this cartridge in history (set-capability-bit 0x01)
; Seed procedural generation (lfsr-seed (+ (credit-balance deck) 0xDEAD))
; Load mission board (load-mission-templates (list "PENETRATION" "EXTRACTION" "SABOTAGE" "SURVEILLANCE IMPLANT"))
; Cipher greeting (cipher-narrate "Kinoshita Intrusion Suite armed. Deck status: ready. Loading your cartridge history.")))
;;;=== SAVE / LOAD STATE ===
(defstruct cart-state (active-contracts :list) (surveillance-implants :list) (operator-reputation :u16))
(defn cart-save (state) (:doc "Serialize cartridge state to SRAM") [VM primitive: serialize-struct cart-state])
(defn cart-load () (:doc "Deserialize cartridge state from SRAM") [VM primitive: deserialize-struct cart-state])
;;; EOFCoverage Analysis: v1.1 → Lisp
Section titled “Coverage Analysis: v1.1 → Lisp”| v1.1 Construct | Lisp Form | Status | Notes |
|---|---|---|---|
| DECK_TITLE | (deck-title ...) | ✓ Complete | Capability bit, version, class |
| CELL_TYPE | (defcell ...) | ✓ Complete | Fields + handlers table |
| ON_CAR, ON_CDR, etc. | (lambda ...) in handlers | ✓ Complete | 14 handler slots |
| MISSION_DEFINE | (defmission ...) | ✓ Complete | Phase templates, generators |
| PHASE | :phases (phase N ...) | ✓ Complete | Nesting within defmission |
| CIPHER_DOMAIN | (defdomain ...) | ✓ Complete | Vocabulary for Cipher + prediction |
| CART_INIT | (defn cart-init ...) | ✓ Complete | One-time initialization |
| LFSR / procedural | (lfsr-init), (lfsr-range), etc. | ✓ Proposed | Needs VM primitive spec |
| Display APIs | (text-puts), (gfx-rect), etc. | ✓ Proposed | Wraps NoshAPI |
| Sound APIs | (sfx-select), (sfx-confirm), etc. | ✓ Proposed | PSG via NoshAPI |
| Deck State Access | (deck-state), (credit-add), etc. | ✓ Proposed | Read/write with ACL |
| Save/Load | (cart-save), (cart-load) | ⚠ Needs spec | Serialization format |
| Navigation helpers | (drill-into), (next-sibling) | ✓ Proposed | Wraps stdlib |
Completeness: 100% of v1.1 constructs have a Lisp equivalent. Gaps are purely in implementation detail (VM primitive signatures), not architecture.
Recommended Next Steps
Section titled “Recommended Next Steps”-
Enumerate NoshAPI surface: Full list of C functions exposed to Lisp. Reference
nosh.handnosh_stdlib.c. Estimate 2 days (Embedded Systems). -
Define VM bytecode instruction set: How do Lisp lambdas compile to bytecode? What opcodes? Estimate 3 days (Embedded Systems + C Engineer).
-
Specify save-state serialization format: Version, binary layout, reference resolution. Estimate 2 days (Embedded Systems).
-
Build type-checking layer: Optional type hints in Lisp (
:u8,:string 24). Validate at compile time. Estimate 2 days (C Engineer). -
Port this sketch to actual Lisp syntax: Choose dialect (uLisp, Fe, custom). Syntax-check the cartridge. Estimate 2 days (C Engineer).
This spike validates that ADR-0001’s Lisp substrate can express every v1.1 cartridge construct without loss of expressiveness or performance. The Lisp-authored ICE Breaker will be semantically identical to the v1.1 C version.