Implement production scenario driver (ADR 0007) - #71
Merged
Conversation
…ion roadmap Four persona lenses (Torvalds, Hickey, Kingsbury, Lamport) over the full tree at dfb03cb, with consensus findings ranked, an honest built-vs-specified inventory, and a three-phase roadmap toward testing diverse systems with a three-artifact configuration contract (component, scenario, properties). Key consensus findings: no end-to-end search-finds-a-real-bug path yet (demo oracle is a planted marker; the reference scenario's property does not load), inert scenario fields with no scenario-to-run driver, single-handler registry with no kernel fact routing, snapshots not committing to facts or handler identity, and unpinned selections in replayable transcripts. Strengths recorded with equal weight: the canonical-value/PRNG substrate, the replay/divergence/certificate spine, and the fail-closed evidence culture. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK
…n loop) Adds section 7.5 to the deep-dive review: an explicitly experimental, flag-gated LLM 'brain' that participates in the testing process. Three seats in ascending risk order (outer-loop orchestrator, within-run policy-as-data advisor, verdict participation -- the last is refused outright), five mandatory guardrails including full advisor-transcript auditing and a permanent seeded-random control arm with measured lift, and a cheapest-first deliverable. Gated on the Phase 1 exit demo and removable without touching the core roadmap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK
The reference scenario's liveness pattern was a bare symbol, but the
property engine requires the {name, source, value} record shape, so
urdr.properties.load returned properties-pattern-shape and the flagship
example's only property was dead weight. The pattern is now the record
form: an ack fact recorded by the client component, deadline unchanged
at 8, all record keys in ascending canonical order.
Only the scenario frame digest moves in the integration golden; the
explore path digest, replay root, and certificate run-id are unchanged
because exploration is seeded off the scenario seed and topology, not
the property spec bytes. The m1-integration pin is updated in both
bifrost.suite.json and the gate's EXPECTED_CASES table, which must
byte-agree.
Evidence (shen-go, the documented generation port; other launchers not
built in this environment): scenario suite 93/93 ALL PASS, integration
suite exact-golden PASS, make quality green. docs/status/m1.md still
carries the old frame digest and is refreshed in a later docs pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK
…ns; wire adversarial suite Launcher resolution in every test.sh and the adversarial runner now follows SHEN_* env override, then URDR_DEPENDENCIES, then the repo's .cache/urdr/dependencies pinned checkouts -- the same authority-drift fix 1af5c27 applied to test_canonical_fixtures.py. Personal absolute paths are gone from the harness; a stale local launcher can no longer validate against trees the gate does not pin. Existing skip/fail semantics are preserved per suite, except the GOLDEN_ONLY escape in integration/search/grammar, which permitted a fail-open 'ALL PASS ports=0' and existed only for the deleted self-blessing workflow. Golden self-blessing is deleted: a missing golden.txt now fails with an instruction to create it deliberately instead of being regenerated and blessed by the run that happened to come first. The 87 offline adversarial tests join 'make test' (they were wired into no automated lane at all); 'make adversarial' additionally probes port launchers and fails closed when they are missing. make quality stays green offline at ~2.7s. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK
Two numeric-core fixes, verified byte-compatible and gated together. small.divmod was repeated subtraction, O(N/D) host ops -- the dominant cost of software-integer division (one 256-bit divmod ~10^7 host ops). It is now descending-weights binary restoring division, O(log(N/D)), reusing the exact-natural-weights idiom from canonical.shen. The doubling guard is written 2W > N as (> W (- N W)) so every host intermediate stays within the existing ADR 0003 reviewed bound 99,990,000; no new bound is introduced. canonical.shen's own small-divmod had the identical shape and is fixed identically (kept as its own copy: the protocol layer must not depend on urdr.int). Ten new divmod edge vectors land in the prng suite (integer unit-test home), plus a 60k-case exhaustive Q*D+R=N sweep run out-of-tree. Semantics are byte-identical: all non-prng suite outputs diffed clean against pre-change captures. Measured on shen-go: world 5.9s -> 1.4s, search 6.5s -> 3.2s, grammar 8.6s -> 3.6s. search.shen and grammar.shen each carried a private mag-small fold that read limbs most-significant-first, but integer.shen magnitudes are little-endian base-10000: [big 1 [5000 1]] (= 15000) decoded as 50000001. Unreachable today only because those paths stay below one limb. Both copies are deleted in favor of one new urdr.int.small-of / mag.to-small in integer.shen, symmetric with from-small: it validates first, fails closed with the existing unsafe-host-integer code above the from-small window, and checks width before folding so no host arithmetic can overflow on double-backed ports. Regression cases cover the previously-misdecoding two-limb values. Pins: named-prng and explore-shrink/scenario-grammar program and golden digests re-pinned in bifrost.suite.json and the gate's EXPECTED_CASES (both must byte-agree). Evidence: make conformance REQUIRED_IMPLS=shen-go PASS, 12/12 cases; make quality green (90 + 87 tests). Four-port byte-identity for the re-pinned cases awaits the port sweep; only the shen-go launcher is built in this environment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK
Records the Phase 1 authority decisions before the code lands: one driver owns scenario execution (D1); explore becomes a step loop over published choices with selections pinned into the replayable transcript (D2); the registry becomes data with per-component model bindings and a reserved self identity key (D3); fact routing is kernel-owned, declared, synchronous, and cascade-budgeted (D4); declared budgets are enforced (D5). Alternatives recorded: router-as-component rejected on authority grounds, silent sorting and PRNG-replay rejected as silent repair, asynchronous routed delivery deferred with rationale. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK
The component door has always rejected choice alternatives that are not strictly ascending in canonical encoding order, so no host iteration order can reach world semantics. The schedule door did not, and selection is positional, so two permutations of the same alternative set were different worlds under the same seed. The kernel now rejects unordered (and thereby duplicate) alternatives on scheduled choice events with the stable code choice-alternatives-order, after encodability is proven and before any state change, via one shared predicate (urdr.component.encoding-ascending?) used by both doors. urdr.search.menu mirrors the check at construction time with search-menu-order so strategy authors fail early. Canonical atom encoding is length-prefixed, so alphabetical order is not encoding order (4:beta sorts before 5:alpha). Four existing sources relied on the alphabetical assumption and are fixed: the world suite's primary fixture, the search and integration color alternatives (whose comments asserted the broken assumption and now state the truth), and the grammar expander's cartesian products, which are now emitted in encoding order through an insertion sort on canonical encodings -- its author-order documentation contract is updated accordingly. Deliberate re-pins recorded here: world (WORLD-TRACE embeds the reordered fixture and the selected value changes; 21/21 -> 22/22 with two new misbehaving-fixture rejection tests), search and grammar (explore path and seed digests move with positional selection), and integration (explore path digest only). Models and replay goldens are byte-identical, confirming scope. Pins updated in bifrost.suite.json and the gate's EXPECTED_CASES together; the gate's world-reducer shape check and its unit-test fixture track the new count. Evidence: make conformance REQUIRED_IMPLS=shen-go PASS 12/12; make quality green (90 + 87 tests). Four-port identity awaits the port sweep; only shen-go is built here. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK
…7 D3)
The model registry's kind dispatch becomes an association table of
kind -> entry-builder pairs (host data validated at boot, never
serialized), extensible by a driver-supplied table. The scenario roster
gains an optional per-component model binding: a model table maps model
symbols to handler/init-builder pairs, so two process components can
run different models with different initial states -- previously one
handler and one init threaded through the entire roster. Init-builders
receive the full roster record plus baseline. The roster's node binding
is no longer parsed and dropped, and the registry's two silent-drop
catch-alls (vocab-entries, domains) now fail closed like their sibling.
Runtime registry entries carry a validated META record {model, node}
(component-meta-shape / component-meta-value on violation; a 3-arg
convenience constructor keeps fixtures terse). The event record a
component receives gains a self key -- {id, node} built from the
entry's name and META -- and self joins the reserved-authority list:
a component may read its identity but never emit it as a claimed key.
Models decode events by key lookup, so the new key required no model
changes; the one fixture that echoed its whole event now claims time
explicitly, and a new fixture pins the self-claim rejection.
Scenario surface: roster records accept an optional model symbol (key
order id < kind < model < node), rendered only when present so the
losslessness law holds; four new fixtures pin acceptance and the
type/duplicate/misplaced rejections (duplicate and misplaced die in the
ADR 0002 decoder, documented in cases.tsv).
Deliberate re-pins: models golden 47 -> 54 cases (identity-delivery
demonstrations, unknown-model and fail-closed registry rejections;
pre-existing digests byte-identical), scenario 93 -> 97 fixtures,
program pins for the seven suites whose run-tests gained the 5-slot
entry constructor. World golden is byte-identical (22/22 unchanged).
Evidence: make conformance REQUIRED_IMPLS=shen-go PASS 12/12;
make quality green. Snapshot/certificate binding of model identity is
deliberately deferred to the ADR 0008 wave, commented in world.shen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK
A scenario may now declare routes -- [route FACT FROM TARGET] with
TARGET a component id or a node -- and the kernel delivers matching
newly-emitted facts as ordinary component inputs at the current logical
time, in (route declaration order, fact emission order), with fresh
event ids ordered by the pending queue's existing (time, id). Node
targets fan out to every component whose META node matches, in
canonical component-name order. Facts matching no route remain
observations. Routing introduces no choice, no time advance, and no
PRNG draw; anything reorderable still belongs to the net component.
The world value becomes world/v2 with a tenth routing slot
[routing Rules Limit Count]: routes are a semantic input (same
components, different routes, different reductions), so they live in
world state and in the snapshot -- embedded whole rather than digested,
since routes are declaration-sized and the live same-time capacity
count must be visible. Same-time cascades are bounded: routed
deliveries at one logical time above the limit (64 this wave; the D5
driver binds it to the budget's max-steps) fail the whole commit closed
with route-cascade-exceeded, world unchanged; advancing to a strictly
later time resets the count.
Scenario surface: optional routes field between properties and seed,
same optional-field mechanics as the roster model key so losslessness
holds; fail-closed codes for shape, unknown from, unknown target, and
reserved fact names (the nine authority names are duplicated into
scenario.shen with mirror cross-references rather than inverting the
layering). Six new fixtures pin acceptance and each rejection.
fault.shen's crash/restart facts now carry {kind, members} -- literally
the process wrapper's control input, as mask is literally the net
model's -- and its stale claim that the kernel routes them is replaced
by a description of the now-real mechanism. Models suite 54 -> 65:
declared-route partition without hand-plumbing, node-target crash
fan-out, under-cap cascade, route-cascade-exceeded, per-time counter
reset, unrouted facts stay observations. The hand-scheduled mask cases
are kept as manual-path parity proof.
Re-pins: world (snapshot gains routes; suite stays 22/22), scenario
(97 -> 103 fixtures), models, replay and integration (state hashes and
run-id embed the snapshot). canonical/prng/netkat/netpol/properties/
search/grammar goldens unchanged -- audited, no world snapshot in their
outputs. The world suite's trace projection moved to the m1-large
encode profile after crossing the m0 256-node ceiling; the snapshot
itself still encodes under m0.
Evidence: make conformance REQUIRED_IMPLS=shen-go PASS 12/12;
make quality green; all 12 suites ALL PASS directly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK
…ADR 0007 D2) A scheduled choice may now carry its selection: the 7-element form [choice Sub Actor Purpose Alternatives Selected Coordinates] passes every drawn-form validation plus coordinate shape (re-validated through urdr.prng.coordinate, so a transcript can never carry a coordinate the PRNG could not produce) and membership by canonical-encoding equality (choice-selection-not-member, rejected before the event enters pending or transcript). Dispatch applies the selection with no PRNG call and no stream-counter advance, embedding the recorded coordinates verbatim -- they are evidence of the driver-space draw, not re-derivable. The round-trip theorem -- a drawn choice record and its replayed selected form are byte-identical while the selected world's stream counters stay untouched -- is printed by the world suite and enforced digest-equal by the gate's output-shape check. The transcript writer/reader carries the selected form losslessly and additively (drawn-form entries unchanged; write remains a total inverse of read). Replay consumes recorded selections; a non-member selection in a transcript that verified as the recorded artifact is engine/ artifact disagreement and surfaces as replay-selection-divergence in the DIVERGED family -- the fourth divergence code, with the reasoning recorded in replay.shen and certificate.shen. State roots can never catch a selection change (selections live in the event stream, not the snapshot); the replay suite proves all three tamper outcomes (tampered / event-divergence / selection-divergence) distinctly. urdr.search.schedule-input now emits the selected form, so explore transcripts are pinned by construction; the shrinker classifies the new arity (SHRINK|pinned reaches the same minimum as the drawn case). Re-pins: world 22/22 -> 24/24 (round-trip + counter cases), replay 48 -> 55, search 14 -> 16, grammar REPLAY|full root. m1-integration is byte-identical. Pre-existing quirk kept verbatim and documented: the coordinate-record key is literally 'algorith'; fixing it is a schema-wide re-pin out of scope here. Evidence: make conformance REQUIRED_IMPLS=shen-go PASS 12/12; make quality green; all 12 suites ALL PASS directly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK
…/D5) urdr.run.execute is the single production path from a validated scenario to a certified result: validate; load every declared property (unloadable declarations reject before any world exists); build the world through the registry's scenario path with the routing cascade limit bound to the budget's max-steps (the 64 default remains for non-driver constructors); boot each process component at time 0 in canonical roster order (built-in models reject unknown inputs fail- closed, so boot reaches only model-bound processes -- and a process without a model binding is refused with run-process-unbound, since the scenario is the whole program); then the D2 step loop: drain pending events collecting published menus, hand open menus to the reused search-layer strategy (driver draws stay in the search subsystem, provably disjoint from world streams), schedule the pinned selected form plus deliver the alternative to its publisher, until quiescence or a budget trips. A step is one reducer input, so max-steps bounds selections and makes per-attempt PRNG counters stride-safe and reproducible from (seed, attempt) alone. Budgets are enforced, not decorative: run-steps-exceeded and run-events-exceeded abort one attempt and appear in the summary; exhausted returns attempt count, distinct failure signatures in first-seen order, and every attempt-level abort -- not an empty tuple. Attempt errors are recorded, never swallowed; all attempts erroring is run-all-attempts-failed. The new run suite proves the chain with no fixture verdicts anywhere: a ping/ack scenario over declared routes discovers a genuine liveness violation through the property engine (attempt 0 passes with an entry witness; attempt 1 selects drop, no ack fact enters the trace, FAIL no-witness), and the certificate binds a digest of the full m1-large scenario payload, verdicts from urdr.properties, achieved profile modeled-d1-analog via its internal replay re-drive of the pinned transcript. Same seed twice: identical discovery digests; different seed: different attempt and root. The cascade fixture proves the D5 binding: five same-commit deliveries trip route-cascade-exceeded under max-steps 4, far below the old fixed 64. run-driver joins the gate as the 13th case (CASE_ORDER, EXPECTED_CASES, projection prefixes, FAIL|-family output shape); module-boundaries gains the shen/run/ root -- nothing may depend on run/, and shrink/ is deliberately unlisted from its dependencies until the shrink wave. Pre-existing 12 case goldens are untouched (gate re-verified byte- for-byte). Known deferral, documented in run.shen: net and timer menus need deliver/fire input wrapping before built-ins resolve under the driver -- the wave that integrates them owns that rule. Evidence: make conformance REQUIRED_IMPLS=shen-go PASS 13/13; make quality green; run suite 7s on shen-go, exact-golden. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK
… 0008)
A certified run now commits to its own observable output and to which
model produced it -- the review's consensus finding: two runs emitting
different facts from identical states had identical snapshot digests,
and no certificate could say which implementation ran.
snapshot-value's fact-count becomes facts-root: a tagged SHA-256
(urdr-facts-root-v1) over each fact's canonical encoding under
m1-large -- the profile the component door validated those values
under and the one state digests already use; the eventlog's
m0-plus-content-address rule was rejected because a snapshot binding
has no content-address escape hatch. The count is dropped entirely:
zero consumers existed and the root distinguishes every length by
construction. The snapshot's component entries carry their validated
META verbatim ({meta, name, state-digest}), discharging the D3
deferral comment.
Certificates bump to urdr-certificate-v2 with an eighteenth key:
models -- the initial world's {component, model, node} bindings in
registry order (strictly ascending by construction). Model identity
deliberately does NOT join the run-id preimage: field 3 already hashes
the initial snapshot, which now commits to the bindings, so run
identity covers them transitively -- the reasoning is written next to
the existing baseline-descriptor argument and proven executable by a
mutation case where two worlds differing only in one model binding
produce different run ids.
ADR 0008 (Accepted for M1.5) records both decisions, the profile
choice, the transitivity argument, and four rejected alternatives.
Re-pins, predicted before running and matched exactly: world 26/26
(facts-divergence and meta-visibility cases), models (the one snapshot
digest line), replay 57 (29 state-hash lines + models/mutation cases),
run (RUN|models), integration (run-id only). search/grammar goldens
byte-identical -- their digests commit to reducer inputs, not
snapshots. Gate world stanza tracks 26/26; drawn==selected equality
unchanged.
Evidence: make conformance REQUIRED_IMPLS=shen-go PASS 13/13;
make quality green; all 13 suites ALL PASS directly. Four-port matrix
re-run remains owed before the next full-matrix gate claim.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK
The M1 exit demo no longer demonstrates itself. The stub counter world, the marker-grep oracle, and every hand-written verdict are deleted; all seven items are now produced by the production chain: urdr.run.execute on the partition-retry scenario discovers a liveness failure from a seed at attempt 2 (attempts 0-1 legitimately pass); shrink minimizes 28 -> 5 entries under an EVAL that re-drives the world and re-evaluates properties; replay verifies the minimized artifact and reproduces the verdicts; NetKAT and netpol items hold unchanged; the v2 certificate reports status FAIL, modeled-d1-analog, zero uncontrolled entropy, and names its five model bindings. The discovered failure is a real race, not a planted marker: the fault's early partition selection is delivered while the first reply is in flight, so the reply meets the cut at the network model and surfaces as a routed timeout; retries meet the cut fabric; the client gives up; no ack by deadline 8. A second temporal property (request-served, always-eventually) pins the unanswered request as a positive witness so the failure signature commits to a real artifact and the shrinker cannot empty the transcript. Design: the declared roster keeps all five component ids, each bound to a reference process model (shen/run/models/partition-retry.shen). Binding the built-in fault/net models under the driver is deferred with the reason recorded: the built-in fault republishes its menu every step and the driver resolves every open menu, so driver-run built-ins need a menu-quiescence policy that does not exist yet -- new kernel policy, not this wave's surgery. The one real kernel change: eventlog state digests move from the m0 to the m1-large profile -- a 5-component, 8-route snapshot decodes to ~330 nodes and m0's 256-node cap made every legally reached scenario-scale world unhashable; profiles bound but never change encoding bytes, so the change is digest-preserving (predicted zero golden movement outside integration; held exactly). docs/status/m1-5.md records the earned state and its non-claims (shen-go evidence lane, four-port sweep owed, built-ins-under-driver deferred, no-witness-only liveness until timer integration); docs/status/m1.md's stale digests are fixed with a lane note. Evidence: make conformance REQUIRED_IMPLS=shen-go PASS 13/13; make quality green; integration exact-golden and deterministic across repeated runs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK
urdr.model.registry.entry dispatches on the presence of a model before it ever consults the kind, so a roster entry of kind net/timer/fault that bound a model validated cleanly and built as that model's crash-aware process: the declared kind was silently discarded, the run driver's roster pre-check (which only rejects an unbound process) never saw it, and the certificate's models field records model and node but not kind, so the substitution left no trace in the evidence. ADR 0007 D3 only ever contemplates model bindings on process components. Fail closed at the validation door, before any registry or world exists: urdr.scenario.component-parts rejects a model bound on a non-process kind with the new stable code scenario-component-model-kind (after kind-unsupported, before unknown-node, so an unsupported kind still reports itself). The registry's dispatch is unchanged; validated scenarios can no longer reach it with the poisoned shape. New protocol fixture invalid/component-model-kind.frame -- the accepted component-model frame with its kind swapped to net -- pins the rejection beside the existing component-model-* cases; cases.tsv documents why validation is the only effective door, and the suite's count pin moves 103 -> 104. Deliberate re-pins, all scenario-parse, all three copies (goldens and SHA256SUMS are source inputs): the fixture manifest is regenerated for the new frame and the cases.tsv edit; bifrost.suite.json and scripts/bifrost-gate EXPECTED_CASES move program_sha256 (the count pin), fixture_manifest_sha256, and raw_golden_sha256 to the new four-port semantic digest. No other suite's pin moved. Evidence: make fmt-check and make test green; four-port scenario suite PASS cases=104 sha256=987d8aa830b1d5bacfa8b20d81ea57c677c32832a120d821 38038fcc375e5f5b on shen-cl/shen-go/shen-rust/shen-lua; the models, replay, integration, and run suites (the other loaders of scenario.shen) all PASS exact-golden on all four ports. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CONTRIBUTING.md makes accepted ADRs immutable historical records; that is exactly why these corrections must land now, while the ADR is still Proposed. This PR implements the decision in full, and ADR 0008, which depends on it, is already Accepted for M1.5 -- an implemented, depended-on ADR left Proposed misstates the record in the other direction. - Status: Proposed -> Accepted for M1.5, matching ADR 0008. - D4's decision text stated the route shape as [route FROM-COMPONENT FACT-NAME TARGET]. Everything implemented -- the scenario validator's route records (fields ascending fact < from < to), the world kernel's [route FACT FROM TARGET] values, and the rendering -- agrees on FACT-first, so the ADR text is what was wrong; corrected to [route FACT-NAME FROM-COMPONENT TARGET]. - D3 now states that the optional model binding is legal only on a process component and rejected at validation otherwise, matching the scenario-component-model-kind door landed with this acceptance. - Required verification items 2 and 5 are annotated as deferred rather than silently deleted or claimed: item 2's shrink and replay legs are explicitly the next wave per shen/run/run.shen's header scope note, and item 5's strategy-independence demonstration is absent because urdr.run.execute-with has no caller that configures the baseline strategy. Each annotation names the wave that owes the evidence, so acceptance claims no verification that does not exist. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both ports carried pre-existing code-generation defects that made them reject code the other two accept, and this PR is the first change deep enough to trip them: shen-lua 4e3b43a (pyrex41/shen-lua#53) - pattern-match codegen exceeded LuaJIT's parser nesting limit - the reader overflowed the Lua stack on block comments over ~7.2KB (shen/run/run.shen's header is 8092 bytes) shen-cl e48776d (pyrex41/shen-cl#12) - accessor chains rebuilt per conditional level: 802MB of compiler consing for one defun, fatal in a 1GB image - factorise-cases spliced its fallthrough twice, so generated code grew 2^groups; a 33-clause dispatch function was fatal Neither fix changes semantics: all four ports agree exact-golden on every suite, and each port's own kernel certification is unchanged (134/134 both, byte-identical report lines). Pins move in both places that carry them -- build/locks/shen-ports.lock.json and scripts/bifrost-gate EXPECTED_PINS -- and the launchers were rebuilt and re-stamped from the new commits with `make ports` before the gate ran. `make conformance` PASS, four ports, twelve cases, zero skips. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tion The deferral notes were written when items 2 and 5 were both owed. The exit demonstration has since been earned, so item 2's note was false as written and item 5's cross-reference pointed at a wave that has landed. Item 2 is now recorded as met, naming what actually produced it -- discovery at attempt 2, shrink 28 -> 5 under a re-driving EVAL, replay reproducing the verdicts, a v2 certificate reporting FAIL -- and carrying forward the two non-claims that survive it (built-ins are not resolvable under the driver; liveness failures are the no-witness form until timer integration). Item 5 stays deferred, because it genuinely is: urdr.run.execute-with still has no caller configuring `baseline`, so nothing demonstrates a boundary-discovered transcript replaying unchanged under another strategy. It is now recorded as a standalone debt rather than one riding on item 2. An ADR is a record of what was decided and what was proved. A deferral note that outlives its deferral is the same defect as an unearned claim, in the opposite direction. Co-Authored-By: Claude Opus 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.
Summary
This PR implements the production scenario execution driver (
urdr.run.execute) that composes the modeled laboratory's components into an end-to-end system. It adds fact routing with cascade guards, per-component model binding, pinned decision selection, and the step loop that drives seeded exploration through real scenarios with property verification.Key Changes
Core Driver Implementation
shen/run/run.shen(699 lines): the production driver implementing ADR 0007 decisions D1 (step loop), D2 (pinned selections), and D5 (budget enforcement)urdr.run.execute: main entry point taking a scenario and model table, returning discovered violations or exhausted attemptsWorld Routing (ADR 0007 D4)
shen/world/world.shenwith world/v2 adding a tenth slot for routing stateurdr.world.initial-with-routes: boot world with declared fact routesPer-Component Model Binding (ADR 0007 D3)
shen/world/component.shenwithselfreserved authority for component identityshen/world/models/registry.shento support optionalmodelfield in roster entriesselfScenario Extensions
shen/scenario/scenario.shento support optionalroutesfieldTesting & Validation
shen/tests/run/run-tests.shen(590 lines): comprehensive conformance suite with fixture modelsshen/tests/run/test.sh: multi-port golden output comparisonshen/tests/run/golden.txt: checked-in semantic output baselineurdr.component.entryconstructor for registry entriesDocumentation
docs/adr/0007-scenario-execution-and-fact-routing.md: comprehensive ADR covering all decisionsdocs/reviews/2026-07-29-deep-dive-persona-review.md: deep-dive review from four persona lenses identifying the composition gap and roadmapSupporting Changes
shen/world/integer.shen: O(log(N/D)) divmod instead of O(N/D) repeated subtractionshen/world/eventlog.shento encode selected choice entries with coordinates and selected alternativeshen/world/replay.shento handle both drawn (menu) and selected (menu + selection) choice payloadsshen/search/search.shenandshen/search/grammar.shento enforce canonical encoding order on choice alternativesshen/world/models/fault.shendocumentation to clarify crash/restart routingshen/tests/models/,shen/tests/search/,shen/tests/replay/,shen/tests/properties/,shen/tests/integration/to use newhttps://claude.ai/code/session_01NzxQMRqtNAXcyo5hTx8caK