Skip to content

feat: integrate agent context snapshots into chats#26389

Draft
kylecarbs wants to merge 2 commits into
mainfrom
chatd-context-integration
Draft

feat: integrate agent context snapshots into chats#26389
kylecarbs wants to merge 2 commits into
mainfrom
chatd-context-integration

Conversation

@kylecarbs

@kylecarbs kylecarbs commented Jun 15, 2026

Copy link
Copy Markdown
Member

Makes the chat context foundation from #26385 live. That PR added the storage columns, writer queries, and a dormant agentapi.ContextDirtyMarker trigger with no production callers; this PR wires them together end to end.

When a workspace agent pushes a context snapshot, bound chats now hydrate to that snapshot's hash, and a later push with a different hash flips already-pinned chats to dirty (emitting a context_dirty watch event after the transaction commits). Chat creation pins the agent's latest snapshot when one already exists. The experimental chat API exposes this as Chat.Context (*ChatContext with dirty, dirty_since, error), and a new PUT /api/experimental/chats/{chat}/context endpoint re-pins the agent's latest snapshot and clears the dirty marker.

context_dirty_resources stays NULL (the resource-level diff is deferred to the UI phase) and the live per-turn context pull is unchanged.

The end-to-end test provisions a workspace agent via the echo provisioner, connects it over the Agent API v2.10, and exercises the full path: an initial push hydrates a bound chat (clean), a second push with a different hash marks it dirty, the API reports the dirty state, and the refresh endpoint clears it.

Decision log
  • API shape — sub-struct. Dirty state is surfaced as codersdk.Chat.Context *ChatContext { Dirty bool; DirtySince *time.Time; Error string } rather than flat fields, matching the RFC's named ChatContext type and leaving room for future fields (resource diff, sources). db2sdk.Chat populates it when the chat is context-tracked (len(ContextAggregateHash) > 0), dirty, or carries a snapshot error, and leaves it nil (omitempty) otherwise. Dirty mirrors context_dirty_since being set.
  • Marker wiring. The chat daemon is injected directly as the agentapi.ContextDirtyMarker. It is unconditionally constructed (only its background worker is gated), so the marker is always non-nil and the wiring matches every other api.chatDaemon call site. agentapi still treats a nil marker as "chatd absent", so PushContextState stays a pure write path for any future caller that does not wire chatd in.
  • Refresh is atomic. RefreshChatContext reads the agent's latest snapshot and re-pins the chat in one repeatable-read transaction, so a concurrent push cannot land between the read and the write and leave the chat pinned to a stale hash with the dirty marker cleared.
  • Hydrate + dirty run inside the push transaction. The fan-out shares the push's transaction so a concurrent refresh cannot interleave with the version gate; context_dirty watch events publish only after commit. The pinned hash on dirtied chats is intentionally left unchanged — the refresh endpoint re-pins it.
  • Dirtied chats keep their pinned hash. Drift is advisory: a dirty chat stays usable, and refreshing is the only path that advances the pinned hash.
  • Test binds chats.agent_id directly. In production the binding is set lazily during a chat turn (chatd.persistBuildAgentBinding); the test sets it via dbgen so it exercises the context flow rather than turn resolution.

Plan: coderd/x/chatd context integration + E2E (sub-struct API, create-time + push-time hydration, refresh endpoint; context_dirty_resources and the per-turn pull untouched).

🤖 Generated by Coder Agents on behalf of @kylecarbs

@github-actions

Copy link
Copy Markdown

Docs preview

📖 View docs preview for docs/reference/api/chats.md

@kylecarbs kylecarbs force-pushed the chatd-context-integration branch from 57341f8 to 9c176dc Compare June 15, 2026 22:35
Makes the chat context foundation (#26385) live. Agent context pushes now
hydrate bound chats and mark them dirty on drift, chat creation pins the
agent's latest snapshot, the experimental chat API reports the pinned
context state, and a new refresh endpoint re-pins the latest snapshot and
clears the dirty marker.

- coderd/x/chatd/context_hydration.go: HydrateAndMarkChatsDirty (push-time
  hydrate + dirty fan-out, publishes context_dirty after commit),
  hydrateChatContextOnCreate (create-time pin, best-effort), and
  RefreshChatContext (re-pin latest snapshot + clear dirty).
- coderd/workspaceagentsrpc.go: wire the chat daemon in as the agentapi
  ContextDirtyMarker, nil-guarded so a disabled daemon stays a pure write
  path.
- codersdk + db2sdk: expose Chat.Context (*ChatContext) carrying dirty
  state and snapshot error; re-add the context_dirty watch event.
- coderd: PUT /api/experimental/chats/{chat}/context refresh endpoint.

context_dirty_resources stays NULL and the live per-turn context pull is
unchanged. Adds an end-to-end test where an echo-provisioned agent pushes
an initial snapshot (hydrate), re-pushes a different hash (drift -> dirty),
the API reports dirty, and refresh clears it.
@kylecarbs kylecarbs force-pushed the chatd-context-integration branch from 9c176dc to dd9a1ee Compare June 15, 2026 23:34

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review

coder-agents-review Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Chat: Review posted | View chat
Requested: 2026-06-16 00:35 UTC by @kylecarbs
Spend: $76.08 / $100.00

Review history
  • R1 (2026-06-16): 19 reviewers, 4 Nit, 4 Note, 1 P2, 7 P3, 1 P4, COMMENT. Review
  • R2 (2026-06-16): 11 reviewers, 7 Nit, 4 Note, 1 P2, 10 P3, 1 P4, COMMENT. Review

deep-review v0.7.1 | Round 2 | 210261b..bedf763

Last posted: Round 2, 23 findings (1 P2, 10 P3, 1 P4, 7 Nit, 4 Note), COMMENT. Review

Finding inventory

Finding inventory

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 Nit Author fixed (bedf763) coderd/exp_chats.go:2627 Missing @produce json swagger annotation on refreshChatContext R1 Netero, Meruem Yes
CRF-2 Note Author fixed (bedf763) coderd/x/chatd/context_hydration.go:86 hydrateChatContextOnCreate has zero test coverage R1 Netero Yes
CRF-3 Note Author accepted R2 (no consumer for clean-transition event yet; deferred to UI phase) coderd/x/chatd/context_hydration.go:116 RefreshChatContext does not emit watch event when clearing dirty R1 Netero Yes
CRF-4 P2 Author fixed (bedf763) coderd/x/chatd/context_hydration.go:126 RefreshChatContext reads snapshot and writes pin in separate non-transactional calls; concurrent push can leave chat falsely clean R1 Mafuuu P2, Knov P2, Meruem P2, Hisoka P3, Ryosuke P3, Chopper P3, Kite P3, Knuckle P3, Razor P3 Yes
CRF-5 P3 Author fixed (bedf763) PR description Decision log claims "helper that returns nil interface" that does not exist R1 Mafu-san Yes
CRF-6 P3 Author fixed (bedf763) coderd/x/chatd/context_hydration.go:102 hydrateChatContextOnCreate unconditional SetChatContextSnapshot can overwrite concurrent push stamp R1 Hisoka P2, Ryosuke P3, Kite P3, Zoro P3 Yes
CRF-7 P3 Author fixed (bedf763) coderd/x/chatd/context_integration_test.go:115 Refresh test does not prove pinned hash advanced; a third push of hashB after refresh would close the loop R1 Bisky Yes
CRF-8 P3 Author fixed (bedf763) coderd/x/chatd/context_integration_test.go:83 ChatContext.Error field never exercised end-to-end R1 Bisky P3, Chopper P3 Yes
CRF-9 P3 Author fixed (bedf763) coderd/x/chatd/context_integration_test.go:60 No negative assertion that unrelated chats are unaffected by push fan-out R1 Chopper Yes
CRF-10 P3 Author fixed (bedf763) coderd/x/chatd/context_hydration.go:59 GetActiveChatsByAgentID fetches all active chats inside push tx when only flipped IDs needed R1 Knov P3, Hisoka Note, Knuckle Note Yes
CRF-11 P3 Author fixed (bedf763) coderd/x/chatd/context_hydration.go:86 hydrateChatContextOnCreate and RefreshChatContext duplicate resolve-latest-snapshot-and-pin sequence R1 Robin Yes
CRF-12 P4 Author fixed (bedf763) coderd/x/chatd/context_hydration.go:29 Comment bloat pattern: 7 nolint/mechanism comments restate code (lines 29, 56, 90, 117) R1 Gon P2 (downgraded: no runtime impact, comments are verbose not incorrect) Yes
CRF-13 Nit Author fixed (bedf763) coderd/x/chatd/context_hydration.go:51 Interface doc says callback is nil when nothing transitioned; implementation returns non-nil func(){} R1 Mafuuu, Knov, Razor Yes
CRF-14 Nit Author fixed (bedf763) coderd/x/chatd/context_hydration.go:44 flipped does not encode direction; dirtied matches the domain R1 Gon Yes
CRF-15 Nit Author fixed (bedf763) coderd/x/chatd/context_hydration.go:74 Inline publish loop duplicates existing publishChatPubsubEvents (chatd.go:3495) R1 Zoro Yes
CRF-16 Note Author accepted R2 (lives in #26385 foundation migration; widening scope not warranted) coderd/database/queries/chats.sql:1494 HydrateAgentChatsContext filters by archived=false but not status; stamps terminal chats too R1 Chopper Yes
CRF-17 Note Author accepted R2 (no watcher consumes Context yet; deferred to UI phase) coderd/x/chatd/chatd.go:1464 Created pubsub event published before hydration; watchers see nil Context R1 Mafuuu, Meruem Yes

Contested and acknowledged

CRF-3 (Note, coderd/x/chatd/context_hydration.go:116) - RefreshChatContext does not emit watch event on dirty clear

  • Finding: No corresponding "context clean" event when the refresh endpoint clears the dirty marker; other watchers see stale dirty state.
  • Author defense: No watcher consumes Context yet. The initiating HTTP client sees the cleared state in the 200 response. Clean-transition event deferred to the UI phase.
  • Author accepted: Consequence bounded to watch subscribers; no current consumer affected.

CRF-16 (Note, coderd/database/queries/chats.sql:1494) - HydrateAgentChatsContext stamps terminal chats

  • Finding: HydrateAgentChatsContext filters by archived=false but not by active status, unlike MarkChatsContextDirtyByAgent. Terminal chats receive a pinned hash.
  • Author defense: The query lives in the merged foundation migration (feat: add chat context pinning storage and push trigger #26385). Gating by status to match the dirty query would widen this PR's scope.
  • Author accepted: Harmless today; no UI consumer keys visibility off Context != nil.

CRF-17 (Note, coderd/x/chatd/chatd.go:1464) - Created event published before hydration

  • Finding: The "created" pubsub event carries nil Context because it fires before hydrateChatContextOnCreate runs.
  • Author defense: No watcher consumes Context yet. The HTTP creator re-reads after CreateChat and sees the hydrated state. Reordering deferred to UI phase.
  • Author accepted: Consequence bounded; no current consumer affected.

Round log

Round 1

Panel. 19 reviewers (Bisky, Hisoka, Mafu-san, Mafuuu, Pariston, Gon, Leorio, Ging-Go, Ryosuke, Chopper, Robin, Knov, Kurapika, Kite, Meruem, Knuckle, Zoro, Razor, Killua). 1 P2, 7 P3, 1 P4, 4 Nit, 4 Note. Reviewed against 210261b..dd9a1ee.

Round 2

Churn guard: PROCEED. 14 addressed, 3 acknowledged. Panel: 11 reviewers (Bisky, Hisoka, Mafu-san, Mafuuu, Pariston, Gon, Leorio, Meruem, Kite, Chopper, Knov). 2 P3, 3 Nit, 2 Note new. Reviewed against 210261b..bedf763.

| CRF-18 | P3 | Open | coderd/x/chatd/context_hydration.go:82 | Post-commit callback uses request-scoped ctx; gRPC stream death drops dirty events | R2 | Hisoka | Yes |
| CRF-19 | P3 | Open | coderd/x/chatd/context_hydration.go:79 | Post-commit re-read TOCTOU: event kind=dirty but payload may show clean | R2 | Hisoka P3, Chopper Note | Yes |
| CRF-20 | P3 | Open | coderd/x/chatd/context_integration_test.go:134 | Dirty-step assertions omit Context.Error; design invariant unverified | R2 | Chopper | Yes |
| CRF-21 | Nit | Open | coderd/x/chatd/context_hydration.go:18 | latestAgentSnapshot doc restates signature in 2 of 3 sentences | R2 | Gon | Yes |
| CRF-22 | Nit | Open | coderd/x/chatd/context_hydration.go:99 | "NULL-guarded" is SQL implementation detail in Go doc | R2 | Gon | Yes |
| CRF-23 | Nit | Open | commit message | Commit subject names process, not fix | R2 | Leorio | Yes |

About deep-review

CRF = Coder Review Finding (P0-P4, Nit, Note)

Reviewer Focus
Bisky tests
Chopper ops/errors
Churn-guard change verification
Ging language modernization
Gon naming
Hisoka edge cases
Killua perf
Kite change integrity
Knov contracts
Knuckle SQL
Kurapika security
Law decomposition
Leorio docs
Luffy product
Mafu-san process
Mafuuu contracts
Melody dispatch/pairing
Meruem structural
Nami frontend
Netero mechanical checks
Pariston premise testing
Pen-botter product gaps
Razor verification
Robin duplication
Ryosuke Go arch
Takumi concurrency
Zoro shape

🤖 Managed by Coder Agents.

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The transactional design of HydrateAndMarkChatsDirty is strong: running hydration and dirty marking inside the push's ReadModifyUpdate transaction prevents phantom events from rolled-back retries, and the post-commit callback pattern ensures watch events only fire for committed state. The SDK type design (nullable ChatContext sub-struct, omitempty) is clean.

1 P2, 7 P3, 1 P4, 4 Nit, 4 Note across 19 reviewers.

"I tried to build a case against this change and could not." (Pariston)

🤖 This review was automatically generated with Coder Agents.

Comment thread coderd/x/chatd/context_hydration.go Outdated
Comment thread coderd/x/chatd/context_hydration.go Outdated
Comment thread coderd/x/chatd/context_integration_test.go Outdated
Comment thread coderd/x/chatd/context_integration_test.go
Comment thread coderd/x/chatd/context_integration_test.go
Comment thread coderd/x/chatd/chatd.go
// Pin the chat to the agent's latest context snapshot if one exists.
// Best-effort: a chat created before its agent has pushed is hydrated
// by that agent's next push.
p.hydrateChatContextOnCreate(ctx, chat)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note [CRF-17] The created pubsub event is published (line 1459) before hydrateChatContextOnCreate runs. The event payload carries the pre-hydration chat struct, so Context is nil. Watch subscribers see a chat created with no context and have no follow-up event for the hydration. The HTTP handler re-reads after CreateChat returns, so the creator sees the hydrated state. Worth noting for the UI phase where watch events may drive real-time context badges. (Mafuuu, Meruem)

🤖

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Acknowledged — deferring to the UI phase as the Note suggests. No watcher consumes Context yet, and the HTTP creator re-reads after CreateChat, so the creator sees the hydrated state. When watch events drive context badges we'll reorder (or emit a follow-up event).

— 🤖 Coder Agents, on behalf of @kylecarbs

Comment thread coderd/x/chatd/context_hydration.go
// clears the dirty marker. It backs PUT /chats/{chat}/context (no body). A
// chat with no bound agent, or whose agent has no snapshot, simply has its
// pinned hash and dirty marker cleared.
func (p *Server) RefreshChatContext(ctx context.Context, chat database.Chat) (database.Chat, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note [CRF-3] RefreshChatContext does not emit a watch event when it clears the dirty marker. HydrateAndMarkChatsDirty publishes ChatWatchEventKindContextDirty when a chat becomes dirty, but no corresponding event signals the transition back to clean. The initiating HTTP client sees the cleared state in the 200 response, but other watchers continue to see dirty until they re-fetch. (Netero)

🤖

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Acknowledged — deferring. There is no "context clean" watch event kind or consumer yet; the initiating client sees the cleared state in the 200 response. The UI phase will define the clean-transition event for other watchers.

— 🤖 Coder Agents, on behalf of @kylecarbs

Comment thread coderd/workspaceagentsrpc.go
// Chats created before the agent finished its initial push land with a
// NULL pinned hash. Stamp them now so they start clean. This is their
// first hydration, so no dirty event is emitted.
if err := tx.HydrateAgentChatsContext(ctx, database.HydrateAgentChatsContextParams{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note [CRF-16] HydrateAgentChatsContext filters only by archived = false, while MarkChatsContextDirtyByAgent also filters by active statuses (waiting, running, paused, pending, requires_action). Terminal chats (completed, errored) receive a pinned hash, causing db2sdk.Chat to emit a non-nil Context sub-struct for finished chats. Harmless today, but the UI may later key context badge visibility off Context != nil. (Chopper)

🤖

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Acknowledged — harmless today as noted. HydrateAgentChatsContext lives in the merged foundation migration (#26385); gating it by status to match the dirty query is a reasonable follow-up there rather than widening this PR's scope.

— 🤖 Coder Agents, on behalf of @kylecarbs

- RefreshChatContext now reads the snapshot and re-pins in one
  repeatable-read transaction, closing a TOCTOU window where a
  concurrent push could leave the chat pinned to a stale hash with the
  dirty marker cleared (CRF-4).
- hydrateChatContextOnCreate pins via the NULL-guarded
  HydrateAgentChatsContext so a concurrent push that already hydrated
  the chat is not clobbered (CRF-6).
- The dirty fan-out resolves only the dirtied chats after commit
  instead of scanning every active chat for the agent (CRF-10), and
  reuses publishChatPubsubEvents (CRF-15).
- Extract a shared latestAgentSnapshot helper (CRF-11), rename
  flipped->dirtied (CRF-14), align the no-op callback contract with its
  doc (CRF-13), and trim restated comments (CRF-12).
- Add @produce json to the refresh endpoint (CRF-1).
- Tests: exercise the snapshot-error path end-to-end, assert an
  agent-less chat is untouched by the fan-out, and re-push the pinned
  hash to prove refresh advanced the pin (CRF-7/8/9); add an internal
  test for create-time hydration (CRF-2).

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All 14 fixed R1 findings verified against bedf763. The R1 P2 (TOCTOU in RefreshChatContext) is properly closed: snapshot read and re-pin now share a single ReadModifyUpdate transaction with serialization-error retry. Create-time hydration correctly uses the NULL-guarded HydrateAgentChatsContext. The shared latestAgentSnapshot helper eliminated the duplication. Test coverage is substantially improved.

3 P3, 2 Nit across 11 reviewers. R1 acknowledged Notes (CRF-3, CRF-16, CRF-17) remain deferred to the UI phase.

"This is a gem." (Bisky, on the integration test)

Process note: the fix commit subject (fix(chatd): address deep-review feedback on chat context) names the process, not the fix. If not squash-merged, consider fix(chatd): close TOCTOU in context refresh, tighten create-time hydration. (Leorio)

🤖 This review was automatically generated with Coder Agents.

return func() {
dirtyChats := make([]database.Chat, 0, len(dirtiedIDs))
for _, id := range dirtiedIDs {
chat, err := p.db.GetChatByID(ctx, id)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3 [CRF-18] The publishDirty closure captures the RPC-derived ctx and uses it for p.db.GetChatByID calls after the transaction commits. If the agent's gRPC stream dies between commit and callback invocation, context cancellation silently drops every dirty pubsub notification. Database state is correct; watchers never learn about the drift.

The rest of chatd.go uses context.WithoutCancel(ctx) for exactly this class of post-commit fire-and-forget work (8 call sites: lines 2371, 2505, 2635, 2665, 2765, 5110, 5207, 5220). The fix is one line: detach ctx before the closure or inside it. (Hisoka)

🤖

// The publish runs after commit, so resolve the dirtied chats then,
// reading only the transitioned IDs rather than scanning every active
// chat for the agent.
return func() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3 [CRF-19] The publishDirty callback re-reads each dirtied chat from p.db after commit. Between commit and re-read, a concurrent RefreshChatContext can clear context_dirty_since. The callback then publishes a context_dirty event whose Chat.Context.Dirty == false. Event kind says "dirty"; payload says "clean."

The window is narrow (callback runs synchronously after commit), but structurally real. No consumer exists today, but when the UI phase wires watchers to context badges, they need to decide whether to trust the event payload or always re-fetch on context_dirty.

Capturing the chat data needed for the event payload inside the transaction (e.g., via RETURNING * or a SELECT inside the TX) would close both this and CRF-18, since the callback would not need a DB read at all. (Hisoka P3, Chopper Note)

🤖

got, err = expClient.GetChat(ctx, chat.ID)
require.NoError(t, err)
require.NotNil(t, got.Context)
require.True(t, got.Context.Dirty, "drift should mark the chat dirty")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3 [CRF-20] After push #2 marks the chat dirty, the test asserts Dirty and DirtySince but not Context.Error. MarkChatsContextDirtyByAgent sets only context_dirty_since; the pinned error should be unchanged (empty, from push #1). Adding require.Empty(t, got.Context.Error, "dirty chat's error reflects the original pin") verifies the design invariant that dirtied chats' pinned error is not overwritten by the dirty fan-out.

The complementary assertion after refresh (require.Equal(t, snapshotError, refreshed.Context.Error)) already exists. The dirty-step negative case is what distinguishes "error unchanged" from "error updated." (Chopper)

🤖

"github.com/coder/coder/v2/codersdk"
)

// latestAgentSnapshot returns the agent's most recent pinned context snapshot.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit [CRF-21] Two of the three doc sentences restate the signature. Sentence 1 ("returns the agent's most recent pinned context snapshot") restates the function name. Sentence 3 ("It takes a Store so callers can run it...") restates the db database.Store parameter. Only sentence 2 (the ok/nil-error contract) carries information the code does not show.

Trim to: // ok is false (nil error) when no snapshot exists. (Gon)

🤖

// has not pushed yet is hydrated later by that agent's next push. Failures
// are logged and swallowed so they never block chat creation.
//
// It stamps via the NULL-guarded HydrateAgentChatsContext so a concurrent

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit [CRF-22] "stamps via the NULL-guarded HydrateAgentChatsContext" leaks the SQL WHERE context_aggregate_hash IS NULL clause into the Go doc. The invariant (concurrent push that already hydrated the chat is not clobbered) is valuable; the SQL mechanism is not.

Trim to: // A concurrent push that already hydrated the chat is not clobbered. (Gon)

🤖

// ok is false (with a nil error) when the agent has not pushed a snapshot yet.
// It takes a Store so callers can run it against either the daemon database or
// an open transaction.
func latestAgentSnapshot(ctx context.Context, db database.Store, agentID uuid.UUID) (aggregateHash []byte, snapshotError string, ok bool, err error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit [CRF-23] The fix commit subject (fix(chatd): address deep-review feedback on chat context) names the process, not the fix. If not squash-merged, consider: fix(chatd): close TOCTOU in context refresh, tighten create-time hydration. (Leorio)

🤖

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant