templates: relationshipMasterDeleteRefused="false" is the cascade, not the refusal (#7144) - #7182
Merged
Merged
Conversation
…t the refusal (#7144) CompositionChildren read the flag through ModelValues.truthy, which any non-empty string satisfies - so an .edm spelling the attribute out as "false" generated the refusal it is asking not to have. The intent generator only ever emits the attribute when it holds, so this could only bite the hand-authored path #7100 explicitly supports (the reverse index is derived, so a hand-authored .edm gets the cascade too). ModelValues.bool parses the value instead: only true, in any case, is true; anything else, an absent key included, is false - the cascade the absent attribute already meant. Fixes #7144 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
delchev
force-pushed
the
issue-7144-master-delete-refused-boolean
branch
from
September 8, 2026 21:08
3f270ba to
c0501a8
Compare
delchev
pushed a commit
that referenced
this pull request
Sep 10, 2026
…g obeys one rule (#7231) (#7273) #7182 (#7144) fixed CompositionChildren.refusesMasterDelete misreading relationshipMasterDeleteRefused="false" as true by adding a new helper, ModelValues.bool - but ModelValues.isTrue already existed for exactly this ("the model persists its flags as strings") and is what every other flag is read through (dataUnique, isRequiredProperty, widgetIsMajor, detailCalendar, ...). The result was two helpers for "is this string flag true": relationshipMaster- DeleteRefused honoured "TRUE" / " true " while isRequiredProperty="TRUE" stayed false. bool had exactly one caller. Case-insensitive parsing is the wanted behaviour here - #7182 deliberately locked it with tests (CompositionChildrenTest.aWrittenOutTrueIsTheRefusal / aWrittenOutFalseIsTheCascade) because the flag guards a destructive cascade, so a hand-authored "True" must refuse, not silently delete the children. So this makes isTrue the single robust reader rather than dropping to a presence/lowercase test: - ModelValues.isTrue now parses the value (Boolean.parseBoolean, trimmed, any case) - the exact body bool had - so every .edm flag is read the same way. - ModelValues.bool is deleted; CompositionChildren routes through isTrue. - New ModelValuesTest pins the single rule directly at the helper (lowercase/ uppercase/padded true, written-out false in any case, absent key/map, Boolean). The change is lenient-only for the other flags (the modeler always emits lowercase "true"/"false"), so generated output is byte-identical. Verified: mvn formatter:validate (BUILD SUCCESS, cache wiped); ide-template unit suite green (125 tests, incl. new ModelValuesTest and the unchanged CompositionChildrenTest); ModelGenerationIT green (1/1). Fixes #7231 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
CompositionChildrenread the composition child'srelationshipMasterDeleteRefusedflag throughModelValues.truthy, which any non-empty string satisfies — so an.edmcarrying the attribute spelled out as"false"generated exactly the REFUSE behavior it is asking not to have: the master's delete rejected while children exist, instead of the cascade.The intent generator only ever emits the attribute when the refusal holds (
EdmIntentGeneratorwrites the literal"true", and omits the key otherwise), so this could only bite the hand-authored / tool-produced path #7100 explicitly supports — the reverse index is derived frommasterEntity/masterEntityId, precisely so a hand-authored.edmgets the cascade too.ModelValues.boolparses the value instead of testing for presence: onlytrue, in any case, is true; anything else — an absent key included — is false, which is the cascade the absent attribute already meant.truthyis untouched, since JavaScript truthiness is the right reading everywhere else in the parameter graph (widget lengths, free-text fields); this one attribute is a boolean an author can write out in full.Nothing an intent Generate produces changes.
Tests
CompositionChildrenTest(module suite green, 6 tests in that class): a written-out"false"/"FALSE"is the cascade, and a"True"is still the refusal.Fixes #7144