Release Notes -- 2026-05-26¶
Databricks Forge v1.0.2
v1.0.2 -- deploy.sh: zero-touch Lakebase + SP grant bootstrap + --destroy prompt¶
Bug Fixes¶
-
Silent missing
postgresbinding../deploy.sh(no Lakebase flags) previously printedPostgres binding: (not set - app must already have postgres resource), deployed an app with nopostgresresource, and the app crashed on every startup withFATAL: Lakebase resource binding env vars missing. The deploy script now auto-provisions a per-app Lakebase project (named after--app-name, sanitized to[a-z0-9-]{1,63}), defaultdatabricks_postgresdatabase, and waits for the endpoint to becomeACTIVEbefore continuing. Re-deploys discover the existingpostgresresource on the app and reuse the same binding. A hard pre-deploy guard now refuses to proceed if the binding can't be resolved. -
App service principal lacked
publicschema permissions. On a fresh Lakebase project, thepublicschema is owned by the deploying user, and the SP role minted by Lakebase on first bind had zero privileges.prisma db pushinscripts/start.shfailed withpermission denied for schema public.deploy.shnow runs a newbootstrap_lakebase_sp_grantsstep as the project owner which: - installs
pgvector+databricks_authextensions, - ensures the SP DB role exists (defensive; Lakebase mints it on first connect),
- grants
CONNECT+USAGE/CREATEonpublic+ table/sequence privileges +ALTER DEFAULT PRIVILEGES, - transfers ownership of any pre-existing
public.*tables to the SP so Prisma canALTER/DROPthem on schema migrations.
Idempotent. If the deploying user isn't the project owner (a teammate
re-deploying), the step skip-warns rather than failing — the original
deploy already applied the grants. This also self-heals the
cross-tool case where .deploy_local.sh previously created tables
owned by forge_local_dev: re-running ./deploy.sh reassigns
ownership to the SP.
--destroysilently left Lakebase project + data in place. The destroy flow now prompts about deleting the associated Lakebase project after the app is removed. Default answer is keep (data preservation wins). Non-interactive flags:--destroy-database(soft delete, recoverable),--purge-database(hard delete, immediate),--keep-database(skip the prompt, preserve — default when run in a non-TTY context like CI).
Improvements¶
-
Deployer gets SQL Editor access by default. When
deploy.shauto-provisions the project AND--lakebase-bootstrap-useris unset, the deploying user's email is used so they get a Databricks OAuth role on the new database immediately — no extra flag needed to inspect their own deploy. Opt out with--lakebase-bootstrap-user "". -
Scale-to-zero is now configured at the management plane. Lakebase Autoscaling treats scale-to-zero (
suspend_timeout_durationin the REST API) as an immutable project property, set only at project creation viadatabricks postgres create-project ... --json '{"spec":{"default_endpoint_settings":{"suspend_timeout_duration":"300s"}}}'.deploy.shnow bakes the value into thecreate-projectpayload when it auto-provisions a project (default300s), with operator override via--lakebase-scale-to-zero-seconds N. Re-deploys against an existing project leave the setting alone; passing--lakebase-scale-to-zero-secondson a re-deploy emits a warning explaining the value is immutable post-creation (workaround: destroy + redeploy, or migrate to a fresh project via--lakebase-project-id NEW). The configure helper is now a reporting-only step that prints the project's actual configured value during every deploy.
The legacy LAKEBASE_SCALE_TO_ZERO_TIMEOUT env var and
--lakebase-no-scale-to-zero flag have been removed — they were
runtime-side concepts that never took effect at the management plane
(and surfaced as "unsupported parameter" errors when operators tried
the equivalent CLI command).
- New flags.
--lakebase-project-id ID— override the auto-derived project ID.--lakebase-scale-to-zero-seconds N— branch scale-to-zero timeout.-
--destroy-database/--purge-database/--keep-database— non-interactive destroy choices. -
Relaxed flags.
--lakebase-branchand--lakebase-databaseare now optional (still paired — both or neither). They remain available as power-user overrides to bind an existing, externally-managed project/branch/database. The script validates that they are not combined with--lakebase-project-id.
Documentation¶
- Comprehensive cleanup of stale flag references across
README.md,QUICKSTART.md,docs/quickstart.md,docs/DEPLOYMENT.md, andAGENTS.md. The retired flags —--lakebase-auth-mode,--lakebase-native-user,--lakebase-native-password,--rotate-lakebase-native-password,--print-generated-native-password,--lakebase-runtime-mode,--lakebase-enable-pooler-experiment,--lakebase-scale-to-zero-timeout,--lakebase-no-scale-to-zero— were documented as if still supported even thoughdeploy.shno longer accepts them. - New "Lakebase auto-provisioning" section in
docs/DEPLOYMENT.mdexplaining the full lifecycle (resolution → endpoint-active wait → scale-to-zero config → SP grant bootstrap → deployer-as-bootstrap default → destroy prompt). - Updated env-var table in
README.md: replaced retired runtime variables (LAKEBASE_AUTH_MODE,LAKEBASE_NATIVE_USER,LAKEBASE_NATIVE_PASSWORD,LAKEBASE_POOLER_HOST,LAKEBASE_USERNAME) with the current OAuth-only surface (PGHOST/PGUSER/PGDATABASE/LAKEBASE_ENDPOINT/LAKEBASE_BOOTSTRAP_USER).
Behavior Changes¶
./deploy.sh(no flags) now succeeds end-to-end on a clean workspace — no manual Lakebase pre-provisioning required../deploy.sh --destroyis now interactive by default. Pass--keep-databaseor--destroy-databaseto silence the prompt in CI.- The success banner always prints the Postgres branch/database/endpoint (no more "(not set)" branch) and adds an "Auto-provisioned project" line when the script created the project on this run.
--destroy --destroy-databasenow finds projects auto-provisioned with a uniqueness suffix (e.g.forge-demo-69aa11f1when the bareforge-demoname was taken). Previously the destroy resolver only looked for the exactsanitize_lakebase_project_id "$APP_NAME"name and silently skipped suffixed projects.--destroyno longer exits early when the app is already absent. Previously, ifdatabricks apps deletereturned "does not exist" (e.g. the app was deleted out-of-band via the Databricks UI or a prior aborted run), the destroy flow returned before cleaning workspace files or processing--destroy-database. The Lakebase project would silently orphan and continue accruing cost. The branch now falls through to workspace + Lakebase cleanup.- Lakebase branch discovery prefers the branch explicitly marked
status.default == true(Lakebase guarantees exactly one), falling back to the canonicalproduction/mainname, then the first entry only as a last resort. Previously the picker blindly took the first item returned bylist-branches, which could route the app to a developer sandbox branch on multi-branch projects and serve incorrect data.
Known Limitations¶
--destroy --keep-databasefollowed by re-deploy will leave the app inCRASHEDstate. Each Databricks Apps deploy mints a new service-principal role. On a preserved Lakebase database, the pre-existing tables and indexes are owned by the previous SP (now gone). PostgreSQL requires the deploying user to be a member of the new SP role withADMIN OPTIONto transfer ownership; Lakebase does not grant that option to the deployer. The new SP canSELECT/INSERT/UPDATEexisting tables but cannotALTER/DROPthem, so Prisma's startupdb pushfails withmust be owner of index idx_embeddings_hnsw(or similar) and the app crashes on first request.
deploy.sh now detects this gap, prints a clear WARN after
the SP grant bootstrap reporting N pre-existing tables not
re-owned, and surfaces the two workarounds:
./deploy.sh --destroy --destroy-databaseto wipe and start fresh (preferred for non-production).- Manually grant the deployer role membership on the new SP via
the Postgres SQL editor:
GRANT "<new-sp-uuid>" TO "<deployer-email>" WITH ADMIN OPTION;then re-run./deploy.shto retry the ownership transfer.
Long-term fix on the table: move prisma db push from
scripts/start.sh (runs as SP) into deploy.sh's management-plane
step (runs as deployer, who already owns the schema). Tracked
separately.
Outcome map registry consolidation¶
Bug Fixes¶
-
Visible duplicates in the Outcomes browser.
INDUSTRY_OUTCOMESpreviously registered both the v2 split modules AND their legacy collapsed variants, so the dropdown listed Retail twice (retail+rcg-as-"Retail & Consumer Goods"), Healthcare twice (healthcare+hls), and Sports Betting / Real Money Gaming as a duplicate cluster. The legacy modules (rcg.ts,hls.ts,sports-betting.ts) plus their.enrichment.tsre-export shims have been deleted.INDUSTRY_ALIAS_MAPstill resolves legacy ids (rcg,hls,sports-betting) to the canonical v2 ids so oldForgeRunrows continue to load. -
Demo wizard auto-generated ad-hoc outcome maps. The research engine contained a Pass 3.5 (
runOutcomeMapGeneration) and Pass 3.5b (runEnrichmentOnlyGeneration) that, when the classifier returnedisNew: true, fired an LLM to invent an outcome map and persisted it toforge_outcome_mapsstampedcreatedBy='demo-wizard'. Discovery itself never created maps; this was a Demo Mode regression. The pass file, the wizard's "New industry outcome map generated and saved" banner, theoutcome-map-generationphase label, theOUTCOME_MAP_GENERATION_PROMPTandENRICHMENT_ONLY_GENERATION_PROMPTtemplates, and thegeneratedOutcomeMapfield onResearchEngineResultare all gone. The classifier prompt is now closed-list — it MUST return one of the registered industry ids — and the engine still routes the result throughnormalizeIndustryIdwith a closest-match fallback so a degenerate LLM response cannot bypass the registry.
Improvements¶
- Consultant-grade depth across the v2 split modules. RCG / HLS /
SPORTS_BETTING content (deep
whyChangenarratives,businessValueoutcome statements,typicalDataEntities, andtypicalSourceSystemsper use case) was lifted into the canonical v2 modules: rcg.ts→ split acrossretail.ts(omni-channel fulfilment, CDP / real-time personalisation, multi-brand loyalty, store labour / in-store execution, competitor pricing) andconsumer-goods.ts(supplier risk + demand forecasting, retailer-supplier collaboration, field operations, knowledge management, consumer sentiment).hls.ts→ split acrosshealthcare.ts(patient care, population health, claims, payer ops) andlife-sciences.ts(drug discovery, clinical trials, pharmacovigilance). Cross-cutting compliance use cases got authored on both sides with industry-appropriate sourcing.sports-betting.ts→ folded wholesale intoreal-money-gaming.ts.- Five thin v2 modules uplifted to the same bar.
capital-markets.ts,media-advertising.ts,energy-utilities.ts,games.ts, anddigital-natives.tspreviously had only name + 1-line description per use case. Each now ships deepwhyChangeprose, quantifiedbusinessValueoutcomes (sourced from the existing*.enrichment.tskpiTarget+benchmarkImpactdata), 4-6typicalDataEntities, and 3-5typicalSourceSystemsper reference use case. - Master Repository converter writes directly to v2.
scripts/convert-master-repo.mjsnow maps the XLSX names directly to the canonical v2 ids (Retail→retail,Consumer Goods→consumer-goods,Life Sciences→life-sciences,Healthcare→healthcare,Real Money Gaming [Digital]→real-money-gaming). Future re-runs no longer round-trip through the legacy id namespace.
Behavior Changes¶
- The Outcomes browser dropdown is shorter and free of duplicates. Three
legacy entries (
rcg,hls,sports-betting) are gone from the visible list; they continue to resolve to canonical ids for existingForgeRun.config.industryrows. - The Demo wizard timeline no longer shows an "Industry Knowledge" step
and never writes to
forge_outcome_maps. If the classifier picks an id that is somehow unmapped, the engine logs a server-side warning and falls back to the closest registered industry — it never papers over the gap with a per-customer LLM-generated map. forge_outcome_mapsrows previously stampedcreatedBy='demo-wizard'are NOT auto-deleted; they continue to override the (now-richer) built-ins for any collidingindustryId. To purge them in one shot:prisma.forgeOutcomeMap.deleteMany({ where: { createdBy: "demo-wizard" } }).
Known Limitations¶
- The per-industry benchmark packs in
data/benchmark/{rcg,hls,sports-betting}*.jsonremain on disk. They're keyed by the legacy industry ids and are still consulted by older runs that resolve throughINDUSTRY_ALIAS_MAP. Retiring them properly needs a benchmark migration tracked separately.
All Commits¶
| Hash | Summary |
|---|---|
| (pending) | feat(deploy): auto-provision Lakebase project + SP grant bootstrap (zero-flag deploy) |
| (pending) | feat(deploy): --destroy prompts about Lakebase project + --destroy-database / --purge-database / --keep-database flags |
| (pending) | feat(deploy): scale-to-zero baked into create-project payload (immutable post-creation, reporting on re-deploy) |
| (pending) | feat(deploy): destroy resolver finds suffixed Lakebase projects (<app>-<8hex>) when the bare name is taken |
| (pending) | feat(deploy): SP-grant bootstrap detects the --keep-database ownership gap and surfaces actionable workarounds |
| (pending) | fix(deploy): destroy continues to workspace + Lakebase cleanup when the app is already absent |
| (pending) | fix(deploy): pick the branch with status.default == true (fall back to production/main) instead of list-branches[0] |
| (pending) | docs: clean up retired Lakebase flag references across README, QUICKSTART, docs/DEPLOYMENT, AGENTS |