docs(framing): revision 2 --- five findings, two of them my own retractions
Revision 1 rejected on five findings, all upheld. 1. The >6s selector could not have captured the failure. Both reproducing binaries finish in ~5.19s INCLUDING the 5s timeout (:3097, :3131), so the failing launcher lives about 5.1s. This also falsifies my earlier retraction, which had argued the instance "must live >=8s" --- so the "mechanism located" claim is NOT refuted by that argument. It stays unproven for a different reason: the suite spawns launchers from five call sites, so command line alone cannot attribute one to this test. Key on the PID the test records. 2. Diagnostics rewritten to DISCRIMINATE blocked delivery, inherited ignore, and an escaped process group: before-and-after snapshots for test parent / launcher / probe, per-thread SigBlk from /proc/<pid>/task/*/status, SigPnd/ShdPnd, and PID/PPID/PGID/SID. Relatedly, "two processes with default disposition" is withdrawn --- SIG_IGN is inherited across fork and survives exec, so absence of handler code says nothing about runtime disposition, and inherited ignore is the leading hypothesis precisely because the source is silent. Revision 1 contradicted its own hypothesis. 3. Counts corrected: 119 green result summaries and TWO red binaries, not "119 binaries green, one red". Reductions are now enumerated R1-R10 and F1-F5 with command, run count and log each, preserved off the tmpfs --- /tmp is a tmpfs and these were nearly lost mid-lane. 4. Acceptance contract corrected: A2 now requires three consecutive green runs on the reviewed fixed head of this branch, not on main, which is unobtainable before approval and merge; journey step 12(a) "closing is clean" is named, since revision 1 reasoned from grade movement which §20 warns against; and A5 is explicitly conditional on D4, with bet 1 restated as a bet --- the witness uses a wrapper and headless probe, not the real GUI path. 5. Portability closed: this branch now tracks githubsucks/gpu-probe-sigint-teardown, and panel-mapping-generation was pushed to 16cf3a2 so its retraction travels. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
This commit is contained in:
parent
f1992a65d9
commit
9988e974af
|
|
@ -279,14 +279,18 @@ from #171 and #215.
|
||||||
**`72da24a`**, worktree
|
**`72da24a`**, worktree
|
||||||
`/home/jeans/Repos/personal/pmacs-probe-sigint`. Recover with
|
`/home/jeans/Repos/personal/pmacs-probe-sigint`. Recover with
|
||||||
`git fetch githubsucks && git checkout gpu-probe-sigint-teardown`.
|
`git fetch githubsucks && git checkout gpu-probe-sigint-teardown`.
|
||||||
- **No PR. Framing revision 1 at `docs/gpu-probe-sigint-framing.md`;
|
- **No PR. Framing revision 2 at `docs/gpu-probe-sigint-framing.md`;
|
||||||
NO IMPLEMENTATION and no fix proposed** — the mechanism is not known
|
NO IMPLEMENTATION and no fix proposed** — the mechanism is not known
|
||||||
yet, and the framing says so rather than guessing.
|
yet, and the framing says so rather than guessing. Revision 1 was
|
||||||
|
rejected on five findings, all upheld.
|
||||||
- **Why it exists.** `ctrl_c_on_launcher_group_does_not_reach_spawned_daemon`
|
- **Why it exists.** `ctrl_c_on_launcher_group_does_not_reach_spawned_daemon`
|
||||||
fails in gate stage `sweep-crdt` with "child did not exit within 5s".
|
fails in gate stage `sweep-crdt` with "child did not exit within 5s".
|
||||||
**Pre-existing on `main`** — `72da24a` fails it in a clean worktree
|
**Pre-existing on `main`** — `72da24a` fails it in a clean worktree
|
||||||
with its own target dir, 119 binaries green and one red. While it
|
with its own target dir. The correct count is **119 green result
|
||||||
reds, **no branch can present a green sixteen-stage gate, `main`
|
summaries and TWO red binaries**: `gpu_initial_target_acceptance`
|
||||||
|
includes the suite as a module, so a reproducing sweep reds twice
|
||||||
|
(log `…-2144707/09-sweep-crdt.log:3097` and `:3131`). While it reds,
|
||||||
|
**no branch can present a green sixteen-stage gate, `main`
|
||||||
included.**
|
included.**
|
||||||
- **`panel-mapping-generation` (§5b) is HELD BEHIND THIS LANE** by
|
- **`panel-mapping-generation` (§5b) is HELD BEHIND THIS LANE** by
|
||||||
explicit instruction. That lane is code-complete at `5174f73` with
|
explicit instruction. That lane is code-complete at `5174f73` with
|
||||||
|
|
@ -305,19 +309,43 @@ from #171 and #215.
|
||||||
`pmacs-gpu/src` for signal machinery returns nothing. The probe polls
|
`pmacs-gpu/src` for signal machinery returns nothing. The probe polls
|
||||||
at 50ms (`pmacs-gpu/src/main.rs:1065`). Two processes with default
|
at 50ms (`pmacs-gpu/src/main.rs:1065`). Two processes with default
|
||||||
`SIGINT` disposition should both die at once.
|
`SIGINT` disposition should both die at once.
|
||||||
- **One retracted claim, kept as a warning.** An earlier "mechanism
|
- **TWO retracted claims, both mine.** (a) "Mechanism located" —
|
||||||
located" report — launcher in `do_wait`, probe child in
|
launcher in `do_wait`, probe child in `futex_do_wait`. (b) The
|
||||||
`futex_do_wait` — was retracted on its own evidence: the sampler
|
retraction of (a), which argued the failing launcher "must live ≥8s".
|
||||||
caught 394 launchers with a maximum lifetime of 5s, while the failing
|
**(b)'s arithmetic is false**: both reproducing binaries finish in
|
||||||
instance must live 8s or more. It had described a HEALTHY teardown.
|
~5.19s *including* the 5s timeout, so the failing launcher lives
|
||||||
The first step is therefore an instrument recording **only**
|
about **5.1s** — inside what the sampler saw, and a ">6s" selector
|
||||||
launchers outliving ~6s, with `/proc/<pid>/status` signal masks —
|
would have captured nothing, repeating the error it was meant to
|
||||||
`SigIgn` survives `fork` AND `exec`, handlers do not.
|
correct. (a) is therefore not refuted by (b); it stays **unproven for
|
||||||
|
a different reason** — the suite spawns launchers from five call
|
||||||
|
sites, so command line alone cannot attribute one to this test.
|
||||||
|
**Do not key on process age. Key on the PID the test records.**
|
||||||
|
- **Diagnostics must DISCRIMINATE** blocked delivery, inherited ignore,
|
||||||
|
and an escaped process group: snapshots **before and after** the
|
||||||
|
signal, for test parent / launcher / probe; **per-thread** `SigBlk`
|
||||||
|
from `/proc/<pid>/task/*/status`; `SigPnd`/`ShdPnd`; and
|
||||||
|
`PID`/`PPID`/`PGID`/`SID`. A post-failure snapshot cannot prove
|
||||||
|
inheritance.
|
||||||
|
- **"Neither binary handles signals" does NOT mean default
|
||||||
|
disposition.** `SIG_IGN` is inherited across `fork` and survives
|
||||||
|
`exec`, so an inherited non-default disposition is the leading
|
||||||
|
hypothesis precisely because the source is silent. Revision 1's
|
||||||
|
"two processes with default disposition" claim contradicted its own
|
||||||
|
hypothesis and is withdrawn.
|
||||||
|
- **Reduction evidence is enumerated** in the framing §4 with command,
|
||||||
|
run count and log for each of R1–R10 and F1–F5, with the logs
|
||||||
|
preserved off the tmpfs at
|
||||||
|
`/home/jeans/build/pmacs-gate-targets/probe-sigint-evidence/` —
|
||||||
|
`/tmp` is a tmpfs and these were nearly lost to a cleanup mid-lane.
|
||||||
|
- **Coherence: journey step 12(a), "closing is clean", IS touched** —
|
||||||
|
Ctrl-C teardown of a GPU session is that step, grade movement or not.
|
||||||
|
Revision 1 claimed no journey step, reasoning from grade movement,
|
||||||
|
which §20 explicitly warns against.
|
||||||
- **Gates:** `./scripts/gate --protocol --acceptance
|
- **Gates:** `./scripts/gate --protocol --acceptance
|
||||||
gpu_invocation_acceptance` at minimum; acceptance criterion A2
|
gpu_invocation_acceptance` at minimum; A2 requires `sweep-crdt` green
|
||||||
requires `sweep-crdt` green **three consecutive times** before the
|
**three consecutive runs on the reviewed fixed head of this branch**
|
||||||
fix is believed, since 1/1 is not evidence for a defect that hid from
|
— not "on main", which is unobtainable before approval and merge.
|
||||||
every reduction.
|
1/1 is not evidence for a defect that hid from every reduction.
|
||||||
|
|
||||||
## `scripts/gate` TMPDIR isolation — PR #240 OPEN
|
## `scripts/gate` TMPDIR isolation — PR #240 OPEN
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
# GPU launcher / probe SIGINT teardown — framing
|
# GPU launcher / probe SIGINT teardown — framing
|
||||||
|
|
||||||
Revision 1. Status: **awaiting approval. No implementation.**
|
Revision 2. Status: **awaiting approval. No implementation.**
|
||||||
|
|
||||||
|
Revision 1 was rejected on five findings. Each is answered below, and
|
||||||
|
the two that changed the technical picture — the lifetime arithmetic
|
||||||
|
(§5) and the disposition claim (§3) — are recorded as corrections
|
||||||
|
rather than quietly rewritten.
|
||||||
|
|
||||||
## 1. The problem, stated as what is observed
|
## 1. The problem, stated as what is observed
|
||||||
|
|
||||||
`gpu_invocation_acceptance::crdt::ctrl_c_on_launcher_group_does_not_reach_spawned_daemon`
|
`ctrl_c_on_launcher_group_does_not_reach_spawned_daemon` fails with
|
||||||
fails inside the `sweep-crdt` gate stage with
|
|
||||||
|
|
||||||
```
|
```
|
||||||
child did not exit within 5s (tests/gpu_invocation_acceptance.rs:180, called from :1115)
|
child did not exit within 5s (tests/gpu_invocation_acceptance.rs:180, called from :1115)
|
||||||
|
|
@ -13,148 +17,209 @@ child did not exit within 5s (tests/gpu_invocation_acceptance.rs:180, called f
|
||||||
|
|
||||||
The test spawns `pmacs --gpu --socket <s>` in its own process group
|
The test spawns `pmacs --gpu --socket <s>` in its own process group
|
||||||
(`process_group(0)`, `:1107`), waits for the probe to report
|
(`process_group(0)`, `:1107`), waits for the probe to report
|
||||||
`phase=ready`, sends `SIGINT` to the **group**, and requires the
|
`phase=ready`, sends `SIGINT` to the **group** (`:1113`), and requires
|
||||||
launcher to exit within five seconds.
|
the launcher to exit within five seconds.
|
||||||
|
|
||||||
This is **pre-existing on `main`**. It is not caused by any feature
|
**It fails in two binaries, not one.** `tests/gpu_initial_target_acceptance.rs`
|
||||||
branch: the identical `build-crdt && sweep-crdt` pair run at `72da24a`
|
includes the suite as a module, so a reproducing sweep reds twice.
|
||||||
in a clean worktree with its own target directory fails the same test —
|
Reference run `20260816T064549Z-2144707/09-sweep-crdt.log`:
|
||||||
119 test binaries green, one red.
|
|
||||||
|
| | line | result |
|
||||||
|
|---|---|---|
|
||||||
|
| `gpu_initial_target_acceptance` | 3097 | `FAILED. 14 passed; 1 failed … 5.19s` |
|
||||||
|
| `gpu_invocation_acceptance` | 3131 | `FAILED. 14 passed; 1 failed … 5.18s` |
|
||||||
|
| green result summaries | — | **119** |
|
||||||
|
|
||||||
|
So the correct statement is **119 green result summaries and two red
|
||||||
|
binaries**. Revision 1 said "119 binaries green, one red", which was
|
||||||
|
wrong on both halves.
|
||||||
|
|
||||||
|
**This is pre-existing on `main`.** The identical `build-crdt &&
|
||||||
|
sweep-crdt` pair at `72da24a`, clean worktree, own target directory,
|
||||||
|
fails the same test.
|
||||||
|
|
||||||
## 2. Why this blocks more than one lane
|
## 2. Why this blocks more than one lane
|
||||||
|
|
||||||
`sweep-crdt` is stage 15 of the sixteen-stage `--protocol` gate. While it
|
`sweep-crdt` is stage 15 of the sixteen-stage `--protocol` gate. While
|
||||||
reds, **no branch can present a green gate**, `main` included. The
|
it reds, **no branch can present a green gate**, `main` included.
|
||||||
`panel-mapping-generation` (§5b) lane is complete with its own fifteen
|
`panel-mapping-generation` (§5b) is complete with its own fifteen
|
||||||
stages green and is held behind this lane by explicit instruction.
|
stages green and is held behind this lane by explicit instruction.
|
||||||
|
|
||||||
## 3. Ground truth (cited, not recalled)
|
## 3. Ground truth (cited), and what it does *not* establish
|
||||||
|
|
||||||
- **The launcher does not handle signals.** `run_gpu`
|
- **Neither binary contains signal-handling code.** `run_gpu`
|
||||||
(`src/main.rs:324`) builds a `Command` for the GPU binary and blocks
|
(`src/main.rs:324`) blocks in `command.status()` (`:363`) — a plain
|
||||||
in `command.status()` (`:363`) — a plain `waitpid`. It installs no
|
`waitpid` — with no handler installed. Grepping
|
||||||
handler, so `SIGINT`'s default action should terminate it outright.
|
|
||||||
- **`pmacs-gpu` does not handle signals either.** Grepping
|
|
||||||
`SIGINT|signal_hook|sigaction|ctrlc|set_handler|pthread_sigmask|sigprocmask`
|
`SIGINT|signal_hook|sigaction|ctrlc|set_handler|pthread_sigmask|sigprocmask`
|
||||||
across `pmacs-gpu/src` returns **nothing**. The probe should also die
|
across `pmacs-gpu/src` returns nothing.
|
||||||
on the default action.
|
- **The probe never blocks indefinitely.**
|
||||||
- **The probe never blocks indefinitely.** `run_headless_managed_probe`
|
`run_headless_managed_probe` (`pmacs-gpu/src/main.rs:1065`) loops on
|
||||||
(`pmacs-gpu/src/main.rs:1065`) loops on
|
`event_rx.recv_timeout(Duration::from_millis(50))`.
|
||||||
`event_rx.recv_timeout(Duration::from_millis(50))`, so it wakes twenty
|
- **The daemon *does* handle signals, deliberately.**
|
||||||
times a second regardless of traffic.
|
`src/daemon.rs:629-641` registers `SIGTERM`/`SIGINT` via
|
||||||
- **The daemon *does* handle signals**, and deliberately:
|
|
||||||
`src/daemon.rs:629-641` registers `SIGTERM`/`SIGINT` through
|
|
||||||
`signal_hook::flag`. The daemon is the process the test asserts must
|
`signal_hook::flag`. The daemon is the process the test asserts must
|
||||||
**survive**; it is detached from the launcher's group, which is the
|
**survive**, detached from the launcher's group.
|
||||||
property under test.
|
|
||||||
- **Only one test in the suite uses `process_group(0)`** — this one.
|
|
||||||
|
|
||||||
Taken together the ground truth **deepens** the puzzle rather than
|
**Correction to revision 1.** Revision 1 concluded from the first two
|
||||||
explaining it: two processes with default `SIGINT` disposition, one of
|
bullets that "two processes with default `SIGINT` disposition should
|
||||||
them polling at 50 ms, should both die immediately.
|
both die at once". **That does not follow, and it contradicted this
|
||||||
|
document's own leading hypothesis.** Absence of handler *code* says
|
||||||
|
nothing about runtime *disposition*: `SIG_IGN` is inherited across
|
||||||
|
`fork` **and** survives `exec`, so either process can hold a
|
||||||
|
non-default disposition it never installed — from the test harness,
|
||||||
|
from `cargo`, or from the invoking shell. Inherited ignore is a live
|
||||||
|
candidate precisely because the source is silent. What the source
|
||||||
|
establishes is narrower: **neither binary sets a disposition itself**,
|
||||||
|
so whatever disposition they hold at runtime was inherited, and that is
|
||||||
|
measurable rather than arguable.
|
||||||
|
|
||||||
## 4. What has been ruled out, each by measurement
|
## 4. Reductions attempted — each with command, count, and log
|
||||||
|
|
||||||
Recorded so this lane does not re-run them.
|
Preserved off the tmpfs at
|
||||||
|
`/home/jeans/build/pmacs-gate-targets/probe-sigint-evidence/`, because
|
||||||
|
`/tmp` is a tmpfs and these were nearly lost to a cleanup mid-lane.
|
||||||
|
|
||||||
| hypothesis | how it was refuted |
|
| # | reduction | runs | result | log |
|
||||||
|---|---|
|
|---|---|---|---|---|
|
||||||
| machine load | red on a quiet box, load 2.77 at launch |
|
| R1 | `cargo test --features crdt --test gpu_invocation_acceptance ctrl_c_on_launcher_group` | 3 | green, 0.15–0.17 s | *(console; superseded by R2)* |
|
||||||
| tmpfs starving RAM | `/tmp` 21 G → 1.2 G, available 27 G → 45 G; still red |
|
| R2 | `cargo test --features crdt --test gpu_invocation_acceptance` (whole suite) | 1 | green, 15 passed | `gpu3.log` |
|
||||||
| leaked test daemons | peak 58, only +8 per sweep; green runs already sat at 46–60 |
|
| R3 | `cargo test --workspace --features crdt --no-fail-fast -- --skip basedpyright ctrl_c_on_launcher_group` | 1 | green — every binary runs, only this test executes | `filtered.log` |
|
||||||
| inotify exhaustion | 47 instances in use of 1024 |
|
| R4 | `cargo test --features crdt --lib --test gpu_invocation_acceptance --no-fail-fast` | 1 | green, 2145 + 15 | `two.log` |
|
||||||
| `--workspace` feature unification | same two targets under `--workspace` are green |
|
| R5 | `--test gate_script_acceptance --test gpu_invocation_acceptance` | 1 | green | `suspect.log` |
|
||||||
| a specific preceding test | **all 37 preceding targets + the suite run green** |
|
| R6 | three GPU suites in sweep order (`gpu_font`, `gpu_initial_target`, `gpu_invocation`) | 1 | green | `gpu3.log` |
|
||||||
| later targets / other packages | they run at log lines 4848+, after the failure at 3066 |
|
| R7 | targets 1–19 (incl. `--lib --bins`) + the suite | 1 | green | `half1.log` |
|
||||||
|
| R8 | targets 20–37 + the suite | 1 | green | `half2.log` |
|
||||||
|
| R9 | **all 37 preceding targets** + the suite | 1 | green | `prefix.log` |
|
||||||
|
| R10 | `--workspace` with only `gpu_initial_target` + `gpu_invocation` | 1 | green | `wsonly.log` |
|
||||||
|
| F1–F5 | full `cargo test --workspace --features crdt --no-fail-fast -- --skip basedpyright` | 5 | **red, 5/5** | `base-sweep.log` (at `72da24a`), `postclean.log`, `sweep-inst.log`, `sweep-diag.log`, gate `…-2144707` |
|
||||||
|
|
||||||
**The last row is the strange one and is the real shape of this
|
**R9 is the shape of the problem.** The same binaries, in the same
|
||||||
problem**: the same binaries, in the same order, with the same tests
|
order, with the same tests before it, pass as a subset and fail as part
|
||||||
before it, pass as a subset and fail as part of the whole 119-target
|
of the whole. R10 rules out `--workspace` feature unification; other
|
||||||
sweep. Reproduction is 5/5 in the full sweep across two trees, and 0/N
|
packages' targets run at log lines 4848+, after the failure at 3066, so
|
||||||
in every reduction attempted.
|
they cannot be implicated either.
|
||||||
|
|
||||||
## 5. One retracted claim, kept as a warning
|
Also refuted, by measurement: machine load (red on a quiet box, load
|
||||||
|
2.77); tmpfs starving RAM (**tested by experiment** — `/tmp` 21 G →
|
||||||
|
1.2 G, available 27 G → 45 G, still red); leaked daemons (peak 58, +8
|
||||||
|
per sweep, green runs already at 46–60); inotify (47 of 1024).
|
||||||
|
|
||||||
An earlier attempt reported the mechanism as "the launcher blocks in
|
## 5. Two retracted claims, both mine, kept as warnings
|
||||||
`do_wait` on a probe child stuck in `futex_do_wait`". **That was
|
|
||||||
retracted on its own evidence.** The sampler behind it caught 394
|
|
||||||
launchers and the longest-lived was **5 s total**; the failing instance
|
|
||||||
must outlive its `SIGINT` by 5 s, so its lifetime would be 8 s or more.
|
|
||||||
What was described is a *healthy* teardown from another test in the
|
|
||||||
suite. The pair is worth keeping only as the normal shape.
|
|
||||||
|
|
||||||
The lesson binds this lane's first step: **an instrument that samples
|
**Claim A — "mechanism located".** Reported the launcher blocked in
|
||||||
every launcher and hopes to catch the failing one is not good enough.**
|
`do_wait` on a probe child in `futex_do_wait`.
|
||||||
|
|
||||||
|
**Claim B — the retraction of A.** Argued A was unsupported because the
|
||||||
|
failing launcher "must live ≥ 8 s" while the sampler's longest-lived
|
||||||
|
was 5 s.
|
||||||
|
|
||||||
|
**Claim B's arithmetic is false.** Both reproducing binaries finish in
|
||||||
|
**~5.19 s including the five-second timeout** (`:3097`, `:3131`), so
|
||||||
|
`phase=ready` is reached in roughly a tenth of a second and the failing
|
||||||
|
launcher lives about **5.1 s total** — squarely inside what the sampler
|
||||||
|
observed. A ">6 s" selector would therefore have captured **nothing**,
|
||||||
|
repeating the very sampling error it was written to correct.
|
||||||
|
|
||||||
|
So A is **not** refuted by B. A remains **unproven for a different
|
||||||
|
reason**: the suite spawns launchers from **five** call sites
|
||||||
|
(`:38, :65, :509, :534, :544, :574, :725, :1097` — eight `--gpu`
|
||||||
|
arguments across the file), so a launcher captured by command line
|
||||||
|
alone cannot be attributed to *this* test. The `do_wait` /
|
||||||
|
`futex_do_wait` pair is consistent with the failing instance and
|
||||||
|
consistent with a healthy sibling, and nothing recorded distinguishes
|
||||||
|
them.
|
||||||
|
|
||||||
|
The standing lesson is now the opposite of revision 1's: **do not key
|
||||||
|
on process age at all.** Key on identity.
|
||||||
|
|
||||||
## 6. Bets
|
## 6. Bets
|
||||||
|
|
||||||
1. The failure is a real teardown defect reachable by a user pressing
|
1. **The failure is a real teardown defect** — a user pressing Ctrl-C
|
||||||
Ctrl-C, not a test artifact — because the test asserts an ordinary
|
on `pmacs --gpu` sees the same hang. **This is a bet, not a
|
||||||
product property and the two binaries involved carry no signal
|
finding**, and the current witness does not reach the real GUI
|
||||||
handling at all.
|
path: it goes through a wrapper script and `--headless-managed-probe`
|
||||||
|
(`:1090-1093`), not a live wgpu frontend. Confirming or dropping this
|
||||||
|
bet is D4 below.
|
||||||
2. It is **not** a timing margin. A green run finishes in 0.15 s against
|
2. It is **not** a timing margin. A green run finishes in 0.15 s against
|
||||||
a 5 s deadline (33×). A margin that large does not erode; something
|
a 5 s deadline — 33×. Margins that large do not erode.
|
||||||
different happens.
|
3. Therefore **raising the deadline is not a fix** and is out of scope.
|
||||||
3. Therefore **raising the deadline is not a fix** and is explicitly out
|
If the conclusion turns out to be that the deadline is wrong, that
|
||||||
of scope. If the conclusion turns out to be that the deadline is
|
needs its own argument and its own approval.
|
||||||
wrong, that requires its own argument and its own approval.
|
|
||||||
|
|
||||||
## 7. First step — an instrument that keys on the failing instance
|
## 7. First step — diagnostics keyed on identity, not age
|
||||||
|
|
||||||
No fix is proposed yet, because the mechanism is unknown. The first
|
No fix is proposed; the mechanism is unknown. The first commit is
|
||||||
commit is diagnostic only:
|
diagnostic only, and it must **discriminate** the three live candidates:
|
||||||
|
blocked delivery, inherited ignore, and an escaped or wrong process
|
||||||
|
group.
|
||||||
|
|
||||||
- **D1.** Sample only launchers whose lifetime exceeds ~6 s, so the
|
- **D1 — key on the PID this test records.** The test already owns
|
||||||
failing instance is the *only* thing recorded, and capture for it:
|
`launcher.id()`. Capture around its own `kill`, not by scanning for
|
||||||
`/proc/<pid>/status` (`SigBlk`, `SigIgn`, `SigCgt`, `State`), the
|
age or command line.
|
||||||
per-thread `wchan` under `/proc/<pid>/task/*/wchan`, and the same for
|
- **D2 — snapshot before *and* after the signal**, for the test parent,
|
||||||
every child. `SigIgn`/`SigBlk` answers directly whether `SIGINT` was
|
the launcher, and the probe:
|
||||||
ignored or blocked — including whether it was **inherited**, since
|
- `SigIgn`, `SigCgt`, `SigBlk` — **per thread**, from
|
||||||
`SIG_IGN` survives both `fork` and `exec` while handlers do not.
|
`/proc/<pid>/task/*/status`, since `SigBlk` is thread-specific and
|
||||||
- **D2.** Record whether the launcher had already reaped its child at
|
a process-wide reading would hide a blocked delivery on the one
|
||||||
the moment the deadline expired, which separates "the child will not
|
thread that matters;
|
||||||
die" from "the launcher will not notice".
|
- `SigPnd` and `ShdPnd` — a pending-but-undelivered `SIGINT` is
|
||||||
- **D3.** Run the full sweep under D1/D2 until the failure is captured
|
exactly what distinguishes blocked delivery from ignore;
|
||||||
**with** its diagnostics, and only then propose a fix.
|
- `PID`, `PPID`, `PGID`, `SID` for each — which settles whether the
|
||||||
|
signal was even addressed to the right group, and whether anything
|
||||||
|
escaped it.
|
||||||
|
A post-failure snapshot alone cannot prove inheritance; the
|
||||||
|
before/after pair is what makes the claim provable.
|
||||||
|
- **D3 — run the full sweep under D1/D2 until the failure is captured
|
||||||
|
*with* its diagnostics.** Only then propose a fix.
|
||||||
|
- **D4 — settle bet 1 separately.** Establish whether a real
|
||||||
|
`pmacs --gpu` session, not the wrapper/headless probe, reproduces the
|
||||||
|
hang. The answer decides whether A5 is an obligation or is dropped.
|
||||||
|
|
||||||
## 8. Acceptance criteria for the eventual fix
|
## 8. Acceptance criteria for the eventual fix
|
||||||
|
|
||||||
Deliberately written now, so the fix cannot quietly become "make the
|
Written now so the fix cannot quietly become "make the test pass".
|
||||||
test pass".
|
|
||||||
|
|
||||||
- **A1.** The named mechanism is stated and demonstrated, not inferred:
|
- **A1.** The mechanism is stated and demonstrated, not inferred: a
|
||||||
a witness that fails before the change and passes after, plus a
|
witness failing before the change and passing after, plus a mutation
|
||||||
mutation showing the witness bites its own clause.
|
showing the witness bites its own clause.
|
||||||
- **A2.** `sweep-crdt` green on `main` for **three consecutive full
|
- **A2.** `sweep-crdt` green for **three consecutive full runs on the
|
||||||
runs** — 1/1 is not evidence for a defect that hid from every
|
reviewed fixed head of this branch**. Not "on main" — that is
|
||||||
reduction.
|
unobtainable before this lane is approved, gated and merged, and
|
||||||
- **A3.** The reduction paradox is explained or explicitly recorded as
|
revision 1 stated an impossible precondition. Post-merge
|
||||||
unexplained. If the fix makes the sweep green without accounting for
|
confirmation on `main` is a follow-up, not a gate on the fix.
|
||||||
why subsets always passed, that gap is stated in the record rather
|
- **A3.** The R9 paradox is explained, or explicitly recorded as
|
||||||
than left for the next reader to rediscover.
|
unexplained. A fix that greens the sweep without accounting for why
|
||||||
- **A4.** No deadline is raised, and no test is skipped, retried, or
|
every subset passed leaves a gap, and the gap is stated rather than
|
||||||
serialised to obtain green.
|
left for the next reader.
|
||||||
- **A5.** If the mechanism proves to be in `pmacs-gpu`'s shutdown path,
|
- **A4.** No deadline raised, no test skipped, retried, or serialised
|
||||||
a Ctrl-C on a real `pmacs --gpu` session tears down the frontend and
|
to obtain green.
|
||||||
leaves the daemon running — the product property the test encodes.
|
- **A5.** **Conditional on D4.** If bet 1 holds, this is unconditional:
|
||||||
|
Ctrl-C on a real `pmacs --gpu` session tears down the frontend and
|
||||||
|
leaves the daemon running. If D4 shows the hang is reachable only
|
||||||
|
through the wrapper/headless path, bet 1 is dropped, A5 is struck,
|
||||||
|
and the lane is recorded as gate-correctness only.
|
||||||
|
|
||||||
## 9. Coherence impact (`COHERENCE.md` §20)
|
## 9. Coherence impact (`COHERENCE.md` §20)
|
||||||
|
|
||||||
- **Journey steps touched: none.** This is a teardown-correctness and
|
- **Journey step touched: 12(a), "closing is clean."** Ctrl-C teardown
|
||||||
gate-trustworthiness lane; no journey step changes grade.
|
of a GPU session is exactly that step, whether or not its grade
|
||||||
|
moves. **Revision 1 said "journey steps touched: none", which was
|
||||||
|
false** — it reasoned from grade movement, which §20 explicitly warns
|
||||||
|
against.
|
||||||
|
- **Grade movement: none expected.** This restores a property that is
|
||||||
|
supposed to hold, rather than opening a new one.
|
||||||
- **Interaction islands: none added.**
|
- **Interaction islands: none added.**
|
||||||
- **Config registry: not touched.**
|
- **Config registry: not touched. Background-work attribution: not
|
||||||
- **Background-work attribution: not touched.**
|
touched.**
|
||||||
|
- Beyond step 12(a), what this lane restores is every *other* lane's
|
||||||
Naming these explicitly matters: a reader auditing §20 by grade movement
|
ability to prove itself, since no branch can show a green gate while
|
||||||
would otherwise conclude this lane touches nothing, when what it
|
stage 15 reds.
|
||||||
restores is the ability of every other lane to prove itself.
|
|
||||||
|
|
||||||
## 10. Out of scope
|
## 10. Out of scope
|
||||||
|
|
||||||
- Raising or removing the 5 s deadline (bet 3).
|
- Raising or removing the 5 s deadline (bet 3).
|
||||||
- The ~10 daemons each sweep leaks. Real, separately recorded, and not
|
- The ~10 daemons each sweep leaks — real, separately recorded, and not
|
||||||
implicated here — green runs already ran at 46–60 leaked daemons.
|
implicated: green runs already ran at 46–60 leaked daemons.
|
||||||
- The `gpu_initial_target_acceptance` binary including this suite as a
|
- `gpu_initial_target_acceptance` including the suite as a module. It
|
||||||
module, which makes a reproducing sweep report the failure twice. A
|
is why the failure reds twice, and it is a tidiness question, not a
|
||||||
tidiness question, not a correctness one.
|
correctness one.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue