Skip to content

feat: full nanoflow support — CREATE, DROP, SHOW, DESCRIBE, DIFF, MERMAID, security, and agentic skill#301

Merged
ako merged 18 commits intomendixlabs:mainfrom
retran:pr4-nanoflows-all
Apr 29, 2026
Merged

feat: full nanoflow support — CREATE, DROP, SHOW, DESCRIBE, DIFF, MERMAID, security, and agentic skill#301
ako merged 18 commits intomendixlabs:mainfrom
retran:pr4-nanoflows-all

Conversation

@retran
Copy link
Copy Markdown
Contributor

@retran retran commented Apr 24, 2026

Why

Nanoflows are a core Mendix document type for mobile and offline-first apps. Until this PR, mxcli had read-only nanoflow support (SHOW, DESCRIBE) but could not create, modify, or manage nanoflows — blocking agentic workflows that need to scaffold, refactor, or secure nanoflow logic.

This gap was visible in the feature matrix: nanoflows lagged far behind microflows in every dimension. This PR brings nanoflows to full feature parity with microflows across grammar, executor, SDK, validation, visualization, and security management.

Proposal: docs/11-proposals/PROPOSAL_nanoflow_support.md
Test plan: docs/15-testing/nanoflow-test-cases.md (19 sections, 126 test cases)

What Changed

New MDL commands

Command Description
CREATE [OR MODIFY] NANOFLOW Create nanoflows with body, parameters, return type, folder placement
DROP NANOFLOW Remove a nanoflow from the project
CALL NANOFLOW Call a nanoflow from within a flow body (valid in both microflows and nanoflows)
CALL JAVASCRIPT ACTION Call a JavaScript action from within a flow body
GRANT EXECUTE ON NANOFLOW Grant module role access to a nanoflow
REVOKE EXECUTE ON NANOFLOW Revoke module role access from a nanoflow
SHOW ACCESS ON NANOFLOW Display which roles have access to a nanoflow
MOVE NANOFLOW Move a nanoflow to a different module or folder
RENAME NANOFLOW Rename a nanoflow
DIFF (nanoflow support) Detect and display nanoflow changes between .mpr versions

CLI enhancements

  • describe nanoflow --format mermaid — generates Mermaid flowchart diagrams for nanoflows
  • describe nanoflow --format elk — generates ELK JSON layout data for nanoflow visualization in VS Code
  • LSP snippet completionsCREATE NANOFLOW (with params), CALL MICROFLOW, CALL NANOFLOW, CALL JAVASCRIPT ACTION, CALL JAVA ACTION snippets in the language server

VS Code extension

  • Nanoflow diagram preview (Show Diagram and Show Diagram with Source) — uses the same ELK.js renderer as microflows, with bidirectional source-map sync
  • Nanoflow context menu parity: diagram commands now appear for nanoflows in the project tree

Validation

Type-switch validation rejects 21 action types that Mendix does not allow in nanoflows (Java actions, REST calls, workflow actions, import/export mappings, file downloads, etc.). Entity resolver errors propagate upfront — no silent failures on invalid parameter or return types. ValidateNanoflowBody provides the same semantic checks (undeclared variables, missing returns, branch scoping) as ValidateMicroflowBody via shared validateFlowBody helper.

Parser and formatter fixes

  • Negative number literals: Removed -? from NUMBER_LITERAL lexer rule — negation now handled by unaryExpression, fixing expressions like $var -2 that were incorrectly tokenized.
  • Multi-predicate XPath: Formatter now correctly splits [pred1][pred2] XPath constraints instead of stripping only outermost brackets.
  • Multi-line string literals: Added escapeExpressionValue() to escape \n/\r/\t inside single-quoted string regions (e.g. embedded JSON in change object actions).
  • If-in-loop bodies: Added full ExclusiveSplit handling to traverseLoopBody — if/else blocks inside while/loop bodies now emit correctly with end if;.
  • Empty JS/Java action params: Parameters with empty/nil values are now omitted from argument lists instead of emitting invalid ... or bare = ).
  • Flow lookup caching: lookupNanoflowReturnType and lookupMicroflowReturnType lazily cache results with bool flags (handles empty-slice-from-backend correctly). Both include GetRawUnitByName fast-path before module walk.
  • Nanoflow forward-reference detection: allNames() in validator now includes nanoflows.

Bug fixes and improvements

  • JavaScript action support: call javascript action Module.ActionName(params) — grammar rule, parser, AST node, visitor, builder, validation, serializer. JS actions roundtrip correctly through describe → drop → create cycle.
  • Association retrieve roundtrip: retrieve $X from $Y/Module.Association syntax preserved on roundtrip. Previously, the builder converted association retrieves to database retrieves with XPath constraints on reverse traversals.
  • Nanoflow serialization rewrite: serializeNanoflow() was incomplete — missing ReturnType, ObjectCollection, and Flows. Created nanoflows lost their body when written to .mpr.
  • Empty-then optimization: If/else blocks with empty true branches are swapped and condition negated for readable DESCRIBE output.
  • NanoflowCallAction BSON field corrected from ResultVariableName to OutputVariableName.
  • JavaScript action references validated separately from Java actions.
  • Module existence validated for SHOW NANOFLOWS/MICROFLOWS.
  • Numeric return literals no longer get spurious $ prefix.
  • Empty nanoflow/microflow names rejected at create time.
  • NanoflowCallAction error handling type resolved correctly.
  • not() expression spacing preserved on roundtrip.
  • Mermaid renderer handles NanoflowCallAction.
  • AllowedModuleRoles preserved through drop/recreate cycle.
  • ELK error handling: ListDomainModels errors now propagated in all ELK and describe paths (previously swallowed).
  • ELK refactoring: buildFlowELK extracted as generic flow renderer with flowELKInput struct, replacing microflow-specific buildMicroflowELK.
  • Mock backend stubs: All 6 nanoflow mock stubs now return descriptive errors instead of nil, nil.
  • Doc fixes: Corrected BSON mapping disallowed actions list, fixed example syntax, fixed proposal keyword and count.

Agentic skill

New Claude Code skill at .claude/skills/mendix/write-nanoflows.md — guides AI agents through nanoflow creation with MDL syntax, parameter types, body actions, security management, and validation rules.

Shared helpers

  • buildEntityNames extracted to eliminate duplication between microflow and nanoflow ELK and Mermaid rendering.
  • serializeNanoflow() fully rewritten to serialize body, flows, return type, and parameters.
  • renderMicroflowMDL parameterized with flowType to support both microflow and nanoflow MDL source generation.
  • describeNanoflowToString wraps nanoflow as Microflow struct for shared MDL rendering pipeline.
  • validateFlowBody extracted from ValidateMicroflowBody/ValidateNanoflowBody to eliminate duplication.

Testing

Automated tests (all pass with make build && make test):

  • 33 integration tests (roundtrip_nanoflow_test.go) — CREATE, DROP, CALL, GRANT/REVOKE, SHOW, MOVE, RENAME, MERMAID, validation, error paths
  • 36 mock unit tests (cmd_nanoflows_mock_test.go) — not-connected guards, duplicate handling, idempotent grant/revoke, all 21 disallowed actions, nested body validation
  • 5 BSON roundtrip tests (roundtrip_test.go) — parse→serialize→parse cycle with activities, flows, and roles
  • 5 JS action empty param tests (cmd_microflows_format_action_test.go) — empty/nil/mixed param handling

Manual testing: 19-section test plan executed across 6 sessions against 3 App Gallery demo projects (223 nanoflows total). Final session (2026-04-29, commit ae49ce7): 268 tests executed, 268 pass, 0 failures. Full roundtrip (describe→check) passes for all 223 nanoflows across all 3 projects.

Known limitations

Description Severity Status
Complex nanoflow roundtrip (describe→drop→create→describe) produces cosmetic diffs: anchor directions, whitespace normalization, on error rollback appended. Does not affect describe→check validation. Low Accepted
Security roles persist through drop/recreate N/A By design — matches microflow behavior
Dangling call reference after callee drop renders stale name N/A By design — no cascading deletes

Documentation updated

  • MDL_FEATURE_MATRIX.md — nanoflow row reflects implemented state
  • MDL_QUICK_REFERENCE.md — added CREATE, MOVE, GRANT/REVOKE, SHOW ACCESS nanoflow syntax
  • 01-language-reference.md — added CREATE/DROP/GRANT/REVOKE nanoflow sections
  • grammar-reference.md — added createNanoflowStatement, dropNanoflowStatement, callJavaScriptActionStatement
  • PROPOSAL_nanoflow_support.md — rewritten from proposal to feature description
  • nanoflow-test-cases.md — comprehensive QA test plan (19 sections, 126 test cases)
  • 10-bson-mapping.md — added Nanoflow Mapping section with type differences, allowed actions, JS action field mapping
  • examples/create_nanoflow/ — new Go example with 4 nanoflow patterns
  • CHANGELOG.md — unreleased entries for all nanoflow features
  • SDK_EQUIVALENCE.md — updated nanoflow CRUD feature list
  • docs-site/src/language/nanoflows.md — added Security section with cross-references
  • CLAUDE.md — added write-nanoflows.md to skill table

Stats

92 files changed, +19,287 / −10,947, 16 commits

Grammar → AST → Visitor → Executor → SDK → Tests → Docs → VS Code — full pipeline coverage.

@retran retran marked this pull request as draft April 24, 2026 17:57
@retran retran force-pushed the pr4-nanoflows-all branch 3 times, most recently from 1c71d9f to 5b17c36 Compare April 24, 2026 19:51
@github-actions
Copy link
Copy Markdown

AI Code Review

What Looks Good

The PR implements comprehensive nanoflow support, bringing it to full feature parity with microflows. Key strengths:

  • Complete pipeline coverage: Grammar → AST → Visitor → Executor → Backend → SDK → Tests → Docs
  • Thorough validation: Rejects 21 disallowed actions with clear error messages
  • Security management: Full GRANT/REVOKE/SHOW ACCESS support for nanoflows
  • Documentation: New skill file (write-nanoflows.md), updated quick reference, language reference, BSON mapping, and test plan
  • Examples: New Go example and doctype test file
  • Test coverage: 33 integration tests, 36 mock unit tests, 5 BSON roundtrip tests, plus 77+ manual test cases
  • Roundtrip fidelity: Properly preserves nanoflow bodies, parameters, return types, and JavaScript action calls
  • Related improvements: JavaScript action full pipeline, association retrieve roundtrip, nanoflow diff, empty-then optimization

The implementation follows all MDL syntax design guidelines:

  • Uses standard CRUD verbs (CREATE/DROP/GRANT/REVOKE/SHOW/CALL)
  • Qualified names everywhere (Module.NanoflowName)
  • Proper property format with colon separators
  • Correct use of AS for mappings (not flagged in appropriate contexts)
  • Reads as English for citizen developers
  • No keyword overloading
  • Diff-friendly syntax

Recommendation

Approve the PR. The implementation is complete, well-tested, and follows all project conventions. The nanoflow support addresses a significant gap in the feature set and enables agentic workflows for nanoflow management as intended.

No blocking issues were identified. The PR is ready to merge.


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

@retran retran force-pushed the pr4-nanoflows-all branch 4 times, most recently from 74e5ea1 to 8b23f02 Compare April 24, 2026 20:33
@github-actions
Copy link
Copy Markdown

AI Code Review

Review Summary

This PR implements full nanoflow support in mxcli, closing a significant gap in the MDL feature matrix. The changes are thorough and follow the established patterns for MDL feature implementation.

Critical Issues

None found.

Moderate Issues

None found.

Minor Issues

  1. Test coverage gap for diff output: The PR's automated test coverage section explicitly notes a gap: | Diff output | None | **Gap** |. While manual testing covers this (as stated in the manual testing priority), adding automated tests for mxcli diff with nanoflow changes would strengthen confidence.

  2. LSP/VS Code extension changes not visible: The truncated diff doesn't show changes to cmd/mxcli/lsp.go or vscode-mdl/package.json. Though the PR claims full pipeline coverage including LSP, and nanoflows likely reuse existing microflow LSP capabilities (given similar structure), verification of LSP wiring for nanoflow-specific features (if any) would be ideal. However, the PR does update Mermaid diagram viewer documentation to include nanoflows, suggesting visualization support is addressed.

What Looks Good

  • Complete MDL pipeline wiring: Grammar, AST, visitor, executor, backend, and documentation are all updated for nanoflow CREATE/DROP/CALL/GRANT/REVOKE/SHOW ACCESS.
  • Strong adherence to MDL design guidelines:
    • Uses standard CRUD verbs (CREATE, DROP, GRANT, REVOKE, SHOW)
    • Qualified names everywhere (Module.Element)
    • Property format consistent (folder 'path')
    • Clear distinction between colon (property) and AS (mapping) - no misuse of AS observed
    • Statements read as English for citizen developers
    • No keyword overloading; each keyword has single consistent meaning
  • Comprehensive documentation:
    • New skill (write-nanoflows.md)
    • Updated quick reference, language reference, BSON mapping
    • Examples and changelog entries
    • Feature matrix updated to reflect implemented state
  • Robust test coverage:
    • 33 integration tests + 36 mock unit tests + 5 BSON roundtrip tests
    • Extensive manual test plan (77+ cases) executed against 3 real projects
    • Validation covers 21 disallowed actions, error handling, edge cases
  • Valuable bug fixes alongside feature work:
    • JavaScript action full pipeline (OBS-7)
    • Association retrieve roundtrip fidelity (RT-2)
    • Empty-then optimization for readable DESCRIBE
    • Nanoflow diff support
    • Security role persistence through drop/recreate (by design, matching microflows)
  • Consistency with existing patterns: Nanoflow syntax mirrors microflow where appropriate (parameters, return types, body, folder) while correctly restricting client-side actions.

Recommendation

Approve the PR. The changes are high-quality, thoroughly tested, and fully address the nanoflow support gap. The minor test coverage gap for diff output is acknowledged in the test plan and covered by manual validation; it does not block merging given the overall strength of the implementation. No blocker issues were identified.

The PR successfully enables agentic workflows to scaffold, refactor,


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

@github-actions
Copy link
Copy Markdown

AI Code Review

What Looks Good

The PR successfully implements full nanoflow support with excellent attention to detail:

  • Complete feature parity: Nanoflows now match microflows across CRUD operations, security management, visualization (Mermaid/ELK), validation, and roundtrip capabilities
  • Thorough pipeline implementation: Grammar → AST → Visitor → Executor → Backend → LSP → DESCRIBE roundtrip all properly wired
  • Comprehensive testing: 33 integration tests, 36 mock unit tests, 5 BSON roundtrip tests, plus extensive manual test plan (123 test cases)
  • Documentation excellence: Updated feature matrix, quick reference, language reference, BSON mapping, and added dedicated nanoflow skill
  • Smart refactoring: ELK rendering generalized to support both microflows/nanoflows, reducing duplication
  • Proper validation: Correctly rejects 21 disallowed nanoflow actions with clear error messages
  • VS Code integration: Diagram preview and context menu parity achieved
  • Agentic enablement: Added write-nanoflows.md skill for AI-assisted development

The implementation follows all MDL syntax design guidelines:

  • Uses standard CREATE/ALTER/DROP/SHOW/DESCRIBE verbs
  • Proper qualified names (Module.Element)
  • Correct colon/AS usage (colon for properties, AS for mappings)
  • Reads as English for citizen developers
  • No keyword overloading
  • Diff-friendly syntax

Recommendation

Approve - The PR is production-ready with comprehensive test coverage, proper architectural implementation, and excellent documentation. All checklist items have been satisfactorily addressed. The nanoflow support brings the CLI to feature parity with microflows as intended.


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

@retran retran force-pushed the pr4-nanoflows-all branch from c4e4ebe to 6c0dad8 Compare April 28, 2026 16:19
@retran retran marked this pull request as ready for review April 28, 2026 16:23
Copy link
Copy Markdown
Collaborator

@ako ako left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #301 Review — feat: full nanoflow support

Overview

Very comprehensive PR bringing nanoflows to feature parity with microflows: CREATE/DROP/GRANT/REVOKE/MOVE/RENAME, JavaScript action support, association retrieve roundtrip fix, empty-then optimization, Mermaid/ELK diagram parity, and VS Code extension nanoflow context menus. Full-stack pipeline coverage with good test counts (33 integration + 36 mock unit + 5 BSON roundtrip).

Pipeline checklist

Layer Status
Grammar (createNanoflowStatement, grantNanoflowAccess, etc.)
Parser regenerated
AST nodes (CallNanoflowStmt, CallJavaScriptActionStmt, etc.)
Visitor
Builder (addCallNanoflowAction, addCallJavaScriptActionAction)
Formatter (NanoflowCallAction, JavaScriptActionCallAction cases)
Parser BSON (AllowedModuleRoles, ObjectCollection, ReturnType)
Writer BSON (serializeNanoflow fully rewritten)
Security (grant/revoke/show access)
Validation (21-action denylist, binary return type check)
ELK/Mermaid/Diff
VS Code extension

Issues

1. DownloadFileStmt missing from nanoflow denylist

The bson-mapping doc added in this PR explicitly lists Microflows as a server-side-only action that cannot be used in nanoflows. But checkDisallowedNanoflowAction in nanoflow_validation.go does not include a case *ast.DownloadFileStmt entry. The denylist comment says "when adding new action AST types, check whether they are available in nanoflows" — DownloadFileStmt (added in PR #333) needs that case:

case *ast.DownloadFileStmt:
    return "download file is not allowed in nanoflows"

Without it, create nanoflow will silently accept and write a DownloadFileAction that Studio Pro will reject with CE6007 (or similar).

2. AllowedModuleRoles type mismatch in grant/revoke

In execGrantNanoflowAccess, the existing roles from the parsed nanoflow are model.ID values (UUIDs from BSON) but the new roles from the MDL statement are qualified-name strings ("Module.Role"):

for _, r := range nf.AllowedModuleRoles {    // model.ID — UUID strings
    merged = append(merged, string(r))
}
for _, role := range s.Roles {
    qn := role.Module + "." + role.Name      // qualified name strings
    merged = append(merged, qn)
}
ctx.Backend.UpdateAllowedRoles(nf.ID, merged)  // mix of IDs and names

If UpdateAllowedRoles writes the slice as-is to BSON, the next parseNanoflow round will have a mix of real UUIDs and unresolvable role names. This is the same pattern used in the microflow grant/revoke, so either the backend resolves them or both commands have the same bug — but it's worth verifying that UpdateAllowedRoles normalises to IDs before writing.

3. lookupNanoflowReturnType calls ListNanoflows() per invocation

For each call nanoflow statement encountered during flow graph build, lookupNanoflowReturnType calls fb.backend.ListNanoflows() (a backend read) and then fb.backend.GetModuleByName(). For a microflow that calls N nanoflows this is 2N backend reads. The microflow equivalent lookupMicroflowReturnType has the same pattern, so it's consistent, but caching the nanoflow list in flowBuilder (like fb.nanoflows) would make this O(1) amortised. Flag for a follow-up if performance becomes visible on large projects.

Correctness notes (positive)

int32(2) for parameter mapping arrays confirmed correct — The writer uses int32(2) as the BSON array sentinel for NanoflowCallParameterMapping and JavaScriptActionParameterMapping. This is consistent with the existing microflow call parameter mapping serialization and is the correct Mendix sentinel for arrays of mapping documents (distinct from int32(3) for object collection arrays).

Association retrieve simplification is sound — Removing the reverse-traversal XPath rewrite in favour of always using AssociationRetrieveSource is the correct fix. Studio Pro resolves traversal direction from association metadata at runtime; the old XPath rewrite was fragile and broke DESCRIBE roundtrip.

negateIfCondition double-negation guard is correct — The paren-depth tracker in the not(x) unwrap path correctly rejects unbalanced inputs (e.g., not() or )) and the test cases cover the edge cases.

Empty-then swap applied in both traversal functions — The optimization is correctly duplicated in both traverseFlow and traverseFlowUntilMerge. Note that the second location also removes the empty else block after the swap; the first does not. This asymmetry is harmless (the first location's empty else is pruned naturally by the outer loop) but worth confirming.

Nit

The getErrorHandling function in nanoflow_validation.go includes cases for disallowed action types (CallJavaActionStmt, RestCallStmt, etc.). The comment explains this is safe because the denylist is checked first (via continue). That ordering guarantee holds today, but is fragile — if the loop order in validateNanoflowStatements ever changes (e.g., recursion before denylist check), unreachable error handlers on disallowed actions would be silently traversed. Consider removing the disallowed types from getErrorHandling since their error handlers can never be reached after the denylist blocks them.

Summary

Item 1 (DownloadFileStmt in denylist) is the only blocking issue — it's a one-line fix that prevents silent Studio Pro rejection. Item 2 (ID/name mix in UpdateAllowedRoles) should be verified against the backend implementation. Everything else is solid. The BSON roundtrip tests and the explicit denylist maintenance warning in the comment are exactly the right defensive patterns for a feature of this scope.

@retran retran marked this pull request as draft April 28, 2026 19:39
Copy link
Copy Markdown
Collaborator

@ako ako left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #301 — Supplemental Review (Checklist Pass)

Following a full walk of the CLAUDE.md PR checklist, here are findings not covered in the first review.

Documentation gaps

1. CLAUDE.md skill table does not list write-nanoflows.md — Moderate

The "IMPORTANT: Before Writing MDL Scripts" section in CLAUDE.md lists every skill agents should read before writing MDL (write-microflows.md, create-page.md, etc.). write-nanoflows.md is absent. Without this entry, agents working on nanoflow tasks won't know the skill exists.

Fix: add one line to the skill table in CLAUDE.md:

- `.claude/skills/write-nanoflows.md` - **READ before writing nanoflows** - Nanoflow syntax, restrictions, security management

2. docs-site/src/ not updated — Moderate

No changes to the docs site are in the diff. The CLAUDE.md checklist says: "Site docs — docs-site/src/ pages added or updated for user-facing features." CREATE/DROP/GRANT nanoflow are all user-facing. This may be intentional if the docs site is published separately, but it should be confirmed or a follow-up issue filed.

LSP completions — Minor

lsp_completions_gen.go is not in the diff. NANOFLOW / NANOFLOWS were already present as bare keywords from before this PR. The new statement forms (call javascript action, grant/revoke execute on nanoflow, create or modify nanoflow) do not have snippet-level completions. This is consistent with how other new statement types have been handled (completions are added separately), but worth tracking.

DESCRIBE roundtrip for call javascript action not explicitly tested — Minor

The formatter emits the JS action's qualified name from a.JavaScriptAction directly. There is no test that takes the formatted output, feeds it back through the parser, and confirms no error (checklist finding #4). Given the existing grammar rule is correct, this is low risk, but a single visitor-level roundtrip test would close the gap.

Mock backend nanoflow stubs — Minor

The checklist requires: "every new backend method has a Func-field stub with a descriptive "MockBackend.X not configured" error default (not nil, nil)." The diff shows ListNanoflowsFunc, DeleteNanoflowFunc, MoveNanoflowFunc in test setup but the zero-value defaults in the mock definition file should be verified to emit the required error string rather than nil, nil. Worth a quick grep of mdl/backend/mock/ to confirm.

@retran
Copy link
Copy Markdown
Contributor Author

retran commented Apr 29, 2026

Thanks for the thorough review, Ako! Pushed a commit addressing your feedback:

Addressed

  1. DownloadFileStmt — Added to the nanoflow denylist. Good catch.
  2. Unreachable cases in getErrorHandling — Removed all 8 cases that are already denied and skipped via continue before reaching this function. Added a comment explaining the rationale.
  3. Perf: lookupNanoflowReturnType calling ListNanoflows() per invocation — Added lazy caching to both lookupNanoflowReturnType and lookupMicroflowReturnType in flowBuilder. Uses a bool loaded flag (not nil-check) so empty slices from the backend are cached correctly.
  4. Mock stubs — All 6 nanoflow mock methods now return fmt.Errorf("MockBackend.<Method> not configured") instead of silent nil, nil.
  5. CLAUDE.md — Added write-nanoflows.md to the skill table.
  6. docs-site — Added a Security section to nanoflows.md with cross-references to grant-revoke.md and document-access.md.
  7. Roundtrip test — Added TestRoundtripNanoflow_CallJavaScriptAction with a t.Skip guard if no JS actions exist in the test module.

AllowedModuleRoles — not a bug

I investigated this one carefully. AllowedModuleRoles uses model.ID as its type, but the values stored are actually qualified name strings like "MyModule.User" — not UUIDs. This is confirmed by:

  • mdl/catalog/builder_permissions.go:189 comment: role names stored as qualified strings
  • sdk/mpr/writer_security.go:124 doc: "roles should be qualified name strings like Module.RoleName"
  • Test data uses []model.ID{"MyModule.User"}

The string(r) cast in grant/revoke produces the correct qualified name. The type name is misleading but the behavior is correct.

Deferred

  • Error swallowing in lookup functions — Pre-existing pattern (microflows had the same issue). The cache actually improves it (errors hit once not repeatedly). A signature change to (type, error) would be a larger refactor — happy to do it as a follow-up if you'd like.
  • LSP snippet completions — Editor plugin work, separate PR scope.

All tests pass. Let me know if anything else needs attention!

@retran
Copy link
Copy Markdown
Contributor Author

retran commented Apr 29, 2026

Update: Also added the LSP snippet completions in a follow-up commit:

  • CREATE NANOFLOW (with params) — mirrors the existing microflow variant
  • CALL MICROFLOW, CALL NANOFLOW, CALL JAVASCRIPT ACTION, CALL JAVA ACTION — statement-level snippets for all call types

These show up in the general completion context for both microflow and nanoflow bodies.

@retran retran force-pushed the pr4-nanoflows-all branch from 8b6af58 to e7098cf Compare April 29, 2026 09:16
@retran
Copy link
Copy Markdown
Contributor Author

retran commented Apr 29, 2026

Manual QA Results — Nanoflow Feature Parity

Binary: mxcli v0.7.0-236-ge7098cf (rebased on latest main d783877).
Test projects: EnquiriesManagement (79 nanoflows), Evora-FactoryManagement (93), LatoProductInventory (51).

All sections pass — zero regressions

Section Scope Result
§1 SHOW Count verification, module filter, empty/non-existent module PASS
§2 DESCRIBE Simple + complex nanoflows, all 223 produce valid MDL PASS
§3 CREATE Minimal, 5 param types, with activities, create-or-modify, duplicate rejection PASS
§4 VALIDATION Java action rejected, DownloadFileStmt rejected (new), Binary return rejected, nested disallowed PASS
§5 DROP Existing + non-existent error PASS
§6 CALL Call nanoflow with args, call JS action PASS
§7-8 SECURITY Grant, idempotent grant, revoke, idempotent revoke, show access, non-existent role error PASS
§9 RENAME Simple rename verified in show PASS
§10 MOVE To existing module, non-existent module error PASS
§11 MERMAID Simple + complex (14 nodes), non-existent error PASS
§12 ROUNDTRIP 223/223 bulk describe. Full roundtrip: 13/79 exact, 66 with pre-existing parser diffs only PASS
§13 CATALOG select * from catalog.nanoflows, module filter, MicroflowType=NANOFLOW PASS
§15 MULTI-STEP Iterative create-or-modify (4 progressive modifications) PASS
§16 FAILURE Validation mid-batch: good→bad→good3 = fail-fast correct PASS
§17 SECURITY CASCADE Grant → modify body → access preserved PASS
§18 BOUNDARY 20 parameters, 4-level nesting, rapid create/drop ×10 PASS
§19 ELK Nanoflow + microflow ELK output, complex graph (14 nodes, 15 edges), non-existent error PASS

Roundtrip diff categories (all pre-existing, not from this PR)

  • on error rollback appended on re-create (default error handling)
  • Expression whitespace normalization
  • Anchor/position value changes
  • 6 nanoflows unparseable (negative literals, XPath brackets, embedded JSON)

Automated tests

  • go test ./...: 29 packages, 0 failures
  • go vet ./...: clean (except ANTLR-generated parser)

@retran
Copy link
Copy Markdown
Contributor Author

retran commented Apr 29, 2026

QA Session 5 — Parser Fixes Verified (c35c589)

Binary: v0.7.0-237-gc35c589 (rebased on latest main). 3 test projects: 223 nanoflows total.

Parser fixes — all 5 previously-unparseable nanoflows now pass

Nanoflow Root cause fixed Status
AgentCommons.Variable_FindInPrompt Negative literal -2 in lexer PASS
ApplicationCore.TaskInbox_Clear Multi-predicate XPath [a][b] PASS
WorkflowCommons.ACT_AuditTrailViewer_All Embedded JSON newlines in string PASS
WorkflowCommons.ACT_AuditTrailViewer_Minimal Embedded JSON newlines in string PASS
WorkflowCommons.SUB_AuditTrailViewer_Default if/else inside while loop body PASS

Full regression test — all sections pass

Section Result
§1 SHOW (counts, filters, edge cases) PASS
§2 DESCRIBE (simple, complex, all 223 valid MDL) PASS
§3-4 CREATE + VALIDATION (DownloadFileStmt denied, java action denied) PASS
§5-6 DROP + CALL PASS
§7-8 SECURITY (grant/revoke/show access, idempotent ops) PASS
§9-10 RENAME + MOVE PASS
§11 MERMAID (simple + complex 14 nodes) PASS
§12 ROUNDTRIP (222/223 bulk pass, 1 pre-existing) PASS
§13 CATALOG PASS
§15-18 Multi-step, failure, security cascade, boundary (20 params, 4-level nesting, rapid x10) PASS
§19 ELK (nanoflow + microflow regression check) PASS

Known pre-existing issue (not from this PR)

  • LatoBikesUI.ACT_Login: UseAuthToken = ) — empty JS action argument value in formatter

Automated

  • go test ./...: 29 packages, 0 failures
  • go vet ./...: clean (except ANTLR-generated parser)

retran added 3 commits April 29, 2026 13:32
- SHOW ACCESS ON NANOFLOW — query nanoflow security grants
- DESCRIBE MERMAID for nanoflows via CLI --format mermaid
- Nanoflow diff support — unified diff output for modified nanoflows
- JavaScript action BSON parsing (read path)
- NanoflowCallAction formatter for DESCRIBE output
- Hard-code nanoflow $Type to "Microflows$Nanoflow"
- Preserve AllowedModuleRoles through drop/recreate cycles
- Validate module existence, numeric return types, empty names
- Normalize empty-then branches in DESCRIBE for readable if/else
- Expression spacing fix (not() parenthesization)
retran added 12 commits April 29, 2026 13:32
- Document intentional behaviors in nanoflow test plan
- Add nanoflow references to ARCHITECTURE, CLAUDE, CHANGELOG
- Update MDL_FEATURE_MATRIX, MDL_QUICK_REFERENCE, language reference
- Add nanoflow examples to agentic skills (security, pages, validation)
- Add nanoflow MDL examples to doctype-tests
- Propagate describeNanoflow errors in diff command
- Match create-or-modify pattern in diff output
- Add nanoflow-specific fields (@excluded, folder, comment) to MDL output
- Guard empty-then swap edge case in if/else normalization
- Handle missing JS action references gracefully in formatter
- Harden negation expression rendering
…e fix

Full pipeline for `call javascript action` syntax:
- Grammar rule, AST node, visitor, builder, validator, BSON serializer
- JavaScript actions allowed in nanoflows (client-side), disallowed check
  skips them correctly
- Separate JS action reference validation from Java action validation

Association retrieve roundtrip fix:
- Preserve AssociationRetrieveSource on roundtrip instead of converting
  to DatabaseRetrieveSource with XPath for reverse traversals
…ixes

- Add Nanoflow Mapping section to BSON mapping documentation
- Add create_nanoflow Go example with 4 nanoflow patterns
- Update CHANGELOG with JS action syntax and association retrieve entries
- Add nanoflow datasource option to create-page skill
- Update SDK_EQUIVALENCE nanoflow feature list
- Exhaustive nanoflow denylist test (21 disallowed + JS action allowed)
- Document denylist ordering dependency in error handling
- Fix isNumericLiteral: reject trailing dot ("5." → false)
Add nanoflow visualization via --format elk. Backend: refactor
buildMicroflowELK into generic buildFlowELK with flowELKInput struct,
add nanoflowELK() + describeNanoflowToString(), parameterize
renderMicroflowMDL with flowType. Frontend: add nanoflow to diagram
context menus and preview title handling.

Fix swallowed ListDomainModels error in both microflowELK and
nanoflowELK.
- Propagate ListDomainModels error in describeNanoflowToString
- Use shared buildEntityNames() in both microflow and nanoflow ELK paths
- Remove Commit/Rollback from BSON mapping disallowed list (allowed by implementation)
- Fix example: add missing 'in' keyword in show nanoflows
- Fix proposal: CREATE OR REPLACE to CREATE OR MODIFY, correct nanoflow count
- Add clarifying comments for best-effort errors, Rollback default, BSON key asymmetry
…s, improve mocks/docs

- Add DownloadFileStmt to nanoflow denylist
- Remove unreachable cases from getErrorHandling
- Cache ListNanoflows/ListMicroflows in flowBuilder (bool flag for empty-slice safety)
- Mock nanoflow stubs return descriptive errors
- Add roundtrip test for CallJavaScriptAction (with t.Skip guard)
- Add write-nanoflows.md skill file + CLAUDE.md entry
- Add security cross-reference in docs-site nanoflows.md
- CREATE NANOFLOW (with params) snippet
- CALL MICROFLOW, CALL NANOFLOW, CALL JAVASCRIPT ACTION, CALL JAVA ACTION snippets
…cates, embedded JSON, if-in-loop

- Remove leading -? from NUMBER_LITERAL lexer rule; negation handled by unaryExpression
- Split multi-predicate XPath constraints at ][ boundaries in retrieve formatter
- Escape newlines inside string literal regions in expression values
- Add ExclusiveSplit handling to traverseLoopBody for if/else inside while/loop
….' placeholder

Empty parameter values (nil, empty string) in JavaScript and Java action
calls are now omitted from the argument list. Previously they were emitted
as 'Param = ...' which is not valid MDL syntax.

Fixes LatoBikesUI.ACT_Login (UseAuthToken with empty value).
@retran retran force-pushed the pr4-nanoflows-all branch from 135b741 to ae49ce7 Compare April 29, 2026 11:34
@retran
Copy link
Copy Markdown
Contributor Author

retran commented Apr 29, 2026

Full Manual QA Report — Session 6 (2026-04-29)

Branch: pr4-nanoflows-all (commit ae49ce7)
Build: v0.7.0-245-gae49ce7make build clean, go test ./... 29 packages 0 failures
Test projects: EnquiriesManagement (79), Evora-FactoryManagement (93), LatoProductInventory (51)
Scope: Full §1–§19 + roundtrip + exploratory
Delta from Session 5: Rebased on upstream/main (f5f893c, 5 new merged PRs), self-review fixes (nanoflow validation parity, fast-path lookup, code cleanup)

Results Summary

Section Area Tests Pass Fail
§1 SHOW NANOFLOWS 6 6 0
§2 DESCRIBE NANOFLOW 3 3 0
§3 CREATE NANOFLOW 5 5 0
§4 VALIDATION 3 3 0
§5 DROP 2 2 0
§6 CALL NANOFLOW 1 1 0
§7-8 SECURITY (grant/revoke/show) 7 7 0
§9 RENAME 1 1 0
§10 MOVE 2 2 0
§11 MERMAID 3 3 0
§12 ROUNDTRIP (describe→check) 223 223 0
§13 CATALOG 1 1 0
§15.4 ITERATIVE CREATE OR MODIFY 3 3 0
§16.1 FAILURE MID-BATCH 1 1 0
§17.6 SECURITY AFTER MODIFY 1 1 0
§18 BOUNDARY (20 params, deep nesting, rapid x10) 3 3 0
§19 ELK DIAGRAMS (nanoflow + microflow regression) 3 3 0

Totals: 268 tests executed, 268 pass, 0 failures.

Roundtrip Details

All 223 nanoflows across 3 projects pass describe → check:

  • ENQ: 79/79
  • Evora: 93/93
  • Lato: 51/51

Key Verifications Since Last Report

  • Rebase on upstream/main (f5f893c): no regressions from 5 newly merged PRs (import mapping result types, java action return type inference, void EndEvent return, reverse reference owner-both, change-action items storage)
  • Self-review fixes verified: nanoflow forward-reference detection (allNames), ValidateNanoflowBody parity with microflows, GetRawUnitByName fast-path lookup, doc comment fixes, workflow stmt consolidation
  • DownloadFileStmt denylist confirmed working (§4.2)
  • Empty JS/Java action params fix confirmed — 223/223 roundtrip (was 222/223 before fix)
  • 5 previously-unparseable nanoflows all pass (negative literals, XPath predicates, embedded JSON, if-in-loop)
  • Microflow ELK regression check: PASS

Known Issues (unchanged, pre-existing)

  • RT-2: Cosmetic roundtrip diffs on full describe→drop→create→describe cycle (anchor directions, whitespace normalization, on error rollback appended) — does NOT affect describe→check validation
  • golangci-lint Go version mismatch (tool built with 1.25, project targets 1.26)

…e flow body checks

- Add nanoflows to allNames() for forward-reference detection in validate
- Add ValidateNanoflowBody call for semantic checks (undeclared vars, missing returns)
- Extract shared validateFlowBody helper from ValidateMicroflowBody/ValidateNanoflowBody
- Add GetRawUnitByName fast-path to lookupNanoflowReturnType (mirrors microflow pattern)
- Collapse 11 individual workflow stmt cases into multi-type case in nanoflow denylist
- Fix doc comment on addTransformJsonAction (was copy-pasted from addExportToMappingAction)
@retran retran force-pushed the pr4-nanoflows-all branch from ae49ce7 to 3954e54 Compare April 29, 2026 11:51
@retran retran marked this pull request as ready for review April 29, 2026 11:53
@retran retran marked this pull request as draft April 29, 2026 11:53
@retran retran force-pushed the pr4-nanoflows-all branch from 373fc8b to 9ac9dbb Compare April 29, 2026 12:20
@github-actions
Copy link
Copy Markdown

AI Code Review

Review Summary

This PR implements full nanoflow support in mxcli, bringing it to parity with microflows across the entire stack. The changes are comprehensive and well-executed.

What Looks Good

  • Full pipeline coverage: Grammar → AST → visitor → executor → SDK → tests → docs → VS Code extension all properly updated
  • Comprehensive testing: 33 integration tests, 36 mock unit tests, 5 BSON roundtrip tests, plus extensive manual testing (268 tests across 3 demo projects with 223 nanoflows)
  • Proper MDL syntax: Follows CREATE/ALTER/DROP/SHOW/DESCRIBE patterns, uses qualified names, correct colon/AS usage, reads as English
  • Shared helpers: Extracted validateFlowBody, buildEntityNames, and flow ELK builders to eliminate duplication
  • LSP enhancements: Added snippet completions for nanoflow creation and calls
  • VS Code integration: Diagram previews, context menu parity, ELK JSON support
  • Security management: GRANT/REVOKE EXECUTE ON NANOFLOW with proper validation
  • Visualization: Mermaid and ELK diagram generation for nanoflows
  • Documentation: Updated skills, quick reference, language reference, BSON mapping, and changelog

Moderate Issues

  • Disallowed actions maintenance: The nanoflow validation lists 21 disallowed action types in nanoflow_validation.go via manual case branches. This creates a maintenance risk if Mendix adds new action types. Consider centralizing this list or deriving it from metamodel data.
  • Changelog wording: The "Nanoflow bug fixes" entry mentions MICROFLOWS in the nanoflow section (e.g., "Module existence validation for SHOW NANOFLOWS/MICROFLOWS"), which is slightly confusing though technically accurate since the fix benefits both.

Minor Issues

  • None identified beyond the moderate issues above.

Recommendation

Approve the PR. The implementation is thorough, follows all architectural guidelines, and includes proper testing and documentation. The maintenance concern about disallowed actions is common in such projects and doesn't block merging given the comprehensive test coverage that would catch regressions.

The PR successfully closes the nanoflow feature gap mentioned in the feature matrix and enables agentic workflows for nanoflow scaffolding, refactoring, and security management.


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

- Move JS action call and ELK layout from Future Work to Completed in proposal
- Fix stale action counts in proposal (25/32+ → actual ~16 case branches)
- Expand disallowed activities list in docs-site nanoflows.md (add DOWNLOAD FILE, REST, workflow, etc.)
- Add CALL JAVASCRIPT ACTION to docs-site calling examples
- Add CHANGELOG entries: LSP snippets, parser fixes, validation parity, DownloadFileStmt, flow cache, empty params
- Update feature matrix: nanoflow Tests column N → Y
- Document ValidateNanoflowBody/validateFlowBody and flow builder cache in parser architecture
- Add CALL JAVASCRIPT/JAVA ACTION and nanoflow restrictions to quick reference
- Update CLAUDE.md implementation status line
@retran retran force-pushed the pr4-nanoflows-all branch from 9ac9dbb to f914d3d Compare April 29, 2026 12:40
@retran
Copy link
Copy Markdown
Contributor Author

retran commented Apr 29, 2026

Addressing AI Review Moderate Issues

Disallowed actions maintenance

The denylist in nanoflow_validation.go already had a maintenance comment — expanded it with the case/type count (12 branches, 22 types) and a cross-reference to the test plan (docs/15-testing/nanoflow-test-cases.md §4.1) so both stay in sync when new action types are added.

An allowlist approach was considered but rejected: nanoflows share the microflow AST, and new action types should default to allowed (client-side) unless explicitly flagged as server-side-only. The denylist approach matches Mendix's own model where nanoflows are "microflows minus server-side actions."

Changelog wording

Renamed "Nanoflow bug fixes" → "Flow bug fixes" since the fixes (module validation, empty names, numeric returns) genuinely apply to both microflows and nanoflows. Expanded the slash notation to be clearer.

Documentation self-review

Ran 7 rounds of doc self-review (26 total findings fixed):

  • Corrected disallowed action lists across all docs (was listing RETRIEVE/COMMIT/DELETE as disallowed — they're allowed)
  • Standardized counts: 12 case branches, 22 action types, 11 workflow types
  • Standardized CREATE [OR MODIFY] keyword (was OR REPLACE in some places)
  • Fixed test case syntax (folder not in folder), added TransformJson test case
  • Updated feature matrix (Nanoflow Access Tests/Skills → Y, removed stale "Missing" entries)
  • Added nanoflow statements to EBNF grammar summary

@retran retran marked this pull request as ready for review April 29, 2026 14:32
@ako ako merged commit 475e4f1 into mendixlabs:main Apr 29, 2026
3 of 4 checks passed
@github-actions
Copy link
Copy Markdown

AI Code Review

Review Summary

After reviewing this PR against the CLAUDE.md checklist, I find it implements nanoflow support comprehensively while adhering to project guidelines. The changes span the full pipeline from grammar to VS Code extension with proper test coverage.

Critical Issues

  • None found

Moderate Issues

  • None found

Minor Issues

  • Maintenance risk: The PR mentions validation rejects 21 disallowed nanoflow action types via type-switch. This manually maintained list will require updates if Mendix changes nanoflow-capable actions. However, this follows existing patterns and is necessary for correctness.
  • Documentation inconsistency: In docs/05-mdl-specification/10-bson-mapping.md, the section title uses singular "Nanoflow Mapping" while content uses plural "Nanoflows" in descriptions. Minor but worth noting.

What Looks Good

  • Full pipeline coverage: Grammar → AST → Visitor → Executor → Backend → LSP → Docs → VS Code extension all properly updated
  • Syntax compliance: New MDL commands follow CREATE/ALTER/DROP/SHOW/DESCRIBE pattern, use qualified names (Module.Element), proper property format (Key: value), and correct colon/AS usage (colon for properties, AS for name mapping)
  • Infrastructure reuse: Smart extraction of shared helpers (validateFlowBody, buildEntityNames, serializeNanoflow) eliminating microflow/nanoflow duplication
  • Comprehensive testing: 33 integration tests, 36 mock unit tests, 5 BSON roundtrip tests, plus 126-test-case manual plan executed across 3 demo projects (268 tests, 0 failures)
  • Validation parity: Nano

Automated review via OpenRouter (Nemotron Super 120B) — workflow source

@retran retran deleted the pr4-nanoflows-all branch April 29, 2026 21:51
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.

2 participants