Skip to content

Commit 6c06603

Browse files
dmealingclaude
andcommitted
test(codegen): pin the @provided own-only read the cherry-pick had no test for
The cherry-picked fix (6b89546, from the draft int-backed-enum branch) changed codegen behaviour in three ports and shipped with NO test — its branch's enum tests cover @intValueMap, a different feature. A behaviour change riding into a release untested is how the divergence it fixes got there in the first place. Two cases, on the existing FR-019 runGen harness: - a CHAINED declaration materializes. Root abstract `@provided Base`, root abstract `Derived extends Base`, entity field extends Derived. Under the old resolving read Derived is classified provided and the port emits an import of a hand-written `Derived` the adopter never declared; it must emit the type instead. - the marked declaration itself is STILL provided, so the fix cannot be "read own everywhere" overreach. PROVEN NON-VACUOUS: reverting just the TS half (ownAttrs -> attr) turns the first case red and leaves the other six green, then restoring it turns it back. A test that passes with and without the change it guards is worse than no test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 6b89546 commit 6c06603

1 file changed

Lines changed: 59 additions & 0 deletions

File tree

‎server/typescript/packages/codegen-ts/test/templates/enum-shared-provided.test.ts‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,3 +224,62 @@ describe("FR-019 inline enum unchanged", () => {
224224
expect(t).not.toContain('from "./enums"');
225225
});
226226
});
227+
228+
// ── @provided is DECLARATION-LAYER, not inherited ────────────────────────────
229+
//
230+
// `@provided` says "THIS type is supplied by hand-written / third-party code". Like
231+
// `abstract`, it is a fact about the declaration, not about the values it carries, so
232+
// it must NOT flow down an extends chain. TS, C# and Python read it RESOLVING while
233+
// Java and Kotlin read it own-only; the JVM side was right, and the divergence is
234+
// reachable only through a CHAINED declaration — a root-level abstract enum `B extends`
235+
// a root-level abstract `@provided A`.
236+
//
237+
// Under a resolving read, B is classified provided and the ports emit an import of a
238+
// hand-written `B` THE ADOPTER NEVER DECLARED (the marker was authored on A), instead of
239+
// materializing B from its inherited @values. This test pins the own-only read; it did
240+
// not exist when the fix was written, so the behaviour was unguarded in three ports.
241+
242+
/** Root abstract `@provided Base`, root abstract `Derived extends Base`, entity uses Derived. */
243+
function chainedProvidedModel(): unknown {
244+
return {
245+
"metadata.root": {
246+
package: "acme",
247+
children: [
248+
{ "field.enum": { name: "Base", abstract: true, "@provided": true, "@values": ["A", "B"] } },
249+
{ "field.enum": { name: "Derived", abstract: true, extends: "Base" } },
250+
{
251+
"object.entity": {
252+
name: "Order",
253+
children: [
254+
{ "field.long": { name: "id" } },
255+
{ "field.enum": { name: "kind", extends: "Derived" } },
256+
{ "source.rdb": { "@table": "orders" } },
257+
{ "identity.primary": { name: "id", "@fields": ["id"], "@generation": "increment" } },
258+
],
259+
},
260+
},
261+
],
262+
},
263+
};
264+
}
265+
266+
describe("FR-019 @provided does not inherit (ADR-0039 own read)", () => {
267+
test("a chained declaration MATERIALIZES rather than importing a type nobody declared", async () => {
268+
const root = await loadRoot(chainedProvidedModel());
269+
const { files } = await gen(root, "~/hand-written-enums");
270+
271+
// Derived is NOT provided, so it must be emitted...
272+
expect(files["enums.ts"]).toBeDefined();
273+
expect(files["enums.ts"]).toContain("Derived");
274+
// ...and must NOT be imported from the provided module.
275+
const all = Object.values(files).join("\n");
276+
expect(all).not.toContain('Derived } from "~/hand-written-enums"');
277+
});
278+
279+
test("the marked declaration itself is still provided", async () => {
280+
const root = await loadRoot(sharedModel({ provided: true }));
281+
const { files } = await gen(root, "~/hand-written-enums");
282+
// Status carries @provided on its OWN declaration — nothing emitted for it.
283+
expect(files["enums.ts"]).toBeUndefined();
284+
});
285+
});

0 commit comments

Comments
 (0)