All notable changes to the public surface are documented here. Exact version pins are the install contract, so a breaking change only lands where a pin is deliberately moved. Releases happen only on an explicit maintainer decision; the Unreleased section accumulates until then.
한국어 요약은 각 절 하단에 둔다.
Nothing yet.
-
Root surface reshaped to a porcelain machine handle (37 exports -> 6). The root now exports exactly
boot,open,createWebComputer,checkEnvironment,PyProcError, andPYPROC_ERROR_CODES.bootresolves to aPyprocMachinehandle whose namespaces are the model's vocabulary:run/runAsync(execute),fs(files),term(terminal),proc(worker process pool),history(checkpoint/restore volatile, commit/recover/export durable), plus theruntimeescape hatch for capability detail (enableSyscallBridge,enableAsgiServer,enableDeviceFs, ...). Root class exports are gone; the classes remain as typed contracts reached through the handle. -
openis the one revival verb. Its trust contract follows the source instead of flattening semantics:open(bundleBlob, trustOpts)verifies envelope integrity and signature before touching the heap (replacesopenMachine),open({ dir, name })revives an OPFS session save by manifest replay plus delta (replacesbootSession().load(...)), andopen({ persistent })opens the multi-tab persistent machine and returns aKernelElectionhandle (replacesopenPersistentMachine). -
Deterministic boot is an explicit opt-in.
boot({ deterministic: true, ...manifest })replacesbootSession(manifest).PYTHONHASHSEED=0and the entropy stub change guest-visible semantics, so they are never the default; the choice is recorded in the environment fingerprint of every durable commit, andhistory.export/history.saveexist only in this mode (a non-deterministic state has no replay guarantee). -
Subpaths reshaped. New:
pyproc/history, the state kernel's contract surface (sha256 address law, object model,StateStorecontract,commitState/openStateprotocol, signed tags,PYBUNDLE1bundle codec,PAGE_SIZE). Removed:pyproc/runtime,pyproc/reactive,pyproc/syscall-bridge,pyproc/process-os(their capabilities moved onto the handle, see the migration map). Remaining:pyproc/machine,pyproc/worker,pyproc/assets, and the demotedpyproc/gpu/pyproc/socket/pyproc/wasi. -
One bundle format (
PYBUNDLE1).machine.history.export()writes a single signed, content-addressed envelope;openreads it. The layout is authoritative indocs/reference/bundleFormat.md. The legacy.pymachineenvelopes (meta v2/v3) are still readable through a format-detecting reader, and that legacy reader sunsets at the next breaking release: re-export machines you intend to keep. -
State kernel (
src/state) refounds the journal. Durable commits are now content-addressed objects with HEAD/PREV generations, verify-on-read (PYPROC_STATE_CORRUPT, with PREV fallback) and owner fencing (PYPROC_STATE_FENCE_STALEprotects HEAD from a superseded writer). Existing journals are migrated automatically on first recover; no consumer action is needed. -
Machine crypto injection.
pyproc/machinepersistence and image constructors now require a provider fromcreateMachineCryptoProvider(crypto?)instead of a bareCryptoobject, so digest/signature law lives in one place (the state kernel). -
Removed
SharedKernel(and its SharedWorker host asset). It was documented as a non-canonical auxiliary path;KernelElection/openPersistentMachineis the canonical multi-tab lane and keeps document-levelcrossOriginIsolated(SharedWorker cannot). Migration: replacenew SharedKernel(...)withopenPersistentMachine({ name, manifest }). -
Moved GPU surface (
GpuCompute,GpuArray,GpuBridge) from the root export to thepyproc/gpusubpath, and removedRuntime.enableGpu(). GPU needs a real adapter and a windowed session, so it cannot be covered by the headless CI gate that guards the root surface. Migration:import { GpuCompute } from "pyproc/gpu"and construct directly. -
Moved
SocketBridgefrom the root export to thepyproc/socketsubpath, and removedRuntime.enableSocketBridge(). It requires an external WS to TCP relay that pyproc does not ship. Migration:import { SocketBridge } from "pyproc/socket"; new SocketBridge(rt, cfg). -
Moved
bootWasi/WasiSessionfrom the root export to thepyproc/wasisubpath. The WASI lane is a research preview that proves the engine-independent core; the production Python surface is the Pyodide lane. Migration: import frompyproc/wasi. -
Removed alias methods that duplicated one behavior under two names:
ReactiveController.timeTravel(...)(userestoreLive(...)orcp.restore()),PyProc.interrupt(pid)(usesignal(pid, SIGNAL.INT)),PyProc.mapSerial(fnSrc, args)(a benchmark baseline, not a product surface; run tasks throughexec(pid, ...)sequentially if you need a serial reference).
| Before | After |
|---|---|
boot() -> Runtime |
boot() -> PyprocMachine; the runtime is machine.runtime |
bootSession(manifest) |
boot({ deterministic: true, ...manifest }) |
openMachine(blob, trustOpts) |
open(blob, trustOpts) |
session.exportImage(opts) |
machine.history.export(opts) |
session.save(dir, name) / session.load(dir, name) |
machine.history.save(dir, name) / open({ dir, name }) |
openPersistentMachine(opts) |
open({ persistent: opts }) |
rt.enableReactive() checkpoint/restore |
machine.history.checkpoint() / restore() / tree() / prune() (raw controller stays at machine.runtime.enableReactive()) |
rt.enableJournal(cfg) commit/recover/pack |
machine.history.commit / recover / watch / pack with { dir, ... } |
new PyProc(opts) + pool.boot(n) |
await machine.proc({ lanes: n, ...opts }) |
rt.enableTerminal(cfg) |
machine.term(cfg) |
createMachineKeyPair / exportMachinePublicKey / fingerprintMachinePublicKey |
createStateKeyPair / exportStatePublicKey / fingerprintStatePublicKey from pyproc/history |
bootEnv(manifest, dirs) / runScript(rt, src) |
boot manifest options (packages, env, setup, wheelDir) |
import { Runtime } from "pyproc/runtime" |
root boot() + machine.runtime (types via index.d.ts) |
bare Crypto into machine persistence/image constructors |
createMachineCryptoProvider(crypto) from pyproc/machine |
PyProc.forkMany(srcPid, dstPids): the speculative-exploration primitive. A parent's delta is one value, so a fan-out harvests it once and broadcasts over a SharedArrayBuffer instead of re-harvesting per lane:O(heap + N x delta)rather thanO(N x heap). Lanes stay isolated and candidate results are byte-identical to a serial run.forkis now a 1:1 delegation (name and return shape unchanged). An agent loop is three calls: fan out, run candidates,fork(winner, main)to adopt.PyProcErrorandPYPROC_ERROR_CODES: one error contract for the whole surface. Every error thrown by pyproc now carriescode(programmatic branching axis),retryable, and optionalcontext(worker Python exceptions arrive withcontext.pyExcType, e.g."KeyboardInterrupt"). Worker boundaries preserve codes.- Checkpoint handles:
reactive.checkpoint()now returns{ ..., sp, restore() }, so a restore is one call (cp.restore()) instead of carryingstackSaveplus an index.restore/restoreLiveaccept omittedsavedSP(the node-stored value is used). ReactiveController.collectDelta(fromIdx?, toIdx?, opts?): the shared primitive behind session save, journal commit, and machine image export.ReactiveController.markDirty(): report heap mutations that bypassexecSeq(live PyProxy calls) so the nextrestoreLiveupgrades to the rehash path.ReactiveController.pruneTo(j)/dispose(): memory valves for the checkpoint tree.Runtime.noteStateMutation()and boundary-recording restores: a restore now counts as a state mutation, so observers such as the journal idle watcher commit restored state.Runtime.enableReactive()is memoized (one controller per runtime): two controllers could silently corrupt each other's live-diff restores.MachineJournalcfg.onStatus(observe idle-commit success/failure; failures carryPYPROC_JOURNAL_IO) andcfg.pruneAfterCommit(tree pruning after each commit).PyProc.respawn(pid)andJobControl.killHard(jobId): forced lane recovery that keeps fork symmetry (replay reboot).PyProc.mapno longer leaves silentundefinedholes when every lane dies; unrun tasks resolve to{ error: "pool exhausted: ..." }.- Nested machine containers now route
run/heapLen/kill/spawnthrough an explicit path router at any depth, and a dead container rejects immediately instead of hanging. PyProc.bootInfo: the lastboot()result ({ workers, avgBootMs, forked }) is kept on the pool, so paths that do not consume the return value directly (such asmachine.proc()) still have an observation point.- Asset provenance policy v2: the engine boot set (
pyodide.js/pyodide.mjs/pyodide.asm.mjs/pyodide.asm.wasm/python_stdlib.zip/pyodide-lock.json, bytes cross-verified between the GitHub release and the jsdelivr CDN) is now described in the single asset catalog with a second distribution vocabulary,upstream-cdn-runtime-reference(referencing upstream's own distribution point at runtime is not redistribution). Both Web Computer guests now carry the same described provenance in signed envelopes; the "undescribed guest" marker is retired.
- 루트 37개 -> 6개(porcelain 머신 핸들):
boot/open/createWebComputer/checkEnvironment/PyProcError/PYPROC_ERROR_CODES만 남는다.boot가 돌려주는 머신 핸들의 어휘(run/fs/term/proc/history)가 표면이고, 능력 상세는machine.runtime탈출구로 연다. - open 통합: 외부 bundle(무결성+서명 선검증),
{ dir, name }세션 저장(리플레이+델타),{ persistent }멀티탭(KernelElection반환, 구openPersistentMachine)을 부활 동사 하나로 통합. 결정적 부팅은boot({ deterministic: true })opt-in이고history.export/save는 그 모드 전용. - subpath 재편:
pyproc/history신설(상태 커널 계약: 주소 법, 오브젝트 모델, store, 서명 tag, bundle 코덱).pyproc/runtime/reactive/syscall-bridge/process-os소멸 (핸들 동사로 이동, 위 마이그레이션 표 참조). - 단일 bundle 포맷
PYBUNDLE1: 구.pymachinev2/v3 reader는 다음 브레이킹 릴리즈에 일몰 예고(보관할 머신은 재내보내기). - 상태 커널(
src/state) 신설과 저널 재기초: content-addressed HEAD/PREV 세대, verify-on-read(PYPROC_STATE_CORRUPT), fence(PYPROC_STATE_FENCE_STALE). 구 저널은 첫 recover에서 자동 이관. - machine 암호 주입: persistence/image 생성자는 맨
Crypto가 아니라createMachineCryptoProvider가 만든 provider를 요구한다. - forkMany: 부모 델타를 한 번만 수확해 N 레인에 방송(4.05배). 그 위 4-후보 병렬 탐색이 직렬 재시도 대비 5.2배. fork는 1:1 위임으로 이름과 반환 계약 불변.
- SharedKernel 삭제(정본은 openPersistentMachine), GPU/Socket/WASI는 subpath로 강등, 별칭 3종(timeTravel/interrupt/mapSerial) 절삭.
- PyProcError 단일 오류 계약(코드/재시도 가능성/파이썬 예외 타입이 워커 경계를 건너온다).
- 체크포인트 핸들(cp.restore() 한 호출), collectDelta/markDirty/pruneTo/dispose, 복원의 경계 기록, 컨트롤러 memoize, 저널 onStatus/pruneAfterCommit, respawn/killHard, map 부분 실패 정직화, 컨테이너 중첩 라우팅과 사망 즉시 거부.
PyProc.bootInfo: 마지막 boot() 결과를 풀에 보관(반환을 직접 받지 않는machine.proc()경로의 관측 지점).- 자산 provenance 정책 v2: 엔진 부팅 집합 6파일을 단일 catalog가 기술(두 유통 경로
바이트 교차 검증), 배포 어휘
upstream-cdn-runtime-reference신설(상류 배포 지점 런타임 참조는 재배포가 아니다). 두 guest가 같은 기술된 출처를 봉투에 나르고 미기술 게스트 표식은 은퇴.