test: qa rounds#78
Conversation
|
Important Review skippedReview was skipped due to path filters ⛔ Files ignored due to path filters (50)
CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughAdds coordinator config resolution and agent endpoint, propagates session Model through session/identity/scheduler paths, enforces coordination-channel matching for task scheduling, prevents network self-echo, improves observer session-snapshot recovery, detaches hook-observer contexts from caller cancellation, and introduces many UI components/stories and styling updates. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 15
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (6)
internal/scheduler/scheduler_channel_test.go-15-90 (1)
15-90:⚠️ Potential issue | 🟡 MinorAdd an empty-channel regression case for channel-bound runs.
Current tests validate matching and mismatching channels, but they don’t guard the critical edge case where a session has
Channel == ""while the run is channel-bound.Suggested test addition
+ t.Run("Should not wake unscoped session for channel-bound work", func(t *testing.T) { + t.Parallel() + + base := time.Date(2026, 4, 26, 14, 0, 0, 0, time.UTC) + work := workSnapshot("task-1", "run-1", taskpkg.ScopeWorkspace, "ws-1", []string{"go"}, base) + work.Run.CoordinationChannelID = "finance" + + source := &fakeTaskSource{pending: []RunSnapshot{work}} + sessions := &fakeSessionSource{sessions: []SessionSnapshot{ + { + ID: "sess-unscoped", + WorkspaceID: "ws-1", + Channel: "", + State: "active", + Capabilities: []string{"go"}, + CreatedAt: base, + }, + }} + waker := &fakeWaker{} + scheduler := newTestScheduler(t, source, sessions, waker, WithClock(clockwork.NewFakeClockAt(base))) + + result, err := scheduler.RunOnce(testutil.Context(t)) + if err != nil { + t.Fatalf("RunOnce() error = %v", err) + } + if result.WakeAttempts != 0 || result.NoMatchRuns != 1 { + t.Fatalf("result = %#v, want one no-match and no wake attempts", result) + } + })As per coding guidelines, "Focus on critical paths: workflow execution, state management, error handling" and tests should ensure behavior regressions are caught.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/scheduler/scheduler_channel_test.go` around lines 15 - 90, Add a third test case in scheduler_channel_test.go that asserts a session with Channel == "" does not match a channel-bound run: create a workSnapshot with Run.CoordinationChannelID = "finance" (reuse workSnapshot used in the other cases), use fakeTaskSource{pending: []RunSnapshot{work}}, create fakeSessionSource{sessions: []SessionSnapshot{{ID: "sess-empty", WorkspaceID: "ws-1", Channel: "", State: "active", Capabilities: []string{"go"}, CreatedAt: base}}}, and a fakeWaker; call scheduler := newTestScheduler(..., WithClock(...)) and scheduler.RunOnce(testutil.Context(t)) and assert result.WakeAttempts == 0, result.NoMatchRuns == 1 and len(waker.targetsSnapshot()) == 0 to ensure empty session channel is treated as non-matching for channel-bound runs.web/src/systems/network/mocks/handlers.ts-127-139 (1)
127-139:⚠️ Potential issue | 🟡 MinorGuard required fields with runtime type checks before
.trim().At Line 127, non-string payload values can throw (e.g.,
channel: 123) before returning the intended 400 contract response.Suggested hardening
http.post("/api/network/send", async ({ request }) => { const body = (await request.json()) as { @@ trace_id?: string; }; - if (!body.session_id?.trim() || !body.channel?.trim() || !body.kind?.trim()) { + const asNonEmpty = (value: unknown): string => (typeof value === "string" ? value.trim() : ""); + const sessionId = asNonEmpty(body.session_id); + const channel = asNonEmpty(body.channel); + const kind = asNonEmpty(body.kind); + + if (!sessionId || !channel || !kind) { return HttpResponse.json( { error: "Session, channel, and kind are required." }, { status: 400 } ); } return HttpResponse.json({ message: { id: body.id?.trim() || "msg_storybook_sent", - session_id: body.session_id.trim(), - channel: body.channel.trim(), - kind: body.kind.trim(), + session_id: sessionId, + channel, + kind,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/network/mocks/handlers.ts` around lines 127 - 139, The current guard calls .trim() on body.session_id, body.channel, and body.kind which will throw for non-string inputs; update the validation to first check typeof body.session_id === "string" && typeof body.channel === "string" && typeof body.kind === "string" (or safely coerce) before calling .trim(), and return the same 400 HttpResponse.json when any of those type checks fail; locate the checks around the existing body.session_id?.trim() / body.channel?.trim() / body.kind?.trim() usage and apply the type guards so subsequent calls like body.session_id.trim() are safe.web/src/storybook/web-storybook-stories-and-fixtures.test.tsx-23-24 (1)
23-24:⚠️ Potential issue | 🟡 MinorRoute system imports through a public barrel instead of deep internals.
Line 23 imports
@/systems/network/components/stories/network-workspace-shell.storiesdirectly from a system-internal path. Please expose a public test-facing entrypoint (or import via an allowed public barrel) so this test does not depend on network internals.As per coding guidelines, "Cross-system imports MUST only go through the public barrel (
@/systems/<domain>). Never reach into another system's internals".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/storybook/web-storybook-stories-and-fixtures.test.tsx` around lines 23 - 24, The test imports deep internals (network-workspace-shell.stories and -network.stories) instead of using the public system barrel; add a public test-facing export in the systems network barrel (e.g., update the `@/systems/network` index to export the story modules or create a stories sub-barrel) and update the test imports to use that public barrel (import from '@/systems/network' or '@/systems/network/stories') so the test no longer reaches into network internals.internal/observe/observer_test.go-98-102 (1)
98-102:⚠️ Potential issue | 🟡 MinorIsolate the live-source path in this test.
Registering the session in
h.registrymakes this case pass even if the live-source lookup breaks, becauserecoverSessionSnapshotcan still succeed through the registry fallback. Leave the registry unseeded here, or force the fallback path to fail, so this test actually proves the live-source branch.As per coding guidelines,
**/*_test.go: "Ensure tests can fail when business logic changes."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/observe/observer_test.go` around lines 98 - 102, The test is seeding the registry so recoverSessionSnapshot succeeds via registry fallback; remove or disable that seeding so the live-source path is exercised: delete (or comment out) the call to h.registry.RegisterSession(...) that uses sessionInfoFromSession(info) (or explicitly clear/unseed h.registry), and ensure h.source.sessions = []*session.Info{info} remains set so recoverSessionSnapshot must load from the live source; alternatively force the registry lookup to fail by making h.registry return not-found for that session to guarantee the live-source branch is tested.internal/network/manager_test.go-751-753 (1)
751-753:⚠️ Potential issue | 🟡 MinorThese metric expectations are heartbeat-timing sensitive.
The exact
sent/receivedandKindGreetcounts here assume neither session heartbeat fires beforeStatus()runs. SinceJoinChannel()starts live 1-second heartbeats, slower CI can legitimately observe extra greet traffic and fail this test intermittently. I’d make the test config use a much longer greet interval, or assert only the deltas introduced by the explicitKindSay.One way to stabilize it
- manager, err := NewManager( + cfg := testManagerConfig() + cfg.GreetInterval = 3600 + manager, err := NewManager( ctx, - testManagerConfig(), + cfg, prompter, filepath.Join(t.TempDir(), "network.audit"), nil, WithManagerLogger(logger), WithManagerClock(func() time.Time { return fixedNow }), )Also applies to: 781-793
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/network/manager_test.go` around lines 751 - 753, The test is flaky because heartbeat-driven greet traffic (started by manager.JoinChannel via the testJoinRequest session config) can increment sent/received and KindGreet counts before Status() is sampled; update the test to stabilize it by either configuring the session used in testJoinRequest to use a much longer heartbeat/greet interval so no heartbeat fires during the check, or change the assertions around Status() to only assert deltas caused by the explicit KindSay (i.e., compute baselines before the Say and assert only the difference for sent/received and KindSay while allowing KindGreet to be >= baseline). Ensure you modify the testJoinRequest/session config or the Status() assertions accordingly and reference KindGreet/KindSay, manager.JoinChannel and Status() when making the change.internal/network/router.go-639-653 (1)
639-653:⚠️ Potential issue | 🟡 MinorDirected self-WHOIS is now suppressed, but the manager still audits it as received.
Line 640 drops the local responder when the directed target is also the sender. That means a self-directed WHOIS now returns with no
Generatedresponse, butManager.controlMessageReceivers()still records the target session as having received the request. This will skew received audits/stats for a message that was intentionally skipped.Possible follow-up
// internal/network/manager.go case KindWhois: ... if envelope.IsDirected() { - if target, ok := m.peers.LocalByPeer(envelope.Channel, *envelope.To); ok { + if target, ok := m.peers.LocalByPeer(envelope.Channel, *envelope.To); ok && !isEnvelopeSender(target, envelope) { return []string{target.SessionID} } return nil }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/network/router.go` around lines 639 - 653, The router currently suppresses directed self-WHOIS in router.peers handling (envelope.IsDirected() branch using isEnvelopeSender) but Manager.controlMessageReceivers() still audits that target as having received the request; change the audit logic in Manager.controlMessageReceivers() to detect the same condition (envelope.IsDirected() && hasDirectedTarget && isEnvelopeSender(directedTarget, envelope)) and skip recording that session as a receiver when true so suppressed self-directed WHOIS messages are not counted.
🧹 Nitpick comments (12)
internal/workspace/resolver_test.go (1)
919-924: Consider hardening the deep-copy assertion by mutating cloned autonomy fields.Current checks confirm values are copied, but not clone independence for this branch. Adding one mutation/assertion pair would future-proof this test.
Suggested test hardening
cloned := cloneConfig(&original) cloned.Session.Limits.Timeout = 2 * time.Minute +cloned.Autonomy.Coordinator.AgentName = "mutated-coordinator" cloned.Providers["claude"] = aghconfig.ProviderConfig{} cloned.Skills.DisabledSkills[0] = "beta" cloned.Hooks.Declarations[0].Args[0] = "two" @@ if !cloned.Autonomy.Coordinator.Enabled { t.Fatal("cloned Autonomy.Coordinator.Enabled = false, want true") } +if got, want := original.Autonomy.Coordinator.AgentName, "coordinator"; got != want { + t.Fatalf("original Autonomy.Coordinator.AgentName = %q, want %q", got, want) +}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/workspace/resolver_test.go` around lines 919 - 924, The test currently only checks values on cloned.Autonomy.Coordinator (DefaultTTL and Enabled) but not that the clone is independent; modify the test to mutate a field on cloned.Autonomy.Coordinator (e.g., change cloned.Autonomy.Coordinator.DefaultTTL or toggle cloned.Autonomy.Coordinator.Enabled) and then assert the original Autonomy.Coordinator value on the source config did not change (ensuring deep-copy semantics); reference the cloned.Autonomy.Coordinator and the original source variable used in the test to perform these assertions.web/src/components/app-sidebar.tsx (1)
138-148: Consider extracting shared active-nav styles to avoid drift.
NavItemandFooterSlotnow duplicate the same active container and indicator classes. A small local constant/helper would reduce maintenance risk.Possible lightweight refactor
+const NAV_ITEM_BASE_CLASS = + "relative flex items-center gap-2 rounded-[6px] px-2 py-1.5 text-[13px] text-[color:var(--color-text-secondary)] transition-colors hover:bg-[color:var(--color-hover)] hover:text-[color:var(--color-text-primary)]"; +const NAV_ITEM_ACTIVE_CLASS = + "bg-[color:var(--color-surface)] font-medium text-[color:var(--color-text-primary)]"; +const NAV_ACTIVE_INDICATOR_CLASS = + "absolute -left-2 top-1.5 bottom-1.5 w-[2px] rounded-r-[2px] bg-[color:var(--color-accent)]";Also applies to: 484-494
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/app-sidebar.tsx` around lines 138 - 148, NavItem and FooterSlot duplicate the same active container and indicator class strings which risks style drift; extract those shared classes into a local constant or helper (e.g., ACTIVE_CONTAINER_CLASSES and ACTIVE_INDICATOR_CLASSES) and use them in both NavItem and FooterSlot where isActive controls the container class and the indicator span (refer to the isActive conditional rendering and the span with data-testid={`nav-active-${testKey}`}) so both components reuse the same class definitions.packages/ui/src/components/mono-badge.tsx (1)
20-20: Component docs are now slightly out of sync with supported tones.
"solid-accent"is a non-tinted variant, while the component docs still describe tinted usage only. Consider updating the comment to prevent confusion for consumers.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ui/src/components/mono-badge.tsx` at line 20, The comment/docs for the MonoBadge component are out of sync because the style key "solid-accent" (a non-tinted variant) is supported but not documented; update the component comment or JSDoc in mono-badge.tsx (MonoBadge / the styles mapping that contains "solid-accent") to explicitly describe both tinted and non-tinted tones, noting that "solid-accent" is a non-tinted variant that uses --color-accent and --color-accent-ink, and add a short usage note so consumers understand when to choose "solid-accent" vs the tinted variants.web/src/systems/network/mocks/network-mocks.test.ts (1)
48-76: Consider adding a failure-path contract test for required fields.You already cover the happy path; adding one 400-case assertion would lock down the new validation behavior.
Example additional test
+ it("returns 400 when required send fields are missing", async () => { + const response = await getResponse( + handlers, + new Request("http://localhost/api/network/send", { + body: JSON.stringify({ channel: "storybook" }), + method: "POST", + }), + { baseUrl: "http://localhost" } + ); + + expect(response).not.toBeUndefined(); + expect(response?.status).toBe(400); + await expect(response?.json()).resolves.toMatchObject({ + error: "Session, channel, and kind are required.", + }); + });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/network/mocks/network-mocks.test.ts` around lines 48 - 76, Add a negative test to network-mocks.test.ts that uses getResponse and handlers to POST to "http://localhost/api/network/send" with a request body missing a required field (e.g., omit channel or kind or session_id) and assert the response has status 400 (response?.ok === false) and that the returned JSON contains an error describing the missing field (e.g., contains "missing" or specific field name); keep the same Request construction pattern as the happy-path test to ensure the validation behavior is locked down.web/src/systems/network/components/stories/network-workspace-shell.stories.tsx (1)
56-61: Unconventional use ofglobalThis.Error.Using
globalThis.Errorinstead of justErroris unusual. While it works,Erroris globally available and more idiomatic. This may have been intentional to avoid linting rules, but worth noting for consistency.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/network/components/stories/network-workspace-shell.stories.tsx` around lines 56 - 61, The requireFixture function uses globalThis.Error which is unconventional; change the throw to use the plain Error constructor instead (replace globalThis.Error with Error) in function requireFixture to follow idiomatic/global lint expectations and keep behavior identical.web/src/systems/network/components/network-workspace-shell.tsx (2)
79-97: Avatar palette uses hardcoded hex values.The
AVATAR_PALETTEcontains ad-hoc color tokens. Per coding guidelines, colors should be pulled fromDESIGN.mdrather than invented. Consider defining these as CSS variables intokens.cssor confirming they align with the design system's avatar color specification.As per coding guidelines: "Pull every color, font, radius, spacing step, and motion value from
DESIGN.md— never invent tokens"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/network/components/network-workspace-shell.tsx` around lines 79 - 97, The AVATAR_PALETTE array embeds hardcoded hex values; update it to reference design-system tokens instead and ensure pickAvatarColors(seed) returns those token references. Replace the literal hex pairs in AVATAR_PALETTE with CSS variable names (or exported token constants) defined in tokens.css or the DESIGN.md avatar color spec, e.g., use token identifiers like --avatar-bg-1 / --avatar-fg-1 (or exported JS constants) so AVATAR_PALETTE and pickAvatarColors rely on canonical tokens rather than ad-hoc hex strings; also add or verify corresponding variables exist in tokens.css per the design spec.
432-434: Inline color value for hover state.
hover:bg-white/[0.014]uses an ad-hoc opacity value. Consider using a CSS variable-based hover surface token for consistency with the flat depth model.As per coding guidelines: "Tokens live in
packages/ui/src/tokens.css; never override with ad-hoc hex values in components"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/network/components/network-workspace-shell.tsx` around lines 432 - 434, The hover color uses an ad-hoc opacity value ("hover:bg-white/[0.014]") inside the className built by cn; replace that inline alpha with the project token-based hover surface token from tokens.css (e.g., use the CSS variable token instead of the ad-hoc value) by swapping "hover:bg-white/[0.014]" for the corresponding token-based class or utility (reference the className string and cn call where grouped is used to locate the site of change) so the component uses the standardized hover surface token rather than an inline color.packages/ui/src/components/kind-chip.test.tsx (1)
20-25: Potential brittleness in style comparison.
style.backgroundmay return normalized values (e.g.,rgb()format) depending on the test environment, whileKIND_DOT_COLORS.receiptisvar(--color-success). This should work in jsdom since inline styles aren't computed, but be aware if tests become flaky after environment changes.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ui/src/components/kind-chip.test.tsx` around lines 20 - 25, The test comparing dot?.style.background to KIND_DOT_COLORS.receipt is brittle because different environments may normalize CSS values; update the assertion in the KindChip test to check the raw style string contains the CSS variable instead of strict equality — e.g., assert that dot?.getAttribute('style') or dot?.style.background includes KIND_DOT_COLORS.receipt (reference KIND_DOT_COLORS.receipt and the KindChip test case) so the test remains stable across environments.internal/observe/observer_test.go (1)
93-149: Prefer one table-driven test witht.Run("Should...")subtests here.These two cases only vary by recovery source, so consolidating them would remove duplicated setup/assert logic and match the test structure required in this repo.
As per coding guidelines,
**/*_test.go: "Table-driven tests with subtests (t.Run) as default pattern" and "MUST use t.Run("Should...") pattern for ALL test cases".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/observe/observer_test.go` around lines 93 - 149, These two tests (TestOnAgentEventRecoversSessionSnapshotFromLiveSource and TestOnAgentEventRecoversSessionSnapshotFromRegistry) should be merged into a single table-driven test using t.Run("Should...") subtests: create a slice of cases describing the recovery source ("live" vs "registry") and per-case setup (for the live case set h.source.sessions = []*session.Info{info}, for the registry case call h.registry.RegisterSession(...)); inside the loop call the common logic (newHarness/newSession, h.observer.OnAgentEvent with appropriate TurnID/Text, then h.observer.QueryEvents and the shared assertions) so duplicated setup/assert code is removed and each case uses t.Run("Should recover from <source>") to satisfy the repository's subtest pattern.internal/session/query.go (1)
279-279: Consider normalizingmeta.Modelduring hydration for consistency.Optional: trim at read time too, so older/manual metadata with stray whitespace doesn’t leak into API/session snapshots.
♻️ Proposed tweak
- Model: meta.Model, + Model: strings.TrimSpace(meta.Model),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/session/query.go` at line 279, Normalize meta.Model during hydration by trimming whitespace and/or applying a consistent normalization (e.g., strings.TrimSpace or lowercasing as your conventions dictate) where the struct field is set (the location that currently assigns Model: meta.Model). Also optionally apply the same normalization when reading/serializing session metadata to prevent older/manual entries with stray whitespace from leaking into API/session snapshots; update any code paths that consume meta.Model to expect the normalized form.internal/api/core/agent_identity.go (1)
148-165: Consider wrapping the error with context.Line 158 returns the error from
ResolveCoordinatorConfigwithout wrapping. Adding context would help trace failures.♻️ Suggested improvement
cfg, err := h.CoordinatorConfig.ResolveCoordinatorConfig(ctx, trimmedWorkspaceID) if err != nil { - return contract.CoordinatorConfigPayload{}, err + return contract.CoordinatorConfigPayload{}, fmt.Errorf("resolve coordinator config: %w", err) }As per coding guidelines: "Use explicit error returns with wrapped context:
fmt.Errorf("context: %w", err)in Go".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/api/core/agent_identity.go` around lines 148 - 165, In agentCoordinatorConfigPayload, wrap the error returned by h.CoordinatorConfig.ResolveCoordinatorConfig with contextual information (e.g., include workspaceID and operation) before returning so callers can trace failures; update the error return after calling ResolveCoordinatorConfig to use fmt.Errorf("resolve coordinator config for workspace %q: %w", trimmedWorkspaceID, err) (or equivalent) to preserve the original error while adding context.internal/network/router_test.go (1)
160-212: Split the new echo coverage intot.Runsubtests.These are two independent behaviors—broadcast self-echo and directed self-echo—so separate subtests will isolate failures better and match the repo’s default test style.
As per coding guidelines, "Use table-driven tests with subtests (
t.Run) as default pattern" and "MUST use t.Run("Should...") pattern for ALL test cases".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/network/router_test.go` around lines 160 - 212, The test TestRouterDoesNotDeliverLocalEchoesToSender should be split into two t.Run subtests (use the "Should ..." naming pattern) to isolate broadcast vs direct self-echo behavior: keep the shared setup (NewPeerRegistry, RegisterLocal, spyRouterTransport, NewRouter) outside, then add t.Run("Should not deliver broadcast self-echo to sender") to perform the router.Send with KindSay and the router.Receive on transport.Message(0).payload and assert zero deliveries, and a separate t.Run("Should not deliver direct self-echo to sender") that performs the router.Send with KindDirect (To=sender.PeerID, InteractionID) and router.Receive on transport.Message(1).payload and asserts zero deliveries; ensure you reuse mustPeerCard, mustRawJSON, and stringPtr helpers and preserve existing assertions and error handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@internal/api/udsapi/agent_channels_test.go`:
- Around line 72-116: Wrap the existing
TestAgentCoordinatorConfigRouteReturnsResolvedPayload body in a subtest using
t.Run("Should return resolved workspace coordinator payload", func(t *testing.T)
{ ... }) so the test follows the required t.Run("Should ...") pattern; locate
the TestAgentCoordinatorConfigRouteReturnsResolvedPayload function and move its
current contents into a t.Run call while keeping all setup (manager :=
activeAgentSessionManager, handlers := newTestHandlers,
handlers.CoordinatorConfig = agentCoordinatorConfigResolverFunc, engine :=
newTestRouter, performAgentKernelRequest, decodeJSONResponse and assertions)
unchanged inside the subtest body.
In `@internal/automation/dispatch.go`:
- Around line 56-60: The hardcoded constant dispatcherSessionStopTimeout should
be made configurable via dispatcher options rather than fixed in code: remove or
replace the package-level const dispatcherSessionStopTimeout and add a field
(e.g., SessionStopTimeout time.Duration) to the dispatcher options/config struct
used by NewDispatcher (or Dispatcher) and its option helpers; wire that value
into the shutdown logic that currently references dispatcherSessionStopTimeout
and provide a sensible default (10*time.Second) when the option is not set so
existing behavior remains unchanged.
In `@internal/daemon/daemon_integration_test.go`:
- Around line 2377-2483: The test function
TestBootRunsWorkspaceTaskRunHookWithRelativeScriptPath must be wrapped in a
t.Run subtest using the repository's "Should..." naming convention; update the
body of TestBootRunsWorkspaceTaskRunHookWithRelativeScriptPath so its existing
implementation is executed inside t.Run("Should run workspace task-run hook with
relative script path", func(t *testing.T) { ... }), keeping all existing setup,
payload creation, hook dispatch, and assertions intact (references:
TestBootRunsWorkspaceTaskRunHookWithRelativeScriptPath, d.boot,
d.hooks.DispatchTaskRunEnqueued, seedDaemonWorkspace,
hookspkg.TaskRunEnqueuedPayload).
In `@internal/daemon/harness_context_test.go`:
- Around line 98-129: The test-case name strings in the table-driven tests (the
name field used by t.Run(tc.name, ...)) do not follow the required "Should..."
subtest naming pattern; update the name values for the new matrix entries (e.g.,
the case currently titled "coordinator startup session resolves coordinator
policy" and the subsequent "spawned worker network turn resolves spawned
policy") to begin with "Should" (for example "Should resolve coordinator policy
on startup session" and "Should resolve spawned policy for spawned worker
network turn"), leaving the rest of the HarnessResolutionInput,
HarnessSessionInput, HarnessTurnRequest, wantSections/wantTags, and other fields
(symbols: name, HarnessResolutionInput, HarnessSessionInput, HarnessTurnRequest,
t.Run) unchanged so t.Run(tc.name, ...) uses the new "Should..." names.
- Around line 417-458: Wrap the new test function
TestSectionSelectorAcceptsCoordinatorStartupSession in an explicit subtest using
t.Run with a "Should..." description; e.g., inside
TestSectionSelectorAcceptsCoordinatorStartupSession call t.Run("Should select
coordinator startup sections", func(t *testing.T) { ... }) and move all existing
test logic (resolver/selector/descriptors creation, selector.Select call,
assertions on resolved.Session.SessionClass and selected names) into that
subtest so the test follows the required t.Run("Should...") subtest pattern.
In `@internal/daemon/notifier_test.go`:
- Around line 412-471: Split the monolithic
TestScopeWorkspaceHookDeclsOnlyInjectsSupportedMatcherFields into table-driven
subtests using t.Run("Should ...") entries: build a table of cases (e.g.,
"Should inject workspace fields for session", "Should only inject WorkspaceID
for task-run", "Should not inject workspace fields for message", "Should not
mutate original decls") that each call scopeWorkspaceHookDecls with the same
inputs and assert the specific Matcher fields and
hookspkg.ValidateMatcherForEvent results; keep the original decls and resolved
values for reuse, reference the function under test scopeWorkspaceHookDecls and
use hookspkg.ValidateMatcherForEvent in each subtest, and ensure the final case
verifies the original decls were not mutated.
In `@internal/hooks/matcher_test.go`:
- Around line 443-458: Update the t.Run case names in the table-driven test for
MatcherFieldAllowedForEvent so they follow the "Should..." pattern; specifically
rename the entries currently named "session workspace root", "task run workspace
id", "task run workspace root", "message workspace id", and "invalid event" to
descriptive "Should..." strings (e.g., "Should allow session workspace root",
"Should allow task run workspace id", "Should not allow task run workspace
root", "Should not allow message workspace id", "Should not allow invalid
event") so t.Run uses the required format while keeping the same event constants
(HookSessionPostCreate, HookTaskRunEnqueued, HookMessageDelta,
HookEvent("bad.event")) and field values ("workspace_root", "workspace_id") used
by MatcherFieldAllowedForEvent.
In `@internal/observe/observer.go`:
- Around line 621-632: The registry recovery currently re-adds stopped sessions
into the in-memory cache by calling o.trackSession in the ListSessions loop;
change this to avoid caching sessions that are no longer live. Specifically, in
the loop that iterates sessions returned by o.registry.ListSessions, only call
o.trackSession for sessions whose persisted metadata indicates they are active
(e.g., check a liveliness field like info.State/Status not equal to "stopped" or
!info.Stopped); otherwise, return the observed snapshot without calling
o.trackSession (or treat recovery as a one-shot lookup). Also ensure this
behavior is consistent with OnSessionStopped which evicts from o.sessions so
stopped sessions are never re-added.
- Around line 603-605: Remove the silent context.Background() fallback in
recoverSessionSnapshot and observedSessionSnapshot; do not substitute a
background context when ctx is nil — instead make the failure loud so callers
must pass a valid context. Concretely, delete the block `if ctx == nil { ctx =
context.Background() }` in both recoverSessionSnapshot and
observedSessionSnapshot and replace it with a clear guard that surfaces the bug
(for example `if ctx == nil { panic("nil context passed to
recoverSessionSnapshot") }` and similarly for observedSessionSnapshot) so
upstream callers are forced to propagate a non-nil context.
In `@internal/scheduler/scheduler.go`:
- Around line 519-534: coordinationChannelMatches currently treats an empty
candidate.Channel as a wildcard and returns true, which allows a run with a
non-empty Run.CoordinationChannelID to match an unscoped session; update
coordinationChannelMatches (and its use of SessionSnapshot.Channel and
RunSnapshot.Run.CoordinationChannelID) so that an empty session channel only
matches when the run's CoordinationChannelID is also empty (i.e., trim both
values and return true only if both are empty or both are equal), keeping the
existing nil guard for work.
In `@internal/store/globaldb/global_db_task_test.go`:
- Around line 1070-1112: The test body in
TestGlobalDBUpdateTaskRunAllowsQueuedSessionRelease must be wrapped as a named
subtest per project policy; replace the current top-level assertions with
t.Run("Should release queued session when requeued", func(t *testing.T) {
t.Parallel(); /* move the current body here unchanged */ }) so the existing
setup, CreateTask/CreateTaskRun, UpdateTaskRun and assertions remain identical
but run as a subtest; do the same for the other new test referenced around lines
1114-1136 (wrap its body in a t.Run("Should ...", func(t *testing.T) {
t.Parallel(); ... })) so every test case uses the t.Run("Should...") pattern.
In `@internal/task/hooks_test.go`:
- Around line 136-181: The test
TestTaskRunObservationHooksDetachFromCallerCancellation must be converted to use
t.Run subtests for the two hook-context assertions: wrap the
enqueued-cancel/assertion logic into a t.Run("Should keep enqueued hook context
active") subtest and the post-claim-cancel/assertion into a t.Run("Should keep
post-claim hook context active") subtest; keep the setup (store, manager with
WithTaskRunHooks, CreateTask, EnqueueRun/ClaimRun and their cancels) but move
the specific cancel+assertContextStillActive(enqueuedCtx, t, "enqueued") and
cancel+assertContextStillActive(postClaimCtx, t, "post-claim") calls into their
respective t.Run blocks so the file follows the required t.Run("Should...")
pattern while still referencing enqueuedCtx, postClaimCtx,
manager.EnqueueRun/ClaimRun and assertContextStillActive.
In `@internal/task/hooks.go`:
- Around line 123-127: Replace the use of context.Background() with
context.TODO() in the taskRunObservationHookContext function: when ctx is nil,
return context.TODO() instead of context.Background() so the function uses the
internal package's preferred placeholder; keep the rest of the function
(including the call to context.WithoutCancel(ctx)) unchanged.
In `@internal/task/manager_integration_test.go`:
- Around line 1091-1153: The test function
TestTaskManagerRecoverRunOnBootRequeuesBoundRunWithGlobalDB must be wrapped in a
t.Run("Should ...") subtest: replace the top-level t.Parallel() and direct test
body with a single t.Run("Should requeue bound run on boot and release session
binding", func(t *testing.T) { t.Parallel(); /* existing test body */ }),
keeping all existing setup and assertions intact (references:
TestTaskManagerRecoverRunOnBootRequeuesBoundRunWithGlobalDB, manager.CreateTask,
manager.EnqueueRun, manager.ClaimNextRun, manager.RecoverRunOnBoot,
db.GetTaskRun) so the repo-wide "Should..." subtest pattern is satisfied.
In `@web/src/routes/_app/stories/-network.stories.tsx`:
- Line 12: Importing networkStatusFixture directly from the internals violates
cross-system import rules; update the import in _network.stories.tsx to
re-export networkStatusFixture from the public barrel by changing the source to
the systems network public barrel (use "@/systems/network") so the story
consumes networkStatusFixture via the public API rather than the deep path.
---
Minor comments:
In `@internal/network/manager_test.go`:
- Around line 751-753: The test is flaky because heartbeat-driven greet traffic
(started by manager.JoinChannel via the testJoinRequest session config) can
increment sent/received and KindGreet counts before Status() is sampled; update
the test to stabilize it by either configuring the session used in
testJoinRequest to use a much longer heartbeat/greet interval so no heartbeat
fires during the check, or change the assertions around Status() to only assert
deltas caused by the explicit KindSay (i.e., compute baselines before the Say
and assert only the difference for sent/received and KindSay while allowing
KindGreet to be >= baseline). Ensure you modify the testJoinRequest/session
config or the Status() assertions accordingly and reference KindGreet/KindSay,
manager.JoinChannel and Status() when making the change.
In `@internal/network/router.go`:
- Around line 639-653: The router currently suppresses directed self-WHOIS in
router.peers handling (envelope.IsDirected() branch using isEnvelopeSender) but
Manager.controlMessageReceivers() still audits that target as having received
the request; change the audit logic in Manager.controlMessageReceivers() to
detect the same condition (envelope.IsDirected() && hasDirectedTarget &&
isEnvelopeSender(directedTarget, envelope)) and skip recording that session as a
receiver when true so suppressed self-directed WHOIS messages are not counted.
In `@internal/observe/observer_test.go`:
- Around line 98-102: The test is seeding the registry so recoverSessionSnapshot
succeeds via registry fallback; remove or disable that seeding so the
live-source path is exercised: delete (or comment out) the call to
h.registry.RegisterSession(...) that uses sessionInfoFromSession(info) (or
explicitly clear/unseed h.registry), and ensure h.source.sessions =
[]*session.Info{info} remains set so recoverSessionSnapshot must load from the
live source; alternatively force the registry lookup to fail by making
h.registry return not-found for that session to guarantee the live-source branch
is tested.
In `@internal/scheduler/scheduler_channel_test.go`:
- Around line 15-90: Add a third test case in scheduler_channel_test.go that
asserts a session with Channel == "" does not match a channel-bound run: create
a workSnapshot with Run.CoordinationChannelID = "finance" (reuse workSnapshot
used in the other cases), use fakeTaskSource{pending: []RunSnapshot{work}},
create fakeSessionSource{sessions: []SessionSnapshot{{ID: "sess-empty",
WorkspaceID: "ws-1", Channel: "", State: "active", Capabilities: []string{"go"},
CreatedAt: base}}}, and a fakeWaker; call scheduler := newTestScheduler(...,
WithClock(...)) and scheduler.RunOnce(testutil.Context(t)) and assert
result.WakeAttempts == 0, result.NoMatchRuns == 1 and
len(waker.targetsSnapshot()) == 0 to ensure empty session channel is treated as
non-matching for channel-bound runs.
In `@web/src/storybook/web-storybook-stories-and-fixtures.test.tsx`:
- Around line 23-24: The test imports deep internals
(network-workspace-shell.stories and -network.stories) instead of using the
public system barrel; add a public test-facing export in the systems network
barrel (e.g., update the `@/systems/network` index to export the story modules or
create a stories sub-barrel) and update the test imports to use that public
barrel (import from '@/systems/network' or '@/systems/network/stories') so the
test no longer reaches into network internals.
In `@web/src/systems/network/mocks/handlers.ts`:
- Around line 127-139: The current guard calls .trim() on body.session_id,
body.channel, and body.kind which will throw for non-string inputs; update the
validation to first check typeof body.session_id === "string" && typeof
body.channel === "string" && typeof body.kind === "string" (or safely coerce)
before calling .trim(), and return the same 400 HttpResponse.json when any of
those type checks fail; locate the checks around the existing
body.session_id?.trim() / body.channel?.trim() / body.kind?.trim() usage and
apply the type guards so subsequent calls like body.session_id.trim() are safe.
---
Nitpick comments:
In `@internal/api/core/agent_identity.go`:
- Around line 148-165: In agentCoordinatorConfigPayload, wrap the error returned
by h.CoordinatorConfig.ResolveCoordinatorConfig with contextual information
(e.g., include workspaceID and operation) before returning so callers can trace
failures; update the error return after calling ResolveCoordinatorConfig to use
fmt.Errorf("resolve coordinator config for workspace %q: %w",
trimmedWorkspaceID, err) (or equivalent) to preserve the original error while
adding context.
In `@internal/network/router_test.go`:
- Around line 160-212: The test TestRouterDoesNotDeliverLocalEchoesToSender
should be split into two t.Run subtests (use the "Should ..." naming pattern) to
isolate broadcast vs direct self-echo behavior: keep the shared setup
(NewPeerRegistry, RegisterLocal, spyRouterTransport, NewRouter) outside, then
add t.Run("Should not deliver broadcast self-echo to sender") to perform the
router.Send with KindSay and the router.Receive on transport.Message(0).payload
and assert zero deliveries, and a separate t.Run("Should not deliver direct
self-echo to sender") that performs the router.Send with KindDirect
(To=sender.PeerID, InteractionID) and router.Receive on
transport.Message(1).payload and asserts zero deliveries; ensure you reuse
mustPeerCard, mustRawJSON, and stringPtr helpers and preserve existing
assertions and error handling.
In `@internal/observe/observer_test.go`:
- Around line 93-149: These two tests
(TestOnAgentEventRecoversSessionSnapshotFromLiveSource and
TestOnAgentEventRecoversSessionSnapshotFromRegistry) should be merged into a
single table-driven test using t.Run("Should...") subtests: create a slice of
cases describing the recovery source ("live" vs "registry") and per-case setup
(for the live case set h.source.sessions = []*session.Info{info}, for the
registry case call h.registry.RegisterSession(...)); inside the loop call the
common logic (newHarness/newSession, h.observer.OnAgentEvent with appropriate
TurnID/Text, then h.observer.QueryEvents and the shared assertions) so
duplicated setup/assert code is removed and each case uses t.Run("Should recover
from <source>") to satisfy the repository's subtest pattern.
In `@internal/session/query.go`:
- Line 279: Normalize meta.Model during hydration by trimming whitespace and/or
applying a consistent normalization (e.g., strings.TrimSpace or lowercasing as
your conventions dictate) where the struct field is set (the location that
currently assigns Model: meta.Model). Also optionally apply the same
normalization when reading/serializing session metadata to prevent older/manual
entries with stray whitespace from leaking into API/session snapshots; update
any code paths that consume meta.Model to expect the normalized form.
In `@internal/workspace/resolver_test.go`:
- Around line 919-924: The test currently only checks values on
cloned.Autonomy.Coordinator (DefaultTTL and Enabled) but not that the clone is
independent; modify the test to mutate a field on cloned.Autonomy.Coordinator
(e.g., change cloned.Autonomy.Coordinator.DefaultTTL or toggle
cloned.Autonomy.Coordinator.Enabled) and then assert the original
Autonomy.Coordinator value on the source config did not change (ensuring
deep-copy semantics); reference the cloned.Autonomy.Coordinator and the original
source variable used in the test to perform these assertions.
In `@packages/ui/src/components/kind-chip.test.tsx`:
- Around line 20-25: The test comparing dot?.style.background to
KIND_DOT_COLORS.receipt is brittle because different environments may normalize
CSS values; update the assertion in the KindChip test to check the raw style
string contains the CSS variable instead of strict equality — e.g., assert that
dot?.getAttribute('style') or dot?.style.background includes
KIND_DOT_COLORS.receipt (reference KIND_DOT_COLORS.receipt and the KindChip test
case) so the test remains stable across environments.
In `@packages/ui/src/components/mono-badge.tsx`:
- Line 20: The comment/docs for the MonoBadge component are out of sync because
the style key "solid-accent" (a non-tinted variant) is supported but not
documented; update the component comment or JSDoc in mono-badge.tsx (MonoBadge /
the styles mapping that contains "solid-accent") to explicitly describe both
tinted and non-tinted tones, noting that "solid-accent" is a non-tinted variant
that uses --color-accent and --color-accent-ink, and add a short usage note so
consumers understand when to choose "solid-accent" vs the tinted variants.
In `@web/src/components/app-sidebar.tsx`:
- Around line 138-148: NavItem and FooterSlot duplicate the same active
container and indicator class strings which risks style drift; extract those
shared classes into a local constant or helper (e.g., ACTIVE_CONTAINER_CLASSES
and ACTIVE_INDICATOR_CLASSES) and use them in both NavItem and FooterSlot where
isActive controls the container class and the indicator span (refer to the
isActive conditional rendering and the span with
data-testid={`nav-active-${testKey}`}) so both components reuse the same class
definitions.
In `@web/src/systems/network/components/network-workspace-shell.tsx`:
- Around line 79-97: The AVATAR_PALETTE array embeds hardcoded hex values;
update it to reference design-system tokens instead and ensure
pickAvatarColors(seed) returns those token references. Replace the literal hex
pairs in AVATAR_PALETTE with CSS variable names (or exported token constants)
defined in tokens.css or the DESIGN.md avatar color spec, e.g., use token
identifiers like --avatar-bg-1 / --avatar-fg-1 (or exported JS constants) so
AVATAR_PALETTE and pickAvatarColors rely on canonical tokens rather than ad-hoc
hex strings; also add or verify corresponding variables exist in tokens.css per
the design spec.
- Around line 432-434: The hover color uses an ad-hoc opacity value
("hover:bg-white/[0.014]") inside the className built by cn; replace that inline
alpha with the project token-based hover surface token from tokens.css (e.g.,
use the CSS variable token instead of the ad-hoc value) by swapping
"hover:bg-white/[0.014]" for the corresponding token-based class or utility
(reference the className string and cn call where grouped is used to locate the
site of change) so the component uses the standardized hover surface token
rather than an inline color.
In
`@web/src/systems/network/components/stories/network-workspace-shell.stories.tsx`:
- Around line 56-61: The requireFixture function uses globalThis.Error which is
unconventional; change the throw to use the plain Error constructor instead
(replace globalThis.Error with Error) in function requireFixture to follow
idiomatic/global lint expectations and keep behavior identical.
In `@web/src/systems/network/mocks/network-mocks.test.ts`:
- Around line 48-76: Add a negative test to network-mocks.test.ts that uses
getResponse and handlers to POST to "http://localhost/api/network/send" with a
request body missing a required field (e.g., omit channel or kind or session_id)
and assert the response has status 400 (response?.ok === false) and that the
returned JSON contains an error describing the missing field (e.g., contains
"missing" or specific field name); keep the same Request construction pattern as
the happy-path test to ensure the validation behavior is locked down.
🪄 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: dc973a48-bc95-4840-b545-3301b77540ab
⛔ Files ignored due to path filters (16)
.compozy/tasks/autonomous/reviews-002/_meta.mdis excluded by!**/*.md.compozy/tasks/autonomous/reviews-002/issue_001.mdis excluded by!**/*.md.compozy/tasks/autonomous/reviews-002/issue_002.mdis excluded by!**/*.md.compozy/tasks/autonomous/reviews-002/issue_003.mdis excluded by!**/*.md.compozy/tasks/autonomous/reviews-002/issue_004.mdis excluded by!**/*.md.compozy/tasks/autonomous/reviews-002/issue_005.mdis excluded by!**/*.md.compozy/tasks/autonomous/reviews-002/issue_006.mdis excluded by!**/*.md.compozy/tasks/autonomous/reviews-002/issue_007.mdis excluded by!**/*.md.compozy/tasks/autonomous/reviews-002/issue_008.mdis excluded by!**/*.md.compozy/tasks/autonomous/reviews-002/issue_009.mdis excluded by!**/*.md.compozy/tasks/autonomous/reviews-002/issue_010.mdis excluded by!**/*.md.compozy/tasks/autonomous/reviews-002/issue_011.mdis excluded by!**/*.md.compozy/tasks/autonomous/reviews-002/issue_012.mdis excluded by!**/*.mdopenapi/agh.jsonis excluded by!**/*.jsonpackages/ui/README.mdis excluded by!**/*.mdweb/src/generated/agh-openapi.d.tsis excluded by!**/generated/**
📒 Files selected for processing (85)
internal/agentidentity/identity.gointernal/api/core/agent_channels.gointernal/api/core/agent_channels_internal_test.gointernal/api/core/agent_identity.gointernal/api/core/agent_tasks.gointernal/api/core/conversions_parsers_test.gointernal/api/core/handlers.gointernal/api/core/interfaces.gointernal/api/core/tasks_surface_integration_test.gointernal/api/spec/spec.gointernal/api/udsapi/agent_channels_test.gointernal/api/udsapi/agent_identity_test.gointernal/api/udsapi/agent_tasks_test.gointernal/api/udsapi/handlers_test.gointernal/api/udsapi/routes.gointernal/api/udsapi/server.gointernal/automation/dispatch.gointernal/automation/dispatch_stop_timeout_test.gointernal/automation/dispatch_test.gointernal/cli/agent_kernel_test.gointernal/cli/cli_integration_test.gointernal/cli/client_test.gointernal/daemon/daemon.gointernal/daemon/daemon_integration_test.gointernal/daemon/harness_context.gointernal/daemon/harness_context_test.gointernal/daemon/hooks_bridge.gointernal/daemon/notifier_test.gointernal/daemon/scheduler_runtime.gointernal/hooks/matcher.gointernal/hooks/matcher_test.gointernal/network/manager.gointernal/network/manager_test.gointernal/network/router.gointernal/network/router_test.gointernal/observe/observer.gointernal/observe/observer_test.gointernal/scheduler/scheduler.gointernal/scheduler/scheduler_channel_test.gointernal/scheduler/types.gointernal/session/manager_start.gointernal/session/query.gointernal/session/session.gointernal/store/globaldb/global_db_task.gointernal/store/globaldb/global_db_task_test.gointernal/store/types.gointernal/task/hooks.gointernal/task/hooks_test.gointernal/task/lease_hooks.gointernal/task/manager.gointernal/task/manager_integration_test.gointernal/workspace/clone.gointernal/workspace/resolver_test.gopackages/ui/src/components/kind-chip.test.tsxpackages/ui/src/components/kind-chip.tsxpackages/ui/src/components/mono-badge.test.tsxpackages/ui/src/components/mono-badge.tsxpackages/ui/src/components/mono-chip.test.tsxpackages/ui/src/components/mono-chip.tsxpackages/ui/src/components/pills.tsxpackages/ui/src/components/search-input.tsxpackages/ui/src/components/sidebar.tsxpackages/ui/src/components/stories/kind-chip.stories.tsxpackages/ui/src/components/stories/mono-chip.stories.tsxpackages/ui/src/components/stories/typing-dots.stories.tsxpackages/ui/src/components/stories/wire-card.stories.tsxpackages/ui/src/components/stories/wire-chip.stories.tsxpackages/ui/src/components/typing-dots.test.tsxpackages/ui/src/components/typing-dots.tsxpackages/ui/src/components/wire-card.test.tsxpackages/ui/src/components/wire-card.tsxpackages/ui/src/components/wire-chip.test.tsxpackages/ui/src/components/wire-chip.tsxpackages/ui/src/index.tspackages/ui/src/tokens.cssweb/src/components/app-sidebar.test.tsxweb/src/components/app-sidebar.tsxweb/src/routes/_app/-network.test.tsxweb/src/routes/_app/stories/-network.stories.tsxweb/src/storybook/web-storybook-stories-and-fixtures.test.tsxweb/src/systems/network/components/network-workspace-shell.tsxweb/src/systems/network/components/stories/network-create-channel-dialog.stories.tsxweb/src/systems/network/components/stories/network-workspace-shell.stories.tsxweb/src/systems/network/mocks/handlers.tsweb/src/systems/network/mocks/network-mocks.test.ts
💤 Files with no reviewable changes (1)
- internal/cli/cli_integration_test.go
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
internal/task/hooks_test.go (1)
189-230:⚠️ Potential issue | 🟠 MajorWrap this case in a
t.Run("Should...")subtest to satisfy test policy.Line 189 defines a new test case body directly; this file’s policy requires
Should...subtests for test cases.Suggested structure update
func TestTaskRunPreClaimHookUsesCallerCancellation(t *testing.T) { t.Parallel() - - var preClaimCtx context.Context - store := newInMemoryManagerStore() - manager := newTaskManagerForTestWithOptions(t, store, WithTaskRunHooks(recordingTaskRunHooks{ - preClaim: func( - ctx context.Context, - payload hookspkg.TaskRunPreClaimPayload, - ) (hookspkg.TaskRunPreClaimPayload, error) { - preClaimCtx = ctx - return payload, nil - }, - })) - actor := validActorContext() - taskRecord, err := manager.CreateTask(context.Background(), CreateTask{ - Scope: ScopeGlobal, - Title: "Pre-claim hook context task", - }, actor) - if err != nil { - t.Fatalf("CreateTask() error = %v", err) - } - run, err := manager.EnqueueRun(context.Background(), EnqueueRun{TaskID: taskRecord.ID}, actor) - if err != nil { - t.Fatalf("EnqueueRun() error = %v", err) - } - - claimCtx, cancelClaim := context.WithCancel(context.Background()) - if _, err := manager.ClaimRun(claimCtx, run.ID, ClaimRun{}, actor); err != nil { - t.Fatalf("ClaimRun() error = %v", err) - } - cancelClaim() - - if preClaimCtx == nil { - t.Fatal("pre-claim hook context was not captured") - } - select { - case <-preClaimCtx.Done(): - default: - t.Fatal("pre-claim hook context was not canceled with caller context") - } + t.Run("Should cancel pre-claim hook context with caller cancellation", func(t *testing.T) { + var preClaimCtx context.Context + store := newInMemoryManagerStore() + manager := newTaskManagerForTestWithOptions(t, store, WithTaskRunHooks(recordingTaskRunHooks{ + preClaim: func( + ctx context.Context, + payload hookspkg.TaskRunPreClaimPayload, + ) (hookspkg.TaskRunPreClaimPayload, error) { + preClaimCtx = ctx + return payload, nil + }, + })) + actor := validActorContext() + taskRecord, err := manager.CreateTask(context.Background(), CreateTask{ + Scope: ScopeGlobal, + Title: "Pre-claim hook context task", + }, actor) + if err != nil { + t.Fatalf("CreateTask() error = %v", err) + } + run, err := manager.EnqueueRun(context.Background(), EnqueueRun{TaskID: taskRecord.ID}, actor) + if err != nil { + t.Fatalf("EnqueueRun() error = %v", err) + } + + claimCtx, cancelClaim := context.WithCancel(context.Background()) + if _, err := manager.ClaimRun(claimCtx, run.ID, ClaimRun{}, actor); err != nil { + t.Fatalf("ClaimRun() error = %v", err) + } + cancelClaim() + + if preClaimCtx == nil { + t.Fatal("pre-claim hook context was not captured") + } + select { + case <-preClaimCtx.Done(): + default: + t.Fatal("pre-claim hook context was not canceled with caller context") + } + }) }As per coding guidelines,
**/*_test.go: "MUST use t.Run("Should...") pattern for ALL test cases".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/task/hooks_test.go` around lines 189 - 230, The test TestTaskRunPreClaimHookUsesCallerCancellation must be wrapped in a t.Run subtest with a "Should..." description; refactor the body so the existing logic (creation of store, manager via newTaskManagerForTestWithOptions, capturing preClaimCtx in the preClaim hook, CreateTask, EnqueueRun, creating claimCtx and calling manager.ClaimRun, calling cancelClaim, and the final assertions on preClaimCtx.Done()) is executed inside t.Run("Should cancel pre-claim hook context when caller cancels", func(t *testing.T) { ... }), keeping references to TestTaskRunPreClaimHookUsesCallerCancellation, manager.ClaimRun, and preClaimCtx unchanged.
🧹 Nitpick comments (5)
web/src/systems/network/storybook.ts (1)
1-1: Replace wildcard re-export with an explicit export binding.Line 1 uses a wildcard re-export (
export * as ... from ...), which breaks the repo rule that forbidsexport * frominweb/src. You can keep the same consumer API with an explicit namespace import/export.Proposed change
-export * as networkWorkspaceShellStories from "./components/stories/network-workspace-shell.stories"; +import * as networkWorkspaceShellStories from "./components/stories/network-workspace-shell.stories"; + +export { networkWorkspaceShellStories };As per coding guidelines "
web/src/**/*.{tsx,ts}: Prefer named exports for components and utils; noexport * from."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/network/storybook.ts` at line 1, The wildcard re-export "export * as networkWorkspaceShellStories from \"./components/stories/network-workspace-shell.stories\"" violates the repo rule; replace it with an explicit namespace import and named export: add "import * as networkWorkspaceShellStories from \"./components/stories/network-workspace-shell.stories\";" and then "export { networkWorkspaceShellStories };" so consumers keep the same API while avoiding "export *".internal/scheduler/scheduler_channel_test.go (1)
15-125: Consider converting these subtests to a table-driven layout.The three subtests repeat nearly identical setup/assert scaffolding. A table-driven structure would reduce duplication and make it easier to add new channel-compatibility cases.
♻️ Suggested refactor sketch
func TestRunOnceHonorsCoordinationChannel(t *testing.T) { t.Parallel() - t.Run("Should wake only same-channel sessions for channel-bound work", func(t *testing.T) { - ... - }) - - t.Run("Should record no match when only wrong-channel sessions are available", func(t *testing.T) { - ... - }) - - t.Run("Should record no match when only unscoped sessions are available for channel-bound work", func(t *testing.T) { - ... - }) + tests := []struct { + name string + base time.Time + sessions []SessionSnapshot + wantAttempts int + wantSucceeded int + wantNoMatch int + wantTargetID string + }{ + { + name: "Should wake only same-channel sessions for channel-bound work", + base: time.Date(2026, 4, 26, 13, 30, 0, 0, time.UTC), + sessions: []SessionSnapshot{ + {ID: "sess-marketing", WorkspaceID: "ws-1", Channel: "marketing", State: "active", Capabilities: []string{"go"}}, + {ID: "sess-finance", WorkspaceID: "ws-1", Channel: "finance", State: "active", Capabilities: []string{"go"}}, + }, + wantAttempts: 1, wantSucceeded: 1, wantNoMatch: 0, wantTargetID: "sess-finance", + }, + { + name: "Should record no match when only wrong-channel sessions are available", + base: time.Date(2026, 4, 26, 13, 45, 0, 0, time.UTC), + sessions: []SessionSnapshot{ + {ID: "sess-marketing", WorkspaceID: "ws-1", Channel: "marketing", State: "active", Capabilities: []string{"go"}}, + }, + wantAttempts: 0, wantSucceeded: 0, wantNoMatch: 1, + }, + { + name: "Should record no match when only unscoped sessions are available for channel-bound work", + base: time.Date(2026, 4, 26, 14, 0, 0, 0, time.UTC), + sessions: []SessionSnapshot{ + {ID: "sess-unscoped", WorkspaceID: "ws-1", Channel: "", State: "active", Capabilities: []string{"go"}}, + }, + wantAttempts: 0, wantSucceeded: 0, wantNoMatch: 1, + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + work := workSnapshot("task-1", "run-1", taskpkg.ScopeWorkspace, "ws-1", []string{"go"}, tc.base) + work.Run.CoordinationChannelID = "finance" + source := &fakeTaskSource{pending: []RunSnapshot{work}} + sessions := &fakeSessionSource{sessions: tc.sessions} + waker := &fakeWaker{} + scheduler := newTestScheduler(t, source, sessions, waker, WithClock(clockwork.NewFakeClockAt(tc.base))) + + result, err := scheduler.RunOnce(testutil.Context(t)) + if err != nil { + t.Fatalf("RunOnce() error = %v", err) + } + if result.WakeAttempts != tc.wantAttempts || result.WakeSucceeded != tc.wantSucceeded || result.NoMatchRuns != tc.wantNoMatch { + t.Fatalf("result = %#v, wants attempts=%d succeeded=%d noMatch=%d", result, tc.wantAttempts, tc.wantSucceeded, tc.wantNoMatch) + } + targets := waker.targetsSnapshot() + if tc.wantTargetID == "" { + if len(targets) != 0 { + t.Fatalf("wake targets = %d, want 0", len(targets)) + } + return + } + if len(targets) != 1 || targets[0].Session.ID != tc.wantTargetID { + t.Fatalf("targets = %#v, want single target %q", targets, tc.wantTargetID) + } + }) + } }As per coding guidelines:
**/*_test.go: “Follow conventions: ... use table-driven layout.”🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/scheduler/scheduler_channel_test.go` around lines 15 - 125, The three nearly identical subtests ("Should wake only same-channel sessions for channel-bound work", "Should record no match when only wrong-channel sessions are available", and "Should record no match when only unscoped sessions are available for channel-bound work") should be consolidated into a table-driven test: create a slice of test cases each with a name, sessions ([]SessionSnapshot), expectedWakeAttempts, expectedNoMatchRuns, and expectedWokenSessionIDs; for each case build the same work using workSnapshot (set Run.CoordinationChannelID="finance"), create source := &fakeTaskSource{pending: []RunSnapshot{work}}, sessions := &fakeSessionSource{sessions: tc.sessions}, waker := &fakeWaker{}, scheduler := newTestScheduler(..., WithClock(clockwork.NewFakeClockAt(base))) and then call scheduler.RunOnce(testutil.Context(t)) and assert result.WakeAttempts/result.NoMatchRuns and waker.targetsSnapshot() match the expected values; reuse existing helpers (workSnapshot, fakeTaskSource, fakeSessionSource, fakeWaker, newTestScheduler, scheduler.RunOnce) so the assertions and setup logic are shared and duplication removed.internal/daemon/notifier_test.go (1)
442-483: Optional: reduce order-coupling in scoped-declaration assertions.Assertions are currently index-based (
scoped[0],scoped[1],scoped[2]). Looking up byName/Eventwould make the test more resilient to future fixture reordering.Example hardening
+findDeclByName := func(t *testing.T, decls []hookspkg.HookDecl, name string) hookspkg.HookDecl { + t.Helper() + for _, d := range decls { + if d.Name == name { + return d + } + } + t.Fatalf("hook declaration %q not found", name) + return hookspkg.HookDecl{} +} ... - if scoped[1].Matcher.WorkspaceID != resolved.ID { - t.Fatalf("task-run WorkspaceID = %q, want %q", scoped[1].Matcher.WorkspaceID, resolved.ID) - } +taskRun := findDeclByName(t, scoped, "task-run") +if taskRun.Matcher.WorkspaceID != resolved.ID { + t.Fatalf("task-run WorkspaceID = %q, want %q", taskRun.Matcher.WorkspaceID, resolved.ID) +}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/daemon/notifier_test.go` around lines 442 - 483, The test is brittle because it asserts on scoped slice elements by fixed indices (scoped[0], scoped[1], scoped[2]); change the assertions to locate hooks by a stable identifier (e.g., HookDecl.Name or HookDecl.Event) before asserting their Matcher fields. Implement a small lookup helper that scans the scoped []hookspkg.HookDecl for the expected Name/Event and returns the matching HookDecl (or fails the test if missing), then replace the index-based checks with calls to that helper and keep the existing validation via hookspkg.ValidateMatcherForEvent.internal/api/udsapi/agent_channels_test.go (1)
112-117: Consider asserting the remaining coordinator fields to harden mapping coverage.The test currently skips
Provider,Model,MaxChildren, andMaxActivePerWorkspace, so mapping regressions there could pass undetected.Suggested assertion expansion
- if !response.Coordinator.Enabled || - response.Coordinator.AgentName != "coordinator" || - response.Coordinator.DefaultTTLSeconds != 2700 || - response.Coordinator.Source != contract.CoordinatorConfigSourceWorkspace || - response.Coordinator.WorkspaceID != "ws-1" { + if !response.Coordinator.Enabled || + response.Coordinator.AgentName != "coordinator" || + response.Coordinator.Provider != "codex" || + response.Coordinator.Model != "gpt-4o" || + response.Coordinator.DefaultTTLSeconds != 2700 || + response.Coordinator.MaxChildren != 5 || + response.Coordinator.MaxActivePerWorkspace != 1 || + response.Coordinator.Source != contract.CoordinatorConfigSourceWorkspace || + response.Coordinator.WorkspaceID != "ws-1" { t.Fatalf("coordinator = %#v, want workspace coordinator payload", response.Coordinator) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/api/udsapi/agent_channels_test.go` around lines 112 - 117, The test's coordinator assertions are incomplete—add checks for the remaining fields on response.Coordinator (Provider, Model, MaxChildren, MaxActivePerWorkspace) to fully validate the mapping; update the t.Fatalf condition in the test that currently checks Enabled, AgentName, DefaultTTLSeconds, Source, and WorkspaceID to also assert expected values for Provider, Model, MaxChildren, and MaxActivePerWorkspace so any regressions in those fields fail the test.internal/automation/dispatch_test.go (1)
799-840: Add a negative-timeout case to fully lock the fallback contract.This test validates
0, but the constructor fallback logic applies to any<= 0. Add one negative duration case to prevent regressions from<= 0to== 0.Proposed test addition
{ name: "Should fall back to default for invalid session stop timeout", opt: WithDispatcherSessionStopTimeout(0), want: defaultDispatcherSessionStopTimeout, }, + { + name: "Should fall back to default for negative session stop timeout", + opt: WithDispatcherSessionStopTimeout(-1 * time.Second), + want: defaultDispatcherSessionStopTimeout, + },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/automation/dispatch_test.go` around lines 799 - 840, Update the table-driven test in TestNewDispatcherSessionStopTimeoutOption to include a negative-duration case to ensure the constructor treats any duration <= 0 as invalid and falls back to default; specifically add a case with opt: WithDispatcherSessionStopTimeout(-1 * time.Second) and want: defaultDispatcherSessionStopTimeout so the assertion on dispatcher.sessionStopTimeout (after calling NewDispatcher with the options and WithDispatcherGlobalWorkspacePath) covers both zero and negative inputs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@internal/automation/dispatch_test.go`:
- Around line 1452-1466: The test double currently reads sessionAttemptPlan from
c.bySessionID then may return early on waitForRelease or plan.stopErr without
recording the stop attempt, so update the stub in the stop flow to append a stop
entry to c.stopLog immediately after loading plan (use c.mu to protect the
slice) and before calling waitForRelease or checking plan.stopErr; this ensures
notify, waitForRelease, and any early return paths still have their attempt
recorded for assertions (reference c.bySessionID, sessionAttemptPlan, notify,
waitForRelease, and c.stopLog).
In `@web/src/systems/network/mocks/handlers.ts`:
- Around line 143-145: The handler registered with
http.post("/api/network/send") calls await request.json() which can throw on
malformed/empty JSON and bypass the subsequent validation
(readRecord/readRequiredString); wrap the JSON parsing in a try/catch inside the
handler (around await request.json()), and on parse error return a controlled
400 response (including a brief error message like "Malformed JSON") instead of
letting the exception propagate, so the validation path using readRecord and
readRequiredString still only runs on successfully parsed JSON.
- Around line 147-167: The mock currently accepts any non-empty string for kind
(readRequiredString), which can mask invalid runtime values; add a validation
step in the handler that checks kind against an allowed set (e.g.,
["status","request","reply","blocker","handoff","result","review_request"]) and
if it is not one of those return HttpResponse.json({ error: "Invalid kind" }, {
status: 400 });—place the allowedKinds array and the validation immediately
after const kind = readRequiredString(body, "kind") and before the existing
session/channel/kind presence check so the handler only returns the message when
kind is one of the supported runtime values.
---
Duplicate comments:
In `@internal/task/hooks_test.go`:
- Around line 189-230: The test TestTaskRunPreClaimHookUsesCallerCancellation
must be wrapped in a t.Run subtest with a "Should..." description; refactor the
body so the existing logic (creation of store, manager via
newTaskManagerForTestWithOptions, capturing preClaimCtx in the preClaim hook,
CreateTask, EnqueueRun, creating claimCtx and calling manager.ClaimRun, calling
cancelClaim, and the final assertions on preClaimCtx.Done()) is executed inside
t.Run("Should cancel pre-claim hook context when caller cancels", func(t
*testing.T) { ... }), keeping references to
TestTaskRunPreClaimHookUsesCallerCancellation, manager.ClaimRun, and preClaimCtx
unchanged.
---
Nitpick comments:
In `@internal/api/udsapi/agent_channels_test.go`:
- Around line 112-117: The test's coordinator assertions are incomplete—add
checks for the remaining fields on response.Coordinator (Provider, Model,
MaxChildren, MaxActivePerWorkspace) to fully validate the mapping; update the
t.Fatalf condition in the test that currently checks Enabled, AgentName,
DefaultTTLSeconds, Source, and WorkspaceID to also assert expected values for
Provider, Model, MaxChildren, and MaxActivePerWorkspace so any regressions in
those fields fail the test.
In `@internal/automation/dispatch_test.go`:
- Around line 799-840: Update the table-driven test in
TestNewDispatcherSessionStopTimeoutOption to include a negative-duration case to
ensure the constructor treats any duration <= 0 as invalid and falls back to
default; specifically add a case with opt: WithDispatcherSessionStopTimeout(-1 *
time.Second) and want: defaultDispatcherSessionStopTimeout so the assertion on
dispatcher.sessionStopTimeout (after calling NewDispatcher with the options and
WithDispatcherGlobalWorkspacePath) covers both zero and negative inputs.
In `@internal/daemon/notifier_test.go`:
- Around line 442-483: The test is brittle because it asserts on scoped slice
elements by fixed indices (scoped[0], scoped[1], scoped[2]); change the
assertions to locate hooks by a stable identifier (e.g., HookDecl.Name or
HookDecl.Event) before asserting their Matcher fields. Implement a small lookup
helper that scans the scoped []hookspkg.HookDecl for the expected Name/Event and
returns the matching HookDecl (or fails the test if missing), then replace the
index-based checks with calls to that helper and keep the existing validation
via hookspkg.ValidateMatcherForEvent.
In `@internal/scheduler/scheduler_channel_test.go`:
- Around line 15-125: The three nearly identical subtests ("Should wake only
same-channel sessions for channel-bound work", "Should record no match when only
wrong-channel sessions are available", and "Should record no match when only
unscoped sessions are available for channel-bound work") should be consolidated
into a table-driven test: create a slice of test cases each with a name,
sessions ([]SessionSnapshot), expectedWakeAttempts, expectedNoMatchRuns, and
expectedWokenSessionIDs; for each case build the same work using workSnapshot
(set Run.CoordinationChannelID="finance"), create source :=
&fakeTaskSource{pending: []RunSnapshot{work}}, sessions :=
&fakeSessionSource{sessions: tc.sessions}, waker := &fakeWaker{}, scheduler :=
newTestScheduler(..., WithClock(clockwork.NewFakeClockAt(base))) and then call
scheduler.RunOnce(testutil.Context(t)) and assert
result.WakeAttempts/result.NoMatchRuns and waker.targetsSnapshot() match the
expected values; reuse existing helpers (workSnapshot, fakeTaskSource,
fakeSessionSource, fakeWaker, newTestScheduler, scheduler.RunOnce) so the
assertions and setup logic are shared and duplication removed.
In `@web/src/systems/network/storybook.ts`:
- Line 1: The wildcard re-export "export * as networkWorkspaceShellStories from
\"./components/stories/network-workspace-shell.stories\"" violates the repo
rule; replace it with an explicit namespace import and named export: add "import
* as networkWorkspaceShellStories from
\"./components/stories/network-workspace-shell.stories\";" and then "export {
networkWorkspaceShellStories };" so consumers keep the same API while avoiding
"export *".
🪄 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: 62ac584c-d76f-4d37-ae83-34d433c73dc3
⛔ Files ignored due to path filters (99)
.agents/skills/agh-code-guidelines/SKILL.mdis excluded by!**/*.md,!.agents/**.agents/skills/agh-code-guidelines/references/coding-style.mdis excluded by!**/*.md,!.agents/**.agents/skills/agh-code-guidelines/references/concurrency-patterns.mdis excluded by!**/*.md,!.agents/**.agents/skills/agh-test-conventions/SKILL.mdis excluded by!**/*.md,!.agents/**.agents/skills/agh-test-conventions/references/test-shape-rules.mdis excluded by!**/*.md,!.agents/**.agents/skills/interface-design/SKILL.mdis excluded by!**/*.md,!.agents/**.agents/skills/interface-design/references/critique.mdis excluded by!**/*.md,!.agents/**.agents/skills/interface-design/references/example.mdis excluded by!**/*.md,!.agents/**.agents/skills/interface-design/references/principles.mdis excluded by!**/*.md,!.agents/**.agents/skills/interface-design/references/validation.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/SKILL.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/architecture.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/cli-ingest-codebase.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/cli-inspect.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/cli-search-index.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/compilation-guide.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/error-handling.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/frontmatter-schemas.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/lint-procedure.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/output-formats.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/tooling-tips.mdis excluded by!**/*.md,!.agents/**.agents/skills/obsidian-cli/SKILL.mdis excluded by!**/*.md,!.agents/**.agents/skills/viz/SKILL.mdis excluded by!**/*.md,!.agents/**.agents/skills/viz/assets/swiss-pulse-tokens.mdis excluded by!**/*.md,!.agents/**.agents/skills/viz/references/mode-diagram.mdis excluded by!**/*.md,!.agents/**.agents/skills/viz/references/mode-infographic.mdis excluded by!**/*.md,!.agents/**.agents/skills/viz/references/mode-publish.mdis excluded by!**/*.md,!.agents/**.agents/skills/viz/references/mode-visualize.mdis excluded by!**/*.md,!.agents/**.compozy/tasks/_archived/20260417-021722-site/_techspec.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/_meta.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_001.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_002.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_003.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_004.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_005.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_006.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_007.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_008.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_009.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_010.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_011.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_012.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_013.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_014.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_015.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_016.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_017.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_018.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_019.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_020.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_021.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_022.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_023.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_024.mdis excluded by!**/*.md.compozy/tasks/qa-review/reviews-001/issue_025.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/_meta.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_001.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_002.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_003.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_004.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_005.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_006.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_007.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_008.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_009.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_010.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_011.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_012.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_013.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_014.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_015.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_016.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_017.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_018.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_019.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_020.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_021.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_022.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_023.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_024.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_025.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_026.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_027.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_028.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_029.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_030.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_031.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_032.mdis excluded by!**/*.md.compozy/tasks/qa-rounds/reviews-001/issue_033.mdis excluded by!**/*.mdAGENTS.mdis excluded by!**/*.mdCLAUDE.mdis excluded by!**/*.mdDESIGN.mdis excluded by!**/*.mddocs/_memory/analysis/analysis_existing_surfaces.mdis excluded by!**/*.mddocs/_memory/analysis/analysis_qmd_collections.mdis excluded by!**/*.mddocs/design/design-system/ui_kits/marketing/Sections.jsxis excluded by!docs/design/**/*internal/AGENTS.mdis excluded by!**/*.mdinternal/CLAUDE.mdis excluded by!**/*.mdpackages/site/AGENTS.mdis excluded by!**/*.mdpackages/site/CLAUDE.mdis excluded by!**/*.md
📒 Files selected for processing (33)
.compozy/tasks/_archived/20260417-021722-site/architecture.htmlinternal/api/core/agent_identity.gointernal/api/udsapi/agent_channels_test.gointernal/automation/dispatch.gointernal/automation/dispatch_test.gointernal/daemon/daemon_integration_test.gointernal/daemon/harness_context_test.gointernal/daemon/notifier_test.gointernal/hooks/matcher_test.gointernal/network/manager_test.gointernal/network/router.gointernal/network/router_test.gointernal/observe/observer.gointernal/observe/observer_test.gointernal/scheduler/scheduler.gointernal/scheduler/scheduler_channel_test.gointernal/session/query.gointernal/session/query_test.gointernal/store/globaldb/global_db_task_test.gointernal/task/hooks.gointernal/task/hooks_test.gointernal/task/manager_integration_test.gointernal/workspace/resolver_test.gopackages/ui/src/components/kind-chip.test.tsxpackages/ui/src/components/mono-badge.tsxweb/src/components/app-sidebar.tsxweb/src/routes/_app/stories/-network.stories.tsxweb/src/storybook/web-storybook-stories-and-fixtures.test.tsxweb/src/systems/network/components/network-workspace-shell.tsxweb/src/systems/network/components/stories/network-workspace-shell.stories.tsxweb/src/systems/network/mocks/handlers.tsweb/src/systems/network/mocks/network-mocks.test.tsweb/src/systems/network/storybook.ts
✅ Files skipped from review due to trivial changes (3)
- internal/task/hooks.go
- .compozy/tasks/_archived/20260417-021722-site/architecture.html
- web/src/routes/_app/stories/-network.stories.tsx
🚧 Files skipped from review as they are similar to previous changes (12)
- packages/ui/src/components/mono-badge.tsx
- internal/scheduler/scheduler.go
- internal/store/globaldb/global_db_task_test.go
- internal/automation/dispatch.go
- web/src/systems/network/components/stories/network-workspace-shell.stories.tsx
- internal/daemon/harness_context_test.go
- web/src/storybook/web-storybook-stories-and-fixtures.test.tsx
- internal/observe/observer_test.go
- web/src/systems/network/mocks/network-mocks.test.ts
- web/src/components/app-sidebar.tsx
- internal/network/router.go
- internal/network/manager_test.go
| c.mu.Lock() | ||
| plan, ok := c.bySessionID[id] | ||
| c.mu.Unlock() | ||
| if !ok { | ||
| plan = sessionAttemptPlan{} | ||
| } | ||
|
|
||
| notify(plan.stopStarted) | ||
| if err := waitForRelease(ctx, plan.stopRelease); err != nil { | ||
| return err | ||
| } | ||
| if plan.stopErr != nil { | ||
| return plan.stopErr | ||
| } | ||
|
|
There was a problem hiding this comment.
Record stop attempts before wait/error branches in the test double.
On Line 1460 and Line 1463, early returns bypass c.stopLog append, so failed/timed-out stop attempts are invisible to assertions. Log first, then block/fail.
Proposed fix
func (c *recordingSessionCreator) StopWithCause(
ctx context.Context,
id string,
cause session.StopCause,
detail string,
) error {
if err := ctx.Err(); err != nil {
return err
}
c.mu.Lock()
plan, ok := c.bySessionID[id]
- c.mu.Unlock()
if !ok {
plan = sessionAttemptPlan{}
}
+ c.stopLog = append(c.stopLog, stopCall{
+ sessionID: strings.TrimSpace(id),
+ cause: cause,
+ detail: strings.TrimSpace(detail),
+ })
+ c.mu.Unlock()
notify(plan.stopStarted)
if err := waitForRelease(ctx, plan.stopRelease); err != nil {
return err
}
if plan.stopErr != nil {
return plan.stopErr
}
-
- c.mu.Lock()
- defer c.mu.Unlock()
-
- c.stopLog = append(c.stopLog, stopCall{
- sessionID: strings.TrimSpace(id),
- cause: cause,
- detail: strings.TrimSpace(detail),
- })
return nil
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@internal/automation/dispatch_test.go` around lines 1452 - 1466, The test
double currently reads sessionAttemptPlan from c.bySessionID then may return
early on waitForRelease or plan.stopErr without recording the stop attempt, so
update the stub in the stop flow to append a stop entry to c.stopLog immediately
after loading plan (use c.mu to protect the slice) and before calling
waitForRelease or checking plan.stopErr; this ensures notify, waitForRelease,
and any early return paths still have their attempt recorded for assertions
(reference c.bySessionID, sessionAttemptPlan, notify, waitForRelease, and
c.stopLog).
| http.post("/api/network/send", async ({ request }) => { | ||
| const body = readRecord(await request.json()); | ||
| const sessionId = readRequiredString(body, "session_id"); |
There was a problem hiding this comment.
Handle malformed JSON with a controlled 400 response.
At Line 144, await request.json() can throw for malformed/empty JSON and skip your explicit validation path.
Proposed fix
http.post("/api/network/send", async ({ request }) => {
- const body = readRecord(await request.json());
+ let parsed: unknown;
+ try {
+ parsed = await request.json();
+ } catch {
+ return HttpResponse.json({ error: "Invalid JSON body." }, { status: 400 });
+ }
+
+ const body = readRecord(parsed);
const sessionId = readRequiredString(body, "session_id");
const channel = readRequiredString(body, "channel");
const kind = readRequiredString(body, "kind");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/systems/network/mocks/handlers.ts` around lines 143 - 145, The
handler registered with http.post("/api/network/send") calls await
request.json() which can throw on malformed/empty JSON and bypass the subsequent
validation (readRecord/readRequiredString); wrap the JSON parsing in a try/catch
inside the handler (around await request.json()), and on parse error return a
controlled 400 response (including a brief error message like "Malformed JSON")
instead of letting the exception propagate, so the validation path using
readRecord and readRequiredString still only runs on successfully parsed JSON.
| const kind = readRequiredString(body, "kind"); | ||
|
|
||
| if (!sessionId || !channel || !kind) { | ||
| return HttpResponse.json( | ||
| { error: "Session, channel, and kind are required." }, | ||
| { status: 400 } | ||
| ); | ||
| } | ||
|
|
||
| return HttpResponse.json({ | ||
| message: { | ||
| id: readOptionalString(body, "id") ?? "msg_storybook_sent", | ||
| session_id: sessionId, | ||
| channel, | ||
| kind, | ||
| to: readOptionalString(body, "to"), | ||
| interaction_id: readOptionalString(body, "interaction_id"), | ||
| reply_to: readOptionalString(body, "reply_to"), | ||
| trace_id: readOptionalString(body, "trace_id"), | ||
| causation_id: readOptionalString(body, "causation_id"), | ||
| expires_at: typeof body?.expires_at === "number" ? body.expires_at : undefined, |
There was a problem hiding this comment.
Constrain kind to supported runtime values in the mock.
At Line 147/161, any non-empty string is accepted as kind. That can make Storybook/tests pass for values runtime won’t accept.
Proposed fix
+const NETWORK_MESSAGE_KINDS = new Set([
+ "status",
+ "request",
+ "reply",
+ "blocker",
+ "handoff",
+ "result",
+ "review_request",
+]);
+
export const handlers: HttpHandler[] = [
@@
http.post("/api/network/send", async ({ request }) => {
@@
if (!sessionId || !channel || !kind) {
return HttpResponse.json(
{ error: "Session, channel, and kind are required." },
{ status: 400 }
);
}
+
+ if (!NETWORK_MESSAGE_KINDS.has(kind)) {
+ return HttpResponse.json({ error: "Invalid kind." }, { status: 400 });
+ }Based on learnings: Network message kinds are limited to status / request / reply / blocker / handoff / result / review_request in MVP.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/systems/network/mocks/handlers.ts` around lines 147 - 167, The mock
currently accepts any non-empty string for kind (readRequiredString), which can
mask invalid runtime values; add a validation step in the handler that checks
kind against an allowed set (e.g.,
["status","request","reply","blocker","handoff","result","review_request"]) and
if it is not one of those return HttpResponse.json({ error: "Invalid kind" }, {
status: 400 });—place the allowedKinds array and the validation immediately
after const kind = readRequiredString(body, "kind") and before the existing
session/channel/kind presence check so the handler only returns the message when
kind is one of the supported runtime values.
## 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>
## 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>
## 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>
## 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 --> [](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>
## 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 --> [](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>
Summary by CodeRabbit
New Features
Improvements
UI/UX Updates
Bug Fixes