Skip to content

fix(coding-agents): cap conversation backfill per run, like git deepening - #4002

Open
oldnicke wants to merge 1 commit into
vectorize-io:mainfrom
oldnicke:fix/3990-chat-batch-per-run-cap
Open

fix(coding-agents): cap conversation backfill per run, like git deepening#4002
oldnicke wants to merge 1 commit into
vectorize-io:mainfrom
oldnicke:fix/3990-chat-batch-per-run-cap

Conversation

@oldnicke

@oldnicke oldnicke commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #3990 — conversation backfill now takes a bounded batch per run, the way git deepening already does.

deepen handed ingestChats every session the harness's chatReader returned, so the size of one run was set by however much session history happened to exist. Git ingestion, by contrast, slices DIFF_BATCH (50) out of a DEEPEN_DIFF_TARGET window per run and logs recent history fully deepened when drained.

Changes

  • chatBatch (default 5, 0 = uncapped)core/chat.ts's nextChatBatch() bounds each run to the N most recent pending sessions; later runs take the rest, and dedup by chat:<id> is what makes them advance.
  • Newest-first is not symmetric with git, which is the subtle part. rev-list is newest-first, so git slices the head; the session backlog is chronological (ingestChats relies on that order to stagger synthesized timestamps, since a later chat may amend an earlier one), so nextChatBatch slices the tail. Slicing the head would have ingested the oldest sessions and left recent decisions for last.
  • Default well below 50 — a commit contributes one diff, a session contributes a whole compacted transcript.
  • Log lines mirroring git's: how many were deferred (ingesting the 5 most recent of 19 pending conversations (chatBatch=5) — the rest follow on later runs) and, on the drained run, conversation history fully ingested (N sessions).
  • install --import-conversations passes --chat-batch 0. That run is attended, prints the session and turn count up front and warns that it takes a while; silently importing 5 of 19 and leaving the rest to a path that never runs on its own would be the worse surprise. --chat-batch also gives the benchmark/e2e suites a deterministic one-shot ingest. A malformed flag value falls back to the configured cap, not to uncapped — a typo must not be what makes an unattended run unbounded again.
  • chatBatch rides the existing config layering (file, per-harness, per-bank, HINDSIGHT_CHAT_BATCH), and is documented in the README, the generated companion skill and the docs page.

One correction to the issue's premise

Worth flagging for triage: on 0.4.3 the SessionStart-spawned run does not feed conversations at all. startBackgroundSeed spawns deepen --repo ... --gitlog-limit ... with no --conversations, and every harness's reader is jsonChatReader, which returns [] without that file (confirmed against the published tarball: dist/deepen.js contains no reference to .claude/projects or importLocalHistory). The only path that currently feeds sessions is the opt-in install --import-conversations, which builds the temp file from importLocalHistory.

So the unbounded run that exists today is that explicit import — which is why it keeps its uncapped behaviour here — and this PR adds the guard the issue asks for on every non-interactive run, including any future automatic feed. If the 265 MB run described in the issue happened without --import-conversations, that is a second bug (something feeding sessions into a background run) and the deepen log line from that run would be the thing to chase.

Testing

  • npm test in hindsight-integrations/coding-agents: 719 passed (55 files), including the new cases.
  • New tests: nextChatBatch takes the tail / keeps a short backlog in order / treats 0 as uncapped / default stays below the diff batch; chatBatch config default, file override, explicit 0 surviving resolution (?? not ||), HINDSIGHT_CHAT_BATCH, and per-bank override.
  • docs-freshness.test.ts passes — the companion skill and the RawConfig-is-documented check cover the new field; hindsight-docs/scripts/sync-coding-agents-doc.mjs --check is clean.
  • ./scripts/hooks/lint.sh and npx tsc --noEmit clean; npx prettier --check src/ clean.
  • Not exercised against a live server: the change is in batch selection, and no e2e/benchmark path passes --conversations.

…ning

Git ingestion is deliberately progressive: each run takes DIFF_BATCH (50) of
the not-yet-ingested commits inside a DEEPEN_DIFF_TARGET window and logs
"recent history fully deepened" once drained. Conversation import had no
equivalent — deepen handed ingestChats every session the chatReader returned,
so the size of one run was set by however much session history happened to
exist. Session history is the channel with the least natural bound: it
accumulates for as long as the agent is used and has no window at all.

Add the missing per-run cap:

- `chatBatch` (default 5, `0` = uncapped) bounds each run to the N most
  RECENT pending sessions. Newest-first matters and is not symmetric with
  git: rev-list is newest-first so git slices the head, while the session
  backlog is chronological (ingestChats staggers timestamps from that order),
  so nextChatBatch slices the TAIL. Slicing the head would ingest the oldest
  sessions and leave recent decisions for last.
- The default is far below DIFF_BATCH's 50 because a commit contributes one
  diff while a session contributes a whole compacted transcript.
- deepen logs how many were deferred, and mirrors the git line with
  "conversation history fully ingested" once the backlog drains.
- `install --import-conversations` passes `--chat-batch 0`: that run is
  attended, states how many sessions it is importing and warns that it takes
  a while. Capping it would silently import 5 and leave the rest to a path
  that never runs on its own.

`chatBatch` follows the existing config layering (file, per-harness, per-bank,
HINDSIGHT_CHAT_BATCH) and is documented in the README, the companion skill and
the docs page.

Fixes vectorize-io#3990
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.

coding-agents: conversation backfill is uncapped per run, unlike progressive git deepening

1 participant