feat: extract agent-bus scheduling kernel - #15
Merged
Merged
Conversation
Four defects in the extracted scheduling kernel, all of the same shape: code carried over from the source implementation kept an assumption its original environment satisfied, while the portable abstraction changed. SpawnGuard reservations leaked on any failed submit. `pre_check` reserves tokens and registers the job, but the RAII release lives in `_run_and_finalize`, which does not exist until `create_task` has run — so an unregistered role (`get_prompt_for` raising) or a failing session dispatch leaked the reservation permanently, decaying `remaining_tokens` and the concurrency count for the life of the bus. Resolve the system prompt before reserving, register the job entry before spawning, and release explicitly on every path that can raise in between. Sessions get the same treatment on both the free and the queued dispatch — the latter matters because `_drain_session_queue` swallows dispatch failures by design, so nothing upstream is left to hand the reservation back. `AgentComm.consume` ordered its durable cursor with `int(event.id)`, but `EventId` is an opaque string and `new_event_id()` returns uuid4 hex. Add an explicit `KernelEvent.seq` ordinal and read it through `event_ordinal`, falling back to a decimal id so stores that expose their integer primary key keep working. A store that stamps neither now raises `EventStoreContractError` naming the fix instead of a bare `ValueError`, and `AgentBus` logs the lost durable-recovery capability at ERROR rather than swallowing it at debug — that blanket `except Exception` is why the whole L1-0 path could be dead with nothing in the logs. `_AgentCommEventStore` declared `EventSink.append(task_id, event_type, payload, agent_role)` but was called with a whole `KernelEvent`, so a host implementing the documented protocol bound the event to `task_id` and returned None. Messaging genuinely needs the richer append — `from_agent` / `to_agent` / `message_type` / `correlation_id` are the fields the reader queries on — so declare that signature and drop the `EventSink` inheritance. `EventSink` stays exactly as it was for telemetry; the two roles are now distinct and documented. `resolve_research_wall` selected its input by key presence, so `wall_deadline_s` was unreadable whenever `research_wall_time_s` existed: `hard_total_s` came back 0, `check_wall_feasibility` passed unconditionally, and the total-task ceiling was silently unenforced. Read both keys independently and select on value validity. Contract tests cover all four, including the store-ordering contract the `consume` docstring referenced but that did not exist in this package. Validation: ruff clean, pyright 0 errors, 849 passed (was 812), `uv build`, plus a smoke run of all four paths against the built wheel. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Validation
uv run ruff check agent_core testsuv run pyright agent_core— 0 errors, 0 warningsuv run pytest -q— 809 passeduv build