Skip to content

Backfill repo_id for legacy Control sessions #421

Description

@charlesrhoward

Problem

Sessions created before the repo_id column existed have repo_id = NULL and only a project name. The client reconstructs a repo by fuzzy name match, so the sidebar and header show a repo. The server nulls every repo field for those sessions, so the coordinator has no repo tools (sandbox_start, spawn_worktree, open_pr are filtered out when ctx.repoId is null). The user sees a project; the agent says it has none.

Six modules still branch on the project name as a fallback.

Where

  • neon/migrations/20260812120000_control_sessions_repo.sql adds the column with no backfill.
  • app/api/control/chat/_lib/context.ts:111-121 returns repoId: null and overrides whatever the client sent.
  • lib/control/session-project.ts:25-45 (resolveControlSessionRepo) does the name match on the client.
  • Name-based fallbacks: lib/control/session-groups.ts:83, components/control/session-list.tsx:63,134,383, components/control/control-shell.tsx:371, app/api/control/sessions/route.ts:117.

Fix

  1. Write a Neon migration that sets repo_id where the session's project name matches exactly one connected repo for that user or team (same rule as resolveControlSessionRepo). Leave ambiguous rows null and log their count in the migration comment.
  2. Commit the migration file in the repo. Never apply it through the MCP tool without the file (see project_live_db_changes_need_migration_files in the project notes: applying without a file blocks production deploys).
  3. Add a tests/db/ case that inserts a legacy row, runs migrations, and asserts repo_id is populated.
  4. For sessions that remain null, make the UI say so: group them under "Unlinked" with a tooltip "This session has no linked repository. Start a new mission to link one." instead of guessing.

Exit criteria

  • Migration file exists under neon/migrations/ and applies cleanly on a fresh branch (pnpm test:db).
  • DB test covers the backfill for an unambiguous name and leaves an ambiguous one null.
  • After deploy, run the read-only query select count(*) from control_sessions where repo_id is null against production and post the before and after numbers in the PR.
  • Sidebar shows "Unlinked" for the remaining rows instead of a guessed repo.
  • pnpm lint, pnpm typecheck, pnpm test:db pass.

Out of scope

Removing every name-based fallback in one PR. Once the backfill lands, the fallbacks become dead code and can be removed one module at a time.

https://claude.ai/code/session_01SQ4nS96XYRztd5w9QkubPf

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Reliability or a user-visible class of bug.apiAPI routes and request handling.bugSomething isn't workingcontrolControl surface (coordinator, missions, sidebar).

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions