feat(comms): agent roster read path — GetRoster + set_status (SEA-1721) - #163
Merged
Conversation
Manager-comms substrate T2. Replaces the T1 GetRoster CodeUnimplemented stub
with a real body and wires the two agent-initiated relay arms (roster, set_status).
- comms: (*Comms).roster joins all three roster sources for the vantage agent's
scope — the durable tree (treeForScope: NEIGHBORHOOD/SUBTREE/OWNER), the live
presence enum (in-memory source, absent -> OFFLINE), and the durable activity
string (agent_activity table, absent -> empty) — clipped to the CALLER's
account-visible set (D9, via ListAccounts) so a tree agent the caller may not
see never leaks. GetRoster delegates to it; vantage defaults to the caller.
- comms: SetStatusAsAccount truncates activity server-side to 140 runes (never
cutting a codepoint), write-throughs Store.SetActivity (commits), and returns
the truncated value so the publish carries exactly what landed.
- presence: Publisher.PresenceFor projects the last-published enum for a set
(absent omitted); Publisher.PublishActivity always publishes
AgentPresenceChanged{current presence, activity} (absent presence -> OFFLINE).
- runnerhub: Hub.PresenceFor / PublishActivity delegate to a nil-safe
presenceSource (mirrors the sink setter); executeCall gains the roster arm
and the set_status arm (ordered write-then-publish: durable SetActivity commits
first, best-effort PublishActivity fires the live event with the truncated
string, never gated on and never erroring the call). The fail-closed default
is untouched; its message now names the recognized variant set.
- server: wireHubServiceCycles + startPresencePublisher bridge the hub's
presence source into comms (hubPresenceSource adapter, mirroring the
AskAnswerWaker bridge).
Red-first: neighborhood/subtree/owner scoping; D9 clip drops a non-visible
agent; OFFLINE default + presence join; activity round-trips through the durable
store and survives a simulated restart (fresh handler, empty presence, same
store); set_status truncates over-cap and the truncated value lands in the table;
relay roster arm forwards + wraps; set_status arm write-then-publishes the
server-truncated value and succeeds with no presence source. Each proven
red-sensitive by mutating the implementation.
Refs SEA-1721
Co-authored-by: Matt Wilkinson <matt@sealedsecurity.com>
…ath (SEA-1721)
Review-fix for the T2 roster PR (mandatory skill://review, 1 medium + 1 low
test-adequacy gaps; source unchanged, guards/order already correct).
- RosterAsAccount and SetStatusAsAccount both fail closed on an empty account
(errNoActor -> CodeInvalidArgument), refusing to attribute an unresolved
caller to the bootstrap-admin fallback — but neither guard had a test that
fails on its removal. Add two pgtest cases mirroring the sibling security test
(agent_caller_pgtest_test.go): TestRosterAsAccountEmptyAccountFailsClosed
(asserts the error AND a nil response — no tree read, no ListAccounts("")
enumeration; SUBTREE scope isolates the guard, since OWNER scope errors
independently) and TestSetStatusAsAccountEmptyAccountFailsClosedNoWrite
(asserts the error AND that agent_activity holds no row for the empty id).
- The set_status relay arm returns before PublishActivity when the durable
write fails, so a subscriber never sees a status the store rejected — but the
fakeCommsCaller.setStatusErr field was unused. Add
TestRelayCommsCallSetStatusArmWriteErrorDoesNotPublish: the failure renders
in-band (CommsCallError, transport survives) and src.published stays empty.
Each proven red-first by mutating the guard/order and watching the test fail.
Co-authored-by: Matt Wilkinson <matt@sealedsecurity.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.
What
Manager-comms substrate T2 (SEA-1721): the agent roster read path. Replaces the T1
GetRosterCodeUnimplementedstub with a real body, and wires the two agent-initiated relay arms (roster,set_status). Design record section T2 (design.md:426-452) + T3 (set_status ordering, :473-486).Independent — base is
main. T2 touches onlyinternal/comms(roster),internal/presence,internal/runnerhub(relay arms),server/sinks.go— no migration, no overlap with T4's channel-policy legs. It does not stack on #161.Changes
comms.rosterjoins all three roster sources for the vantage agent's scope — durable tree (treeForScope: NEIGHBORHOOD/SUBTREE/OWNER), live presence enum (absent → OFFLINE), durable activity string (agent_activity, absent → empty) — clipped to the CALLER's account-visible set (D9, viaListAccounts) so a tree agent the caller may not see never leaks.GetRosterdelegates; vantage defaults to the caller.SetStatusAsAccounttruncates activity server-side to 140 runes (never mid-codepoint), write-throughsStore.SetActivity(commits), returns the truncated value.Publisher.PresenceFor(project last-published enum for a set),Publisher.PublishActivity(always publishesAgentPresenceChanged, absent presence → OFFLINE).Hub.PresenceFor/PublishActivitydelegate to a nil-safepresenceSource;executeCallgains therosterarm and theset_statusarm (ordered write-then-publish — durableSetActivitycommits first, best-effortPublishActivityfires the live event with the truncated string, never gated on, never errors the call). Fail-closed default untouched.hubPresenceSourceadapter bridges the hub's presence into comms (mirrors theAskAnswerWakerbridge).Tests (red-first, each proven red-sensitive by mutation)
PresenceForOFFLINE default; nil-source all-OFFLINE;PublishActivityforwards; nil-source publish is safe.Verification
go build ./...,go vet, CI-exactgolangci-lint run --config .golangci.yml ./...all clean (0 issues);internal/comms(21.5s),internal/runnerhub(17.6s),internal/presencepgtest suites green under-race. Mutation checks: D9-clip bypass, OFFLINE-default flip, truncation bypass, durable-activity-read stub, and publish-raw-instead-of-truncated each fail exactly the intended test(s).Realization notes (for the human gate)
SetChannelPolicy/UpdatePinnedBoardstubs leftCodeUnimplemented— those are T4's and T6's legs; T2 is independent off main and does not touch them.executeCall's fail-closed default error message said"has no post/list variant set"; now that roster + set_status are handled it names the recognized set (post/list/roster/set_status). T6 addspin.Refs SEA-1721