Skip to content

feat(appkit): add appkit db verify - #674

Draft
ditadi wants to merge 1 commit into
stack/database-dev-flow/05-db-initfrom
stack/database-dev-flow/06-db-verify
Draft

ditadi wants to merge 1 commit into
stack/database-dev-flow/05-db-initfrom
stack/database-dev-flow/06-db-verify

Conversation

@ditadi

@ditadi ditadi commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

🥞 Stacked PR (generated by Stack)

Use this link to review incremental changes.


Stacked on #672.

Summary

Adds appkit db verify, a read-only check that answers "will my app work with its database?".

  • appkit db verify checks the branch .env points at, which is normally your dev or session branch:

    • every table and column config/database/schema.ts declares exists (the same check the plugin runs on start);
    • every committed migration has been applied;
    • no committed migration is one the migrator will never run there. That covers a migration merged out of order (older than one the branch already ran) and one edited after it ran;
    • the branch ran no migration this checkout does not commit, for example one from another git branch.
  • appkit db verify --deployed checks a databricks.yml target's app through the Databricks API only. -t, --target picks the target; without it, verify uses the bundle's default target. It checks that:

    • the app exists;
    • its postgres resource names the target's branch and database, with CAN_CONNECT_AND_CREATE;
    • its service principal has a role on the branch;
    • the app is running;
    • its active deployment has every committed migration.

    --deployed reads no database, so it needs no Postgres role on the deploy branch. It refuses when the target's workspace.host is not the workspace the shell is authenticated against.

Both exit 1 on any finding, and each finding names its fix. The OK lines say what was checked and nothing more.

Details

  • The local check runs in one READ ONLY transaction that is rolled back, then the pool closes.

  • Drift comes from reconciling the journal table's (created_at, hash) rows with the committed journal and files. The result is pending, stranded and edited migrations, plus rows no committed migration matches. Two entries that share a when keep their own rows. The migrator itself is unchanged.

  • The deployed migrations come from the journal in the snapshot the active deployment runs. That is deployment_artifacts.source_code_path, read through the workspace export API. When the journal cannot be read, verify falls back to the migrations generated after the deployment's create_time, and the report says which method it used.

  • With --deployed, a crashed, stopped, failed or in-progress app is reported with the app's own status message and the command to run next (databricks apps logs, start or deploy).

  • databricks.yml is read once for the guard, init and verify. The reader:

    • follows include:;
    • merges target overrides, with an app's resources merged by name;
    • resolves ${var.*}, ${bundle.target} and ${bundle.name};
    • reads the branch on an app's postgres resource as well as from postgres_branch;
    • lists every target with its workspace.host.

    A reference only a deploy resolves, such as a lookup or ${workspace.*}, reads as unresolved, never as a value.

  • A target with several apps on a postgres resource is refused, because verify checks one app per target.

  • The app is read with GET /api/2.0/apps/{name} and the journal with GET /api/2.0/workspace/export, both through the workspace client's request, in the API's snake_case. The authenticated host comes from the client's getHost.

  • findSchemaProblems is split out of the plugin's startup check, so verify reports the same problems the app would fail on.

Tests

  • The local tests cover:

    • a matching branch;
    • missing columns and pending migrations;
    • no journal table;
    • out-of-order, edited and uncommitted migrations;
    • the read-only transaction, including rollback and cleanup on failure.
  • The --deployed tests use a faked Apps, Workspace and Lakebase API where the developer has no role on the deploy branch. They cover:

    • --target, an unknown target and a bundle without a default target;
    • a shell authenticated against another workspace, refused before any API call;
    • a deployment missing a committed migration, by its journal and by deploy time;
    • each binding mismatch and each app state;
    • a missing app, branch or database;
    • an undeclared, unresolvable or per-target app name, and several apps on postgres.

    They also assert that no database connection and no write happens.

  • The bundle reader tests cover:

    • include:;
    • variable and ${bundle.*} resolution per target;
    • per-target hosts;
    • resource merging by name;
    • an implicit default target;
    • an invalid included file.
  • Migration drift runs against a local Postgres 14 with the real migrator, including two entries with one when.

  • Checked live, read-only, against a workspace through the workspace client:

    • the apps API's postgres resource format and a missing app's 404;
    • the active deployment's source_code_path, and a file in it exported and decoded from base64;
    • the authenticated host from getHost.

    A stopped app's response (it has no active deployment) and the service principal's role lookup were checked on the first revision. The live export read the snapshot's package.json, not a migration journal.

`appkit db verify` checks, read-only, that the branch .env points at has every
table and column config/database/schema.ts declares and every committed
migration. It also reports the migrations the migrator would never run there:
merged out of order, edited after they ran, or run from a checkout that no
longer commits them.

With --deployed it checks a databricks.yml target's app through the
Databricks API only: the app exists, its postgres resource names the target's
branch and database with CAN_CONNECT_AND_CREATE, its service principal has a
role there, it is running, and its active deployment has every committed
migration. -t picks the target. Verify refuses when the target's
workspace.host is not the workspace the shell is authenticated against. It
reads no database, so it needs no role on the deploy branch.

databricks.yml is read once for the guard, init and verify. The reader follows
include:, resolves ${var.*}, ${bundle.target} and ${bundle.name}, reads the
branch on an app's postgres resource, and lists every target.

Signed-off-by: ditadi <victordperd@gmail.com>
@ditadi
ditadi force-pushed the stack/database-dev-flow/06-db-verify branch from 42df642 to 1b3bde7 Compare October 20, 2026 12:22
@ditadi
ditadi force-pushed the stack/database-dev-flow/05-db-init branch from c56de21 to 98ef27b Compare October 20, 2026 12:23
@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

🤖 AppKit PR bot

🔬 Run evals

Start an eval for this PR from the evals-monitor app: Go to Evals Monitor →

📦 Try this PR's app template

Scaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh auth login — and the Databricks CLI):

gh run download 39422043965 -R databricks/appkit -n appkit-template-0.89.0-pr.a796dd4-stack-database-dev-flow-06-db-verify-674 -D appkit-pr-674 \
  && unzip -o "appkit-pr-674/appkit-template-0.89.0-pr.a796dd4-stack-database-dev-flow-06-db-verify-674.zip" -d "appkit-pr-674" \
  && databricks apps init --template "appkit-pr-674"

The template pins @databricks/appkit and @databricks/appkit-ui to tarballs built from this branch, so the scaffolded app runs against this PR's code.

This branch has not been deployed

No deployments
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.

1 participant