From 05aacb7a2a5241f1a92bbc547111c9c58218dedb Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Mon, 19 Oct 2026 22:41:27 -0400 Subject: [PATCH 1/8] P300: compare live unjudged owners through the declared parity row --- src/agent_comms/commander_parity/fleet.py | 45 +++++++++++++++++++++++ src/agent_comms/commander_parity/rows.py | 5 +++ 2 files changed, 50 insertions(+) create mode 100644 src/agent_comms/commander_parity/fleet.py diff --git a/src/agent_comms/commander_parity/fleet.py b/src/agent_comms/commander_parity/fleet.py new file mode 100644 index 0000000000..71d0c86842 --- /dev/null +++ b/src/agent_comms/commander_parity/fleet.py @@ -0,0 +1,45 @@ +"""Live board and work comparisons; neither side is a recorded answer.""" + +from __future__ import annotations + +from dataclasses import dataclass + +from pydantic import JsonValue + +from ..commander.judge import Edit +from ..commander.order import Commander +from ..field_codec import FieldCodec +from ..tool_caller import ThreadCaller +from ..tools import CommsUnjudgedTool +from . import ParityComparison + + +@dataclass(frozen=True) +class ReadComparison(ParityComparison): + """Compare complete wire facts, not a count that can hide different records.""" + + owner: str + current: JsonValue + native: JsonValue + + @property + def passed(self) -> bool: + return self.current == self.native + + def describe(self) -> str: + return f"owner={self.owner}; complete_current_native_equal={self.passed}" + + +class UnjudgedComparison(ReadComparison): + @classmethod + def read(cls) -> ParityComparison: + context = Commander.read(Commander.path()) + current = Edit.unjudged(context.comms, context.commander) + native = CommsUnjudgedTool(thread=context.commander).apply( + context.comms, ThreadCaller(context.commander) + ) + return cls( + "CommsUnjudgedTool / judge.Edit.unjudged", + FieldCodec.encode(current), + FieldCodec.encode(native.edits), + ) diff --git a/src/agent_comms/commander_parity/rows.py b/src/agent_comms/commander_parity/rows.py index ab22a2feb2..6d35aa8e49 100644 --- a/src/agent_comms/commander_parity/rows.py +++ b/src/agent_comms/commander_parity/rows.py @@ -13,6 +13,7 @@ from . import ParityComparison, ParityRow, UnverifiedParity from .load import LoadComparison from .measurements import RuleComparison, StorageComparison, measured_load +from .fleet import UnjudgedComparison class CreateProblemParityRow(ParityRow): @@ -110,6 +111,10 @@ class UnjudgedParityRow(ParityRow): native = "`comms_unjudged`: calls and unit messages after the last verdict" phases = (ReviewQueuePhase,) + @classmethod + def verify(cls) -> ParityComparison: + return UnjudgedComparison.read() + class PublicStoryParityRow(ParityRow): number = 13 From 9d95395bc0084ab498e1759106a5c0956bbade58 Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Mon, 19 Oct 2026 22:45:42 -0400 Subject: [PATCH 2/8] P300: run live board, branch and order-work comparisons and name missing owners --- src/agent_comms/commander_parity/fleet.py | 214 ++++++++++++++++++++-- src/agent_comms/commander_parity/rows.py | 28 ++- 2 files changed, 228 insertions(+), 14 deletions(-) diff --git a/src/agent_comms/commander_parity/fleet.py b/src/agent_comms/commander_parity/fleet.py index 71d0c86842..c4f01f333a 100644 --- a/src/agent_comms/commander_parity/fleet.py +++ b/src/agent_comms/commander_parity/fleet.py @@ -1,22 +1,40 @@ -"""Live board and work comparisons; neither side is a recorded answer.""" +"""Live board, branch and work comparisons against their current consumers.""" from __future__ import annotations +import io +import re +import sys +from collections.abc import Callable +from contextlib import redirect_stdout from dataclasses import dataclass +from types import CodeType, FrameType from pydantic import JsonValue from ..commander.judge import Edit -from ..commander.order import Commander +from ..commander.order import BoardVerb, Commander, hhmm from ..field_codec import FieldCodec +from ..native_tool_call import CodingCall from ..tool_caller import ThreadCaller -from ..tools import CommsUnjudgedTool -from . import ParityComparison +from ..tools import ( + CommsOrderWorkTool, + CommsThreadsTool, + CommsTodoListTool, + CommsUnjudgedTool, + CommsWorkBranchesTool, + TodoList, + UnjudgedEdits, +) +from ..transcript_events import ToolStartTranscript +from ..turn_digests import TurnsSince +from ..work_branches import WorkBranches +from . import ParityComparison, UnverifiedParity @dataclass(frozen=True) class ReadComparison(ParityComparison): - """Compare complete wire facts, not a count that can hide different records.""" + """Compare complete projected facts, not a count that can hide different records.""" owner: str current: JsonValue @@ -27,19 +45,189 @@ def passed(self) -> bool: return self.current == self.native def describe(self) -> str: - return f"owner={self.owner}; complete_current_native_equal={self.passed}" + return f"owner={self.owner}; current_native_equal={self.passed}" -class UnjudgedComparison(ReadComparison): +def observe[T]( + code: CodeType, + result_type: type[T], + current: Callable[[], JsonValue], + native: Callable[[T], JsonValue], + owner: str, +) -> ParityComparison: + """Observe the real native return used by the current path without replacing either. + + A second read of a changing fleet is not a parity comparison of the first read. + The profile hook only records returns and restores any existing observer. + """ + results: list[T] = [] + previous = sys.getprofile() + + def returned(frame: FrameType, event: str, value: object) -> None: + if event == "return" and frame.f_code is code and isinstance(value, result_type): + results.append(value) + if previous: + previous(frame, event, value) + + sys.setprofile(returned) + try: + rendered = current() + finally: + sys.setprofile(previous) + if len(results) != 1: + return UnverifiedParity( + f"{owner}: expected one live native return, observed {len(results)}" + ) + return ReadComparison(owner, rendered, native(results[0])) + + +@dataclass(frozen=True) +class BoardFacts: + problem: str + owner_file: str + holder: str + order: str + due: str + progress: str + delivered: bool + strikes: int + + @classmethod + def rendered(cls, board: str) -> tuple[BoardFacts, ...]: + rows = [] + for line in board.splitlines(): + if re.match(r"^\| P[1-9][0-9]*:", line): + values = tuple(part.strip() for part in line.split("|")[1:-1]) + if len(values) != 9: + raise ValueError("The current board has an ambiguous row") + problem, owner_file, holder, order, due, progress, delivered, strikes, _ = values + rows.append( + cls( + problem, + owner_file, + "" if holder.startswith("unassigned:") else holder, + order, + due, + progress, + delivered != "no", + int(strikes), + ) + ) + return tuple(rows) + + @classmethod + def native_rows(cls, listed: TodoList) -> tuple[BoardFacts, ...]: + return tuple( + cls( + f"{todo.id}: {todo.text}", + todo.order.owner.to_wire(), + todo.holder, + todo.order.id, + hhmm(todo.deadline), + listed.progress[todo.id].line if todo.id in listed.progress else "-", + not todo.pending, + todo.strike_count, + ) + for todo in sorted(listed.todos, key=lambda item: int(item.id[1:])) + ) + + +class BoardComparison: + @classmethod + def read(cls) -> ParityComparison: + context = Commander.read(Commander.path()) + fleet = CommsThreadsTool().apply(context.comms, ThreadCaller(context.commander)) + names = {record.thread.name for record in fleet.threads} + + def current() -> JsonValue: + output = io.StringIO() + with redirect_stdout(output): + BoardVerb().run(context) + return FieldCodec.encode(BoardFacts.rendered(output.getvalue())) + + def native(listed: TodoList) -> JsonValue: + if any(todo.holder and todo.holder not in names for todo in listed.todos): + raise ValueError("A board holder is absent from the live native fleet") + return FieldCodec.encode(BoardFacts.native_rows(listed)) + + return observe( + CommsTodoListTool.apply.__code__, + TodoList, + current, + native, + "CommsTodoListTool + CommsThreadsTool / Commander BoardVerb", + ) + + +class BranchComparison: @classmethod def read(cls) -> ParityComparison: context = Commander.read(Commander.path()) - current = Edit.unjudged(context.comms, context.commander) - native = CommsUnjudgedTool(thread=context.commander).apply( - context.comms, ThreadCaller(context.commander) + current: list[JsonValue] = [] + native: list[JsonValue] = [] + for repo in context.repos: + current.append( + FieldCodec.encode( + WorkBranches(repo.checkout).read(context.comms.registry.snapshot()) + ) + ) + reply = CommsWorkBranchesTool( + checkout=str(repo.checkout), + unlinked_only=False, + ).apply(context.comms, ThreadCaller(context.commander)) + native.append(FieldCodec.encode(reply.branches)) + return ReadComparison( + "CommsWorkBranchesTool / current Git and forge branch reader", + current, + native, ) - return cls( + + +class OrderWorkComparison: + @classmethod + def read(cls) -> ParityComparison: + context = Commander.read(Commander.path()) + current: list[JsonValue] = [] + native: list[JsonValue] = [] + for todo in context.held_orders(): + since = todo.order.at.recorded_at("An order") + turns = context.comms.transcripts.turns(todo.holder, TurnsSince(since)) + calls: dict[str, str] = {} + for turn in reversed(turns.turns): + for event in turn.events: + if isinstance(event, ToolStartTranscript) and not event.before(since): + call = CodingCall.decode( + event.tool_call_id, event.tool_name, event.raw_input + ) + calls[event.tool_call_id] = call.digest() + current.append(FieldCodec.encode((todo.id, tuple(reversed(calls.items()))))) + reply = CommsOrderWorkTool(problem=todo.id).apply( + context.comms, + ThreadCaller(context.commander), + ) + native.append( + FieldCodec.encode( + ( + todo.id, + tuple((call.tool_call_id, call.digest) for call in reply.calls), + ) + ) + ) + return ReadComparison( + "CommsOrderWorkTool / tool_watch CodingCall digests from live source turns", + current, + native, + ) + + +class UnjudgedComparison: + @classmethod + def read(cls) -> ParityComparison: + context = Commander.read(Commander.path()) + return observe( + CommsUnjudgedTool.apply.__code__, + UnjudgedEdits, + lambda: FieldCodec.encode(Edit.unjudged(context.comms, context.commander)), + lambda reply: FieldCodec.encode(reply.edits), "CommsUnjudgedTool / judge.Edit.unjudged", - FieldCodec.encode(current), - FieldCodec.encode(native.edits), ) diff --git a/src/agent_comms/commander_parity/rows.py b/src/agent_comms/commander_parity/rows.py index 6d35aa8e49..7ac526abf0 100644 --- a/src/agent_comms/commander_parity/rows.py +++ b/src/agent_comms/commander_parity/rows.py @@ -11,9 +11,9 @@ StoryPhase, ) from . import ParityComparison, ParityRow, UnverifiedParity +from .fleet import BoardComparison, BranchComparison, OrderWorkComparison, UnjudgedComparison from .load import LoadComparison from .measurements import RuleComparison, StorageComparison, measured_load -from .fleet import UnjudgedComparison class CreateProblemParityRow(ParityRow): @@ -55,6 +55,10 @@ class BoardParityRow(ParityRow): native = "`CommsTodoListTool` and the fleet tool, derived" phases = (OneOrderOwnerPhase,) + @classmethod + def verify(cls) -> ParityComparison: + return BoardComparison.read() + class BranchHygieneParityRow(ParityRow): number = 6 @@ -63,6 +67,10 @@ class BranchHygieneParityRow(ParityRow): native = "`CommsWorkBranchesTool`" phases = (OneOrderOwnerPhase,) + @classmethod + def verify(cls) -> ParityComparison: + return BranchComparison.read() + class StrikeLimitParityRow(ParityRow): number = 7 @@ -103,6 +111,10 @@ class OrderWorkParityRow(ParityRow): native = "`comms_order_work`: both transcript families by `tool_call_id`" phases = (ReviewQueuePhase,) + @classmethod + def verify(cls) -> ParityComparison: + return OrderWorkComparison.read() + class UnjudgedParityRow(ParityRow): number = 12 @@ -123,6 +135,13 @@ class PublicStoryParityRow(ParityRow): native = "`comms_order_story`, `comms_fleet_story`; send-back reason posted once" phases = (StoryPhase,) + @classmethod + def verify(cls) -> ParityComparison: + return UnverifiedParity( + "Missing native owners CommsOrderStoryTool and CommsFleetStoryTool; " + "the narrative file alone does not prove native story or exactly-once publication." + ) + class ScheduledWakeParityRow(ParityRow): number = 14 @@ -252,6 +271,13 @@ class MomentumParityRow(ParityRow): ) phases = (CommanderPagePhase,) + @classmethod + def verify(cls) -> ParityComparison: + return UnverifiedParity( + "Missing native CommitMomentum and prediction/outcome owner; " + "there is no current prediction workflow to compare." + ) + class MeasuredLoadParityRow(ParityRow): number = 28 From 2e61017f5ed1d5b9c8718bb834e75ae0a72d0d09 Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Mon, 19 Oct 2026 22:51:20 -0400 Subject: [PATCH 3/8] P300: normalize unassigned board holders at the display boundary --- src/agent_comms/commander_parity/fleet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/agent_comms/commander_parity/fleet.py b/src/agent_comms/commander_parity/fleet.py index c4f01f333a..82d98a6868 100644 --- a/src/agent_comms/commander_parity/fleet.py +++ b/src/agent_comms/commander_parity/fleet.py @@ -121,7 +121,7 @@ def native_rows(cls, listed: TodoList) -> tuple[BoardFacts, ...]: cls( f"{todo.id}: {todo.text}", todo.order.owner.to_wire(), - todo.holder, + todo.holder or "", todo.order.id, hhmm(todo.deadline), listed.progress[todo.id].line if todo.id in listed.progress else "-", From cda78119450d78919a22249e994148844f39664c Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Mon, 19 Oct 2026 22:57:52 -0400 Subject: [PATCH 4/8] P300: use runtime-owned return events and actual watch-session decoding --- src/agent_comms/commander_parity/fleet.py | 106 +++++++++++++--------- 1 file changed, 63 insertions(+), 43 deletions(-) diff --git a/src/agent_comms/commander_parity/fleet.py b/src/agent_comms/commander_parity/fleet.py index 82d98a6868..bdfe408f24 100644 --- a/src/agent_comms/commander_parity/fleet.py +++ b/src/agent_comms/commander_parity/fleet.py @@ -4,19 +4,22 @@ import io import re -import sys from collections.abc import Callable +from configparser import ConfigParser from contextlib import redirect_stdout from dataclasses import dataclass -from types import CodeType, FrameType +from sys import monitoring +from types import CodeType from pydantic import JsonValue from ..commander.judge import Edit from ..commander.order import BoardVerb, Commander, hhmm from ..field_codec import FieldCodec +from ..native_entries import NativeEntry from ..native_tool_call import CodingCall from ..tool_caller import ThreadCaller +from ..tool_declaration import EditCall from ..tools import ( CommsOrderWorkTool, CommsThreadsTool, @@ -26,15 +29,13 @@ TodoList, UnjudgedEdits, ) -from ..transcript_events import ToolStartTranscript -from ..turn_digests import TurnsSince from ..work_branches import WorkBranches from . import ParityComparison, UnverifiedParity @dataclass(frozen=True) class ReadComparison(ParityComparison): - """Compare complete projected facts, not a count that can hide different records.""" + """Compare projected facts, not a count that can hide different records.""" owner: str current: JsonValue @@ -50,35 +51,37 @@ def describe(self) -> str: def observe[T]( code: CodeType, - result_type: type[T], - current: Callable[[], JsonValue], - native: Callable[[T], JsonValue], + current: Callable[[], object], + native: Callable[[T], object], owner: str, ) -> ParityComparison: """Observe the real native return used by the current path without replacing either. - A second read of a changing fleet is not a parity comparison of the first read. - The profile hook only records returns and restores any existing observer. + A second read of a changing fleet is not a comparison of the first read. + Only this function's return event is enabled; other profilers are untouched. """ results: list[T] = [] - previous = sys.getprofile() + tool = monitoring.PROFILER_ID + if monitoring.get_tool(tool): + return UnverifiedParity(f"{owner}: the Python profiler slot is already owned") - def returned(frame: FrameType, event: str, value: object) -> None: - if event == "return" and frame.f_code is code and isinstance(value, result_type): - results.append(value) - if previous: - previous(frame, event, value) + def returned(returned_code: CodeType, offset: int, value: T) -> None: + results.append(value) - sys.setprofile(returned) + monitoring.use_tool_id(tool, __name__) try: + monitoring.register_callback(tool, monitoring.events.PY_RETURN, returned) + monitoring.set_local_events(tool, code, monitoring.events.PY_RETURN) rendered = current() finally: - sys.setprofile(previous) + monitoring.set_local_events(tool, code, 0) + monitoring.register_callback(tool, monitoring.events.PY_RETURN, None) + monitoring.free_tool_id(tool) if len(results) != 1: return UnverifiedParity( f"{owner}: expected one live native return, observed {len(results)}" ) - return ReadComparison(owner, rendered, native(results[0])) + return ReadComparison(owner, FieldCodec.encode(rendered), FieldCodec.encode(native(results[0]))) @dataclass(frozen=True) @@ -109,7 +112,7 @@ def rendered(cls, board: str) -> tuple[BoardFacts, ...]: order, due, progress, - delivered != "no", + ConfigParser.BOOLEAN_STATES[delivered.partition(",")[0]], int(strikes), ) ) @@ -120,9 +123,9 @@ def native_rows(cls, listed: TodoList) -> tuple[BoardFacts, ...]: return tuple( cls( f"{todo.id}: {todo.text}", - todo.order.owner.to_wire(), + todo.order.checked().owner.to_wire(), todo.holder or "", - todo.order.id, + todo.order.checked().id, hhmm(todo.deadline), listed.progress[todo.id].line if todo.id in listed.progress else "-", not todo.pending, @@ -139,20 +142,19 @@ def read(cls) -> ParityComparison: fleet = CommsThreadsTool().apply(context.comms, ThreadCaller(context.commander)) names = {record.thread.name for record in fleet.threads} - def current() -> JsonValue: + def current() -> tuple[BoardFacts, ...]: output = io.StringIO() with redirect_stdout(output): BoardVerb().run(context) - return FieldCodec.encode(BoardFacts.rendered(output.getvalue())) + return BoardFacts.rendered(output.getvalue()) - def native(listed: TodoList) -> JsonValue: + def native(listed: TodoList) -> tuple[BoardFacts, ...]: if any(todo.holder and todo.holder not in names for todo in listed.todos): raise ValueError("A board holder is absent from the live native fleet") - return FieldCodec.encode(BoardFacts.native_rows(listed)) + return BoardFacts.native_rows(listed) return observe( CommsTodoListTool.apply.__code__, - TodoList, current, native, "CommsTodoListTool + CommsThreadsTool / Commander BoardVerb", @@ -163,6 +165,8 @@ class BranchComparison: @classmethod def read(cls) -> ParityComparison: context = Commander.read(Commander.path()) + if not context.repos: + return UnverifiedParity("CommsWorkBranchesTool has no configured repository to invoke") current: list[JsonValue] = [] native: list[JsonValue] = [] for repo in context.repos: @@ -187,24 +191,37 @@ class OrderWorkComparison: @classmethod def read(cls) -> ParityComparison: context = Commander.read(Commander.path()) + held = context.held_orders() + if not held: + return UnverifiedParity("CommsOrderWorkTool has no live held problem to invoke") current: list[JsonValue] = [] native: list[JsonValue] = [] - for todo in context.held_orders(): - since = todo.order.at.recorded_at("An order") - turns = context.comms.transcripts.turns(todo.holder, TurnsSince(since)) - calls: dict[str, str] = {} - for turn in reversed(turns.turns): - for event in turn.events: - if isinstance(event, ToolStartTranscript) and not event.before(since): - call = CodingCall.decode( - event.tool_call_id, event.tool_name, event.raw_input - ) - calls[event.tool_call_id] = call.digest() - current.append(FieldCodec.encode((todo.id, tuple(reversed(calls.items()))))) + for todo in held: reply = CommsOrderWorkTool(problem=todo.id).apply( context.comms, ThreadCaller(context.commander), ) + since = todo.order.checked().at.recorded_at("An order") + calls: dict[str, str] = {} + session = context.comms.registry.require(todo.held().owner).session_file + if not session: + return UnverifiedParity("Current tool_watch has no native session for this order") + with open(session, "rb") as source: + for line in source: + if not line.endswith(b"\n"): + return UnverifiedParity( + "Current tool_watch source ends in an incomplete record" + ) + entry = NativeEntry.read(line) + if entry.timestamp.at.timestamp() >= since: + for message in entry.messages: + if message.assistant: + for pi_call in message.tool_calls: + call = CodingCall.decode( + pi_call.id, pi_call.name, pi_call.arguments + ) + calls[pi_call.id] = call.digest() + current.append(FieldCodec.encode((todo.id, tuple(reversed(calls.items()))))) native.append( FieldCodec.encode( ( @@ -214,7 +231,7 @@ def read(cls) -> ParityComparison: ) ) return ReadComparison( - "CommsOrderWorkTool / tool_watch CodingCall digests from live source turns", + "CommsOrderWorkTool / actual tool_watch NativeEntry and CodingCall digests", current, native, ) @@ -224,10 +241,13 @@ class UnjudgedComparison: @classmethod def read(cls) -> ParityComparison: context = Commander.read(Commander.path()) + + def native(reply: UnjudgedEdits) -> tuple[EditCall, ...]: + return reply.edits + return observe( CommsUnjudgedTool.apply.__code__, - UnjudgedEdits, - lambda: FieldCodec.encode(Edit.unjudged(context.comms, context.commander)), - lambda reply: FieldCodec.encode(reply.edits), + lambda: Edit.unjudged(context.comms, context.commander), + native, "CommsUnjudgedTool / judge.Edit.unjudged", ) From f4855c354dad400dfb63aad607f31a54b6a1bebb Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Mon, 19 Oct 2026 23:02:13 -0400 Subject: [PATCH 5/8] P300: keep original coordination arguments in recorded work digests --- src/agent_comms/native_tools.py | 8 ++++++++ src/agent_comms/tool_declaration.py | 12 +++++++++--- src/agent_comms/transcript_events.py | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/agent_comms/native_tools.py b/src/agent_comms/native_tools.py index d4dc9e90c4..16fc1609f2 100644 --- a/src/agent_comms/native_tools.py +++ b/src/agent_comms/native_tools.py @@ -4,6 +4,7 @@ import json from abc import abstractmethod +from collections.abc import Mapping from dataclasses import dataclass, field from pathlib import Path from typing import ClassVar @@ -71,6 +72,10 @@ def create_call( return CoordinationCall( call_id=call_id, declared_name=cls.declared_name, arguments=arguments) + def recorded_digest(self, arguments: Mapping[str, object], *, call_id: str) -> str: + """Use the same native call owner as tool_watch, with original fields and identity.""" + return self.create_call(call_id, dict(arguments)).digest() + @classmethod def native_extension(cls, package: Path) -> Path: return package / "agent-comms-extensions/global-agent-comms/index.mjs" @@ -86,6 +91,9 @@ class CoordinationCall(NativeRequestTools, NativeExecutableTool, declared_name=N def reads(self) -> str: return json.dumps(self.arguments) + def recorded_digest(self, arguments: Mapping[str, object], *, call_id: str) -> str: + return self.digest() + class ArgumentTool: """One declared execution record supplies validation and native serialization.""" diff --git a/src/agent_comms/tool_declaration.py b/src/agent_comms/tool_declaration.py index ea109bd1f3..ad751c694f 100644 --- a/src/agent_comms/tool_declaration.py +++ b/src/agent_comms/tool_declaration.py @@ -79,6 +79,10 @@ def digest(self) -> str: """What the call does in one line, enough to judge it.""" return f'{self.declared_name} {one_line(self.reads(), 260)}' + def recorded_digest(self, arguments: Mapping[str, object], *, call_id: str) -> str: + """The recorded call uses this declaration's existing presentation.""" + return self.digest() + @classmethod def caption(cls, name: str, tool: ToolDeclaration | None) -> str: """A call reads as its label, then what its record names; with no record, its label.""" @@ -86,9 +90,11 @@ def caption(cls, name: str, tool: ToolDeclaration | None) -> str: return cls.for_name(name).label + (' ' + reads if reads else '') @classmethod - def call_digest(cls, name: str, tool: ToolDeclaration | None, arguments: object) -> str: - """A call in one line: its record's digest; with no record, its name and raw arguments.""" - return tool.digest() if tool else f'{name} {one_line(json.dumps(arguments), 260)}' + def call_digest(cls, name: str, tool: ToolDeclaration | None, + arguments: Mapping[str, object], *, call_id: str) -> str: + """A call keeps its declaration's digest and its original recorded arguments.""" + return (tool.recorded_digest(arguments, call_id=call_id) if tool + else f'{name} {one_line(json.dumps(arguments), 260)}') @classmethod def result_diff(cls, result, ok): diff --git a/src/agent_comms/transcript_events.py b/src/agent_comms/transcript_events.py index 175f29c615..c700d07420 100644 --- a/src/agent_comms/transcript_events.py +++ b/src/agent_comms/transcript_events.py @@ -369,7 +369,7 @@ def record_call(self, calls: dict[str, OrderCall], since: float) -> None: """A call recorded before ``since`` is not work since then.""" if not self.before(since): digest = tool_declaration.ToolDeclaration.call_digest( - self.tool_name, self.tool, self.raw_input) + self.tool_name, self.tool, self.raw_input, call_id=self.tool_call_id) calls[self.tool_call_id] = OrderCall( self.tool_call_id, self.tool_name, digest, RunningCallState) From a06069f605e375d664a9fba3a0d5196f0a6f6f62 Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Mon, 19 Oct 2026 23:03:47 -0400 Subject: [PATCH 6/8] P300: let declared and undeclared tool records own their digests --- src/agent_comms/tool_declaration.py | 10 +++------- src/agent_comms/transcript_events.py | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/agent_comms/tool_declaration.py b/src/agent_comms/tool_declaration.py index ad751c694f..9e369f2652 100644 --- a/src/agent_comms/tool_declaration.py +++ b/src/agent_comms/tool_declaration.py @@ -89,13 +89,6 @@ def caption(cls, name: str, tool: ToolDeclaration | None) -> str: reads = one_line(text := tool.reads(), len(text)) if tool else '' return cls.for_name(name).label + (' ' + reads if reads else '') - @classmethod - def call_digest(cls, name: str, tool: ToolDeclaration | None, - arguments: Mapping[str, object], *, call_id: str) -> str: - """A call keeps its declaration's digest and its original recorded arguments.""" - return (tool.recorded_digest(arguments, call_id=call_id) if tool - else f'{name} {one_line(json.dumps(arguments), 260)}') - @classmethod def result_diff(cls, result, ok): """Opaque metadata cannot invent edit evidence.""" @@ -111,3 +104,6 @@ class UndeclaredTool(ToolDeclaration, declared_name=None): @property def label(self) -> str: return self.name + + def recorded_digest(self, arguments: Mapping[str, object], *, call_id: str) -> str: + return f'{self.name} {one_line(json.dumps(arguments), 260)}' diff --git a/src/agent_comms/transcript_events.py b/src/agent_comms/transcript_events.py index c700d07420..44d468991c 100644 --- a/src/agent_comms/transcript_events.py +++ b/src/agent_comms/transcript_events.py @@ -368,8 +368,8 @@ def title(self) -> str: def record_call(self, calls: dict[str, OrderCall], since: float) -> None: """A call recorded before ``since`` is not work since then.""" if not self.before(since): - digest = tool_declaration.ToolDeclaration.call_digest( - self.tool_name, self.tool, self.raw_input, call_id=self.tool_call_id) + declaration = self.tool or tool_declaration.UndeclaredTool(self.tool_name) + digest = declaration.recorded_digest(self.raw_input, call_id=self.tool_call_id) calls[self.tool_call_id] = OrderCall( self.tool_call_id, self.tool_name, digest, RunningCallState) From 6b261d06249bc9d051c4bf8bc4e9d882aae734e4 Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Mon, 19 Oct 2026 23:04:54 -0400 Subject: [PATCH 7/8] P300: cover original coordination and undeclared call evidence --- tests/test_commander_tool_watch.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test_commander_tool_watch.py b/tests/test_commander_tool_watch.py index 55371d8d1d..689f0104c4 100644 --- a/tests/test_commander_tool_watch.py +++ b/tests/test_commander_tool_watch.py @@ -10,6 +10,8 @@ from agent_comms.native_tool_call import CodingCall from agent_comms.native_tool_call import SelectedToolDenied from agent_comms.todos import StorageStrikeTodo +from agent_comms.tool_declaration import ToolDeclaration +from agent_comms.transcript_events import ToolStartTranscript from test_commander_problem_orders import create @@ -52,6 +54,30 @@ def test_coordination_call_digests_its_arguments(): assert call.digest() == 'comms_threads {}' +def test_recorded_coordination_digest_keeps_original_request_arguments(): + arguments = {'from': 'worker', 'to': 'lead', 'body': 'the original body'} + event = ToolStartTranscript( + position=1, timestamp=1.0, tool_call_id='original-call', tool_name='comms_send', + raw_input=arguments, + tool=ToolDeclaration.record('comms_send', arguments, call_id='original-call'), + ) + calls = {} + event.record_call(calls, 0.0) + assert calls['original-call'].digest == CodingCall.decode( + 'original-call', 'comms_send', arguments).digest() + assert 'the original body' in calls['original-call'].digest + + +def test_undeclared_record_keeps_original_name_and_arguments(): + event = ToolStartTranscript( + position=1, timestamp=1.0, tool_call_id='external-call', tool_name='external_unknown', + raw_input={'original': 'argument'}, + ) + calls = {} + event.record_call(calls, 0.0) + assert calls['external-call'].digest == 'external_unknown {"original": "argument"}' + + def test_a_malformed_line_raises_instead_of_skipping_history(tool_watch, commander, commander_script): comms, _ = commander whole = json.dumps({"type": "message", "id": "m1", "timestamp": "2026-10-18T22:00:00.000Z", From 2abf5c4ff97be15df71b57df747b77a221115911 Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Mon, 19 Oct 2026 23:06:51 -0400 Subject: [PATCH 8/8] P300: observe branch records once instead of racing two forge snapshots --- src/agent_comms/commander_parity/fleet.py | 52 +++++++++++++---------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/src/agent_comms/commander_parity/fleet.py b/src/agent_comms/commander_parity/fleet.py index bdfe408f24..4fd21f6bd6 100644 --- a/src/agent_comms/commander_parity/fleet.py +++ b/src/agent_comms/commander_parity/fleet.py @@ -29,7 +29,7 @@ TodoList, UnjudgedEdits, ) -from ..work_branches import WorkBranches +from ..work_branches import WorkBranch, WorkBranches from . import ParityComparison, UnverifiedParity @@ -52,8 +52,10 @@ def describe(self) -> str: def observe[T]( code: CodeType, current: Callable[[], object], - native: Callable[[T], object], + native: Callable[[tuple[T, ...]], object], owner: str, + *, + expected: int = 1, ) -> ParityComparison: """Observe the real native return used by the current path without replacing either. @@ -77,11 +79,13 @@ def returned(returned_code: CodeType, offset: int, value: T) -> None: monitoring.set_local_events(tool, code, 0) monitoring.register_callback(tool, monitoring.events.PY_RETURN, None) monitoring.free_tool_id(tool) - if len(results) != 1: + if not results or len(results) != expected: return UnverifiedParity( - f"{owner}: expected one live native return, observed {len(results)}" + f"{owner}: expected {expected} live owner returns, observed {len(results)}" ) - return ReadComparison(owner, FieldCodec.encode(rendered), FieldCodec.encode(native(results[0]))) + return ReadComparison( + owner, FieldCodec.encode(rendered), FieldCodec.encode(native(tuple(results))) + ) @dataclass(frozen=True) @@ -148,7 +152,8 @@ def current() -> tuple[BoardFacts, ...]: BoardVerb().run(context) return BoardFacts.rendered(output.getvalue()) - def native(listed: TodoList) -> tuple[BoardFacts, ...]: + def native(observed: tuple[TodoList, ...]) -> tuple[BoardFacts, ...]: + listed = observed[0] if any(todo.holder and todo.holder not in names for todo in listed.todos): raise ValueError("A board holder is absent from the live native fleet") return BoardFacts.native_rows(listed) @@ -167,23 +172,26 @@ def read(cls) -> ParityComparison: context = Commander.read(Commander.path()) if not context.repos: return UnverifiedParity("CommsWorkBranchesTool has no configured repository to invoke") - current: list[JsonValue] = [] - native: list[JsonValue] = [] - for repo in context.repos: - current.append( - FieldCodec.encode( - WorkBranches(repo.checkout).read(context.comms.registry.snapshot()) - ) + + def current() -> tuple[tuple[WorkBranch, ...], ...]: + return tuple( + CommsWorkBranchesTool(checkout=str(repo.checkout), unlinked_only=False) + .apply(context.comms, ThreadCaller(context.commander)) + .branches + for repo in context.repos ) - reply = CommsWorkBranchesTool( - checkout=str(repo.checkout), - unlinked_only=False, - ).apply(context.comms, ThreadCaller(context.commander)) - native.append(FieldCodec.encode(reply.branches)) - return ReadComparison( - "CommsWorkBranchesTool / current Git and forge branch reader", + + def native( + readings: tuple[tuple[WorkBranch, ...], ...], + ) -> tuple[tuple[WorkBranch, ...], ...]: + return readings + + return observe( + WorkBranches.read.__code__, current, native, + "CommsWorkBranchesTool / actual consumed Git and forge branch records", + expected=len(context.repos), ) @@ -242,8 +250,8 @@ class UnjudgedComparison: def read(cls) -> ParityComparison: context = Commander.read(Commander.path()) - def native(reply: UnjudgedEdits) -> tuple[EditCall, ...]: - return reply.edits + def native(observed: tuple[UnjudgedEdits, ...]) -> tuple[EditCall, ...]: + return observed[0].edits return observe( CommsUnjudgedTool.apply.__code__,