Skip to content

v0.10.0-dev.5

@wmadden-electric wmadden-electric tagged this 20 Aug 12:27
* docs(drive): open alchemy-provider-adoption project — spec, plan, design 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>

* feat(lowering): alchemy beta.67 foundation — bump, PrismaComposer type-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>

* feat(lowering): adopt upstream alchemy/Prisma postgres resources

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>

* docs(drive): draft upstream alchemy PR body

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

* docs(drive): rewrite upstream PR body — grounding example, narrative, alternatives

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

* docs(drive): unwrap PR body — GitHub renders single newlines as breaks

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

* docs(drive): add embedder DX sample to upstream PR body

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

* feat(lowering): adopt upstream alchemy/Prisma compute resources

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>

* docs(design): ADR-0043 — Prisma Cloud resources come from the upstream Alchemy provider

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

* fix(lowering): report migrated poison rows as retained, correct migration 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>

* feat(lowering): env changes always reach the running app again

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>

* docs(drive): Composer PR body

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

* docs(design): rewrite ADR-0043 — grounding example, durable statements 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>

* docs(design): DATABASE_URL is self-healed on first deploy, not absent

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>

* feat(lowering): claim DATABASE_URL with poison values at provision

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>

* docs: DATABASE_URL is claimed with a poison value at provision

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>

* docs: address PR 197 review — stale names, propagation claims, --fresh 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>

* feat(lowering): deployment replaced when its environment changes, reused 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>

* refactor(local-target): one implementation of the shared upstream-attribute 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>

* fix(lowering): retire only LEGACY poison rows, decided by the props shape

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>

* fix(lowering): migrate a replaced poison row's old generation before 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>

* fix(lowering): finish the rebase onto the platform state API (main)

Integration fixes after rebasing onto main (PR #209 replaced the SQL
state store with the platform state API):

- legacy-resources.test.ts round-trip suite now drives the REAL hosted
  layer (stateLayerAgainst -> stock HTTP client -> on-read migration)
  against the in-process fake state API instead of the deleted SQL
  store and Postgres harness; the pure migration and provider
  acceptance tests are unchanged
- the adoption ADR is renumbered ADR-0046 (main took 0043-0045);
  references updated
- lockfile regenerated on main's pins (effect beta.103 constellation,
  @prisma/management-api-sdk ^1.57.0, no postgres) plus
  @effect/platform-node for the upstream providers

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

* refactor: address operator review — plain names, shared util, terse comments

- rename mangleExtensionId to envVarSafeExtensionId; comments say the
  literal transformation
- cut the oversized comments this PR added (deploy-fingerprint 85-line
  header, preflight-transport, legacy-resources, providers,
  deployment-edge, pointer-timestamps, local-target, extension,
  descriptors/compute, test headers) to the constraints the code cannot
  express
- replace local-target's isRecord with effect's Predicate.isObject
- extract the resource type-id strings in Bucket/BucketKey into consts
  (with the legacy alias ids named too)
- rename the "poison" vocabulary: database-url-poison.ts becomes
  database-url-claim.ts (claimDatabaseUrlKeys, PLACEHOLDER_VALUE,
  RESERVED_DATABASE_URL_KEYS); legacy-resources' retirePoisonRow becomes
  retireDatabaseUrlClaimRow; tests and docs follow

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

* fix: address PR 197 review — atomic copy fallback, async hashing, early preflight-env, doc alignment

Review fixes, one per finding:
- deploy-fingerprint: the no-hardlink copy fallback writes through a temp file and renames, and a racing EEXIST is success — no reader can see a partial artifact.
- local-target compute: the artifact hash uses async file APIs so a large artifact no longer blocks the whole converge's event loop.
- execute-deploy-destroy: the preflight transport env is serialized right after the preflight loop, so an extension-id collision fails as DEPLOY.PREFLIGHT_FAILED before the stack file is written.
- serializer: the input row's secret names are sorted and unique, so a binding refactor that reorders or duplicates leaves cannot move the deploy fingerprint.
- preflight-transport test asserts both colliding extension ids by name.
- legacy-resources: round-trip test covers getReplacedResources through the real layer.
- Docs: deploying.md and the Drive assets describe fingerprint-based replacement (not always-redeploy), ADR-0048 records the create-only DATABASE_URL claim beside the never-modify rule, gotchas.md records the stable-identity secret exception, alchemy-lowering.md credits the upstream classes, spec.md closes the settled adoption questions, design-notes.md spells out the 3.75s retry arithmetic.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>

* docs(drive): PR-body asset — upstream #1061 merged, swap waits on a release

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>

* fix: address PR 197 re-review — resolved dependency values move the fingerprint, env-scoped reporter URL

Code, one per finding:
- compute serialize: a dependency-input value already resolved at plan time is authored config (ADR-0042 keeps secret values behind pointers and resources, which are still Outputs), so its text is hashed — a changed producer setting (a store's bucket) now replaces the consumer's deployment. Resource-built values stay withheld.
- compute deploy: fingerprintedArtifactPath runs inside Effect.try so filesystem failures are deploy errors, not defects.
- serializer: secret names for the fingerprint are collected from the pointers the document actually carries, not from every bound leaf a schema transform may drop.
- preflight: updatedAt rows compare by parsed time, not string order.
- builds reporter: the Management API base URL resolves from the supplied env map, not process env, so a custom-env run reports to the host its credentials target.
- legacy-resources: the two stacked doc comments on CLAIMED_DATABASE_URL_KEYS are one block.
- Tests: preflight-transport compares against containerEnvVarName; deployment-edge pins that the combined app expression resolves to the app id; preflight pins recency (a newer template beats an older branch override); local-dev integration rejects an empty or missing env.json.

Docs: ADR-0048 names the real ownership boundary (upstream support, not Management API existence) and the legacy-state scope split against ADR-0045; deploying.md documents the stable-identity secret exception; pdp-data-model.md notes the create-only claim; plan.md and spec.md reflect the one-PR slice-3 override and the verified DoD items.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>

* chore(drive): drop the PR-body asset files

The PR bodies live on the PRs themselves; the checked-in copies only go stale.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>

* fix: apply code-review findings — one host resolver, Output-safe fingerprints, paired env rows

Correctness:
- The CLI engine host resolves PRISMA_API_URL before PRISMA_MANAGEMENT_API_URL, the same precedence every other Prisma Cloud client uses, so one env var can no longer split a deploy across two API hosts. Pinned by a runtime test.
- A dependency value that is any alchemy Output stays withheld in the deploy fingerprint — upstreamAny emptiness alone let a literal- or effect-built Output be pushed as an object that hashed as null for every value.
- managementApiBaseUrl's env-record branch treats an empty variable as unset, matching the Config branch.
- The CLI blanks every extension's preflight transport variable it did not produce, so a stale value exported into the shell cannot read as this run's payload.

Structure and reuse:
- compute serialize keeps each env row's resource and fingerprint entry in one list element, so a row cannot exist without its entry.
- The reserved DATABASE_URL key set and the artifact content type each have one definition (database-url-claim.ts, compute/artifact.ts).
- The fingerprint material sorts by its unique row key instead of restringifying rows in the comparator; the serializer's secret collector is a required parameter.
- The generated stack header no longer claims the file is independently runnable without the CLI-provided environment.

Conventions (per the operator's global rules): the new ADR, the .drive project docs, the deploying.md upgrade section, and a gotchas.md bullet are unwrapped to one paragraph per line; 'gates' becomes 'blocks'; the coined 'restart-amplifies' is replaced with a plain description.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>

* docs+test: address final review round — legacy-state scope in index and guide, fallback URL test

The ADR index and the deploying guide qualify on-read migration to platform-state-API rows (retired SQL stores stay destroy-only, ADR-0045); the spec names liveProviderLayer as a temporary-dependency cleanup, not a composition blocker; the runtime test pins the fallback to PRISMA_MANAGEMENT_API_URL when PRISMA_API_URL is empty.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Assets 2
Loading