Files
roboco/roboco/services/gateway/choreographer/_protocol.py
T
f2e5676198 W7: Possibilities matrix (work-already-done fast path) (#522)
* [W7] Add possibilities_matrix_enabled feature flag (default off)

* [W7] Add _work_appears_done predicate (status+commits+PR+ACs+no-open-findings)

* [W7] Add CI-green quality proxy for the fast path (local fallback on no-CI)

* [W7] Add work-already-done fast path in i_am_done (slimmed gates, no rich plan)

* [W7] Add WORK_ALREADY_DONE prompt state

* [W7] Make fast path mypy-clean (cast to helpers for _resolve_ci_status; typed mock locals)

* [W7] Extract _all_criteria_addressed to bring _work_appears_done under xenon B

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-15 04:33:24 +02:00

159 lines
4.6 KiB
Python

"""Typed stub mixins inherit from for static analysis.
The role mixins (`board.py`, `doc.py`, `qa.py`, …) call methods like
``self.task.get(...)`` and ``self._emit_rejection(...)`` that live on
the legacy ``Choreographer`` class in ``_impl.py``. Without a typed
reference, mypy resolves those as ``Any`` (via ``# type: ignore[attr-defined]``)
which then bubbles up as ``no-any-return`` errors at every Envelope-returning
verb.
This module gives mypy a typed view of those helpers. ``ChoreographerHelpers``
is **not** a Protocol — Protocol with abstract members causes the
composed ``Choreographer`` class to be flagged as instantiating an
abstract class. Instead it's a plain class with stub signatures used
ONLY under ``TYPE_CHECKING``; at runtime mixins inherit from ``object``
so there's no abstract-method baggage. The real implementations live
on ``_LegacyChoreographer`` and are picked up by Python's MRO when the
composed ``Choreographer`` runs.
"""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from uuid import UUID
from roboco.services.gateway.choreographer._verb_runner import VerbRunner
from roboco.services.gateway.envelope import Envelope
class ChoreographerHelpers:
"""Typed stub of attributes + helpers role mixins call on ``self``.
Stub bodies (``...``) are never executed; the real methods live on
``_LegacyChoreographer`` and resolve via MRO at runtime.
"""
task: Any
work_session: Any
git: Any
a2a: Any
journal: Any
audit: Any
evidence_repo: Any
async def _emit_rejection(
self,
env: Envelope,
*,
agent_id: UUID,
task_id: UUID | None,
verb: str,
) -> Envelope:
raise NotImplementedError
async def _teardown_sandbox_best_effort(self, agent_id: UUID) -> None:
raise NotImplementedError
async def _toolchain_broken_guard(
self, agent_id: UUID, task: Any, *, reviewer: bool = False
) -> Envelope | None:
raise NotImplementedError
async def _conventions_guard(
self,
agent_id: UUID,
task: Any,
briefing: dict[str, Any],
preferred_parent: str | None = None,
) -> Envelope | None:
raise NotImplementedError
@classmethod
def _free_text_soup(
cls, checks: tuple[tuple[str, Any, int], ...]
) -> Envelope | None:
raise NotImplementedError
@staticmethod
def _soup_or_decision_env(
soup: Envelope | None, decision: Any, briefing: dict[str, Any]
) -> Envelope | None:
raise NotImplementedError
async def _guard_free_text(
self,
*,
checks: tuple[tuple[str, Any, int], ...],
task: Any,
agent_id: UUID,
role_str: str,
verb: str,
) -> Envelope | None:
raise NotImplementedError
async def _briefing_for(
self,
agent_id: UUID,
task_id: UUID | None,
*,
task: Any | None = None,
include_ac_coverage: bool = False,
full: bool = False,
include_company_goals: bool = False,
) -> dict[str, Any]:
raise NotImplementedError
async def _project_slug_for(self, t: Any) -> str | None:
raise NotImplementedError
@staticmethod
def _with_briefing(
env: Envelope,
briefing: dict[str, Any],
) -> Envelope:
raise NotImplementedError
async def _run_claim_guards(
self,
*,
agent_id: UUID,
task: Any,
role_str: str | None = None,
skip_dev_guards: bool = False,
) -> Envelope | None:
raise NotImplementedError
async def _touch(self, task_id: UUID | None) -> None:
raise NotImplementedError
def _verb_runner(self) -> VerbRunner:
raise NotImplementedError
async def _build_tracing_gap(
self,
agent_id: UUID,
task_id: UUID,
missing: list[str],
*,
task: Any | None = None,
) -> Envelope:
raise NotImplementedError
async def _resolve_ci_status(self, task_id: UUID, t: Any) -> dict[str, Any] | None:
raise NotImplementedError
def actor_context_fields(agent: Any) -> tuple[str | None, str | None]:
"""``(actor_slug, agent_team)`` for a spec ``Context``, None-agent safe.
Every verb builds its policy Context with the same two conditional
kwargs; inlining them pushed nine verbs over the xenon B threshold when
the team-match sweep added ``agent_team`` to all 27 sites.
"""
if agent is None:
return None, None
team = getattr(agent, "team", None)
return getattr(agent, "slug", None), str(team) if team else None