feat(intent): cross-model schedule source (model: on schedules + forEach) - #6532
Open
delchev wants to merge 1 commit into
Open
feat(intent): cross-model schedule source (model: on schedules + forEach)#6532delchev wants to merge 1 commit into
delchev wants to merge 1 commit into
Conversation
…ach) A schedule's source entity - and a generate forEach collection - may live in another intent model, referenced by `model: <uses alias>`. This lets a schedule live with the module that owns the CREATED rows instead of being forced into the source's module with a dependency in the wrong direction. - Omitted `model:` = local, fully backward compatible (existing generations stay byte-identical: `sourceGenFolder` defaults to the local gen folder). - The generated JobHandler imports the OWNER's `gen.<owner>.data...` classes and only READS them (the leafOnly precedent); one writer per state is preserved. - v1 scope: the generate action only. A cross-model source with notify is rejected at parse (notify needs the source's relation metadata). - Validation split (mirrors relations / dependsOn / leafOnly): the `model:` alias must be a declared `uses:` (parse); the source entity and every where/map/match field reference are validated at generation against the owner's .model, via CrossModelSupport (workspace first, registry fallback). An unresolvable owner or a mistyped field drops the schedule with a warning - never code that can't compile. Includes IntentParser + GlueIntentGenerator unit tests and a two-module HTTP-only IT (IntentCrossModelScheduleSourceIT) asserting the generated Job tokens, the running-instance row creation over REST, and both loud-failure paths. Co-Authored-By: Claude Opus 4.8 <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.
What
A P6 schedule's source
entity— and, inside a scheduledgenerate, aforEachcollection — may now live in another intent model, referenced by a newmodel: <uses alias>key. Omittingmodel:keeps today's behaviour (local source), and existing generations stay byte-identical.Why
Today a schedule's source must be a local entity, so the module that owns the created rows cannot own the schedule — it is forced into the source's module with a
uses:back-edge, a dependency in the wrong direction (and a leaf-first-generation / bootstrap headache for any pair of mutually-referencing models). Letting the consumer own the schedule and read the source cross-model removes that inversion. This is the existing consumer→owneruses:direction — a consumer's generated code already binds to an owner (PROJECTION entities,leafOnlyvalidation), so no new coupling is introduced.How
ScheduleIntent.model— new field (Gson-mapped YAML key).model:must name a declareduses:alias (parse); for a cross-model source the local entity/field checks are skipped and validated later; a cross-model source withnotifyis rejected (v1 scope —notifyneeds the source's relation metadata, which only a local entity carries);forEach.modelhandled the same way.CrossModelSupport(workspace.modelfirst, registry fallback, loud failure) — the same two-tier resolution relations /dependsOn/leafOnlyalready use. Everywhere/map/matchreference is validated at generation against the owner's properties (skipped on the convention fallback, likedependsOn); a miss drops that schedule with a warning rather than emitting code that cannot compile. EmitssourceCrossModel/sourceModel(+forEachCrossModel/forEachModel), every existing glue key preserved.generateUtils.js+Job.java.template— the source (and cross-model forEach) imports resolve against the owner'sgen.<owner>.data…package (theleafOnlyprecedent — the job only READS the source).sourceGenFolderdefaults to the local folder, so local schedules regenerate byte-identically.intent-assistant-guide.md; plus the two doc sites (see below).Validation split (mirrors relations / dependsOn / leafOnly)
model:names a declareduses:aliasnotify+ cross-model source (rejected, v1).modelwhere/map/matchfields exist on the ownerScope
v1 is generate-action schedules only; the cross-model source is read-only (a schedule never writes it — one-writer-per-state preserved). Out of scope:
notifyover a cross-model source (needsNotificationSupportoverTargetInfo, no driving case), and any write to the source.Tests
IntentParserTest(declared-alias / undeclared-alias / notify-rejected / cross-model forEach) andGlueSchedulesTest(local stays not-cross-model; cross-model source emits the source + forEach keys and the Criteria). Full engine-intent suite green (308).IntentCrossModelScheduleSourceIT(two mutually-referencing modules, HTTP-only): asserts the generatedJobtokens (owner-package source import, Criteria, owner-package forEach FQNs) and the OUTERMOST layer — publish both, force-sync, seed the source over REST, and assert the cron-fired job created the target + child rows over REST — plus both loud-failure paths (owner.modelabsent; awhere-field typo reported naming the owner model).IntentEngineIT(36) +IntentEmissionCoverageIT(1) green — local-source Job emission unchanged.Docs
Vendor-neutral spec (intentfile.org) and branded (dirigible.io
/help/intent/) updated in the same effort.Notes / deviations
The
/parseendpoint receives only raw YAML, so — exactly as for relations,dependsOnandleafOnly— cross-model reference resolution happens at generation, not parse. No/parsesignature change was needed.