From 1219e0df4b2be13cb44fda4d23115df8762f9d0b Mon Sep 17 00:00:00 2001 From: Stuart Kerr Date: Mon, 3 Aug 2026 16:45:18 -0400 Subject: [PATCH 1/2] fix(hooks): drain held-open Windows input --- docs/adr/0055-proactivity-that-meshes.md | 1 + plugin/scripts/hook-input.mjs | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/docs/adr/0055-proactivity-that-meshes.md b/docs/adr/0055-proactivity-that-meshes.md index 7302acfd..077225e3 100644 --- a/docs/adr/0055-proactivity-that-meshes.md +++ b/docs/adr/0055-proactivity-that-meshes.md @@ -681,6 +681,7 @@ clause as the pre-agreed escalation (§3.5); Task-prompt scanning — Fable's re delegation drift goes to the interrupt tier (§3.7.9). ## Currency log +| 2026-08-03 | Bounded the shared hook-input parser on Windows inherited pipes by draining readable bytes and polling until the existing idle/empty deadlines. | Post-merge main CI run `30847567626` failed only `swarm-slot-recycler.test.mjs` on Windows because the held-open envelope was not surfaced through `data`; `tests/unit/swarm-slot-recycler.test.mjs` and `tests/unit/hook-input.test.mjs` pass 43/43 after the platform-specific parser fix. | | 2026-08-03 | Re-read the proactive hook mesh after the Codex staged-host correction; no contract change. | PR #100 exact-SHA release evidence is green; Windows unit remains the sole required red lane. | | Date | What changed | Why (with referents) | diff --git a/plugin/scripts/hook-input.mjs b/plugin/scripts/hook-input.mjs index ae65c36a..f7c478c4 100644 --- a/plugin/scripts/hook-input.mjs +++ b/plugin/scripts/hook-input.mjs @@ -54,11 +54,14 @@ export function readStdinBounded({ maxBytes = 65536, idleMs = 50, emptyMs = 250 let settled = false; let idleTimer; let emptyTimer; + let poll; const cleanup = () => { clearTimeout(idleTimer); clearTimeout(emptyTimer); + clearInterval(poll); process.stdin.off('data', onData); + process.stdin.off('readable', onReadable); process.stdin.off('end', onEnd); process.stdin.off('error', onError); process.stdin.pause(); @@ -87,11 +90,20 @@ export function readStdinBounded({ maxBytes = 65536, idleMs = 50, emptyMs = 250 }; const onEnd = () => finish(); const onError = () => finish(); + // Windows inherited pipes can expose bytes through the readable interface without emitting + // a data event while the writer keeps stdin open. Drain that interface and poll it briefly; + // the envelope contract is one value, never EOF. + const onReadable = () => { + let chunk; + while ((chunk = process.stdin.read()) !== null) onData(chunk); + }; process.stdin.on('data', onData); + if (process.platform === 'win32') process.stdin.on('readable', onReadable); process.stdin.once('end', onEnd); process.stdin.once('error', onError); emptyTimer = setTimeout(finish, emptyMs); + if (process.platform === 'win32') poll = setInterval(onReadable, 10); process.stdin.resume(); }); } From b18ce02747ae9c1500df89b1d06b29115f83216c Mon Sep 17 00:00:00 2001 From: Stuart Kerr Date: Mon, 3 Aug 2026 16:46:16 -0400 Subject: [PATCH 2/2] fix(release): reject failed stranger evidence triggers --- .github/workflows/release-aggregate.yml | 3 +++ docs/adr/0062-remote-durable-release-transaction.md | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-aggregate.yml b/.github/workflows/release-aggregate.yml index 6ee3716a..c616392d 100644 --- a/.github/workflows/release-aggregate.yml +++ b/.github/workflows/release-aggregate.yml @@ -22,6 +22,9 @@ permissions: jobs: release-aggregate: name: release-aggregate + # Failed stranger runs have no binding receipt; only successful workflow_run events and + # explicit recovery dispatches are valid aggregate inputs. + if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-latest timeout-minutes: 20 steps: diff --git a/docs/adr/0062-remote-durable-release-transaction.md b/docs/adr/0062-remote-durable-release-transaction.md index fb96696b..73d86ca1 100644 --- a/docs/adr/0062-remote-durable-release-transaction.md +++ b/docs/adr/0062-remote-durable-release-transaction.md @@ -3,7 +3,7 @@ id: ADR-062 title: Remote-durable staged release transaction status: Accepted date: 2026-08-02 -updated: 2026-08-02 +updated: 2026-08-03 authors: [Stuart Kerr] tags: [release, evidence, transaction, npm, github, receipts, recovery] supersedes: [] @@ -12,6 +12,7 @@ governs: - .github/workflows/ci.yml - .github/workflows/stranger-matrix.yml - .github/workflows/protected-release.yml + - .github/workflows/release-aggregate.yml - scripts/release.mjs - scripts/release-transaction.mjs - scripts/release-transaction-provider.mjs @@ -21,6 +22,12 @@ governs: # ADR-062 — Remote-durable staged release transaction +## Currency log + +| Date | What changed | Why (with referents) | +|---|---|---| +| 2026-08-03 | `release-aggregate` now runs only for a successful stranger-matrix completion or explicit recovery dispatch. | Post-merge run `30847604771` attempted to download `stranger-evidence-9de40a59…` from a failed run with no artifact; run `30848438803` then proved successful stranger evidence still waits for exact-SHA CI convergence. `.github/workflows/release-aggregate.yml`. | + **Status**: Accepted **Date**: 2026-08-02