Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
20ee1e4
Record the config-file resolution slice: decided spec, dispatch plan,…
wmadden-electric Aug 25, 2026
1664501
Remove the deprecated defineConfig alias before launch
wmadden-electric Aug 25, 2026
8011098
Engine 0.3.0: this slice changes the engine's public surface
wmadden-electric Aug 25, 2026
8e7964f
loadConfig resolves a chain of config files instead of one
wmadden-electric Aug 25, 2026
32a9dab
Review rework for the chain loader
wmadden-electric Aug 25, 2026
f801b50
Sections merge per key over the config chain, with provenance
wmadden-electric Aug 25, 2026
350d1c5
Harden section resolution: guarded reads, strict path lookup, frozen …
wmadden-electric Aug 25, 2026
5ba8a31
Skills reads resolve through the engine's chain resolver
wmadden-electric Aug 25, 2026
1331eaa
Out-of-handler skills reads go through the Runtime loader seam
wmadden-electric Aug 25, 2026
c99418a
init below an ancestor config scaffolds only, and the e2e rerun worka…
wmadden-electric Aug 25, 2026
f381e5e
init reads the config chain from the context, and machine output says…
wmadden-electric Aug 25, 2026
721231c
Docs and records follow the config-chain truth, plus three review nits
wmadden-electric Aug 25, 2026
3eb998a
Config resolution review fixes: realpath parent links, user-code merg…
wmadden-electric Aug 25, 2026
cb83ae5
Ledger: two config-chain review findings whose fixes live outside thi…
wmadden-electric Aug 25, 2026
056d38f
Config section validators receive the resolved value's provenance
wmadden-electric Aug 25, 2026
1167cd3
Ledger: the family path fix shipped in tandem, not deferred
wmadden-electric Aug 25, 2026
3153d08
Address review: --config reaches the post-login tip; docs match --con…
wmadden-electric Aug 26, 2026
85a6e4e
Merge main: the chain engine release becomes 0.4.0
wmadden-electric Aug 26, 2026
d081406
Guard the prototype lookup in the conformance provenance builder
wmadden-electric Aug 26, 2026
d0aca8a
Register the three parent-directive diagnostics in the error reference
wmadden-electric Aug 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion .drive/projects/prisma-cli-v8/deferred.md
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ The cleanup PR removed the compute config and `init`, made service commands para

## From the agent-skills delivery (project closed 2026-08-22)

- **Config evaluation fails through unrealpath'd pnpm symlinks; the verified fix waits for the next engine release.** The engine's lazy `await import("c12")` (packages/cli-engine/src/config-loader.ts) resolves through a pnpm symlink without realpathing, so c12's own `pathe` import walks up from the symlink path and misses its store siblings — `CLI.CONFIG_UNREADABLE: Cannot find package 'pathe'`. Affects this repo's dev layout and pnpm `hoist=false` installs only; npm and default-pnpm installs work. The fix is one line, verified empirically: import c12 via `pathToFileURL(realpathSync(fileURLToPath(import.meta.resolve("c12"))))`. It was implemented on PR #219 and reverted because any engine change forces a version bump and the families (`@prisma/orm-toolchain`, `@prisma/composer-cli`) peer-pin the engine exactly, requiring a coordinated family release. Ship it with the next engine version train; the init e2e's rerun workaround (removing the config before the second binary run) comes out at the same time.
- ~~**Config evaluation fails through unrealpath'd pnpm symlinks.**~~ Closed (2026-08-25): the one-line realpath fix shipped — `packages/cli-engine/src/config-loader.ts` imports c12 via `realpathSync(import.meta.resolve("c12"))` on main, released with engine 0.2.2 (#224). The init e2e's rerun workaround came out with the config-file-resolution slice (D4, 2026-08-25): the rerun no longer deletes the scaffold first and now covers the config-present path directly.


The agent-skills project (skills sync/list, `prisma init`, the staleness notice; PR #219) closed with these items still open; details were in its own ledger, summarized here as the surviving record.
Expand All @@ -523,3 +523,23 @@ The agent-skills project (skills sync/list, `prisma init`, the staleness notice;
- **`prisma@8.0.0-rc.8` on npm is broken and immutable.** The `prisma` wrapper package carries its own copies of the product pins, and the grammar-cleanup branch bumped only `packages/cli/package.json` — so the published `prisma` bin resolved `@prisma/orm-toolchain@8.0.0-rc.4`, whose old family keys make the mount table's lookups undefined and every invocation crash ("Cannot read properties of undefined (reading 'needs')"). rc.9 fixes it. Consider `npm deprecate prisma@8.0.0-rc.8` (needs a maintainer's npm auth; CI publishes via OIDC and has no deprecate step).
- ~~**The release checks did not catch a `prisma` bin that crashes on install.**~~ Closed (2026-08-24, on the rc.9 PR): worse than hoisting — check 3b never installed or started the wrapper's bin at all, only the shell's. Three guards now exist: `packages/cli/tests/manifest-pins.test.ts` (every PR: the wrapper's dependencies must deep-equal the shell's), the tarball check's new `sibling-pin-mismatch` finding (pack time: shared dependency names across packed manifests must carry identical specifiers), and per-package sandboxes in check 3b (every bin-bearing package installs and starts from its own tree). Each guard was proven against the planted rc.8 defect.
- **Two manifests hand-carry the same pins.** `update-product-versions.mjs` rewrites both, and three checks now fail on divergence (see the closed entry above), so the class cannot ship again. Deriving one manifest from the other at pack time would remove the duplication itself — still a design call, no longer urgent.

## Config-file resolution rulings (2026-08-25)

The design in `specs/config-file-resolution.md` is decided (per-key merge with section-owned semantics, automatic ancestor discovery with a reserved `parent: false | "path"` key, repo-boundary stop, post-merge validation with provenance, declaring-file-relative paths, `--config` anchoring the chain at the named file, no shadowing notices); the dispatch plan is `plans/config-file-resolution.md`. Two rulings recorded here because they close or supersede standing observations:

- **`readProjectSkillsConfig`'s hand-rolled resolution must consolidate into the engine resolver** (ruled 2026-08-25) — lands as D3 of the slice; until then the staleness notice and the commands can disagree about which config governs when run from a subdirectory.
- **Subdirectory `prisma init` skips the skills sync, postinstall script, and devDependency by default** (ruled 2026-08-25) — those steps belong to the repository root; lands as D4 of the slice, which needs D1's ancestor discovery to detect "subdirectory" at all.

## Left open by the config-file-resolution slice (2026-08-25)

- **`--config` does not reach the post-login skills tip — FIXED 2026-08-26.** `CommandContext` now exposes `configPath` (the file `--config` named, undefined otherwise), and `resolveAgentSetupTipCommand` passes it to `readProjectSkillsConfig`, so a login run with `--config` shows the tip against the named file's chain. Regression-tested in `packages/cli/tests/agent-setup-tip.test.ts`.

## Config-chain review findings: what shipped and what is still open (2026-08-25)

Post-merge review of the config-chain slice confirmed two issues that could not be fixed inside prisma-cli alone. The operator ruled that the family path resolution is not acceptable to defer, so it was fixed in tandem across all three repositories:

- **Root-declared family sections resolved their relative paths against cwd — FIXED, in tandem.** The chain delivers a root config's `composer`/`orm` sections to subdirectory runs, and the family packages resolved `configPath`, contract inputs/output, and `migrations.dir` against `ctx.cwd`. The engine gained the seam that makes declaring-file resolution possible: `ConfigSection.validate` now takes a second argument, `validate(raw, provenance)`, and a validator resolves its path-valued keys through `resolveSectionPath(provenance, key, path)`, returning absolute paths so downstream code never resolves against cwd. A one-argument validator stays assignable, so shipped sections keep working. Upstream adoption: composer https://github.com/prisma/composer/pull/262 and orm https://github.com/prisma/prisma/pull/30128, both waiting on the engine release carrying this work — 0.4.0, since 0.3.0 shipped the SDK-peer change on 2026-08-26 — publishing before their CI can install.
- **A marker-less Prisma 7 `prisma.config.ts` at the repo root blocks every config-needing command — including `prisma init` — in every subdirectory. RULED 2026-08-26: keep it fatal.** Chain evaluation is deliberately no-skip (ratified: a broken file anywhere fails resolution), and the missing-marker error is chain-fatal, so a repository migrating from Prisma 7 cannot run the v8 migration entry point anywhere until the old root config is updated or removed. The error does name the file and the fix. The operator ruled the case is not worth an escape path: erroring out without doing anything untoward is safe, if inconvenient, and a Prisma 8 install inside a Prisma 7 repository needs far more plumbing than this anyway. No warn-and-ignore softening; the no-skip rule stands as ratified.

Discovered while doing the above: **the chain engine release's removal of the deprecated `defineConfig` alias (written as 0.3.0, now 0.4.0 after the SDK-peer change took 0.3.0) breaks 307 files in the orm repository** that still import it from `@prisma/cli-engine` (mostly `prisma.config.ts` test fixtures). `definePrismaConfig` has been the name since engine 0.2.0, so the rename lands on the current 0.2.3 pin without waiting for anything; it is a prerequisite for the orm engine bump. Composer is unaffected.
46 changes: 46 additions & 0 deletions .drive/projects/prisma-cli-v8/plans/config-file-resolution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Config-file resolution — dispatch plan

Slice contract: `specs/config-file-resolution.md`. One PR into `main`. Sequential dispatches; each hands the next a state where `pnpm typecheck` and `pnpm exec turbo run test --concurrency=1` are green (the sequential run — the parallel `pnpm test` has a known engine-dist race). Engine-surface hazard applies to every dispatch: verify `@prisma/cli-engine`'s committed version is still unpublished before merging the PR; if a train shipped it, bump the engine version first.

## D1 — The loader discovers a chain

**Outcome:** `loadConfig` resolves an ordered chain of config files instead of one: anchor directory (cwd, or the `--config` file's directory) upward to the first `.git` directory; `parent: false` ends collection, `parent: "path"` names the next link explicitly (cycle-checked, may cross the boundary), no `.git` above means anchor-only. `parent` joins the reserved top-level keys (loader strips it like the marker; `reservedConfigSectionName` covers it; construction-time rejection includes it). Every file on the chain is evaluated with the existing marker/version/unreadable classification, each failure naming its file. `LoadedConfig` becomes a chain shape — per-file `{path, sections}` in nearest-first order plus file-level diagnostics — and every existing consumer (`needs.ts`, hosts, engine tests, the skills reader temporarily via a nearest-file adapter) compiles and passes against it with single-file behavior unchanged: one file in cwd behaves exactly as today.

**Builds on:** clean main. **Hands to D2:** the chain type, discovery green under new engine tests (boundary stop, `parent` forms, cycle guard, anchored fixtures per the spec's test-anchoring requirement), all suites green.

**Focus:** the loader doc comment says "cwd only, no walking up" — it and the `EVALUATE_ONE_FILE_ONLY` rationale need rewriting to the new truth. Symlink-resolve the anchor. Windows realpath on every chain comparison. The unknown-key check in `needs.ts` iterates the chain per file from this dispatch on.

## D2 — Sections merge per key with provenance

**Outcome:** `ConfigSection` gains optional `merge(parent, child)`; the engine default merges per key at the section's top level and replaces below. `checkConfiguration` folds each needed section over the chain nearest-first, validates the merged view (validators unchanged), and hands `ctx.config` the resolved value. Every resolved value carries provenance; post-merge validation diagnostics name the contributing file; relative-path resolution against the declaring file is provided as an engine helper the provenance makes possible (sections opt in by resolving paths through it). Merging never mutates the frozen exports.

**Builds on:** D1's chain. **Hands to D3:** engine tests covering shadowing, fall-through (nested file lacking a section the root has), partial merge (root `skills.check` + package `skills.agents`), provenance in error copy, and the ORM absence-error firing only on a chain with no `orm` section anywhere; all suites green.

**Focus:** `merge` must be optional and type-backward-compatible — the shipped orm/composer dists implement `ConfigSection` against the current engine and must keep working with the default. `__proto__`/`fromEntries` discipline extends to the merged object.

## D3 — One resolver in the product

**Outcome:** `readProjectSkillsConfig` and the out-of-handler reads (skills staleness notice, post-login tip) resolve through the engine's chain resolver; the hand-rolled `existsSync` + direct `loadConfig` path and D1's temporary adapter are deleted. From any subdirectory, the staleness notice and the skills commands agree on the governing config. The skills section keeps its null-collapsing contract for out-of-handler callers.

**Builds on:** D2's resolver. **Hands to D4:** exactly one resolution code path, skills unit tests green from nested-directory fixtures.

**Focus:** the "one stat before paying for transpile" property `readProjectSkillsConfig` had should survive — chain discovery is stat-only until a file exists; keep the no-config fast path.

## D4 — Subdirectory init scaffolds only

**Outcome:** `prisma init` run in a directory whose discovered chain contains an ancestor config skips the skills sync, the `postinstall` script, and the `prisma` devDependency by default, reporting each as skipped-with-reason; explicit flags still opt in; root init (no ancestor config) is byte-for-byte unchanged. Unit tests cover both shapes; the init e2e gains the subdirectory case. If D1's chain work removed the cause of the e2e rerun workaround (`e2e/init.e2e.ts:189-200`), the workaround comes out; otherwise its comment is updated to name what still forces it.

**Builds on:** D3 (init detects the ancestor through the same resolver as everything else). **Hands to D5:** init behavior finished, suites and init e2e green.

## D5 — Docs, records, full verification

**Outcome:** user-facing docs describe discovery, merging, `parent`, and the two-config layout (the config documentation surface plus `docs/product/*` touchpoints that mention config today); the ledger closes the stale pathe entry (the loader realpath fix shipped in engine 0.2.2) and records this slice's rulings; the spec's status line gains the landed date. Full verification per AGENTS.md, including conformance (`pnpm exec turbo run conformance --filter @prisma/cli --force`) and the sequential test run; the engine-version-unpublished check from the plan header re-verified at PR-open.

**Builds on:** D4. **Hands to:** slice-DoD; PR-open.

## Hazard inventory (2026-08-25)

- Engine surface changes ride the unpublished engine version or force the three-repo re-peer chain — check at start AND at merge; the version can publish out from under a long-running slice.
- This repository contains fixture `prisma.config.ts` files and will gain more; every loader/resolver test must pin its chain (temp dirs outside the repo, or explicit `parent: false` fixtures) or a real ancestor config leaks in — the exact failure the prior round's review caught.
- `tests/e2e-coverage.test.ts` parses `src/cli.ts` as text; D4 does not touch the mount table, but any drive-by edit there must keep the `mountedCommands` literal's shape.
- The parallel `pnpm test` race (engine dist rebuild vs cli tests) predates this slice; verify with the sequential run and do not chase it here.
Loading
Loading