Export the Pi provider catalog validator for forked profiles repos #7

Closed
opened 2026-08-22 04:27:37 +01:00 by vnprc-agent · 1 comment

A deployment that redirects the framework's profiles input at its own definitions repo cannot validate its own Pi provider catalog, because this repo exports only the applied result and keeps the validator internal.

lib.piProviders is the validated catalog for this template's pi-providers.json. validatePiProviders — the parameterized function the pi-provider-catalog check already drives with sabotage fixtures — is a let binding and is not exported. A fork therefore has three options, and none of them is good: re-export this template's catalog and give up on holding any provider data of its own; copy the validator into its own flake, where it drifts from the one the check exercises; or expose an unvalidated catalog and lose the contract the framework relies on when it joins provider metadata to credential selection.

allod/secrets already solves the same problem the other way. It exports lib.mkPiCredentialContract beside the applied lib.piCredentials and friends, precisely so a private registry can run the same validation over its own data. The two halves of the Pi join should be symmetric.

Proposal

Export the existing binding:

lib.validatePiProviders = validatePiProviders;

No behavior changes here. checkedPiProviders stays the value lib.piProviders forces, the sabotage witnesses stay as they are, and the function is already written to be called with an arbitrary catalog — that is how the check feeds it fixtures today.

Why it matters now

The framework forces profiles.lib.piProviders at composition, so every deployment must supply the attribute. A deployment with real provider data has no supported way to supply a validated one.

Notes

Consider whether the validator belongs in a lib/ file rather than inline in flake.nix, the way allod/secrets factors lib/pi-credential-contract.nix. That would make the reuse path obvious and keep the flake's let block from carrying a hundred lines of schema logic. Either shape closes the gap; the export is the part that matters.

A deployment that redirects the framework's `profiles` input at its own definitions repo cannot validate its own Pi provider catalog, because this repo exports only the applied result and keeps the validator internal. `lib.piProviders` is the validated catalog for this template's `pi-providers.json`. `validatePiProviders` — the parameterized function the `pi-provider-catalog` check already drives with sabotage fixtures — is a `let` binding and is not exported. A fork therefore has three options, and none of them is good: re-export this template's catalog and give up on holding any provider data of its own; copy the validator into its own flake, where it drifts from the one the check exercises; or expose an unvalidated catalog and lose the contract the framework relies on when it joins provider metadata to credential selection. `allod/secrets` already solves the same problem the other way. It exports `lib.mkPiCredentialContract` beside the applied `lib.piCredentials` and friends, precisely so a private registry can run the same validation over its own data. The two halves of the Pi join should be symmetric. ### Proposal Export the existing binding: ```nix lib.validatePiProviders = validatePiProviders; ``` No behavior changes here. `checkedPiProviders` stays the value `lib.piProviders` forces, the sabotage witnesses stay as they are, and the function is already written to be called with an arbitrary catalog — that is how the check feeds it fixtures today. ### Why it matters now The framework forces `profiles.lib.piProviders` at composition, so every deployment must supply the attribute. A deployment with real provider data has no supported way to supply a *validated* one. ### Notes Consider whether the validator belongs in a `lib/` file rather than inline in `flake.nix`, the way `allod/secrets` factors `lib/pi-credential-contract.nix`. That would make the reuse path obvious and keep the flake's `let` block from carrying a hundred lines of schema logic. Either shape closes the gap; the export is the part that matters.
Author

Fixed on master in 718c6cf. lib.validatePiProviders is exported, and the same change replaced the closed-world schema with structural validation — provider ID shape, an https:// base URL because the provider credential is a bearer token, and a non-empty model list whose entries carry a non-empty id. Adapter names and model fields now pass through untouched.

A deployment fork has since used both halves: its profiles repo holds its own pi-providers.json run through the exported validator, and the loosening is what made its catalog expressible at all — one of its providers uses api = "anthropic-messages" with thinkingLevelMap and compat on its models, none of which the old schema accepted. The reconciler merges provider objects into models.json verbatim, so nothing downstream needed a matching change.

allod/nexus got the same treatment in its pi-provider registry validator and --api flag.

Fixed on master in `718c6cf`. `lib.validatePiProviders` is exported, and the same change replaced the closed-world schema with structural validation — provider ID shape, an `https://` base URL because the provider credential is a bearer token, and a non-empty model list whose entries carry a non-empty `id`. Adapter names and model fields now pass through untouched. A deployment fork has since used both halves: its profiles repo holds its own `pi-providers.json` run through the exported validator, and the loosening is what made its catalog expressible at all — one of its providers uses `api = "anthropic-messages"` with `thinkingLevelMap` and `compat` on its models, none of which the old schema accepted. The reconciler merges provider objects into `models.json` verbatim, so nothing downstream needed a matching change. `allod/nexus` got the same treatment in its `pi-provider` registry validator and `--api` flag.
Sign in to join this conversation.
No description provided.