Skip to content

feat: add network threads#105

Merged
pedronauck merged 6 commits into
mainfrom
networkthreads
May 6, 2026
Merged

feat: add network threads#105
pedronauck merged 6 commits into
mainfrom
networkthreads

Conversation

@pedronauck
Copy link
Copy Markdown
Member

@pedronauck pedronauck commented May 5, 2026

Summary by CodeRabbit

  • New Features

    • Channel-centric network API: channels, threads, direct rooms, thread/direct messages, and work endpoints across HTTP, UDS, CLI, Host API and native tools.
    • Thread/direct surfaces and durable work lifecycle: work IDs, work states, richer message metadata (surface/thread/direct/work) and expanded runtime metrics.
    • CLI/daemon/host tooling to list/inspect threads, directs, messages, and work; new network hook events for thread/direct/message/work lifecycle.
  • Bug Fixes

    • Stopping a blocking prompt no longer emits spurious runtime errors; certain prompt errors are suppressed on cancellation.

@pedronauck pedronauck self-assigned this May 5, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented May 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agh-site Ready Ready Preview, Comment May 6, 2026 3:59am

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

Caution

Review failed

Pull request was closed or merged during review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 68b334ae-4cb8-440d-b4d3-6e46bb26d672

📥 Commits

Reviewing files that changed from the base of the PR and between aea75b1 and 6860957.

⛔ Files ignored due to path filters (3)
  • .compozy/tasks/network-threads/reviews-007/issue_001.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-007/issue_002.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-007/issue_003.md is excluded by !**/*.md
📒 Files selected for processing (3)
  • internal/acp/client.go
  • internal/acp/client_test.go
  • internal/daemon/network_e2e_assertions_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/daemon/network_e2e_assertions_test.go

Walkthrough

Adds prompt-stop suppression for certain ACP prompt errors; and a large network redesign introducing surfaces (thread/direct), Work-centric lifecycle (WorkID/WorkState), durable conversation persistence, new network hooks/events, expanded API/CLI/HostAPI surfaces, contract changes, and extensive tests.

Changes

ACP Prompt Stop Short-circuit

Layer / File(s) Summary
Behavior Change
internal/acp/client.go
runPrompt now returns early on prompt errors when a stop was requested and the error is classified suppressible.
Error Classification Helper
internal/acp/client.go
Added shouldSuppressPromptErrorOnStop(err error) bool to classify cancellable/context errors, certain ACP request errors, and FailureCanceled.
Tests
internal/acp/client_test.go
Added blocking scenario block_prompt_until_cancel and TestPromptStopDoesNotEmitRuntimeError; updated PromptNetworkMeta assertions to include Surface/DirectID/WorkID/Trust.

Network & Hooks Overhaul

Layer / File(s) Summary
Data Shape / Contracts
internal/network/envelope.go, internal/network/lifecycle.go, internal/acp/types.go, internal/api/contract/contract.go
Replaces InteractionID with WorkID; introduces Surface (thread/direct), ThreadID, DirectID, WorkID, WorkState; updates ACP PromptNetworkMeta and API contract types; adds new conversation/thread/direct/work payload types.
Core Lifecycle & Router
internal/network/lifecycle.go, internal/network/router.go, internal/network/manager.go
Introduces Work type and Work-centric APIs (OpenWork, ApplyWorkEnvelope), Work state transitions, router works storage, and two-phase send API (PrepareSend, PublishPrepared); manager wired for conversation persistence.
Persistence & Audit
internal/network/manager.go, internal/network/audit.go, internal/network/delivery.go
Integrates durable conversation persistence, simplifies audit writer, adds surface/thread/direct/work fields to audit entries, and expands status/metrics with counts for threads, direct rooms, works, messages, transitions, resolves and metric samples.
Hook Types & Dispatch
internal/hooks/payloads.go, internal/hooks/types.go, internal/hooks/events.go, internal/network/hooks.go
Adds NetworkPayload and specific network payload aliases; introduces NetworkMatcher and CompactionMatcher; adds network hook events and a HookDispatcher interface; manager dispatches network hooks on persisted writes.
Hook Matching & Wiring
internal/hooks/matcher.go, internal/hooks/dispatch.go, internal/daemon/hooks_bridge.go
Normalizer/validator extended for NetworkMatcher/CompactionMatcher; added DispatchNetworkXxx APIs and hooksNotifier implementations; daemon wires manager hook dispatcher.
API Handlers & Spec
internal/api/core/network_conversations.go, internal/api/core/network.go, internal/api/spec/spec.go, internal/api/contract/responses.go
Added channel-centric handlers (threads, directs, messages, work); NetworkSendRequest.UnmarshalJSON validation added; contract envelopes/payloads updated to pointer optional fields and new payload types; spec moved to channel-centric routes.
Routes & Tests
internal/api/httpapi/routes.go, internal/api/udsapi/routes.go, internal/api/*_test.go
Replaced peer-centric messaging routes with channel-centric routes; added many tests for direct resolve, conversation reads, route/spec parity, and read-path behavior.
CLI & Client Surface
internal/cli/network.go, internal/cli/client.go, internal/cli/*
CLI and daemon client extended to support threads, directs, work; added query/path/value builders, JSONL output, renderers, and matching tests for send/list/resolve flows.
Test Utilities & Stubs
internal/api/testutil/apitest.go, internal/daemon/daemon_test.go
StubNetworkStore and recording registries extended with conversation methods (ResolveDirectRoom, WriteConversationMessage, ListThreads, GetThread, ListConversationMessages, GetWork) to support new read/write tests.
Extension Host API & Protocol
internal/extension/host_api_network.go, internal/extension/host_api.go, internal/extension/protocol/host_api.go
New Host API network handlers and method registrations; added WithHostAPINetworkService/WithHostAPINetworkStore options; protocol host API method ordering updated; capability mappings extended for network methods.
Config / Manifest / Hook Config
internal/config/hooks.go, internal/extension/manifest.go, internal/extension/manager.go
Hook matcher config gains channel/surface/kind/direction/work_state fields; parsing/normalization loops switched to index/pointer iteration; cloning/deep-copy updated for nested matchers.
Observability & Metrics
internal/network/hooks_test.go, internal/network/manager.go, internal/daemon/native_tools.go
New metrics (delivery queue depth, per-category counters, low-cardinality labels) and tests asserting metric label hygiene; native tooling adapted to return redacted structured network results.
Comprehensive Tests
many packages (internal/api, internal/daemon, internal/cli, internal/hooks, internal/network)
Extensive test additions/updates for conversation read paths, direct resolve idempotency/races, hook dispatch ordering, persistence-before-side-effects, lifecycle transitions and cancellation races, CLI/HostAPI parity, and payload privacy assertions.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Manager
    participant ConversationStore
    participant HookDispatcher
    participant AuditStore

    Client->>Manager: Send/Receive envelope (with Surface/WorkID)
    Manager->>ConversationStore: WriteConversationMessage(entry)
    ConversationStore-->>Manager: WriteResult(message_id, work_id, duplicate)
    alt not duplicate
        Manager->>HookDispatcher: DispatchNetworkHooks(payload per event)
        HookDispatcher-->>Manager: Ack / error
        Manager->>AuditStore: WriteNetworkAudit(entry with persisted flags)
    else duplicate
        Manager->>AuditStore: WriteNetworkAudit(mark duplicate)
    end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~150 minutes

Possibly related PRs

  • compozy/agh#69: Touches ACP prompt error/failure handling and relates to the ACP client stop/error suppression logic.
  • compozy/agh#10: Overlapping changes to the hooks subsystem (events, payloads, matcher plumbing) similar to this PR’s network hook additions.
  • compozy/agh#73: Related edits to network API payloads and timeline/channel metadata that overlap with the contract and envelope changes in this PR.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
internal/extension/host_api_bridges.go (1)

577-586: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't block bridge ingest on full prompt completion.

drainAgentEvents only returns when the prompt event channel closes. Calling it inline here turns message ingest into a full prompt wait, and registerPromptDelivery(...) does not run until after the terminal event. That effectively disables live bridge delivery and can hang this RPC on slow or long-running prompts.

💡 Minimal fix
 	eventsCh, err := h.promptBridgeSession(
 		context.WithoutCancel(ctx),
 		sessionID,
 		message,
 		bridgePromptNetworkMeta(envelope),
 	)
 	if err != nil {
 		return hostAPIPromptSubmission{}, err
 	}
-	drainAgentEvents(eventsCh)
+	go drainAgentEvents(eventsCh)
 
 	events, err := h.sessions.Events(ctx, sessionID, store.EventQuery{
 		AfterSequence: lastSequence,
 	})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/extension/host_api_bridges.go` around lines 577 - 586, The code
currently calls drainAgentEvents(eventsCh) inline which blocks until the prompt
channel closes and prevents registerPromptDelivery(...) from running; change
this to run the drain in the background (e.g., spawn a goroutine: go
drainAgentEvents(eventsCh)) so promptBridgeSession returns immediately and
registerPromptDelivery can proceed without waiting for full prompt completion.
internal/extension/host_api.go (1)

1774-1780: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't block Host API prompt submission on the full agent event stream.

drainAgentEvents(eventsCh) now waits for the prompt to finish before sessions/create / sessions/prompt return. For blocked or long-running prompts, that can hang the RPC indefinitely, and context.WithoutCancel(ctx) means client cancellation no longer bounds the wait. This should keep draining in the background, or stop once the turn-init event is durable and return from there.

As per coding guidelines, "Detached execution lifetime — work that outlives an HTTP/UDS request must detach via context.WithoutCancel(ctx), never tie execution lifetime to request lifetime" and "context.WithoutCancel does NOT preserve deadlines — re-attach a deadline if needed".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/extension/host_api.go` around lines 1774 - 1780, After calling
h.sessions.Prompt, don't block on drainAgentEvents; instead spawn it in a
detached goroutine so the RPC can return immediately: create detachedCtx :=
context.WithoutCancel(ctx) and if the incoming ctx has a deadline re-attach that
deadline to detachedCtx (use context.WithDeadline) before launching the
goroutine, then run drainAgentEvents(eventsCh) inside that goroutine (using
detachedCtx if drainAgentEvents needs a ctx). This keeps
h.sessions.Prompt/sessionID/message from hanging while still continuing to
consume events in the background and preserves any original deadline semantics.
internal/api/core/network_test.go (1)

324-343: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert the new direct-room metadata in this test.

Surface and DirectID are now part of the fixture, but this case still only verifies trace/proof/ext fields. NetworkEnvelopePayloadFromEnvelope could drop either conversation field and this test would stay green.

As per coding guidelines, tests must verify behavior outcomes, not just function calls.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/api/core/network_test.go` around lines 324 - 343, The test currently
builds a network.Envelope with Surface and DirectID but doesn't assert they
survive conversion; update the test that calls
NetworkEnvelopePayloadFromEnvelope to also assert the resulting payload includes
the direct-room metadata (e.g. payload.Surface equals network.SurfaceDirect or
the expected enum/string and payload.DirectID equals
"direct_0123456789abcdef0123456789abcdef"); ensure the assertions reference the
network.Envelope fixture fields (Surface, DirectID) and the conversion function
NetworkEnvelopePayloadFromEnvelope so the test fails if those conversation
fields are dropped.
internal/network/router.go (1)

297-326: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

PublishPrepared can publish an envelope that never went through PrepareSend.

SendResult is exported and mutable, and this method does not re-run envelope validation, target-presence checks, or lifecycle checks before publishing. It also returns prepared.Subject verbatim even though publishEnvelope() recomputes the real subject internally, so the returned subject can diverge from what was actually published.

At minimum, recompute the subject here and rerun the same validation/preflight guards, or make the prepared token opaque so callers cannot forge it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/network/router.go` around lines 297 - 326, PublishPrepared currently
accepts a mutable SendResult and skips validation/preflight, allowing callers to
publish envelopes that never passed PrepareSend and return a subject that may
not match publishEnvelope's computed subject; fix by re-running the same
validation/guards used by PrepareSend (target presence, envelope validation,
lifecycle checks) inside PublishPrepared before calling publishEnvelope,
recompute the subject with subjectForEnvelope (or use the subject value
returned/used by publishEnvelope) instead of trusting prepared.Subject, and
treat SendResult as an opaque token for callers (or document/make fields
unexported) so callers cannot forge prepared tokens; update references to
PublishPrepared, SendResult, publishEnvelope, subjectForEnvelope, PrepareSend,
and syncSentLifecycle accordingly.
internal/network/lifecycle.go (1)

231-249: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Enforce the receipt/trace recipient against the work counterparty.

This function only validates to for say/capability. A participant can therefore send a receipt or trace for work A↔B to some other peer in the same thread/direct container and it will still pass validateWorkEnvelope, because only from is checked. The router will then deliver that lifecycle message to the addressed local peer even though they are not part of the work.

💡 Suggested fix
 func validateWorkDirection(current Work, env Envelope) error {
-	if env.Kind != KindSay && env.Kind != KindCapability {
-		return nil
-	}
 	if env.To == nil {
 		return fmt.Errorf("%w: %s to is required", ErrMissingField, env.Kind)
 	}
 
 	expectedTarget, ok := current.counterparty(env.From)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/network/lifecycle.go` around lines 231 - 249, The
validateWorkDirection function currently only enforces env.To for KindSay and
KindCapability; update it to also require and validate env.To for lifecycle
messages (receipt and trace). In validateWorkDirection, include KindReceipt and
KindTrace (or the appropriate constants used for receipts/traces) in the
condition that enforces env.To, and keep the same error handling: return
ErrMissingField if env.To is nil and return ErrWorkActorNotAllowed when *env.To
!= current.counterparty(env.From). Use the existing current.counterparty(...)
call and the same fmt.Errorf shapes so receipts/traces are checked against the
work counterparty just like say/capability messages.
🟡 Minor comments (14)
internal/hooks/dispatch_events.go-136-144 (1)

136-144: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Return zero correlation when the network actor id is unknown.

If both PeerFrom and SessionID are blank, this branch still emits ActorKind: "network_peer" with an empty ActorID. That creates a partial canonical correlation record and differs from the fallback path below, which returns DispatchCorrelation{} when no identifier exists. Guard actorID == "" before building the struct.

As per coding guidelines, "Every domain operation must emit a canonical event with correlation keys (workspace_id, session_id, parent_session_id, root_session_id, agent_name, task_id, run_id, claim_token_hash, lease_until, workflow_id, coordinator_session_id, scheduler_reason, hook_event, hook_name, spawn_depth, actor_kind, actor_id, release_reason)."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/hooks/dispatch_events.go` around lines 136 - 144, The NetworkPayload
branch currently emits a DispatchCorrelation with ActorKind "network_peer" even
when both PeerFrom and SessionID are blank; modify the case handling for
NetworkPayload so that after computing actorID from
strings.TrimSpace(typed.PeerFrom) and fallback to
strings.TrimSpace(typed.SessionID) you check if actorID == "" and if so return
an empty DispatchCorrelation{} instead of building a partial record; otherwise
return DispatchCorrelation{ActorKind: "network_peer", ActorID: actorID}. Ensure
you reference the NetworkPayload type, PeerFrom, SessionID, and
DispatchCorrelation symbols when making the change.
internal/api/spec/spec.go-1275-1283 (1)

1275-1283: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the after cursor description for thread listing.

This endpoint paginates threads, but the parameter text says “message id”. That will mislead clients reading the generated OpenAPI.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/api/spec/spec.go` around lines 1275 - 1283, The OpenAPI parameter
for the "after" query in the listNetworkThreads operation is incorrectly
described as a "message id"; update the parameter description used in the Path
"/api/network/channels/{channel}/threads" / OperationID "listNetworkThreads" so
the queryParam("after", ...) text refers to a thread cursor/id (e.g., "Return
threads after the specified thread id" or "Return results after the specified
thread cursor") to accurately reflect pagination for threads.
internal/api/spec/spec.go-1275-1434 (1)

1275-1434: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add missing OpenAPI specification for GET /api/network/peers/{peer_id}/messages endpoint.

The NetworkPeerMessages handler is fully implemented, tested, and registered as a public route, but missing from the OpenAPI spec. Similar message endpoints for threads and directs are documented (lines 1313 and 1396 respectively), so this should follow the same pattern in internal/api/spec/spec.go.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/api/spec/spec.go` around lines 1275 - 1434, The OpenAPI spec is
missing the entry for the GET /api/network/peers/{peer_id}/messages endpoint;
add a new ParameterSpec/ResponseSpec block matching the pattern used by
listNetworkThreadMessages and listNetworkDirectRoomMessages: create a route
object with Method "GET", Path "/api/network/peers/{peer_id}/messages",
OperationID "listNetworkPeerMessages" (or match the existing handler name
NetworkPeerMessages), Summary "List messages for a network peer", Tags
[]string{"network"}, Transports {TransportHTTP, TransportUDS}, Parameters
including pathParam("peer_id","Peer id"), query params before/after/kind/work_id
and intQueryParam("limit"), and Responses mirroring the others (200 ->
contract.NetworkPeerMessagesResponse{}, 400/404/503/500 ->
contract.ErrorPayload{}).
internal/bridges/types.go-621-625 (1)

621-625: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate work_id with the same canonical rules as the other AGH conversation IDs.

thread_id and direct_id are format-checked here, but work_id only gets generic length/control-character validation. That means malformed values like "foo" pass InboundMessageEnvelope.Validate() and only fail later in downstream network code.

Suggested fix
 	switch field {
 	case "thread_id":
 		if !strings.HasPrefix(trimmed, "thread_") {
 			return fmt.Errorf("bridges: invalid network conversation thread_id %q", value)
 		}
 	case "direct_id":
 		if !strings.HasPrefix(trimmed, "direct_") || len(trimmed) != len("direct_")+32 {
 			return fmt.Errorf("bridges: invalid network conversation direct_id %q", value)
 		}
+	case "work_id":
+		if !strings.HasPrefix(trimmed, "work_") {
+			return fmt.Errorf("bridges: invalid network conversation work_id %q", value)
+		}
 	}

Also applies to: 999-1017

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/bridges/types.go` around lines 621 - 625, Replace the generic
length/control-character check for normalized.WorkID in
InboundMessageEnvelope.Validate() with the same canonical validation used for
thread_id and direct_id by calling
validateBridgeNetworkConversationID(normalized.WorkID, "work_id"); i.e., locate
the block that currently only checks normalized.WorkID and swap it so it invokes
validateBridgeNetworkConversationID and returns its error (same pattern as used
for thread_id/direct_id) to ensure malformed work_id values are rejected early.
internal/network/perf_bench_test.go-12-23 (1)

12-23: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

This benchmark no longer constructs a direct message.

BenchmarkFormatNetworkMessageDirect now sets KindSay, but it does not mark the envelope as a direct surface or provide a DirectID. That makes it easy for the benchmark to drift into measuring the generic say formatter instead of the direct-message path its name implies. Either add the direct routing metadata here or rename the benchmark.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/network/perf_bench_test.go` around lines 12 - 23, The benchmark
BenchmarkFormatNetworkMessageDirect is constructing a KindSay envelope but not
marking it as a direct message, so change the test message construction to
include the direct routing metadata (set the envelope's DirectID to a non-empty
value and/or set the Surface to the direct surface constant used in your
codebase) so the formatter exercises the direct-message code path;
alternatively, if you intended to measure the generic say formatter, rename
BenchmarkFormatNetworkMessageDirect to reflect that intent. Ensure you modify
the message creation in the benchmark (the same block that sets Protocol, ID,
Kind, Channel, From, To, WorkID, ReplyTo, TraceID, CausationID, TS, Body) to add
DirectID (and Surface/direct flag) when keeping the current benchmark name.
internal/api/udsapi/handlers_test.go-549-562 (1)

549-562: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

This doesn't actually verify the HTTP router surface.

got is collected once from the UDS engine, then compared to the documented HTTP and UDS route sets. If HTTP registration drops a network route while the spec remains shared, this still passes because no HTTP router is ever instantiated here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/api/udsapi/handlers_test.go` around lines 549 - 562, The test
TestRegisterNetworkRoutesMatchDocumentedHTTPAndUDSSurface only instantiates a
UDS router and reuses its routes for both TransportHTTP and TransportUDS, so it
never verifies the HTTP router surface; fix by instantiating an HTTP router
(e.g., call newTestRouter with the same newTestHandlers but configured for
HTTP), collect its routes with registeredNetworkRoutesFromEngine on that HTTP
engine, then compare the HTTP-collected routes to
documentedNetworkRoutesForTransport(apispec.TransportHTTP) and the UDS-collected
routes to documentedNetworkRoutesForTransport(apispec.TransportUDS) using the
existing comparison logic.
internal/hooks/network_dispatch_test.go-23-38 (1)

23-38: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use event-consistent fixtures for the direct-room case.

Both the matcher and networkDispatchTestPayload force Surface: "thread" with a thread ID for every event. That means HookNetworkDirectRoomOpened never exercises the direct-surface / direct-ID path, so a regression there would still pass this test.

Also applies to: 84-103

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/hooks/network_dispatch_test.go` around lines 23 - 38, The test
currently forces NetworkMatcher{Surface: "thread"} and
networkDispatchTestPayload fixtures for all events, so
HookNetworkDirectRoomOpened never hits the direct-surface path; update the test
to create event-consistent fixtures: when iterating events (the events slice and
HookDecl creation), detect HookNetworkDirectRoomOpened and set the matcher and
the corresponding networkDispatchTestPayload for that case to use Surface:
"direct" and a direct-room ID (instead of "thread" and thread ID), while leaving
other events unchanged; ensure references to HookDecl,
HookMatcher/NetworkMatcher, networkDispatchTestPayload, and
HookNetworkDirectRoomOpened are used so the direct-room case exercises the
direct-surface/direct-ID code path.
internal/extension/manifest_test.go-150-153 (1)

150-153: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert the full matcher mapping here.

This only checks Channel and WorkState after hookConfigMatcher(...). If the conversion drops Surface, Kind, or Direction, the new test still passes even though those are part of the network matcher path added in this PR.

💡 Tighten the assertion
 	hookMatcher := hookConfigMatcher(matcher)
-	if hookMatcher.NetworkMatcher == nil || hookMatcher.Channel != "builders" || hookMatcher.WorkState != "completed" {
+	if hookMatcher.NetworkMatcher == nil ||
+		hookMatcher.Channel != "builders" ||
+		hookMatcher.Surface != "thread" ||
+		hookMatcher.Kind != "trace" ||
+		hookMatcher.Direction != "received" ||
+		hookMatcher.WorkState != "completed" {
 		t.Fatalf("hookConfigMatcher() = %#v, want network matcher fields", hookMatcher)
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/extension/manifest_test.go` around lines 150 - 153, The test only
validates Channel and WorkState from hookConfigMatcher(matcher) and may miss
regressions in NetworkMatcher fields; update the test to assert the complete
matcher mapping by comparing hookMatcher (the full return value of
hookConfigMatcher) against an expected struct/value that includes
NetworkMatcher.Surface, NetworkMatcher.Kind, NetworkMatcher.Direction, Channel,
and WorkState (or use reflect.DeepEqual/cmp to compare the whole hookMatcher to
expected). Ensure the assertion fails if any of Surface/Kind/Direction are
dropped or mistranslated.
internal/hooks/dispatch_events_test.go-64-93 (1)

64-93: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert the exact turn ID here.

These subtests only prove that TurnIDFromPayload() returns some trimmed non-empty string. If the implementation starts pulling the wrong field, this still passes. Comparing against the exact trimmed turn ID would make the test regression-sensitive.

As per coding guidelines, "MUST test meaningful business logic, not trivial operations" and "Check tests can fail when business logic changes."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/hooks/dispatch_events_test.go` around lines 64 - 93, The test
currently only checks that TurnIDFromPayload returns a non-empty trimmed string;
change the table-driven tests to include the exact expected trimmed turn ID for
each case and assert equality (e.g., add an expected field to each case and
replace the loose checks with if got != tc.expected { t.Fatalf(...)}), ensuring
you still trim inputs with surrounding spaces and call
TurnIDFromPayload(payload) for each payload; reference the test cases slice and
the TurnIDFromPayload function to locate where to add the expected values and
perform the strict equality assertion.
internal/acp/client_test.go-424-437 (1)

424-437: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Cover the new routing fields in this metadata round-trip.

This fixture now sets Surface and DirectID, but the test never asserts them. A regression that drops the new conversation-routing metadata would still pass here.

As per coding guidelines, "Focus on critical paths: workflow execution, state management, error handling" and "Check tests can fail when business logic changes."

Also applies to: 462-467

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/acp/client_test.go` around lines 424 - 437, The test fixture
populates PromptNetworkMeta.Surface and .DirectID but the assertions don't
verify them; update the round-trip assertions in internal/acp/client_test.go to
check that the decoded/returned PromptNetworkMeta has the same Surface and
DirectID as the fixture (add assertions for PromptNetworkMeta.Surface and
PromptNetworkMeta.DirectID where other meta fields are asserted), and do this
for both places the fixture is used (the block around the existing metadata
assertions and the second occurrence around lines 462-467) so a regression
dropping routing metadata will fail.
internal/network/audit_test.go-213-215 (1)

213-215: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Parallelize this new top-level test.

Everything here is per-test state, so leaving the top-level case serialized just slows the package and breaks the default parallel-test convention already used elsewhere in this file.

As per coding guidelines, **/*_test.go: "Default to t.Parallel in Go tests unless there is a specific reason to disable it (opt-out with t.Setenv)."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/network/audit_test.go` around lines 213 - 215, The top-level test
TestAuditWriterRecordsRepeatedGreetHeartbeatsOnlyAsAuditRows is not marked
parallel; add t.Parallel() as the first statement in the
TestAuditWriterRecordsRepeatedGreetHeartbeatsOnlyAsAuditRows function to allow
the whole test to run in parallel (leaving the existing t.Run subcases as-is),
ensuring per-test state remains isolated while following the file's
parallel-test convention.
internal/network/manager_test.go-312-313 (1)

312-313: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Lock the conversation-order counters on read.

publishCountAtWrite and promptCountAtWrite are written under s.mu, but these assertions read them directly. If WriteConversationMessage ever runs on a worker goroutine, this helper will start failing under -race even when the ordering is correct. Add tiny getter methods that read those fields under the same mutex and use those from the assertions.

Example fix
 type recordingConversationStore struct {
 	store.NetworkConversationStore

 	mu                  sync.Mutex
 	entries             []store.NetworkConversationMessage
 	publishCount        func() int
 	promptCount         func() int
 	publishCountAtWrite int
 	promptCountAtWrite  int
 	result              store.NetworkConversationWriteResult
 	err                 error
 }
+
+func (s *recordingConversationStore) publishCountWritten() int {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	return s.publishCountAtWrite
+}
+
+func (s *recordingConversationStore) promptCountWritten() int {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	return s.promptCountAtWrite
+}

As per coding guidelines, "Run tests with -race flag and ensure CGO_ENABLED=1 for race-sensitive packages."

Also applies to: 389-390, 1699-1743

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/network/manager_test.go` around lines 312 - 313, The test reads
s.publishCountAtWrite and s.promptCountAtWrite without locking though they are
written under s.mu; add small getter methods (e.g., func (s *<type>)
publishCountAtWriteLocked() int and func (s *<type>) promptCountAtWriteLocked()
int) that acquire s.mu, return the field, and update the test helper to call
these getters in place of direct field access; ensure assertions in
manager_test.go (around the lines referencing
publishCountAtWrite/promptCountAtWrite and other occurrences noted) use those
getters so reads are synchronized with WriteConversationMessage which holds
s.mu.
internal/api/core/network.go-302-349 (1)

302-349: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Redundant surface check results in unreachable code.

At lines 324-327, the condition surface == "" is checked with an inner if for threadID != "" || directID != "", but both branches return the same error. The inner check at line 324-325 makes the standalone return at line 327 unreachable when threadID or directID is set. The logic should be simplified.

🐛 Proposed fix to simplify the surface check
 	if surface == "" {
-		if threadID != "" || directID != "" {
-			return NewNetworkValidationError(fmt.Errorf("%w: surface is required", network.ErrMissingField))
-		}
 		return NewNetworkValidationError(fmt.Errorf("%w: surface is required", network.ErrMissingField))
 	}

If the intent was to provide different error messages, consider:

 	if surface == "" {
 		if threadID != "" || directID != "" {
-			return NewNetworkValidationError(fmt.Errorf("%w: surface is required", network.ErrMissingField))
+			return NewNetworkValidationError(fmt.Errorf("%w: surface is required when thread_id or direct_id is specified", network.ErrMissingField))
 		}
 		return NewNetworkValidationError(fmt.Errorf("%w: surface is required", network.ErrMissingField))
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/api/core/network.go` around lines 302 - 349, In
validateNetworkSendConversation, the redundant nested surface == "" check with
an inner if (threadID != "" || directID != "") returns the same
NewNetworkValidationError in both branches, making the inner branch unnecessary
and unreachable; simplify by replacing that nested if/return with a single check
that if surface == "" returns NewNetworkValidationError(fmt.Errorf("%w: surface
is required", network.ErrMissingField)); this removes the unreachable branch and
keeps behavior for validateNetworkSendConversation, ref.Validate, and the
subsequent work_id checks unchanged.
internal/network/router_test.go-1452-1461 (1)

1452-1461: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make these validation checks fail for the reason the test names claim.

Both assertions accept any non-nil error, and OpenWork(Envelope{Kind: KindSay}, time.Time{}) is invalid in several ways before it ever proves the "non-opener" path. Use a fully valid non-opener envelope and assert the specific error so this test breaks on the intended regression.

As per coding guidelines, tests MUST have specific error assertions (ErrorContains, ErrorAs).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/network/router_test.go` around lines 1452 - 1461, The test
TestWorkValidationErrors currently accepts any non-nil error; change it to
assert specific validation failures: keep the first assertion calling
(Work{}).Validate() but check the exact error (e.g., using t.ErrorContains or
t.ErrorAs) that Validate returns for an empty Work; for the OpenWork assertion,
construct a syntactically/semantically valid Envelope that is not an opener
(e.g., populate required fields like ID, Sender, Timestamp but set Kind to
KindSay) and call OpenWork with that Envelope and a valid time, then assert the
specific "non-opener" error returned by OpenWork using t.ErrorContains or
t.ErrorAs so the test fails only when the non-opener path regresses; target
symbols: TestWorkValidationErrors, Work.Validate, OpenWork, Envelope, KindSay.
🧹 Nitpick comments (6)
internal/network/helpers_test.go (1)

12-12: ⚡ Quick win

Remove duplicated test scenarios for KindSay.

Line [12] repeats KindSay, and Lines [77-79] duplicate the same SayBody.Kind() assertion. This adds noise and can mask missing coverage when enum values change.

Proposed cleanup
-	validKinds := []Kind{KindGreet, KindWhois, KindSay, KindSay, KindCapability, KindReceipt, KindTrace}
+	validKinds := []Kind{KindGreet, KindWhois, KindSay, KindCapability, KindReceipt, KindTrace}
...
-	if got := (SayBody{}).Kind(); got != KindSay {
-		t.Fatalf("SayBody.Kind() = %q, want %q", got, KindSay)
-	}

Also applies to: 77-79

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/network/helpers_test.go` at line 12, Remove the duplicated KindSay
entries and redundant assertion: in the test's validKinds slice remove the
second KindSay so each Kind value appears once, and delete the duplicate
assertion block that checks SayBody.Kind() (leave a single assertion for
SayBody.Kind()). Update any expected counts or table-driven test expectations
that relied on the duplicated entry so the test still validates all unique Kind
values exactly once.
internal/api/udsapi/agent_channels_test.go (1)

365-368: ⚡ Quick win

Assert the resolved direct room ID, not just that a pointer exists.

The new routing contract is surface-based, so this test should fail if reply resolution produces the wrong direct room or an empty string. Seed source.DirectID and check *seen.DirectID exactly; seen.DirectID != nil alone won't catch that regression.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/api/udsapi/agent_channels_test.go` around lines 365 - 368, The test
currently only asserts seen.DirectID != nil which misses wrong/empty direct-room
resolution; seed the expected direct room by setting source.DirectID to the
exact string you expect and replace the nil check with an equality assertion
that *seen.DirectID == expectedDirectID (i.e., compare *seen.DirectID to the
seeded source.DirectID value) in the same test that inspects seen (the block
checking seen.Kind, seen.Surface, seen.DirectID), so the test fails if reply
resolution returns the wrong or empty direct room ID.
internal/hooks/hooks_test.go (1)

1571-1571: ⚡ Quick win

Add a non-matching compaction case here.

This only exercises CompactionMatcher with the matching "token_limit" reason, so the test still passes if the new nested matcher is ignored completely. Add a second dispatch with a different Reason and assert the payload stays unchanged.

Also applies to: 1652-1655

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/hooks/hooks_test.go` at line 1571, Add a second test dispatch that
uses HookMatcher with CompactionMatcher where Reason is something other than
"token_limit" (e.g., "other_reason") to exercise the non-matching path; call the
same dispatch/handle function used for the matching case and then assert that
the returned/handled payload is unchanged from the input. Specifically, add a
new HookMatcher{CompactionMatcher: &CompactionMatcher{Reason: "other_reason"}}
dispatch alongside the existing matching dispatch and add an assertion that the
payload equals the original payload (no modifications) to ensure the nested
matcher is evaluated.
internal/daemon/network_e2e_assertions_test.go (1)

168-314: ⚡ Quick win

Wrap these cases in t.Run("Should ...") subtests.

The added/updated cases are still flat top-level tests, so this file is drifting from the repo’s required Go test structure.

As per coding guidelines, **/*_test.go: Use t.Run('Should ...') pattern for Go test subtests instead of flat test structures.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/daemon/network_e2e_assertions_test.go` around lines 168 - 314, The
top-level tests TestValidateNetworkCorrelationSurfacesUsesTargetedAttributes,
TestValidateNetworkCorrelationSurfacesRejectsSplitTranscriptMatches,
TestValidateNetworkAuditEntryMatchesDuplicateRejection, and
TestValidateNetworkAuditEntryRejectsWrongContainer should be converted to use
t.Run subtests (e.g. t.Run("Should validate ...", func(t *testing.T) { ... }))
so they follow the repo test pattern; wrap each existing test body in a t.Run
with a descriptive "Should ..." name, keep calling t.Parallel() inside each
subtest (or at the parent if you want all subtests parallel), and leave the
calls to validateNetworkCorrelationSurfaces and validateNetworkAuditEntry and
their expectations unchanged.
internal/api/httpapi/network_test.go (1)

18-93: ⚡ Quick win

Mark the subtest parallel as well.

The parent test is parallelized, but this new t.Run("Should ...") block still runs serially. Adding t.Parallel() here keeps the new coverage aligned with the rest of the suite's default test behavior.

As per coding guidelines, "Use t.Run("Should ...") subtests with t.Parallel as default (opt-out with t.Setenv)."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/api/httpapi/network_test.go` around lines 18 - 93, The subtest
"Should create deterministic direct room" inside network_test.go is not marked
parallel; add t.Parallel() as the first statement inside that t.Run closure
(immediately after func(t *testing.T) {) so the subtest runs concurrently like
the parent suite; update the subtest containing newTestHomePaths,
newTestHandlers, handlers.Network = ..., handlers.NetworkStore = ..., engine :=
newTestRouter(...) etc. to include t.Parallel() at the top of the closure.
internal/api/core/agent_channels.go (1)

860-877: 💤 Low value

Hardcoded query key limits reusability.

The parsePositiveIntQuery function now hardcodes the key as "limit", which reduces its flexibility compared to the previous signature that accepted a key parameter. If only the limit query parameter needs this parsing, consider renaming to parseLimitQuery for clarity.

♻️ Optional: Rename for clarity
-func parsePositiveIntQuery(c *gin.Context) (int, error) {
-	const key = "limit"
+func parseLimitQuery(c *gin.Context) (int, error) {
+	const key = "limit"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/api/core/agent_channels.go` around lines 860 - 877, The function
parsePositiveIntQuery currently hardcodes the query key "limit", reducing reuse;
change its signature back to accept a key parameter (e.g., func
parsePositiveIntQuery(c *gin.Context, key string) (int, error)), replace the
constant key usage with the parameter, and update all call sites to pass the
desired query name (or if you intentionally only want "limit", instead rename
the function to parseLimitQuery and adjust callers accordingly); ensure error
messages still reference the provided key and tests/build are updated
accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fbd455d9-1770-4b71-904c-9ec558be8cc6

📥 Commits

Reviewing files that changed from the base of the PR and between d5cda0b and f6b7c2d.

⛔ Files ignored due to path filters (64)
  • internal/skills/bundled/skills/agh-network/SKILL.md is excluded by !**/*.md
  • internal/testutil/acpmock/testdata/browser_session_lifecycle_fixture.json is excluded by !**/*.json
  • internal/testutil/acpmock/testdata/driver_fault_fixture.json is excluded by !**/*.json
  • internal/testutil/acpmock/testdata/network_collaboration_fixture.json is excluded by !**/*.json
  • internal/testutil/acpmock/testdata/permission_env_fixture.json is excluded by !**/*.json
  • internal/testutil/acpmock/testdata/tool_permission_fixture.json is excluded by !**/*.json
  • openapi/agh.json is excluded by !**/*.json
  • packages/site/content/blog/posts/introducing-agh-the-first-agent-network-protocol.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/capability-discovery.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/conformance.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/delivery.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/ed25519-jcs.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/envelope.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/examples.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/guide/minimal-sender.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/guide/nats-transport.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/guide/testing.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/guide/trust-verification.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/interactions.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/message-kinds.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/nats.mdx is excluded by !**/*.mdx
  • packages/site/content/protocol/overview.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/directs/index.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/directs/list.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/directs/messages.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/directs/meta.json is excluded by !**/*.json
  • packages/site/content/runtime/cli-reference/network/directs/resolve.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/directs/show.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/index.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/meta.json is excluded by !**/*.json
  • packages/site/content/runtime/cli-reference/network/send.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/threads/index.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/threads/list.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/threads/messages.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/threads/meta.json is excluded by !**/*.json
  • packages/site/content/runtime/cli-reference/network/threads/show.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/work/index.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/work/lookup.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/network/work/meta.json is excluded by !**/*.json
  • packages/site/content/runtime/cli-reference/network/work/status.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/observe/events.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/cli-reference/task/run/enqueue.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/core/agents/capabilities.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/core/network/channels-and-peers.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/core/network/delivery-and-safety.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/core/network/directs.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/core/network/index.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/core/network/meta.json is excluded by !**/*.json
  • packages/site/content/runtime/core/network/protocol.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/core/network/task-ingress.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/core/network/threads.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/core/network/work.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/guides/coordinate-agents-over-network.mdx is excluded by !**/*.mdx
  • packages/site/content/runtime/use-cases/handoff-between-agents.mdx is excluded by !**/*.mdx
  • sdk/typescript/src/generated/contracts.ts is excluded by !**/generated/**
  • web/e2e/fixtures/artifacts.test.ts is excluded by !**/fixtures/**
  • web/e2e/fixtures/artifacts.ts is excluded by !**/fixtures/**
  • web/e2e/fixtures/browser-artifact-session.test.ts is excluded by !**/fixtures/**
  • web/e2e/fixtures/browser-artifact-session.ts is excluded by !**/fixtures/**
  • web/e2e/fixtures/runtime-seed.test.ts is excluded by !**/fixtures/**
  • web/e2e/fixtures/runtime-seed.ts is excluded by !**/fixtures/**
  • web/e2e/fixtures/selectors.test.ts is excluded by !**/fixtures/**
  • web/e2e/fixtures/selectors.ts is excluded by !**/fixtures/**
  • web/src/generated/agh-openapi.d.ts is excluded by !**/generated/**
📒 Files selected for processing (236)
  • internal/acp/client.go
  • internal/acp/client_test.go
  • internal/acp/types.go
  • internal/api/contract/contract.go
  • internal/api/contract/contract_test.go
  • internal/api/contract/responses.go
  • internal/api/core/agent_channels.go
  • internal/api/core/agent_channels_internal_test.go
  • internal/api/core/authored_context.go
  • internal/api/core/coverage_helpers_test.go
  • internal/api/core/errors.go
  • internal/api/core/interfaces.go
  • internal/api/core/network.go
  • internal/api/core/network_conversations.go
  • internal/api/core/network_details.go
  • internal/api/core/network_test.go
  • internal/api/core/test_helpers_test.go
  • internal/api/httpapi/handlers_test.go
  • internal/api/httpapi/network_test.go
  • internal/api/httpapi/routes.go
  • internal/api/spec/spec.go
  • internal/api/testutil/apitest.go
  • internal/api/udsapi/agent_channels_test.go
  • internal/api/udsapi/handlers_test.go
  • internal/api/udsapi/network_test.go
  • internal/api/udsapi/routes.go
  • internal/api/udsapi/transport_parity_integration_test.go
  • internal/bridges/types.go
  • internal/bridges/types_test.go
  • internal/cli/cli_integration_test.go
  • internal/cli/client.go
  • internal/cli/command_paths_test.go
  • internal/cli/helpers_test.go
  • internal/cli/hooks.go
  • internal/cli/hooks_test.go
  • internal/cli/network.go
  • internal/cli/network_client_test.go
  • internal/cli/network_test.go
  • internal/config/agent.go
  • internal/config/agent_edit.go
  • internal/config/hooks.go
  • internal/config/hooks_test.go
  • internal/config/merge.go
  • internal/config/tool_surface.go
  • internal/daemon/boot.go
  • internal/daemon/daemon.go
  • internal/daemon/daemon_acpmock_faults_integration_test.go
  • internal/daemon/daemon_network_collaboration_integration_test.go
  • internal/daemon/daemon_test.go
  • internal/daemon/hooks_bridge.go
  • internal/daemon/native_tools.go
  • internal/daemon/native_tools_test.go
  • internal/daemon/network_e2e_assertions_test.go
  • internal/daemon/prompt_input_composite_integration_test.go
  • internal/extension/capability.go
  • internal/extension/capability_test.go
  • internal/extension/contract/host_api.go
  • internal/extension/contract/sdk.go
  • internal/extension/contract/sdk_test.go
  • internal/extension/host_api.go
  • internal/extension/host_api_bridges.go
  • internal/extension/host_api_network.go
  • internal/extension/host_api_network_test.go
  • internal/extension/manager.go
  • internal/extension/manifest.go
  • internal/extension/manifest_test.go
  • internal/extension/protocol/host_api.go
  • internal/extension/protocol/host_api_test.go
  • internal/hooks/async_clone_test.go
  • internal/hooks/dispatch.go
  • internal/hooks/dispatch_events.go
  • internal/hooks/dispatch_events_test.go
  • internal/hooks/events.go
  • internal/hooks/events_test.go
  • internal/hooks/hooks_test.go
  • internal/hooks/introspection.go
  • internal/hooks/introspection_test.go
  • internal/hooks/matcher.go
  • internal/hooks/matcher_test.go
  • internal/hooks/network_dispatch_test.go
  • internal/hooks/payloads.go
  • internal/hooks/payloads_test.go
  • internal/hooks/types.go
  • internal/network/audit.go
  • internal/network/audit_test.go
  • internal/network/delivery.go
  • internal/network/delivery_test.go
  • internal/network/envelope.go
  • internal/network/envelope_integration_test.go
  • internal/network/helpers_test.go
  • internal/network/hooks.go
  • internal/network/hooks_test.go
  • internal/network/lifecycle.go
  • internal/network/lifecycle_test.go
  • internal/network/manager.go
  • internal/network/manager_integration_test.go
  • internal/network/manager_test.go
  • internal/network/perf_bench_test.go
  • internal/network/router.go
  • internal/network/router_integration_test.go
  • internal/network/router_test.go
  • internal/network/stats.go
  • internal/network/tasks.go
  • internal/network/tasks_integration_test.go
  • internal/network/tasks_test.go
  • internal/network/validate.go
  • internal/network/validate_test.go
  • internal/session/query.go
  • internal/session/query_test.go
  • internal/settings/collections.go
  • internal/settings/service_test.go
  • internal/situation/service.go
  • internal/situation/service_test.go
  • internal/skills/bundled/bundled_test.go
  • internal/store/globaldb/global_db.go
  • internal/store/globaldb/global_db_heartbeat_test.go
  • internal/store/globaldb/global_db_network_audit.go
  • internal/store/globaldb/global_db_network_audit_test.go
  • internal/store/globaldb/global_db_network_conversation_repository_test.go
  • internal/store/globaldb/global_db_network_conversations.go
  • internal/store/globaldb/global_db_network_conversations_test.go
  • internal/store/globaldb/global_db_network_messages.go
  • internal/store/globaldb/global_db_network_messages_test.go
  • internal/store/globaldb/global_db_soul_test.go
  • internal/store/globaldb/global_db_test.go
  • internal/store/globaldb/tx_helpers.go
  • internal/store/network_conversation_types_test.go
  • internal/store/sessiondb/session_db.go
  • internal/store/sessiondb/session_db_extra_test.go
  • internal/store/store.go
  • internal/store/store_helpers_test.go
  • internal/store/types.go
  • internal/testutil/acpmock/fixture.go
  • internal/testutil/acpmock/fixture_test.go
  • internal/testutil/e2e/artifacts.go
  • internal/testutil/e2e/runtime_harness.go
  • internal/testutil/e2e/runtime_harness_helpers_test.go
  • internal/tools/builtin/builtin_test.go
  • internal/tools/builtin/network.go
  • internal/tools/builtin/toolsets.go
  • internal/tools/builtin_ids.go
  • internal/tools/native_test.go
  • internal/tools/schema.go
  • packages/site/components/blog/kind-chip.tsx
  • packages/site/components/landing/__tests__/landing.test.tsx
  • packages/site/components/landing/network-protocol-visual.tsx
  • packages/site/components/landing/network-section.tsx
  • packages/site/components/landing/primitives/network-kinds.ts
  • packages/site/lib/landing-cli-snippets.test.ts
  • packages/site/lib/protocol-rfc-hard-cut.test.ts
  • packages/site/lib/runtime-manual-cli-examples.test.ts
  • sdk/go/extension_test.go
  • sdk/go/host_api.go
  • sdk/typescript/src/host-api.test.ts
  • sdk/typescript/src/host-api.ts
  • sdk/typescript/src/index.ts
  • web/e2e/bridges.spec.ts
  • web/e2e/network.spec.ts
  • web/e2e/storybook-bootstrap.spec.ts
  • web/src/hooks/routes/use-network-page.ts
  • web/src/routeTree.gen.ts
  • web/src/routes/_app/-network-routes.test.ts
  • web/src/routes/_app/-network-task14-routes.test.ts
  • web/src/routes/_app/-network.test.tsx
  • web/src/routes/_app/network.$channel.activity.tsx
  • web/src/routes/_app/network.$channel.directs.$directId.tsx
  • web/src/routes/_app/network.$channel.directs.tsx
  • web/src/routes/_app/network.$channel.threads.$threadId.tsx
  • web/src/routes/_app/network.$channel.threads.tsx
  • web/src/routes/_app/network.tsx
  • web/src/routes/_app/settings/-network.test.tsx
  • web/src/routes/_app/stories/-network.stories.tsx
  • web/src/storybook/web-storybook-stories-and-fixtures.test.tsx
  • web/src/systems/network/adapters/network-api.ts
  • web/src/systems/network/components/activity/activity-feed.test.tsx
  • web/src/systems/network/components/activity/activity-feed.tsx
  • web/src/systems/network/components/activity/index.ts
  • web/src/systems/network/components/composer/channel-thread-composer.test.tsx
  • web/src/systems/network/components/composer/channel-thread-composer.tsx
  • web/src/systems/network/components/composer/composer-slash-popover.tsx
  • web/src/systems/network/components/composer/composer-toolbar.tsx
  • web/src/systems/network/components/composer/composer.test.tsx
  • web/src/systems/network/components/composer/composer.tsx
  • web/src/systems/network/components/composer/detail-composer.tsx
  • web/src/systems/network/components/composer/index.ts
  • web/src/systems/network/components/composer/use-composer-state.ts
  • web/src/systems/network/components/directs/direct-room.test.tsx
  • web/src/systems/network/components/directs/direct-room.tsx
  • web/src/systems/network/components/directs/directs-list.test.tsx
  • web/src/systems/network/components/directs/directs-list.tsx
  • web/src/systems/network/components/directs/index.ts
  • web/src/systems/network/components/directs/new-direct-dialog.tsx
  • web/src/systems/network/components/directs/use-direct-room-view.ts
  • web/src/systems/network/components/empty-states/conversation-error.tsx
  • web/src/systems/network/components/empty-states/daemon-down.tsx
  • web/src/systems/network/components/empty-states/direct-empty.tsx
  • web/src/systems/network/components/empty-states/directs-empty.tsx
  • web/src/systems/network/components/empty-states/empty-states.test.tsx
  • web/src/systems/network/components/empty-states/index.ts
  • web/src/systems/network/components/empty-states/network-empty.tsx
  • web/src/systems/network/components/empty-states/thread-empty.tsx
  • web/src/systems/network/components/empty-states/threads-empty.tsx
  • web/src/systems/network/components/network-workspace-shell.test.tsx
  • web/src/systems/network/components/network-workspace-shell.tsx
  • web/src/systems/network/components/shell/channel-header.tsx
  • web/src/systems/network/components/shell/channel-rail-recents.tsx
  • web/src/systems/network/components/shell/channel-rail-row.tsx
  • web/src/systems/network/components/shell/channel-rail.test.tsx
  • web/src/systems/network/components/shell/channel-rail.tsx
  • web/src/systems/network/components/shell/channel-tabs.test.tsx
  • web/src/systems/network/components/shell/channel-tabs.tsx
  • web/src/systems/network/components/shell/index.ts
  • web/src/systems/network/components/shell/inspector-activity-feed.tsx
  • web/src/systems/network/components/shell/inspector-members-list.tsx
  • web/src/systems/network/components/shell/list-filter-bar.test.tsx
  • web/src/systems/network/components/shell/list-filter-bar.tsx
  • web/src/systems/network/components/shell/network-inspector.tsx
  • web/src/systems/network/components/shell/network-shell.tsx
  • web/src/systems/network/components/shell/right-rail.tsx
  • web/src/systems/network/components/stories/channel-header.stories.tsx
  • web/src/systems/network/components/stories/channel-rail.stories.tsx
  • web/src/systems/network/components/stories/composer.stories.tsx
  • web/src/systems/network/components/stories/empty-states.stories.tsx
  • web/src/systems/network/components/stories/message-row.stories.tsx
  • web/src/systems/network/components/stories/network-shell.stories.tsx
  • web/src/systems/network/components/stories/network-workspace-shell.stories.tsx
  • web/src/systems/network/components/stories/thread-overlay.stories.tsx
  • web/src/systems/network/components/stories/timeline.stories.tsx
  • web/src/systems/network/components/stories/work.stories.tsx
  • web/src/systems/network/components/thread-overlay/index.ts
  • web/src/systems/network/components/thread-overlay/thread-overlay-header.tsx
  • web/src/systems/network/components/thread-overlay/thread-overlay-replies.tsx
  • web/src/systems/network/components/thread-overlay/thread-overlay-root.tsx
  • web/src/systems/network/components/thread-overlay/thread-overlay.test.tsx
  • web/src/systems/network/components/thread-overlay/thread-overlay.tsx
  • web/src/systems/network/components/thread-overlay/use-thread-overlay-view.ts

Comment thread internal/acp/client.go
Comment thread internal/api/core/network_details.go
Comment thread internal/cli/hooks_test.go
Comment thread internal/config/hooks_test.go
Comment thread internal/config/hooks.go
Comment thread internal/daemon/daemon_acpmock_faults_integration_test.go
Comment thread internal/extension/manager.go
Comment thread internal/hooks/introspection_test.go
Comment thread internal/hooks/payloads.go
Comment thread internal/network/router.go
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
internal/network/audit_test.go (1)

260-275: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add t.Parallel() in the subtest.

This subtest is missing t.Parallel() while all sibling subtests in the file use it, inconsistent with the project's default testing pattern.

✅ Suggested patch
 	t.Run("Should return audit write failures", func(t *testing.T) {
+		t.Parallel()
+
 		storeErr := errors.New("audit store unavailable")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/network/audit_test.go` around lines 260 - 275, The subtest "Should
return audit write failures" is missing t.Parallel(), causing inconsistency with
sibling subtests; inside the t.Run block for that test (around the setup using
failingAuditStore, NewAuditWriter and the RecordSent call) add a call to
t.Parallel() immediately after the subtest starts so the subtest runs in
parallel with its siblings.
internal/config/hooks.go (1)

200-239: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep nested matchers nil unless that matcher family is actually configured.

toHookMatcher() now always returns non-nil NetworkMatcher and CompactionMatcher, even for hooks that never set any of those fields. That changes the meaning of pointer presence for downstream code and makes config-defined hooks look like they opted into these matcher families when they did not. Gate each allocation on at least one non-empty field.

Suggested fix
 func (m parsedHookMatcher) toHookMatcher(scopeAgentName string) (hookspkg.HookMatcher, error) {
 	matcher := hookspkg.HookMatcher{
 		AgentName:        strings.TrimSpace(m.AgentName),
 		AgentType:        strings.TrimSpace(m.AgentType),
 		WorkspaceID:      strings.TrimSpace(m.WorkspaceID),
 		WorkspaceRoot:    strings.TrimSpace(m.WorkspaceRoot),
 		SessionType:      strings.TrimSpace(m.SessionType),
 		InputClass:       strings.TrimSpace(m.InputClass),
 		ACPEventType:     strings.TrimSpace(m.ACPEventType),
 		TurnID:           strings.TrimSpace(m.TurnID),
 		ToolID:           strings.TrimSpace(m.ToolID),
 		ToolName:         strings.TrimSpace(m.ToolName),
 		DecisionClass:    strings.TrimSpace(m.DecisionClass),
 		MessageRole:      strings.TrimSpace(m.MessageRole),
 		MessageDeltaType: strings.TrimSpace(m.MessageDeltaType),
 	}
-	matcher.NetworkMatcher = &hookspkg.NetworkMatcher{
-		Channel:   strings.TrimSpace(m.Channel),
-		Surface:   strings.TrimSpace(m.Surface),
-		Kind:      strings.TrimSpace(m.Kind),
-		Direction: strings.TrimSpace(m.Direction),
-		WorkState: strings.TrimSpace(m.WorkState),
-	}
-	matcher.CompactionMatcher = &hookspkg.CompactionMatcher{
-		Reason:   strings.TrimSpace(m.CompactionReason),
-		Strategy: strings.TrimSpace(m.CompactionStrategy),
-	}
+	channel := strings.TrimSpace(m.Channel)
+	surface := strings.TrimSpace(m.Surface)
+	kind := strings.TrimSpace(m.Kind)
+	direction := strings.TrimSpace(m.Direction)
+	workState := strings.TrimSpace(m.WorkState)
+	if channel != "" || surface != "" || kind != "" || direction != "" || workState != "" {
+		matcher.NetworkMatcher = &hookspkg.NetworkMatcher{
+			Channel:   channel,
+			Surface:   surface,
+			Kind:      kind,
+			Direction: direction,
+			WorkState: workState,
+		}
+	}
+	reason := strings.TrimSpace(m.CompactionReason)
+	strategy := strings.TrimSpace(m.CompactionStrategy)
+	if reason != "" || strategy != "" {
+		matcher.CompactionMatcher = &hookspkg.CompactionMatcher{
+			Reason:   reason,
+			Strategy: strategy,
+		}
+	}
 	if m.ToolReadOnly != nil {
 		value := *m.ToolReadOnly
 		matcher.ToolReadOnly = &value
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/config/hooks.go` around lines 200 - 239, In toHookMatcher, avoid
always allocating matcher.NetworkMatcher and matcher.CompactionMatcher; instead,
only set matcher.NetworkMatcher to &hookspkg.NetworkMatcher{...} if at least one
of Channel, Surface, Kind, Direction, or WorkState is non-empty (after
TrimSpace), and only set matcher.CompactionMatcher to
&hookspkg.CompactionMatcher{...} if either CompactionReason or
CompactionStrategy is non-empty; leave those pointer fields nil when no related
fields are configured so downstream code can rely on nil meaning "not
configured". Use the same trimmed values you already build for the matcher
fields to decide the allocations in parsedHookMatcher.toHookMatcher.
internal/extension/manager.go (1)

1620-1651: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve nil matcher pointers when no network or compaction fields are configured.

hookConfigMatcher() now makes NetworkMatcher and CompactionMatcher non-nil for every hook, even when all fields in those groups are empty. That removes the existing “nil means this matcher family is absent” signal for downstream consumers, including the new CLI/network rendering path added in this PR. Only allocate each nested matcher when at least one field in that family is set.

Suggested fix
 func hookConfigMatcher(cfg HookMatcherConfig) hookspkg.HookMatcher {
 	matcher := hookspkg.HookMatcher{
 		AgentName:        strings.TrimSpace(cfg.AgentName),
 		AgentType:        strings.TrimSpace(cfg.AgentType),
 		WorkspaceID:      strings.TrimSpace(cfg.WorkspaceID),
 		WorkspaceRoot:    strings.TrimSpace(cfg.WorkspaceRoot),
 		SessionType:      strings.TrimSpace(cfg.SessionType),
 		InputClass:       strings.TrimSpace(cfg.InputClass),
 		ACPEventType:     strings.TrimSpace(cfg.ACPEventType),
 		TurnID:           strings.TrimSpace(cfg.TurnID),
 		ToolID:           strings.TrimSpace(cfg.ToolID),
 		ToolName:         strings.TrimSpace(cfg.ToolName),
 		DecisionClass:    strings.TrimSpace(cfg.DecisionClass),
 		MessageRole:      strings.TrimSpace(cfg.MessageRole),
 		MessageDeltaType: strings.TrimSpace(cfg.MessageDeltaType),
 	}
-	matcher.NetworkMatcher = &hookspkg.NetworkMatcher{
-		Channel:   strings.TrimSpace(cfg.Channel),
-		Surface:   strings.TrimSpace(cfg.Surface),
-		Kind:      strings.TrimSpace(cfg.Kind),
-		Direction: strings.TrimSpace(cfg.Direction),
-		WorkState: strings.TrimSpace(cfg.WorkState),
-	}
-	matcher.CompactionMatcher = &hookspkg.CompactionMatcher{
-		Reason:   strings.TrimSpace(cfg.CompactionReason),
-		Strategy: strings.TrimSpace(cfg.CompactionStrategy),
-	}
+	channel := strings.TrimSpace(cfg.Channel)
+	surface := strings.TrimSpace(cfg.Surface)
+	kind := strings.TrimSpace(cfg.Kind)
+	direction := strings.TrimSpace(cfg.Direction)
+	workState := strings.TrimSpace(cfg.WorkState)
+	if channel != "" || surface != "" || kind != "" || direction != "" || workState != "" {
+		matcher.NetworkMatcher = &hookspkg.NetworkMatcher{
+			Channel:   channel,
+			Surface:   surface,
+			Kind:      kind,
+			Direction: direction,
+			WorkState: workState,
+		}
+	}
+	reason := strings.TrimSpace(cfg.CompactionReason)
+	strategy := strings.TrimSpace(cfg.CompactionStrategy)
+	if reason != "" || strategy != "" {
+		matcher.CompactionMatcher = &hookspkg.CompactionMatcher{
+			Reason:   reason,
+			Strategy: strategy,
+		}
+	}
 	if cfg.ToolReadOnly != nil {
 		value := *cfg.ToolReadOnly
 		matcher.ToolReadOnly = &value
 	}
 	return matcher
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/extension/manager.go` around lines 1620 - 1651, In
hookConfigMatcher, avoid always allocating matcher.NetworkMatcher and
matcher.CompactionMatcher; instead check whether any of the corresponding cfg
fields are non-empty and only then create & assign hookspkg.NetworkMatcher or
&hookspkg.CompactionMatcher. Concretely, in hookConfigMatcher inspect
cfg.Channel|Surface|Kind|Direction|WorkState and create matcher.NetworkMatcher =
&hookspkg.NetworkMatcher{...} only if at least one of those trimmed values is
non-empty, and likewise inspect cfg.CompactionReason|CompactionStrategy and only
assign matcher.CompactionMatcher = &hookspkg.CompactionMatcher{...} when at
least one is non-empty, leaving the pointer nil otherwise (keep existing
ToolReadOnly handling).
🧹 Nitpick comments (6)
internal/daemon/network_e2e_assertions_test.go (2)

298-322: ⚡ Quick win

Wrap test body in t.Run("Should ...") for consistency.

Same issue as above—this test should use the subtest pattern for consistency with the rest of the file.

♻️ Proposed fix
 func TestValidateNetworkAuditEntryRejectsWrongContainer(t *testing.T) {
 	t.Parallel()
 
+	t.Run("Should reject mismatched direct_id", func(t *testing.T) {
+		t.Parallel()
+
 	entries := []store.NetworkAuditEntry{
 		{
 			MessageID: "msg_direct_01",
 			Direction: "delivered",
 			Kind:      "say",
 			Surface:   "direct",
 			DirectID:  "direct_wrong",
 			WorkID:    "work_patch_42",
 		},
 	}
 
 	if err := validateNetworkAuditEntry(entries, networkAuditExpectation{
 		MessageID: "msg_direct_01",
 		Direction: "delivered",
 		Kind:      "say",
 		Surface:   "direct",
 		DirectID:  "direct_test_01",
 		WorkID:    "work_patch_42",
 	}); err == nil {
 		t.Fatal("validateNetworkAuditEntry() error = nil, want direct_id mismatch")
 	}
+	})
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/daemon/network_e2e_assertions_test.go` around lines 298 - 322, Wrap
the test body of TestValidateNetworkAuditEntryRejectsWrongContainer in a subtest
using t.Run("Should reject when direct_id mismatches", func(t *testing.T) { ...
}) while keeping t.Parallel() and the existing assertions intact; locate the
test function TestValidateNetworkAuditEntryRejectsWrongContainer and move the
current entries setup and the call to validateNetworkAuditEntry (with the
networkAuditExpectation) into the t.Run closure so the test follows the same
subtest pattern used elsewhere in the file.

270-296: ⚡ Quick win

Wrap test body in t.Run("Should ...") for consistency.

This test uses a flat structure while the other tests in this file use t.Run("Should ...") subtests. As per coding guidelines, "MUST use t.Run('Should...') pattern for ALL test cases."

♻️ Proposed fix
 func TestValidateNetworkAuditEntryMatchesDuplicateRejection(t *testing.T) {
 	t.Parallel()
 
+	t.Run("Should match duplicate rejection audit entry", func(t *testing.T) {
+		t.Parallel()
+
 	entries := []store.NetworkAuditEntry{
 		{
 			MessageID: "msg_direct_01",
 			Direction: "rejected",
 			Kind:      "say",
 			Surface:   "direct",
 			DirectID:  "direct_test_01",
 			WorkID:    "work_patch_42",
 			Reason:    "duplicate",
 		},
 	}
 
 	if err := validateNetworkAuditEntry(entries, networkAuditExpectation{
 		MessageID: "msg_direct_01",
 		Direction: "rejected",
 		Kind:      "say",
 		Surface:   "direct",
 		DirectID:  "direct_test_01",
 		WorkID:    "work_patch_42",
 		Reason:    "duplicate",
 	}); err != nil {
 		t.Fatalf("validateNetworkAuditEntry() error = %v", err)
 	}
+	})
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/daemon/network_e2e_assertions_test.go` around lines 270 - 296, Wrap
the test body of TestValidateNetworkAuditEntryMatchesDuplicateRejection in a
t.Run subtest named starting with "Should" (e.g., t.Run("Should validate
duplicate rejection"), func(t *testing.T) { ... }), keeping the existing
t.Parallel() and all existing setup and assertions intact; locate the test by
the function name TestValidateNetworkAuditEntryMatchesDuplicateRejection and
ensure the call to validateNetworkAuditEntry (with the networkAuditExpectation)
remains unchanged inside the t.Run closure.
internal/network/helpers_test.go (1)

307-310: 💤 Low value

Variable name blankDirect is misleading after KindDirect removal.

This test uses KindSay but the variable is named blankDirect, which is confusing given KindDirect was removed from the valid kinds. Consider renaming to reflect what's actually being tested.

Suggested rename
-	blankDirect, err := DecodeBody(KindSay, mustRawJSON(t, map[string]any{"text": "\n"}))
-	if !errors.Is(err, ErrInvalidBody) || blankDirect != nil {
-		t.Fatalf("DecodeBody(blank direct) body = %#v, error = %v, want nil + ErrInvalidBody", blankDirect, err)
+	blankSayNewline, err := DecodeBody(KindSay, mustRawJSON(t, map[string]any{"text": "\n"}))
+	if !errors.Is(err, ErrInvalidBody) || blankSayNewline != nil {
+		t.Fatalf("DecodeBody(blank say newline) body = %#v, error = %v, want nil + ErrInvalidBody", blankSayNewline, err)
	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/network/helpers_test.go` around lines 307 - 310, The variable name
blankDirect is misleading because the test calls DecodeBody with KindSay; rename
the variable to something like blankSay or blankBody to reflect the actual kind
being tested. Update the declaration and all uses of blankDirect in the test
block that calls DecodeBody(KindSay, ...) and keep the error check against
ErrInvalidBody unchanged so the assertion still verifies DecodeBody,
ErrInvalidBody and nil return value for the blank input.
internal/hooks/hooks_test.go (1)

1666-1679: ⚡ Quick win

Split the unmatched compaction path into its own subtest.

This is a second behavior case inside TestDispatchPermissionAndContextHooksApplyPatches; moving it into t.Run("Should leave compaction untouched when no hook matches", ...) will keep failures isolated and match the repo’s Go test conventions.

As per coding guidelines, **/*_test.go: Use t.Run('Should ...') pattern for Go test subtests instead of flat test structures.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/hooks/hooks_test.go` around lines 1666 - 1679, Move the unmatched
compaction verification into its own Go subtest by wrapping the existing
unmatchedPayload block inside t.Run("Should leave compaction untouched when no
hook matches", func(t *testing.T) { ... }), keeping the call to
hooks.DispatchContextPreCompact, error check, and the three assertions
(Reason/Strategy, ContextBlocks length) unchanged; place this t.Run inside
TestDispatchPermissionAndContextHooksApplyPatches so failures are isolated and
follow the repo’s t.Run subtest convention.
internal/extension/manifest_test.go (1)

110-160: ⚡ Quick win

Wrap this new parser scenario in a named subtest.

This new case should follow the repo’s t.Run("Should ...") convention for consistent failure reporting. Keep it serial here, since withDaemonVersion mutates process-wide test state.

As per coding guidelines, "Use t.Run('Should ...') pattern for Go test subtests instead of flat test structures".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/extension/manifest_test.go` around lines 110 - 160, Wrap the
existing TestLoadManifestParsesNetworkHookMatcher body in a named subtest using
t.Run with a "Should ..." description (e.g., t.Run("Should parse network hook
matcher", func(t *testing.T) { ... })), moving the call to withDaemonVersion and
all test logic into that subtest so it runs serially; keep all references to
LoadManifest, manifestTOMLFileName, hookConfigMatcher and the matcher assertions
unchanged but scoped inside the subtest closure to preserve behavior and avoid
parallel execution.
internal/api/httpapi/network_test.go (1)

144-145: 💤 Low value

Consider using newTestRouter for consistency.

This test manually creates a gin.Engine and registers only one route, while other tests in this file use newTestRouter(t, handlers). If the goal is test isolation, this is fine, but using the shared router helper would ensure the handler is wired the same way as production.

♻️ Suggested change for consistency
-		engine := gin.New()
-		engine.GET("/api/network/peers/:peer_id/messages", handlers.NetworkPeerMessages)
+		engine := newTestRouter(t, handlers)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/api/httpapi/network_test.go` around lines 144 - 145, The test
creates a gin.Engine directly and registers only the GET route for
handlers.NetworkPeerMessages instead of using the existing test helper
newTestRouter, leading to inconsistent wiring; replace the manual engine setup
by calling newTestRouter(t, handlers) and use its returned router so the handler
is registered the same way as other tests (or, if isolation is required,
explicitly document why and ensure middleware and group wiring matches
production by mirroring newTestRouter's setup).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/acp/client_test.go`:
- Around line 1094-1125: The TestPromptStopDoesNotEmitRuntimeError function
should be converted to use a t.Run("Should ...") subtest and register guaranteed
cleanup right after the helper process is started: after calling
startHelperProcess(t, driver, "block_prompt_until_cancel", "", StartOpts{})
immediately call t.Cleanup to stop/terminate the proc (e.g., call driver.Stop or
equivalent) to avoid leaking the helper on failures, then keep the existing
logic (Prompt, select, Stop, collectEvents) inside the t.Run body; ensure
references to New(), startHelperProcess, driver.Stop, eventsCh and collectEvents
are preserved and used in the subtest so cleanup always runs even if the test
fails early.

In `@internal/api/core/network_details.go`:
- Around line 1150-1160: summarizeNetworkMessageHistory() currently merges
presence episodes using only channel + peer pair, which collapses pings across
different routing contexts; change the episode grouping key to include routing
metadata Surface, ThreadID, DirectID and WorkID (and keep PeerFrom/PeerTo as
before) so episodes are scoped by surface/thread/direct/work; when merging
choose and preserve the routing fields from the earliest message in the episode
(not the later one) so earlier rows aren't relabeled; apply the same fix to the
other merge/episode-creation sites in this file where similar logic appears (the
nearby presence-merge blocks that handle DisplayName/SessionID/Local/WorkID).

In `@internal/hooks/dispatch_events_test.go`:
- Around line 64-130: Rename the subtest names in the table-driven cases (the
cases slice used by the Test that calls TurnIDFromPayload) from terse labels
like "input" to descriptive "Should ..." phrases (e.g., "Should return turn ID
for input payload") and ensure each subtest goroutine calls t.Parallel() at the
top of the t.Run body unless the subtest intentionally opts out; update the
cases variable entries' name fields and add t.Parallel() inside the anonymous
t.Run closures that invoke TurnIDFromPayload; apply the same change pattern to
the other table-driven subtests in this file that the review references (the
other cases blocks around the file) so all follow the "Should ..." naming and
default to t.Parallel().

In `@internal/hooks/network_dispatch_test.go`:
- Around line 9-86: The test TestDispatchNetworkHooksUseAsyncObservationPayloads
currently asserts all six events in one flat loop; split each event into its own
t.Run subtest (e.g., t.Run(fmt.Sprintf("Should dispatch %s", event.String()),
func(t *testing.T){ ... })) so failures localize. Keep the setup (decls,
executors, hooks, Rebuild) outside the loop, then inside each subtest call the
appropriate dispatch function (DispatchNetworkThreadOpened,
DispatchNetworkDirectRoomOpened, DispatchNetworkMessagePersisted,
DispatchNetworkWorkOpened, DispatchNetworkWorkTransitioned,
DispatchNetworkWorkClosed) using networkDispatchTestPayload(event), and assert
reading from the shared seen channel with the same timeout; run subtests
serially (do not call t.Parallel()) to preserve ordering.

In `@internal/network/manager.go`:
- Around line 1080-1092: The durable delivery path is double-counting and
double-logging because recordSentDelivery and recordReceivedDelivery call both
record*Observed(...) and recordAudit*(...), while
recordAuditSent/recordAuditReceived already increment the same counters and emit
the same logs; update recordSentDelivery and recordReceivedDelivery to call
recordAuditSent/recordAuditReceived only when durable is false (i.e., skip the
audit call for durable deliveries) or alternatively ensure recordAudit* no-ops
when the observed path has already incremented — adjust the logic in
recordSentDelivery, recordReceivedDelivery and mirror the same change in the
other affected block (around the 1351-1393 region) referencing the same
functions so counters/logs are not duplicated.

---

Outside diff comments:
In `@internal/config/hooks.go`:
- Around line 200-239: In toHookMatcher, avoid always allocating
matcher.NetworkMatcher and matcher.CompactionMatcher; instead, only set
matcher.NetworkMatcher to &hookspkg.NetworkMatcher{...} if at least one of
Channel, Surface, Kind, Direction, or WorkState is non-empty (after TrimSpace),
and only set matcher.CompactionMatcher to &hookspkg.CompactionMatcher{...} if
either CompactionReason or CompactionStrategy is non-empty; leave those pointer
fields nil when no related fields are configured so downstream code can rely on
nil meaning "not configured". Use the same trimmed values you already build for
the matcher fields to decide the allocations in parsedHookMatcher.toHookMatcher.

In `@internal/extension/manager.go`:
- Around line 1620-1651: In hookConfigMatcher, avoid always allocating
matcher.NetworkMatcher and matcher.CompactionMatcher; instead check whether any
of the corresponding cfg fields are non-empty and only then create & assign
hookspkg.NetworkMatcher or &hookspkg.CompactionMatcher. Concretely, in
hookConfigMatcher inspect cfg.Channel|Surface|Kind|Direction|WorkState and
create matcher.NetworkMatcher = &hookspkg.NetworkMatcher{...} only if at least
one of those trimmed values is non-empty, and likewise inspect
cfg.CompactionReason|CompactionStrategy and only assign
matcher.CompactionMatcher = &hookspkg.CompactionMatcher{...} when at least one
is non-empty, leaving the pointer nil otherwise (keep existing ToolReadOnly
handling).

In `@internal/network/audit_test.go`:
- Around line 260-275: The subtest "Should return audit write failures" is
missing t.Parallel(), causing inconsistency with sibling subtests; inside the
t.Run block for that test (around the setup using failingAuditStore,
NewAuditWriter and the RecordSent call) add a call to t.Parallel() immediately
after the subtest starts so the subtest runs in parallel with its siblings.

---

Nitpick comments:
In `@internal/api/httpapi/network_test.go`:
- Around line 144-145: The test creates a gin.Engine directly and registers only
the GET route for handlers.NetworkPeerMessages instead of using the existing
test helper newTestRouter, leading to inconsistent wiring; replace the manual
engine setup by calling newTestRouter(t, handlers) and use its returned router
so the handler is registered the same way as other tests (or, if isolation is
required, explicitly document why and ensure middleware and group wiring matches
production by mirroring newTestRouter's setup).

In `@internal/daemon/network_e2e_assertions_test.go`:
- Around line 298-322: Wrap the test body of
TestValidateNetworkAuditEntryRejectsWrongContainer in a subtest using
t.Run("Should reject when direct_id mismatches", func(t *testing.T) { ... })
while keeping t.Parallel() and the existing assertions intact; locate the test
function TestValidateNetworkAuditEntryRejectsWrongContainer and move the current
entries setup and the call to validateNetworkAuditEntry (with the
networkAuditExpectation) into the t.Run closure so the test follows the same
subtest pattern used elsewhere in the file.
- Around line 270-296: Wrap the test body of
TestValidateNetworkAuditEntryMatchesDuplicateRejection in a t.Run subtest named
starting with "Should" (e.g., t.Run("Should validate duplicate rejection"),
func(t *testing.T) { ... }), keeping the existing t.Parallel() and all existing
setup and assertions intact; locate the test by the function name
TestValidateNetworkAuditEntryMatchesDuplicateRejection and ensure the call to
validateNetworkAuditEntry (with the networkAuditExpectation) remains unchanged
inside the t.Run closure.

In `@internal/extension/manifest_test.go`:
- Around line 110-160: Wrap the existing
TestLoadManifestParsesNetworkHookMatcher body in a named subtest using t.Run
with a "Should ..." description (e.g., t.Run("Should parse network hook
matcher", func(t *testing.T) { ... })), moving the call to withDaemonVersion and
all test logic into that subtest so it runs serially; keep all references to
LoadManifest, manifestTOMLFileName, hookConfigMatcher and the matcher assertions
unchanged but scoped inside the subtest closure to preserve behavior and avoid
parallel execution.

In `@internal/hooks/hooks_test.go`:
- Around line 1666-1679: Move the unmatched compaction verification into its own
Go subtest by wrapping the existing unmatchedPayload block inside t.Run("Should
leave compaction untouched when no hook matches", func(t *testing.T) { ... }),
keeping the call to hooks.DispatchContextPreCompact, error check, and the three
assertions (Reason/Strategy, ContextBlocks length) unchanged; place this t.Run
inside TestDispatchPermissionAndContextHooksApplyPatches so failures are
isolated and follow the repo’s t.Run subtest convention.

In `@internal/network/helpers_test.go`:
- Around line 307-310: The variable name blankDirect is misleading because the
test calls DecodeBody with KindSay; rename the variable to something like
blankSay or blankBody to reflect the actual kind being tested. Update the
declaration and all uses of blankDirect in the test block that calls
DecodeBody(KindSay, ...) and keep the error check against ErrInvalidBody
unchanged so the assertion still verifies DecodeBody, ErrInvalidBody and nil
return value for the blank input.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: adfab84c-1898-4635-ad84-d73a589b232f

📥 Commits

Reviewing files that changed from the base of the PR and between f6b7c2d and 8c66377.

⛔ Files ignored due to path filters (33)
  • .compozy/tasks/network-threads/reviews-004/issue_001.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_002.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_003.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_004.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_005.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_006.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_007.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_008.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_009.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_010.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_011.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_012.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_013.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_014.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_015.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_016.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_017.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_018.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_019.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_020.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_021.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_022.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_023.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_024.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_025.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_026.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_027.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_028.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_029.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_030.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-004/issue_031.md is excluded by !**/*.md
  • openapi/agh.json is excluded by !**/*.json
  • web/src/generated/agh-openapi.d.ts is excluded by !**/generated/**
📒 Files selected for processing (27)
  • internal/acp/client.go
  • internal/acp/client_test.go
  • internal/api/core/network.go
  • internal/api/core/network_details.go
  • internal/api/httpapi/network_test.go
  • internal/api/spec/spec.go
  • internal/api/udsapi/agent_channels_test.go
  • internal/api/udsapi/handlers_test.go
  • internal/cli/hooks_test.go
  • internal/config/hooks.go
  • internal/config/hooks_test.go
  • internal/daemon/daemon_acpmock_faults_integration_test.go
  • internal/daemon/network_e2e_assertions_test.go
  • internal/extension/manager.go
  • internal/extension/manifest_test.go
  • internal/hooks/dispatch_events.go
  • internal/hooks/dispatch_events_test.go
  • internal/hooks/hooks_test.go
  • internal/hooks/introspection_test.go
  • internal/hooks/network_dispatch_test.go
  • internal/network/audit_test.go
  • internal/network/helpers_test.go
  • internal/network/manager.go
  • internal/network/manager_test.go
  • internal/network/perf_bench_test.go
  • internal/network/router.go
  • internal/network/router_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/api/udsapi/handlers_test.go

Comment thread internal/acp/client_test.go
Comment thread internal/hooks/dispatch_events_test.go
Comment thread internal/hooks/network_dispatch_test.go
Comment thread internal/network/manager.go
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (5)
internal/hooks/hooks_test.go (1)

1652-1683: 💤 Low value

Add t.Parallel() to subtests for consistency.

Both subtests follow the t.Run("Should ...") naming pattern correctly, but are missing t.Parallel() calls. Other subtests in this file (e.g., lines 664, 844, 1229) include t.Parallel(). The parent test already calls t.Parallel() and the hooks instance is thread-safe.

♻️ Proposed fix
 	t.Run("Should patch context compaction when a hook matches", func(t *testing.T) {
+		t.Parallel()
+
 		contextPayload, err := hooks.DispatchContextPreCompact(t.Context(), ContextPreCompactPayload{
 	t.Run("Should leave compaction untouched when no hook matches", func(t *testing.T) {
+		t.Parallel()
+
 		unmatchedPayload, err := hooks.DispatchContextPreCompact(t.Context(), ContextPreCompactPayload{

As per coding guidelines: "Use t.Run('Should ...') subtests with t.Parallel as default (opt-out with t.Setenv)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/hooks/hooks_test.go` around lines 1652 - 1683, The two subtests that
call hooks.DispatchContextPreCompact (the "Should patch context compaction when
a hook matches" and "Should leave compaction untouched when no hook matches"
t.Run blocks) need to be marked parallel; add t.Parallel() as the first
statement inside each subtest function so they run concurrently with the parent
and other subtests while keeping use of DispatchContextPreCompact,
contextPayload and unmatchedPayload intact.
internal/extension/manifest_test.go (1)

152-160: ⚡ Quick win

Assert nested NetworkMatcher fields directly for stronger regression protection.

The current check validates promoted fields on hookMatcher. Given the pointer-based matcher shape, asserting hookMatcher.NetworkMatcher.<field> directly makes this test stricter and better aligned with the migration intent.

Suggested assertion tightening
-		if hookMatcher.NetworkMatcher == nil ||
-			hookMatcher.Channel != "builders" ||
-			hookMatcher.Surface != "thread" ||
-			hookMatcher.Kind != "trace" ||
-			hookMatcher.Direction != "received" ||
-			hookMatcher.WorkState != "completed" {
+		if hookMatcher.NetworkMatcher == nil ||
+			hookMatcher.NetworkMatcher.Channel != "builders" ||
+			hookMatcher.NetworkMatcher.Surface != "thread" ||
+			hookMatcher.NetworkMatcher.Kind != "trace" ||
+			hookMatcher.NetworkMatcher.Direction != "received" ||
+			hookMatcher.NetworkMatcher.WorkState != "completed" {
 			t.Fatalf("hookConfigMatcher() = %#v, want network matcher fields", hookMatcher)
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/extension/manifest_test.go` around lines 152 - 160, The test is
asserting promoted fields on hookMatcher instead of the nested pointer, so
update the assertions to directly check the NetworkMatcher pointer and its
fields: ensure hookMatcher.NetworkMatcher != nil and then assert
hookMatcher.NetworkMatcher.Channel == "builders",
hookMatcher.NetworkMatcher.Surface == "thread", hookMatcher.NetworkMatcher.Kind
== "trace", hookMatcher.NetworkMatcher.Direction == "received", and
hookMatcher.NetworkMatcher.WorkState == "completed" (all in the
hookConfigMatcher test that calls hookConfigMatcher/matcher).
internal/acp/client_test.go (1)

1097-1123: ⚡ Quick win

Make the subtest parallel and avoid relying on double-stop idempotency

This subtest skips t.Parallel() and currently invokes Stop() both explicitly and again in cleanup. Guarding cleanup after a successful explicit stop makes this test less brittle.

Suggested patch
 t.Run("Should not emit runtime error after explicit stop", func(t *testing.T) {
+	t.Parallel()
+
 	driver := New()
 	proc := startHelperProcess(t, driver, "block_prompt_until_cancel", "", StartOpts{})
 	t.Cleanup(func() {
-		stopProcess(t, driver, proc)
+		if proc != nil {
+			stopProcess(t, driver, proc)
+		}
 	})
@@
 	if err := driver.Stop(testutil.Context(t), proc); err != nil {
 		t.Fatalf("Stop() error = %v", err)
 	}
+	proc = nil
 	for _, event := range collectEvents(t, eventsCh) {
 		if event.Type == EventTypeError {
 			t.Fatalf("prompt events contain %q after explicit stop: %#v", EventTypeError, event)
 		}
 	}
 })

As per coding guidelines, "Default to t.Parallel in Go tests unless there is a specific reason to disable it (opt-out with t.Setenv)."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/acp/client_test.go` around lines 1097 - 1123, Add t.Parallel() at
the top of the subtest, and avoid double-stopping in cleanup by tracking whether
the explicit Stop succeeded; call driver.Stop(testutil.Context(t), proc) as you
do now, set a local flag (e.g., stopped) on success, and change the t.Cleanup
closure that currently calls stopProcess(t, driver, proc) to only call it when
that flag is false. This touches the subtest around New(),
startHelperProcess(...), driver.Stop(...), and the t.Cleanup closure to make the
test parallel-safe and prevent a second stop.
internal/hooks/dispatch_events_test.go (1)

513-574: 💤 Low value

Consider organizing into subtests for better test isolation and failure reporting.

This test covers 9 distinct validation scenarios in a flat structure. While the logic is correct, organizing into t.Run("Should ...") subtests would:

  • Provide clearer failure messages identifying which scenario failed
  • Allow parallel execution of independent scenarios
  • Align with the table-driven pattern used elsewhere in this file

Additionally, the error assertions (lines 523-528, 545-547, 568-573) only check err == nil without validating error content. Consider using errors.Is or checking error messages for more specific assertions.

♻️ Example subtest structure (partial)
 func TestHookTypeValidationBranches(t *testing.T) {
 	t.Parallel()

+	t.Run("Should unmarshal valid HookSource from text", func(t *testing.T) {
+		t.Parallel()
+		var source HookSource
+		if err := source.UnmarshalText([]byte(" config ")); err != nil {
+			t.Fatalf("UnmarshalText(config) error = %v, want nil", err)
+		}
+		if source != HookSourceConfig {
+			t.Fatalf("source = %v, want HookSourceConfig", source)
+		}
+	})
+
+	t.Run("Should reject marshal of invalid HookSource", func(t *testing.T) {
+		t.Parallel()
+		_, err := HookSource(200).MarshalText()
+		if err == nil {
+			t.Fatal("MarshalText(invalid) error = nil, want error")
+		}
+	})
+	// ... additional subtests
 }

As per coding guidelines, "Use t.Run('Should ...') pattern for Go test subtests instead of flat test structures."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/hooks/dispatch_events_test.go` around lines 513 - 574, Split
TestHookTypeValidationBranches into named t.Run subtests for each scenario
(e.g., "Unmarshal valid config", "Marshal invalid source", "Unmarshal unknown
source", "PriorityFromInt valid", "RegisteredHook validate sync/required",
"ResolvedHook validate name mismatch", "ResolvedHook nil validate", etc.) and
call t.Parallel() inside subtests where they are independent; keep the same
setup code but move each assertion into its corresponding subtest. Replace bare
err==nil checks with stronger assertions using errors.Is or comparing
err.Error()/strings.Contains to expected error values/messages for the
UnmarshalText/MarshalText, RegisteredHook.Validate and ResolvedHook.Validate
failure checks, and reference the exact symbols from the diff (UnmarshalText,
MarshalText, PriorityFromInt, RegisteredHook.Validate, ResolvedHook.Validate,
NewTypedNativeExecutor) so reviewers can locate the code. Ensure test names are
descriptive so failures show which case failed.
internal/network/helpers_test.go (1)

214-248: ⚡ Quick win

Cover the remaining terminal work states in the transition matrix.

This matrix only pins completed as terminal. failed and canceled are part of the new lifecycle too, so regressions like failed -> working would currently slip through.

Suggested matrix additions
 		{name: "ShouldAllowNeedsInputToWorking", current: WorkStateNeedsInput, next: WorkStateWorking, want: true},
 		{name: "ShouldAllowNeedsInputToCanceled", current: WorkStateNeedsInput, next: WorkStateCanceled, want: true},
 		{name: "ShouldRejectCompletedToWorking", current: WorkStateCompleted, next: WorkStateWorking, want: false},
+		{name: "ShouldRejectFailedToWorking", current: WorkStateFailed, next: WorkStateWorking, want: false},
+		{name: "ShouldRejectCanceledToCompleted", current: WorkStateCanceled, next: WorkStateCompleted, want: false},
 	}

As per coding guidelines, **/*_test.go: Focus on critical paths: workflow execution, state management, error handling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/network/helpers_test.go` around lines 214 - 248, The test matrix in
helpers_test.go currently treats only Completed as a terminal state; add test
rows covering the other terminal states (WorkStateFailed and WorkStateCanceled)
to ensure transitions like failed->working and canceled->working are rejected.
Specifically, add entries such as "ShouldRejectFailedToWorking",
"ShouldRejectCanceledToWorking", "ShouldRejectFailedToSubmitted", and
"ShouldRejectCanceledToSubmitted" with current set to WorkStateFailed or
WorkStateCanceled, next set to WorkStateWorking or WorkStateSubmitted, and
want=false, so the existing assertions around canApplyTrace and
ValidateWorkTransition (the functions named canApplyTrace and
ValidateWorkTransition) will catch regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/api/core/network_details.go`:
- Around line 1154-1164: The visibility logic currently only checks PeerTo
inside isDirectedChannelMessage(), so messages with Surface == "direct" or a
non-empty DirectID are misclassified; update isDirectedChannelMessage() (and any
similar directed-message checks used elsewhere) to also treat entries as
directed when entry.Surface equals the SurfaceDirect value (or literal "direct")
or when entry.DirectID is non-empty/trimmed, and ensure the same change is
applied to the parallel check used around the other mapping path noted (the
second occurrence that mirrors isDirectedChannelMessage()). Trim whitespace when
reading Surface/DirectID to match the struct population.

In `@internal/daemon/network_e2e_assertions_test.go`:
- Around line 152-158: optionalAuditFieldMatches currently treats an empty want
string as “don't care,” which prevents tests from asserting that routing fields
must be absent; change the function signature (optionalAuditFieldMatches) to use
a tri-state expectation—e.g. accept a *string (nil = ignore, pointer to "" =
must be empty, pointer to "X" = must equal) or add an explicit check flag
alongside the desired string—then implement logic to: return true when want is
nil (ignore), return true only if strings.TrimSpace(got) == "" when want points
to "", and otherwise compare trimmed values; update all callers to pass nil/ptr
values (or the flag) so tests can distinguish ignore vs must-be-empty vs
must-equal.

In `@internal/network/helpers_test.go`:
- Around line 210-212: The test currently asserts
OpenWork(withDirectSurface(openErrEnv), ...) returns ErrInvalidField, but this
case represents an actor/permission mismatch; update the assertion to expect the
actor-mismatch sentinel instead (use errors.Is(err, ErrActorMismatch) or the
project's defined ErrActorMismatch constant) when calling OpenWork with
withDirectSurface(openErrEnv) and time.Time{}; keep the rest of the call
(OpenWork, withDirectSurface, openErrEnv) unchanged so callers can distinguish
actor-mismatch from field-validation errors.

---

Nitpick comments:
In `@internal/acp/client_test.go`:
- Around line 1097-1123: Add t.Parallel() at the top of the subtest, and avoid
double-stopping in cleanup by tracking whether the explicit Stop succeeded; call
driver.Stop(testutil.Context(t), proc) as you do now, set a local flag (e.g.,
stopped) on success, and change the t.Cleanup closure that currently calls
stopProcess(t, driver, proc) to only call it when that flag is false. This
touches the subtest around New(), startHelperProcess(...), driver.Stop(...), and
the t.Cleanup closure to make the test parallel-safe and prevent a second stop.

In `@internal/extension/manifest_test.go`:
- Around line 152-160: The test is asserting promoted fields on hookMatcher
instead of the nested pointer, so update the assertions to directly check the
NetworkMatcher pointer and its fields: ensure hookMatcher.NetworkMatcher != nil
and then assert hookMatcher.NetworkMatcher.Channel == "builders",
hookMatcher.NetworkMatcher.Surface == "thread", hookMatcher.NetworkMatcher.Kind
== "trace", hookMatcher.NetworkMatcher.Direction == "received", and
hookMatcher.NetworkMatcher.WorkState == "completed" (all in the
hookConfigMatcher test that calls hookConfigMatcher/matcher).

In `@internal/hooks/dispatch_events_test.go`:
- Around line 513-574: Split TestHookTypeValidationBranches into named t.Run
subtests for each scenario (e.g., "Unmarshal valid config", "Marshal invalid
source", "Unmarshal unknown source", "PriorityFromInt valid", "RegisteredHook
validate sync/required", "ResolvedHook validate name mismatch", "ResolvedHook
nil validate", etc.) and call t.Parallel() inside subtests where they are
independent; keep the same setup code but move each assertion into its
corresponding subtest. Replace bare err==nil checks with stronger assertions
using errors.Is or comparing err.Error()/strings.Contains to expected error
values/messages for the UnmarshalText/MarshalText, RegisteredHook.Validate and
ResolvedHook.Validate failure checks, and reference the exact symbols from the
diff (UnmarshalText, MarshalText, PriorityFromInt, RegisteredHook.Validate,
ResolvedHook.Validate, NewTypedNativeExecutor) so reviewers can locate the code.
Ensure test names are descriptive so failures show which case failed.

In `@internal/hooks/hooks_test.go`:
- Around line 1652-1683: The two subtests that call
hooks.DispatchContextPreCompact (the "Should patch context compaction when a
hook matches" and "Should leave compaction untouched when no hook matches" t.Run
blocks) need to be marked parallel; add t.Parallel() as the first statement
inside each subtest function so they run concurrently with the parent and other
subtests while keeping use of DispatchContextPreCompact, contextPayload and
unmatchedPayload intact.

In `@internal/network/helpers_test.go`:
- Around line 214-248: The test matrix in helpers_test.go currently treats only
Completed as a terminal state; add test rows covering the other terminal states
(WorkStateFailed and WorkStateCanceled) to ensure transitions like
failed->working and canceled->working are rejected. Specifically, add entries
such as "ShouldRejectFailedToWorking", "ShouldRejectCanceledToWorking",
"ShouldRejectFailedToSubmitted", and "ShouldRejectCanceledToSubmitted" with
current set to WorkStateFailed or WorkStateCanceled, next set to
WorkStateWorking or WorkStateSubmitted, and want=false, so the existing
assertions around canApplyTrace and ValidateWorkTransition (the functions named
canApplyTrace and ValidateWorkTransition) will catch regressions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6eae0c68-2c8d-4d46-bf6a-9e6e8eb355bf

📥 Commits

Reviewing files that changed from the base of the PR and between 8c66377 and 5b6dadf.

⛔ Files ignored due to path filters (11)
  • .compozy/tasks/network-threads/reviews-005/issue_001.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-005/issue_002.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-005/issue_003.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-005/issue_004.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-005/issue_005.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-005/issue_006.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-005/issue_007.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-005/issue_008.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-005/issue_009.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-005/issue_010.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-005/issue_011.md is excluded by !**/*.md
📒 Files selected for processing (11)
  • internal/acp/client_test.go
  • internal/api/core/network_details.go
  • internal/api/httpapi/network_test.go
  • internal/daemon/network_e2e_assertions_test.go
  • internal/extension/manifest_test.go
  • internal/hooks/dispatch_events_test.go
  • internal/hooks/hooks_test.go
  • internal/hooks/network_dispatch_test.go
  • internal/network/helpers_test.go
  • internal/network/manager.go
  • internal/network/manager_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/api/httpapi/network_test.go

Comment thread internal/api/core/network_details.go
Comment thread internal/daemon/network_e2e_assertions_test.go Outdated
Comment thread internal/network/helpers_test.go
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
internal/acp/client_test.go (1)

1094-1135: 💤 Low value

Add t.Parallel() inside the subtest for consistency.

The subtest is missing t.Parallel() which other subtests in this file include (e.g., lines 363-364). This should be added unless there's a specific reason to run sequentially.

Suggested fix
 	t.Run("Should not emit runtime error after explicit stop", func(t *testing.T) {
+		t.Parallel()
+
 		driver := New()

As per coding guidelines, "Default to t.Parallel in Go tests unless there is a specific reason to disable it (opt-out with t.Setenv)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/acp/client_test.go` around lines 1094 - 1135, The subtest inside
TestPromptStopDoesNotEmitRuntimeError (the t.Run with name "Should not emit
runtime error after explicit stop") is missing t.Parallel(); add a call to
t.Parallel() as the first statement inside that subtest function to match other
tests' parallelization (or explicitly opt out only if you need to use t.Setenv
or require sequential execution). This ensures the subtest runs in parallel like
the rest of the file.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/daemon/network_e2e_assertions_test.go`:
- Around line 26-37: The test helper networkAuditExpectation struct omits the
ReplyTo, TraceID and CausationID fields that the audit persistence code
(functions that set ReplyTo/TraceID/CausationID) writes, so extend the
networkAuditExpectation type to include pointer/string fields for ReplyTo,
TraceID and CausationID and update the assertion logic that compares actual
persisted audit records (the helper assertions referenced around the existing
checks at 84-92 and 114-149) to compare those new fields as well (treat nil vs
empty appropriately), ensuring the tests fail if durable audit persistence stops
storing these correlation keys.
- Around line 247-283: The negative test fixture doesn't provide routing
attributes in any single message/audit row so a buggy
validateNetworkCorrelationSurfaces can pass by aggregating across messages;
update the test data (the messages slice, audit slice, and the
networkCorrelationExpectation) so at least one transcript UIMessage contains the
explicit attributes surface, direct-id, causation-id and trust (e.g., add
attributes to the first messages[0].Parts[0].Text or include them as metadata in
that message), and ensure the audit entries include the corresponding routing
fields for the same MessageID (e.g., add audit rows with
DirectID/WorkID/TraceID/CausationID or the appropriate fields matching
"msg_direct_01"), so the negative case truly verifies that
validateNetworkCorrelationSurfaces (and the networkCorrelationExpectation) does
not succeed by combining attributes from multiple messages.

---

Nitpick comments:
In `@internal/acp/client_test.go`:
- Around line 1094-1135: The subtest inside
TestPromptStopDoesNotEmitRuntimeError (the t.Run with name "Should not emit
runtime error after explicit stop") is missing t.Parallel(); add a call to
t.Parallel() as the first statement inside that subtest function to match other
tests' parallelization (or explicitly opt out only if you need to use t.Setenv
or require sequential execution). This ensures the subtest runs in parallel like
the rest of the file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8a1e5a10-db54-4095-8fa3-d54b758157fb

📥 Commits

Reviewing files that changed from the base of the PR and between 5b6dadf and aea75b1.

⛔ Files ignored due to path filters (8)
  • .compozy/tasks/network-threads/reviews-006/issue_001.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-006/issue_002.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-006/issue_003.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-006/issue_004.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-006/issue_005.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-006/issue_006.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-006/issue_007.md is excluded by !**/*.md
  • .compozy/tasks/network-threads/reviews-006/issue_008.md is excluded by !**/*.md
📒 Files selected for processing (6)
  • internal/acp/client_test.go
  • internal/api/core/network_details.go
  • internal/daemon/network_e2e_assertions_test.go
  • internal/hooks/dispatch_events_test.go
  • internal/hooks/hooks_test.go
  • internal/network/helpers_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/hooks/dispatch_events_test.go

Comment thread internal/daemon/network_e2e_assertions_test.go
Comment thread internal/daemon/network_e2e_assertions_test.go
@pedronauck pedronauck merged commit 0b371ea into main May 6, 2026
6 of 8 checks passed
@pedronauck pedronauck deleted the networkthreads branch May 6, 2026 04:01
pedronauck added a commit that referenced this pull request May 26, 2026
## Release v0.0.1

This PR prepares the release of version v0.0.1.

### Changelog

## 0.0.1 - 2026-05-26



### Other Changes

- Lessons learned



### ♻️ Refactoring

- Project structure (#7)
- Kb improvements (#12)
- Rename spaces to channels (#17)
- Add extensions gaps (#21)
- Improve tool calls ui (#22)
- Remove web app header
- Module improvements (#29)
- Memory improvements (#35)
- Storybook for web and ui (#38)
- Enable AGH network by default for new installs (#57)
- Hermes adjustments (#69)
- Badges design (#84)
- Storybook scenario and logos gallery
- Migrate typescript tests (#114)
- Internal go packages (#120)
- Ui patterns (#127)
- Improve e2e tests (#130)
- Ui redesign
- Workspace isolation across runtime surfaces (#145)
- Prod ready applies (#162)
- Tool card ui (#164)
- Alpha on logo
- Prod ready features (#167)
- Thread sheet (#202)



### 🎉 Features

- Implement config foundation packages
- Implement sqlite store package
- Add ACP client package
- Add session lifecycle manager
- Implement observe package
- Add daemon composition root
- Add uds api server
- Implement cli package
- Add http api server
- Add system design
- Add foundation types, schemas, and layout shell for web client
- Add daemon health polling and agent sidebar systems for web client
- Add session system CRUD, streaming core, and session store for web
client
- Add chat view, messages, and composer tests for web client
- Add tool cards and renderers for web client
- Add file-backed memory store core
- Scaffold memory session seams
- Add memory dream consolidation service
- Wire memory assembler into daemon
- Add memory api and cli
- New skills system (#1)
- Add workspace entity (#5)
- Add new skill capabilities (#8)
- Web ui v2 (#9)
- Improve hooks system (#10)
- Session resilience (#11)
- Add extensability (#13)
- Add automation (#16)
- Add channels (#14)
- Add network implementation (#15)
- Add network, bridges and automations web pages (#18)
- Ext registry (#20)
- Add core tasks (#19)
- Bridge adapters (#23)
- Add site (#26)
- Add ext refac and sandbox (#25)
- Settings ui (#37)
- Tasks ui (#36)
- Harness improvements (#44)
- Agent capabilities (#49)
- Redesign ui (#48)
- Unify capability (#53)
- Redesign network workspace (#59)
- Add task deletion and split session delete from stop (#58)
- Session provider selection (#60)
- Production grade adjustments (#66)
- Autonomous system (#75)
- Add agent session route (#80)
- Tools registry (#85)
- Agents soul (#88)
- Add network threads (#105)
- Orchestration improvements (#106)
- Memory v2 (#108)
- Agent categories (#113)
- Providers model (#118)
- Add canonical AGH bundled skill (#143)
- Onboarding and improvements (#198)
- Onboarding and improvements (#201)



### 🐛 Bug Fixes

- Review round
- Review rounds
- Resolve memory extensibility review batch
- Embed web into daemon
- Defaults agents
- Acp integration (#4)
- Lint errors
- Prd folder
- Remove orphan web actions and dead surfaces (#55)
- Qa testing and fixes (#73)
- New review rounds (#82)
- Security audit (#90)
- Release qa round (#95)
- Add missing tools (#141)
- New qa round (#147)
- Advanced qa round (#149)
- Homebrew tap
- Final review round (#151)
- Daemon healthy
- Reasoning models (#158)
- Lint errors (#160)
- Review round (#168)
- Release adjustments (#171)
- Stabilize release ci fixtures
- Stabilize release integration gate
- Stabilize release verify gates
- Stabilize release integration flows
- Stabilize release verify gates
- Stabilize main verify shutdown
- Ignore stale acpmock cancel
- Marketplace search focus and filtering (#193)
- Website video
- Workspace command select



### 📚 Documentation

- Update agents.md
- Update prd
- Update skills
- Update compozy tasks
- Update compozy
- Update compozy
- Add new skills
- Archive prd
- Update prds
- Update rfc
- Update prds
- Update prds
- Add automation prd
- Channels prd
- Update prd
- Update prd
- New prds
- Archive prds
- Bridges adapters prd
- Sandbox prd
- Update
- Archive prd
- Update
- Add new prd
- New design
- Update prd
- Archive prds
- Update prds
- Tasks-ui prd tasks
- Update prd
- Update design docs
- Agent capabilities prd
- Improve site docs
- Remove old design references
- Udpate
- Autonomous prd
- Update skills
- Blog design
- Agent sould prd
- Final qa plan
- Update
- Remove codex ledgers from gitignore
- Remove not needed files
- Udpate ledger
- Update cy-codex-loop skill
- Orchestration improves prd
- Update prds
- Orch improvs prd
- Memv2 prd
- Providers model prd
- Update refacs prd
- New design proposal
- Update rules
- Update skills
- New blog posts (#173)
- Format docs
- Remove old design files
- Remove old
- Skeeper update



### 📦 Build System

- Initial structure
- Commitlint
- Frontend base structure
- Update vscode settings
- Add subagents
- Coderabbit
- Prd and tooling
- Bun lock
- Lint tooling
- Copy.md and tooling adjusts
- Add repoclone rc
- Upgrade skeeper to v0.2.0
- Update go.mod
- Adopt task artifacts into skeeper
- Sync codex plans with skeeper
- Skeeper lock
- Skeeper lock
- New skills
- Skeeper lock
- Skeeper lock
- Skeeper lock
- Update deps and go
- Regenerate daytona sidecar assets for go 1.26.3
- Fix cliff
- Ignore docs on fmt
- Build web assets before goreleaser
- Extend release dry-run timeout



### 🔧 CI/CD

- Lint errors
- Fint release pr
- Fix goreleaser



### 🧪 Testing

- Add e2e tests (#27)
- Qa rounds (#78)
- Improve test suite (#138)
- Harden daemon-served restart reloads
- Harden daemon-served readiness waits
- Stabilize dashboard focus assertion
- Stabilize release integration gates
- Stabilize release e2e markers
- Stabilize release e2e flows

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This was referenced May 26, 2026
pedronauck added a commit that referenced this pull request May 26, 2026
## Release v0.0.1

This PR prepares the release of version v0.0.1.

### Changelog

## 0.0.1 - 2026-05-26



### Other Changes

- Lessons learned



### ♻️ Refactoring

- Project structure (#7)
- Kb improvements (#12)
- Rename spaces to channels (#17)
- Add extensions gaps (#21)
- Improve tool calls ui (#22)
- Remove web app header
- Module improvements (#29)
- Memory improvements (#35)
- Storybook for web and ui (#38)
- Enable AGH network by default for new installs (#57)
- Hermes adjustments (#69)
- Badges design (#84)
- Storybook scenario and logos gallery
- Migrate typescript tests (#114)
- Internal go packages (#120)
- Ui patterns (#127)
- Improve e2e tests (#130)
- Ui redesign
- Workspace isolation across runtime surfaces (#145)
- Prod ready applies (#162)
- Tool card ui (#164)
- Alpha on logo
- Prod ready features (#167)
- Thread sheet (#202)



### 🎉 Features

- Implement config foundation packages
- Implement sqlite store package
- Add ACP client package
- Add session lifecycle manager
- Implement observe package
- Add daemon composition root
- Add uds api server
- Implement cli package
- Add http api server
- Add system design
- Add foundation types, schemas, and layout shell for web client
- Add daemon health polling and agent sidebar systems for web client
- Add session system CRUD, streaming core, and session store for web
client
- Add chat view, messages, and composer tests for web client
- Add tool cards and renderers for web client
- Add file-backed memory store core
- Scaffold memory session seams
- Add memory dream consolidation service
- Wire memory assembler into daemon
- Add memory api and cli
- New skills system (#1)
- Add workspace entity (#5)
- Add new skill capabilities (#8)
- Web ui v2 (#9)
- Improve hooks system (#10)
- Session resilience (#11)
- Add extensability (#13)
- Add automation (#16)
- Add channels (#14)
- Add network implementation (#15)
- Add network, bridges and automations web pages (#18)
- Ext registry (#20)
- Add core tasks (#19)
- Bridge adapters (#23)
- Add site (#26)
- Add ext refac and sandbox (#25)
- Settings ui (#37)
- Tasks ui (#36)
- Harness improvements (#44)
- Agent capabilities (#49)
- Redesign ui (#48)
- Unify capability (#53)
- Redesign network workspace (#59)
- Add task deletion and split session delete from stop (#58)
- Session provider selection (#60)
- Production grade adjustments (#66)
- Autonomous system (#75)
- Add agent session route (#80)
- Tools registry (#85)
- Agents soul (#88)
- Add network threads (#105)
- Orchestration improvements (#106)
- Memory v2 (#108)
- Agent categories (#113)
- Providers model (#118)
- Add canonical AGH bundled skill (#143)
- Onboarding and improvements (#198)
- Onboarding and improvements (#201)



### 🐛 Bug Fixes

- Review round
- Review rounds
- Resolve memory extensibility review batch
- Embed web into daemon
- Defaults agents
- Acp integration (#4)
- Lint errors
- Prd folder
- Remove orphan web actions and dead surfaces (#55)
- Qa testing and fixes (#73)
- New review rounds (#82)
- Security audit (#90)
- Release qa round (#95)
- Add missing tools (#141)
- New qa round (#147)
- Advanced qa round (#149)
- Homebrew tap
- Final review round (#151)
- Daemon healthy
- Reasoning models (#158)
- Lint errors (#160)
- Review round (#168)
- Release adjustments (#171)
- Stabilize release ci fixtures
- Stabilize release integration gate
- Stabilize release verify gates
- Stabilize release integration flows
- Stabilize release verify gates
- Stabilize main verify shutdown
- Ignore stale acpmock cancel
- Marketplace search focus and filtering (#193)
- Website video
- Workspace command select



### 📚 Documentation

- Update agents.md
- Update prd
- Update skills
- Update compozy tasks
- Update compozy
- Update compozy
- Add new skills
- Archive prd
- Update prds
- Update rfc
- Update prds
- Update prds
- Add automation prd
- Channels prd
- Update prd
- Update prd
- New prds
- Archive prds
- Bridges adapters prd
- Sandbox prd
- Update
- Archive prd
- Update
- Add new prd
- New design
- Update prd
- Archive prds
- Update prds
- Tasks-ui prd tasks
- Update prd
- Update design docs
- Agent capabilities prd
- Improve site docs
- Remove old design references
- Udpate
- Autonomous prd
- Update skills
- Blog design
- Agent sould prd
- Final qa plan
- Update
- Remove codex ledgers from gitignore
- Remove not needed files
- Udpate ledger
- Update cy-codex-loop skill
- Orchestration improves prd
- Update prds
- Orch improvs prd
- Memv2 prd
- Providers model prd
- Update refacs prd
- New design proposal
- Update rules
- Update skills
- New blog posts (#173)
- Format docs
- Remove old design files
- Remove old
- Skeeper update



### 📦 Build System

- Initial structure
- Commitlint
- Frontend base structure
- Update vscode settings
- Add subagents
- Coderabbit
- Prd and tooling
- Bun lock
- Lint tooling
- Copy.md and tooling adjusts
- Add repoclone rc
- Upgrade skeeper to v0.2.0
- Update go.mod
- Adopt task artifacts into skeeper
- Sync codex plans with skeeper
- Skeeper lock
- Skeeper lock
- New skills
- Skeeper lock
- Skeeper lock
- Skeeper lock
- Update deps and go
- Regenerate daytona sidecar assets for go 1.26.3
- Fix cliff
- Ignore docs on fmt
- Build web assets before goreleaser
- Extend release dry-run timeout



### 🔧 CI/CD

- Lint errors
- Fint release pr
- Fix goreleaser
- Fix release



### 🧪 Testing

- Add e2e tests (#27)
- Qa rounds (#78)
- Improve test suite (#138)
- Harden daemon-served restart reloads
- Harden daemon-served readiness waits
- Stabilize dashboard focus assertion
- Stabilize release integration gates
- Stabilize release e2e markers
- Stabilize release e2e flows

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
pedronauck added a commit that referenced this pull request May 26, 2026
## Release v0.0.2

This PR prepares the release of version v0.0.2.

### Changelog

## 0.0.2 - 2026-05-26



### Other Changes

- Lessons learned



### ♻️ Refactoring

- Project structure (#7)
- Kb improvements (#12)
- Rename spaces to channels (#17)
- Add extensions gaps (#21)
- Improve tool calls ui (#22)
- Remove web app header
- Module improvements (#29)
- Memory improvements (#35)
- Storybook for web and ui (#38)
- Enable AGH network by default for new installs (#57)
- Hermes adjustments (#69)
- Badges design (#84)
- Storybook scenario and logos gallery
- Migrate typescript tests (#114)
- Internal go packages (#120)
- Ui patterns (#127)
- Improve e2e tests (#130)
- Ui redesign
- Workspace isolation across runtime surfaces (#145)
- Prod ready applies (#162)
- Tool card ui (#164)
- Alpha on logo
- Prod ready features (#167)
- Thread sheet (#202)



### 🎉 Features

- Implement config foundation packages
- Implement sqlite store package
- Add ACP client package
- Add session lifecycle manager
- Implement observe package
- Add daemon composition root
- Add uds api server
- Implement cli package
- Add http api server
- Add system design
- Add foundation types, schemas, and layout shell for web client
- Add daemon health polling and agent sidebar systems for web client
- Add session system CRUD, streaming core, and session store for web
client
- Add chat view, messages, and composer tests for web client
- Add tool cards and renderers for web client
- Add file-backed memory store core
- Scaffold memory session seams
- Add memory dream consolidation service
- Wire memory assembler into daemon
- Add memory api and cli
- New skills system (#1)
- Add workspace entity (#5)
- Add new skill capabilities (#8)
- Web ui v2 (#9)
- Improve hooks system (#10)
- Session resilience (#11)
- Add extensability (#13)
- Add automation (#16)
- Add channels (#14)
- Add network implementation (#15)
- Add network, bridges and automations web pages (#18)
- Ext registry (#20)
- Add core tasks (#19)
- Bridge adapters (#23)
- Add site (#26)
- Add ext refac and sandbox (#25)
- Settings ui (#37)
- Tasks ui (#36)
- Harness improvements (#44)
- Agent capabilities (#49)
- Redesign ui (#48)
- Unify capability (#53)
- Redesign network workspace (#59)
- Add task deletion and split session delete from stop (#58)
- Session provider selection (#60)
- Production grade adjustments (#66)
- Autonomous system (#75)
- Add agent session route (#80)
- Tools registry (#85)
- Agents soul (#88)
- Add network threads (#105)
- Orchestration improvements (#106)
- Memory v2 (#108)
- Agent categories (#113)
- Providers model (#118)
- Add canonical AGH bundled skill (#143)
- Onboarding and improvements (#198)
- Onboarding and improvements (#201)



### 🐛 Bug Fixes

- Review round
- Review rounds
- Resolve memory extensibility review batch
- Embed web into daemon
- Defaults agents
- Acp integration (#4)
- Lint errors
- Prd folder
- Remove orphan web actions and dead surfaces (#55)
- Qa testing and fixes (#73)
- New review rounds (#82)
- Security audit (#90)
- Release qa round (#95)
- Add missing tools (#141)
- New qa round (#147)
- Advanced qa round (#149)
- Homebrew tap
- Final review round (#151)
- Daemon healthy
- Reasoning models (#158)
- Lint errors (#160)
- Review round (#168)
- Release adjustments (#171)
- Stabilize release ci fixtures
- Stabilize release integration gate
- Stabilize release verify gates
- Stabilize release integration flows
- Stabilize release verify gates
- Stabilize main verify shutdown
- Ignore stale acpmock cancel
- Marketplace search focus and filtering (#193)
- Website video
- Workspace command select



### 📚 Documentation

- Update agents.md
- Update prd
- Update skills
- Update compozy tasks
- Update compozy
- Update compozy
- Add new skills
- Archive prd
- Update prds
- Update rfc
- Update prds
- Update prds
- Add automation prd
- Channels prd
- Update prd
- Update prd
- New prds
- Archive prds
- Bridges adapters prd
- Sandbox prd
- Update
- Archive prd
- Update
- Add new prd
- New design
- Update prd
- Archive prds
- Update prds
- Tasks-ui prd tasks
- Update prd
- Update design docs
- Agent capabilities prd
- Improve site docs
- Remove old design references
- Udpate
- Autonomous prd
- Update skills
- Blog design
- Agent sould prd
- Final qa plan
- Update
- Remove codex ledgers from gitignore
- Remove not needed files
- Udpate ledger
- Update cy-codex-loop skill
- Orchestration improves prd
- Update prds
- Orch improvs prd
- Memv2 prd
- Providers model prd
- Update refacs prd
- New design proposal
- Update rules
- Update skills
- New blog posts (#173)
- Format docs
- Remove old design files
- Remove old
- Skeeper update



### 📦 Build System

- Initial structure
- Commitlint
- Frontend base structure
- Update vscode settings
- Add subagents
- Coderabbit
- Prd and tooling
- Bun lock
- Lint tooling
- Copy.md and tooling adjusts
- Add repoclone rc
- Upgrade skeeper to v0.2.0
- Update go.mod
- Adopt task artifacts into skeeper
- Sync codex plans with skeeper
- Skeeper lock
- Skeeper lock
- New skills
- Skeeper lock
- Skeeper lock
- Skeeper lock
- Update deps and go
- Regenerate daytona sidecar assets for go 1.26.3
- Fix cliff
- Ignore docs on fmt
- Build web assets before goreleaser
- Extend release dry-run timeout



### 🔧 CI/CD

- Lint errors
- Fint release pr
- Fix goreleaser
- Fix release
- Fix release process



### 🧪 Testing

- Add e2e tests (#27)
- Qa rounds (#78)
- Improve test suite (#138)
- Harden daemon-served restart reloads
- Harden daemon-served readiness waits
- Stabilize dashboard focus assertion
- Stabilize release integration gates
- Stabilize release e2e markers
- Stabilize release e2e flows
- Improve suite speed

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
pedronauck added a commit that referenced this pull request May 27, 2026
## Release v0.0.2

This PR prepares the release of version v0.0.2.

### Changelog

## 0.0.2 - 2026-05-26



### Other Changes

- Lessons learned



### ♻️ Refactoring

- Project structure (#7)
- Kb improvements (#12)
- Rename spaces to channels (#17)
- Add extensions gaps (#21)
- Improve tool calls ui (#22)
- Remove web app header
- Module improvements (#29)
- Memory improvements (#35)
- Storybook for web and ui (#38)
- Enable AGH network by default for new installs (#57)
- Hermes adjustments (#69)
- Badges design (#84)
- Storybook scenario and logos gallery
- Migrate typescript tests (#114)
- Internal go packages (#120)
- Ui patterns (#127)
- Improve e2e tests (#130)
- Ui redesign
- Workspace isolation across runtime surfaces (#145)
- Prod ready applies (#162)
- Tool card ui (#164)
- Alpha on logo
- Prod ready features (#167)
- Thread sheet (#202)



### 🎉 Features

- Implement config foundation packages
- Implement sqlite store package
- Add ACP client package
- Add session lifecycle manager
- Implement observe package
- Add daemon composition root
- Add uds api server
- Implement cli package
- Add http api server
- Add system design
- Add foundation types, schemas, and layout shell for web client
- Add daemon health polling and agent sidebar systems for web client
- Add session system CRUD, streaming core, and session store for web
client
- Add chat view, messages, and composer tests for web client
- Add tool cards and renderers for web client
- Add file-backed memory store core
- Scaffold memory session seams
- Add memory dream consolidation service
- Wire memory assembler into daemon
- Add memory api and cli
- New skills system (#1)
- Add workspace entity (#5)
- Add new skill capabilities (#8)
- Web ui v2 (#9)
- Improve hooks system (#10)
- Session resilience (#11)
- Add extensability (#13)
- Add automation (#16)
- Add channels (#14)
- Add network implementation (#15)
- Add network, bridges and automations web pages (#18)
- Ext registry (#20)
- Add core tasks (#19)
- Bridge adapters (#23)
- Add site (#26)
- Add ext refac and sandbox (#25)
- Settings ui (#37)
- Tasks ui (#36)
- Harness improvements (#44)
- Agent capabilities (#49)
- Redesign ui (#48)
- Unify capability (#53)
- Redesign network workspace (#59)
- Add task deletion and split session delete from stop (#58)
- Session provider selection (#60)
- Production grade adjustments (#66)
- Autonomous system (#75)
- Add agent session route (#80)
- Tools registry (#85)
- Agents soul (#88)
- Add network threads (#105)
- Orchestration improvements (#106)
- Memory v2 (#108)
- Agent categories (#113)
- Providers model (#118)
- Add canonical AGH bundled skill (#143)
- Onboarding and improvements (#198)
- Onboarding and improvements (#201)



### 🐛 Bug Fixes

- Review round
- Review rounds
- Resolve memory extensibility review batch
- Embed web into daemon
- Defaults agents
- Acp integration (#4)
- Lint errors
- Prd folder
- Remove orphan web actions and dead surfaces (#55)
- Qa testing and fixes (#73)
- New review rounds (#82)
- Security audit (#90)
- Release qa round (#95)
- Add missing tools (#141)
- New qa round (#147)
- Advanced qa round (#149)
- Homebrew tap
- Final review round (#151)
- Daemon healthy
- Reasoning models (#158)
- Lint errors (#160)
- Review round (#168)
- Release adjustments (#171)
- Stabilize release ci fixtures
- Stabilize release integration gate
- Stabilize release verify gates
- Stabilize release integration flows
- Stabilize release verify gates
- Stabilize main verify shutdown
- Ignore stale acpmock cancel
- Marketplace search focus and filtering (#193)
- Website video
- Workspace command select



### 📚 Documentation

- Update agents.md
- Update prd
- Update skills
- Update compozy tasks
- Update compozy
- Update compozy
- Add new skills
- Archive prd
- Update prds
- Update rfc
- Update prds
- Update prds
- Add automation prd
- Channels prd
- Update prd
- Update prd
- New prds
- Archive prds
- Bridges adapters prd
- Sandbox prd
- Update
- Archive prd
- Update
- Add new prd
- New design
- Update prd
- Archive prds
- Update prds
- Tasks-ui prd tasks
- Update prd
- Update design docs
- Agent capabilities prd
- Improve site docs
- Remove old design references
- Udpate
- Autonomous prd
- Update skills
- Blog design
- Agent sould prd
- Final qa plan
- Update
- Remove codex ledgers from gitignore
- Remove not needed files
- Udpate ledger
- Update cy-codex-loop skill
- Orchestration improves prd
- Update prds
- Orch improvs prd
- Memv2 prd
- Providers model prd
- Update refacs prd
- New design proposal
- Update rules
- Update skills
- New blog posts (#173)
- Format docs
- Remove old design files
- Remove old
- Skeeper update



### 📦 Build System

- Initial structure
- Commitlint
- Frontend base structure
- Update vscode settings
- Add subagents
- Coderabbit
- Prd and tooling
- Bun lock
- Lint tooling
- Copy.md and tooling adjusts
- Add repoclone rc
- Upgrade skeeper to v0.2.0
- Update go.mod
- Adopt task artifacts into skeeper
- Sync codex plans with skeeper
- Skeeper lock
- Skeeper lock
- New skills
- Skeeper lock
- Skeeper lock
- Skeeper lock
- Update deps and go
- Regenerate daytona sidecar assets for go 1.26.3
- Fix cliff
- Ignore docs on fmt
- Build web assets before goreleaser
- Extend release dry-run timeout



### 🔧 CI/CD

- Lint errors
- Fint release pr
- Fix goreleaser
- Fix release
- Fix release process
- Fix release sync
- Decouple release dry-run npm auth
- Persist web assets git auth



### 🧪 Testing

- Add e2e tests (#27)
- Qa rounds (#78)
- Improve test suite (#138)
- Harden daemon-served restart reloads
- Harden daemon-served readiness waits
- Stabilize dashboard focus assertion
- Stabilize release integration gates
- Stabilize release e2e markers
- Stabilize release e2e flows
- Improve suite speed


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated web assets dependency to a newer version for improved
stability and performance.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/compozy/agh/pull/211?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
pedronauck added a commit that referenced this pull request May 27, 2026
## Release v0.0.2

This PR prepares the release of version v0.0.2.

### Changelog

## 0.0.2 - 2026-05-27



### Other Changes

- Lessons learned



### ♻️ Refactoring

- Project structure (#7)
- Kb improvements (#12)
- Rename spaces to channels (#17)
- Add extensions gaps (#21)
- Improve tool calls ui (#22)
- Remove web app header
- Module improvements (#29)
- Memory improvements (#35)
- Storybook for web and ui (#38)
- Enable AGH network by default for new installs (#57)
- Hermes adjustments (#69)
- Badges design (#84)
- Storybook scenario and logos gallery
- Migrate typescript tests (#114)
- Internal go packages (#120)
- Ui patterns (#127)
- Improve e2e tests (#130)
- Ui redesign
- Workspace isolation across runtime surfaces (#145)
- Prod ready applies (#162)
- Tool card ui (#164)
- Alpha on logo
- Prod ready features (#167)
- Thread sheet (#202)



### 🎉 Features

- Implement config foundation packages
- Implement sqlite store package
- Add ACP client package
- Add session lifecycle manager
- Implement observe package
- Add daemon composition root
- Add uds api server
- Implement cli package
- Add http api server
- Add system design
- Add foundation types, schemas, and layout shell for web client
- Add daemon health polling and agent sidebar systems for web client
- Add session system CRUD, streaming core, and session store for web
client
- Add chat view, messages, and composer tests for web client
- Add tool cards and renderers for web client
- Add file-backed memory store core
- Scaffold memory session seams
- Add memory dream consolidation service
- Wire memory assembler into daemon
- Add memory api and cli
- New skills system (#1)
- Add workspace entity (#5)
- Add new skill capabilities (#8)
- Web ui v2 (#9)
- Improve hooks system (#10)
- Session resilience (#11)
- Add extensability (#13)
- Add automation (#16)
- Add channels (#14)
- Add network implementation (#15)
- Add network, bridges and automations web pages (#18)
- Ext registry (#20)
- Add core tasks (#19)
- Bridge adapters (#23)
- Add site (#26)
- Add ext refac and sandbox (#25)
- Settings ui (#37)
- Tasks ui (#36)
- Harness improvements (#44)
- Agent capabilities (#49)
- Redesign ui (#48)
- Unify capability (#53)
- Redesign network workspace (#59)
- Add task deletion and split session delete from stop (#58)
- Session provider selection (#60)
- Production grade adjustments (#66)
- Autonomous system (#75)
- Add agent session route (#80)
- Tools registry (#85)
- Agents soul (#88)
- Add network threads (#105)
- Orchestration improvements (#106)
- Memory v2 (#108)
- Agent categories (#113)
- Providers model (#118)
- Add canonical AGH bundled skill (#143)
- Onboarding and improvements (#198)
- Onboarding and improvements (#201)



### 🐛 Bug Fixes

- Review round
- Review rounds
- Resolve memory extensibility review batch
- Embed web into daemon
- Defaults agents
- Acp integration (#4)
- Lint errors
- Prd folder
- Remove orphan web actions and dead surfaces (#55)
- Qa testing and fixes (#73)
- New review rounds (#82)
- Security audit (#90)
- Release qa round (#95)
- Add missing tools (#141)
- New qa round (#147)
- Advanced qa round (#149)
- Homebrew tap
- Final review round (#151)
- Daemon healthy
- Reasoning models (#158)
- Lint errors (#160)
- Review round (#168)
- Release adjustments (#171)
- Stabilize release ci fixtures
- Stabilize release integration gate
- Stabilize release verify gates
- Stabilize release integration flows
- Stabilize release verify gates
- Stabilize main verify shutdown
- Ignore stale acpmock cancel
- Marketplace search focus and filtering (#193)
- Website video
- Workspace command select



### 📚 Documentation

- Update agents.md
- Update prd
- Update skills
- Update compozy tasks
- Update compozy
- Update compozy
- Add new skills
- Archive prd
- Update prds
- Update rfc
- Update prds
- Update prds
- Add automation prd
- Channels prd
- Update prd
- Update prd
- New prds
- Archive prds
- Bridges adapters prd
- Sandbox prd
- Update
- Archive prd
- Update
- Add new prd
- New design
- Update prd
- Archive prds
- Update prds
- Tasks-ui prd tasks
- Update prd
- Update design docs
- Agent capabilities prd
- Improve site docs
- Remove old design references
- Udpate
- Autonomous prd
- Update skills
- Blog design
- Agent sould prd
- Final qa plan
- Update
- Remove codex ledgers from gitignore
- Remove not needed files
- Udpate ledger
- Update cy-codex-loop skill
- Orchestration improves prd
- Update prds
- Orch improvs prd
- Memv2 prd
- Providers model prd
- Update refacs prd
- New design proposal
- Update rules
- Update skills
- New blog posts (#173)
- Format docs
- Remove old design files
- Remove old
- Skeeper update



### 📦 Build System

- Initial structure
- Commitlint
- Frontend base structure
- Update vscode settings
- Add subagents
- Coderabbit
- Prd and tooling
- Bun lock
- Lint tooling
- Copy.md and tooling adjusts
- Add repoclone rc
- Upgrade skeeper to v0.2.0
- Update go.mod
- Adopt task artifacts into skeeper
- Sync codex plans with skeeper
- Skeeper lock
- Skeeper lock
- New skills
- Skeeper lock
- Skeeper lock
- Skeeper lock
- Update deps and go
- Regenerate daytona sidecar assets for go 1.26.3
- Fix cliff
- Ignore docs on fmt
- Build web assets before goreleaser
- Extend release dry-run timeout
- Fix release dry-run token contract



### 🔧 CI/CD

- Lint errors
- Fint release pr
- Fix goreleaser
- Fix release
- Fix release process
- Fix release sync
- Decouple release dry-run npm auth
- Persist web assets git auth
- Require npm auth before release merge



### 🧪 Testing

- Add e2e tests (#27)
- Qa rounds (#78)
- Improve test suite (#138)
- Harden daemon-served restart reloads
- Harden daemon-served readiness waits
- Stabilize dashboard focus assertion
- Stabilize release integration gates
- Stabilize release e2e markers
- Stabilize release e2e flows
- Improve suite speed


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
  * Updated dependencies to latest versions.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/compozy/agh/pull/214?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant