Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
fa931e9
Stream wire JSONL from declared stored fields and SQL suffix selection
trissim Oct 29, 2026
19d359f
Publish export-owned progress and cooperative SQLite cancellation
trissim Oct 29, 2026
e923d6e
Merge remote-tracking branch 'origin/main' into fix/wire-export
trissim Oct 29, 2026
3b67e7e
Keep one scope and cutoff owner and preserve stored floating point va…
trissim Oct 29, 2026
e0ac840
Let the cancellation capability own SQLite interruption
trissim Oct 29, 2026
a9aea28
Keep export selection and wire projection with their owners
trissim Oct 29, 2026
0533367
Keep foreign wire and SQLite values at typed decoding boundaries
trissim Oct 29, 2026
8c5e64e
Merge remote-tracking branch 'origin/main' into fix/wire-export
trissim Oct 29, 2026
eeee8ec
Project captured display identities through registry rows
trissim Oct 29, 2026
d1fdcfc
Acquire relationship projections through captured rows and input capa…
trissim Oct 29, 2026
b8c1418
Keep birth projection and retained rows on their wire owners
trissim Oct 29, 2026
b6ee567
Retain group source inputs before acquiring complete relationship views
trissim Oct 29, 2026
6a8a18d
Require the already supplied person at relationship entry construction
trissim Oct 29, 2026
d9b4c5e
Acquire selected lookup threads through the captured row owner
trissim Oct 29, 2026
ae91096
Repair nominal acquisition interfaces and real fixture preconditions
trissim Oct 29, 2026
9b105df
Serialize retained thread rows through their existing raw owner
trissim Oct 29, 2026
0524dd6
Let ThreadIncarnation strictly resolve its original current peer
trissim Oct 29, 2026
544dc19
Defer captured goal fields and carry lookup metadata across revisions
trissim Oct 30, 2026
5933cd9
Separate explicit new-thread tags from parent-derived fork membership
trissim Oct 29, 2026
984d8f4
Collect required creation inputs through native command bindings
trissim Oct 29, 2026
f9d18ba
Keep native context edits distinct from complete command authorization
trissim Oct 29, 2026
ee7b547
Complete creation bindings through native field and presence owners
trissim Oct 29, 2026
89a4397
Leave child names unsupplied until creation form completion
trissim Oct 29, 2026
8c08089
Remove invalid trailing comma from pending context edits
trissim Oct 29, 2026
acf0a67
Keep native union members and derive their editor transactions
trissim Oct 29, 2026
7d3d6ac
Make unchosen a nominal member of editor selection
trissim Oct 29, 2026
502402a
Ask the value decoder directly for editor projections
trissim Oct 29, 2026
85a31ac
Remove absent editor defaults and reuse scalar admission
trissim Oct 30, 2026
f4f0750
Separate explicit new-thread tags from parent-derived fork membership
trissim Oct 29, 2026
51928ec
Collect required creation inputs through native command bindings
trissim Oct 29, 2026
5c66f0a
Keep native context edits distinct from complete command authorization
trissim Oct 29, 2026
b2f766f
Complete creation bindings through native field and presence owners
trissim Oct 29, 2026
d44eff3
Leave child names unsupplied until creation form completion
trissim Oct 29, 2026
a44c624
Remove invalid trailing comma from pending context edits
trissim Oct 29, 2026
6e53464
Keep native union members and derive their editor transactions
trissim Oct 29, 2026
d50cc18
Make unchosen a nominal member of editor selection
trissim Oct 29, 2026
7b139e1
Ask the value decoder directly for editor projections
trissim Oct 29, 2026
3b94c9b
Remove absent editor defaults and reuse scalar admission
trissim Oct 30, 2026
e66d9b7
Join channel activity to captured tag declarations
trissim Oct 30, 2026
e46b1e1
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
d66befe
Delete the stale ThreadRows.lookup_names left by the #3632 merge
trissim Oct 30, 2026
b5d760a
Keep channel membership and capability refusal on their declarations
trissim Oct 30, 2026
4eb1f00
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
3c295bc
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
c96de47
Merge remote-tracking branch 'origin/work/commander-layout--P927' int…
trissim Oct 30, 2026
0b8893d
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
e1ee783
Preserve scoped copy records and mutate actual producer bodies
trissim Oct 30, 2026
dde9bd0
Integrate current main while preserving pending fork input and declar…
trissim Oct 30, 2026
745e7e9
Merge remote-tracking branch 'origin/main' into work/commander-layout…
trissim Oct 30, 2026
3d5cbac
Merge remote-tracking branch 'origin/main' into work/commander-layout…
trissim Oct 30, 2026
5adaa97
Let native member selection own omitted editor arguments
trissim Oct 30, 2026
1e6e09c
Merge remote-tracking branch 'origin/main' into work/commander-layout…
trissim Oct 30, 2026
fa34aa0
Integrate current main with captured thread membership
trissim Oct 30, 2026
f7ef4ac
Merge remote-tracking branch 'origin/main' into work/commander-layout…
trissim Oct 30, 2026
1f3a4c3
Hold one display selection and bus cut across history pages
trissim Oct 30, 2026
556868b
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
9ef2162
Keep captured reader retirement inside its page-use owner
trissim Oct 30, 2026
b09c25b
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
0575f6a
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
44bbc97
Give each captured thread row its own lazy decoded value
trissim Oct 30, 2026
043ef56
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
b41818b
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
069aadc
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
6302e33
Own written thread rows through their decoded override
trissim Oct 30, 2026
5b4af2c
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
4c600de
Use declared JSON and incarnation values at row and release boundaries
trissim Oct 30, 2026
73bf866
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
c1bd982
Give capability joins one acquisition and refusal owner
trissim Oct 30, 2026
d8f0595
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
4cfd1e2
Keep history pages on their original archive catalogue
trissim Oct 30, 2026
f8ee6dc
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
ff5e9d0
Keep display construction and captured reader policy with their owners
trissim Oct 30, 2026
33e7362
Capture checkout refs and commit history once per heartbeat read
trissim Oct 30, 2026
f800f7e
Memoize graph queries and release pass readers from retained caches
trissim Oct 30, 2026
bbc06e7
Share heartbeat turn digests and edit counts across rules and cards
trissim Oct 30, 2026
814a1c8
Retain plan parses by blob across main updates and prune deleted modules
trissim Oct 30, 2026
f5570ee
Share one repository graph across worktree heads and batch remote rea…
trissim Oct 30, 2026
316230c
Decode branch upstreams at the repository boundary and delete sentine…
trissim Oct 30, 2026
af19ffc
Deal /prime on demand through the rule gate, in four variants
trissim Oct 30, 2026
9154aa9
Merge remote-tracking branch 'origin/main' into hotfix/prime-redeal
trissim Oct 30, 2026
035d26f
Merge remote-tracking branch 'origin/main' into hotfix/prime-redeal
trissim Oct 30, 2026
12012e1
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
8d45e9e
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
1f74fa0
Merge remote-tracking branch 'origin/main' into work/commander-layout…
trissim Oct 30, 2026
38261de
Decode /prime's variant once into its family and use the client's own…
trissim Oct 30, 2026
eea6176
Merge remote-tracking branch 'origin/main' into hotfix/prime-redeal
trissim Oct 30, 2026
f99aa2a
Refuse /prime out loud in a session no bus thread holds
trissim Oct 30, 2026
bef276b
Merge remote-tracking branch 'origin/main' into hotfix/prime-redeal
trissim Oct 30, 2026
3c755d6
Hand UnboundPrime the DeckStart that owns the session id
trissim Oct 30, 2026
b0e085f
Merge remote-tracking branch 'origin/main' into hotfix/prime-redeal
trissim Oct 30, 2026
a79f53d
Merge main into wire export; preserve shared stored record reader
trissim Oct 30, 2026
a99716c
Point /prime's read instructions at the gate's batch window
trissim Oct 30, 2026
a6eb302
Merge remote-tracking branch 'origin/main' into work/frame-baseline--…
trissim Oct 30, 2026
ea3f0c5
Merge current main into wire export
trissim Oct 30, 2026
fa6f016
Use FieldCodec for exact stored float JSON on the held read
trissim Oct 30, 2026
5892ab2
Merge current main after export codec repair
trissim Oct 30, 2026
ce33201
Merge remote-tracking branch 'origin/main' into work/commander-layout…
trissim Oct 30, 2026
c3daf80
Merge remote-tracking branch 'origin/main' into work/producer-digest-…
trissim Oct 30, 2026
6338a86
Deal /prime with its own trigger on both paths, after main's deal rea…
trissim Oct 30, 2026
c82b40a
Name the install's own failure when restarting its owners fails too
trissim Oct 30, 2026
2072c0d
Derive a pending binding's command from its context's declared command
trissim Oct 30, 2026
36eeb53
Merge remote-tracking branch 'origin/main' into HEAD
trissim Oct 30, 2026
461cbb7
Export: each format reads the stored history it renders; delete the w…
Oct 30, 2026
173a739
Merge remote-tracking branch 'origin/main' into cc/export-claims-3616
trissim Oct 30, 2026
2bca15d
Merge remote-tracking branch 'origin/main' into HEAD
Oct 30, 2026
469ae4d
Find best merge bases from the branch-only commits, not the whole sha…
Oct 30, 2026
fe00249
Pin the held bus's stores instead of truncating their WAL before the …
trissim Oct 30, 2026
c7c0be2
Merge remote-tracking branch 'origin/main' into hotfix/installer-wal-…
trissim Oct 30, 2026
7a344c6
Test: stored Text and JSONL exports render a claim-notice row
Oct 30, 2026
044b0d3
Exclude remote references by name, not a rev-list flag the graph cann…
Oct 30, 2026
eab4c4f
Give owners back through a context instead of probing the failure for…
trissim Oct 30, 2026
abb0d90
Merge remote-tracking branch 'origin/main' into hotfix/installer-wal-…
trissim Oct 30, 2026
f14659d
Let each /prime variant build its own deal trigger instead of handing…
trissim Oct 30, 2026
3c84bb9
Hand upstreams the history and published heads, not the reader that i…
trissim Oct 30, 2026
c194d56
Assert the unsupplied tags field by its type, not a missing default
trissim Oct 30, 2026
1f68dcd
Decode git's worktree record by its declared line order, not a name-k…
trissim Oct 30, 2026
efb40c5
Let CliCommand's declared default answer type stand in channel_targets
trissim Oct 30, 2026
b6ef779
Merge #3697 at 1f68dcd88 into batch/integ-20261030
trissim Oct 30, 2026
93d5383
Merge #3737 at abb0d90aa into batch/integ-20261030
trissim Oct 30, 2026
71dabc6
Merge #3616 at 7a344c660 into batch/integ-20261030
trissim Oct 30, 2026
11173a9
Merge #3595 at efb40c5f7 into batch/integ-20261030
trissim Oct 30, 2026
763a7c3
Merge #3723 at f14659dfd into batch/integ-20261030
trissim Oct 30, 2026
e71c805
Merge #3607 at a6eb30272 into batch/integ-20261030
trissim Oct 30, 2026
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
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ agent-comms-commander = "agent_comms.commander.cli:main"
agent-comms-integrate = "agent_comms.integration:main"
agent-comms-commander-skill = "agent_comms_hooks.skill:main"
agent-comms-commander-reread = "agent_comms_hooks.reread:main"
agent-comms-prime = "agent_comms_hooks.prime:main"
agent-comms-commander-deferral-guard = "agent_comms_hooks.deferral:main"
agent-comms-commander-bounded-waits = "agent_comms_hooks.bounded_waits:main"
agent-comms-read-gate = "agent_comms_hooks.read_gate:main"
Expand Down
2 changes: 1 addition & 1 deletion src/agent_comms/attempt_recovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ def require_session_exit(self, session_files: tuple[Path, ...]) -> None:
if not self.issued_for(self._store):
raise RecoveryBlocked("native exit observation requires acquired owner loss")
session_dir = (
self._store.session.path.parent / "native-sessions" / self.release.incarnation().lookup
self._store.session.path.parent / "native-sessions" / self.release.incarnation.lookup
)
proc = Path("/proc")
if not proc.is_dir():
Expand Down
87 changes: 69 additions & 18 deletions src/agent_comms/bus.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Append-only database history and capability-declared record queries."""

from __future__ import annotations
Expand Down Expand Up @@ -38,6 +38,7 @@
Claimed,
ClaimMessage,
Message,
StoredWireHistory,
MessageKind,
PublicRecord,
)
Expand All @@ -49,6 +50,7 @@
ResourceClaim,
)
from agent_comms.errors import CommittedMessageError, RelationViolationError, UnclaimedError
from agent_comms.coordination_errors import CoordinationReadUnavailable
from agent_comms.field_codec import ClaimId, FieldCodec, MessageId, ThreadLookup
from agent_comms.locked_store import BusFile, FileStore, SQLiteReader, StoreCommittedError
from agent_comms.message_reference import MessageReference
Expand Down Expand Up @@ -130,13 +132,18 @@
def advanced(self, source: BusReader, selection: DisplayUnreadSelection) -> DisplayUnread:
queries = selection.queries()
through = source.revision()
if through == self.through and tuple(self.counted) == queries:
return self
earlier = {query.counting: query for query in self.counted}
kept = {query: query for query in queries if query in self.counted}
moved = {query: (earlier[query.counting], parts) for query in queries
if query not in kept and query.counting in earlier
and (parts := query.moved(earlier[query.counting]))}
reusable = {query: earlier[query.counting] for query in queries
if query.counting in earlier
and query.same_membership(earlier[query.counting])}
kept = {query: previous for query, previous in reusable.items()
if query == previous}
if through == self.through and len(kept) == len(queries):
if tuple(self.counted) == queries:
return self
return DisplayUnread(through, {query: self.counted[kept[query]] for query in queries})
moved = {query: (previous, parts) for query, previous in reusable.items()
if query not in kept and (parts := query.moved(previous))}
progressed = (*kept, *(previous for previous, _ in moved.values()))
appended = source.count_unread(
progressed if through != self.through else (), through=through, after=self.through)
Expand Down Expand Up @@ -174,6 +181,10 @@
with self.observing() as db:
yield BusSnapshot.from_connection(db)

@abstractmethod
def captured_reading(self) -> AbstractContextManager[BusSnapshot]:
"""Retain a cut independently of ordinary reads on the acquiring thread."""

def revision(self) -> int:
with self.observing() as db:
return BusRow.last_seq(db)
Expand All @@ -186,10 +197,10 @@
with self.observing() as db:
return BusActivityIndex.aggregate(db, predicate, parameters)

def participant_activity(self, names: frozenset[str]) -> ChannelActivity:
marks = ','.join('?' for _ in names)
def participant_activity(self, predicate: str,
parameters: tuple[object, ...]) -> ChannelActivity:
with self.observing() as db:
return BusDisplayIndex.aggregate(db, f'participant IN ({marks})', tuple(names))
return BusDisplayIndex.aggregate(db, predicate, parameters)

def claim_projection(self) -> ClaimProjection:
with self.observing() as db:
Expand Down Expand Up @@ -253,9 +264,36 @@

def page(self, before: int, limit: int) -> tuple[BusRecord, ...]:
with self.observing() as db:
return BusCapability.at_sequences(db, tuple(row.seq for row in BusRow.select(
db, where="{seq} < ?", parameters=(before,),
order_by=("seq",), descending=True, limit=limit)))
return BusCapability.at_sequences(
db, tuple(row.seq for row in self._page_rows(db, before, limit)),
)

def input_page(self, before: int, limit: int) -> tuple[MessageInput, ...]:
"""The same global sequence window, without attachment/report/answer acquisition."""
with self.observing() as db:
return tuple(
MessageInput.read_from(db, row.seq)
for row in self._page_rows(db, before, limit)
)

@staticmethod
def _page_rows(db: sqlite3.Connection, before: int, limit: int) -> list[BusRow]:
return BusRow.select(
db, where="{seq} < ?", parameters=(before,),
order_by=("seq",), descending=True, limit=limit,
)

@contextmanager
def stored_message_history(
self, predicate: str = "1", parameters: tuple[object, ...] = (),
*, through: int,
) -> Iterator[StoredWireHistory]:
"""Stream declared public wire fields from one read snapshot, without Messages."""
with self.observing() as db:
query = Message.stored_wire_query(db, MessageIdentitySource)
query = (f'SELECT seq, timestamp, wire FROM ({query}) '
f'WHERE seq <= ? AND ({predicate})')
yield StoredWireHistory(db, query, (through, *parameters))

def message_history(self) -> Iterator[Message]:
"""Public bulk export, paged within one committed SQLite snapshot."""
Expand Down Expand Up @@ -288,22 +326,22 @@
upper: int | None = None, descending: bool = False, limit: int = 100,
kinds: tuple[type[MessageKind], ...] = (),
) -> tuple[Message, ...]:
"""A captured display scope narrows the addressed table before decoding."""
"""A captured display scope reads public message capabilities, not delivery payloads."""
with self.observing() as db:
upper = BusRow.last_seq(db) + 1 if upper is None else upper
order = "DESC" if descending else "ASC"
members = ""
if kinds:
members = MessageInput.render(' AND {type} IN (') + ','.join('?' for _ in kinds) + ')'
rows = db.execute(
return tuple(Message.selected(
db,
f'SELECT seq FROM "{Addressed.table.declared_name}" '
f'JOIN "{MessageInput.table.declared_name}" USING(seq) '
f'WHERE ({predicate}) AND seq > ? AND seq < ?{members} '
f'ORDER BY seq {order} LIMIT ?',
(*parameters, lower, upper, *(kind.declared_name for kind in kinds), limit),
)
headers = (BusRow.require(db, seq=FieldCodec.decode(int, row[0])) for row in rows)
return BusCapability.at_sequences(db, tuple(header.seq for header in headers))
descending=descending,
))

def latest_conversations(
self, predicate: str, parameters: tuple[object, ...], through: int,
Expand Down Expand Up @@ -469,7 +507,8 @@
counts[query] = FieldCodec.decode(int, db.execute(
f'WITH {ReadCursor.sql("?")}, requests AS ('
f'SELECT \'viewer\' AS actor,* FROM "{Addressed.table.declared_name}" '
f'JOIN "{MessageInput.table.declared_name}" USING(seq) WHERE seq > ? AND seq <= ? '
f'JOIN "{MessageInput.table.declared_name}" USING(seq) '
f'WHERE seq > ? AND seq <= ? '
f'AND ({query.predicate}) AND sender NOT IN (SELECT value FROM json_each(?))), '
f'{ReadCursor.joined_sql} SELECT count(*) FROM cursors WHERE {ReadCursor.unread_sql}',
(CursorRow.binding(query.cursors), max(after, query.lower_bound), through,
Expand Down Expand Up @@ -498,6 +537,14 @@
with self.reader_snapshot() as db:
yield db

@contextmanager
def captured_reading(self) -> Iterator[BusSnapshot]:
# Unlike a nested ordinary read, a presentation outlives this worker's
# next request. Its transaction must never enter the thread-local pool.
with CoordinationReadUnavailable.checking():
with closing(self.read_snapshot(self.path, check_same_thread=False)) as db:
yield BusSnapshot.from_connection(db)


class Bus(FileStore, StoredBusReader, ReconciledFile, WalStore, CarriedWriter, BusFile, Watched):
"""One SQLite transaction owns the sequence and all of a record's fields."""
Expand Down Expand Up @@ -655,3 +702,7 @@
@contextmanager
def reading(self) -> Iterator[BusSnapshot]:
yield self

@contextmanager
def captured_reading(self) -> Iterator[BusSnapshot]:
yield self
11 changes: 11 additions & 0 deletions src/agent_comms/bus_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,17 @@ def require_matched(cls, matches: Iterable[ReferenceMatch], refusal: Exception)
if not all(match.matched for match in matches):
raise refusal

@classmethod
def reference_predicate(
cls, references: tuple[MessageReference, ...],
) -> tuple[str, tuple[object, ...]]:
plans = FieldCodec.field_plans(MessageReference)
columns = cls._column_list(tuple(plan.name for plan in plans))
selected = ', '.join('json_extract(value, ?)' for plan in plans)
return (f'({columns}) IN (SELECT {selected} FROM json_each(?))',
(*(f'$.{plan.key}' for plan in plans),
FieldCodec.compact([FieldCodec.encode(reference) for reference in references])))

@classmethod
def require_sequences(cls, db: sqlite3.Connection, sequences: tuple[int, ...]) -> None:
matches = ReferenceMatch.read(db.execute(
Expand Down
25 changes: 10 additions & 15 deletions src/agent_comms/channel_targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
from .repo import Checkout
from .response_policy import DirectPolicy, MentionedPolicy
from .thread_identity import ThreadIncarnation
from .thread_name import ThreadName
from .typed_table import sql_literal
from .wake_policy import BoundedTriageWake, FullWake, MessageAudience

if TYPE_CHECKING:
from .audience_manifest import AudiencedMessage, FrozenRecipient
from .catalog_document import CatalogAccess, CatalogDocument
from .channels import Channel
from .cli_command import CliCommand
from .cli_result import CliResult
from .cli_command import CliCommand, CommandBinding
from .comms import Comms
from .goal_management import Goals
from .historical_views import ChannelHistory, DMHistory, HistoryView
Expand Down Expand Up @@ -166,7 +166,7 @@ def resolve(self, snapshot: RegistrySnapshot, require_channel: Callable[[str], C
def bindings[C: CliCommand](
self, declaration: type[C], comms: Comms, channel: SurroundingChannel, resolved,
*, project: Checkout, snapshot: RegistrySnapshot, catalog: CatalogAccess,
) -> tuple[C, ...]: ...
) -> tuple[CommandBinding, ...]: ...

def history_view(self, viewer: DisplayViewer, require_channel: Callable[[str], Channel],
channel: type[ChannelHistory], direct: type[DMHistory]) -> HistoryView:
Expand All @@ -177,7 +177,7 @@ def history_result(self, require_channel: Callable[[str], Channel], messages: tu
raise ValueError("History requires a #channel or DM peer.")

def contexts(
self, declaration: type[CliCommand[CliResult]], channel: ChannelSelection,
self, declaration: type[CliCommand], channel: ChannelSelection,
) -> tuple[SurroundingChannel, ...]:
return (NoChannel(),)

Expand Down Expand Up @@ -393,7 +393,7 @@ def history_result(self, require_channel: Callable[[str], Channel], messages: tu
return self.history_result_type.for_target(self.name, messages, has_older)

def contexts(
self, declaration: type[CliCommand[CliResult]], channel: ChannelSelection,
self, declaration: type[CliCommand], channel: ChannelSelection,
) -> tuple[SurroundingChannel, ...]:
return declaration.selection_channels(channel, self.name)

Expand All @@ -413,15 +413,13 @@ def resolve(self, snapshot: RegistrySnapshot, require_channel: Callable[[str], C
def bindings[C: CliCommand](
self, declaration: type[C], comms: Comms, channel: SurroundingChannel, resolved: ResolvedThread,
*, project: Checkout, snapshot: RegistrySnapshot, catalog: CatalogAccess,
) -> tuple[C, ...]:
) -> tuple[CommandBinding, ...]:
return declaration.thread_bindings(comms, resolved.thread, resolved.status, channel, catalog=catalog)

def validate(self, message: Message) -> None:
if message.sender == self.name and message.type.conversation_message:
raise RelationViolationError(f"Thread {message.sender!r} cannot message itself.")
allowed = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_")
if not set(self.name) <= allowed:
raise ValueError(f"Message target {self.name!r} is not a thread name or #channel.")
ThreadName.require(self.name)

def wake_policy(self, recipient: FrozenRecipient, mentions: frozenset[str]) -> FullWake:
return FullWake()
Expand Down Expand Up @@ -483,10 +481,7 @@ def __post_init__(self) -> None:
object.__setattr__(self, "name", self.incarnation.name)

def selected_name(self, snapshot: RegistryProvenance) -> str:
if not self.incarnation.current(snapshot):
raise UnregisteredThreadError(
f"Original DM peer {self.name!r} is no longer registered.")
return super().selected_name(snapshot)
return self.incarnation.require_current(snapshot).name

def require_publication(self, message: Message, snapshot: RegistryProvenance,
require_channel: Callable[[str], Channel]) -> None:
Expand Down Expand Up @@ -562,7 +557,7 @@ def resolve(self, snapshot: RegistrySnapshot, require_channel: Callable[[str], C
def bindings[C: CliCommand](
self, declaration: type[C], comms: Comms, channel: SurroundingChannel, resolved: ResolvedChannel,
*, project: Checkout, snapshot: RegistrySnapshot, catalog: CatalogAccess,
) -> tuple[C, ...]:
) -> tuple[CommandBinding, ...]:
return declaration.channel_bindings(comms, resolved, project=project, snapshot=snapshot, catalog=catalog)

def validate(self, sender: Message | None = None):
Expand Down Expand Up @@ -654,7 +649,7 @@ def resolve(self, snapshot: RegistrySnapshot, require_channel: Callable[[str], C
def bindings[C: CliCommand](
self, declaration: type[C], comms: Comms, channel: SurroundingChannel, resolved,
*, project: Checkout, snapshot: RegistrySnapshot, catalog: CatalogAccess,
) -> tuple[C, ...]:
) -> tuple[CommandBinding, ...]:
return declaration.project_bindings(comms, resolved)


Expand Down
12 changes: 6 additions & 6 deletions src/agent_comms/check_root.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from .launch_runtime import ThreadLaunch
from .native_entries import ImportedSessionWriter, NativeEntry
from .native_session_files import CheckSession
from .read_basis import MemberActivityDisplayScope
from .read_basis import NamedActivityDisplayScope
from .registry_document import RosterVisibility
from .session_file import RegistrySessionLocation
from .thread_storage import StorageRoots
Expand Down Expand Up @@ -94,11 +94,11 @@ def _populate(self, copied: Comms) -> None:
targets = frozenset(
target for name in names for target in catalog.targets_for(snapshot.require(name).tags)
)
scope = MemberActivityDisplayScope("#check", targets, participant_names=selected | aliases)
scope = NamedActivityDisplayScope("#check", targets, participants=selected | aliases)
with self.source.bus.bus.reading() as source:
messages = scope.history(source, limit=self.max_records)
history = scope.history(source, limit=self.max_records)
copied.registry.store.prepare_native_root()
Bus.install(Bus.path_in(copied.root), history=messages)
Bus.install(Bus.path_in(copied.root), history=history)
copied.channels.catalog.replace(catalog)
declarations = {}
for name in names:
Expand Down Expand Up @@ -131,7 +131,7 @@ def _populate(self, copied: Comms) -> None:
edit.document.advance_claim(name)
edit.document.owners.advance(name)
edit.commit()
if messages:
if history:
# Imported history is displayable, not fresh input for this root.
# Position acceptance itself; human read markers own a different fact.
privacy = copied.registry.store.privacy()
Expand All @@ -141,7 +141,7 @@ def _populate(self, copied: Comms) -> None:
AcceptanceFrontier(
wire_root_id=privacy.namespace,
recipient_lookup=thread.incarnation.require_recorded().lookup,
through_seq=messages[-1].seq,
through_seq=history[-1].seq,
).advance(db)

def _session(self, original: Thread, root: Path, slot: str, project: Path) -> str:
Expand Down
Loading
Loading