From 1579bb32718f83c23741405d05e5d22eec00ebde Mon Sep 17 00:00:00 2001 From: Denys Rafael Date: Mon, 31 Aug 2026 15:34:49 +0300 Subject: [PATCH] docs: adopt cooperative Windows execution --- .../workflows/autopilot-windows-helper.yml | 109 ----- ...continuity-evidence-implementation-plan.md | 2 +- ...8-31-cooperative-harness-execution-plan.md | 460 ++++++++++++++++++ skills/autopilot/docs/README.md | 2 + ...ooperative-harness-execution-on-windows.md | 98 ++++ skills/autopilot/docs/architecture.md | 6 +- skills/autopilot/docs/implementation-plan.md | 4 +- skills/autopilot/references/adapters.md | 10 +- skills/autopilot/references/recovery.md | 2 +- skills/autopilot/runtime/native/README.md | 32 +- 10 files changed, 589 insertions(+), 136 deletions(-) delete mode 100644 .github/workflows/autopilot-windows-helper.yml create mode 100644 skills/autopilot/docs/2026-08-31-cooperative-harness-execution-plan.md create mode 100644 skills/autopilot/docs/adr/0002-use-cooperative-harness-execution-on-windows.md diff --git a/.github/workflows/autopilot-windows-helper.yml b/.github/workflows/autopilot-windows-helper.yml deleted file mode 100644 index 67dc76d..0000000 --- a/.github/workflows/autopilot-windows-helper.yml +++ /dev/null @@ -1,109 +0,0 @@ -name: Autopilot Windows Job Object helper - -on: - workflow_dispatch: - -permissions: - contents: read - -jobs: - build-and-validate: - name: Reproducible MSVC x64 helper and real Job Object tests - runs-on: windows-latest - defaults: - run: - working-directory: skills/autopilot/runtime - steps: - - name: Check out repository - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 - - name: Set up Node.js - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 - with: - node-version: 24 - cache: npm - cache-dependency-path: skills/autopilot/runtime/package-lock.json - - name: Configure Git identity - shell: bash - run: | - git config user.name "Autopilot CI" - git config user.email "autopilot-ci@example.invalid" - - name: Build helper twice and compare SHA-256 - shell: pwsh - run: | - $env:AUTOPILOT_WORKFLOW_SHA = (git hash-object ../../../.github/workflows/autopilot-windows-helper.yml).Trim() - ./scripts/build-windows-helper.ps1 - - name: Install reproducible helper for package validation - shell: pwsh - run: | - New-Item -ItemType Directory -Force native/bin/win32-x64 | Out-Null - Copy-Item native/build/windows-job-helper/artifact/job-helper.exe native/bin/win32-x64/job-helper.exe - Copy-Item native/build/windows-job-helper/artifact/job-helper.json native/bin/win32-x64/job-helper.json - - name: Install development dependencies - run: npm ci - - name: Typecheck - run: npm run typecheck - - name: Lint - run: npm run lint - - name: Check formatting - run: npm run format:check - - name: Compile runtime and tests - shell: pwsh - run: | - npm run build - ./node_modules/.bin/tsc.cmd -p tsconfig.test.json - node scripts/copy-native-helper.mjs - - name: Run isolated native Windows suites - run: node --test --test-concurrency=1 .test-dist/test/windows-job.test.js .test-dist/test/process-supervisor.test.js - - name: Run remaining protected suites serially - shell: pwsh - run: | - $tests = Get-ChildItem .test-dist/test/*.test.js | - Where-Object { $_.Name -notin @('windows-job.test.js', 'process-supervisor.test.js') } | - ForEach-Object { $_.FullName } - node --test --test-concurrency=1 $tests - - name: Collect sanitized failure diagnostics - if: failure() - shell: pwsh - run: | - $autopilotTemp = node -p "require('node:os').tmpdir()" - node scripts/collect-windows-diagnostics.mjs ` - --root $autopilotTemp ` - --output native/build/windows-job-helper/diagnostics/windows-supervision.json - - name: Upload sanitized failure diagnostics - if: failure() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 - with: - name: autopilot-windows-diagnostics-${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }} - path: skills/autopilot/runtime/native/build/windows-job-helper/diagnostics/windows-supervision.json - if-no-files-found: error - retention-days: 7 - - name: Verify packaged helper identity - if: success() - shell: pwsh - run: | - $source = (Get-FileHash -Algorithm SHA256 native/bin/win32-x64/job-helper.exe).Hash - $packaged = (Get-FileHash -Algorithm SHA256 dist/native/win32-x64/job-helper.exe).Hash - if ($source -ne $packaged) { throw "packaged helper digest changed" } - $manifest = Get-Content dist/native/win32-x64/job-helper.json | ConvertFrom-Json - if ($manifest.sha256 -ne $source.ToLowerInvariant()) { throw "packaged helper manifest changed" } - if ($manifest.provenance -ne "github-actions-workflow-dispatch") { throw "helper provenance is not trusted" } - if ($manifest.sourceCommit -ne "${{ github.sha }}") { throw "helper source commit provenance changed" } - $sourceSha = (Get-FileHash -Algorithm SHA256 native/windows-job-helper.c).Hash.ToLowerInvariant() - if ($manifest.sourceSha256 -ne $sourceSha) { throw "helper source digest provenance changed" } - $workflowSha = (git hash-object ../../../.github/workflows/autopilot-windows-helper.yml).Trim() - if ($manifest.workflowSha -ne $workflowSha) { throw "helper workflow SHA provenance changed" } - if ($manifest.workflowRunId -ne "${{ github.run_id }}") { throw "helper workflow run provenance changed" } - if ($manifest.workflowRunAttempt -ne "${{ github.run_attempt }}") { throw "helper workflow attempt provenance changed" } - if ($manifest.workflowEvent -ne "workflow_dispatch") { throw "helper workflow event provenance changed" } - if ($manifest.repository -ne "${{ github.repository }}") { throw "helper repository provenance changed" } - if ($manifest.workflowName -ne "${{ github.workflow }}") { throw "helper workflow name provenance changed" } - if ($manifest.workflowRef -ne "${{ github.workflow_ref }}") { throw "helper workflow ref provenance changed" } - if (-not $manifest.toolset) { throw "helper toolset provenance is absent" } - - name: Upload reviewed bootstrap artifact - if: success() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 - with: - name: autopilot-job-helper-win32-x64-${{ github.sha }} - path: skills/autopilot/runtime/native/build/windows-job-helper/artifact/ - if-no-files-found: error - retention-days: 7 diff --git a/skills/autopilot/docs/2026-08-30-continuity-evidence-implementation-plan.md b/skills/autopilot/docs/2026-08-30-continuity-evidence-implementation-plan.md index 3e8e6ec..385b2ff 100644 --- a/skills/autopilot/docs/2026-08-30-continuity-evidence-implementation-plan.md +++ b/skills/autopilot/docs/2026-08-30-continuity-evidence-implementation-plan.md @@ -556,7 +556,7 @@ Validate modified Markdown links and balanced fences with the repository's estab ### Windows validation evidence -GitHub Actions run [33335872725](https://github.com/drafael/coding-harness/actions/runs/33335872725) passed Node 24 typecheck, lint, format check, the 162-test suite, and deterministic generated-artifact checks on both `ubuntu-latest` and `windows-latest` at merge commit `b511331`. The Windows runs exposed and then verified fixes for unsupported directory fsync, direct governed-hook execution, portable fake CLI fixtures, descendant process-tree cancellation, CRLF-neutral restack assertions, and bounded Git worktree administration paths. Windows writes still do not claim POSIX-equivalent sudden-power-loss directory metadata durability because Node.js cannot fsync a Windows directory handle. A source-controlled x64 Job Object helper, manifest verification, and a pinned Windows bootstrap workflow now define the restart boundary, but the capability remains disabled until that workflow produces a reproducible artifact, real fault-injection tests pass, and the reviewed binary and digest are checked into the package. +GitHub Actions run [33335872725](https://github.com/drafael/coding-harness/actions/runs/33335872725) passed Node 24 typecheck, lint, format check, the 162-test suite, and deterministic generated-artifact checks on both `ubuntu-latest` and `windows-latest` at merge commit `b511331`. The Windows runs exposed and then verified fixes for unsupported directory fsync, direct governed-hook execution, portable fake CLI fixtures, descendant process-tree cancellation, CRLF-neutral restack assertions, and bounded Git worktree administration paths. Windows writes still do not claim POSIX-equivalent sudden-power-loss directory metadata durability because Node.js cannot fsync a Windows directory handle. Later protected run [33353702353](https://github.com/drafael/coding-harness/actions/runs/33353702353) passed the full 179-test partition and produced a reviewed reproducible x64 Job Object artifact. [ADR 0002](adr/0002-use-cooperative-harness-execution-on-windows.md) records the decision not to package that artifact because of the native executable's antivirus and application-reputation surface. Windows restart reattachment therefore remains disabled while the cooperative harness execution plan is implemented. ### Direct Pi validation evidence diff --git a/skills/autopilot/docs/2026-08-31-cooperative-harness-execution-plan.md b/skills/autopilot/docs/2026-08-31-cooperative-harness-execution-plan.md new file mode 100644 index 0000000..9adcfaf --- /dev/null +++ b/skills/autopilot/docs/2026-08-31-cooperative-harness-execution-plan.md @@ -0,0 +1,460 @@ +# Cooperative harness execution implementation plan + +- **Status:** Approved design; PR 1 decision and promotion shutdown complete, runtime implementation not started +- **Date:** 2026-08-31 +- **Audience:** Autopilot implementers and reviewers +- **Related:** [Architecture](architecture.md), [continuity implementation plan](2026-08-30-continuity-evidence-implementation-plan.md), [durable event engine ADR](adr/0001-durable-event-engine.md) + +## Objective + +Remove the project-owned Windows Job Object executable from the planned package and prefer harness-managed worker execution where a version-pinned integration can preserve exact attempt identity. + +The replacement uses **cooperative terminality**. Autopilot accepts a worker's terminal result only while the exact harness connection that admitted the worker remains authoritative. It does not claim OS process-tree quiescence. If continuity becomes ambiguous, Autopilot records `EXECUTION_STATE_UNKNOWN`, preserves the worktree and evidence, launches no replacement, and requires explicit operator recovery. + +This change addresses the security, reputation, and antivirus risk of shipping a custom native executable. It deliberately trades automatic Windows recovery after harness loss for a smaller packaged trust boundary. + +## Approved decisions + +1. Do not check the reviewed Windows x64 helper artifact into the repository. +2. Do not silently replace the helper with an N-API addon, PowerShell P/Invoke, runtime compilation, or experimental FFI. +3. Prefer harness-managed subagents where a public, version-pinned integration exists. +4. Accept cooperative terminality only through the uninterrupted harness instance that admitted the exact attempt. +5. Treat extension reload with lost identity, session replacement, harness exit, missing terminal response, ambiguous cancellation, and backend identity change as `EXECUTION_STATE_UNKNOWN`. +6. Never use `reattach() ?? launch()` for a cooperative execution subject. +7. Preserve the runtime as the only lifecycle writer. Harnesses and workers remain observation and execution mechanisms; they cannot append canonical lifecycle events or expand authority. +8. Keep implementation attempts in dedicated Autopilot worktrees. An unknown worktree is permanently quarantined from future workers. +9. Keep reviews session-scoped unless review continuity is separately proven. +10. Keep the existing POSIX process-group supervision path for CLI adapters. The native removal applies to the project-owned Windows helper. + +## Terms + +**Cooperative terminality** + +An exact terminal response from the uninterrupted harness instance that admitted the execution. It proves the harness's logical result, not OS process-tree quiescence. + +**Harness instance** + +The process/session/integration identity through which Autopilot admitted and observed one execution. The exact fields are provider-specific and version-pinned. + +**Execution subject** + +The provider or harness identity for one admitted worker, bound to the Autopilot run, item, attempt, lease epoch, and context hash. + +**Unknown execution** + +An execution for which Autopilot cannot prove that the original harness instance remains authoritative or cannot obtain a matching terminal response. Unknown is nonterminal and cannot be retried automatically. + +**Adopted tree** + +An exact tree sealed after operator confirmation that an unknown worker is no longer active. Adoption authorizes verification of that tree; it does not retroactively prove clean worker termination. + +## Research findings + +The approved design follows a read-only review of the current runtime, Pi 0.84.4 with pi-subagents 0.60.0, and current public Claude Code, Codex, and OpenCode integration surfaces. + +| Harness surface | Useful identity and control | Continuity boundary | Why it is not process proof | +|---|---|---|---| +| Pi structured delegation | Exact `requestId`, `ownerRunId`, and `nodeId`; exact cancellation tuple; at most one terminal response | Process-local extension context | Events and ownership maps are process-local; terminal status is logical | +| Pi async RPC | Durable run artifacts, exact run status, stop requests, conservative process-terminal projection | Same Pi process/session is the narrow candidate | On Windows, pi-subagents 0.60.0 reports process-tree terminality as unknown; launch reply is not an idempotent admission key | +| Claude Agent SDK | Session identity, streaming result, interrupt/close, conversation resume | Original SDK query while connected | Resume starts or reconstructs execution through a provider subprocess; no active-query attachment contract | +| Codex app-server | Durable thread ID, turn ID, status/events, interrupt, live turn rejoin while the same server survives | Same app-server process | Turn interruption can leave background terminals; stored history is not OS quiescence | +| OpenCode server | Session/message identity, status, live SSE, abort, child sessions | Same server process and live status | No distinct durable prompt-run ID or replayable SSE cursor; abort is cooperative for arbitrary tools | + +No reviewed harness currently guarantees that a Windows terminal or cancellation response means every local descendant has stopped and no future filesystem mutation can occur. The new assurance level must state this limitation directly. + +Primary external references: + +- [Claude Agent SDK TypeScript](https://code.claude.com/docs/en/agent-sdk/typescript) +- [Claude Agent SDK sessions](https://code.claude.com/docs/en/agent-sdk/sessions) +- [Codex SDK](https://developers.openai.com/codex/sdk) +- [Codex app-server](https://developers.openai.com/codex/app-server) +- [OpenCode server](https://opencode.ai/docs/server/) +- [OpenCode SDK](https://opencode.ai/docs/sdk/) + +## Architecture + +### Ownership + +```text +Operator + | + v +Autopilot coordinator — sole events.jsonl writer + | + | exact attempt identity and bounded task + v +Harness integration — owns worker admission and logical terminal response + | + v +Worker — edits only the dedicated Autopilot worktree +``` + +Autopilot continues to own: + +- charter, grants, retry policy, and lifecycle transitions; +- worktree and writer lease identity; +- verification, review, hooks, commits, pushes, delivery, merge, and cleanup; +- terminal acceptance and unknown-state recovery. + +The harness owns: + +- worker admission; +- provider-specific execution identity; +- progress and logical terminal delivery; +- cooperative cancellation while the connection remains authoritative. + +The worker owns no lifecycle or external Git/provider effect. + +### Execution-assurance model + +The current `restartReattachment` Boolean conflates three facts: + +1. who owns execution; +2. whether the execution can be observed after coordinator interruption; +3. whether terminal observation proves process-tree quiescence. + +Replace that assumption with a versioned execution-assurance description selected per execution mode. The representation must distinguish at least: + +- runtime-managed versus harness-managed ownership; +- process-supervised versus cooperative terminality; +- session-only, same-harness-instance, or durable-subject continuity; +- ordinary admission versus explicitly idempotent get-or-create admission. + +Do not finalize a broad provider abstraction before the Pi integration proves the minimum fields. Preserve old adapter manifest and journal readability. + +### Admission + +Before asking the harness to start work, Autopilot durably records: + +- run, item, attempt, and lease epoch; +- attempt context hash and expected repository identities; +- harness, integration mode, and version; +- selected execution assurance; +- admission intent and a unique request identity. + +After admission, Autopilot records the harness subject identity immediately when the API exposes it. If continuity is lost between admission and durable subject capture, the execution becomes unknown. Autopilot must not repeat admission unless that exact integration has a separately proven idempotent get-or-create contract. + +### Terminal acceptance + +A cooperative terminal result is accepted only when all of these remain true: + +1. The original harness connection remained uninterrupted from admission through terminal response. +2. Harness instance, request, subject, run, item, attempt, lease epoch, and context hash match. +3. The result is structurally valid and respects output bounds. +4. Pause, stop, cancellation, lease replacement, or lock-token replacement did not overtake completion. +5. Repository HEAD, managed refs, Git configuration, index, tree, and changed paths remain authorized. +6. Required gates and independent review bind the exact accepted tree before commit and delivery. + +The runtime must document that this is a cooperative result, not process-terminal proof. + +### Cancellation and pause + +A cancellation request or harness acknowledgment is not terminal. Autopilot waits for the matching terminal response on the same authoritative connection. + +- Matching terminal cancellation can satisfy an operator-requested pause without charging the attempt. +- Natural completion that wins the timestamp race remains chargeable under the existing rules. +- Connection loss or identity change during cancellation becomes unknown. +- Unknown cancellation cannot permit a replacement attempt. + +### Repository and effect safety + +Every implementation attempt uses a dedicated Autopilot worktree. The worker may edit authorized roots but may not commit, push, deliver, merge, or clean up. + +After cooperative terminal response, the runtime: + +1. reobserves repository identity and authorized changes; +2. runs predicates, hooks, and independent review against an exact tree; +3. reobserves before commit; +4. commits the exact accepted tree; +5. rechecks effect preconditions before every external mutation. + +A late write after commit cannot change the committed tree, but it can dirty and quarantine the retained worktree. A late ref, configuration, index, or pre-commit tree change blocks the effect. + +This sequence reduces the impact of late cooperative activity but does not claim to prevent a background process or external side effect. + +## Unknown-state recovery + +An interrupted cooperative attempt enters nonterminal `WAITING` with reason `EXECUTION_STATE_UNKNOWN`. Its report contains bounded operational evidence: + +- run, item, attempt, lease, and context identities; +- harness/backend/version and known subject identity; +- last accepted status and timestamp; +- continuity-loss reason; +- current repository HEAD, tree, refs, configuration identity, and changed paths; +- whether the worktree changed after the last trusted observation. + +Late provider output may be retained for diagnosis but cannot restore authority. + +### Abandon and retry + +The operator confirms they have externally stopped or accounted for the old execution. Autopilot records the attestation without claiming OS proof, seals the old worktree observation, permanently quarantines that worktree from workers, charges the interrupted attempt unless it was solely a confirmed pause, and creates a fresh attempt in a new worktree. + +### Adopt the current tree for verification + +The operator confirms the old execution is no longer active and authorizes evaluation of the exact current tree. Autopilot seals that tree, launches no implementation worker, and runs every required predicate, hook, and independent review. Any worktree change during adoption or verification returns the attempt to unknown. + +### Stop the run + +The operator terminally stops the run. State and worktree remain available until explicit cleanup. + +No recovery action may silently reconnect, repeat admission, reuse the unknown worktree for a worker, or infer quiescence from PID absence, a provider transcript, or a late terminal message. + +## Delivery plan + +### PR 1: Record the decision and stop native promotion + +**Objective:** Make the security decision durable before runtime changes. + +Scope: + +- Add an ADR for cooperative harness execution that qualifies the foreground-CLI statement in ADR 0001 without changing journal ownership. +- Record that the reviewed x64 helper artifact will not be packaged. +- Disable or remove the helper artifact workflow so it cannot be promoted accidentally. +- Update implementation status and the security rationale. + +Validation: + +- Documentation links resolve. +- No runtime behavior or generated runtime file changes. +- The repository contains no packaged helper binary. + +### PR 2: Separate continuity from quiescence + +**Objective:** Represent cooperative execution without granting restart or quiescence implicitly. + +Likely components: + +```text +skills/autopilot/runtime/src/adapter-protocol.ts +skills/autopilot/runtime/src/adapter-process.ts +skills/autopilot/runtime/src/engine.ts +skills/autopilot/runtime/src/events.ts +skills/autopilot/runtime/src/reducer.ts +skills/autopilot/runtime/src/projection.ts +skills/autopilot/runtime/src/policy.ts +skills/autopilot/runtime/src/report.ts +skills/autopilot/runtime/schemas/adapter.schema.json +skills/autopilot/runtime/schemas/charter.schema.json +skills/autopilot/runtime/test/adapter-contract.test.ts +skills/autopilot/runtime/test/engine.test.ts +skills/autopilot/runtime/test/reducer.test.ts +skills/autopilot/runtime/test/fault-injection.test.ts +``` + +Required behavior: + +- Select execution assurance per request/mode. +- Preserve old manifests and journals. +- Persist cooperative admission identity and assurance. +- Remove `reattach() ?? launch()` for non-idempotent subjects. +- Map cooperative continuity loss to nonterminal unknown. +- Preserve existing process-supervised behavior where still supported. +- Keep review execution session-scoped. + +Validation: + +- Controlled adapter tests cover every assurance combination used in production. +- Crash before admission produces no subject. +- Crash after admission but before subject capture produces unknown and no duplicate launch. +- Restart with a cooperative active attempt never launches a replacement. +- Existing POSIX supervisor tests remain green. + +### PR 3: Add operator recovery + +**Objective:** Make unknown cooperative attempts safe and usable without inferring process state. + +Likely components: + +```text +skills/autopilot/runtime/src/events.ts +skills/autopilot/runtime/src/reducer.ts +skills/autopilot/runtime/src/projection.ts +skills/autopilot/runtime/src/engine.ts +skills/autopilot/runtime/src/report.ts +skills/autopilot/runtime/src/cli.ts +skills/autopilot/runtime/test/engine.test.ts +skills/autopilot/runtime/test/reducer.test.ts +skills/autopilot/runtime/test/fault-injection.test.ts +skills/autopilot/runtime/test/cli.test.ts +``` + +Required behavior: + +- Add fenced abandon, adopt, and stop controls. +- Bind controls to the current run-lock token and exact attempt/lease identity. +- Permanently exclude unknown worktrees from later workers. +- Seal adopted tree identity before verification. +- Preserve pause-specific uncharged behavior. + +Validation: + +- Stale controls and stale lock tokens are rejected. +- Late results cannot overtake recovery. +- Changed tree, refs, configuration, or index invalidates adoption. +- A successfully adopted tree passes the ordinary verification, commit, and delivery boundaries. + +### PR 4: Add the Pi in-process backend + +**Objective:** Remove the outer `pi --print` process for Pi implementation workers while preserving exact cooperative correlation. + +Before implementation, read the complete applicable Pi documentation and follow its extension API references. The first version should use the public process-local structured delegation API rather than depend on async recovery. + +Likely components: + +```text +skills/autopilot/runtime/adapters/pi/ +skills/autopilot/runtime/src/adapters.ts +skills/autopilot/runtime/src/pi-subagents.ts +skills/autopilot/runtime/src/doctor.ts +skills/autopilot/runtime/test/pi-subagents.test.ts +skills/autopilot/runtime/test/adapter-contract.test.ts +skills/autopilot/references/adapters.md +``` + +Exact packaging and extension entry-point paths must follow Pi's documented package/extension conventions; do not invent a second launcher. + +Required behavior: + +- Invoke the runtime core from the owning Pi extension context. +- Emit a structured delegation request only after durable admission intent. +- Bind `requestId`, `ownerRunId`, and `nodeId` to the attempt identity. +- Accept at most one exact terminal response from the uninterrupted context. +- Treat reload, session replacement, Pi exit, stale context, and missing response as unknown. +- Report direct Pi fallback as a different, session-scoped execution mode. + +Validation in a disposable repository: + +1. normal edit and terminal response; +2. cancellation during a tool call; +3. pause racing completion; +4. Autopilot extension reload; +5. Pi session replacement; +6. whole Pi process termination; +7. loss after request emit but before child identity capture; +8. late result after unknown classification; +9. stale-context handling; +10. operator abandon, adopt, and stop. + +### PR 5: Remove Windows native containment + +**Objective:** Complete the binary-removal boundary after cooperative behavior is available. + +Remove: + +- Windows Job helper C source and native documentation; +- helper manifest discovery and Windows Job protocol code; +- helper build/copy scripts; +- protected workflow remnants; +- native helper, packaging, and Job-specific tests; +- generated native copies and declarations. + +Retain: + +- POSIX process-group supervision for CLI adapters; +- Windows direct live-session cancellation as a session-scoped behavior; +- fail-closed unknown handling after Windows continuity loss; +- ordinary runtime diagnostics that do not depend on native artifacts. + +Validation: + +- Package inventory contains no project-owned `.exe` or `.node` helper. +- Windows adapters do not advertise process-supervised restart recovery. +- Windows continuity loss deterministically becomes unknown. +- Ubuntu and Windows typecheck, lint, formatting, full tests, package smoke, and generated-artifact checks pass. + +### Later provider work + +Investigate each provider as a separate boundary after Pi is proven. + +- Codex: version-pin a harness-owned app-server and exact thread/turn reconciliation. +- OpenCode: require exact prompt-attempt correlation and REST reconciliation around live-only events. +- Claude Code: remain session-scoped until an active execution attachment surface exists. + +Do not add a provider-neutral durable-subject framework based only on hypothetical future consumers. + +## Validation matrix + +| Scenario | Expected result | +|---|---| +| Exact uninterrupted cooperative completion | Candidate proceeds to repository verification | +| Harness terminal response is malformed or oversized | Attempt fails; no commit or effect | +| Harness connection drops before terminal | `EXECUTION_STATE_UNKNOWN`; no replacement | +| Admission response is lost | `EXECUTION_STATE_UNKNOWN`; admission is not repeated | +| Cancellation acknowledged but terminal is missing | `EXECUTION_STATE_UNKNOWN` | +| Pause terminal cancellation wins | Nonterminal pause; attempt uncharged | +| Natural completion wins the pause race | Ordinary charge and completion handling | +| Lease or lock token changes before terminal | Late result quarantined | +| Worktree changes after terminal but before commit | Verification blocked | +| Worktree changes after accepted commit | Commit remains exact; worktree quarantined/cleanup blocked | +| Operator abandons with current fence | Old worktree quarantined; fresh worktree may be created | +| Operator adopts unchanged exact tree | Verification-only path; no worker launch | +| Operator control uses stale fence | Rejected | +| Whole harness process exits | Unknown; operator recovery required | +| Windows package smoke | No project-owned native executable or addon | + +## Documentation updates + +Implementation PRs must align these documents with shipped behavior: + +```text +README.md +docs/prerequisites.md +skills/autopilot/README.md +skills/autopilot/SKILL.md +skills/autopilot/docs/README.md +skills/autopilot/docs/architecture.md +skills/autopilot/docs/getting-started.md +skills/autopilot/docs/implementation-plan.md +skills/autopilot/docs/runtime-cli.md +skills/autopilot/references/adapters.md +skills/autopilot/references/recovery.md +``` + +Use these terms consistently: + +- `cooperative terminality` for exact uninterrupted harness completion; +- `process-supervised terminality` only where process-tree proof exists; +- `conversation resume` for a new execution continuing provider history; +- `active execution reattachment` only when a live exact subject is rejoined; +- `EXECUTION_STATE_UNKNOWN` for ambiguous continuity. + +Do not describe provider terminal, session status, transcript persistence, PID absence, or cancellation acknowledgment as quiescence. + +## Security and reliability consequences + +Benefits: + +- no project-owned Windows executable or native addon in the package; +- reduced antivirus, binary reputation, architecture, compiler-provenance, and quarantine exposure; +- harness integrations can use public structured APIs instead of terminal scraping; +- continuity loss remains fail-closed. + +Costs: + +- Windows whole-harness loss no longer has automatic process-tree recovery; +- cooperative terminality can miss an escaped background process or external side effect; +- unknown executions require operator intervention and may consume attempts; +- provider-specific integration and fault evidence are required; +- a harness terminal response is a weaker boundary than Job Object accounting. + +The package and user-facing reports must expose these costs rather than presenting binary removal as equivalent assurance. + +## Implementation stop conditions + +Pause and revisit the design if implementation shows any of the following: + +1. Pi cannot invoke the runtime core without introducing a second lifecycle writer. +2. Structured delegation can emit work before Autopilot durably records admission intent. +3. The extension cannot distinguish its original context from a replacement context. +4. A cooperative terminal response cannot be bound to the exact attempt and lease. +5. Unknown-state recovery requires reusing an uncertain worktree for another writer. +6. Backward journal readability would require rewriting canonical events. +7. Removing the helper would silently downgrade an existing packaged consumer rather than an explicitly reported capability. + +## Remaining evidence gaps + +- Live Pi fault-injection against extension reload, session replacement, whole-process loss, and late writes has not been run. +- No provider currently proves Windows process-tree quiescence through its public subagent contract. +- Codex app-server live rejoin, OpenCode disconnect reconciliation, and Claude interruption behavior were researched but not exercised for this design. +- Cooperative terminality does not prevent external effects performed by worker tools before terminal response. +- The exact Pi extension packaging and invocation surface must be chosen from complete Pi documentation during PR 4. diff --git a/skills/autopilot/docs/README.md b/skills/autopilot/docs/README.md index 735ea14..715e7a1 100644 --- a/skills/autopilot/docs/README.md +++ b/skills/autopilot/docs/README.md @@ -14,8 +14,10 @@ The [main README](../README.md) is the short path for starting an unattended run - [Architecture](architecture.md): goals, contracts, event model, scheduling, adapters, Git ownership, verification, recovery, and remaining boundaries. - [ADR 0001: Use a durable event engine with explicit authority](adr/0001-durable-event-engine.md): the central architectural decision and its consequences. +- [ADR 0002: Use cooperative harness execution on Windows](adr/0002-use-cooperative-harness-execution-on-windows.md): the decision not to package a project-owned native helper and the resulting assurance boundary. - [Implementation plan](implementation-plan.md): original phased implementation, acceptance evidence, and unverified integrations. - [Continuity and evidence plan](2026-08-30-continuity-evidence-implementation-plan.md): attempt context, predicate evidence, independent review, and blocked/deferred supervision work. +- [Cooperative harness execution plan](2026-08-31-cooperative-harness-execution-plan.md): approved binary-free Windows execution assurance, unknown-state recovery, Pi integration, and delivery sequence. - [Restack successor lifecycle design](restack-successor-design.md): explicit authority, verification, Git mutation, and recovery contract for successful-stack restacking. - [Runtime CLI reference](runtime-cli.md): maintainer automation, state overrides, journal repair, and build commands. diff --git a/skills/autopilot/docs/adr/0002-use-cooperative-harness-execution-on-windows.md b/skills/autopilot/docs/adr/0002-use-cooperative-harness-execution-on-windows.md new file mode 100644 index 0000000..1a4c787 --- /dev/null +++ b/skills/autopilot/docs/adr/0002-use-cooperative-harness-execution-on-windows.md @@ -0,0 +1,98 @@ +# ADR 0002: Use cooperative harness execution on Windows + +- **Status:** Accepted +- **Date:** 2026-08-31 +- **Related:** [Architecture](../architecture.md), [cooperative harness execution plan](../2026-08-31-cooperative-harness-execution-plan.md), [ADR 0001](0001-durable-event-engine.md) + +## Context + +Autopilot needs a trustworthy boundary around implementation workers. On POSIX hosts, the runtime can own a detached process group and prove terminality before replacing a worker. Windows does not expose equivalent Job Object ownership through the Node.js 24 public API. + +A source-controlled C broker was implemented to fill that gap. It creates the harness suspended, assigns it to an unnamed Job Object configured with `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE`, resumes it only after assignment, and exposes authenticated query and termination through a named pipe. A protected Windows workflow built the helper reproducibly and passed the real cancellation, deadline, broker-death, restart, privacy, and packaging suites. Run `33353702353` produced reviewed x64 executable SHA-256 `e9017028a38c8e564aa7b73541dd1996e5b5ddf8075a7c136e06b5d55c7effef`. + +The artifact met the technical containment contract, but shipping a custom native executable creates a different operational risk. Unsigned, low-reputation executables that create suspended processes, manage process trees, and host control pipes may be quarantined or flagged by antivirus and endpoint security products. A native Node addon would still be a project-owned PE binary. PowerShell P/Invoke would add runtime compilation and policy variability. Node 26's FFI is experimental and outside the Node 24 baseline. + +Current harness subagent and server APIs provide useful logical identities and cancellation, but none reviewed here proves Windows OS process-tree quiescence. Pi structured delegation is process-local. Claude session resume starts or reconstructs execution. Codex app-server can rejoin a live turn while the same server survives, but interrupted turns may retain background terminals. OpenCode session abort is cooperative for arbitrary tools. + +The project must choose between shipping the native helper and accepting a weaker, explicit harness terminality boundary. + +## Decision + +Autopilot will not package the reviewed Windows Job Object executable or replace it with another project-owned native binary. + +Windows harness-managed implementations will use **cooperative terminality** when a version-pinned integration is available. Autopilot accepts a terminal result only while the exact harness connection that admitted the exact attempt remains authoritative. The result must match the run, item, attempt, lease epoch, context hash, and harness subject identity, and the runtime must revalidate repository identity and authorized changes before verification, commit, or delivery. + +Cooperative terminality does not claim that every OS descendant has exited. Connection loss, extension reload with lost identity, session replacement, harness-process exit, missing terminal response, ambiguous cancellation, or backend identity change produces nonterminal `EXECUTION_STATE_UNKNOWN`. Autopilot preserves the worktree and evidence, launches no replacement, and requires fenced operator recovery. + +The implementation will distinguish execution ownership, continuity, admission idempotency, and terminal assurance instead of treating `restartReattachment` as one Boolean. A cooperative subject cannot use `reattach() ?? launch()` unless that integration later proves an explicit idempotent get-or-create contract. + +The runtime remains the sole lifecycle writer. Harnesses admit workers and return observations; workers edit only authorized roots. The runtime continues to own verification, hooks, commits, pushes, delivery, merge, and cleanup. + +This decision changes the planned Windows boundary only: + +- the accepted helper artifact will not be checked in; +- Windows restart reattachment remains unsupported until cooperative integration ships, and whole-harness loss remains unknown afterward; +- the existing POSIX process-group supervision path remains supported for CLI adapters; +- reviews remain session-scoped unless separately proven. + +ADR 0001 remains authoritative for the event engine, grants, effects, and single lifecycle writer. This ADR qualifies its statement that the portable foreground CLI owns every worker process; an approved harness integration may own worker admission while the Autopilot runtime still owns lifecycle decisions. + +## Operator recovery + +An unknown cooperative execution enters nonterminal waiting. The operator may: + +1. attest that the old execution has been externally stopped or accounted for, quarantine the old worktree, and authorize a fresh attempt in a new worktree; +2. attest that the old execution is inactive and adopt the exact current tree for verification without launching another implementation worker; or +3. terminally stop the run. + +Operator attestation does not become OS process proof. Late provider output cannot restore authority, and an uncertain worktree cannot be assigned to another worker. + +## Alternatives considered + +### Package the reviewed C broker + +This preserves the strongest Windows containment and restart behavior. It was rejected because the project owner prioritizes avoiding a custom executable that can trigger antivirus, application-reputation, or endpoint policy controls. + +### Replace the executable with N-API + +A dedicated Node broker with an N-API addon could preserve the Job Object contract. It would still ship an architecture-specific native DLL, require trusted builds and manifests, and expose the same process-management behavior to endpoint monitoring. It changes the binary shape without removing the concern. + +### Use pure Node.js 24 child processes + +Node.js 24 does not expose per-attempt Job Object creation, assignment, accounting, termination, or handle ownership. Libuv's internal global Job allows silent breakaway and does not provide JavaScript quiescence evidence. This option cannot support the existing restart claim. + +### Use Node.js FFI + +Node 26 includes an experimental, build-gated FFI that could support a future TypeScript broker without a project-owned PE artifact. It is not available in the Node 24 baseline and introduces unsafe pointer and structure handling. It remains a research option, not the production boundary. + +### Keep the helper as an optional fallback + +A fallback would preserve the binary, toolchain, provenance, testing, and antivirus surface. It would also create two production execution paths and make active assurance harder to identify. The package will instead report cooperative or session-scoped behavior explicitly. + +## Consequences + +Benefits: + +- the package contains no project-owned Windows executable or native addon; +- antivirus, binary reputation, architecture, compiler-provenance, and quarantine exposure are reduced; +- harness integrations can use public structured APIs rather than terminal scraping; +- continuity loss remains fail-closed and cannot spend another attempt automatically. + +Costs: + +- Windows whole-harness loss does not have automatic process-tree recovery; +- a cooperative terminal response can miss an escaped background process or external side effect; +- unknown attempts require operator intervention and may consume budget; +- provider integrations require separate version-pinned evidence; +- reports and documentation must distinguish cooperative terminality from process proof. + +## Follow-up + +Implementation follows the ordered boundaries in the cooperative harness execution plan: + +1. record this decision and stop native artifact promotion; +2. separate continuity from quiescence in the adapter and journal contracts; +3. add fenced abandon, adopt, and stop recovery; +4. implement and fault-test Pi structured delegation in-process; +5. remove the retained Windows helper source, build, protocol, and test surfaces; +6. investigate other harnesses independently after Pi proves the boundary. diff --git a/skills/autopilot/docs/architecture.md b/skills/autopilot/docs/architecture.md index 70df22a..3f1b19a 100644 --- a/skills/autopilot/docs/architecture.md +++ b/skills/autopilot/docs/architecture.md @@ -1,10 +1,10 @@ # Harness-agnostic Autopilot design -- **Status:** Developer-preview implementation available; POSIX attempt-scoped implementation-process reattachment and controlled-fixture sealed restack successors are packaged, while notification wake is not promoted and live restack mutation remains unverified without renewed disposable-target authority +- **Status:** Developer-preview implementation available; POSIX attempt-scoped implementation-process reattachment and controlled-fixture sealed restack successors are packaged. Windows restart reattachment remains disabled while approved cooperative harness execution is implemented; notification wake is not promoted, and live restack mutation remains unverified without renewed disposable-target authority. - **Date:** 2026-08-22 - **Audience:** Coding-harness maintainers and adapter authors - **Implementation plan:** [Autopilot implementation plan](implementation-plan.md) -- **Decision record:** [Use a durable event engine with explicit authority](adr/0001-durable-event-engine.md) +- **Decision records:** [Use a durable event engine with explicit authority](adr/0001-durable-event-engine.md) and [use cooperative harness execution on Windows](adr/0002-use-cooperative-harness-execution-on-windows.md) ## Summary @@ -285,7 +285,7 @@ interface HarnessPort { The capability manifest describes unattended execution, useful concurrency, event streaming, cancellation, restart reattachment, tool restrictions, and assurance level. -Adapters return observations. They never write the journal or choose lifecycle transitions. On POSIX hosts, built-in CLI implementation executions run beneath a detached, attempt-scoped supervisor that owns the harness pipes and bounded output/activity capture. Before harness launch, a separately detached watchdog durably confirms readiness. The harness then joins the supervisor's known process group. All terminal publication is a watchdog-owned handshake: the supervisor publishes a bounded completion candidate, the watchdog terminates and confirms the group is quiescent, and only then publishes the durable result and terminal status. This also covers supervisor exit before child-identity publication. On Windows x64, the same supervision path is enabled only when the package contains the source-built helper whose SHA-256 manifest and PE machine identity verify. That helper is a persistent request-derived broker. It creates an unnamed Job Object with `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE`, creates the harness suspended, assigns it before any user code runs, and resumes it only after assignment. The broker retains the sole lifetime Job Object handle; neither the harness nor a same-token control client can open or retain another handle. Query and termination use a versioned named-pipe channel rather than a reopenable kernel name or PID snapshot, while the JavaScript watchdog still owns deadline arbitration and terminal publication. Until the reproducible MSVC artifact is reviewed and checked into the package, Windows continues to report restart reattachment as unsupported and uses `taskkill` only for the existing direct-execution fallback. Windows ARM64 remains unsupported. The supervisor writes only fenced operational artifacts under `runs//executions//`; it cannot write `events.jsonl`, receipts, leases, snapshots, or Git state. A fresh coordinator reconstructs the exact request from the journaled attempt and immutable context, reattaches to running or terminal supervisor artifacts, and waits for terminal process-tree evidence before allowing a replacement attempt. Missing, mismatched, or incomplete bootstrap artifacts remain `EXECUTION_STATE_UNKNOWN`. Review executions remain session-scoped. +Adapters return observations. They never write the journal or choose lifecycle transitions. On POSIX hosts, built-in CLI implementation executions run beneath a detached, attempt-scoped supervisor that owns the harness pipes and bounded output/activity capture. Before harness launch, a separately detached watchdog durably confirms readiness. The harness then joins the supervisor's known process group. All terminal publication is a watchdog-owned handshake: the supervisor publishes a bounded completion candidate, the watchdog terminates and confirms the group is quiescent, and only then publishes the durable result and terminal status. This also covers supervisor exit before child-identity publication. The reviewed Windows x64 Job Object helper will not be packaged because a custom process-management executable creates antivirus, application-reputation, architecture, and provenance risk. The source and runtime path remain temporarily for ordered removal, but the artifact-producing workflow is gone and Windows continues to report restart reattachment as unsupported. Windows currently uses `taskkill` only for the existing session-scoped direct-execution fallback. The approved replacement is version-pinned cooperative harness execution: only an exact terminal response from the uninterrupted harness instance may proceed to repository verification. Harness loss becomes `EXECUTION_STATE_UNKNOWN`, launches no replacement, and requires operator recovery. This boundary does not prove process-tree quiescence. The supervisor writes only fenced operational artifacts under `runs//executions//`; it cannot write `events.jsonl`, receipts, leases, snapshots, or Git state. On supported POSIX attempts, a fresh coordinator reconstructs the exact request from the journaled attempt and immutable context, reattaches to running or terminal supervisor artifacts, and waits for terminal process-tree evidence before allowing a replacement attempt. Review executions remain session-scoped. The runtime inspects the real worktree after an agent exits. Unexpected commits, refs, or out-of-scope edits become reconciliation findings. diff --git a/skills/autopilot/docs/implementation-plan.md b/skills/autopilot/docs/implementation-plan.md index 9173e9f..384aa96 100644 --- a/skills/autopilot/docs/implementation-plan.md +++ b/skills/autopilot/docs/implementation-plan.md @@ -1,10 +1,10 @@ # Harness-agnostic Autopilot implementation plan -- **Status:** Developer-preview implementation available; POSIX attempt-scoped implementation reattachment and controlled-fixture sealed restack successors are packaged. The Windows x64 Job Object source and trusted bootstrap workflow are implemented, but Windows restart reattachment remains disabled until the reproducible native artifact is reviewed and checked into the package. +- **Status:** Developer-preview implementation available; POSIX attempt-scoped implementation reattachment and controlled-fixture sealed restack successors are packaged. The reviewed Windows x64 Job Object artifact will not be packaged; Windows restart reattachment remains disabled while cooperative harness execution is implemented. - **Date:** 2026-08-22 - **Audience:** Autopilot implementers and reviewers - **Governing design:** [Autopilot architecture](architecture.md) -- **Decision record:** [Use a durable event engine with explicit authority](adr/0001-durable-event-engine.md) +- **Decision records:** [Use a durable event engine with explicit authority](adr/0001-durable-event-engine.md) and [use cooperative harness execution on Windows](adr/0002-use-cooperative-harness-execution-on-windows.md) ## Objective diff --git a/skills/autopilot/references/adapters.md b/skills/autopilot/references/adapters.md index b5681fd..a32b10a 100644 --- a/skills/autopilot/references/adapters.md +++ b/skills/autopilot/references/adapters.md @@ -6,10 +6,10 @@ Adapters start fresh noninteractive sessions and normalize observations. They ca | Adapter | Command surface | Assurance | Restart reattachment | Verification status | |---|---|---|---|---| -| Pi | Pi JSON mode plus `pi-subagents` structured delegation when version 0.53.0+ is installed; direct Pi fallback otherwise | Cooperative | Supervised implementation attempts on POSIX; Windows x64 only with a verified packaged Job Object helper | Local edit, exact-tree review, verification, commit, and provider amendment passed with Pi 0.84.4 through pi-subagents 0.60.0; the direct fallback, process-tree cancellation, and restart reattachment have controlled coverage | -| Claude Code | `claude --print --output-format stream-json --safe-mode ...` | Cooperative | Supervised implementation attempts on POSIX; Windows x64 only with a verified packaged Job Object helper | The current 2.1.251 credential reaches the API but requires `ANTHROPIC_WORKSPACE_ID`; authenticated edit and review flows remain unverified | -| Codex | `codex exec --json --ephemeral --sandbox workspace-write ...` | Cooperative overall; Codex enforces the workspace sandbox, while item-path restrictions are post-checked | Supervised implementation attempts on POSIX; Windows x64 only with a verified packaged Job Object helper | Disposable local edit, exact-tree review, verification, and commit passed with 0.151.0 | -| OpenCode | `opencode run --format json --pure --auto ...` | Cooperative | Supervised implementation attempts on POSIX; Windows x64 only with a verified packaged Job Object helper | Disposable local edit, exact-tree review, verification, and commit passed with 1.18.25 | +| Pi | Pi JSON mode plus `pi-subagents` structured delegation when version 0.53.0+ is installed; direct Pi fallback otherwise | Cooperative | Supervised implementation attempts on POSIX; session-scoped on Windows while the approved in-process cooperative backend is implemented | Local edit, exact-tree review, verification, commit, and provider amendment passed with Pi 0.84.4 through pi-subagents 0.60.0; the direct fallback, process-tree cancellation, and restart reattachment have controlled coverage | +| Claude Code | `claude --print --output-format stream-json --safe-mode ...` | Cooperative | Supervised implementation attempts on POSIX; session-scoped on Windows | The current 2.1.251 credential reaches the API but requires `ANTHROPIC_WORKSPACE_ID`; authenticated edit and review flows remain unverified | +| Codex | `codex exec --json --ephemeral --sandbox workspace-write ...` | Cooperative overall; Codex enforces the workspace sandbox, while item-path restrictions are post-checked | Supervised implementation attempts on POSIX; session-scoped on Windows | Disposable local edit, exact-tree review, verification, and commit passed with 0.151.0 | +| OpenCode | `opencode run --format json --pure --auto ...` | Cooperative | Supervised implementation attempts on POSIX; session-scoped on Windows | Disposable local edit, exact-tree review, verification, and commit passed with 1.18.25 | The adapter parser bounds output and rejects malformed JSON-mode output. The runtime ignores model completion claims and inspects the worktree directly. @@ -36,7 +36,7 @@ Unit tests use controlled fake CLIs for command construction, changed-head denia - Queue execution becomes serial when an adapter reports concurrency one. - Missing required assurance or grants stops before edits. -- On POSIX hosts, supervised implementation processes reattach after coordinator loss. Windows x64 advertises the same capability only when the package contains the manifest-bound native Job Object helper; missing, tampered, bootstrap-only, and ARM64 helpers leave it disabled. Legacy attempts, reviews, and incomplete supervisor or Job Object bootstraps fail closed. +- On POSIX hosts, supervised implementation processes reattach after coordinator loss. The reviewed Windows Job Object helper will not be packaged, so Windows restart reattachment remains disabled. The planned Pi cooperative backend will accept terminality only through the uninterrupted owning harness instance; harness loss will remain `EXECUTION_STATE_UNKNOWN`. Legacy attempts, reviews, and incomplete supervisor bootstraps fail closed. - Late results from expired leases are quarantined. - Provider head changes block merge. - Review findings block the current attempt and enter the next deterministic attempt context as untrusted data. diff --git a/skills/autopilot/references/recovery.md b/skills/autopilot/references/recovery.md index 1897e32..4781926 100644 --- a/skills/autopilot/references/recovery.md +++ b/skills/autopilot/references/recovery.md @@ -34,7 +34,7 @@ node runtime/dist/src/cli.js --state-dir resume Resume acquires the coordinator lock, validates the sealed charter and journal, rebuilds projection state, verifies context artifacts, inspects existing worktrees and refs, and continues within the original limits. A paused unfinished item receives a fresh lease and newly hashed context; its pause-cancelled physical launch is not charged to the attempt budget. An item with a durable `ITEM_VERIFIED` checkpoint continues commit, push, change-request, check, thread, or merge reconciliation from fresh exact observations without launching another worker. Resume does not re-open `SUCCEEDED` or `STOPPED` runs. -On POSIX hosts, built-in harness adapters supervise implementation executions with a detached, attempt-scoped helper and a pre-established process-group watchdog. Windows x64 uses the same restart path only when a packaged native helper passes its SHA-256 manifest and x64 PE checks. The persistent broker creates the harness suspended, assigns it to an unnamed Job Object with kill-on-close, and resumes it only after assignment; no executable arguments or credentials are placed in an unsafe shell command or durable broker artifact. The broker alone owns the lifetime Job Object handle. The watchdog keeps canonical timestamp arbitration, queries or terminates through the exact request-derived broker channel, proves zero active processes, and alone publishes terminal artifacts. A missing, changed, ARM64, or not-yet-checked-in helper leaves Windows restart reattachment disabled while direct process-tree cancellation remains available. After coordinator loss, `resume` reconstructs the exact request from the journaled attempt and immutable context, reattaches to matching running or terminal artifacts, and observes quiescence before permitting a replacement attempt. Legacy attempts, review executions, mismatched requests, and incomplete supervisor or Job Object bootstrap artifacts remain `EXECUTION_STATE_UNKNOWN` and cannot launch a speculative replacement. +On POSIX hosts, built-in harness adapters supervise implementation executions with a detached, attempt-scoped helper and a pre-established process-group watchdog. After coordinator loss, `resume` reconstructs the exact request from the journaled attempt and immutable context, reattaches to matching running or terminal artifacts, and observes process-group quiescence before permitting a replacement attempt. The reviewed Windows x64 Job Object helper will not be packaged, so Windows restart reattachment remains disabled while the cooperative harness backend is implemented. Current Windows execution and cancellation are session-scoped. Under the approved cooperative design, only an exact terminal response through the uninterrupted owning harness instance may proceed; harness, session, or exact-subject loss becomes `EXECUTION_STATE_UNKNOWN` and cannot launch a speculative replacement. Legacy attempts, review executions, mismatched requests, and incomplete supervisor artifacts also remain unknown. ## Address review comments with an amendment successor diff --git a/skills/autopilot/runtime/native/README.md b/skills/autopilot/runtime/native/README.md index 962b15d..42e56f5 100644 --- a/skills/autopilot/runtime/native/README.md +++ b/skills/autopilot/runtime/native/README.md @@ -1,24 +1,26 @@ -# Windows Job Object helper +# Windows Job Object helper source -`windows-job-helper.c` is the source of the optional `win32-x64` process-containment helper. It uses only Win32 APIs and is not an npm dependency or Node native addon. +- **Status:** Retained temporarily for removal; not approved for packaging +- **Decision:** [Use cooperative harness execution on Windows](../../docs/adr/0002-use-cooperative-harness-execution-on-windows.md) +- **Implementation plan:** [Cooperative harness execution](../../docs/2026-08-31-cooperative-harness-execution-plan.md) -The runtime enables Windows restart reattachment only when both files exist under `native/bin/win32-x64/` and the executable matches the manifest SHA-256 and x64 PE machine identity: +`windows-job-helper.c` is the source of the optional `win32-x64` process-containment helper that was developed and validated before the project chose a binary-free Windows package boundary. + +The helper creates the harness suspended, assigns it to an unnamed Job Object with `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE`, and resumes it only after assignment. A persistent broker owns the sole lifetime Job handle and exposes authenticated query and termination through a request-derived named pipe. These mechanics remain historical implementation evidence; they are not the approved future package architecture. + +Protected workflow run [`33353702353`](https://github.com/drafael/coding-harness/actions/runs/33353702353) built the x64 helper reproducibly, passed 179 tests exactly once, and produced reviewed executable SHA-256: ```text -job-helper.exe -job-helper.json +e9017028a38c8e564aa7b73541dd1996e5b5ddf8075a7c136e06b5d55c7effef ``` -Do not build or fabricate this executable on another operating system. Run the manually dispatched `Autopilot Windows Job Object helper` GitHub Actions workflow in `drafael/coding-harness`; manifests from local builds or other workflow events are marked untrusted and rejected by packaged capability discovery. It selects the hosted x64 MSVC toolchain, builds twice in clean directories with reproducible linker flags, compares SHA-256, checks the PE architecture, runs the real Windows containment and restart suite, and uploads a commit-named bootstrap artifact. - -After reviewing the exact workflow run, compiler line, test output, artifact digest, and source commit: +The artifact will not be copied into `native/bin/win32-x64/` or checked into the repository. The protected artifact-producing workflow has been removed so it cannot be promoted accidentally. Local builds remain `local-untrusted` and cannot enable packaged capability discovery. -1. Download that workflow artifact without executing it. -2. Independently hash `job-helper.exe` and compare it with `job-helper.json` and the workflow log. -3. Copy only the reviewed executable and manifest into `native/bin/win32-x64/`. -4. Run the ordinary Ubuntu/Windows runtime CI and confirm generated `dist/native/win32-x64/` is identical. -5. Record the workflow URL, source commit, compiler version, and SHA-256 in the delivery evidence. +Until the retained source and runtime paths are removed in the planned cleanup PR: -The helper receives a bounded binary request on stdin. Executable arguments and environment values are never unsafely shell-interpolated or persisted in broker identity artifacts. Bare native commands are resolved to absolute `.exe`/`.com` targets. Recognized npm `.cmd` launchers are resolved to their Node entry point and receive the original argument array directly; arbitrary batch files fail closed. The broker creates an **unnamed** Job Object with `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE`, creates the target suspended, assigns it before any user code runs, and then resumes it. The broker is the sole lifetime job-handle owner. Restarted coordinators query or terminate through its versioned named-pipe channel and never open or inherit a Job Object handle. +- no packaged helper means Windows restart reattachment remains disabled; +- Windows uses the existing session-scoped direct execution and cancellation fallback; +- helper absence or changed execution state must fail closed; +- no documentation or report may imply that the reviewed artifact ships. -The two-build comparison proves repeatability only within the exact toolset recorded by that workflow run. The manifest binds the helper and C-source SHA-256 values to the source commit, workflow-file Git blob SHA, workflow name/ref/run identity, and complete `cl.exe /Bv` toolset output. Toolset drift requires a fresh reviewed artifact; the workflow does not claim cross-toolset reproducibility. Windows ARM64 is intentionally unsupported. +Do not build, install, or substitute a local helper. The retained source, build script, protocol implementation, and tests remain only to keep the transition reviewable until cooperative execution and native cleanup land in their ordered PRs.