diff --git a/.github/workflows/witnesses.yml b/.github/workflows/witnesses.yml index cd3d6d9c0b7..73dd67ff77f 100644 --- a/.github/workflows/witnesses.yml +++ b/.github/workflows/witnesses.yml @@ -8,6 +8,8 @@ on: description: Immutable healed commit required by an auto-heal revalidation run required: false type: string + schedule: + - cron: 17 9 * * * merge_group: push: branches: [main] @@ -31,6 +33,7 @@ jobs: required-witnesses-build: runs-on: [self-hosted, linux, arm64] timeout-minutes: 90 + if: github.event_name != 'schedule' steps: - name: Record runner filesystem at job start run: | @@ -114,6 +117,7 @@ jobs: required-witnesses-floor: runs-on: [self-hosted, linux, arm64] timeout-minutes: 180 + if: github.event_name != 'schedule' steps: - name: Record runner filesystem at job start run: | @@ -236,6 +240,7 @@ jobs: rust-unit-tests: runs-on: [self-hosted, linux, arm64] timeout-minutes: 60 + if: github.event_name != 'schedule' steps: - name: Record runner filesystem at job start run: | @@ -313,6 +318,7 @@ jobs: fabric-evidence: runs-on: [self-hosted, linux, arm64] timeout-minutes: 70 + if: github.event_name != 'schedule' steps: - name: Record runner filesystem at job start run: | @@ -594,11 +600,89 @@ jobs: if-no-files-found: error retention-days: 14 if: always() && steps.heal_commit_push.outputs.heal_author_commit_required == '1' + wet-receipts: + runs-on: [self-hosted, linux, arm64] + timeout-minutes: 360 + if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' + permissions: + contents: write + pull-requests: write + steps: + - name: Record runner filesystem at job start + run: | + # dissolve-on: toolchain_filesystem_probe -- delete the start/end runner-filesystem instrument after its joined readings identify and the fleet fixes the toolchain deleter, OR after per-job runner microVMs make the shared filesystem eviction class impossible + GUNBC_TOOLCHAIN_FS_PREFIX='GUNBC_TOOLCHAIN_FS phase=start' + echo "$GUNBC_TOOLCHAIN_FS_PREFIX time_utc=$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || echo unavailable) host=$(hostname 2>/dev/null || echo unavailable) runner=${RUNNER_NAME:-unset}" + echo "$GUNBC_TOOLCHAIN_FS_PREFIX runner_temp=${RUNNER_TEMP:-unset} rustup_home=${RUSTUP_HOME:-unset} cargo_home=${CARGO_HOME:-unset} uptime_seconds=$(cut -d' ' -f1 /proc/uptime 2>/dev/null || echo unavailable)" + echo "$GUNBC_TOOLCHAIN_FS_PREFIX loadavg=$(tr ' ' ',' < /proc/loadavg 2>/dev/null || echo unavailable)" + df -Pk "${RUNNER_TEMP:-/path-that-does-not-exist}" 2>&1 | while IFS= read -r GUNBC_TOOLCHAIN_FS_LINE; do echo "$GUNBC_TOOLCHAIN_FS_PREFIX df_blocks=$GUNBC_TOOLCHAIN_FS_LINE"; done + df -Pik "${RUNNER_TEMP:-/path-that-does-not-exist}" 2>&1 | while IFS= read -r GUNBC_TOOLCHAIN_FS_LINE; do echo "$GUNBC_TOOLCHAIN_FS_PREFIX df_inodes=$GUNBC_TOOLCHAIN_FS_LINE"; done + for GUNBC_TOOLCHAIN_FS_PATH in "${RUNNER_TEMP:-/path-that-does-not-exist}"/rustup/toolchains/*/bin/rustc "${RUNNER_TEMP:-/path-that-does-not-exist}"/rustup/toolchains/*/bin/rustfmt "${RUNNER_TEMP:-/path-that-does-not-exist}"/cargo/bin/cargo; do if [ -e "$GUNBC_TOOLCHAIN_FS_PATH" ]; then GUNBC_TOOLCHAIN_FS_STAT=$(stat -c 'size=%s mtime_epoch=%Y mtime=%y inode=%i' "$GUNBC_TOOLCHAIN_FS_PATH" 2>&1 || echo stat-unavailable); echo "$GUNBC_TOOLCHAIN_FS_PREFIX kind=file path=$GUNBC_TOOLCHAIN_FS_PATH exists=yes $GUNBC_TOOLCHAIN_FS_STAT"; else echo "$GUNBC_TOOLCHAIN_FS_PREFIX kind=file path=$GUNBC_TOOLCHAIN_FS_PATH exists=no size=unavailable mtime_epoch=unavailable mtime=unavailable inode=unavailable"; fi; done + for GUNBC_TOOLCHAIN_FS_PATH in "${RUNNER_TEMP:-/path-that-does-not-exist}"/rustup/toolchains/*/bin "${RUNNER_TEMP:-/path-that-does-not-exist}"/rustup/toolchains "${RUNNER_TEMP:-/path-that-does-not-exist}"/cargo/bin; do if [ -d "$GUNBC_TOOLCHAIN_FS_PATH" ]; then GUNBC_TOOLCHAIN_FS_STAT=$(stat -c 'mtime_epoch=%Y mtime=%y inode=%i' "$GUNBC_TOOLCHAIN_FS_PATH" 2>&1 || echo stat-unavailable); echo "$GUNBC_TOOLCHAIN_FS_PREFIX kind=directory path=$GUNBC_TOOLCHAIN_FS_PATH exists=yes $GUNBC_TOOLCHAIN_FS_STAT"; else echo "$GUNBC_TOOLCHAIN_FS_PREFIX kind=directory path=$GUNBC_TOOLCHAIN_FS_PATH exists=no mtime_epoch=unavailable mtime=unavailable inode=unavailable"; fi; done + if: always() + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + ref: ${{ inputs.expected_healed_sha || github.sha }} + - name: Refuse a heal revalidation whose run subject or checkout does not name the expected healed SHA + run: | + EXPECTED_HEALED_SHA="${{ inputs.expected_healed_sha }}" + RUN_SUBJECT_HEAD="${{ github.sha }}" + if [ -n "$EXPECTED_HEALED_SHA" ]; then + ACTUAL_HEAD="$(git rev-parse HEAD)" + if ! [ "$RUN_SUBJECT_HEAD" = "$EXPECTED_HEALED_SHA" ]; then + echo "::error::heal revalidation refused: workflow run subject $RUN_SUBJECT_HEAD does not equal expected healed head $EXPECTED_HEALED_SHA" + exit 1 + fi + if ! [ "$ACTUAL_HEAD" = "$EXPECTED_HEALED_SHA" ]; then + echo "::error::heal revalidation refused: checkout head $ACTUAL_HEAD does not equal expected healed head $EXPECTED_HEALED_SHA" + exit 1 + fi + echo "heal revalidation preflight: checkout names expected healed head $EXPECTED_HEALED_SHA" + fi + - name: Isolate toolchain homes + run: | + # dissolve-on: ci_toolchain_home_isolation_script -- orch-emitted foreign-executor prelude step wiping and setting HOME/CARGO_HOME/RUSTUP_HOME under RUNNER_TEMP so concurrent runner slots stop sharing one toolchain; leaf rm/echo strings remain until a typed per-job filesystem-and-environment effect lands on host_effect_apply (shell-to-intent Phase 2). This obligation covers THIS carrier and ci_isolate_toolchain_script, which share that terminal construction; ci_pin_rustup_default_script carries its own obligation because it does not + rm -rf "$RUNNER_TEMP/rustup" "$RUNNER_TEMP/cargo" + echo "HOME=$RUNNER_TEMP" >> "$GITHUB_ENV" + echo "CARGO_HOME=$RUNNER_TEMP/cargo" >> "$GITHUB_ENV" + echo "RUSTUP_HOME=$RUNNER_TEMP/rustup" >> "$GITHUB_ENV" + - name: Install Rust toolchain + uses: actions-rust-lang/setup-rust-toolchain@v1.16.0 + with: + components: rustfmt + cache: false + - name: Pin rustup default (isolated RUSTUP_HOME has no default toolchain) + run: | + # dissolve-on: ci_pin_rustup_default_script -- orch-emitted foreign-executor step selecting a rustup default toolchain inside an isolated RUSTUP_HOME, which starts with none, and resolving the cargo binary that selection implies. The leaf rustup/command/echo strings remain until a typed TOOLCHAIN-SELECTION effect lands on host_effect_apply -- NOT the filesystem-and-environment effect ci_toolchain_home_isolation_script waits on, which is why this is a separate obligation: that effect landing alone would leave this carrier standing + rustup default "$(rustup show active-toolchain | awk '{print $1; exit}')" + if [ -x "$CARGO_HOME/bin/cargo" ]; then CARGO_BIN="$CARGO_HOME/bin/cargo"; else CARGO_BIN="$(command -v cargo || true)"; fi + if [ -z "$CARGO_BIN" ]; then echo "::error::no cargo binary: neither the isolated $CARGO_HOME/bin/cargo shim nor PATH carries one"; exit 1; fi + echo "CARGO_BIN=$CARGO_BIN" >> "$GITHUB_ENV" + - name: Build the witness fold + id: build_witness_fold + run: | + cargo build --release -p v1-compiler --bin claim_batch --bin gunbc --bin cssl_assemble + - name: Wet receipts lane (rows named by the run, not by this label) + id: wet_receipts_run + run: | + ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) + cd "$ROOT" + 'target/release/claim_batch' '--wet-route' '--source-root' 'dag' '--source-root' 'src/v2' '--receipt-out' 'dag/gunbc/witness/wet_lane/latest-attempt.json' '--receipt-tsv-out' 'dag/gunbc/witness/wet_lane/latest-attempt.tsv' + - name: Upload the receipt artifact + uses: actions/upload-artifact@v4 + with: + name: wet-lane-receipt + path: dag/gunbc/witness/wet_lane + if-no-files-found: error + retention-days: 14 + if: "!cancelled() && steps.wet_receipts_run.outcome != 'skipped'" witnesses: runs-on: [self-hosted, linux, arm64] needs: [required-witnesses-build, required-witnesses-floor, rust-unit-tests] timeout-minutes: 5 - if: always() + if: always() && github.event_name != 'schedule' steps: - name: Every required lane must have succeeded run: | diff --git a/dag/extdeps/exec/command.dag b/dag/extdeps/exec/command.dag index 407a39eb0a5..fd75206e272 100644 --- a/dag/extdeps/exec/command.dag +++ b/dag/extdeps/exec/command.dag @@ -110,6 +110,7 @@ fn argv_command(program: NonEmptyStr, arguments: List) -> ArgvCommand decl_ref(module_path: "extdeps.tools.mkdir", decl_name: "mkdir_parents_command_at"), decl_ref(module_path: "extdeps.tools.mkdir", decl_name: "mkdir_exact_command_at"), decl_ref(module_path: "gunbc.claim_executor_cli", decl_name: "claim_executor_command"), + decl_ref(module_path: "gunbc.claim_executor_cli", decl_name: "claim_batch_command"), decl_ref(module_path: "gunbc.repo_local_git_config", decl_name: "reconcile_install_command"), ] = ArgvCommand { program: program, arguments: arguments } diff --git a/dag/gunbc/claim_executor_cli.dag b/dag/gunbc/claim_executor_cli.dag index dad854d0b1e..dc5355d292d 100644 --- a/dag/gunbc/claim_executor_cli.dag +++ b/dag/gunbc/claim_executor_cli.dag @@ -26,3 +26,14 @@ fn claim_executor_command(mode_flag: String, operands: List) -> ArgvComm arguments: append([mode_flag], items: operands), ) } + +// The sibling batch binary, same reasoning and same shape: built from this tree, flags owned +// here, path relative to the checkout the job stands in. +data claim_batch_release_path: NonEmptyStr = "target/release/claim_batch" + +fn claim_batch_command(mode_flag: String, operands: List) -> ArgvCommand { + argv_command( + program: claim_batch_release_path, + arguments: append([mode_flag], items: operands), + ) +} diff --git a/dag/gunbc/discovery_census.dag b/dag/gunbc/discovery_census.dag index 14917b32791..18b456e048a 100644 --- a/dag/gunbc/discovery_census.dag +++ b/dag/gunbc/discovery_census.dag @@ -14,6 +14,7 @@ import v2.workflow.required_floor { RequiredFloorDisposition, Planned, PlannedAsChangedWitness, DeclinedLongModule, DeclinedFixtureMember, DeclinedCostDebt, DeclinedOutsideRequiredGate, DeclinedOutsideGateClosure, DeclinedDiscoveryExcluded, + DeclinedRoutedToWetLane, required_floor_site_disposition, } import v2.std.live_tree { LiveTreeDisposition } @@ -265,6 +266,8 @@ fn census_partition_step(acc: CensusPartition, row: CensusRow) -> CensusPartitio CensusPartition { planned: acc.planned, declined: concat([row], acc.declined) } DeclinedDiscoveryExcluded { matched_substring: _ } => CensusPartition { planned: acc.planned, declined: concat([row], acc.declined) } + DeclinedRoutedToWetLane => + CensusPartition { planned: acc.planned, declined: concat([row], acc.declined) } } } @@ -338,6 +341,7 @@ type CensusCounts { declined_outside_required_gate: Int declined_outside_gate_closure: Int declined_discovery_excluded: Int + declined_routed_to_wet_lane: Int } fn census_counts_zero() -> CensusCounts { @@ -349,7 +353,8 @@ fn census_counts_zero() -> CensusCounts { declined_cost_debt: 0, declined_outside_required_gate: 0, declined_outside_gate_closure: 0, - declined_discovery_excluded: 0 + declined_discovery_excluded: 0, + declined_routed_to_wet_lane: 0 } } @@ -364,7 +369,8 @@ fn census_counts_add(counts: CensusCounts, d: RequiredFloorDisposition) -> Censu declined_cost_debt: counts.declined_cost_debt, declined_outside_required_gate: counts.declined_outside_required_gate, declined_outside_gate_closure: counts.declined_outside_gate_closure, - declined_discovery_excluded: counts.declined_discovery_excluded + declined_discovery_excluded: counts.declined_discovery_excluded, + declined_routed_to_wet_lane: counts.declined_routed_to_wet_lane } PlannedAsChangedWitness => CensusCounts { @@ -375,7 +381,8 @@ fn census_counts_add(counts: CensusCounts, d: RequiredFloorDisposition) -> Censu declined_cost_debt: counts.declined_cost_debt, declined_outside_required_gate: counts.declined_outside_required_gate, declined_outside_gate_closure: counts.declined_outside_gate_closure, - declined_discovery_excluded: counts.declined_discovery_excluded + declined_discovery_excluded: counts.declined_discovery_excluded, + declined_routed_to_wet_lane: counts.declined_routed_to_wet_lane } DeclinedLongModule { matched_prefix: _ } => CensusCounts { @@ -386,7 +393,8 @@ fn census_counts_add(counts: CensusCounts, d: RequiredFloorDisposition) -> Censu declined_cost_debt: counts.declined_cost_debt, declined_outside_required_gate: counts.declined_outside_required_gate, declined_outside_gate_closure: counts.declined_outside_gate_closure, - declined_discovery_excluded: counts.declined_discovery_excluded + declined_discovery_excluded: counts.declined_discovery_excluded, + declined_routed_to_wet_lane: counts.declined_routed_to_wet_lane } DeclinedFixtureMember { matched_prefix: _ } => CensusCounts { @@ -397,7 +405,8 @@ fn census_counts_add(counts: CensusCounts, d: RequiredFloorDisposition) -> Censu declined_cost_debt: counts.declined_cost_debt, declined_outside_required_gate: counts.declined_outside_required_gate, declined_outside_gate_closure: counts.declined_outside_gate_closure, - declined_discovery_excluded: counts.declined_discovery_excluded + declined_discovery_excluded: counts.declined_discovery_excluded, + declined_routed_to_wet_lane: counts.declined_routed_to_wet_lane } DeclinedCostDebt => CensusCounts { @@ -408,7 +417,8 @@ fn census_counts_add(counts: CensusCounts, d: RequiredFloorDisposition) -> Censu declined_cost_debt: counts.declined_cost_debt + 1, declined_outside_required_gate: counts.declined_outside_required_gate, declined_outside_gate_closure: counts.declined_outside_gate_closure, - declined_discovery_excluded: counts.declined_discovery_excluded + declined_discovery_excluded: counts.declined_discovery_excluded, + declined_routed_to_wet_lane: counts.declined_routed_to_wet_lane } DeclinedOutsideRequiredGate => CensusCounts { @@ -419,7 +429,8 @@ fn census_counts_add(counts: CensusCounts, d: RequiredFloorDisposition) -> Censu declined_cost_debt: counts.declined_cost_debt, declined_outside_required_gate: counts.declined_outside_required_gate + 1, declined_outside_gate_closure: counts.declined_outside_gate_closure, - declined_discovery_excluded: counts.declined_discovery_excluded + declined_discovery_excluded: counts.declined_discovery_excluded, + declined_routed_to_wet_lane: counts.declined_routed_to_wet_lane } DeclinedOutsideGateClosure => CensusCounts { @@ -430,7 +441,8 @@ fn census_counts_add(counts: CensusCounts, d: RequiredFloorDisposition) -> Censu declined_cost_debt: counts.declined_cost_debt, declined_outside_required_gate: counts.declined_outside_required_gate, declined_outside_gate_closure: counts.declined_outside_gate_closure + 1, - declined_discovery_excluded: counts.declined_discovery_excluded + declined_discovery_excluded: counts.declined_discovery_excluded, + declined_routed_to_wet_lane: counts.declined_routed_to_wet_lane } DeclinedDiscoveryExcluded { matched_substring: _ } => CensusCounts { @@ -441,7 +453,20 @@ fn census_counts_add(counts: CensusCounts, d: RequiredFloorDisposition) -> Censu declined_cost_debt: counts.declined_cost_debt, declined_outside_required_gate: counts.declined_outside_required_gate, declined_outside_gate_closure: counts.declined_outside_gate_closure, - declined_discovery_excluded: counts.declined_discovery_excluded + 1 + declined_discovery_excluded: counts.declined_discovery_excluded + 1, + declined_routed_to_wet_lane: counts.declined_routed_to_wet_lane + } + DeclinedRoutedToWetLane => + CensusCounts { + offered: counts.offered + 1, + planned: counts.planned, + declined_long_module: counts.declined_long_module, + declined_fixture_member: counts.declined_fixture_member, + declined_cost_debt: counts.declined_cost_debt, + declined_outside_required_gate: counts.declined_outside_required_gate, + declined_outside_gate_closure: counts.declined_outside_gate_closure, + declined_discovery_excluded: counts.declined_discovery_excluded, + declined_routed_to_wet_lane: counts.declined_routed_to_wet_lane + 1 } } } diff --git a/dag/gunbc/explicit_witness_admission.dag b/dag/gunbc/explicit_witness_admission.dag index 2d3eb36d83a..76a35b5a60d 100644 --- a/dag/gunbc/explicit_witness_admission.dag +++ b/dag/gunbc/explicit_witness_admission.dag @@ -272,12 +272,84 @@ data explicit_witness_admissions: List = [ dissolution: unbound_dissolution(description: "every leaf reaches LeafEstablished by execution — this row deletes in the completing change, promoting the unchanged group root to ordinary DiscoverySelection as the lane's permanent regression wall") ), known_red_probe( - entry: "dag/test/claim/self_host_parse_engine_hooks_behavioral_witness_test.dag", - f: "self_host_parse_engine_hooks_behavioral_receipt_holds", + entry: "dag/test/claim/self_host_00_compile_behavioral_witness_test.dag", + f: "self_host_00_compile_behavioral_receipt_holds", kind: ExecutionWitnessKind, budget: FastLaneEvalBudget, - reason: "SelfEmitted wet behavioral receipt, red on assemble (cargo/shim closure refuse — unresolved std_algebra/std_types/std_nat/List; cadence run 30126573464). Phase-0 forbids SelfEmitted-with-zero-executing-consumer, so it runs Wet expect_red on the falsifier quarantine batch; still-red is agreement. Owner: #7199 falsifier lane / self-host assemble.", - dissolution: unbound_dissolution(description: "the local wet receipt greens under gunbc_falsifier_self_host_wet_receipt_wall_budget; this row deletes and the green wet SelfHostWetReceiptBinding restores") + reason: "Wet-route behavioral receipt, MEASURED assertion-false in the committed wet-lane envelope — the in-tree receipt dag/gunbc/witness/wet_lane/latest-attempt.json carries this identity's row and its run provenance (the instrument is the wet receipts lane, claim_batch --wet-route; re-derive by dispatching it): the emitted self-host crate refuses at rustc under the declared toolchain/lint contract (non-snake-case emitted module names such as `pub mod Optional`, plus v1_compiled type errors), so the behavioral comparison never reaches agreement. Enrolled per the per-identity join ruling 2026-08-30 (wall 3: this authority is the ONLY expected-red roster the wet join consumes).", + dissolution: unbound_dissolution(description: "this identity produces Pass in a fresh candidate-exact wet receipt after the emitted self-host crate is accepted under the declared Rust toolchain/lint contract — at which point the pass is observed as now-passing by the wet join and this row deletes in the same change") + ), + known_red_probe( + entry: "dag/test/claim/self_host_01_tokenize_behavioral_witness_test.dag", + f: "self_host_01_tokenize_behavioral_receipt_holds", + kind: ExecutionWitnessKind, + budget: FastLaneEvalBudget, + reason: "Wet-route behavioral receipt, MEASURED assertion-false in the committed wet-lane envelope — the in-tree receipt dag/gunbc/witness/wet_lane/latest-attempt.json carries this identity's row and its run provenance (the instrument is the wet receipts lane, claim_batch --wet-route; re-derive by dispatching it): the emitted self-host crate refuses at rustc under the declared toolchain/lint contract (non-snake-case emitted module names such as `pub mod Optional`, plus v1_compiled type errors), so the behavioral comparison never reaches agreement. Enrolled per the per-identity join ruling 2026-08-30 (wall 3: this authority is the ONLY expected-red roster the wet join consumes).", + dissolution: unbound_dissolution(description: "this identity produces Pass in a fresh candidate-exact wet receipt after the emitted self-host crate is accepted under the declared Rust toolchain/lint contract — at which point the pass is observed as now-passing by the wet join and this row deletes in the same change") + ), + known_red_probe( + entry: "dag/test/claim/self_host_02_parse_behavioral_witness_test.dag", + f: "self_host_02_parse_behavioral_receipt_holds", + kind: ExecutionWitnessKind, + budget: FastLaneEvalBudget, + reason: "Wet-route behavioral receipt, MEASURED assertion-false in the committed wet-lane envelope — the in-tree receipt dag/gunbc/witness/wet_lane/latest-attempt.json carries this identity's row and its run provenance (the instrument is the wet receipts lane, claim_batch --wet-route; re-derive by dispatching it): the emitted self-host crate refuses at rustc under the declared toolchain/lint contract (non-snake-case emitted module names such as `pub mod Optional`, plus v1_compiled type errors), so the behavioral comparison never reaches agreement. Enrolled per the per-identity join ruling 2026-08-30 (wall 3: this authority is the ONLY expected-red roster the wet join consumes).", + dissolution: unbound_dissolution(description: "this identity produces Pass in a fresh candidate-exact wet receipt after the emitted self-host crate is accepted under the declared Rust toolchain/lint contract — at which point the pass is observed as now-passing by the wet join and this row deletes in the same change") + ), + known_red_probe( + entry: "dag/test/claim/self_host_03_ingest_behavioral_witness_test.dag", + f: "self_host_03_ingest_behavioral_receipt_holds", + kind: ExecutionWitnessKind, + budget: FastLaneEvalBudget, + reason: "Wet-route behavioral receipt, MEASURED assertion-false in the committed wet-lane envelope — the in-tree receipt dag/gunbc/witness/wet_lane/latest-attempt.json carries this identity's row and its run provenance (the instrument is the wet receipts lane, claim_batch --wet-route; re-derive by dispatching it): the emitted self-host crate refuses at rustc under the declared toolchain/lint contract (non-snake-case emitted module names such as `pub mod Optional`, plus v1_compiled type errors), so the behavioral comparison never reaches agreement. Enrolled per the per-identity join ruling 2026-08-30 (wall 3: this authority is the ONLY expected-red roster the wet join consumes).", + dissolution: unbound_dissolution(description: "this identity produces Pass in a fresh candidate-exact wet receipt after the emitted self-host crate is accepted under the declared Rust toolchain/lint contract — at which point the pass is observed as now-passing by the wet join and this row deletes in the same change") + ), + known_red_probe( + entry: "dag/test/claim/self_host_03_resolve_behavioral_witness_test.dag", + f: "self_host_03_resolve_behavioral_receipt_holds", + kind: ExecutionWitnessKind, + budget: FastLaneEvalBudget, + reason: "Wet-route behavioral receipt, MEASURED assertion-false in the committed wet-lane envelope — the in-tree receipt dag/gunbc/witness/wet_lane/latest-attempt.json carries this identity's row and its run provenance (the instrument is the wet receipts lane, claim_batch --wet-route; re-derive by dispatching it): the emitted self-host crate refuses at rustc under the declared toolchain/lint contract (non-snake-case emitted module names such as `pub mod Optional`, plus v1_compiled type errors), so the behavioral comparison never reaches agreement. Enrolled per the per-identity join ruling 2026-08-30 (wall 3: this authority is the ONLY expected-red roster the wet join consumes).", + dissolution: unbound_dissolution(description: "this identity produces Pass in a fresh candidate-exact wet receipt after the emitted self-host crate is accepted under the declared Rust toolchain/lint contract — at which point the pass is observed as now-passing by the wet join and this row deletes in the same change") + ), + known_red_probe( + entry: "dag/test/claim/self_host_04_infer_behavioral_witness_test.dag", + f: "self_host_04_infer_behavioral_receipt_holds", + kind: ExecutionWitnessKind, + budget: FastLaneEvalBudget, + reason: "Wet-route behavioral receipt, MEASURED assertion-false in the committed wet-lane envelope — the in-tree receipt dag/gunbc/witness/wet_lane/latest-attempt.json carries this identity's row and its run provenance (the instrument is the wet receipts lane, claim_batch --wet-route; re-derive by dispatching it): the emitted self-host crate refuses at rustc under the declared toolchain/lint contract (non-snake-case emitted module names such as `pub mod Optional`, plus v1_compiled type errors), so the behavioral comparison never reaches agreement. Enrolled per the per-identity join ruling 2026-08-30 (wall 3: this authority is the ONLY expected-red roster the wet join consumes).", + dissolution: unbound_dissolution(description: "this identity produces Pass in a fresh candidate-exact wet receipt after the emitted self-host crate is accepted under the declared Rust toolchain/lint contract — at which point the pass is observed as now-passing by the wet join and this row deletes in the same change") + ), + known_red_probe( + entry: "dag/test/claim/self_host_materialization_carriers_behavioral_witness_test.dag", + f: "self_host_materialization_carriers_behavioral_receipt_holds", + kind: ExecutionWitnessKind, + budget: FastLaneEvalBudget, + reason: "Wet-route behavioral receipt, MEASURED assertion-false in the committed wet-lane envelope — the in-tree receipt dag/gunbc/witness/wet_lane/latest-attempt.json carries this identity's row and its run provenance (the instrument is the wet receipts lane, claim_batch --wet-route; re-derive by dispatching it): the emitted self-host crate refuses at rustc under the declared toolchain/lint contract (non-snake-case emitted module names such as `pub mod Optional`, plus v1_compiled type errors), so the behavioral comparison never reaches agreement. Enrolled per the per-identity join ruling 2026-08-30 (wall 3: this authority is the ONLY expected-red roster the wet join consumes).", + dissolution: unbound_dissolution(description: "this identity produces Pass in a fresh candidate-exact wet receipt after the emitted self-host crate is accepted under the declared Rust toolchain/lint contract — at which point the pass is observed as now-passing by the wet join and this row deletes in the same change") + ), + known_red_probe( + entry: "dag/test/claim/self_host_program_assembly_behavioral_witness_test.dag", + f: "self_host_program_assembly_behavioral_receipt_holds", + kind: ExecutionWitnessKind, + budget: FastLaneEvalBudget, + reason: "Wet-route behavioral receipt, MEASURED assertion-false in the committed wet-lane envelope — the in-tree receipt dag/gunbc/witness/wet_lane/latest-attempt.json carries this identity's row and its run provenance (the instrument is the wet receipts lane, claim_batch --wet-route; re-derive by dispatching it): the emitted self-host crate refuses at rustc under the declared toolchain/lint contract (non-snake-case emitted module names such as `pub mod Optional`, plus v1_compiled type errors), so the behavioral comparison never reaches agreement. Enrolled per the per-identity join ruling 2026-08-30 (wall 3: this authority is the ONLY expected-red roster the wet join consumes).", + dissolution: unbound_dissolution(description: "this identity produces Pass in a fresh candidate-exact wet receipt after the emitted self-host crate is accepted under the declared Rust toolchain/lint contract — at which point the pass is observed as now-passing by the wet join and this row deletes in the same change") + ), + known_red_probe( + entry: "dag/test/claim/self_host_program_partition_behavioral_witness_test.dag", + f: "self_host_program_partition_behavioral_receipt_holds", + kind: ExecutionWitnessKind, + budget: FastLaneEvalBudget, + reason: "Wet-route behavioral receipt, MEASURED assertion-false in the committed wet-lane envelope — the in-tree receipt dag/gunbc/witness/wet_lane/latest-attempt.json carries this identity's row and its run provenance (the instrument is the wet receipts lane, claim_batch --wet-route; re-derive by dispatching it): the emitted self-host crate refuses at rustc under the declared toolchain/lint contract (non-snake-case emitted module names such as `pub mod Optional`, plus v1_compiled type errors), so the behavioral comparison never reaches agreement. Enrolled per the per-identity join ruling 2026-08-30 (wall 3: this authority is the ONLY expected-red roster the wet join consumes).", + dissolution: unbound_dissolution(description: "this identity produces Pass in a fresh candidate-exact wet receipt after the emitted self-host crate is accepted under the declared Rust toolchain/lint contract — at which point the pass is observed as now-passing by the wet join and this row deletes in the same change") + ), + known_red_probe( + entry: "dag/test/claim/self_host_source_authority_behavioral_witness_test.dag", + f: "self_host_source_authority_behavioral_receipt_holds", + kind: ExecutionWitnessKind, + budget: FastLaneEvalBudget, + reason: "Wet-route behavioral receipt, MEASURED assertion-false in the committed wet-lane envelope — the in-tree receipt dag/gunbc/witness/wet_lane/latest-attempt.json carries this identity's row and its run provenance (the instrument is the wet receipts lane, claim_batch --wet-route; re-derive by dispatching it): the emitted self-host crate refuses at rustc under the declared toolchain/lint contract (non-snake-case emitted module names such as `pub mod Optional`, plus v1_compiled type errors), so the behavioral comparison never reaches agreement. Enrolled per the per-identity join ruling 2026-08-30 (wall 3: this authority is the ONLY expected-red roster the wet join consumes).", + dissolution: unbound_dissolution(description: "this identity produces Pass in a fresh candidate-exact wet receipt after the emitted self-host crate is accepted under the declared Rust toolchain/lint contract — at which point the pass is observed as now-passing by the wet join and this row deletes in the same change") ), known_red_probe( entry: "dag/test/claim/self_host_use_site_verdict_behavioral_witness_test.dag", diff --git a/dag/gunbc/floor/floor_wet_route_seed_growth.dag b/dag/gunbc/floor/floor_wet_route_seed_growth.dag new file mode 100644 index 00000000000..1730c452a2a --- /dev/null +++ b/dag/gunbc/floor/floor_wet_route_seed_growth.dag @@ -0,0 +1,41 @@ +module gunbc.floor_wet_route_seed_growth + +import gunbc.roadmap_model { RoadmapNodeId } +import gunbc.seed_growth { SeedGrowthJustification } +import std.decl_ref { DeclarationRef, WholeDeclaration } + +// FORWARD-FREEZE RECEIPT for the wet execution route consumed by the required floor and +// produced by the wet receipts lane. The modeled authority is v2.workflow.floor_wet_route +// (WetRouteRow, WetReceiptEnvelope, WetLaneReceiptStanding, the standing fold and the +// roster); these declarations are its seed-side realization at the two boundaries the model +// cannot reach itself — the floor's envelope join and the lane's executor — not a second +// policy. +data floor_wet_route_seed_growth_justification: SeedGrowthJustification = SeedGrowthJustification { + hand_authored_declarations: [ + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "WetReceiptEnvelope", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "WetReceiptIdentityRow", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "read_wet_receipt_envelope", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "wet_receipt_tsv_projection", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "wet_subject_digest", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "wet_executor_contract_digest", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "wet_receipt_publication_transaction_valid_for_this_run", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "wet_lane_receipt_standing", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "wet_receipt_identity_verdicts", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "WetLaneReceiptStanding", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "WetRouteLaneRow", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "wet_route_lane_rows", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "WetLaneExecutedReceipt", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "write_wet_receipt_envelope", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "wet_subject_entry_subjects", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "WET_OUTCOME_WIRES", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "WetIdentityVerdicts", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "WetBootstrapLease", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "WetSeedBootstrapAdmission", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "wet_seed_bootstrap_admission", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.cli_run", decl_name: "wet_seed_bootstrap_lease_declared", field: WholeDeclaration } + ], + reason: "WHY RUST IS STILL NEEDED: the required floor executes in the seed, and the wet receipts lane executes real host effects through the seed interpreter. v2.workflow.floor_wet_route owns the routed population, the receipt vocabulary and the staleness budget; the Rust realization decodes that authority at two boundaries the model cannot yet reach itself. On the floor side, read_wet_receipt_envelope parses the lane's committed envelope pair (refusing on any drift between the JSON authority and its canonical TSV projection, which wet_receipt_tsv_projection defines once for writer and reader), wet_subject_digest computes the candidate tree's validity key from the same resolver the lane uses, and wet_lane_receipt_standing realizes the modeled seven-arm envelope standing so the run refuses when the receipt is missing, expired, ancestor-subject, executor-snapshot-different, contract-broken or roster-inexact, and wet_receipt_identity_verdicts realizes the per-identity join against the explicit_witness_admission projection (unexpected red and no-verdict rows block; enrolled reds hold; enrolled passes red as now-passing) — a modeled roster with no consumer at this boundary would let 'routed to wet' decay into a skip list, which is the coverage-by-illusion class the route exists to refuse. On the lane side, wet_route_lane_rows derives the executable population from the same roster at run time (never a second list in YAML or argv) and write_wet_receipt_envelope is the single producer of the pair the floor's reader consumes, one projection function so the two cannot disagree.\n\nWHY IT IS ADMITTED AGAINST THE v1 FREEZE: gunbc.v1_maintenance_standing v1_seed_standing admits work serving the v2 self-host program. The routed population IS the self-host behavioral evidence — DESIGN section 7's proof-by-execution — which sat entirely in route_gap_held with no executing route. It adds no language behavior, compatibility route, escape hatch, seed feature, or emitted public surface, and it opens no flag that suppresses the join: the only dispositions are a fresh receipt, a typed refusal, or the lane executing for real.\n\nHAND-ITEM DELTA: +21, exactly the envelope types, their reader/projection/writer, the two digest producers (semantic subject and executor contract), the standing type and fold, the per-identity verdict join, and the publication-transaction observer (floor side), and the roster row type with its decoder and the executed-receipt row type (lane side), enumerated above. The DeclinedRoutedToWetLane arm is a variant on the pre-existing RequiredFloorDisposition enum; wet_route_standing_blocking, stale_wet_route and declined_routed_to_wet_lane are fields on the pre-existing RequiredFloorOutcome; the site-loop decline, the contradiction walls, the changed-witness candidate-exact arm and the claim_batch --wet-route branch are inside declarations that already existed.\n\nTHE ROSTER UNDERCOUNTED ITSELF BY SEVEN AND THAT IS RECORDED RATHER THAN QUIETLY CORRECTED (review 59187, 2026-09-03). It claimed +14 while the stage0 diff carried twenty-one hand-authored wet declarations: wet_subject_entry_subjects (the subject enumerator the digest folds over), WET_OUTCOME_WIRES (the outcome wire spelling shared by writer and reader), WetIdentityVerdicts (the per-identity join's result carrier), and the four bootstrap-lease surfaces -- WetBootstrapLease, WetSeedBootstrapAdmission, wet_seed_bootstrap_admission and wet_seed_bootstrap_lease_declared. The review named three of the seven; the census that found the other four enumerates every top-level wet-named declaration in the seed file and subtracts those already present on main, because the local-repo wet lane's own declarations share the prefix and are NOT this route's growth. WHY IT MATTERS BEYOND THE COUNT: an under-enumerated roster does not merely misreport a number, it exempts the unnamed surfaces from the dissolution trigger below, so they would survive the deletion this row promises and no check would notice -- section 7 requires a declared row per retained surface precisely so the seed cannot grow silently. The four lease surfaces are the ones to watch, since the lease is one-shot by construction and its dissolution is the earliest of the seven.", + owning_dissolution_lane: "v1-hand-queue-drain" as RoadmapNodeId, + trigger: "Delete the enumerated seed declarations when the self-emitted claim executor consumes v2.workflow.floor_wet_route directly — the modeled roster, receipt and staleness fold then remain the sole authority and the hand-written decode/join/writer disappear with the v1 floor bridge.", + current_boundary: "v2.workflow.floor_wet_route WetRouteRow/WetReceiptEnvelope/WetLaneReceiptStanding -> v1_compiler.cli_run wet_route_lane_rows/read_wet_receipt_envelope/wet_subject_digest/wet_lane_receipt_standing -> v1_compiler.cli_run run_required_floor and the claim_batch --wet-route lane" +} diff --git a/dag/gunbc/floor/wet_seed_bootstrap_lease.dag b/dag/gunbc/floor/wet_seed_bootstrap_lease.dag new file mode 100644 index 00000000000..7b54e66ffc8 --- /dev/null +++ b/dag/gunbc/floor/wet_seed_bootstrap_lease.dag @@ -0,0 +1,96 @@ +module gunbc.wet_seed_bootstrap_lease + +import v2.workflow.floor_wet_route { BootstrapExecutorSnapshotReceipt } +import v2.std.optional { Optional, Absent, Present } +import std.types { EpochSecs } + +// THE DECLARED ONE-SHOT BOOTSTRAP LEASE ROW (parent lease ruling 2026-08-30), homed OUTSIDE +// the wet semantic closure on purpose: `v2.workflow.floor_wet_route` is inside its own wet +// subject digest, so a lease row declared there would move the semantic digest when flipped +// Absent→Present and invalidate the very envelope it exists to admit. This module imports +// the route authority (downward edge only — no routed witness closure imports this module), +// so flipping this row, like a receipt-pair refresh, moves neither digest. +// +// Absent is the standing state, and IT IS THE STATE TODAY: no lease is declared, so nothing +// here is currently waived. NO `gunbc.rung_drop` ROW EXISTS FOR THIS MECHANISM YET, and none +// is owed while the row is Absent — an unexercised mechanism regresses no rung. An earlier +// revision of this comment named `gunbc.rung_drop` `wet_executor_bootstrap_lease` as though it +// were a live citation (review 57856); it was a forward obligation wearing the grammar of a +// reference, which §3 refuses because a reader cannot tell the two apart by reading. Stated as +// the obligation it is: flipping this row to Present is admissible ONLY in a push that also +// authors the matching `gunbc.rung_drop` row, naming the envelope it admits, and only under an +// operator grant — the flip and the drop row are one transaction, and neither exists yet. The +// admission semantics — exact envelope-digest/attempt-seq/subject/roster join, the fixed +// executed_at + 28,800s window with `not_after` derived and checked — are owned by +// `v2.workflow.floor_wet_route.wet_seed_bootstrap_admission`, which takes this row as a +// parameter; this module carries only the declaration. +// +// TWO LIFECYCLES, AND THEY ARE NOT THE SAME EVENT (parent ruling 2026-08-31, lifecycle +// correction). An earlier revision of this comment said the row "deletes in the same +// transaction as the first exact-main receipt (the rung-drop row's restoration)", fusing them; +// both halves were wrong. +// THIS OPERATIONAL ROW must REMAIN IN THE MERGED TREE for as long as v7 is executor-different. +// Deleting it in v7's own merge would leave main immediately red for exactly the mismatch the +// merge just admitted. It deletes with the first executor-exact receipt refresh, or at its +// fixed expiry — whichever comes first. +// THE RUNG-DROP ROW does not retire on v7's merge, on this row's deletion, or on one receipt +// that happens to land executor-exact. It retires only on its capability-shaped trigger, +// because the executor race is structural and recurs on every later candidate. +// +// THIS RULING AUTHORIZES v7 ONLY. The earlier lease retired unexercised; this is not a rolling +// renewal, and no successor lease is authorized by it. A v8 row would need its own ruling and +// its own drop row. +// +// WHY THIS ROW IS `Absent` AND THE MECHANISM AROUND IT IS NOT (parent ruling 2026-08-31, +// SHAPE 1). The wet subject digest folds the closure subject of `v2.workflow.floor_wet_route` +// itself — that module is one of the digest's own entries — so the lease TYPE and ADMISSION +// FUNCTION, which cannot live anywhere else without splitting the authority, MOVE THE VERY +// DIGEST A LEASE EXISTS TO ADMIT. An envelope executed before the mechanism landed is therefore +// never candidate-exact against a head that carries the mechanism, and a lease naming it could +// never be admitted. That is self-defeating in the same shape as the transform-in-the-subject +// defect this route already repaired. +// +// So the mechanism lands FIRST, with this row `Absent` and no envelope claim, and the wet lane +// is dispatched afterwards ON THE TREE THAT CARRIES IT. That run's envelope is semantic-exact by +// construction. If no executor drift occurs while it runs, no lease is needed at all — which is +// the outcome to prefer, because the ruling that authorized a lease authorized ONE envelope (v7) +// and explicitly authorized no successor. Flipping this row again requires its own grant. + +// FLIPPED TO PRESENT 2026-09-03, UNDER AN OPERATOR GRANT AND NOT A MANAGER RULING. The grant +// was given by the operator in response to an escalation on gunbc#9725, which is the authority +// this module's paragraph above reserves the flip to. It is recorded as an operator grant +// deliberately: the escalating lane refused to self-authorize and its manager refused to grant +// what the artifact reserves to the operator, so a later reader must be able to tell which +// authority actually answered. A manager decision here would have been authorization inherited +// from an adjacent authority, which is the thing the reservation exists to stop. +// +// WHAT MOVED, AND IT IS THE RACE THIS MECHANISM WAS BUILT FOR, EXERCISED FOR THE FIRST TIME ON +// A REAL RECEIPT. The wet lane ran 2h31m on run 33745596102. Its SEMANTIC subject digest still +// matches the evaluated tree exactly -- the floor's own refusal says so, "the same semantic +// subject ran under a superseded seed build". Only the EXECUTOR axis moved: the envelope was +// executed under seed executor b6a2c43b and the evaluated tree computes 3dcd74ec, because CI +// evaluates the MERGE REF and main merged src/v1/stage0 while the lane was running. No semantic +// fact changed under the receipt; the seed it ran on was superseded mid-flight. +// +// THIS ROW ADMITS EXACTLY ONE ENVELOPE AND CANNOT BE READ AS A STANDING PERMISSION. All four +// exact facts below are pinned with no wildcard: the envelope digest is the sha256 of the +// committed latest-attempt.json bytes, the attempt_seq, the semantic subject digest, and the +// roster digest. `wet_seed_bootstrap_admission` refuses with NotApplicable if ANY of the four +// fails to join, so a later receipt -- a refresh, a re-dispatch, a second attempt -- does not +// inherit this admission and needs its own grant. The grant covers this receipt and nothing +// after it. +// +// THE WINDOW IS CLOSED-FORM AND CHECKED AGAINST THE EVALUATED TREE'S COMMIT TIME, not against +// wall clock at read time, so the admission cannot be extended by re-running later. +data wet_seed_bootstrap_lease_declared: Optional = Present { + value: BootstrapExecutorSnapshotReceipt { + lease_identity: "wet-executor-bootstrap-2026-09-03-run-33745596102", + exact_envelope_digest: "ffa6ca1592d15448ebb454343f80daa51f357c5f84e8b5e7b131c9410b675be7", + exact_attempt_seq: 1, + exact_semantic_subject_digest: "b6aee692e0fb274d3ca76a8089a6fda05b2d86ea8c46dd2a4bbd6c14c070b493", + exact_roster_digest: "ab78f9748327de68df15f8e0bb6521180ad3fb5a9b6342409e0d27e928668fdf", + observed_executor_contract_digest: "b6a2c43b221f78196425310dad8b0ff410e2d9f1f33727abe13beca6d11d9188", + executed_at_unix_secs: 1788432786 as EpochSecs, + not_after_unix_secs: 1788461586 as EpochSecs + } +} diff --git a/dag/gunbc/guarantee_stall.dag b/dag/gunbc/guarantee_stall.dag index fc134e51d90..b9963ba53ea 100644 --- a/dag/gunbc/guarantee_stall.dag +++ b/dag/gunbc/guarantee_stall.dag @@ -670,6 +670,87 @@ data authority_target_same_expression_equivalence_stall: GuaranteeStall = Guaran next_rung_trigger: "a lane that runs ONE expression through BOTH realizations and refuses a divergence, sufficient for an emission differing from its authority in value OR in what it evaluates being caught, demonstrated by a red on a fixture where the two agree on the returned value and differ on which subexpressions ran; the fixture is already executed and dated on gunbc#10139, so what is owed is enrolment and not a harness, and enrolling behavioral_differential discharges the seed-Rust versus emitted-Rust axis ONLY and does not touch this row" } +// THE SEED REIMPLEMENTS THE WET GATE RATHER THAN INVOKING IT (gunbc#9725). Filed as a STALL and +// deliberately NOT as a `gunbc.rung_drop` row, because nothing regressed: the executing path never +// held the fused guarantee, so there is no previous rung to record and no runway to expire. A drop +// row asserts THIS WAS BETTER AND WILL BE AGAIN; this asserts THIS HAS NEVER BEEN BETTER AND HERE IS +// WHAT WOULD MAKE IT SO. Filing it as a drop would fabricate a previous rung that never executed -- +// rung inflation arriving through the ledger rather than through a diagnostic, and the worse kind, +// because a drop row reads as evidence of past rigour. +// +// THE MODEL PATH IS AT THE CEILING AND THE EXECUTING PATH IS NOT. `v2.workflow.floor_wet_route` +// `wet_route_gate_disposition_for_receipt` derives the bootstrap admission from the same envelope it +// derives the standing from, so the mismatched pair has no constructor there. The seed does not call +// it: `src/v1/stage0` contains no invocation of `wet_route_gate_disposition`, only two comments +// citing it, and the admission that gates a real dispatch is the seed's own `matches!` over its own +// standing and admission types. DESIGN 4b(1) takes the MINIMUM across in-scope paths, so the class +// sits at the executing path's rung and not the model's. +// +// WHAT HOLDS THE PAIRING TODAY, in these words because a reader who has only "mitigatable" will not +// rank it: LEXICAL PROXIMITY AND A COMMENT. Two crate-visible producers are called at one production +// site each, in one straight-line block, both derived from one envelope, and the pairing is read off +// two locals. Nothing derives or checks the relation. There is no parameter position for a caller to +// supply a foreign standing because there is no other caller: the invalid state is WRITABLE and is +// not currently written. +data wet_lane_seed_admission_pairing_stall: GuaranteeStall = GuaranteeStall { + subject: "the seed's wet-lane admission decision is REIMPLEMENTED in v1_compiler.cli_run.required_floor_runner rather than taken from the fused entry v2.workflow.floor_wet_route wet_route_gate_disposition_for_receipt, so the pairing of receipt standing with bootstrap-lease admission is held by lexical proximity and a comment on the path that actually gates a dispatch", + current: Mitigatable, + ceiling: StructurallyImpossible, + blocker: ClimbableButUnbuilt, + population: BoundedPopulation { + members: ["v1_compiler.cli_run.required_floor_runner -- the single production site pairing wet_lane_receipt_standing with wet_seed_bootstrap_admission, one decision, both producers crate-visible and callable independently"] + }, + next_rung_trigger: "THE SEED'S ADMISSION DECISION IS TAKEN BY THE FUSED ENTRY RATHER THAN REIMPLEMENTED, **AND** v2.workflow.floor_wet_route CARRIES THE THREE REPAIRS THE SEED ALREADY MAKES: the executor arm evaluated LAST rather than fifth of nine, the envelope digest DERIVED FROM the envelope rather than accepted beside it, and a negative age REFUSED rather than clamped. BOTH HALVES ARE THE TRIGGER AND THE SECOND IS NOT DECORATION: the port makes the seed take the .dag answer, so against today's .dag it would RESTORE all three defects, and a trigger whose satisfaction regresses its own class is worse than no trigger because it retires the row that would have warned. Vehicle: the seed decoder port inside the wet-route authority cutover, SUFFICIENT FOR preserving every refusal the seed currently makes -- not when it merely decodes the same types, and not when a second implementation is shown to agree. Agreement between two implementations retires nothing here, because the class is that there are two." +} + +// THE MODEL LAGS THE SEED ON THREE NAMED DEFECTS, WHICH IS THE DIVERGENCE RUNNING BACKWARDS +// (gunbc#9725). The substrate is supposed to be the authority and the seed one realization of it; +// here the EXECUTING path is strictly stricter than the authored model, on three counts that were +// repaired in `v1_compiler.cli_run.required_floor_runner` and not in `v2.workflow.floor_wet_route`. +// +// WHY THE MODEL WAS NOT REPAIRED WITH IT, and it is a hard constraint rather than a preference: +// that module is a TERM OF THE WET SEMANTIC SUBJECT, and the subject is `closure_content_digest` +// over RAW FILE CONTENT. Any byte changed there -- a comment included -- moves the digest the +// committed receipt is pinned to and voids the operator-granted lease that admits it, forcing a +// ~2.5h re-dispatch and a second grant to repair an artifact that has no executing consumer. +// +// THE DIVERGENCE DIRECTION IS SAFE AND STILL WRONG. A stricter seed cannot ADMIT anything the +// model would refuse, so nothing is fail-open today; what is wrong is that the authority is the +// laggard, so a reader consulting the substrate learns the weaker rule and any consumer generated +// from it inherits the weaker rule. It is filed as a countable debt rather than left inside the +// admission stall's prose, because it will be invisible the moment that PR merges. +data wet_route_model_lags_seed_stall: GuaranteeStall = GuaranteeStall { + subject: "v2.workflow.floor_wet_route authors rules its own seed realization has already superseded, the population being exactly the members enumerated below rather than any number stated here: the executor arm returns fifth of nine rather than last (so ExecutorSnapshotDifferent means only that executor disagreement was the FIRST blocking arm reached, with roster join, identity conformance, outcome vocabulary, age sanity and staleness unevaluated); wet_route_gate_disposition_for_receipt accepts `envelope` and `envelope_digest` as independent parameters rather than deriving the digest from the envelope it judges; the same function takes `roster_identities` and `roster_digest` as a second independent subject/digest pair; wet_route_identity_rows_block_with_publication waives ALL FOUR per-identity classes under a valid publication transaction where only unexpected_red and now_passing are waivable; and the negative-age arm, while present here, is the one the seed had to be taught separately", + current: Mitigatable, + ceiling: StructurallyGuaranteed, + blocker: ClimbableButUnbuilt, + population: BoundedPopulation { + members: [ + "v2.workflow.floor_wet_route wet_lane_receipt_standing -- executor arm ordered fifth of nine", + "v2.workflow.floor_wet_route wet_route_gate_disposition_for_receipt -- envelope and envelope_digest are independent parameters, demonstrated constructible by v2.test.floor_wet_route.wet_lease_admits_an_envelope_whose_content_the_digest_does_not_name", + "v2.workflow.floor_wet_route wet_route_gate_disposition_for_receipt -- roster_identities and roster_digest are a SECOND independent subject/digest pair in the same signature, the recurrence that makes the shape a class rather than an instance", + "v2.workflow.floor_wet_route wet_route_identity_rows_block_with_publication -- returns false unconditionally under a valid publication transaction, waiving no_verdict and cost_debt alongside the two waivable classes; the seed refuses both regardless (review 59383)", + "v2.workflow.floor_wet_route -- the module is a term of its own semantic subject, so repairing it requires a re-dispatch and a fresh lease grant" + ] + }, + next_rung_trigger: "every rule enumerated in this row's population is authored in v2.workflow.floor_wet_route itself, landed on a head whose wet receipt was dispatched AFTER them so the subject digest covers them -- which means the repair rides a re-dispatch rather than waiting for one, and the admitting witness above flips from a recorded observation to a refusal control in the same change. NOT satisfied by the seed continuing to be stricter, which is the state this row exists to count." +} + +data wet_receipt_wall_ms_fabricated_on_refusal_arms_stall: GuaranteeStall = GuaranteeStall { + subject: "v2.workflow.floor_wet_route WetReceiptIdentityRow declares `wall_ms: Milliseconds` NON-OPTIONAL, so the two pre-execution refusal arms in v1_compiler.bin.claim_batch -- entry resolve failed, closure subject failed -- must write a synthesized `0` for a duration that was never measured. NOTHING RAN, so `0ms` is not a fast execution: it is the absence of one, and any consumer that averages, sorts or thresholds on wall_ms without first branching on the outcome wire reads a fabricated measurement. The tell is inside the same struct literal: `observed_entry_rel` and `observed_function` are Optional and correctly written as None on exactly these arms, with an annotation above the type stating that a fabricated observation is the plausible output DESIGN section 5 forbids -- and wall_ms fabricates one two fields later. Found by review 59401 on gunbc#9725; the prose/body disagreement is a specimen of gunbc.recurring_failure_mode subject_and_its_digest_as_independent_parameters, third face", + current: Mitigatable, + ceiling: StructurallyImpossible, + blocker: ClimbableButUnbuilt, + population: BoundedPopulation { + members: [ + "v1_compiler.bin.claim_batch -- the entry-resolve-failed receipt arm writes wall_ms: 0", + "v1_compiler.bin.claim_batch -- the closure-subject-failed receipt arm writes wall_ms: 0", + "v2.workflow.floor_wet_route WetReceiptIdentityRow -- the field whose type forces both" + ] + }, + next_rung_trigger: "wall_ms carried as Optional, so an unmeasured duration has NO CONSTRUCTOR that produces a number and every consumer must eliminate the absence before arithmetic -- and a wet receipt actually DISPATCHED under that schema, because the schema change alone leaves the committed envelope carrying the old shape. NOT satisfied by a consumer that branches on the outcome wire, which is the mitigation this row is counting; and not by editing the type alone, because v2.workflow.floor_wet_route is a term of its own semantic subject and the change rides a re-dispatch" +} + // THE DELIBERATELY DROPPED HALF OF gunbc#10258'S DISPLAY CONTRACT. That lane printed module // identity beside source path from ResolvedGraph, but only after typed resolution. The // loader-boundary preflight that replaced it answers the actual landing decision at its native @@ -688,6 +769,9 @@ data pre_resolve_entry_closure_module_identity_stall: GuaranteeStall = Guarantee data all_guarantee_stalls: List = [ pre_resolve_entry_closure_module_identity_stall, + wet_receipt_wall_ms_fabricated_on_refusal_arms_stall, + wet_route_model_lags_seed_stall, + wet_lane_seed_admission_pairing_stall, generated_artifact_registry_membership_stall, authority_target_same_expression_equivalence_stall, runner_microvm_guest_size_derivation_stall, diff --git a/dag/gunbc/rung_drop.dag b/dag/gunbc/rung_drop.dag index cfc198e503f..897467e459b 100644 --- a/dag/gunbc/rung_drop.dag +++ b/dag/gunbc/rung_drop.dag @@ -493,7 +493,36 @@ data floor_cut_behavioural_regression_differential: RungDrop = RungDrop { identi data floor_cut_receipt_discriminating_arms: RungDrop = RungDrop { identity: "floor_cut_receipt_discriminating_arms" as NonEmptyStr, subject: "The receipt machinery's own discriminating arms", declared: "2026-09-03", standing: Standing, declaration: AuthoredProse { legacy: FloorCutReceiptDiscriminatingArms, authored: "**THE RECEIPT MACHINERY'S OWN DISCRIMINATING ARMS HAVE NO EXECUTING CONSUMER, AND THIS ROW DECLARES THAT RUNG (2026-09-03).** Split out of `floor_cut`, third of the three losses its own prose names and its five siblings omit. PREVIOUS RUNG: 2 (mechanically preventable). TEMPORARY RUNG: 1 (mitigatable) -- the selftest and census targets exist (`behavioral-receipt-selftest`, `behavioral-receipt-census`) and `floor_cut` records that no workflow invokes them. WHY THIS IS ITS OWN SUBJECT AND NOT A DETAIL OF THE TWO ABOVE, which is the whole reason it must not be folded into them: a differential's value is entirely in whether it still GOES RED on a real divergence, and that property is established by its discriminating arms and by nothing else. Restoring an equivalence comparison whose own falsification controls never execute yields an instrument that reports EQUIVALENT and cannot be shown to be capable of reporting anything else -- DESIGN section 4b(4) keeps the discriminating RED enrolled precisely so a climb does not dissolve the evidence that the higher rung is real. BOUNDED POPULATION: one capability -- executing evidence that the receipt machinery can still distinguish an equivalent emission from a divergent one. RESTORATION TRIGGER, A CAPABILITY: the receipt machinery's falsification controls executing on the required path, SUFFICIENT FOR a deliberately divergent fixture producing a RED from that machinery in a required lane. **`floor_cut` CANNOT RETIRE WHILE THIS ROW STANDS.**" } } + +// THE ONE-SHOT EXECUTOR-SNAPSHOT ADMISSION, GRANTED BY OPERATOR RULING 2026-09-03 IN RESPONSE TO +// AN ESCALATION ON gunbc#9725. Recorded as an OPERATOR grant and not a manager ruling, because +// the reservation in gunbc.wet_seed_bootstrap_lease names the operator and a reader must be able +// to tell which authority answered: the escalating lane refused to self-authorize, and its +// manager refused to grant what the artifact reserves to the operator. +// +// WHAT IS ADMITTED, AND IT IS NARROW BY CONSTRUCTION. One envelope, pinned on four exact facts +// (envelope digest, attempt_seq, semantic subject digest, roster digest) with no wildcard, past +// exactly one standing -- ReceiptExecutorSnapshotDifferent -- and never past a semantic-subject, +// contract, roster, expiry or missing standing. The SEMANTIC subject matched the evaluated tree +// exactly; the floor's own refusal says "the same semantic subject ran under a superseded seed +// build". Only the executor axis moved, and it moved because CI evaluates the MERGE REF while +// main merged src/v1/stage0 during a 2h31m dispatch. +// +// THIS IS A DECLARED SAFETY REGRESSION WITH A FINITE RUNWAY, NOT A FIX. What is lost for the +// duration: the floor accepts a receipt whose executing seed is not the evaluated tree's seed, +// so for this one envelope the executor axis is asserted rather than verified. The window is +// closed-form -- executed_at plus a fixed 28,800s, checked against the EVALUATED TREE'S COMMIT +// TIME rather than wall clock, so it cannot be extended by re-running later. +// +// AND THE MECHANISM WORKED, INCLUDING THE PART WHERE IT STOPPED THE AUTHOR. The axis moved under +// a live run and the outcome was a typed refusal naming both digests, an escalation to the named +// authority, and a bounded grant -- not a silent stale-evidence admission, and not a lost 2h31m +// dispatch. A lease that admits nothing until someone with the authority says so is the shape +// this row is evidence for. +data wet_executor_bootstrap_lease: RungDrop = RungDrop { identity: "wet_executor_bootstrap_lease" as NonEmptyStr, subject: "The wet-lane receipt executor-contract axis, for exactly one envelope: run 33745596102, attempt_seq 1, envelope digest ffa6ca15", declared: "2026-09-03", standing: Standing, declaration: TypedDeclaration { previous: StructurallyGuaranteed, temporary: Mitigatable, reason: ReplacementStaged { replacement: "gunbc.wet_seed_bootstrap_lease wet_seed_bootstrap_lease_declared -- the declared one-shot lease, pinned to four exact facts and refusing with NotApplicable if any fails to join, so no later receipt inherits this admission" }, population: ["one wet-lane receipt envelope: run 33745596102, attempt_seq 1, envelope digest ffa6ca1592d15448ebb454343f80daa51f357c5f84e8b5e7b131c9410b675be7, admitted past ReceiptExecutorSnapshotDifferent and no other standing"], restoration_trigger: "THE EXECUTOR AXIS IS DERIVED FROM THE EVALUATED TREE RATHER THAN THE DISPATCH TREE. The artifact must be SUFFICIENT FOR this: a dispatch whose executor contract moves mid-run produces a receipt admissible with NO grant, because the axis the floor checks is a property of the tree being evaluated and not of the seed the lane happened to execute on. NOT satisfied by the next receipt landing executor-exact, and NOT by the executor snapshot happening to match -- both are luck while the capability stays dead, and a trigger a favourable runner slot can fire names less than the capability it restores." } } + data rung_drop_roster: List = [ + wet_executor_bootstrap_lease, floor_cut_heal, floor_cut_effect_gates, floor_cut_fmt_gate, diff --git a/dag/gunbc/seed_growth_admission.dag b/dag/gunbc/seed_growth_admission.dag index ae71aa7ffda..c90241b1b15 100644 --- a/dag/gunbc/seed_growth_admission.dag +++ b/dag/gunbc/seed_growth_admission.dag @@ -58,6 +58,7 @@ import gunbc.seed_growth { SeedGrowthJustification } import gunbc.stage0_rust_host_observation { stage0_rust_observation_seed_growth_justification } import gunbc.floor_non_verdict_enrollment { floor_non_verdict_seed_growth_justification } import gunbc.floor_route_gap_seed_growth { floor_route_gap_seed_growth_justification } +import gunbc.floor_wet_route_seed_growth { floor_wet_route_seed_growth_justification } import gunbc.cross_claim_pure_share_seed_growth { cross_claim_pure_share_seed_growth_justification } import gunbc.cross_claim_demand_census_seed_growth { cross_claim_demand_census_seed_growth_justification } import gunbc.frame_independent_symbol_seed_growth { frame_independent_symbol_seed_growth_justification } @@ -201,6 +202,7 @@ fn seed_growth_justification_roster() -> List { anonymous_record_resolution_seed_growth_justification, floor_non_verdict_seed_growth_justification, floor_route_gap_seed_growth_justification, + floor_wet_route_seed_growth_justification, floor_cost_debt_seed_growth_justification, cross_claim_pure_share_seed_growth_justification, cross_claim_demand_census_seed_growth_justification, diff --git a/dag/gunbc/v1/v1_witness_census.dag b/dag/gunbc/v1/v1_witness_census.dag index 552b486205f..48393a0a2e4 100644 --- a/dag/gunbc/v1/v1_witness_census.dag +++ b/dag/gunbc/v1/v1_witness_census.dag @@ -6,7 +6,8 @@ import std.dissolution { DissolutionCondition, unbound_dissolution } import gunbc.replacement_cut { EvidenceDisposition, ReenrollAgainstY, ReplaceEvidence, RetireEvidence } import v2.workflow.required_floor { RequiredFloorDisposition, Planned, PlannedAsChangedWitness, DeclinedLongModule, DeclinedFixtureMember, DeclinedOutsideRequiredGate, - DeclinedOutsideGateClosure, DeclinedDiscoveryExcluded, DeclinedCostDebt + DeclinedOutsideGateClosure, DeclinedDiscoveryExcluded, DeclinedCostDebt, + DeclinedRoutedToWetLane } // XL-5's SECOND DELIVERABLE: the wall that stops the bankruptcy transaction greening by LOSING @@ -124,6 +125,7 @@ fn floor_standing_is_fixture_member(s: RequiredFloorDisposition) -> Bool { DeclinedOutsideGateClosure => false DeclinedDiscoveryExcluded { matched_substring: _ } => false DeclinedCostDebt => false + DeclinedRoutedToWetLane => false } } diff --git a/dag/gunbc/witness/wet_lane/latest-attempt.json b/dag/gunbc/witness/wet_lane/latest-attempt.json new file mode 100644 index 00000000000..37d727c47b5 --- /dev/null +++ b/dag/gunbc/witness/wet_lane/latest-attempt.json @@ -0,0 +1,173 @@ +{ + "schema_version": 2, + "subject_digest": "b6aee692e0fb274d3ca76a8089a6fda05b2d86ea8c46dd2a4bbd6c14c070b493", + "executor_contract_digest": "b6a2c43b221f78196425310dad8b0ff410e2d9f1f33727abe13beca6d11d9188", + "attempt_seq": 1, + "executed_at_unix_secs": 1788432786, + "published_at_unix_secs": 1788441447, + "run_id": "33745596102", + "head_sha": "7ef0e5db32401bb75aa107f70b23b39f2543b550", + "rows": [ + { + "identity": "test.claim.self_host_00_compile_behavioral_witness.self_host_00_compile_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 657785, + "observed_entry_rel": "dag/test/claim/self_host_00_compile_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_00_compile_behavioral_witness.self_host_00_compile_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_01_tokenize_behavioral_witness.self_host_01_tokenize_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 400579, + "observed_entry_rel": "dag/test/claim/self_host_01_tokenize_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_01_tokenize_behavioral_witness.self_host_01_tokenize_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_02_parse_behavioral_witness.self_host_02_parse_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 486237, + "observed_entry_rel": "dag/test/claim/self_host_02_parse_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_02_parse_behavioral_witness.self_host_02_parse_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_03_ingest_behavioral_witness.self_host_03_ingest_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 707036, + "observed_entry_rel": "dag/test/claim/self_host_03_ingest_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_03_ingest_behavioral_witness.self_host_03_ingest_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_03_normalize_behavioral_witness.self_host_03_normalize_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 423348, + "observed_entry_rel": "dag/test/claim/self_host_03_normalize_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_03_normalize_behavioral_witness.self_host_03_normalize_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_03_resolve_behavioral_witness.self_host_03_resolve_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 439636, + "observed_entry_rel": "dag/test/claim/self_host_03_resolve_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_03_resolve_behavioral_witness.self_host_03_resolve_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_04_infer_behavioral_witness.self_host_04_infer_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 567946, + "observed_entry_rel": "dag/test/claim/self_host_04_infer_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_04_infer_behavioral_witness.self_host_04_infer_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_artifact_materialization_real_execution_witness.a_real_cargo_build_materializes_through_the_real_digest", + "outcome": "pass", + "wall_ms": 273, + "observed_entry_rel": "dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag", + "observed_function": "test.claim.self_host_artifact_materialization_real_execution_witness.a_real_cargo_build_materializes_through_the_real_digest" + }, + { + "identity": "test.claim.self_host_artifact_materialization_real_execution_witness.a_target_the_build_never_produced_refuses_and_does_not_materialize", + "outcome": "pass", + "wall_ms": 274, + "observed_entry_rel": "dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag", + "observed_function": "test.claim.self_host_artifact_materialization_real_execution_witness.a_target_the_build_never_produced_refuses_and_does_not_materialize" + }, + { + "identity": "test.claim.self_host_artifact_materialization_real_execution_witness.changing_only_the_source_bytes_names_exactly_the_artifact_axis", + "outcome": "pass", + "wall_ms": 493, + "observed_entry_rel": "dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag", + "observed_function": "test.claim.self_host_artifact_materialization_real_execution_witness.changing_only_the_source_bytes_names_exactly_the_artifact_axis" + }, + { + "identity": "test.claim.self_host_artifact_materialization_real_execution_witness.rebuilding_identical_source_in_place_moves_no_axis", + "outcome": "pass", + "wall_ms": 487, + "observed_entry_rel": "dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag", + "observed_function": "test.claim.self_host_artifact_materialization_real_execution_witness.rebuilding_identical_source_in_place_moves_no_axis" + }, + { + "identity": "test.claim.self_host_artifact_materialization_real_execution_witness.the_digest_is_of_the_file_cargo_named_not_of_some_other_real_file", + "outcome": "pass", + "wall_ms": 288, + "observed_entry_rel": "dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag", + "observed_function": "test.claim.self_host_artifact_materialization_real_execution_witness.the_digest_is_of_the_file_cargo_named_not_of_some_other_real_file" + }, + { + "identity": "test.claim.self_host_artifact_materialization_real_execution_witness.the_materialized_path_is_the_one_the_real_cargo_stream_named", + "outcome": "pass", + "wall_ms": 281, + "observed_entry_rel": "dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag", + "observed_function": "test.claim.self_host_artifact_materialization_real_execution_witness.the_materialized_path_is_the_one_the_real_cargo_stream_named" + }, + { + "identity": "test.claim.self_host_body_producer_behavioral_witness.self_host_body_producer_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 418978, + "observed_entry_rel": "dag/test/claim/self_host_body_producer_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_body_producer_behavioral_witness.self_host_body_producer_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_discovery_enumeration_behavioral_witness.self_host_discovery_enumeration_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 458046, + "observed_entry_rel": "dag/test/claim/self_host_discovery_enumeration_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_discovery_enumeration_behavioral_witness.self_host_discovery_enumeration_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_logic_behavioral_witness.self_host_logic_behavioral_receipt_holds", + "outcome": "pass", + "wall_ms": 178087, + "observed_entry_rel": "dag/test/claim/self_host_logic_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_logic_behavioral_witness.self_host_logic_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_materialization_carriers_behavioral_witness.self_host_materialization_carriers_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 376290, + "observed_entry_rel": "dag/test/claim/self_host_materialization_carriers_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_materialization_carriers_behavioral_witness.self_host_materialization_carriers_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_parse_engine_hooks_behavioral_witness.self_host_parse_engine_hooks_behavioral_receipt_holds", + "outcome": "pass", + "wall_ms": 493566, + "observed_entry_rel": "dag/test/claim/self_host_parse_engine_hooks_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_parse_engine_hooks_behavioral_witness.self_host_parse_engine_hooks_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_program_assembly_behavioral_witness.self_host_program_assembly_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 617240, + "observed_entry_rel": "dag/test/claim/self_host_program_assembly_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_program_assembly_behavioral_witness.self_host_program_assembly_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_program_partition_behavioral_witness.self_host_program_partition_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 502858, + "observed_entry_rel": "dag/test/claim/self_host_program_partition_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_program_partition_behavioral_witness.self_host_program_partition_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_source_authority_behavioral_witness.self_host_source_authority_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 593703, + "observed_entry_rel": "dag/test/claim/self_host_source_authority_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_source_authority_behavioral_witness.self_host_source_authority_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_target_carriers_behavioral_witness.self_host_target_carriers_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 632448, + "observed_entry_rel": "dag/test/claim/self_host_target_carriers_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_target_carriers_behavioral_witness.self_host_target_carriers_behavioral_receipt_holds" + }, + { + "identity": "test.claim.self_host_use_site_verdict_behavioral_witness.self_host_use_site_verdict_behavioral_receipt_holds", + "outcome": "assertion-false", + "wall_ms": 618291, + "observed_entry_rel": "dag/test/claim/self_host_use_site_verdict_behavioral_witness_test.dag", + "observed_function": "test.claim.self_host_use_site_verdict_behavioral_witness.self_host_use_site_verdict_behavioral_receipt_holds" + } + ] +} diff --git a/dag/gunbc/witness/wet_lane/latest-attempt.tsv b/dag/gunbc/witness/wet_lane/latest-attempt.tsv new file mode 100644 index 00000000000..a43153da905 --- /dev/null +++ b/dag/gunbc/witness/wet_lane/latest-attempt.tsv @@ -0,0 +1,26 @@ +# generated projection of the wet-lane receipt envelope (latest-attempt.json). Edit neither file by hand: the required floor re-projects and refuses on any drift. +# schema_version=2 subject_digest=b6aee692e0fb274d3ca76a8089a6fda05b2d86ea8c46dd2a4bbd6c14c070b493 executor_contract_digest=b6a2c43b221f78196425310dad8b0ff410e2d9f1f33727abe13beca6d11d9188 attempt_seq=1 executed_at_unix_secs=1788432786 published_at_unix_secs=1788441447 run_id=33745596102 head_sha=7ef0e5db32401bb75aa107f70b23b39f2543b550 +# identity outcome wall_ms observed_entry_rel observed_function +test.claim.self_host_00_compile_behavioral_witness.self_host_00_compile_behavioral_receipt_holds assertion-false 657785 dag/test/claim/self_host_00_compile_behavioral_witness_test.dag test.claim.self_host_00_compile_behavioral_witness.self_host_00_compile_behavioral_receipt_holds +test.claim.self_host_01_tokenize_behavioral_witness.self_host_01_tokenize_behavioral_receipt_holds assertion-false 400579 dag/test/claim/self_host_01_tokenize_behavioral_witness_test.dag test.claim.self_host_01_tokenize_behavioral_witness.self_host_01_tokenize_behavioral_receipt_holds +test.claim.self_host_02_parse_behavioral_witness.self_host_02_parse_behavioral_receipt_holds assertion-false 486237 dag/test/claim/self_host_02_parse_behavioral_witness_test.dag test.claim.self_host_02_parse_behavioral_witness.self_host_02_parse_behavioral_receipt_holds +test.claim.self_host_03_ingest_behavioral_witness.self_host_03_ingest_behavioral_receipt_holds assertion-false 707036 dag/test/claim/self_host_03_ingest_behavioral_witness_test.dag test.claim.self_host_03_ingest_behavioral_witness.self_host_03_ingest_behavioral_receipt_holds +test.claim.self_host_03_normalize_behavioral_witness.self_host_03_normalize_behavioral_receipt_holds assertion-false 423348 dag/test/claim/self_host_03_normalize_behavioral_witness_test.dag test.claim.self_host_03_normalize_behavioral_witness.self_host_03_normalize_behavioral_receipt_holds +test.claim.self_host_03_resolve_behavioral_witness.self_host_03_resolve_behavioral_receipt_holds assertion-false 439636 dag/test/claim/self_host_03_resolve_behavioral_witness_test.dag test.claim.self_host_03_resolve_behavioral_witness.self_host_03_resolve_behavioral_receipt_holds +test.claim.self_host_04_infer_behavioral_witness.self_host_04_infer_behavioral_receipt_holds assertion-false 567946 dag/test/claim/self_host_04_infer_behavioral_witness_test.dag test.claim.self_host_04_infer_behavioral_witness.self_host_04_infer_behavioral_receipt_holds +test.claim.self_host_artifact_materialization_real_execution_witness.a_real_cargo_build_materializes_through_the_real_digest pass 273 dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag test.claim.self_host_artifact_materialization_real_execution_witness.a_real_cargo_build_materializes_through_the_real_digest +test.claim.self_host_artifact_materialization_real_execution_witness.a_target_the_build_never_produced_refuses_and_does_not_materialize pass 274 dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag test.claim.self_host_artifact_materialization_real_execution_witness.a_target_the_build_never_produced_refuses_and_does_not_materialize +test.claim.self_host_artifact_materialization_real_execution_witness.changing_only_the_source_bytes_names_exactly_the_artifact_axis pass 493 dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag test.claim.self_host_artifact_materialization_real_execution_witness.changing_only_the_source_bytes_names_exactly_the_artifact_axis +test.claim.self_host_artifact_materialization_real_execution_witness.rebuilding_identical_source_in_place_moves_no_axis pass 487 dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag test.claim.self_host_artifact_materialization_real_execution_witness.rebuilding_identical_source_in_place_moves_no_axis +test.claim.self_host_artifact_materialization_real_execution_witness.the_digest_is_of_the_file_cargo_named_not_of_some_other_real_file pass 288 dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag test.claim.self_host_artifact_materialization_real_execution_witness.the_digest_is_of_the_file_cargo_named_not_of_some_other_real_file +test.claim.self_host_artifact_materialization_real_execution_witness.the_materialized_path_is_the_one_the_real_cargo_stream_named pass 281 dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag test.claim.self_host_artifact_materialization_real_execution_witness.the_materialized_path_is_the_one_the_real_cargo_stream_named +test.claim.self_host_body_producer_behavioral_witness.self_host_body_producer_behavioral_receipt_holds assertion-false 418978 dag/test/claim/self_host_body_producer_behavioral_witness_test.dag test.claim.self_host_body_producer_behavioral_witness.self_host_body_producer_behavioral_receipt_holds +test.claim.self_host_discovery_enumeration_behavioral_witness.self_host_discovery_enumeration_behavioral_receipt_holds assertion-false 458046 dag/test/claim/self_host_discovery_enumeration_behavioral_witness_test.dag test.claim.self_host_discovery_enumeration_behavioral_witness.self_host_discovery_enumeration_behavioral_receipt_holds +test.claim.self_host_logic_behavioral_witness.self_host_logic_behavioral_receipt_holds pass 178087 dag/test/claim/self_host_logic_behavioral_witness_test.dag test.claim.self_host_logic_behavioral_witness.self_host_logic_behavioral_receipt_holds +test.claim.self_host_materialization_carriers_behavioral_witness.self_host_materialization_carriers_behavioral_receipt_holds assertion-false 376290 dag/test/claim/self_host_materialization_carriers_behavioral_witness_test.dag test.claim.self_host_materialization_carriers_behavioral_witness.self_host_materialization_carriers_behavioral_receipt_holds +test.claim.self_host_parse_engine_hooks_behavioral_witness.self_host_parse_engine_hooks_behavioral_receipt_holds pass 493566 dag/test/claim/self_host_parse_engine_hooks_behavioral_witness_test.dag test.claim.self_host_parse_engine_hooks_behavioral_witness.self_host_parse_engine_hooks_behavioral_receipt_holds +test.claim.self_host_program_assembly_behavioral_witness.self_host_program_assembly_behavioral_receipt_holds assertion-false 617240 dag/test/claim/self_host_program_assembly_behavioral_witness_test.dag test.claim.self_host_program_assembly_behavioral_witness.self_host_program_assembly_behavioral_receipt_holds +test.claim.self_host_program_partition_behavioral_witness.self_host_program_partition_behavioral_receipt_holds assertion-false 502858 dag/test/claim/self_host_program_partition_behavioral_witness_test.dag test.claim.self_host_program_partition_behavioral_witness.self_host_program_partition_behavioral_receipt_holds +test.claim.self_host_source_authority_behavioral_witness.self_host_source_authority_behavioral_receipt_holds assertion-false 593703 dag/test/claim/self_host_source_authority_behavioral_witness_test.dag test.claim.self_host_source_authority_behavioral_witness.self_host_source_authority_behavioral_receipt_holds +test.claim.self_host_target_carriers_behavioral_witness.self_host_target_carriers_behavioral_receipt_holds assertion-false 632448 dag/test/claim/self_host_target_carriers_behavioral_witness_test.dag test.claim.self_host_target_carriers_behavioral_witness.self_host_target_carriers_behavioral_receipt_holds +test.claim.self_host_use_site_verdict_behavioral_witness.self_host_use_site_verdict_behavioral_receipt_holds assertion-false 618291 dag/test/claim/self_host_use_site_verdict_behavioral_witness_test.dag test.claim.self_host_use_site_verdict_behavioral_witness.self_host_use_site_verdict_behavioral_receipt_holds diff --git a/dag/gunbc/witness/witness_floor_workflow.dag b/dag/gunbc/witness/witness_floor_workflow.dag index 2cdc055e4cf..12269325539 100644 --- a/dag/gunbc/witness/witness_floor_workflow.dag +++ b/dag/gunbc/witness/witness_floor_workflow.dag @@ -40,10 +40,10 @@ import gunbc.compile_permit_scope { import extdeps.github.actions { Workflow, Job, Step, RunStep, UsesStep, upload_artifact_action, - WorkflowTrigger, Push, PullRequest, WorkflowDispatch, + WorkflowTrigger, Push, PullRequest, WorkflowDispatch, Schedule, PullRequestActivity, Opened, Synchronize, Reopened, DispatchInput, InputString, - WorkflowPermissions, PermRead, + WorkflowPermissions, PermRead, PermWrite, ConcurrencySpec, ConcurrencyMappingQueueNotMax, ConcurrencyMappingQueueMax, CancelInProgressSpec, CancelInProgressBool, CancelInProgressExpression, CancelInProgressWhenQueueMax, QueueMaxCancelInProgressFalse, QueueMaxCancelInProgressExpression, @@ -68,6 +68,9 @@ import gunbc.repo_identity { gunbc_default_branch_name } import gunbc.merge_admission_produce { ci_repo_root_shell } import gunbc.ci_layer_roots { witness_layer_roots } import gunbc.fabric_witness_run { witnesses_lane_run_command, build_lane_run_command } +import gunbc.claim_executor_cli { claim_batch_command } +import extdeps.cron.schedule_model { CronSchedule, Wildcard } +import v2.workflow.floor_wet_route { floor_wet_route_receipt_json_rel_path, floor_wet_route_receipt_tsv_rel_path } import extdeps.exec.command { ArgvCommand, shell_command_render } import gunbc.required_lanes_gate { RequiredLane, required_lanes_gate_stmts } import extdeps.github.expressions { ContextAccess, Github, Needs, interpolate } @@ -1568,7 +1571,7 @@ fn witness_floor_job() -> Job { needs: [], env: none, outputs: none, - if_condition: none, + if_condition: Present { value: not_on_wet_cadence_condition() }, timeout_minutes: 180, continue_on_error: none, concurrency: none, @@ -1767,7 +1770,7 @@ fn rust_unit_tests_job() -> Job { needs: [], env: none, outputs: none, - if_condition: none, + if_condition: Present { value: not_on_wet_cadence_condition() }, timeout_minutes: 60, continue_on_error: none, concurrency: none, @@ -1775,6 +1778,195 @@ fn rust_unit_tests_job() -> Job { } } +// ═══════════════════════════════════════════════════════════════════════════════════════════ +// THE WET RECEIPTS LANE (parent ruling 2026-08-30, FLOOR-ROUTE-GAP-SELF-HOST). A separate, +// NON-REQUIRED job that executes the `v2.workflow.floor_wet_route` roster with real effects — +// a real gunbc emit, real cargo builds of the seed-linked shims, real driver runs — and lands +// the per-identity receipt the required floor's DeclinedRoutedToWetLane join refuses without. +// It runs on a daily schedule and on manual dispatch, never per pull request and never as a +// required context: one seed-linked behavioral receipt alone measured ~305s of witness wall +// (gunbc#9371), which the 2026-08-29 bankruptcy ruling prices off the required path. +// +// THE POPULATION IS DERIVED, NEVER SPELLED HERE: `claim_batch --wet-route` reads +// `floor_wet_route_roster` from the .dag authority at run time, so a roster edit needs no +// workflow regeneration and no second list can drift. The receipt — a latest-attempt JSON +// envelope keyed by the wet subject digest, plus its canonical TSV projection (authority +// `v2.workflow.floor_wet_route`) — reaches main by PULL REQUEST (transport a' as amended, +// same ruling): this job uploads the refreshed pair as a run artifact and writes nothing, and +// a PERSON opens the carrying PR; merging stays under the ordinary rule. No bot push to the +// protected default branch, and no API read anywhere on the required path — the floor only +// ever reads the committed pair. A RECEIPT MERGE CANNOT RELAUNCH THIS LANE by construction +// rather than by path filter: the job's condition admits only schedule and +// workflow_dispatch, and a merge to main is a push event, so the amendment's +// no-relaunch requirement holds without a paths: clause to drift. +// ═══════════════════════════════════════════════════════════════════════════════════════════ + +// THE REQUIRED LANES DO NOT RUN ON THE WET CADENCE. The schedule trigger exists for the +// wet-receipts job alone; without this condition every daily tick would also pay a full +// required floor, a whole-workspace build and the unit-test job on an unchanged main — cost +// with no new subject, against the 2026-08-29 bankruptcy's whole point. Skipped-on-schedule is +// safe for the required context because a schedule run guards no merge: required checks bind +// to pull-request and merge-group heads, which the schedule event never carries. +fn not_on_wet_cadence_condition() -> String { + "github.event_name != 'schedule'" +} + +data wet_receipts_job_id: String = "wet-receipts" + +// Daily, at a fixed off-peak minute; the floor's freshness budget +// (`floor_wet_route_cadence_secs` + `floor_wet_route_receipt_grace_secs`) is declared beside +// this cadence's model in `v2.workflow.floor_wet_route`, which is the authority a reader +// should price the tolerated miss count from. +data wet_receipts_cron: CronSchedule = CronSchedule { + minute: extdeps.cron.schedule_model.Exact { value: 17 }, + hour: extdeps.cron.schedule_model.Exact { value: 9 }, + day_of_month: Wildcard, + month: Wildcard, + day_of_week: Wildcard +} + +fn wet_receipts_job_condition() -> String { + "github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'" +} + +// The lane builds exactly the three bins its rows execute through: claim_batch (the wet +// executor), gunbc (the emit the cssl harness dispatches), cssl_assemble (the closure +// assembler those transports invoke). +data wet_receipts_required_bins: List = ["claim_batch", "gunbc", "cssl_assemble"] + +fn wet_receipts_run_command() -> ArgvCommand { + claim_batch_command( + mode_flag: "--wet-route", + operands: append( + fold( + witness_layer_roots, + init: [], + f: fn(acc, root) { append(acc, items: ["--source-root", root]) }, + ), + items: [ + "--receipt-out", floor_wet_route_receipt_json_rel_path, + "--receipt-tsv-out", floor_wet_route_receipt_tsv_rel_path, + ], + ), + ) +} + +fn wet_receipts_run_step() -> Step { + RunStep { + name: Present { value: "Wet receipts lane (rows named by the run, not by this label)" }, + id: Present { value: "wet_receipts_run" }, + run: required_lane_run_script(command: wet_receipts_run_command()), + shell: none, + env: none, + working_directory: none, + if_condition: none, + continue_on_error: none, + timeout_minutes: none + } +} + +// THE UPLOAD IS THE LANE'S ONLY PUBLICATION, AND IT RUNS ON EVERY EVENT. This job executes the +// routed rows and hands the receipt pair out as an artifact; it holds no repository-write step on +// any ref, so no lane run pushes anywhere. Two consequences, and the second is the one that gets +// forgotten. A workflow_dispatch is how a receipt is seeded or refreshed for an in-flight change +// (the changed-witness remedy, and how this lane's own first receipt was produced): the +// dispatching author downloads the artifact and commits it on their branch. AND THE SCHEDULED RUN +// IS THE SAME SHAPE — it executes on its cron and uploads, and a person must land the pair before +// the envelope ages past v2.workflow.floor_wet_route floor_wet_route_receipt_staleness_budget_secs +// or the required floor refuses every open pull request. That recurring obligation is declared as +// admitted debt, with its dissolution, at v2.workflow.floor_wet_route +// wet_receipt_hand_commit_dissolve_on; read the window from that module rather than from a figure +// repeated here. The hand step can only DELAY a receipt — the floor re-projects, re-digests and +// re-joins every committed pair, so a hand-committed envelope the tree does not support is refused +// exactly as a lane-committed one would be. THE RECEIPT IS UPLOADED EVEN WHEN THE LANE IS RED — +// `!cancelled()` rather than the implicit success() — because an honest fail receipt is the routed +// witnesses' verdict channel and an absent one refuses every open pull request once the budget +// above elapses; the lane's own red stays on this job. +// The BuildBuddy remote executors cannot produce this receipt at all — the first attempt +// was OOM-killed at a ~0.9 GiB availability floor against the ~5 GiB the wet chain resides at — +// which is why the lane is pinned to the repository's own runners and no local fallback is +// documented. +fn wet_receipts_artifact_step() -> Step { + UsesStep { + name: Present { value: "Upload the receipt artifact" }, + id: none, + uses: upload_artifact_action, + with: Present { + value: [ + kv(key: "name", value: yaml_string(s: "wet-lane-receipt")), + kv(key: "path", value: yaml_string(s: "dag/gunbc/witness/wet_lane")), + kv(key: "if-no-files-found", value: yaml_string(s: "error")), + kv(key: "retention-days", value: yaml_int(n: 14)), + ] + }, + env: none, + if_condition: Present { value: "!cancelled() && steps.wet_receipts_run.outcome != 'skipped'" }, + continue_on_error: none, + timeout_minutes: none + } +} + +fn wet_receipts_bound_steps() -> List { + append( + prepared_bound_steps(build_script: repo_self_build_command(bins: wet_receipts_required_bins)), + items: [ + WitnessFloorBoundStep { + step: wet_receipts_run_step(), + role: consumes_only(capabilities: [CargoCapability, RustcCapability]), + step_name: "Wet receipts lane (rows named by the run, not by this label)", + }, + WitnessFloorBoundStep { + step: wet_receipts_artifact_step(), + role: capability_neutral, + step_name: "Upload the receipt artifact", + }, + ], + ) +} + +fn wet_receipts_capability_closure_holds() -> Bool { + capability_closure_is_closed( + v: workflow_job_capability_closure( + steps: list_map( + xs: wet_receipts_bound_steps(), + f: fn(b) { CapabilityAnnotatedStep { step_name: b.step_name, role: b.role } }, + ) + ), + ) +} + +// timeout_minutes: 360, superseding the provisional 180 the fold-job note above also covered. +// 360 IS derived from a run, unlike 180: wet-receipts run 33420133863 (2026-08-31) was killed +// by the 180 cap at witness 15 of 23, after 162 minutes of witness execution alone — re-derive +// from that job's `wet-lane: identity=... wall_ms=` lines, whose per-row sum projects the full +// roster past 4.5h with the seven stage witnesses at 15.3–20.3 min each. The instrument is the +// lane's own per-identity wall_ms receipt, not this sentence; question 360 by re-measuring a +// completed run, and shrink it when the stage-witness cost drops. +fn wet_receipts_job() -> Job { + Job { + id: wet_receipts_job_id, + name: none, + runner: gunbc_ci_selected_runner_spec(), + steps: list_map(xs: wet_receipts_bound_steps(), f: fn(b) { b.step }), + needs: [], + env: none, + outputs: none, + if_condition: Present { value: wet_receipts_job_condition() }, + timeout_minutes: 360, + continue_on_error: none, + concurrency: none, + permissions: Present { + value: WorkflowPermissions { + contents: Present { value: PermWrite }, + pull_requests: Present { value: PermWrite }, + issues: none, + actions: none, + id_token: none + } + } + } +} + fn fabric_evidence_bound_steps() -> List { append( prepared_bound_steps(build_script: witness_floor_build_script()), @@ -1813,7 +2005,7 @@ fn fabric_evidence_job() -> Job { needs: [], env: none, outputs: none, - if_condition: none, + if_condition: Present { value: not_on_wet_cadence_condition() }, timeout_minutes: fabric_ci_evidence_calibration_timeout_minutes + fabric_ci_evidence_prelude_allowance_minutes, continue_on_error: none, concurrency: none, @@ -2185,7 +2377,7 @@ fn build_lane_job() -> Job { needs: [], env: none, outputs: none, - if_condition: none, + if_condition: Present { value: not_on_wet_cadence_condition() }, timeout_minutes: 90, continue_on_error: none, concurrency: none, @@ -2327,7 +2519,7 @@ fn build_lane_job() -> Job { // the required context skipped on a head still the merge candidate. The exclusion treats // `cancelled` as evidence of supersession; the measurement says it is evidence of nothing. fn required_lanes_aggregate_job_condition() -> String { - "always()" + concat("always() && ", not_on_wet_cadence_condition()) } // // THE STEP-LEVEL `always()` STAYS, guarding a different thing. It is about EARLIER STEPS IN THIS @@ -2622,6 +2814,7 @@ fn required_lanes_aggregate_job() -> Job { fn witness_floor_triggers() -> List { [ WorkflowDispatch { inputs: [ci_heal_expected_healed_sha_input] }, + Schedule { cron: wet_receipts_cron }, MergeGroup, Push { branches: [gunbc_default_branch_name], paths: [] }, PullRequest { @@ -2641,7 +2834,8 @@ fn witness_floor_lane_jobs() -> List { rust_unit_tests_job(), fabric_evidence_job(), emit_copy_qualification_battery_job(), - heal_generated_artifacts_job() + heal_generated_artifacts_job(), + wet_receipts_job() ] } @@ -2693,7 +2887,7 @@ data witness_floor_workflow: Workflow = { // whole-workflow closure would be the wrong shape, and checking only the job that existed first // would leave the new one guarded by nothing while the emission still refused on its behalf. // That is the inert half DESIGN §6 names: machinery that exists and gates nothing. -data witness_floor_capability_closure_per_job_note: String = "expected_witness_floor_yml conjoins required_lanes_gate_is_renderable and every job capability closure, including the independent fabric-evidence lane; adding a job without adding its conjunct would emit that job unchecked." +data witness_floor_capability_closure_per_job_note: String = "expected_witness_floor_yml conjoins required_lanes_gate_is_renderable and every job capability closure — witness_floor, build_lane, rust_unit_tests, the independent fabric-evidence lane and the wet-receipts lane; adding a job without adding its conjunct would emit that job unchecked." type WitnessFloorGenerationOutcome = WitnessFloorGenerated { content: String } @@ -2776,7 +2970,7 @@ fn expected_witness_floor_yml() -> WitnessFloorGenerationOutcome { WorkflowToolchainHomeRefused { job_id: j, refusal: r } => WitnessFloorGenerationRefused { reason: toolchain_home_refusal_reason(job_id: j, refusal: r) } WorkflowToolchainHomesAdmitted => - if witness_floor_capability_closure_holds() && build_lane_capability_closure_holds() && rust_unit_tests_capability_closure_holds() && fabric_evidence_capability_closure_holds() && emit_copy_qualification_capability_closure_holds() && heal_generated_artifacts_capability_closure_holds() && required_lanes_gate_is_renderable() { + if witness_floor_capability_closure_holds() && build_lane_capability_closure_holds() && rust_unit_tests_capability_closure_holds() && fabric_evidence_capability_closure_holds() && emit_copy_qualification_capability_closure_holds() && heal_generated_artifacts_capability_closure_holds() && wet_receipts_capability_closure_holds() && required_lanes_gate_is_renderable() { WitnessFloorGenerated { content: serialize_yaml(v: project_workflow_to_yaml(workflow: witness_floor_workflow)) } diff --git a/dag/test/claim/discovery_census_witness_test.dag b/dag/test/claim/discovery_census_witness_test.dag index acbd8ec1fae..4c9006d3e2f 100644 --- a/dag/test/claim/discovery_census_witness_test.dag +++ b/dag/test/claim/discovery_census_witness_test.dag @@ -37,6 +37,7 @@ import v2.workflow.required_floor { RequiredFloorDisposition, Planned, PlannedAsChangedWitness, DeclinedLongModule, DeclinedFixtureMember, DeclinedOutsideRequiredGate, DeclinedCostDebt, DeclinedOutsideGateClosure, DeclinedDiscoveryExcluded, + DeclinedOutsideGateClosure, DeclinedDiscoveryExcluded, DeclinedRoutedToWetLane, required_floor_site_disposition, } import v2.workflow.floor_terminal_ledger { ClaimDisposition, Passed } @@ -143,8 +144,8 @@ fn refusal_is_empty_target_name(c: LabelRefusal) -> Bool { test fn w_site_label_is_the_module_path_as_package() -> Bool { let rendered = rendered_planned_labels(sites: mixed_sites()) - list_holds(xs: rendered, wanted: "//test/claim/alpha_witness:w_alpha") - && list_holds(xs: rendered, wanted: "//test/claim/alpha_witness:w_beta") + list_holds(xs: rendered, wanted: "//v2/test/claim/alpha_witness:w_alpha") + && list_holds(xs: rendered, wanted: "//v2/test/claim/alpha_witness:w_beta") } // THE LEADING EMPTY SEGMENT IS THE CONTROL THE OBVIOUS JOIN FAILS. An accumulator that skips the @@ -213,12 +214,14 @@ test fn w_fixture_home_declines_with_its_matched_prefix() -> Bool { ) { DeclinedFixtureMember { matched_prefix: p } => p == "v2.test.fixture.walk_plan_stage." Planned => false + PlannedAsChangedWitness => false DeclinedLongModule { matched_prefix: _ } => false DeclinedOutsideRequiredGate => false DeclinedCostDebt => false DeclinedOutsideGateClosure => false DeclinedDiscoveryExcluded { matched_substring: _ } => false PlannedAsChangedWitness => false + DeclinedRoutedToWetLane => false } } @@ -229,12 +232,14 @@ test fn w_long_home_module_declines_with_its_matched_prefix() -> Bool { ) { DeclinedLongModule { matched_prefix: p } => p == "test.claim.long." Planned => false + PlannedAsChangedWitness => false DeclinedFixtureMember { matched_prefix: _ } => false DeclinedOutsideRequiredGate => false DeclinedCostDebt => false DeclinedOutsideGateClosure => false DeclinedDiscoveryExcluded { matched_substring: _ } => false PlannedAsChangedWitness => false + DeclinedRoutedToWetLane => false } } @@ -247,6 +252,7 @@ test fn w_long_home_is_a_prefix_not_a_substring() -> Bool { identity: "v2.test.claim.not_test_claim_long.witness.a_claim" ) { Planned => true + PlannedAsChangedWitness => false DeclinedLongModule { matched_prefix: _ } => false DeclinedFixtureMember { matched_prefix: _ } => false DeclinedOutsideRequiredGate => false @@ -254,6 +260,7 @@ test fn w_long_home_is_a_prefix_not_a_substring() -> Bool { DeclinedOutsideGateClosure => false DeclinedDiscoveryExcluded { matched_substring: _ } => false PlannedAsChangedWitness => false + DeclinedRoutedToWetLane => false } } @@ -263,6 +270,7 @@ test fn w_site_is_planned_when_no_home_matched() -> Bool { identity: "v2.test.claim.ordinary_witness.a_claim" ) { Planned => true + PlannedAsChangedWitness => false DeclinedLongModule { matched_prefix: _ } => false DeclinedFixtureMember { matched_prefix: _ } => false DeclinedOutsideRequiredGate => false @@ -270,6 +278,7 @@ test fn w_site_is_planned_when_no_home_matched() -> Bool { DeclinedOutsideGateClosure => false DeclinedDiscoveryExcluded { matched_substring: _ } => false PlannedAsChangedWitness => false + DeclinedRoutedToWetLane => false } } @@ -283,12 +292,14 @@ test fn w_site_outside_the_required_gate_is_declined() -> Bool { ) { DeclinedOutsideRequiredGate => true Planned => false + PlannedAsChangedWitness => false DeclinedLongModule { matched_prefix: _ } => false DeclinedFixtureMember { matched_prefix: _ } => false DeclinedCostDebt => false DeclinedOutsideGateClosure => false DeclinedDiscoveryExcluded { matched_substring: _ } => false PlannedAsChangedWitness => false + DeclinedRoutedToWetLane => false } } @@ -315,7 +326,8 @@ test fn w_counts_partition_the_offered_population() -> Bool { + counts.declined_outside_required_gate + counts.declined_outside_gate_closure + counts.declined_discovery_excluded - + counts.declined_cost_debt) + + counts.declined_cost_debt + + counts.declined_routed_to_wet_lane) } // THE SITE FUNCTION NEVER RETURNS `DeclinedCostDebt`, AND THAT IS A CLAIM ABOUT WHERE THE @@ -347,7 +359,9 @@ test fn w_rostered_identity_declines_for_cost_debt() -> Bool { DeclinedOutsideRequiredGate => false DeclinedOutsideGateClosure => false DeclinedDiscoveryExcluded { matched_substring: _ } => false + DeclinedRoutedToWetLane => false Planned => false + PlannedAsChangedWitness => false DeclinedLongModule { matched_prefix: _ } => false DeclinedFixtureMember { matched_prefix: _ } => false PlannedAsChangedWitness => false @@ -365,10 +379,12 @@ test fn w_unrostered_sibling_in_the_same_module_reaches_the_gate_decline() -> Bo identity: "dag.test.claim.lifecycle_survivor_corpus_census.a_sibling_the_roster_does_not_hold" ) { Planned => false + PlannedAsChangedWitness => false DeclinedOutsideRequiredGate => true DeclinedCostDebt => false DeclinedOutsideGateClosure => false DeclinedDiscoveryExcluded { matched_substring: _ } => false + DeclinedRoutedToWetLane => false DeclinedLongModule { matched_prefix: _ } => false DeclinedFixtureMember { matched_prefix: _ } => false PlannedAsChangedWitness => false @@ -390,7 +406,9 @@ test fn w_home_decline_outranks_cost_debt() -> Bool { DeclinedCostDebt => false DeclinedOutsideGateClosure => false DeclinedDiscoveryExcluded { matched_substring: _ } => false + DeclinedRoutedToWetLane => false Planned => false + PlannedAsChangedWitness => false DeclinedFixtureMember { matched_prefix: _ } => false PlannedAsChangedWitness => false } @@ -433,6 +451,7 @@ test fn w_planned_and_outside_gate_rows_partition_once_each() -> Bool { && count(split.declined) == 1 && all(split.planned, r => match r.disposition { Planned => true + PlannedAsChangedWitness => false DeclinedLongModule { matched_prefix: _ } => false DeclinedFixtureMember { matched_prefix: _ } => false DeclinedOutsideRequiredGate => false @@ -440,16 +459,19 @@ test fn w_planned_and_outside_gate_rows_partition_once_each() -> Bool { DeclinedOutsideGateClosure => false DeclinedDiscoveryExcluded { matched_substring: _ } => false PlannedAsChangedWitness => false + DeclinedRoutedToWetLane => false }) && all(split.declined, r => match r.disposition { DeclinedOutsideRequiredGate => true Planned => false + PlannedAsChangedWitness => false DeclinedLongModule { matched_prefix: _ } => false DeclinedFixtureMember { matched_prefix: _ } => false DeclinedCostDebt => false DeclinedOutsideGateClosure => false DeclinedDiscoveryExcluded { matched_substring: _ } => false PlannedAsChangedWitness => false + DeclinedRoutedToWetLane => false }) } @@ -509,11 +531,11 @@ test fn w_required_aggregate_dependencies_are_exactly_the_planned_subset() -> Bo is_required_aggregate(t: a) && (target_identity(t: a) == "//:required") && ((a.dependencies |> count) == 3) - && list_holds(xs: rendered, wanted: "//test/claim/alpha_witness:w_alpha") - && list_holds(xs: rendered, wanted: "//test/claim/alpha_witness:w_beta") + && list_holds(xs: rendered, wanted: "//v2/test/claim/alpha_witness:w_alpha") + && list_holds(xs: rendered, wanted: "//v2/test/claim/alpha_witness:w_beta") && !list_holds(xs: rendered, wanted: "//test/claim/long/slow_witness:w_slow") && !list_holds(xs: rendered, wanted: "//v2/test/fixture/walk_plan_stage/common:w_member") - && list_holds(xs: rendered, wanted: "//test/claim/reads_tree_witness:w_reads") + && list_holds(xs: rendered, wanted: "//v2/test/claim/reads_tree_witness:w_reads") } } } diff --git a/dag/test/claim/match_exhaustiveness_coproduct_witness_test.dag b/dag/test/claim/match_exhaustiveness_coproduct_witness_test.dag index 7d7a51b6eca..d1480e45e8c 100644 --- a/dag/test/claim/match_exhaustiveness_coproduct_witness_test.dag +++ b/dag/test/claim/match_exhaustiveness_coproduct_witness_test.dag @@ -34,9 +34,9 @@ data missing_arm_coproduct_source: String = "module exhaust_missing\ntype Trio = // The negative omits exactly `DeclinedOutsideRequiredGate`; the positive differs only by // including it. Both name every later arm so growth in the imported authority makes these // controls fail closed instead of changing which omission the negative measures. -data imported_projected_missing_arm_source: String = "module exhaust_imported_projected_missing\nimport v2.workflow.required_floor { RequiredFloorDisposition, Planned, PlannedAsChangedWitness, DeclinedLongModule, DeclinedFixtureMember, DeclinedOutsideRequiredGate, DeclinedCostDebt, DeclinedOutsideGateClosure, DeclinedDiscoveryExcluded }\ntype Row { disposition: RequiredFloorDisposition }\nfn f(row: Row) -> Bool {\n match row.disposition {\n Planned => true\n PlannedAsChangedWitness => true\n DeclinedLongModule { matched_prefix: _ } => false\n DeclinedFixtureMember { matched_prefix: _ } => false\n DeclinedCostDebt => false\n DeclinedOutsideGateClosure => false\n DeclinedDiscoveryExcluded { matched_substring: _ } => false\n }\n}\n" +data imported_projected_missing_arm_source: String = "module exhaust_imported_projected_missing\nimport v2.workflow.required_floor { RequiredFloorDisposition, Planned, PlannedAsChangedWitness, DeclinedLongModule, DeclinedFixtureMember, DeclinedOutsideRequiredGate, DeclinedCostDebt, DeclinedOutsideGateClosure, DeclinedDiscoveryExcluded, DeclinedRoutedToWetLane }\ntype Row { disposition: RequiredFloorDisposition }\nfn f(row: Row) -> Bool {\n match row.disposition {\n Planned => true\n PlannedAsChangedWitness => true\n DeclinedLongModule { matched_prefix: _ } => false\n DeclinedFixtureMember { matched_prefix: _ } => false\n DeclinedCostDebt => false\n DeclinedOutsideGateClosure => false\n DeclinedDiscoveryExcluded { matched_substring: _ } => false\n DeclinedRoutedToWetLane => false\n }\n}\n" -data imported_projected_exhaustive_source: String = "module exhaust_imported_projected_complete\nimport v2.workflow.required_floor { RequiredFloorDisposition, Planned, PlannedAsChangedWitness, DeclinedLongModule, DeclinedFixtureMember, DeclinedOutsideRequiredGate, DeclinedCostDebt, DeclinedOutsideGateClosure, DeclinedDiscoveryExcluded }\ntype Row { disposition: RequiredFloorDisposition }\nfn f(row: Row) -> Bool {\n match row.disposition {\n Planned => true\n PlannedAsChangedWitness => true\n DeclinedLongModule { matched_prefix: _ } => false\n DeclinedFixtureMember { matched_prefix: _ } => false\n DeclinedOutsideRequiredGate => false\n DeclinedCostDebt => false\n DeclinedOutsideGateClosure => false\n DeclinedDiscoveryExcluded { matched_substring: _ } => false\n }\n}\n" +data imported_projected_exhaustive_source: String = "module exhaust_imported_projected_complete\nimport v2.workflow.required_floor { RequiredFloorDisposition, Planned, PlannedAsChangedWitness, DeclinedLongModule, DeclinedFixtureMember, DeclinedOutsideRequiredGate, DeclinedCostDebt, DeclinedOutsideGateClosure, DeclinedDiscoveryExcluded, DeclinedRoutedToWetLane }\ntype Row { disposition: RequiredFloorDisposition }\nfn f(row: Row) -> Bool {\n match row.disposition {\n Planned => true\n PlannedAsChangedWitness => true\n DeclinedLongModule { matched_prefix: _ } => false\n DeclinedFixtureMember { matched_prefix: _ } => false\n DeclinedOutsideRequiredGate => false\n DeclinedCostDebt => false\n DeclinedOutsideGateClosure => false\n DeclinedDiscoveryExcluded { matched_substring: _ } => false\n DeclinedRoutedToWetLane => false\n }\n}\n" fn non_exhaustive_blocking_count(source: String) -> Int { match compile_dag_diagnostic_census(source) { diff --git a/dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag b/dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag index 8aa985d05c7..2c22cf7057b 100644 --- a/dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag +++ b/dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag @@ -20,7 +20,7 @@ import v2.std.node { symbol_identity_digest } data live_tree_disposition: LiveTreeDisposition = ReadsLiveTree -data real_execution_home_doc: String = "Wet execution witness for the artifact axis: it writes a real minimal crate into a real mktemp directory, runs a REAL cargo build through cargo.Build.BuildManifestMessages, decodes cargo's own JSON message stream, and digests the file cargo named with a REAL sha512sum. shell.Mktemp.Dir, Filesystem.Write and cargo.Build.* have no mock_response, so the hermetic discovery corpus refuses this file by construction; it is excluded from discovery (gunbc.ci_layer_roots witness_exclusion_frontier) and enrolled in bin_witness_wet_entries, same lane as the other real-execution witnesses. The pure decision folds are witnessed hermetically on every PR in test.claim.self_host_artifact_materialization_witness — this file adds only what a fixture cannot supply: that the flag cargo is actually invoked with produces the stream the decode expects, and that the path in that stream is a file sha512sum can read." +data real_execution_home_doc: String = "Wet execution witness for the artifact axis: it writes a real minimal crate into a real mktemp directory, runs a REAL cargo build through cargo.Build.BuildManifestMessages, decodes cargo's own JSON message stream, and digests the file cargo named with a REAL sha512sum. shell.Mktemp.Dir, Filesystem.Write and cargo.Build.* have no mock_response, so the hermetic discovery corpus refuses this file by construction; its identities are routed off hermetic execution by v2.workflow.floor_wet_route and executed by the wet receipts lane (claim_batch --wet-route), whose committed per-identity receipt the required floor joins against. The pure decision folds are witnessed hermetically on every PR in test.claim.self_host_artifact_materialization_witness — this file adds only what a fixture cannot supply: that the flag cargo is actually invoked with produces the stream the decode expects, and that the path in that stream is a file sha512sum can read." data why_the_crate_is_this_small_doc: String = "The crate is one no-dependency bin because the witness cost derives from what it proves (DESIGN witness-cost ruling): the subject is the round trip from a real cargo invocation to a real digest, and the smallest crate that crosses that boundary is the requirement plus one. A larger or realistic-looking crate would buy verisimilitude and nothing else, and a dependency would make the witness need a registry it has no reason to reach. Each claim builds its OWN crate in its OWN mktemp directory and nothing is shared between them, which is why the cost is stated as three builds of a no-dependency hello-world rather than one. This file therefore does NOT witness the one-build-one-artifact control the lane owes: that control is about reusing a built artifact across invocations, and asserting it here — where every claim deliberately starts from an empty target directory — would be naming a property nothing in this file exercises." diff --git a/dag/test/claim/witness_floor_workflow_consolidation_witness_test.dag b/dag/test/claim/witness_floor_workflow_consolidation_witness_test.dag index 02f1a0953cd..c378f2fe0d5 100644 --- a/dag/test/claim/witness_floor_workflow_consolidation_witness_test.dag +++ b/dag/test/claim/witness_floor_workflow_consolidation_witness_test.dag @@ -306,6 +306,15 @@ test fn w_RED_fabric_evidence_executes_without_gating() -> Bool { // forms share: a pattern loose enough to survive any producer is a pattern that stops // discriminating, which is exactly how the job-level guard defect above went green.) // +// THE `&& github.event_name != 'schedule'` CONJUNCT (2026-08-30, wet receipts lane) IS NOT +// THE CANCELLED-EXCLUSION RETURNING, and the pattern pins the whole spelling so the two cannot +// be confused. The schedule event exists for the wet-receipts job alone and never carries a +// merge candidate: required checks bind to pull-request and merge-group heads, so a skipped +// aggregate on a schedule tick guards nothing and a red one would be daily noise about lanes +// that were deliberately not run. The negative clause below still refuses any lane-result +// exclusion — `!= 'cancelled'` stays unauthorable — which is the half gunbc#9339's dissolution +// made this witness the regression control for. +// // THIS IS EMITTED-SHAPE EVIDENCE, NOT A BEHAVIOURAL GITHUB RECEIPT, and the caveat survives the // re-pointing unchanged. It proves the job condition and the live-attempt refusal are present at // their distinct YAML grains. It does not prove what GitHub does with a required context on a @@ -315,7 +324,7 @@ test fn w_RED_fabric_evidence_executes_without_gating() -> Bool { test fn w_RED_aggregate_runs_on_a_cancelled_lane_and_refuses_a_failed_one() -> Bool { match expected_witness_floor_yml() { WitnessFloorGenerated { content: yml } => - string_contains(s: yml, pattern: "\n if: always()\n") + string_contains(s: yml, pattern: "\n if: always() && github.event_name != 'schedule'\n") && !string_contains(s: yml, pattern: "!= 'cancelled'") && string_contains(s: yml, pattern: "\n if: always()") && string_contains(s: yml, pattern: "exit 1") diff --git a/docs/design-rung-drops.md b/docs/design-rung-drops.md index 9af31a858bc..7782ce871ac 100644 --- a/docs/design-rung-drops.md +++ b/docs/design-rung-drops.md @@ -8,6 +8,10 @@ Generated from `gunbc.rung_drop`. Do not hand-edit — the generated-artifact ph Each row declares a safety guarantee that was lowered: what stood before, what stands now, why, over what population, and the trigger that restores it. A drop is retired by its trigger and by nothing else. +### The wet-lane receipt executor-contract axis, for exactly one envelope: run 33745596102, attempt_seq 1, envelope digest ffa6ca15 — declared 2026-09-03 + +The wet-lane receipt executor-contract axis, for exactly one envelope: run 33745596102, attempt_seq 1, envelope digest ffa6ca15: RUNG DROP, structurally guaranteed -> mitigatable (replacement staged: gunbc.wet_seed_bootstrap_lease wet_seed_bootstrap_lease_declared -- the declared one-shot lease, pinned to four exact facts and refusing with NotApplicable if any fails to join, so no later receipt inherits this admission). Population: one wet-lane receipt envelope: run 33745596102, attempt_seq 1, envelope digest ffa6ca1592d15448ebb454343f80daa51f357c5f84e8b5e7b131c9410b675be7, admitted past ReceiptExecutorSnapshotDifferent and no other standing. Restored when: THE EXECUTOR AXIS IS DERIVED FROM THE EVALUATED TREE RATHER THAN THE DISPATCH TREE. The artifact must be SUFFICIENT FOR this: a dispatch whose executor contract moves mid-run produces a receipt admissible with NO grant, because the axis the floor checks is a property of the tree being evaluated and not of the seed the lane happened to execute on. NOT satisfied by the next receipt landing executor-exact, and NOT by the executor snapshot happening to match -- both are luck while the capability stays dead, and a trigger a favourable runner slot can fire names less than the capability it restores.. + ### Heal job for generated artifacts — declared 2026-09-01 · RETIRED **RETIRED — TRIGGER FIRED.** 2026-09-02 -- THE CAPABILITY, OBSERVED, NOT THE EMISSION. gunbc#10118 restored the heal job as a job of gunbc.witness_floor_workflow, and the row is retired on an EXECUTED repair of a REAL divergence rather than on that emission. THE PROBE: commit 330c74f0735364644c6a527a2d61de8da0a37cd8 hand-edited docs/plans/input-envelope-roadmap.md, a generated projection, from 3555 bytes (sha256 4da64e1495ef627c31fa21f3e31e2746ba28c5be447c9f6565d9a004f2c23ead) to 3754 and did not regenerate it. The subject was chosen against the emitted script rather than assumed: it carries a git add line and does NOT appear in the AUTHOR_COMMIT_DRIFT population, so it exercises the PUSH arm; the three workflow projections would have exercised bundle-and-refuse while looking like a heal run. THE RECEIPT, run 33683175090 job 100433326005: HealProduced prior_head=330c74f0735364644c6a527a2d61de8da0a37cd8 healed_head=bc704687540d25796f53f88687226ee1a735743c changed_artifacts=docs/plans/input-envelope-roadmap.md -- exactly one path, no blast radius across the other 32 auto-push rows -- then SupersededByHealedHead and exit 1. The branch head moved, authored gunbc-ci-auto-heal , under the checkout persist-credentials binding gunbc.heal_push_plan resolves the push authority from. IDENTITY CONFIRMED TWO WAYS: the healed file is byte-identical to the pre-drift digest recorded BEFORE the probe, and a clean source-built regeneration on the healed head (whose src/ and dag/ are identical to the tree the binary was built from) changed ZERO files. RESTORED RUNG: 2 (mechanically preventable) -- drift is caught by the required generated-artifact phase and now CORRECTED without an author, which is the previous rung this row lost. NOT RESTORED, and this row does not claim it: revalidation of the head heal creates. CORRECTED 2026-09-03, AND THE ORIGINAL SENTENCE IS QUOTED RATHER THAN DELETED BECAUSE THE RECORD OF WHAT WAS CLAIMED IS THE POINT. This row said: 'An Actions-credential push starts no run, so heal exits nonzero with SupersededByHealedHead rather than reporting a verdict about a head nothing judged.' THE FIRST CLAUSE IS FALSE; EVERYTHING IT WAS OFFERED TO SUPPORT STANDS. Measured over the entire heal-push population since the job was restored -- n=4, healed heads bc704687540d25796f53f88687226ee1a735743c, 695f264c77, 7de8273834 and 958f743f9ec056f73fbd4e4adedf84a65a7bc41b, re-derivable by listing repos/gunb-ai/gunbc/actions/runs filtered to actor.login == github-actions[bot] and reading each run's ATTEMPT 1 rather than its latest attempt -- a pull_request run WAS created for the healed head 4 times out of 4. WHAT GITHUB WITHHOLDS IS EXECUTION, NOT CREATION: 0 of those 4 started a single job on the triggering attempt. Runs 33711005806, 33703032560 and 33705120607 completed action_required with zero jobs; run 33686753487 completed failure with zero jobs. EXACTLY ONE of the four ever executed a job at all: run 33703032560 on attempt 2, after a human acted. The other re-attempt, 33705120607 attempt 2, was cancelled having also started zero jobs, so a second attempt is not itself a verdict either. So the loss this clause names is unchanged -- no EXECUTED verdict exists for the healed head, and heal exits nonzero rather than speaking for a tree it produced -- while the shape of it is not. The judge is CREATED AND HELD, not absent. READ THIS AT ATTEMPT GRAIN OR IT INVERTS, and both obvious proxies fail toward the reassuring answer: GitHub stamps run_started_at equal to created_at on a run that never ran, and a held run still concludes failure or cancelled rather than action_required, so neither a start timestamp nor a conclusion string is an execution receipt. Count JOBS, ON THE ATTEMPT THE CLAIM IS ABOUT -- 'count jobs' alone is not the discriminator, because the default endpoint silently answers for the LATEST attempt. AND THE RUN OBJECT ITSELF MANUFACTURES THE WRONG NUMBER, verified on run 33703032560: its top-level created_at is ATTEMPT 1's creation while its run_started_at is ATTEMPT 2's start, so the object hands back two fields from two different attempts and names neither, and only run_attempt reveals it. Subtracting them yields a start delay that never happened. Reading the latest attempt hides the class outright: on run 33703032560 attempt 1 is action_required with 0 jobs and attempt 2, created 1h47m later after a human acted, runs 6. THREE READERS MADE A VERSION OF THIS ERROR IN ONE NIGHT, EACH LEVEL INVISIBLE FROM THE ONE ABOVE: a run's conclusion read as an execution receipt, then a job count taken on the wrong attempt, then the cross-attempt subtraction above -- recorded because the reader who warned about the second level was standing in the third while writing the warning. There was never a released run here; a human re-ran it. A CONSEQUENCE FOR THIS ROW'S OWN LANGUAGE, and it is why the clause is scoped rather than merely corrected: a held run CAN be released later and judge the head. Of the four, run 33703032560 eventually executed 6 jobs on a head heal had pushed. So 'a head nothing judged' is true AT EXIT TIME and may stop being true afterwards without anyone touching anything. The exit is a statement by the run printing it about the moment it prints, never a standing property of the healed head, and a carrier that states it unscoped is wrong the moment somebody approves. THE HOLD DISCRIMINATES ON THE EVENT, NOT ON THE IDENTITY OR THE TOKEN, and this arm is measured TWO-SIDED with the identity held constant on both sides. Forward: of 500 workflow_dispatch runs sampled, ZERO concluded action_required -- including all 151 actored by github-actions[bot], the same identity and default-token surface whose pull_request runs are held. Reverse control: the entire status=action_required listing is 17 runs and ALL 17 are event=pull_request, zero workflow_dispatch. Re-derive by listing repos/gunb-ai/gunbc/actions/runs with event=workflow_dispatch grouped by actor.login and conclusion, against the status=action_required listing grouped by event. Measured by cool-koi-623 and reproduced independently at the wider sample by fierce-ram-670, which is why the sample sizes here are the larger pair. Two things follow that the refuted premise concealed: releasing the healed head is an approve on that specific gated run (POST /actions/runs//approve) and not a re-run of another run, and a dispatched revalidation is a SECOND run on that head rather than the only one, costing a whole additional run and landing check-runs beside the gated run's on one commit where a name-keyed reader cannot tell them apart. That second cost buys something measured rather than duplicating what would have happened anyway -- by the event discriminator above, a dispatched run is the only route to the healed head that executes without a human. WHAT IS NOT ESTABLISHED AND IS NOT WRITTEN AS IF IT WERE: whether a dispatched run's contexts clear branch protection. repos/gunb-ai/gunbc/branches/main/protection is 403 to this token, and the held run is what protection was waiting on, so closing the REVALIDATION gap is measured and clearing the MERGE gate is not. WHY THE HOLD EXISTS IS LIKEWISE UNDETERMINED BECAUSE UNREADABLE, which is the honest shape and not an unexplained gap: repos/gunb-ai/gunbc/actions/permissions is 403 to these session tokens, so whether a repository setting explains it cannot be read from here. THE RETIREMENT ITSELF STANDS, stated as the output of the question rather than left to be inferred, and this correction does not move the row's rung: the restored capability is automatic repair of drifted generated artifacts, which the receipt above observed, and revalidation was already declared NOT RESTORED here. Its trigger is a workflow_dispatch input on gunbc.witness_floor_workflow carrying the healed sha, which every dispatched run binds its own github.sha and checkout against before any witness counts; tools.ci_heal_dispatch is the modeled half and stays unconsumed until then. That gap is a separate obligation, not this row. `floor_cut` DOES NOT RETIRE ON THIS: its trigger is the conjunction of five siblings and this is one. diff --git a/src/v1/stage0/src/bin/claim_batch.rs b/src/v1/stage0/src/bin/claim_batch.rs index f3d4d69f774..de8c284c43d 100644 --- a/src/v1/stage0/src/bin/claim_batch.rs +++ b/src/v1/stage0/src/bin/claim_batch.rs @@ -188,6 +188,12 @@ struct ParsedArgs { fixture_store: Option, eval_budget_ms: Option, pre_push: bool, + /// The wet receipts lane: derive the row population from + /// `v2.workflow.floor_wet_route.floor_wet_route_roster`, execute each row with real + /// effects, and write the per-identity receipt TSV the required floor joins against. + wet_route: bool, + receipt_out: Option, + receipt_tsv_out: Option, print_entry_closure: bool, } @@ -252,6 +258,9 @@ fn parse_args(args: &[String]) -> Result { let mut fixture_store: Option = None; let mut eval_budget_ms: Option = None; let mut pre_push = false; + let mut wet_route = false; + let mut receipt_out: Option = None; + let mut receipt_tsv_out: Option = None; let mut print_entry_closure = false; let mut i = 1; @@ -306,6 +315,15 @@ fn parse_args(args: &[String]) -> Result { notice_title = require_value(args, i, "--notice-title")?; } "--claim-run" => {} + "--wet-route" => wet_route = true, + "--receipt-tsv-out" => { + i += 1; + receipt_tsv_out = Some(PathBuf::from(require_value(args, i, "--receipt-tsv-out")?)); + } + "--receipt-out" => { + i += 1; + receipt_out = Some(PathBuf::from(require_value(args, i, "--receipt-out")?)); + } "--wet" => execution_mode = ExecutionMode::Wet, "--hermetic" => execution_mode = ExecutionMode::Hermetic, "--record" => execution_mode = ExecutionMode::Record, @@ -357,6 +375,9 @@ fn parse_args(args: &[String]) -> Result { fixture_store, eval_budget_ms, pre_push, + wet_route, + receipt_out, + receipt_tsv_out, print_entry_closure, }) } @@ -574,6 +595,7 @@ fn validate_fixture_flags( Ok(()) } +#[allow(clippy::too_many_arguments)] fn run_witnesses( index: &MultiEntryIndex, group: &EntryGroup, @@ -747,6 +769,222 @@ fn run() -> Result { // phases — a 20-minute silent resolve is uninterpretable. let _phase_profile = v1_compiler::cli_run::PhaseProfile::install_from_env(); + // THE WET RECEIPTS LANE. Population derived from the .dag authority at run time (never a + // second roster in YAML or argv), every row executed with real effects, and one receipt + // row per identity written for the required floor's freshness join. The lane is red if any + // row fails — that red is the routed witnesses' verdict channel — but the receipt is + // written for every row FIRST, fail rows included, so the floor can see an honest fail + // rather than an absent receipt. + if parsed.wet_route { + let receipt_out = match &parsed.receipt_out { + Some(p) => p.clone(), + None => { + eprintln!("claim_batch: --wet-route requires --receipt-out "); + return Err(ExitCode::from(2)); + } + }; + let receipt_tsv_out = match &parsed.receipt_tsv_out { + Some(p) => p.clone(), + None => { + eprintln!( + "claim_batch: --wet-route requires --receipt-tsv-out " + ); + return Err(ExitCode::from(2)); + } + }; + // THE WET SUBJECT DIGEST AND THE EXECUTION CLOCK, both captured BEFORE any witness + // runs: the digest is the envelope's validity key (computed by the same resolver the + // floor uses, which is what makes candidate-exactness a decidable equality), and + // executed_at is the conservative freshness basis — the tree's wet subject as of the + // moment execution began. + let subject_digest = match v1_compiler::cli_run::wet_subject_digest(&source_roots) { + Ok(d) => d, + Err(e) => { + eprintln!("claim_batch: {e}"); + return Err(ExitCode::from(1)); + } + }; + let executor_contract_digest = + match v1_compiler::cli_run::wet_executor_contract_digest(&source_roots) { + Ok(d) => d, + Err(e) => { + eprintln!("claim_batch: {e}"); + return Err(ExitCode::from(1)); + } + }; + let executed_at_unix_secs = match std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_secs()) + { + Ok(secs) => secs, + Err(e) => { + eprintln!( + "claim_batch: system clock is before the unix epoch ({e}) — refusing to \ + stamp executed_at on the wet envelope with a fabricated timestamp" + ); + return Err(ExitCode::from(1)); + } + }; + eprintln!( + "wet-lane: subject_digest={subject_digest} \ + executor_contract_digest={executor_contract_digest}" + ); + let rows = match v1_compiler::cli_run::wet_route_lane_rows(&source_roots) { + Ok(rows) => rows, + Err(e) => { + eprintln!("claim_batch: {e}"); + return Err(ExitCode::from(1)); + } + }; + if rows.is_empty() { + eprintln!( + "claim_batch: --wet-route: the roster is empty (fail closed — an empty \ + lane writes no receipt and greens nothing)" + ); + return Err(ExitCode::from(2)); + } + eprintln!( + "wet-lane: executing {} routed row(s) from v2.workflow.floor_wet_route", + rows.len() + ); + let index = process_shared_index(&source_roots); + // The one authority for module-path ↔ file, reused rather than re-derived (DESIGN §3). + let module_path_index = v1_compiler::cli_run::build_module_path_index(&source_roots); + let whole_tree_published_keys = + match precompute_whole_tree_published_mock_keys(&source_roots) { + Ok(keys) if keys.is_empty() => None, + Ok(keys) => Some(Rc::new(keys)), + Err(e) => { + eprintln!( + "claim_batch: whole-tree published mock corpus precompute failed: {e}" + ); + return Err(ExitCode::from(1)); + } + }; + let mut receipts: Vec = Vec::new(); + let mut any_failed = false; + let mut timings = ResolveTimings::default(); + for row in &rows { + let (graph, source_indices) = match resolve_timed(&index, &row.entry_rel, &mut timings) + { + Ok(r) => r, + Err(_) => { + println!( + "FAIL {} (entry resolve failed: {})", + row.function, row.entry_rel + ); + receipts.push(v1_compiler::cli_run::WetLaneExecutedReceipt { + identity: row.identity.clone(), + outcome_wire: "resolve-failed", + wall_ms: 0, + // NOTHING RESOLVED, SO NOTHING IS OBSERVED. Copying the roster's own + // entry and function in here would fabricate the observation the + // consumer's foreign-resolution join exists to check. + observed_entry_rel: None, + observed_function: None, + }); + any_failed = true; + continue; + } + }; + let closure_subject = match closure_subject_for_entry(&index, &row.entry_rel) { + Ok(s) => s, + Err(e) => { + println!("FAIL {} (closure subject: {e})", row.function); + receipts.push(v1_compiler::cli_run::WetLaneExecutedReceipt { + identity: row.identity.clone(), + outcome_wire: "closure-subject-failed", + wall_ms: 0, + observed_entry_rel: None, + observed_function: None, + }); + any_failed = true; + continue; + } + }; + let ctx = make_eval_context_with_runtime_options( + &graph, + source_indices, + ExecutionMode::Wet, + fixture_store.clone(), + whole_tree_published_keys.clone(), + ); + ctx.set_witness_eval_budget(eval_budget_ms); + // WHAT THIS RUN ACTUALLY RESOLVED, read from the node the interpreter's own lookup + // SELECTS for this name — the same selection `run_claim` is about to execute, not a + // second derivation and not the roster row echoed back. Recorded BEFORE the call so + // it describes the declaration that ran even when the run then fails. + // + // `None` when the name selects nothing, or when the module index cannot name + // exactly one module for the selected node's file: an unobservable resolution is + // absent, never guessed. + let selected = ctx.selected_function_identity(&row.function, &module_path_index); + let observed_function = selected + .as_ref() + .map(|s| format!("{}.{}", s.module_path, s.decl_name)); + let observed_entry_rel = selected + .as_ref() + .map(|s| v1_compiler::cli_run::workspace_relative_repo_path(&s.source_file)); + let (outcome, receipt) = run_claim_measured(&ctx, &closure_subject, &row.function); + // The RAW typed outcome, kept at wire grain (one of cli_run::WET_OUTCOME_WIRES): + // an assertion that ran and returned false and an infrastructure failure that + // produced no verdict are different facts with different floor standings. + let outcome_wire = match &outcome { + ClaimOutcome::Pass => "pass", + ClaimOutcome::Fail => "assertion-false", + ClaimOutcome::NotBool { .. } => "not-bool", + ClaimOutcome::RuntimeError { .. } => "runtime-error", + ClaimOutcome::BudgetInterrupted { .. } => "budget-interrupted", + ClaimOutcome::CompletedOverBudget { .. } => "completed-over-budget", + ClaimOutcome::HostToolUnresolved { .. } => "host-tool-unresolved", + ClaimOutcome::HostEffectRefused { .. } => "host-effect-refused", + ClaimOutcome::Panicked { .. } => "panicked", + ClaimOutcome::NotAttempted { .. } => "not-attempted", + }; + report_outcome(&row.function, outcome, &mut any_failed); + let wall_ms = receipt.wall_nanos / 1_000_000; + eprintln!( + "wet-lane: identity={} outcome={} wall_ms={}", + row.identity, outcome_wire, wall_ms + ); + timings.witnesses += 1; + timings.witness_ms += wall_ms; + receipts.push(v1_compiler::cli_run::WetLaneExecutedReceipt { + identity: row.identity.clone(), + outcome_wire, + wall_ms, + observed_entry_rel, + observed_function, + }); + v1_compiler::v1_interpreter::eval_call_memo_frame_exit(&ctx); + } + let json_path = receipt_out.to_string_lossy().to_string(); + let tsv_path = receipt_tsv_out.to_string_lossy().to_string(); + if let Err(e) = v1_compiler::cli_run::write_wet_receipt_envelope( + &json_path, + &tsv_path, + &receipts, + &subject_digest, + &executor_contract_digest, + executed_at_unix_secs, + ) { + eprintln!("claim_batch: {e}"); + return Err(ExitCode::from(1)); + } + eprintln!( + "wet-lane: envelope written json={} tsv={} rows={} total_wall_ms={}", + json_path, + tsv_path, + receipts.len(), + timings.witness_ms + ); + return if any_failed { + Ok(ExitCode::from(1)) + } else { + Ok(ExitCode::SUCCESS) + }; + } + let (entry_groups, discovery_notice) = if let Some(disc) = parsed.discovery { let excludes = witness_exclusion_substrings(); let mut rows = diff --git a/src/v1/stage0/src/bin/claim_executor.rs b/src/v1/stage0/src/bin/claim_executor.rs index 3846af9866c..c260bb3d00a 100644 --- a/src/v1/stage0/src/bin/claim_executor.rs +++ b/src/v1/stage0/src/bin/claim_executor.rs @@ -1458,7 +1458,7 @@ fn report_required_floor_outcome(outcome: &v1_compiler::cli_run::RequiredFloorOu eprintln!( "required-floor: declared={} offered={} routed={} declined_long={} declined_fixture={} \ declined_outside_required_gate={} declined_outside_gate_closure={} \ - declined_discovery_excluded={} — every DECLARED witness identity in the tree is exactly \ + declined_discovery_excluded={} declined_routed_to_wet_lane={} — every DECLARED witness identity in the tree is exactly \ one of these, joined at identity grain (FloorDispositionJoinInexact refuses otherwise), \ and no `*_test.dag` entry declared zero sites (v2.workflow.floor_discovery_producer \ refuses a barren or misplaced sidecar upstream of this line, over the full module \ @@ -1470,7 +1470,8 @@ fn report_required_floor_outcome(outcome: &v1_compiler::cli_run::RequiredFloorOu outcome.declined_fixture_member, outcome.declined_outside_required_gate, outcome.declined_outside_gate_closure, - outcome.declined_discovery_excluded + outcome.declined_discovery_excluded, + outcome.declined_routed_to_wet_lane ); // WHY route_gap IS NOW SPELLED route_gap_unenrolled, AND WHY route_gap_held JOINS IT HERE. // The old field printed `outcome.route_gap.len()` under the bare name `route_gap` — the @@ -1512,7 +1513,8 @@ fn report_required_floor_outcome(outcome: &v1_compiler::cli_run::RequiredFloorOu known_red_passed_over_budget={} known_red_host_tool_unresolved={} \ known_red_host_effect_refused={} known_red_runtime_errored={} \ known_red_observation_unreadable={} over_cost_line_diagnostic={} \ - withheld_cost_debt={} stale_cost_debt={}", + withheld_cost_debt={} stale_cost_debt={} routed_to_wet_lane={} \ + wet_route_standing_blocking={} stale_wet_route={}", outcome.claims_planned, outcome.claims_executed, outcome.not_attempted_after_abort, @@ -1538,7 +1540,10 @@ fn report_required_floor_outcome(outcome: &v1_compiler::cli_run::RequiredFloorOu outcome.known_red_observation_unreadable.len(), outcome.over_cost_line_diagnostic, outcome.withheld_cost_debt.len(), - outcome.stale_cost_debt.len() + outcome.stale_cost_debt.len(), + outcome.declined_routed_to_wet_lane, + outcome.wet_route_standing_blocking.len(), + outcome.stale_wet_route.len() ); // ONE receipt, both numbers (#8642). This replaced a per-miss trace line that had no hit // counterpart, so the ratio it is really about was never readable. @@ -1636,6 +1641,12 @@ fn report_required_floor_outcome(outcome: &v1_compiler::cli_run::RequiredFloorOu for stale in &outcome.stale_cost_debt { eprintln!("required-floor: STALE-COST-DEBT {stale}"); } + for blocking in &outcome.wet_route_standing_blocking { + eprintln!("required-floor: WET-ROUTE-STANDING {blocking}"); + } + for stale in &outcome.stale_wet_route { + eprintln!("required-floor: STALE-WET-ROUTE {stale}"); + } for errored in &outcome.known_red_runtime_errored { eprintln!("required-floor: KNOWN-RED-RUNTIME-ERRORED {errored}"); } @@ -1730,6 +1741,14 @@ fn required_floor_outcome_is_clean(outcome: &v1_compiler::cli_run::RequiredFloor // roster that has stopped describing the tree, which voids the contract's monotone // claim, so it blocks exactly as `stale_quarantine` and `stale_route_gap` do. && outcome.stale_cost_debt.is_empty() + // THE WET ROUTE'S TWO BLOCKING JOINS. The receipt standing blocks on every arm but + // FreshExactSubject — missing, expired, an ancestor-subject receipt, a broken + // contract, an inexact roster join, or a FAILED latest attempt — because each is the + // decline decaying into a skip list or the lane's own line-stop; and a roster row + // this run did not route names an identity the tree no longer offers + // (`v2.workflow.floor_wet_route`). + && outcome.wet_route_standing_blocking.is_empty() + && outcome.stale_wet_route.is_empty() // A CHANGED witness identity that did not execute to a passing verdict — declined, // absent from the disposition receipt, or without a terminal Passed verdict — reds the // required context. The classification authority is diff --git a/src/v1/stage0/src/cli_run.rs b/src/v1/stage0/src/cli_run.rs index 3efaf964ad3..bdff5fbc1ab 100644 --- a/src/v1/stage0/src/cli_run.rs +++ b/src/v1/stage0/src/cli_run.rs @@ -93,7 +93,9 @@ mod serve_budget_refusal; pub(crate) use required_floor_runner::*; pub use required_floor_runner::{ floor_discovery_path_excluded, make_eval_context, make_eval_context_with_runtime_options, - run_claim_measured, run_required_floor, + run_claim_measured, run_required_floor, wet_executor_contract_digest, wet_route_lane_rows, + wet_subject_digest, write_wet_receipt_envelope, WetLaneExecutedReceipt, WetReceiptEnvelope, + WetRouteLaneRow, }; mod entry_resolve; pub(crate) use active_workset::*; @@ -127,8 +129,9 @@ pub fn source_root_ingest_module_identities_for_ci( Ok(identities) } pub use entry_resolve::{ - load_sources_for_entry, process_shared_index, resolve_entry_graph, resolve_entry_with_index, - resolve_stage_totals, source_root_ingest_content_hash_fnv1a64, whole_tree_resolved_ctx, + build_module_path_index, load_sources_for_entry, process_shared_index, resolve_entry_graph, + resolve_entry_with_index, resolve_stage_totals, source_root_ingest_content_hash_fnv1a64, + whole_tree_resolved_ctx, }; mod live_read_decode; pub(crate) use live_read_decode::*; @@ -4889,8 +4892,9 @@ fn truncate_histogram_label(s: &str, max: usize) -> String { } } -/// Workspace-relative path for module-graph closure queries (`v2.lens.module_graph`). -fn workspace_relative_repo_path(path: &str) -> String { +/// Workspace-relative path for module-graph closure queries (`v2.lens.module_graph`), and for +/// the wet lane's observed-entry receipt field, which records a selected node's span file. +pub fn workspace_relative_repo_path(path: &str) -> String { let norm = path.strip_prefix("./").unwrap_or(path).replace('\\', "/"); let p = Path::new(&norm); if p.is_absolute() { @@ -17305,6 +17309,47 @@ pub fn closure_subject_for_entry(index: &MultiEntryIndex, entry: &str) -> Result Ok(subject_digest_for_closure(&sources)) } +/// THE TREE-ONLY CLOSURE SUBJECT OF ONE ENTRY, and it is deliberately NOT +/// `closure_subject_for_entry` above. +/// +/// `subject_digest_for_closure` folds TWO axes: the closure's `.dag` content and +/// `transform_content_digest()`, which hashes the bytes of the RUNNING EXECUTABLE +/// (`/proc/self/exe`). In a resolve CACHE key that second axis is correct and load-bearing — an +/// artifact produced by one compiler must not be served to another — which is why the shared +/// function keeps it and this one does not replace it. +/// +/// It is wrong in a SEMANTIC SUBJECT, and measurably so. The wet-lane receipt's +/// candidate-exactness test is `envelope.subject_digest == computed_subject_digest`, where the +/// envelope is written by `claim_batch` and the equality is checked by `claim_executor`. Two +/// different executables hash to two different transform digests, so that equality was +/// UNSATISFIABLE BY CONSTRUCTION on every tree, in every event, for as long as the subject +/// carried the transform axis — the floor refused seven consecutive landing cycles for a +/// staleness that never existed. The receipt that pinned it: a one-line edit to a `.rs` file +/// touching zero `.dag` moved the "semantic" subject digest from 5cc866cd221e7b56 to +/// 846ead7b689b7ead on one commit and one pristine checkout, while +/// `wet_executor_contract_digest` moved too — correctly, that one is ABOUT the seed bytes. +/// +/// The executor axis is not lost by removing it here: `wet_executor_contract_digest` carries it +/// as its own declared axis over its own declared input roster, checked by its own standing arm +/// (`ReceiptExecutorSnapshotDifferent`). Folding the running image into the semantic subject +/// double-counted that axis and destroyed the semantic one; this restores the §3 split the wet +/// route's own carrier already describes. The enrolled RED is +/// `v2.test.floor_wet_route.wet_subject_is_independent_of_the_running_binary`. +pub fn wet_closure_subject_for_entry( + index: &MultiEntryIndex, + entry: &str, +) -> Result { + let sources = load_sources_for_entry_with_pool(index, entry)?; + Ok(wet_closure_subject(&sources)) +} + +/// The tree-only subject itself, split out from the entry loader so the wall that keeps it +/// tree-only is assertable on synthetic sources without resolving the corpus. Enrolled RED: +/// `wet_subject_is_independent_of_the_running_binary`. +pub fn wet_closure_subject(sources: &[Rc]) -> String { + crate::resolved_graph_cache::closure_content_digest(sources) +} + /// The exact source-path population the entry loader will hand to resolution. /// /// This stops at the loader boundary: it runs the same import, qualified-reference, and bare-name @@ -39859,6 +39904,15 @@ pub enum RequiredFloorDisposition { /// own remedy. `collect_deferred_discovery_rows` receipts the same removal at ENTRY grain; /// this is the identity grain the population join is keyed on. DeclinedDiscoveryExcluded { matched_substring: String }, + /// Declined because the qualified identity is enrolled in `v2.workflow.floor_wet_route`: + /// its subject is a real host-effect chain no honest mock can answer (a real gunbc emit, + /// a real cargo build, real scratch I/O), so its executing consumer is the wet receipts + /// lane at that lane's cadence, never the hermetic fold. Carries no payload — the roster + /// is the authority for the population, and the lane's committed receipt is the authority + /// for each identity's last verdict. NEVER a quiet skip: the floor joins every routed + /// identity against the lane's receipt and REFUSES the run when the receipt is absent or + /// stale beyond the declared budget, so a dead lane un-routes its population loudly. + DeclinedRoutedToWetLane, /// Selected by the changed-witness sublane and NOT PRESENT IN THE DECLARED POPULATION at all, /// because the module that declares it is outside the run's discovery roots. /// @@ -40036,6 +40090,10 @@ pub struct RequiredFloorOutcome { pub declined_outside_gate_closure: usize, /// Declared identities excluded from discovery by an `exclude_substrings` match. pub declined_discovery_excluded: usize, + /// Declared identities declined from hermetic execution because `v2.workflow.floor_wet_route` + /// routes them to the wet receipts lane. Counted, never green-by-decline: the three + /// blocking collections below are what keep the decline honest. + pub declined_routed_to_wet_lane: usize, pub claims_planned: usize, pub claims_executed: usize, pub receipt_identities: usize, @@ -40115,6 +40173,16 @@ pub struct RequiredFloorOutcome { /// leaves a line behind that withholds nothing, and the roster's length then overstates the /// debt in the direction that flatters. Same shape as `stale_quarantine`, same reason. pub stale_cost_debt: Vec, + /// BLOCKING. The wet-lane receipt standing for the routed population, when it is any arm + /// but `FreshExactSubject` (authority `v2.workflow.floor_wet_route.WetLaneReceiptStanding`): + /// missing, expired, subject-mismatch (an ancestor receipt — blocked by ruling), + /// contract-mismatch, roster-inexact, or a FAILED latest attempt. At most one entry; it + /// carries the standing's own description and remedy. + pub wet_route_standing_blocking: Vec, + /// BLOCKING. A `floor_wet_route` roster row naming an identity this run did not offer and + /// route — renamed, deleted, or declined by an earlier home policy. Same rot guard as + /// `stale_cost_debt`. + pub stale_wet_route: Vec, /// ENROLLED AS EXPECTED-RED AND THREW, or answered with a non-verdict. Its own collections /// for the same reason `route_gap` is not folded into `host_tool_unresolved`: the remedy /// differs. A throw is a defect in the witness or its subject; an unreadable observation is @@ -40685,6 +40753,7 @@ fn write_required_floor_disposition_tsv( let mut declined_outside_gate = 0usize; let mut declined_gate_closure = 0usize; let mut declined_discovery_excluded = 0usize; + let mut declined_routed_to_wet_lane = 0usize; let mut declined_changed_witness_outside_discovery = 0usize; for row in rows { match &row.disposition { @@ -40698,6 +40767,7 @@ fn write_required_floor_disposition_tsv( RequiredFloorDisposition::DeclinedDiscoveryExcluded { .. } => { declined_discovery_excluded += 1 } + RequiredFloorDisposition::DeclinedRoutedToWetLane => declined_routed_to_wet_lane += 1, RequiredFloorDisposition::DeclinedChangedWitnessOutsideDiscovery { .. } => { declined_changed_witness_outside_discovery += 1 } @@ -40708,7 +40778,7 @@ fn write_required_floor_disposition_tsv( "# summary\ttotal={}\tplanned={}\tplanned_as_changed_witness={}\tdeclined_long_module={}\tdeclined_fixture_member={}\ \tdeclined_outside_required_gate={}\tdeclined_outside_gate_closure={}\ \tdeclined_discovery_excluded={}\tdeclined_cost_debt={}\ - \tdeclined_changed_witness_outside_discovery={}", + \tdeclined_routed_to_wet_lane={}\tdeclined_changed_witness_outside_discovery={}", rows.len(), planned, planned_as_changed_witness, @@ -40718,6 +40788,7 @@ fn write_required_floor_disposition_tsv( declined_gate_closure, declined_discovery_excluded, declined_cost_debt, + declined_routed_to_wet_lane, declined_changed_witness_outside_discovery ) .map_err(|e| format!("write_required_floor_disposition_tsv: write {path}: {e}"))?; diff --git a/src/v1/stage0/src/cli_run/required_floor_runner.rs b/src/v1/stage0/src/cli_run/required_floor_runner.rs index 39e24b40b54..7a0728f194b 100644 --- a/src/v1/stage0/src/cli_run/required_floor_runner.rs +++ b/src/v1/stage0/src/cli_run/required_floor_runner.rs @@ -271,6 +271,1487 @@ pub(crate) fn floor_route_gap_expectation_mismatch( } } +/// The committed wet receipt envelope — the host realization of +/// `v2.workflow.floor_wet_route.WetReceiptEnvelope`, committed at +/// `floor_wet_route_receipt_json_rel_path` with its canonical TSV projection beside it. +/// Field names mirror the .dag declaration exactly; `deny_unknown_fields` keeps a widened +/// producer from being silently narrowed on read. +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct WetReceiptEnvelope { + pub schema_version: u64, + pub subject_digest: String, + pub executor_contract_digest: String, + pub attempt_seq: u64, + pub executed_at_unix_secs: u64, + pub published_at_unix_secs: u64, + pub run_id: String, + pub head_sha: String, + pub rows: Vec, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct WetReceiptIdentityRow { + pub identity: String, + /// The wire spelling of `WetLaneOutcome` — one of the 12 closed arms in + /// `WET_OUTCOME_WIRES` (never a collapsed pass/fail Bool; parent outcome-grain wall); + /// validated on read, unknown wires refuse as ContractMismatch. + pub outcome: String, + pub wall_ms: u64, + /// WHAT THE LANE ACTUALLY RESOLVED AND ACTUALLY INVOKED, recorded at the producer from the + /// node the interpreter's own lookup SELECTED (`selected_function_identity`) — never copied + /// back from the roster row that asked for it. The distinction is the whole value: a + /// recopied entry and function make every downstream foreign-entry / foreign-function join + /// tautological, so the receipt would agree with the roster by construction and a witness + /// executing out of a different file would receipt as if it had not. + /// + /// `None` is the honest reading for a row that never reached a resolved declaration (entry + /// resolve failed, closure subject failed): there is no observation to record, and a + /// fabricated one would be exactly the plausible output DESIGN §5 forbids. + #[serde(default)] + pub observed_entry_rel: Option, + #[serde(default)] + pub observed_function: Option, +} + +/// Read the committed envelope pair. Fail-closed on shape: a malformed envelope, an invalid +/// outcome, a duplicate identity, an orphaned or drifted TSV projection are each a refusal +/// naming the file — a receipt that cannot be read coherently must not be distinguishable +/// from one that was never produced only by accident. Both files absent is the one +/// non-error absence: the Missing standing, decided by the caller. +/// +/// THE HAND-EDIT RED lives here (parent amendment 2026-08-30): the TSV is re-projected from +/// the JSON and compared byte-for-byte, so an edit to either file alone refuses +/// deterministically on the required path. This proves the committed pair is +/// self-consistent, NOT that the lane produced it — the declared trust boundary for +/// authenticity is ordinary pull-request approval of the refresh PR. +/// Returns the envelope AND the digest of the exact bytes it was decoded from. +/// +/// THE DIGEST IS CARRIED, NEVER RE-DERIVED FROM THE PATH. It used to be computed at the lease +/// site by a SECOND `std::fs::read` of the same path, ~2500 lines and one whole floor fold +/// later. Two reads of one path with nothing carrying the first read's bytes to the second is a +/// window: a write landing between them -- `write_wet_receipt_envelope` from the wet dispatch +/// binary overwrites an existing receipt by design -- produces an envelope and a digest that +/// describe DIFFERENT bytes, and the lease's exact-envelope-digest join would then be checked +/// against a file the decoded envelope did not come from. Returning them together makes that +/// pair unconstructible rather than merely unlikely, which is the same move the gate already +/// makes for standing-vs-admission. +pub(crate) fn read_wet_receipt_envelope( + json_rel: &str, + tsv_rel: &str, +) -> Result, String> { + let json_text = match std::fs::read_to_string(json_rel) { + Ok(c) => Some(c), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => None, + Err(e) => return Err(format!("wet-lane receipt {json_rel}: {e}")), + }; + let tsv_text = match std::fs::read_to_string(tsv_rel) { + Ok(c) => Some(c), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => None, + Err(e) => return Err(format!("wet-lane receipt projection {tsv_rel}: {e}")), + }; + let json_text = match (json_text, &tsv_text) { + (None, None) => return Ok(None), + (None, Some(_)) => { + return Err(format!( + "wet-lane receipt: {tsv_rel} exists but its authority {json_rel} does not — \ + the projection is orphaned, which only a hand edit produces. Regenerate both \ + from a lane run" + )); + } + (Some(j), _) => j, + }; + let envelope_digest = { + use sha2::Digest as _; + format!("{:x}", sha2::Sha256::digest(json_text.as_bytes())) + }; + let envelope: WetReceiptEnvelope = serde_json::from_str(&json_text) + .map_err(|e| format!("wet-lane receipt {json_rel}: {e}"))?; + let mut seen = HashSet::new(); + for row in &envelope.rows { + if !WET_OUTCOME_WIRES.contains(&row.outcome.as_str()) { + return Err(format!( + "wet-lane receipt {json_rel}: identity {} outcome `{}` is outside the closed \ + wire vocabulary", + row.identity, row.outcome + )); + } + if !seen.insert(row.identity.as_str()) { + return Err(format!( + "wet-lane receipt {json_rel}: duplicate identity {}", + row.identity + )); + } + } + let Some(tsv_text) = tsv_text else { + return Err(format!( + "wet-lane receipt: {json_rel} exists but its projection {tsv_rel} does not — the \ + committed pair is incomplete. Regenerate both from a lane run" + )); + }; + let expected = wet_receipt_tsv_projection(&envelope); + if tsv_text != expected { + return Err(format!( + "wet-lane receipt: {tsv_rel} is not the canonical projection of {json_rel} — one \ + of the pair was edited by hand. Regenerate both from a lane run instead of \ + editing either" + )); + } + Ok(Some((envelope, envelope_digest))) +} + +/// The one canonical TSV rendering of an envelope, shared by the lane's writer and the +/// floor's drift check so the two cannot disagree about the format. Rows in envelope order +/// (the writer sorts by identity before publishing). +pub fn wet_receipt_tsv_projection(envelope: &WetReceiptEnvelope) -> String { + let mut out = String::new(); + out.push_str( + "# generated projection of the wet-lane receipt envelope (latest-attempt.json). Edit \ + neither file by hand: the required floor re-projects and refuses on any drift.\n", + ); + out.push_str(&format!( + "# schema_version={} subject_digest={} executor_contract_digest={} attempt_seq={} \ + executed_at_unix_secs={} published_at_unix_secs={} run_id={} head_sha={}\n", + envelope.schema_version, + envelope.subject_digest, + envelope.executor_contract_digest, + envelope.attempt_seq, + envelope.executed_at_unix_secs, + envelope.published_at_unix_secs, + envelope.run_id, + envelope.head_sha + )); + out.push_str("# identity\toutcome\twall_ms\tobserved_entry_rel\tobserved_function\n"); + for row in &envelope.rows { + // `-` renders the ABSENCE of an observation, which is a real state (a row that never + // reached a resolved declaration), not a default standing in for one. The projection is + // re-derived and compared byte-for-byte on read, so the rendering is decided here once. + out.push_str(&format!( + "{}\t{}\t{}\t{}\t{}\n", + row.identity, + row.outcome, + row.wall_ms, + row.observed_entry_rel.as_deref().unwrap_or("-"), + row.observed_function.as_deref().unwrap_or("-") + )); + } + out +} + +/// THE PER-ENTRY WET SUBJECT — the named instrument behind `wet_subject_digest` (DESIGN §6: +/// name the producer, never transcribe its output). +/// +/// The aggregate sha can say only THAT a producer and a consumer disagree; it cannot say WHERE, +/// and a disagreement whose locus is unreadable is the one that survives. This one did, for +/// seven landing cycles: the floor printed `envelope carries X but this tree computes Y` every +/// run, and there was no way to ask which entry moved. Every caller of the digest folds THIS, +/// so the producer's list and the consumer's list diff directly, entry by entry. +/// +/// Returned sorted and deduplicated by entry, so two runs' lists are comparable positionally. +pub fn wet_subject_entry_subjects( + source_roots: &[String], +) -> Result, String> { + let rows = wet_route_lane_rows(source_roots)?; + let index = process_shared_index(source_roots); + let mut entries: Vec<&str> = vec!["src/v2/workflow/floor_wet_route.dag"]; + for row in &rows { + entries.push(row.entry_rel.as_str()); + } + entries.sort_unstable(); + entries.dedup(); + let mut pairs: Vec<(String, String)> = Vec::new(); + for entry in entries { + let subject = wet_closure_subject_for_entry(&index, entry) + .map_err(|e| format!("wet_subject_digest: closure subject for {entry}: {e}"))?; + pairs.push((entry.to_string(), subject)); + } + Ok(pairs) +} + +/// THE WET SUBJECT DIGEST — the receipt's validity key (parent amendment 2026-08-30): +/// sha256 over the sorted per-entry closure subjects of every roster row plus the closure +/// subject of the route authority module itself, so a change to any routed witness, its +/// import closure, the harness .dag implementation, the roster, or the receipt contract +/// moves the digest, while a change outside those closures does not. The DECLARED +/// subject-universe exclusion is `v2.workflow.floor_wet_route.wet_subject_digest_exclusions`: +/// the seed-Rust harness binaries are outside it. +/// +/// IT IS A FUNCTION OF THE TREE AND OF NOTHING ELSE, which is what makes candidate-exactness a +/// decidable equality — and which this function did NOT establish until 2026-08-31. It folded +/// `closure_subject_for_entry`, whose digest mixes in the bytes of the running executable, so +/// the producer (`claim_batch`) and the consumer (`claim_executor`) — different binaries — +/// could never agree, on any tree. An earlier revision of this note asserted the two computed +/// it "identically from the same resolver": true about the resolver, false about the +/// conclusion, and the false half is what every session planned against. It now folds +/// `wet_closure_subject_for_entry`, which carries the `.dag` closure content alone; the seed +/// executor keeps its own axis in `wet_executor_contract_digest`. The wall that keeps this +/// honest is the enrolled RED +/// `v2.test.floor_wet_route.wet_subject_is_independent_of_the_running_binary`. +pub fn wet_subject_digest(source_roots: &[String]) -> Result { + let pairs = wet_subject_entry_subjects(source_roots)?; + for (entry, subject) in &pairs { + eprintln!("[wet-subject] entry={entry} closure_subject={subject}"); + } + let mut subjects: Vec = pairs.into_iter().map(|(_, subject)| subject).collect(); + subjects.sort_unstable(); + use sha2::Digest as _; + let mut hasher = sha2::Sha256::new(); + for (i, subject) in subjects.iter().enumerate() { + if i > 0 { + hasher.update(b"\n"); + } + hasher.update(subject.as_bytes()); + } + Ok(format!("{:x}", hasher.finalize())) +} + +/// THE EXECUTOR CONTRACT DIGEST (residual-A repair, parent ruling 2026-08-30): sha256 over +/// the bytes of every file under the declared input roster +/// (`v2.workflow.floor_wet_route.wet_executor_contract_input_prefixes` — the seed crate, +/// workspace manifests and lockfile, toolchain pin, cargo config, and the wet +/// workflow/command model files), each contributing its repo-relative path and content. +/// This is a deliberately conservative SUPERSET: an extra wet rerun for a seed edit that +/// changed no wet behavior is accepted; a seed executor change that leaves an old receipt +/// reading candidate-exact is not. A declared prefix matching nothing on disk REFUSES — +/// a rotted roster row is a silently narrowing digest. +pub fn wet_executor_contract_digest(source_roots: &[String]) -> Result { + let index = process_shared_index(source_roots); + let entry = "src/v2/workflow/floor_wet_route.dag"; + let (graph, source_indices) = resolve_entry_with_index(&index, entry) + .map_err(|e| format!("wet_executor_contract_digest: resolve {entry}: {e}"))?; + let ctx = make_eval_context( + &graph, + source_indices, + v1_interpreter::ExecutionMode::Hermetic, + ); + let value = v1_interpreter::run_in_context( + &ctx, + "v2.workflow.floor_wet_route.wet_executor_contract_input_prefixes", + false, + ) + .map_err(|e| format!("wet_executor_contract_input_prefixes: {e}"))?; + let items = floor_decode_list(&ctx, Some(&value)) + .map_err(|e| format!("wet_executor_contract_input_prefixes: {e}"))?; + let mut prefixes: Vec = Vec::new(); + for item in items { + match item { + v1_interpreter::Value::Str(p) => prefixes.push(p.to_string()), + other => { + return Err(format!( + "wet_executor_contract_input_prefixes: expected a String path, got {}", + floor_value_shape(Some(other)) + )) + } + } + } + let mut files: BTreeSet = BTreeSet::new(); + for prefix in &prefixes { + if prefix.ends_with('/') { + let dir = prefix.trim_end_matches('/'); + let mut stack = vec![std::path::PathBuf::from(dir)]; + let mut found_any = false; + while let Some(d) = stack.pop() { + let entries = std::fs::read_dir(&d).map_err(|e| { + format!( + "wet_executor_contract_digest: read_dir {}: {e}", + d.display() + ) + })?; + for entry in entries { + let entry = entry.map_err(|e| { + format!( + "wet_executor_contract_digest: read_dir {}: {e}", + d.display() + ) + })?; + let path = entry.path(); + if path.is_dir() { + stack.push(path); + } else { + found_any = true; + files.insert(path.to_string_lossy().to_string()); + } + } + } + if !found_any { + return Err(format!( + "wet_executor_contract_digest: declared input prefix {prefix} matched no \ + files — the roster row has rotted, and a silently narrowing digest is the \ + under-invalidation this repair forbids" + )); + } + } else { + if !std::path::Path::new(prefix).is_file() { + return Err(format!( + "wet_executor_contract_digest: declared input file {prefix} does not exist \ + — the roster row has rotted, and a silently narrowing digest is the \ + under-invalidation this repair forbids" + )); + } + files.insert(prefix.clone()); + } + } + use sha2::Digest as _; + let mut hasher = sha2::Sha256::new(); + for file in &files { + let content = std::fs::read(file) + .map_err(|e| format!("wet_executor_contract_digest: read {file}: {e}"))?; + hasher.update(file.as_bytes()); + hasher.update([0u8]); + hasher.update(&content); + hasher.update([0u8]); + } + Ok(format!("{:x}", hasher.finalize())) +} + +/// Host realization of `v2.workflow.floor_wet_route.WetLaneReceiptStanding`, one value per +/// evaluated tree. Exactly `FreshExactSubject` is clean; the polarity is the .dag fold's +/// `wet_route_standing_blocks_floor`, realized in `WetLaneReceiptStanding::blocks`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) enum WetLaneReceiptStanding { + FreshExactSubject { + age_secs: u64, + }, + Missing, + Expired { + age_secs: u64, + }, + SubjectMismatch { + axis: &'static str, + receipt_digest: String, + computed_digest: String, + }, + ExecutorSnapshotDifferent { + receipt_digest: String, + computed_digest: String, + }, + ContractMismatch { + detail: String, + }, + RosterInexact { + detail: String, + }, +} + +impl WetLaneReceiptStanding { + pub(crate) fn blocks(&self) -> bool { + !matches!(self, WetLaneReceiptStanding::FreshExactSubject { .. }) + } + pub(crate) fn describe(&self) -> String { + match self { + WetLaneReceiptStanding::FreshExactSubject { age_secs } => { + format!("fresh-exact-subject age_secs={age_secs}") + } + WetLaneReceiptStanding::Missing => "missing — no envelope committed; run the wet \ + receipts lane (workflow_dispatch on the witnesses workflow, or claim_batch \ + --wet-route) and land its envelope" + .to_string(), + WetLaneReceiptStanding::Expired { age_secs } => format!( + "expired — executed {age_secs}s before the evaluated commit, past the declared \ + cadence + grace; restore the lane's cadence and land a fresh envelope" + ), + WetLaneReceiptStanding::SubjectMismatch { + axis, + receipt_digest, + computed_digest, + } => format!( + "subject-mismatch axis={axis} — envelope carries {receipt_digest} but this \ + tree computes {computed_digest}; the lane has not executed this candidate's \ + wet subject on that axis (an ancestor receipt blocks by ruling; an \ + executor-contract miss means the seed executor changed without a wet rerun). \ + workflow_dispatch the lane on this head and land its envelope" + ), + WetLaneReceiptStanding::ExecutorSnapshotDifferent { + receipt_digest, + computed_digest, + } => format!( + "executor-snapshot-different — envelope was executed under seed executor \ + {receipt_digest} but this tree computes {computed_digest}; the same semantic \ + subject ran under a superseded seed build. Re-run the lane on this head, or \ + (bootstrap only) a declared one-shot lease naming exactly this envelope may \ + admit it inside its fixed window" + ), + WetLaneReceiptStanding::ContractMismatch { detail } => { + format!("contract-mismatch — {detail}") + } + WetLaneReceiptStanding::RosterInexact { detail } => { + format!("roster-inexact — {detail}") + } + } + } +} + +/// Host realization of `v2.workflow.floor_wet_route.BootstrapExecutorSnapshotReceipt` — the +/// declared one-shot lease row — and its admission evaluation +/// (`wet_seed_bootstrap_admission`). The lease admits exactly one named envelope past +/// `ExecutorSnapshotDifferent` — never past any other standing — inside a FIXED window of +/// executed_at + window with no slide or renewal; `not_after` is derived and checked, not +/// trusted. Digest derivations realized here (the .dag fn takes them as parameters): +/// envelope digest is sha256 over the committed latest-attempt.json bytes; roster digest is +/// sha256 over the newline-joined sorted roster identities. +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct WetBootstrapLease { + pub lease_identity: String, + pub exact_envelope_digest: String, + pub exact_attempt_seq: u64, + pub exact_semantic_subject_digest: String, + pub exact_roster_digest: String, + pub observed_executor_contract_digest: String, + pub executed_at_unix_secs: u64, + pub not_after_unix_secs: u64, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) enum WetSeedBootstrapAdmission { + Admitted { not_after_unix_secs: u64 }, + Expired { detail: String }, + NotApplicable, +} + +pub(crate) fn wet_seed_bootstrap_admission( + lease: Option<&WetBootstrapLease>, + window_secs: u64, + envelope_digest: &str, + attempt_seq: u64, + semantic_subject_digest: &str, + roster_digest: &str, + evaluated_tree_commit_secs: u64, +) -> WetSeedBootstrapAdmission { + let Some(r) = lease else { + return WetSeedBootstrapAdmission::NotApplicable; + }; + if r.exact_envelope_digest != envelope_digest + || r.exact_attempt_seq != attempt_seq + || r.exact_semantic_subject_digest != semantic_subject_digest + || r.exact_roster_digest != roster_digest + { + return WetSeedBootstrapAdmission::NotApplicable; + } + if r.not_after_unix_secs != r.executed_at_unix_secs + window_secs { + return WetSeedBootstrapAdmission::NotApplicable; + } + if evaluated_tree_commit_secs > r.not_after_unix_secs { + return WetSeedBootstrapAdmission::Expired { + detail: format!( + "the evaluated tree's commit time {} exceeds the lease's fixed not_after {}", + evaluated_tree_commit_secs, r.not_after_unix_secs + ), + }; + } + WetSeedBootstrapAdmission::Admitted { + not_after_unix_secs: r.not_after_unix_secs, + } +} + +/// Read the declared lease row (`gunbc.wet_seed_bootstrap_lease.wet_seed_bootstrap_lease_declared` +/// — homed OUTSIDE the wet semantic closure so a flip moves no digest) and the fixed window +/// from the route authority. Absent is the standing state; fail-closed on shape. +pub(crate) fn wet_seed_bootstrap_lease_declared( + source_roots: &[String], +) -> Result<(Option, u64), String> { + let index = process_shared_index(source_roots); + let entry = "dag/gunbc/floor/wet_seed_bootstrap_lease.dag"; + let (graph, source_indices) = resolve_entry_with_index(&index, entry) + .map_err(|e| format!("wet_seed_bootstrap_lease_declared: resolve {entry}: {e}"))?; + let ctx = make_eval_context( + &graph, + source_indices, + v1_interpreter::ExecutionMode::Hermetic, + ); + let window = match v1_interpreter::run_in_context( + &ctx, + "v2.workflow.floor_wet_route.wet_seed_bootstrap_lease_window_secs", + false, + ) { + Ok(v1_interpreter::Value::Int(n)) if n > 0 => n as u64, + Ok(other) => { + return Err(format!( + "wet_seed_bootstrap_lease_window_secs: expected a positive Int, got {}", + floor_value_shape(Some(&other)) + )) + } + Err(e) => return Err(format!("wet_seed_bootstrap_lease_window_secs: {e}")), + }; + let value = v1_interpreter::run_in_context( + &ctx, + "gunbc.wet_seed_bootstrap_lease.wet_seed_bootstrap_lease_declared", + false, + ) + .map_err(|e| format!("wet_seed_bootstrap_lease_declared: {e}"))?; + let v1_interpreter::Value::Variant { + variant_name, + fields, + .. + } = &value + else { + return Err(format!( + "wet_seed_bootstrap_lease_declared: expected Optional, got {}", + floor_value_shape(Some(&value)) + )); + }; + if ctx.sym_eq(*variant_name, "Absent") { + return Ok((None, window)); + } + if !ctx.sym_eq(*variant_name, "Present") { + return Err(format!( + "wet_seed_bootstrap_lease_declared: expected Absent/Present, got {}", + ctx.resolve(*variant_name) + )); + } + let Some(v1_interpreter::Value::Record { fields: rf, .. }) = ctx.field(fields, "value") else { + return Err("wet_seed_bootstrap_lease_declared: Present must carry a \ + BootstrapExecutorSnapshotReceipt record" + .to_string()); + }; + let field_str = |name: &str| -> Result { + match ctx.field(rf, name) { + Some(v1_interpreter::Value::Str(s)) => Ok(s.to_string()), + other => Err(format!( + "wet_seed_bootstrap_lease_declared: {name} must be String, got {}", + floor_value_shape(other) + )), + } + }; + let field_u64 = |name: &str| -> Result { + match ctx.field(rf, name) { + Some(v1_interpreter::Value::Int(n)) if *n >= 0 => Ok(*n as u64), + other => Err(format!( + "wet_seed_bootstrap_lease_declared: {name} must be a non-negative Int, got {}", + floor_value_shape(other) + )), + } + }; + Ok(( + Some(WetBootstrapLease { + lease_identity: field_str("lease_identity")?, + exact_envelope_digest: field_str("exact_envelope_digest")?, + exact_attempt_seq: field_u64("exact_attempt_seq")?, + exact_semantic_subject_digest: field_str("exact_semantic_subject_digest")?, + exact_roster_digest: field_str("exact_roster_digest")?, + observed_executor_contract_digest: field_str("observed_executor_contract_digest")?, + executed_at_unix_secs: field_u64("executed_at_unix_secs")?, + not_after_unix_secs: field_u64("not_after_unix_secs")?, + }), + window, + )) +} + +/// The standing fold, mirroring the .dag decision order exactly: unreadable-contract facts +/// before subject facts, subject before roster, roster before time, time before verdict. +/// +/// `evaluated_tree_commit_secs` IS REQUIRED, exactly as the authority declares it +/// (`v2.workflow.floor_wet_route.wet_lane_receipt_standing` takes +/// `evaluated_tree_commit_unix_secs: EpochSecs`, not an `Optional`). It was an `Option` +/// here until review 57856, and the `None` arm skipped BOTH time comparisons and then fell +/// through to `FreshExactSubject { age_secs: 0 }` — reporting a receipt whose age could not be +/// computed as a receipt that is fresh. That is ⊤-as-ignorance rendered as ⊤-as-answer, the +/// absorbing fallback DESIGN §5 names, and it was a §3 defect besides: the Rust widened a +/// parameter the .dag declares total, so the two authorities disagreed about whether the fact +/// is optional at all. The repair is not a new standing arm — inventing one here would fork the +/// coproduct away from its authority — it is that the CALLER refuses when the commit time is +/// unobservable, so this fold is only ever reached with the fact it requires. +#[allow(clippy::too_many_arguments)] +pub(crate) fn wet_lane_receipt_standing( + envelope: Option<&WetReceiptEnvelope>, + computed_subject_digest: &str, + computed_executor_contract_digest: &str, + roster: &BTreeSet, + evaluated_tree_commit_secs: u64, + schema_version: u64, + staleness_budget_secs: u64, + publication_skew_secs: u64, +) -> WetLaneReceiptStanding { + let Some(e) = envelope else { + return WetLaneReceiptStanding::Missing; + }; + if e.schema_version != schema_version { + return WetLaneReceiptStanding::ContractMismatch { + detail: format!( + "schema_version {} is not the version {} this floor reads", + e.schema_version, schema_version + ), + }; + } + if e.executed_at_unix_secs > e.published_at_unix_secs { + return WetLaneReceiptStanding::ContractMismatch { + detail: "executed_at exceeds published_at".to_string(), + }; + } + if e.published_at_unix_secs > evaluated_tree_commit_secs + publication_skew_secs { + return WetLaneReceiptStanding::ContractMismatch { + detail: format!( + "published_at {} exceeds the evaluated tree's commit time {} beyond the \ + declared {}s skew", + e.published_at_unix_secs, evaluated_tree_commit_secs, publication_skew_secs + ), + }; + } + if e.subject_digest != computed_subject_digest { + return WetLaneReceiptStanding::SubjectMismatch { + axis: "semantic-subject", + receipt_digest: e.subject_digest.clone(), + computed_digest: computed_subject_digest.to_string(), + }; + } + // THE EXECUTOR ARM IS DEFERRED TO LAST, DELIBERATELY, AND THE ORDER IS THE GUARANTEE. + // + // It used to return HERE, fifth of nine, which made `ExecutorSnapshotDifferent` mean only + // "executor disagreement was the FIRST blocking arm reached" -- the roster join, the + // observed-identity conformance, the outcome-vocabulary check, the age sanity and the + // staleness budget were never evaluated on that path. A bootstrap lease then admits on + // exactly that arm, so the lease was silently waiving four axes it was never granted + // against, and a receipt admitted under it carried NO established roster or identity + // conformance at all. The measurement that the rows join the roster exactly was the + // author's instrument reading the file, not this function returning true. + // + // Deferring the comparison to the end inverts that: every later condition is evaluated + // first, so reaching this line at all means the standing WOULD have been + // `FreshExactSubject` had the digests agreed. The lease therefore waives exactly one axis + // -- the one it is granted against -- and any other defect refuses ahead of it. + let executor_snapshot_differs = e.executor_contract_digest != computed_executor_contract_digest; + let row_ids: BTreeSet<&str> = e.rows.iter().map(|r| r.identity.as_str()).collect(); + let missing: Vec<&str> = roster + .iter() + .map(|s| s.as_str()) + .filter(|id| !row_ids.contains(*id)) + .collect(); + let extra: Vec<&str> = row_ids + .iter() + .copied() + .filter(|id| !roster.contains(*id)) + .collect(); + if !missing.is_empty() || !extra.is_empty() { + return WetLaneReceiptStanding::RosterInexact { + detail: format!( + "envelope rows are not exactly the routed roster (missing: [{}]; off-roster: \ + [{}])", + missing.join(", "), + extra.join(", ") + ), + }; + } + for row in &e.rows { + if !WET_OUTCOME_WIRES.contains(&row.outcome.as_str()) { + return WetLaneReceiptStanding::ContractMismatch { + detail: format!( + "row {} carries outcome `{}`, outside the closed wire vocabulary — the \ + producer and this reader no longer share an outcome grammar", + row.identity, row.outcome + ), + }; + } + } + // THE OBSERVED-RESOLUTION JOIN. `observed_function` is the qualified name of the node the + // lane's interpreter actually selected; the row's `identity` is what the roster asked for. + // Comparing them catches a witness that executed out of a different declaration than the + // one routed — the bare-name precedence collision this corpus has already shipped once, + // where a reference bound to a homonym in another module and the run reported under the + // requested name. It is not tautological because the two sides have different producers: + // one is read off the selected node's span, the other is authored in the roster. + // + // A row that reached no declaration carries no observation and is not judged here; its + // outcome already says so, and `wet_receipt_no_verdict_identities` blocks on it. + for row in &e.rows { + if let Some(observed) = row.observed_function.as_deref() { + if observed != row.identity { + return WetLaneReceiptStanding::ContractMismatch { + detail: format!( + "row {} was executed as `{observed}` — the lane resolved a different \ + declaration than the routed identity names, so the receipt does not \ + attest the witness the roster asked for", + row.identity + ), + }; + } + } + } + // A NEGATIVE AGE REFUSES; IT DOES NOT CLAMP. `saturating_sub` used to floor this at zero, + // which rendered a receipt executed AFTER the tree it is a verdict about as the FRESHEST + // possible receipt -- the absorbing arm DESIGN section 5 names, reading bottom-as-ignorance + // as bottom-as-answer. `v2.workflow.floor_wet_route` already refuses this; the seed did not, + // and the two disagreed on a receipt no honest producer emits and a tampered one does. + if e.executed_at_unix_secs > evaluated_tree_commit_secs { + return WetLaneReceiptStanding::ContractMismatch { + detail: format!( + "executed_at {} is later than the evaluated tree's commit time {} — a receipt \ + cannot be executed after the tree it is a verdict about", + e.executed_at_unix_secs, evaluated_tree_commit_secs + ), + }; + } + let age_secs = evaluated_tree_commit_secs - e.executed_at_unix_secs; + if age_secs > staleness_budget_secs { + return WetLaneReceiptStanding::Expired { age_secs }; + } + if executor_snapshot_differs { + return WetLaneReceiptStanding::ExecutorSnapshotDifferent { + receipt_digest: e.executor_contract_digest.clone(), + computed_digest: computed_executor_contract_digest.to_string(), + }; + } + WetLaneReceiptStanding::FreshExactSubject { age_secs } +} + +/// THE PER-IDENTITY VERDICT PROJECTIONS (host realization of +/// `v2.workflow.floor_wet_route.wet_receipt_unexpected_red_identities` and siblings, parent +/// ruling 2026-08-30): the receipt's rows join the expected-red roster exactly as dry claims +/// do. Fail + not enrolled blocks (the fail-closed arm); fail + enrolled is held (counted, +/// non-blocking); pass + enrolled is now-passing (blocks until the roster row is removed). +pub(crate) fn wet_receipt_identity_verdicts( + envelope: &WetReceiptEnvelope, + expected_red: &BTreeSet, +) -> WetIdentityVerdicts { + let mut unexpected_red = Vec::new(); + let mut held = Vec::new(); + let mut now_passing = Vec::new(); + let mut no_verdict = Vec::new(); + let mut cost_debt = Vec::new(); + for row in &envelope.rows { + let enrolled = expected_red.contains(&row.identity); + match (row.outcome.as_str(), enrolled) { + ("pass", false) => {} + ("pass", true) => now_passing.push(row.identity.clone()), + ("assertion-false", true) => held.push(row.identity.clone()), + ("assertion-false", false) => unexpected_red.push(row.identity.clone()), + // COST IS NOT A VERDICT, and this wire used to fall through to `no_verdict` + // below. `completed-over-budget` is minted only over a PASS: the witness ran to + // completion and was then found over the line, so the verdict is known and the + // elapsed figure is exact — the opposite of `budget-interrupted`, where the + // deadline preempted the answer. The dry side of this same runner has drawn that + // line for `ClaimOutcome::CompletedOverBudget` since it grew + // `completed_over_cost_requirement`; the wet side had not, so a routed identity + // that answered and cost too much read as "correctness unknown" and sent the + // reader to debug a witness that is not broken. It still blocks — this route + // enrolls no cost-debt population — but it blocks with a cost remedy, and being a + // completion it is roster drift when enrolled exactly as a plain pass is. + ("completed-over-budget", enrolled_here) => { + cost_debt.push(row.identity.clone()); + if enrolled_here { + now_passing.push(row.identity.clone()); + } + } + // Every other wire is a way of producing NO subject verdict, and it blocks + // regardless of enrollment: an enrollment asserts the witness reaches its + // subject and answers, so it cannot hold an infrastructure failure. Only an + // explicitly enrolled typed pre-verdict expectation could — no wet identity + // carries one today, and this arm grows when one does. + _ => no_verdict.push(format!("{} ({})", row.identity, row.outcome)), + } + } + WetIdentityVerdicts { + unexpected_red, + held, + now_passing, + no_verdict, + cost_debt, + } +} + +/// The five per-identity populations, named rather than positional: four of them block and +/// each carries a different remedy — repair the witness, retire the roster row, restore the +/// execution, pay the cost — so a caller that mixes two up sends the reader somewhere useless. +/// A five-wide tuple made that mix-up a silent argument-order edit. +pub(crate) struct WetIdentityVerdicts { + pub(crate) unexpected_red: Vec, + pub(crate) held: Vec, + pub(crate) now_passing: Vec, + pub(crate) no_verdict: Vec, + pub(crate) cost_debt: Vec, +} + +/// THE PUBLICATION TRANSACTION, observed for THIS run (host realization of +/// `v2.workflow.floor_wet_route.WetReceiptPublicationTransaction`): the run's own diff is +/// confined to the two committed receipt paths (nothing else changed, nothing departed) and +/// the committed envelope's attempt sequence advances over the base tree's envelope (absent +/// at base counts as 0, so the first publication admits). Any unobservable input is an Err — +/// the caller keeps blocking on it, never admits. +pub(crate) fn wet_receipt_publication_transaction_valid_for_this_run( + json_rel: &str, + tsv_rel: &str, + envelope: Option<&WetReceiptEnvelope>, +) -> Result { + let Some(envelope) = envelope else { + return Ok(false); + }; + let (changed, departed) = floor_git_diff_name_status_range()?; + if !departed.is_empty() { + return Ok(false); + } + if changed.is_empty() { + return Ok(false); + } + if !changed.iter().all(|p| p == json_rel || p == tsv_rel) { + return Ok(false); + } + let (base_ref, _event) = floor_diff_baseline_readout()?; + let base_attempt_seq = { + let output = std::process::Command::new("git") + .args(["show", &format!("{base_ref}:{json_rel}")]) + .output() + .map_err(|e| format!("git show {base_ref}:{json_rel}: {e}"))?; + if output.status.success() { + let text = String::from_utf8(output.stdout) + .map_err(|e| format!("base envelope {base_ref}:{json_rel}: {e}"))?; + let base: WetReceiptEnvelope = serde_json::from_str(&text) + .map_err(|e| format!("base envelope {base_ref}:{json_rel}: {e}"))?; + base.attempt_seq + } else { + 0 + } + }; + Ok(envelope.attempt_seq > base_attempt_seq) +} + +/// One routed row of `v2.workflow.floor_wet_route.floor_wet_route_roster`, decoded for the +/// wet receipts lane: the entry file to resolve, the function to run, and the qualified +/// identity the receipt is keyed by. The roster is the single population authority — the lane +/// derives its work from it at run time, so a roster edit needs no second surface updated. +#[derive(Debug, Clone)] +pub struct WetRouteLaneRow { + pub identity: String, + pub entry_rel: String, + pub function: String, +} + +/// Decode the wet-route roster from its .dag authority. Fail-closed on shape and on +/// duplicates, exactly as the floor's own read is. +pub fn wet_route_lane_rows(source_roots: &[String]) -> Result, String> { + let index = process_shared_index(source_roots); + let entry = "src/v2/workflow/floor_wet_route.dag"; + let (graph, source_indices) = resolve_entry_with_index(&index, entry) + .map_err(|e| format!("wet_route_lane_rows: resolve {entry}: {e}"))?; + let ctx = make_eval_context( + &graph, + source_indices, + v1_interpreter::ExecutionMode::Hermetic, + ); + let value = v1_interpreter::run_in_context( + &ctx, + "v2.workflow.floor_wet_route.floor_wet_route_roster", + false, + ) + .map_err(|e| format!("floor_wet_route_roster: {e}"))?; + let items = floor_decode_list(&ctx, Some(&value)) + .map_err(|e| format!("floor_wet_route_roster: {e}"))?; + let mut seen = HashSet::new(); + let mut out = Vec::new(); + for item in items { + let v1_interpreter::Value::Record { type_name, fields } = item else { + return Err(format!( + "floor_wet_route_roster: expected WetRouteRow, got {}", + floor_value_shape(Some(item)) + )); + }; + if !ctx.sym_eq(*type_name, "WetRouteRow") { + return Err(format!( + "floor_wet_route_roster: expected WetRouteRow, got record {}", + ctx.resolve(*type_name) + )); + } + let field_str = |name: &str| -> Result { + match ctx.field(fields, name) { + Some(v1_interpreter::Value::Str(s)) => Ok(s.to_string()), + other => Err(format!( + "floor_wet_route_roster: {name} must be String, got {}", + floor_value_shape(other) + )), + } + }; + let row = WetRouteLaneRow { + identity: field_str("identity")?, + entry_rel: field_str("entry_rel")?, + function: field_str("function")?, + }; + if !seen.insert(row.identity.clone()) { + return Err(format!( + "floor_wet_route_roster: duplicate routed identity: {}", + row.identity + )); + } + out.push(row); + } + Ok(out) +} + +/// One executed receipt row for the wet lane's committed envelope — the producer side of +/// `read_wet_receipt_envelope`. +pub struct WetLaneExecutedReceipt { + pub identity: String, + /// The raw typed outcome's wire name — one of `WET_OUTCOME_WIRES` — never a collapsed + /// Bool: an assertion that ran and returned false and an infrastructure failure that + /// produced no verdict are different facts with different standings (parent ruling + /// 2026-08-30, wall 1). + pub outcome_wire: &'static str, + pub wall_ms: u128, + /// The observed resolution — see `WetReceiptIdentityRow::observed_entry_rel`. Read from + /// the selected node, not from the roster row. + pub observed_entry_rel: Option, + pub observed_function: Option, +} + +/// The closed wire vocabulary for a wet row's outcome. A committed envelope carrying any +/// other string is a contract mismatch — the producer and reader no longer share an outcome +/// grammar, and guessing would absorb the distinction the grain exists to carry. +pub const WET_OUTCOME_WIRES: [&str; 12] = [ + "pass", + "assertion-false", + "not-bool", + "runtime-error", + "budget-interrupted", + "completed-over-budget", + "host-tool-unresolved", + "host-effect-refused", + "panicked", + "not-attempted", + "resolve-failed", + "closure-subject-failed", +]; + +/// Write the wet lane's committed pair: the envelope JSON (authority) and its canonical TSV +/// projection. LATEST-ATTEMPT SEMANTICS: `attempt_seq` advances over whatever envelope is +/// committed at `json_path` (1 on first publication); a committed envelope that exists but +/// cannot be parsed REFUSES rather than silently restarting the sequence. `run_id` and +/// `head_sha` come from the producing run's environment (GITHUB_RUN_ID / GITHUB_SHA on the +/// lane; "local" only when GITHUB_ACTIONS is unset, where it is a truthful provenance +/// statement). On CI a missing citation var REFUSES rather than mislabeling the publication +/// as local, and a pre-epoch clock refuses rather than publishing timestamp 0 (review 57955). +pub fn write_wet_receipt_envelope( + json_path: &str, + tsv_path: &str, + rows: &[WetLaneExecutedReceipt], + subject_digest: &str, + executor_contract_digest: &str, + executed_at_unix_secs: u64, +) -> Result<(), String> { + let prior_attempt_seq = match std::fs::read_to_string(json_path) { + Ok(text) => { + let prior: WetReceiptEnvelope = serde_json::from_str(&text).map_err(|e| { + format!( + "write_wet_receipt_envelope: committed envelope {json_path} exists but \ + cannot be parsed ({e}) — investigate before overwriting; a silent \ + attempt_seq restart would erase the attempt ordering" + ) + })?; + prior.attempt_seq + } + Err(e) if e.kind() == std::io::ErrorKind::NotFound => 0, + Err(e) => return Err(format!("write_wet_receipt_envelope: read {json_path}: {e}")), + }; + let on_ci = std::env::var("GITHUB_ACTIONS").is_ok(); + let run_id = + match std::env::var("GITHUB_RUN_ID") { + Ok(v) => v, + Err(_) if !on_ci => "local".to_string(), + Err(_) => return Err( + "write_wet_receipt_envelope: GITHUB_ACTIONS is set but GITHUB_RUN_ID is absent \ + — refusing to publish a CI envelope with a fabricated run citation" + .to_string(), + ), + }; + let head_sha = match std::env::var("GITHUB_SHA") { + Ok(v) => v, + Err(_) if !on_ci => "local".to_string(), + Err(_) => { + return Err( + "write_wet_receipt_envelope: GITHUB_ACTIONS is set but GITHUB_SHA is absent — \ + refusing to publish a CI envelope with a fabricated head citation" + .to_string(), + ) + } + }; + let published_at_unix_secs = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_secs()) + .map_err(|e| { + format!( + "write_wet_receipt_envelope: system clock is before the unix epoch ({e}) — \ + refusing to publish a fabricated publication timestamp" + ) + })?; + let mut sorted: Vec<&WetLaneExecutedReceipt> = rows.iter().collect(); + sorted.sort_by(|a, b| a.identity.cmp(&b.identity)); + let envelope = WetReceiptEnvelope { + schema_version: 2, + subject_digest: subject_digest.to_string(), + executor_contract_digest: executor_contract_digest.to_string(), + attempt_seq: prior_attempt_seq + 1, + executed_at_unix_secs, + published_at_unix_secs, + run_id, + head_sha, + rows: sorted + .iter() + .map(|row| WetReceiptIdentityRow { + identity: row.identity.clone(), + outcome: row.outcome_wire.to_string(), + wall_ms: row.wall_ms as u64, + observed_entry_rel: row.observed_entry_rel.clone(), + observed_function: row.observed_function.clone(), + }) + .collect(), + }; + if let Some(parent) = std::path::Path::new(json_path).parent() { + std::fs::create_dir_all(parent).map_err(|e| { + format!( + "write_wet_receipt_envelope: mkdir {}: {e}", + parent.display() + ) + })?; + } + let json_text = serde_json::to_string_pretty(&envelope) + .map_err(|e| format!("write_wet_receipt_envelope: serialize: {e}"))?; + std::fs::write(json_path, format!("{json_text}\n")) + .map_err(|e| format!("write_wet_receipt_envelope: write {json_path}: {e}"))?; + std::fs::write(tsv_path, wet_receipt_tsv_projection(&envelope)) + .map_err(|e| format!("write_wet_receipt_envelope: write {tsv_path}: {e}"))?; + Ok(()) +} + +#[cfg(test)] +mod wet_subject_transform_independence_tests { + use super::*; + use crate::resolved_graph_cache::{ + derive_subject_digest, subject_digest_for_closure, KeyInputMaterials, + }; + + // A NON-DEGENERATE CLOSURE. An empty source list makes both digests fold to their seed + // constant, and two constants comparing unequal would prove nothing about real content — + // the assertions below would hold by construction and keep holding after the wall was gone. + fn two_module_closure() -> Vec> { + vec![ + std::rc::Rc::new(v1_compiler_compile::SourceFile { + path: "dag/test/claim/a_test.dag".to_string(), + content: "module test.claim.a\nfn holds() -> Bool { true }\n".to_string(), + }), + std::rc::Rc::new(v1_compiler_compile::SourceFile { + path: "dag/test/claim/b_test.dag".to_string(), + content: "module test.claim.b\nfn holds() -> Bool { false }\n".to_string(), + }), + ] + } + + // THE DISCRIMINATING RED FOR THE SEVEN-CYCLE DEFECT, enrolled permanently rather than + // retired now that it greens (DESIGN 4b, dissolution-on-climb: the production machinery + // dissolves, the evidence stays). + // + // WHAT WENT WRONG. The wet-lane receipt's candidate-exactness test is + // `envelope.subject_digest == computed_subject_digest`. The envelope is written by + // `claim_batch`; the equality is checked by `claim_executor`. The subject folded + // `subject_digest_for_closure`, which mixes `transform_content_digest()` — the bytes of the + // RUNNING EXECUTABLE — into the digest. Two binaries, two digests, so that equality was + // unsatisfiable BY CONSTRUCTION on every tree in every event, and the floor refused seven + // consecutive landing cycles for a staleness that did not exist. + // + // WHY THIS SHAPE. Spawning two real executables inside a lib test would measure the build + // rather than the property, so the transform axis is varied directly and the wet subject is + // required not to move with it. Each assertion is paired with the positive control that + // makes it discriminating: without them a wall that had been removed would still read green. + #[test] + fn wet_subject_is_independent_of_the_running_binary() { + let sources = two_module_closure(); + let closure = wet_closure_subject(&sources); + let transform_a = crate::v1_rt::atom_identity_hash("binary-claim-batch".to_string()); + let transform_b = crate::v1_rt::atom_identity_hash("binary-claim-executor".to_string()); + + // POSITIVE CONTROL: varying the transform digest genuinely moves a digest that folds + // it. Correct for the resolve cache — an artifact built by one compiler must not be + // served to another — and it proves the variation below is real rather than inert. + assert_ne!( + derive_subject_digest(&KeyInputMaterials::new(closure.clone(), transform_a)), + derive_subject_digest(&KeyInputMaterials::new(closure.clone(), transform_b)), + "positive control failed: varying the transform digest did not move a subject that folds it, so this test cannot discriminate and the wall below proves nothing" + ); + + // THE WALL. The wet semantic subject is the .dag closure content and nothing else, so + // it is NOT the cache subject. Re-pointing `wet_closure_subject` at + // `subject_digest_for_closure` — which is exactly the defect — reds this line. + assert_ne!( + wet_closure_subject(&sources), + subject_digest_for_closure(&sources), + "the wet semantic subject folded the running executable's bytes: producer and consumer are different binaries, so candidate-exactness is now unsatisfiable on every tree" + ); + } + + // THE SUBJECT MOVES ON WHAT IT CLAIMS TO MEASURE. A tree-only digest that ignored content + // would satisfy the test above trivially, so the same wall needs its other half: .dag + // content changes the subject, and nothing else does. + #[test] + fn the_wet_subject_moves_on_dag_content() { + let sources = two_module_closure(); + let mut edited = two_module_closure(); + std::rc::Rc::get_mut(&mut edited[1]).unwrap().content = + "module test.claim.b\nfn holds() -> Bool { true }\n".to_string(); + assert_ne!( + wet_closure_subject(&sources), + wet_closure_subject(&edited), + "the wet subject did not move when a routed module's .dag content changed, so it cannot detect the staleness it exists to detect" + ); + // And it is stable across repeated computation on identical content — the property the + // producer and the consumer rely on when they compare across two processes. + assert_eq!( + wet_closure_subject(&sources), + wet_closure_subject(&two_module_closure()), + "the wet subject is not a function of content alone" + ); + } +} + +#[cfg(test)] +mod wet_lane_receipt_tests { + use super::*; + + fn scratch_dir(name: &str) -> std::path::PathBuf { + let dir = + std::env::temp_dir().join(format!("gunbc_wet_receipt_{}_{name}", std::process::id())); + std::fs::create_dir_all(&dir).unwrap(); + dir + } + + fn one_row() -> Vec { + vec![WetLaneExecutedReceipt { + identity: "test.claim.x.holds".to_string(), + outcome_wire: "pass", + wall_ms: 42, + observed_entry_rel: Some("dag/test/claim/x_test.dag".to_string()), + observed_function: Some("test.claim.x.holds".to_string()), + }] + } + + fn write_fixture(name: &str) -> (String, String) { + let dir = scratch_dir(name); + let json = dir + .join("latest-attempt.json") + .to_string_lossy() + .to_string(); + let tsv = dir.join("latest-attempt.tsv").to_string_lossy().to_string(); + std::fs::remove_file(&json).ok(); + std::fs::remove_file(&tsv).ok(); + write_wet_receipt_envelope(&json, &tsv, &one_row(), "subject-d", "exec-d", 1000) + .expect("write"); + (json, tsv) + } + + #[test] + fn writer_output_reads_back_and_attempt_seq_advances() { + let (json, tsv) = write_fixture("roundtrip"); + let (envelope, envelope_digest) = read_wet_receipt_envelope(&json, &tsv) + .expect("read back") + .expect("present"); + assert_eq!(envelope.attempt_seq, 1); + assert_eq!(envelope.rows.len(), 1); + assert_eq!(envelope.rows[0].outcome, "pass"); + assert_eq!(envelope.subject_digest, "subject-d"); + write_wet_receipt_envelope(&json, &tsv, &one_row(), "subject-d", "exec-d", 2000) + .expect("rewrite"); + let (second, _) = read_wet_receipt_envelope(&json, &tsv) + .expect("read back") + .expect("present"); + assert_eq!(second.attempt_seq, 2, "latest-attempt seq must advance"); + } + + /// THE CARRIED DIGEST IS OF THE BYTES THE ENVELOPE WAS DECODED FROM, AND THE DISCRIMINATING + /// RED IS THE REWRITE. The digest used to be re-derived from the path at the lease site, so + /// a write landing between the decode and that second read produced an envelope and a digest + /// describing different bytes. Here the file is REWRITTEN after the first read: the carried + /// digest must still match the bytes its own envelope came from, and must NOT match the file + /// now on disk. Re-deriving from the path would flip both assertions. + #[test] + fn carried_digest_names_the_bytes_the_envelope_was_decoded_from() { + use sha2::Digest as _; + let (json, tsv) = write_fixture("carried_digest"); + let (first, first_digest) = read_wet_receipt_envelope(&json, &tsv) + .expect("read back") + .expect("present"); + let bytes_at_decode = std::fs::read(&json).expect("read json"); + assert_eq!( + first_digest, + format!("{:x}", sha2::Sha256::digest(&bytes_at_decode)), + "the carried digest must be of the bytes decoded in that same call" + ); + write_wet_receipt_envelope(&json, &tsv, &one_row(), "subject-d", "exec-d", 2000) + .expect("rewrite between the reads"); + let bytes_after_write = std::fs::read(&json).expect("read json again"); + let digest_from_the_path_now = format!("{:x}", sha2::Sha256::digest(&bytes_after_write)); + assert_ne!( + first_digest, digest_from_the_path_now, + "the rewrite must move the on-disk digest, or this test proves nothing" + ); + assert_eq!( + first.attempt_seq, 1, + "the envelope in hand is still the one decoded before the rewrite" + ); + } + + /// THE HAND-EDIT RED: flip one projection byte and the drift check refuses. Remove the + /// re-projection comparison and this test greens a forged receipt. + #[test] + fn hand_edited_projection_refuses_on_drift() { + let (json, tsv) = write_fixture("tamper_tsv"); + let content = std::fs::read_to_string(&tsv).unwrap(); + let forged = content.replace("\tpass\t", "\tfail\t"); + assert_ne!(content, forged, "fixture must contain the edited cell"); + std::fs::write(&tsv, forged).unwrap(); + let err = read_wet_receipt_envelope(&json, &tsv).unwrap_err(); + assert!(err.contains("not the canonical projection"), "got: {err}"); + } + + /// The same wall from the other side: edit the JSON authority and the committed TSV no + /// longer projects from it. + #[test] + fn hand_edited_envelope_refuses_on_drift() { + let (json, tsv) = write_fixture("tamper_json"); + let content = std::fs::read_to_string(&json).unwrap(); + let forged = content.replace("\"pass\"", "\"assertion-false\""); + assert_ne!(content, forged); + std::fs::write(&json, forged).unwrap(); + let err = read_wet_receipt_envelope(&json, &tsv).unwrap_err(); + assert!(err.contains("not the canonical projection"), "got: {err}"); + } + + #[test] + fn orphaned_projection_refuses() { + let (json, tsv) = write_fixture("orphan"); + std::fs::remove_file(&json).unwrap(); + let err = read_wet_receipt_envelope(&json, &tsv).unwrap_err(); + assert!(err.contains("orphaned"), "got: {err}"); + } + + #[test] + fn absent_pair_is_missing_not_error() { + let envelope = read_wet_receipt_envelope("/nonexistent/la.json", "/nonexistent/la.tsv") + .expect("absent pair is the missing state"); + assert!(envelope.is_none()); + } + + fn fixture_envelope() -> WetReceiptEnvelope { + WetReceiptEnvelope { + schema_version: 2, + subject_digest: "subject-d".to_string(), + executor_contract_digest: "exec-d".to_string(), + attempt_seq: 1, + executed_at_unix_secs: 1000, + published_at_unix_secs: 1001, + run_id: "r".to_string(), + head_sha: "s".to_string(), + rows: vec![WetReceiptIdentityRow { + identity: "test.claim.x.holds".to_string(), + outcome: "pass".to_string(), + wall_ms: 42, + observed_entry_rel: Some("dag/test/claim/x_test.dag".to_string()), + observed_function: Some("test.claim.x.holds".to_string()), + }], + } + } + + fn roster() -> BTreeSet { + ["test.claim.x.holds".to_string()].into_iter().collect() + } + + #[test] + fn standing_fresh_exact_subject_is_the_one_clean_arm() { + let e = fixture_envelope(); + let standing = + wet_lane_receipt_standing(Some(&e), "subject-d", "exec-d", &roster(), 1001, 2, 100, 10); + assert_eq!( + standing, + WetLaneReceiptStanding::FreshExactSubject { age_secs: 1 } + ); + assert!(!standing.blocks()); + } + + #[test] + fn standing_missing_and_subject_mismatch_and_failed_block() { + assert!(wet_lane_receipt_standing(None, "d", "e", &roster(), 1, 2, 100, 10).blocks()); + let e = fixture_envelope(); + let mismatch = + wet_lane_receipt_standing(Some(&e), "other-d", "exec-d", &roster(), 1001, 2, 100, 10); + assert!(matches!( + mismatch, + WetLaneReceiptStanding::SubjectMismatch { + axis: "semantic-subject", + .. + } + )); + let executor_mismatch = wet_lane_receipt_standing( + Some(&e), + "subject-d", + "other-exec", + &roster(), + 1001, + 2, + 100, + 10, + ); + assert!(matches!( + executor_mismatch, + WetLaneReceiptStanding::ExecutorSnapshotDifferent { .. } + )); + assert!(executor_mismatch.blocks()); + // THE ONE-SHOT BOOTSTRAP LEASE admits exactly its named envelope inside the fixed + // window, refuses a slid window, an expired window, and any mismatched exact fact. + let lease = WetBootstrapLease { + lease_identity: "wet-envelope-test".to_string(), + exact_envelope_digest: "env-digest".to_string(), + exact_attempt_seq: 1, + exact_semantic_subject_digest: "subject-d".to_string(), + exact_roster_digest: "roster-d".to_string(), + observed_executor_contract_digest: "executor-d".to_string(), + executed_at_unix_secs: 1000, + not_after_unix_secs: 1000 + 28_800, + }; + assert!(matches!( + wet_seed_bootstrap_admission( + Some(&lease), + 28_800, + "env-digest", + 1, + "subject-d", + "roster-d", + 1000 + 28_800, + ), + WetSeedBootstrapAdmission::Admitted { .. } + )); + assert!(matches!( + wet_seed_bootstrap_admission( + Some(&lease), + 28_800, + "env-digest", + 1, + "subject-d", + "roster-d", + 1001 + 28_800, + ), + WetSeedBootstrapAdmission::Expired { .. } + )); + assert!(matches!( + wet_seed_bootstrap_admission( + Some(&lease), + 28_800, + "other-envelope", + 1, + "subject-d", + "roster-d", + 1001, + ), + WetSeedBootstrapAdmission::NotApplicable + )); + let slid = WetBootstrapLease { + not_after_unix_secs: 1001 + 28_800, + ..lease.clone() + }; + assert!(matches!( + wet_seed_bootstrap_admission( + Some(&slid), + 28_800, + "env-digest", + 1, + "subject-d", + "roster-d", + 1001, + ), + WetSeedBootstrapAdmission::NotApplicable + )); + assert!(matches!( + wet_seed_bootstrap_admission( + None, + 28_800, + "env-digest", + 1, + "subject-d", + "roster-d", + 1001, + ), + WetSeedBootstrapAdmission::NotApplicable + )); + // Per-identity verdicts are not an envelope standing (parent ruling 2026-08-30): a + // failing row leaves the standing fresh, and the join classifies it by enrollment. + let mut failed = fixture_envelope(); + failed.rows[0].outcome = "assertion-false".to_string(); + let failed_standing = wet_lane_receipt_standing( + Some(&failed), + "subject-d", + "exec-d", + &roster(), + 1001, + 2, + 100, + 10, + ); + assert!(matches!( + failed_standing, + WetLaneReceiptStanding::FreshExactSubject { .. } + )); + let empty: BTreeSet = BTreeSet::new(); + let v = wet_receipt_identity_verdicts(&failed, &empty); + let (unexpected, held, now_passing, no_verdict) = + (v.unexpected_red, v.held, v.now_passing, v.no_verdict); + assert_eq!(unexpected, vec!["test.claim.x.holds".to_string()]); + assert!(held.is_empty()); + assert!(now_passing.is_empty()); + assert!(no_verdict.is_empty()); + let enrolled: BTreeSet = ["test.claim.x.holds".to_string()].into(); + let v = wet_receipt_identity_verdicts(&failed, &enrolled); + let (unexpected, held, now_passing, no_verdict) = + (v.unexpected_red, v.held, v.now_passing, v.no_verdict); + assert!(unexpected.is_empty()); + assert_eq!(held, vec!["test.claim.x.holds".to_string()]); + assert!(now_passing.is_empty()); + assert!(no_verdict.is_empty()); + let passing = fixture_envelope(); + let v = wet_receipt_identity_verdicts(&passing, &enrolled); + let (unexpected, held, now_passing, no_verdict) = + (v.unexpected_red, v.held, v.now_passing, v.no_verdict); + assert!(unexpected.is_empty()); + assert!(held.is_empty()); + assert_eq!(now_passing, vec!["test.claim.x.holds".to_string()]); + assert!(no_verdict.is_empty()); + // An infrastructure outcome is never held by an assertion-false enrollment. + let mut hollow = fixture_envelope(); + hollow.rows[0].outcome = "runtime-error".to_string(); + let v = wet_receipt_identity_verdicts(&hollow, &enrolled); + let (unexpected, held, now_passing, no_verdict) = + (v.unexpected_red, v.held, v.now_passing, v.no_verdict); + assert!(unexpected.is_empty()); + assert!(held.is_empty()); + assert!(now_passing.is_empty()); + assert_eq!( + no_verdict, + vec!["test.claim.x.holds (runtime-error)".to_string()] + ); + // COST IS NOT A VERDICT, and the two budget wires are the discriminating pair: + // `completed-over-budget` reached its verdict (the arm is minted only over a pass), so + // it is cost debt AND — being a completion — roster drift when enrolled; + // `budget-interrupted` never reached one, so it stays no-verdict and is not cost debt. + // Each is asserted absent from the other's population, so re-collapsing them fails + // here in both directions rather than in neither. + let mut over = fixture_envelope(); + over.rows[0].outcome = "completed-over-budget".to_string(); + let v = wet_receipt_identity_verdicts(&over, &enrolled); + assert_eq!(v.cost_debt, vec!["test.claim.x.holds".to_string()]); + assert!(v.no_verdict.is_empty()); + assert_eq!(v.now_passing, vec!["test.claim.x.holds".to_string()]); + assert!(v.held.is_empty()); + assert!(v.unexpected_red.is_empty()); + let v_unenrolled = wet_receipt_identity_verdicts(&over, &empty); + assert_eq!( + v_unenrolled.cost_debt, + vec!["test.claim.x.holds".to_string()] + ); + assert!(v_unenrolled.now_passing.is_empty()); + assert!(v_unenrolled.no_verdict.is_empty()); + let mut interrupted = fixture_envelope(); + interrupted.rows[0].outcome = "budget-interrupted".to_string(); + let v = wet_receipt_identity_verdicts(&interrupted, &enrolled); + assert!(v.cost_debt.is_empty()); + assert_eq!( + v.no_verdict, + vec!["test.claim.x.holds (budget-interrupted)".to_string()] + ); + assert!(v.now_passing.is_empty()); + } +} + /// `v2.workflow.required_floor`'s claims execute Hermetic (pure in-process evaluation), so /// CPU is the judged basis. A lane that later admits an execution mode whose purpose is /// external or blocking interaction picks wall instead — but the choice is made here, by @@ -916,7 +2397,8 @@ pub(crate) fn floor_diff_edits_from_line_ranges( pub(crate) struct ChangedWitnessProjectionRow { pub identity: String, /// Wire name of the `ChangedWitnessExecutionStanding` arm: `planned-and-passed`, - /// `planned-and-known-red-held`, `planned-without-terminal-verdict`, `declined`, + /// `planned-and-known-red-held`, `planned-without-terminal-verdict`, + /// `routed-with-candidate-exact-receipt`, `declined`, /// `missing-disposition`. pub standing: &'static str, /// The disposition receipt's label for the identity (`required_floor_disposition_label`), @@ -1017,10 +2499,20 @@ fn identity_home_is_declared_non_executing(module_path: &str) -> bool { /// and the terminal rows read through `claim_disposition` — the SAME projection the disposition /// TSV's outcome column uses, so this projection cannot disagree with the receipt about what a /// row's outcome was. It realizes the arms the .dag fold names; it does not invent a fifth. +// EIGHT ARGUMENTS, AND THE GROUPING REFACTOR IS DELIBERATELY NOT TAKEN. The arity crossed the lint's +// threshold by MERGE rather than by authoring: this branch added `wet_receipt_candidate_exact` for the +// transported route while main added `wet_lane` and `candidate` for the hermetic one, and neither +// change was over the line alone. The three do form one concept -- the wet join's inputs -- so a +// struct would be the honest model, and that is exactly why it is not done HERE: this is the v1 seed, +// which is frozen to growth for its own sake and admits changes only as they serve the v2 self-host +// program (DESIGN section 3, v1_maintenance_standing). Restructuring a seed signature is investment in +// the arm that shrinks toward zero. The allow matches the two this file already carries. +#[allow(clippy::too_many_arguments)] pub(crate) fn changed_witness_projection_rows( changed: &[String], disposition_rows: &[RequiredFloorDispositionRow], terminal: &[ClaimTerminalRow], + wet_receipt_candidate_exact: bool, verdict_only: &HashSet, observations: &HashMap, wet_lane: &LocalRepoWetLaneOutcome, @@ -1121,6 +2613,30 @@ pub(crate) fn changed_witness_projection_rows( blocks: !green, } } + // THE CANDIDATE-EXACT ADMISSION (#9717 composition, parent amendment + // 2026-08-30): a changed wet-routed identity is admitted exactly when the + // committed envelope's subject digest matches this candidate's computed wet + // subject — the lane executed exactly this tree's wet subject, edit included. + // Under every other receipt standing the routed decline blocks like any other. + // + // THE STANDING IS SPELLED AS `v2.workflow.floor_changed_witness` SPELLS IT. This arm + // was authored against `floor_wet_route`'s own receipt standing and emitted + // "routed-with-candidate-exact-receipt"; since #9975 the same standing is named + // `HermeticRouteGapHeldAndWetPassed` and the seed already emits that string on the + // hermetic path. Two spellings for one standing is a nickname, so the disposition label + // below stays this arm's own fact and the standing defers to the shared one. + Some(RequiredFloorDisposition::DeclinedRoutedToWetLane) + if wet_receipt_candidate_exact => + { + ChangedWitnessProjectionRow { + identity: identity.clone(), + cost: None, + standing: "hermetic-route-gap-held-and-wet-passed", + disposition: "declined_routed_to_wet_lane".to_string(), + outcome: "not_executed".to_string(), + blocks: false, + } + } // A DECLINE BLOCKS UNLESS THE TREE GRANTS AN EXEMPTION, and the grant is membership in // a roster, never the absence of a match anywhere else. // @@ -1752,8 +3268,8 @@ pub(crate) fn emit_changed_witness_projection( "One row per ADDED/MODIFIED witness identity in this change, at the disposition \ receipt's own grain (qualified `module.function`). Standing vocabulary: \ `v2.workflow.floor_changed_witness.ChangedWitnessExecutionStanding`; every \ - standing except planned-and-passed and planned-and-known-red-held reds the \ - required floor.\n\n", + standing except planned-and-passed, planned-and-known-red-held and \ + routed-with-candidate-exact-receipt reds the required floor.\n\n", ); text.push_str("| identity | disposition | outcome | standing |\n|---|---|---|---|\n"); for row in rows { @@ -4619,6 +6135,160 @@ pub fn run_required_floor( cost_debt_roster.len() ); + // THE WET EXECUTION ROUTE (`v2.workflow.floor_wet_route`): identities whose subject is a + // real host-effect chain no honest mock can answer, declined from hermetic execution and + // executed by the wet receipts lane at that lane's cadence. The floor's obligation here is + // the JOIN, not the verdict: every routed identity must show a receipt from that lane that + // is younger than the declared staleness budget, and an absent or stale receipt REFUSES the + // run — a row may not sit in "routed to wet" with no evidence the lane still runs it. + let wet_route_roster: HashSet = { + let value = v1_interpreter::run_in_context( + &hermetic, + "v2.workflow.floor_wet_route.floor_wet_route_identities", + false, + ) + .map_err(|e| format!("floor_wet_route_identities: {e}"))?; + let items = floor_decode_list(&hermetic, Some(&value)) + .map_err(|e| format!("floor_wet_route_identities: {e}"))?; + let mut out = HashSet::new(); + for item in items { + match item { + v1_interpreter::Value::Str(s) => { + if !out.insert(s.to_string()) { + return Err(format!( + "floor_wet_route_identities: duplicate routed identity: {s}" + )); + } + } + other => { + return Err(format!( + "floor_wet_route_identities: expected a qualified name, got {}", + floor_value_shape(Some(other)) + )); + } + } + } + out + }; + // EXACTLY ONE MECHANISM HOLDS A ROW (gunbc.quarantine_probe_disposition): a wet-routed + // identity asserts it never executes hermetically, so a cost-debt withhold over the same + // row would be a second holder claiming one fact. Refused here, at the point both rosters + // are live, rather than surfacing later as an unexplainable stale row. + { + let mut both: Vec<&String> = wet_route_roster.intersection(&cost_debt_roster).collect(); + both.sort_unstable(); + if !both.is_empty() { + return Err(format!( + "REQUIRED-FLOOR REFUSAL cause=WetRouteCostDebtDoubleEnrollment — {} identity(ies) \ + enrolled in both v2.workflow.floor_wet_route (which routes them off the hermetic \ + floor) and v2.workflow.floor_cost_debt (which withholds a claim the floor would \ + otherwise run). One mechanism holds a row: [{}]", + both.len(), + both.iter() + .map(|s| s.as_str()) + .collect::>() + .join(", ") + )); + } + } + let wet_route_staleness_budget_secs: u64 = { + let qualified = "v2.workflow.floor_wet_route.floor_wet_route_receipt_staleness_budget_secs"; + match v1_interpreter::run_in_context(&hermetic, qualified, false) { + Ok(v1_interpreter::Value::Int(n)) if n > 0 => n as u64, + Ok(other) => { + return Err(format!( + "{qualified}: expected a positive Int, got {}", + floor_value_shape(Some(&other)) + )) + } + Err(e) => return Err(format!("{qualified}: {e}")), + } + }; + let wet_route_str_row = |qualified: &str| -> Result { + match v1_interpreter::run_in_context(&hermetic, qualified, false) { + Ok(v1_interpreter::Value::Str(s)) => Ok(s.to_string()), + Ok(other) => Err(format!( + "{qualified}: expected a String, got {}", + floor_value_shape(Some(&other)) + )), + Err(e) => Err(format!("{qualified}: {e}")), + } + }; + let wet_route_int_row = |qualified: &str| -> Result { + match v1_interpreter::run_in_context(&hermetic, qualified, false) { + Ok(v1_interpreter::Value::Int(n)) if n > 0 => Ok(n as u64), + Ok(other) => Err(format!( + "{qualified}: expected a positive Int, got {}", + floor_value_shape(Some(&other)) + )), + Err(e) => Err(format!("{qualified}: {e}")), + } + }; + let wet_route_receipt_json_rel_path = + wet_route_str_row("v2.workflow.floor_wet_route.floor_wet_route_receipt_json_rel_path")?; + let wet_route_receipt_tsv_rel_path = + wet_route_str_row("v2.workflow.floor_wet_route.floor_wet_route_receipt_tsv_rel_path")?; + let wet_route_schema_version = + wet_route_int_row("v2.workflow.floor_wet_route.floor_wet_route_receipt_schema_version")?; + let wet_route_publication_skew_secs = + wet_route_int_row("v2.workflow.floor_wet_route.floor_wet_route_publication_skew_secs")?; + // The expected-verdict authority is gunbc.explicit_witness_admission at function grain + // (parent ruling 2026-08-30, wall 3) — no roster is authored beside it; this reads its + // identity-grain projection for the wet route, before the hermetic context is dropped. + let wet_expected_red: BTreeSet = { + let qualified = "v2.workflow.floor_wet_route.wet_route_expected_assertion_false_identities"; + let value = v1_interpreter::run_in_context(&hermetic, qualified, false) + .map_err(|e| format!("{qualified}: {e}"))?; + let items = + floor_decode_list(&hermetic, Some(&value)).map_err(|e| format!("{qualified}: {e}"))?; + let mut out = BTreeSet::new(); + for item in items { + match item { + v1_interpreter::Value::Str(id) => { + if !out.insert(id.to_string()) { + return Err(format!("{qualified}: duplicate enrolled identity: {id}")); + } + } + other => { + return Err(format!( + "{qualified}: expected a qualified name, got {}", + floor_value_shape(Some(other)) + )); + } + } + } + out + }; + let wet_route_envelope_and_digest: Option<(WetReceiptEnvelope, String)> = + if wet_route_roster.is_empty() { + None + } else { + read_wet_receipt_envelope( + &wet_route_receipt_json_rel_path, + &wet_route_receipt_tsv_rel_path, + )? + }; + let wet_route_envelope: Option = wet_route_envelope_and_digest + .as_ref() + .map(|(e, _)| e.clone()); + let wet_route_envelope_digest: Option = wet_route_envelope_and_digest + .as_ref() + .map(|(_, d)| d.clone()); + eprintln!( + "[floor-wet-route] roster routes {} identity(ies) to the wet receipts lane; committed \ + envelope: {}", + wet_route_roster.len(), + wet_route_envelope + .as_ref() + .map(|e| format!( + "attempt_seq={} rows={} subject_digest={}", + e.attempt_seq, + e.rows.len(), + e.subject_digest + )) + .unwrap_or_else(|| "absent".to_string()) + ); + // EXACTLY ONE DECLARED MECHANISM HOLDS A ROW, and when cost debt withholds one it is the // holder. `gunbc.quarantine_probe_disposition` states the rule this implements: the question // is never WHICH roster names a row, it is whether exactly one MECHANISM holds it, and a row @@ -4738,6 +6408,7 @@ pub fn run_required_floor( // to decide admission, and never written back onto the authored roster. let mut cost_debt_observations: HashMap = HashMap::new(); let mut outcome_withheld_cost_debt: Vec = Vec::new(); + let mut wet_route_seen: HashSet = HashSet::new(); // THE POPULATION, AT IDENTITY GRAIN. The discovery authority above answered over the FULL // module index, so this loop sees every DECLARED witness identity in the tree and classifies // each one — the prepared closure and the exclusion map decide which are offered and which @@ -4811,7 +6482,13 @@ pub fn run_required_floor( identity: identity.clone(), agreement: storage_agreement, }); - if selected_as_changed_witness { + // A CHANGED WET-ROUTED IDENTITY IS NOT PLANNED INTO THE HERMETIC SUBLANE: its + // subject is a real host-effect chain the hermetic route refuses by construction + // (v2.workflow.floor_wet_route), so planning it here would manufacture a + // route-gap red. It keeps its routed decline and is judged at the changed-set + // grain by the candidate-exact receipt admission instead — the .dag selector + // (required_floor_disposition_with_changed_selection) preserves the same arm. + if selected_as_changed_witness && !wet_route_roster.contains(&identity) { planned_identities.insert(identity.clone()); disposition_rows.push(RequiredFloorDispositionRow { identity: identity.clone(), @@ -4884,6 +6561,20 @@ pub fn run_required_floor( }); continue; } + // THE WET ROUTE, after cost debt (the double-enrollment refusal above makes the + // order unobservable in practice) and before the gate test, because routing is an + // execution-route fact about the identity, not a gate-membership fact. Declined at + // build, never skipped at execution — same partition arithmetic as cost debt — and + // the receipt join AFTER this loop is what keeps the decline honest: an absent or + // stale wet-lane receipt for any identity seen here refuses the run. + if wet_route_roster.contains(&identity) { + wet_route_seen.insert(identity.clone()); + disposition_rows.push(RequiredFloorDispositionRow { + identity, + disposition: RequiredFloorDisposition::DeclinedRoutedToWetLane, + }); + continue; + } // THE FOURTH DECLINE, AFTER COST DEBT so a rostered identity outside the gate still // enters `cost_debt_seen` and the roster's staleness check keeps its meaning. if !inside_required_gate { @@ -5516,6 +7207,35 @@ pub fn run_required_floor( )); } } + // THE SAME CONTRADICTION AGAINST THE WET ROUTE, in both directions. A wet-routed identity + // never executes hermetically, so a `floor_route_gap` row over it (its hermetic execution + // gaps) and a `floor_expected_red` row over it (it reaches its subject and answers false) + // each assert a hermetic execution that no longer happens. Supplying the route and deleting + // the debt row are therefore ONE change, which is exactly what this wall enforces. + { + let mut both: Vec<&String> = wet_route_roster + .iter() + .filter(|q| { + route_gap_roster.contains(q.as_str()) || expected_red_roster.contains(q.as_str()) + }) + .collect(); + both.sort(); + if !both.is_empty() { + return Err(format!( + "REQUIRED-FLOOR REFUSAL cause=WetRouteRosterClaimsContradict count={} — these \ + identities are enrolled in v2.workflow.floor_wet_route (which routes them off \ + hermetic execution entirely) AND in floor_route_gap or floor_expected_red \ + (each of which asserts a fact about their hermetic execution). Both cannot be \ + true: routing an identity to the wet lane and deleting its hermetic debt row \ + are one change: {}", + both.len(), + both.iter() + .map(|q| q.as_str()) + .collect::>() + .join(", ") + )); + } + } // THE NON-VERDICT ROSTER. See `v2.workflow.floor_non_verdict` for the contract; the short // form is that an enrolled expected-red identity which produces NO VERDICT — it throws, or @@ -5761,6 +7481,9 @@ pub fn run_required_floor( completed_over_cost_requirement: Vec::new(), withheld_cost_debt: outcome_withheld_cost_debt, stale_cost_debt: Vec::new(), + declined_routed_to_wet_lane: wet_route_seen.len(), + wet_route_standing_blocking: Vec::new(), + stale_wet_route: Vec::new(), known_red_runtime_errored: Vec::new(), non_verdict_unenrolled: Vec::new(), stale_non_verdict: Vec::new(), @@ -7006,6 +8729,293 @@ pub fn run_required_floor( )); } } + let mut wet_route_candidate_exact = false; + // THE WET ROUTE'S JOINS, all blocking. The reverse join asks whether every roster row + // still names an identity this run offered and routed — the same rot guard every sibling + // roster carries. The forward join is ONE standing for the whole routed population + // (authority `v2.workflow.floor_wet_route.WetLaneReceiptStanding`): the committed + // envelope against this tree's computed wet subject digest, the roster, and the tree's + // own commit time. Exactly `FreshExactSubject` is clean; Missing, Expired, + // SubjectMismatch (an ancestor receipt — blocked by ruling, no cadence-lag arm), + // ContractMismatch, RosterInexact and Failed each refuse with their own remedy. + { + for identity in wet_route_roster + .iter() + .filter(|q| reverse_joins_answerable && !wet_route_seen.contains(*q)) + { + outcome.stale_wet_route.push(format!( + "{identity} is enrolled in v2.workflow.floor_wet_route but was not offered and \ + routed by this run — it was renamed, deleted, or declined by an earlier home \ + policy. Delete or correct the row: a wet route over an identity the floor does \ + not hold routes nothing and can never ask to be removed." + )); + } + // FRESHNESS AGAINST THE EVALUATED TREE'S OWN COMMIT TIME, never this host's wall + // clock, so the join is a deterministic property of the commit (parent ruling + // 2026-08-30). On CI a failed observation REFUSES; a local run without one reports + // NOT EVALUATED loudly and skips only the two time comparisons — every tree-derived + // half of the standing still executes. Same composition #9717 uses for the diff + // observation. + let evaluated_tree_commit_secs: Option = std::process::Command::new("git") + .args(["log", "-1", "--format=%ct", "HEAD"]) + .output() + .ok() + .filter(|o| o.status.success()) + .and_then(|o| String::from_utf8(o.stdout).ok()) + .and_then(|t| t.trim().parse::().ok()); + // THE REFUSAL IS UNCONDITIONAL, NOT CI-CONDITIONAL (review 57856). It was gated on + // `GITHUB_ACTIONS` until then: CI refused, and a local run printed a NOT EVALUATED line + // and carried on with `None`, which the standing fold below turned into + // `FreshExactSubject { age_secs: 0 }`. So the value a local operator read said FRESH + // about a receipt whose age had not been computed — a typed lie mitigated by a println + // beside it, which is exactly the diagnostic-names-it/mechanism-stays-silent shape. + // + // An environment-conditional wall is not a wall: `GITHUB_ACTIONS` is an env var, so the + // arm that fabricated freshness was reachable by unsetting it. The freshness join needs + // this fact, the authority declares it total, and a routed population whose freshness + // cannot be evaluated must refuse WHEREVER it runs. A local run losing the ability to + // proceed here is the correct loss: it never had a verdict to proceed on. + let evaluated_tree_commit_secs = match evaluated_tree_commit_secs { + Some(t) => t, + None => { + if !wet_route_seen.is_empty() { + return Err( + "REQUIRED-FLOOR REFUSAL cause=WetRouteCommitTimeUnobservable — the \ + wet-route freshness join needs the evaluated tree's commit time (git \ + log -1 --format=%ct) and could not observe it. A routed population \ + with an unevaluable freshness join must refuse, not skip, and must \ + not render as fresh." + .to_string(), + ); + } + // No routed population: the freshness join has no subject, so there is nothing + // to refuse about. The standing fold is not reached on this path. + 0 + } + }; + if !wet_route_seen.is_empty() { + let computed_digest = wet_subject_digest(source_roots)?; + let computed_executor_digest = wet_executor_contract_digest(source_roots)?; + let roster_sorted: BTreeSet = wet_route_roster.iter().cloned().collect(); + let standing = wet_lane_receipt_standing( + wet_route_envelope.as_ref(), + &computed_digest, + &computed_executor_digest, + &roster_sorted, + evaluated_tree_commit_secs, + wet_route_schema_version, + wet_route_staleness_budget_secs, + wet_route_publication_skew_secs, + ); + // THE GATE DISPOSITION (`v2.workflow.floor_wet_route.wet_route_gate_disposition`): + // exactly FreshExactSubject admits ordinarily, and ExecutorSnapshotDifferent may + // be admitted by the declared one-shot bootstrap lease — visibly, never by + // widening any other standing. The lease's admission requires every exact fact + // to join (envelope digest, attempt_seq, semantic subject, roster) inside its + // fixed window; anything else refuses exactly as before. + let lease_admission = if matches!( + standing, + WetLaneReceiptStanding::ExecutorSnapshotDifferent { .. } + ) { + let (lease, window_secs) = wet_seed_bootstrap_lease_declared(source_roots)?; + let envelope = wet_route_envelope + .as_ref() + .expect("executor-snapshot standing entails an envelope"); + // Carried from the ONE read the envelope was decoded from, never re-derived + // from the path -- see `read_wet_receipt_envelope`. + let envelope_digest = wet_route_envelope_digest + .clone() + .expect("executor-snapshot standing entails a decoded envelope and its digest"); + let roster_digest = { + use sha2::Digest as _; + let joined = roster_sorted.iter().cloned().collect::>().join("\n"); + format!("{:x}", sha2::Sha256::digest(joined.as_bytes())) + }; + wet_seed_bootstrap_admission( + lease.as_ref(), + window_secs, + &envelope_digest, + envelope.attempt_seq, + &computed_digest, + &roster_digest, + evaluated_tree_commit_secs, + ) + } else { + WetSeedBootstrapAdmission::NotApplicable + }; + // THE PAIRING HERE IS LOAD-BEARING AND IT IS NOT ENFORCED BY THIS EXPRESSION. This + // `matches!` pairs two CONSTRUCTORS and discards their contents, so it cannot tell a + // lease admitted for THIS envelope from one admitted for another. It is correct today + // only because `standing` and `lease_admission` are both derived above from the SAME + // envelope, digest and roster in one block -- a property of this code path, never of the + // values. + // + // THE GATE ITSELF NO LONGER ACCEPTS THAT PAIR. `v2.workflow.floor_wet_route` + // `wet_route_gate_disposition_for_receipt` derives the standing and the admission + // internally from one envelope, so the mismatched pair has no constructor there; the + // two-argument door it replaced admitted lease-for-A with standing-from-B, verified by + // construction before the repair. That fused entry is the authority this decode must + // adopt when the seed next follows the model's shape -- the decoder port is INSIDE the + // authority cutover, not downstream of it -- and until then a change that separates + // these two derivations reintroduces a hole the model has already closed. + let admitted_under_lease = matches!( + (&standing, &lease_admission), + ( + WetLaneReceiptStanding::ExecutorSnapshotDifferent { .. }, + WetSeedBootstrapAdmission::Admitted { .. } + ) + ); + if admitted_under_lease { + if let WetSeedBootstrapAdmission::Admitted { + not_after_unix_secs, + } = &lease_admission + { + eprintln!( + "[floor-wet-route] ADMITTED UNDER BOOTSTRAP LEASE — \ + executor-snapshot-different envelope admitted by the declared \ + one-shot lease (not_after={not_after_unix_secs}); the standing \ + stays different, the admission is the lease's, and the lease \ + deletes with the first exact-main receipt" + ); + } + } + wet_route_candidate_exact = !standing.blocks() || admitted_under_lease; + if standing.blocks() && !admitted_under_lease { + outcome.wet_route_standing_blocking.push(format!( + "wet-lane receipt standing for {} routed identity(ies): {}", + wet_route_seen.len(), + standing.describe() + )); + } + // THE PER-IDENTITY JOIN (`v2.workflow.floor_wet_route` + // `wet_receipt_unexpected_red_identities` and siblings, parent ruling + // 2026-08-30): once the envelope-level standing is fresh, the receipt's rows + // join the expected-red roster exactly as dry claims do. Fail + not enrolled + // BLOCKS (the fail-closed arm that stays live); fail + enrolled is HELD — + // counted, visible, retiring only by an observed pass; pass + enrolled is + // NOW-PASSING — blocks until the roster row is removed, the wet mirror of the + // dry stale-quarantine. + // + // THE PUBLICATION WALL (residual B) waives exactly TWO of the four + // per-identity classes -- `unexpected_red` and `now_passing` -- and only when + // THIS run's own diff is a valid publication transaction: every changed path + // inside the receipt namespace (nothing departed elsewhere) and the attempt + // sequence advancing over the base tree's envelope. Those two are OBSERVED + // VERDICTS that disagree with the roster, so publishing them is exactly the + // honest act, and their remedies live outside the receipt namespace. + // + // `no_verdict` AND `cost_debt` ARE NEVER WAIVED, and the asymmetry is the whole + // wall (review 59383). `no_verdict` is the ABSENCE of a verdict -- publishing it + // would merge an attempt in which a routed identity produced nothing, which is + // the fabricated-plausible-output arm of DESIGN.md §5 wearing a receipt's + // costume: the transaction would convert a hole into a green merge path. + // `cost_debt` DID reach a verdict and then exceeded the line, so the figure is + // exact and republishing it waives a cost the lane measured. A failure arm must + // refuse, never widen. + // + // Envelope-level standings are never waived either. An unobservable diff or base + // leaves the transaction invalid -- the wall fails closed toward blocking. + if !standing.blocks() || admitted_under_lease { + let envelope = wet_route_envelope + .as_ref() + .expect("admitted standing entails an envelope"); + let WetIdentityVerdicts { + unexpected_red, + held, + now_passing, + no_verdict, + cost_debt, + } = wet_receipt_identity_verdicts(envelope, &wet_expected_red); + eprintln!( + "[floor-wet-route] verdicts: unexpected_red={} held={} now_passing={} \ + no_verdict={} cost_debt={} (held identities are enrolled expected-reds \ + observed by the lane; they retire only by an observed pass. cost_debt \ + rows REACHED their verdict and then exceeded the line — a cost, not a \ + defect)", + unexpected_red.len(), + held.len(), + now_passing.len(), + no_verdict.len(), + cost_debt.len() + ); + for id in &held { + eprintln!("[floor-wet-route] known-red-held identity={id}"); + } + if !unexpected_red.is_empty() || !now_passing.is_empty() { + let transaction_valid = wet_receipt_publication_transaction_valid_for_this_run( + &wet_route_receipt_json_rel_path, + &wet_route_receipt_tsv_rel_path, + wet_route_envelope.as_ref(), + ); + let waived = match transaction_valid { + Ok(true) => { + eprintln!( + "[floor-wet-route] unexpected_red and now_passing \ + ADMITTED as a publication transaction: the diff is \ + confined to the receipt namespace and attempt_seq \ + advances — main will carry the honest verdicts, and every \ + other run reds on them until repaired or enrolled. \ + no_verdict and cost_debt are NOT waivable and are \ + evaluated below regardless" + ); + true + } + Ok(false) => false, + Err(e) => { + eprintln!( + "[floor-wet-route] publication transaction NOT EVALUATED \ + ({e}) — the per-identity reds keep blocking" + ); + false + } + }; + if !waived { + if !unexpected_red.is_empty() { + outcome.wet_route_standing_blocking.push(format!( + "unexpected wet red for [{}] — the lane observed a failure \ + the expected-red roster does not hold; repair it or enroll \ + it with its reason", + unexpected_red.join(", ") + )); + } + if !now_passing.is_empty() { + outcome.wet_route_standing_blocking.push(format!( + "wet known-red now passing for [{}] — the lane observed the \ + enrolled red passing; delete its \ + explicit_witness_admission row in the same change", + now_passing.join(", ") + )); + } + } + } + if !no_verdict.is_empty() { + outcome.wet_route_standing_blocking.push(format!( + "wet no-subject-verdict for [{}] — the lane produced no \ + verdict for these rows, which no assertion-false \ + enrollment can hold; repair the lane or the witness route", + no_verdict.join(", ") + )); + } + if !cost_debt.is_empty() { + outcome.wet_route_standing_blocking.push(format!( + "wet completed-over-budget for [{}] — these rows REACHED \ + their verdict and then exceeded the lane's line, so the \ + figure is exact and the debt is a COST, not a defect: \ + reduce the cost, or move the row to a lane declaring its \ + own ceiling. Do not enroll it as expected-red, which \ + asserts a failure it does not exhibit", + cost_debt.join(", ") + )); + } + } + eprintln!( + "[floor-wet-route] routed={} standing={} stale_roster_rows={}", + wet_route_seen.len(), + standing.describe(), + outcome.stale_wet_route.len() + ); + } + } // THE ROSTER IS A TWO-WAY JOIN, NOT A ONE-WAY LOOKUP. Enrollment as written above only ever // asks "is this executing claim enrolled". The reverse question — is every enrolled identity // still executing — has no consumer unless it is asked here, and without it the roster rots @@ -7423,6 +9433,7 @@ pub fn run_required_floor( &changed_witnesses, &outcome.required_floor_disposition, &terminal_rows, + wet_route_candidate_exact, &cost_debt_verdict_only, &cost_debt_observations, &wet_lane, @@ -7466,6 +9477,7 @@ pub(crate) fn required_floor_disposition_label( RequiredFloorDisposition::DeclinedCostDebt => "declined_cost_debt", RequiredFloorDisposition::DeclinedOutsideGateClosure => "declined_outside_gate_closure", RequiredFloorDisposition::DeclinedDiscoveryExcluded { .. } => "declined_discovery_excluded", + RequiredFloorDisposition::DeclinedRoutedToWetLane => "declined_routed_to_wet_lane", RequiredFloorDisposition::DeclinedChangedWitnessOutsideDiscovery { .. } => { "declined_changed_witness_outside_discovery" } @@ -7496,7 +9508,8 @@ pub(crate) fn required_floor_disposition_matched_prefix( | RequiredFloorDisposition::PlannedAsChangedWitness | RequiredFloorDisposition::DeclinedOutsideRequiredGate | RequiredFloorDisposition::DeclinedOutsideGateClosure - | RequiredFloorDisposition::DeclinedCostDebt => "", + | RequiredFloorDisposition::DeclinedCostDebt + | RequiredFloorDisposition::DeclinedRoutedToWetLane => "", } } @@ -8076,6 +10089,7 @@ mod changed_witness_projection_tests { changed, dispositions, terminal, + false, &HashSet::new(), &HashMap::new(), &no_wet_lane(), @@ -8203,6 +10217,49 @@ mod changed_witness_projection_tests { ); } + /// THE CANDIDATE-EXACT ADMISSION: a changed wet-routed identity under a + /// candidate-exact fresh receipt is green — the lane executed exactly this candidate's + /// wet subject. + #[test] + fn routed_changed_identity_with_candidate_exact_receipt_is_green() { + let rows = changed_witness_projection_rows( + &["m.wet".to_string()], + &[disposition( + "m.wet", + RequiredFloorDisposition::DeclinedRoutedToWetLane, + )], + &[], + true, + &HashSet::new(), + &HashMap::new(), + &no_wet_lane(), + TEST_CANDIDATE, + ); + assert_eq!(rows[0].standing, "hermetic-route-gap-held-and-wet-passed"); + assert!(!rows[0].blocks); + } + + /// AND ITS REFUSAL: under any non-exact receipt standing (ancestor digest included, by + /// ruling) the routed decline blocks like every other decline. + #[test] + fn routed_changed_identity_without_candidate_exact_receipt_blocks() { + let rows = changed_witness_projection_rows( + &["m.wet".to_string()], + &[disposition( + "m.wet", + RequiredFloorDisposition::DeclinedRoutedToWetLane, + )], + &[], + false, + &HashSet::new(), + &HashMap::new(), + &no_wet_lane(), + TEST_CANDIDATE, + ); + assert_eq!(rows[0].standing, "declined"); + assert!(rows[0].blocks); + } + /// Positive control: a diff with no changed witness identities projects ZERO rows — zero /// lines, nothing blocking, the required context stays green. #[test] @@ -8328,6 +10385,7 @@ mod changed_witness_projection_tests { kind: BudgetKind::Cpu, }, )], + false, &verdict_only_set(), &observation(505), &no_wet_lane(), @@ -8379,6 +10437,7 @@ mod changed_witness_projection_tests { RequiredFloorDisposition::PlannedAsChangedWitness, )], &[terminal("m.a", ClaimOutcome::Pass)], + false, &verdict_only_set(), &HashMap::new(), &no_wet_lane(), @@ -8401,6 +10460,7 @@ mod changed_witness_projection_tests { RequiredFloorDisposition::PlannedAsChangedWitness, )], &[terminal("m.a", ClaimOutcome::Fail)], + false, &verdict_only_set(), &observation(505), &no_wet_lane(), @@ -8443,6 +10503,7 @@ mod changed_witness_projection_tests { &changed, &dispositions, &terminal, + false, &HashSet::new(), &HashMap::new(), lane, diff --git a/src/v1/stage0/src/v1_interpreter.rs b/src/v1/stage0/src/v1_interpreter.rs index 7b1b0704f7c..10dfb0a6803 100644 --- a/src/v1/stage0/src/v1_interpreter.rs +++ b/src/v1/stage0/src/v1_interpreter.rs @@ -4270,6 +4270,11 @@ pub struct SelectedFunctionIdentity { pub module_path: String, pub decl_name: String, pub bare_name_ambiguous: bool, + /// The source file the SELECTED node was authored in, read off its span — not the file a + /// caller asked for. A wet receipt records this as its observed entry, and the difference + /// is the whole point: copying the roster's entry back into the receipt would make the + /// consumer's foreign-entry join tautological. + pub source_file: String, } /// The module path a source file authors, or `None` when the index cannot name exactly one. @@ -4841,6 +4846,7 @@ impl InterpContext { decl_name: authored_name_at(self.source_indices.clone(), node.clone()), bare_name_ambiguous: !name.contains('.') && self.indexes.ambiguous_bare_function_names.contains(name), + source_file: file.to_string(), }) } } diff --git a/src/v2/compiler/effect_demand_floor_join.dag b/src/v2/compiler/effect_demand_floor_join.dag index 6c6d55a4af2..367bdcb8c24 100644 --- a/src/v2/compiler/effect_demand_floor_join.dag +++ b/src/v2/compiler/effect_demand_floor_join.dag @@ -78,6 +78,7 @@ type FloorStandingCounts { declined_outside_gate_closure: Int declined_discovery_excluded: Int declined_cost_debt: Int + declined_routed_to_wet_lane: Int } // EVERY WAY THE POPULATION CAN BE WRONG IS AN ARM, AND NONE OF THEM IS A SKIP. An entry the walk found @@ -158,7 +159,8 @@ fn floor_join_disposition_name(d: RequiredFloorDisposition) -> String { DeclinedOutsideRequiredGate => "declined_outside_required_gate", DeclinedOutsideGateClosure => "declined_outside_gate_closure", DeclinedDiscoveryExcluded { matched_substring } => "declined_discovery_excluded", - DeclinedCostDebt => "declined_cost_debt" + DeclinedCostDebt => "declined_cost_debt", + DeclinedRoutedToWetLane => "declined_routed_to_wet_lane" } } @@ -172,20 +174,22 @@ fn floor_join_counts_zero() -> FloorStandingCounts { declined_outside_required_gate: 0, declined_outside_gate_closure: 0, declined_discovery_excluded: 0, - declined_cost_debt: 0 + declined_cost_debt: 0, + declined_routed_to_wet_lane: 0 } } fn floor_join_counts_add(c: FloorStandingCounts, d: RequiredFloorDisposition) -> FloorStandingCounts { match d { - Planned => FloorStandingCounts { offered: c.offered + 1, planned: c.planned + 1, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt }, - PlannedAsChangedWitness => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness + 1, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt }, - DeclinedLongModule { matched_prefix } => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module + 1, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt }, - DeclinedFixtureMember { matched_prefix } => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member + 1, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt }, - DeclinedOutsideRequiredGate => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate + 1, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt }, - DeclinedOutsideGateClosure => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure + 1, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt }, - DeclinedDiscoveryExcluded { matched_substring } => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded + 1, declined_cost_debt: c.declined_cost_debt }, - DeclinedCostDebt => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt + 1 } + Planned => FloorStandingCounts { offered: c.offered + 1, planned: c.planned + 1, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt, declined_routed_to_wet_lane: c.declined_routed_to_wet_lane }, + PlannedAsChangedWitness => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness + 1, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt, declined_routed_to_wet_lane: c.declined_routed_to_wet_lane }, + DeclinedLongModule { matched_prefix } => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module + 1, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt, declined_routed_to_wet_lane: c.declined_routed_to_wet_lane }, + DeclinedFixtureMember { matched_prefix } => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member + 1, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt, declined_routed_to_wet_lane: c.declined_routed_to_wet_lane }, + DeclinedOutsideRequiredGate => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate + 1, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt, declined_routed_to_wet_lane: c.declined_routed_to_wet_lane }, + DeclinedOutsideGateClosure => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure + 1, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt, declined_routed_to_wet_lane: c.declined_routed_to_wet_lane }, + DeclinedDiscoveryExcluded { matched_substring } => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded + 1, declined_cost_debt: c.declined_cost_debt, declined_routed_to_wet_lane: c.declined_routed_to_wet_lane }, + DeclinedCostDebt => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt + 1, declined_routed_to_wet_lane: c.declined_routed_to_wet_lane }, + DeclinedRoutedToWetLane => FloorStandingCounts { offered: c.offered + 1, planned: c.planned, planned_as_changed_witness: c.planned_as_changed_witness, declined_long_module: c.declined_long_module, declined_fixture_member: c.declined_fixture_member, declined_outside_required_gate: c.declined_outside_required_gate, declined_outside_gate_closure: c.declined_outside_gate_closure, declined_discovery_excluded: c.declined_discovery_excluded, declined_cost_debt: c.declined_cost_debt, declined_routed_to_wet_lane: c.declined_routed_to_wet_lane + 1 } } } diff --git a/src/v2/test/claim/effect_demand/effect_demand_floor_join_test.dag b/src/v2/test/claim/effect_demand/effect_demand_floor_join_test.dag index 50429dd18e3..70181a66b15 100644 --- a/src/v2/test/claim/effect_demand/effect_demand_floor_join_test.dag +++ b/src/v2/test/claim/effect_demand/effect_demand_floor_join_test.dag @@ -122,9 +122,9 @@ test fn floor_join_witness_an_unreached_entry_is_excluded_not_refused() -> Bool test fn floor_join_witness_standing_is_the_floors_own_rule() -> Bool { let j = probe_join() - probe_disposition_of(join: j, identity: "v2.test.probe_a.t_a", expected: fn(d) { match d { Planned => true, PlannedAsChangedWitness => false, DeclinedLongModule { matched_prefix } => false, DeclinedFixtureMember { matched_prefix } => false, DeclinedOutsideRequiredGate => false, DeclinedOutsideGateClosure => false, DeclinedDiscoveryExcluded { matched_substring } => false, DeclinedCostDebt => false } }) - && probe_disposition_of(join: j, identity: "v2.test.long.probe_c.t_c", expected: fn(d) { match d { Planned => false, PlannedAsChangedWitness => false, DeclinedLongModule { matched_prefix } => matched_prefix == "v2.test.long.", DeclinedFixtureMember { matched_prefix } => false, DeclinedOutsideRequiredGate => false, DeclinedOutsideGateClosure => false, DeclinedDiscoveryExcluded { matched_substring } => false, DeclinedCostDebt => false } }) - && probe_disposition_of(join: j, identity: "test.claim.probe_d.t_d", expected: fn(d) { match d { Planned => false, PlannedAsChangedWitness => false, DeclinedLongModule { matched_prefix } => false, DeclinedFixtureMember { matched_prefix } => false, DeclinedOutsideRequiredGate => true, DeclinedOutsideGateClosure => false, DeclinedDiscoveryExcluded { matched_substring } => false, DeclinedCostDebt => false } }) + probe_disposition_of(join: j, identity: "v2.test.probe_a.t_a", expected: fn(d) { match d { Planned => true, PlannedAsChangedWitness => false, DeclinedLongModule { matched_prefix } => false, DeclinedFixtureMember { matched_prefix } => false, DeclinedOutsideRequiredGate => false, DeclinedOutsideGateClosure => false, DeclinedDiscoveryExcluded { matched_substring } => false, DeclinedCostDebt => false, DeclinedRoutedToWetLane => false } }) + && probe_disposition_of(join: j, identity: "v2.test.long.probe_c.t_c", expected: fn(d) { match d { Planned => false, PlannedAsChangedWitness => false, DeclinedLongModule { matched_prefix } => matched_prefix == "v2.test.long.", DeclinedFixtureMember { matched_prefix } => false, DeclinedOutsideRequiredGate => false, DeclinedOutsideGateClosure => false, DeclinedDiscoveryExcluded { matched_substring } => false, DeclinedCostDebt => false, DeclinedRoutedToWetLane => false } }) + && probe_disposition_of(join: j, identity: "test.claim.probe_d.t_d", expected: fn(d) { match d { Planned => false, PlannedAsChangedWitness => false, DeclinedLongModule { matched_prefix } => false, DeclinedFixtureMember { matched_prefix } => false, DeclinedOutsideRequiredGate => true, DeclinedOutsideGateClosure => false, DeclinedDiscoveryExcluded { matched_substring } => false, DeclinedCostDebt => false, DeclinedRoutedToWetLane => false } }) } test fn floor_join_witness_cost_debt_arm_is_reached_from_the_policy_roster() -> Bool { @@ -134,7 +134,7 @@ test fn floor_join_witness_cost_debt_arm_is_reached_from_the_policy_roster() -> probe_disposition_of( join: effect_demand_floor_join(discovered: rows, nodes: nodes, edges: edges, seam_modules: probe_seam_modules, owned_data_records_supplied: 0), identity: "test.claim.belt_tick_receipt_home_witness.the_belt_member_bootstraps_its_own_receipts_directory", - expected: fn(d) { match d { Planned => false, PlannedAsChangedWitness => false, DeclinedLongModule { matched_prefix } => false, DeclinedFixtureMember { matched_prefix } => false, DeclinedOutsideRequiredGate => false, DeclinedOutsideGateClosure => false, DeclinedDiscoveryExcluded { matched_substring } => false, DeclinedCostDebt => true } } + expected: fn(d) { match d { Planned => false, PlannedAsChangedWitness => false, DeclinedLongModule { matched_prefix } => false, DeclinedFixtureMember { matched_prefix } => false, DeclinedOutsideRequiredGate => false, DeclinedOutsideGateClosure => false, DeclinedDiscoveryExcluded { matched_substring } => false, DeclinedCostDebt => true, DeclinedRoutedToWetLane => false } } ) } diff --git a/src/v2/test/floor_changed_witness_test.dag b/src/v2/test/floor_changed_witness_test.dag index 1841998f647..66e61d31799 100644 --- a/src/v2/test/floor_changed_witness_test.dag +++ b/src/v2/test/floor_changed_witness_test.dag @@ -25,7 +25,7 @@ import v2.workflow.required_floor { RequiredFloorDisposition, Planned, PlannedAsChangedWitness, DeclinedLongModule, DeclinedFixtureMember, DeclinedOutsideRequiredGate, DeclinedOutsideGateClosure, DeclinedDiscoveryExcluded, - DeclinedCostDebt, + DeclinedCostDebt, DeclinedRoutedToWetLane, required_floor_disposition_with_changed_selection, ChangedWitnessCostPolicy, OrdinaryChangedWitnessCostPolicy, ChangedCostDebtVerdictOnly, changed_witness_cost_policy, @@ -189,6 +189,7 @@ test fn changed_selector_replaces_an_ordinary_decline_with_its_own_planned_arm() DeclinedCostDebt => false DeclinedFixtureMember { matched_prefix: _ } => false DeclinedDiscoveryExcluded { matched_substring: _ } => false + DeclinedRoutedToWetLane => false } } @@ -205,6 +206,27 @@ test fn unchanged_identity_keeps_its_ordinary_disposition() -> Bool { DeclinedCostDebt => false DeclinedFixtureMember { matched_prefix: _ } => false DeclinedDiscoveryExcluded { matched_substring: _ } => false + DeclinedRoutedToWetLane => false + } +} + +// THE PRESERVED ARM: selection may not plan a wet-routed identity into hermetic execution — +// its subject is a real host-effect chain the hermetic route refuses by construction, so the +// selector keeps the routed decline and the candidate-exact receipt admission is its verdict. +test fn changed_selection_preserves_the_wet_route_decline() -> Bool { + match required_floor_disposition_with_changed_selection( + ordinary: DeclinedRoutedToWetLane {}, + selected_as_changed_witness: true, + ) { + DeclinedRoutedToWetLane => true + Planned => false + PlannedAsChangedWitness => false + DeclinedLongModule { matched_prefix: _ } => false + DeclinedOutsideRequiredGate => false + DeclinedOutsideGateClosure => false + DeclinedCostDebt => false + DeclinedFixtureMember { matched_prefix: _ } => false + DeclinedDiscoveryExcluded { matched_substring: _ } => false } } @@ -292,12 +314,58 @@ test fn declined_cost_debt_is_declined() -> Bool { ) == "declined" } +// A WET-ROUTED DECLINE GREENS ONLY ON AN EXECUTED, CANDIDATE-EXACT JOIN. Routing an identity to +// the wet lane says the ordinary floor did not run it, so admitting the edit on the routing alone +// would green a changed witness that nothing executed. The admission is bought by the wet join +// naming THIS candidate. +// +// THE JOIN IS `wet_evidence`'s, RE-EXPRESSED FROM THE RECEIPT STANDING THIS WITNESS WAS AUTHORED +// AGAINST. It originally read `floor_wet_route`'s own `ReceiptFreshExactSubject`, which since #9975 +// would be a second authority answering a question `hermetic_route_gap_wet_join_complete` already +// answers; the behaviour under test is unchanged and the fixture now differs from its refusal twin +// by exactly the candidate the evidence names. +test fn routed_to_wet_lane_greens_on_a_candidate_exact_join() -> Bool { + let s = changed_standing_with_wet( + reading: ordinary_changed_reading( + disposition: DeclinedRoutedToWetLane {}, + terminal: NotExecuted {} + ), + wet: wet_admitted(identity: wet_identity, candidate: wet_candidate, lane: lane_holds()), + ) + match s { + HermeticRouteGapHeldAndWetPassed { evidence: _, identity: _, candidate: _ } => + !changed_witness_standing_blocks(standing: s) + PlannedAndPassed => false + PlannedAndKnownRedHeld => false + PlannedAndPassedWithCostDebtObserved { observation: _ } => false + CostObservationMissingUnderVerdictOnly => false + PlannedWithoutTerminalVerdict => false + Declined { disposition: _ } => false + MissingDisposition => false + } +} + +// AND ITS REFUSAL, which is what stops the arm being a free pass: evidence bound to a DIFFERENT +// candidate is a verdict about a tree without this edit, so the changed identity declines. There is +// no cadence-lag admission arm by ruling, and this fixture differs from the one above in the +// candidate alone. +test fn routed_to_wet_lane_declines_when_the_join_names_another_candidate() -> Bool { + standing_kind( + s: changed_standing_with_wet( + reading: ordinary_changed_reading( + disposition: DeclinedRoutedToWetLane {}, + terminal: NotExecuted {} + ), + wet: wet_admitted(identity: wet_identity, candidate: wet_other_candidate, lane: lane_holds()), + ) + ) == "declined" +} + // A changed identity with no disposition row at all is a fact the receipt cannot speak for. test fn absent_row_is_missing_disposition() -> Bool { standing_kind(s: changed_standing_of(reading: NoDispositionRow {})) == "missing-disposition" } -// Blocking polarity: the passed and enrolled-held standings are green. test fn passed_and_known_red_held_are_green() -> Bool { !changed_witness_standing_blocks(standing: PlannedAndPassed {}) && !changed_witness_standing_blocks(standing: PlannedAndKnownRedHeld {}) diff --git a/src/v2/test/floor_wet_route_test.dag b/src/v2/test/floor_wet_route_test.dag new file mode 100644 index 00000000000..db73dd6077a --- /dev/null +++ b/src/v2/test/floor_wet_route_test.dag @@ -0,0 +1,785 @@ +module v2.test.floor_wet_route + +import v2.workflow.floor_wet_route { + WetRouteRow, + WetLaneOutcome, WetPass, WetAssertionFalse, WetRuntimeError, WetCompletedOverBudget, WetResolveFailed, + WetBudgetInterrupted, + WetReceiptIdentityRow, WetReceiptEnvelope, + WetLaneReceiptStanding, + ReceiptFreshExactSubject, ReceiptMissing, ReceiptExpired, ReceiptSubjectMismatch, + ReceiptContractMismatch, ReceiptRosterInexact, ReceiptExecutorSnapshotDifferent, + BootstrapExecutorSnapshotReceipt, + WetSeedBootstrapAdmission, BootstrapExecutorSnapshotLeaseAdmitted, BootstrapLeaseExpired, + BootstrapLeaseNotApplicable, + wet_seed_bootstrap_admission, wet_seed_bootstrap_lease_window_secs, + WetFloorGateDisposition, WetFloorAdmittedFresh, WetFloorAdmittedUnderBootstrapLease, + WetFloorRefused, + wet_route_gate_disposition, wet_route_gate_disposition_for_receipt, wet_route_disposition_blocks_floor, + wet_lane_receipt_standing, + wet_route_standing_blocks_floor, + wet_receipt_unexpected_red_identities, + wet_receipt_held_identities, + wet_receipt_now_passing_identities, + wet_receipt_no_verdict_identities, + wet_receipt_cost_debt_identities, + wet_receipt_rows_executed_the_identity_they_claim, + wet_route_identity_rows_block, + WetReceiptPublicationTransaction, + wet_receipt_publication_transaction_valid, + wet_route_identity_rows_block_with_publication, + floor_wet_route_receipt_schema_version, + floor_wet_route_receipt_staleness_budget_secs, + floor_wet_route_publication_skew_secs, + wet_time_scalar, + floor_wet_route_roster, + floor_wet_route_identities, +} +import v2.std.algebra { filter, fold_list, length } +import v2.std.collection { List } +import std.types { EpochSecs } +import v2.std.logic { Bool } +import v2.std.optional { Optional, Absent, Present, optional_absent, optional_present } +import v2.std.text { String } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } + +// Every fixture below is authored in this source; the module reaches nothing outside the +// substrate inputs. +data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly + +// THE FOLD'S EXECUTING CONSUMERS. `v2.workflow.floor_wet_route` is the authority the required +// floor's host projection realizes; these witnesses execute the .dag standing fold itself, one +// discriminating arm each. The lane-side half of the route — that the routed witnesses run +// with real effects and that a planted self-host fault yields the exact FAIL marker — is +// established on the wet receipts lane by the receipts themselves (the cssl harness's +// three-conjunct fault check is already the executing control there); these witnesses own the +// floor-side half: the join that makes a dead, drifted, or silently failing lane a refusal +// instead of a decline. The fixture roster is a two-identity stand-in — the fold takes the +// roster as an argument precisely so its arms are testable without copying the live roster, +// which stays covered by the distinctness witness at the bottom. + +data fixture_digest: String = "fixture-subject-digest" + +data fixture_executor_digest: String = "fixture-executor-digest" + +fn fixture_roster_identities() -> List { + ["test.claim.fixture.alpha_holds", "test.claim.fixture.beta_holds"] +} + +fn fixture_rows(alpha: WetLaneOutcome, beta: WetLaneOutcome) -> List { + [ + WetReceiptIdentityRow { identity: "test.claim.fixture.alpha_holds", outcome: alpha, wall_ms: 305558, observed_entry_rel: optional_present(value: "dag/test/claim/fixture_test.dag"), observed_function: optional_present(value: "test.claim.fixture.alpha_holds") }, + WetReceiptIdentityRow { identity: "test.claim.fixture.beta_holds", outcome: beta, wall_ms: 12, observed_entry_rel: optional_present(value: "dag/test/claim/fixture_test.dag"), observed_function: optional_present(value: "test.claim.fixture.beta_holds") } + ] +} + +// Executed at the constant base 1000000 and published one second later; a caller makes the +// receipt AGE by passing evaluated_tree_commit_unix_secs = 1000000 + age, so every fixture's +// age is a visible literal at its use site. +fn fixture_envelope(rows: List) -> WetReceiptEnvelope { + WetReceiptEnvelope { + schema_version: floor_wet_route_receipt_schema_version(), + subject_digest: fixture_digest, + executor_contract_digest: fixture_executor_digest, + attempt_seq: 1, + executed_at_unix_secs: 1000000, + published_at_unix_secs: 1000001, + run_id: "fixture-run", + head_sha: "0000000000000000000000000000000000000000", + rows: rows + } +} + +fn standing_at(envelope: Optional, tree_secs: EpochSecs) -> WetLaneReceiptStanding { + wet_lane_receipt_standing( + envelope: envelope, + computed_subject_digest: fixture_digest, + computed_executor_contract_digest: fixture_executor_digest, + roster_identities: fixture_roster_identities(), + evaluated_tree_commit_unix_secs: tree_secs + ) +} + +test fn wet_route_fresh_exact_receipt_is_the_one_clean_standing() -> Bool { + let standing = standing_at( + envelope: Present { value: fixture_envelope(rows: fixture_rows(alpha: WetPass {}, beta: WetPass {})) }, + tree_secs: 1000001 + ) + match standing { + ReceiptFreshExactSubject { age_secs: age } => + wet_time_scalar(x: age) == 1 && !wet_route_standing_blocks_floor(standing: standing) + ReceiptMissing => false + ReceiptExpired { age_secs: _ } => false + ReceiptSubjectMismatch { axis: _, receipt_digest: _, computed_digest: _ } => false + ReceiptExecutorSnapshotDifferent { receipt_digest: _, computed_digest: _ } => false + ReceiptContractMismatch { detail: _ } => false + ReceiptRosterInexact { detail: _ } => false + } +} + +// THE PER-IDENTITY JOIN, arm one — the fail-closed arm that stays live: a wet red the +// expected-red roster does not hold blocks and is named. The envelope standing stays fresh +// (per-identity verdicts are not an envelope fact), so both facts are asserted together. +test fn wet_route_unexpected_red_blocks_and_is_named() -> Bool { + let rows = fixture_rows(alpha: WetPass {}, beta: WetAssertionFalse {}) + let unexpected = wet_receipt_unexpected_red_identities(rows: rows, expected_red_identities: []) + let standing = standing_at(envelope: Present { value: fixture_envelope(rows: rows) }, tree_secs: 1000001) + length(xs: unexpected) == 1 + && fold_list(xs: unexpected, empty: true, cons: fn(acc, id) { acc && id == "test.claim.fixture.beta_holds" }) + && wet_route_identity_rows_block(unexpected_red: unexpected, now_passing: [], no_verdict: [], cost_debt: []) + && !wet_route_standing_blocks_floor(standing: standing) +} + +// Arm two — known red held: the same failing row under an enrolled identity is counted, +// named, and does NOT block. The three projections partition the rows: nothing lands in two. +test fn wet_route_enrolled_red_is_held_not_blocking() -> Bool { + let rows = fixture_rows(alpha: WetPass {}, beta: WetAssertionFalse {}) + let enrolled = ["test.claim.fixture.beta_holds"] + let unexpected = wet_receipt_unexpected_red_identities(rows: rows, expected_red_identities: enrolled) + let held = wet_receipt_held_identities(rows: rows, expected_red_identities: enrolled) + let now_passing = wet_receipt_now_passing_identities(rows: rows, expected_red_identities: enrolled) + length(xs: unexpected) == 0 + && length(xs: held) == 1 + && fold_list(xs: held, empty: true, cons: fn(acc, id) { acc && id == "test.claim.fixture.beta_holds" }) + && length(xs: now_passing) == 0 + && !wet_route_identity_rows_block(unexpected_red: unexpected, now_passing: now_passing, no_verdict: [], cost_debt: []) +} + +// Arm three — now passing: an enrolled identity the receipt observes PASSING blocks until +// its roster row is removed, so the fix is counted the moment the lane sees it. +test fn wet_route_enrolled_pass_is_now_passing_and_blocks() -> Bool { + let rows = fixture_rows(alpha: WetPass {}, beta: WetPass {}) + let enrolled = ["test.claim.fixture.beta_holds"] + let held = wet_receipt_held_identities(rows: rows, expected_red_identities: enrolled) + let now_passing = wet_receipt_now_passing_identities(rows: rows, expected_red_identities: enrolled) + length(xs: held) == 0 + && length(xs: now_passing) == 1 + && fold_list(xs: now_passing, empty: true, cons: fn(acc, id) { acc && id == "test.claim.fixture.beta_holds" }) + && wet_route_identity_rows_block(unexpected_red: [], now_passing: now_passing, no_verdict: [], cost_debt: []) +} + +// Arm four — no subject verdict: an infrastructure failure is never held by an +// assertion-false enrollment; it blocks regardless, because an enrollment asserts the +// witness reaches its subject and answers. +test fn wet_route_no_verdict_outcome_blocks_even_when_enrolled() -> Bool { + let rows = [ + WetReceiptIdentityRow { identity: "test.claim.fixture.alpha_holds", outcome: WetPass {}, wall_ms: 1, observed_entry_rel: optional_present(value: "dag/test/claim/fixture_test.dag"), observed_function: optional_present(value: "test.claim.fixture.alpha_holds") }, + WetReceiptIdentityRow { identity: "test.claim.fixture.beta_holds", outcome: WetRuntimeError {}, wall_ms: 2, observed_entry_rel: optional_present(value: "dag/test/claim/fixture_test.dag"), observed_function: optional_present(value: "test.claim.fixture.beta_holds") } + ] + let enrolled = ["test.claim.fixture.beta_holds"] + let no_verdict = wet_receipt_no_verdict_identities(rows: rows) + let held = wet_receipt_held_identities(rows: rows, expected_red_identities: enrolled) + length(xs: no_verdict) == 1 + && fold_list(xs: no_verdict, empty: true, cons: fn(acc, id) { acc && id == "test.claim.fixture.beta_holds" }) + && length(xs: held) == 0 + && wet_route_identity_rows_block(unexpected_red: [], now_passing: [], no_verdict: no_verdict, cost_debt: []) +} + +// Arm five — COST IS NOT A VERDICT, and this is the pair that discriminates the two budget +// arms. `WetCompletedOverBudget` means the witness ran to completion and was then found over +// the line: the seed mints that arm only over a pass, so the verdict is known and the elapsed +// figure is exact. `WetBudgetInterrupted` means the deadline preempted the answer: no verdict +// exists and the figure is a lower bound. They land in DIFFERENT populations and each is +// asserted absent from the other's, so collapsing them back into one — which is what this +// module did until the canonical floor's own split was read against it — fails this witness in +// both directions rather than in neither. +test fn wet_route_completed_over_budget_is_cost_debt_not_no_verdict() -> Bool { + let over = [ + WetReceiptIdentityRow { identity: "test.claim.fixture.alpha_holds", outcome: WetPass {}, wall_ms: 1, observed_entry_rel: optional_present(value: "dag/test/claim/fixture_test.dag"), observed_function: optional_present(value: "test.claim.fixture.alpha_holds") }, + WetReceiptIdentityRow { identity: "test.claim.fixture.beta_holds", outcome: WetCompletedOverBudget {}, wall_ms: 900, observed_entry_rel: optional_present(value: "dag/test/claim/fixture_test.dag"), observed_function: optional_present(value: "test.claim.fixture.beta_holds") } + ] + let interrupted = [ + WetReceiptIdentityRow { identity: "test.claim.fixture.alpha_holds", outcome: WetPass {}, wall_ms: 1, observed_entry_rel: optional_present(value: "dag/test/claim/fixture_test.dag"), observed_function: optional_present(value: "test.claim.fixture.alpha_holds") }, + WetReceiptIdentityRow { identity: "test.claim.fixture.beta_holds", outcome: WetBudgetInterrupted {}, wall_ms: 900, observed_entry_rel: optional_present(value: "dag/test/claim/fixture_test.dag"), observed_function: optional_present(value: "test.claim.fixture.beta_holds") } + ] + let over_cost = wet_receipt_cost_debt_identities(rows: over) + let over_no_verdict = wet_receipt_no_verdict_identities(rows: over) + let interrupted_cost = wet_receipt_cost_debt_identities(rows: interrupted) + let interrupted_no_verdict = wet_receipt_no_verdict_identities(rows: interrupted) + length(xs: over_cost) == 1 + && fold_list(xs: over_cost, empty: true, cons: fn(acc, id) { acc && id == "test.claim.fixture.beta_holds" }) + && length(xs: over_no_verdict) == 0 + && length(xs: interrupted_cost) == 0 + && length(xs: interrupted_no_verdict) == 1 + && wet_route_identity_rows_block(unexpected_red: [], now_passing: [], no_verdict: [], cost_debt: over_cost) +} + +// Arm six — and because completing over budget IS a completion, an ENROLLED identity that +// completes over budget is roster drift exactly as a plain pass is. Held is the arm it must +// not reach: an expected-red enrollment asserts a failure this row does not exhibit, so +// holding it here would let a cost debt retire a red that never came back. +test fn wet_route_enrolled_over_budget_is_now_passing_not_held() -> Bool { + let rows = [ + WetReceiptIdentityRow { identity: "test.claim.fixture.alpha_holds", outcome: WetPass {}, wall_ms: 1, observed_entry_rel: optional_present(value: "dag/test/claim/fixture_test.dag"), observed_function: optional_present(value: "test.claim.fixture.alpha_holds") }, + WetReceiptIdentityRow { identity: "test.claim.fixture.beta_holds", outcome: WetCompletedOverBudget {}, wall_ms: 900, observed_entry_rel: optional_present(value: "dag/test/claim/fixture_test.dag"), observed_function: optional_present(value: "test.claim.fixture.beta_holds") } + ] + let enrolled = ["test.claim.fixture.beta_holds"] + let held = wet_receipt_held_identities(rows: rows, expected_red_identities: enrolled) + let now_passing = wet_receipt_now_passing_identities(rows: rows, expected_red_identities: enrolled) + let unexpected = wet_receipt_unexpected_red_identities(rows: rows, expected_red_identities: enrolled) + length(xs: held) == 0 + && length(xs: unexpected) == 0 + && length(xs: now_passing) == 1 + && fold_list(xs: now_passing, empty: true, cons: fn(acc, id) { acc && id == "test.claim.fixture.beta_holds" }) +} + +// Arm seven — THE OBSERVED-RESOLUTION JOIN, with the control that makes it discriminating. +// A receipt whose row records that the lane resolved a DIFFERENT declaration than the routed +// identity refuses at envelope grain, even though every other fact — subject, executor +// contract, roster membership, freshness — is exact. The positive control is the same envelope +// with the honest observation, which stays fresh: without it this witness would pass over an +// envelope that refuses for any reason at all. +test fn wet_route_foreign_observed_resolution_refuses() -> Bool { + let honest = fixture_rows(alpha: WetPass {}, beta: WetPass {}) + let foreign = [ + WetReceiptIdentityRow { identity: "test.claim.fixture.alpha_holds", outcome: WetPass {}, wall_ms: 1, observed_entry_rel: optional_present(value: "dag/test/claim/fixture_test.dag"), observed_function: optional_present(value: "test.claim.fixture.alpha_holds") }, + WetReceiptIdentityRow { identity: "test.claim.fixture.beta_holds", outcome: WetPass {}, wall_ms: 2, observed_entry_rel: optional_present(value: "dag/test/claim/other_test.dag"), observed_function: optional_present(value: "test.claim.other.beta_holds") } + ] + let unobserved = [ + WetReceiptIdentityRow { identity: "test.claim.fixture.alpha_holds", outcome: WetPass {}, wall_ms: 1, observed_entry_rel: optional_absent(), observed_function: optional_absent() }, + WetReceiptIdentityRow { identity: "test.claim.fixture.beta_holds", outcome: WetResolveFailed {}, wall_ms: 0, observed_entry_rel: optional_absent(), observed_function: optional_absent() } + ] + let foreign_standing = standing_at(envelope: Present { value: fixture_envelope(rows: foreign) }, tree_secs: 1000001) + let honest_standing = standing_at(envelope: Present { value: fixture_envelope(rows: honest) }, tree_secs: 1000001) + wet_receipt_rows_executed_the_identity_they_claim(rows: honest) + && !wet_receipt_rows_executed_the_identity_they_claim(rows: foreign) + && wet_receipt_rows_executed_the_identity_they_claim(rows: unobserved) + && wet_route_standing_blocks_floor(standing: foreign_standing) + && !wet_route_standing_blocks_floor(standing: honest_standing) +} + +// THE COVERAGE-BY-ILLUSION CONTROL: routed with no envelope ever committed must refuse, +// never decline quietly. This is the arm the falsifier deletion (2026-08-15) reached nowhere. +test fn wet_route_missing_envelope_blocks() -> Bool { + let standing = standing_at(envelope: Absent, tree_secs: 1000000) + match standing { + ReceiptMissing => wet_route_standing_blocks_floor(standing: standing) + ReceiptFreshExactSubject { age_secs: _ } => false + ReceiptExpired { age_secs: _ } => false + ReceiptSubjectMismatch { axis: _, receipt_digest: _, computed_digest: _ } => false + ReceiptExecutorSnapshotDifferent { receipt_digest: _, computed_digest: _ } => false + ReceiptContractMismatch { detail: _ } => false + ReceiptRosterInexact { detail: _ } => false + } +} + +test fn wet_route_expired_envelope_blocks() -> Bool { + let over = wet_time_scalar(x: floor_wet_route_receipt_staleness_budget_secs()) + 1 + let standing = standing_at( + envelope: Present { value: fixture_envelope(rows: fixture_rows(alpha: WetPass {}, beta: WetPass {})) }, + tree_secs: 1000000 + over + ) + match standing { + ReceiptExpired { age_secs: age } => + wet_time_scalar(x: age) == over && wet_route_standing_blocks_floor(standing: standing) + ReceiptFreshExactSubject { age_secs: _ } => false + ReceiptMissing => false + ReceiptSubjectMismatch { axis: _, receipt_digest: _, computed_digest: _ } => false + ReceiptExecutorSnapshotDifferent { receipt_digest: _, computed_digest: _ } => false + ReceiptContractMismatch { detail: _ } => false + ReceiptRosterInexact { detail: _ } => false + } +} + +// The boundary discriminates the comparison's direction: a receipt EXACTLY at the budget is +// still fresh, so the wall fires on `>` and a re-spelling as `>=` reds here. +test fn wet_route_envelope_at_exact_budget_is_fresh() -> Bool { + let at = wet_time_scalar(x: floor_wet_route_receipt_staleness_budget_secs()) + let standing = standing_at( + envelope: Present { value: fixture_envelope(rows: fixture_rows(alpha: WetPass {}, beta: WetPass {})) }, + tree_secs: 1000000 + at + ) + match standing { + ReceiptFreshExactSubject { age_secs: age } => wet_time_scalar(x: age) == at + ReceiptMissing => false + ReceiptExpired { age_secs: _ } => false + ReceiptSubjectMismatch { axis: _, receipt_digest: _, computed_digest: _ } => false + ReceiptExecutorSnapshotDifferent { receipt_digest: _, computed_digest: _ } => false + ReceiptContractMismatch { detail: _ } => false + ReceiptRosterInexact { detail: _ } => false + } +} + +// THE CANDIDATE-EXACTNESS WALL (#9717 composition): an envelope produced for a DIFFERENT wet +// subject — an ancestor tree, or any tree whose routed closures differ — blocks, carrying +// both digests so the refusal is a located mismatch, not advice. An ancestor-subject receipt +// has no admission arm by ruling. +test fn wet_route_subject_mismatch_blocks_and_carries_both_digests() -> Bool { + let standing = wet_lane_receipt_standing( + envelope: Present { value: fixture_envelope(rows: fixture_rows(alpha: WetPass {}, beta: WetPass {})) }, + computed_subject_digest: "a-different-subject-digest", + computed_executor_contract_digest: fixture_executor_digest, + roster_identities: fixture_roster_identities(), + evaluated_tree_commit_unix_secs: 1000001 + ) + match standing { + ReceiptSubjectMismatch { axis: a, receipt_digest: r, computed_digest: c } => + a == "semantic-subject" + && r == fixture_digest + && c == "a-different-subject-digest" + && wet_route_standing_blocks_floor(standing: standing) + ReceiptFreshExactSubject { age_secs: _ } => false + ReceiptMissing => false + ReceiptExpired { age_secs: _ } => false + ReceiptExecutorSnapshotDifferent { receipt_digest: _, computed_digest: _ } => false + ReceiptContractMismatch { detail: _ } => false + ReceiptRosterInexact { detail: _ } => false + } +} + +// An envelope missing a routed identity's row is NOT a fresh receipt with a hole — the join +// is exact in both directions, and an inexact roster blocks before any verdict is read. +test fn wet_route_roster_inexact_blocks() -> Bool { + let one_row_only = [ + WetReceiptIdentityRow { identity: "test.claim.fixture.alpha_holds", outcome: WetPass {}, wall_ms: 1, observed_entry_rel: optional_present(value: "dag/test/claim/fixture_test.dag"), observed_function: optional_present(value: "test.claim.fixture.alpha_holds") } + ] + let standing = standing_at( + envelope: Present { value: fixture_envelope(rows: one_row_only) }, + tree_secs: 1000001 + ) + match standing { + ReceiptRosterInexact { detail: _ } => wet_route_standing_blocks_floor(standing: standing) + ReceiptFreshExactSubject { age_secs: _ } => false + ReceiptMissing => false + ReceiptExpired { age_secs: _ } => false + ReceiptSubjectMismatch { axis: _, receipt_digest: _, computed_digest: _ } => false + ReceiptExecutorSnapshotDifferent { receipt_digest: _, computed_digest: _ } => false + ReceiptContractMismatch { detail: _ } => false + } +} + +// A clock that cannot have produced the envelope honestly is a contract violation, decided +// before subject or verdict: published_at beyond the evaluated commit time plus the declared +// skew means the "committed" receipt postdates the tree claiming it. +test fn wet_route_publication_beyond_skew_is_contract_mismatch() -> Bool { + let base = fixture_envelope(rows: fixture_rows(alpha: WetPass {}, beta: WetPass {})) + let late = WetReceiptEnvelope { + schema_version: base.schema_version, + subject_digest: base.subject_digest, + executor_contract_digest: base.executor_contract_digest, + attempt_seq: base.attempt_seq, + executed_at_unix_secs: 1000000, + published_at_unix_secs: 1000000 + wet_time_scalar(x: floor_wet_route_publication_skew_secs()) + 1, + run_id: base.run_id, + head_sha: base.head_sha, + rows: base.rows + } + let standing = standing_at(envelope: Present { value: late }, tree_secs: 1000000) + match standing { + ReceiptContractMismatch { detail: _ } => wet_route_standing_blocks_floor(standing: standing) + ReceiptFreshExactSubject { age_secs: _ } => false + ReceiptMissing => false + ReceiptExpired { age_secs: _ } => false + ReceiptSubjectMismatch { axis: _, receipt_digest: _, computed_digest: _ } => false + ReceiptExecutorSnapshotDifferent { receipt_digest: _, computed_digest: _ } => false + ReceiptRosterInexact { detail: _ } => false + } +} + +// THE EXECUTOR-CONTRACT AXIS (residual-A repair, parent ruling 2026-08-30; arm split by the +// lease ruling): a receipt whose semantic subject matches but whose executor contract does +// not — a candidate that changed the seed executor without a wet rerun — lands on its OWN +// standing arm, named by both digests, and blocks under the leaseless gate. +test fn wet_route_executor_contract_mismatch_blocks_on_its_own_axis() -> Bool { + let standing = wet_lane_receipt_standing( + envelope: Present { value: fixture_envelope(rows: fixture_rows(alpha: WetPass {}, beta: WetPass {})) }, + computed_subject_digest: fixture_digest, + computed_executor_contract_digest: "a-different-executor-digest", + roster_identities: fixture_roster_identities(), + evaluated_tree_commit_unix_secs: 1000001 + ) + match standing { + ReceiptExecutorSnapshotDifferent { receipt_digest: r, computed_digest: c } => + r == fixture_executor_digest + && c == "a-different-executor-digest" + && wet_route_standing_blocks_floor(standing: standing) + ReceiptSubjectMismatch { axis: _, receipt_digest: _, computed_digest: _ } => false + ReceiptFreshExactSubject { age_secs: _ } => false + ReceiptMissing => false + ReceiptExpired { age_secs: _ } => false + ReceiptContractMismatch { detail: _ } => false + ReceiptRosterInexact { detail: _ } => false + } +} + +// THE ONE-SHOT BOOTSTRAP LEASE (parent ruling 2026-08-30), executed arm by arm. A fixture +// lease naming exactly the fixture envelope, inside its fixed window, admits the +// executor-different standing — visibly, on the lease arm, never as fresh — and every +// deviation refuses: a different envelope digest is not applicable, a window overrun is +// expired, and a semantic-subject mismatch is never admitted by any lease. +fn fixture_lease() -> BootstrapExecutorSnapshotReceipt { + BootstrapExecutorSnapshotReceipt { + lease_identity: "fixture-lease-identity", + exact_envelope_digest: "fixture-envelope-digest", + exact_attempt_seq: 1, + exact_semantic_subject_digest: fixture_digest, + exact_roster_digest: "fixture-roster-digest", + observed_executor_contract_digest: "fixture-conceded-executor-digest", + executed_at_unix_secs: 1000000, + not_after_unix_secs: 1000000 + wet_seed_bootstrap_lease_window_secs() + } +} + +fn fixture_admission_at(tree_secs: EpochSecs) -> WetSeedBootstrapAdmission { + wet_seed_bootstrap_admission( + lease: Present { value: fixture_lease() }, + envelope_digest: "fixture-envelope-digest", + attempt_seq: 1, + semantic_subject_digest: fixture_digest, + roster_digest: "fixture-roster-digest", + evaluated_tree_commit_unix_secs: tree_secs + ) +} + +fn executor_different_standing() -> WetLaneReceiptStanding { + ReceiptExecutorSnapshotDifferent { + receipt_digest: fixture_executor_digest, + computed_digest: "a-superseding-executor-digest" + } +} + +test fn wet_lease_admits_exactly_its_envelope_inside_the_window() -> Bool { + let disposition = wet_route_gate_disposition_for_receipt( + envelope: Present { value: fixture_envelope(rows: fixture_rows(alpha: WetPass {}, beta: WetPass {})) }, + envelope_digest: "fixture-envelope-digest", + computed_subject_digest: fixture_digest, + computed_executor_contract_digest: "a-superseding-executor-digest", + roster_identities: fixture_roster_identities(), + roster_digest: "fixture-roster-digest", + evaluated_tree_commit_unix_secs: 1000000 + wet_seed_bootstrap_lease_window_secs(), + lease: Present { value: fixture_lease() } + ) + match disposition { + WetFloorAdmittedUnderBootstrapLease { not_after_unix_secs: n } => + wet_time_scalar(x: n) == wet_time_scalar(x: 1000000) + wet_time_scalar(x: wet_seed_bootstrap_lease_window_secs()) + && !wet_route_disposition_blocks_floor(disposition: disposition) + WetFloorAdmittedFresh { age_secs: _ } => false + WetFloorRefused { standing: _ } => false + } +} + +test fn wet_lease_beyond_its_fixed_window_is_expired_and_blocks() -> Bool { + let admission = fixture_admission_at(tree_secs: 1000001 + wet_seed_bootstrap_lease_window_secs()) + let expired = match admission { + BootstrapLeaseExpired { detail: _ } => true + BootstrapExecutorSnapshotLeaseAdmitted { exact_envelope_digest: _, exact_attempt_seq: _, exact_semantic_subject_digest: _, exact_roster_digest: _, executed_at_unix_secs: _, not_after_unix_secs: _ } => false + BootstrapLeaseNotApplicable => false + } + expired + && wet_route_disposition_blocks_floor( + disposition: wet_route_gate_disposition(standing: executor_different_standing()) + ) +} + +test fn wet_lease_naming_a_different_envelope_is_not_applicable_and_blocks() -> Bool { + let admission = wet_seed_bootstrap_admission( + lease: Present { value: fixture_lease() }, + envelope_digest: "some-other-envelope-digest", + attempt_seq: 1, + semantic_subject_digest: fixture_digest, + roster_digest: "fixture-roster-digest", + evaluated_tree_commit_unix_secs: 1000001 + ) + let not_applicable = match admission { + BootstrapLeaseNotApplicable => true + BootstrapExecutorSnapshotLeaseAdmitted { exact_envelope_digest: _, exact_attempt_seq: _, exact_semantic_subject_digest: _, exact_roster_digest: _, executed_at_unix_secs: _, not_after_unix_secs: _ } => false + BootstrapLeaseExpired { detail: _ } => false + } + not_applicable + && wet_route_disposition_blocks_floor( + disposition: wet_route_gate_disposition(standing: executor_different_standing()) + ) +} + +// THE PIN IS FOUR-WAY AND TWO OF ITS LEGS HAD NO WITNESS. The fold refuses a lease whose +// envelope digest, attempt_seq, semantic subject digest OR roster digest disagrees with the +// receipt in hand, and only the envelope and semantic-subject legs were asserted. An unasserted +// leg of a conjunction is indistinguishable from an absent one: deleting `exact_attempt_seq` +// from the comparison would have kept every existing witness green. These two close that, and +// they matter more than the arithmetic suggests -- the whole claim that this lease "admits +// exactly one receipt" rests on all four legs holding, and a lease that ignored attempt_seq +// would silently admit a LATER attempt against an earlier attempt's declared row, which is +// precisely the stale-evidence class the route exists to refuse. +test fn wet_lease_naming_a_different_attempt_seq_is_not_applicable_and_blocks() -> Bool { + let admission = wet_seed_bootstrap_admission( + lease: Present { value: fixture_lease() }, + envelope_digest: "fixture-envelope-digest", + attempt_seq: 2, + semantic_subject_digest: fixture_digest, + roster_digest: "fixture-roster-digest", + evaluated_tree_commit_unix_secs: 1000001 + ) + let not_applicable = match admission { + BootstrapLeaseNotApplicable => true + BootstrapExecutorSnapshotLeaseAdmitted { exact_envelope_digest: _, exact_attempt_seq: _, exact_semantic_subject_digest: _, exact_roster_digest: _, executed_at_unix_secs: _, not_after_unix_secs: _ } => false + BootstrapLeaseExpired { detail: _ } => false + } + not_applicable + && wet_route_disposition_blocks_floor( + disposition: wet_route_gate_disposition(standing: executor_different_standing()) + ) +} + +// AND THE ROSTER LEG, whose failure mode is the widest of the four: a lease written against one +// routed population would otherwise admit a receipt executed against a different one, so rows +// added to or removed from the roster since the lease was declared would ride in unexecuted. +test fn wet_lease_naming_a_different_roster_is_not_applicable_and_blocks() -> Bool { + let admission = wet_seed_bootstrap_admission( + lease: Present { value: fixture_lease() }, + envelope_digest: "fixture-envelope-digest", + attempt_seq: 1, + semantic_subject_digest: fixture_digest, + roster_digest: "a-different-roster-digest", + evaluated_tree_commit_unix_secs: 1000001 + ) + let not_applicable = match admission { + BootstrapLeaseNotApplicable => true + BootstrapExecutorSnapshotLeaseAdmitted { exact_envelope_digest: _, exact_attempt_seq: _, exact_semantic_subject_digest: _, exact_roster_digest: _, executed_at_unix_secs: _, not_after_unix_secs: _ } => false + BootstrapLeaseExpired { detail: _ } => false + } + not_applicable + && wet_route_disposition_blocks_floor( + disposition: wet_route_gate_disposition(standing: executor_different_standing()) + ) +} + +// THE SEMANTIC-SUBJECT LEG OF THE PIN, WHICH HAD NO DISCRIMINATING WITNESS UNTIL NOW. The +// witness below it -- `wet_lease_never_admits_a_semantic_subject_mismatch` -- looks like this +// one's coverage and is not: it holds the lease APPLICABLE and varies the STANDING, asserting +// that an admitted lease cannot launder a subject mismatch. That is a real and different +// proposition. Deleting `exact_semantic_subject_digest` from the fold's pin leaves it GREEN, +// measured by mutation, so the leg it appears to guard was decoration. +// +// This one varies the pin itself: a lease declared against one semantic subject, presented with +// a receipt for another, must be NotApplicable -- the lease is a bounded admission of EXECUTOR +// drift and must never admit a receipt about a different program. +test fn wet_lease_declared_against_another_semantic_subject_is_not_applicable() -> Bool { + let admission = wet_seed_bootstrap_admission( + lease: Present { value: fixture_lease() }, + envelope_digest: "fixture-envelope-digest", + attempt_seq: 1, + semantic_subject_digest: "a-different-semantic-subject-digest", + roster_digest: "fixture-roster-digest", + evaluated_tree_commit_unix_secs: 1000001 + ) + let not_applicable = match admission { + BootstrapLeaseNotApplicable => true + BootstrapExecutorSnapshotLeaseAdmitted { exact_envelope_digest: _, exact_attempt_seq: _, exact_semantic_subject_digest: _, exact_roster_digest: _, executed_at_unix_secs: _, not_after_unix_secs: _ } => false + BootstrapLeaseExpired { detail: _ } => false + } + not_applicable + && wet_route_disposition_blocks_floor( + disposition: wet_route_gate_disposition(standing: executor_different_standing()) + ) +} + +// The non-widening half: an ADMITTED lease still refuses every standing that is not the +// executor-snapshot arm — the semantic-subject mismatch stays blocked, so the lease can never +// launder a different program. +test fn wet_lease_never_admits_a_semantic_subject_mismatch() -> Bool { + let admission = fixture_admission_at(tree_secs: 1000001) + let semantic = ReceiptSubjectMismatch { + axis: "semantic-subject", + receipt_digest: fixture_digest, + computed_digest: "a-different-subject-digest" + } + wet_route_disposition_blocks_floor( + disposition: wet_route_gate_disposition(standing: semantic) + ) + && wet_route_disposition_blocks_floor( + disposition: wet_route_gate_disposition(standing: ReceiptMissing {}) + ) +} + +// A tampered declared row — a not_after that is not exactly executed_at plus the fixed +// window — is not applicable: the window is derived and checked, never trusted. +test fn wet_lease_with_slid_window_is_not_applicable() -> Bool { + let slid = BootstrapExecutorSnapshotReceipt { + lease_identity: "fixture-lease-identity", + exact_envelope_digest: "fixture-envelope-digest", + exact_attempt_seq: 1, + exact_semantic_subject_digest: fixture_digest, + exact_roster_digest: "fixture-roster-digest", + observed_executor_contract_digest: "fixture-conceded-executor-digest", + executed_at_unix_secs: 1000000, + not_after_unix_secs: 1000001 + wet_seed_bootstrap_lease_window_secs() + } + let admission = wet_seed_bootstrap_admission( + lease: Present { value: slid }, + envelope_digest: "fixture-envelope-digest", + attempt_seq: 1, + semantic_subject_digest: fixture_digest, + roster_digest: "fixture-roster-digest", + evaluated_tree_commit_unix_secs: 1000001 + ) + match admission { + BootstrapLeaseNotApplicable => true + BootstrapExecutorSnapshotLeaseAdmitted { exact_envelope_digest: _, exact_attempt_seq: _, exact_semantic_subject_digest: _, exact_roster_digest: _, executed_at_unix_secs: _, not_after_unix_secs: _ } => false + BootstrapLeaseExpired { detail: _ } => false + } +} + +// THE PUBLICATION WALL (residual B): per-identity reds are admitted exactly when the run's +// own diff is a valid publication transaction — a red refresh PR can land its own envelope, +// and nothing else can ride that waiver. +test fn wet_route_identity_reds_waived_only_under_valid_publication_transaction() -> Bool { + let unexpected = ["test.claim.fixture.beta_holds"] + let valid = WetReceiptPublicationTransaction { + diff_confined_to_receipt_namespace: true, + attempt_seq_advances: true + } + let stray_path = WetReceiptPublicationTransaction { + diff_confined_to_receipt_namespace: false, + attempt_seq_advances: true + } + let replayed = WetReceiptPublicationTransaction { + diff_confined_to_receipt_namespace: true, + attempt_seq_advances: false + } + !wet_route_identity_rows_block_with_publication( + unexpected_red: unexpected, + now_passing: [], + no_verdict: [], + cost_debt: [], + publication_transaction_valid: wet_receipt_publication_transaction_valid(t: valid) + ) + && !wet_route_identity_rows_block_with_publication( + unexpected_red: [], + now_passing: ["test.claim.fixture.alpha_holds"], + no_verdict: [], + cost_debt: [], + publication_transaction_valid: wet_receipt_publication_transaction_valid(t: valid) + ) + && !wet_route_identity_rows_block_with_publication( + unexpected_red: [], + now_passing: [], + no_verdict: ["test.claim.fixture.beta_holds"], + cost_debt: [], + publication_transaction_valid: wet_receipt_publication_transaction_valid(t: valid) + ) + && wet_route_identity_rows_block_with_publication( + unexpected_red: unexpected, + now_passing: [], + no_verdict: [], + cost_debt: [], + publication_transaction_valid: wet_receipt_publication_transaction_valid(t: stray_path) + ) + && wet_route_identity_rows_block_with_publication( + unexpected_red: unexpected, + now_passing: [], + no_verdict: [], + cost_debt: [], + publication_transaction_valid: wet_receipt_publication_transaction_valid(t: replayed) + ) +} + +// AND ITS NON-WIDENING HALF: envelope-level standings are never waived by a valid +// transaction — an expired or missing envelope blocks its own publication PR too, because +// the waiver is defined over the per-identity polarity and never consulted for the +// envelope's own standing. +test fn wet_route_publication_transaction_waives_no_envelope_standing() -> Bool { + let expired = standing_at( + envelope: Present { value: fixture_envelope(rows: fixture_rows(alpha: WetPass {}, beta: WetPass {})) }, + tree_secs: 1000000 + floor_wet_route_receipt_staleness_budget_secs() + 1 + ) + let missing = standing_at(envelope: Absent, tree_secs: 1000000) + wet_route_standing_blocks_floor(standing: expired) + && wet_route_standing_blocks_floor(standing: missing) + && !wet_route_identity_rows_block_with_publication( + unexpected_red: [], + now_passing: [], + no_verdict: [], + cost_debt: [], + publication_transaction_valid: false + ) +} + +// Roster hygiene the host wall then re-checks at run grain: identities are pairwise +// distinct (a duplicated row would receipt one witness twice and mask a missing sibling), +// and the projection is total — one identity per row, no more and no fewer. No population +// count is asserted here: the roster IS the population authority, and a literal copied from +// it would collapse to measure() == measure(). +test fn wet_route_roster_identities_are_distinct() -> Bool { + let rows = floor_wet_route_roster() + let identities = floor_wet_route_identities() + let distinct = fold_list( + xs: identities, + empty: true, + cons: fn(acc, id) { + acc && length(xs: identities |> filter(other => other == id)) == 1 + } + ) + distinct && length(xs: identities) == length(xs: rows) +} + +// THE OFF-DIAGONAL, WHICH IS A RELATION AND NOT A SIXTH ARM. Every existing lease witness varies the +// lease against its own declared inputs; this pair varies the RECEIPT the lease is asked to admit, +// holding the lease fixed. Before the door was fused, lease-for-A + standing-from-B was ADMITTED -- +// constructed and observed, not inferred -- because the executor-different arm discarded both +// standing digests and all four exact_ admission fields and kept only not_after. +// +// It is now unconstructible rather than checked FOR THAT RELATION: the standing and the admission +// are both derived inside `wet_route_gate_disposition_for_receipt` from ONE envelope, so there is no +// argument position in which a standing-from-B could be paired with a lease-for-A. +// +// THE GUARANTEE COVERS THE STANDING RELATION ONLY, AND A RESIDUAL SEAM SITS ONE LEVEL DOWN. Do not +// read the sentence above as closing the whole question. `wet_route_gate_disposition_for_receipt` +// still takes `envelope` and `envelope_digest` as TWO INDEPENDENT PARAMETERS, and nothing in the +// signature ties the digest to the envelope it is supposedly the digest OF -- so envelope A paired +// with digest B remains constructible at that boundary. `wet_lease_admits_an_envelope_whose_content_the_digest_does_not_name` +// below CONSTRUCTS exactly that state and records what the gate does with it, so this seam is +// measured rather than asserted away. +// +// WHY IT IS NOT LIVE TODAY, stated as the narrow claim it is: on the executing path the digest is +// computed FROM the envelope bytes at one site in `v1_compiler.cli_run.required_floor_runner` +// (sha256 of the committed receipt file), so the pair cannot diverge for want of a caller who would +// diverge it. That is correctness by straight-line construction at one call site, which is the same +// rung -- and the same shape -- as the seed-side pairing rostered at `gunbc.rung_drop` +// `wet_lane_seed_admission_pairing_unfused`. Writable, not written. +// +// dissolve-on: the digest ceases to be a parameter -- the entry derives it from the envelope it is +// judging, the way it now derives the admission -- at which point this seam has no constructor and +// the witness below flips from a recorded observation to a permanent regression control. +fn lease_gate_for(envelope: Optional, envelope_digest: String) -> WetFloorGateDisposition { + wet_route_gate_disposition_for_receipt( + envelope: envelope, + envelope_digest: envelope_digest, + computed_subject_digest: fixture_digest, + computed_executor_contract_digest: "a-superseding-executor-digest", + roster_identities: fixture_roster_identities(), + roster_digest: "fixture-roster-digest", + evaluated_tree_commit_unix_secs: 1000001, + lease: Present { value: fixture_lease() } + ) +} + +test fn wet_lease_admits_the_receipt_it_names() -> Bool { + match lease_gate_for(envelope: Present { value: fixture_envelope(rows: fixture_rows(alpha: WetPass {}, beta: WetPass {})) }, envelope_digest: "fixture-envelope-digest") { + WetFloorAdmittedUnderBootstrapLease { not_after_unix_secs: _ } => true + WetFloorAdmittedFresh { age_secs: _ } => false + WetFloorRefused { standing: _ } => false + } +} + +test fn wet_lease_refuses_a_mismatched_envelope_digest() -> Bool { + match lease_gate_for(envelope: Present { value: fixture_envelope(rows: fixture_rows(alpha: WetPass {}, beta: WetPass {})) }, envelope_digest: "envelope-B-digest") { + WetFloorRefused { standing: _ } => true + WetFloorAdmittedUnderBootstrapLease { not_after_unix_secs: _ } => false + WetFloorAdmittedFresh { age_secs: _ } => false + } +} + +// THE RESIDUAL SEAM, CONSTRUCTED. This holds the digest FIXED at the value the lease names and +// varies the ENVELOPE CONTENT instead -- beta reports WetAssertionFalse rather than WetPass, so the +// bytes a real digest would cover are different while the digest handed in is unchanged. The gate +// has no way to detect that: it is told the digest rather than deriving it. This witness therefore +// records the seam's actual behaviour rather than a hoped-for refusal, and it is named for what it +// observes. It is the discriminating input for the dissolve-on above: when the entry derives the +// digest from the envelope, this state stops being constructible and this witness must be rewritten +// as the refusal control it cannot be today. +test fn wet_lease_admits_an_envelope_whose_content_the_digest_does_not_name() -> Bool { + match lease_gate_for(envelope: Present { value: fixture_envelope(rows: fixture_rows(alpha: WetPass {}, beta: WetAssertionFalse {})) }, envelope_digest: "fixture-envelope-digest") { + WetFloorAdmittedUnderBootstrapLease { not_after_unix_secs: _ } => true + WetFloorRefused { standing: _ } => false + WetFloorAdmittedFresh { age_secs: _ } => false + } +} diff --git a/src/v2/workflow/floor_changed_witness.dag b/src/v2/workflow/floor_changed_witness.dag index 159c87ca543..a6f6ba4ea81 100644 --- a/src/v2/workflow/floor_changed_witness.dag +++ b/src/v2/workflow/floor_changed_witness.dag @@ -4,6 +4,7 @@ import v2.workflow.required_floor { RequiredFloorDisposition, Planned, PlannedAsChangedWitness, DeclinedLongModule, DeclinedFixtureMember, DeclinedCostDebt, DeclinedOutsideRequiredGate, DeclinedOutsideGateClosure, DeclinedDiscoveryExcluded, + DeclinedRoutedToWetLane, ChangedWitnessCostPolicy, OrdinaryChangedWitnessCostPolicy, ChangedCostDebtVerdictOnly, } import v2.workflow.floor_terminal_ledger { @@ -292,10 +293,28 @@ fn changed_witness_execution_standing( DeclinedOutsideGateClosure => Declined { disposition: d } DeclinedDiscoveryExcluded { matched_substring: _ } => Declined { disposition: d } DeclinedCostDebt => Declined { disposition: d } + DeclinedRoutedToWetLane => + if hermetic_route_gap_wet_join_complete(evidence: wet, identity: identity, candidate: candidate) { + HermeticRouteGapHeldAndWetPassed { evidence: wet, identity: identity, candidate: candidate } + } else { + Declined { disposition: d } + } } } } +// `DeclinedRoutedToWetLane` IS NOT AN ORDINARY DECLINE, and it is the one disposition whose +// greenness is bought by execution elsewhere rather than by exclusion. Routing an identity to the +// wet lane says the ordinary floor did not run it; greening the edit on that alone would be exactly +// the coverage inflation the wet route exists to refuse. So it greens ONLY when the wet join is +// complete for THIS candidate, and it falls to `Declined` otherwise. +// +// THE JOIN IT CONSULTS IS `wet_evidence`'s, NOT A SECOND ONE. The branch that authored this arm +// read it from `v2.workflow.floor_wet_route`'s own receipt standing, which since #9975 would be a +// second authority answering a question `hermetic_route_gap_wet_join_complete` already answers. The +// polarity is therefore read from that predicate rather than re-enumerated here, so the arm and the +// blocking fold below cannot disagree about which standing is clean. +// // THE BLOCKING POLARITY, STATED ONCE. Exactly two standings are green, and both required // execution: a changed witness identity that did not run to a passing or enrolled-held verdict // — for any reason, including a decline that is perfectly lawful for the STANDING population — diff --git a/src/v2/workflow/floor_cost_debt.dag b/src/v2/workflow/floor_cost_debt.dag index 2036d79568a..c77789a181a 100644 --- a/src/v2/workflow/floor_cost_debt.dag +++ b/src/v2/workflow/floor_cost_debt.dag @@ -682,8 +682,58 @@ fn floor_cost_debt_proven_chunk_04() -> List { Cons { head: "test.claim.roadmap_receipt_continuity_acceptance.roadmap_receipt_continuity_acceptance_contract_holds", tail: Cons { head: "test.claim.roadmap_receipt_continuity_acceptance.witness_dispatch_never_presents_empty_frontier_on_authority_refusal", tail: Cons { head: "test.claim.roadmap_row_witness.roadmap_row_page_carries_the_cells", tail: Cons { head: "test.claim.roadmap_sandbox_witness.witness_family_fixture_frame_occurrences_exact", tail: Cons { head: "test.claim.roadmap_sandbox_witness.witness_sandbox_carries_auditioner_control", tail: Cons { head: "test.claim.roadmap_site_surface_readiness.witness_roadmap_site_surface_readiness_materialized_batch_holds", tail: Cons { head: "test.claim.roadmap_static_site_witness.witness_artifact_digests_are_content_hashes", tail: Cons { head: "test.claim.roadmap_static_site_witness.witness_dispatch_artifact_matches_file_content", tail: Cons { head: "test.claim.roadmap_static_site_witness.witness_healthz_route_json_ok", tail: Cons { head: "test.claim.roadmap_static_site_witness.witness_readback_script_checks_health_and_digests", tail: Cons { head: "test.claim.roadmap_static_site_witness.witness_readback_script_curls_are_wall_clock_bounded", tail: Cons { head: "test.claim.roadmap_static_site_witness.witness_roadmap_route_is_plain_text", tail: Cons { head: "test.claim.roadmap_static_site_witness.witness_site_artifact_model_populated", tail: Cons { head: "test.claim.roadmap_static_site_witness.witness_static_site_route_authority_paths_locked", tail: Cons { head: "test.claim.roadmap_static_site_witness.witness_text_routes_include_health_and_artifacts", tail: Cons { head: "test.claim.roadmap_tactile_witness.witness_sound_toggle_label_is_painted_by_the_program_not_the_markup", tail: Cons { head: "test.claim.seed_growth_admission_witness.a_live_roster_declaration_is_not_reported_stale", tail: Cons { head: "test.claim.sessions_panel_witness.sessions_panel_keystone_holds", tail: Cons { head: "test.claim.shell_exec_run_argv_embed_witness.witness_apply_script_requires_bash_receiver", tail: Cons { head: "test.claim.shell_exec_run_argv_embed_witness.witness_apply_script_stays_under_argv_embed_budget", tail: Empty {} } } } } } } } } } } } } } } } } } } } } } +// THE FIFTH w_RED IN witness_floor_workflow_consolidation, ENROLLED BY THE CHANGE THAT CAUSED IT +// (gunbc#9725, the wet execution route). +// +// PROVENANCE, STATED BECAUSE A ROW THAT SAYS ONLY "505ms" TEACHES NOTHING. This identity is NOT +// PLANNED ON MAIN AT ALL -- zero rows in 3549 on two consecutive main runs' claim-cost receipts. +// It executes only as a CHANGED witness, and it is changed because #9725 edits +// `gunbc.witness_floor_workflow`. The mechanism is indirect and worth naming: the witness +// generates the WHOLE emitted workflow YAML and scans it four times, and #9725 adds 204 lines of +// authority to the file that produces that YAML (the wet-receipts job). The witness's own body is +// untouched by that PR. So the cost is attributable to the change and not to the claim, and the +// 500ms line had never been exercised against this identity before -- the first PR to touch that +// authority is the one that discovers it. +// +// BOTH OBSERVATIONS, because the pair is what makes it a measurement rather than a sample: +// 504ms CPU at head 1e6f7eee and 505ms CPU at head 1732bff, read from the +// `required-floor-claim-cost` artifact rather than a log line, against a 500ms line. The only +// commit between those two heads touched a ledger row and its generated projection, so nothing in +// that delta could have moved cost. It reproduces. +// +// WHAT THIS ROW ACTUALLY DOES, and it is a STRONGER ACT THAN JOINING A LIST. `v2.workflow +// required_floor` `changed_witness_cost_policy` selects `ChangedCostDebtVerdictOnly` only when an +// identity is BOTH changed AND held by this roster -- the module is explicit that no identity +// gains the override by being changed alone. Under that policy the CPU line is observed and +// reported and DECIDES NOTHING. So this row is what CREATES the override for this identity; it +// does not merely record a cost. +// +// AND IT WILL READ LIKE AN ANOMALY THAT IT IS NOT. `cost_debt_roster_standing` will report this +// identity as `CostDebtWithholdOverriddenForChangedVerdict` rather than `CostDebtWithheld` +// whenever #9725's descendants touch the workflow authority. That standing IS NOT STALE: the +// roster line is not edited, deleted or automatically repaid by it, and what changed is only that +// changed-witness selection temporarily required the row's correctness. A reader filing a defect +// against that standing would be filing against the modeled behaviour. +// +// THE FAMILY IS THE FINDING, AND IT IS EVIDENCE ABOUT THE LINE RATHER THAN ABOUT THE WITNESSES. +// This module already has EIGHT identities on this roster, four of them `w_RED_*` siblings, and +// the annotation above describes the population as "474-505ms CPU on three consecutive CI runs +// ... the ceiling itself is what decides them, run by run, by which runner slot the job landed +// on". This row makes a fifth `w_RED_` member at 505. When a roster's membership is a whole +// family clustered within 6% of the threshold, THE THRESHOLD IS SITTING INSIDE THE DISTRIBUTION +// IT IS SUPPOSED TO BOUND, and every future member reds for the same non-reason. Four mitigations +// of one cause is the signal that nobody has priced the cause. +// +// dissolve-on: NOT "the cost comes down", which only this row's author could judge. The capability +// is the one `v2.workflow.floor_cost_debt`'s own dissolution already names and which the cost lane +// owns -- a per-witness DECLARED COST ENVELOPE replacing the shared ceiling, so that a claim's +// bound is derived from its own measured shape rather than from a line calibrated on a different +// population. At that point this family stops being decided by runner slot, the explicit +// debt-removal transaction can retire all five rows together, and the roster collapses. Until +// then the row stands, and reducing THIS witness's cost below 500ms would retire this row alone +// while leaving the mis-grounded line to catch the next member. fn floor_cost_debt_proven_chunk_05() -> List { - Cons { head: "test.claim.ssh_transport_witness.witness_apply_script_stays_under_argv_embed_budget", tail: Cons { head: "test.claim.toolchain_home_standing_witness.every_fleet_converge_yml_job_carries_a_toolchain_home_standing", tail: Cons { head: "test.claim.toolchain_home_standing_witness.every_witnesses_yml_job_carries_a_toolchain_home_standing", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_RED_aggregate_runs_on_a_cancelled_lane_and_refuses_a_failed_one", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_RED_lane_contexts_collide_with_no_other_emitted_workflow", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_RED_the_pull_request_activity_set_is_the_three_that_carry_a_new_subject", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_RED_the_retired_step_names_do_not_return", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_ci_invokes_one_composed_mode_not_a_step_ladder", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_no_phase_precondition_reads_another_phases_outcome", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_the_required_workflow_carries_both_lanes", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_the_required_workflow_does_not_build_the_parse_binary", tail: Cons { head: "test.claim.workflow_dispatch_input_witness.fleet_converge_apply_step_binds_plan_hash_to_env_not_shell_literal", tail: Cons { head: "test.claim.workflow_dispatch_input_witness.fleet_converge_workflow_has_build_job_needs_release_bins", tail: Cons { head: "test.claim.workflow_dispatch_input_witness.fleet_converge_workflow_has_no_heal_revalidation_paste_through", tail: Cons { head: "test.claim.workflow_dispatch_input_witness.workflow_dispatch_choice_input_projects_options_list", tail: Cons { head: "v2.lens.registry.completeness_test.lens_registry_completeness_holds_live", tail: Cons { head: "v2.test.claim.body_lowering.declaration_structure_preserved.coproduct_declaration_interior_is_not_retained_holds", tail: Cons { head: "v2.test.claim.body_lowering.declaration_structure_preserved.fn_type_alias_interior_is_not_retained_holds", tail: Cons { head: "v2.test.claim.body_lowering.declaration_structure_preserved.record_literal_field_init_is_not_retained_holds", tail: Empty {} } } } } } } } } } } } } } } } } } } } + Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_RED_fabric_evidence_executes_without_gating", tail: Cons { head: "test.claim.ssh_transport_witness.witness_apply_script_stays_under_argv_embed_budget", tail: Cons { head: "test.claim.toolchain_home_standing_witness.every_fleet_converge_yml_job_carries_a_toolchain_home_standing", tail: Cons { head: "test.claim.toolchain_home_standing_witness.every_witnesses_yml_job_carries_a_toolchain_home_standing", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_RED_aggregate_runs_on_a_cancelled_lane_and_refuses_a_failed_one", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_RED_lane_contexts_collide_with_no_other_emitted_workflow", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_RED_the_pull_request_activity_set_is_the_three_that_carry_a_new_subject", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_RED_the_retired_step_names_do_not_return", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_ci_invokes_one_composed_mode_not_a_step_ladder", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_no_phase_precondition_reads_another_phases_outcome", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_the_required_workflow_carries_both_lanes", tail: Cons { head: "test.claim.witness_floor_workflow_consolidation_witness_test.w_the_required_workflow_does_not_build_the_parse_binary", tail: Cons { head: "test.claim.workflow_dispatch_input_witness.fleet_converge_apply_step_binds_plan_hash_to_env_not_shell_literal", tail: Cons { head: "test.claim.workflow_dispatch_input_witness.fleet_converge_workflow_has_build_job_needs_release_bins", tail: Cons { head: "test.claim.workflow_dispatch_input_witness.fleet_converge_workflow_has_no_heal_revalidation_paste_through", tail: Cons { head: "test.claim.workflow_dispatch_input_witness.workflow_dispatch_choice_input_projects_options_list", tail: Cons { head: "v2.lens.registry.completeness_test.lens_registry_completeness_holds_live", tail: Cons { head: "v2.test.claim.body_lowering.declaration_structure_preserved.coproduct_declaration_interior_is_not_retained_holds", tail: Cons { head: "v2.test.claim.body_lowering.declaration_structure_preserved.fn_type_alias_interior_is_not_retained_holds", tail: Cons { head: "v2.test.claim.body_lowering.declaration_structure_preserved.record_literal_field_init_is_not_retained_holds", tail: Empty {} }}}}}}}}}}}}}}}}}}}} } fn floor_cost_debt_proven_chunk_06() -> List { diff --git a/src/v2/workflow/floor_route_gap.dag b/src/v2/workflow/floor_route_gap.dag index bbef399713f..829c0f7fd33 100644 --- a/src/v2/workflow/floor_route_gap.dag +++ b/src/v2/workflow/floor_route_gap.dag @@ -200,184 +200,133 @@ fn floor_route_gap_chunk_00() -> List { fn floor_route_gap_chunk_01() -> List { Cons { - head: "test.claim.host_build_cache_provision_real_execution.provision_read_back_failure_not_converged_by_real_execution", - tail: Cons { + head: "test.claim.host_build_cache_provision_real_execution.provision_read_back_failure_not_converged_by_real_execution", + tail: Cons { head: "test.claim.http_client_get_real_execution.http_client_get_missing_target_red_control_by_real_execution", tail: Cons { - head: "test.claim.http_client_get_real_execution.http_client_get_roundtrip_by_real_execution", - tail: Cons { - head: "test.claim.interp_recorded_fixture_witness_test.interp_recorded_fixture_keystone_holds", - tail: Cons { - head: "test.claim.materialized_ssh_key_file_real_execution_witness.witness_ssh_key_bracket_write_owner_only_shreds_and_not_under_target", - tail: Cons { - head: "test.claim.materialized_ssh_key_file_real_execution_witness.witness_write_owner_only_refuses_when_path_already_exists", - tail: Cons { - head: "test.claim.namespace_import_closure_witness.namespace_import_closure_receipt_holds", - tail: Cons { - head: "test.claim.parse_test.parse_witness_floor_holds", - tail: Cons { - head: "test.claim.parse_test.parse_witness_perf_holds", - tail: Cons { - head: "test.claim.proc_self_cgroup_real_execution_witness.bash_assign_from_source_observed_shell_holds", - tail: Cons { - head: "test.claim.proc_self_cgroup_real_execution_witness.bash_assign_from_source_refuses_ambiguous_shell_holds", - tail: Cons { - head: "test.claim.proc_self_cgroup_real_execution_witness.bash_assign_from_source_refuses_malformed_shell_holds", - tail: Cons { - head: "test.claim.proc_self_cgroup_real_execution_witness.bash_assign_from_source_refuses_missing_shell_holds", - tail: Cons { - head: "test.claim.random_bytes_csprng_witness.random_bytes_base64url_mint_16_length_holds", - tail: Cons { - head: "test.claim.random_bytes_csprng_witness.random_bytes_base64url_mint_20_length_holds", - tail: Cons { - head: "test.claim.random_bytes_csprng_witness.random_bytes_count_holds", - tail: Cons { - head: "test.claim.random_bytes_csprng_witness.random_bytes_zero_holds", - tail: Cons { - head: "test.claim.repo_local_git_config_real_execution.repo_local_git_config_actuator_sets_local_bindings_by_real_execution", - tail: Cons { - head: "test.claim.roadmap_belt_actuate_witness.witness_exec_all_fails_on_later_step", - tail: Cons { - head: "test.claim.roadmap_belt_actuate_witness.witness_exec_all_runs_every_step_when_ok", - tail: Cons { - head: "test.claim.roadmap_belt_actuate_witness.witness_exec_all_short_circuits_after_failure", - tail: Cons { - head: "test.claim.roadmap_belt_actuate_witness.witness_exec_fails_on_nonzero_exit", - tail: Cons { - head: "test.claim.roadmap_belt_actuate_witness.witness_exec_ok_runs_echo", - tail: Cons { - head: "test.claim.roadmap_belt_actuate_witness.witness_exec_refuses_missing_program", - tail: Cons { - head: "test.claim.roadmap_belt_actuate_witness.witness_named_exec_steps_locate_the_first_failure", - tail: Cons { - head: "test.claim.run_verdict_exit_status_witness_test.run_failure_verdict_reaches_nonzero_exit", - tail: Cons { - head: "test.claim.run_verdict_exit_status_witness_test.run_non_process_exit_return_refuses", - tail: Cons { - head: "test.claim.run_verdict_exit_status_witness_test.run_success_verdict_reaches_zero_exit", - tail: Cons { - head: "test.claim.self_host_00_compile_behavioral_witness.self_host_00_compile_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_01_tokenize_behavioral_witness.self_host_01_tokenize_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_02_parse_behavioral_witness.self_host_02_parse_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_03_ingest_behavioral_witness.self_host_03_ingest_behavioral_receipt_holds", - tail: Empty {} - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } + head: "test.claim.http_client_get_real_execution.http_client_get_roundtrip_by_real_execution", + tail: Cons { + head: "test.claim.interp_recorded_fixture_witness_test.interp_recorded_fixture_keystone_holds", + tail: Cons { + head: "test.claim.materialized_ssh_key_file_real_execution_witness.witness_ssh_key_bracket_write_owner_only_shreds_and_not_under_target", + tail: Cons { + head: "test.claim.materialized_ssh_key_file_real_execution_witness.witness_write_owner_only_refuses_when_path_already_exists", + tail: Cons { + head: "test.claim.namespace_import_closure_witness.namespace_import_closure_receipt_holds", + tail: Cons { + head: "test.claim.parse_test.parse_witness_floor_holds", + tail: Cons { + head: "test.claim.parse_test.parse_witness_perf_holds", + tail: Cons { + head: "test.claim.proc_self_cgroup_real_execution_witness.bash_assign_from_source_observed_shell_holds", + tail: Cons { + head: "test.claim.proc_self_cgroup_real_execution_witness.bash_assign_from_source_refuses_ambiguous_shell_holds", + tail: Cons { + head: "test.claim.proc_self_cgroup_real_execution_witness.bash_assign_from_source_refuses_malformed_shell_holds", + tail: Cons { + head: "test.claim.proc_self_cgroup_real_execution_witness.bash_assign_from_source_refuses_missing_shell_holds", + tail: Cons { + head: "test.claim.random_bytes_csprng_witness.random_bytes_base64url_mint_16_length_holds", + tail: Cons { + head: "test.claim.random_bytes_csprng_witness.random_bytes_base64url_mint_20_length_holds", + tail: Cons { + head: "test.claim.random_bytes_csprng_witness.random_bytes_count_holds", + tail: Cons { + head: "test.claim.random_bytes_csprng_witness.random_bytes_zero_holds", + tail: Cons { + head: "test.claim.repo_local_git_config_real_execution.repo_local_git_config_actuator_sets_local_bindings_by_real_execution", + tail: Cons { + head: "test.claim.roadmap_belt_actuate_witness.witness_exec_all_fails_on_later_step", + tail: Cons { + head: "test.claim.roadmap_belt_actuate_witness.witness_exec_all_runs_every_step_when_ok", + tail: Cons { + head: "test.claim.roadmap_belt_actuate_witness.witness_exec_all_short_circuits_after_failure", + tail: Cons { + head: "test.claim.roadmap_belt_actuate_witness.witness_exec_fails_on_nonzero_exit", + tail: Cons { + head: "test.claim.roadmap_belt_actuate_witness.witness_exec_ok_runs_echo", + tail: Cons { + head: "test.claim.roadmap_belt_actuate_witness.witness_exec_refuses_missing_program", + tail: Cons { + head: "test.claim.roadmap_belt_actuate_witness.witness_named_exec_steps_locate_the_first_failure", + tail: Cons { + head: "test.claim.run_verdict_exit_status_witness_test.run_failure_verdict_reaches_nonzero_exit", + tail: Cons { + head: "test.claim.run_verdict_exit_status_witness_test.run_non_process_exit_return_refuses", + tail: Cons { + head: "test.claim.run_verdict_exit_status_witness_test.run_success_verdict_reaches_zero_exit", + tail: Empty {} + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } } + } } fn floor_route_gap_chunk_02() -> List { Cons { - head: "test.claim.self_host_03_normalize_behavioral_witness.self_host_03_normalize_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_03_resolve_behavioral_witness.self_host_03_resolve_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_04_infer_behavioral_witness.self_host_04_infer_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_body_producer_behavioral_witness.self_host_body_producer_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_discovery_enumeration_behavioral_witness.self_host_discovery_enumeration_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_logic_behavioral_witness.self_host_logic_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_materialization_carriers_behavioral_witness.self_host_materialization_carriers_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_parse_engine_hooks_behavioral_witness.self_host_parse_engine_hooks_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_program_assembly_behavioral_witness.self_host_program_assembly_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_program_partition_behavioral_witness.self_host_program_partition_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_source_authority_behavioral_witness.self_host_source_authority_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_target_carriers_behavioral_witness.self_host_target_carriers_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.self_host_use_site_verdict_behavioral_witness.self_host_use_site_verdict_behavioral_receipt_holds", - tail: Cons { - head: "test.claim.srv3_install_media_fetch_real_execution.install_media_hash_matches_false_on_wrong_hash_by_real_execution", - tail: Cons { + head: "test.claim.srv3_install_media_fetch_real_execution.install_media_hash_matches_false_on_wrong_hash_by_real_execution", + tail: Cons { head: "test.claim.srv3_install_media_fetch_real_execution.install_media_hash_matches_true_by_real_execution", tail: Cons { - head: "test.claim.srv3_install_media_fetch_real_execution.observe_install_media_fetch_covers_absent_verified_and_mismatch_by_real_execution", - tail: Cons { - head: "test.claim.srv3_seeded_install_media_real_execution.install_media_remaster_ensure_grub_cmdline_inserts_by_real_execution", - tail: Cons { - head: "test.claim.typed_witness_invocation.typed_claim_batch_pooled_run_red_control_holds", - tail: Cons { - head: "test.claim.typed_witness_invocation.typed_claim_executor_verify_build_artifacts_red_control_holds", - tail: Cons { - head: "test.claim.typed_witness_invocation.typed_gunbc_cli_run_claim_holds", - tail: Cons { - head: "test.claim.typed_witness_invocation.typed_is_executable_negative_red_control_holds", - tail: Cons { - head: "test.claim.typed_witness_invocation.typed_is_executable_positive_holds", - tail: Cons { - head: "test.claim.typed_witness_invocation.typed_is_nonempty_positive_holds", - tail: Cons { - head: "test.claim.typed_witness_invocation.typed_is_nonempty_zero_byte_red_control_holds", - tail: Cons { - head: "test.claim.typed_witness_invocation.typed_witness_bin_run_args_splice_holds", - tail: Cons { - head: "test.claim.typed_witness_invocation.typed_witness_bin_run_argv_holds", - tail: Empty {} - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } + head: "test.claim.srv3_install_media_fetch_real_execution.observe_install_media_fetch_covers_absent_verified_and_mismatch_by_real_execution", + tail: Cons { + head: "test.claim.srv3_seeded_install_media_real_execution.install_media_remaster_ensure_grub_cmdline_inserts_by_real_execution", + tail: Cons { + head: "test.claim.typed_witness_invocation.typed_claim_batch_pooled_run_red_control_holds", + tail: Cons { + head: "test.claim.typed_witness_invocation.typed_claim_executor_verify_build_artifacts_red_control_holds", + tail: Cons { + head: "test.claim.typed_witness_invocation.typed_gunbc_cli_run_claim_holds", + tail: Cons { + head: "test.claim.typed_witness_invocation.typed_is_executable_negative_red_control_holds", + tail: Cons { + head: "test.claim.typed_witness_invocation.typed_is_executable_positive_holds", + tail: Cons { + head: "test.claim.typed_witness_invocation.typed_is_nonempty_positive_holds", + tail: Cons { + head: "test.claim.typed_witness_invocation.typed_is_nonempty_zero_byte_red_control_holds", + tail: Cons { + head: "test.claim.typed_witness_invocation.typed_witness_bin_run_args_splice_holds", + tail: Cons { + head: "test.claim.typed_witness_invocation.typed_witness_bin_run_argv_holds", + tail: Empty {} + } + } + } + } + } + } + } + } + } + } + } } + } } fn floor_route_gap_chunk_03() -> List { @@ -561,66 +510,48 @@ fn floor_route_gap_expectation_chunk_02() -> List { Cons { head: FloorRouteGapExpectation { identity: "test.claim.host_cli_dependency_wet_witness_test.observe_echo_wet_posix_command_v_check_does_not_crash", operation: "Check", ground: NoMockResponse {} }, tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.host_cli_dependency_wet_witness_test.observe_npm_wet_posix_command_v_check_does_not_crash", operation: "Check", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.interpreter_dispatch_bijection_real_roster_witness_test.interpreter_dispatch_bijection_real_roster_red_holds", operation: "Check", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.json_protocol_schema_memory_split_wet_witness_test.wet_finish_parse_largest_protocol_schema_only", operation: "Check", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.json_protocol_schema_memory_split_wet_witness_test.wet_finish_parse_canonicalize_largest_protocol_schema_only", operation: "Check", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.namespace_structural_root_exposure_generated_witness_test.namespace_structural_root_exposure_generated_witness_holds", operation: "IsExecutable", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.no_fake_anomalies_witness.passing_run_shows_no_fake_anomaly_holds", operation: "Run", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.no_fake_anomalies_witness.red_control_entry_with_real_anomaly_still_shows_glyph_holds", operation: "Run", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.roadmap_receipt_continuity_live_witness.live_roadmap_acceptance_history_integrity_holds", operation: "git.Inspect.HeadCommit", ground: UnpublishedMockCase {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.self_host_artifact_materialization_real_execution_witness.a_real_cargo_build_materializes_through_the_real_digest", operation: "Dir", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.self_host_artifact_materialization_real_execution_witness.the_materialized_path_is_the_one_the_real_cargo_stream_named", operation: "Dir", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.self_host_artifact_materialization_real_execution_witness.a_target_the_build_never_produced_refuses_and_does_not_materialize", operation: "Dir", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.self_host_artifact_materialization_real_execution_witness.the_digest_is_of_the_file_cargo_named_not_of_some_other_real_file", operation: "Dir", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.self_host_artifact_materialization_real_execution_witness.changing_only_the_source_bytes_names_exactly_the_artifact_axis", operation: "Dir", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.self_host_artifact_materialization_real_execution_witness.rebuilding_identical_source_in_place_moves_no_axis", operation: "Dir", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.served_surface_browser_artifact_integrity_witness.witness_checked_in_screenshots_match_receipts", operation: "Dir", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.stage0_regen_convergence_real_execution_witness.a_real_regen_stage0_verify_run_reports_zero_divergence", operation: "Run", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.stage0_regen_convergence_real_execution_witness.w_RED_an_unrecognized_flag_does_not_report_the_success_marker", operation: "Run", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.stage0_rust_host_observation_live_witness.live_rust_observation_matches_actions_subject", operation: "Get", ground: NoMockResponse {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.stage0_rust_host_observation_live_witness.scaffold_host_observation_is_live_and_observed", operation: "git.Inspect.HeadCommit", ground: UnpublishedMockCase {} }, - tail: Cons { - head: FloorRouteGapExpectation { identity: "test.claim.stage0_rust_host_observation_live_witness.scaffold_host_observation_reaches_path_derived_verdict", operation: "git.Inspect.HeadCommit", ground: UnpublishedMockCase {} }, - tail: Empty {} - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } + head: FloorRouteGapExpectation { identity: "test.claim.host_cli_dependency_wet_witness_test.observe_npm_wet_posix_command_v_check_does_not_crash", operation: "Check", ground: NoMockResponse {} }, + tail: Cons { + head: FloorRouteGapExpectation { identity: "test.claim.interpreter_dispatch_bijection_real_roster_witness_test.interpreter_dispatch_bijection_real_roster_red_holds", operation: "Check", ground: NoMockResponse {} }, + tail: Cons { + head: FloorRouteGapExpectation { identity: "test.claim.json_protocol_schema_memory_split_wet_witness_test.wet_finish_parse_largest_protocol_schema_only", operation: "Check", ground: NoMockResponse {} }, + tail: Cons { + head: FloorRouteGapExpectation { identity: "test.claim.json_protocol_schema_memory_split_wet_witness_test.wet_finish_parse_canonicalize_largest_protocol_schema_only", operation: "Check", ground: NoMockResponse {} }, + tail: Cons { + head: FloorRouteGapExpectation { identity: "test.claim.namespace_structural_root_exposure_generated_witness_test.namespace_structural_root_exposure_generated_witness_holds", operation: "IsExecutable", ground: NoMockResponse {} }, + tail: Cons { + head: FloorRouteGapExpectation { identity: "test.claim.no_fake_anomalies_witness.passing_run_shows_no_fake_anomaly_holds", operation: "Run", ground: NoMockResponse {} }, + tail: Cons { + head: FloorRouteGapExpectation { identity: "test.claim.no_fake_anomalies_witness.red_control_entry_with_real_anomaly_still_shows_glyph_holds", operation: "Run", ground: NoMockResponse {} }, + tail: Cons { + head: FloorRouteGapExpectation { identity: "test.claim.roadmap_receipt_continuity_live_witness.live_roadmap_acceptance_history_integrity_holds", operation: "git.Inspect.HeadCommit", ground: UnpublishedMockCase {} }, + tail: Cons { + head: FloorRouteGapExpectation { identity: "test.claim.served_surface_browser_artifact_integrity_witness.witness_checked_in_screenshots_match_receipts", operation: "Dir", ground: NoMockResponse {} }, + tail: Cons { + head: FloorRouteGapExpectation { identity: "test.claim.stage0_regen_convergence_real_execution_witness.a_real_regen_stage0_verify_run_reports_zero_divergence", operation: "Run", ground: NoMockResponse {} }, + tail: Cons { + head: FloorRouteGapExpectation { identity: "test.claim.stage0_regen_convergence_real_execution_witness.w_RED_an_unrecognized_flag_does_not_report_the_success_marker", operation: "Run", ground: NoMockResponse {} }, + tail: Cons { + head: FloorRouteGapExpectation { identity: "test.claim.stage0_rust_host_observation_live_witness.live_rust_observation_matches_actions_subject", operation: "Get", ground: NoMockResponse {} }, + tail: Cons { + head: FloorRouteGapExpectation { identity: "test.claim.stage0_rust_host_observation_live_witness.scaffold_host_observation_is_live_and_observed", operation: "git.Inspect.HeadCommit", ground: UnpublishedMockCase {} }, + tail: Cons { + head: FloorRouteGapExpectation { identity: "test.claim.stage0_rust_host_observation_live_witness.scaffold_host_observation_reaches_path_derived_verdict", operation: "git.Inspect.HeadCommit", ground: UnpublishedMockCase {} }, + tail: Empty {} + } + } + } + } + } + } + } + } + } + } + } + } + } + } } } diff --git a/src/v2/workflow/floor_wet_route.dag b/src/v2/workflow/floor_wet_route.dag new file mode 100644 index 00000000000..8670865e991 --- /dev/null +++ b/src/v2/workflow/floor_wet_route.dag @@ -0,0 +1,1016 @@ +module v2.workflow.floor_wet_route + +import v2.std.algebra { any, contains, filter, fold_list, length, list_append } +import v2.std.collection { List } +import std.types { Int, EpochSecs, Seconds, Milliseconds, NonEmptyStr } +import std.dissolution { DissolutionCondition, unbound_dissolution } +import gunbc.explicit_witness_admission { known_red_probe_execution_roster } +import std.witness_admission { + WitnessExpectedVerdict, ExpectWitnessHolds, ExpectAssertionFalse, ExpectTypedPreVerdictRefusal, +} +import v2.std.logic { Bool } +import v2.std.optional { Optional, Absent, Present } +import v2.std.text { String } + + +// THE WET EXECUTION ROUTE: identities the required floor DECLINES from hermetic execution +// because their subject is a real host effect chain no honest mock can answer, routed instead +// to the wet receipts lane — a separate, non-required workflow job that executes them with +// real effects (`claim_batch --wet-route`) and publishes a per-attempt receipt envelope this +// floor then joins against. +// +// WHY A ROUTE AND NOT A MOCK (operator/parent ruling 2026-08-30, work item +// FLOOR-ROUTE-GAP-SELF-HOST, option (b)). Every identity below reaches +// `tools.self_host_curated_seed_linked_harness` or the artifact-materialization wet chain: +// mktemp, a real `gunbc compile` of the subject module, a real cargo build of the emitted +// crate, two driver executions, recursive scratch removal. `gunbc.hermetic_mock_fidelity` is +// the filed error class for answering any link of that chain with a canned value — the witness +// then asserts about the mock, and a mock for the FIRST refused operation (shell.Mktemp.Dir) +// only moves the refusal to the next link while the identity stays held. The honest route for +// the whole chain is real execution; the honest per-PR fact is a typed decline that names +// where the execution happens and REFUSES when that lane stops producing evidence. +// +// WHERE THE LANE RUNS, AND WHAT THAT COSTS THE GUARANTEE (§4b rung honesty, stated at the +// grain the ruling demanded). The wet receipts lane runs on a schedule and on manual +// dispatch, never per pull request and never as a required context — the 2026-08-29 CI +// bankruptcy ruling priced an ~87-minute required gate out of existence, and one seed-linked +// behavioral receipt alone measured ~305s of witness wall (gunbc#9371, first green since the +// falsifier deletion). So for every identity on this roster the rung is MECHANICALLY +// PREVENTABLE AT THE LANE'S CADENCE: a regression in a routed witness is caught at the next +// wet run, not at the merge that introduces it — with one carve-out that is per-merge after +// all: a change to the WET SUBJECT itself moves the subject digest, so a pull request that +// edits a routed witness or its closure is refused at merge unless a candidate-exact receipt +// accompanies it (`ReceiptSubjectMismatch` below). This is not a §4b(3) drop from anything +// the required floor previously established — these identities were route_gap_held, executing +// into a typed refusal and reaching no verdict at all, so the lane's cadence-grain verdict is +// a strict climb from no-verdict, and the drop ledger gains no row. +// +// THE RECEIPT IS AN ENVELOPE KEYED BY THE WET SUBJECT, NOT BY A COMMIT (parent amendment to +// transport a', 2026-08-30). A commit SHA over-keys the join: a prose-only merge would expire +// a receipt whose subject is byte-identical. The validity key is `subject_digest` — sha256 +// over the sorted per-entry closure subjects of every roster row PLUS the closure subject of +// this module itself (roster, schema, cadence rows all live here, so a contract edit moves +// the digest; the receipt namespace is outside every closure by construction, so publishing +// a receipt never expires itself). `head_sha` on the envelope is PROVENANCE ONLY — a citation +// of the producing run, never compared. DECLARED EXCLUSION, refusal-shaped, in +// `wet_subject_digest_exclusions()` below states what remains outside BOTH digests. +// +// THE EXECUTOR CONTRACT IS A SECOND, INDEPENDENTLY NAMED DIGEST (parent ruling 2026-08-30, +// residual-A repair). The semantic subject digest cannot see the seed-Rust executor: a +// candidate that changes claim_batch, cssl_assemble or the seed interpreter leaves every +// .dag closure untouched, and an old receipt would read candidate-exact though the new +// executor never ran. So the envelope also carries `executor_contract_digest` — sha256 over +// the declared conservative SUPERSET of executor inputs (`wet_executor_contract_input_prefixes()` +// below: the whole seed crate, the workspace manifests and lockfile, the pinned toolchain +// file, cargo config, and the wet workflow/command model files). Over-invalidation (an extra +// wet rerun for a seed edit that did not change wet behavior) is accepted; under-invalidation +// is not. The built binary's own sha stays provenance, never the comparison. +// +// PUBLICATION SEMANTICS: LATEST-ATTEMPT. The lane overwrites one committed envelope per run, +// pass or fail — a FAILED attempt publishes too, and its per-identity verdicts are then the +// standing facts the floor adjudicates (see THE PER-IDENTITY JOIN below): an UNEXPECTED wet +// red stops the line at the next cadence rather than hiding behind a surviving older green. +// `attempt_seq` advances monotonically so two attempts are ordered facts, not overwrites of +// one. +// +// HOW THE RECEIPT REACHES THE FLOOR (transport a'): the lane writes +// `floor_wet_route_receipt_json_rel_path` (the envelope, authority) and +// `floor_wet_route_receipt_tsv_rel_path` (its canonical row projection, for human diff +// review), uploads the pair as a run artifact, and STOPS — it holds no repository-write step +// on any ref. A PERSON carries the pair into the tree on a pull request, which merges under +// the ordinary rule; that recurring obligation, and its dissolution, are declared at +// `wet_receipt_hand_commit_dissolve_on` below. The +// required floor reads ONLY the committed files from the tree: hermetic, no network, no +// api.github.com read on the required path (a rate-limited API refusal would be a correct +// AND nondeterministic merge gate, the class the 2026-08-29 bankruptcy ruled against), and +// no bot push to a ruleset-protected main. THE HAND-EDIT RED is mirror integrity: the floor +// re-projects the TSV from the JSON and refuses on any byte difference, so an edit to either +// file alone is refused deterministically. That proves the pair is self-consistent, NOT that +// the lane produced it — an author who regenerates both consistently defeats it, and the +// declared trust boundary for that is ordinary pull-request approval, where a receipt edit +// outside a lane-opened refresh PR is loud. +// +// FRESHNESS IS MEASURED AGAINST THE EVALUATED TREE'S OWN COMMIT TIME, never the reading +// host's wall clock, so the join is a deterministic property of the commit: age = +// commit_time(HEAD under evaluation) − executed_at, refused past cadence + grace. The grace +// prices the publication pipeline — render, the refresh PR's own CI, approval, merge — so a +// receipt executed on time never expires while its PR sits in ordinary review. The envelope +// carries BOTH clocks: `executed_at_unix_secs` (freshness basis) and +// `published_at_unix_secs`, ordered executed ≤ published ≤ commit_time + skew, and an +// ordering violation is `ReceiptContractMismatch` — a clock that cannot have produced the +// envelope honestly. +// +// COMPOSITION WITH THE CHANGED-WITNESS STANDING (#9717): `floor_changed_witness` matches +// exhaustively over `RequiredFloorDisposition`, so the routed arm is a compile-forced +// decision there. A changed wet-routed declaration is admitted ONLY under a candidate-exact +// fresh receipt (`ReceiptFreshExactSubject` — the digest proves the lane executed exactly +// this candidate's wet subject); under any other standing it blocks at the changed-set +// grain, and greening it by decline would be the coverage inflation this module exists to +// refuse. The standing is envelope-level: a changed routed identity whose own receipt row +// is an unexpected red still reds the run through the per-identity join itself. An ancestor-subject receipt BLOCKS — there is no cadence-lag admission arm +// (parent ruling 2026-08-30). The remedy is live: workflow_dispatch the wet receipts lane on +// the head and land its envelope with the change. +// +// THE PUBLICATION WALL (residual B, parent ruling 2026-08-30). Latest-attempt semantics have +// a self-sealing corner: a red attempt's own refresh pull request would red on its own +// per-identity verdicts, so without a wall main silently keeps the last SUCCESS — +// latest-success wearing latest-attempt's name. The wall is a typed admission, not a widen: +// exactly the PER-IDENTITY reds (unexpected red, enrolled-now-passing) are waived, and only +// for a run whose own diff is a valid publication transaction +// (`WetReceiptPublicationTransaction`) — every changed path inside the receipt namespace and +// the attempt sequence advancing over the base envelope. Both waived classes have remedies +// that live OUTSIDE the receipt namespace (a repair, or an expected-red roster removal), so +// a receipt-confined refresh PR could not carry them by construction. Canonical rendering is +// already the reader's unconditional wall, and candidate-exactness and roster exactness are +// entailed by the fold reaching a verdict at all. Every ENVELOPE-level blocking standing +// blocks the publication PR too: an expired or subject-mismatched envelope advances nothing +// and is refused, never admitted. +// +// THE PER-IDENTITY JOIN (parent ruling 2026-08-30, replacing the envelope-level ReceiptFailed +// arm). The receipt is per-identity, so its verdicts join `floor_expected_red` exactly as dry +// claims do: receipt pass + not enrolled = clean; receipt fail + enrolled = KNOWN RED HELD — +// counted, visible, non-blocking, retiring only by an observed pass (the roster's shrink-only +// contract); receipt fail + NOT enrolled = UNEXPECTED wet red — blocks, the fail-closed arm +// that stays live; receipt pass + enrolled = NOW PASSING — blocks until the roster row is +// removed, exactly as the dry stale-quarantine does. An envelope-level "any failure blocks" +// arm was rejected because a known pre-existing red that seals main and every PR is not +// fail-closed but a denial of service on the line, and an observe-only mode was rejected as a +// §5 escape hatch that would also blind NEW wet reds. The expected-red population is passed +// IN (the live `floor_expected_red` roster intersected with this roster by the caller), so +// this fold stays pure and testable. +// +// THE LANE'S COST IS READ FROM THE LANE, NOT FROM PROSE: every wet run prints one +// `wet-lane:` line per identity carrying its measured wall, and the envelope rows carry the +// same figure, so the roster's price is re-derivable from any run and no number is +// transcribed here. + +type WetRouteRow = { + identity: String, + entry_rel: String, + function: String +} + +// THE OUTCOME GRAIN IS THE RAW TYPED OBSERVATION, never a collapsed Bool (parent ruling +// 2026-08-30, wall 1): the lane's executor distinguishes an assertion that RAN and returned +// false from every way of producing NO subject verdict — and collapsing them would hold an +// infrastructure failure as if the witness answered, the exact defect the dry expected-red +// roster documents. Arms mirror the executor's ClaimOutcome plus the lane's own two +// pre-execution refusals. +type WetLaneOutcome = + WetPass + | WetAssertionFalse + | WetNotBool + | WetRuntimeError + | WetBudgetInterrupted + | WetCompletedOverBudget + | WetHostToolUnresolved + | WetHostEffectRefused + | WetPanicked + | WetNotAttempted + | WetResolveFailed + | WetClosureSubjectFailed + +// One identity's row inside the envelope: the lane's verdict, its measured wall, and WHAT THE +// LANE ACTUALLY RESOLVED AND INVOKED. +// +// THE OBSERVED PAIR IS NOT THE ROSTER ROW ECHOED BACK, and that is the whole reason it exists. +// The producer reads it from the declaration the interpreter's own lookup SELECTED for the +// routed name (the seed's `selected_function_identity`), so `observed_function` is the +// qualified name of the node that ran and `observed_entry_rel` is the file it was authored in. +// Copying the roster's `entry_rel`/`function` into the receipt would make every downstream +// foreign-resolution join agree by construction — a witness that executed out of a different +// declaration (the bare-name precedence collision this corpus has shipped once already) would +// receipt as though it had not. +// +// `Absent` is the honest reading for a row that never reached a resolved declaration — entry +// resolve or closure subject failed. There is no observation, and a fabricated one is the +// plausible output §5 forbids; the row's own outcome already carries why. +type WetReceiptIdentityRow = { + identity: String, + outcome: WetLaneOutcome, + wall_ms: Milliseconds, + observed_entry_rel: Optional, + observed_function: Optional +} + +// THE COMMITTED RECEIPT ENVELOPE (`floor_wet_route_receipt_json_rel_path`). One attempt, +// latest-attempt semantics. `subject_digest` is the validity key; `head_sha` and `run_id` +// are provenance citations of the producing run; the two clocks are ordered +// executed ≤ published. +type WetReceiptEnvelope = { + schema_version: Int, + subject_digest: String, + executor_contract_digest: String, + attempt_seq: Int, + executed_at_unix_secs: EpochSecs, + published_at_unix_secs: EpochSecs, + run_id: String, + head_sha: String, + rows: List +} + +// TIME FIELDS CONSUME THE STD CARRIERS (review 57576 on gunbc#9725, and the parent ruling +// that followed it): `wall_ms` is `std.types.Milliseconds`, the two publication clocks and +// the fold's evaluated-tree commit parameter are `std.types.EpochSecs` — the corpus's one +// authority for a POSIX Unix-epoch instant — and the cadence/grace/budget/skew rows are +// `std.types.Seconds` durations. An instant and a duration stay two types, so the freshness +// subtraction and the skew inequality are the only places they meet. The pre-existing +// `observed_cpu_ms`/`observed_wall_ms` fields in `v2.workflow.required_floor` remain the +// same debt on main under their own declared dissolution row; this module does not widen +// into repairing them. + +// THE FLOOR-SIDE STANDING OF THE COMMITTED ENVELOPE, one value per evaluated tree, decided +// from four facts the floor holds: the envelope (or its absence), the wet subject digest the +// floor computed for the tree under evaluation, the roster, and the tree's own commit time. +// Exactly one arm is clean, and every arm is a fact about the ENVELOPE — validity, subject, +// contract, roster, age. Per-identity verdicts (pass/fail per routed witness) are NOT a +// standing arm: they join `floor_expected_red` in the per-identity fns below (parent ruling +// 2026-08-30). The arms carry the `Receipt` prefix because names resolve globally. +// `ReceiptExecutorSnapshotDifferent` is the executor-contract axis SPLIT OUT of the generic +// subject mismatch (parent lease ruling 2026-08-30): a semantic-subject mismatch means the +// lane executed a DIFFERENT PROGRAM and is never admissible, while an executor-snapshot +// difference means the same semantic subject ran under a superseded seed build — still a +// refusal by default, but the one arm the one-shot bootstrap admission below may admit, and +// the split keeps that admission from ever widening onto the semantic axis. The arm does NOT +// make the mismatch look exact: the standing stays different; only the gate DISPOSITION may +// admit it, visibly, as `WetFloorAdmittedUnderBootstrapLease`. +type WetLaneReceiptStanding = + ReceiptFreshExactSubject { age_secs: Seconds } + | ReceiptMissing + | ReceiptExpired { age_secs: Seconds } + | ReceiptSubjectMismatch { axis: String, receipt_digest: String, computed_digest: String } + | ReceiptExecutorSnapshotDifferent { receipt_digest: String, computed_digest: String } + | ReceiptContractMismatch { detail: String } + | ReceiptRosterInexact { detail: String } + +// The receipt schema this floor reads. A committed envelope carrying any other version is +// `ReceiptContractMismatch` — the producer and consumer no longer share a contract, and +// guessing across versions would be an absorbing read. +fn floor_wet_route_receipt_schema_version() -> Int { + 2 +} + +// A NEGATIVE AGE REFUSES RATHER THAN CLAMPING, and the arm it replaced is the reason this note +// exists. `raw_age < 0` used to become `0`, which reported the impossible state as +// `ReceiptFreshExactSubject { age_secs: 0 }` -- the FRESHEST possible reading. That is DESIGN +// section 5's absorbing fallback exactly: the arm that cannot compute an honest answer substituted +// the most permissive one, and it did so silently, so a clock defect on the lane host would have +// read as a perfect receipt forever. +// +// IT WAS NARROW, AND NARROW IS NOT THE SAME AS HARMLESS. The two walls above bound it: executed_at +// may not exceed published_at, and published_at may not exceed the tree commit plus the declared +// publication skew, so a negative age was bounded BELOW by that skew rather than unbounded. The +// clamp was still a widen, and the correct shape for a bounded-but-impossible reading is a typed +// refusal naming it, never a substituted value that happens to be small. +// +// WHAT THE AGE AXIS IS FOR, because it is NOT redundant with the subject axis and reading it +// that way is the live trap. The standing fold reaches `ReceiptExpired` only AFTER the subject +// digest, the executor contract digest and the roster join all match — so an exact receipt for +// an untouched tree still ages out, which invites the conclusion that aging buys nothing. It +// buys the only thing the digests cannot: both of them are computed from REPOSITORY FILES, and +// `wet_executor_contract_input_prefixes` covers the toolchain PIN, not the realized toolchain, +// the runner image, the resolved dependency bytes, or any service the wet rows actually touch. +// A wet receipt is an OBSERVATION OF EXTERNAL REALITY, which DESIGN §4b deliberately keeps off +// the guarantee ladder — observed at a declared boundary, never fabricated. Observations of the +// unmodeled decay while every modeled digest stays identical. So the two axes bound two +// different drifts: the subject axis bounds what we MODEL, the age axis bounds what we DO NOT. +// Re-keying expiry to the subject would not remove this route's recurring cost, it would remove +// our ability to NOTICE it — a stale observation cited as current, with nothing refusing. That +// is the absorbing-fallback shape, not a bound, and it is why the age leg stays. +// +// Daily cadence; three days of grace pricing the publication pipeline (render, a human +// retrieving the run artifact, the refresh commit's own CI, approval, merge — each a real +// latency between executed_at and the receipt standing in a tree). The retrieval leg is +// human because the lane holds no repository-write step; the recurring obligation that +// creates is declared at wet_receipt_hand_commit_dissolve_on, and grace prices it +// rather than excusing it. The staleness budget is DERIVED as their sum so the tolerated miss +// count is a read, not an inference, and no third figure exists to drift. +fn floor_wet_route_cadence_secs() -> Seconds { + 86400 +} + +fn floor_wet_route_receipt_grace_secs() -> Seconds { + 259200 +} + +fn floor_wet_route_receipt_staleness_budget_secs() -> Seconds { + floor_wet_route_cadence_secs() + floor_wet_route_receipt_grace_secs() +} + +// Tolerated forward clock skew between the publishing host and the evaluated commit's own +// timestamp: published_at may not exceed commit_time + this figure. +fn floor_wet_route_publication_skew_secs() -> Seconds { + 3600 +} + + +data floor_wet_route_receipt_json_rel_path: String = "dag/gunbc/witness/wet_lane/latest-attempt.json" + +data floor_wet_route_receipt_tsv_rel_path: String = "dag/gunbc/witness/wet_lane/latest-attempt.tsv" + +// THE EXECUTOR-CONTRACT INPUT ROSTER: the repo-relative path prefixes whose bytes the +// executor-contract digest hashes, in both the lane (producer) and the required floor +// (consumer). A prefix ending in '/' names a directory walked recursively; any other row is +// one file. A declared row matching nothing on disk REFUSES — a rotted roster row is a +// silently narrowing digest, the exact under-invalidation this repair forbids. +fn wet_executor_contract_input_prefixes() -> List { + [ + "src/v1/stage0/", + "Cargo.toml", + "Cargo.lock", + "rust-toolchain.toml", + ".cargo/", + "dag/gunbc/witness/witness_floor_workflow.dag", + "dag/gunbc/claim_executor_cli.dag" + ] +} + +// THE DECLARED SUBJECT-UNIVERSE EXCLUSION (parent condition on the amended transport, stated +// as a row a reviewer and a gate can consume rather than prose): after the two digests — +// semantic subject over the .dag closures, executor contract over the roster above — what +// remains outside is only the named residue below. The restoration trigger names the +// capability, not an artifact: a digest whose subject universe includes the executing +// harness as .dag-closure bytes — which the emitted self-host executor provides. +type WetSubjectDigestExclusion = { + excluded_component: String, + why_outside: String, + restoration_trigger: String +} + +fn wet_subject_digest_exclusions() -> List { + [ + WetSubjectDigestExclusion { + excluded_component: "the installed toolchain and host OS the pinned rust-toolchain.toml resolves to at build time", + why_outside: "the executor-contract digest hashes the tree's declared executor inputs — the seed crate sources, manifests, lockfile, toolchain pin, cargo config and wet workflow/command models — but not the bytes of the installed compiler or operating system those pins resolve to on the runner", + restoration_trigger: "a wet lane executed by the emitted self-host executor, whose implementation is .dag-closure bytes and therefore inside the semantic subject digest's universe" + } + ] +} + +// THE STANDING FOLD. Decision order is deliberate: unreadable-contract facts are decided +// before subject facts, subject before roster, roster before time, time before verdict — +// each later question is only meaningful once the earlier ones hold. +fn wet_lane_receipt_standing( + envelope: Optional, + computed_subject_digest: String, + computed_executor_contract_digest: String, + roster_identities: List, + evaluated_tree_commit_unix_secs: EpochSecs +) -> WetLaneReceiptStanding { + match envelope { + Absent => ReceiptMissing {} + Present { value: e } => { + if e.schema_version != floor_wet_route_receipt_schema_version() { + ReceiptContractMismatch { detail: "schema_version is not the version this floor reads" } + } else { + if wet_time_scalar(x: e.executed_at_unix_secs) > wet_time_scalar(x: e.published_at_unix_secs) { + ReceiptContractMismatch { detail: "executed_at exceeds published_at" } + } else { + if wet_time_scalar(x: e.published_at_unix_secs) > wet_time_scalar(x: evaluated_tree_commit_unix_secs) + wet_time_scalar(x: floor_wet_route_publication_skew_secs()) { + ReceiptContractMismatch { detail: "published_at exceeds the evaluated tree's commit time beyond the declared skew" } + } else { + if e.subject_digest != computed_subject_digest { + ReceiptSubjectMismatch { axis: "semantic-subject", receipt_digest: e.subject_digest, computed_digest: computed_subject_digest } + } else { + if e.executor_contract_digest != computed_executor_contract_digest { + ReceiptExecutorSnapshotDifferent { receipt_digest: e.executor_contract_digest, computed_digest: computed_executor_contract_digest } + } else { + if wet_receipt_rows_join_roster_exactly(rows: e.rows, roster_identities: roster_identities) { + if !wet_receipt_rows_executed_the_identity_they_claim(rows: e.rows) { + ReceiptContractMismatch { detail: "a row records an observed resolution that is not the identity it claims — the lane executed a different declaration than the routed identity names" } + } else { + let raw_age = wet_time_scalar(x: evaluated_tree_commit_unix_secs) - wet_time_scalar(x: e.executed_at_unix_secs) + if raw_age < 0 { + ReceiptContractMismatch { detail: "executed_at is later than the evaluated tree commit — a receipt cannot be executed after the tree it is a verdict about" } + } else { + let age = raw_age + if age > wet_time_scalar(x: floor_wet_route_receipt_staleness_budget_secs()) { + ReceiptExpired { age_secs: age } + } else { + ReceiptFreshExactSubject { age_secs: age } + } + } + } + } else { + ReceiptRosterInexact { detail: "the envelope's identity rows are not exactly the routed roster" } + } + } + } + } + } + } + } + } +} + +// Exact identity join: every roster identity has exactly one envelope row and no envelope +// row is off-roster. Completeness is an identity join, not a count equality — but with +// membership proven in both directions, the two lengths agreeing closes the multiset. +fn wet_receipt_rows_join_roster_exactly( + rows: List, + roster_identities: List +) -> Bool { + let row_ids = rows |> map(row => row.identity) + let every_roster_id_present = fold_list( + xs: roster_identities, + empty: true, + cons: fn(acc, id) { acc && contains(xs: row_ids, item: id, eq: string_eq) } + ) + let every_row_on_roster = fold_list( + xs: row_ids, + empty: true, + cons: fn(acc, id) { acc && contains(xs: roster_identities, item: id, eq: string_eq) } + ) + every_roster_id_present && every_row_on_roster && length(xs: rows) == length(xs: roster_identities) +} + +fn string_eq(a: String, b: String) -> Bool { + a == b +} + +// THE OBSERVED-RESOLUTION JOIN. `observed_function` is the qualified name of the declaration +// the lane's interpreter actually SELECTED; `identity` is what the roster asked for. The two +// sides have different producers — one read off the selected node, one authored in the roster — +// so comparing them is a real check and not a restatement: it catches a witness that executed +// out of a different declaration than the one routed, which is a shape this corpus has shipped +// (a bare reference binding to a homonym in another module while the run reported under the +// requested name). +// +// A row with no observation is NOT judged here. Nothing resolved, so there is nothing to +// disagree with; the row's own outcome already says it produced no verdict, and +// `wet_receipt_no_verdict_identities` blocks on it. +fn wet_receipt_rows_executed_the_identity_they_claim(rows: List) -> Bool { + fold_list( + xs: rows, + empty: true, + cons: fn(acc, row) { + match row.observed_function { + Absent => acc + Present { value: observed } => acc && observed == row.identity + } + } + ) +} + +// THE PER-IDENTITY VERDICT PROJECTIONS (parent ruling 2026-08-30, walls 1 and 3). The +// expected-verdict authority is `gunbc.explicit_witness_admission` at FUNCTION grain — the +// same rows the hermetic probe cadence consumes — projected onto this route's identities by +// `wet_route_expected_assertion_false_identities` below; no second enrollment roster exists +// beside it. The algebra is the dry floor's: pass + unenrolled = clean; pass + enrolled = +// NOW PASSING (blocks until the admission row deletes); assertion-false + enrolled = KNOWN +// RED HELD (counted, non-blocking, retiring only by an observed pass); assertion-false + +// unenrolled = UNEXPECTED RED (blocks — the fail-closed arm that stays live); and EVERY +// no-subject-verdict outcome blocks regardless of enrollment, because an enrollment asserts +// the witness reaches its subject and answers — only an explicitly enrolled typed +// pre-verdict expectation could hold one, and no wet identity carries such a row today; the +// projection grows an arm when one does, and until then the outcome blocks. + +fn wet_route_expected_assertion_false_identities() -> List { + floor_wet_route_roster() + |> filter(row => any( + xs: known_red_probe_execution_roster(), + predicate: fn(entry) { + (entry.entry as String) == row.entry_rel && entry.function == row.function + } + )) + |> map(row => row.identity) +} + +fn wet_receipt_unexpected_red_identities( + rows: List, + expected_red_identities: List +) -> List { + fold_list( + xs: rows, + empty: [], + cons: fn(acc, row) { + match row.outcome { + WetAssertionFalse => + if contains(xs: expected_red_identities, item: row.identity, eq: string_eq) { + acc + } else { + list_append(left: acc, right: [row.identity]) + } + WetPass => acc + WetNotBool => acc + WetRuntimeError => acc + WetBudgetInterrupted => acc + WetCompletedOverBudget => acc + WetHostToolUnresolved => acc + WetHostEffectRefused => acc + WetPanicked => acc + WetNotAttempted => acc + WetResolveFailed => acc + WetClosureSubjectFailed => acc + } + } + ) +} + +fn wet_receipt_held_identities( + rows: List, + expected_red_identities: List +) -> List { + fold_list( + xs: rows, + empty: [], + cons: fn(acc, row) { + match row.outcome { + WetAssertionFalse => + if contains(xs: expected_red_identities, item: row.identity, eq: string_eq) { + list_append(left: acc, right: [row.identity]) + } else { + acc + } + WetPass => acc + WetNotBool => acc + WetRuntimeError => acc + WetBudgetInterrupted => acc + WetCompletedOverBudget => acc + WetHostToolUnresolved => acc + WetHostEffectRefused => acc + WetPanicked => acc + WetNotAttempted => acc + WetResolveFailed => acc + WetClosureSubjectFailed => acc + } + } + ) +} + +fn wet_receipt_now_passing_identities( + rows: List, + expected_red_identities: List +) -> List { + fold_list( + xs: rows, + empty: [], + cons: fn(acc, row) { + match row.outcome { + WetPass => + if contains(xs: expected_red_identities, item: row.identity, eq: string_eq) { + list_append(left: acc, right: [row.identity]) + } else { + acc + } + WetCompletedOverBudget => + if contains(xs: expected_red_identities, item: row.identity, eq: string_eq) { + list_append(left: acc, right: [row.identity]) + } else { + acc + } + WetAssertionFalse => acc + WetNotBool => acc + WetRuntimeError => acc + WetBudgetInterrupted => acc + WetHostToolUnresolved => acc + WetHostEffectRefused => acc + WetPanicked => acc + WetNotAttempted => acc + WetResolveFailed => acc + WetClosureSubjectFailed => acc + } + } + ) +} + +// Every way of producing no subject verdict, spelled arm-by-arm so an eventual thirteenth +// outcome must be classified here, never absorbed. +// +// `WetCompletedOverBudget` IS NOT ONE OF THEM, and it used to be. The witness ran to completion +// and the seed only ever mints that arm over a PASS, so the verdict is known and the elapsed +// figure is exact — the opposite of `WetBudgetInterrupted`, where the deadline preempted the +// answer and the figure is a lower bound. The canonical floor already draws that line at the +// same grain (`required_floor_runner` routes `ClaimOutcome::CompletedOverBudget` to +// `completed_over_cost_requirement`, never to `interrupted_before_verdict`, and says in its own +// words that a cost is not a defect). Holding a cost debt in the no-verdict population sent the +// reader to the wrong remedy: it read as "correctness unknown" over a row that demonstrably +// answered, so the fix it invites is to debug a witness that is not broken instead of to pay +// down its cost. The row still blocks — this route enrolls no cost-debt population — but it +// blocks as `wet_receipt_cost_debt_identities` with a cost remedy. +fn wet_receipt_no_verdict_identities(rows: List) -> List { + fold_list( + xs: rows, + empty: [], + cons: fn(acc, row) { + match row.outcome { + WetPass => acc + WetAssertionFalse => acc + WetNotBool => list_append(left: acc, right: [row.identity]) + WetRuntimeError => list_append(left: acc, right: [row.identity]) + WetBudgetInterrupted => list_append(left: acc, right: [row.identity]) + WetCompletedOverBudget => acc + WetHostToolUnresolved => list_append(left: acc, right: [row.identity]) + WetHostEffectRefused => list_append(left: acc, right: [row.identity]) + WetPanicked => list_append(left: acc, right: [row.identity]) + WetNotAttempted => list_append(left: acc, right: [row.identity]) + WetResolveFailed => list_append(left: acc, right: [row.identity]) + WetClosureSubjectFailed => list_append(left: acc, right: [row.identity]) + } + } + ) +} + +// THE COST-DEBT POPULATION: rows that reached their verdict and then exceeded the lane's line. +// A cost is not a verdict, so this axis is orthogonal to the three above — an identity appears +// here and, if it is enrolled as expected-red, in `wet_receipt_now_passing_identities` as well, +// because completing over budget is a completion and the seed mints the arm only over a pass. +// This route enrolls no cost-debt roster, so every row here blocks; what the population buys is +// that the diagnostic names a cost remedy rather than a correctness one. +fn wet_receipt_cost_debt_identities(rows: List) -> List { + fold_list( + xs: rows, + empty: [], + cons: fn(acc, row) { + match row.outcome { + WetCompletedOverBudget => list_append(left: acc, right: [row.identity]) + WetPass => acc + WetAssertionFalse => acc + WetNotBool => acc + WetRuntimeError => acc + WetBudgetInterrupted => acc + WetHostToolUnresolved => acc + WetHostEffectRefused => acc + WetPanicked => acc + WetNotAttempted => acc + WetResolveFailed => acc + WetClosureSubjectFailed => acc + } + } + ) +} + +// THE PER-IDENTITY BLOCKING POLARITY, STATED ONCE: an unexpected red, an enrolled row now +// passing, any row with no subject verdict, or any row carrying cost debt blocks; held rows are +// counted and do not. The four populations stay separate all the way to the diagnostic because +// their remedies differ — repair, retire a roster row, restore an execution, pay a cost. +fn wet_route_identity_rows_block( + unexpected_red: List, + now_passing: List, + no_verdict: List, + cost_debt: List +) -> Bool { + length(xs: unexpected_red) != 0 + || length(xs: now_passing) != 0 + || length(xs: no_verdict) != 0 + || length(xs: cost_debt) != 0 +} + +// THE ONE SANCTIONED BRIDGE from a refined time scalar to plain Int arithmetic, and a +// DECLARED WORKAROUND (§5 unmarked_workaround is the failure mode this marking preempts): +// the interpreter has no `as` cast in either direction for refined scalars (measured on +// this change: `EpochSecs as Int` refuses at eval exactly like the roadmap witness note's +// `2 as Seconds`), but parameter positions admit a refined value where Int is declared — +// the SAME mechanism and the SAME debt `gunbc.roadmap_forecast` rides passing an EpochMs +// difference into `millisecond(count:)`; that precedent is cited as one class, not a second +// authority. Every arithmetic site in this module routes through this ONE identity so the +// census counts one row, and its dissolution names the capability, not an artifact. +fn wet_time_scalar(x: Int) -> Int { + x +} + +data wet_time_scalar_dissolve_on: DissolutionCondition = unbound_dissolution( + description: "🟡 workaround: wet_time_scalar parameter-position identity bridging refined time scalars (EpochSecs/Seconds) to Int arithmetic. dissolve-on: refined-scalar coercion is modeled in the interpreter — an `as` cast (or subtype-widening rule) from a where-refined scalar to its base Int that evaluates, sufficient for `EpochSecs as Int` and `Seconds as Int` to run under gunbc run — at which point every wet_time_scalar call site converts to the modeled coercion and this function deletes; the roadmap_forecast EpochMs-difference-into-millisecond(count:) site is the same debt and dissolves on the same capability." as NonEmptyStr, +) + +// THE HAND-COMMITTED ENVELOPE, ON MAIN AND ON EVERY CANDIDATE ALIKE — a declared out-of-band +// actuation, not a silent one (DESIGN §6: a hand-authored actuation step is presumed scaffold +// until it carries its dissolution). +// +// WHAT IS HAND-ACTUATED, AND IT IS RECURRING, NOT PER-CANDIDATE. `gunbc.witness_floor_workflow`'s +// wet-receipts job EXECUTES the routed rows and uploads the pair as the `wet-lane-receipt` +// artifact, and there it stops: the job carries no repository-write step on any ref. So EVERY +// receipt this route ever consumes reaches the tree through a person — the candidate case (a head +// whose landing needs a fresh envelope) and, the one that becomes folklore, the STANDING case on +// main. The scheduled lane runs at floor_wet_route_cadence_secs and uploads; nothing commits. A +// receipt ages out at floor_wet_route_receipt_staleness_budget_secs (derived above as cadence + +// grace, so read it there rather than carrying a number here), at which point the required floor +// refuses on EVERY open pull request, not only one — so a person must download the artifact and +// commit the pair inside that window, again on the next expiry, and so on for as long as this row +// stands. That is a human step inside a mechanism whose whole purpose is that no verdict is +// hand-supplied, and it is declared here as admitted recurring debt rather than left to be +// rediscovered by whoever is on shift when the floor goes red. +// +// WHY IT IS NOT A HOLE. The committed bytes are not trusted for being committed: the floor +// re-projects the TSV from the JSON and refuses on drift, re-computes the subject and executor +// digests from the tree and refuses on mismatch, and joins the roster at identity grain. A +// hand-committed envelope that says anything the tree does not support is refused exactly as a +// lane-committed one would be. What the hand step can do is DELAY a receipt, never fabricate one — +// and a missed refresh is loud: the floor refuses, it does not carry the last green forward. +// +// DISSOLVES WHEN the lane acquires a MODELED repository-write effect — a typed write on +// `host_effect_apply` reached through the emitted pipeline, not a hand-authored git/gh `run:` +// string — and writes its receipt pair onto the head it executed, on any branch a required floor +// can gate, with no human retrieval step between execution and receipt. Both halves are the +// capability: a hand-shell actuator that pushed from the lane would move the human out of the +// loop while putting an unmodeled foreign-executor process in the repository's write path, which +// is the DESIGN §6 out-of-band-actuation tell this row exists to name — it would not retire this +// row, it would add a second one. Neither does a change that merely uploads the artifact more +// conveniently, or that automates the fetch from outside the lane. +data wet_receipt_hand_commit_dissolve_on: DissolutionCondition = unbound_dissolution( + description: "🟡 out-of-band actuation, RECURRING AND UNBOUNDED: every wet-lane receipt envelope this route consumes is fetched from the run artifact and committed by hand, because gunbc.witness_floor_workflow's wet-receipts job uploads the pair and holds no repository-write step on any ref. The obligation is standing, not one-off — the scheduled lane executes and uploads at floor_wet_route_cadence_secs and commits nothing, so a person must land a fresh pair within floor_wet_route_receipt_staleness_budget_secs of each execution, indefinitely; a miss refuses the required floor on every open pull request until someone does. dissolve-on: the lane writes its own receipt pair onto the head it executed, on any branch a required floor gates, through a MODELED typed repository-write effect on host_effect_apply reached from the emitted pipeline — no human retrieval between execution and receipt, and no hand-authored git/gh run string standing in for the modeled effect. Conveniences around the fetch do not retire this row." as NonEmptyStr, +) + +// THE ONE-SHOT BOOTSTRAP ADMISSION (parent lease ruling 2026-08-30, re-instantiated +// 2026-08-31 bound to envelope v7). The structural race it prices: a wet cycle takes ~2.5h +// while main merges src/v1/stage0 every ~1-2h, so an envelope can be executor-stale on every +// mergeable head without any semantic fact changing. +// +// WHY THE RE-INSTANTIATION IS SOUNDER THAN THE ORIGINAL RULING, and this is the fact that +// changed under it: when the lease was first ruled admissible, the SEMANTIC subject digest was +// not a function of the tree at all — it folded `transform_content_digest()`, the bytes of the +// running executable, so producer and consumer could never agree and "executor-only drift" was +// not a state anyone could actually establish. That defect is fixed (`wet_closure_subject`), the +// semantic axis is now tree-only and provably convergent, and a lease that admits ONLY past +// `ReceiptExecutorSnapshotDifferent` is therefore admitting past a genuinely isolated axis +// rather than past a digest that was noise on both. The narrowness the original ruling assumed +// is now real rather than asserted. The lease +// admits EXACTLY ONE named envelope past `ReceiptExecutorSnapshotDifferent` — never past a +// semantic-subject, contract, roster, expiry or missing standing — bound by envelope digest +// and attempt_seq (never commit ancestry: a squash merge erases ancestry), inside a FIXED +// window of `executed_at + wet_seed_bootstrap_lease_window_secs()` with no slide, renewal or +// commit-count bound. `not_after` is DERIVED and checked, not trusted: a declared row whose +// not_after is not exactly executed_at + window is not applicable. The declared row deletes in +// the same transaction as the first exact-main receipt (the rung-drop row's restoration). +fn wet_seed_bootstrap_lease_window_secs() -> Seconds { + 28800 +} + +// `lease_identity` names WHICH lease this row is, so a second row cannot be mistaken for a +// renewal of this one, and `observed_executor_contract_digest` records the executor digest the +// lease was authored AGAINST -- the one fact the admission is conceding. Neither participates in +// the admission join: the join is over the exact envelope/attempt/subject/roster facts below, +// and recording the conceded digest is what makes the concession readable rather than implicit. +type BootstrapExecutorSnapshotReceipt = { + lease_identity: String, + exact_envelope_digest: String, + exact_attempt_seq: Int, + exact_semantic_subject_digest: String, + exact_roster_digest: String, + observed_executor_contract_digest: String, + executed_at_unix_secs: EpochSecs, + not_after_unix_secs: EpochSecs +} + +type WetSeedBootstrapAdmission = + BootstrapExecutorSnapshotLeaseAdmitted { + exact_envelope_digest: String, + exact_attempt_seq: Int, + exact_semantic_subject_digest: String, + exact_roster_digest: String, + executed_at_unix_secs: EpochSecs, + not_after_unix_secs: EpochSecs + } + | BootstrapLeaseExpired { detail: String } + | BootstrapLeaseNotApplicable + +// THE DECLARED LEASE ROW LIVES OUTSIDE THIS MODULE — `gunbc.wet_seed_bootstrap_lease` +// (dag/gunbc/floor/wet_seed_bootstrap_lease.dag) — deliberately: the wet SEMANTIC subject +// digest hashes this module's closure subject, so a row declared here would move the digest +// the moment it flips Absent→Present and invalidate the very envelope it admits. The +// admission fn below therefore takes the lease as a parameter; the required floor runner +// reads the declared row from its own module. + +// THE ADMISSION EVALUATION: every exact fact must join, and the window is closed-form. Any +// mismatch is NotApplicable (the lease names a different envelope — not an error, just not +// this one); a joined lease outside its window is Expired, the arm that distinguishes "the +// lease died of age" from "no lease names this envelope". +fn wet_seed_bootstrap_admission( + lease: Optional, + envelope_digest: String, + attempt_seq: Int, + semantic_subject_digest: String, + roster_digest: String, + evaluated_tree_commit_unix_secs: EpochSecs +) -> WetSeedBootstrapAdmission { + match lease { + Absent => BootstrapLeaseNotApplicable {} + Present { value: r } => { + if r.exact_envelope_digest != envelope_digest + || r.exact_attempt_seq != attempt_seq + || r.exact_semantic_subject_digest != semantic_subject_digest + || r.exact_roster_digest != roster_digest { + BootstrapLeaseNotApplicable {} + } else { + if wet_time_scalar(x: r.not_after_unix_secs) + != wet_time_scalar(x: r.executed_at_unix_secs) + wet_time_scalar(x: wet_seed_bootstrap_lease_window_secs()) { + BootstrapLeaseNotApplicable {} + } else { + if wet_time_scalar(x: evaluated_tree_commit_unix_secs) > wet_time_scalar(x: r.not_after_unix_secs) { + BootstrapLeaseExpired { detail: "the evaluated tree's commit time exceeds the lease's fixed not_after window" } + } else { + BootstrapExecutorSnapshotLeaseAdmitted { + exact_envelope_digest: r.exact_envelope_digest, + exact_attempt_seq: r.exact_attempt_seq, + exact_semantic_subject_digest: r.exact_semantic_subject_digest, + exact_roster_digest: r.exact_roster_digest, + executed_at_unix_secs: r.executed_at_unix_secs, + not_after_unix_secs: r.not_after_unix_secs + } + } + } + } + } + } +} + +// THE GATE DISPOSITION — the canonical fold the blocking polarity consumes (review 57656: +// a coproduct must not be flattened to Bool at the consumer; the algebra lives here). Exactly +// two arms admit, and each carries its admission's own evidence: `WetFloorAdmittedFresh` is +// the ordinary exact-subject admission, and `WetFloorAdmittedUnderBootstrapLease` is the +// declared one-shot admission, distinct so no reader can mistake a leased envelope for an +// exact one. `WetFloorRefused` carries the standing so the refusal stays located and typed. +type WetFloorGateDisposition = + WetFloorAdmittedFresh { age_secs: Seconds } + | WetFloorAdmittedUnderBootstrapLease { not_after_unix_secs: EpochSecs } + | WetFloorRefused { standing: WetLaneReceiptStanding } + +// THE DOOR TAKES THE FACTS, NOT A STANDING AND AN ADMISSION. An earlier shape took those as two +// INDEPENDENTLY CONSTRUCTED arguments and, on the executor-different arm, discarded both standing +// digests and all four `exact_` admission fields, keeping only `not_after`. So a lease validly +// admitted for envelope A admitted an executor-different standing derived from envelope B -- +// verified by construction before this repair, not reasoned about. +// +// IT SURVIVED A COMPLETE MUTATION MATRIX, WHICH IS THE POINT. Every arm of +// `wet_seed_bootstrap_admission` discriminates: envelope digest, attempt_seq, semantic subject, +// roster, the derived window, expiry. All six verify the lease against ITS OWN DECLARED INPUTS, and +// nothing verified it against THE STANDING IT WAS ADMITTING. That is the neighbouring-proposition +// failure one level up from the pin: a complete, green set of assertions about an adjacent question. +// +// SO THE PAIR IS NO LONGER CONSTRUCTIBLE RATHER THAN CHECKED. Both values are derived here from ONE +// envelope and one set of computed digests, so there is no argument position in which a caller could +// supply a standing about a different receipt. A sixth witness would have been validation standing +// where construction was available (DESIGN section 5); this is the construction. +fn wet_route_gate_disposition_for_receipt( + envelope: Optional, + envelope_digest: String, + computed_subject_digest: String, + computed_executor_contract_digest: String, + roster_identities: List, + roster_digest: String, + evaluated_tree_commit_unix_secs: EpochSecs, + lease: Optional +) -> WetFloorGateDisposition { + let standing = wet_lane_receipt_standing( + envelope: envelope, + computed_subject_digest: computed_subject_digest, + computed_executor_contract_digest: computed_executor_contract_digest, + roster_identities: roster_identities, + evaluated_tree_commit_unix_secs: evaluated_tree_commit_unix_secs + ) + match envelope { + Absent => wet_route_gate_disposition(standing: standing) + Present { value: e } => + match standing { + ReceiptExecutorSnapshotDifferent { receipt_digest: _, computed_digest: _ } => + match wet_seed_bootstrap_admission( + lease: lease, + envelope_digest: envelope_digest, + attempt_seq: e.attempt_seq, + semantic_subject_digest: computed_subject_digest, + roster_digest: roster_digest, + evaluated_tree_commit_unix_secs: evaluated_tree_commit_unix_secs + ) { + BootstrapExecutorSnapshotLeaseAdmitted { + exact_envelope_digest: _, exact_attempt_seq: _, exact_semantic_subject_digest: _, + exact_roster_digest: _, executed_at_unix_secs: _, not_after_unix_secs: n + } => WetFloorAdmittedUnderBootstrapLease { not_after_unix_secs: n } + BootstrapLeaseExpired { detail: _ } => WetFloorRefused { standing: standing } + BootstrapLeaseNotApplicable => WetFloorRefused { standing: standing } + } + ReceiptFreshExactSubject { age_secs: a } => WetFloorAdmittedFresh { age_secs: a } + ReceiptMissing => WetFloorRefused { standing: standing } + ReceiptExpired { age_secs: _ } => WetFloorRefused { standing: standing } + ReceiptSubjectMismatch { axis: _, receipt_digest: _, computed_digest: _ } => + WetFloorRefused { standing: standing } + ReceiptContractMismatch { detail: _ } => WetFloorRefused { standing: standing } + ReceiptRosterInexact { detail: _ } => WetFloorRefused { standing: standing } + } + } +} + +// THE NO-LEASE DOOR, which is every consumer that is not the bootstrap path. It takes NO admission +// argument at all: an executor-different standing refuses here by construction, so the only way to +// reach an admission is through the fused entry above, which derives it from the same envelope. +fn wet_route_gate_disposition(standing: WetLaneReceiptStanding) -> WetFloorGateDisposition { + match standing { + ReceiptFreshExactSubject { age_secs: a } => WetFloorAdmittedFresh { age_secs: a } + ReceiptMissing => WetFloorRefused { standing: standing } + ReceiptExpired { age_secs: _ } => WetFloorRefused { standing: standing } + ReceiptSubjectMismatch { axis: _, receipt_digest: _, computed_digest: _ } => + WetFloorRefused { standing: standing } + ReceiptExecutorSnapshotDifferent { receipt_digest: _, computed_digest: _ } => + WetFloorRefused { standing: standing } + ReceiptContractMismatch { detail: _ } => WetFloorRefused { standing: standing } + ReceiptRosterInexact { detail: _ } => WetFloorRefused { standing: standing } + } +} + +fn wet_route_disposition_blocks_floor(disposition: WetFloorGateDisposition) -> Bool { + match disposition { + WetFloorAdmittedFresh { age_secs: _ } => false + WetFloorAdmittedUnderBootstrapLease { not_after_unix_secs: _ } => false + WetFloorRefused { standing: _ } => true + } +} + +// THE ENVELOPE-LEVEL BLOCKING POLARITY, STATED ONCE, as a read of the canonical disposition +// fold above rather than a second enumeration of the standing (review 57656). This +// projection evaluates the LEASELESS gate — the admission parameter is the terminal +// `BootstrapLeaseNotApplicable`, so a leased envelope is visible only to consumers that +// evaluate `wet_seed_bootstrap_admission` against the envelope's own facts and consume +// `wet_route_gate_disposition` directly (the required floor runner does exactly that). The +// per-identity polarity is `wet_route_identity_rows_block` above, decided from the same +// envelope's rows once the disposition admits. +fn wet_route_standing_blocks_floor(standing: WetLaneReceiptStanding) -> Bool { + wet_route_disposition_blocks_floor(disposition: wet_route_gate_disposition(standing: standing)) +} + +// THE PUBLICATION TRANSACTION (residual B): the two facts a run must observe about ITSELF to +// admit a receipt carrying per-identity reds. Canonical rendering is the reader's +// unconditional wall, and candidate-exactness, contract validity and roster exactness are +// entailed by the standing fold reaching `ReceiptFreshExactSubject` at all — so exactly +// these two conjuncts remain. +type WetReceiptPublicationTransaction = { + diff_confined_to_receipt_namespace: Bool, + attempt_seq_advances: Bool +} + +fn wet_receipt_publication_transaction_valid(t: WetReceiptPublicationTransaction) -> Bool { + t.diff_confined_to_receipt_namespace && t.attempt_seq_advances +} + +// The pull-request polarity: exactly the PER-IDENTITY reds are waived, and only under a +// valid publication transaction — the wall that keeps latest-attempt from decaying into +// latest-success. Both waived classes carry remedies outside the receipt namespace, so a +// receipt-confined refresh PR could not resolve them in the same diff by construction. +// Envelope-level standings are never waived: an expired or mismatched envelope advances +// nothing and blocks a publication PR exactly as it blocks any other run. +fn wet_route_identity_rows_block_with_publication( + unexpected_red: List, + now_passing: List, + no_verdict: List, + cost_debt: List, + publication_transaction_valid: Bool +) -> Bool { + if publication_transaction_valid { + false + } else { + wet_route_identity_rows_block( + unexpected_red: unexpected_red, + now_passing: now_passing, + no_verdict: no_verdict, + cost_debt: cost_debt + ) + } +} + +// THE ROSTER. The self-host behavioral cluster: the seventeen per-module seed-linked +// behavioral receipts (config authority +// `tools.self_host_module_behavioral_transport_roster`; kernel +// `tools.self_host_curated_seed_linked_harness`) and the six artifact-materialization +// real-execution claims. Each row was route_gap_held on main's required floor at enrollment +// (operation Dir, ground NoMockResponse — the first link of the chain, measured, not read), +// and each leaves `floor_route_gap` in the same change that lands here. +// +// An identity may be enrolled here or in `floor_route_gap`, never both: this roster asserts +// the identity does not execute hermetically at all, the other asserts its hermetic +// execution gaps — both cannot be true of one run. The route-gap wall stays live for +// everything NOT routed, so this roster cannot quietly widen into a skip list. +fn floor_wet_route_roster() -> List { + [ + WetRouteRow { identity: "test.claim.self_host_00_compile_behavioral_witness.self_host_00_compile_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_00_compile_behavioral_witness_test.dag", function: "self_host_00_compile_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_01_tokenize_behavioral_witness.self_host_01_tokenize_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_01_tokenize_behavioral_witness_test.dag", function: "self_host_01_tokenize_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_02_parse_behavioral_witness.self_host_02_parse_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_02_parse_behavioral_witness_test.dag", function: "self_host_02_parse_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_03_ingest_behavioral_witness.self_host_03_ingest_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_03_ingest_behavioral_witness_test.dag", function: "self_host_03_ingest_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_03_normalize_behavioral_witness.self_host_03_normalize_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_03_normalize_behavioral_witness_test.dag", function: "self_host_03_normalize_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_03_resolve_behavioral_witness.self_host_03_resolve_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_03_resolve_behavioral_witness_test.dag", function: "self_host_03_resolve_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_04_infer_behavioral_witness.self_host_04_infer_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_04_infer_behavioral_witness_test.dag", function: "self_host_04_infer_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_body_producer_behavioral_witness.self_host_body_producer_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_body_producer_behavioral_witness_test.dag", function: "self_host_body_producer_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_discovery_enumeration_behavioral_witness.self_host_discovery_enumeration_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_discovery_enumeration_behavioral_witness_test.dag", function: "self_host_discovery_enumeration_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_logic_behavioral_witness.self_host_logic_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_logic_behavioral_witness_test.dag", function: "self_host_logic_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_materialization_carriers_behavioral_witness.self_host_materialization_carriers_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_materialization_carriers_behavioral_witness_test.dag", function: "self_host_materialization_carriers_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_parse_engine_hooks_behavioral_witness.self_host_parse_engine_hooks_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_parse_engine_hooks_behavioral_witness_test.dag", function: "self_host_parse_engine_hooks_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_program_assembly_behavioral_witness.self_host_program_assembly_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_program_assembly_behavioral_witness_test.dag", function: "self_host_program_assembly_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_program_partition_behavioral_witness.self_host_program_partition_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_program_partition_behavioral_witness_test.dag", function: "self_host_program_partition_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_source_authority_behavioral_witness.self_host_source_authority_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_source_authority_behavioral_witness_test.dag", function: "self_host_source_authority_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_target_carriers_behavioral_witness.self_host_target_carriers_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_target_carriers_behavioral_witness_test.dag", function: "self_host_target_carriers_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_use_site_verdict_behavioral_witness.self_host_use_site_verdict_behavioral_receipt_holds", entry_rel: "dag/test/claim/self_host_use_site_verdict_behavioral_witness_test.dag", function: "self_host_use_site_verdict_behavioral_receipt_holds" }, + WetRouteRow { identity: "test.claim.self_host_artifact_materialization_real_execution_witness.a_real_cargo_build_materializes_through_the_real_digest", entry_rel: "dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag", function: "a_real_cargo_build_materializes_through_the_real_digest" }, + WetRouteRow { identity: "test.claim.self_host_artifact_materialization_real_execution_witness.the_materialized_path_is_the_one_the_real_cargo_stream_named", entry_rel: "dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag", function: "the_materialized_path_is_the_one_the_real_cargo_stream_named" }, + WetRouteRow { identity: "test.claim.self_host_artifact_materialization_real_execution_witness.a_target_the_build_never_produced_refuses_and_does_not_materialize", entry_rel: "dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag", function: "a_target_the_build_never_produced_refuses_and_does_not_materialize" }, + WetRouteRow { identity: "test.claim.self_host_artifact_materialization_real_execution_witness.the_digest_is_of_the_file_cargo_named_not_of_some_other_real_file", entry_rel: "dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag", function: "the_digest_is_of_the_file_cargo_named_not_of_some_other_real_file" }, + WetRouteRow { identity: "test.claim.self_host_artifact_materialization_real_execution_witness.changing_only_the_source_bytes_names_exactly_the_artifact_axis", entry_rel: "dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag", function: "changing_only_the_source_bytes_names_exactly_the_artifact_axis" }, + WetRouteRow { identity: "test.claim.self_host_artifact_materialization_real_execution_witness.rebuilding_identical_source_in_place_moves_no_axis", entry_rel: "dag/test/claim/self_host_artifact_materialization_real_execution_witness_test.dag", function: "rebuilding_identical_source_in_place_moves_no_axis" } + ] +} + +fn floor_wet_route_identities() -> List { + floor_wet_route_roster() |> map(row => row.identity) +} + +// Membership at identity grain, the shape `floor_cost_debt_holds` established: the site +// disposition asks this once per offered identity. +fn floor_wet_route_holds(name: String) -> Bool { + contains(xs: floor_wet_route_identities(), item: name, eq: string_eq) +} diff --git a/src/v2/workflow/required_floor.dag b/src/v2/workflow/required_floor.dag index e818efb7da8..cb6c2acb31a 100644 --- a/src/v2/workflow/required_floor.dag +++ b/src/v2/workflow/required_floor.dag @@ -23,6 +23,7 @@ import v2.workflow.floor_terminal_ledger { } import v2.workflow.floor_route_gap { floor_route_gap_roster } import v2.workflow.floor_cost_debt { floor_cost_debt_roster, floor_cost_debt_holds } +import v2.workflow.floor_wet_route { floor_wet_route_holds } import v2.workflow.local_repo_wet_terminal { local_repo_wet_schedule } import std.dissolution { DissolutionCondition, unbound_dissolution } import std.nat { Nat } @@ -113,18 +114,33 @@ type RequiredFloorDisposition = | DeclinedOutsideGateClosure | DeclinedDiscoveryExcluded { matched_substring: String } | DeclinedCostDebt + | DeclinedRoutedToWetLane // The changed-witness sublane is a second selector over the SAME identity-grain disposition, // not a widening of `required_gate_prefixes` and not a terminal row beside a decline. Selection // therefore replaces the static gate's answer with one planned arm before execution; every // identity still has exactly one disposition and the ordinary answer is preserved unchanged for -// the standing population. +// the standing population. ONE ARM IS PRESERVED EVEN WHEN SELECTED: `DeclinedRoutedToWetLane` +// asserts the identity's subject is a real host-effect chain the hermetic route refuses by +// construction (`v2.workflow.floor_wet_route`), so planning a changed wet-routed identity here +// would manufacture a route-gap red rather than execute it. Its changed-set verdict comes from +// the candidate-exact wet receipt admission in `floor_changed_witness` instead. fn required_floor_disposition_with_changed_selection( ordinary: RequiredFloorDisposition, selected_as_changed_witness: Bool, ) -> RequiredFloorDisposition { if selected_as_changed_witness { - PlannedAsChangedWitness {} + match ordinary { + DeclinedRoutedToWetLane => ordinary + Planned => PlannedAsChangedWitness {} + PlannedAsChangedWitness => PlannedAsChangedWitness {} + DeclinedLongModule { matched_prefix: _ } => PlannedAsChangedWitness {} + DeclinedFixtureMember { matched_prefix: _ } => PlannedAsChangedWitness {} + DeclinedOutsideRequiredGate => PlannedAsChangedWitness {} + DeclinedOutsideGateClosure => PlannedAsChangedWitness {} + DeclinedDiscoveryExcluded { matched_substring: _ } => PlannedAsChangedWitness {} + DeclinedCostDebt => PlannedAsChangedWitness {} + } } else { ordinary } @@ -227,6 +243,7 @@ fn cost_debt_roster_standing(reading: CostDebtDispositionReading) -> CostDebtRos DeclinedLongModule { matched_prefix: _ } => CostDebtDeclaredButNotWithheld {} DeclinedFixtureMember { matched_prefix: _ } => CostDebtDeclaredButNotWithheld {} DeclinedOutsideRequiredGate => CostDebtDeclaredButNotWithheld {} + DeclinedRoutedToWetLane => CostDebtDeclaredButNotWithheld {} } } } @@ -696,9 +713,13 @@ fn required_floor_site_disposition( if floor_cost_debt_holds(name: identity) { DeclinedCostDebt {} } else { - match first_module_prefix_match(module_path: module_path, prefixes: required_gate_prefixes()) { - ModulePrefixUnmatched => DeclinedOutsideRequiredGate {} - ModulePrefixMatched { prefix: _ } => Planned {} + if floor_wet_route_holds(name: identity) { + DeclinedRoutedToWetLane {} + } else { + match first_module_prefix_match(module_path: module_path, prefixes: required_gate_prefixes()) { + ModulePrefixUnmatched => DeclinedOutsideRequiredGate {} + ModulePrefixMatched { prefix: _ } => Planned {} + } } } }