v0.4.0 Automation execution plan

August 4, 2026 ยท View on GitHub

Status: authoritative and resumable.

Integration branch: agent/v0.4-automation-integration

Frozen Phase 1 baseline: PR #70 head b4308ee73dfb6206a61fb71e6f70b4447656af05

This file is the source of truth for the v0.4.0 engineering work. After a context reset, read this file, the final integration PR description, and the current Git status before continuing from the first incomplete gate.

1. Live baseline

Recorded on 2026-08-03 (Asia/Hong_Kong):

  • origin/main: ca347b915026ac44b5f9e63a3224bc4eabe53e6f
  • PR #70: open Draft, base main, head b4308ee73dfb6206a61fb71e6f70b4447656af05
  • PR #70 CI: run 30808409605, conclusion success
  • PR #70 review: Codex found no major issue at b4308ee; no unresolved review threads
  • PR #70 manual smoke checkbox is still unchecked, so no historical GUI smoke result is accepted as final evidence
  • Issue #69: open; partial rollout and global-state writes are not reliably visible to the outer rollback path
  • PR #62: closed, unmerged, superseded by #70; design reference only
  • final integration branch did not exist remotely before this worktree was created

Local isolated baseline at b4308ee:

  • Node: 110 passed
  • Core: 91 passed, 1 conditional WSL-only test skipped
  • Application: 9 passed
  • WinForms: 29 passed
  • release version verification for v0.3.2: passed
  • git diff --check: passed

Evidence is under the ignored artifacts/evidence/baseline-b4308ee-* directory.

Current integration evidence recorded on 2026-08-04:

  • implementation commit 28c4dd4 passed the visible Windows Release Headful gate on the interactive input desktop
  • manifest coverage: 40/40; required Headful scenarios: 53/53; errors/blockers: 0/0; 17 real dialogs were handled; published EXE SHA-256 independently matched
  • the evidence contains real native dialogs, sync/switch/restore/prune file and SQLite effects, prune physical-deletion/sentinel checks, restart persistence, and GUI-to-Application operation/lifecycle traces
  • Node passed 183/183; Core passed 188 with one expected WSL environment gate; Application passed 49/49, Automation 27/27, WinForms 66/66, and GUI contract tests 36/36; the Release solution built with zero warnings and errors
  • the post-review hardening requires explicit relocation targets, publishes and revalidates automatic-prune deletion targets, and reserves exit code 5 for failures with complete-rollback evidence; independent stable-diff review found no P0/P1/P2

2. Architecture and ownership

The required dependency direction is:

Core storage and domain operations
             ^
Application use cases and immutable operation state
             ^                         ^
Business Automation host          WinForms event adapter
                                         ^
                                  real WinForms controls
                                         ^
                                  GUI Automation bridge

Responsibilities:

  • Core owns config, rollout, SQLite, global state, backups, transaction primitives, restore, storage resolution, locking, and WSL safety.
  • Application owns status, diagnostics, plan, sync, switch, restore, prune, settings/provider changes, operation serialization, cancellation, immutable inputs, plan freshness, and structured outcomes.
  • WinForms owns rendering, native/platform dialogs, focus, external folder launching, and conversion of real control events to Application calls.
  • Business Automation calls Application use cases directly and never copies Core workflows.
  • GUI Automation drives actual control instances on the UI thread and records the control-event-to-Application causal chain. It may not call Application directly while claiming a control was exercised.

3. Transaction and recovery model (Issue #69)

Both Node and .NET implementations use equivalent semantics:

  1. Acquire the existing per-Codex-Home operation lock.
  2. Refuse a new write if an unresolved transaction journal exists.
  3. Scan and fingerprint targets, validate SQLite, and create the managed backup before any target mutation.
  4. Create a durable transaction journal under the operation's managed backup as transaction-journal.jsonl before the first target mutation.
  5. Stage replacement content beside each target, flush it, and use a same-directory atomic replacement. Each append-only journal record is flushed before the associated target transition.
  6. Before replacing each target, record applying; after replacement and metadata restoration, record applied. The outer coordinator receives the durable applied list even when the batch throws.
  7. SQLite remains protected by its own transaction. Rollout/global-state file mutations are compensated from the managed backup if any normal failure or cancellation occurs.
  8. Rollback records each target independently. If rollback itself fails, keep the journal and return the original error, rollback errors, backup path, incomplete targets, and safe recovery instructions.
  9. A completed operation atomically marks the journal committed; a completed rollback marks it rolledBack. Terminal journals may be retained as audit evidence and pruned with their managed backup.
  10. Startup/status checks detect non-terminal or truncated journals. Read-only diagnostics remain available and show the bound backup; mutations are blocked until an explicit restore marks that journal rolled back. No silent half-complete state is accepted, and pruning protects every backup referenced by a non-terminal journal.

The fault-injection matrix covers backup failure, staging failure, first and Nth target failure, atomic replacement failure, global-state primary/backup partial failure, rollback failure, cancellation, crash/restart recovery, concurrency, duplicate execution, idempotent success, and the ordinary success path. Tests inspect disk state independently of returned objects.

--apply remains unavailable until this matrix passes in both implementations.

M1 evidence at the first implementation checkpoint: Node 120/120; Core 101 passed / 1 pre-existing WSL-only conditional skip. Both ran with fresh temporary HOME/UserProfile/Codex/SQLite/AppData/Temp/cache roots and inherited credential-like environment variables removed.

4. Application use cases

Application exposes one IApplicationService boundary with immutable request and result records for:

  • Describe
  • GetStatus / diagnostics
  • CreatePlan
  • Sync
  • Switch
  • Restore
  • Prune

Every operation has an operationId, lifecycle state, structured warnings and errors, cancellation, and one-at-a-time concurrency protection. WinForms and Business Automation use the same implementation. Existing #70 behavior is a regression gate: provider fallback, three model modes, busy locking, immutable snapshots, no await-time parameter drift, refresh serialization, and hard blocking after a failed storage refresh.

5. Business Automation protocol

The Windows Release build contains CodexProviderSync.Automation.exe and automation-protocol-v0.4.schema.json.

Protocol family: experimental 0.4; one process invocation emits exactly one JSON result on stdout. Diagnostics go to stderr. Commands:

  • describe
  • status
  • plan
  • sync
  • switch
  • restore
  • prune

Write commands default to plan-only. Mutation requires all of:

  • explicit --apply
  • a plan document produced by the same protocol version
  • the exact SHA-256 plan digest
  • an unexpired plan
  • matching normalized inputs, target paths, target fingerprint, and isolated root policy

Restore relocation additionally requires the explicit trio --sqlite-home, --allow-sqlite-home-relocation, and --no-config. Sync and switch plans list each concrete automatic-prune deletion target; checked cleanup must match that exact set and its recursive fingerprints before any planned backup is deleted.

Exit codes are stable within protocol 0.4: 0 success, 2 validation or usage, 3 stale/invalid plan, 4 target busy/concurrency, 5 operation failed but rollback completed, 6 recovery required/rollback incomplete, 7 cancellation/timeout, and 10 internal protocol failure. Code 5 requires explicit complete-rollback evidence. A failure before the Application reaches Applying is reported as 2; an applying failure without rollback or recovery evidence fails closed as 10.

Machine-readable results distinguish success, warning, failure, rollback, and recovery. Unknown commands, malformed input, unsupported capabilities, path escape, timeout, cancellation, stale plans, and duplicate execution are schema-tested. No command reads or modifies auth.json.

6. GUI interaction inventory

Static MainForm entries currently discovered:

RegionStable IDTypeActionsCapability
storagestorage.codexHomeComboBoxget/set/selectsettings + refresh input
storagestorage.codexHome.browseButtoninvokedialog service
storagestorage.sqliteHomeTextBoxget/setsettings + refresh input
storagestorage.sqliteHome.browseButtoninvokedialog service
storagestatus.refreshButtoninvokerefresh
statusstatus.outputRichTextBoxgetui-only result rendering
providerprovider.listListViewget/selectprovider selection
providerprovider.manualIdTextBoxget/setmanual provider input
providerprovider.addManualButtoninvokeadd provider
providerprovider.removeManualButtoninvokeremove provider
executionexecution.updateConfigCheckBoxget/set/togglesync/switch mode
executionexecution.model.followProviderRadioButtonget/setmodel mode
executionexecution.model.keepCurrentRadioButtonget/setmodel mode
executionexecution.model.customRadioButtonget/setmodel mode
executionexecution.customModelTextBoxget/setmodel input
restorerestore.includeConfigCheckBoxget/setrestore options
restorerestore.includeDatabaseCheckBoxget/setrestore options
restorerestore.includeSessionsCheckBoxget/setrestore options
backupbackup.retentionCountNumericUpDownget/setretention
operationoperation.executeButtoninvokesync/switch
restorerestore.executeButtoninvokerestore
backupbackups.openDirectoryButtoninvokeui-only shell boundary
backupbackups.pruneButtoninvokeprune
updateupdates.checkButtoninvokeupdate check
logslogs.openDirectoryButtoninvokeui-only shell boundary

Runtime enumeration is authoritative and may add stable IDs for containers, focusable status elements, application-owned dialogs, and keyboard commands. Provider rows use template provider.row with a normalized provider ID hash as instanceKey; visible text and list order never participate in identity.

Native folder-picker internals are exempt because Windows owns them. The real browse button event and real FolderBrowserDialog still run; the external Headful driver selects a path inside the isolated root. Shell-open actions use an isolated launcher in Automation mode and verify the requested isolated path.

7. GUI bridge and safety

The bridge is disabled in normal mode. Automation launch requires an isolated root containing the sentinel .codex-provider-sync-test-root and a bootstrap descriptor created with user-only access. The descriptor contains a random pipe name and one-time token; the token is never placed on the command line or written to ordinary logs.

Transport is a Windows named pipe with PipeOptions.CurrentUserOnly, one authenticated client, request allowlists, bounded messages, timeouts, and replay rejection. Paths must remain under the canonical isolated root. Normal mode, missing/wrong/replayed credentials, a second client, path traversal, and non-isolated dialog/capture paths are rejected.

Capabilities:

  • ui.launch (harness/bootstrap)
  • ui.describe
  • ui.snapshot
  • ui.get
  • ui.set
  • ui.invoke
  • ui.wait
  • ui.shutdown

Commands marshal to the actual WinForms UI thread. ui.invoke uses real control APIs (PerformClick, selection/text/check changes, and real window messages for keyboard paths). The external Headful driver operates real native and application-owned dialogs while the pending ui.invoke observes the real event and Application completion path. A deterministic operation gate can hold a real use case to test busy, disabled, cancel, and timeout states.

Each business action emits:

automationId -> GUI event -> operationId -> Application capability -> result

with UI-thread identity, event name, timestamps, structured outcome, redacted values, and schema-2 Application operation ID/kind/lifecycle records.

8. Manifest and coverage gate

The static manifest records window/region, control type, actions, visible/enabled conditions, Application capability or ui-only, risk, scenario IDs, and narrow exemptions. Runtime snapshots record created instances, visible/enabled/busy state, safe values/options, dialogs, and active operations.

The gate fails for an unregistered interactive control, duplicate ID, missing template, unused manifest entry, unexecuted declared action, missing E2E mapping, missing business trace, or unjustified exemption. Required coverage is 100% for declarations, runtime instances, and declared entry actions.

Generated matrix:

window -> automationId/templateId -> control -> action -> API
       -> Application capability/ui-only -> test -> trace -> result

9. Isolated verification and one-command regression

Every test process receives an explicit allowlisted environment with temporary HOME, USERPROFILE, CODEX_HOME, SQLite Home, AppData, LocalAppData, Temp, NuGet cache, npm cache, settings, backups, logs, captures, and fixture provider URLs using example.invalid. Credential-like inherited variables are removed. Every root contains the sentinel and every candidate read/write path is checked before launch. Tests refuse to start if isolation cannot be proven.

The one-command Windows gate is invoked with:

pwsh ./scripts/run-windows-gui-e2e.ps1

It performs Release publish, isolated fixture creation, real visible GUI launch, bridge authentication, manifest traversal, all Business and GUI scenarios, filesystem/result equivalence, trace/evidence/coverage generation, restart verification, and safe shutdown. A hidden or skipped run is not a Headful pass. Implementation commit 28c4dd4 passed the full-entry gate with 40/40 manifest entries and 53/53 required scenarios; relevant implementation changes require a new run.

Formal matrix:

  • all existing Node/.NET tests
  • transaction fault injection and crash recovery
  • Application unit and concurrency/cancellation tests
  • Business host process/schema/exit-code tests
  • bridge protocol and security tests
  • manifest/runtime/action/trace gate
  • sync/switch/restore/prune Business-vs-GUI filesystem equivalence
  • Windows Release publish and published-host invocation
  • real visible Windows Release GUI full-entry E2E and restart
  • macOS Core/Application build compatibility
  • release version and package-content verification
  • GitHub CI at the exact final head

10. Version, packaging, and compatibility

All shipped npm/.NET projects move together to 0.4.0. The protocol remains experimental 0.4; manifest and protocol versions identify incompatible changes. The Windows ZIP includes the GUI, Automation host, schema, and static manifest. No formal tag or Release is created in this work.

11. PR #62 disposition

Retained: layering, shared application behavior, structured machine protocol, plan/apply, explicit write opt-in, temporary fixtures, stable identifiers, schema validation, and package verification.

Changed: no stable JSONL v1 promise; one-shot 0.4 JSON is the initial Business API; plan lifetime is evidence-driven; UI Automation is a real Headful bridge, not a hidden layout probe; the release may contain the companion executable because current requirements now justify it.

Rejected: fixed five-minute lifetime as a permanent contract, a prematurely stable v1 surface, reflection-based MainForm invocation, hidden/mock GUI substitution, and future macOS migration as a v0.4 blocker.

12. Milestones and gates

  • M0a: read governing instructions and live GitHub state
  • M0b: create integration worktree from exact PR #70 head
  • M0c: isolated baseline bound to b4308ee
  • M0d: independent architecture review and checkpoint push
  • M1: #69 transaction/recovery implementation and fault matrix
  • M2: complete shared Application use cases and WinForms migration
  • M3: Business Automation host, schema, packaging, and process tests
  • M4: GUI manifest, stable IDs, real-control bridge, trace, and safety
  • M5: one-command Release Headful E2E and 100% entry/action gate
  • M6: version/docs/release notes/migration notes and preview package
  • M7: final exact-head local suite, policy-authorized Claude reliability challenge, independent local final-diff/GitHub review, CI, and handoff report

Completion is permitted only when every required item passes at the same final head. Otherwise the handoff states PARTIAL-BLOCKED with exact external blockers; touching real data or a protected boundary is FAILED.