Skip to content

feat(sync,exec): okdev sync wait; split command-exit from delivery-failure exit semantics#159

Merged
acmore merged 2 commits into
mainfrom
feat/sync-wait-and-exec-exit-semantics
Jul 5, 2026
Merged

feat(sync,exec): okdev sync wait; split command-exit from delivery-failure exit semantics#159
acmore merged 2 commits into
mainfrom
feat/sync-wait-and-exec-exit-semantics

Conversation

@acmore

@acmore acmore commented Jul 5, 2026

Copy link
Copy Markdown
Owner

What

Two scripting-reliability gaps in the edit-run loop, addressed together because both are about making okdev's exit behavior trustworthy for scripts and agents.

okdev sync wait (new subcommand)

Blocks until every configured sync mapping has zero pending bytes in both directions, then returns:

vim train.py && okdev sync wait && okdev exec -- python train.py
  • Purely a wait — it never starts or repairs sync. If background sync is not running it fails fast with guidance instead of blocking.
  • Forces an immediate rescan on both sides before polling, so a file written moments earlier is indexed now rather than after the FS-watcher delay — without this the wait could "converge" before syncthing even noticed the new file.
  • --timeout (default 10m) with pending-byte progress while waiting; timeout error points at okdev status --details.

Fanout exec exit semantics

Previously any pod failure — including the command itself exiting non-zero — produced the same FAILED: ... N of M pods failed framing and exit 1, so scripts could not tell "my command failed" from "okdev could not deliver the command". Now:

outcome framing exit code
command ran, exited non-zero (single pod) COMMAND EXITED NON-ZERO: remote status verbatim (exit 3 → 3)
command ran, exited non-zero (multi-pod) COMMAND EXITED NON-ZERO: 1
any delivery failure (unreachable, timeout, container gone) FAILED: 69 (sysexits EX_UNAVAILABLE)

The single-pod case also fixes a docs/behavior mismatch: the command reference promised the remote status is "always preserved", but the fanout path flattened it to 1.

Testing

  • Unit: sync wait cmd shape + inactive-session fail-fast; single-pod exit-status preservation; multi-pod remote-exit framing (no sentinel); mixed exit+timeout carries ErrExecInfraFailure and classifies to 69.
  • Kind e2e: smoke — write file → sync waitexec cat proves the guarantee; single-pod exit 3 → exit status 3 with COMMAND EXITED NON-ZERO framing. pytorchjob — multi-pod exit 3 → exit 1, no FAILED: header.
  • gofmt, go vet, go test -race ./... all clean.

Docs (command-reference.md) and skill references updated.

🤖 Generated with Claude Code

acmore and others added 2 commits July 6, 2026 00:15
…y-failure semantics

okdev sync wait [session] [--timeout 10m] blocks until every sync mapping
has zero pending bytes in both directions, giving scripts the edit-run
guarantee (vim f.py && okdev sync wait && okdev exec -- python f.py). It
forces a rescan on both sides first so files written moments earlier are
indexed immediately instead of after the FS-watcher delay, and fails fast
with guidance when background sync is not running.

Fanout exec failures are now layered: when every failing pod merely
reported a non-zero command exit, the summary is COMMAND EXITED NON-ZERO
and okdev exits with the remote status (single pod, preserving the
documented verbatim-exit contract) or 1 (multi-pod). Any delivery failure
(unreachable, timeout, container gone) keeps the FAILED framing and maps
to new dedicated exit code 69 (sysexits EX_UNAVAILABLE) via the
ErrExecInfraFailure sentinel, so scripts can tell "my command failed"
from "okdev could not deliver the command" without parsing output.

Covered by unit tests plus kind e2e scenarios (sync wait convergence
guarantee, single-pod exit-status preservation, multi-pod non-zero
framing). Docs and skill references updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@acmore acmore force-pushed the feat/sync-wait-and-exec-exit-semantics branch from 06a76fa to e63940c Compare July 5, 2026 16:16
@acmore acmore merged commit b437497 into main Jul 5, 2026
2 checks passed
@acmore acmore deleted the feat/sync-wait-and-exec-exit-semantics branch July 5, 2026 16:29
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