Skip to content

feat(cli): harden resumable run sessions and add status preflight - #7

Merged
factory-ain3sh merged 10 commits into
mainfrom
run-hardening
Jul 28, 2026
Merged

feat(cli): harden resumable run sessions and add status preflight#7
factory-ain3sh merged 10 commits into
mainfrom
run-hardening

Conversation

@factory-ain3sh

@factory-ain3sh factory-ain3sh commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Description

What

Hardens vfs run into a resumable, externally-materializable session runtime, and adds vfs status <session-id> --json for daemon preflight.

Why

Handoff receive means a daemon writes two files and expects vfs run --session <id> to just work, on a machine where the session has never run, possibly after a previous owner was SIGKILLed mid-flight. Run needed a defined receiver contract and a recovery story instead of assuming it created every session it resumes.

How

  • Receiver contract: an externally materialized session is exactly delta.db + base_path (UTF-8 text file naming the receiver's base checkout). mnt/, procs/, .session.lock, and SQLite sidecars are created or recovered lazily by run.
  • Recovery primitives (vfs-core, vfs-mount): interrupted pack publications roll forward from backup, stale mounts detach, dead-owner proc records are reaped, all under the session lock.
  • vfs status --json: reports stopped | busy | live | stale-recovered, pid, pack generation, and seeded flag; preflight performs the same recovery so the daemon reads a truthful state.
  • Exit-status contract: reserved startup statuses (2 usage, 3 session live, 4 mount/sandbox install failed, 5 session missing/malformed, 126/127 exec) documented in the MANUAL; wrapped-command status passes through unchanged, signals as 128+n.
  • Recursive self-binds for directory allows (0dc24f1, found by the live cross-machine handoff demo): a plain MS_BIND self-bind of an --allow'd directory shadowed any mount nested beneath it. An externally materialized checkout under an allowed data dir kept its overlay for the inherited-cwd view but served the raw base tree to any subprocess spawned with an absolute cwd, silently losing the delta. Directory allows now bind with MS_BIND | MS_REC.

Stack (merged bottom-up 2026-07-28, vfs main @ 3b2af42):

  1. refactor: rename agentfs to vfs across runtime, tooling, and docs #4 rename agentfs to vfs
  2. feat(cli): add vfs pack for atomic session transfer artifacts #5 vfs pack
  3. feat(cli): add vfs seed for portable dirty-base capture #6 vfs seed
  4. feat(cli): harden resumable run sessions and add status preflight #7 run hardening + status <- this PR

Related Issue

Part of AC-768

Reviewer Guide

Diff shape: ~40% run/mod.rs (lifecycle + recovery + status), ~25% platform run paths simplified against the shared core, ~25% tests (run/tests.rs, test-run-resume-hardening.sh), ~10% mount recovery (vfs-mount).
Review depth: Standard, deep on the recovery ladder in run/mod.rs.
Read order:

  1. crates/vfs-cli/src/cmd/run/mod.rs — resume ladder: validate external materialization, recover pack publication, detach stale mount, reap procs, then start
  2. crates/vfs-mount/src/lib.rs — stale-mount detection/detach primitives
  3. crates/vfs-cli/src/cmd/run/linux.rs / darwin.rs — platform paths now delegating to the shared lifecycle
  4. crates/vfs-cli/tests/test-run-resume-hardening.sh — the receiver-contract and crash-resume matrix

Risk & Impact

Recovery runs on every resume, so a false-positive "stale" classification could detach a healthy session; liveness is derived from the advisory lock plus proc records, both released by the kernel on process death, which keeps the classification crash-consistent. Exit statuses 3/4/5 are now API for the daemon caller; changing them later is a breaking change.

Verification

Behavior verified. Two-file external materialization resumes cold; SIGKILL of the owner mid-run then resume recovers mount and proc state; vfs status reports stale-recovered after preflight cleanup; wrapped-command exit statuses pass through including 128+n (verified @ fb69618). Full cross-machine handoff demo (Factory /handoff over a relay, delta read back on the receiver) verified @ 0dc24f1; clip in Factory-AI/factory-mono#16942.
Regression coverage. test-run-resume-hardening.sh (new) pins the receiver contract, the crash-resume matrix, and the nested-checkout-under-allowed-ancestor case (fails on a plain MS_BIND binary, passes with MS_REC); test-sigkill-recovery.sh updated for the shared recovery path; run/tests.rs covers status classification.
Not tested. Cross-platform handoff (darwin sender to linux receiver) end-to-end in CI; exercised manually, no darwin CI runner.
Standard validators. cargo build/test and CLI shell suites clean.

Changes after the last review pass (post-`0dc24f1`)
  • 3480120 preserves live-session joiners: exclusive-lock startup rejected vfs run --session <id> against a running session as SessionStillRunning. prepare_session now downgrades to a shared lock and validates the live mount, runtime status file, and session database before joining (StartState::Live); teardown validation aligned with mount-failure exit code 4. Caught by test-run-resume-hardening.sh on the first CI run against main.
  • 5e4010e and 9a74282 cfg-gate Linux-only session-preparation helpers and the Live start state out of macOS builds.
  • Re-verified at 9a74282: full workspace suite plus resume-hardening, bounded-teardown, and corruption-torture (legacy and io_uring) shell suites green.

factory-ain3sh and others added 2 commits July 24, 2026 16:03
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
factory-ain3sh and others added 5 commits July 27, 2026 16:16
A plain MS_BIND self-bind of an allowed directory shadowed any mount
nested beneath it, so an externally materialized checkout under an
allowed data dir served the raw base tree to absolute-path resolution
while the inherited-cwd view stayed on the overlay.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
# Conflicts:
#	crates/vfs-cli/src/cmd/run/darwin.rs
Base automatically changed from seed-verb to main July 28, 2026 02:59
factory-ain3sh and others added 3 commits July 27, 2026 20:13
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
@factory-ain3sh
factory-ain3sh merged commit 3b2af42 into main Jul 28, 2026
10 checks passed
@factory-ain3sh
factory-ain3sh deleted the run-hardening branch July 28, 2026 03:49
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