feat(database,web): automation scope, repositories, and run target (expand migration 1)

Merged
DA
6d ago
+18067-18

PR 1 of the approved automations plan (docs/proposals/automations-scope.md §4, round 3). This is the expand step only: additive, with nothing dropped.

Schema (automation):

  • organization_id: the workspace. Nullable for now, cascading with the workspace.
  • scope: personal or workspace, default personal.
  • repositories: an ordered jsonb list of owner/name, the first where the agent starts. It holds one entry until full multi-repo (automations-multi-repo.md).
  • target_kind: new-agent or same-agent.
  • target_agent_id: the agent a Same-agent run continues, set null when that agent is deleted.
  • archive_successful: default false.
  • plan_id becomes nullable, and the contract step drops it.
  • Index (organization_id, scope, created_at).

Migrations:

  • 20261014210424_automation_scope: generated, then hardened to be idempotent (IF NOT EXISTS, guarded constraints) so a preview database that ran an earlier draft folder runs it as a no-op.
  • 20261014210429_automation_scope_backfill: a custom backfill, following the precedent of plan_organization_backfill. Each existing row takes its plan's workspace and [plan.repository]. The backfill is idempotent.

Wire (automation-wire.ts, all optional, so v0.12.0 is unaffected; it has no automations UI):

  • AUTOMATION_SCOPE and AUTOMATION_TARGET.
  • Create and change accept scope, target ({kind: new-agent} or {kind: same-agent, agentId}) and archiveSuccessful.
  • The summary answers scope, repositories, target and archiveSuccessful.

API:

  • A new automation takes its plan's workspace and repository. Where the maker names neither scope nor target, it is personal and gets a new agent each run.
  • A Same-agent target must name an agent the account can read; otherwise the request is refused as invalid.
  • A workspace scope is refused in the account's personal workspace (D8).
  • Who may see and change an automation by scope (D2) is the next PR. Runs don't read the target yet (PR 10).

A plan's automations follow it. updatePlan carries a plan's new workspace or repository onto its automations, in the same transaction, so a moved plan's automations never cascade away with the workspace it left. A row an older build inserted during the rollout, with no workspace and empty repositories, reads its plan's values until the contract step fills it.

Tests:

  • automations-app.test.ts: the defaults; Same agent plus archive round-trip; an unreadable agent refused; a workspace scope refused in a personal workspace and accepted in a team one.
  • automation-store.test.ts: a new row takes its plan's workspace and repository; a plan given another repository and moved to another workspace takes its automations along; an older build's empty row reads its plan's values.
  • The migrations test and drizzle-kit check pass.

No Mac UI. pnpm check:affected exits 0.

šŸ¤– Generated with Claude Code


Open workspace in Conductor


Devin Review


Summary by cubic

Adds workspace ownership, scope, repositories, and run target to automations, with existing rows backfilled from their plans.

  • automation gains organization_id, scope (personal/workspace), repositories, target_kind (new-agent/same-agent), target_agent_id, and archive_successful; plan_id becomes nullable.
  • Existing rows are backfilled from their plan's workspace and repository; the backfill is idempotent, and rows an older build inserted during rollout read their plan's values until the contract step fills them.
  • Create and change requests accept scope, target, and archiveSuccessful; all optional, so clients without the automations UI are unaffected.
  • A new automation defaults to personal scope with a new agent each run; a same-agent target must name an agent the account can read, and a workspace scope is refused in a personal workspace.
  • Moving a plan to another workspace or repository takes its automations along.
  • The migrations are idempotent and keep their original names, so a database that already ran them, or an earlier draft folder, reruns them as a no-op.