Skip to content

intent: a status NAME in the items rule of a cross-model source is refused, not left unresolved (#7225) - #7300

Merged
delchev merged 1 commit into
masterfrom
issue-7225-items-where-cross-model-status
Sep 10, 2026
Merged

intent: a status NAME in the items rule of a cross-model source is refused, not left unresolved (#7225)#7300
delchev merged 1 commit into
masterfrom
issue-7225-items-where-cross-model-status

Conversation

@delchev

@delchev delchev commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Cause

items: where: may name the item's status by its seeded name (#7164). With a cross-model source (fromUses:) the item's nomenclature is seeded in the owner model, so StatusSymbolResolver.rewriteGeneratesItemsWhere could not resolve it and returned silently - { field: Status, value: APPROVED } rendered as .eq("Status", "APPROVED"), a rule that matched nothing on every click, with no diagnostic. A second defect sat behind it: the resolver looked the item entity up by NAME among the LOCAL entities, so a local entity that merely shares the cross-model item's name lent its own nomenclature to the rewrite - an id positional in the wrong seed list.

Change

  • StatusSymbolResolver: a create-from with fromUses: leaves its items rule alone entirely (no local lookup by a foreign entity's name). Which condition names the status is knowable only from the owner .model, so the refusal lives where that model is read.
  • GlueIntentGenerator: the cross-model item source is resolved once (it was resolved twice for perspective and key), and a where condition on its statusProperty (the owner .model's DOCUMENT_STATUS property) whose value is not a whole number is refused with the message every other cross-model status site gives: a cross-model status must be referenced by its numeric seed id. Mirrors the sourceStatus refusal a few lines above in the same block. With no owner model (the convention fallback) or an owner entity declaring no status, nothing is checked, as before.
  • IntentParser: javadoc only - the items-rule validation notes that a cross-model source's items are checked at generation time.

Not touched: the second half of the issue (refuse: / guard / check messages rendered into Java literals unescaped) was already fixed by #7241 via #7262 - itemRefuseJavaLiteral, guard.messageJavaLiteral and check.messageJavaLiteral are what the templates render on master.

Out of scope: the same silent shape in a cross-model schedules[].where is #7288; the TargetInfo.statusProperty() check introduced here is reusable there.

Verification

  • New tests: StatusSymbolIntentTest.aCrossModelItemSourceIsNotResolvedAgainstASameNamedLocalEntity (the local same-named entity's seed id is NOT taken); GlueGeneratesItemsWhereTest × 3 against a mocked owner .model carrying a DOCUMENT_STATUS property - a name is refused naming the relation, the name and the owner model; a seed id renders .eq("Status", 3) with the perspective and key read off the owner model; a string on an ordinary column is not treated as a status.
  • mvn -pl components/engine/engine-intent test: 1204 tests, 0 failures.
  • formatter:validate on the module with the cache wiped: unchanged.
  • Not run: integration tests. The change is a parse/generation-time refusal plus a de-duplicated resolve call; no template or emitted-source shape changed.

Fixes #7225

🤖 Generated with Claude Code

…fused, not left unresolved (#7225)

A create-from's `items: where:` may name the item's status by its seeded
name (#7164). When the source is cross-model (`fromUses:`) the item's
nomenclature is seeded in the owner model, so the parser's resolver could
not rewrite the name - and returned silently, leaving `.eq("Status",
"APPROVED")` in the generated query: a rule that matched nothing on every
click. Worse, a LOCAL entity sharing the item's name lent its own
nomenclature to the rewrite, an id positional in the wrong seed list.

The resolver now leaves a cross-model source's items rule alone entirely,
and GlueIntentGenerator - the one place the owner .model tells WHICH
condition names the status (its DOCUMENT_STATUS property) - refuses a
non-numeric value there with the message every other cross-model status
site gives: a cross-model status must be referenced by its numeric seed
id. The item source is resolved once instead of twice.

The refuse:/guard/check literal escaping half of the issue was already
shipped by #7241 (#7262) and is not touched here.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@delchev
delchev merged commit bf4f618 into master Sep 10, 2026
10 checks passed
@delchev
delchev deleted the issue-7225-items-where-cross-model-status branch September 10, 2026 13:39
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: items.where with a status NAME on a cross-model item source is silently left unresolved; the refuse: message is an unescaped Java literal

1 participant