feat(mdl): USE BUILDING BLOCK v1 — instantiate an Atlas block onto a page - #19
Merged
Conversation
Mark the Building-Blocks proposal partial — READ (SHOW/DESCRIBE + CATALOG.building_blocks) shipped in PR #16/#17 and is validated live against a real Atlas app — and add the USE BUILDING BLOCK instantiate slice: - Syntax mirroring `use fragment` (`use building block Mod.Name [as prefix_]`), a page-body element sourced from a persisted Pages$BuildingBlock. - Deep-copy / no-live-link / prefix semantics. - The configuration decision: afterwards via `alter page` (v1), an optional inline override block (v1.1), a possible `over database …` data-context shortcut — and explicitly NOT implicit slot inference. - v1 implementation approach: reuse the fragment-expansion hook; convert the block's BSON widgets to []*ast.WidgetV3 by round-tripping through the DESCRIBE renderer + visitor.Build (verified re-parseable), not a hand-written converter. Also corrects the doc's stale storage-type (Pages$BuildingBlock) and refreshes the proposals README index. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
Instantiate an out-of-the-box Atlas building block onto a page in one line,
instead of hand-mirroring its DESCRIBE output. Mirrors `use fragment`:
use building block Atlas_Web_Content.Card
use building block Atlas_Web_Content.Card as cust_
It's a page-body element (valid anywhere `use fragment` is), sourced from a
persisted Pages$BuildingBlock rather than a script-scoped `define fragment`. v1
is deep-copy only (+ optional `as <prefix>` rename); configure the copied widgets
afterwards with `alter page` (inline config is the v1.1 slice in the proposal).
Wiring mirrors use fragment: a `useBuildingBlockRef` grammar rule → a
USE_BUILDING_BLOCK sentinel WidgetV3 in the visitor → expansion in the same
expandIfFragment hook. The block's BSON widgets are turned into []*ast.WidgetV3
by round-tripping through the DESCRIBE renderer (render → `define fragment`
wrapper → visitor.Build → .Widgets) rather than a hand-written BSON→AST
converter, so it reuses the full widget parser and degrades to a clear parse
error. The prefix rename reuses prefixWidgetNames.
Verified end-to-end against the real Atlas_Web_Content.Card on a live 11.12.1
project: the container + dynamictext deep-copy with the cust_ prefix, preserving
the card-title class and the 'Card style' design property. Unit tests
(mock-backend) cover prefix/no-prefix/not-found and the parse.
Notes: requires MXCLI_ENGINE=legacy until the modelsdk ListBuildingBlocks lands
(PR #17). Compound/nested design-property values (e.g. Spacing: [...]) are a
pre-existing create-page writer gap (they drop on direct authoring too), out of
scope here.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
ako
pushed a commit
that referenced
this pull request
Jul 24, 2026
…rimary path Now that USE BUILDING BLOCK v1 exists, the skill leads with the one-line instantiation instead of the hand-mirror workaround: - Workflow renamed discover → inspect → USE (was → mirror). Step 3 is now `use building block Mod.Name [as prefix_]` (deep-copy), step 4 configures the copied widgets with `alter page`. Mirroring is reframed as the explicit fallback (hand-tuning, or the modelsdk engine before its building-block support lands). - Capability table: Instantiate → ✅ v1 (deep-copy; configure afterwards; legacy engine today). Capability note updated to "discovery AND instantiation both work". - Validation checklist updated to prefer `use building block` + `alter page`. All `use building block` / `alter page` examples are bare page-body lines, which the skill-MDL checker auto-skips (first keyword not in its create/alter/drop entity|page checkable set) — verified with a binary built WITHOUT the grammar, so this PR's CI is green even before the USE BUILDING BLOCK feature (#19) merges. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
ako
pushed a commit
that referenced
this pull request
Jul 28, 2026
Ledger findings #17–19: a `set $x = <expr>` value re-serialized from the AST silently corrupted the stored Mendix expression — `mxcli check` passed, `mx check` gave only a generic CE0117: - #17 a division's right operand lost its `$` (`$a / $b` → `$a/b`) - #18 a decimal literal lost its fraction (`2.0` → `2`), breaking Decimal - #19 a small decimal became scientific notation (`0.000001` → `1e-06`) shouldPreserveExpressionSource now keeps the raw source whenever the expression contains a `/` or a decimal literal (a `.` adjacent to a digit), mirroring the existing XPath-where handling — so the exact text survives instead of a lossy AST round-trip. (MDL division is `div`; `/` is the member-access separator, which is what caused the `$`-loss mis-parse — preserving source is the robust fix either way.) Test: TestShouldPreserveExpressionSource_DivisionAndDecimals; repro mdl-examples/bug-tests/ledger-17-19-expression-serialization.mdl. Symptom table updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
ako
pushed a commit
that referenced
this pull request
Jul 28, 2026
…ecimals Corrects the earlier ledger #17-19 fix, which over-broadly preserved raw expression source whenever it saw a '/'. In MDL '/' is the member-access separator (`$obj/Attr`), not division (that is `div`), so preserving on '/' source-froze every association-navigation path and regressed TestAssociationNavParsing. - shouldPreserveExpressionSource: drop the '/' trigger; keep the decimal-literal trigger (findings #18/#19 — `2.0`->`2`, `0.000001`->`1e-06` are genuine AST-serializer losses that raw-source preservation fixes). - New MDL045: walk the microflow expression tree for a BinaryExpr with operator '/' (`$Dec / 2`, `(...) / $x`) and reject with an actionable "use div" message, instead of silently writing an invalid expression that fails the build (CE0117). The bare `$a / $b` form degrades to a member path and is caught by `check --references`. Tests: TestShouldPreserveExpressionSource_Decimals (renamed), TestValidateMicroflow_SlashDivision. Repros: ledger-17-19 (passes) + ledger-17-slash-division.fail.mdl (MDL045). Skill + symptom-table updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
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.
Implements v1 of
USE BUILDING BLOCK— the INSTANTIATE capability from the Building-Blocks proposal, and the biggest lever for theatlas-designskill. It turns the skill's "discover → inspect → mirror" workflow into "discover → use".Also adds the
USE BUILDING BLOCKfollow-up slice toshow-describe-building-blocks.md(and marks READ as shipped).What it does
Deep-copies an out-of-the-box Atlas building block onto a page in one line, instead of hand-copying its
DESCRIBEoutput:It's a page-body element (valid anywhere
use fragmentis), sourced from a persistedPages$BuildingBlock. v1 = deep-copy only (+ optionalas <prefix>); you configure the copied widgets afterwards with the shippedalter pagecommands. (Inline configuration is the v1.1 slice in the proposal — never implicit slots.)How (reuses the fragment machinery)
useBuildingBlockRefrule (USE BUILDING BLOCK qualifiedName (AS ident)?), wired everywhereuseFragmentRefis a page-body alternative. (BUILDING/BLOCKtokens already existed from READ.)USE_BUILDING_BLOCKsentinelWidgetV3, mirroringbuildUseFragmentRef.expandIfFragmenthook. The one hard part — turning the block's persisted BSON widgets into[]*ast.WidgetV3— is solved by round-tripping through the DESCRIBE renderer (render →define fragment __tmpwrapper →visitor.Build→.Widgets), so it reuses the entire existing widget parser and degrades to a clear parse error rather than a fragile hand-written converter. Prefix rename reusesprefixWidgetNames.Verification
Atlas_Web_Content.Cardon a live Mendix 11.12.1 project:use building block Atlas_Web_Content.Card as cust_→ thecontainer+dynamictextdeep-copy with thecust_prefix, preserving thecard-titleclass and the'Card style'design property.make grammar+go build ./...+go vet+gofmtclean;mdl/executor+mdl/visitorsuites green.Notes / follow-ups
MXCLI_ENGINE=legacytoday. modelsdk support arrives with theListBuildingBlocksimpl in fix(building-blocks): modelsdk ListBuildingBlocks + exec-safe doctype example #17 (same method both call) — no extra work here.Spacing: ['margin-bottom': 'L']) currently drop — verified to be a pre-existing create-page BSON-writer gap (they drop on direct authoring too, andDESCRIBE/expansion both handle them faithfully), so it's out of scope for this PR. Simple toggle properties (Card style: on) round-trip fine.🤖 Generated with Claude Code
https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
Generated by Claude Code