Canonical contract projections
The internal/project/contractprojection package owns the reserved
leapview.contract/v1 projection boundary for Source, Model, and SemanticModel.
It is distinct from graph, artifact, release, deployment, and authorization
decision identities. It does not publish contracts or authorize activation.
Authority boundary
Projection payloads are generated from
api/data-resources/contract-projections.tsp. They are explicit allowlists,
not embeddings of authoring or runtime objects. Resource inputs must pass the
existing generated authoring validation before a constructor can seal a
projection. Canonicalization accepts only the sealed projection types.
Exported read views cannot become sealed inputs through JSON decoding.
Contract identity includes the projection profile, resource envelope, stable authored identity, version/compatibility input, and resource-specific contract content. It excludes credentials, target configuration, runtime state, source locations, and reviewed descriptive fields. Projection does not allocate Project or Resource UIDs.
Model source references, SQL resource references, and SemanticModel dataset
references resolve through a ReferenceContext built from the existing validated
project graph. Resolution uses explicit IDs first and project-local names as a
fallback, verifies the expected resource kind, and fails on unavailable authority.
The context does not create a registry or allocate an identity. Relationship
targets retain their member suffix while resolving the resource portion.
Source and Model authoring metadata may carry the version and compatibility used by the projection. When present, that authored contract metadata is authoritative: the constructor fallback must match it, and a mismatch is rejected. Resources without authored contract metadata may still use the explicit constructor fallback. Field classification, critical-data-element markers, authoritative definition links, and deprecation guidance are projected; authoritative links are a sorted, deduplicated set after URL normalization. Tags and prose remain reviewed descriptive exclusions. FAI-622 must bind these bytes to its publication authority before downstream deployment/history use.
The reviewed exclusion manifest records why an authored field is omitted and binds that decision to the generated field shape. Generation rejects unclassified fields, overlapping exclusions, stale paths, and changed excluded shapes. New fields require a projection or an explicit reviewed exclusion; they do not silently disappear from identity.
Determinism and integrity
The projection boundary normalizes typed semantic values, contractual defaults, and declared collections before RFC 8785 serialization. Exact semantic literals use tagged representations; unsupported approximate or unsafe numeric representations fail instead of rounding into another identity. General text is normalized to NFC, with invalid text and normalization collisions rejected. SHA-256 identifies the exact canonical bytes.
Named filter literals are typed using their full physical-field reference in declared dimension bindings, not the dimension's presentation name. Missing or conflicting typed bindings fail closed; this package does not infer a physical schema or duplicate compiler lowering. Unique-check fields are sets, while entity/relationship field tuples and relationship paths retain their order. Check severity, aggregate empty-result behavior, and declared time defaults are materialized consistently with the existing runtime.
Model SQL is represented by an allowlisted projection of the existing parsed SQL representation, not raw SQL text or DuckDB's raw parser JSON. Unsupported SQL constructs fail closed. Publication decoding and digesting validate every nested AST node against the same closed representation and require its exact deterministic encoding. Implicit relation qualifiers resolve through query scope to stable resource identities; explicit aliases and CTE names retain their query-local meaning, and ambiguous qualifiers fail closed. Execution SQL and existing execution digests are unchanged.
Projection identifiers use the generated contracts' ASCII character rules.
URL normalization preserves distinct IPv6 zone identifiers, including zone
names that begin with 25; percent decoding is not applied a second time.
Tests cover canonical bytes and digests, input sealing, malformed inputs, projection coverage, and an independent JavaScript serialization corpus. The JavaScript implementation is fixture-only; production has one RFC 8785 implementation behind the projection package.
Downstream ownership
FAI-620 supplies the only canonical inputs consumed by FAI-622 compatibility
and publication authority. The pure contractversion classifier compares
already-canonical bytes; it does not project, serialize, or hash resources.
The separate contractpublication domain binds an explicit genesis or exact
existing baseline to the candidate profile, authored identity, version,
canonical bytes, digest, validation checks, compatibility/security result, and
the directly published affected-resource identity, and any required widening
approval. The direct identity is the immutable seed for later Project-owned
dependency-graph expansion; it does not claim to contain the consumer graph.
For the qualified dashboard-consumer profile, ProjectGraph edges point from a
consumer to its dependency and AffectedDashboards intersects each dashboard's
transitive dependency closure with that direct seed. It returns stable IDs in
sorted, deduplicated order, excludes unrelated dashboards, and cannot operate
on cyclic or duplicate-edge graphs because graph construction rejects them.
This qualification does not claim a generic closure of every non-dashboard
resource kind and does not copy graph-derived consumers into publication
evidence.
PostgreSQL appends and replays that evidence through caller-owned transactions.
Reusing a version with different bytes, using a stale or mismatched baseline,
omitting required widening approval, or reading tampered evidence fails closed.
Publication alone does not authorize activation. The approval evidence is an exact, bounded input to deployment policy, not a consumer authorization decision. FAI-645 consumes the stable publication and policy identities for lifecycle/history integration; FAI-649 binds them into qualified activation and cutover.
FAI-662's sealed-input and coverage safeguards remain at this boundary. Its database publication-integrity requirements are enforced by append-only publication storage and replay validation. FAI-622 stores the existing instance-qualified authored ID and kind; it does not allocate or resolve a ResourceUID. FAI-670 retains Project-qualified ResourceUID authority. Its inventory distinguishes canonical contract evidence from unversioned and non-contract-bearing resources; allocation does not invent publication authority. FAI-645 is a downstream consumer; its cache, lifecycle, and audit implementation remains outside FAI-622.
This component boundary alone is not a conformance claim. ADR-0017's current supported-profile status is recorded by its qualification matrix and activation contract; broader ADR-0016 status remains separate.