Skip to content

fix(intent): a generates: map key is validated against the target (#6953) - #6961

Merged
delchev merged 1 commit into
masterfrom
issue-6953-generates-map-key-validation
Aug 27, 2026
Merged

fix(intent): a generates: map key is validated against the target (#6953)#6961
delchev merged 1 commit into
masterfrom
issue-6953-generates-map-key-validation

Conversation

@delchev

@delchev delchev commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Fixes #6953.

Problem

A map: entry has two ends and only one was checked. The value side has always been resolved against the source (validateMapSource); the key side - the property the target receives - was never checked against the target at all.

The generator pascal-cases the key and emits target.<Key> = ..., so a key the target does not declare is not a mis-mapping that shows up at run time: it is Java that does not compile, and client Java compiles as one registry-wide batch, so one bad key takes every module's beans down with it. The model parses clean, generates clean, and fails in generated code - the authored-but-broken class this module refuses everywhere else.

generates:
  - name: identificationLog
    from: Fine
    to: FineLog
    map:
      Vehicle: vehicle.plateNumber   # FineLog has no Vehicle relation -> target.Vehicle = ...
      violationAt: violationAt       # FineLog has no violationAt field

postings: never had the hole - it checks its map keys against its creates target.

Fix

IntentParser.validateMapTarget(...), beside validateMapSource, with the same message shape and the same case-insensitive match (the key is authored PascalCase, the target's field camelCase). Applied at the three sites that mint a record from a map:

site target message
generates[].map to: generates [x] map [K] is not a field or to-one relation of [T]
generates[].items.map items to: generates [x] items map [K] …
schedules[].generate.map generate's to: schedule [x] generate map [K] …

A cross-model target (uses:) is exempt, the convention every cross-model reference follows: its property names live in the owner's .model and are resolved at generation time. The items map inherits that exemption, since a cross-model header implies a cross-model item target.

Two in-repo fixtures were the bug

Both mapped onto a LOCAL target that declared no such property, and both would have generated Java that does not compile:

  • GlueGeneratesTest.anEventDrivenGenerateWithoutABackReferenceFailsLoudly - map: { Note: note } onto a Declaration with no note field.
  • IntentParserTest.scheduleGenerateChildrenValidate - map: { Person: id } onto a Claim with no Person relation.

They now declare the property they meant. rejectsMapSourceThatIsNotASourceProperty also gained the target field it was missing, so it isolates the source-side error again.

Verification

  • 930/930 engine-intent tests pass.
  • 4 new tests in GeneratesIntentTest: the three sites plus the cross-model skip (which also covers the items map being exempt).
  • 117 .intent documents - every in-repo fixture plus the production-intent corpus - parse unchanged. No false positives.
  • mvn formatter:format produces no reformatting.

The authoring guide (intent-assistant-guide.md) documented only the value side of map:; it now states the key-side rule and the cross-model exemption.

Related: the back-reference map entry doubles as the at-most-once guard (#6711), so a mistyped key there silently broke the guard derivation too - this catches it at parse time.

🤖 Generated with Claude Code

)

A `map:` entry has two ends and only one was checked. The value side has
always been resolved against the source; the KEY side - the property the
target receives - was never checked against the target at all. The generator
pascal-cases the key and emits `target.<Key> = ...`, so a key the target does
not declare is not a mis-mapping that shows up at run time: it is Java that
does not compile, and client Java compiles as one registry-wide batch, so one
bad key takes every module's beans down with it. The model parses clean,
generates clean, and fails in generated code - the authored-but-broken class
this module refuses everywhere else.

`postings:` never had the hole - it checks its `map` keys against its
`creates` target. This closes the asymmetry with the same message shape and
the same case-insensitive match (the key is authored PascalCase, the target's
field camelCase), applied at the three sites that mint a record from a map:
`generates[].map` (target = `to:`), `generates[].items.map` (target = the
items `to:`) and `schedules[].generate.map`.

A CROSS-MODEL target (`uses:`) is exempt, the convention every cross-model
reference follows: its property names live in the owner's `.model` and are
resolved at generation time. The items map inherits that exemption, since a
cross-model header implies a cross-model item target.

Two in-repo fixtures turned out to be exactly the bug being closed - both
mapped onto a LOCAL target that declared no such property, and both would
have generated Java that does not compile. They now declare the property they
meant. Every other fixture and the whole production-intent corpus (117 .intent
documents) parse unchanged.

Related: the back-reference map entry doubles as the at-most-once guard
(#6711), so a mistyped key there silently broke the guard derivation too -
this catches it at parse time.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@delchev
delchev merged commit 01ef07f into master Aug 27, 2026
10 checks passed
@delchev
delchev deleted the issue-6953-generates-map-key-validation branch August 27, 2026 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Intent parser: generates: map keys are not validated against the target - an unknown key generates Java that does not compile

1 participant