# Release gates

A milestone is done when its gate passes, not when its code exists. Numbers here
are proposed targets, not measured results.

| Milestone | Deliverable | Gate | State |
|---|---|---|---|
| M0 | behaviour inventory | current failures reproducible and written down, integration failures told apart from interpreter failures | **done** — [baseline-inventory.md](baseline-inventory.md) |
| M1 | host ABI + C probe | interactive read, exact binary I/O, cancellation, no deadlock | **done** — `test/python-abi/` |
| M2 | source-built interpreter | scripts, CLI flags, two isolated programs concurrently | **done** — `test/python-runtime/`, and `pythoncheck.html` in the harness |
| M3 | files and processes | cross-runtime pipelines, correct EOF, cleanup, file consistency | descriptor layer and Emscripten FS bridge done; spawn, pipes into Python, and symlinks not started |
| M4 | environments | two independent venvs, offline and online wheel installs | **partial** — online wheels install transactionally into the owned interpreter and expose `console_scripts`; the package includes its ABI wheel index, but venvs, offline indexes, source builds, and per-environment site-packages remain |
| M5 | native packages | Pydantic core and one small extension survive repeated import/exit | **done for the current ABI** — C and PyO3 side-module wheels load through ordinary CPython imports; `pydantic==2.9.0` selects and runs with `pydantic-core==2.23.2` |
| M6 | local networking | echo server, concurrent connections, timeouts, port reuse | **partial** — the host-owned virtual TCP stack (`src/net/virtual-socket.ts`), its socket ABI family (`1792`), and router integration are done and cover `box.request()` to a non-JS listener plus cross-stack `EADDRINUSE` (`test/virtual-socket.test.ts`, `test/python-socket-abi.test.ts`, `test/universal-server.test.ts`); the CPython `_sbx_socket` adapter and `socket`/`selectors` patches are written but not yet built into the interpreter, so no Python process has bound a port through it |
| M7 | web serving | FastAPI validation, streaming, WebSocket, shutdown | **partial** — a real FastAPI/Pydantic 2 application validates and answers through ASGI; Uvicorn cannot yet serve through `box.request()` |
| M8 | threads | sync endpoints, AnyIO operations, thread cleanup | **partial** — pthread CPython, `asyncio.to_thread()`, context/cancellation/file I/O, concurrent thread sockets, executor shutdown, and synchronous FastAPI endpoints pass; browser full-stack coverage is in `test/fixtures/fullstack-browser`; churn/cleanup soak is outstanding |
| M9 | persistence | recovery after an interrupted write or install | not started |
| M10 | ML | correct inference, bounded memory, cancellation | not started |
| M11 | source builds | compile, install and import a representative C extension in-browser | not started |
| M12 | release | browser matrix, soak tests, rollback exercise | not started |

M6 still gates any broad FastAPI hosting claim. Importing the framework and
calling its public ASGI interface is useful evidence, but a publishable server
runtime must also route a real Uvicorn listener through `box.request()`. M5
still gates current Pydantic 2 releases because their Rust extension is native.

## Standing gates

Checked at every release, not once:

| Area | Gate |
|---|---|
| Process isolation | no module, global or environment leakage across independent processes |
| Process churn | 10,000 short launches with no growth in live resource counts |
| I/O | binary correctness, partial reads and writes, EOF, backpressure, Unicode terminal boundaries |
| Cancellation | kill succeeds during startup, blocked input, network wait, import and inference |
| Filesystem | rename, unlink and open semantics match the declared contract under concurrent access |
| Packaging | an interrupted install never reports a complete environment |
| Threads | repeated creation, blocking, imports and teardown do not deadlock |
| Storage | reload after an interrupted commit recovers a valid state |
| Node regression | every supported Node behaviour still passes |

Fault injection belongs in the same suite: worker crash mid-syscall, truncated
runtime assets, missing extension symbols, quota exhaustion, lost connections,
GPU device loss, cancellation during extraction, stale responses after PID
reuse, and teardown while children are blocked.
