Repository navigation
v1.0.12
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog,
and the project adheres to Semantic Versioning.
[1.0.12] — 2026-05-07
Closes the four "not-yet-production-ready" items v1.0.11 made
explicit. Two of them are runtime features (conflict-merge UI,
CRIU subprocess capture); two are honesty/UX (loud warnings on
empty engine layers, V1-engine workaround documented). One — V1
bit-exact KV restore — remains a vLLM-side change beyond
ProcessFork's reach and is now documented with the V0 +
enforce_eager=True workaround.
pf merge-resolve / pf merge-finalize — interactive conflict resolution
- New top-level commands. Replace the v1.1-deferred placeholder
with a real round-trip:pf merge A B→ if conflicts, exits 3 with the resolve+
finalize hint pointing at the merged-CID.pf merge-resolve <merged-cid> --workdir <dir>extracts
the merged FS into<dir>(which must NOT pre-exist),
scans for Git-style markers, and prints the conflict
file list.- Operator hand-edits.
pf merge-finalize <merged-cid> --workdir <dir>re-walks
the resolved tree, builds a single-parent image whose
parent is<merged-cid>, returns the finalized CID.
pf merge-finalizerefuses if any file in<dir>still
contains conflict markers (exit code 3); pass--forceto
finalize as-is (for tree fixtures with legitimate<<<<<<<
content).- Scan covers all three Git marker variants (
<<<<<<<,
=======,>>>>>>>); skips symlinks and binary files (NUL
byte heuristic). - Round-trip regression test (
merge_resolve_finalize_round_trip)
exercises: snapshot-X-A-B-with-parent → conflicting merge →
resolve workdir → finalize-without-resolution-fails →
hand-resolve → finalize succeeds → finalized image's
manifest.parents == [merged-cid] → checkout shows resolved
content with no markers.--forcepath tested separately.
processfork-criu adapter + pf snapshot --criu-pid <PID>
- New Python package
processfork-criu(Linux-only at runtime)
promotes the world layer'sprocsblob from
procs.unsupported.v1toprocs.criu.v1. The bundle is a
header-line JSON dict + raw tarball of CRIU'simages-dir
output, ready forpf verifyto round-trip. - New CLI flag
pf snapshot --criu-pid <PID>shells out to
python3 -m processfork_criu(via inline script) to perform
the dump. On macOS / Windows / non-criu Linux hosts the
command exits with a clear "CRIU unavailable: …" message and
the snapshot fails fast — no silent half-state. - Python API:
processfork_criu.dump_pid(pid, leave_running=True, tcp_established=False)returns aCriuBundlewhose
serialize()is the on-disk format;restore_bundle(bundle, target_dir=...)returns the new PID aftercriu restore. - Test layering reflects the honesty caveat (same as the Modal
vLLM lane: code is committed, validation lives where the
kernel lives):- Layer 1 — runs on every host (8 tests): version match,
v1 marker constants, header+tarball envelope round-trips,
deserialize rejects wrong-kind / missing-newline,
is_available()False on macOS,dump_pid/
restore_bundleraise clean RuntimeError on macOS. - Layer 2 — Linux only, no criu needed (1 test, skips on
macOS):is_available()reflects whethercriuis on
$PATH. - Layer 3 — Linux + criu binary (1 test, skips otherwise):
end-to-end: spawn a heartbeat-writing Python child,
criu dumpit, SIGKILL the original PID,criu restore,
assert the restored PID writes new heartbeats. This is
the operator-runs-it validation; the maintainer's macOS
CI has not run it. README has the caveat.
- Layer 1 — runs on every host (8 tests): version match,
- Rust-side test (
snapshot_criu_pid_fails_cleanly_on_non_linux)
confirmspf snapshot --criu-pid 1on macOS exits non-zero
with stderr mentioning CRIU/python3 (no panic, no silent empty
procs blob).
Loud warning when generic CLI snapshot writes empty engine layers
pf snapshotnow emits a multi-line stderr warning explaining
that the model + cache layers are empty and that engine state
requires the vLLM/SGLang adapter to populate. World (FS+env),
trace, and effects ARE captured.- New
--allow-empty-engine-layersflag suppresses the warning
for CI/automation that has internalized the boundary. - The empty model + cache envelopes now carry a
"note": "generic-cli-empty: populated by adapters, not by walking a directory"field so downstream tooling can detect them.
V1-engine bit-exact workaround documented
adapters/pf-vllm/README.mdgets a new "Bit-exact replay: V0
vs V1 engine" section with the V0 +enforce_eager=True
workaround for callers who need byte-identical regenerated
output. Calls out the throughput cost (1.3–1.8× slower
without CUDA graphs), V0's feature-frozen status upstream,
and when V1 + output-equivalent is acceptable (snapshot
before destructive change vs. RL rollout reproducibility).- README's bit-exact metric row links to this section.
Versions
processfork(Rust + Python wheel): 1.0.11 → 1.0.12- All 8 internal
pf-*crate version pins: → 1.0.12 - npm
@processfork/sdk: 1.0.11 → 1.0.12 - New
processfork-criuPython package: 1.0.12
Verification
cargo fmt --check,cargo clippy --workspace --all-targets -- -D warnings,cargo deny check: clean.cargo test --workspace: 204 passed (was 199; +5 from the
merge-resolve / merge-finalize / criu-pid integration tests).pytest crates/pf-py/python/tests/ adapters/pf-claude-code/tests/ adapters/pf-criu/tests/: 25 passed, 2 skipped (CRIU Linux-
only paths).node --test crates/pf-ts/test/smoke.mjs: 8/8.pf snapshot --criu-pid 1on macOS: exits non-zero with
"CRIU is Linux-only" — no panic.
What's still not in scope
- vLLM V1 engine bit-exact KV restore. Documented workaround
(V0 +enforce_eager); upstream V1 deterministic batch
scheduling is the actual fix and lives in vllm/. - Generic CLI model/cache layer auto-discovery. The "walk a
directory and produce a valid LoRA diff" approach is the
source of most "I restored my agent and it half-worked"
reports; we keep the empty-envelope-with-loud-warning path
instead.