Composer's configuration is the composer section of prisma.config.ts - #328
Open
wmadden-electric wants to merge 27 commits into
Open
wmadden-electric wants to merge 27 commits into
wmadden-electric wants to merge 27 commits into
Conversation
The composer section of prisma.config.ts used to carry only a pointer to
prisma-composer.config.ts. It now holds the configuration itself,
{ extensions, state }, typed as PrismaAppConfig from core.
The validator checks the fields configShapeDiagnostics checks today
(extension ids and node registries, unique ids, a state descriptor with a
string extension and a create function) and returns every descriptor as
the config file's own object. Unknown fields are now errors. configPath
gets its own CONFIG.LEGACY_FIELD error that shows the section to write.
An absent section is an error: the engine calls the validator with
undefined and an empty provenance, so the message cannot check a
directory for the old file and names it unconditionally.
The section's merge takes the nearest declaring file's section whole, so
the section always comes from exactly one file, the one the generated
stack will import.
Handlers now pass the validated section to the operations as deps.config
in place of the retired configPath; the pipelines still find the old file
for the stack import until they are reworked. Test harnesses that seeded
an empty config now seed a valid section.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
… config
The pipelines no longer look for prisma-composer.config.ts. Each operation
(deploy, destroy, dev, log) takes a required config input,
{ value: PrismaAppConfig, path: string }: the composer section of
prisma.config.ts and the path of the file that declared it. The public
operations on @prisma/composer/control gain the same input, since
@prisma/composer cannot import the engine that evaluates the file.
The handlers build that input from the validated section. The declaring
file comes from the engine's resolveSectionOverChain over ctx.configFiles,
the same provenance the validator received. Before any operation runs, a
prisma-composer.config.* beside that file fails with CONFIG.LEGACY_FILE,
so an old file is never silently ignored.
The generated deploy and dev stack files now import prisma.config.ts and
pass its composer property to lower(). load-config.ts, the c12 evaluation
and the entry-anchored walk-up are deleted with their tests, and the
registry-coverage fix names the composer section instead of the old file.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The pre-flight inspected the app's installed tree to explain a failed executor import as DEPS.EFFECT_VERSION_CONFLICT. It ran from the old config loader and from executorLoadFailure. The loader is gone, and the design for this change retires the diagnosis instead of keeping a separate tree walk for one failure mode. A failed executor import is now always DEPS.EXECUTOR_UNLOADABLE, with the import error's message in the summary and the error as its cause. The end-to-end test that breaks the executor import asserts exactly that. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Two user-facing fixes still told people to edit prisma-composer.config.ts: the build-time ASSEMBLE.EXTENSION_MISSING fix in assemble-services.ts and the lowering error for an unconfigured extension in core's deploy.ts. Both now point at `extensions` in the composer section of prisma.config.ts, and their tests assert the new wording. Comments across core, the node and nextjs build extensions and the Prisma Cloud target that named the old file now name prisma.config.ts. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…oser-cli c12 evaluated prisma-composer.config.ts in the deleted config loader, which was its only importer. The engine loads prisma.config.ts with its own pinned copy, so none of the three packages needs to declare it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Files under __tests__/fixtures/ are not test files to the no-bare-cast plugin, so the fixture's two `as` casts raised the ratchet count. The fixture now states its compromise through blindCast. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
All ten examples, test/integration and the website drop prisma-composer.config.ts. Each directory's prisma.config.ts now carries a composer section with the same extensions and state, next to any orm section it already had. The store keeps its module-level ORM-only configs; its root gains the composer section, which the modules inherit through the config chain. The configs import definePrismaConfig from @prisma/cli-engine, since no example depends on the prisma host, so every directory that lacked it now declares @prisma/cli-engine 0.6.2. Composer's defineConfig is imported by its own name; where an orm section also needs one, the ORM module is a namespace import. An aliased named import would count as a bare cast under the no-bare-cast ratchet. tsconfig includes, integration fixtures and comments that named the old file are updated, and the programmatic deploy test reads its config from the new file. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The tarball resolution check used to run `prisma-composer deploy app.ts` with no config and treat reaching the executor as proof alchemy loads, and the adversarial shape looked for the retired pre-flight's error. With the composer section required, that run now stops at the engine before alchemy is reached, so neither assertion proved anything. Every shape now imports alchemy's root, Output, Provider and Stack entries from the installed app. The healthy shapes must import them cleanly; the adversarial shape, with effect overridden to 4.0.0-beta.93, must fail to. The Prisma Cloud entry is left out because it needs platform peers only @prisma/composer-prisma-cloud installs. The --help checks stay. Run locally on 2026-09-30: all four shapes pass; the adversarial import fails with "Schema.TaggedError is not a function" in alchemy's AuthProvider. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…error The maintainer skill for upgrading alchemy and effect still explained the retired CLI pre-flight. It now says what a consumer sees instead: a wrong effect fails evaluation of prisma.config.ts with the engine's CLI.CONFIG_UNREADABLE and the module error, before any command runs. The section on the regression script describes the alchemy import probe that replaced the binary run. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…ig.ts The guides and the skill now describe the one config file: the composer section of prisma.config.ts, written with defineConfig from @prisma/composer/config and definePrismaConfig from prisma/config. They cover how the file is found and that the nearest declaring file's section is used whole, the three CONFIG diagnostics that refuse the old prisma-composer.config.ts setup, the removed ComposerSection type, and the required config input on the programmatic operations. The effect-conflict section now describes what a user actually sees: a CLI.CONFIG_UNREADABLE failure evaluating prisma.config.ts with alchemy's module error. Running locally notes that dev reads the config once, so a change needs a restart. The programmatic example branches on result.ok, which is the shape the operations return. Command names stay as prisma-composer; they change separately. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
ADR-0049 records the decision: the composer section of prisma.config.ts is Composer's whole configuration; the validator checks identifying fields, passes descriptors through by reference and takes the nearest declaring file's section whole; the old file and configPath are refused with diagnostics and never migrated; the programmatic operations take the config; and the effect pre-flight is retired, with the verified facts behind that. ADR-0017 now names prisma.config.ts in its example and prose. ADR-0043 and ADR-0044 drop the retired DEPS.EFFECT_VERSION_CONFLICT and the old file, each with an amendment note, and the index registers ADR-0049 and annotates the three amended records. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The no-bare-cast plugin matched every `as` token, so an import or export
rename such as `import { defineConfig as composer }` counted as a bare
cast and raised the ratchet. The pattern now matches the TsAsExpression
node, the type assertion itself; `as const` stays exempt. The cast count
on this branch and its merge base is unchanged at 21.
A lint-casts test adds aliased imports, a namespace import, an aliased
export and `as const`, and asserts a zero delta. It fails against the old
pattern.
converge.ts no longer needs its inline `import()` types to dodge the
false positive, so it uses ordinary aliased type imports.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Every example, test/integration and the website now import
`defineConfig as composer` from @prisma/composer/config and write
`composer: composer({ ... })`, and the ORM section uses
`defineConfig as orm`, the same form the guides, the skill, the ADRs and
the refusal messages show. The previous commit stopped the cast lint from
counting import renames, which is what had forced a different spelling.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…ig check
The programmatic operations trusted their config input: a host could pass
the whole prisma.config.ts export, point at a file with an old
prisma-composer.config.ts beside it, or name a file that does not exist,
and the mistake surfaced late, possibly after containers were created.
One engine-free module, src/composer-config.ts, now owns what makes a
composer section valid: the field checks the validator ran, the retired
file check and the missing-file check. The section validator calls it
and, because it has the provenance, returns the section together with its
declaring file and refuses a retired file itself. So the handlers pass
ctx.config straight through, and the second resolve of the config chain
in family/composer-config.ts is gone with its unreachable throw. The
pipeline runs the same checks on the programmatic input before the entry
is loaded, so deploy, destroy, dev and log refuse a bad config before any
container or preflight runs. A value that still carries a `composer` key
gets a fix that says to pass that property.
The input type is now ComposerConfigSource { value, file }, exported from
@prisma/composer/control, and PipelineResult carries it as configSource.
The retired-shape codes read subject first like the rest of the
namespace: CONFIG.FIELD_RETIRED for configPath, CONFIG.FILE_RETIRED for
the old file, which is now reported under the engine's section headline
with the other two. CONFIG.SECTION_MISSING says no loaded prisma.config.ts
declares the section, which is also true when there is no file at all.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The stack files the deploy and dev commands generate now import the declaring prisma.config.ts and pass its composer export to lower(), but the tests only matched the rendered text. A new cli test writes both stack files against a real prisma.config.ts fixture and runs each in a child process, with the @prisma/composer and alchemy imports replaced by a preloaded stub whose lower() prints what it received. The test fails when the stack passes the whole export instead of its composer property. The local-dev integration proof hand-renders its own dev stack; its fixture config is now a prisma.config.ts and the stack reads its composer export, the same shape the real generator writes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
A dev session keeps the composer section it started with, but each rebuild's Alchemy child imports prisma.config.ts from disk. After an edit, the parent would check coverage and assemble against the old extensions while the child lowered against the new ones. dev now watches the declaring prisma.config.ts. When it changes, the operation emits a new `config-changed` DevEvent, and the CLI prints that the file changed and dev must be restarted to apply it. Rebuilds are paused until then: a later build change repeats the notice instead of converging with mixed config. A test edits the file mid-session, then a watched build output, and asserts two notices and a single converge. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The adversarial shape accepted any failure to import alchemy, so a renamed alchemy subpath or a typo in the probe would also have passed. Its probe now reports whether effect is to blame: the error or its stack names an effect module under node_modules or an effect module specifier, or the message is `X.Y is not a function` and the installed effect has no X.Y. Paths are matched on node_modules/ because the scratch directory's own name contains "effect". Any other failure fails the script. Run locally on 2026-09-30: all four shapes pass; the adversarial verdict is "Schema.TaggedError is not a function", which effect 4.0.0-beta.93's Schema does not export. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…g watch
The guides, the skill and the ADRs follow the review fixes:
- The retired-shape codes are CONFIG.FIELD_RETIRED and CONFIG.FILE_RETIRED,
and all three refusals appear under CLI.CONFIG_SECTION_INVALID.
CONFIG.SECTION_MISSING is described for the no-file case too.
- The programmatic input is `config: { value, file }` (ComposerConfigSource).
The example builds `file` from import.meta.url, and the text says a
relative file resolves against cwd and lists the refusals the operations
now return before any work starts.
- The deploying guide's result bullets describe the Result shape the
operations return ({ ok, value } / { ok: false, failure } with a dotted
code) instead of the old `outcome`/`kind` shape, for deploy, dev and log.
- Getting started no longer claims only Composer's commands read the file.
- Running locally and the skill describe dev's watch on prisma.config.ts:
it reports an edit and pauses rebuilds until restarted.
ADR-0049 records that the validator returns the declaring file, that the
section check is one engine-free module the pipeline also runs, the
value/file invariant the child relies on, that the Alchemy child evaluates
every section's imports and why that is accepted, the dev behaviour, and
which ADR-0028 rule the dependency-cruiser exclusion loses. ADR-0044's
CONFIG registry lists the codes the code emits and marks the three retired
ones.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The section validator checked fields first and reported every finding; the programmatic check looked for the old file first and threw only the first finding. The same bad input could get different codes on the CLI and in code, and on the CLI an old prisma-composer.config.ts was reported only once the fields were valid. checkComposerConfig in composer-config.ts is now the one check: the old file first, then every field finding. The section validator reports them all as diagnostics; the operations throw the first and carry all of them in meta.findings. The only difference left is where the file comes from: provenance on the CLI, the caller's path resolved against cwd in code. The old-file check now resolves the config file through symlinks before taking its directory, so a linked prisma.config.ts is checked beside the file it points to, as the engine's real paths already were. Tests cover the order and a symlinked file on both routes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…section The deploy and dev stack files read `prismaConfig.composer` and handed it straight to lower(). When the imported prisma.config.ts declares no composer section, which happens when a file inherits the section from a parent file or a programmatic caller names the wrong file, the child failed inside lower() with a TypeError. Both stacks now check the export first and throw a message naming the file and saying it declares no `composer` section. The stack-file evaluation test runs both generated files against a fixture that declares no section and asserts that message on stderr. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
… and wins races Three gaps in the pause on a prisma.config.ts edit: - Any write event paused dev for good, including a save that leaves the content unchanged (format-on-save, touch, a branch switch). dev now hashes the file at start and pauses only when the content differs. - The config watcher had no error handler, so a watch failure went unnoticed and later edits went undetected. Its errors now arrive as watch-error events, like the build watcher's, and dev keeps running. - A build watch on a directory that contains prisma.config.ts could fire before the config watcher and converge once with mixed config. Every rebuild now compares the hash itself, synchronously, before starting. OperationDeps gains a `watch` seam so the tests can hand dev fake watchers and fire them in a chosen order; one test per case. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The adversarial shape's blame check treated any `X.Y is not a function` as effect's fault whenever effect had no function at `X.Y`, which is also true when effect has no `X` at all, so a failure unrelated to effect could pass. The decision now lives in scripts/effect-blame.mjs, which the probe imports, and `X.Y is not a function` counts only when the installed effect exports a module `X` without a function `Y`. The path and module-specifier rules are unchanged. scripts/effect-blame.test.mjs covers each rule, including a probe error naming a module effect does not have, and a scratch directory whose name contains "effect". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
local-dev.integration.ts hand-rendered its own copy of the dev stack file, so a regression in the real generator would not show there. It now calls renderDevStackFile, which @prisma/composer-cli/testing exports next to the control double for tests that drive Alchemy directly; the integration package may import only published packages. Publishing the renderer put it in the testing entry's static graph, and check-family-static-graph.mjs reads every built line that starts with `import` as an import of that module. The renderer's template had such lines for the generated file's own imports, so they are now assembled from strings. The generated file is unchanged; its tests pass as before. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
|
Warning Gizmo skipped this review: 120 reviewable files exceeds the 100-file limit. Split the PR or review it manually. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Advanced Run ID:
Comment |
wmadden-electric
added a commit
to prisma/orm
that referenced
this pull request
Sep 30, 2026
The two review passes and the round-2 verification for prisma/composer#328, plus the grounding map the slice spec was written from. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
commit: |
The test that ran both generated stack files against a config with no composer section spawned two child processes in one test. On macOS CI that took 5.3 s and hit bun's 5 s default timeout, while the single-child tests beside it took 1–2 s. It is now one test per stack, with the same assertions, so each stays well inside the default. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
A dev rebuild re-assembles every service's artifact directory, and its converge child reads those directories. The watch callback started every rebuild fire-and-forget, so a build change during a rebuild started a second one that rewrote the artifacts under the first child. That is the same failure the store proof hits on macOS CI: "no main.js/main.mjs found in bundle dir .../artifacts/storefront", or an unrelated service restarting. Rebuilds are now serialized. A change during a rebuild is recorded, and all such changes coalesce into one more rebuild after it finishes, unless prisma.config.ts has changed in the meantime. A test fires build changes while a converge is held open and asserts that converges never overlap and that three changes produce two rebuilds; it fails before this change with four concurrent converges. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…tch loop Criterion 2's fallback attempt touches catalog's built artifact and then converges the dev stack directly with alchemy. The touch also fires the running dev session's own watch loop, which re-assembles every service's artifact directory, so the direct converge read those directories while they were being rewritten. It failed with "no main.js/main.mjs found in bundle dir .../artifacts/storefront" or with storefront's pid changing: on this machine 3 of 3 runs on the branch and 2 of 3 on main (edaf7b2). The attempt now waits for the session's front-door reprint for its touch, as attempt 1 already does, before assembling and converging directly. Five consecutive runs pass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The storefront-auth deploy, verify and destroy job took between 2m20s and 2m55s on main over the last week and 3m08s on this branch with the same per-phase timings, so the three-minute limit was already marginal and one main run timed out this morning. Five minutes keeps a slow platform hour from failing a green deploy. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Slice 1 of the one-config-file project (spec and design in prisma/orm#30536). After this PR a Composer project has one config file:
deployanddevread that section.prisma-composer.config.tsis not read by anything. A project that still has it gets, under the engine's section-invalid headline:The decision
Composer's configuration is the
composersection ofprisma.config.ts, written the way the ORM section is written:definePrismaConfigwrapping adefineConfigfrom@prisma/composer/config. The section validator checks the identifying fields the old loader checked,extensionswith a stringidand an objectnodeseach, unique ids, andstatewith a stringextensionand a functioncreate, and passes the built descriptors through by reference. Composer's own loader, its walk-up discovery, theconfigPathpointer field, thec12dependency and theeffectversion pre-flight are deleted. This is a breaking change for release-candidate users and ships before GA. ADR-0049 records it.Why the section used to be a pointer, and why that stops
The section held one field, a path to the second file. Its header said a section validator must be light because it loads with the command tree at start-up. The engine loads validators with the family but only runs them when a command needs config, and the ORM section already holds built descriptors with functions inside. So the second file had no reason to exist.
What follows from one section
The declaring file travels with the value. The deploy runs inside an Alchemy child process that imports the config file itself, so the pipeline needs the file as well as the section. The validator returns both,
{ value, file }, takingfilefrom the engine's provenance. The section merges whole across a config chain, nearest file wins, so a section always has exactly one declaring file. The generated stack files import that file and read itscomposerexport, and refuse a file that has none.The programmatic operations take the config.
deploy,destroy,devandlogon@prisma/composer/controlused to find the config by walking up from the entry.@prisma/composermust not import the engine, so they take a requiredconfig: ComposerConfigSource, the same{ value, file }shape, and the caller evaluates the file. One shared check runs on both routes, CLI and programmatic, and reports the same findings in the same order, before any container or preflight runs. Guides, skill and ADR-0043 are updated.The old shape is refused, not migrated.
CONFIG.FIELD_RETIREDfor aconfigPathfield,CONFIG.FILE_RETIREDfor an old file beside the declaring file,CONFIG.SECTION_MISSINGwhen no loaded file declares the section. Each shows the section to write. Moving one object literal does not justify a codemod.The
effectpre-flight is retired. It compared theeffectversion Alchemy resolves against Composer's pin before evaluating the old file, because Alchemy's peer range>=4.0.0-rc.115 || >=4.0.0accepts release candidates that remove modules Alchemy imports. That is still true today:alchemy@2.0.0-beta.79fails at import witheffect@4.0.0-rc.118and works withrc.115. After this PR the engine evaluates the file and reports an import failure asCLI.CONFIG_UNREADABLEwith the module error, exit code 2. The case is rare, catastrophic, and only the user's package manager can fix it, so failing fast with the real error is the right behaviour. The pins oneffectand its companions stay, and the tarball-resolution CI script keeps proving a clean install resolves oneeffectthat Alchemy loads. It now proves that by importing Alchemy directly instead of running the binary, and its adversarial shape passes only wheneffectis what broke.devwatches the config file. It keeps the section it started with. On a real change it says the file changed anddevmust be restarted, and pauses rebuilds so the parent and the child never run on different configs.Everything else follows. All ten examples, the integration test project and the website config carry the section and lose the old file. Three user-facing messages that named the old file now name the section. The Biome cast-count plugin flagged
import { defineConfig as composer }as a cast; an import alias is not a cast, so the plugin now matches the type-assertion node only, with a test.Not in this PR
prisma-composerbinary still exists and still works on the new section. Its removal and the docs sweep that stops naming it are slice 2.dependency-cruiserexcludesprisma.config.ts, so control-plane imports in config files are not cruised. Recorded as deferred.prismahost binary.Verification
check:cli-engine-pin,check:family-static-graph,check:skill-packaging,test:scripts, the website content test, and the cli (263), core (239), assemble (9) and Prisma Cloud target (386) suites pass.test/integrationpasses; one run of the store local-dev proof failed on an emulator port clash under the parallel turbo run and passed alone and on rerun.scripts/check-npm-effect-resolution.mjsrun with network after building the tarballs: exit 0, all four shapes OK; the adversarial tree fails at the Alchemy import withSchema.TaggedError is not a function.examples/orm-demowith the built binary:deploy --helpexits 0; a signed-in deploy passes config validation and stops at assemble; the restored old file givesCONFIG.FILE_RETIRED;configPathgivesCONFIG.FIELD_RETIRED; a programmaticdeploygiven the whole config export instead of itscomposerproperty is refused withCONFIG.FIELD_UNKNOWNbefore any preflight.Alternatives rejected
effectmessage. Nothing else would consume it.@prisma/composer/config. Import sorters put the crashing control import first.Agent: columbo-17
🤖 Generated with Claude Code