Skip to content

intent: a cross-model schedules[].where status name is refused at Generate (#7288) - #7310

Open
delchev wants to merge 1 commit into
masterfrom
issue-7288-cross-model-schedule-status-name
Open

intent: a cross-model schedules[].where status name is refused at Generate (#7288)#7310
delchev wants to merge 1 commit into
masterfrom
issue-7288-cross-model-schedule-status-name

Conversation

@delchev

@delchev delchev commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Cause

PR #7269 (#7251) resolves a seeded status NAME in schedules[].where for a same-model source and skips a cross-model one on purpose - the owner's nomenclature is seeded in its own model, and WHICH of the { field, op, value } triples names the status is unknowable from this file. The issue asked that a cross-model source "keeps id-only and says so". Nothing said so, at either end:

  • IntentParser.validateWhereStatusValue returns early when source == null, and validateSchedules sets source = null for every cross-model schedule.
  • the generation-time check the javadoc deferred to validates only field existence (isMissing(sourceProps, condition.getField())), never the value.

So

schedules:
  - { name: dunning, entity: SalesInvoice, model: invoices, cron: ..., where: [{ field: Status, op: eq, value: OVERDUE }] }

parsed, generated and rendered .eq("Status", "OVERDUE") against an integer status FK - a query matching nothing for as long as the schedule kept ticking, with no diagnostic. That is #7251's own failure mode, one model: key away.

Change

The refusal is made where the owner's .model is in hand: at generation, off the DOCUMENT_STATUS widget the edm generator gave the status FK, which is what tells which condition is the status one. This is exactly how the sibling cross-model items: where: rule is refused (#7225), so the two now share one helper (crossModelStatusName); the items-side check is unchanged behaviourally.

  • GlueIntentGenerator.buildSchedules throws IntentValidationException (a 422) for a cross-model schedule whose where compares the owner's status relation with a non-integer, naming the relation, the name, the owner model and the id-only rule - the same sentence resolveSymbol uses for the header-level sites.
  • Only the status condition is refused: every other condition compares an ordinary column, where a string literal is just a literal. A seed id renders unchanged.
  • The parser and resolver javadoc that ended on "keeps the numeric seed id" now says where a name written there is refused, instead of leaving the reader to assume it is tolerated.
  • Module guide + the intent assistant guide updated so the assistant does not propose the shape.

No new authoring key, and no shape that used to work stops working - the spec already states the rule (intent-specification 1.2: "a nomenclature owned by another model is seeded there ... such a reference is an authoring error directing the author to the numeric id"), so this closes an implementation hole rather than changing the DSL; no doc-site PR is warranted.

Verified

  • mvn -pl components/engine/engine-intent test - 1211 tests, 0 failures.
  • Three new tests in GlueSchedulesTest, against a mocked owner .model (so statusProperty() is a real fact, not a convention default): the refusal names all four facts; a seed id still renders Criteria.create().eq("Status", 4) with the perspective read off the owner model; a string on a non-status condition still renders .eq("Number", "SI-1"). A new buildSchedulesForTest(model, context) hook mirrors the existing generates one.
  • mvn formatter:validate with the formatter cache wiped - BUILD SUCCESS.
  • mvn -P release ... install -pl components/engine/engine-intent (javadoc) - BUILD SUCCESS.
  • Not run: the integration suite. No IT fixture declares a cross-model schedule with a status condition, so no IT exercises this path either way.

Fixes #7288

…erate (#7288)

#7251 resolves a seeded status NAME in a schedule's row query for a
same-model source and leaves a cross-model one alone on purpose - its
nomenclature is seeded in the owner model, and which of the conditions
even names the status is unknowable from this file. But the skip was
silent on both ends: the parser's own invariant check returns early for a
cross-model source, and the generation-time check validates only that
each where field EXISTS. So a name against a cross-model source parsed,
generated and rendered as .eq("Status", "OVERDUE") against an integer FK
- a query matching nothing for as long as the job kept ticking, with no
diagnostic. That is #7251's failure one `model:` key away.

The refusal is made where the owner's `.model` is in hand: at generation,
off the DOCUMENT_STATUS widget that tells which property is the status
one, exactly as the sibling cross-model `items: where:` rule is refused
(#7225) - both now through one shared `crossModelStatusName`. The message
names the relation, the name, the owner model and the id-only rule, and
the parser/resolver javadoc that deferred to "keeps the numeric seed id"
now says where a name is refused instead.

Only the status condition is refused: every other condition compares an
ordinary column, where a string literal is just a literal. A seed id
renders unchanged.

Verified: engine-intent unit suite green (1211 tests), three new tests in
GlueSchedulesTest (the refusal names all four facts, a seed id still
renders as Criteria.create().eq("Status", 4), a string on a non-status
condition still renders), formatter:validate with the cache wiped, and
the -P release javadoc build on the module. No integration test run - no
IT fixture declares a cross-model schedule with a status condition.

Fixes #7288
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: a cross-model schedules[].where status NAME is still silently unresolved (#7251 follow-up)

1 participant