Repository navigation
zmx seed daemon inherits redirected pipes and prevents bounded EOF attestation #834
Description
Describe the bug
The live capture core cannot finish attesting an exited daemonising zmx seed when the daemon inherits the launcher's redirected stdout/stderr pipes. The owned launcher exits, but its daemon keeps those pipes open; the required bounded both-stream EOF never arrives. The single coordinator B slot stopped before any GraphCode GUI launch or image capture.
To reproduce
Steps to reproduce the behavior:
- Historical run
cdba36a51f144798b40fd78bdb50251bused the unchanged production supervisor at source944ee565ed2e36885b8cf1087fc5fbe2d05d38b6(full tree identical to merged mainbadcf5149be2a01abd866e4cf180521f485fa2c4) and pinned zmx source785b3fd15dcafd1882b495c831a10f98c201b908. - The B worker launches its real offline peer and the zmx daemon seed. The original slot lease was
640c69a9-049e-46ba-9ebe-5c813a3f93a1, granted2026-10-15T23:50:18.4647178Z; this is retained provenance, not a new execution grant. - At
23:50:45Z, worker PID 37428 recorded:Process.Start identity attestation failed for zmx-seed PID 36288: Exited zmx-seed PID 36288 did not reach bounded stdout/stderr EOF; cannot attest it genuinely gone.; guarded rollback also failed: Rollback stdout reader did not reach bounded EOF for PID 36288. - Worker exit was 1. The final manifest contains zero GUI launches, zero images and a pending seed-launch rollback. The supervisor release is
CLEANUP_UNPROVEN, not a zero-survivor success.
No repeat live slot, experiment, process-name kill or production-source change is authorized by this issue.
Expected behavior
A real daemonising zmx seed must have separately owned, bounded output capture and generation-bound lifecycle evidence for its launcher, daemon and descendants. Launch/rollback/cleanup must not depend on a pipe that the deliberately live daemon inherits. Keep fail-closed ownership, kernel-exit and EOF requirements meaningful; do not turn missing EOF, empty CIM results or an unproved descendant into success.
Proposed design to plan-review after #833: redirect the seed's stdout/stderr to owned files, or use a launch mechanism that prevents unwanted handle inheritance. Specify launcher versus daemon attestation and when files/streams become quiescent; a file snapshot is not proof that a live writer has closed. Track and clean up the actual owned daemon/descendants by verified generation. Preserve diagnostics and original failure classification.
Add a real-zmx, no-GUI seed rehearsal to the preflight so this path cannot remain hidden behind the Start-CapOfflineSeed stub. Test-only #833 handles compiler-log readers; this issue concerns the capture core's real daemon-launch path and must not be silently folded into that fixture-only PR.
Screenshots
None: the manifest reports guiLaunches=[] and images=[]; the official release reports captures=0.
Environment
- GraphCode version: production capture source
944ee565ed2e36885b8cf1087fc5fbe2d05d38b6, treea6ccbfd5580d9fba0c336da93e716609c4538ce0, identical to mainbadcf5149be2a01abd866e4cf180521f485fa2c4. - macOS version: not applicable; Windows and PowerShell 7.
- Backend: isolated offline fixture, no paid/backend turn.
- Pinned zmx binary SHA-256:
DFFF744FA8D7B0FB483416674C2FF4C2647EA46A3BDD82A95DC173A1FA07DC5B.
Additional context
Retained evidence under C:\gccp\capture-coordinator-b1:
worker.log: primary seed attestation and rollback error.manifest.json: run IDcdba36a51f144798b40fd78bdb50251b, launcher PID 36288, creation file time134365818411426552, kernel-exited=true but pending rollback; peer PID 46440 has kernel exit and both EOF true; no GUI/images.lease-release.json: SHA-256DED09AD2C54E77E4AF6E4251F06467F2BEABEC999B9D7CE80E3536A1C985058F,CLEANUP_UNPROVEN, worker stdout/stderr EOF false, no accepted final journal binding. Its empty survivor array does not override the unproved cleanup status.- Coordinator console:
C:\gcs\coord2\coor-b-slot1-console.txt, SHA-2567DE661F76921934337EEAA909AF20DB80BFFB44F22F8DB77AE1DA8E20DA5D0C5. - Journal directory:
C:\gccp\runs\cdba36a51f144798b40fd78bdb50251b\process-journal; immutable published snapshots remain preserved.
Operator-observed root cause: launcher PID 36288 spawned daemon PID 22760, which inherited the launcher's output pipes. The operator stopped the verified orphaned fixture daemon at C:\gccp\runtime\zmx.exe and subsequently reported no remaining zmx, graphcode-windows or graphcoded processes. This later cleanup is a separate operator action, not a rewrite of the original CLEANUP_UNPROVEN receipt or an invented original EOF proof.
The passing 59-case core-59b preflight explicitly stubs Start-CapOfflineSeed and is not a real zmx/peer rehearsal; it therefore did not exercise this defect. The live track is stopped with no retries. Refs #826, #829 and #833. Schedule this core prerequisite after #833 and before D's Quick Chat adapter or option 1 integration. Plan review must precede any source edits; close nothing on the strength of this report alone.
Activity
coneilen commentedon Oct 16, 2026
Observed EOF-attestation-family failure to retain for #834; underlying cause is not established.
In original PR #836 hardening run https://github.com/scgopi/GraphCode/actions/runs/38832369710, Windows 2025 job https://github.com/scgopi/GraphCode/actions/runs/38832369710/job/116753830293 executed 59 UiCaptureDriver cases: 57 passed and 2 failed. The primary reported case was
same capture command handles target nonzero: Failure/release/EOF evidence missing.The repaired rehearsal-report gate also rejected the unsuccessful rehearsal. No uploaded case artifact was available (artifact inventory count 0), so the log does not identify which missing proof field or timing caused this.This was the default stubbed offline/no-desktop rehearsal, NOT a real pinned-zmx/peer run or proof of the #834 daemon-inherited-file/pipe mechanism. The same source head 359a033 passed 59/59 on Windows 2022, and the ONE operator-authorized failed-job diagnostic rerun passed an actual 59/59/0 on Windows 2025 (job 116759891173, same workflow attempt 2). Preserve the original failed observation and watch for recurrence; do not silently treat the rerun as a source fix.
Original raw log: C:\gcs\coord2\833-836-hardening2025-failed-job-raw.log; SHA-256 C55FDB3B79E7FEBFBC9AC1BD34AACE603DF6BABA3018D3A63829A52C280E4436. Diagnostic success raw log: C:\gcs\coord2\833-836-hardening2025-diagnostic2-success-raw.log; SHA-256 6FE4D50158FEEB038E8F859F4EE6A8FBD1E62EA68A40D750EFE43B0B4F52F273.
PR #836 is now merged as 78ef35d with its exact reviewed fixture blob preserved. This clears only the fixture-fix merge dependency: it does NOT grant #834 implementation/native execution, change its approved seven-import design, or resume the stopped live B capture track. Exact clean work surface, sole-writer lease, source-boundary review and orphan-cleanup/native grants still apply.
Document milestone-led Windows parity gates (#837)
coneilen commentedon Oct 16, 2026
Plan approved: job-based ownership pivot
This is an operator-delegated design decision for later user review, not a claim that the user personally reviewed the source or that runtime acceptance has passed. The previous custom-launch candidate remains frozen as history on its existing branch/worktree; the pivot uses a new branch,
coneilen-capture-job-ownership.Approved mechanism: assign a gated normal launcher/worker to a kill-on-close job before releasing it; clear the worker's own standard-handle inheritance before any child launch; launch public pinned zmx normally; use owned output files, job membership and terminate/wait-empty/ActiveProcesses=0, with independent file-close and real pipe-EOF proofs. Keep J5 binding/publication/hash-chain functions byte-unchanged, strict generic J4 foreign-process refusal, and N1's strict owned-root fixture.
The corrected standalone diagnostic established that real zmx can start inside the added nested job (exit0,444ms,endpoint probe successful). Its in-script cleanup receipt failed; the separate operator post-hoc clean census does not retroactively repair that receipt. The exact cause of the old custom launch's exit1 remains unproved. The pivot is an approved ownership/proof design choice, not a demonstrated exact-parameter diagnosis.
M1 source is now frozen for one independent Sonnet source review: five leased files, no commit or native suite, ParseFile0, exact-AST compile-only with six loaded types, and 26 protected J4/J5 function extents byte-identical. Source-owned imports are 26 declarations/24 unique APIs. Prospective case counts are64offline and67with real-seed definitions, retaining original59; zero behavioral cases have run for this source. Handoff SHA256
99C9E8EB59FEC7FAF0F80EAC57BAFAEDD623290C77420148A7CB358C8D42E7CF; patch94B5611A9A5206B1B67FDE39044BD1681D40E4A9802819DE2E66BD90C051271F.Runtime M2 stays held until review and explicit admission. It must cover original59 plus the updated positive count, real normal/nonzero/timeout paths, job-empty/file-close/raw-EOF proof. If M2 fails, stop and report without a fix chain. M3 is a new-branch PR using historical run
cdba36a51f144798b40fd78bdb50251bas RED, not an unsafe reproduction.Review and publication must disclose the changed pre-execution identity proof, foreign-writer absence and cached/duplicated standard-handle limits, plus the current private-pipe-pump versus direct-file-STD and uncensused app/peer receipt questions. No candidate GREEN, capture/parity acceptance, issue closure or ledger promotion is claimed here.
Bound Windows capture seed lifecycle and output ownership (#845)