This plan implements the features described in in/in-4.md through
in/in-7.md, plus the CNF-2 and canonical interning semantics in
in/in-9.md through in/in-14.md, the milestone-gated testing workflow in
in/in-15.md, the homomorphic collapse contract in in/in-16.md, and the
conceptual contract in in/in-17.md, the Min(Prism) projection commutation
track in in/in-18.md, the topos/sheaf formalization in in/in-19.md, the
hyperlattice/Cayley-Dickson framing in in/in-20.md, and the semantic
justification patches in in/in-21.md through in/in-25.md (gauge symmetry,
canonical novelty, hyperoperator fixed points, ordinal boundary), plus the
Agda proof roadmap in in/in-26.md, as a concrete evolution of the current
prism_vm.py implementation. The commutation glossary in in/glossary.md is
normative for ambiguous terms and test obligations.
Each in/in-*.md note now includes a short NOTE header indicating whether it
has been refined, consolidated, or obsoleted. See audit_in_versions.md for
the current cross-version audit.
- Establish the Ledger + candidate pipeline as the canonical execution path.
- Converge on CNF-2 symmetric rewrite semantics with a fixed-arity candidate pipeline (slot1 enabled from m2; hyperstrata visibility enforced under test guards).
- Enforce univalence: full-key equality for interning and no truncation aliasing.
- Introduce self-hosted CD coordinates as interned CNF-2 objects and define aggregation as coordinate-space normalization.
- Preserve a stable, testable baseline while the new mode is built out.
- Stage arena scheduling and 2:1 BSP locality as performance-only concerns.
- Full hierarchical arena migration across levels (L1/L2/global).
- Perfect allocator for all graph rewrite rules beyond ADD.
- Full macro system or higher-order quotation semantics.
- Persistent event-log storage or snapshotting for CQRS beyond in-memory.
- Treating 2:1 locality as a semantic invariant before functional correctness is locked down.
- Ordinal-indexed termination proofs or proof-theoretic strength claims.
prism_vm.py uses a stable heap (Manifest) with:
opcode,arg1,arg2,active_countarrays.- Hash-consing via
trace_cache(hint-only; no retroactive pointer rewrites). - Static optimization and branchless dispatch (
optimize_ptr,dispatch_kernel). kernel_addand a stubkernel_mul.
Ledger + candidate pipeline is the canonical execution path. Baseline
PrismVM stays as an oracle. Arena scheduling is performance-only and must be
denotation-invariant with respect to the Ledger CNF-2 engine; minimal scheduler
variants are required by m3 for invariance tests, while performance-grade
locality begins at m4+.
Ledger denotation is the spec; ID equality is engine-local until baseline
migrates to the Ledger interner.
These are already in effect in code/tests and are treated as non-negotiable.
- Canonical identity is ledger interning; interning is semantic compression (no reclamation of unique structure).
- Univalence is enforced by full key-byte equality and a semantic id cap.
- CORRUPT is a hard semantic error (alias risk); OOM is a resource boundary.
- Sorting/swizzling and scheduling are renormalization only and must not
affect denotation after
q. - BSPˢ is a gauge symmetry: any BSPˢ effect must be erased by
q.
- CNF-2 symmetric rewrite semantics are the target for BSP. Every rewrite site emits exactly two candidate slots (enabled or disabled).
- Slot1 continuation is enabled at m2; hyperstrata visibility is enforced under test guards (m3 normative) to justify continuation.
- m1 uses the intrinsic cycle path; CNF-2 pipeline is gated off until m2.
- Univalence is enforced by full-key equality (hash as hint only) and no truncation aliasing in key encoding.
- CD coordinates are interned CNF-2 objects (
OP_COORD_*), and coordinate equality is pointer equality. - Evaluator (Manifest/Arena) and Canonicalizer (Ledger) are linked by a total
quotient map
q; denotation is defined by projecting provisional nodes throughqand must commute with scheduling (seein/in-16.md).qis an irreversible coarse-graining boundary, not an evaluator or scheduling step. - Reserved glyphs/roles are normative:
qis meaning-forming projection,σdenotes BSPˢ permutation (gauge), andρdenotes pointer/id remaps induced by renormalization. Never describeσorρasq. - Glossary adjunction/coherence discipline is normative: any new polysemous term must declare axes, commutation equations, and test obligations.
- Entropy terms are semantic descriptors (Arena vs canonical vs hyperoperator vs gauge); do not add counters unless a test explicitly requires it.
- Hyperstrata visibility rule is normative from m2 for CNF-2 slot1: pre-step rows
are immutable during a cycle, and within-cycle visibility is defined by the
(s,t)staging order; the frozen read model is the hyperstrata collapse corollary. - 2:1 BSP swizzle/locality is staged as a performance invariant:
- m1-m2: rank-only sort (or no sort) is acceptable for correctness tests.
- m3: denotation invariance must hold across unsorted/rank/morton/block scheduler variants (even if slow).
- m4+: 2:1 swizzle is mandatory for the performance profile, but must not change denotation (same canonical ids/decoded normal forms).
- Baseline
PrismVMis a regression implementation through m3; comparisons are on decoded normal forms and termination behavior, not raw ids. - Canonical novelty monotonicity and hyperoperator representation fixed points
are semantic justifications (m3-m4); they do not imply termination and do
not require operational counters (see
in/in-22.mdthroughin/in-25.md). These claims are scoped to the pre-CORRUPT (id-cap) regime. - Min(Prism) witness principle: semantic invariants proved under projection
π_Kare treated as representative at scale (m3+).
- No-copy sharing and alpha-equivalence collapse (see placeholder tests).
- Binding without names (structural or coordinate-based encoding).
- Damage/locality instrumentation as a performance-only concern (m4+).
Univalence = no ambiguity of identity. A proposed node maps to exactly one canonical node iff its full encoded key bytes are identical. Hashing, sorting, or indexing strategies may accelerate lookup, but equality is decided only by full key-byte equality.
Univalence does not require the absence of hash collisions; it requires that collisions never introduce ambiguity. Full-key comparison (or structurally collision-free indexing) is mandatory.
For every interned node, define a canonical key K after canonicalization:
K = encode(op)
|| encode(rep(a1))
|| encode(rep(a2))
|| encode(extra(op))
Where:
rep(id)= canonical representative ofid- equals
idin m1–m3 - becomes
find(id)if rewrite-union is introduced later
- equals
- Commutative ops (
ADD, later others):- sort
(rep(a1), rep(a2))before encoding
- sort
extra(op)is empty unless explicitly defined (e.g. future flags)
Two nodes are equal iff their full K byte sequences are identical.
In m1–m3, K uses a fixed-width encoding:
op-> 1 byterep(a1)-> 16 bitsrep(a2)-> 16 bits- total: 5 bytes
This encoding is injective only over a bounded id domain.
Therefore, the id bound is a semantic invariant, not a memory limit.
Define (naming is capacity vs legal id):
LEDGER_CAPACITY = 65535(backing array length / capacity)MAX_ID = 65534(max legal id;LEDGER_CAPACITY - 1)MAX_COUNT = MAX_ID + 1(next-free upper bound; equalsLEDGER_CAPACITY)id = 0reserved forNULLid = 1reserved forZERO
Invariant:
- All reachable ids used in key encoding must satisfy
id <= MAX_ID. ledger.countis a next-free pointer and may equalMAX_COUNT(full).- Any allocation that would make
count > MAX_COUNTis CORRUPT.
Violating this invariant would cause key aliasing and destroy univalence.
Therefore:
- Exceeding
MAX_IDis CORRUPT, not OOM. - Continuing execution past this point is semantically undefined and forbidden.
To maintain determinism and avoid undefined behavior in JIT-compiled code:
Device-side (checked packing / interning):
- If any of the following occur:
count > MAX_COUNTa1 > MAX_IDa2 > MAX_ID
- Then:
- set a persistent
corrupt = Trueflag in the Ledger/interner state - clamp offending values to a safe sentinel (e.g.
0) to keep execution defined - continue execution without crashing or branching on host state
- set a persistent
Host-side:
- After
block_until_ready():- if
corrupt == True, raise a hard runtime error:
- if
RuntimeError("CORRUPT: key encoding alias risk (id width exceeded)")
This guarantees:
- no silent ambiguity
- deterministic failure
- identical behavior across CPU/GPU backends
- Hashes, buckets, sorted lanes, or Morton orderings are acceleration only.
- Equality is decided only by full key-byte comparison.
- Any index backend must be rebuildable from the canonical event stream and must preserve full-key equality semantics.
The fixed-width id cap is intentional and semantic.
Growth beyond this bound is expected to occur via structure, not scalar ids:
- COORD primitives (
OP_COORD_*) represent arbitrarily large coordinate spaces as interned CNF-2 DAGs - Coordinate equality is pointer equality
- Coordinate normalization happens before parent nodes are packed and interned
Thus:
- semantic expressiveness can grow without widening id fields
- the id bound remains a correctness invariant, not a scalability bottleneck
Variable-length key encoding is not permitted implicitly.
A future milestone may introduce:
- a new
KeyCodecVarLen - varint or structural encoding of child ids
- a radix/trie index backend
This is a semantic upgrade, not an optimization, and must:
- preserve the Univalence Contract
- preserve determinism
- pass the same univalence and injectivity test suite
Until that milestone is explicitly landed, fixed-width hard-cap mode is the law.
- Univalence means no ambiguity, not “no hash collisions”
- Fixed-width keys are acceptable only with a semantic id cap
- Exceeding the cap is CORRUPT, not OOM
- Partial allocation of "new" proposals is invalid; fixed-width mode must treat any unmet new allocation as CORRUPT (no silent spawn clipping).
- COORD enables structural growth without widening ids
- Var-length encoding, if added, is a deliberate semantic transition
Define a shared denotation interface used for cross-engine comparisons:
denote(ptr, store) -> normal_form_ptrandpretty(ptr) -> string/tuple.- Soundness:
pretty(denote_engine(expr)) == pretty(denote_ledger(expr)). - Idempotence:
denote(denote(x)) == denote(x). - ID equivalence is engine-local until baseline migrates to the Ledger interner.
- Termination: within the same step budget, either both converge or both do not; non-termination or timeout is treated as a mismatch.
- CORRUPT dominance: if
corrupt == Trueat any point, the denotation result must be("corrupt", ...); clamped sentinel values must never be reported as("ok", ...). - OOM dominance: if
oom == Trueat any point, the denotation result must be("oom", ...); sentinel ids returned by stop paths are not semantic values. - Univalence alignment: any engine-level compare or normalization must preserve the Univalence Contract (full key-byte equality, corrupt trap on overflow).
- Structural invariants (hashes, pointer topology checks) are implementation
diagnostics only; semantic claims must be stated via
pretty(denote(q(...))). - Homomorphic projection: define
q(provisional_node) -> canonical_idand compare denotations only after projection; evaluator steps must commute withqup to canonical rewrite (seein/in-16.md). - Normal-form reporting:
prettyshould return tagged outcomes (e.g.,("ok", decoded),("oom", ...),("corrupt", ...),("timeout", steps)).
- Read model backend (m1): keep the current ordered index (sorted lanes + binary search), maintained via full-array merge in m1. Tests assert full-key equality and do not assume any specific index structure so trie or hash-bucket indexes can replace it later.
- Univalence encoding (m1): hard-cap mode with 5-byte key; enforce
LEDGER_CAPACITY = 65535,MAX_ID = 65534, and checked packing fora1/a2. - Aggregation scope (m4): coordinate aggregation applies to
OP_ADDonly;OP_MULremains Peano-style until explicitly lifted.
For each step below:
- Add pytest tests for expected behavior and a null hypothesis case.
- Add program fixtures (in
tests/or a dedicatedprograms/) mirroring the pytest coverage for black-box validation. - Commit tests first, then implement, then commit again.
Section 0 is Ledger-only (m1). Sections 1-2 land in m2 to introduce the
CNF-2 pipeline and the q boundary. Sections 4-9 supply scheduler variants
needed for m3 denotation invariance; performance-grade locality remains m4+.
Objective: treat the Ledger as the canonical read model and enforce univalence.
Tests (before implementation):
- Pytest:
test_ledger_full_key_equality(expected: hash collision does not merge distinct nodes). - Pytest:
test_key_width_no_alias(null: distinct child ids never alias in key encoding). - Pytest:
test_intern_corrupt_flag_trips(expected: corrupt flag is set and host raises). - Pytest:
test_intern_nodes_early_out_on_oom_returns_zero_ids(null: no mutation; count/key prefix unchanged). - Pytest:
test_intern_nodes_early_out_on_corrupt_returns_zero_ids(null: no mutation; count/key prefix unchanged). - Pytest:
test_corrupt_is_sticky_and_non_mutating(expected: corrupt blocks future interns; no mutation). - Pytest:
test_gather_guard_negative_index_raises(expected: guarded gather trips on idx < 0). - Pytest:
test_gather_guard_oob_raises(expected: guarded gather trips on idx >= size). - Pytest:
test_gather_guard_valid_indices_noop(null: valid gather remains intact). - Pytest:
test_scatter_guard_negative_index_raises(expected: guarded scatter trips on idx < 0). - Pytest:
test_scatter_guard_oob_raises(expected: guarded scatter trips on idx > size). - Pytest:
test_scatter_guard_allows_sentinel_drop(null: sentinel index is allowed). - Pytest:
test_scatter_guard_valid_index_writes(expected: valid scatter writes). - Program:
tests/ledger_univalence.txt(expected: deterministic canonical ids). - Program null:
tests/ledger_noop.txt(expected: no changes).
Tasks:
- Ensure interning uses full-key equality; hash is a hint only.
- Add a canonicalize-before-pack hook for any derived representations.
- Guard against truncation aliasing (m1 uses hard-cap mode).
- Enforce
LEDGER_CAPACITY = 65535, defineMAX_ID = 65534, reserve0/1for NULL/ZERO, and hard-trap oncount > MAX_COUNT(lazy on allocation; eager if count already exceeds the bound). - Implement a deterministic JAX trap:
- Maintain a
corruptflag (oroom) in the interner state. - In checked packing, set
corrupton bounds violations (a1/a2 > MAX_ID) and clamp unsafe values to sentinel zeros to keep computation defined. - Host must raise if
corruptis true afterblock_until_ready().
- Maintain a
- Treat index arrays as rebuildable read models (event log optional).
- Add a reference interner contract test suite that validates injectivity and full-key equality across interner backends.
Objective: pin down sharing and binding semantics early, even before lambda encoding is fully implemented.
Tests (before implementation):
- Pytest:
test_no_copy_sharing(expected: repeated use does not allocate duplicates; xfail until lambda encoding exists). - Pytest:
test_alpha_equivalence_collapses(expected:lambda x. x==lambda y. y; xfail until lambda encoding exists). - Program:
tests/no_copy.txt(expected: reuse does not grow structure; placeholder). - Program:
tests/alpha_equiv.txt(expected: alpha-equivalent forms match; placeholder).
Tasks:
- Add placeholder tests with clear xfail reasons tied to lambda encoding.
- Define a minimal lambda encoding surface (even if stubbed) to route the tests.
- Flip xfail to pass when the encoding lands.
Objective: enforce fixed-arity rewrite semantics and explicit strata discipline.
Tests (before implementation):
- Pytest:
test_cnf2_fixed_arity(expected: exactly 2 candidate slots per site). - Pytest:
test_cnf2_slot_layout_indices(expected: slot0 at2*i, slot1 at2*i+1; compaction preserves slot0 mapping). - Pytest:
test_candidate_compaction_enabled_only(null: disabled slots dropped). - Pytest:
test_candidate_intern_sees_only_enabled(expected: disabled slots are never interned). - Program:
tests/cnf2_basic.txt(expected: same normal form as baseline).
Tasks:
- Add a
CandidateBufferstructure:enabled,opcode,arg1,arg2arrays sized to2 * |frontier|.
- Implement CNF-2 rewrite emission (always two slots; predicates control enable).
- Slot semantics:
slot0= local rewriteslot1= continuation / wrapper / second-stage
- Hyperstrata order (visibility boundary):
slot0writes stratum0 (s=0).slot1reads only pre-step rows + stratum0, writes stratum1 (s=1).- wrapper emission reads only pre-step + prior strata, writes stratum2 (
s=2).
- Emission invariant: buffer shape is
2 * |frontier|every cycle. - Candidate emission must be frontier-permutation invariant (up to slot layout) and independent of BSPˢ scheduling choices.
- m2 invariant: slot1 is enabled; slot1 nodes must only reference ids
< start(stratum1)(hyperstrata visibility rule under guards). - m3 invariant: hyperstrata visibility rule is fully normative and enforced across all strata (slot0, slot1, wrap).
- Implement compaction (enabled mask + prefix sums).
- Intern compacted candidates via
intern_nodes(can be fused in m3). - Optional debug: track origin site indices for strata violation tracing.
Objective: enforce explicit strata boundaries, prevent within-tier references,
and project provisional nodes through q at the stratum boundary.
Tests (before implementation):
- Pytest:
test_strata_no_within_tier_refs(expected: new nodes only reference prior strata). - Pytest:
test_stratum_commit_projects_q(expected: provisional nodes map to canonical ids and swizzle is stable). - Pytest:
test_commit_stratum_count_mismatch_fails(expected: guard trips or corrupt flag is set deterministically). - Program:
tests/strata_basic.txt(expected: same normal form as baseline). - Program null:
tests/strata_noop.txt(expected: no changes).
Tasks:
- Add a lightweight
Stratumrecord (offset + count) for new ids. - Strict strata (default): nodes in
Simay only reference ids< start(Si). - During a BSPᵗ superstep, rewrite eligibility and candidate payloads must be computed from the pre-step read model and must not observe within-step identity creation unless within-tier mode is explicitly enabled and validated.
- Future mode: allow within-stratum references only if they are to earlier ids in the same stratum (topological order), gated by explicit opt-in.
- Add validators that enforce the selected rule, scanning only up to
ledger.count. - Wire validators into
cycle_candidates(guarded by a debug flag); when slot1 is enabled, validate stratum0/stratum1 and each wrapper micro-stratum. - Add a
commit_stratumboundary:- Validate strata, project through
q, intern, and swizzle provisional ids. - Treat projection as the denotation boundary for evaluator emissions.
- Validate strata, project through
Objective: add CD coordinates as interned CNF-2 objects and define parity/aggregation.
Tests (before implementation):
- Pytest:
test_coord_opcodes_exist(expected:OP_COORD_*registered). - Pytest:
test_coord_pointer_equality(expected: identical coordinates intern to same id). - Pytest:
test_coord_xor_parity_cancel(expected: parity cancellation is idempotent). - Pytest:
test_coord_norm_idempotent(expected: canonicalization is stable). - Pytest:
test_coord_norm_confluent_small(expected: small expressions converge). - Pytest:
test_coord_norm_probe_only_runs_for_pairs(expected: probe counts only coord pairs). - Pytest:
test_coord_norm_probe_skips_non_coord_batch(null: probe stays zero). - Pytest:
test_coord_xor_batch_uses_single_intern_call(expected: batch path bounds interning). - Pytest:
test_coord_norm_batch_matches_host(expected: batch path matches host). - Pytest:
test_coord_add_aggregates_in_cycle_candidates(expected: coord add lifts to XOR result). - Pytest:
test_coord_mul_does_not_aggregate(null: coord mul does not lift). - Program:
tests/coord_basic.txt(expected: canonical ids for coordinates). - Program null:
tests/coord_noop.txt(expected: no rewrite for non-coord ops).
Tasks:
- Add
OP_COORD_ZERO,OP_COORD_ONE,OP_COORD_PAIR. - Representation invariant: coordinates are stored only as interned
OP_COORD_*DAGs; no linear bitstrings/digit arrays are stored anywhere. OP_COORD_PAIRis ordered (no commutative canonicalization unless staged).- Coordinate normalization is part of canonicalization-before-pack (key-safe normalization), not a semantic rewrite stage.
- Coordinate normalization operates on
rep(id)children (future Canonicalₑ) before packing keys and interning. - Implement coordinate construction and XOR/parity rewrite rules in the BSP path.
- Aggregation scope (m4): coordinate lifting applies to
OP_ADDonly;OP_MULremains Peano-style until explicitly lifted. - Normalization order:
- Build coordinate CNF-2 objects.
- Normalize parity/XOR to a canonical coordinate object.
- Only then pack keys and intern any coordinate-carrying node.
Objective: add performance-only instrumentation for damage/locality without affecting denotation.
Tests (before implementation):
- Pytest:
test_damage_metrics_no_semantic_effect(expected: enabling metrics does not change denotation). - Pytest:
test_damage_metrics_disabled_noop(null: metrics remain zero/empty when disabled). - Program:
tests/damage_metrics.txt(expected: metrics are emitted under debug flag). - Program null:
tests/damage_metrics_off.txt(expected: no metrics emitted).
Tasks:
- Add per-cycle metrics (delta canonical nodes, reuse rate, damage rate).
- Define "damage" in terms of locality boundary crossings (tile/halo or block) for m4
legacy metrics; m5 replaces this with spectral entropy (see
in/in-27.md). - Gate instrumentation behind a debug flag; treat it as a pure read-only pass.
- Add a small metrics summary to telemetry without altering scheduling.
Objective: capture host/CPU telemetry baselines without enforcing budgets yet.
Tests (before implementation):
- Pytest:
test_audit_host_performance_intrinsic(expected: host perf script emits JSON). - Pytest:
test_audit_memory_stability_intrinsic(expected: memory script emits JSON). - Pytest:
test_collect_host_metrics_summary(expected: host summary table). - Pytest:
test_collect_telemetry_baselines(expected: baseline registry table). - Pytest:
test_capture_trace_dry_run(null: trace capture dry-run succeeds). - Pytest:
test_trace_analyze_cpu_mode(expected: CPU traces report without gating).
Tasks:
- Add
scripts/audit_host_performance.py(cProfile → JSON, record-only). - Add
scripts/audit_memory_stability.py(tracemalloc → JSON, record-only). - Add
scripts/capture_trace.pyto generate JAX traces for a small workload. - Extend
scripts/trace_analyze.py:- detect CPU traces,
- support
--report-onlyand--json-out.
- Add
scripts/collect_host_metrics.pyandscripts/collect_telemetry_baselines.pyto aggregate artifacts into Markdown summaries. - Record run metadata (python/jax/env/flags) into
telemetry_metadata_*.jsonand include it in the telemetry baselines table. - Wire CI (m4) to emit:
artifacts/host_perf_*.jsonartifacts/host_memory_*.jsonartifacts/trace_cpu_report.jsonand include summaries incollected_report/telemetry_baselines.md. Notes:
- No performance budgets yet; record-only until baselines stabilize.
- GPU telemetry remains optional; host/CPU paths must not require pynvml.
Objective: replace host-tuned linear paging with an on-device, BSPˢ entropy-driven servo (Renormˢ) that coarse-grains Morton sorting without affecting denotation.
Tests (before implementation):
- Pytest:
test_spectral_probe_tree_peak(expected:H[10] > 0.8). - Pytest:
test_spectral_probe_noise_spread(expected:Entropy(H) > 3.0bits). - Pytest:
test_lung_capacity_dilate_contract(expected: thresholdsP_buffer > 0.25,P_buffer < 0.10,D_active < 0.40). - Pytest:
test_blind_packing(expected:Entropy(H) < 1.5, legacydamage_rate(tile=512) < 0.01). - Pytest:
test_servo_denotation_invariance(expected: servo on/off yields identical denotation). - Pytest:
test_servo_sort_stable_tiebreaker(expected: equal masked keys preserve index order).
Tasks:
- Extend
Arenaschema with aservostate tensor (uint32 mask + reserved slots). - Implement
_blind_spectral_probe(Entropyₐ):- filter
RANK_HOT, - compute MSB(A ⊕ B) bins,
bincountinto a fixed-size spectrum,- normalize to a probability distribution,
- use
lax.stop_gradientto keep it non-differentiable.
- filter
- Implement spatial hysteresis ("lung") as a memoryless controller over Entropyₐ.
- Apply masked Morton sorting (Renormˢ):
key = morton(ids) & servo_mask,- stable sort via composite key
(masked_key, original_index)on GPU.
- Gate servo enablement behind
PRISM_ENABLE_SERVOor milestone ≥ m5 (default off). - Servo updates are BSPˢ gauge transforms; must commute with
qand preserve denotation:q ∘ Servo = qq ∘ Renormˢ = q
- Keep m4 damage metrics as legacy; m5 entropy metrics are performance-only.
Objective: introduce the fluid arena state and keep it isolated from the
existing Manifest for now.
Tests (before implementation):
- Pytest:
test_arena_init_zero_seed(expected:OP_ZEROseeded at index 1). - Pytest:
test_arena_init_null_free(null: all other rows rank == FREE). - Program:
tests/arena_init.txt(expected: no crashes, optional debug print). - Program null:
tests/arena_empty.txt(expected: no allocations).
Tasks:
- Add an
ArenaNamedTuple with:opcode,arg1,arg2,rankarrayscount(next-free pointer; do not overwrite with active count)
- Add
init_arena()that seedsOP_ZEROand reservesOP_NULL = 0. - Define ranks:
RANK_HOT = 0,RANK_WARM = 1,RANK_COLD = 2,RANK_FREE = 3
- Add new opcodes:
OP_SORT = 99(optional explicit primitive)- keep existing
OP_ZERO,OP_SUC,OP_ADD,OP_MUL.
Objective: implement op_rank to classify nodes into HOT/WARM/COLD/FREE.
Tests (before implementation):
- Pytest:
test_rank_classification(expected: ADD -> HOT, ZERO -> COLD). - Pytest:
test_rank_null_is_free(null: OP_NULL stays FREE). - Program:
tests/rank_basic.txt(expected: HOT/COLD counts match). - Program null:
tests/rank_noop.txt(expected: no rank changes for NULL).
Tasks:
- Implement
op_rank(arena)in JAX:OP_NULL-> FREE- Instructions (
OP_ADD,OP_MUL,OP_SORT) -> HOT - Data (
OP_ZERO,OP_SUC) -> COLD
- Keep rules simple at first; refine once
op_interactexists.
Objective: implement the Rank -> Sort -> Swizzle pipeline.
Tests (before implementation):
- Pytest:
test_swizzle_preserves_edges(expected: graph connectivity preserved). - Pytest:
test_swizzle_null_pointer_stays_zero(null: ptr 0 remains 0). - Program:
tests/sort_swizzle.txt(expected: same decode pre/post cycle). - Program null:
tests/sort_swizzle_empty.txt(expected: no changes).
Tasks:
- Implement
op_sort_and_swizzle(arena):- Compute rank (or accept precomputed rank).
- Compute
perm(stable) andinv_perm. - Permute
opcode,arg1,arg2,rank. - Swizzle pointers via
inv_perm, preserving0as NULL. - Preserve
countas next-free pointer; track active count separately if needed.
- Use
jax.numpy.argsortinitially. - Later: replace with 4-bin partition (prefix sums) for speed.
- Staging note: rank-only sort is sufficient for m1-m2 correctness. 2:1 swizzle is optional until m4.
Objective: implement op_interact to handle ADD rewrites in the fluid model.
Tests (before implementation):
- Pytest:
test_interact_add_zero(expected: ADD(ZERO,y) -> y). - Pytest:
test_interact_add_suc(expected: ADD(SUC(x),y) expands). - Pytest null:
test_interact_non_hot_noop(null: non-HOT nodes unchanged). - Program:
tests/interact_add.txt(expected: correct reduction after cycle). - Program null:
tests/interact_noop.txt(expected: no reduction).
Tasks:
- Implement
op_interact(arena)with masks:ADD(ZERO, y) -> y(in-place rewrite or indirection).ADD(SUC(x), y) -> SUC(ADD(x, y))(requires allocation).
- Allocation strategy:
- Build
spawn_countsper HOT node (0 or 2). - Use prefix sums for unique offsets into FREE region.
- Scatter new nodes with
at[indices].set(...).
- Build
- Add bounds checks:
- Prevent
count + total_spawnfrom exceeding capacity.
- Prevent
Objective: orchestrate the cycle and keep pointers valid across sorts.
Tests (before implementation):
- Pytest:
test_cycle_root_remap(expected: root remains valid across cycles). - Pytest null:
test_cycle_without_sort_keeps_root(null: no swizzle => same ptr). - Program:
tests/cycle_root.txt(expected: same value after N cycles). - Program null:
tests/cycle_noop.txt(expected: no state changes).
Tasks:
- Implement
cycle():op_rankop_sort_and_swizzleop_interact
- Track
root_ptr:- Store root separately (host) and remap via
inv_perm. - Optionally store root in a dedicated arena field.
- Store root separately (host) and remap via
- Add a
run_cycles(n)helper for benchmarking and tests.
Objective: add the 2:1 BSP ordering as a secondary sort key.
Tests (before implementation):
- Pytest:
test_morton_key_stable(expected: stable ordering in same rank). - Pytest null:
test_morton_disabled_matches_rank_sort(null: rank-only same). - Program:
tests/morton_order.txt(expected: consistent ordering). - Program null:
tests/morton_rank_only.txt(expected: identical to rank-only). - Pytest:
test_morton_denotation_invariant(expected: same decoded result with and without 2:1 swizzle).
Tasks:
- Add
swizzle_2to1_dev(x, y)(device) andswizzle_2to1_host(...)(host). - Add
op_morton(arena):- Define a coordinate scheme (initially derive from index or a stored coordinate buffer).
- Default scheme: index-derived
x=idx,y=0(PRISM_ARENA_COORD_SCHEME=index). - Optional scheme: grid (
PRISM_ARENA_COORD_SCHEME=grid,PRISM_ARENA_COORD_GRID_LOG2=<k>).
- Compose sort key:
sort_key = (rank << high_bits) | morton.
- Ensure stable ordering inside ranks when Morton keys collide.
- BSPˢ permutations must be bijections and must satisfy
perm[0]=0andinv_perm[0]=0.
Objective: implement multi-level arenas to constrain shatter.
Tests (before implementation):
- Pytest:
test_block_local_sort(expected: local ordering preserved). - Pytest null:
test_single_block_same_as_global(null: no diff for 1 block). - Program:
tests/hierarchy_basic.txt(expected: stable decode). - Program null:
tests/hierarchy_single_block.txt(expected: same as baseline).
Tasks:
- Partition arena into blocks (e.g., fixed block size).
- Run rank/sort locally per block, then merge.
- Add metadata arrays for block offsets and free ranges.
- This is a later milestone once fluid arena is correct.
Objective: maintain usability and instrumentation.
Tests (before implementation):
- Pytest:
test_repl_mode_switch(expected: mode flag selects BSP). - Pytest null:
test_repl_default_is_baseline(null: default unchanged). - Program:
tests/repl_bsp.txt(expected: BSP path exercised). - Program null:
tests/repl_baseline.txt(expected: current behavior).
Tasks:
- Add a mode switch in
repl():--mode=bspor environment flag.
- Update
parsefor BSP:- Linear allocation into arena, optional
(sort ...).
- Linear allocation into arena, optional
- Update telemetry:
- Counts of HOT/WARM/COLD/FREE.
- Per-cycle allocation delta.
- Provide debug hooks to compare results with the baseline VM.
- m1: Ledger intrinsic core + deterministic keys
- Ledger interning is the reference path (
cycle_intrinsic + intern_nodes). - Full-key equality and hard-cap univalence are enforced.
- Milestone-gated tests are part of the deliverable (see
in/in-15.md).
- Ledger interning is the reference path (
- m2: Strata boundary + total
qprojection- CNF-2 fixed-arity pipeline is enabled (slot1 enabled).
- Evaluator emits strata; no within-tier references.
commit_stratum: validate → projectq→ intern → swizzle ids.
- m3: Canonical rewrites + denotation invariance harness
- Canonical rewrites live in Ledger space (rewrite+intern).
- Slot1 continuation is validated under the hyperstrata visibility rule.
- Denotation invariance across unsorted, rank, and morton/block schedulers.
- m4: Coordinates as interned objects + aggregation
OP_COORD_*objects and idempotent parity normalization.- Coordinate aggregation applies to
OP_ADDonly.
- m5: Full homomorphic collapse (production contract)
- Evaluator is write-model, Ledger is read-model.
- Scheduling affects performance only; meaning is measured after
q. - Autonomic servo (entropy probe + lung + masked Morton) replaces host-tuned paging.
- m6: Hierarchical arenas (optional)
- Local block sort and merge once the contract is stable.
- m1 gate: univalence + no aliasing + baseline equivalence on small suite.
- m2 gate: strata validator passes +
qprojection total on emitted strata. - m3 gate: denotation invariance across unsorted/rank/morton/block schedulers, plus pre-step immutability enforced as a hyperstrata visibility rule.
- m4 gate: coordinate normalization idempotence + parity cancellation + instrumentation is denotation-invariant.
- m5 gate: full-suite denotation invariance + univalence stress tests.
m1:
- Key-byte univalence holds under hard-cap mode (
MAX_IDchecks + corrupt trap). - Deterministic interning for identical inputs within a single engine.
- Baseline vs ledger equivalence on small add-zero suite.
- Guarded gathers and scatters reject out-of-range indices under test guards.
- Interning early-outs when
oomorcorruptis set. - Corrupt is sticky; stop paths leave
countand key-prefix arrays unchanged. m2: - CNF-2 emission is fixed-arity (2 slots per site) with slot1 enabled.
- Compaction never interns disabled payloads.
- Stratum boundary enforces no within-tier refs;
qprojection is total. m3: - Denotation matches ledger intrinsic on the shared suite.
- Denotation invariance across unsorted/rank/morton/block schedulers.
- Pre-step immutability holds under CNF-2 cycles (hyperstrata visibility rule).
- Slot1 continuation respects hyperstrata visibility (reads pre-step + stratum0 only). m4:
- Coordinate normalization is idempotent and confluent on small inputs.
- Coordinate lifting limited to
OP_ADD. - Damage/locality instrumentation does not change denotation when enabled. m5:
- Arena scheduling (rank/sort/morton on/off) preserves denotation end-to-end.
- Servo mask/entropy control is performance-only and preserves denotation.
- Add
tests/harness.pywith shared parse/run/normalize helpers. - Add tests
test_univalence_no_alias_guard,test_add_zero_equivalence_baseline_vs_ledger(both operand orders), andtest_intern_deterministic_ids_single_engine. - Implement key-width fix and hard-trap on
count > MAX_COUNT. - Ensure
cycle_intrinsicreduces the add-zero cases. - Only then introduce CNF-2 pipeline tests (m2).
- CLI (banded): per-milestone configs use
--milestone-bandso each band is exclusive; runningm1→m5covers the full suite without reruns.pytest -c pytest.m2.iniruns only tests markedm2.pytest -c pytest.m1.inirunsm1plus unmarked tests (via--include-unmarked).
- CLI (inclusive):
pytest --milestone=m2runs all tests at or belowm2. - VS Code: edit
.vscode/pytest.envto setPRISM_MILESTONE=m2, then refresh the Testing panel; gating reads the env (or.pytest-milestone) inconftest.pyand usespytest.ini.- For banded selection in VS Code, set
PYTEST_ADDOPTS=--milestone-band=m2(add--include-unmarkedform1).
- For banded selection in VS Code, set
- Marking: tests are tagged
m1..m6with the earliest milestone that must pass. Unmarked tests must be assigned;m1is the only band that includes unmarked tests by default. - See
in/in-15.mdfor the milestone-gated workflow details. Unit tests (ordered by dependency): - Root remap correctness after any permutation/sort.
- Strata discipline: newly created nodes only reference prior strata.
- Lossless univalence/dedup (interning returns canonical ids).
- Key-width aliasing guard (full-key equality, no truncation merges).
- Gather/scatter guards reject out-of-range indices (test-guard mode).
- No-copy sharing (xfail until lambda encoding exists).
- Alpha-equivalence collapse (xfail until lambda encoding exists).
- Coordinate parity normalization (pointer equality for canonical coordinates).
- CNF-2 fixed arity: two candidate slots per rewrite site.
- CNF-2 slot layout indices are stable (slot0/slot1 mapping).
- 2:1 denotation invariance once swizzle is mandatory.
Integration tests:
- Compare baseline
PrismVMeval vsPrismVM_BSPafter N cycles for:(add (suc zero) (suc zero))(add zero (suc (suc zero)))
- Shared semantics harness (
tests/harness.py) to parse/run/normalize across engines and compare decoded normal forms. - Cross-engine equivalence harness (shared suite):
- Baseline
PrismVM - Ledger
cycle_intrinsic - Ledger CNF-2 pipeline
- (m4+) Arena-scheduled pipeline
- Assert decoded normal forms match.
- Optionally assert canonical ids match within each engine.
- Baseline
Performance checks:
- Cycle time (rank/sort/swizzle/interact).
- Allocation pressure vs capacity.
- Damage/locality metrics (when enabled).
- JAX scatter costs: minimize scatter writes, batch with prefix sums.
- Full-array ledger scans: fixed-shape interning touches
LEDGER_CAPACITY-sized buffers even whencountis small (intentional for JIT stability in m1). m4 mitigations: introduce a smallerMAX_CAPACITYfor production runs, maintain per-op counts incrementally;keys_b0_sortednow usessearchsortedto avoid full_bincount_256in the interner. ✅ stage prefix-only scans via dynamic slice + pad. - Pointer invalidation: treat root pointer as part of state, remap every sort, and verify in tests.
- Capacity overflow: add a guard that halts or triggers a sort/compaction.
- Key aliasing: avoid truncation in key encoding or assert limits at intern.
- Interner rebuild cost: avoid full-table merges per tiny batch; use staging buffers and periodic read-model rebuilds after m3.
- JIT recompilations: keep shapes static (fixed LEDGER_CAPACITY).
This section mirrors deferred notes/TODOs in prism_vm.py for double-entry
tracking against the roadmap.
- JAX op dtype normalization (int32) is assumed; tighten if drift appears.
_scatter_dropuses sentinel drop semantics; strict variant available for in-bounds writes (see_scatter_strict). ✅safe_gather_1dclamps indices outside test mode for deterministic behavior. ✅- Add an explicit zero-row (id=1) invariant guard. ✅
init_ledgerrelies on_pack_keybeing defined later; reorder helpers if init moves to import time.validate_stratum_no_within_refs_jaxuses chunked prefix scans viaPRISM_PREFIX_SCAN_CHUNKto avoid full sweeps; host-slice validation remains for guard mode._apply_stratum_qassumescanon_idslength equalsstratum.count; if batching changes, usestratum.countand add a guard._lookup_node_idwhile-loop tuple unpacking (pos, _) is potentially confusing; clarify intent if refactored.- Add CNF-2 observability counters for
rewrite_child/changed/wrap_emit. - CNF-2 candidate layout invariant: slot0 at
2*i, slot1 at2*i+1; document and preserve incycle_candidates. - Consider updating the wrapper frontier directly in
rewrite_childcases to avoid extra cycles when the child normalizes. - Host-only coord helpers (e.g.,
coord_xor, leaf helpers) now cache ledger slices and leaf ids to avoid per-scalar device reads. ✅ _coord_norm_id_jaxrepeats lookups per step; batch coord normalization. ✅- Coord normalization uses
vmapover acond/loop; refactor to a single SIMD-style loop over the coord subset. - Opcode buckets now feed per-op merges; global merge no longer required.
- Overflow checks depend on
requested_new; add a secondary guard onnum_new. - Overflow is treated as CORRUPT in m1 (semantic id cap == capacity); split OOM handling if semantics decouple.
- Per-op merge implemented via
_merge_sorted_keys_bucketed(bucketed merge). ✅ - Add a guard for
new_countvs backing array length ifmax_countdecouples. intern_nodesstop path performs a read-only lookup fallback (implemented)._active_prefix_countclamps to size; add an explicit overflow guard.- Add value-bound guards for swizzled args in test mode. ✅
- Remove the duplicate "JAX Kernels" section header.
Ordered by semantic risk first, then verification depth, then hygiene.
P0 — Semantic/core correctness ✅
- Explicit
qprojection boundary for Arena/Manifest (glossary §17/§21). ✅ (Implemented inproject_manifest_to_ledger/project_arena_to_ledger; covered bytests/test_q_projection.py.) - Hyperstrata / micro-strata visibility beyond the fixed 3-strata cycle. ✅
(Wrapper micro-strata committed in order; exercised by
tests/test_candidate_cycle.py::test_cycle_candidates_wrap_microstrata_validate.)
P1 — Verification depth / semantic completeness ✅
- Min(Prism) full harness:
canon_state+ bounded enumeration + projection commutation. ✅ - Event-sourced/CQRS interner model (read-model rebuild path; in-12/13). ✅
- Hyperlattice / lattice-stable join tests (in-20). ✅
P2 — Hygiene / clarity / roadmap housekeeping ✅
- Clarify
_lookup_node_idtuple unpacking. ✅ - Overflow guard for
_active_prefix_count. ✅ - Remove duplicate "JAX Kernels" header (if not already resolved). ✅
- Agda proof roadmap execution (in-26). ✅
- in-8 interaction-combinator engine pivot (tensor/rule-table path). ✅
P3 — Formalization + next-architecture track ✅
- in-19 staging/site topology: define/encode micro‑strata (
t) + tile (τ) semantics and visibility rules. ✅ - CD morphisms / hyperpair semantics beyond coord opcodes; add lattice‑law tests for CD‑lifted ops. ✅
- Novelty / hyperoperator fixed‑point instrumentation or bounded checks (Min(Prism) expansion). ✅
- Agda proofs (actual theorems) for univalence/gauge/novelty/finite closure/fixed points. ✅
- in-8 interaction‑combinator engine implementation (rule table + port encoding + rewrite kernel). ✅
P4 — Verification hardening + next backend ✅
- No‑copy / alpha‑equivalence tests for ledger sharing (in‑17). ✅
- CQRS replay harness beyond Min(Prism) (optional audit mode). ✅
- Agda boundary theorems (no‑termination / negative capability). ✅
- Interaction‑combinator backend (in‑8) beyond roadmap: data model + kernel prototype. ✅
prism_vm.py: newPrismVM_BSPand arena ops.tests/: new fixtures for cycle-based evaluation.README.md: documented modes and expected behavior.
This is a later-stage pivot that replaces or augments the BSP pipeline with a branchless interaction-combinator engine based on a NodeTypes/Ports/FreeStack layout and rule-table rewrites.
Status: implementation underway (roadmap active). Current state:
- M6–M8 complete in
ic_vm.py+tests/test_ic_vm.py(data model, active-pair matching/compaction, rule table + wiring templates). - M9 ✅: Device-resident prefix-sum allocation plan + FreeStack reuse/overflow guards with
oomboundary (seeic_apply_active_pairsallocation planning + OOM test). - M10 ✅: Device-resident match/alloc/rewire/commit pipeline + reduce loop with end-to-end reduction tests (
tests/test_ic_vm.py).
Prereqs:
- Complete m1 through m5 (BSP cycle verified and stable).
- Decide whether this is a separate backend or a full replacement.
- Settle port encoding (3 ports vs 4-slot encoding) and invariants.
Planned steps (tests-first, pytest + program fixtures):
- M6 ✅: Data model for NodeTypes/Ports/FreeStack and port encoding invariants.
- M7 ✅: Active-pair matching + stream compaction (null: no active pairs).
- M8 ✅: Rule table and wiring templates (annihilation/commutation/erasure).
- M9 ✅: Allocation via prefix sums + FreeStack reuse/overflow guards.
- M10 ⏳: Match/alloc/rewire/commit kernel pipeline and end-to-end reductions.