From 829eceb4236c8976043af0790a141623c7230d5c Mon Sep 17 00:00:00 2001 From: claude Date: Thu, 17 Sep 2026 08:12:30 +0000 Subject: [PATCH] feat(lint): expose service_ref and action_ref on the Starlark activity The catalog already stores ServiceRef and ActionRef for every activity (mdl/catalog/tables.go, builder_microflows.go), but ActivitiesFor did not select them and activityToStarlark did not expose them, so a custom rule could find a RestCallAction yet learn nothing about what it calls. This blocks rules of the form 'every outbound integration must be configured correctly' - the caller can identify the activity type but not the service or operation behind it. --- .claude/skills/mendix/write-lint-rules/SKILL.md | 2 ++ mdl/linter/context.go | 14 ++++++++++++-- mdl/linter/starlark.go | 2 ++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.claude/skills/mendix/write-lint-rules/SKILL.md b/.claude/skills/mendix/write-lint-rules/SKILL.md index 99eccf45bb..4d9ddeb2d2 100644 --- a/.claude/skills/mendix/write-lint-rules/SKILL.md +++ b/.claude/skills/mendix/write-lint-rules/SKILL.md @@ -320,6 +320,8 @@ def count_not(node): | `microflow_qualified_name` | string | `"Sales.ACT_Customer_Create"` | | `module_name` | string | `"Sales"` | | `entity_ref` | string | Referenced entity qualified name | +| `service_ref` | string | Called service document (REST / web service / OData client); empty when the activity calls none | +| `action_ref` | string | Operation or action within that service; empty when the activity calls none | ### permission diff --git a/mdl/linter/context.go b/mdl/linter/context.go index efa313f8d7..225759f6bb 100644 --- a/mdl/linter/context.go +++ b/mdl/linter/context.go @@ -1147,6 +1147,11 @@ type Activity struct { MicroflowQualifiedName string ModuleName string EntityRef string + // ServiceRef is the called service document (REST/web service/OData + // client); ActionRef the operation or action within it. Both are stored + // by the catalog builder and are empty for activities that call neither. + ServiceRef string + ActionRef string } // ActivitiesFor returns an iterator over all activities for a given microflow. @@ -1154,7 +1159,8 @@ func (ctx *LintContext) ActivitiesFor(microflowQualifiedName string) iter.Seq[Ac return func(yield func(Activity) bool) { rows, err := ctx.db.Query(` SELECT Id, Name, Caption, ActivityType, ActionType, - MicroflowId, MicroflowQualifiedName, ModuleName, EntityRef + MicroflowId, MicroflowQualifiedName, ModuleName, EntityRef, + ServiceRef, ActionRef FROM activities WHERE MicroflowQualifiedName = ? ORDER BY Sequence @@ -1168,8 +1174,10 @@ func (ctx *LintContext) ActivitiesFor(microflowQualifiedName string) iter.Seq[Ac for rows.Next() { var a Activity var name, caption, actionType, entityRef sql.NullString + var serviceRef, actionRef sql.NullString err := rows.Scan(&a.ID, &name, &caption, &a.ActivityType, &actionType, - &a.MicroflowID, &a.MicroflowQualifiedName, &a.ModuleName, &entityRef) + &a.MicroflowID, &a.MicroflowQualifiedName, &a.ModuleName, &entityRef, + &serviceRef, &actionRef) if err != nil { ctx.recordQueryError("ActivitiesFor (row scan)", err) continue @@ -1178,6 +1186,8 @@ func (ctx *LintContext) ActivitiesFor(microflowQualifiedName string) iter.Seq[Ac a.Caption = caption.String a.ActionType = actionType.String a.EntityRef = entityRef.String + a.ServiceRef = serviceRef.String + a.ActionRef = actionRef.String if !yield(a) { return diff --git a/mdl/linter/starlark.go b/mdl/linter/starlark.go index a74745b641..7893cd898d 100644 --- a/mdl/linter/starlark.go +++ b/mdl/linter/starlark.go @@ -1053,6 +1053,8 @@ func activityToStarlark(a Activity) starlark.Value { "microflow_qualified_name": starlark.String(a.MicroflowQualifiedName), "module_name": starlark.String(a.ModuleName), "entity_ref": starlark.String(a.EntityRef), + "service_ref": starlark.String(a.ServiceRef), + "action_ref": starlark.String(a.ActionRef), }) }