Skip to content

test(harness): parent cleanup, join gate, fault seams - #2685

Merged
chaliy merged 16 commits into
mainfrom
codex/syntax-diagnostic-budget
Oct 11, 2026
Merged

chaliy merged 16 commits into
mainfrom
codex/syntax-diagnostic-budget

Conversation

@chaliy

@chaliy chaliy commented Oct 11, 2026

Copy link
Copy Markdown
Contributor

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

  • Tests added or updated
  • Backward compatibility considered (internal test harness)

chaliy added 16 commits October 10, 2026 21:58
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.
All five branch commits already reached main via squash merges (#2675, #2677); conflicting files take main's reviewed state.
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.
… selftests

Per completion review on #2684: common cleanup termination funnels every loop exit through one reachable kill guard; bounded is_finished join gate with shared completion grace (receipt is not the termination contract); deterministic paused-after-send proof drives the actual gate with bounded readiness and release/cleanup watchdog; poll/read/reap faults injected through the real parent lifecycle with distinct fail-closed verdicts (no panicking child poll); selftests and retained-pipe fixture under the fail-closed launcher with cap readback and elapsed bounds. Reuses existing retained-pipe fixture; untouched: #2681 distinct probe helper.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
bashkit 2511659 Commit Preview URL

Branch Preview URL
Oct 11 2026, 12:00 PM

@chaliy

chaliy commented Oct 11, 2026

Copy link
Copy Markdown
Contributor Author

Review of PR2685 head25116591d891cc81185079acd1199848e75a2846. Common reachable cleanup kill and unconditional real OS reap before injected observation suppression are useful fixes; preserve them. This is not a claim of a reproduced old hang.

  1. harness_join_gate_proves_paused_sender_unfinished consumes the original JoinHandle in join_finished's negative path. Dropping rel_tx releases it, but there is no observed completion or join of that original thread; joining a newly spawned twin cannot prove the original terminated. Retain ownership on a negative gate outcome (for example return the unfinished handle) and release then finitely observe/join THAT same handle. Exercise the actual runner primitive and negative verdict; do not substitute a disconnected twin or leave a detached thread while asserting none outlives the test.

  2. The live fail_poll test is now real, but bash -c 'sleep 30' can leave a descendant after shell kill, and assertions do not check the launcher effective CPU/stack readback or actual child reap result. Use a direct-exec sleeper or pure-builtin fixture for the direct-child cleanup test, assert effective stack4096/cpu10 and truthful observed termination/reap separately from the injected exitless/incomplete verdict. The reap_never case still invokes run_command_bounded_with directly on an unbounded busy-loop command; route that fixture through the same fail-closed launcher and assert effective limits while retaining honest observation-failure flags. Do not invent successful observation from cleanup or weaken incomplete flags.

  3. Strengthen EXISTING bounded_helper_flags_retained_pipes, which already exercises the same runner, with effective CPU/stack and controlled descendant/reader cleanup proof. No duplicate retained-pipe test. A self-expiring sleep is not a receipt that cleanup completed at the asserted parent deadline; do not claim a process-tree guarantee the helper does not implement.

Read complete issue comments and formal/inline review threads before merge, not formalreviews=[] alone. Keep both scaled ARGV assertions/cap-before-copy/readerror/exactcap/finite is_finished gate. Obtain actual producer exits rather than cargo|tail pipeline0, unchanged full Linux CI and fresh exactmerged proofs/root report before finding closure. The watcher currently exits0 on zero pending even with failed checks, so independently inspect required conclusions; pending CI is not a stall. Preserve all branch/bench/stash/history and use additive normal commits only.

@chaliy
chaliy merged commit debb9b1 into main Oct 11, 2026
33 checks passed
@chaliy
chaliy deleted the codex/syntax-diagnostic-budget branch October 11, 2026 12:23
chaliy added a commit that referenced this pull request Oct 11, 2026
Per completion review on #2685: fail_poll fires only after a readiness file proves the victim truly live (direct-exec sleeper, no orphan); BoundedRun gains a reaped receipt separating actual OS cleanup from exit/observation verdicts; retained-pipe fixture runs under the fail-closed launcher with a file side-channel receipt proving the effective bounds despite incomplete pipe capture. Reuses the existing retained-pipe fixture; untouched: #2681 distinct probe helper.
chaliy added a commit that referenced this pull request Oct 11, 2026
…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).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant