Skip to content

feat: adopt the upstream alchemy/Prisma provider - #197

Open
wmadden-electric wants to merge 25 commits into
mainfrom
claude/alchemy-prisma-composer-eval-93897e
Open

feat: adopt the upstream alchemy/Prisma provider#197
wmadden-electric wants to merge 25 commits into
mainfrom
claude/alchemy-prisma-composer-eval-93897e

Conversation

@wmadden-electric

@wmadden-electric wmadden-electric commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Composer's six hand-written Alchemy resources for Prisma Cloud are gone. Deploys and local dev now run on the official alchemy/Prisma provider (alchemy 2.0.0-beta.67):

// lowering/src/providers.ts — the whole live wiring is now composition, not implementation
Layer.mergeAll(
  Prisma.ProjectProvider(),
  Prisma.DatabaseProvider(),
  Prisma.ConnectionProvider(),
  Prisma.AppProvider(),
  Prisma.DeploymentProvider(),
  Prisma.EnvironmentVariableProvider(),
  // still ours until upstream PR alchemy-run/alchemy#1061 releases:
  BucketProvider(), BucketKeyProvider(),
)

Why: upstream tracks the Management API so we don't, and its deploy lifecycle is better than ours was — cleanup of failed deployments, terminal-status fast-fail, post-promote endpoint observation. Decision record: ADR-0043.

What changed

  • Foundation — alchemy beta.59 → beta.67 (plus the forced effect beta.100 train). Our provider collection tag and remaining resource type-ids renamed to PrismaComposer.*; the old ids are aliases so existing state rows resolve.
  • Postgres family — upstream Project/Database/Connection classes, driven by our own auth layer (PrismaEnvironment from PRISMA_SERVICE_TOKEN, no interactive profile store; one base-URL resolver shared with our SDK client). Branch stages create their database attached with a generated physical name (upstream correctly refuses explicit-name-plus-branch; verified against PDP source). directConnectionString is bound explicitly — upstream's databaseUrl is pooled-first.
  • Compute family — upstream's low-level App/Deployment/EnvironmentVariable, not composite Compute: the COMPOSER_*_ORIGIN self-edge needs the App to exist before env rows, and Deployment has no build path at all (ADR-0005 by structure). The env→deployment ordering edge rides the deployment's app prop as an Output (deployment-edge.ts) — riding artifactPath would silently skip code deploys when a new env row lands in the same deploy (proven with tests against alchemy's real Output machinery, and re-proven live).
  • A deployment is replaced exactly when its environment changes (compute/deploy-fingerprint.ts) — the artifact hard-link directory is named from a hash of the service's environment material, so upstream reuses the deployment when nothing changed and replaces it when the env or artifact did. The hashed material is non-secret by construction (ADR-0042 rows carry literals and pointers, never values); out-of-band rotation of a pointed platform variable is detected via its updatedAt metadata, read at preflight and carried across the CLI→Alchemy process boundary on a new preflight-transport channel. Swaps onto upstream's Deployment.redeployOn (in #1061) at a marked seam when it releases.
  • Legacy state migrates on read (state/legacy-resources.ts) — old type-ids and attribute shapes rewrite in the hosted store; the retired poison DATABASE_URL rows are reported retained (state row dropped, platform variable untouched). Fresh projects get the poison back by a different route: application.provision claims DATABASE_URL/DATABASE_URL_POOLED with "-" via create-only writes (never tracked as resources, never modified or deleted), because the platform otherwise self-heals a missing DATABASE_URL on first deploy with a live credential to one of the app's own databases. Existing rows — platform-seeded or ours — 409 and no-op. The authoring-side name ban remains.
  • Local dev unchanged in shape — the local target binds upstream's resource classes to our emulators at the same seam (ADR-0041).

Verified

  • Full suites green at every commit (build 36/36, typecheck 74/74, tests 62/63 with the one known dev-emulators flake; cast delta −8).
  • Deployed smoke against real Prisma Cloud: fresh deploy + 2/2 smoke, idempotent redeploy (zero churn), the code-plus-new-var scenario that motivated the edge design (deployment replaced, new code live), clean destroy.
  • A genuinely legacy stage (deployed from this PR's merge-base, redeployed from this branch): adopted in place — same database id, app ids, URLs — one-time deployment reship, then steady state byte-identical to a fresh stack. Clean destroy.

Operator notes (also in docs/guides/deploying.md)

  • First deploy after upgrading replaces each service's deployment once.
  • Branch-stage databases migrate to generated physical names; the database's default connection credentials rotate once (the app's own connection is unaffected).
  • The "-" placeholder in DATABASE_URL/DATABASE_URL_POOLED is deliberate and self-restoring; deleting it by hand is not useful (the next deploy's claim or the platform's template filler recreates the row). A user-set value wins over both — the guide has the details.

Follow-up (tracked in TML-3156)

When upstream PR alchemy-run/alchemy#1061 merges and releases: bump alchemy, delete our bucket resources (upstream now ships them with capability bindings), drop the alchemy pnpm patch, and move the deploy fingerprint onto Deployment.redeployOn at the marked seam.

🤖 Generated with Claude Code

…ign notes

Adopt the upstream alchemy/Prisma provider for the six overlapping
resources, keep Composer emulators local, contribute buckets + the generic
Postgres state store upstream. Slices TML-3154/3155/3156.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…e-ids, aliases

Bump alchemy 2.0.0-beta.59 -> .67 (13 pins) + forced effect beta.100
train. Rename the provider collection tag and the eight resource
type-ids from Prisma.* to PrismaComposer.* so they cannot collide with
the upstream alchemy/Prisma provider; old ids wired as aliases so
existing state rows resolve (beta.67 ResourceOptions.aliases).
One-line pnpm patch for upstream Aliases typing under
exactOptionalPropertyTypes; Schedule.both removal handled with
Schedule.upTo (during is inverted in beta.100, verified by probe).

Part of alchemy-provider-adoption (TML-3154).

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Delete Composer's Project/Database/Connection resources; register
upstream's classes in the PrismaComposer collection over a
profile-store-free PrismaEnvironment (PRISMA_SERVICE_TOKEN + shared
managementApiBaseUrl resolver honored identically by our SDK client).
Descriptors bind directConnectionString explicitly; branch stages
create with branchId and a generated physical name (upstream's
reconcile reverts external attach/rename, so create-then-PATCH is not
viable); production keeps explicit names. Legacy state rows migrate on
read in the hosted store (type-ids + attribute shapes), proven against
upstream's real diff/read/reconcile incl. a no-rotation guard; the
one-time branch-stage rename + default-connection rotation is
documented in docs/guides/deploying.md. Local-target providers rebind
the emulators to upstream's classes.

Part of alchemy-provider-adoption (TML-3154).

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
… alternatives

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Replace ComputeService/Deployment/EnvironmentVariable with upstream
App/Deployment/EnvironmentVariable (not composite Compute: the
COMPOSER_*_ORIGIN self-edge needs the App created before env rows, and
Compute owns env rows in a map our per-key state cannot migrate into).
The env->deployment ordering edge rides the app prop as an Output
(deployment-edge.ts) — riding artifactPath would leave the diff
unresolved for brand-new env rows and silently skip code deploys;
proven by tests driving alchemy's real Output machinery. Legacy
compute rows migrate on read incl. poison-row neutralization; the
platform DATABASE_URL is no longer overwritten (system-managed;
authoring-side ban remains). Local target rebinds the emulators to
upstream classes. Known regressions recorded in design notes: env
value changes no longer redeploy (upstream ask filed) and App delete
retry budget is ~3.75s (upstream ask filed).

Part of alchemy-provider-adoption (TML-3155).

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…m Alchemy provider

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…tion docs

Legacy poison DATABASE_URL rows are retired with removalPolicy retain:
the engine drops the state row, calls no API, and prints "retained" —
the previous "deleted" was false (the platform variable survives, still
holding the "-" placeholder on migrated stages). deploying.md,
alchemy-lowering.md and the design notes now say so, with the optional
manual cleanup calls.

Part of alchemy-provider-adoption (TML-3155).

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Restore the pre-swap guarantee that a deploy ships what you declared:
the deploy hook hard-links the content-addressed artifact into a
per-deploy-generation path, so upstream Deployment plans a replace
every deploy (the updatedAt route is impossible: not in stables, and
the env diff plans update every deploy, so plan-time values are
unresolved). No secret material in state. The app ordering edge is
untouched. Cost is the pre-swap profile: one deployment replacement
per service per deploy, until the pinned alchemy version includes
Deployment.redeployOn — the swap is one edit at the marked seam.

Part of alchemy-provider-adoption (TML-3155).

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@wmadden-electric, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 9 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4bd5512b-e105-4ade-a8c2-e92ae9165acf

📥 Commits

Reviewing files that changed from the base of the PR and between e69ce48 and c434e9d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (58)
  • .drive/projects/alchemy-provider-adoption/design-notes.md
  • .drive/projects/alchemy-provider-adoption/spec.md
  • docs/design/03-domain-model/glossary.md
  • docs/design/03-domain-model/layering.md
  • docs/design/05-prisma-cloud/alchemy-lowering.md
  • docs/design/05-prisma-cloud/pdp-data-model.md
  • docs/design/10-domains/core-model.md
  • docs/design/90-decisions/ADR-0043-prisma-cloud-resources-come-from-the-upstream-alchemy-provider.md
  • docs/design/90-decisions/README.md
  • docs/guides/deploying.md
  • docs/guides/running-locally.md
  • examples/bucket/package.json
  • examples/cron/package.json
  • examples/pn-widgets/package.json
  • examples/storage/package.json
  • examples/store/package.json
  • examples/storefront-auth/package.json
  • gotchas.md
  • packages/0-framework/1-core/core/package.json
  • packages/0-framework/1-core/core/src/__tests__/preflight-transport.test.ts
  • packages/0-framework/1-core/core/src/container-transport.ts
  • packages/0-framework/1-core/core/src/control/app-config.ts
  • packages/0-framework/1-core/core/src/preflight-transport.ts
  • packages/0-framework/3-tooling/cli/src/main.ts
  • packages/0-framework/3-tooling/cli/src/run-alchemy.ts
  • packages/1-prisma-cloud/0-lowering/local-target/package.json
  • packages/1-prisma-cloud/0-lowering/local-target/src/compute.ts
  • packages/1-prisma-cloud/0-lowering/local-target/src/postgres.ts
  • packages/1-prisma-cloud/0-lowering/local-target/src/upstream-attributes.ts
  • packages/1-prisma-cloud/0-lowering/lowering/package.json
  • packages/1-prisma-cloud/0-lowering/lowering/src/__tests__/database-url-poison.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/__tests__/deploy-fingerprint.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/__tests__/deployment-edge.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/artifact.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/deploy-fingerprint.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/deployment-edge.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/database-url-poison.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/exports/compute.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/exports/index.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/http.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/state/__tests__/legacy-resources.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/state/legacy-resources.ts
  • packages/1-prisma-cloud/1-extensions/target/package.json
  • packages/1-prisma-cloud/1-extensions/target/src/__tests__/control-lowering.test.ts
  • packages/1-prisma-cloud/1-extensions/target/src/__tests__/invariants.test.ts
  • packages/1-prisma-cloud/1-extensions/target/src/__tests__/pointer-timestamps.test.ts
  • packages/1-prisma-cloud/1-extensions/target/src/__tests__/preflight.test.ts
  • packages/1-prisma-cloud/1-extensions/target/src/control/extension.ts
  • packages/1-prisma-cloud/1-extensions/target/src/control/pointer-timestamps.ts
  • packages/1-prisma-cloud/1-extensions/target/src/descriptors/compute.ts
  • packages/1-prisma-cloud/1-extensions/target/src/descriptors/shared.ts
  • packages/1-prisma-cloud/1-extensions/target/src/preflight.ts
  • packages/1-prisma-cloud/1-extensions/target/src/serializer.ts
  • packages/9-public/composer-prisma-cloud/package.json
  • packages/9-public/composer/package.json
  • scripts/check-npm-effect-resolution.mjs
  • test/integration/package.json
  • website/package.json

Summary by CodeRabbit

  • New Features
    • Added support for upstream Prisma resources for applications, deployments, PostgreSQL databases, connections, and object storage.
    • Added configurable management API endpoints and improved local development provider support.
  • Improvements
    • Existing hosted deployment state migrates automatically while preserving production resources and service URLs.
    • Configuration changes now reliably propagate through fresh deployments.
    • Platform-managed database URLs are no longer overwritten.
  • Documentation
    • Added upgrade, migration, local development, and architecture guidance.
  • Bug Fixes
    • Improved environment-variable ordering, secret handling, and deployment reconciliation.

Walkthrough

This change adopts upstream Alchemy Prisma providers for PostgreSQL and compute resources. It updates provider composition, local emulators, resource descriptors, authentication, redacted environment handling, deployment ordering, and forced redeployment. It adds legacy state migration for existing Composer resources and retains platform-owned database URL rows. It updates tests, documentation, package exports, dependency versions, and the Alchemy type patch.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly and concisely summarizes the primary change: adoption of the upstream alchemy/Prisma provider.
Description check ✅ Passed The description directly explains the upstream provider adoption, retained resources, migration behavior, deployment changes, and validation results.
✨ Finishing Touches 💡 2
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch claude/alchemy-prisma-composer-eval-93897e
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/alchemy-prisma-composer-eval-93897e
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/alchemy-prisma-composer-eval-93897e

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.

…s only

Grounding code first, decision led, alternatives last. Removed
transient project/process references and corrected two statements the
implementation had already overtaken (env changes now always ship via
per-generation artifact paths; upstream dev mode is dual registration,
not an option we pass).

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…-composer-eval-93897e

# Conflicts:
#	docs/design/05-prisma-cloud/alchemy-lowering.md
#	examples/bucket/package.json
#	examples/cron/package.json
#	examples/pn-widgets/package.json
#	examples/storage/package.json
#	examples/store/package.json
#	examples/storefront-auth/package.json
#	packages/0-framework/1-core/core/package.json
#	packages/1-prisma-cloud/0-lowering/local-target/package.json
#	packages/1-prisma-cloud/0-lowering/lowering/package.json
#	packages/9-public/composer-prisma-cloud/package.json
#	pnpm-lock.yaml
#	website/package.json
createDatabase: false removes the default database but not the
variable: the platform heals a missing DATABASE_URL template on the
first Compute deploy from any ready database on the Project (verified
in the control plane: healDefaultDatabaseUrl via materializeDeployEnv).
The authoring-side name ban is the line that holds.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@pkg-pr-new

pkg-pr-new Bot commented Aug 3, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@prisma/composer@197
npm i https://pkg.pr.new/@prisma/composer-prisma-cloud@197

commit: c434e9d

@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: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/design/05-prisma-cloud/pdp-data-model.md (1)

82-89: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Align all deployment-propagation documentation with the shipped replacement mechanism.

These sections describe one stale model: deployment replacement occurs only when artifact content changes and environment changes do not trigger replacement. The shipped lowering uses a fresh generation path and replaces every deployment on every deploy.

  • docs/design/05-prisma-cloud/pdp-data-model.md#L82-L89: state that every deploy creates a replacement deployment under the current stopgap.
  • docs/design/10-domains/core-model.md#L725-L737: remove the claim that environment changes are not propagated.
  • docs/design/10-domains/core-model.md#L1096-L1100: use alwaysRedeployArtifactPath(artifact.path) in the example.
🤖 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 `@docs/design/05-prisma-cloud/pdp-data-model.md` around lines 82 - 89, Align
all three deployment-propagation documentation sites with the shipped
replacement behavior: in docs/design/05-prisma-cloud/pdp-data-model.md lines
82-89, state that every deploy creates a replacement deployment under the
current stopgap; in docs/design/10-domains/core-model.md lines 725-737, remove
the claim that environment changes are not propagated; and in
docs/design/10-domains/core-model.md lines 1096-1100, update the example to use
alwaysRedeployArtifactPath(artifact.path).
🤖 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 @.drive/projects/alchemy-provider-adoption/assets/composer-pr-body.md:
- Line 30: Update the “Full suites green” statement in the PR body to report
tests as non-green, preserving the exact 62/63 pass count and explicitly
identifying the known dev-emulators flake; keep the build and typecheck results
unchanged.
- Line 1: Add a level-one Markdown title before the existing prose in both
.drive/projects/alchemy-provider-adoption/assets/composer-pr-body.md (lines 1-1)
and .drive/projects/alchemy-provider-adoption/assets/upstream-pr-body.md (lines
1-1), ensuring each document begins with an H1 heading.

In @.drive/projects/alchemy-provider-adoption/design-notes.md:
- Around line 14-20: Update the provider model section around “One provider
(upstream’s)” to scope ownership to retained bucket resources: state that
upstream owns PostgreSQL and compute, while Composer continues composing
BucketProvider and BucketKeyProvider until the upstream release; preserve the
existing deploy/dev layer distinction.

In @.drive/projects/alchemy-provider-adoption/spec.md:
- Around line 150-151: Update .drive/projects/alchemy-provider-adoption/spec.md
lines 150-151 to replace the beta.66 open question with the resolved
alchemy@2.0.0-beta.67 decision. In docs/design/03-domain-model/glossary.md lines
378-387, update the surrounding beta.59 reference to alchemy@2.0.0-beta.67.

In `@docs/design/03-domain-model/layering.md`:
- Line 38: Update the Service mapping row in the layering documentation to
replace Platform with the Composer resource graph established by glossary.md and
ADR-0043: ordinary App and Deployment resources, including the existing bundle,
manifest, and endpoint relationship. Keep the Service and ingress description
unchanged.

In `@docs/design/10-domains/config-params.md`:
- Around line 82-83: Update the canonical ADR-0039 decision and index references
to use the renamed origin API consistently, replacing outdated
ComputeService.origin() and endpointDomain terminology or adding an explicit
supersession note that identifies the current API. Ensure this section and the
ADR index do not present conflicting APIs.

In `@docs/guides/running-locally.md`:
- Around line 49-54: Update the --fresh guidance in the local-running
documentation to state that it is safe only when local instances and data are
disposable, rather than always safe. Preserve the stale-framework-state
troubleshooting context while explicitly warning that using --fresh wipes local
data.

In `@gotchas.md`:
- Around line 303-305: Update the gotcha sentence describing Prisma.App and
Prisma.Database so it states that Prisma.App creates on the target Branch, while
Prisma.Database is created at project scope and then attached to the branch via
PATCH. Remove the claim that both resources create directly on the target
Branch.

In `@packages/1-prisma-cloud/0-lowering/local-target/src/postgres.ts`:
- Around line 41-59: Extract the duplicated DEV_TIMESTAMP, isRecord, and
projectIdOfInput definitions from postgres.ts and compute.ts into a shared
upstream-input module, exporting all three symbols. Remove the local copies and
import the shared symbols in both files, while leaving databaseIdOfInput in
postgres.ts unchanged and preserving existing behavior.

In `@packages/1-prisma-cloud/0-lowering/lowering/src/client.ts`:
- Around line 20-33: Discharge URL resolver errors in the exported layer around
managementApiBaseUrl and the ManagementClient effect before returning
managementClientLayer. Apply Layer.orDie or an equivalent catchAll so the
provided layer no longer exposes Config.ConfigError | Error to callers, while
preserving PrismaCredentials as its remaining requirement.

In `@packages/1-prisma-cloud/0-lowering/lowering/src/compute/always-redeploy.ts`:
- Around line 41-66: Add best-effort lifecycle cleanup for directories matching
deploy-<generation> in the artifact parent used by alwaysRedeployArtifactPath.
Run cleanup only after the new deployment succeeds, preserve the newly returned
path and any paths still referenced by provider state, and ignore cleanup
failures so deployment success is unaffected.

In
`@packages/1-prisma-cloud/0-lowering/lowering/src/state/__tests__/legacy-resources.test.ts`:
- Around line 110-130: Extract a generic provider-service factory helper for the
five duplicated factories, centralizing the Effect.Effect cast and PrismaClient
layer setup. Parameterize it by the resource service type, provider, provider
layer, and stub client, then update databaseService, connectionService, and the
other provider factories to delegate to it while preserving their existing
behavior.

In `@packages/1-prisma-cloud/0-lowering/lowering/src/state/legacy-resources.ts`:
- Around line 211-217: Update poisonKeyOf to return a poison key only when the
EnvironmentVariable row’s props still match the legacy shape containing
projectId and key; continue deriving the key from the row attributes or legacy
props as appropriate, and return undefined for poison keys on non-legacy props.
Keep the existing family and POISON_KEYS checks intact.
- Around line 330-331: Move the poisonKey check in the legacy resource migration
flow so the nested old-chain rewrite completes before retirePoisonRow is called,
preserving the migrated EnvironmentVariable shape for replaced poison rows.
Update the surrounding function that handles family/row migration and add a
regression test in the legacy-resources tests covering a replaced poison row and
its migrated old generation.

---

Outside diff comments:
In `@docs/design/05-prisma-cloud/pdp-data-model.md`:
- Around line 82-89: Align all three deployment-propagation documentation sites
with the shipped replacement behavior: in
docs/design/05-prisma-cloud/pdp-data-model.md lines 82-89, state that every
deploy creates a replacement deployment under the current stopgap; in
docs/design/10-domains/core-model.md lines 725-737, remove the claim that
environment changes are not propagated; and in
docs/design/10-domains/core-model.md lines 1096-1100, update the example to use
alwaysRedeployArtifactPath(artifact.path).
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 550b0395-1264-43c7-9b23-1d43865c369c

📥 Commits

Reviewing files that changed from the base of the PR and between 04f5f81 and e69ce48.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (83)
  • .drive/projects/alchemy-provider-adoption/assets/composer-pr-body.md
  • .drive/projects/alchemy-provider-adoption/assets/upstream-pr-body.md
  • .drive/projects/alchemy-provider-adoption/design-notes.md
  • .drive/projects/alchemy-provider-adoption/plan.md
  • .drive/projects/alchemy-provider-adoption/spec.md
  • docs/design/03-domain-model/glossary.md
  • docs/design/03-domain-model/layering.md
  • docs/design/05-prisma-cloud/alchemy-lowering.md
  • docs/design/05-prisma-cloud/pdp-data-model.md
  • docs/design/10-domains/config-params.md
  • docs/design/10-domains/core-model.md
  • docs/design/10-domains/local-dev.md
  • docs/design/90-decisions/ADR-0043-prisma-cloud-resources-come-from-the-upstream-alchemy-provider.md
  • docs/design/90-decisions/README.md
  • docs/guides/deploying.md
  • docs/guides/running-locally.md
  • examples/bucket/package.json
  • examples/cron/package.json
  • examples/pn-widgets/package.json
  • examples/storage/package.json
  • examples/store/package.json
  • examples/storefront-auth/package.json
  • gotchas.md
  • packages/0-framework/1-core/core/package.json
  • packages/1-prisma-cloud/0-lowering/local-target/package.json
  • packages/1-prisma-cloud/0-lowering/local-target/src/__tests__/compute-scoped-env.test.ts
  • packages/1-prisma-cloud/0-lowering/local-target/src/__tests__/postgres-instance-name-drift.test.ts
  • packages/1-prisma-cloud/0-lowering/local-target/src/compute.ts
  • packages/1-prisma-cloud/0-lowering/local-target/src/postgres.ts
  • packages/1-prisma-cloud/0-lowering/local-target/src/providers.ts
  • packages/1-prisma-cloud/0-lowering/lowering/package.json
  • packages/1-prisma-cloud/0-lowering/lowering/src/__tests__/ComputeService.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/__tests__/Database.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/__tests__/EnvironmentVariable.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/__tests__/ServiceKey.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/buckets/Bucket.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/buckets/BucketKey.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/client.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/ComputeService.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/Deployment.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/EnvironmentVariable.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/__tests__/always-redeploy.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/__tests__/deployment-edge.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/always-redeploy.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/artifact.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/deployment-edge.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/credentials.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/exports/compute.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/exports/index.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/exports/postgres.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/postgres/Connection.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/postgres/Database.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/postgres/Project.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/providers.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/state/__tests__/legacy-resources.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/state/layer.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/state/legacy-resources.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/state/service.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/state/transient.ts
  • packages/1-prisma-cloud/0-lowering/lowering/tsdown.config.ts
  • packages/1-prisma-cloud/1-extensions/target/package.json
  • packages/1-prisma-cloud/1-extensions/target/src/__tests__/control-lowering.test.ts
  • packages/1-prisma-cloud/1-extensions/target/src/__tests__/generated-param.test.ts
  • packages/1-prisma-cloud/1-extensions/target/src/__tests__/pg-warm-resource.test.ts
  • packages/1-prisma-cloud/1-extensions/target/src/__tests__/pn-migration-resource.test.ts
  • packages/1-prisma-cloud/1-extensions/target/src/__tests__/s3-credentials.test.ts
  • packages/1-prisma-cloud/1-extensions/target/src/control/extension.ts
  • packages/1-prisma-cloud/1-extensions/target/src/descriptors/compute.ts
  • packages/1-prisma-cloud/1-extensions/target/src/descriptors/postgres.ts
  • packages/1-prisma-cloud/1-extensions/target/src/descriptors/prisma-next.ts
  • packages/1-prisma-cloud/1-extensions/target/src/descriptors/shared.ts
  • packages/1-prisma-cloud/1-extensions/target/src/param.ts
  • packages/1-prisma-cloud/1-extensions/target/src/preflight.ts
  • packages/1-prisma-cloud/1-extensions/target/src/secret.ts
  • packages/1-prisma-cloud/1-extensions/target/src/serializer.ts
  • packages/9-public/composer-prisma-cloud/package.json
  • packages/9-public/composer/package.json
  • patches/alchemy@2.0.0-beta.67.patch
  • pnpm-workspace.yaml
  • scripts/ci-cleanup-utils.ts
  • test/integration/package.json
  • test/integration/test/local-dev.integration.ts
  • website/package.json
💤 Files with no reviewable changes (11)
  • packages/1-prisma-cloud/0-lowering/lowering/src/exports/postgres.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/postgres/Connection.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/postgres/Database.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/postgres/Project.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/tests/Database.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/ComputeService.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/tests/EnvironmentVariable.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/tsdown.config.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/EnvironmentVariable.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/tests/ComputeService.test.ts
  • packages/1-prisma-cloud/0-lowering/lowering/src/compute/Deployment.ts

Comment thread .drive/projects/alchemy-provider-adoption/design-notes.md Outdated
Comment thread .drive/projects/alchemy-provider-adoption/spec.md Outdated
Comment thread docs/design/03-domain-model/layering.md Outdated
Comment thread packages/1-prisma-cloud/0-lowering/lowering/src/client.ts
Comment thread packages/1-prisma-cloud/0-lowering/lowering/src/compute/always-redeploy.ts Outdated
Comment thread packages/1-prisma-cloud/0-lowering/lowering/src/state/legacy-resources.ts Outdated
application.provision claims DATABASE_URL/DATABASE_URL_POOLED
(production + preview, project-level) with "-" via create-only POSTs,
skipping 409s. The platform build-runner self-heals a missing
DATABASE_URL template on first deploy from any ready database, so
without the claim a bypass reader quietly gets a live credential to one
of the app's own databases; with it, direct readers fail loudly. The
rows are never alchemy resources (nothing in state, upstream never owns
them); legacy projects with platform-seeded rows 409 and no-op.

Part of alchemy-provider-adoption (TML-3155).

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The lowering doc and deploy guide describe the create-only claim, why
it exists (the platform fills a missing DATABASE_URL from any ready
database on first deploy), and that manual deletion is not useful —
the claim or the platform recreates the row; a user-set value wins
over both.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…h wording

ADR index origin API naming (App.appEndpointDomain per ADR-0043),
layering Service row, glossary beta pin, spec open question resolved,
design-notes provider-scope claim, gotchas branch-attach fix line
matches its cause, --fresh documented as data-destroying, and the two
propagation passages now describe env changes reaching the running
deployment.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…sed otherwise

Replace the per-run generation path with a deploy fingerprint: the
artifact hard-link directory is named from a hash of the service's
environment material, so upstream's artifactPath comparison replaces
exactly when the environment or artifact changed. The material is
non-secret by construction (ADR-0042 rows carry literals and pointers);
pointed platform variables contribute updatedAt metadata, read at
preflight and carried across the CLI->alchemy process boundary on a new
framework preflight-transport channel (the in-process implementation
lost the timestamps at spawn — caught in review, now covered by a
boundary-spanning test). Secret-bearing rows contribute wiring identity
only; the accepted narrowing is recorded in the module. Docs updated to
the shipped mechanism.

Part of alchemy-provider-adoption (TML-3155); addresses PR 197 A11.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…-composer-eval-93897e

# Conflicts:
#	examples/bucket/package.json
#	examples/cron/package.json
#	examples/pn-widgets/package.json
#	examples/storage/package.json
#	examples/store/package.json
#	examples/storefront-auth/package.json
#	packages/0-framework/1-core/core/package.json
#	packages/1-prisma-cloud/0-lowering/local-target/package.json
#	packages/1-prisma-cloud/0-lowering/lowering/package.json
#	website/package.json
…ribute helpers

The compute and postgres provider families each carried their own
byte-identical DEV_TIMESTAMP, isRecord and projectIdOfInput. They now
import them from src/upstream-attributes.ts, so the 'local' project
fallback and the stamped timestamp cannot drift between the two.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…hape

Upstream's own EnvironmentVariable rows carry the same type-id as the
legacy ones, so a key match alone would retire a live, upstream-managed
DATABASE_URL variable from state on every read. poisonKeyOf now applies
the same props-shape discriminator the rest of the module uses.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…retiring it

The retirement returned early, so the displaced generation nested under
`old` kept its legacy shape and reached the engine unmigrated. The old
chain is rewritten first; the retirement now happens on the fully
migrated row.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric

Copy link
Copy Markdown
Contributor Author

Re the outside-diff finding in the CHANGES_REQUESTED review (deployment propagation docs): done in ce6c2cd.

Both prose sites now describe the mechanism this branch ships — an environment change reaches the running app because the deployment edge replaces the deployment — instead of claiming env-var changes never propagate:

  • docs/design/05-prisma-cloud/pdp-data-model.md (the deployment-immutability passage)
  • docs/design/10-domains/core-model.md (the propagation passage)

core-model.md around 1096-1100 already used the current appAfterEnvironment example, so it needed no change. The deployment edge itself was reworked on this branch since that review: compute/deploy-fingerprint.ts (commit 5b0e934) replaces a deployment when its environment changes and reuses it otherwise.

Comment on lines +55 to +56
export function mangleExtensionId(extensionId: string): string {
return extensionId

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What do you mean "mangle"?

Comment on lines +1 to +19
/**
* Carries what an extension's deploy preflight learned from the CLI process
* into the alchemy process — the same two-process problem, and the same
* channel, as resolved containers (ADR-0037, container-transport.ts).
*
* Preflight runs in the CLI parent, because it is the step that talks to the
* platform. Alchemy then runs as a child process against the generated stack
* file, which re-imports the app config from scratch: every extension factory
* is called again, with none of the parent's state. Anything preflight learned
* that the lowering needs is therefore gone unless it is transported, and env
* vars are the only channel between the two processes. So the CLI writes each
* extension's preflight payload into one env var, and the extension reads its
* own var back in the alchemy process. The framework owns the vars; it never
* reads their contents.
*
* An extension must never put a SECRET VALUE in a payload: the alchemy child's
* environment is not a secret store, and the payload is not encrypted. Carry
* metadata (e.g. when a platform variable was last written), never values.
*/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Don't put giant comments in file headers. Re-review all comments in the diff - don't be so verbose. Nobody needs all this text and it will never be read.

Comment on lines +12 to +14
export function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Pretty sure this util already exists


/** A Prisma **Object Store bucket** inside a project. */
export const Bucket = Resource<Bucket>('Prisma.Bucket');
export const Bucket = Resource<Bucket>('PrismaComposer.Bucket', { aliases: ['Prisma.Bucket'] });

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's stop using magic strings. Extract the 'PrismaComposer.Bucket' id into a const

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Also why do we need the alias?

/** A **bucket access key** for a Prisma Object Store bucket — yields the S3 credentials. */
export const BucketKey = Resource<BucketKey>('Prisma.BucketKey');
export const BucketKey = Resource<BucketKey>('PrismaComposer.BucketKey', {
aliases: ['Prisma.BucketKey'],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why do all these resoruces have aliases?

* it, replace this — pass the canonical `artifact.path` verbatim again and put
* this fingerprint on `redeployOn`. The one call site is
* `descriptors/compute.ts`'s deploy hook.
*/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

THIS IS AN 85 LINE COMMENT!

import { type ManagementApiClient, ManagementClient } from './client.ts';
import { callCreateOnly, type PrismaApiError } from './http.ts';

const POISON_VALUE = '-';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It's really concerning these are "poison keys" and "poison values". Rename all of this without the word poison. You've way overfitted to your own invented vocabulary

Reconciles the preflight env-var listing: main bounded the loop with
drivePagesAsync (#204); this branch made the same loop track the newest
updatedAt for the deploy fingerprint. The merged version walks every page
through the bounded driver and keeps both sides' tests.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…onstellation

alchemy 2.0.0-beta.67 floats @effect/sql-d1 and @effect/vitest
(>=4.0.0-beta.100), and optionally peers on @effect/platform-bun/node in
the same range. Each release of those packages peers on its own exact
effect beta, so the moment a newer beta is published a standalone npm
install resolves a second effect next to our beta.100 pin (TML-3158
again, this time via beta.103). The public packages now pin the whole
constellation at 4.0.0-beta.100 — including the platform-* pins that
were left behind on beta.93, which fail alchemy's >=beta.100 peer range
outright.

The check's API probe moves from Schedule.either (called by alchemy
beta.59, removed in effect beta.100) to Schedule.max (what beta.67's
retry schedules actually call).

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
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