docs(framing): revision 12 --- retract the survivors, select R-b + R-d
Two record defects plus the remedy decision. 1. Withdrawn claims were still asserted elsewhere. The header and §4c's consequences still said bet 1 FALSIFIED, A5 STRUCK, and that a real pmacs --gpu "behaves correctly" --- none of which D4 established, since D4 never ran. Both now say withdrawn/retired BY SCOPE, with the explicit note that nothing here shows a real session is correct, only that no observed evidence of a user-facing defect survives. §4c's pre_exec-implies-assertion conclusion is replaced by a pointer to §7b/§7c. A3/D0b are marked SATISFIED by the controlled explanation --- D0b is not owed and will not run. §9's "Beyond step 12(a)" is gone, since no journey step is touched. The ledger no longer says implementation-absent, mechanism-unknown, or D1/D2-next. 2. Provenance made portable. Both arm commands are fully expanded rather than delegating to a machine-local arms.sh. Full SHA-256 of the two executed binaries are recorded; the 16-character log values are relabelled PREFIXES and carry no claim. The standalone foreground/background SigIgn table is labelled UNRECORDED CORROBORATION --- read ad hoc, no head, no log, no digest --- and the portable probe supersedes it as the recorded check. Remedy selected, §7c: R-b + R-d through one checked-in helper wrapping a behavioural probe --- sh -c 'trap "exit 23" 2; kill -INT $$; exit 0' --- which exits 23 when SIGINT is deliverable and 0 when inherited as ignored. Verified here in both contexts. POSIX shell only, so it answers §7b's portability criterion: no /proc, so not Linux-only, and no sigaction, so no unsafe. scripts/gate fails immediately with the explicit diagnosis; the target test reports the same precondition failure if run directly; no override, because a gate under ignored SIGINT cannot produce valid evidence. R-c rejected. The Linux-only D1/D2 instrumentation is removed once its evidence is portable. A1-A5 are replaced for the new work --- guard bite, direct-test diagnosis, foreground success unaffected, mutation, and an otherwise unchanged gate --- with the old teardown criteria kept in §8b, marked non-binding, so the change of target is visible rather than silent. 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
57d8dae511
commit
ab43132da5
|
|
@ -1,14 +1,14 @@
|
||||||
# GPU launcher / probe SIGINT teardown — framing
|
# GPU launcher / probe SIGINT teardown — framing
|
||||||
|
|
||||||
Revision 11. Status: **MECHANISM FOUND (§4c). Awaiting approval — the
|
Revision 12. Status: **MECHANISM FOUND (§4c), REMEDY SELECTED (§7c).
|
||||||
problem statement has changed, so the remedy in §7/§8 no longer
|
Awaiting approval.**
|
||||||
follows.**
|
|
||||||
|
|
||||||
Revision 10 was approved 2026-08-19 at `4fba9f6`, authorising
|
Revision 10 was approved 2026-08-19 at `4fba9f6`, authorising
|
||||||
diagnostic-only D1/D2. They ran, and found the mechanism on the first
|
diagnostic-only D1/D2. They ran, and found the mechanism on the first
|
||||||
reproducing sweep. It is not what this document was built around: bet 1
|
reproducing sweep. It is not what this document was built around: bet 1
|
||||||
is falsified, A5 is struck, and nothing is wrong with the probe's
|
is **withdrawn by scope** and A5 **retired by scope** (D4 was never
|
||||||
shutdown path.
|
executed, so no claim is made about a real session either way), and
|
||||||
|
nothing in the evidence implicates the probe's shutdown path.
|
||||||
|
|
||||||
Revision 9 was approved 2026-08-19 at `15c25ec`. **That approval did
|
Revision 9 was approved 2026-08-19 at `15c25ec`. **That approval did
|
||||||
not extend to revision 10**, because retiring D0b (§7) materially
|
not extend to revision 10**, because retiring D0b (§7) materially
|
||||||
|
|
@ -399,10 +399,12 @@ ten-minute cap truncating gate runs. **That is the "onset".**
|
||||||
|
|
||||||
### Consequences for the contract
|
### Consequences for the contract
|
||||||
|
|
||||||
- **Bet 1 is FALSIFIED, and A5 is struck** under its own D4 condition.
|
- **Bet 1 is WITHDRAWN BY SCOPE; A5 is RETIRED BY SCOPE.** D4 was
|
||||||
An interactive terminal does not ignore `SIGINT`, so Ctrl-C on a real
|
never executed, so **nothing here establishes that a real
|
||||||
`pmacs --gpu` session behaves correctly. This is not a defect a user
|
`pmacs --gpu` session behaves correctly** — only that no observed
|
||||||
can meet.
|
evidence of a user-facing defect survives, every red run being
|
||||||
|
explained by the runner's invocation. Any user-facing claim needs its
|
||||||
|
own lane and its own evidence.
|
||||||
- **The §7/§8 remedy no longer follows.** What remains is narrower and
|
- **The §7/§8 remedy no longer follows.** What remains is narrower and
|
||||||
genuinely real:
|
genuinely real:
|
||||||
1. **The gate must not be invoked so that `SIGINT` is ignored** — a
|
1. **The gate must not be invoked so that `SIGINT` is ignored** — a
|
||||||
|
|
@ -417,9 +419,10 @@ ten-minute cap truncating gate runs. **That is the "onset".**
|
||||||
D0b: the difference was invocation mode, demonstrated in both
|
D0b: the difference was invocation mode, demonstrated in both
|
||||||
directions.
|
directions.
|
||||||
|
|
||||||
`#![forbid(unsafe_code)]` rules out `pre_exec`, so remedy 2 is a
|
`#![forbid(unsafe_code)]` rules out `pre_exec` as one *mechanism*; it
|
||||||
precondition assertion rather than a repair — but that is a design
|
does **not** select the remedy, and revision 11's leap from the first to
|
||||||
question for the next revision, not a decision taken here.
|
the second did not follow. §7b weighs the candidates and §7c records
|
||||||
|
the decision.
|
||||||
|
|
||||||
## 5. Two retracted claims, both mine, kept as warnings
|
## 5. Two retracted claims, both mine, kept as warnings
|
||||||
|
|
||||||
|
|
@ -580,11 +583,12 @@ group.
|
||||||
measure the mechanism itself. Sharpening an indirect instrument while
|
measure the mechanism itself. Sharpening an indirect instrument while
|
||||||
a direct one is in hand is the wrong order of work.
|
a direct one is in hand is the wrong order of work.
|
||||||
|
|
||||||
**The obligation is not discharged.** A3 still binds: if D1/D2 do not
|
**The obligation is now SATISFIED, by explanation rather than by
|
||||||
account for why every subset passed while the full sweep fails,
|
running D0b.** A3 asked that the subset/full difference be accounted
|
||||||
**D0b runs before this lane closes**, and its result is recorded
|
for: §4c accounts for it — every subset ran foreground and every full
|
||||||
either way. Retiring it as a *precondition* does not retire the
|
sweep backgrounded, and the controlled arms demonstrate the
|
||||||
question.
|
difference in both directions with byte-identical binaries. **D0b is
|
||||||
|
therefore not owed and will not run.**
|
||||||
|
|
||||||
As written, the retired step read: re-run the §4 matrix, at `main`,
|
As written, the retired step read: re-run the §4 matrix, at `main`,
|
||||||
recording the artifact hashes actually executed **at run time**.
|
recording the artifact hashes actually executed **at run time**.
|
||||||
|
|
@ -647,9 +651,76 @@ Whichever is chosen must state what it does on a non-`/proc` unix.
|
||||||
|
|
||||||
No remedy is implemented, and none is selected here.
|
No remedy is implemented, and none is selected here.
|
||||||
|
|
||||||
## 8. Acceptance criteria for the eventual fix
|
## 7c. Remedy — SELECTED: R-b + R-d, via one portable probe
|
||||||
|
|
||||||
Written now so the fix cannot quietly become "make the test pass".
|
**Decided 2026-08-19.** R-b (early gate guard) and R-d (test-local
|
||||||
|
precondition diagnosis), implemented through a **single checked-in
|
||||||
|
helper** built on a behavioural probe rather than `/proc` or `unsafe`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sh -c 'trap "exit 23" 2; kill -INT $$; exit 0'
|
||||||
|
```
|
||||||
|
|
||||||
|
It sends itself `SIGINT`. If the signal is deliverable the trap runs and
|
||||||
|
it exits **23**; if `SIGINT` was inherited as `SIG_IGN` the kill is a
|
||||||
|
no-op and it exits **0**. Verified in both contexts: 23 foreground, 0
|
||||||
|
under `setsid nohup … &`.
|
||||||
|
|
||||||
|
This is **POSIX shell only** — `trap`, `kill`, `$$` — so it settles the
|
||||||
|
portability question §7b raised: no `/proc`, hence not Linux-only, and
|
||||||
|
no `sigaction`, hence no `unsafe`.
|
||||||
|
|
||||||
|
**Both consumers use the same helper**, so the guard and the test can
|
||||||
|
never disagree about what "ignored" means:
|
||||||
|
|
||||||
|
- **`scripts/gate` fails immediately**, before any stage, with an
|
||||||
|
explicit ignored-`SIGINT` diagnosis.
|
||||||
|
- **The target test invokes it** and reports the same precondition
|
||||||
|
failure if run directly, instead of "child did not exit within 5s".
|
||||||
|
|
||||||
|
**No override.** A full gate run under ignored `SIGINT` cannot produce
|
||||||
|
valid evidence, so there is no flag to proceed anyway — a switch that
|
||||||
|
lets the gate run in a state where several suites are meaningless would
|
||||||
|
recreate exactly the failure this lane spent nine revisions on.
|
||||||
|
|
||||||
|
**R-c is rejected**: restoring the child's disposition needs
|
||||||
|
`pre_exec`, which is `unsafe`, and dodging a project invariant to make
|
||||||
|
one test invocation-independent is not a trade this lane will make.
|
||||||
|
|
||||||
|
**The Linux-only D1/D2 instrumentation is removed** once its evidence is
|
||||||
|
portable — it read `/proc`, it has produced its finding, and leaving it
|
||||||
|
in place would carry a platform dependency for no further return.
|
||||||
|
|
||||||
|
## 8. Acceptance criteria — REPLACED for the selected remedy
|
||||||
|
|
||||||
|
The A1–A5 written for a teardown fix no longer describe this work; they
|
||||||
|
are superseded wholesale. What the guard-and-diagnosis change must
|
||||||
|
show:
|
||||||
|
|
||||||
|
- **A1 — the guard bites.** `scripts/gate` invoked with `SIGINT`
|
||||||
|
ignored exits immediately, before any stage runs, naming the ignored
|
||||||
|
signal as the reason.
|
||||||
|
- **A2 — the direct-test diagnosis bites.** The target test run
|
||||||
|
directly with `SIGINT` ignored fails with the precondition message,
|
||||||
|
**not** with "child did not exit within 5s".
|
||||||
|
- **A3 — foreground success is unaffected.** Both target copies pass
|
||||||
|
foreground, and the guard does not fire, so the remedy costs nothing
|
||||||
|
in the normal case.
|
||||||
|
- **A4 — mutation.** Removing the probe's `trap`, or treating exit 0 as
|
||||||
|
"deliverable", makes A1 and A2 fail; each mutation is named against
|
||||||
|
the row it must bite.
|
||||||
|
- **A5 — the gate is otherwise unchanged**: a normal foreground run
|
||||||
|
reaches and passes every stage it did before, with no stage added,
|
||||||
|
skipped, reordered, or made conditional.
|
||||||
|
|
||||||
|
## 8b. Superseded criteria, kept for the record
|
||||||
|
|
||||||
|
These were written for a teardown fix that is no longer the work. They
|
||||||
|
are retained so the change of target is visible rather than silent;
|
||||||
|
**none of them binds.**
|
||||||
|
|
||||||
|
Written when this lane still expected a teardown repair. **Superseded
|
||||||
|
by §8**; kept verbatim below.
|
||||||
|
|
||||||
- **A1.** The mechanism is stated and demonstrated, not inferred: a
|
- **A1.** The mechanism is stated and demonstrated, not inferred: a
|
||||||
witness failing before the change and passing after, plus a mutation
|
witness failing before the change and passing after, plus a mutation
|
||||||
|
|
@ -694,9 +765,9 @@ Written now so the fix cannot quietly become "make the test pass".
|
||||||
- **Interaction islands: none added.**
|
- **Interaction islands: none added.**
|
||||||
- **Config registry: not touched. Background-work attribution: not
|
- **Config registry: not touched. Background-work attribution: not
|
||||||
touched.**
|
touched.**
|
||||||
- Beyond step 12(a), what this lane restores is every *other* lane's
|
- What the lane restores is every *other* lane's ability to prove
|
||||||
ability to prove itself, since no branch can show a green gate while
|
itself: while the gate can be run in a state where several suites are
|
||||||
stage 15 reds.
|
meaningless, a red stage 15 tells you nothing about the branch.
|
||||||
|
|
||||||
## 10. Out of scope
|
## 10. Out of scope
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -179,29 +179,65 @@ cargo test --features crdt --no-fail-fast \
|
||||||
-- ctrl_c_on_launcher_group
|
-- ctrl_c_on_launcher_group
|
||||||
```
|
```
|
||||||
|
|
||||||
Outer invocation, the only difference:
|
Outer invocation, the only difference. `arms.sh` is machine-local, so
|
||||||
|
the commands are given **fully expanded** — a reader elsewhere needs no
|
||||||
|
access to it:
|
||||||
|
|
||||||
```
|
```
|
||||||
fg: /home/jeans/build/pmacs-gate-targets/d0a/arms.sh fg
|
# fg arm
|
||||||
bg: setsid nohup /home/jeans/build/pmacs-gate-targets/d0a/arms.sh bg > /dev/null 2>&1 & disown
|
cd /home/jeans/Repos/personal/pmacs-probe-sigint && \
|
||||||
|
env TMPDIR=/home/jeans/build/pmacs-gate-targets/tmp/arms \
|
||||||
|
CARGO_TARGET_DIR=/home/jeans/build/pmacs-gate-targets/pmacs-probe-sigint-84ed0f9e \
|
||||||
|
cargo test --features crdt --no-fail-fast \
|
||||||
|
--test gpu_invocation_acceptance --test gpu_initial_target_acceptance \
|
||||||
|
-- ctrl_c_on_launcher_group
|
||||||
|
|
||||||
|
# bg arm — byte-identical inner command, wrapped:
|
||||||
|
setsid nohup sh -c '<the fg command above>' > <log> 2>&1 & disown
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The wrapper additionally recorded `git rev-parse HEAD`,
|
||||||
|
`git status --porcelain | wc -l`, the exit status, both copies'
|
||||||
|
results, the executed suffixes, their hashes, and the log digest.
|
||||||
|
|
||||||
| arm | outer | exit | ok | failed | `SigIgn` | binary hashes | log sha256/16 |
|
| arm | outer | exit | ok | failed | `SigIgn` | binary hashes | log sha256/16 |
|
||||||
|---|---|---|---|---|---|---|---|
|
|---|---|---|---|---|---|---|---|
|
||||||
| fg | foreground | 0 | 2 | 0 | not captured (no failure ⇒ no dump) | `91f51d0b…`=`0890b78cca22ac1e`, `6b4b8223…`=`ef6ff1c15e11062a` | `aaec01673691479a` |
|
| fg | foreground | 0 | 2 | 0 | not captured (no failure ⇒ no dump) | `aaec01673691479a…` (prefix) |
|
||||||
| bg | `setsid nohup … &` | 101 | 0 | 2 | `0000000000001007` | **identical**: `0890b78cca22ac1e`, `ef6ff1c15e11062a` | `c744d85a84cb8683` |
|
| bg | `setsid nohup … &` | 101 | 0 | 2 | `0000000000001007` | `c744d85a84cb8683…` (prefix) |
|
||||||
|
|
||||||
**The binaries are byte-identical across arms** — same hashes, same
|
Both arms executed the same two binaries, whose **full** SHA-256 are:
|
||||||
head, same target directory, `dirty=0` — so nothing but the outer
|
|
||||||
invocation varies. `arms.tsv` holds the raw rows.
|
|
||||||
|
|
||||||
### Disposition, measured directly
|
```
|
||||||
|
gpu_initial_target_acceptance-91f51d0b5303ff9f
|
||||||
|
0890b78cca22ac1e80b79845f85fb6e88def3330db15ae123a2a672d3084124c
|
||||||
|
gpu_invocation_acceptance-6b4b8223dea45247
|
||||||
|
ef6ff1c15e11062ab53a075763814f32c1bbc9be1b146d068c60e91fa247c696
|
||||||
|
```
|
||||||
|
|
||||||
|
Same head, same target directory, `dirty=0`, and the binaries were not
|
||||||
|
rebuilt between arms — so nothing but the outer invocation varies. The
|
||||||
|
**log** digests above are 16-character **prefixes**, not full values,
|
||||||
|
and are identifiers only; no claim rests on them.
|
||||||
|
|
||||||
|
### Disposition — UNRECORDED CORROBORATION, not a controlled arm
|
||||||
|
|
||||||
|
This table was read ad hoc from `/proc/self/status` in the two shells
|
||||||
|
and **its runs were not captured**: no head, no cleanliness, no log,
|
||||||
|
no digest. It agrees with the arms above and with §4c's capture, and it
|
||||||
|
is labelled separately for that reason — it corroborates, it does not
|
||||||
|
evidence.
|
||||||
|
|
||||||
| context | child `SigIgn` | `SIGINT` |
|
| context | child `SigIgn` | `SIGINT` |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| foreground | `0000000000001000` | bit 12 (SIGPIPE) only — deliverable |
|
| foreground | `0000000000001000` | bit 12 (SIGPIPE) only — deliverable |
|
||||||
| `setsid nohup … &` | `0000000000000007` | SIGHUP, SIGINT, SIGQUIT — ignored |
|
| `setsid nohup … &` | `0000000000000007` | SIGHUP, SIGINT, SIGQUIT — ignored |
|
||||||
|
|
||||||
|
The portable probe adopted as the remedy (framing §7c) supersedes it as
|
||||||
|
the *recorded* mechanism check:
|
||||||
|
`sh -c 'trap "exit 23" 2; kill -INT $$; exit 0'` exits **23** when
|
||||||
|
`SIGINT` is deliverable and **0** when it is inherited as ignored.
|
||||||
|
Verified in both contexts.
|
||||||
|
|
||||||
### The first D1/D2 capture, and why it is superseded
|
### The first D1/D2 capture, and why it is superseded
|
||||||
|
|
||||||
The capture quoted in framing §4c came from `d12.log`, which finished
|
The capture quoted in framing §4c came from `d12.log`, which finished
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue