feat(agent-harness): synchronize durable snapshots and legacy history - #5701
feat(agent-harness): synchronize durable snapshots and legacy history#5701iscekic wants to merge 2 commits into
Conversation
| async function drainLegacy(signal: AbortSignal = AbortSignal.timeout(30_000)) { | ||
| try { | ||
| signal.throwIfAborted(); | ||
| const authority = await authorize('drain'); |
There was a problem hiding this comment.
WARNING: Drain authorization is not bound by the drain deadline
authorize('drain') (and importLegacy's authorize('import')) omit timeoutMs, so withTimeout never wraps the raw request. signal.throwIfAborted() runs only before the first authorize and after adapter.drain. A hung authorize ignores the AbortSignal; when it later resolves, bindExistingConversation still runs and can recreate deleted local state. drainProjections already passes remaining() into authorize for this reason. Pass the remaining drain deadline into these authorize calls the same way.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| const initial = schedulerRecord(db, selected.id).data.initialHistory; | ||
| if (initial?.status === 'ready') return true; | ||
| const drainLegacy = adapter.drainLegacy; | ||
| if (!drainLegacy) return initial === null; |
There was a problem hiding this comment.
WARNING: Missing drainLegacy adapter busy-loops the Durable Object alarm
Once initialHistory is pending, this return skips the lease/backoff write that sets retryAt to now() + 1_000. maintainAlarm then setAlarm(ingress.retryAt). After that timestamp, retryAt is in the past, so each alarm re-arms immediately and never persists a new delay. Stuck-pending is intended when the adapter is removed; a hot alarm loop is not. Persist a future retryAt (or clamp a past deadline) before returning.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
Code Review SummaryStatus: 2 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
Files Reviewed (8 files)
Fix these issues in Kilo Cloud Reviewed by grok-4.6 · Input: 307.8K · Output: 27.6K · Cached: 797.4K Review guidance: REVIEW.md from base branch |
Summary
No new behavior — this change prepares chat synchronization without enabling it for users.
createSynchronizationchecks currentQuickChatAuthoritybefore and after a bounded import batch, then returns snapshots, history, or exclusive event replay. Snapshots keep settings, active and queued runs, unresolved interactions, device actions, and the event cursor together. The existingcursor_expiredresult still requires a replacement snapshot; production transport and alarm integration remain outside this level.Files
services/agent-harness/src/sync.ts— Source; added (A), 44 lines. Wraps snapshot, paged history, and event replay with authorization and request-time import. Preserves snapshot transactions and replay limits; exposes the synchronization store and drain operations.createLegacyCoordinatorintroducesLegacyAdapterandHistoryProgressSchemafor scope-checked imports and text projection, with fresh authorization before and after delivery. Imports atomically deduplicate text by universally unique identifier (UUID); completed harness text creates projection work with permanent keys in the same transaction. Projection batches share one 30-second deadline, retain 60-second retries, and fence late replies; callers must use the returned store for atomic writes.Files
services/agent-harness/src/legacy.ts— Source; added (A), 269 lines. Normalizes legacy messages as non-executable text, rejects conflicting UUID content, and validates scope and generation before returning durable receipts. Limits drains to 50 deliveries and projects only completed, nonempty text. Prearms recovery before primary waits and checks acknowledgment identity and revision. Bounds raw authorization before local binding, so timed-out replies cannot recreate deleted state. Allows smaller positive timeout overrides without requiring adapter cancellation; retries retain permanent keys.HistoryProgressadds explicitpendingordrainedstatus throughdrainLegacyHistoryWithProgressandcreateQuickChatRuntime.hasPending. The primary query checks authority and all unacknowledged legacy rows, including leased or locked rows, so an empty claim batch cannot prove completion.drainLegacyHistorykeeps its existing delivery-only signature; completion describes the final primary snapshot, not a guarantee against later commits.Files
packages/db/src/quick-chat-runtime.ts— Source; modified (M), 18 changed lines. Adds a primary-snapshot backlog query and exports it through the runtime; invalid authority raisesQuickChatAuthorityError.apps/web/src/lib/agent-harness/history.ts— Source; modified (M), 17 changed lines. Adds the scoped progress wrapper without changing the existing request or cron delivery contracts.apps/web/src/lib/agent-harness/history.test.ts— Test; modified (M), 191 changed lines. Adds PostgreSQL backlog and progress coverage, including lease and lock behavior.SchedulerAdapter.drainLegacyandSchedulerStateSchema.initialHistorygate inference on validateddrainedprogress, using persisted continuation, 30-second attempts, and one-second retries.buildHistorygainslegacyThrough, applies the frozen boundary before the 200-row limit, and excludes later queued harness input. Older executable checkpoints retain their admission boundary; callers without an adapter stay compatible, but removing an adapter cannot bypass persisted pending work.Files
services/agent-harness/src/scheduler.ts— Source; modified (M), 159 changed lines. Persists pending/ready checkpoints and retry wake times, fences stale drains, and preserves Stop without starting model reservations during import. Permanent authorization failures fail the selected run.services/agent-harness/src/model-step.ts— Source; modified (M), 42 changed lines. Replaces paged history scans with a sequence-bounded query before timestamp ordering and trimming. Later imports cannot displace frozen history after restart; legacy text remains untrusted data.services/agent-harness/src/sync.test.ts— Test; added (A), 1,506 lines. Adds SQLite coverage for snapshots, replay, authority, durable import, projections, frozen history, Stop, restart, and timeout recovery.Tests: 2 files —
history.test.tsupdated;sync.test.tsadded, with 43 SQLite synchronization cases and seven timeout/recovery cases.Generated: 0 files changed.
Verification
No manual tests ran because this level does not activate production integration or start a product stack. Full backend, browser, iOS, and Android verification remains pending at the completed stack tip.
Visual Changes
Visual Changes: N/A
Reviewer Notes
shared-agent-harness-3bb0-s14...shared-agent-harness-3bb0-s15only; two commits cover the backlog prerequisite and synchronization coordination.Kilo-Org/cloud. Worktree:/Users/igor/Projects/.worktrees/shared-agent-harness-3bb0.Human steps
No setup is required to merge this level; it adds no secret, configuration value, or database migration.
Notes
E2E: bot-e2e — full backend, browser, iOS, and Android verification remains pending at the completed stack tip.
Stacked PRs — merge bottom to top. Each level shows only its own diff.
Runtime verification (E2E, user advocacy, simplify) runs on the tip PR over every level.
Every level keeps its own checks, its own bot review, and its own threads; each one is answered on its own PR.
Each level is its own deliverable: it builds and passes its own checks alone.
A finding on a level is repaired on that level, then carried upward with stack.sh forward.
shared-agent-harness-3bb0— chore(agent-harness): register workspaces and enforce CI boundaries #5632shared-agent-harness-3bb0-s2— feat(agent-harness): define portable domain and snapshots #5637shared-agent-harness-3bb0-s3— feat(agent-harness): define commands tools and permission policy #5639shared-agent-harness-3bb0-s4— feat(agent-harness): share client state and cursor recovery #5643shared-agent-harness-3bb0-s5— feat(agent-harness): persist command intents and execution receipts #5647shared-agent-harness-3bb0-s6— feat(db): add harness ingress grants and retirement fences #5655shared-agent-harness-3bb0-s7— feat(agent-harness): deliver legacy history and project durable text #5659shared-agent-harness-3bb0-s8— feat(agent-harness): authorize durable grants and registered clients #5662shared-agent-harness-3bb0-s9— feat(agent-harness): fence retirement and retry payload cleanup #5667shared-agent-harness-3bb0-s10— feat(agent-harness): persist authoritative state in SQLite #5675shared-agent-harness-3bb0-s11— feat(agent-harness): admit durable runs and revisioned commands #5678shared-agent-harness-3bb0-s12— feat(agent-harness): recover queued runs and stream checkpointed steps #5688shared-agent-harness-3bb0-s13— feat(agent-harness): resolve interactions and dispatch tools sequentially #5693shared-agent-harness-3bb0-s14— feat(agent-harness): fence designated client tool execution #5697shared-agent-harness-3bb0-s15— feat(agent-harness): synchronize durable snapshots and legacy history #5701 ← this PRshared-agent-harness-3bb0-s16— feat(agent-harness): reuse authorized invitations with durable replay #5704shared-agent-harness-3bb0-s17— feat(integrations): bound repository transport for harness reads #5710shared-agent-harness-3bb0-s18— feat(integrations): expose bounded authorized repository reads #5714shared-agent-harness-3bb0-s19— feat(agent-harness): expose named authorized resource reads #5718 (tip)