Skip to content

PSL contract emit: extension indexTypes not validated — defineConfig / CLI omit composedExtensionPackRefs #895

Description

@cursor

Summary

PSL contract authoring does not validate extension-registered index types when consumers use the standard @prisma-next/postgres/config defineConfig path. Authors see unregistered index type "<type>" even when the extension pack correctly registers the type via defineIndexTypes() and ADR 210.

This affects all extension indexTypes in the PSL lane, not a single extension:

  • ParadeDB @@index(..., type: "bm25", options: { key_field: "id" })
  • prisma-ltree @@index(..., type: "gist") (GiST for ltree / ltree[] columns)

The TypeScript lane works because defineContract({ extensionPacks: { … } }) carries full pack refs including indexTypes. The PSL lane fails because pack refs are never threaded into the PSL provider.

Root cause

Index-type validation runs at contract lowering from a per-contract registry built from attached packs' indexTypes (ADR 210).

TS lane: defineContract({ extensionPacks: { ltree } }) → registry includes gist. ✅

PSL lane:

  1. @prisma-next/postgres defineConfig calls prismaContract(path, { output, target, createNamespace }) without composedExtensionPackRefs.
  2. CLI executeContractEmit passes composedExtensionPacks: stack.extensionPacks.map(p => p.id) (IDs only) in ContractSourceContextno field for pack refs.
  3. PSL interpreter buildComposedExtensionPackRefs() substitutes stub refs (id/kind only, no indexTypes) when real refs are absent.
  4. Authoring type: "gist" (or bm25) → unregistered index type.

The PSL provider already accepts composedExtensionPackRefs (packages/2-sql/2-authoring/contract-psl/src/provider.ts). Integration tests pass refs directly to interpretPslDocumentToSqlContract (e.g. test/integration/test/authoring/psl-index-type-options.integration.test.ts with ParadeDB) — bypassing defineConfig.

Reproduction

  1. Configure @prisma-next/postgres/config with extensions: [paradedbControl] (or any pack with indexTypes).
  2. Author PSL:
model Doc {
  id   Int    @id
  body String
  @@index([body], type: "bm25", options: { key_field: "id" })
}
  1. Run prisma-next contract emit.
  2. Expected: GiST/BM25 index IR (same as TS lane).
  3. Actual: unregistered index type "bm25".

Direct interpreter tests with composedExtensionPackRefs: [paradedbPack] pass; standard config emit does not.

Proposed fix

Wire extension pack refs (which carry indexTypes per ADR 210) into the PSL authoring path:

File / area Change
packages/3-extensions/postgres/src/config/define-config.ts Pass composedExtensionPackRefs: extensions into prismaContract(...)
packages/1-framework/3-tooling/cli/src/control-api/operations/contract-emit.ts Pass stack.extensionPacks as composedExtensionPackRefs in sourceContext
packages/1-framework/1-core/config/src/contract-source-types.ts Optionally extend ContractSourceContext with composedExtensionPackRefs
packages/2-sql/2-authoring/contract-psl/src/provider.ts Prefer context.composedExtensionPackRefs when present, fall back to static options
Tests Extend packages/3-extensions/postgres/test/config/define-config.test.ts; add integration test via real config emit (not direct interpreter call)

Do not add GiST/BM25 to core. Per ADR 210, index types belong on extension packs; the framework should thread pack refs so PSL validation sees them.

Acceptance criteria

  1. PSL config with extensions: [ltreeControl] + @@index([path], type: "gist") emits GiST index IR (same as TS lane).
  2. ParadeDB PSL @@index(..., type: "bm25", options: { key_field: "id" }) works through standard @prisma-next/postgres/config — not only via direct interpreter tests.
  3. No duplicate/conflicting registration when pack refs are threaded correctly.

Motivating consumers

  • prisma-ltree — GiST indexes on ltree columns (ADR-005, extension side complete on TS lane)
  • ParadeDB extension — BM25 full-text indexes (already has direct interpreter tests; config path gap)

References

  • ADR 210 — Index-type registry (docs/architecture docs/adrs/ADR 210 - Index-type registry.md)
  • PSL provider: packages/2-sql/2-authoring/contract-psl/src/provider.ts (composedExtensionPackRefs option)
  • Stub fallback: packages/2-sql/2-authoring/contract-psl/src/interpreter.ts (buildComposedExtensionPackRefs)
  • Postgres defineConfig gap: packages/3-extensions/postgres/src/config/define-config.ts
  • CLI emit: packages/1-framework/3-tooling/cli/src/control-api/operations/contract-emit.ts

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions