Skip to content

Bound Windows capture seed lifecycle and output ownership - #845

Merged
coneilen merged 3 commits into
scgopi:mainfrom
coneilen:coneilen-capture-job-ownership
Oct 16, 2026
Merged

coneilen merged 3 commits into
scgopi:mainfrom
coneilen:coneilen-capture-job-ownership

Conversation

@coneilen

@coneilen coneilen commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Bound daemonising Windows capture seeds and descendants with gated kill-on-close jobs, separately owned output files, and generation-bound cleanup evidence instead of waiting for a deliberately live daemon to release worker pipes.

Refs #834, conservatively rather than automatically closing it: the specified no-GUI lifecycle rehearsal now passes, but source STD-handle clearing and EOF after owned-job cleanup do not establish universal absence of runtime-cached or duplicated inherited handles. Issue-owner acceptance of that ownership/handle boundary remains explicit; absence of GUI testing is not the closure reason.

Changes

  • Assign a held, gated launcher before releasing any target; retain KILL_ON_JOB_CLOSE only, without escape flags. Launch pinned public zmx normally, census owned generations, terminate/wait/query Active=0 before handle close, and preserve original nonzero/timeout failures separately from cleanup failures.
  • Clear each worker's original STD-handle inheritance flags before spawning. Keep actual worker/launcher pipe EOF distinct from job-owned file closure: target-file receipts never manufacture target pipe EOF.
  • Put per-launch zmx state in a fresh five-hex child of the actual owned root. Mirror the pinned provider's UTF-8 hex/SID lease construction with an inclusive 240-character guard and typed overflow refusal. Live B invocation roots must be at most five characters; the historical C:\gccp\capture-coordinator-b1 layout is infeasible. #843 is future session-name work only; no product/session-prefix change is included.
  • Preserve binding/publication/hash-chain semantics and strict generic foreign-identity refusal. Add only measured Open/Copy/total journal diagnostics; the 1000ms transaction budget, seven global retries, eight Open attempts and no-late-success rules remain unchanged.
  • Tolerate exit-receipt sharing/not-yet-published/partial JSON races within the existing deadline, while rejecting complete foreign job/spec/PID/creation identities. Keep the immutable temporary-file/flush/close/rename writer protocol.
  • Prepare both native C fixtures before the added suite job. Hash-bind fourteen source/EXE/OBJ/provenance/compile-command/immutable log-snapshot artifacts into the configuration and result; require the actual suite to consume and verify them without a compile fallback. Retain mutable raw logs and explicitly unproved raw-stream EOF. PowerShell Add-Type compilation remains per-process.
  • Wire the existing ValidationRunner caller through that same prepare -> manifest SHA -> consume flow, retaining its original positive-count/unique-summary/zero-failure assertions. Correct the report-preflight comparison's runtime argument binding and document the computed prebuilt-manifest hash.

Test plan

Current follow-up: remove one success-path observation

New head 58a7723b77a19bf7dd952048d0f609429a6f8407, one DCO-signed commit directly on 30b718f2a69ad8eb65600364fa986282c3f17df8, changes only the module and its tests. The only production change deletes Write-CapJournalObservation ... 'CopyCompleted' between CopyTo and the first post-copy deadline assertion. Open/Copy accumulators, failure observations, existing ReadVerified observation, Flush(true), 1000ms budget, seven retries, eight Open attempts, journal identity/schema and no-late-success semantics remain unchanged.

RED: ./Tools/windows/Tests/ValidationRunner.Tests.ps1 -> Windows2025 Verify runner contract failed on exact30b718 in run38941311015/job117109433142: actual offline child69 executed/66 passed/3 failed; nonempty capture JournalUnavailable sequence1/retries0/openMs0.610/copyMs2.605/totalMs1281.984, concurrent actor cleanup not proved, and downstream report-gate early refusal. This is actual runtime CI RED, not Parse0 or a compiler failure.
GREEN: & 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'C:\Users\coneilen.copilot\session-state\dcb9e98f-c765-404e-9e3b-ad71e4411f9f\files\Invoke-845CopyObservationGreen.ps1' -RunRoot 'C:\gjp8' -ExpectedControllerSha256 '9F46A3D990A9926445517FCD7247B047F20DD01CC1454A9339459701F2DCF8CC' -RuntimeDeadlineUtc '2026-10-16T18:19:18.9968337Z' -OuterDeadlineUtc '2026-10-16T21:45:53.5403616Z' -> exit0/controller PASS72/72/0, original59 all passed with zero missing/failed, all independent post-report checks executed; owned-job Before/Finally/After0/0/0 queried before close, actual stdout/stderr EOF, no in-job vctip.
REGRESSION: & 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'C:\Users\coneilen.copilot\session-state\dcb9e98f-c765-404e-9e3b-ad71e4411f9f\files\Invoke-845FocusedJournal.ps1' -ExpectedRunnerSha256 'B8544FFA9F686719D794DF47F263FD0E5367EEC7C07883DA8DDDAA85C54B2951' -> exit0, actual shared PrepareFixturesOnly two C compiles and fresh14-artifact manifest followed by all registered JournalContractOnly10/10/0, including concurrent actors and the actual harmless managed-worker journal path; JournalTimingContractOnly1/1/0 with all four timing subcases.

The exact CI command above is retained in the failed Windows2025 job, raw log SHA-256 ECE6C0FBAF9C201925E49E6F1FD14EB0296A2794CDEB98132EB2FE5B111F9A11/384746 bytes. The additional success-path flush was a diff-grounded leading hypothesis, not observed causal attribution. Gjp8 passed, and Windows2025 subsequently passed its single authorized diagnostic on the unchanged new head. The actor-cleanup cause remains unobserved; no old-head CI rerun or Defender attribution is claimed. Gjp5's E4B6 module ran before CopyCompleted was added, so this call cannot explain that older N1 failure.

CI follow-up: head 30b718f2 first failed concurrent-actor cleanup and was not rerun; head 58a7723b first failed transient-Open actor cleanup, then its one identical-head Windows2025 diagnostic job 117129884237 passed (69/69/0 and ValidationRunner.Tests.ps1: PASS). Actor cause remains UNOBSERVED; the original failures and diagnostic log SHA-256 FD7603041B9A40051F72C3ADFC4553099D8176E95A1269623DA8F084D50F440A are retained in the dedicated tracker. The separately authorized packaging bootstrap-network retry job 117129880601 also passed; neither job was rerun more than once.

The cheap AST ordering contract identifies CopyTo and its first following Assert-CapJournalTime, rejects any intervening success-path Write-CapJournalObservation regardless of decision text, and ignores catch-only CopyFailed. It positively detects the old source and a renamed observation (one each), accepts the repaired order (zero), and rejects an inserted renamed-write mutant. Timing success evidence now uses the existing post-verification ReadVerified observation and exact transaction accumulator values; all four timing subcases remain.

Gjp8 ran18:00:34.5214019Z-18:05:28.3142930Z. Raw controller C:\gjp8\controller-result.json SHA-256 2B94B6F12DA435DBCFA4B99DFA06D780ADE81023172B76CDFBB7EF7BF4A2E4E8; report C:\gjp8\suite\report.json SHA-256 E3689E1587A7E1E78B3995651D965AD0730C0490B5AF713B35D15B711B44641D. All33 release files, ten full clean/expected-target-failure proofs,96 numbered publication/payload/predecessor links, six actual ready exit0 real-zmx phases, and14 prebuilt artifact consumption/post-suite rehash proofs were checked. The23 expected refusal/injected-negative statuses remain negatives, not clean success. Prebuilt manifest 60CCDB453CB673B497A72FD226CA28C351FAEA3E1A991246ACD58BD4BF22495E. Independent operator replay used only frozen file-proof definitions, with no new native query/run.

All six staged/committed raw Git blobs and disk bytes match Gjp8: module 584A1A983CEA3918575BA051092A563261749F8D285EA1B7F549186E43A05EFB, supervisor 8754C9C08FB7DAB80B836AA6199FE0D25970165C4A011D8C1BCF752F416D061C, worker 19BB271757A925B3318EB7B7BDEB1EE27CF4B57C53BA6CFB2610E5A98CC451A9, capture tests 824770EF8CB8AC804B036C48BCC48B0D7B43607195AFDAC80644C59B34E91456, README 3738A6C8CD98DE68D927E0219C56222292F505C7EC27185B5D4233B08B253CAA, ValidationRunner 04FC5F7F3D599755BB725C93CBA68E4762EB4B722B3FEE8B8636466CDC7CCA4D. No rebase, main merge, EOL rewrite or additional source change in this follow-up. The controller differs from frozen F266 only by root/error, fresh private TEMP and the two updated source-pin metadata values.

Gjp8's bound preflight records outside-future-job vctip25884/53576 and foreign build identities as nonblocking, never adopted/killed. Any host zmx still blocks admission and any suite-job vctip still fails; there is no global after-run zero-process assertion. Raw compiler-stream EOF and outside-precompile descendant liveness remain unproved, distinct from immutable snapshots and actual worker/launcher EOF.

Historical commands and the original Gjp7 evidence below retain their original source versions and results. The earlier actual caller slice69/69 is historical coverage, not a new-head full ValidationRunner result. Neither that earlier GREEN nor current Gjp8 alone establishes a Windows2025 CI outcome; the later same-head diagnostic result is recorded separately above.

Historical RED commands below were recorded against their own frozen controls and retained logs, not rerun after correction. A later safe cleanup never rewrites their failing result.

RED: & 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'C:\Users\coneilen.copilot\session-state\dcb9e98f-c765-404e-9e3b-ad71e4411f9f\files\Invoke-834M2RJobGreen.ps1' -RunRoot 'C:\gjp2' -ExpectedControllerSha256 'B6212FA0C42E86C309AC39DB80F73B4FB2D826016B01ECC378442CF977AC875E' -> exit 1, 68 executed/64 passed/4 failed; all three actual before-phase zmx seeds exited 1, lease paths 264-265 characters; no after phases or harmless targets ran.
RED: & 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'C:\Users\coneilen.copilot\session-state\dcb9e98f-c765-404e-9e3b-ad71e4411f9f\files\Invoke-834PathFixGreen.ps1' -RunRoot 'C:\gjp3' -ExpectedControllerSha256 'B7446CC5434B82319BD2EDAD8434F6D436F6FEBD3DC467CC4DEC9CBB31212F50' -RuntimeDeadlineUtc '2026-10-16T08:01:27.1488314Z' -> exit 1, 69/67/2; the nonzero case's after-phase ReadAllBytes failed with a sharing-violation IOException. Its later retained exit-0 receipt did not retroactively pass that read/readiness check.
RED: & 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'C:\Users\coneilen.copilot\session-state\dcb9e98f-c765-404e-9e3b-ad71e4411f9f\files\Invoke-834ReceiptFixRebootReplacement.ps1' -RunRoot 'C:\gjp5' -ExpectedControllerSha256 'E14F9C51C362E8C616335CA26054AC61C7C30A06928CC0E16C225BA00A379458' -RuntimeDeadlineUtc '2026-10-16T16:05:53.5403616Z' -OuterDeadlineUtc '2026-10-16T21:45:53.5403616Z' -> exit 1, 70/68/2; in-job vctip PID31840 remained at before/finally Active=1, alongside N1 deadline failure and its dependent report gate. After=0 was safety cleanup, not GREEN; its specific compiler parent was unrecorded.
RED: & 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'C:\Users\coneilen.copilot\session-state\dcb9e98f-c765-404e-9e3b-ad71e4411f9f\files\Invoke-834PrebuiltGreen.ps1' -RunRoot 'C:\gjp6' -ExpectedControllerSha256 '2BB8B91FD39DCE9CD577460FE6D8D2D56331A89E3F660E3DA4FA63FE6E52BB33' -RuntimeDeadlineUtc '2026-10-16T17:00:05.1176390Z' -OuterDeadlineUtc '2026-10-16T21:45:53.5403616Z' -> exit 1, 72/71/1; the real report-preflight branch raised PSArgumentException because Where-Object -CEQ was split from its value at supervisor line217. Parser0, N1 PASS and owned-job 0/0/0 did not make this GREEN.
RED: & 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'D:\depot\copilot-worktrees\GraphCode\coneilen-congenial-meme\Tools\windows\Tests\UiCaptureDriver.Tests.ps1' -> old unwired ValidationRunner child refused PrebuiltFixtureRequired with positive 1/0/1 before caller integration; setup-contract refusal, not the core behavioral RED.
GREEN: & 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'C:\Users\coneilen.copilot\session-state\dcb9e98f-c765-404e-9e3b-ad71e4411f9f\files\Invoke-834PreflightGreen.ps1' -RunRoot 'C:\gjp7' -ExpectedControllerSha256 'F2661968D13079CDE44F0C188394BA3266C320EC29416B4C75162EF2583A3701' -RuntimeDeadlineUtc '2026-10-16T17:27:08.0084583Z' -OuterDeadlineUtc '2026-10-16T21:45:53.5403616Z' -> controller PASS/exit0, 72 executed/72 passed/0 failed; original59 all passed, owned-job before/finally/after 0/0/0 queried before close, actual stdout/stderr EOF, no in-job vctip, all independent post-report proof gates executed.
REGRESSION: & 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'C:\Users\coneilen.copilot\session-state\dcb9e98f-c765-404e-9e3b-ad71e4411f9f\files\Invoke-834ValidationCallerSlice.ps1' -EvidenceRoot 'C:\gvr1' -ExpectedCallerSha256 '04FC5F7F3D599755BB725C93CBA68E4762EB4B722B3FEE8B8636466CDC7CCA4D' -ExpectedRunnerSha256 'A988DCEF4EB44F82EE59E778C06EEBDDFC060DEB4FD9BDA4BC285363D1DAF09C' -> exit0; one complete actual ValidationRunner capture-caller AST slice prepared both C fixtures and consumed the bound manifest, producing 69/69/0 with original59 all passed and unchanged summary assertions. This was not the full ValidationRunner.

Retained Gjp7 GREEN proof inventory (historical source version)

  • Gjp7 C:\gjp7\controller-result.json: SHA-256 CEFD46B54141CCC2FC09CE827BADF6D6713ED6EF87E1F6F851096DEA1E826826; C:\gjp7\suite\report.json: 3C330E504EDA195CC1C27F5E5B7358122F7E85B629A0DAE266D3430D00D66536.
  • The controller independently checked 33 actual release files: 10 complete clean/expected-target-failure proofs with 96 numbered publications; the other 23 are expected refusal/injected-negative statuses, not clean successes. All six actual real-zmx seed phases exited0, became ready with daemon1/cmd2, and closed their owned files at lease lengths207/208. Normal/nonzero/timeout refer to the subsequent harmless target, not forced zmx CLI errors/timeouts.
  • Fourteen prebuilt references were in the configuration and final result, verified by the actual suite and rehashed after it. Precompile manifest 904A06C6BFDD317E01DAC083423F14A22E9706FE12E69D3CF32C88A91DC4D7AF.
  • All six raw qualified source files exactly match their staged, committed and post-main-integration Git blobs. Qualification ran before main integration; upstream e9b6b4da..3ba03b23 changed none of those six paths, with all six positively present in both trees. The final PR tree delta is exactly those six files; no post-merge runtime rerun is claimed.
  • The historical original real pipe-retention RED cdba36a51f144798b40fd78bdb50251b is retained unchanged: seed36288 exited while daemon22760 retained worker pipes, EOF false/final binding null/CLEANUP_UNPROVEN; no unsafe reproduction. Gjp4 was interrupted by a Windows Update host reboot, neither a suite PASS nor FAIL.
  • Before the receipt fix: actual exclusive-file production reader RED1/0/1 against module 627A689D54BAA32453C68689B6346C7860613FC90F790B3E1047A621BDD73EBD, retained in 834-receipt-actual-red-evidence.json; afterward focused actual-reader GREEN5/5/0 including typed deadline, partial JSON and foreign identity refusals in 834-receipt-green-evidence.json. The later report fix also has focused synthetic acceptance1/1: the actual production AST accepted valid data and visited all three behavior checks through six precise mutations, not a default rejection shortcut or executed-provider claim.
  • Saved-source Parse0, exact-AST C# six types compiled without invoking declared native methods, 26 source-owned declarations/24 APIs, 22 protected functions byte-identical and four explicitly authorized timing-only exceptions. The native export inventory case uses its disclosed renamed 26-binding contract rather than pretending the old sixteen-binding wording remained.

Limits and publication context

This is offline fixture zmx/cmd-only capture-core qualification: no actual GraphCode B GUI capture, physical input, screenshots, pixels, native accessibility conformance, paid backend turn, macOS parity or product-daemon persistence was established. Shared Swift/macOS product code is unchanged. make test, make check and the full ValidationRunner were not run on this Windows host.

Review note: Tools/windows/Tests/ValidationRunner.Tests.ps1 on main had mixed line endings (922 CRLF lines of 4737). The qualified bytes normalize them to LF, so the GitHub diff shows +933/-923; git diff --ignore-cr-at-eol shows the actual change is +11/-1. The LF bytes are the exact ones qualified (caller slice 69/69 and full 72/72); restoring the CRLF lines would change qualified bytes, so they were kept.

Live B requires a separately authorized fresh owned root of at most five characters. The longest actual B-actions session is78 UTF-8 bytes/156 hex; a five-character owned root plus five-hex state leaf yields240 lease characters for the observed52-character SID. Historical B root30 would yield265 and is refused. Future naming changes remain #843, not a hidden change here.

Both the Copilot host and preparation host may be in ambient jobs; precompile means outside the added suite job, not machine-jobless. Outside-job host vctip/foreign builds are recorded nonblocking and never adopted or killed; any vctip inside the owned suite job still fails. Gjp7 preflight positively observed host zmx0/vctip0 and recorded pre-existing foreign identities in the bound snapshot. No global after-run process-zero claim or telemetry exemption.

Raw compiler logs remain mutable streams with EOF/complete-stream closure UNPROVEN; their canonical single-read exact-byte snapshots are hash-bound immutable files. Seed-file writer exclusion and Active=0 prove the recorded owned closure boundary, not lifetime foreign-writer absence, complete unread daemon pipe tails, preexecution zmx generation, or immunity to runtime-cached/duplicated STD handles. Worker/launcher raw EOF is independently observed, not inferred from typed file closure.

N1's historical load explanation remains a hypothesis: measured Open/Copy/total diagnostics were added, but the 1000ms budget and retry semantics were not changed or excused. All failed logs, old source pins and the reboot interruption are retained separately. The one-line README manifest-hash assignment has old/new provenance: Gjp6 executed 7DA7024D50419B93A1FFE99AB2F1891E20A50B60C4B8034BD31C7C9B5BC31080; Gjp7 actually qualified 3738A6C8CD98DE68D927E0219C56222292F505C7EC27185B5D4233B08B253CAA. No old binding was rewritten.

Checklist

  • I have read the Contributing Guidelines
  • I have signed off my commits (git commit -s) per the DCO
  • Tests pass locally (make test)
  • Code follows the existing style (make check)
  • I added the test/contract before the implementation and observed the intended RED failure

coneilen and others added 3 commits October 16, 2026 10:24
Contain gated capture launches and descendants in kill-on-close jobs.
Separate daemon file closure from actual worker pipe EOF, bound zmx lease
paths, and retain strict identity, journal, cleanup and failure evidence.
Precompile hash-bound native fixtures before the suite job and cover
receipt-sharing races and report acceptance without weakening deadlines.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dcb9e98f-c765-404e-9e3b-ad71e4411f9f
Signed-off-by: Colin Neilens <coneilen@microsoft.com>
Integrate the authorized GraphCanvas-only upstream base without changing the six qualified capture files.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dcb9e98f-c765-404e-9e3b-ad71e4411f9f
Signed-off-by: Colin Neilens <coneilen@microsoft.com>
Remove only the CopyCompleted success-path observation before the next deadline check. Preserve phase accumulators, failure observations and transaction limits; verify ordering and measured timing without another pre-assert write.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dcb9e98f-c765-404e-9e3b-ad71e4411f9f
Signed-off-by: Colin Neilens <coneilen@microsoft.com>
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