Repository navigation
fix(projection): a renamed key with a derived identity serves its item route in all five ports - #412
Merged
Merged
Conversation
…m route in all five ports A view-only projection that passes the base key through on a renamed field and omits @fields on its identity had no item route in TypeScript, did not compile in Kotlin and answered 500 in C#. Each port now takes the key from the loader's own derivation. Pinned by projection/keyed-by-derived-identity in the api-contract corpus.
…on projection identities
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Make all those changes, things should work the same and add conformance tests.
Context: the route-parity work (PR #408) made projection and report read routes identical in all five ports for the cases it covered, and found one more divergence it did not change: a projection whose key field is renamed and whose identity omits
@fields(the derived form the loader recommends). For that projection TypeScript mounts no item route, Kotlin emits code that does not compile, and C# answers 500; Java and Python work. The shared corpus only covers the explicit@fieldsform. Fix the derived form so all five ports behave like Java and Python, and pin it with a shared api-contract conformance case.What Changed
Fixed a projection route divergence across ports. A read-only projection that passes the base entity's key through on a renamed field and declares an identity with no explicit
@fields(the derived form the loader recommends) now serves its item route consistently. TypeScript now mounts aGET /{id}route and by-id query, Kotlin code now compiles, and C# no longer answers 500 on item requests. All five ports now take the key from the loader's own derivation instead of relying on inherited@fieldsthat may name no field of the projection.Added
projection/keyed-by-derived-identity.yamlto the api-contract conformance corpus. The test case covers a projection with a renamed key field and a derived identity (no explicit@fields), gated across all five ports to prevent regression on the route divergence.Updated loader implementations across three ports. C#
MetaIdentity.Fieldsnow computes the key from pass-through fields; Java'sValidationPhaseexports a publiccomputePassthroughKeymethod that its validation uses; Kotlin'sKotlinGenUtilnow provides akeyFieldsfunction for codegen to use consistently with other ports.Documented the derived identity form in source-kinds.md. Clarified when to omit
@fieldson projection identities and how the loader derives the key from the base entity's pass-through field.🤖 Generated with Claude Code
Risk Assessment
✅ Low: Fix applied at the single shared accessor/helper in each port (C# MetaIdentity.Fields getter, TS getPkFields, Kotlin KotlinGenUtil.keyFields, Java extracted computePassthroughKey), matching the already-correct Java/Python behavior; new InvoiceRegister fixture and scenario wired consistently into all five ports' harnesses, and new tests exercise real codegen/render/HTTP behavior rather than source text.
Testing
TS codegen and API integration tests both pass (42 total). C# conformance suite fully passes (1304 tests). Kotlin compilation succeeds after fix - was failing with unresolved reference before. Python unit tests all pass (26 relevant). New conformance fixture InvoiceRegister added with 6 test scenarios: GET list sorted, GET known/unknown key, write-verb 405s. Baseline ci-local.sh --quick run completes through mutation/completeness-gate without failures. All execution succeeded.
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
scripts/ci-local.sh --only ts-fast --only ts-unit --strict-toolchainsserver/typescript packages/codegen-ts/test/projection/routes-file.test.ts (30 tests pass)server/typescript packages/integration-tests/test/api-contract-projection.test.ts (12 live API tests pass)server/csharp MetaObjects.Conformance.Tests (1304 tests pass)server/java metadata codegen-kotlin clean compile (BUILD SUCCESS)server/python tests/unit -k projection (26 tests pass)scripts/ci-local.sh --quick (gates/leak-scan/TS/unit/conformance/completeness - all lanes pass)✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.
Behaviour before this change (minimal projection: renamed key field,
identity.primarywithout@fields)GET /{id}route and no by-id query mountedGET /{id}on the renamed fieldGET /{id}500GET /{id}Java and Python are the correct reference: the loader derives the projection's key from the pass-through field and never writes it back, and those two ports read that derivation; TS, Kotlin and C# read the base identity's inherited
@fields(id), which names no field of the projection. Each of the three now takes the key from the loader's own derivation (TSgetPkFields, KotlinKotlinGenUtil.keyFields, C#MetaIdentity.Fields).Verification on the rebased head (onto #410)
scripts/ci-local.shgreen before the rebase; the only failures were load-related hook timeouts and a vanished Docker container, cleared by rerunning the affected integration suites (C#, Python, Java, Kotlin integration green; TS integration 427/427).projection/api-contract corpus (12 scenarios, including the newkeyed-by-derived-identity.yaml) run in all five ports: TS 12, C# 12, Python 19 (projection tests), Java 12, Kotlin 12.@fieldsprojections and keys that keep the base name generate the same bytes as before (existing corpora unchanged).