Skip to content

Composer's configuration is the composer section of prisma.config.ts - #328

Open
wmadden-electric wants to merge 27 commits into
mainfrom
one-config-file/composer-section
Open

wmadden-electric wants to merge 27 commits into
mainfrom
one-config-file/composer-section

Conversation

@wmadden-electric

Copy link
Copy Markdown
Contributor

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:

// prisma.config.ts
import { definePrismaConfig } from 'prisma/config';
import { defineConfig as composer } from '@prisma/composer/config';
import { nodeBuild } from '@prisma/composer/node/control';
import { prismaCloud, prismaState } from '@prisma/composer-prisma-cloud/control';

export default definePrismaConfig({
  composer: composer({
    extensions: [prismaCloud(), nodeBuild()],
    state: prismaState(),
  }),
});

deploy and dev read that section. prisma-composer.config.ts is not read by anything. A project that still has it gets, under the engine's section-invalid headline:

CONFIG.FILE_RETIRED  <dir>/prisma-composer.config.ts is no longer read.
Composer reads its configuration only from the `composer` section of prisma.config.ts.
Write `composer: composer({ extensions: [...], state: ... })` in prisma.config.ts, with
`import { defineConfig as composer } from '@prisma/composer/config'`. If the project has a
prisma-composer.config.ts, move its extensions and state into that section and delete the file.

The decision

Composer's configuration is the composer section of prisma.config.ts, written the way the ORM section is written: definePrismaConfig wrapping a defineConfig from @prisma/composer/config. The section validator checks the identifying fields the old loader checked, extensions with a string id and an object nodes each, unique ids, and state with a string extension and a function create, and passes the built descriptors through by reference. Composer's own loader, its walk-up discovery, the configPath pointer field, the c12 dependency and the effect version 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 }, taking file from 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 its composer export, and refuse a file that has none.

The programmatic operations take the config. deploy, destroy, dev and log on @prisma/composer/control used to find the config by walking up from the entry. @prisma/composer must not import the engine, so they take a required config: 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_RETIRED for a configPath field, CONFIG.FILE_RETIRED for an old file beside the declaring file, CONFIG.SECTION_MISSING when no loaded file declares the section. Each shows the section to write. Moving one object literal does not justify a codemod.

The effect pre-flight is retired. It compared the effect version Alchemy resolves against Composer's pin before evaluating the old file, because Alchemy's peer range >=4.0.0-rc.115 || >=4.0.0 accepts release candidates that remove modules Alchemy imports. That is still true today: alchemy@2.0.0-beta.79 fails at import with effect@4.0.0-rc.118 and works with rc.115. After this PR the engine evaluates the file and reports an import failure as CLI.CONFIG_UNREADABLE with 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 on effect and its companions stay, and the tarball-resolution CI script keeps proving a clean install resolves one effect that Alchemy loads. It now proves that by importing Alchemy directly instead of running the binary, and its adversarial shape passes only when effect is what broke.

dev watches the config file. It keeps the section it started with. On a real change it says the file changed and dev must 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

  • The prisma-composer binary still exists and still works on the new section. Its removal and the docs sweep that stops naming it are slice 2.
  • dependency-cruiser excludes prisma.config.ts, so control-plane imports in config files are not cruised. Recorded as deferred.
  • A deploy that reaches the Alchemy plan stage needs real credentials and is slice 3's manual QA, from the prisma host binary.

Verification

  • Root typecheck and lint, cast count unchanged at 21, 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/integration passes; 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.mjs run with network after building the tarballs: exit 0, all four shapes OK; the adversarial tree fails at the Alchemy import with Schema.TaggedError is not a function.
  • Manual QA from examples/orm-demo with the built binary: deploy --help exits 0; a signed-in deploy passes config validation and stops at assemble; the restored old file gives CONFIG.FILE_RETIRED; configPath gives CONFIG.FIELD_RETIRED; a programmatic deploy given the whole config export instead of its composer property is refused with CONFIG.FIELD_UNKNOWN before any preflight.

Alternatives rejected

  • An engine hook letting a family veto config evaluation, to keep the friendlier effect message. Nothing else would consume it.
  • Composer's commands loading the config themselves after the check. Bypasses the engine's declarative config need for a message on a rare failure.
  • Running the check at import time inside @prisma/composer/config. Import sorters put the crashing control import first.
  • Making the control-plane entries import Alchemy lazily. A refactor of the lowering layer, not for GA.
  • A codemod for the old file. More code than the feature.

Agent: columbo-17

🤖 Generated with Claude Code

wmadden-electric and others added 23 commits September 30, 2026 17:00
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>
@prisma-gizmo

prisma-gizmo Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Warning

Gizmo skipped this review: 120 reviewable files exceeds the 100-file limit. Split the PR or review it manually.

@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: ae8b1d37-8a29-4b4e-a065-cda51cee12e7

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Comment @coderabbitai help to get the list of available commands.

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>
@pkg-pr-new

pkg-pr-new Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

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

commit: a0ce116

wmadden-electric and others added 3 commits September 30, 2026 18:58
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant