NOT a stable public API. Engine-tier binding primitive — published to crates.io only because the SDK closure requires it on the registry; 3rd parties never name this crate. They meet the value-sets it binds through an SDK product facade or a wire contract, never here.
Schema-Constrained Value-Sets (the enum ↔ CHECK anchor)
A schema-constrained enum is a domain value-set whose members are also
enumerated by a PostgreSQL CHECK (col IN (…)) constraint. The enum and the
constraint are two reifications of one fact ("the legal values of this
column"); left unbound they drift independently — a migration widens the
CHECK, or a variant is added, and the other side silently goes stale.
This crate is the single seam that binds them. The same drift class exists
on both sides of the monorepo (PAS scaccounts, PCS scchat) and neither
core may depend on the other, so the binding primitive is hoisted out of
both — a pure, dependency-free trait + macro (std::BTreeSet only), which
both cores (that ban IO/transport crates) can depend on.
Why engine tier and not crates/shared/
It sat in crates/shared/ (publish = false) until RFC_202607252223
T-03, which is when the placement was first tested rather than assumed:
ppoppo-identity needs to enroll its own EntityType, and engine → shared is forbidden by the crate lattice (xtask::policy::rules::taxonomy)
— so the enrollment was unreachable, and the vocabulary had to keep a
second PAS-local enum alive just to carry it.
The fix was to notice that the folder was wrong, not the lattice. Engine tier means published substrate that no 3rd party names — a dependency-free trait + macro consumed by two service cores and one vocabulary crate is exactly that. The move corrected a misfile that predates the tier; it did not trade a principle for convenience.
The anchor triple (per STANDARDS_SSOT_GOVERNANCE)
- Owner: the domain enum in
accounts-core/accounts-api/chat-core(the closest reified form of the value-set decision). - Anchor: domain-specific — these are tuned domain vocabularies with no
external standard, so this crate doc-comment is the anchor of record
(governance §4). (Formerly PAS
ADR_202605242324_schema-constrained-value-sets.md, folded intoaccounts-coreon its retirement, then hoisted here when PCS adopted the same gate.) - Verification:
bindingsfeeds each service'sschema_check_drift.rsDB test (accounts-api/tests/forscaccounts,chat-api/tests/forscchat), which reads eachCHECKfrom the materialized schema (pg_get_constraintdef) and asserts set-equality withALL. The compile-time half lives in the [impl_schema_constrained!] macro: it emits an exhaustivematch, so adding a variant without listing it fails to build.
Why a DB test and not a file parse
The value-sets evolve through ALTER … DROP/ADD CONSTRAINT migrations (e.g.
lifecycle_state gained tombstoned; oauth_audit_events.event_type
gained otp_issue/otp_verify). The authoritative set is therefore the
result of applying every migration, which only the database knows —
parsing the baseline .sql would report phantom drift. Asking Postgres via
pg_get_constraintdef is the only correct anchor (and avoids the brittle
bespoke-parser ops-tax rejected in STANDARDS_RATE_LIMITS_PPOPPO §Anchor
"Rationale" option A).
Two more rejected alternatives
#[sqlx::Type]alone. Binds the column type (text), not theCHECK's value-set — a typo in the enum still compiles and the set still drifts. Complementary at the query boundary, not a substitute for the verification.- Accept drift under human review. Leaves security-adjacent value-sets (audit taxonomy, lifecycle, step-up purpose) under governance §2's "aspiration, not enforcement" gate. Rejected.
Caveat — the value-equality half is integration-tier
The compile-time exhaustiveness guard covers the Rust side on every build.
The ALL-vs-CHECK set-equality half needs a live database, and there is
no CI job running DB-backed tests — so it bites via each service's
just test-integration and the /deploy:ppoppo pre-flight, not on a plain
cargo test.