From 4963b61556833aaf7888a2757659254bb770a869 Mon Sep 17 00:00:00 2001 From: mikolaj92 Date: Sun, 18 Oct 2026 17:53:46 +0200 Subject: [PATCH 1/3] lokay build --- README.md | 37 +++++++++++++++++-------------------- tests/test_fleet.py | 14 ++++++-------- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index d1e3fd2..265e766 100644 --- a/README.md +++ b/README.md @@ -88,14 +88,12 @@ primitives for long-lived worker OS processes: including optional consumer-owned append paths for stdout/stderr (or an injected opener), immediate-exit probe timing, environment overlay and generation injection, and opaque JSON pid metadata. -- `spawn(spec) -> SpawnResult` -- first-launch-only: writes `pid.json` with - `status="launch_intent"` before `Popen`, then starts a subprocess with - `start_new_session` and a fail-closed immediate-exit probe. Immediate exit - leaves the tombstone; presence of the file blocks automatic relaunch. -- `stop(unit_dir) -> StopResult` -- requests cooperative termination only - through the live `Popen` handle owned by this supervisor. It never sends - SIGKILL, never signals a numeric PID, and never clears the process tombstone. +- `spawn(spec) -> SpawnResult` -- first-launch-only subprocess launch with + `start_new_session` and an immediate-exit probe. +- `stop(unit_dir) -> StopResult` -- requests cooperative termination; `StopResult.killed` and `cleaned` stay `False`. + See [Fail-closed process lifecycle](#fail-closed-process-lifecycle) for launch + persistence, termination authority, and operator clearance. - `stop_process(pid)` -- rejected numeric-PID primitive; always raises `ProcessTombstoneError` because a PID cannot prove process identity. - `liveness(unit_dir) -> Liveness` -- returns `"running"` or `"stale"` from @@ -108,14 +106,14 @@ stays in the consuming project. ### Desired-state reconciliation -`DesiredStateReconciler` builds a generic supervisor on those primitives: the -consumer declares which units should be running and the reconciler converges -reality to that declaration, without each consumer re-implementing the -lock / generation-fencing / atomic-write mechanics. +`DesiredStateReconciler` applies consumer-declared desired state without +re-implementing lock / generation-fencing / atomic-write mechanics. Existing +`pid.json` metadata blocks launch regardless of PID liveness; observation reports +running-or-unknown, not verified workload health. - Per-unit `state.json` (desired / actual / generation), written atomically; `write_json_atomic` / `read_json` are exposed for reuse. -- **Generation fencing**: each (re)spawn increments a generation and the child +- **Generation fencing**: each launch increments a generation and the child is spawned aware of it (the default action injects `DATASOURCE_KIT_GENERATION`; a consumer that injects its own spawn action picks its own variable). A `merge_heartbeat` is accepted only when the reporting generation matches, so a @@ -128,8 +126,9 @@ lock / generation-fencing / atomic-write mechanics. `policy` is a consumer hook (`honor_desired_state` is the default) deciding per unit whether it should run -- the kit never decides which units run. -The default launch handles rich, consumer-declared process specs directly; -launch/stop remain injectable (`spawn_action` / `stop_action`). For example: +The default launch passes consumer-declared specs to `spawn` without bypassing +its first-launch-only fence. Launch/stop remain injectable (`spawn_action` / +`stop_action`). For example: ```python spec = ProcessSpec( @@ -148,11 +147,8 @@ spec = ProcessSpec( Paths and names remain consumer-owned. Environment values are used only for launch and are never serialized into `pid.json`; opaque pid metadata must be JSON-compatible and cannot replace the standard pid fields. Parent-side log -descriptors are closed after spawning. `pid.json` is established as a durable -`launch_intent` fence before `Popen`; surviving the probe window does not create -the file, and immediate exit does not remove it. Presence of the file is a -tombstone that prevents automatic replacement. No health semantics beyond -process liveness -- health interpretation stays in the consumer. +descriptors are closed after spawning. Health interpretation stays in the +consumer. ### Generic fleet pass hosting @@ -489,7 +485,8 @@ FastAPI adapter tests drive the router with `httpx2.AsyncClient` and Fleet worker launch is deliberately first-launch-only. `spawn` writes `pid.json` with `status="launch_intent"` before `Popen`. The session-leader exec gate waits for that durable provenance (`unit`, `generation`, stable random `token`) before executing -consumer code. Immediate exit does not remove the file. Any surviving metadata is a +consumer code. Launch failure or immediate exit leaves the metadata in place. +Any surviving metadata is a tombstone, regardless of PID liveness or readability, and prevents automatic replacement. Disabling never removes it. The owning in-memory supervisor may request cooperative TERM through its live `Popen` diff --git a/tests/test_fleet.py b/tests/test_fleet.py index 173b79c..a9ce64a 100644 --- a/tests/test_fleet.py +++ b/tests/test_fleet.py @@ -67,13 +67,10 @@ def test_spawn_contract_matches_readme_and_docstring() -> None: """Public spawn docs match fence-before-exec, not post-probe pid.json.""" readme = Path(__file__).resolve().parents[1] / "README.md" text = readme.read_text(encoding="utf-8") - assert '`spawn(spec) -> SpawnResult` -- first-launch-only: writes `pid.json` with' in text - assert '`status="launch_intent"` before `Popen`' in text - assert "Immediate exit\n leaves the tombstone; presence of the file blocks automatic relaunch." in text - assert "`pid.json` is established as a durable\n`launch_intent` fence before `Popen`" in text - assert "surviving the probe window does not create\nthe file, and immediate exit does not remove it." in text - assert "Presence of the file is a\ntombstone that prevents automatic replacement." in text - assert "Immediate exit does not remove the file." in text + assert '`spawn(spec) -> SpawnResult` -- first-launch-only subprocess launch' in text + assert '`spawn` writes `pid.json` with\n`status="launch_intent"` before `Popen`' in text + assert "Launch failure or immediate exit leaves the metadata in place." in text + assert "Existing\n`pid.json` metadata blocks launch regardless of PID liveness" in text assert "Any surviving metadata is a\ntombstone, regardless of PID liveness or readability, and prevents automatic replacement." in text assert "after the child survives its probe window, and immediate exit leaves none" not in text assert "writes pid.json atomically, and performs a fail-closed immediate-exit probe." not in text @@ -373,7 +370,8 @@ def test_stop_contract_matches_readme_and_docstring(tmp_path: Path) -> None: readme = Path(__file__).resolve().parents[1] / "README.md" text = readme.read_text(encoding="utf-8") assert "`stop(unit_dir) -> StopResult`" in text - assert "never sends\n SIGKILL, never signals a numeric PID, and never clears the process tombstone." in text + assert "cooperative TERM through its live `Popen`\nhandle" in text + assert "Disabling never removes it." in text assert "`StopResult.killed` and `cleaned` stay `False`." in text assert "`stop_process(pid)` -- rejected numeric-PID primitive" in text assert "no numeric-PID signalling, escalation, adoption, guardian cleanup, or restart is" in text From 37868b01472c3af1825f6ba7ea085aaf4d8936fe Mon Sep 17 00:00:00 2001 From: mikolaj92 Date: Sun, 18 Oct 2026 17:57:42 +0200 Subject: [PATCH 2/3] lokay fix --- tests/test_fleet.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_fleet.py b/tests/test_fleet.py index a9ce64a..f883110 100644 --- a/tests/test_fleet.py +++ b/tests/test_fleet.py @@ -69,6 +69,8 @@ def test_spawn_contract_matches_readme_and_docstring() -> None: text = readme.read_text(encoding="utf-8") assert '`spawn(spec) -> SpawnResult` -- first-launch-only subprocess launch' in text assert '`spawn` writes `pid.json` with\n`status="launch_intent"` before `Popen`' in text + assert "The session-leader exec gate waits for that\ndurable provenance (`unit`, `generation`, stable random `token`) before executing\nconsumer code." in text + assert "The default launch passes consumer-declared specs to `spawn` without bypassing\nits first-launch-only fence." in text assert "Launch failure or immediate exit leaves the metadata in place." in text assert "Existing\n`pid.json` metadata blocks launch regardless of PID liveness" in text assert "Any surviving metadata is a\ntombstone, regardless of PID liveness or readability, and prevents automatic replacement." in text From a615be526f345f500b6a020eb4f55e4b1d1758e5 Mon Sep 17 00:00:00 2001 From: mikolaj92 Date: Sun, 18 Oct 2026 18:04:56 +0200 Subject: [PATCH 3/3] lokay fix --- README.md | 34 ++++++++++++++++------------------ tests/test_fleet.py | 16 ++++++++-------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 265e766..8b98912 100644 --- a/README.md +++ b/README.md @@ -88,12 +88,14 @@ primitives for long-lived worker OS processes: including optional consumer-owned append paths for stdout/stderr (or an injected opener), immediate-exit probe timing, environment overlay and generation injection, and opaque JSON pid metadata. -- `spawn(spec) -> SpawnResult` -- first-launch-only subprocess launch with - `start_new_session` and an immediate-exit probe. -- `stop(unit_dir) -> StopResult` -- requests cooperative termination; +- `spawn(spec) -> SpawnResult` -- first-launch-only: writes `pid.json` with + `status="launch_intent"` before `Popen`, then starts a subprocess with + `start_new_session` and a fail-closed immediate-exit probe. Immediate exit + leaves the tombstone; presence of the file blocks automatic relaunch. +- `stop(unit_dir) -> StopResult` -- requests cooperative termination only + through the live `Popen` handle owned by this supervisor. It never sends + SIGKILL, never signals a numeric PID, and never clears the process tombstone. `StopResult.killed` and `cleaned` stay `False`. - See [Fail-closed process lifecycle](#fail-closed-process-lifecycle) for launch - persistence, termination authority, and operator clearance. - `stop_process(pid)` -- rejected numeric-PID primitive; always raises `ProcessTombstoneError` because a PID cannot prove process identity. - `liveness(unit_dir) -> Liveness` -- returns `"running"` or `"stale"` from @@ -106,14 +108,9 @@ stays in the consuming project. ### Desired-state reconciliation -`DesiredStateReconciler` applies consumer-declared desired state without -re-implementing lock / generation-fencing / atomic-write mechanics. Existing -`pid.json` metadata blocks launch regardless of PID liveness; observation reports -running-or-unknown, not verified workload health. - - Per-unit `state.json` (desired / actual / generation), written atomically; `write_json_atomic` / `read_json` are exposed for reuse. -- **Generation fencing**: each launch increments a generation and the child +- **Generation fencing**: each (re)spawn increments a generation and the child is spawned aware of it (the default action injects `DATASOURCE_KIT_GENERATION`; a consumer that injects its own spawn action picks its own variable). A `merge_heartbeat` is accepted only when the reporting generation matches, so a @@ -126,9 +123,8 @@ running-or-unknown, not verified workload health. `policy` is a consumer hook (`honor_desired_state` is the default) deciding per unit whether it should run -- the kit never decides which units run. -The default launch passes consumer-declared specs to `spawn` without bypassing -its first-launch-only fence. Launch/stop remain injectable (`spawn_action` / -`stop_action`). For example: +The default launch handles rich, consumer-declared process specs directly; +launch/stop remain injectable (`spawn_action` / `stop_action`). For example: ```python spec = ProcessSpec( @@ -147,8 +143,11 @@ spec = ProcessSpec( Paths and names remain consumer-owned. Environment values are used only for launch and are never serialized into `pid.json`; opaque pid metadata must be JSON-compatible and cannot replace the standard pid fields. Parent-side log -descriptors are closed after spawning. Health interpretation stays in the -consumer. +descriptors are closed after spawning. `pid.json` is established as a durable +`launch_intent` fence before `Popen`; surviving the probe window does not create +the file, and immediate exit does not remove it. Presence of the file is a +tombstone that prevents automatic replacement. No health semantics beyond +process liveness -- health interpretation stays in the consumer. ### Generic fleet pass hosting @@ -485,8 +484,7 @@ FastAPI adapter tests drive the router with `httpx2.AsyncClient` and Fleet worker launch is deliberately first-launch-only. `spawn` writes `pid.json` with `status="launch_intent"` before `Popen`. The session-leader exec gate waits for that durable provenance (`unit`, `generation`, stable random `token`) before executing -consumer code. Launch failure or immediate exit leaves the metadata in place. -Any surviving metadata is a +consumer code. Immediate exit does not remove the file. Any surviving metadata is a tombstone, regardless of PID liveness or readability, and prevents automatic replacement. Disabling never removes it. The owning in-memory supervisor may request cooperative TERM through its live `Popen` diff --git a/tests/test_fleet.py b/tests/test_fleet.py index f883110..173b79c 100644 --- a/tests/test_fleet.py +++ b/tests/test_fleet.py @@ -67,12 +67,13 @@ def test_spawn_contract_matches_readme_and_docstring() -> None: """Public spawn docs match fence-before-exec, not post-probe pid.json.""" readme = Path(__file__).resolve().parents[1] / "README.md" text = readme.read_text(encoding="utf-8") - assert '`spawn(spec) -> SpawnResult` -- first-launch-only subprocess launch' in text - assert '`spawn` writes `pid.json` with\n`status="launch_intent"` before `Popen`' in text - assert "The session-leader exec gate waits for that\ndurable provenance (`unit`, `generation`, stable random `token`) before executing\nconsumer code." in text - assert "The default launch passes consumer-declared specs to `spawn` without bypassing\nits first-launch-only fence." in text - assert "Launch failure or immediate exit leaves the metadata in place." in text - assert "Existing\n`pid.json` metadata blocks launch regardless of PID liveness" in text + assert '`spawn(spec) -> SpawnResult` -- first-launch-only: writes `pid.json` with' in text + assert '`status="launch_intent"` before `Popen`' in text + assert "Immediate exit\n leaves the tombstone; presence of the file blocks automatic relaunch." in text + assert "`pid.json` is established as a durable\n`launch_intent` fence before `Popen`" in text + assert "surviving the probe window does not create\nthe file, and immediate exit does not remove it." in text + assert "Presence of the file is a\ntombstone that prevents automatic replacement." in text + assert "Immediate exit does not remove the file." in text assert "Any surviving metadata is a\ntombstone, regardless of PID liveness or readability, and prevents automatic replacement." in text assert "after the child survives its probe window, and immediate exit leaves none" not in text assert "writes pid.json atomically, and performs a fail-closed immediate-exit probe." not in text @@ -372,8 +373,7 @@ def test_stop_contract_matches_readme_and_docstring(tmp_path: Path) -> None: readme = Path(__file__).resolve().parents[1] / "README.md" text = readme.read_text(encoding="utf-8") assert "`stop(unit_dir) -> StopResult`" in text - assert "cooperative TERM through its live `Popen`\nhandle" in text - assert "Disabling never removes it." in text + assert "never sends\n SIGKILL, never signals a numeric PID, and never clears the process tombstone." in text assert "`StopResult.killed` and `cleaned` stay `False`." in text assert "`stop_process(pid)` -- rejected numeric-PID primitive" in text assert "no numeric-PID signalling, escalation, adoption, guardian cleanup, or restart is" in text