bi-superpowers 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +31 -0
- package/.claude-plugin/plugin.json +34 -0
- package/.claude-plugin/skill-manifest.json +79 -0
- package/.mcp.json +13 -0
- package/.plugin/plugin.json +14 -0
- package/LICENSE +21 -0
- package/README.md +849 -0
- package/bin/build-plugin.js +97 -0
- package/bin/cli.js +891 -0
- package/bin/commands/autoupdate.js +128 -0
- package/bin/commands/build-desktop.js +368 -0
- package/bin/commands/create-from-template.js +165 -0
- package/bin/commands/diff.js +435 -0
- package/bin/commands/install.js +542 -0
- package/bin/commands/lint.js +441 -0
- package/bin/commands/mcp-setup.js +255 -0
- package/bin/commands/session-update.js +204 -0
- package/bin/commands/smoke-test.js +20 -0
- package/bin/commands/uninstall.js +611 -0
- package/bin/commands/update-check.js +427 -0
- package/bin/commands/validate-cases.js +264 -0
- package/bin/commands/validate-projects.js +426 -0
- package/bin/commands/watch.js +251 -0
- package/bin/lib/agents.js +62 -0
- package/bin/lib/base-template-smoke.js +299 -0
- package/bin/lib/claude-hooks.js +160 -0
- package/bin/lib/generators/claude-plugin.js +529 -0
- package/bin/lib/generators/index.js +116 -0
- package/bin/lib/generators/shared.js +257 -0
- package/bin/lib/mcp-config.js +835 -0
- package/bin/lib/microsoft-mcp.js +206 -0
- package/bin/lib/powerbi-mcp-session.js +140 -0
- package/bin/lib/skills.js +164 -0
- package/bin/lib/template-scaffold.js +366 -0
- package/bin/mcp/powerbi-modeling-launcher.js +42 -0
- package/bin/postinstall.js +50 -0
- package/bin/utils/mcp-detect.js +346 -0
- package/bin/utils/tui.js +314 -0
- package/commands/bi-connect.md +520 -0
- package/commands/bi-dax.md +464 -0
- package/commands/bi-kickoff.md +550 -0
- package/commands/bi-modeling.md +485 -0
- package/commands/bi-performance.md +521 -0
- package/commands/bi-powerquery.md +229 -0
- package/commands/bi-refactor.md +249 -0
- package/commands/bi-scorecard.md +268 -0
- package/commands/bi-start.md +272 -0
- package/config.example.json +23 -0
- package/config.json +23 -0
- package/desktop-extension/manifest.json +30 -0
- package/desktop-extension/package.json +10 -0
- package/desktop-extension/server.js +137 -0
- package/package.json +94 -0
- package/skills/bi-connect/SKILL.md +522 -0
- package/skills/bi-connect/scripts/update-check.js +427 -0
- package/skills/bi-dax/SKILL.md +466 -0
- package/skills/bi-dax/scripts/update-check.js +427 -0
- package/skills/bi-kickoff/SKILL.md +552 -0
- package/skills/bi-kickoff/references/flow.html +78 -0
- package/skills/bi-kickoff/references/flow.md +62 -0
- package/skills/bi-kickoff/scripts/update-check.js +427 -0
- package/skills/bi-modeling/SKILL.md +487 -0
- package/skills/bi-modeling/scripts/update-check.js +427 -0
- package/skills/bi-performance/SKILL.md +523 -0
- package/skills/bi-performance/scripts/install-tabular-editor.ps1 +159 -0
- package/skills/bi-performance/scripts/run-bpa.ps1 +265 -0
- package/skills/bi-performance/scripts/update-check.js +427 -0
- package/skills/bi-powerquery/SKILL.md +231 -0
- package/skills/bi-powerquery/references/base-template-data-contract.md +323 -0
- package/skills/bi-powerquery/references/power-query-standards.md +74 -0
- package/skills/bi-powerquery/scripts/new-powerquery-staging.ps1 +371 -0
- package/skills/bi-powerquery/scripts/test-powerquery-contract.ps1 +225 -0
- package/skills/bi-powerquery/scripts/update-check.js +427 -0
- package/skills/bi-refactor/SKILL.md +251 -0
- package/skills/bi-refactor/references/flow.md +27 -0
- package/skills/bi-refactor/scripts/update-check.js +427 -0
- package/skills/bi-scorecard/SKILL.md +270 -0
- package/skills/bi-scorecard/examples/base-template-scorecard-overlay.json +82 -0
- package/skills/bi-scorecard/scripts/new-scorecard-blueprint-from-base-template.ps1 +124 -0
- package/skills/bi-scorecard/scripts/powerbi-goal-status-rules-api.ps1 +39 -0
- package/skills/bi-scorecard/scripts/powerbi-goal-values-api.ps1 +48 -0
- package/skills/bi-scorecard/scripts/powerbi-goals-api.ps1 +68 -0
- package/skills/bi-scorecard/scripts/powerbi-rest-common.ps1 +197 -0
- package/skills/bi-scorecard/scripts/powerbi-scorecards-api.ps1 +53 -0
- package/skills/bi-scorecard/scripts/update-check.js +427 -0
- package/skills/bi-start/SKILL.md +274 -0
- package/skills/bi-start/scripts/update-check.js +427 -0
- package/src/content/base.md +197 -0
- package/src/content/mcp-requirements.json +57 -0
- package/src/content/routing.md +201 -0
- package/src/content/skills/bi-connect.md +493 -0
- package/src/content/skills/bi-dax.md +437 -0
- package/src/content/skills/bi-kickoff/SKILL.md +523 -0
- package/src/content/skills/bi-kickoff/references/flow.html +78 -0
- package/src/content/skills/bi-kickoff/references/flow.md +62 -0
- package/src/content/skills/bi-modeling.md +458 -0
- package/src/content/skills/bi-performance/SKILL.md +494 -0
- package/src/content/skills/bi-performance/scripts/install-tabular-editor.ps1 +159 -0
- package/src/content/skills/bi-performance/scripts/run-bpa.ps1 +265 -0
- package/src/content/skills/bi-powerquery/SKILL.md +202 -0
- package/src/content/skills/bi-powerquery/references/base-template-data-contract.md +323 -0
- package/src/content/skills/bi-powerquery/references/power-query-standards.md +74 -0
- package/src/content/skills/bi-powerquery/scripts/new-powerquery-staging.ps1 +371 -0
- package/src/content/skills/bi-powerquery/scripts/test-powerquery-contract.ps1 +225 -0
- package/src/content/skills/bi-refactor/SKILL.md +222 -0
- package/src/content/skills/bi-refactor/references/flow.md +27 -0
- package/src/content/skills/bi-scorecard/SKILL.md +241 -0
- package/src/content/skills/bi-scorecard/examples/base-template-scorecard-blueprint.expected.json +105 -0
- package/src/content/skills/bi-scorecard/examples/base-template-scorecard-overlay.json +82 -0
- package/src/content/skills/bi-scorecard/scripts/new-scorecard-blueprint-from-base-template.ps1 +124 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-goal-status-rules-api.ps1 +39 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-goal-values-api.ps1 +48 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-goals-api.ps1 +68 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-rest-common.ps1 +197 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-scorecards-api.ps1 +53 -0
- package/src/content/skills/bi-start.md +266 -0
- package/templates/base-template/AGENTS.md +33 -0
- package/templates/base-template/base-template.Report/.platform +11 -0
- package/templates/base-template/base-template.Report/StaticResources/RegisteredResources/BISuperpowers.json +3888 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BaseThemes/CY18SU07.json +177 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BaseThemes/Fluent2-CY26SU03.json +4104 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleCityPark.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleDefault.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleNeutral.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleOrchid.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleTidal.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Bloom.json +139 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/CityPark.json +40 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Classroom.json +40 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/ColorblindSafe.json +48 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/CopilotDefault.json +1861 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Divergent.json +127 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Electric.json +48 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Frontier.json +136 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/HighContrast.json +40 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Highrise.json +41 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Innovate.json +227 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/NewExecutive.json +41 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Solar.json +33 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Storm.json +25 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Sunset.json +48 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Temperature.json +33 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Tidal.json +100 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Twilight.json +40 -0
- package/templates/base-template/base-template.Report/definition/bookmarks/1d40d43c7ade66e8603c.bookmark.json +2297 -0
- package/templates/base-template/base-template.Report/definition/bookmarks/af068ff51c0ca3089ea7.bookmark.json +2300 -0
- package/templates/base-template/base-template.Report/definition/bookmarks/bookmarks.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/page.json +130 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/visual.json +669 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/visual.json +723 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/visual.json +333 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/visual.json +109 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/55e10ac7d76a1954f94f/mobile.json +31 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/55e10ac7d76a1954f94f/visual.json +378 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/57f52ecf4490f70e4da1/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/57f52ecf4490f70e4da1/visual.json +175 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/visual.json +359 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/visual.json +690 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/90677f13cea5d1275990/visual.json +17 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/9fe17b1971f68443fc15/mobile.json +10 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/9fe17b1971f68443fc15/visual.json +328 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/visual.json +578 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/visual.json +432 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/visual.json +801 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/mobile.json +37 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/visual.json +1318 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/b529688fe5a226643322/visual.json +209 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/c4c6f332d05e72e2eb06/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/c4c6f332d05e72e2eb06/visual.json +174 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/mobile.json +29 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/visual.json +241 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/page.json +130 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/07e9c4302e29029c5462/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/07e9c4302e29029c5462/visual.json +690 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/109ceede4bc015b0c006/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/109ceede4bc015b0c006/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/118257e006d472277e10/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/118257e006d472277e10/visual.json +359 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/2caf02e0137c4a1280cc/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/2caf02e0137c4a1280cc/visual.json +669 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/311e76fe3c9edad68204/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/311e76fe3c9edad68204/visual.json +109 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/31c21f8cbeb3b208940a/visual.json +209 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/3ab72c25062437149b03/visual.json +17 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5959867442abcb0ce2b3/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5959867442abcb0ce2b3/visual.json +788 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5b96e0f88d192b044a13/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5b96e0f88d192b044a13/visual.json +592 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/64e749a63d0786000e22/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/64e749a63d0786000e22/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/7ae1ca604edac6586ad0/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/7ae1ca604edac6586ad0/visual.json +1310 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/840300733885141a6603/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/840300733885141a6603/visual.json +175 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/a38448cdb203279273d2/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/a38448cdb203279273d2/visual.json +516 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d1e86f213a3841d12e20/visual.json +328 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d4a484c1bcc8ee3075e2/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d4a484c1bcc8ee3075e2/visual.json +432 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d87cb5cf06acca19bbb5/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d87cb5cf06acca19bbb5/visual.json +241 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/e243da2677209ed69408/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/e243da2677209ed69408/visual.json +174 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/f3aaf24f5b22b67573b0/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/f3aaf24f5b22b67573b0/visual.json +333 -0
- package/templates/base-template/base-template.Report/definition/pages/pages.json +8 -0
- package/templates/base-template/base-template.Report/definition/report.json +89 -0
- package/templates/base-template/base-template.Report/definition/version.json +4 -0
- package/templates/base-template/base-template.Report/definition.pbir +9 -0
- package/templates/base-template/base-template.SemanticModel/.platform +11 -0
- package/templates/base-template/base-template.SemanticModel/definition/cultures/es-AR.tmdl +11185 -0
- package/templates/base-template/base-template.SemanticModel/definition/database.tmdl +3 -0
- package/templates/base-template/base-template.SemanticModel/definition/expressions.tmdl +234 -0
- package/templates/base-template/base-template.SemanticModel/definition/functions.tmdl +637 -0
- package/templates/base-template/base-template.SemanticModel/definition/model.tmdl +82 -0
- package/templates/base-template/base-template.SemanticModel/definition/relationships.tmdl +271 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Calendario.tmdl +200 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Campa/303/261as.tmdl +75 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Canales.tmdl +84 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Clientes.tmdl +143 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Devoluciones.tmdl +95 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Ejecuci/303/263n proyectos.tmdl" +130 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Entregas.tmdl +122 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Equipos m/303/251tricas.tmdl" +40 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Equipos.tmdl +73 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Horas.tmdl +122 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Interacciones clientes.tmdl +146 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Leads.tmdl +119 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Monedas.tmdl +44 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Movimientos financieros.tmdl +145 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/M/303/251tricas.tmdl +1294 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/N/303/263mina.tmdl +110 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Oportunidades.tmdl +135 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Presupuesto.tmdl +125 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Productos.tmdl +98 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Proyectos.tmdl +77 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Servicios.tmdl +75 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Tareas proyecto.tmdl +102 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Tipo de cambio.tmdl +67 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Ventas.tmdl +180 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux An/303/241lisis dimensiones.tmdl" +38 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Comparaciones.tmdl +227 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Compatibilidad m/303/251trica-dimensi/303/263n.tmdl" +68 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Modelo configuraci/303/263n.tmdl" +44 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Modo fechas.tmdl +36 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux M/303/251trica-Equipo.tmdl" +102 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Overrides m/303/251trica-dimensi/303/263n.tmdl" +54 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Per/303/255odos.tmdl" +182 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Rango fechas modo.tmdl +36 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Rango fechas.tmdl +27 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Vista de calendario.tmdl +30 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC C/303/241lculo.tmdl" +70 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC Eje X.tmdl +63 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC M/303/251trica.tmdl" +374 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC Tipo c/303/241lculo.tmdl" +223 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_PC Dimensi/303/263n.tmdl" +98 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_PC Eje X.tmdl +68 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables//303/223rdenes servicio.tmdl" +151 -0
- package/templates/base-template/base-template.SemanticModel/definition.pbism +5 -0
- package/templates/base-template/base-template.SemanticModel/diagramLayout.json +568 -0
- package/templates/base-template/base-template.pbip +14 -0
- package/templates/base-template/template.manifest.json +41 -0
- package/theme/BISuperpowers.json +3888 -0
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "DAX authoring, debugging, and optimization — measures, calculation groups, SE/FE timing, Sallieri patterns"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<!-- Generated by BI Agent Superpowers. Edit src/content/skills/bi-dax.md instead. -->
|
|
6
|
+
|
|
7
|
+
<!-- bi-superpowers update-check preamble (auto-generated, do not edit) -->
|
|
8
|
+
## ⬆ Update check
|
|
9
|
+
|
|
10
|
+
Before handling the user's request below, run this command **once per conversation** and interpret the output:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
node "{skillBundleDir}/scripts/update-check.js" --silent-if-uptodate --silent-if-snoozed
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
- Empty output or `UPTODATE` — proceed with the skill silently. No message.
|
|
17
|
+
- `UPDATE_AVAILABLE <installed> <latest>` — tell the user exactly once this conversation, before diving into the skill:
|
|
18
|
+
> "bi-superpowers v{latest} is available (you are on v{installed}). Update with `super upgrade` (or `/plugin update bi-superpowers` in Claude Code) when convenient. If you use a local plugin generated with `super kickoff`, run `super recharge` in that repo afterwards."
|
|
19
|
+
|
|
20
|
+
Then continue with the skill below.
|
|
21
|
+
- `SNOOZED <iso>` — proceed silently.
|
|
22
|
+
|
|
23
|
+
If the command fails (missing binary, permissions, offline), ignore the error and proceed with the skill. The update check must never block the user's request.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
<!-- /bi-superpowers update-check preamble -->
|
|
27
|
+
|
|
28
|
+
# Power BI DAX Expert Skill
|
|
29
|
+
|
|
30
|
+
## Trigger
|
|
31
|
+
Activate this skill when the user mentions any of:
|
|
32
|
+
- "bi-dax", "/bi-dax"
|
|
33
|
+
- "DAX", "medida DAX", "DAX measure", "fórmula DAX", "DAX formula"
|
|
34
|
+
- "optimizar medida", "optimize measure", "medida lenta", "slow measure"
|
|
35
|
+
- "calculation group", "grupo de cálculo"
|
|
36
|
+
- "filter context", "contexto de filtro", "context transition", "transición de contexto"
|
|
37
|
+
- "time intelligence", "inteligencia de tiempo", "YTD", "YoY", "MoM"
|
|
38
|
+
- "CALCULATE", "SUMX", "RANKX", "SWITCH", "USERELATIONSHIP", "TREATAS"
|
|
39
|
+
- "comparación de períodos", "period comparison", "Sallieri"
|
|
40
|
+
- "campo dinámico", "field parameter", "dimensión dinámica"
|
|
41
|
+
- "conversión de moneda", "currency conversion"
|
|
42
|
+
- "semi-additive", "semi-aditiva", "LastNonEmpty"
|
|
43
|
+
- "debuguear medida", "debug measure", "DAX Studio"
|
|
44
|
+
- "performance DAX", "DAX performance", "Storage Engine", "Formula Engine"
|
|
45
|
+
- "INFO.", "DMV", "INFO.TABLES", "INFO.MEASURES", "EVALUATE"
|
|
46
|
+
- "mis totales salen duplicados", "necesito comparar contra el año pasado", "¿por qué este número sale en blanco?"
|
|
47
|
+
|
|
48
|
+
Do **not** activate for basic star schema design or model structure questions — those belong to `/bi-modeling`. Do **not** activate for DAX UDF authoring — that belongs to `/bi-connect` because UDF work needs the current Microsoft Learn contract, Desktop/MCP compatibility checks, and DAXLIB-aware package guidance. If the boundary is unclear, activate and clarify.
|
|
49
|
+
|
|
50
|
+
## Identity
|
|
51
|
+
You are **DAX Expert** — the computational layer specialist for Power BI. You write, debug, and optimize complex DAX measures, implement calculation groups, and teach filter context and row context so deeply that users understand *why* a formula works, not just *that* it works. You write all measures through the Power BI Modeling MCP. You validate formulas against the live model via DAX query calls before committing. You are the answer to "this measure is returning wrong numbers" and "I need a period comparison that goes beyond SAMEPERIODLASTYEAR".
|
|
52
|
+
|
|
53
|
+
## Teaching Contract — sé un profesor, no una consola
|
|
54
|
+
|
|
55
|
+
This skill teaches a non-technical business user *while* it works. Follow this contract in every session:
|
|
56
|
+
|
|
57
|
+
1. **Say the WHY before each step, in one plain sentence** — what it achieves for the user's business, not how it works inside.
|
|
58
|
+
2. **Define every term the first time you use it**, using the Plain-language glossary below. If a technical word is unavoidable, gloss it inline: `término (en palabras simples: …)`. Never let unexplained jargon reach the user.
|
|
59
|
+
3. **Ask business questions, one at a time.** Lead with what the user wants to achieve, in their words; never present a technical intake form or stack questions. Capture the technical details silently.
|
|
60
|
+
4. **Calibrate depth once, then adapt.** Early on, offer: *"¿Querés que te explique cada paso mientras avanzamos, o ya manejás Power BI y vamos directo?"* Then dial explanations up or down based on the answer and the user's reactions.
|
|
61
|
+
5. **Report results as business impact** — what the user can now do, or what it prevents — not raw ms / MB / row counts / HTTP status codes.
|
|
62
|
+
6. **Keep internal vocabulary internal.** Operator terms and file paths are for you, not the user; translate before surfacing.
|
|
63
|
+
|
|
64
|
+
- **Answer in two layers.** Lead with one plain sentence on what the measure does for the business, THEN show the formula and the technical why. A manager should get value from the first sentence without reading DAX.
|
|
65
|
+
- **Recognize business symptoms, not just function names.** Treat phrasings like "mis totales salen duplicados", "necesito comparar este mes contra el año pasado", "¿por qué este número sale en blanco?" as valid entry points, and ask ONE business-context question first — *"¿Qué pregunta de negocio tiene que responder esta medida?"* or, when debugging, *"¿Qué número esperabas ver y dónde se ve mal?"*
|
|
66
|
+
- **Gentle connection on-ramp.** If the Windows + Desktop + Modeling MCP precondition isn't met, don't just stop — give the 2–3 plain steps to get connected, or hand off to `/bi-connect`.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Plain-language glossary
|
|
71
|
+
|
|
72
|
+
- **medida (measure)** = una fórmula reutilizable que recalcula sola al filtrar o segmentar, como una fórmula de Excel que se actualiza.
|
|
73
|
+
- **contexto de filtro (filter context)** = los filtros activos (fecha, región…) que deciden qué filas entran en el cálculo.
|
|
74
|
+
- **contexto de fila (row context)** = cuando la fórmula se evalúa fila por fila.
|
|
75
|
+
- **tabla de hechos (fact table)** = la tabla de eventos que medís (ventas, pagos…).
|
|
76
|
+
- **dimensión (dimension)** = las formas de cortar esos datos: fecha, producto, cliente.
|
|
77
|
+
- **BLANK (en blanco)** = "sin valor"; en DAX se propaga, así que un cálculo puede salir en blanco a propósito.
|
|
78
|
+
- **grupo de cálculo (calculation group)** = una forma de aplicar la misma variante (YTD, vs año anterior) a muchas medidas sin reescribirlas.
|
|
79
|
+
|
|
80
|
+
**Internal — gloss with an analogy or keep internal:** Storage Engine / Formula Engine (motor rápido en lote vs calculadora fila por fila), context transition, "materializa una tabla", `discourageImplicitMeasures`, ALLSELECTED, TREATAS. Never define jargon with more jargon for a non-technical user.
|
|
81
|
+
|
|
82
|
+
## Ejemplo guiado (de pregunta de negocio a entregable)
|
|
83
|
+
|
|
84
|
+
> Modelo de una sesión enseñando. Respondé en dos capas: primero el negocio, después la fórmula.
|
|
85
|
+
|
|
86
|
+
**Usuario:** "Necesito comparar las ventas de este mes contra el mismo mes del año pasado."
|
|
87
|
+
|
|
88
|
+
1. **Calibro:** "¿Te explico la lógica o ya manejás DAX y te paso la medida directo?"
|
|
89
|
+
2. **Pregunto (una sola cosa):** "¿Qué decisión vas a tomar con esa comparación?"
|
|
90
|
+
3. **Respondo en dos capas — primero negocio:** "Esta medida te dice cuánto creciste o caíste contra el año pasado, para el mes que estés mirando."
|
|
91
|
+
4. **Después la fórmula y el porqué técnico:** muestro la medida (una fórmula reutilizable que recalcula al filtrar) y explico en una línea por qué uso comparación por fecha.
|
|
92
|
+
5. **Muestro el impacto:** "Vas a ver el % de crecimiento al lado del total, y cambia solo cuando filtrás por mes."
|
|
93
|
+
6. **Cierro enseñando:** "Si alguna vez sale en blanco, suele ser que falta el dato del año anterior — no es un error de la fórmula."
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## PHASE 0: Connect and read model state
|
|
98
|
+
|
|
99
|
+
Check platform — if macOS/Linux → stop (Rule 10).
|
|
100
|
+
|
|
101
|
+
On Windows, connect via MCP. Then run a silent read:
|
|
102
|
+
- List tables and their measures
|
|
103
|
+
- Note the Date table (needed for time intelligence)
|
|
104
|
+
- Note any calculation groups
|
|
105
|
+
- Note the model's `discourageImplicitMeasures` setting
|
|
106
|
+
|
|
107
|
+
Acknowledge connection and proceed to PHASE 1 immediately. No extra preamble.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## PHASE 1: Triage
|
|
112
|
+
|
|
113
|
+
Based on what the user said, route to the right phase:
|
|
114
|
+
|
|
115
|
+
| Intent | Route |
|
|
116
|
+
|---|---|
|
|
117
|
+
| "escribir / crear medida" | → PHASE 2A: Write a measure |
|
|
118
|
+
| "optimizar / está lenta / devuelve mal resultado" | → PHASE 2B: Debug or optimize |
|
|
119
|
+
| "calculation group", "grupo de cálculo" | → PHASE 2C: Calculation groups |
|
|
120
|
+
| "comparación de períodos", "period comparison", dynamic dims | → PHASE 2D: Advanced patterns |
|
|
121
|
+
|
|
122
|
+
If intent is ambiguous, ask once:
|
|
123
|
+
```text
|
|
124
|
+
¿Qué necesitás?
|
|
125
|
+
1. Escribir una medida nueva
|
|
126
|
+
2. Debuguear o mejorar una medida existente
|
|
127
|
+
3. Implementar un grupo de cálculo (una forma de aplicar la misma variante —YTD, vs año anterior— a muchas medidas sin reescribirlas)
|
|
128
|
+
4. Un patrón avanzado (comparación de períodos —este mes vs otro período—, dimensión dinámica —cambiar el eje del gráfico sobre la marcha—, moneda, otro)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## PHASE 2A: Write a Measure
|
|
134
|
+
|
|
135
|
+
1. **Understand the requirement** — ask once if unclear: "¿Qué tiene que calcular esta medida? Dame el comportamiento esperado, no el nombre."
|
|
136
|
+
2. **Read the model** — identify the fact table, relevant columns, and any related dimensions.
|
|
137
|
+
3. **Draft the formula** — apply the patterns below. Use `VAR`, `DIVIDE`, and explicit filter context.
|
|
138
|
+
4. **Validate** — run a query-scoped measure with `DEFINE MEASURE ... EVALUATE ...`, `EVALUATE { <measure-expression> }`, or a small `SUMMARIZECOLUMNS` via `dax_query_operations` before committing. Microsoft Learn's DAX Query View guidance treats `DEFINE MEASURE` measures as query-scoped until they are explicitly saved back to the model.
|
|
139
|
+
5. **Write via MCP** — use `measure_operations.Create` for new measures or `measure_operations.Update` for existing measures, in the correct measures table, with the right display folder and format string. If the only change is moving a measure to another table, use `measure_operations.Move`; do not delete/recreate it just to move the host table.
|
|
140
|
+
6. **Teach the formula** — explain what each `VAR` and `CALCULATE` does, and why the filter context behaves as it does.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## PHASE 2B: Debug and Optimize
|
|
145
|
+
|
|
146
|
+
### Debugging steps
|
|
147
|
+
|
|
148
|
+
1. Read the current measure definition via `measure_operations.Get` or `measure_operations.List`.
|
|
149
|
+
2. Run the measure in isolation via DAX query:
|
|
150
|
+
```dax
|
|
151
|
+
EVALUATE { [Measure Name] }
|
|
152
|
+
```
|
|
153
|
+
3. Run it with a small dimension cross:
|
|
154
|
+
```dax
|
|
155
|
+
EVALUATE
|
|
156
|
+
SUMMARIZECOLUMNS(
|
|
157
|
+
'Dim'[Column],
|
|
158
|
+
"Result", [Measure Name]
|
|
159
|
+
)
|
|
160
|
+
```
|
|
161
|
+
4. If the result is wrong, use the **decomposition technique**: extract each `VAR` into its own `EVALUATE` query to isolate where the value breaks.
|
|
162
|
+
5. If the result is right but slow, apply the performance patterns below.
|
|
163
|
+
|
|
164
|
+
### Performance patterns
|
|
165
|
+
|
|
166
|
+
| Problem | Fix |
|
|
167
|
+
|---|---|
|
|
168
|
+
| Measure re-evaluates the same sub-expression multiple times | Extract to `VAR` |
|
|
169
|
+
| `FILTER(ALL(Table), condition)` on a large table | Use `TREATAS` or `CALCULATETABLE` with a lookup table instead |
|
|
170
|
+
| `COUNTROWS(FILTER(...))` on a large fact table | Use `CALCULATE(COUNTROWS(...), condition)` — pushes to Storage Engine |
|
|
171
|
+
| `SUMX` iterating millions of rows with complex expressions | Pre-aggregate with `SUMMARIZE` in a `VAR`, then iterate the summary |
|
|
172
|
+
| Bidirectional relationships causing ambiguous paths | Use `USERELATIONSHIP` explicitly inside `CALCULATE` |
|
|
173
|
+
| `IF(ISBLANK([A]), BLANK(), [B])` | BLANK propagates automatically in most functions — test whether the `IF` is actually needed |
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## PHASE 2C: Calculation Groups
|
|
178
|
+
|
|
179
|
+
Calculation groups are the correct Power BI pattern for "apply the same time intelligence or formatting logic to any measure". Use them when the user has 3+ variants of the same transformation (Current, YTD, YoY, MoM, etc.).
|
|
180
|
+
|
|
181
|
+
### Before creating a calculation group:
|
|
182
|
+
|
|
183
|
+
1. Confirm `discourageImplicitMeasures: true` on the model (required for calculation groups).
|
|
184
|
+
2. Check that a proper Date table is marked.
|
|
185
|
+
3. Read any existing calculation groups via MCP to avoid conflicts.
|
|
186
|
+
4. Inventory text/helper measures such as dynamic titles, labels, and dynamic format-string helpers before writing any calculation item that performs math. Microsoft Learn notes that adding a calculation group makes report measures use the `variant` data type, and a math item can throw `Cannot convert value ... of type Text to type Numeric` when it hits a non-numeric measure. Guard those items with `ISSELECTEDMEASURE()` or `ISNUMERIC(SELECTEDMEASURE())` so text measures pass through unchanged.
|
|
187
|
+
|
|
188
|
+
### Standard time intelligence items
|
|
189
|
+
|
|
190
|
+
Write via `calculation_group_operations` in the MCP: use `ListGroups` / `GetGroup` before edits, `CreateGroup` for a new group, `CreateItems` / `UpdateItems` for items, and `ReorderItems` for ordinal changes.
|
|
191
|
+
|
|
192
|
+
| Item name | DAX expression |
|
|
193
|
+
|---|---|
|
|
194
|
+
| Actual | `SELECTEDMEASURE()` |
|
|
195
|
+
| YTD | `CALCULATE(SELECTEDMEASURE(), DATESYTD('Fecha'[Fecha]))` |
|
|
196
|
+
| MAT (12-month rolling) | `CALCULATE(SELECTEDMEASURE(), DATESINPERIOD('Fecha'[Fecha], LASTDATE('Fecha'[Fecha]), -12, MONTH))` |
|
|
197
|
+
| Período Previo | `CALCULATE(SELECTEDMEASURE(), DATEADD('Fecha'[Fecha], -1, <granularity>))` |
|
|
198
|
+
| Variación vs PP | `SELECTEDMEASURE() - CALCULATE(SELECTEDMEASURE(), DATEADD('Fecha'[Fecha], -1, <granularity>))` |
|
|
199
|
+
| Variación % vs PP | `DIVIDE(SELECTEDMEASURE() - CALCULATE(SELECTEDMEASURE(), DATEADD('Fecha'[Fecha], -1, <granularity>)), ABS(CALCULATE(SELECTEDMEASURE(), DATEADD('Fecha'[Fecha], -1, <granularity>))))` |
|
|
200
|
+
|
|
201
|
+
Set `ordinal` on each item so the group sorts predictably in visuals.
|
|
202
|
+
|
|
203
|
+
### Teach the key calculation group caveat
|
|
204
|
+
|
|
205
|
+
When a visual has a measure that itself already uses time intelligence (e.g., `[Sales YTD]`), applying a "YTD" calculation group item double-applies it. The pattern to avoid this: use `ISSELECTEDMEASURE()` guards or, better, rely on calculation groups for **all** time comparisons and keep base measures pure (`SUM`, `COUNTROWS`).
|
|
206
|
+
|
|
207
|
+
Also teach the type caveat: calculation groups apply only to explicit measures (not implicit column aggregations) and make measures flow through visuals as `variant`. If a calculation item applies subtraction, division, multiplication, or date-shift logic, make it numeric-safe:
|
|
208
|
+
|
|
209
|
+
```dax
|
|
210
|
+
IF (
|
|
211
|
+
ISNUMERIC ( SELECTEDMEASURE() ),
|
|
212
|
+
<numeric calculation using SELECTEDMEASURE()>,
|
|
213
|
+
SELECTEDMEASURE()
|
|
214
|
+
)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
For dynamic format strings that reuse a measure and start failing because the measure is now `variant`, wrap the text result with `FORMAT ( [Dynamic format string], "" )` or move reusable format-string logic into a DAX UDF after routing that work to `/bi-connect`.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Model introspection via DMVs
|
|
222
|
+
|
|
223
|
+
Use these DAX queries via `dax_query_operations` to inspect the live model:
|
|
224
|
+
|
|
225
|
+
```dax
|
|
226
|
+
-- List all measures with their expressions
|
|
227
|
+
EVALUATE INFO.MEASURES()
|
|
228
|
+
|
|
229
|
+
-- List all tables
|
|
230
|
+
EVALUATE INFO.TABLES()
|
|
231
|
+
|
|
232
|
+
-- List all calculation groups
|
|
233
|
+
EVALUATE INFO.CALCULATIONGROUPS()
|
|
234
|
+
|
|
235
|
+
-- List all UDFs when the model supports DAX user-defined functions
|
|
236
|
+
EVALUATE INFO.USERDEFINEDFUNCTIONS()
|
|
237
|
+
|
|
238
|
+
-- Check Auto Date/Time annotation
|
|
239
|
+
EVALUATE INFO.ANNOTATIONS()
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
These are faster than reading TMDL files for quick lookups and they reflect the in-memory state, not the last save.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## PHASE 3: After DAX work
|
|
247
|
+
|
|
248
|
+
1. **Final validation** — run a `SUMMARIZECOLUMNS` that crosses the new measure against at least 2 dimensions to confirm it behaves correctly in context.
|
|
249
|
+
2. **Save/export before close** — MCP writes live in Desktop memory. Ask user for `Ctrl+S` before ending the session.
|
|
250
|
+
3. **Inspect persisted snapshot** — Inspect the saved PBIP/TMDL diff and confirm the expected measure or calculation-group files changed, with no report topology or local cache noise.
|
|
251
|
+
Do not treat a live MCP readback as persisted PBIP evidence; it proves only the in-memory Desktop model.
|
|
252
|
+
4. **Suggest commit** — only then recommend a Git commit.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Template DAX Patterns to Replicate
|
|
257
|
+
|
|
258
|
+
The smoke-test template defines reference implementations for the most common DAX needs. **Replicate, don't reinvent**:
|
|
259
|
+
|
|
260
|
+
### Sallieri period comparison (any-period vs. any-period)
|
|
261
|
+
|
|
262
|
+
Drives `[Actual]`, `[Previo]`, `[Variación]`, `[Variación %]`, `[Etiqueta variación %]`, and `[Título comparación]`. The pattern uses `_Aux Comparaciones` plus `_GC Tipo cálculo` filtered by user slicers — *not* hardcoded `SAMEPERIODLASTYEAR`. This is the default for any "compare to previous period" need; never hardcode YoY/MoM unless the user explicitly requires only that one comparison.
|
|
263
|
+
|
|
264
|
+
### Parameterizable currency conversion
|
|
265
|
+
|
|
266
|
+
Reads the base currency from the Power Query `MonedaBase` parameter persisted in `_Aux Modelo configuración[ValorTexto]`, looks up `Tipo de cambio[TipoCambioBase]` for the date and currency, short-circuits when source = target, handles BLANK on missing rates, and uses a `Monetaria` flag in `Métricas` to render the right currency symbol. Never hardcode `"USD"` as the base currency in DAX.
|
|
267
|
+
|
|
268
|
+
### Dynamic field parameters for axis dimension
|
|
269
|
+
|
|
270
|
+
`_PC Dimensión` is a field parameter table that lets the user switch the axis dimension (País / Canal / Producto / etc.) on a single visual. It is filtered by the selected row in `Métricas` through `_Aux Compatibilidad métrica-dimensión`, so the user sees the breakdowns that best explain the selected metric. Pattern:
|
|
271
|
+
- Visual's category axis bound to the parameter column
|
|
272
|
+
- Measures that need to behave differently per dimension use `SWITCH(SELECTEDVALUE('_PC Dimensión'[Campo]), ...)`
|
|
273
|
+
- If the metric list is filtered by team, keep `Equipos métricas` and `_Aux Métrica-Equipo` in the model so a metric can belong to `Dirección`, `Finanzas`, `Ventas`, or any other relevant team without duplicating measures.
|
|
274
|
+
|
|
275
|
+
### Calculation group time intelligence
|
|
276
|
+
|
|
277
|
+
Items in the calculation groups include `_GC Tipo cálculo` (`Actual`, `Previo`, `Variación`, `Variación %`), `_GC Cálculo` (`Valor`, `Acumulado`), and `_GC Métrica` (one item per catalog metric). Each uses `SELECTEDMEASURE()` or guarded `ISSELECTEDMEASURE()` routing so the same carriers apply to the active metric. Base measures stay pure (`SUM`, `COUNTROWS`); time and metric-routing logic lives in calculation groups and helper measures.
|
|
278
|
+
|
|
279
|
+
### Label and color helper measures
|
|
280
|
+
|
|
281
|
+
The one-level `Auxiliar` display folder hosts measures that drive dynamic visual content: `[Etiqueta variación %]`, `[Color bullet variación]`, `[Etiqueta bullet chart]`. They centralize formatting and conditional color logic so visuals don't carry hardcoded thresholds.
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## What this skill does NOT do
|
|
286
|
+
|
|
287
|
+
- **Model structure** (tables, relationships, star schema): that's `/bi-modeling`
|
|
288
|
+
- **DAX UDFs** (user-defined functions, DAXLIB patterns): that's `/bi-connect` — UDFs require current Microsoft Learn syntax/limitations, compatibility-level checks, and dedicated DAXLIB-aware guidance
|
|
289
|
+
- **Report visuals or layout**: that's manual Desktop work
|
|
290
|
+
- **Direct TMDL edits**: never
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Internal operator appendix (agent-only — no es copia para el usuario)
|
|
295
|
+
|
|
296
|
+
> Todo lo que sigue es mecánica para vos, el agente. Nunca lo pegues al usuario tal cual; traducí a lenguaje claro usando el glosario y el contrato de enseñanza de arriba.
|
|
297
|
+
|
|
298
|
+
## MANDATORY RULES
|
|
299
|
+
|
|
300
|
+
**(Interno — reglas del agente; traducí a lenguaje de negocio antes de mostrar nada de acá al usuario.)**
|
|
301
|
+
|
|
302
|
+
1. **MCP FOR ALL WRITES — PBIP FILES ARE READ-ONLY.** Every measure, calculated column, or calculation group item goes through the Power BI Modeling MCP. Never edit `.tmdl`, `.SemanticModel/**`, or `.Report/**` directly. Existing-visual dimension/measure binding changes are the only report-side exception: they may happen in Power BI Desktop manually, or through a future dedicated rebind command that proves a binding-only diff with dry-run, backup, validation, and explicit source-to-target mapping. No safe report rebind command currently ships with this plugin, so read PBIP files for inspection only and never patch PBIR by hand.
|
|
303
|
+
|
|
304
|
+
**Microsoft Learn's PBIP project guidance.** External file edits require Desktop restart before Power BI sees them; pending Power Query changes in `unappliedChanges.json` can overwrite expression edits when applied; and `report.json`, `mobileState.json`, `semanticModelDiagramLayout.json`, and `diagramLayout.json` are unsupported external-edit surfaces. Treat those files as diagnostic-only in this plugin.
|
|
305
|
+
|
|
306
|
+
**REPORT TOPOLOGY LOCK.** Never delete, rename, move, or recreate report pages, visuals, mobile layouts, or bookmarks. Never create replacement visuals/pages to "fix" broken bindings. Do not rebuild a "minimal functional report". A/D/R under any `.Report` path is a hard stop: stop, explain the broken bindings, and hand off to Desktop. A DAX skill changes measures, not report topology.
|
|
307
|
+
|
|
308
|
+
2. **VALIDATE BEFORE COMMITTING.** Before applying any non-trivial measure via MCP, test it using `dax_query_operations` (DAX Query View equivalent) with a query-scoped `DEFINE MEASURE ... EVALUATE ...`, `EVALUATE { <expression> }`, or a small `SUMMARIZECOLUMNS`. If the query returns unexpected results, fix the formula before committing it to the model. DAX query scoped measures are validation scaffolding; persistence happens through `measure_operations.Create` / `measure_operations.Update`, not by assuming a query created a model object.
|
|
309
|
+
|
|
310
|
+
3. **USE THE RIGHT MCP OPERATION FOR THE CHANGE.** For measures, use `measure_operations.Get` / `List` before edits, `Create` for new measures, `Update` for expression/format/folder changes, `Rename` for names, and `Move` for host-table changes. `Update` cannot change the measure's table; delete/recreate is not an acceptable substitute for `Move` because it risks dependencies and lineage.
|
|
311
|
+
|
|
312
|
+
4. **VARIABLES IN EVERY MULTI-STEP FORMULA.** Every measure with more than one computational step uses `VAR`. No exceptions. Variables prevent repeated evaluation, make formulas debuggable, and make the return path explicit. A formula without variables where they would help is a formula that needs rewriting.
|
|
313
|
+
|
|
314
|
+
5. **`DIVIDE` WHEN THE DENOMINATOR CAN BE ZERO/BLANK.** Use `DIVIDE([Numerator], [Denominator])` whenever the denominator can be zero or `BLANK` (the usual measure-over-measure case) — it returns `BLANK` (or your alternate result) instead of failing, and the engine optimizes the zero test. Do not rely on `/` when the denominator might be zero or `BLANK`. Microsoft recommends plain `/` only when the denominator is a **constant that cannot be zero** because it avoids unnecessary zero/blank testing. Rule of thumb: `DIVIDE` for variable denominators, `/` for safe constants.
|
|
315
|
+
|
|
316
|
+
6. **RESPECT BLANK PROPAGATION.** Do not convert `BLANK` to `0` unless there is a specific semantic reason documented in the measure comment. `BLANK` is meaningful — it tells visuals "no data here". Converting to `0` hides missing data and creates false baselines in time intelligence.
|
|
317
|
+
|
|
318
|
+
7. **EXPLAIN FILTER CONTEXT ON EVERY NON-TRIVIAL MEASURE.** Any measure that uses `CALCULATE`, `FILTER`, `REMOVEFILTERS`, `ALLEXCEPT`, `KEEPFILTERS`, or a context transition (`SUMX` iterating a table) requires a brief teaching note explaining what context is modified and why. This is the single hardest concept in DAX — never leave it implicit.
|
|
319
|
+
|
|
320
|
+
8. **READ BEFORE REWRITING.** When the user asks to fix or optimize an existing measure, read its current definition via MCP first. Never rewrite from memory or assumptions.
|
|
321
|
+
|
|
322
|
+
9. **CONSULT MICROSOFT LEARN FOR UNCERTAIN BEHAVIOR.** Before advising on functions with preview behavior, undocumented edge cases, or features that may have changed since training cutoff (calculation groups, UDFs, `INFO.*` DMVs, `TMDL` partition semantics), query the `microsoft-learn` MCP.
|
|
323
|
+
|
|
324
|
+
10. **ONE QUESTION AT A TIME.** Wizard pattern — ask, wait, proceed. Never stack multiple questions.
|
|
325
|
+
|
|
326
|
+
11. **WINDOWS + POWER BI DESKTOP ONLY.** DAX queries against the live model require Desktop and the Modeling MCP. On macOS/Linux: stop and explain.
|
|
327
|
+
|
|
328
|
+
12. **CALCULATION GROUPS NEED NUMERIC GUARDS.** Microsoft Learn's current calculation-group guidance says calculation items apply only to explicit measures and report measures become `variant` once a calculation group exists. Before creating or updating a calculation item that performs math, identify text/helper measures and protect them with `ISSELECTEDMEASURE()` or `ISNUMERIC(SELECTEDMEASURE())`. If a dynamic format-string helper fails because of `variant`, use `FORMAT ( [Helper], "" )` or route a reusable UDF solution to `/bi-connect`.
|
|
329
|
+
|
|
330
|
+
13. **TEMPLATE IS THE REFERENCE.** The BISuperpowers smoke-test template encodes battle-tested DAX patterns: Sallieri period comparison, parameterizable currency conversion, dynamic field parameters, calculation-group time intelligence, label/color helper measures. **When writing a measure that fits any of these scenarios, replicate the template's pattern instead of inventing a new one.** Reinventing produces inconsistent behavior across projects. See "Template DAX Patterns" below for the canonical implementations.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
### Storage Engine vs. Formula Engine
|
|
335
|
+
|
|
336
|
+
**(Interno — material técnico para el agente. Al usuario explicale solo el qué y el impacto en su negocio; no le pases estos términos (TREATAS, ALLSELECTED, context transition, "materializa") sin traducir.)**
|
|
337
|
+
|
|
338
|
+
Teach this whenever relevant: Power BI has two execution engines:
|
|
339
|
+
- **Storage Engine (SE)**: parallelized, fast, columnar. Handles simple aggregations.
|
|
340
|
+
- **Formula Engine (FE)**: single-threaded, slower. Handles `CALCULATE`, iterators, complex filters.
|
|
341
|
+
|
|
342
|
+
The goal is to push as much work as possible to the SE by keeping filters simple and avoiding row-by-row iteration over large tables.
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## DAX Anti-patterns
|
|
347
|
+
|
|
348
|
+
**(Interno — material técnico para el agente. Al usuario explicale solo el qué y el impacto en su negocio; no le pases estos términos (TREATAS, ALLSELECTED, context transition, "materializa") sin traducir.)**
|
|
349
|
+
|
|
350
|
+
| Don't | Do instead | Why |
|
|
351
|
+
|---|---|---|
|
|
352
|
+
| `[Sales] / [Units]` (variable denominator) | `DIVIDE([Sales], [Units])` | `DIVIDE` handles zero/BLANK denominators and lets visuals suppress empty groups. Plain `/` is fine and faster only for a constant non-zero denominator. |
|
|
353
|
+
| `IF(ISERROR([X]), BLANK(), [X])` | Fix the formula that produces the error | ISERROR is a symptom mask, not a fix |
|
|
354
|
+
| `FILTER(ALL(Table), ...)` inside `CALCULATE` on large tables | `TREATAS`, lookup table, or `KEEPFILTERS` | FILTER materializes a table in FE; pushdown to SE |
|
|
355
|
+
| `VAR X = [Measure]` inside `SUMX` | Declare `VAR` before `RETURN`, not inside an iterator | Variables inside iterators re-evaluate per row — this is a common misunderstanding |
|
|
356
|
+
| Convert `BLANK` to `0` by default | Let BLANK propagate | `0` creates false baselines; `BLANK` hides correctly in visuals |
|
|
357
|
+
| Store measures in fact tables | Dedicated measures table | Field list pollution; hard to navigate |
|
|
358
|
+
| Fully-qualify measure references: `Table[Measure]` | `[Measure]` only | Measures are model-scoped, not table-scoped |
|
|
359
|
+
| Omit display folder | Always set display folder | Ungrouped measures are invisible at scale |
|
|
360
|
+
| `CALCULATE([M], FILTER(DimDate, condition))` | `CALCULATE([M], DimDate[Column] = value)` | Direct filter syntax pushes to SE; wrapping in FILTER forces FE |
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## PHASE 2D: Advanced DAX Patterns
|
|
365
|
+
|
|
366
|
+
**(Interno — material técnico para el agente. Al usuario explicale solo el qué y el impacto en su negocio; no le pases estos términos (TREATAS, ALLSELECTED, context transition, "materializa") sin traducir.)**
|
|
367
|
+
|
|
368
|
+
### Period comparison (Sallieri pattern / dynamic periods)
|
|
369
|
+
|
|
370
|
+
When the model uses a **comparison period table** (not `SAMEPERIODLASTYEAR`), the standard time intelligence functions don't apply. The current base-template pattern uses `_Aux Comparaciones` for selected current/previous ranges and `_GC Tipo cálculo` for the carrier state.
|
|
371
|
+
|
|
372
|
+
Core structure:
|
|
373
|
+
```dax
|
|
374
|
+
Previo =
|
|
375
|
+
CALCULATE (
|
|
376
|
+
[Métrica activa],
|
|
377
|
+
'_GC Tipo cálculo'[Tipo cálculo] = "Previo"
|
|
378
|
+
)
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Teach: `_Aux Comparaciones` defines the date ranges, while `_GC Tipo cálculo` tells the carrier whether to read the active metric as current, previous, absolute change, or percentage change. In custom models that do not use the template calculation group, `TREATAS` can remap a comparison-date column to `Calendario[Fecha]` without a physical relationship.
|
|
382
|
+
|
|
383
|
+
### Dynamic field parameters
|
|
384
|
+
|
|
385
|
+
When the model uses field parameters (an `Aux Dimensiones` or `Field Parameters` table that lets the user switch the axis dimension):
|
|
386
|
+
|
|
387
|
+
```dax
|
|
388
|
+
Dimensión Activa =
|
|
389
|
+
SELECTEDVALUE('_PC Dimensión'[Campo])
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
The chart's category axis is bound to the parameter column. Measures that need to behave differently per dimension use `SWITCH(SELECTEDVALUE(...), ...)`.
|
|
393
|
+
|
|
394
|
+
### Currency conversion
|
|
395
|
+
|
|
396
|
+
When the model has an exchange rate table (`Tipo de cambio`) with date-level rates:
|
|
397
|
+
|
|
398
|
+
```dax
|
|
399
|
+
Ventas Convertidas =
|
|
400
|
+
SUMX(
|
|
401
|
+
VALUES('Calendario'[Fecha]),
|
|
402
|
+
VAR TasaCambio =
|
|
403
|
+
CALCULATE(
|
|
404
|
+
SELECTEDVALUE('Tipo de cambio'[Tasa]),
|
|
405
|
+
TREATAS(VALUES('Monedas'[MonedaISO]), 'Tipo de cambio'[Moneda destino])
|
|
406
|
+
)
|
|
407
|
+
RETURN
|
|
408
|
+
DIVIDE([Ventas Base], TasaCambio)
|
|
409
|
+
)
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Teach: iterate the dates in context (`SUMX` over `VALUES('Calendario'[Fecha])`) so each day uses its own rate, and use `SELECTEDVALUE` — not `VALUES` — for the rate. `VALUES` returns a *table* and throws "a table of multiple values was supplied" the moment more than one rate is in context (e.g. a month on the axis). State the rate convention explicitly: `DIVIDE(base, rate)` is correct only when the rate is *target units per base unit*; if it's stored the other way, multiply. Short-circuit when source and target currency match to avoid the join.
|
|
413
|
+
|
|
414
|
+
### Semi-additive measures (snapshots)
|
|
415
|
+
|
|
416
|
+
For headcount, inventory, or balance sheet data where values should **not** be summed across time:
|
|
417
|
+
|
|
418
|
+
```dax
|
|
419
|
+
Saldo Cierre =
|
|
420
|
+
LASTNONBLANKVALUE('Fecha'[Fecha], [Saldo])
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Teach: `LASTNONBLANKVALUE` iterates the dates **in the current context** and returns the value at the last date that isn't blank — so each month/quarter shows *its own* closing balance. Do **not** wrap it in `ALLSELECTED('Fecha')` for a normal closing balance: that lifts the period filter and makes every row show the last balance of the whole selection. For the standard case, prefer the purpose-built `CLOSINGBALANCEMONTH` / `CLOSINGBALANCEQUARTER` / `CLOSINGBALANCEYEAR`. It's a Formula Engine operation (slower than `SUM`) — fine for snapshot tables, avoid on large facts.
|
|
424
|
+
|
|
425
|
+
### Ranking with RANKX
|
|
426
|
+
|
|
427
|
+
```dax
|
|
428
|
+
Ranking Ventas =
|
|
429
|
+
VAR VentasCliente = [Total Ventas]
|
|
430
|
+
RETURN
|
|
431
|
+
IF(
|
|
432
|
+
NOT ISBLANK(VentasCliente),
|
|
433
|
+
RANKX(ALLSELECTED('Clientes'[Cliente]), [Total Ventas], , DESC, DENSE)
|
|
434
|
+
)
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Teach: `ALLSELECTED` scopes the ranking to whatever the user filtered on the page (without it, ranking is always over the full table). Guard with `ISBLANK` because `RANKX` treats a `BLANK` measure as `0` — without the guard, customers with no sales still get ranked (as zero) and pollute the list. The empty slot before `DESC` skips the optional `value` argument.
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Complexity Adaptation
|
|
442
|
+
|
|
443
|
+
Read `config.json → experienceLevel` if available; otherwise infer.
|
|
444
|
+
|
|
445
|
+
- **Guiado**: define filter context vs. row context from scratch before writing any `CALCULATE`; use analogies ("filter context is like applying slicers to the whole formula")
|
|
446
|
+
- **Intermedio**: explain context transitions and the FE/SE split when relevant; skip definitions of `SUM` and `DIVIDE`
|
|
447
|
+
- **Directo**: lead with the formula and the edge cases; skip basics; explain performance characteristics and failure modes
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Related Skills
|
|
452
|
+
|
|
453
|
+
- `/bi-modeling` — when the model structure (relationships, star schema, Date Table) needs to be corrected before the DAX will work
|
|
454
|
+
- `/bi-connect` — for DAX user-defined functions and DAXLIB patterns; also for MCP connection troubleshooting
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## Related Resources
|
|
459
|
+
|
|
460
|
+
- [DAX overview](https://learn.microsoft.com/en-us/dax/dax-overview)
|
|
461
|
+
- [CALCULATE function](https://learn.microsoft.com/en-us/dax/calculate-function-dax)
|
|
462
|
+
- [Understanding filter context and row context](https://learn.microsoft.com/en-us/power-bi/transform-model/desktop-tutorial-create-measures)
|
|
463
|
+
- [Calculation groups in Power BI](https://learn.microsoft.com/en-us/power-bi/transform-model/calculation-groups)
|
|
464
|
+
- [DAX optimization guide](https://learn.microsoft.com/en-us/power-bi/guidance/dax-variables)
|