Skip to content

upstream merge 2026-04-27 PR-B: DB / migration / machineId / main workspace (6 commits)#446

Merged
MocA-Love merged 7 commits intomainfrom
upstream/batch-2026-04-27-pr-b
Apr 27, 2026
Merged

upstream merge 2026-04-27 PR-B: DB / migration / machineId / main workspace (6 commits)#446
MocA-Love merged 7 commits intomainfrom
upstream/batch-2026-04-27-pr-b

Conversation

@MocA-Love
Copy link
Copy Markdown
Owner

Summary

upstream (superset-sh/superset) から fork (MocA-Love/superset) への 2026-04-27 バッチ取り込み 第2弾。22 commits を 3 PR に分割した中の PR-B: DB / migration / machineId / main workspace (6 commits + 1 fix commit)。

依存: このPRは #445 (PR-A) の上に乗っている。base ブランチは upstream/batch-2026-04-27-pr-aPR-A を先にマージしてからこの PR をマージしてください

取り込み内容

SHA PR# 概要
239773e39 upstream superset-sh#3723 v2 project の重複 clone URL 許可。drizzle migration 0036 (再復元) と 0037
959081230 upstream superset-sh#3775 v1 → v2 マイグレーションの安定化 (status synced 追加, retry policy, project setup, branch search 改善)
1cc839895 upstream superset-sh#3781 v1 → v2 マイグレーションの idempotency 強化 (orphan_worktree / worktree_not_registered の retry / skip ロジック)
11c1ea669 upstream superset-sh#3783 v1 マイグレーションの org-idempotent 化 (findMigrationByOtherOrg 撤廃)
9463af0c2 upstream superset-sh#3779 host project setup 時の v2 main workspace 自動作成 (drizzle migration 0038v2_workspace_type enum / main type 追加)
c2cfdbea7 upstream superset-sh#3784 host / client identity を machineId に統合 (drizzle migration 0039)。device.*host.* 改名、v2_hosts.machineId 複合 PK 化

加えて fork 固有の解消 commit a7300ec1f fix(merge): drop fork-incompatible v1 experimental settings を含む。

重要な fork 側修正

Migration 0036 (drop_pending_automation_status) の復元

fork は過去の取り込み (5b38c8a57 chore: post-qstash-ship cleanup) で migration 0036_drop_pending_automation_status.sql を意図的に落としていた。今回 239773e39 (superset-sh#3723) で 0037 を追加するに当たって journal chain (0035 → 0036 → 0037) が不整合になるため、5b38c8a57 の tree から 0036_drop_pending_automation_status.sql0036_snapshot.json を復元して chain を再連結した。

RESEND_API_KEY を optional 化

959081230 (superset-sh#3775) で packages/trpc/src/env.tsRESEND_API_KEY が必須として追加されたが、fork は upstream の support@superset.sh に migration エラーを送る立場ではない。ランタイム起動時に env validation で死なないよう optional 化し、support.sendMigrationReport 呼び出し時に未設定なら 503 SERVICE_UNAVAILABLE を返す no-op に切り替え。

ExperimentalSettings UI を再削除

fork は過去に apps/desktop/.../settings/experimental/ を削除済みだったが、959081230 (superset-sh#3775) と 9463af0c2 (superset-sh#3779) の auto-merge で復活していた。V2LocalOverrideState.setForceV1 が既に存在せず、route 登録もないため build が通らない状態。

  • apps/desktop/.../settings/experimental/ ディレクトリ削除
  • settings-search.ts から EXPERIMENTAL_SUPERSET_V2 / EXPERIMENTAL_V1_MIGRATION ID と SETTINGS_ITEMS エントリ削除
  • V1MigrationSummaryModal"/settings/experimental" リンク削除 (V1 へ戻る UI を fork は提供しない)

v2Workspace.updateNameFromHost の戻り値型修正

959081230 + c2cfdbea7 を同時取り込みすると findFirst の columns 限定 (4列 Pick) によって host-service adopt.tsHostWorkspace 期待型と合わない。getFromHost と同じく columns 限定を外して全列を返すようにした。

host-service-coordinator.ts MIN_HOST_SERVICE_VERSION

0.1.00.3.0 に bump。machineId 統合後の host-service バイナリ要件 (device.*host.* リネーム + 複合 PK)。

Migration 系の fork 固有保持

  • migrate.tsworkspace.type === "branch" 分岐 (worktreeId 無し時に親プロジェクトの mainRepoPath で adopt) は維持
  • branch-search.ts の FORK NOTE (listWorktreeBranches uses (git, repoPath)) は維持しつつ upstream の normalizeWorktreePath を統合

Fork 固有機能ヘルスチェック

baseline と比較し全項目健在を確認:

  • 19 個の独自 tRPC procedures 健在
  • fork 専用依存: ansi_up, @vscode/ripgrep, @xyflow/react
  • fork マーカー: TERMINAL_OPTIONS, SUPERSET_WORKSPACE_NAME, moonshot-ai.kimi-code, MainWindowEffects, INCEPTION_AUTH_PROVIDER_ID, v1MigrationState, TiptapPromptEditor
  • apps/desktop/electron-builder.tsdmg.size = "4g" 維持
  • packages/db/drizzle/ 最大 idx は 0039 に更新 (PR-A 後の 0035 → 0036/0037/0038/0039)
  • packages/local-db/drizzle/ 最大 idx 0072 維持

Test plan

  • bun install 整合性 OK
  • bun run typecheck 全 28 task green
  • bun run lint biome green
  • (ローカル) bun run --filter @superset/desktop build 成功確認
  • (手動) PR-A merge 後にこの PR を rebase / merge し、v1 → v2 migration UX を確認
  • (手動) machineId 統合後の host 登録 / workspace adopt フロー
  • (手動) v2 main workspace の自動生成挙動

次のリファレンス

Kitenite and others added 7 commits April 28, 2026 00:25
* Allow duplicate v2 repo clone URLs

* Add migration to drop v2 repo clone URL unique index

* regen migrations

* Add projects settings action for duplicate imports
* Stabilize v1 to v2 migration

* Update migration modal dither color

* Remove electric proxy changes from migration PR

* Rate limit migration support reports

* Address migration review feedback

* Remove migration cloud rollback

* Address migration review feedback

* Log project local persistence failures

* Preserve clone for project relink recovery
…uperset-sh#3632)

* feat(desktop): auto-create + pin v2 main workspace on host project setup

Each (projectId, hostId) gets a singleton "main" workspace pointing at the
host's configured repoPath, auto-created when a project is created or set
up on a new host. Mains are auto-pinned at creation; existing mains get
backfilled by the startup sweep.

- Schema: v2_workspaces.type pgEnum ('main' | 'worktree', default 'worktree')
  enforced at the DB layer — matches the v2ClientType / v2UsersHostRole
  naming precedent. Partial unique index on (project_id, host_id) WHERE
  type='main', plus a pinned_at timestamp.
- API: v2Workspace.create uses onConflictDoNothing + re-fetch so concurrent
  main creates collapse idempotently instead of racing into a raw
  unique-violation error. Backfills pinned_at on existing main rows.
- Helper: ensureMainWorkspace resolves current branch via git symbolic-ref,
  creates the cloud + local workspace rows. Log-and-continue on any error
  so transient cloud blips don't fail project.setup; the startup sweep
  retries on next boot. Skips on detached HEAD.
- Call sites: project.create (createFromClone, createFromImportLocal) and
  project.setup (clone, import, including early-return paths).
- Recovery: host-service startup sweep iterates local projects and ensures
  each has a main row. Idempotent via the unique index.

* fix main workspace sidebar behavior

* fix preview migration rerun

* fix(host-service): recover missing main workspace during worktree flows

* fix(desktop): protect main workspace delete flows

* fix(desktop): tighten main workspace lifecycle

* fix(db): regenerate v2 main workspace migration

* fix(host-service): reuse host workspace lookup
…3784)

* feat(db): consolidate host/client identity on machineId

Drop UUID surrogates on v2_hosts/v2_clients/v2_users_hosts in favor of
composite primary keys keyed on the existing machineId. Same value the
host service already uses to identify itself (getHostId, formerly
getHashedDeviceId), now canonical end-to-end across DB, cloud API,
relay, and renderer. Drops the dead session_hosts table. Renames the
device-info shared lib + cloud trpc device router to host (v1
device.heartbeat / device.registerDevice retained against the
untouched device_presence table). Bumps host-service version to 0.3.0
so the desktop coordinator force-respawns older binaries that still
call device.ensureV2Host.

* fix: scope relay routing key by organizationId

machineId alone collides on the relay tunnel map when the same physical
machine is registered as a host in multiple orgs. Switch the relay
routing key to "${organizationId}:${machineId}" everywhere the desktop,
host service, and cloud trpc construct it.

Code-splits buildHostRoutingKey / parseHostRoutingKey out of host-info
into a browser-safe @superset/shared/host-routing entry so the renderer
no longer transitively imports node:child_process via host-info.

Adds a useHostTargetUrl hook that wraps the (active host vs relay)
URL resolution with the active organization's id, replacing the inline
${env.RELAY_URL}/hosts/${hostId} pattern at every renderer call site.

* fix(db,trpc): address pr review feedback

- host.ensure: gate v2_users_hosts owner-grant on host.createdByUserId === ctx.userId. Prevents an org member who knows another member's machineId (it's in the synced collection) from calling host.ensure and being granted owner role on someone else's host.

- Drop composite FKs on automations.target_host_id and automation_runs.host_id (migration 0038). These nullable refs originally used ON DELETE SET NULL with a single-column FK; the consolidation made them composite, which breaks SET NULL semantics (PG would try to NULL the NOT NULL organization_id too). Both columns are best-effort pointers — dispatcher already handles the host-not-found path — so dropping the FK is the cleaner fix than the PG15+ column-list workaround. v2_users_hosts (CASCADE) and v2_workspaces (NOT NULL, deletion-blocks) keep their composite FKs intentionally.

* fix(db): scope migration null-out by (organization_id, machine_id)

Pre-PR FK on automation_runs.host_id and automations.target_host_id was
single-column uuid → v2_hosts.id; it didn't enforce that the row's
organization_id matched the host's. If any cross-org row existed (past
bug, manual SQL, etc.), the uuid→machineId translation step would write
the wrong-org's machine_id, and the new composite FK on
(organization_id, host_id) would reject it.

Switch the null-out predicate from `host_id NOT IN (SELECT machine_id …)`
to `NOT EXISTS (… WHERE machine_id = X AND organization_id = X)` so the
migration self-defends instead of trusting the cross-org invariant.

Identical behavior on data that satisfies the invariant (prod confirmed
zero orphans), defensive against environments that don't.
PR-B 取り込み中、3efd92763 (Stabilize v1→v2 migration) と
9abd936 (machineId consolidation) の auto-merge で復活してしまった
fork で削除済みの ExperimentalSettings 関連を再削除する。

- apps/desktop/src/renderer/routes/_authenticated/settings/experimental/
  ディレクトリ削除 (route 未登録 + V2LocalOverrideState の setForceV1
  が既に存在しないため build fail していた)
- settings-search.ts から EXPERIMENTAL_SUPERSET_V2 / EXPERIMENTAL_V1_MIGRATION
  関連 ID と SETTINGS_ITEMS エントリを削除
- V1MigrationSummaryModal の "/settings/experimental" リンクを削除
  (fork は V1 へ戻るオプトアウト UI を持たない)

加えて 3efd927 + 9abd936 を同時取り込みすると
v2Workspace.updateNameFromHost の戻り値型 (4列 Pick) が
host-service adopt.ts の HostWorkspace 期待型と噛み合わなくなるため、
findFirst の columns 限定を外して全列を返すように直す
(getFromHost と同形)。
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eb4a42e9-9c97-41cd-8b2b-d966a13cfc90

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch upstream/batch-2026-04-27-pr-b

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 27, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ⚠️ Neon database branch
  • ⚠️ Electric Fly.io app

Thank you for your contribution! 🎉

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a7300ec1f9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +59 to +63
if (local && project && local.worktreePath === project.repoPath) {
throw new TRPCError({
code: "BAD_REQUEST",
message:
"Main workspaces cannot be deleted. Remove them from the sidebar or remove the project from this host instead.",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Gate main-workspace delete by cloud type, not repoPath

migrateV1DataToV2 still adopts legacy workspace.type === "branch" entries from mainRepoPath, so a non-main workspace can legitimately have worktreePath === project.repoPath. This new precheck classifies those rows as main purely by path and throws before checking cloud v2Workspace.type, which makes migrated repo-root branch workspaces undeletable via workspaceCleanup.destroy.

Useful? React with 👍 / 👎.

Comment on lines +292 to +296
if (ws.worktreePath === localProject.repoPath) {
await ctx.api.v2Workspace.deleteMainForHost.mutate({
id: ws.id,
projectId: input.projectId,
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Confirm workspace type before calling deleteMainForHost

project.remove now routes any repo-root local workspace through v2Workspace.deleteMainForHost, but legacy/migrated repo-root workspaces are not always type="main". In that case deleteMainForHost rejects with BAD_REQUEST, and the mutation exits before local worktree/repo cleanup, so project removal can fail for migrated data. This branch should verify the cloud workspace type first (or handle non-main rows separately).

Useful? React with 👍 / 👎.

@MocA-Love MocA-Love changed the base branch from upstream/batch-2026-04-27-pr-a to main April 27, 2026 23:10
@MocA-Love MocA-Love merged commit 3386302 into main Apr 27, 2026
12 of 13 checks passed
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.

3 participants