--- fp-driver-d2.sh 2026-09-13 00:08:57.520941000 -0700 +++ fp-driver-d2-r2.sh 2026-09-13 01:40:21.961816800 -0700 @@ -126,25 +126,46 @@ SP='C:/Users/decid/AppData/Local/Temp/claude/C--Users-decid-Documents-projects-spt-core/909af448-f4ab-4fa1-ba30-02e38b275a11/scratchpad/bundle-r5' BIN="$SP/fp-bin" # INSTRUMENTS — never written to by a run RUN_ROOT="$SP/fp-run" # one timestamped subdir per run -H="$SP/fp-home-d2-a2" # isolated SPT_HOME, THIS ATTEMPT only. fp-home-d2 belongs to - # the RETAINED failed run and is PRESERVED, not reused or - # cleared: a run that adopted it could not tell its own state - # from that run's, and the evidence of a failure is not scratch - # space (doyle K4QDUUVV). The pre-existence refusal below is - # KEPT unchanged and now bites on a prior ATTEMPT of this - # successor rather than on anyone else's evidence. EARLIER: - # r10 left a populated fp-home beside this one (measured - # present, 10 entries), and a run that adopted it could not - # tell its own state from r10's. The name is fresh so S0b's - # pre-existence refusal -- which is KEPT, unchanged -- bites - # on a prior D2 run rather than on r10's evidence, and - # nothing here reads, writes or removes r10's home. -EXE="$W/target/release/spt.exe" # THE EXECUTABLE r10 ALREADY BUILT. Nothing here builds. +# ---- THE PROVISIONED RIG (doyle W4C2QFLE) ----------------------------------- +# THE HOME IS NO LONGER THIS DRIVER'S TO CREATE. The LAN-bootstrap set gate refuses a fresh +# home BEFORE any firewall admission is attempted (lanhost.rs:184-213 -> LanRefused -> +# serveverb.rs:260; report_lan_admission, which is what reaches the firewall, sits only on the +# Ok arm at :247), so a run whose home was empty could never create the pair it exists to +# measure. Provisioning is therefore a SEPARATE MUTATING PHASE with its own grant -- see +# provision-rig.sh -- and this driver only ever VERIFIES and CONSUMES what that phase produced. +# +# ONE DISPOSABLE EXECUTABLE PATH FOR EVERY ROLE (todlando's constraint), and it is structural +# rather than a convention to remember: the daemon is spawned from std::env::current_exe() +# (daemon.rs:874) and the brain from that supervisor, so invoking ONLY $EXE makes the CLI, the +# supervisor and the brain the same path by construction. +# +# AN EMPTY PIN IS NOT A MISSING SETTING. It is this run stating that it has no provisioned rig, +# exactly as TEARDOWN_B64_SHA256 states it has no authorized removal command. +RIG_ROOT='' # /rig, written by provision-rig.sh. UNPINNED here. +H="$RIG_ROOT/home" # the PROVISIONED isolated SPT_HOME: identity/ (the rig trust + # key), releases/ (the staged set AND the applied record). + # PRIOR HOMES ARE STILL NEVER REUSED OR CLEARED: fp-home-d2 + # and fp-home-d2-a2 belong to retained runs and are preserved + # as their evidence. A rig is ONE ATTEMPT -- S0b consumes this + # one atomically and a second run gets a refusal, not a reuse. +EXE="$RIG_ROOT/bin/spt.exe" # A COPY of the subject, taken by provisioning and hashed + # there. NEVER the worktree build itself and NEVER the fleet + # installation: `update apply` replaces the executable it is + # running, so either of those would be overwritten by the very + # step that makes the gate passable. The copy is what makes + # the apply disposable. Its sha is UNCHANGED from the subject + # r10 built -- a copy that does not hash to EXE_SHA is a + # different subject and S0b refuses it. EXE_SHA='72d309011415b419aabfdb0b4065df1183bfd0069a9f95b5779da62e43349b10' # THE CAPTURE SCRIPT IS A SUBJECT TOO (doyle LIRX7EUS). The elevated leg runs BOTH the product # and this script, and every document this run reasons about is whatever THIS file produced. # An acknowledgment that measures only the executable proves the leg can see one of the two. -CAPTURE_SHA='a0e7afbee4dce9f310ade9704c199b3b759715c06da7e033d286beb7cfda8c06' +# INTEGRATED 2026-09-13 (doyle W4C2QFLE): the capture successor. Its EXIT CONTRACT is five +# values, not three, and every record line below that names them says all five -- a 4 or a 5 +# reaching the ledger as an unlabelled nonzero is the coupled defect this integration closes. +# predecessor chain, every link hash-verified in history/: +# a0e7afbe -> af29bbb3 -> 010666e7 -> 69b8506a (all PRESERVED; none replaced) +CAPTURE_SHA='69b8506ac932841223996e7d5ad5ab03a51662ce4eacc6da77dad458a03f620c' PORT=29470 # never 5470 GUARD_PORT=5470 # the production port this run must not disturb SUBJECT_SHA='85f84d738fa702f35c83910f314aae17849d125c' @@ -177,6 +198,21 @@ HANDOFF_WAIT_S=900 # bounded wait for a liam receipt; narrowed at the point of # waiting to what remains of the experimental budget CLEANUP_HANDOFF_WAIT_S=300 # likewise narrowed to what remains of the reporting deadline +# ---- F5 r2.2 BOUNDS (doyle CT6GS2Y6 / O2VBV5LC / B3CMWRQI) ------------------ +# Three constants the predecessor did not have. Each answers a defect the 20260913T071131Z +# run exhibited, and NONE of them is a duration estimate: +# LEDGER_RESERVE_S the report cannot be starved by the work before it. Every cleanup step +# is bounded by WORK_DEADLINE = REPORT_DEADLINE - this; the ledger owns +# the remainder ALONE and emits without waiting for any child. +# KILL_GRACE_S `timeout -k N` TERMs at the bound and KILLs N seconds later, so a bound +# of `deadline - now` overruns its own deadline by N. Every bound +# subtracts it, so TERM+KILL completes BY the deadline. +# HANDOFF_CAP_S a POLICY ALLOCATION of the activity window -- how much of the 300s this +# run will spend waiting on another agent. 94s and 134s are two samples, +# not a distribution, and nothing here is derived from them. +LEDGER_RESERVE_S=30 +KILL_GRACE_S=5 +HANDOFF_CAP_S=120 # THE TEARDOWN COMMAND IS PINNED, NEVER COMPOSED (doyle 2026-09-13). The removal this run may # need is the PRODUCT'S OWN rendered cleanup command, which only the shipped binary can emit. # Until it has been emitted, decoded, reviewed and pinned here, cleanup REFUSES to dispatch any @@ -218,6 +254,9 @@ TEARDOWN_PIN_STATE=UNCHECKED # set by teardown_pin_verify; reported whatever it says CI_REPO='BigscreenVR/spt-bs-core' # the CODE repo (D3). Issues live elsewhere. PREP_EPOCH=$(date +%s) # the PREPARATION clock starts at process start +PREP_DEADLINE=$((PREP_EPOCH + PREP_BUDGET_S)) # the instant preparation is over; every + # bounded preflight probe runs under THIS one, so a + # pre-GO step cannot be handed a window that has not opened RUN_EPOCH='' # THE EXPERIMENTAL CLOCK DOES NOT EXIST UNTIL GO, and an unset # clock is an UNSTARTED experiment: every activity step refuses # while it is empty. MEASURED REASON (run 20260913T041410Z): @@ -442,9 +481,10 @@ # ---- 5470 preservation: FIELDS, and diff's three distinct answers (F3/F6) -- guard_snapshot() { # TAG - pwsh -NoProfile -File "$BIN/portfields.ps1" -Tag "$1" -OutDir "$R" -Port "$GUARD_PORT" >> "$R/portfields.log" 2>&1 + bounded "portfields_${GUARD_PORT}_$1" "$(cur_deadline)" "$R/.guard.out" "$R/.guard.err" -- \ + pwsh -NoProfile -File "$BIN/portfields.ps1" -Tag "$1" -OutDir "$R" -Port "$GUARD_PORT" local rc=$? - exits "portfields_${GUARD_PORT}_$1_EXIT=$rc" + cat "$R/.guard.out" "$R/.guard.err" >> "$R/portfields.log" 2>/dev/null if [ "$rc" -ne 0 ]; then return 1; fi grep -q "tag=$1 .* valid=YES" "$R/portfields.log" || return 1 return 0 @@ -615,6 +655,13 @@ # while a residual-identity authorization is outstanding, cleanup stays PENDING and the # identities are reported for the next consumer to act on. CLEANUP_EPOCH=0 +# THE DEADLINE INSTANTS. A remaining-seconds helper answers 'how long may this step run'; +# an INSTANT answers 'by when must it be over', and only the second can be handed to a +# sequence of queries without each one silently re-granting itself the rest of the budget. +EXP_DEADLINE=0 # RUN_EPOCH + EXP_BUDGET_S, set at go() +REPORT_DEADLINE=0 # CLEANUP_EPOCH + CLEANUP_REPORT_S, set at end_experimental() +WORK_DEADLINE=0 # REPORT_DEADLINE - LEDGER_RESERVE_S, same place +SETUP_COMPLETION=UNPROVEN # R6: proven only by a run-bound receipt with terminal fields CLEANUP_STOP_STATE=NOT_REACHED # which gate outcome step 1 took (IR-124) TEARDOWN_DISPATCH=NOT_REACHED # whether a teardown command was dispatched, and why not REMOVAL_CHECK=NOT_REACHED # the INDEPENDENT reading, by name and by store @@ -777,6 +824,195 @@ [ "$left" -lt 0 ] && left=0 echo "$left" } +# ---- bounded(): the ONLY enforced bound, and it MEASURES what it stopped ----- +# THE PREDECESSOR ENFORCED NOTHING EXCEPT THE CAPTURES. deadline_check fired at two sites in +# the whole 20260913T071131Z run, and 271 of the 300 seconds ran with no budget read at all: +# a budget checked BETWEEN steps bounds a sequence, not a process. +# +# FOUR THINGS, NOT ONE, and each is a correction doyle made to my first proposal: +# 1. the bound subtracts KILL_GRACE_S, so TERM-then-KILL completes BY the deadline rather +# than five seconds past it, and a step that cannot cover the grace is NOT STARTED; +# 2. the child is REGISTERED BEFORE it can finish, and the register distinguishes the msys +# WRAPPER from the NATIVE child -- they are different processes with different pids, and +# the one bash hands back is the wrapper while the one that may survive is the child; +# 3. on expiry the driver MEASURES what stopped instead of assuming it. `timeout` sends TERM +# to a native Windows process that owes it no POSIX answer, and that process's descendants +# are in no job object the kill reaches. A read-only command still leaves a process; +# 4. whatever the killed step wrote is PRESERVED under a name that says it is unverified. +# An expired bound says the COMPLETION is unverified; it says nothing about the disk. +# +# NOTHING HERE KILLS ANYTHING THIS DRIVER DID NOT SPAWN, and nothing here acquires an +# authority over an elevated leg. Stopping a wait and stopping an operation are different acts. +BOUNDED_STATE=NOT_REACHED # the outcome of the most recent bounded() call +LAUNCH_SEQ=0 +launch_file() { echo "$R/launched-identities.txt"; } +# The WINPID behind an msys pid. `ps` is an msys builtin-class probe over msys's own table: +# it costs no CIM query and it is the only place the mapping exists. An unmappable pid is +# recorded as UNREADABLE -- never as 'the wrapper had no child'. +winpid_of() { # MSYS_PID -> WINPID | UNREADABLE + local p="$1" w + w=$(ps -p "$p" 2>/dev/null | awk -v p="$p" '$1==p {print $4}' | head -1) + case "$w" in (''|*[!0-9]*) echo UNREADABLE ;; (*) echo "$w" ;; esac +} +# ONE bounded CIM query for the children of a live wrapper. It runs WHILE the wrapper is alive +# because that is the only moment the parent link exists: after `timeout` returns, a survivor +# has no edge back to anything this run can name. +register_launched() { # LABEL MSYS_PID DEADLINE + local label="$1" mpid="$2" dl="$3" lf; lf=$(launch_file) + LAUNCH_SEQ=$((LAUNCH_SEQ + 1)) + local wp; wp=$(winpid_of "$mpid") + local now; now=$(date -u +%Y-%m-%dT%H:%M:%SZ) + echo "LAUNCHED seq=$LAUNCH_SEQ label=$label kind=wrapper msys_pid=$mpid winpid=$wp launched=$now" >> "$lf" + if [ "$wp" = UNREADABLE ]; then + echo "LAUNCHED seq=$LAUNCH_SEQ label=$label kind=native state=ATTRIBUTION_INCOMPLETE reason=wrapper-winpid-unreadable" >> "$lf" + record " LAUNCH($label) the wrapper's WINPID could not be read: the native child is ATTRIBUTION_INCOMPLETE, which is NOT a statement that it is gone" + return 0 + fi + local q_left=$(( dl - $(date +%s) )) + [ "$q_left" -gt 3 ] || { + echo "LAUNCHED seq=$LAUNCH_SEQ label=$label kind=native state=ATTRIBUTION_INCOMPLETE reason=no-budget-for-descendant-query" >> "$lf" + return 0 + } + [ "$q_left" -gt 10 ] && q_left=10 + SPT_D2_WP="$wp" timeout -k 2 "$q_left" pwsh -NoProfile -Command ' + $p = [int]$env:SPT_D2_WP + try { $kids = @(Get-CimInstance Win32_Process -Filter "ParentProcessId=$p" -ErrorAction Stop) } + catch { "QUERY=UNREADABLE reason=enumeration-failed"; exit 0 } + if ($kids.Count -eq 0) { "QUERY=NO_CHILD"; exit 0 } + foreach ($k in $kids) { + $c = try { $k.CreationDate.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ") } catch { "UNREADABLE" } + "CHILD pid=$($k.ProcessId) created=$c exe=[$($k.ExecutablePath)]" + } + ' > "$R/.launch-q.$LAUNCH_SEQ" 2>&1 + local qrc=$? + if [ "$qrc" -ne 0 ] || grep -q '^QUERY=UNREADABLE' "$R/.launch-q.$LAUNCH_SEQ" 2>/dev/null; then + echo "LAUNCHED seq=$LAUNCH_SEQ label=$label kind=native state=ATTRIBUTION_INCOMPLETE reason=descendant-query-unreadable(rc=$qrc)" >> "$lf" + return 0 + fi + if grep -q '^QUERY=NO_CHILD' "$R/.launch-q.$LAUNCH_SEQ" 2>/dev/null; then + # A CHILD THAT EXITED BEFORE REGISTRATION IS NOT CONFIRMED GONE (doyle B3CMWRQI). An + # absence at the moment of registration is the absence of a READING, not a reading of an + # absence; only a registered pid re-queried and measured absent is the second thing. + echo "LAUNCHED seq=$LAUNCH_SEQ label=$label kind=native state=ATTRIBUTION_INCOMPLETE reason=no-child-at-registration wrapper_winpid=$wp" >> "$lf" + return 0 + fi + while IFS= read -r line; do + case "$line" in + CHILD\ *) echo "LAUNCHED seq=$LAUNCH_SEQ label=$label kind=native ${line#CHILD } parent_winpid=$wp" >> "$lf" ;; + esac + done < "$R/.launch-q.$LAUNCH_SEQ" + return 0 +} +# What actually stopped. Re-queries THIS call's registered native rows by pid AND creation +# instant -- pid reuse on this box is measured, so a pid answering with a different creation +# time is a DIFFERENT process and ours is gone. +measure_termination() { # LABEL SEQ DEADLINE -> sets TERMINATION + local label="$1" seq="$2" dl="$3" lf; lf=$(launch_file) + TERMINATION=UNREADABLE + local rows; rows=$(grep "^LAUNCHED seq=$seq .* kind=native pid=" "$lf" 2>/dev/null) + if [ -z "$rows" ]; then + TERMINATION=ATTRIBUTION_INCOMPLETE + record " TERMINATION($label)=ATTRIBUTION_INCOMPLETE — no native identity was registered for this launch, so nothing can be re-queried. This is NOT 'confirmed gone'." + return + fi + local q_left=$(( dl - $(date +%s) )) + if [ "$q_left" -le 3 ]; then + TERMINATION=UNREADABLE + record " TERMINATION($label)=UNREADABLE — no budget remained to re-query the registered identities. UNREADABLE is never CLEAR." + return + fi + [ "$q_left" -gt 10 ] && q_left=10 + local live=0 gone=0 unread=0 p c now_c + while IFS= read -r r; do + p=$(echo "$r" | sed -n 's/.*[ ]pid=\([0-9]*\).*/\1/p') + c=$(echo "$r" | sed -n 's/.*[ ]created=\([^ ]*\).*/\1/p') + [ -n "$p" ] || continue + now_c=$(SPT_D2_P="$p" timeout -k 2 "$q_left" pwsh -NoProfile -Command ' + $p = [int]$env:SPT_D2_P + try { $x = @(Get-CimInstance Win32_Process -Filter "ProcessId=$p" -ErrorAction Stop) } + catch { "UNREADABLE"; exit 0 } + if ($x.Count -eq 0) { "GONE"; exit 0 } + try { $x[0].CreationDate.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ") } catch { "UNREADABLE" } + ' 2>/dev/null | tr -d ' \r\n') + case "$now_c" in + GONE) gone=$((gone + 1)) ;; + UNREADABLE|'') unread=$((unread + 1)) ;; + "$c") live=$((live + 1)); record " TERMINATION($label) SURVIVING pid=$p created=$c — the bound expired and this process did not" ;; + *) gone=$((gone + 1)) ;; # same pid, different creation instant: reuse, ours is gone + esac + done </dev/null | tr -d ' ') + sha=$(sha256sum "$f" 2>/dev/null | cut -d' ' -f1) + cp -p "$f" "$f.unverified" 2>/dev/null \ + && record " UNVERIFIED($label) $f preserved as $f.unverified bytes=$sz sha256=$sha — completion is UNVERIFIED; the artifact state is a fact to be INSPECTED, not inferred" \ + || record " UNVERIFIED($label) $f could NOT be preserved (bytes=$sz sha256=$sha) — the original is left exactly where it is and nothing is deleted" + done +} +# THE OUTPUT PATHS ARE PARAMETERS, NOT A REDIRECTION AT THE CALL SITE (r10's defect, and it +# cost IR-123 an unpassable gate): `record` TEES TO STDOUT, so `bounded ... > file` would file +# this function's own log lines into the subject's output. run_cmd already takes OUT and ERR +# for exactly this reason, and this helper keeps the same shape. +# WHICH DEADLINE A STEP IS UNDER IS A PROPERTY OF THE PHASE, NOT OF THE CALL SITE. One +# helper answers it, so a probe called from preparation, from the window and from cleanup +# cannot silently re-grant itself the wrong budget -- which is exactly what a remaining-seconds +# reading does when the clock it reads has not started. +cur_deadline() { + if [ -z "$RUN_EPOCH" ]; then echo "$PREP_DEADLINE" + elif [ "$CLEANUP_EPOCH" -eq 0 ]; then echo "$EXP_DEADLINE" + else echo "$WORK_DEADLINE"; fi +} +bounded() { # LABEL DEADLINE_EPOCH OUT ERR -- COMMAND... + local label="$1" dl="$2" out="$3" err="$4"; shift 4 + if [ "$1" = '--' ]; then shift; else + record "HARNESS_BUG bounded '$label' called without --"; exits "${label}_HARNESS=bad-call"; BOUNDED_STATE=HARNESS_BUG; return 90 + fi + if ! : > "$out" 2>/dev/null || ! : > "$err" 2>/dev/null; then + record "CAPTURE_SETUP_FAILED $label out=$out err=$err"; exits "${label}_CAPTURE=SETUP_FAILED"; BOUNDED_STATE=SETUP_FAILED; return 91 + fi + BOUNDED_STATE=NOT_REACHED + TERMINATION=NOT_MEASURED + case "$dl" in (''|*[!0-9]*) dl=0 ;; esac + local now left; now=$(date +%s); left=$(( dl - now - KILL_GRACE_S )) + if [ "$dl" -le 0 ] || [ "$left" -lt 1 ]; then + BOUNDED_STATE=NOT_STARTED + exits "${label}_BOUND=NOT_STARTED" + record "BOUND_NOT_STARTED $label — ${left}s would remain after the ${KILL_GRACE_S}s escalation reserve. The step is NOT RUN." + record " TRUNCATED phase=$label got 0s. What it would have observed is NOT CAPTURED, which is not the statement 'not present'." + return 125 + fi + stamp "${label}_START bound=${left}s deadline_epoch=$dl" + timeout -k "$KILL_GRACE_S" "$left" "$@" > "$out" 2> "$err" & + local mpid=$! + local myseq + register_launched "$label" "$mpid" "$dl" + myseq="$LAUNCH_SEQ" + wait "$mpid"; local rc=$? + stamp "${label}_END rc=$rc" + exits "${label}_EXIT=$rc" + if [ "$rc" -eq 124 ] || [ "$rc" -eq 137 ]; then + BOUNDED_STATE=EXPIRED + record "BOUND_EXPIRED $label after ${left}s (killer rc=$rc). The bound stopped THIS DRIVER'S WAIT and attempted to stop the operation; what actually stopped is measured below." + measure_termination "$label" "$myseq" "$dl" + return 124 + fi + BOUNDED_STATE=RAN + return $rc +} cleanup_left() { [ "$CLEANUP_EPOCH" -eq 0 ] && { echo "$CLEANUP_REPORT_S"; return; } local now used left @@ -812,6 +1048,7 @@ go() { # WHY [ -n "$RUN_EPOCH" ] && { record "GO ignored - the experimental window is already open (opened $GO_UTC)"; return 0; } RUN_EPOCH=$(date +%s) + EXP_DEADLINE=$((RUN_EPOCH + EXP_BUDGET_S)) GO_UTC=$(date -u +%Y-%m-%dT%H:%M:%SZ) stamp "experimental_GO why=$1" record "GO ($1) at $GO_UTC - the ${EXP_BUDGET_S}s experimental window OPENS NOW, after $((RUN_EPOCH - PREP_EPOCH))s of preparation of the ${PREP_BUDGET_S}s allowed" @@ -820,6 +1057,9 @@ [ -n "$EXPERIMENTAL_ENDED" ] && return 0 EXPERIMENTAL_ENDED="$1" CLEANUP_EPOCH=$(date +%s) + REPORT_DEADLINE=$((CLEANUP_EPOCH + CLEANUP_REPORT_S)) + WORK_DEADLINE=$((REPORT_DEADLINE - LEDGER_RESERVE_S)) + record "REPORTING_DEADLINES report_due=$REPORT_DEADLINE work_until=$WORK_DEADLINE (${LEDGER_RESERVE_S}s is RESERVED for the ledger and is not available to the work above it)" stamp "experimental_END why=$1" if [ -n "$RUN_EPOCH" ]; then record "EXPERIMENTAL_END ($1) at $((CLEANUP_EPOCH - RUN_EPOCH))s of the ${EXP_BUDGET_S}s budget; the ${CLEANUP_REPORT_S}s cleanup REPORTING deadline starts now" @@ -883,23 +1123,44 @@ cmd="$cmd -ControlRuleName '$CONTROL_RULE' -AbsentControlName '$ABSENT_CONTROL'" cmd="$cmd -PreSetupAbsence '$PRE_SETUP_ABSENCE' -SetupIntervalStart '$SETUP_START_UTC' -SetupIntervalEnd '$SETUP_END_UTC'" cmd="$cmd; exit \$LASTEXITCODE" - stamp "d2_${point}_START bound=${bound}s" - timeout -k 5 "$bound" \ - powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "$cmd" \ - > "$R/d2-$point-capture.out" 2> "$R/d2-$point-capture.err" + # THE DEADLINE, NOT A DURATION. The point's own 180s cap (plan §4) stays and becomes the + # earlier of two instants; bounded() subtracts the escalation reserve from whichever wins, + # so TERM-then-KILL completes BY the deadline instead of five seconds past it. + local dl cap; dl=$(cur_deadline); cap=$(( $(date +%s) + bound )) + [ "$cap" -lt "$dl" ] && dl="$cap" + bounded "d2_${point}_capture" "$dl" "$R/d2-$point-capture.out" "$R/d2-$point-capture.err" -- \ + powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "$cmd" local rc=$? + if [ "$rc" -eq 125 ]; then + echo "NO_BUDGET" > "$exf" + record "D2($point) NOT RUN — the remaining budget could not cover the ${KILL_GRACE_S}s escalation reserve. NOT CAPTURED is not 'not present'." + return 1 + fi if [ "$rc" -eq 124 ] || [ "$rc" -eq 137 ]; then echo "TIMEOUT" > "$exf" - stamp "d2_${point}_END rc=TIMEOUT bound=${bound}s" - exits "d2_${point}_capture_EXIT=TIMEOUT(${rc})" - record " D2($point) the bound escalated TERM then KILL (timeout -k 5). A capture that somehow survived carries -IsolatedHome '$H' on its command line, so BY CONSTRUCTION it is counted by the residual-identity probe in cleanup, and a survivor there blocks CLEANUP=VERIFIED." - record "D2($point) CAPTURE_TIMEOUT after ${bound}s (killer rc=$rc) — the process did not return. This is NEITHER a written document NOR a write failure: the observation was not made, and whatever is or is not on disk at $out is not a capture." + # COMPLETION UNVERIFIED IS NOT AN ABSENT DOCUMENT (doyle O2VBV5LC). The serialize, the + # JSON write and the base64 write are separate stages in 69b8506a; an expired bound can + # land anywhere among them, so the artifact state is INSPECTED, never inferred from the + # expiry. Both paths are preserved under names that say so, and neither is read here. + preserve_unverified "d2_${point}_capture" "$out" "$out.b64" + record "D2($point) CAPTURE_COMPLETION=UNVERIFIED after the bound expired (killer rc=$rc). The OBSERVATION was not completed; what is on disk at $out is a separate question, preserved above and not answered here." + # THE SURVIVOR IS FOUND BY ITS REGISTERED IDENTITY, NOT BY A STRING. The predecessor said a + # survivor "carries -IsolatedHome on its command line, so BY CONSTRUCTION it is counted" -- + # that predicate is exactly the one the r10 residuals defeated (they ran `daemon run + # --detached` and `daemon brain`, neither carrying the home). bounded() registered this + # child's pid and creation instant at launch, and cleanup re-queries THAT. + record " D2($point) TERMINATION=$TERMINATION (measured, not assumed; see launched-identities.txt). A SURVIVING or UNREADABLE outcome blocks CLEANUP=VERIFIED." return 124 fi echo "$rc" > "$exf" stamp "d2_${point}_END rc=$rc" exits "d2_${point}_capture_EXIT=$rc" - record "D2($point) native_exit=$rc out=d2-$point.json (0=document written, 2=could not write, 3=arguments rejected; a document full of DENIED states IS a capture)" + # THE EXIT CONTRACT OF 69b8506a, ALL FIVE VALUES (the coupled change this integration owed; + # the predecessor's line knew only 0/2/3, so a 4 or a 5 reached the ledger as an unlabelled + # nonzero). NEITHER 2 NOR ANY OTHER CODE ASSERTS THE ARTIFACT STATE: exit 2 names the STAGE + # that failed (D2_WRITE_FAILED_JSON / D2_WRITE_FAILED_B64) and the file may be absent, + # partial, or a pre-existing one -- that requires inspection. + record "D2($point) native_exit=$rc out=d2-$point.json (0=written AND read back and verified; 2=SERIALIZATION or a WRITE failed, stage named, artifact state NOT asserted; 3=arguments rejected; 4=written, receipt digest not takeable, NONZERO ON PURPOSE; 5=written, read-back digest disagrees with the bytes written. A document full of DENIED states IS a capture.)" # A ZERO IS NOT A CAPTURE. Measured on this box: `-Command "& '' ...; exit $LASTEXITCODE"` # with a path PowerShell cannot resolve prints CommandNotFoundException and still hands the # caller EXIT 0 -- a clean zero from a command that never ran. So the document's existence is @@ -975,7 +1236,8 @@ # that as UNREADABLE rather than as an empty list. capture_run_identities() { # WHEN local when="$1" - SPT_D2_HOME="$H" pwsh -NoProfile -Command ' + bounded "identity_capture_$when" "$(cur_deadline)" "$R/run-identities.txt" "$R/run-identities.err" -- \ + env SPT_D2_HOME="$H" pwsh -NoProfile -Command ' $h = $env:SPT_D2_HOME $pidFile = Join-Path $h "daemon.pid" if (-not (Test-Path $pidFile)) { "IDENT_PROBE=UNREADABLE reason=no-pid-file"; exit 0 } @@ -997,10 +1259,13 @@ $i++ } "IDENT_PROBE=OK tracked=$($rows.Count)" - ' > "$R/run-identities.txt" 2>&1 + ' local rc=$? IDENT_CAPTURE_RC=$rc - exits "identity_capture_${when}_EXIT=$rc" + # A BOUND THAT EXPIRED HERE IS THE WORST ONE TO MISREAD: cleanup can only re-query an + # identity somebody wrote down, so an expired identity capture makes the run's residue + # UNREADABLE -- which is never CLEAR -- rather than making the host empty. + cat "$R/run-identities.err" >> "$R/run-identities.txt" 2>/dev/null while IFS= read -r line; do record " IDENTITY($when) $line"; done < "$R/run-identities.txt" local n n=$(grep -c '^IDENT role=' "$R/run-identities.txt" 2>/dev/null) @@ -1235,6 +1500,48 @@ end_experimental "cleanup entered" record "CLEANUP_BEGIN states=[$(ls "$ST" 2>/dev/null | tr '\n' ' ')] reporting_deadline=${CLEANUP_REPORT_S}s" + # R6 — IS SOMEONE ELSE STILL ACTING ON THIS HOST? (doyle O2VBV5LC.) This is a different + # question from the marker/measurement gates below, which ask "is there something to stop". + # A measurement taken while an elevated leg is mid-reconcile can read LIVE or GONE for + # reasons that have nothing to do with what this run left behind, and dispatching a removal + # while a setup may still be writing is two elevated commands mutating one rule store with + # no ordering between them. So: while the setup is OUTSTANDING, EVERY cleanup mutation is + # withheld -- the listener stop, the rule teardown and the daemon stop alike. + # + # PROOF OF COMPLETION IS THE RECEIPT'S TERMINAL FIELDS, NOT ITS PRESENCE. A NONZERO native + # exit is a COMPLETED outcome (doyle B3CMWRQI): the test is whether the leg FINISHED, not + # whether it succeeded, and treating a refusal as outstanding would withhold cleanup from + # exactly the runs that most need it. Only an UNREAD exit (255: absent, malformed, or more + # than one record) fails this, because an unread exit is not a zero one. + # + # THE READ HAPPENS ONCE AND NEVER WAITS. A receipt that arrived late is evidence to read, + # never a reason to spend reporting budget waiting for one. + SETUP_OUTSTANDING=no + if [ -z "${SETUP_RECEIPT:-}" ] || ! has_state fw_mutation_may_have_occurred; then + SETUP_COMPLETION=NOT_REQUESTED + record "R6 setup_completion=NOT_REQUESTED — no elevated setup was ever dispatched, so nothing is outstanding and the gates below decide on their own measurements" + else + local r6_missing='' r6_nonce r6_exit + [ -f "$SETUP_RECEIPT" ] || r6_missing="$r6_missing no-receipt-file" + r6_nonce=$(grep -c "^nonce: $SETUP_NONCE\$" "$SETUP_RECEIPT" 2>/dev/null) + case "$r6_nonce" in (''|*[!0-9]*) r6_nonce=0 ;; esac + [ "$r6_nonce" -eq 1 ] || r6_missing="$r6_missing nonce-lines=$r6_nonce" + r6_exit=$(HO_RECEIPT="$SETUP_RECEIPT" handoff_exit) + [ "$r6_exit" = 255 ] && r6_missing="$r6_missing exit-record-unread" + case "$SETUP_END_UTC" in + ABSENT|UNPARSEABLE|'') r6_missing="$r6_missing setup-return-stamp=$SETUP_END_UTC" ;; + esac + [ "$TS_ORDER" = OK ] || r6_missing="$r6_missing timestamp_order=$TS_ORDER" + if [ -n "$r6_missing" ]; then + SETUP_COMPLETION="UNPROVEN:$r6_missing" + SETUP_OUTSTANDING=yes + record "R6 setup_completion=UNPROVEN missing:$r6_missing — the leg cannot be shown to have finished. UNPROVEN IS TREATED AS OUTSTANDING: a leg that finished without writing a terminal field is indistinguishable from one still running, and the cost of being wrong this way is a PENDING report." + else + SETUP_COMPLETION=PROVEN + record "R6 setup_completion=PROVEN nonce=$SETUP_NONCE exit=$r6_exit (a nonzero exit is a COMPLETED outcome) setup_return=$SETUP_END_UTC timestamp_order=$TS_ORDER" + fi + fi + # 1. THE LISTENER -- MEASURED BEFORE IT IS TOUCHED (doyle 2026-09-13; IR-124). # The predecessor ran `serve lan --stop` on has_state listener_may_exist ALONE. That marker # is set BEFORE the setup is dispatched, deliberately, so that a REFUSED setup still tears @@ -1252,7 +1559,12 @@ # UNREADABLE -- attribution could not be established: PENDING/review, NO COMMAND. An # unreadable host is not an empty one, and it is not a licence to act either. residue_scan pre-stop no - if ! has_state listener_may_exist; then + if [ "$SETUP_OUTSTANDING" = yes ]; then + CLEANUP_STOP_STATE=WITHHELD_OUTSTANDING_SETUP + CLEANUP_VERDICT=PENDING + record "CLEANUP_STOP_WITHHELD setup=$SETUP_COMPLETION — the elevated setup cannot be shown to have finished. NO stop is issued: the stop verb is the AUTOSTARTING one of IR-124, and racing it against a leg that may still be starting processes is how residue gets manufactured. Disposition PENDING/review." + cfail "listener stop withheld: the setup is outstanding ($SETUP_COMPLETION). This is a REFUSAL TO ACT, not a failed action." + elif ! has_state listener_may_exist; then record "CLEANUP_SKIP listener - no listener_may_exist state was ever marked" CLEANUP_STOP_STATE=NOT_MARKED elif [ "$RESIDUE_LIVE" -gt 0 ]; then @@ -1314,7 +1626,12 @@ # anything present -- there IS something to remove: verify the pin and dispatch. removal_check pre-teardown REMOVAL_PRE="$REMOVAL_CHECK" - if [ "$REMOVAL_PRE" = CONFIRMED ]; then + if [ "$SETUP_OUTSTANDING" = yes ]; then + TEARDOWN_DISPATCH=WITHHELD_OUTSTANDING_SETUP + CLEANUP_VERDICT=PENDING + record "TEARDOWN_WITHHELD setup=$SETUP_COMPLETION nonce=$SETUP_NONCE rules=$RULE_TAILNET,$RULE_LAN — NO removal is requested while the setup may still be writing to the same store. The pre-teardown reading above is recorded as taken, and it is NOT read as a final state: a store being mutated concurrently has no final state to read." + cfail "teardown withheld: the setup is outstanding ($SETUP_COMPLETION). Owned rules MAY REMAIN and their removal is PENDING/review." + elif [ "$REMOVAL_PRE" = CONFIRMED ]; then TEARDOWN_DISPATCH=NOT_NEEDED_MEASURED_ABSENT CLEANUP_VERDICT=NOTHING_TO_REMOVE record "TEARDOWN_NOT_NEEDED - both owned names measured ABSENT in both stores before any teardown was asked for, with each store's controls alive in the same sample. NO command is dispatched: asking an elevated leg to remove what is not there is how residue gets manufactured." @@ -1352,9 +1669,10 @@ local t_rc; t_rc=$(handoff_exit) TEARDOWN_RC="$t_rc" exits "cleanup_teardown_receipt_EXIT=$t_rc" - pwsh -NoProfile -File "$BIN/census.ps1" -Tag cleanup-teardown-post -OutDir "$R" >> "$R/census.log" 2>&1 + bounded census_cleanup_teardown_post "$(cur_deadline)" "$R/.census.out" "$R/.census.err" -- \ + pwsh -NoProfile -File "$BIN/census.ps1" -Tag cleanup-teardown-post -OutDir "$R" local c_rc=$? - exits "census_cleanup_teardown_post_EXIT=$c_rc" + cat "$R/.census.out" "$R/.census.err" >> "$R/census.log" 2>/dev/null # THE REVIEWED REMOVER SUCCEEDS SILENTLY (doyle 2026-09-13). The previous conjunction # required the product's LAN_FIREWALL_CLEAN line, which belonged to the `serve lan --stop` # verb this integration replaced. The reviewed payload prints NOTHING on success -- it @@ -1407,7 +1725,12 @@ # acting on a marker that was never a measurement is not justified by the marker. if has_state daemon_may_run; then residue_scan pre-daemon-stop no - if [ "$RESIDUE_LIVE" -gt 0 ]; then + if [ "$SETUP_OUTSTANDING" = yes ]; then + DAEMON_STOP_STATE=WITHHELD_OUTSTANDING_SETUP + CLEANUP_VERDICT=PENDING + record "DAEMON_STOP_WITHHELD setup=$SETUP_COMPLETION — the elevated leg dispatches through the daemon (ensure_running, serveverb.rs:191), so stopping it while that leg may still be acting races the processes it is starting. NO command is issued; disposition PENDING/review." + cfail "daemon stop withheld: the setup is outstanding ($SETUP_COMPLETION)." + elif [ "$RESIDUE_LIVE" -gt 0 ]; then DAEMON_STOP_STATE=ADMITTED record "DAEMON_STOP_ADMITTED - $RESIDUE_LIVE tracked identity/identities measured LIVE by pid + creation time; the stop has something to stop" elif [ "$RESIDUE_UNREADABLE" -gt 0 ]; then @@ -1520,6 +1843,20 @@ else record "CLEANUP_REPORT_WINDOW ${left}s of ${CLEANUP_REPORT_S}s remained when the report was written" fi + # THE DEFERRED VALIDATIONS LAND HERE, on the reporting clock, bounded by WORK_DEADLINE like + # everything else in this phase. t3's was always here; t1's and t2's join it. + d2_validate_at t1; D2_T1_VALID="$VALIDATE_RESULT"; D2_T1_QF="$VALIDATE_QF" + d2_validate_at t2; D2_T2_VALID="$VALIDATE_RESULT"; D2_T2_QF="$VALIDATE_QF" + # EVERY LAUNCHED IDENTITY THIS RUN COULD NOT ACCOUNT FOR, PRINTED AS A LINE RATHER THAN + # WAITED ON (doyle B3CMWRQI). The ledger owns the reserved interval and must emit on time; + # an un-reaped child is reported as OUTSTANDING, which is a line to print. + if [ -f "$(launch_file)" ]; then + local out_n; out_n=$(grep -c 'state=ATTRIBUTION_INCOMPLETE' "$(launch_file)" 2>/dev/null) + case "$out_n" in (''|*[!0-9]*) out_n=0 ;; esac + record "LAUNCHED_IDENTITIES $(grep -c '^LAUNCHED ' "$(launch_file)" 2>/dev/null) rows, of which $out_n are ATTRIBUTION_INCOMPLETE — see launched-identities.txt. An incomplete attribution is NOT a process measured absent." + else + record "LAUNCHED_IDENTITIES none recorded — no bounded child was ever launched, or the register could not be written" + fi d2_ledger emit_ceiling summary record "CLEANUP_END steps_failed=$CLEANUP_FAILURES original_rc=$ORIGINAL_RC original_why=[$ORIGINAL_WHY]" @@ -1756,11 +2093,70 @@ [ "$elev" = 'False' ] || die "this driver is ELEVATED. The trial driver must remain unelevated; elevated work goes to liam by handoff." # =========================================================================== -# S0b PRE-EXISTING STATE IS REJECTED, NEVER TRUNCATED (D10) +# S0b THE PROVISIONED RIG IS VERIFIED AND CONSUMED — NEVER PROVISIONED HERE # =========================================================================== -if [ -e "$H" ]; then - die "isolated home $H already exists. A prior run's home would make provenance unreadable; MOVE it, do not let this run truncate it (D10)." +# PREPARATION VERIFIES; IT DOES NOT PROVISION (doyle W4C2QFLE). Everything in this section is +# READ-ONLY over the rig except one atomic marker, and that marker is the consumption. +# +# THE PRODUCT'S GATES DO NOT REJECT EVERY UNRELATED OR PREVIOUSLY USED HOME, and I said +# otherwise in the first proposal — doyle corrected it. A home that happens to carry a matching +# applied set would satisfy the conjuncts perfectly well. So exclusive creation, provenance and +# one-attempt consumption are THE RIG'S OWN obligations, enforced here and in provision-rig.sh, +# and never inferred from the product refusing something. +if [ -z "$RIG_ROOT" ]; then + die "no provisioned rig is pinned (RIG_ROOT is empty). This driver does not create one: provisioning is a separate mutating phase with its own grant, and a run that provisioned its own subject could not tell a prepared home from one it repaired to make a check pass." fi +[ -d "$RIG_ROOT" ] || die "the pinned rig root does not exist: $RIG_ROOT" +[ -d "$H" ] || die "the pinned rig has no home at $H" +[ -f "$EXE" ] || die "the pinned rig has no executable at $EXE" +PROVENANCE="$H/provenance.json" +[ -f "$PROVENANCE" ] || die "no provenance record at $PROVENANCE. An intentionally provisioned home is a MEASURABLE property, not an assertion: without the record this home is indistinguishable from a leftover." +# ONE ATTEMPT, CONSUMED ATOMICALLY. mkdir either creates the directory or fails because it is +# already there; a test-then-create would leave a window in which two runs both read 'absent'. +# A CONSUMED RIG IS NEVER CLEARED AND NEVER REUSED: the refusal is the point, and the evidence +# of the previous attempt -- successful or failed -- stays exactly where it is. +if ! mkdir "$H/.consumed" 2>/dev/null; then + die "this provisioned rig has ALREADY BEEN CONSUMED (see $H/.consumed). A rig is one attempt: provision a new one rather than reusing or clearing this, whose contents are the previous attempt's evidence." +fi +{ echo "run_id=$RUN_ID"; echo "consumed_utc=$(date -u +%Y-%m-%dT%H:%M:%SZ)"; echo "driver=$0"; } > "$H/.consumed/run.txt" 2>/dev/null +record "RIG_CONSUMED $H/.consumed created by run $RUN_ID — exclusive creation, so a second run refuses rather than sharing this subject" +# PROVENANCE FIELDS, read as plain strings. The rig does NOT parse the product's cache files: +# what the applied state is was measured by provisioning, with the product's own output kept +# beside this record, and re-deriving it here from internals would be a second, weaker reading. +prov_field() { # KEY -> value | '' + sed -n 's/.*"'"$1"'"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$PROVENANCE" | head -1 +} +P_RUN=$(prov_field rig_id); P_EXE=$(prov_field rig_exe) +P_SHA=$(prov_field rig_exe_sha256); P_HOME=$(prov_field home) +P_VER=$(prov_field applied_version); P_KEY=$(prov_field trust_key_id) +P_EVID=$(prov_field applied_evidence) +record "RIG_PROVENANCE rig_id=$P_RUN exe=$P_EXE sha256=$P_SHA home=$P_HOME applied_version=$P_VER trust_key_id=$P_KEY evidence=$P_EVID" +for f in P_RUN P_EXE P_SHA P_HOME P_VER P_EVID; do + eval "v=\$$f" + [ -n "$v" ] || die "the provenance record is missing $f. An incomplete provenance record does not establish that this home was prepared for anything." +done +# THE BYTES, MEASURED HERE AND NOT TAKEN FROM THE RECORD. A provenance file that says what the +# sha is proves only what provisioning believed; this is the reading that binds the subject. +RIG_EXE_SHA_NOW=$(sha256sum "$EXE" 2>/dev/null | cut -d' ' -f1) +[ -n "$RIG_EXE_SHA_NOW" ] || die "could not hash $EXE — an unmeasured executable is not the subject" +[ "$RIG_EXE_SHA_NOW" = "$EXE_SHA" ] || die "the rig executable hashes to $RIG_EXE_SHA_NOW and the pinned subject is $EXE_SHA. Different bytes are a different subject." +[ "$P_SHA" = "$EXE_SHA" ] || die "the provenance record names $P_SHA and this run's subject is $EXE_SHA: this rig was provisioned for a different binary." +# THE PATHS, COMPARED CANONICALLY with the same r2 comparison the binder check uses. A string +# comparison would accept two spellings of one path and reject one path spelt two ways. +rig_canon=$(binder_path_canon "$EXE") || die "could not canonicalise $EXE" +prov_canon=$(binder_path_canon "$P_EXE") || die "could not canonicalise the provenance path $P_EXE" +[ "$rig_canon" = "$prov_canon" ] || die "the provisioned executable ($P_EXE) is not the one this run would invoke ($EXE)" +home_canon=$(binder_path_canon "$H") || die "could not canonicalise $H" +prov_home=$(binder_path_canon "$P_HOME") || die "could not canonicalise the provenance home $P_HOME" +[ "$home_canon" = "$prov_home" ] || die "the provenance record belongs to a different home ($P_HOME): this rig is not this run's" +# THE APPLIED STATE'S EVIDENCE. Provisioning verified a genuine Applied state with the product's +# own output; PREP requires that evidence to EXIST and to name the same version. It is not +# re-derived from the release cache here: a second, weaker reading of the same fact would add no +# assurance and would put the rig in the business of parsing product internals. +[ -f "$P_EVID" ] || die "the applied-state evidence named by the provenance record is absent ($P_EVID). A recorded version with no evidence beside it is a claim, not a measurement." +grep -q "$P_VER" "$P_EVID" || die "the applied-state evidence does not mention version $P_VER" +record "RIG_VERIFIED exe_sha256=$RIG_EXE_SHA_NOW (measured here) canonical_path=$rig_canon applied_version=$P_VER evidence=$P_EVID" +record " BINDER EQUALITY IS NOT CHECKED HERE (doyle W4C2QFLE): whether the LISTENER is this executable is a POST-SETUP question, and there is no listener yet. It is measured at setup-post-listener, where it has a subject." # =========================================================================== # S0c INSTRUMENTS: present, and HASHED INTO THE EVIDENCE (F10 + C) @@ -1886,9 +2282,10 @@ # CENSUS AND BRACKET HELPERS — every call's exit and validity enforced (F-a) # =========================================================================== census_at() { # TAG - pwsh -NoProfile -File "$BIN/census.ps1" -Tag "$1" -OutDir "$R" >> "$R/census.log" 2>&1 + bounded "census_$1" "$(cur_deadline)" "$R/.census.out" "$R/.census.err" -- \ + pwsh -NoProfile -File "$BIN/census.ps1" -Tag "$1" -OutDir "$R" local rc=$? - exits "census_$1_EXIT=$rc" + cat "$R/.census.out" "$R/.census.err" >> "$R/census.log" 2>/dev/null [ "$rc" -eq 0 ] || return 1 grep -q "tag=$1 .* valid=YES" "$R/census.log" || return 1 return 0 @@ -1897,9 +2294,12 @@ grep "tag=$1 " "$R/census.log" | tail -1 } port_at() { # TAG — the trial port's rules and listener identity - pwsh -NoProfile -File "$BIN/portfields.ps1" -Tag "$1" -OutDir "$R" -Port "$PORT" >> "$R/portfields.log" 2>&1 + bounded "portfields_${PORT}_$1" "$(cur_deadline)" "$R/.probe.out" "$R/.probe.err" -- \ + pwsh -NoProfile -File "$BIN/portfields.ps1" -Tag "$1" -OutDir "$R" -Port "$PORT" local rc=$? - exits "portfields_${PORT}_$1_EXIT=$rc" + # THE PROBE'S OWN OUTPUT STILL REACHES THE LOG. bounded() takes OUT and ERR as parameters + # because `record` tees to stdout; the log this rig greps is assembled here instead. + cat "$R/.probe.out" "$R/.probe.err" >> "$R/portfields.log" 2>/dev/null [ "$rc" -eq 0 ] || return 1 grep -q "tag=$1 .* valid=YES" "$R/portfields.log" || return 1 return 0 @@ -2005,20 +2405,28 @@ d1_capture() { # TAG local tag="$1" D1_OK=no - python "$BIN/d1_render.py" --repo "$W" --blob "$SUBJECT_BLOB" --out "$R/d1-$tag.b64" \ - > "$R/d1-$tag-render.out" 2>&1 + # THE RENDER TOUCHES NO HOST AND STILL CANNOT MOVE (doyle CT6GS2Y6). Its output IS the + # command the post-mutation snapshot runs, two lines below, and the A2.1 pre-check on its + # stdout gates that snapshot. Host-free is not the test for deferral; ordering is. + bounded "d1_${tag}_render" "$(cur_deadline)" "$R/d1-$tag-render.out" "$R/d1-$tag-render.err" -- \ + python "$BIN/d1_render.py" --repo "$W" --blob "$SUBJECT_BLOB" --out "$R/d1-$tag.b64" local rc=$? - exits "d1_${tag}_render_EXIT=$rc" + cat "$R/d1-$tag-render.err" >> "$R/d1-$tag-render.out" 2>/dev/null if [ "$rc" -ne 0 ]; then record "D1_FAILED($tag) render exit $rc — see d1-$tag-render.out. The capture is DISCARDED, not patched up." return 1 fi grep -q 'PRECHECK Named-Rules=1 PersistentStore=0 Get-NetIPAddress=1 ActiveStore=2' "$R/d1-$tag-render.out" \ || { record "D1_FAILED($tag) the render did not satisfy its own A2.1 pre-check; capture discarded"; return 1; } - powershell.exe -NoLogo -NoProfile -NonInteractive -EncodedCommand "$(cat "$R/d1-$tag.b64")" \ - > "$R/d1-$tag-snapshot.json" 2> "$R/d1-$tag-snapshot.err" + bounded "d1_${tag}_exec" "$(cur_deadline)" "$R/d1-$tag-snapshot.json" "$R/d1-$tag-snapshot.err" -- \ + powershell.exe -NoLogo -NoProfile -NonInteractive -EncodedCommand "$(cat "$R/d1-$tag.b64")" local prc=$? - exits "d1_${tag}_exec_EXIT=$prc" + if [ "$prc" -eq 124 ]; then + # COMPLETION UNVERIFIED, NOT AN ABSENT SNAPSHOT. The partial is preserved and left unread. + preserve_unverified "d1_${tag}_exec" "$R/d1-$tag-snapshot.json" + record "D1_FAILED($tag) the out-of-band capture did not complete within its bound; its partial output is PRESERVED UNREAD and this run makes no claim about what it contains" + return 1 + fi if [ "$prc" -ne 0 ]; then record "D1_FAILED($tag) the out-of-band capture exited $prc — see d1-$tag-snapshot.err" return 1 @@ -2214,6 +2622,9 @@ "create the owned pair with the product itself (never a hand netsh, so the rules carry the shipped desired_specs shape) AND take the t1 capture inside this same elevated leg" \ "env -u SPT_INSTALL_NO_FIREWALL SPT_HOME=\"$H\" \"$EXE\" serve lan --bootstrap --port $PORT" SETUP_OUT="$HO_OUT"; SETUP_ERR="$HO_ERR" # captured now: a later handoff rebinds HO_* +# THE SETUP'S RECEIPT PATH AND NONCE, CAPTURED FOR R6. Cleanup has to ask whether THIS command +# finished before it may mutate anything, and a later handoff rebinds HO_RECEIPT/HO_NONCE. +SETUP_RECEIPT="$HO_RECEIPT"; SETUP_NONCE="$HO_NONCE" # THE t1 RIDER, appended to the request this driver just wrote. It is NOT a second handoff # and NOT a second nonce: one nonce is one execution, and an elevated read cannot be added # after this leg returns without a second authorization. It costs one block in the request. @@ -2269,14 +2680,31 @@ # The wait cannot outlive the experimental budget: the deadline ends activity, whoever is # holding it up. HANDOFF_WAIT_S=$(exp_left) -record "HANDOFF_WAIT bounded to ${HANDOFF_WAIT_S}s — what remains of the experimental budget" +# THE CAP IS A POLICY ALLOCATION, NOT AN ESTIMATE (doyle CT6GS2Y6). It answers how much of the +# activity window this run will spend waiting on another agent, and it exists because one slow +# counterparty can otherwise consume the whole window and leave nothing for the observations the +# window exists to take -- run 20260913T041410Z spent 134s here and reached neither t1 nor t2. +# 94s and 134s are two samples, not a distribution, and no number here is derived from them. +if [ "$HANDOFF_WAIT_S" -gt "$HANDOFF_CAP_S" ]; then + record "HANDOFF_CAP applied: ${HANDOFF_CAP_S}s of the ${HANDOFF_WAIT_S}s that remain — the rest of the window is RESERVED for the post-mutation observations, which cannot be taken anywhere else" + HANDOFF_WAIT_S=$HANDOFF_CAP_S +fi +record "HANDOFF_WAIT bounded to ${HANDOFF_WAIT_S}s — the lesser of the cap and what remains of the experimental budget" # CONTEXT NAME KEPT VERBATIM: 'trial' is handoff_await's name for THE NORMAL FLOW, as # opposed to 'cleanup'. There are no trials here; renaming it would edit a function this # change has no reason to touch, so the name stays and this line says what it means. if ! handoff_await trial; then HANDOFF_RECEIPT_UTC="$(date -u +%Y-%m-%dT%H:%M:%SZ)" record "HANDOFF_INTERVAL request=$HANDOFF_REQUEST_UTC receipt=$HANDOFF_RECEIPT_UTC — the handoff's bounds. The setup command's own bounds were never returned." - die "no verified setup receipt within the experimental budget. State markers are left set for the authorized teardown: a REFUSED or UNANSWERED setup can still have left rules behind." + # THE WAIT STOPPED; THE COMMAND MAY NOT HAVE. This driver never entered that leg and has no + # authority to stop it, asks for none, and does not re-ask: one nonce is one execution, so a + # second request would be a second authorization rather than a retry. It also does NOT proceed + # into the post-mutation set -- those readings would be recorded under names asserting they are + # AFTER a setup that may still be writing, which is a falsified observation and worse than a + # missing one. Activity ends here and cleanup is entered through the EXIT trap, where R6 + # withholds EVERY mutation while the command is outstanding. + record "HANDOFF_CAP_EXPIRED nonce=$SETUP_NONCE receipt_awaited=$SETUP_RECEIPT — the wait ended, the command's disposition is UNKNOWN, and nothing was killed or re-requested" + die "no verified setup receipt within the bounded wait. The elevated command may still be acting: state markers are left set, no cleanup mutation may run while it is outstanding (R6), and a REFUSED or UNANSWERED setup can still have left rules behind." fi HANDOFF_RECEIPT_UTC="$(date -u +%Y-%m-%dT%H:%M:%SZ)" SETUP_RC=$(handoff_exit) @@ -2331,7 +2759,10 @@ case "$D2_T1" in (''|*[!0-9]*) D2_T1=UNPARSEABLE ;; esac exits "d2_t1_capture_EXIT=$D2_T1" record "D2(t1) native_exit=$D2_T1 — the ELEVATED capture, read from its own file, never from the setup's exit" - d2_validate_at t1; D2_T1_VALID="$VALIDATE_RESULT"; D2_T1_QF="$VALIDATE_QF" + # VALIDATION IS DEFERRED TO THE REPORTING WINDOW (doyle CT6GS2Y6, approved). It touches no + # host, and its result is read at exactly three lines, all inside d2_ledger, which runs in + # cleanup: no in-window decision consumes it, so charging it to the activity budget was the + # category error F5 named. It runs beside the t3 validation that was always there. else D2_T1=UNAVAILABLE record "D2_T1=UNAVAILABLE — the seq-001 request named the elevated capture and no exit file came back." @@ -2416,7 +2847,8 @@ d2_capture_at t2 "$(exp_left)" D2_T2=$(tr -d ' ' < "$R/d2-t2.exit" 2>/dev/null || echo UNRECORDED) -d2_validate_at t2; D2_T2_VALID="$VALIDATE_RESULT"; D2_T2_QF="$VALIDATE_QF" +# t2's validation is DEFERRED with t1's — see the note at the t1 site. This is the 11s +# reporting tail that overran the window in run 20260913T071131Z. # =========================================================================== # S11 HAND BACK TO CLEANUP. t3, the manifest and the teardown live there.