Skip to content

cli-sessions: share and fork storage rules - #8224

Open
iscekic wants to merge 29 commits into
mainfrom
drain/cli-session-copy-limits
Open

iscekic wants to merge 29 commits into
mainfrom
drain/cli-session-copy-limits

Conversation

@iscekic

@iscekic iscekic commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Evidence

Evidence: demonstrated — An authenticated local API run against disposable PostgreSQL and a local S3-compatible fixture verified share publication, refreshed content through the same link, forking the published data, allowance refusals, the copy size bound, and delete cleanup. A separate storage exercise rebuilt a database on main's migration chain holding session rows and verified the new migration's backfill. All checks ran at head c0da2b72855b7718eb96a65e2b4f253dabd58c4f.

  • Local API exercise at head c0da2b72 (Next.js dev server, disposable PostgreSQL, local S3-compatible fixture reached through the real AWS SDK client with presigned uploads): 43 of 43 assertions passed. They covered the first publication, the same link republishing changed content into a new folder with the previous folder removed, one share row per link, forking the published data into a sessions/ copy marked as a fork, deleting the source removing the share row and both share-copy objects while the fork stayed readable, and both per-account allowances at their boundary admitting the request that reaches the limit and refusing the next one without writing a row.
  • Copy size bound: four source blobs totalling more than the copy limit made the share request answer HTTP 400 naming the limit, and neither a share row nor a shared folder was written.
  • Migration backfill: a database migrated through main's chain, holding one session row with a source reference and one without, applied the new migration through the real migrator. Both columns and the owner index were created, the index is valid, and only the row carrying a source reference was marked.
  • POSTGRES_URL=<disposable> bash scripts/verify-drizzle-bootstrap.sh — the complete migration chain, including the new migration, applied to an empty disposable database.
  • NODE_ENV=test pnpm --filter web exec jest --runInBand src/routers/cli-sessions-router.test.ts src/lib/user/deletion-queue/handlers/cli-v1.test.ts src/lib/r2/cli-sessions.test.ts — 3 suites, 150 tests passed, including concurrent snapshot access.
  • pnpm --filter @kilocode/db test --runInBand — 9 suites, 50 tests passed. The generated migration journal guard passed.
  • Concurrent publication and the per-blob upload cap are covered by the suites above; the upload route's per-type cap times the blob count equals the copy cap, so the copy limit cannot be exceeded through that route alone.
  • The allowances and the copy size limit are enforced before a copy starts, so a refused request leaves no stored data.

No visual surface changed; no screenshot is attached. Storage-provider behavior was exercised through a local S3-compatible fixture, not the production provider.

Change

Share publication uses a stable link and records current-copy URLs after copying completes. Pending folder cleanup is stored in pending_copy_ids and retried by subsequent lifecycle calls. Fork and account cleanup resolve the recorded storage folders. The branch ships one generated migration, 0302_flippant_jackpot.sql, which adds the fork marker column, the pending-copy column, and the share owner index, and backfills the fork marker from the existing source reference. It composes after main's 0301_contributor_credit_window.sql. Human merge handling remains required for the schema change.

Production prerequisites

None.

Proxy answers

The owner's proxy gave these answers in the owner's place.

  1. Question: Byte accounting — Answer: Count caps and an exact per-copy byte cap; no added byte-accounting column. Confidence: 0.55
  2. Question: Copy coverage — Answer: Apply the policy at every supported server-side copy site. Confidence: 0.90
  3. Question: Per-owner limits — Answer: 200 shares and 200 forks per owner. Confidence: 0.40
  4. Question: Share identity — Answer: Session, owner, and shared_state. Confidence: 0.60
  5. Question: Earlier publication preference — Answer: Return the existing link untouched. Confidence: 0.45
  6. Question: Fork accounting — Answer: Add the generated fork marker and owner index; require human merge handling for the schema change. Confidence: 0.75
  7. Question: Generated-file gate — Answer: Repair the gate and retry the approved workflow. Confidence: 0.85
  8. Question: Merge completion — Answer: Preserve the gated workflow. Confidence: 0.65
  9. Question: Inherited migration snapshot check — Answer: Repair the check while retaining source checks. Confidence: 0.80
  10. Question: Generated migration metadata — Answer: Fix the generated-file exemption in the workflow repository. Confidence: 0.85
  11. Question: Share publication — Answer: Refresh the existing link. This supersedes answer 5. Confidence: 0.60
  12. Question: Temporary gate routing — Answer: Allow the temporary local credential route, then restore it. Confidence: 0.70
  13. Question: Cleanup tracking — Answer: Durable cleanup tracking, retried by later lifecycle calls rather than a periodic sweep. Confidence: 0.50
  14. Question: Remaining gated publication — Answer: Allow the existing temporary local route for the remaining publications, then restore and verify it. Confidence: 0.62

CLI session copies now follow explicit per-account rules:
- one share link per session and shared state; sharing the same session
  again returns the link that already exists
- an account may hold 200 shared sessions and 200 forked sessions; the
  count is checked inside the same transaction that writes the row
- every copy is measured against the size of one session before it
  writes, and a copy that does not fit is refused
- a failed copy leaves no share row and no fork row behind
- deleting a session also deletes its share rows and their
  shared-sessions objects

BLOB_TYPES and the 5 MiB per-blob upload cap now live in
lib/cli-sessions/session-copies.ts and are shared with the v2 upload
route.
@iscekic iscekic added drain Work item from the findings drain janitor:trust Janitor finding: trust boundary hardening labels Oct 20, 2026
Comment thread apps/web/src/lib/cli-sessions/session-copies.ts Outdated
Comment thread apps/web/src/lib/cli-sessions/session-copies.ts Outdated
Comment thread apps/web/src/lib/cli-sessions/session-copies.ts Outdated
Comment thread apps/web/src/lib/cli-sessions/session-copies.ts Outdated
Comment thread apps/web/src/routers/cli-sessions-router.ts Outdated
@kilo-code-bot

kilo-code-bot Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental range since 61c4ef60 only renumbers the CLI session storage migration to 0302_flippant_jackpot.sql after main's 0301_contributor_credit_window and regenerates the snapshot/journal; the SQL content is byte-identical to the previously reviewed file and the new snapshot chains onto main's 0301 snapshot id.

Assumptions: [INFERENCE] the migrator honors the existing COMMIT;/CREATE INDEX CONCURRENTLY/BEGIN; pattern used by other migrations (the statement shape is unchanged from 0296/0301 handlings already in the repo); migration application was verified statically via the journal ordering, snapshot prevId, and SQL, not by running the migrator in this read-only review. The four earlier Kilo inline findings on this PR are carried as addressed: the fork path resolves the current share copy folder under a FOR SHARE row lock, and account cleanup takes FOR UPDATE before deleting current and pending folders.

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 0
Files Reviewed (13 files)
  • packages/db/src/migrations/0302_flippant_jackpot.sql - 0 issues (100% rename of the reviewed 0301_tranquil_photon.sql; additive NOT NULL columns carry defaults, index stays CONCURRENTLY with COMMIT;/BEGIN; boundaries, backfill scoped to forked_from IS NOT NULL)
  • packages/db/src/migrations/meta/0302_snapshot.json - 0 issues (generated; prevId equals main's 0301 snapshot ff5b8190, contains is_fork, pending_copy_ids, IDX_shared_cli_sessions_kilo_user_id with concurrently: true, and main's credits_window_granted_microdollars)
  • packages/db/src/migrations/meta/_journal.json - 0 issues (generated; idx: 302 appended with when newer than 0301)
  • packages/db/src/schema.ts - 0 issues (branch columns match migration and snapshot; the other line is main's contributor credit column)
  • DEVELOPMENT.md - 0 issues (docs only, no images)
  • apps/web/src/lib/cli-sessions/session-copies.ts - 0 issues (unchanged since previous review; targeted check confirms fork resolves sharedSessionCurrentCopyId under a row lock and publication keeps pending_copy_ids retry state)
  • apps/web/src/routers/cli-sessions-router.ts - 0 issues (unchanged since previous review; targeted check confirms .for('share') on fork and .for('update') on delete/refresh)
  • apps/web/src/lib/user/deletion-queue/handlers/cli-v1.ts - 0 issues (unchanged since previous review; targeted check confirms FOR UPDATE lock and current+pending copy ids)
  • apps/web/src/lib/r2/cli-sessions.ts - 0 issues (unchanged since previous review; copy size pre-check measures before writing)
  • apps/web/src/app/api/upload-cli-session-blob-v2/route.ts - 0 issues (unchanged since previous review; blob cap now sourced from the shared constant)
  • apps/web/src/lib/r2/cli-sessions.test.ts, apps/web/src/routers/cli-sessions-router.test.ts, apps/web/src/lib/user/deletion-queue/handlers/cli-v1.test.ts - 0 issues (test coverage for the copy limit, copy-folder resolution, and cleanup locks)
Previous Review Summaries (12 snapshots, latest commit 61c4ef6)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 61c4ef6)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental range since the last review contains only origin/main merges plus the migration renumber, and the new 0301_tranquil_photon.sql preserves the previously reviewed column additions, concurrent index boundaries, and fork backfill with a snapshot whose prevId chains onto main's 0300 entry.

Assumptions: [INFERENCE] the repository's transactional migrator commits the trailing BEGIN;/backfill block and applies the migration because its journal when is newer than 0300; the tests quoted in the PR that exercised the real migrator were not re-run here (read-only review), so migration application was verified statically via the journal, snapshot chain, and SQL. Merge state is BLOCKED on required checks/reviews, not on a merge conflict.

Files Reviewed (6 files)
  • packages/db/src/migrations/0301_tranquil_photon.sql - 0 issues (identical DDL to the previously reviewed 0297/0298 branch migrations, now consolidated: is_fork and pending_copy_ids are additive NOT NULL columns with defaults, the IDX_shared_cli_sessions_kilo_user_id build keeps COMMIT;/BEGIN; migrator boundaries, and the backfill remains scoped to forked_from IS NOT NULL)
  • packages/db/src/migrations/meta/0301_snapshot.json - 0 issues (generated; differs from main's 0300 snapshot only by is_fork, pending_copy_ids, and the concurrent kilo_user_id index; prevId equals the 0300 snapshot id)
  • packages/db/src/migrations/meta/_journal.json - 0 issues (generated; identical to main plus one appended idx: 301 entry whose when is newer than every earlier entry, so it is not skipped by drizzle's folderMillis check)
  • packages/db/src/schema.ts - 0 issues (targeted: the branch's five-line addition matches the migration and snapshot; the remaining diff came from the main merge)
  • DEVELOPMENT.md - 0 issues (targeted: the branch section predates this review; the rest of the range diff came from main)
  • apps/web/src/lib/cli-sessions/session-copies.ts, apps/web/src/routers/cli-sessions-router.ts, apps/web/src/lib/user/deletion-queue/handlers/cli-v1.ts - 0 issues (targeted check: byte-identical to the previously reviewed commit 098d00a0, so no re-analysis beyond confirming the merge did not revert them)

The remaining files in the 098d00a0..HEAD range (mobile, session-ingest, webhook-agent-ingest, i18n/nativewind tooling, other migrations) came exclusively from origin/main merges and are not part of this pull request's changed files, so they were not reviewed. All existing Kilo inline findings on this PR have author replies describing fixes that are present in the current HEAD.

Previous review (commit 098d00a)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Account cleanup now re-reads each shared row under FOR UPDATE and deletes its copy folders inside that transaction, which serializes it with the fork's FOR SHARE and the refresh/delete FOR UPDATE paths; the incremental change introduces no new correctness, security, or deadlock issue.

Assumptions: [INFERENCE] an in-flight fork's blob copy keeps its FOR SHARE lock for the duration of the R2 calls, so account cleanup can wait on that lock for as long as a copy runs; this mirrors the existing cliSessions.delete and publish paths and is not a new pattern. No in-memory leak was found; the retained-copy risk remains the R2 folders tracked through pending_copy_ids.

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 0
Files Reviewed (4 files)
  • apps/web/src/lib/user/deletion-queue/handlers/cli-v1.ts - 0 issues (shared rows are locked FOR UPDATE before the copy folders are resolved and deleted; blob delete, low-time exit, and row delete share one transaction; non-shared rows keep the previous behavior)
  • apps/web/src/lib/user/deletion-queue/handlers/cli-v1.test.ts - 0 issues (the new NOWAIT probe runs on the first blob delete, while the handler's transaction holds the row lock, and would fail the test if the lock were absent)
  • apps/web/src/routers/cli-sessions-router.ts - 0 issues (targeted: fork takes FOR SHARE before resolving the current copy id, so the new FOR UPDATE serializes both orders; share refresh and session delete already take FOR UPDATE)
  • apps/web/src/lib/cli-sessions/session-copies.ts - 0 issues (targeted: publish and clearPendingSharedSessionCopy lock the same row, and no path takes the owner advisory lock after a share row lock, so the new lock ordering adds no deadlock cycle)

Previous review (commit de0f8ab)

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The new FOR SHARE on the share row closes the refresh and session-delete races, but the account-deletion queue deletes the same copy folder without taking that lock, so a fork racing it is still stored empty with no error.

Assumptions: [INFERENCE] the account-deletion queue (handleCliV1Blobs) can run concurrently with a fork of a public share, and its blob deletes are not otherwise serialized with the share row; the fork transaction also holds a pool connection across R2 I/O, which mirrors the existing publish path and was not flagged.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/routers/cli-sessions-router.ts 305 The fork holds FOR SHARE on the share row, but handleCliV1Blobs deletes the current shared-sessions/<copyId> objects before deleting the row and takes no lock, so a concurrent fork copies missing objects and stores all four blob urls as null.
Files Reviewed (5 files)
  • apps/web/src/routers/cli-sessions-router.ts - 1 issue (fork now resolves the current copy id inside a row-locked transaction; refresh and session-delete paths verified to take FOR UPDATE)
  • apps/web/src/routers/cli-sessions-router.test.ts - 0 issues (new lock test is deterministic; noWait assertion matches the held FOR SHARE, pool max 10 avoids connection starvation)
  • apps/web/src/lib/cli-sessions/session-copies.ts - 0 new issues (targeted: publish takes FOR UPDATE before copying and retains the previous folder through pending_copy_ids)
  • apps/web/src/lib/user/deletion-queue/handlers/cli-v1.ts - 0 new issues (targeted: share blob deletes at line 198 precede the unlocked row delete at line 213; reported above)
  • apps/web/src/lib/r2/cli-sessions.ts - 0 new issues (targeted: failed source HeadObject calls are swallowed, so a missing folder yields null blob urls)

Fix these issues in Kilo Cloud

Previous review (commit a458d8f)

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The previous fork-source and account-cleanup findings are fixed, but a fork that resolves a share's copy folder just before that owner's refresh commits can copy from the folder the refresh deletes, yielding an empty fork with no error.

Assumptions: [INFERENCE] copyBlobs swallows every failed source HeadObject (verified at apps/web/src/lib/r2/cli-sessions.ts:195-206), so the race stores null blob urls instead of failing; no lock or grace period keeps a superseded folder readable for an in-flight fork. No in-memory leak was found; the remaining orphan risk is the R2 copy folders retained through pending_copy_ids.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/routers/cli-sessions-router.ts 266 A fork resolves the share's current copy folder when it reads the row; a concurrent refresh commits new urls and deletes that folder, and the fork's source HeadObject failures are swallowed, so the fork is stored empty.
Files Reviewed (10 files)
  • DEVELOPMENT.md - 0 issues (documents the pending-copy retry lifecycle)
  • apps/web/src/lib/cli-sessions/session-copies.ts - 0 new issues (current/pending copy-id split, pending retry before refresh, post-commit cleanup retained for retry)
  • apps/web/src/lib/user/deletion-queue/handlers/cli-v1.ts - 0 issues (deletion now covers current and pending folders per shared row)
  • apps/web/src/lib/user/deletion-queue/handlers/cli-v1.test.ts - 0 issues (covers current and pending folder deletion)
  • apps/web/src/routers/cli-sessions-router.ts - 1 issue (fork resolves the current copy folder; race with post-commit removal reported above)
  • apps/web/src/routers/cli-sessions-router.test.ts - 0 issues (retry-after-failure and fork-source coverage added)
  • packages/db/src/migrations/0298_wooden_pixie.sql - 0 issues (additive NOT NULL DEFAULT '[]' column is safe on a populated table)
  • packages/db/src/schema.ts - 0 issues (pending_copy_ids typed and defaulted)
  • packages/db/src/migrations/meta/0298_snapshot.json - 0 issues (generated)
  • packages/db/src/migrations/meta/_journal.json - 0 issues (generated, entry 298 matches the new migration)

Previous review (commit ffb7c00)

Status: 3 Issues Found | Recommendation: Address before merge

Executive Summary

Publishing each share under a fresh shared-sessions/<copyId> folder (instead of <shareId>) breaks server-side forking of a shared session and leaves share blobs behind after account deletion, since both consumers still address the share id folder.

Assumptions: [INFERENCE] kilocode --fork <shareId> reaches the fork procedure that copies from shared-sessions/<share_id>; copyBlobs swallows missing HeadObject responses, so the mismatch produces a fork with null blob urls rather than an error.

Overview

Severity Count
CRITICAL 1
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

CRITICAL

File Line Issue
apps/web/src/lib/cli-sessions/session-copies.ts 223 Copies now land in shared-sessions/<copyId> while getForkableSession copies from shared-sessions/<share_id>, so forking any share created or refreshed here yields an empty session.

WARNING

File Line Issue
apps/web/src/lib/cli-sessions/session-copies.ts 222 The account-deletion handler deletes shared-sessions/<share_id>, so the per-copy folders holding the shared conversation blobs remain in R2 after the account is deleted.

SUGGESTION

File Line Issue
apps/web/src/lib/cli-sessions/session-copies.ts 255 The post-commit deletion of the previous copy is unguarded and unretried: a failure fails an already-published refresh and orphans the old folder.
Files Reviewed (3 files)
  • apps/web/src/lib/cli-sessions/session-copies.ts - 3 issues (new copy-id publish path; sharedSessionCopyIds and rollback cleanup verified; targeted check of the fork and account-deletion consumers)
  • apps/web/src/routers/cli-sessions-router.ts - 0 new issues (share delete path now derives copy folders per row; removed createSharedSessionCopy; fork source still keyed by share id, reported above)
  • apps/web/src/routers/cli-sessions-router.test.ts - 0 new issues (refresh, failed-refresh, and failed-first-copy cases updated; fork tests mock copyBlobs, so they do not exercise the real folder keys)

Fix these issues in Kilo Cloud

Previous review (commit 45341ef)

Status: 1 Issues Found | Recommendation: Address before merge

Executive Summary

The new SELECT ... FOR UPDATE serializes concurrent refreshes and deletes, but a re-share still copies into the live shared-sessions/<shareId> folder, so a partial copy failure leaves the published snapshot mixed.

Assumptions: [INFERENCE] a copy can fail or the request be terminated after some CopyObject calls succeed; copyBlobs copies with Promise.all and performs no rollback, and the repository has no staging prefix for share refreshes.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/routers/cli-sessions-router.ts 298 The row lock only serializes refreshes; the copy still overwrites the live shared-sessions/<shareId> keys in place with no rollback, so a failed refresh serves a mixed snapshot.
Files Reviewed (3 files)
  • apps/web/src/routers/cli-sessions-router.ts - 1 issue (in-place refresh of a published share; the new share-row lock correctly serializes refresh vs delete, and the row-vanished branch still cleans up copies and throws CONFLICT)
  • apps/web/src/lib/cli-sessions/session-copies.ts - 0 new issues (targeted check: reserveSharedSession reuse, linked-session share count, is_fork fork count, fork discard unchanged)
  • apps/web/src/routers/cli-sessions-router.test.ts - 0 new issues (the vanished-row test was removed because the row lock now blocks that interleaving; the CONFLICT branch is now untested)

Fix these issues in Kilo Cloud

Previous review (commit c5cb7fb)

Status: 1 Issues Found | Recommendation: Address before merge

Executive Summary

Reusing the published share id makes a re-share overwrite the live snapshot in place, so a failed blob copy can leave the published link serving a mixed or partial session snapshot.

Assumptions: [INFERENCE] a copy can fail or a request be terminated after some CopyObject calls succeed; copyBlobs copies blobs with Promise.all and performs no rollback in the repository.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/routers/cli-sessions-router.ts 288 A re-share copies into the live shared-sessions/<shareId> folder; a copy failure leaves the published snapshot mixed because the row and old objects are kept.
Files Reviewed (3 files)
  • apps/web/src/lib/cli-sessions/session-copies.ts - 0 issues (reuse lookup restores the interrupted-reservation path; the earlier allowance-count and index findings stay resolved)
  • apps/web/src/routers/cli-sessions-router.ts - 1 issue (in-place refresh of a published share)
  • apps/web/src/routers/cli-sessions-router.test.ts - 0 issues (reuse, completion, and preserved-row cases covered; the partial-object case on refresh failure is not)

Fix these issues in Kilo Cloud

Previous review (commit 136b103)

Status: 1 Issues Found | Recommendation: Address before merge

Executive Summary

The latest commit makes every share publish a fresh snapshot and removes share reuse, which resolves the earlier reuse and concurrency findings; one reliability gap remains where an interrupted reservation is never reclaimed and permanently counts against the share allowance.

Assumptions: [INFERENCE] a request can be terminated between the reservation insert and the completion update (timeout, deploy, or crash), because no sweep for null-blob share rows exists in the repository.

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 1
Issue Details (click to expand)

SUGGESTION

File Line Issue
apps/web/src/lib/cli-sessions/session-copies.ts 103 With reuse removed, a reservation left by a terminated request keeps session_id set and no blob urls, so it counts against the 200-share allowance forever with no cleanup path; add a sweep or a reclaimable lease.
Files Reviewed (8 files)
  • apps/web/src/lib/cli-sessions/session-copies.ts - 1 issue (share admission, discard, and inventory helpers; reuse removal leaves the interrupted-reservation gap)
  • apps/web/src/routers/cli-sessions-router.ts - 0 issues (fresh share id per request, conditional completion update returning its row, fork path via shared admission)
  • apps/web/src/lib/r2/cli-sessions.ts - 0 issues (measure-before-copy size limit and SessionBlobCopyTooLargeError fire before any write)
  • apps/web/src/app/api/upload-cli-session-blob-v2/route.ts - 0 issues (constants moved to the shared module)
  • packages/db/src/schema.ts - 0 issues (is_fork marker and concurrent user index match the migration)
  • packages/db/src/migrations/0297_mysterious_devos.sql - 0 issues (NOT NULL with default on a populated table, CREATE INDEX CONCURRENTLY with COMMIT/BEGIN breakpoints, fork backfill present)
  • apps/web/src/routers/cli-sessions-router.test.ts - 0 issues (share cap, fork cap, fresh-share and cleanup cases covered)
  • apps/web/src/lib/r2/cli-sessions.test.ts - 0 issues (copy size limit covered)

Previous review (commit 79be98a)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental range from the previously reviewed commit contains only a merge of origin/main; no pull request file changed, and the CLI session copy, share, fork, and delete paths are byte-identical to the state already reviewed.

Files Reviewed (2 files)
  • apps/web/src/lib/cli-sessions/session-copies.ts - 0 issues (unchanged since the prior review; re-checked that the share count requires a linked session, the fork count uses is_fork, reservations without blobs are re-copied, and fork cleanup is scoped to its own reservation)
  • apps/web/src/routers/cli-sessions-router.ts - 0 issues (unchanged since the prior review; re-checked the conditional completion update that returns its row and removes orphaned share objects, and the per-share blob delete retry before row deletion)

Reviewed incrementally from 28bc51c27488a2afc473619274141ea7adf6992d at HEAD 79be98a9d17ed46cfaafb88add564d3d17904ffd. The range's remaining files (apps/web/src/lib/ai-gateway/*, services/usage-ingest/*, apps/web/src/lib/app-builder/*, apps/web/src/lib/agent-briefing/*, other ProfilePickerPopover/offeringPricing files, DEVELOPMENT.md, ENVIRONMENT.md) came from the origin/main merge and are not part of this pull request's changed files (gh pr diff 8224), so they were not re-reviewed. All 24 existing inline comments have author replies describing fixes that are present in the current HEAD code.

Previous review (commit 28bc51c)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental change replaces the bulk share cleanup in cliSessions.delete with per-share blob deletion under a bounded retry, and the loop only removes each share row after its objects are deleted; the retry/partial-failure semantics are covered by five new tests and no new correctness, security, or data-integrity issue was found.

Files Reviewed (2 files)
  • apps/web/src/routers/cli-sessions-router.ts - 0 issues (verified deleteShareBlobsWithRetry retries only the idempotent four-key shared-sessions/<shareId> deletion, throws the last error after three attempts, and that removing share rows per share_id after object deletion keeps rows in sync with stored blobs; the remaining deleteSharedSessionCopies caller at line 307 is intact)
  • apps/web/src/routers/cli-sessions-router.test.ts - 0 issues (new tests cover retry success, persistent failure retaining session and shares, partial cleanup resumability, ordering of share vs source blob deletion, cross-publisher shares, and non-owner refusal; the merge resolution's removal of the obsolete shareForWebhookTrigger suite matches main)

Reviewed incrementally from 961fdfe3d66a64c7c035f2a2ecc0d0ca96c73589 at HEAD 28bc51c27488a2afc473619274141ea7adf6992d; unrelated files entered the range through the main merge and were not re-reviewed.

Previous review (commit 961fdfe)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental commit resolves the last open finding: when the completion update matches no row, the handler now deletes the shared-session objects it copied before returning CONFLICT, and the test asserts that cleanup; no new issues found.

Files Reviewed (2 files)
  • apps/web/src/routers/cli-sessions-router.ts - 0 issues (cleanup on the CONFLICT path verified against deleteSharedSessionCopies, which is idempotent and targets only the per-share shared-sessions/<shareId> keys)
  • apps/web/src/routers/cli-sessions-router.test.ts - 0 issues (assertion matches the copy's folder/filename set)

Previous finding resolved: the orphaned shared-sessions/<shareId> objects from a vanished reservation are now removed before the conflict is thrown, with cleanup failures intentionally not masking the CONFLICT.

Previous review (commit 6302ee8)

Status: 1 Issue Found | Recommendation: Merge after optional cleanup

Executive Summary

Both prior findings are fixed: the completion update now returns its row and fails with CONFLICT, and the dangling {@link} reference is gone; the only remaining gap is that a failed completion leaves the copied share objects orphaned.

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 1
Issue Details (click to expand)

SUGGESTION

File Line Issue
apps/web/src/routers/cli-sessions-router.ts 288 The CONFLICT path leaves the already-copied shared-sessions/<shareId> objects unreferenced forever; the fork path cleans up its partial copy in discardReservedFork, so this path should delete them be

[Snapshot truncated.]

Additional previous summary content was truncated to keep this comment within platform limits.


Reviewed by deepseek-flash-latest · Input: 69.4K · Output: 10K · Cached: 838K

Review guidance: REVIEW.md from base branch main

- add cli_sessions.is_fork, set by the fork paths, and count the fork
  allowance from it so the marker survives source deletion
- add an index on shared_cli_sessions.kilo_user_id for the share count
- a share row with no copied blob is completed on the next request
- copy results always write all four blob url columns, so a session
  without blobs stores explicit NULLs
Comment thread apps/web/src/routers/cli-sessions-router.ts Outdated
Comment thread packages/db/src/migrations/0292_reflective_chronomancer.sql Outdated
Comment thread packages/db/src/migrations/0292_reflective_chronomancer.sql Outdated
Comment thread apps/web/src/lib/cli-sessions/session-copies.ts Outdated
Comment thread apps/web/src/routers/cli-sessions-router.ts Outdated
Comment thread apps/web/src/lib/cli-sessions/session-copies.ts Outdated
Comment thread apps/web/src/routers/cli-sessions-router.ts Outdated
@iscekic
iscekic enabled auto-merge October 20, 2026 02:37
@iscekic iscekic added the merge:human Substantive functional risk requires human review. label Oct 20, 2026
@iscekic

iscekic commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator Author

bot: The main-merge resolution is verified locally: 140 targeted tests, web typecheck, targeted lint, and an authenticated API smoke all passed. It retains main’s share-cleanup retry behavior and webhook-procedure removal. The factory gate currently rejects the inherited generated migration snapshot, which is unchanged from the published head. Per the proxy decision, the gated workflow is preserved and no merge-resolution commit has been published. Factory-gate repair is required before retrying.

@iscekic

iscekic commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator Author

bot: The verified main-merge resolution is now published. The proxy-approved local factory repair passed eight focused probes and a typecheck; the commit completed through a freshly loaded gate. The generated migration snapshot is unchanged. CI and review are running on the published head.

@iscekic

iscekic commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator Author

bot: Integrated main with a clean merge. Verification on the integrated tree: local migrations applied successfully; both CLI-session suites passed (140 tests); web typecheck passed; whitespace check passed. The separately invoked database schema suite passed 54 of 55 tests, with an inherited TodoItemSessionOrigin enum-registry expectation mismatch; the test and enum-definition files match main. No application source edits were needed for this follow-up. An empty commit requests review of the current head.

@iscekic
iscekic disabled auto-merge October 22, 2026 09:46
@iscekic iscekic added merge:human Substantive functional risk requires human review. and removed merge:human Substantive functional risk requires human review. labels Oct 22, 2026
@iscekic iscekic added merge:human Substantive functional risk requires human review. and removed merge:human Substantive functional risk requires human review. needs:prod-action Prod prerequisite (env var, secret, firewall rule, config) needed before merge labels Oct 24, 2026
@iscekic iscekic added merge:human Substantive functional risk requires human review. and removed merge:human Substantive functional risk requires human review. labels Oct 24, 2026
@iscekic

iscekic commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

bot: The synced head is re-verified locally on a disposable database: the complete migration chain applies from empty, the new columns and owner index are present, the three affected suites pass (150 tests), the database package suites pass (50 tests), and the schema generator reports no drift. The branch is mergeable, its checks are green, and no review threads are open.

@iscekic iscekic added merge:human Substantive functional risk requires human review. and removed merge:human Substantive functional risk requires human review. labels Oct 24, 2026
@iscekic

iscekic commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

Changes requested: renumber the migration so the branch merges with main.

  • main now has 0299_lame_mojo (from feat(cloud-agent): add automatic repository environments #8678), so this branch conflicts in packages/db/src/migrations/meta/0299_snapshot.json and meta/_journal.json.
  • Merge main into the branch, take main's journal and snapshots, and regenerate this PR's migration as 0300. Keep the concurrent index pattern.
  • Re-run the migration and empty-database checks after the renumber.
  • Keep the current repeated-share behavior: the same share id now points at a fresh copy of the session's current blobs. That resolves the earlier share-reuse request.

@iscekic

iscekic commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

bot: The head already carries the requested migration state, and I re-ran the checks on it.

  • packages/db/src/migrations/meta/_journal.json, the 0299 migration, and its snapshot are identical to main. The branch adds only entry 300, 0300_natural_kate_bishop, and that snapshot's prevId is the 0299 snapshot id.
  • The branch migration keeps the concurrent index pattern: the column changes commit, the index is created concurrently, then the backfill runs in the following transaction.
  • POSTGRES_URL=<disposable> bash scripts/verify-drizzle-bootstrap.sh on head 8d6728899e: the complete chain, ending with the branch migration, applied to an empty database.
  • Applied the branch chain onto a database already at main's chain and holding session and share rows: both new columns and the owner index were created, the index reports valid, and only the row with a recorded source reference was marked.
  • NODE_ENV=test pnpm --filter web exec jest --runInBand src/routers/cli-sessions-router.test.ts src/lib/user/deletion-queue/handlers/cli-v1.test.ts src/lib/r2/cli-sessions.test.ts — 3 suites, 150 tests passed.

The stable-link re-publication behavior is unchanged and remains covered by the re-publication test.

…y-limits

# Conflicts:
#	packages/db/src/migrations/meta/0300_snapshot.json
#	packages/db/src/migrations/meta/_journal.json
@iscekic iscekic added merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head merge:human Substantive functional risk requires human review. and removed merge:human Substantive functional risk requires human review. merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head labels Oct 24, 2026
@iscekic

iscekic commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

Changes requested: renumber the migration again. It collides with main.

@iscekic iscekic added merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head merge:blocked:insufficient-e2e Verification does not cover the change merge:human Substantive functional risk requires human review. and removed merge:human Substantive functional risk requires human review. merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head merge:blocked:insufficient-e2e Verification does not cover the change labels Oct 24, 2026
@iscekic

iscekic commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

bot: Renumbered and re-verified at head c0da2b72.

  • The branch now adds only journal entry 302, 0302_flippant_jackpot, after main's 0301_contributor_credit_window. The journal difference against main is that single appended entry, and the 0299, 0300, and 0301 migrations and snapshots are identical to main. The branch migration's when timestamp is greater than 0301's.
  • The migration keeps the concurrent index pattern: the column changes commit, CREATE INDEX CONCURRENTLY builds IDX_shared_cli_sessions_kilo_user_id, then the backfill runs in the following transaction.
  • Empty database: pnpm drizzle:verify-bootstrap applied the complete chain, ending with the branch migration.
  • Populated database: applied the chain through 0301, inserted session rows (one carrying a source link) plus a share row, then applied the branch migration. Both new columns exist as NOT NULL with defaults, the owner index is valid, the linked row was marked while the root row was not, and the existing share row kept its stored copy references.
  • pnpm drizzle check passes and pnpm drizzle generate reports no schema changes on the merged tree.
  • Suites: the three affected web suites (150 tests) and the database package suites (50 tests) pass at this head.

This branch has not been deployed

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

Labels

drain Work item from the findings drain janitor:trust Janitor finding: trust boundary hardening merge:human Substantive functional risk requires human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant