Skip to content

fix(session): preserve time_updated on project_id migration#29109

Open
divitkashyap wants to merge 1 commit into
anomalyco:devfrom
divitkashyap:fix/session-time-updated-25392
Open

fix(session): preserve time_updated on project_id migration#29109
divitkashyap wants to merge 1 commit into
anomalyco:devfrom
divitkashyap:fix/session-time-updated-25392

Conversation

@divitkashyap
Copy link
Copy Markdown

Issue for this PR

Closes #25392

Type of change

  • Bug fix

What does this PR do?

Two bulk UPDATE statements in project.ts rewrite session.project_id without touching time_updated:

  1. Project.fromDirectory — moves sessions from the global project into a real project when their directory matches (runs every time you open a project).
  2. Project.migrateProjectId — moves sessions when a project's ID changes (e.g. directory rename).

Because time_updated has Drizzle's .$onUpdate(() => Date.now()) hook, every row touched by those UPDATEs gets its time_updated stamped to the current time. Net effect for users with any legacy global-scoped sessions: /sessions shows every old session with today's date on every startup.

Fix: pass the column through unchanged via sql\${SessionTable.time_updated}`, which makes Drizzle skip the auto-update. Same pattern that projectors.ts(PR #27094) anddata-migration.ts` already use elsewhere in the file.

How did you verify your code works?

Extended the existing regression test in test/project/migrate-global.test.ts — captures time_updated before calling fromDirectory, then asserts it is identical after. Confirmed the test fails without the fix (the column drifts by tens of ms) and passes with it.

$ bun test test/project/migrate-global.test.ts
 4 pass
 0 fail

Also verified directly against a local DB:

sqlite3 ~/.local/share/opencode/opencode.db \
  "SELECT id, datetime(time_updated/1000, 'unixepoch') FROM session ORDER BY time_updated DESC LIMIT 10"

Before the fix: every recently-opened project's sessions cluster on the launch timestamp. After: the historical timeline is preserved.

bun turbo typecheck --filter opencode passes.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@divitkashyap
Copy link
Copy Markdown
Author

divitkashyap commented May 24, 2026

@nexxeln this is a follow-up to your #27094 — same root cause ($onUpdate firing on bulk writes), but two Project.* paths still lacked the preserve clause. Repro and confirmation are in the test (it fails on dev, passes with the change). Happy to adjust if you would prefer the preserve logic encapsulated differently.

Bulk-rewriting project_id on session rows during startup project
discovery (Project.fromDirectory and Project.migrateProjectId) was
firing Drizzle's $onUpdate hook on time_updated, scrambling the
/sessions timeline by stamping every migrated session with the
startup timestamp.

Pass the column through unchanged via sql\`\${SessionTable.time_updated}\`
so Drizzle skips the auto-update, matching the existing pattern in
projectors.ts and data-migration.ts.

Closes anomalyco#25392
@divitkashyap divitkashyap force-pushed the fix/session-time-updated-25392 branch from 3ed0424 to c9f83fc Compare May 25, 2026 02:05
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.

[BUG] Startup bulk-updates time_updated for all project sessions, corrupting /sessions timeline

1 participant