diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b857449..91a9263c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve ### Added +- **Type-family parity projection design**: Named + `js-sdl-type-family-vs-rust-l1-type-family.v0` as the next fair parity + projection for schema-extension and non-table GraphQL facts before admitting + those fixtures to the default sentinel corpus. - **Rust IR fixture contract note**: Moved the core-rs IR contract and fixture backlog card into the active `0013` design packet, naming the v0.0.6 fixture classes, canonical byte rules, diagnostics contract, and repo evidence. diff --git a/docs/BEARING.md b/docs/BEARING.md index 7d72f378..daea4178 100644 --- a/docs/BEARING.md +++ b/docs/BEARING.md @@ -119,7 +119,9 @@ rejection, alias conflicts in both registration orders, and the Rust IR fixture contract now housed under the active `0013` packet. Invalid SDL diagnostics now expose stable `WesleyError::diagnostic()` codes and parser line/column spans where available, while semantic lowering spans remain -explicitly absent. +explicitly absent. The next non-table projection is now named as +`js-sdl-type-family-vs-rust-l1-type-family.v0` so schema-extension fixtures do +not enter default parity on table evidence alone. The next pulls are: @@ -127,9 +129,9 @@ The next pulls are: target dispatch already rejects missing modules, invalid product/database target names, duplicate names, and aliases that collide before or after the owning target loads. -2. Define the next parity projection before broadening `pnpm parity:ir` beyond - table-compatible SDL. Schema extensions and non-table L1 facts need a fair - projection before they become JS/Rust parity evidence. +2. Implement the named type-family projection and admit + `schema-extensions-schema.graphql` only after + `js-sdl-type-family-vs-rust-l1-type-family.v0` passes. 3. Capture a Rust core performance baseline over the canonical corpus after the fixture and projection boundaries are named. diff --git a/docs/design/0013-rust-ir-parity-sentinel/SOURCE_type-family-parity-projection.md b/docs/design/0013-rust-ir-parity-sentinel/SOURCE_type-family-parity-projection.md new file mode 100644 index 00000000..2fdfb013 --- /dev/null +++ b/docs/design/0013-rust-ir-parity-sentinel/SOURCE_type-family-parity-projection.md @@ -0,0 +1,161 @@ +--- +title: Type-family parity projection +legend: SOURCE +packet: 0013-rust-ir-parity-sentinel +status: active +release: v0.0.6 +--- + +# Type-family parity projection + +## Why Now + +`schema-extensions-schema.graphql` already passes the current +`js-table-vs-rust-table.v0` projection when run as an explicit fixture. That is +useful, but narrow: it proves the folded table facts agree and says nothing +about the scalar, interface, union, enum, or input-object facts that made the +fixture worth adding to the Rust L1 corpus. + +The legacy JS `GraphQLAdapter.parseSDL` table IR intentionally drops those +non-table facts. Widening the current table projection and declaring victory +would therefore be false evidence. + +## Hill + +Wesley names a second parity projection before admitting schema-extension and +non-table fixtures to the default parity sentinel corpus. + +That projection compares GraphQL type-family structure fairly: + +- JS side: canonical SDL structure from the GraphQL AST after extension + folding +- Rust side: projected Rust L1 type-family facts + +The projection must not depend on product, database, runtime, or generated-code +semantics. + +## Projection Name + +Use: + +```text +js-sdl-type-family-vs-rust-l1-type-family.v0 +``` + +This name is intentionally explicit. The JS side is not the legacy table IR; it +is a canonical SDL structural projection produced in JS from the parsed SDL. +The Rust side is L1 IR projected into the same structural shape. + +## First Fixture + +The first default-corpus candidate is: + +```text +test/fixtures/ir-parity/schema-extensions-schema.graphql +``` + +Current observed behavior: + +- `pnpm parity:ir --fixture test/fixtures/ir-parity/schema-extensions-schema.graphql` + passes under `js-table-vs-rust-table.v0` +- that pass covers only the `users` and `teams` table facts +- legacy table IR reports empty `enums`, `scalars`, and `relationships` +- Rust L1 retains `DateTime`, `Named`, `Node`, `Timestamped`, `SearchResult`, + `Status`, and `UserFilter` + +Therefore, admitting this fixture to the default parity corpus requires the new +type-family projection, not just adding it to the current table fixture list. + +## Included Facts + +The v0 projection includes these generic GraphQL facts: + +- scalar type names and directives +- object type names +- object implemented interfaces +- object field names, type references, default values, and directives +- interface names +- interface implemented interfaces +- interface field names, type references, default values, and directives +- union names and member type names +- enum names and enum value names +- input object names +- input field names, type references, default values, and directives + +The projection includes only facts that both sides can derive from SDL and Rust +L1 without target-specific interpretation. + +## Excluded Facts + +The v0 projection excludes: + +- table-specific compatibility facts already covered by + `js-table-vs-rust-table.v0` +- generated relationship records +- operation catalogs and runtime optic facts +- directive location validation +- product, database, scheduler, transport, replication, and deployment + semantics +- invalid SDL diagnostics +- performance measurements + +These exclusions keep the projection structural. Other release slices own those +contracts. + +## Normalization Rules + +- Fold `extend scalar`, `extend type`, `extend interface`, `extend union`, + `extend enum`, and `extend input` blocks into their base definitions before + projection. +- Sort projected type records by deterministic code-point order of + `kind:name`. +- Sort projected field, argument, enum value, union member, interface, and + directive arrays by deterministic code-point order because the projection + treats them as semantic fact sets. +- Preserve GraphQL nullability and list wrapper structure. +- Preserve directive argument values after each side has produced semantic + values. +- Preserve Rust L1 canonical core directive names. +- Do not use this projection to prove legacy directive alias behavior unless + the admitted fixture uses canonical directive spelling or the JS structural + projection explicitly normalizes aliases as a named lowerer rule. +- Remove top-level envelope metadata before hashing. + +## Implementation Shape + +The implementation should add projection selection instead of overloading the +current table projection. + +Expected shape: + +- keep `js-table-vs-rust-table.v0` as the default table projection +- add `js-sdl-type-family-vs-rust-l1-type-family.v0` +- allow fixtures to name their projection +- keep failure reports keyed by projection, fixture, mismatch path, legacy + hash, and Rust hash +- admit `schema-extensions-schema.graphql` to the default sentinel corpus only + after the new projection passes + +The JS-side structural projection may reuse the existing canonical SDL +machinery in `packages/wesley-core/src/domain/canonicalize.mjs`, but the +projected comparison shape must be documented in code rather than relying on +raw canonical bytes alone. + +## Playback Questions + +1. Does the projection name make clear which lowerer/projection source is used + on each side? +2. Does the projection compare non-table type-family facts that the current + table adapter drops? +3. Does the fixture admission rule prevent `schema-extensions-schema.graphql` + from becoming default parity evidence before the new projection exists? +4. Does the implementation avoid product, database, and runtime semantics? +5. Does failure output still identify the first semantic mismatch path? + +## Non-Goals + +- Do not retire legacy Node lowering in this projection. +- Do not broaden Rust L1 golden regeneration. +- Do not add Nine Lives, WASM runtime policy, or module runtime behavior. +- Do not change Echo, jedit, Continuum, `git-warp`, `warp-ttd`, or + `wesley-postgres`. diff --git a/docs/design/0013-rust-ir-parity-sentinel/SOURCE_wesley-core-rs-ir-contract-and-fixtures.md b/docs/design/0013-rust-ir-parity-sentinel/SOURCE_wesley-core-rs-ir-contract-and-fixtures.md index 75d93838..50f577ea 100644 --- a/docs/design/0013-rust-ir-parity-sentinel/SOURCE_wesley-core-rs-ir-contract-and-fixtures.md +++ b/docs/design/0013-rust-ir-parity-sentinel/SOURCE_wesley-core-rs-ir-contract-and-fixtures.md @@ -51,6 +51,9 @@ The v0.0.6 corpus must keep these classes explicit: - **Invalid SDL**: negative diagnostics with stable codes and spans where the lowerer can provide them. +The schema-extension admission projection is +[Type-family parity projection](./SOURCE_type-family-parity-projection.md). + ## Canonical Bytes - Canonical JSON is UTF-8, newline-free, sorted-object-key JSON. diff --git a/docs/design/0013-rust-ir-parity-sentinel/rust-ir-parity-sentinel.md b/docs/design/0013-rust-ir-parity-sentinel/rust-ir-parity-sentinel.md index 927be17c..4bea677c 100644 --- a/docs/design/0013-rust-ir-parity-sentinel/rust-ir-parity-sentinel.md +++ b/docs/design/0013-rust-ir-parity-sentinel/rust-ir-parity-sentinel.md @@ -181,6 +181,21 @@ the default v0 sentinel corpus. The former still carries non-table Rust L1 coverage that needs a separate projection before it is fair parity evidence; the latter is scale coverage rather than the first compatibility sentinel. +## Next Projection + +The next projection is named in +[Type-family parity projection](./SOURCE_type-family-parity-projection.md). + +It defines `js-sdl-type-family-vs-rust-l1-type-family.v0` for structural +GraphQL type-family facts that the legacy JS table adapter drops: scalars, +interfaces, unions, enums, input objects, object/interface implements, and +extension-folded fields or members. + +`schema-extensions-schema.graphql` may enter the default sentinel corpus only +after that projection exists and passes. Running the fixture through +`js-table-vs-rust-table.v0` is useful table evidence, but it is not non-table +type-family parity evidence. + The supporting [core-rs IR contract and fixtures note](./SOURCE_wesley-core-rs-ir-contract-and-fixtures.md) records the release-scoped fixture classes, canonical byte rules, diagnostic diff --git a/docs/design/README.md b/docs/design/README.md index 6f9327b1..439a4b8f 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -19,7 +19,8 @@ Current packets: - [`0010`](./0010-wesley-graft-mcp-boundary/wesley-graft-mcp-boundary.md): Wesley+Graft MCP boundary for legal agent optics - [`0011`](./0011-causal-suffix-bundle-family-and-runtime-sync/causal-suffix-bundle-family-and-runtime-sync.md): Causal suffix bundle family and runtime sync - [`0012`](./0012-product-leftover-cleanup/product-leftover-cleanup.md): Product leftover cleanup for the v0.0.5 clean-house release -- [`0013`](./0013-rust-ir-parity-sentinel/rust-ir-parity-sentinel.md): Rust IR parity sentinel for the v0.0.6 compiler-truth release +- [`0013`](./0013-rust-ir-parity-sentinel/rust-ir-parity-sentinel.md): Rust IR parity sentinel for the v0.0.6 compiler-truth release, including the + [type-family parity projection](./0013-rust-ir-parity-sentinel/SOURCE_type-family-parity-projection.md) - [`0014`](./0014-domain-empty-core-boundary/domain-empty-core-boundary.md): Domain-empty Wesley core boundary for the v0.0.6 compiler-truth release - [Module Contract](./wesley-module-contract.md): Generic core boundary versus external module-owned domain surfaces - [Module Capability Contract](./wesley-module-capability-contract.md): The capability surfaces external modules should implement