Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions src/agent_comms/thread_identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from functools import cached_property
from typing import TYPE_CHECKING, Callable, ClassVar, Self, TypeVar, Annotated

from metaclass_registry import AutoRegisterMeta, RegistryConfig

from agent_comms.participant_identity import ParticipantIdentity
from .agent_backend import AgentBackend, NewThreadBackend, RuntimeLocation
Expand Down Expand Up @@ -211,19 +212,16 @@ def commanding_identity(self) -> ThreadIncarnation:
return self.authority


class BirthlessIncarnation(ThreadIncarnation):
class BirthlessIncarnation(ThreadIncarnation, metaclass=AutoRegisterMeta):
"""A member whose wire birth is a declared mark, not recorded evidence; never a lookup.

Each member declares its mark in ``WIRE_BIRTH``; the record decodes a mark to its member."""

WIRE_BIRTH: ClassVar[float]
members: ClassVar[dict[float, type[BirthlessIncarnation]]] = {}

def __init_subclass__(cls, **kwargs: object) -> None:
super().__init_subclass__(**kwargs)
if cls.WIRE_BIRTH in BirthlessIncarnation.members:
raise TypeError(f"Wire birth {cls.WIRE_BIRTH} is already declared")
BirthlessIncarnation.members[cls.WIRE_BIRTH] = cls
__registry_config__: ClassVar[RegistryConfig] = RegistryConfig(
registry_dict={}, key_attribute="WIRE_BIRTH", registry_name="birthless incarnation",
)
__registry__: ClassVar[dict[float, type[BirthlessIncarnation]]]

@property
def wire_birth(self) -> float:
Expand Down Expand Up @@ -357,8 +355,8 @@ class ThreadIncarnationRecord:
created_at: float

def incarnation(self) -> ThreadIncarnation:
if self.created_at in BirthlessIncarnation.members:
return BirthlessIncarnation.members[self.created_at].recorded_as(self.name)
if member := BirthlessIncarnation.__registry__.get(self.created_at):
return member.recorded_as(self.name)
return RecordedThreadIncarnation(self.name, self.created_at)

@classmethod
Expand Down
88 changes: 88 additions & 0 deletions tests/test_birthless_declarations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""Only concrete birth-marker declarations decode; external identity spelling stays fixed."""

import runpy
from abc import abstractmethod
from types import SimpleNamespace

import pytest
from metaclass_registry import DuplicateRegistryKeyError

from agent_comms import thread_identity
from agent_comms.thread_identity import (
CoreWatcherIncarnation,
DeletedThreadIncarnation,
RecordedThreadIncarnation,
ThreadIncarnation,
UnrecordedThreadIncarnation,
)


@pytest.mark.parametrize('birth,member,decoded_name', [
(-2.0, CoreWatcherIncarnation, 'core_watcher'),
(-1.0, DeletedThreadIncarnation, 'original'),
(0.0, UnrecordedThreadIncarnation, 'original'),
(1.0, RecordedThreadIncarnation, 'original'),
])
def test_external_birth_markers_survive_wire_and_cli_boundaries(birth, member, decoded_name):
wire = {'name': 'original', 'created_at': birth}
identity = ThreadIncarnation.from_wire(wire)
assert type(identity) is member
assert identity.to_wire() == {**wire, 'name': decoded_name}
assert ThreadIncarnation.from_arguments(identity.cli_arguments) == identity
renamed = identity.renamed('renamed')
assert type(renamed) is member
assert renamed.to_wire() == {**wire, 'name': 'renamed'}


@pytest.mark.parametrize('birth', [-3.0, float('inf'), float('nan')])
def test_unknown_nonrecorded_birth_cannot_create_a_live_identity(birth):
with pytest.raises(ValueError):
ThreadIncarnation.from_wire({'name': 'unknown', 'created_at': birth})


@pytest.fixture
def identity_family():
# Execute the actual class declarations without changing the canonical registry.
return SimpleNamespace(**runpy.run_path(thread_identity.__file__, run_name=thread_identity.__name__))


def test_new_concrete_marker_drives_the_existing_decoder(identity_family):
class HistoricalMarker(identity_family.BirthlessIncarnation):
WIRE_BIRTH = -91.0

@property
def birth_description(self) -> str:
return 'historical marker'

wire = {'name': 'historical', 'created_at': HistoricalMarker.WIRE_BIRTH}
identity = identity_family.ThreadIncarnation.from_wire(wire)
assert type(identity) is HistoricalMarker
assert identity.to_wire() == wire
assert identity_family.ThreadIncarnation.from_arguments(identity.cli_arguments) == identity
with pytest.raises(ValueError, match='positive recorded birth'):
identity.require_recorded()


def test_abstract_specialization_does_not_contest_an_existing_marker(identity_family):
class UnfinishedDeleted(identity_family.DeletedThreadIncarnation):
@abstractmethod
def unfinished(self): ...

with pytest.raises(TypeError, match='abstract'):
UnfinishedDeleted('name')
decoded = identity_family.ThreadIncarnation.from_wire({'name': 'name', 'created_at': -1.0})
assert type(decoded) is identity_family.DeletedThreadIncarnation


def test_new_abstract_marker_is_not_a_decoder(identity_family):
class UnfinishedMarker(identity_family.BirthlessIncarnation):
WIRE_BIRTH = -92.0

with pytest.raises(ValueError, match='positive recorded birth'):
identity_family.ThreadIncarnation.from_wire({'name': 'name', 'created_at': UnfinishedMarker.WIRE_BIRTH})


def test_two_concrete_owners_cannot_claim_one_marker(identity_family):
with pytest.raises(DuplicateRegistryKeyError):
class CompetingDeleted(identity_family.DeletedThreadIncarnation):
pass
Loading