Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: add persisted whole-chat summary with background generation - #26657

Merged
jaaydenh merged 37 commits into
mainfrom
chat-summary-62j9
Jul 23, 2026
Merged

feat: add persisted whole-chat summary with background generation#26657
jaaydenh merged 37 commits into
mainfrom
chat-summary-62j9

Conversation

@jaaydenh

@jaaydenh jaaydenh commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Adds a persisted whole-chat summary that backs the chat summary popover. A new nullable chats.summary column is populated in the background after a successful root-chat turn and pushed to clients via a new chat_summary_change watch event (distinct from summary_change, which is bound to last_turn_summary), so the popover reads chat.summary straight off the loaded Chat with no extra query.

This is the data source for the popover and per-chat cost UI built in #26649; the popover can consume chat.summary once this lands (the field is nullable, so merge order does not matter).

How it works

  • Generation runs in the existing successful-turn finalize hook, detached from the request so the user's turn is never blocked. A cadence gate generates the first summary after one completed turn, then regenerates every three turns, using the chats.summary_generated_at freshness marker. Generation reads compaction-aware history, renders it to a bounded plain-text transcript (short transcripts are skipped), and asks for a 1-3 sentence summary via structured output. Failures never clear an existing summary.
  • Staleness is guarded by history_version (mirroring last_turn_summary), so a background write racing a newer turn loses while worker lifecycle transitions cannot reject a fresh write.
  • Model selection uses the chat's configured model.

Deferred to follow-ups

  • Cost accounting: the chat_messages.cost_source discriminator and summary/title usage recording were removed from this PR so summary persistence is not blocked by hidden accounting rows advancing history_version. Title usage recording stays on main's InsertChatMessages path.
  • Model override: deployment-wide summary generation model selection is split into feat: add chat summary generation model override #26803; the base feature always uses the chat model.

Notes

  • Migration 000540 adds chats.summary and chats.summary_generated_at, and recreates chats_expanded to expose the new columns.
  • Root chats only; shared viewers pick up the summary on their next refetch (live watch events are owner-only).

Refs #26649

Add a persisted chats.summary populated by a background generator after
successful root-chat turns, delivered live via a new chat_summary_change
watch event, with per-feature cost attribution and a deployment-wide
summary-generation model override.
@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Docs preview

Check off each page once it's been reviewed. If a page changes in a later push, its checkbox clears automatically so it gets a fresh look. Pages not yet wired into the docs navigation aren't listed here.

The UnknownContextReturns400 subtest hardcodes the valid override
context list in its expected error. Adding the summary_generation
context changed the message, so update both assertions.
@jaaydenh

Copy link
Copy Markdown
Contributor Author

/coder-agents-review
@codex review

@coder-agents-review

coder-agents-review Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Chat: Review posted | View chat
Requested: 2026-06-29 13:54 UTC by @jaaydenh
Spend: $148.31 / $150.00

Review history
  • R1 (2026-06-26): 26 reviewers, 6 Nit, 1 Note, 1 P0, 2 P2, 8 P3, 4 P4, REQUEST_CHANGES. Review
  • R3 (2026-06-29), 6 Nit, 1 Note, 1 P0, 2 P2, 8 P3, 5 P4, COMMENT. Review
  • R4 (2026-06-29): 7 reviewers, 6 Nit, 1 Note, 1 P0, 2 P2, 10 P3, 5 P4, COMMENT. Review

deep-review v0.9.0 | Round 4 | c782cbc..7a57ac0

Last posted: Round 4, 25 findings (1 P0, 2 P2, 10 P3, 5 P4, 6 Nit, 1 Note), COMMENT. Review

Finding inventory

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 P3 Author fixed (313f8b7) coderd/x/chatd/chatd.go:5136 recordChatSummaryUsage duplicates ~40 lines of recordManualTitleUsage transaction body R1 Netero Yes
CRF-2 P0 Author fixed (313f8b7) coderd/database/migrations/000530_chat_summary.up.sql:1 Duplicate migration number 000530 collides with 000530_relay_host_nats_port from main R1 Mafuuu P0, Knuckle P0 Yes
CRF-3 P2 Author fixed (313f8b7) site/src/api/queries/chats.ts:468 summary_change events overwrite whole-chat summary with stale value when isFreshEnough is true; cross-clobber between event types R1 Komugi P2, Mafuuu P3 Yes
CRF-4 P2 Author fixed (313f8b7) coderd/x/chatd/chatd.go:4941 p.inflight.Go bypasses goInflight admission gate; summary goroutines launch after shutdown admission closes, blocking drain up to 120s R1 Hisoka P2, Takumi P2, Komugi P3, Meruem P3 Yes
CRF-5 P3 Author fixed (313f8b7) coderd/x/chatd/chatd.go:4968 shouldGenerateChatSummary uses stale chat snapshot; rapid turns both pass cadence gate, causing redundant LLM calls R1 Hisoka P3, Meruem P3, Killua P2, Takumi Note, Mafuuu Note Yes
CRF-6 P3 Author fixed (313f8b7) coderd/x/chatd/summary_override.go:1 summary_override.go is a verbatim structural clone of title_override.go differing only in DB getter and context string R1 Robin P3, Zoro P3, Ryosuke P3 Yes
CRF-7 P3 Author fixed (313f8b7) coderd/database/migrations/000530_chat_summary.up.sql:14 cost_source TEXT column has no CHECK constraint; accepts any string R1 Knov P3, Kite P3, Knuckle P4, Ryosuke Nit Yes
CRF-8 P3 Author fixed (313f8b7) coderd/x/chatd/chatd.go:5106 turnStatusLabelWriteTimeout used for chat summary write timeout; misleading name R1 Gon P3, Chopper Nit Yes
CRF-9 Nit Author fixed (313f8b7) coderd/x/chatd/chatd.go:5159 Comment restates code ("Use a valid empty JSON array" above content := "[]") R1 Gon Yes
CRF-10 Nit Author fixed (313f8b7) coderd/x/chatd/quickgen.go:892 summaryMaxOutputTokens comment adds nothing beyond the constant name R1 Gon Yes
CRF-11 Nit Author fixed (313f8b7) coderd/x/chatd/quickgen.go:908 renderChatSummaryTranscript doc restates role-switch filtering the code already shows R1 Gon Yes
CRF-12 Nit Author fixed (313f8b7) codersdk/chats.go:126 Chat.Summary doc includes UI implementation detail ("shown in the chat summary popover") R1 Gon Yes
CRF-13 Nit Author fixed (313f8b7) coderd/x/chatd/chatd.go:4938 Comment references nonexistent "processChat" function; actual callers go through afterGenerationOutcome R1 Takumi, Meruem Yes
CRF-14 P3 Author contested; panel closed R2 (5/6 accept) coderd/x/chatd/chatd.go:4993 No orchestration-level test covers generateAndStoreChatSummary or the interaction between recordChatSummaryUsage and updateChatSummary R1 Ryosuke P3, Chopper P3 Yes
CRF-15 P4 Author fixed (313f8b7) coderd/x/chatd/summarygen_internal_test.go:54 TestRenderChatSummaryTranscript never exercises ChatMessageVisibilityUser R1 Bisky Yes
CRF-16 P4 Author fixed (313f8b7) coderd/x/chatd/summarygen_internal_test.go:151 TestShouldGenerateChatSummary does not verify model-only user messages excluded from turn count R1 Bisky Yes
CRF-17 P3 Author fixed (313f8b7) coderd/x/chatd/quickgen.go:1074 countSentenceTerminators counts periods inside dotted identifiers (file extensions, Go packages) R1 Razor P3, Pen-Botter Note Yes
CRF-18 P4 Author contested; panel closed R2 (6/6 accept) coderd/x/chatd/chatd.go:4903 First-turn summary (threshold=1) adds near-zero value over the title R1 Luffy Yes
CRF-19 P4 Author fixed (313f8b7) site/src/pages/AgentsPage/AgentSettingsAgentsPageView.tsx:154 Settings UI exposes summary model override before the consuming popover UI ships R1 Pen-Botter Yes
CRF-20 Note Author accepted R2 (shipped API constraint) codersdk/chats.go:1775 summary_change vs chat_summary_change naming inversion (constrained by shipped API) R1 Gon, Leorio, Ryosuke, Zoro, Luffy, Pen-Botter Yes
CRF-21 P3 Author contested; panel closed R2 (6/6 accept) coderd/x/chatd/chatd.go:4961 Every successful turn loads full message history before cadence gate check; 2/3 loads are discarded R1 Killua Yes
CRF-22 Nit Author fixed (313f8b7) coderd/x/chatd/quickgen.go:1045 errors.As with pre-declared target; errors.AsType available since 1.26 and used elsewhere in codebase R1 Ging-Go Yes
CRF-23 P4 Author fixed (5d0a775) coderd/x/chatd/summarygen_internal_test.go:216 TestValidateGeneratedChatSummary does not pin CRF-17 fix (dotted identifiers in countSentenceTerminators) R2 Bisky Yes

Contested and acknowledged

CRF-14 (P3, coderd/x/chatd/chatd.go:4993) - No orchestration-level test for generateAndStoreChatSummary

  • Finding: Reviewer proposed adding a gomock integration test mirroring TestRegenerateChatTitle_PersistsAndBroadcasts to exercise the wiring (ordering, skip paths, failure-with-usage).
  • Author defense: Individual components are unit-tested, ordering is structural in generateAndStoreChatSummary, a full gomock integration test is "a reasonable follow-up" to avoid a large mock-heavy test for "marginal added safety."

CRF-18 (P4, coderd/x/chatd/chatd.go:4903) - First-turn summary threshold=1

  • Finding: After one turn, summary adds near-zero value over the title; threshold of 2-3 would defer the first LLM call.
  • Author defense: summaryFirstTurnThreshold=1 is a deliberate product choice; summaryRefreshTurnThreshold=3 bounds subsequent spend.

CRF-20 (Note, codersdk/chats.go:1775) - Event naming inversion

  • Finding: summary_change maps to last_turn_summary; chat_summary_change maps to summary. Naming is inverted.
  • Author accepted: summary_change is shipped API surface, renaming is a breaking change. chat_ prefix was the least-bad option. Leaving as documented.

CRF-21 (P3, coderd/x/chatd/chatd.go:4961) - Premature full message load before cadence gate

  • Finding: 2/3 of turns load full message history then discard it when the cadence gate rejects.
  • Author defense: The full message load is needed for both the cadence gate (countCompletedTurnsSince reads the messages) and renderChatSummaryTranscript. A lightweight COUNT query for the refresh path is "a fair optimization but out of scope for this fix."

Law analysis

Effective LOC: 1704 additions, 68 deletions (31 files). Head SHA: 0bc176d. Verdict: Don't split. Enforcement: Advisory. Concerns: 8 (schema, queries, cost attribution, background generation, model override, SDK/API, frontend, infrastructure plumbing). All serve one feature with a linear dependency chain. Effective human-reviewed content ~1285 lines at 38.7% test density.

Round log

Round 1

Panel (26 reviewers). 1 P0, 2 P2, 7 P3, 3 P4, 5 Nit, 4 Note. Reviewed against 637a801..0bc176d.

Round 2

Churn guard: PROCEED (17 addressed, 1 acknowledged, 3 contested, 0 deferred, 0 silent). Author pushed 313f8b7 addressing all P0/P2/P3 findings except CRF-14 (contested), CRF-21 (contested). CRF-18 (P4, contested). CRF-20 (Note, acknowledged). Panel closed CRF-14 (5/6), CRF-18 (6/6), CRF-21 (6/6). 1 new P4 (CRF-23).

Round 3

Churn guard: PROCEED (1 addressed). CRF-23 fixed in 5d0a775. All 23 findings resolved. Reviewed against c782cbc..5d0a775.
| CRF-24 | P3 | Open | coderd/x/chatd/chatd.go:4947 | Doc comment claims "records its cost" but usage recording was deferred to #26689 | R4 | Netero | Yes |
| CRF-25 | P3 | Open | coderd/x/chatd/summarygen_internal_test.go:204 | RefreshAfterThresholdTurns does not verify pre-marker exclusion; time filter in countCompletedTurnsSince is untested | R4 | Bisky | Yes |

Round 4

Churn guard: PROCEED (0 open from prior). Panel (7 reviewers). PR restructured: model override split to #26803, usage recording deferred to #26689, read ordering fixed, goInflight approach changed. 2 new P3s (CRF-24, CRF-25). Reviewed against c782cbc..7a57ac0.

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
Komugi flake/determinism
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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0bc176d8c4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread coderd/x/chatd/chatd.go Outdated

@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.

Deep review of PR #26657

Well-structured feature addition. The optimistic concurrency control, cost attribution, and background generation patterns are solid. Three findings worth addressing before merge.

🔴 Migration version collision

000530_chat_summary collides with 000530_relay_host_nats_port which already exists on main. golang-migrate/iofs returns source.ErrDuplicateMigration for duplicate version numbers, blocking all deployments. Renumber to 000531 (or whatever the next free slot is at merge time).

🟡 Stale chat struct in cadence gate

generateAndStoreChatSummary receives the chat struct snapshotted when the turn finished, but messages are re-read from DB. If two consecutive turns complete quickly, both background goroutines see the same stale chat.Summary.Valid / chat.SummaryGeneratedAt and both pass the cadence gate. Both generate a summary and call updateChatSummary. Since UpdateChatSummary checks history_version but does not update it, both writes can succeed; the second silently overwrites the first. The summaries are likely identical (same input), so data is not corrupted, but one LLM call is wasted.

A cheap fix: re-read the chat row at the top of generateAndStoreChatSummary:

chat, err = p.db.GetChatByID(authCtx, chat.ID)

🟡 p.inflight.Go bypasses shutdown admission gate

maybeGenerateChatSummaryAsync calls p.inflight.Go(func(){...}) directly instead of p.goInflight(func(){...}). The comment explains why (deadlock avoidance with drainInflight). The goroutine IS tracked in p.inflight so it cannot outlive the server. But combined with context.WithoutCancel(ctx) and chatSummaryWorkTimeout = 120s, a summary launched right before shutdown could block Close() for up to 2 minutes. This creates an asymmetry: finalizeSuccessfulTurnStatusLabelAndPush uses goInflight and is silently dropped during shutdown, but summary generation runs regardless.

If the 120s shutdown delay is acceptable, this is fine. If fast shutdown matters, consider adding an early select on p.ctx.Done() inside generateAndStoreChatSummary before the model call.

Comment thread coderd/database/migrations/000534_chat_summary.up.sql Outdated
Comment thread coderd/x/chatd/chatd.go
Comment thread coderd/x/chatd/chatd.go Outdated

@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.

Solid feature addition. The optimistic concurrency via history_version, cost attribution model, and background generation pipeline are well-designed. The test suite covers the critical paths: cadence gate, transcript rendering, validation, override resolution, SQL staleness race, cost source tagging, and frontend event merging. Six reviewers independently confirmed the event isolation pattern works correctly.

1 P0, 2 P2, 7 P3, 3 P4, 5 Nit.

The P0 (migration collision) blocks all CI. The two P2s (frontend cross-clobber between event types, shutdown admission bypass) are the substantive findings requiring fixes.

"The goroutine IS tracked in p.inflight so it can't outlive the server, but combined with context.WithoutCancel(ctx) and chatSummaryWorkTimeout = 120s, a summary launched right before shutdown could block Close() for up to 2 minutes." (Hisoka)

🤖 This review was automatically generated with Coder Agents.

Comment thread coderd/database/migrations/000534_chat_summary.up.sql Outdated
Comment thread site/src/api/queries/chats.ts Outdated
Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/summary_override.go Outdated
Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread site/src/pages/AgentsPage/AgentSettingsAgentsPageView.tsx Outdated
Comment thread codersdk/chats.go Outdated
Comment thread coderd/x/chatd/chatd.go Outdated
jaaydenh added 2 commits June 29, 2026 06:59
# Conflicts:
#	docs/admin/security/audit-logs.md
Resolve the actionable findings from the deep review of #26657:

- P0/CRF-2: renumber the chat summary migration from 000530 to 000534 to
  avoid colliding with 000530_relay_host_nats_port on main.
- CRF-3: scope summary_change/chat_summary_change merges to their own
  field so an equal-timestamp event cannot clobber the other summary;
  add the equal-timestamp regression tests.
- CRF-4/CRF-13: bail out of background summary generation when shutdown
  has begun so Close() is not blocked, and fix the stale comment.
- CRF-5: re-read the chat before the cadence gate so rapid turns do not
  both pass against a stale snapshot.
- CRF-7: add a CHECK constraint on chat_messages.cost_source.
- CRF-8: use a dedicated chatSummaryWriteTimeout for the summary write.
- CRF-17: only count sentence terminators at a word boundary so dotted
  identifiers do not inflate the count.
- CRF-1/CRF-6: deduplicate the usage-recording and model-override
  resolution paths shared by title and summary generation.
- CRF-15/CRF-16: cover ChatMessageVisibilityUser and model-only user
  messages in the summary tests.
- CRF-9/10/11/12/19/22: comment cleanups, errors.AsType, and drop the
  popover reference from the settings description.

Copy link
Copy Markdown
Contributor Author

Addressed the deep-review feedback in 313f8b711a (also merged latest main, which resolves the merge conflict). Summary of changes:

Blocking

  • CRF-2 (P0): Renumbered the migration 000530_chat_summary000534_chat_summary (next free slot after main's 000533) and re-ran make gen.

P2

  • CRF-3: summary/last_turn_summary are now each scoped strictly to their own watch event (chat_summary_change / summary_change) instead of isFreshEnough, so an equal-timestamp event can no longer clobber the other field. Added equal-timestamp regression tests.
  • CRF-4 / CRF-13: The background summary goroutine now returns early when inflightClosed is set, so generation can't block Close() for up to chatSummaryWorkTimeout. Rewrote the stale processChat comment.

P3

  • CRF-5: Re-read the chat via GetChatByID before the cadence gate so rapid back-to-back turns don't both pass against a stale snapshot.
  • CRF-7: Added CHECK (cost_source IN ('summary','title')) to the migration.
  • CRF-8: Added a dedicated chatSummaryWriteTimeout for the whole-chat summary write.
  • CRF-17: countSentenceTerminators now only counts terminators at a word boundary, so dotted identifiers no longer inflate the count.
  • CRF-1 / CRF-6: Deduplicated the usage-recording path (recordHiddenUsageMessageTx) and the model-override resolution path (resolveGenerationModelOverride); the override files are now thin wrappers.

P4 / Nit

  • CRF-15 / CRF-16: Added coverage for ChatMessageVisibilityUser and model-only user messages.
  • CRF-9 / CRF-10 / CRF-11 / CRF-12 / CRF-19 / CRF-22: Comment cleanups, dropped the popover reference, and switched to errors.AsType.

Responses (not changed) — left inline replies on CRF-14, CRF-18, CRF-20, and CRF-21 with rationale.

Copy link
Copy Markdown
Contributor 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 P0/P2/P3 findings from round 1 are addressed. The fixes are well-executed: the deduplication extractions (CRF-1, CRF-6) are genuine generalizations, the frontend cross-clobber fix (CRF-3) correctly scopes each field to its own event type with regression tests, the shutdown admission guard (CRF-4) avoids the deadlock concern while preventing 120s drain delays, and the cadence gate re-read (CRF-5) eliminates redundant LLM calls.

Contested findings closed by panel:

  • CRF-14 (P3, no orchestration test): 5/6 accept. Components are well-tested; orchestration is a linear pipeline with no conditional branching the unit tests miss.
  • CRF-18 (P4, first-turn threshold): 6/6 accept. Product decision.
  • CRF-21 (P3, premature full load): 6/6 accept. Messages are needed for both the cadence gate and the transcript renderer.

1 new P4 below.

"The code held up. The recordHiddenUsageMessageTx refactor is clean, the UpdateChatMessageCostSource two-step insert-then-tag avoids threading cost_source through the batch insert, and the history_version staleness guard mirrors the proven UpdateChatLastTurnSummary pattern." (Hisoka)

🤖 This review was automatically generated with Coder Agents.

Comment thread coderd/x/chatd/summarygen_internal_test.go
CRF-23: add TestCountSentenceTerminators so the CRF-17 fix is covered.
Without it, removing the word-boundary guard in countSentenceTerminators
would not fail any test. The test asserts periods inside dotted
identifiers are not counted and that a dotted-identifier-dense summary
stays under summaryMaxSentences.
@jaaydenh

Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@coder-agents-review

Copy link
Copy Markdown
Contributor

@jaaydenh ⛔ This review has reached its per-chat spend limit ($119.20 / $100.00). Further review rounds are paused.

To raise the limit and continue, comment:

/coder-agents-review set-spend-limit:150

This is a per-chat budget, separate from any account-level usage limit.

🤖 Managed by Coder Agents.

@jaaydenh

Copy link
Copy Markdown
Contributor Author

/coder-agents-review set-spend-limit:150

@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 23 findings resolved. CRF-23 (P4, test pin for dotted-identifier sentence counting) addressed in 5d0a775 with TestCountSentenceTerminators. The test asserts dotted identifiers (auth.rbac.Policy, file.go) are not counted as sentence boundaries and that a dotted-identifier-dense summary passes validation. Removing the unicode.IsSpace boundary guard now fails the test.

CI: 25 passed, 2 failing (UI Review, UI Tests). The UI failures appear unrelated to the changes in this PR.

No further findings.

🤖 This review was automatically generated with Coder Agents.

jaaydenh and others added 2 commits June 29, 2026 10:02
Move summary generation model overrides out of the persisted summary PR so the base feature always uses the chat model.

Co-authored-by: Cursor <[email protected]>
Remove cost_source, UpdateChatMessageCostSource, and summary usage
recording from the whole-chat summary feature so summary persistence
is not blocked by hidden accounting rows advancing history_version.
Title usage recording reverts to main's InsertChatMessages path.

Co-authored-by: Cursor <[email protected]>
@jaaydenh

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 877bbf0ffb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/chatd.go
Comment thread coderd/x/chatd/chatd.go Outdated
…races

Addresses two issues from the codex review of background whole-chat
summary generation:

- Read the chat (and its history_version) before loading the transcript
  so a turn committing between the two reads leaves the captured
  history_version behind the transcript. UpdateChatSummary then rejects
  the write instead of persisting a summary that omits the just-committed
  turn and advancing the cadence marker past it.

- Launch the background summary goroutine through goInflight instead of
  p.inflight.Go. goInflight serializes the WaitGroup Add with
  drainInflight under inflightMu and drops the launch once shutdown has
  begun, matching the sibling finalize and last-turn-summary helpers. The
  previous direct Add raced drainInflight's Wait and could delay Close.

Copy link
Copy Markdown
Contributor Author

Addressed the latest codex review feedback in 7a57ac0:

  • [P1] Keep the transcript and history version in syncgenerateAndStoreChatSummary now reads the chat (and its history_version) before loading the transcript, so the captured history_version is never newer than the message set it guards. A turn committing between the two reads now makes the UpdateChatSummary guard reject the write instead of persisting a summary that omits the just-committed turn.
  • [P2] Gate summary goroutines through the inflight admission lockmaybeGenerateChatSummaryAsync now launches via goInflight, which performs the WaitGroup Add under inflightMu (serialized with drainInflight) and drops the launch once shutdown has begun, matching the sibling finalize/last-turn-summary helpers.
  • [P1] Record usage from summary generation — deferred to fix(coderd): exclude accounting rows from chat history_version #26689, which adds recordChatSummaryUsage / InsertChatAccountingMessage and excludes accounting rows from history_version.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7a57ac09c5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread coderd/x/chatd/chatd.go Outdated
@jaaydenh

Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@jaaydenh

jaaydenh commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Do we really need to add over 1k lines for this? Doesn't this share functionality with title generation?

This already does share some functionality with title generation. Most of the new code is from adding a new endpoint and tests.

jaaydenh added 6 commits July 7, 2026 20:35
…00541

Main added 000540_workspace_build_orchestrations, which collided with this
branch's 000540_chat_summary and made golang-migrate fail with "duplicate
migration file" in every Postgres-backed test. Renumber to the next free
slot. The migration content is unchanged and the chats_expanded recreation
still matches the current schema; workspace_build_orchestrations does not
touch the chats table.
Comment thread coderd/database/querier_test.go Outdated
require.NoError(t, err)
db := database.New(sqlDB)

ctx := testutil.Context(t, testutil.WaitMedium)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It seems this wasn't amended?

Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/chatd.go
Comment thread coderd/x/chatd/chatd.go Outdated

// If a turn commits after this read, the stale history_version makes the
// eventual summary write lose instead of omitting that newer turn.
chat, err := p.db.GetChatByID(authCtx, chat.ID)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why do we need authCtx to fetch the chat, but we can updateChatSummary using the original ctx?

Edit: Answered this myself by reading further. It seems updateChatSummary escalates privileges by itself.

This needs a complete rethink in how it's structured IMO. The only consumer of the unauthenticated ctx seems to be generateChatSummary, and we pay the prices of juggling contexts containing auth for a single call. The mixture of self-escalating methods and non- also adds to make it harder to grasp what the authenticated path is.

Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/chatd_internal_test.go
Comment thread site/src/api/queries/chats.ts Outdated
@jaaydenh
jaaydenh requested a review from mafredri July 20, 2026 13:55
@linear-code

linear-code Bot commented Jul 21, 2026

Copy link
Copy Markdown

CODAGT-568

@mafredri mafredri left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggestions for the remaining mechanical fixes. The complete suggestion set was applied together in an isolated worktree and the affected package tests passed.

🤖 This review was automatically generated with Coder Agents.

Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/chatd.go
Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/chatd.go
Comment thread coderd/x/chatd/chatd.go
Comment thread coderd/x/chatd/chatd_internal_test.go Outdated
Comment thread coderd/x/chatd/chatd_internal_test.go Outdated
Comment thread coderd/x/chatd/chatd_internal_test.go Outdated
Comment thread coderd/x/chatd/chatd_internal_test.go Outdated
@jaaydenh
jaaydenh merged commit 3c7a1d3 into main Jul 23, 2026
32 checks passed
@jaaydenh
jaaydenh deleted the chat-summary-62j9 branch July 23, 2026 15:36
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 23, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants