Repository navigation
test(harness): join completion gate, fault seams, launcher-bound selftests - #2684
Conversation
macOS bash 3.2 reports -c input as line 0, modern GNU bash as line 1. Compare diagnostic shape with line number normalized.
…gression A long -c ARG0 stamped on every report line could evict the structural payload out of the 1 KiB diagnostic budget. Truncate the shell name to 64 chars first so 'syntax error ...' always survives; renumber the threat entry to TM-DOS-136 (main already owns 135 via #2674); add a bounded-child regression exercising the exact finding shape (multiline token x long ARG0) at two scales.
The 64-char cut mangled long script paths (breaking the oracle's path
replacement and hiding which script failed). Widen to 256 chars with a
16-char tail: realistic paths print verbatim with attribution suffixes
(': eval') intact, while a kilobyte-scale ARG0 still cannot evict the
structural payload out of the 1 KiB total. The total stays the enforced
bound.
The scaled multiline-token x long-ARG0 regression now asserts the whole harness contract at both scales (200/2000 lines x 8 KiB ARG0): no watchdog timeout, raw child exit 2, no output-cap overshoot, finished reader threads, and effective stack=4096/cpu=10 caps read back from the launcher. Shape and 1 KiB assertions unchanged.
run_command_bounded cleanup per lifecycle review: truncate retention before extending (retention never passes the 8192 cap); retry Interrupted, fail closed with partial bytes on real reader errors (new read_error field, never relabeled as EOF); exact-cap EOF is not excess; reap inside a finite 5s grace, never an unbounded wait; timed_out retained as recorded; drain 2s + reap 5s graces documented against the execution deadline. Consumer regression gains !read_error and the corrected 8192-byte cap text. Bounded selftests: exact-cap, cap+1, Interrupted/error scripted pipes, timeout kill+reap, overflow flag.
Per lifecycle review on #2682: join readers only after all channel receipts (receipt proves all blocking work done; missing receipts skip the join and fail incomplete), with panicking readers failing visibly; reap extracted into a poll seam with deterministic verdict unit tests; timeout/overflow selftests run under the fail-closed launcher with stack/cpu readback and elapsed-total bounds; retained-pipe case gains elapsed proof and read_error distinction. Reuses existing bounded_helper_flags_retained_pipes; does not touch #2681's distinct probe helper.
…tests Per completion review on #2683: join readers only while is_finished inside the shared completion grace (a receipt is not the termination contract); deterministic paused-after-send proof with release/cleanup watchdog; poll/read/reap faults injected through the real parent lifecycle with distinct fail-closed verdicts (no panicking expect on child poll); timeout/overflow selftests under the fail-closed launcher with cap readback and elapsed bounds; existing retained-pipe fixture reused and strengthened. Untouched: #2681 distinct probe helper.
…tests Per completion review on #2683: join readers only while is_finished inside the shared completion grace (a receipt is not the termination contract); deterministic paused-after-send proof with release/cleanup watchdog; poll/read/reap faults injected through the real parent lifecycle with distinct fail-closed verdicts (no panicking expect on child poll); timeout/overflow selftests under the fail-closed launcher with cap readback and elapsed bounds; existing retained-pipe fixture reused and strengthened. Untouched: #2681 distinct probe helper.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bashkit | 49a1ffc | Commit Preview URL Branch Preview URL |
Oct 11 2026, 10:54 AM |
PR 2684: parent-error cleanup and real completion proofReviewed exact head 49a1ffc. The is_finished deadline before joining is a useful correction; CPU/stack launchers and overflow elapsed checks also improve the proof. This is not a demonstrated hang claim about the old implementation.
Keep documented total wall + drain + join + reap bounds consistent with elapsed assertions, remove stale claims that channel delivery alone proves thread completion, and retain every prior negative/real Linux failure. Read this complete issue comment plus all earlier issue comments, reviews and inline threads before merging. Pending or missing checks remain unknown. No CI waiver, force push, extra PR, or finding closure from candidate CI alone; after all fixes, require exact merged revision producer and assertion exits plus durable files and the fresh runner report. |
## What changed Test-only, one file: threat_model_tests.rs. Closes the completion review on #2684 without touching #2681 distinct run_bounded_probe helper: - Common cleanup termination: every loop exit (observed completion, deadline, oversized, poll failure) funnels through one reachable kill guard; verdicts recorded pre-kill are never recomputed. Previously the poll-fault break skipped its kill guard. - Bounded join completion gate via a shared join_finished primitive: readers join only while is_finished inside JOIN_GRACE (a receipt is not the termination contract since scheduling can pause the sender after send). Unfinished handles stay detached and fail incomplete; panics fail visibly. No reproduced production hang is claimed. - Deterministic paused-after-send proof drives the actual gate primitive with bounded readiness (recv_timeout), explicit release, and a finite join-cleanup watchdog. - Poll/read/reap faults injected through the real parent lifecycle with distinct fail-closed verdicts: the panicking child.try_wait expect is gone; unavailable reap keeps real bounded OS cleanup while the verdict reports None (no invented success). - Timeout/overflow/retained-pipe selftests under the shared fail-closed launcher with stack/cpu readback and elapsed-total bounds; the existing retained-pipe fixture is reused and strengthened, never duplicated. ## Before / After Before: poll-fault break skipped termination; unconditional join after receipts; reap untestable without OS fakery; child poll panicked; selftests bypassed the launcher. After: threat_model 222 passed (only pre-existing macOS nesting abort skipped, identical on unmodified code); error 14, partial_parse 11 green; fmt plus clippy -D warnings clean. ## Risk - Test-only change. No production code touched. ## Checklist - [x] Tests added or updated - [x] Backward compatibility considered (internal test harness)
…receipts (#2686) ## What changed Test-only, one file: threat_model_tests.rs. Closes the completion review on #2685 without touching #2681 distinct run_bounded_probe helper: - join_finished returns the unfinished handle, so the paused-after-send proof releases and joins THAT SAME thread through the actual gate primitive (bounded readiness, release, finite join cleanup, elapsed watchdog). No twin thread, no detached-while-asserting-cleanup. - Poll-fault fixture uses a direct-exec sleeper: the shell replaces itself, so killing closes the pipes at once with no orphan and no 30s descendant. - reap_never keeps the real bounded OS cleanup while only the observation is discarded for the verdict: no zombies by construction, no invented exit/reap success. - Retained-pipe fixture runs under the fail-closed launcher; because incomplete pipe capture precludes the stderr readback by design, the effective bounds are proven through a per-process receipt file the fixture shell writes before parking the sleeper (removed afterwards). Existing fixture reused and strengthened, never duplicated. - Prior review debt acknowledged: #2684 merged on formal reviews alone while the completion comment was unresolved; this followup resolves it before any merge. ## Before / After Before: twin-thread gate proof; forked sleeper orphan in the poll fixture; reap skipped under fault; no launcher proof on the retained fixture. After: threat_model 222 passed (only pre-existing macOS nesting abort skipped, identical on unmodified code); error 14, partial_parse 11 green; fmt plus clippy -D warnings clean. ## Risk - Test-only change. No production code touched. ## Checklist - [x] Tests added or updated - [x] Backward compatibility considered (internal test harness) ## Update: readiness gating, reaped receipt, launcher receipts Follow-up commits on the same branch add: - fail_poll fires only after a readiness file proves the victim truly live under bounds (direct-exec sleeper, no orphan); readiness itself is asserted alongside the reaped receipt, cap readback, and elapsed bound. - BoundedRun gains a reaped receipt: OS termination accounted for, orthogonal to exit_code and to injected observation faults (which discard the observation, never the cleanup). reap_never asserts real cleanup ran alongside its discarded verdict. - Retained-pipe fixture runs under the fail-closed launcher; because incomplete pipe capture precludes the stderr readback by design, the effective stack/cpu bounds are proven through a per-process receipt file the fixture shell writes before parking the sleeper (removed afterwards).
What changed
Test-only, one file: threat_model_tests.rs. Closes the completion review on #2683 without touching #2681 distinct run_bounded_probe helper:
Before / After
Before: unconditional join after receipts; reap untestable without OS fakery; child poll panicked; selftests bypassed the launcher.
After: threat_model 222 passed (only pre-existing macOS nesting abort skipped, identical on unmodified code); error 14, partial_parse 11 green; fmt plus clippy -D warnings clean.
Risk
Checklist