mirror of
https://github.com/razzant/ouroboros.git
synced 2026-08-22 09:13:21 +00:00
Marketplace: auto-rename a ClawHub skill that collides with another bucket (e.g. native weather -> weather-clawhub), keeping the landed directory, sidecar, manifest name, and translated_manifest_sha256 consistent; update pins the existing directory. Map registry 404->404 / 429->429 across info/preview/search and install/update. Label preview as registry-metadata-only. Offer an LLM-first "Make runnable" repair affordance for instruction skills. Review: scope review reserves output headroom inside the reviewer's 1M context window (the shared 920K prompt SSOT is unchanged), so an oversize prompt routes to the existing non-blocking budget_exceeded skip instead of a hard provider 400. Supervisor: /evolve stop breaks the hard-timeout auto-retry chain and cancels the running evolution worker (kill_pid_tree-first teardown, terminal cancelled, no re-enqueue). Abnormal task termination reconstructs cost/rounds from durable llm_usage events and _handle_task_done falls back to the persisted task result, so per-task and evolution-campaign accounting no longer record zeros. Preflight: guarantee full process-tree teardown (process group + recursive PID tree + escaped session groups + temp-root sweep) behind platform_layer helpers, and make the timeout configurable via OUROBOROS_PREFLIGHT_TIMEOUT_SEC (300s). Logs: worker tasks forward append_jsonl log lines to the dashboard over EVENT_Q (suppressing types already delivered live to avoid double broadcast), and the Logs page backfills recent history on load/reconnect with exact-duplicate dedupe. UI: drop the duplicate Files header; import apiFetch so the MCP status refresh works. Bumps all version carriers to 6.12.0 and syncs ARCHITECTURE/DEVELOPMENT docs.
66 lines
2.8 KiB
Python
66 lines
2.8 KiB
Python
"""Coverage for the v6.12.0 dashboard log-delivery path: the worker-side log
|
|
sink (suppression contract), the main-side _handle_log_event consumer (broadcast
|
|
+ checkpoint-only persist), and the logs.js backfill/dedupe wiring."""
|
|
|
|
import inspect
|
|
import json
|
|
import pathlib
|
|
from types import SimpleNamespace
|
|
|
|
REPO = pathlib.Path(__file__).resolve().parent.parent
|
|
|
|
|
|
def test_worker_log_sink_suppresses_live_sibling_types():
|
|
from supervisor.workers import WORKER_LOG_SINK_SUPPRESSED_TYPES, worker_main
|
|
|
|
# These five already arrive live via a dedicated EVENT_Q sibling/handler;
|
|
# forwarding the worker's append_jsonl copy too would double-broadcast.
|
|
assert WORKER_LOG_SINK_SUPPRESSED_TYPES == frozenset(
|
|
{"tool_call", "llm_round", "task_checkpoint", "task_done", "llm_usage"}
|
|
)
|
|
src = inspect.getsource(worker_main)
|
|
assert "set_log_sink" in src
|
|
assert "emit_log_event" in src
|
|
assert "WORKER_LOG_SINK_SUPPRESSED_TYPES" in src
|
|
|
|
|
|
def test_handle_log_event_broadcasts_all_but_persists_only_checkpoints(tmp_path):
|
|
from supervisor import events as ev
|
|
from supervisor import state as supervisor_state
|
|
|
|
(tmp_path / "logs").mkdir()
|
|
events_file = tmp_path / "logs" / "events.jsonl"
|
|
broadcast = []
|
|
ctx = SimpleNamespace(
|
|
DRIVE_ROOT=tmp_path,
|
|
append_jsonl=supervisor_state.append_jsonl,
|
|
bridge=SimpleNamespace(push_log=lambda e: broadcast.append(e)),
|
|
)
|
|
|
|
# A previously-missing worker log type is forwarded live, never re-persisted.
|
|
ev._handle_log_event(
|
|
{"type": "log_event", "data": {"type": "task_received", "task_id": "t1"}}, ctx
|
|
)
|
|
assert any(e.get("type") == "task_received" for e in broadcast)
|
|
assert not events_file.exists()
|
|
|
|
# task_checkpoint is broadcast AND persisted exactly once (the worker
|
|
# suppresses its own copy, so this single main-side write is the only one).
|
|
ev._handle_log_event(
|
|
{"type": "log_event", "data": {"type": "task_checkpoint", "task_id": "t1", "round": 1}}, ctx
|
|
)
|
|
assert any(e.get("type") == "task_checkpoint" for e in broadcast)
|
|
lines = [ln for ln in events_file.read_text(encoding="utf-8").splitlines() if ln.strip()]
|
|
assert len(lines) == 1 and json.loads(lines[0])["type"] == "task_checkpoint"
|
|
|
|
|
|
def test_logs_js_backfills_all_streams_and_dedupes_without_dropping_preconnect():
|
|
src = (REPO / "web" / "modules" / "logs.js").read_text(encoding="utf-8")
|
|
for stream in ("'events'", "'tools'", "'progress'", "'supervisor'"):
|
|
assert stream in src, f"backfill must include the {stream} log stream"
|
|
# Exact-duplicate guard collapses backfill/live overlap…
|
|
assert "renderedLogKeys" in src
|
|
# …and backfill reruns on reconnect…
|
|
assert "ws.on('open'" in src
|
|
# …without a load-time timestamp skip that could drop the pre-connect window.
|
|
assert "loadStart" not in src
|