# Repro: caller-context cross-product blowup at requires-call yield points.
#
# Pattern (perry's dominant shape, distilled):
#   - 5 enum comp-vars (s0..s4) recording last-read status from each
#     of 5 requires-ports.
#   - Each handler READS prior comp-vars in guards to decide what to
#     do, then ASSIGNS from a requires-port reply.
#   - Vars are GENUINELY READ (not write-only), so dead-var analysis
#     correctly keeps them live.
#
# State counts (no queue overrides):
#   - dzn:   3,271 states
#   - ours: 26,796 states   (8.2× — STRONGER than perry's 3.7×)
#
# Both engines are weak-failures EQUAL (the dzn baseline is the
# wf-eq oracle). The extra states ours produces are intermediate
# "post-call yield-point" snapshots that distinguish on the OLD value
# of the comp-var about to be overwritten by the call's reply. dzn's
# LPS doesn't generate those intermediate states because each
# summand updates only a small slice of the state vector.
#
# Why this is a useful repro:
#   - 50 lines of Dezyne, both engines run in <1s.
#   - Pattern is real (perry uses it heavily).
#   - Strong signal-to-noise (8× ratio).
#   - Fixable via per-program-point "var about to be overwritten"
#     projection at the post-requires-call yield-point snapshot —
#     scope-bounded refactor, not a full engine rearchitecture.
#
# Measured ceiling (NUC_DBG_EMIT_HASH=1 diagnostic, 2026-05-30):
#   - 35,000+ emit() calls total during BFS exploration.
#   - Only 81 unique sim snapshots across all emits.
#   - 332× redundancy from per-emit unique ID allocation without dedup.
#
# Cross-step-dedup fix LANDED 2026-05-30 (opt-in env gate
# NUC_CROSS_STEP_DEDUP=1):
#   - This repro: 26,796 → 1,314 states (20× compression).
#   - Perry: 1,762,720 → 259,600 states (6.8× compression), 13.8s → 2.0s wall.
#   - Both wf-EQUAL to dzn (confirmed via scripts/wf-check.py).
#   - Mechanism: lift the per-handler-firing `seen: HashMap<DedupKey,
#     usize>` dedup map inside `step_frontier::enumerate()` to
#     BFS-wide via `Simulator.seen_across_bfs`. DedupKey was extended
#     with `comp_idx`, `trigger_port`, `provides_emit_port`,
#     `terminal_marker` so different BFS-step activations with the
#     same per-step key but different cross-step context don't merge.
#     AwaitingCall/AwaitingSpont/AwaitingForeign FrameSig variants
#     extended with port/event/assign_to identity (was just a bare
#     tag — sufficient within-step but lost across-step).
#   - Gate is DEFAULT-OFF. Two opt-in modes:
#     - NUC_CROSS_STEP_DEDUP=1 (permissive): perry 1.76M → 260K
#       (5.5× wall speedup), but 26 corpus regressions (over-merges
#       on recursion-tracked activations).
#     - + NUC_CROSS_STEP_DEDUP_SAFE=1: strips complex-history keys
#       from the cross-step map (call_states / drain_history non-empty
#       at canonical-insert time). Trades the perry win for fewer
#       corpus regressions: this repro still 26.8K → 1.3K (20× win
#       — no recursion in the repro), and corpus drops from 26 fails
#       to 18 (verify back to 613/0, phenom 142→146, lts 584→586).
#     - Remaining 18 SAFE failures are mostly system models — the
#       DedupKey needs per-leaf scope info to be sound for the
#       per-leaf composition path. Single-component non-system models
#       run cleanly under either mode.
#
# State-count factor budget set to ~9× to gate at the current shape;
# any future fix that brings ours toward dzn's count will pass with
# room. A fix that makes ours WORSE than 9× current ratio fails.
((max-state-factor 9))
skip simulate
skip c
skip cs
skip scheme
skip javascript
