Skip to content

fix(api,e2e): finish Sandbox → Box rename — 3 schema gaps + fixture column names#720

Merged
DorianZheng merged 1 commit into
boxlite-ai:mainfrom
G4614:fix/box-rename-missing-migration-and-fixture
Jun 10, 2026
Merged

fix(api,e2e): finish Sandbox → Box rename — 3 schema gaps + fixture column names#720
DorianZheng merged 1 commit into
boxlite-ai:mainfrom
G4614:fix/box-rename-missing-migration-and-fixture

Conversation

@G4614

@G4614 G4614 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Bug

Migration1781016743403 (#706) renamed most sandbox-vocabulary objects to
box-vocabulary equivalents but missed three pieces, leaving the schema
inconsistent with the renamed TypeORM entities and TS enum. Every box-
touching API path crashed until I added the catch-up rename below;
fixture_setup also still wrote the old organization-quota column names.

Layer What got missed Symptom
runner.currentStartedSandboxes entity renamed to currentStartedBoxes, no schema migration every ResourceManager / SnapshotManager query: `column Runner.currentStartedBoxes does not exist`
organization.sandboxLimitedNetworkEgress entity / service renamed to boxLimitedNetworkEgress, no schema migration box create: `column Organization.boxLimitedNetworkEgress does not exist`
job_resourcetype_enum value SANDBOX TS ResourceType.BOX = 'BOX', Postgres enum still only knows 'SANDBOX' runner job poll: `invalid input value for enum job_resourcetype_enum: "BOX"`
scripts/test/e2e/fixture_setup.py still UPDATEs max_cpu_per_sandbox / max_memory_per_sandbox / max_disk_per_sandbox (#706's main migration already renamed those columns to max_*_per_box) fixture_setup: `column "max_cpu_per_sandbox" of relation "organization" does not exist`

Fix

New post-deploy migration Migration1781072797240 performs the three
schema renames the original missed. Each step is guarded with an
information_schema / pg_enum state check, so partial-state
environments are safe to re-run and the migration is idempotent on
hosts where someone has already hand-applied any of the three renames.

fixture_setup.py is updated to use the new column names.

Test plan

Verified locally on a partial-state DB:

  1. Confirmed the bug: API 500 on box create with the three errors above,
    fixture_setup 500 on quota patch.
  2. Applied this migration: schema renames cleanly (guards skip no-ops),
    migrations row recorded.
  3. Restarted API + ran the e2e back-pressure suite — all 3 cases pass:
[same-box]              elapsed_b=0.456s rc=0 out='fast-b\n'
[cross-box]             elapsed_b=0.482s rc=0 out='fast-b\n'
[slow-consumer x-box]   elapsed_b=0.419s rc=0 out='fast-b\n'

No down() change to data — the down() just inverts the renames so the
migration is reversible if needed. Each down step is also guarded.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores

    • Applied post-deployment database migration to standardize schema naming conventions across multiple tables.
    • Updated database enumeration values to align with current system terminology.
  • Tests

    • Updated e2e test fixture quota configuration to ensure test environment compatibility with revised resource limit parameters.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR finalizes a sandbox→box schema rename by introducing a post-deploy database migration that conditionally renames two table columns and updates a PostgreSQL enum label, while adjusting the e2e test fixture to target the renamed per-box quota limits.

Changes

Schema migration sandbox→box rename completion

Layer / File(s) Summary
Migration up/down column and enum renames
apps/api/src/migrations/post-deploy/1781072797240-migration.ts
Post-deploy TypeORM migration adds conditional renames in up() for runner.currentStartedSandboxescurrentStartedBoxes, organization.sandboxLimitedNetworkEgressboxLimitedNetworkEgress, and job_resourcetype_enum SANDBOXBOX label, each guarded by IF EXISTS/NOT EXISTS checks. down() reverses all three operations.
Test fixture quota columns update
scripts/test/e2e/fixture_setup.py
E2E test fixture patch_admin_quota() switches admin organization quota settings from per-sandbox columns to per-box columns (max_cpu_per_box, max_memory_per_box, max_disk_per_box).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

  • #711: Both PRs add post-deploy migrations for the sandbox→box rename workstream, targeting schema column and enum label finalization.

Poem

🐰 From sandbox names to boxes bright,
The columns shuffle through the night,
The enum hops from old to new,
While fixtures dance the migration through! 🎭

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: completing a schema rename from 'Sandbox' to 'Box' by addressing 3 schema gaps and fixing fixture column names.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

…column names

Migration1781016743403 (PR boxlite-ai#706) renamed most sandbox-vocabulary objects
to box-vocabulary equivalents but missed three pieces; the API and runner
crashed on every box-touching path until those caught up. fixture_setup
also still wrote the old organization-quota column names.

Schema gaps added in a follow-up post-deploy migration:
- `runner.currentStartedSandboxes`           -> `currentStartedBoxes`
- `organization.sandboxLimitedNetworkEgress` -> `boxLimitedNetworkEgress`
- `job_resourcetype_enum` value `SANDBOX`    -> `BOX`

Symptoms before the fix:
- ResourceManager / SnapshotManager queries: `column Runner.currentStartedBoxes does not exist`
- Box service create path: `column Organization.boxLimitedNetworkEgress does not exist`
- Runner job poll: `invalid input value for enum job_resourcetype_enum: "BOX"`
- fixture_setup: `column "max_cpu_per_sandbox" of relation "organization" does not exist`

Each migration step is guarded with a state check (`information_schema` /
`pg_enum`), so partial-state environments are safe to re-run and the
migration is idempotent on hosts where someone has already hand-applied
any of the three renames. The down() restores the previous names.

Verified locally: applied the migration to a partial-state DB; API +
runner come up clean; `scripts/test/e2e/cases/test_unread_stream_back_pressure.py`
(3 cases) and existing e2e cases pass against the restored stack.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@G4614 G4614 force-pushed the fix/box-rename-missing-migration-and-fixture branch from 2e3587a to 9a53ec8 Compare June 10, 2026 06:45
@G4614 G4614 marked this pull request as ready for review June 10, 2026 06:54
@G4614 G4614 requested a review from a team as a code owner June 10, 2026 06:54
@G4614 G4614 enabled auto-merge June 10, 2026 06:54

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/migrations/post-deploy/1781072797240-migration.ts`:
- Around line 108-113: In down(), the ALTER TABLE ... RENAME COLUMN statements
are not safe if the source column is missing; before running the rename via
queryRunner.query, first check for the source column's existence using a SELECT
against information_schema.columns (or pg_catalog) and only execute the ALTER
for organization when "sandboxLimitedNetworkEgress" exists and for runner when
"currentStartedSandboxes" exists; update the two rename sites in the down()
function (the queryRunner.query calls that currently rename
"sandboxLimitedNetworkEgress" -> "boxLimitedNetworkEgress" and
"currentStartedSandboxes" -> "currentStartedBoxes") to perform this conditional
check and skip the ALTER if the column is absent so rollbacks remain idempotent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 29ecdae3-dcde-4192-8616-e3cb52f84717

📥 Commits

Reviewing files that changed from the base of the PR and between 8a62978 and 9a53ec8.

📒 Files selected for processing (2)
  • apps/api/src/migrations/post-deploy/1781072797240-migration.ts
  • scripts/test/e2e/fixture_setup.py

Comment on lines +108 to +113
await queryRunner.query(
`ALTER TABLE IF EXISTS "organization" RENAME COLUMN "boxLimitedNetworkEgress" TO "sandboxLimitedNetworkEgress"`,
)
await queryRunner.query(
`ALTER TABLE IF EXISTS "runner" RENAME COLUMN "currentStartedBoxes" TO "currentStartedSandboxes"`,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

down() column renames are not safely guarded for partial-state rollbacks.

ALTER TABLE IF EXISTS ... RENAME COLUMN ... only guards table existence. If the table exists but the source column is absent, rollback fails. This breaks the intended idempotent/safe rollback behavior for mixed states.

Suggested fix
-    await queryRunner.query(
-      `ALTER TABLE IF EXISTS "organization" RENAME COLUMN "boxLimitedNetworkEgress" TO "sandboxLimitedNetworkEgress"`,
-    )
-    await queryRunner.query(
-      `ALTER TABLE IF EXISTS "runner" RENAME COLUMN "currentStartedBoxes" TO "currentStartedSandboxes"`,
-    )
+    await queryRunner.query(`
+      DO $$
+      BEGIN
+        IF EXISTS (
+          SELECT 1 FROM information_schema.columns
+          WHERE table_name = 'organization' AND column_name = 'boxLimitedNetworkEgress'
+        ) AND NOT EXISTS (
+          SELECT 1 FROM information_schema.columns
+          WHERE table_name = 'organization' AND column_name = 'sandboxLimitedNetworkEgress'
+        ) THEN
+          ALTER TABLE "organization"
+            RENAME COLUMN "boxLimitedNetworkEgress" TO "sandboxLimitedNetworkEgress";
+        END IF;
+      END $$;
+    `)
+    await queryRunner.query(`
+      DO $$
+      BEGIN
+        IF EXISTS (
+          SELECT 1 FROM information_schema.columns
+          WHERE table_name = 'runner' AND column_name = 'currentStartedBoxes'
+        ) AND NOT EXISTS (
+          SELECT 1 FROM information_schema.columns
+          WHERE table_name = 'runner' AND column_name = 'currentStartedSandboxes'
+        ) THEN
+          ALTER TABLE "runner"
+            RENAME COLUMN "currentStartedBoxes" TO "currentStartedSandboxes";
+        END IF;
+      END $$;
+    `)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await queryRunner.query(
`ALTER TABLE IF EXISTS "organization" RENAME COLUMN "boxLimitedNetworkEgress" TO "sandboxLimitedNetworkEgress"`,
)
await queryRunner.query(
`ALTER TABLE IF EXISTS "runner" RENAME COLUMN "currentStartedBoxes" TO "currentStartedSandboxes"`,
)
await queryRunner.query(`
DO $$
BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'organization' AND column_name = 'boxLimitedNetworkEgress'
) AND NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'organization' AND column_name = 'sandboxLimitedNetworkEgress'
) THEN
ALTER TABLE "organization"
RENAME COLUMN "boxLimitedNetworkEgress" TO "sandboxLimitedNetworkEgress";
END IF;
END $$;
`)
await queryRunner.query(`
DO $$
BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'runner' AND column_name = 'currentStartedBoxes'
) AND NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'runner' AND column_name = 'currentStartedSandboxes'
) THEN
ALTER TABLE "runner"
RENAME COLUMN "currentStartedBoxes" TO "currentStartedSandboxes";
END IF;
END $$;
`)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/migrations/post-deploy/1781072797240-migration.ts` around lines
108 - 113, In down(), the ALTER TABLE ... RENAME COLUMN statements are not safe
if the source column is missing; before running the rename via
queryRunner.query, first check for the source column's existence using a SELECT
against information_schema.columns (or pg_catalog) and only execute the ALTER
for organization when "sandboxLimitedNetworkEgress" exists and for runner when
"currentStartedSandboxes" exists; update the two rename sites in the down()
function (the queryRunner.query calls that currently rename
"sandboxLimitedNetworkEgress" -> "boxLimitedNetworkEgress" and
"currentStartedSandboxes" -> "currentStartedBoxes") to perform this conditional
check and skip the ALTER if the column is absent so rollbacks remain idempotent.

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.

2 participants