mirror of
https://github.com/razzant/ouroboros.git
synced 2026-10-03 12:18:39 +00:00
Module side. 22 D08 owners classified: 4 byte-identical across tip/reference
(schedule_contract, supervisor/__init__, active_activity, schedule_time);
6 pure upstream drift - tip bytes stand (promotion_source, tools/followup,
message_bus, queue_transitions, state, task_admission); 4 NEW post-cutoff
upstream modules with no ledger rows - untouched (cognitive_operations,
log_addressing, subagent_task_truth, task_dispatch); 4 monoliths split.
The split: 16 leaves, 142 moved spans, every span transplant-tool proof-green
against git show HEAD:<monolith> (ast=tokens=byte-roundtrip on every symbol,
leaf_invariants=[], unread_declared=[]). supervisor/events.py 4476->1947:
eight handler families (chat_delivery, subagent_admission, schedule_task,
project_routing, coop_checkpoint, budget, worker_reports, runtime_controls).
supervisor/queue.py 1587->1265: queue_schedules on the _queue handle.
supervisor/workers.py 4396->2808: worker_promotion/chat_lane/pool_lifecycle
on the _pool handle + worker_process (the child, no pool state).
tools/control.py 3225->2110 (SHARED D07/D08): only the D08 leaves
control_events/control_routing/control_runtime; D07 rows untouched.
Facades = tip parent - moved spans + re-export block, facade audit green
(every kept span byte-identical to tip, every moved name re-exported).
Drift-probe first per leaf: 4 reference leaves fully byte-true, 12 with
41 upstream-drifted spans re-emitted from tip bytes; no oracle semantics
replayed over drift.
HOT-DEFERRED with evidence (cancel/custody D09-class; upstream 65b5d19f
re-decomposed this ownership): events_task_done family, _handle_cancel_task,
_close_campaign_after_owner_stop, events_evolution_done, queue_snapshot,
queue_timeouts, queue_evolution (upstream's own evolution_lifecycle.py
supersedes), worker_assignment, worker_health. Deferred semantic-delta rows:
D06 events taxonomy (dispatch/EVENT_HANDLERS keep tip bytes), D04 retired
timeout knobs, six retired-name rows. Row 2016 (_handle_schedule_task)
deferred on a mechanism finding: its >300-line FUNCTION_DEBT entry is
(path, qualname)-keyed and this tree's transition validator has no D11
same-qualname relocation rule - the handler stays with its debt key.
Test side: identity suites test_events_extraction (5, pins the deferred
inventory as the F2 work order), test_control_extraction (5),
test_worker_process_extraction (5, reference-verbatim); LEAVES table in
test_module_handle_extraction gains six tool-derived declared-set rows.
Dead-patch class re-pointed to owner leaves mirroring reference adaptations
across 13 files (coop quiescence, schedules, worker_process trio, promote
admission seam -> control_events, pool-disabled probe -> control_routing,
evolution restart claims -> control_runtime alias, budget append_jsonl ->
events_budget, ephemeral-turn source scan -> worker_chat_lane, routing
producers AST scan -> control_routing, worker_main scan -> worker_process,
resource-leak source contracts reference-verbatim); all 15 touched test
files lossless (test-name multisets equal), no new ast-identical dup bodies.
HOT_CODE_PATHS mirrors the 12 hot leaves (D04-block precedent).
size-ratchet manifest regenerated with the official tool (queue.py enters
the 1001-1500 band with rationale; giants shrink in place); ratchet lane
5 passed. ruff check . --select F clean. CI-shape battery on this tree:
parallel 11965 passed rc=0, serial 609 passed rc=0. Import smoke fwd+rev
green; worker_main stays picklable from supervisor.worker_process.
docs/v7next/LEDGER_CORRECTIONS.md: D08 lane section (11 entries).
(cherry picked from commit 1426ea3ae2413580992575f5ab890497469a6657)
75 lines
2.7 KiB
Python
75 lines
2.7 KiB
Python
"""Structural contracts for the semantic-no-op worker child-process extraction."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import ast
|
|
import pathlib
|
|
import pickle
|
|
|
|
from supervisor import worker_process, workers
|
|
|
|
REPO = pathlib.Path(__file__).parents[1]
|
|
|
|
_MOVED = (
|
|
"WORKER_LOG_SINK_SUPPRESSED_TYPES",
|
|
"_bind_worker_repo_root",
|
|
"_current_custody_session_id",
|
|
"_log_worker_crash",
|
|
"_prepare_worker_task_runtime",
|
|
"worker_main",
|
|
)
|
|
|
|
# What could NOT move: the pool's own state, and everything that reads it. The
|
|
# child process has none of it, which is exactly why the seam sits here.
|
|
_POOL_STATE = (
|
|
"REPO_DIR", "DRIVE_ROOT", "MAX_WORKERS", "WORKERS", "PENDING", "RUNNING",
|
|
"CRASH_TS", "QUEUE_SEQ_COUNTER_REF", "_CTX", "_LAST_SPAWN_TIME",
|
|
)
|
|
|
|
|
|
def test_the_child_process_module_never_imports_the_pool():
|
|
tree = ast.parse(pathlib.Path(worker_process.__file__).read_text(encoding="utf-8"))
|
|
for node in ast.walk(tree):
|
|
if isinstance(node, ast.ImportFrom):
|
|
assert node.module != "supervisor.workers"
|
|
if isinstance(node, ast.Import):
|
|
assert all(alias.name != "supervisor.workers" for alias in node.names)
|
|
|
|
|
|
def test_workers_facade_reexports_every_moved_identity():
|
|
for name in _MOVED:
|
|
assert getattr(workers, name) is getattr(worker_process, name), name
|
|
|
|
|
|
def test_worker_main_is_still_module_level_and_picklable_by_name():
|
|
"""Spawn platforms re-import the target by qualified name; a nested or
|
|
wrapped function would break every non-fork host."""
|
|
assert worker_process.worker_main.__module__ == "supervisor.worker_process"
|
|
assert worker_process.worker_main.__qualname__ == "worker_main"
|
|
assert pickle.loads(pickle.dumps(worker_process.worker_main)) is worker_process.worker_main
|
|
tree = ast.parse(pathlib.Path(worker_process.__file__).read_text(encoding="utf-8"))
|
|
assert any(
|
|
isinstance(node, ast.FunctionDef) and node.name == "worker_main"
|
|
for node in tree.body
|
|
)
|
|
|
|
|
|
def test_the_pool_kept_its_state_and_the_child_module_declares_none_of_it():
|
|
child = vars(worker_process)
|
|
for name in _POOL_STATE:
|
|
assert hasattr(workers, name), name
|
|
assert name not in child, name
|
|
|
|
|
|
def test_worker_process_extraction_size_bounds():
|
|
counts = {
|
|
module.__name__: len(
|
|
pathlib.Path(module.__file__).read_text(encoding="utf-8").splitlines()
|
|
)
|
|
for module in (workers, worker_process)
|
|
}
|
|
assert counts["supervisor.worker_process"] <= 1000
|
|
# The pool itself is NOT split by this commit: its remaining size is bound to
|
|
# the module-global state the spec defers to the QueueState step, so this
|
|
# bound records the honest current ceiling rather than claiming a win.
|
|
assert counts["supervisor.workers"] <= 2894
|