@luquimbo/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.
Files changed (193) hide show
  1. package/.claude-plugin/plugin.json +8 -0
  2. package/.mcp.json +25 -0
  3. package/AGENTS.md +244 -0
  4. package/CHANGELOG.md +265 -0
  5. package/LICENSE +21 -0
  6. package/README.md +211 -0
  7. package/bin/build-plugin.js +30 -0
  8. package/bin/cli.js +1064 -0
  9. package/bin/commands/add.js +533 -0
  10. package/bin/commands/add.test.js +77 -0
  11. package/bin/commands/build-desktop.js +166 -0
  12. package/bin/commands/changelog.js +443 -0
  13. package/bin/commands/diff.js +325 -0
  14. package/bin/commands/lint.js +419 -0
  15. package/bin/commands/lint.test.js +103 -0
  16. package/bin/commands/mcp-setup.js +246 -0
  17. package/bin/commands/pull.js +287 -0
  18. package/bin/commands/pull.test.js +36 -0
  19. package/bin/commands/push.js +231 -0
  20. package/bin/commands/push.test.js +14 -0
  21. package/bin/commands/search.js +344 -0
  22. package/bin/commands/search.test.js +115 -0
  23. package/bin/commands/setup.js +545 -0
  24. package/bin/commands/setup.test.js +46 -0
  25. package/bin/commands/sync-profile.js +405 -0
  26. package/bin/commands/sync-profile.test.js +14 -0
  27. package/bin/commands/sync-source.js +418 -0
  28. package/bin/commands/sync-source.test.js +14 -0
  29. package/bin/commands/watch.js +206 -0
  30. package/bin/lib/generators/claude-plugin.js +266 -0
  31. package/bin/lib/generators/claude-plugin.test.js +110 -0
  32. package/bin/lib/generators/index.js +116 -0
  33. package/bin/lib/generators/shared.js +282 -0
  34. package/bin/lib/licensing/index.js +35 -0
  35. package/bin/lib/licensing/storage.js +364 -0
  36. package/bin/lib/licensing/storage.test.js +55 -0
  37. package/bin/lib/licensing/validator.js +213 -0
  38. package/bin/lib/licensing/validator.test.js +137 -0
  39. package/bin/lib/microsoft-mcp.js +176 -0
  40. package/bin/lib/microsoft-mcp.test.js +106 -0
  41. package/bin/lib/skills.js +84 -0
  42. package/bin/mcp/powerbi-modeling-launcher.js +38 -0
  43. package/bin/postinstall.js +44 -0
  44. package/bin/utils/errors.js +159 -0
  45. package/bin/utils/git.js +298 -0
  46. package/bin/utils/logger.js +142 -0
  47. package/bin/utils/mcp-detect.js +274 -0
  48. package/bin/utils/mcp-detect.test.js +105 -0
  49. package/bin/utils/pbix.js +305 -0
  50. package/bin/utils/pbix.test.js +37 -0
  51. package/bin/utils/profiles.js +312 -0
  52. package/bin/utils/projects.js +168 -0
  53. package/bin/utils/readline.js +206 -0
  54. package/bin/utils/readline.test.js +47 -0
  55. package/bin/utils/tui.js +314 -0
  56. package/bin/utils/tui.test.js +127 -0
  57. package/commands/contributions.md +265 -0
  58. package/commands/data-model-design.md +468 -0
  59. package/commands/dax-doctor.md +248 -0
  60. package/commands/fabric-scripts.md +452 -0
  61. package/commands/migration-assistant.md +290 -0
  62. package/commands/model-documenter.md +242 -0
  63. package/commands/pbi-connect.md +239 -0
  64. package/commands/project-kickoff.md +905 -0
  65. package/commands/report-layout.md +296 -0
  66. package/commands/rls-design.md +533 -0
  67. package/commands/theme-tweaker.md +624 -0
  68. package/config.example.json +23 -0
  69. package/config.json +23 -0
  70. package/desktop-extension/manifest.json +37 -0
  71. package/desktop-extension/package.json +10 -0
  72. package/desktop-extension/server.js +95 -0
  73. package/docs/openrouter-free-models.md +92 -0
  74. package/library/examples/README.md +151 -0
  75. package/library/examples/finance-reporting/README.md +351 -0
  76. package/library/examples/finance-reporting/data-model.md +267 -0
  77. package/library/examples/finance-reporting/measures.dax +557 -0
  78. package/library/examples/hr-analytics/README.md +371 -0
  79. package/library/examples/hr-analytics/data-model.md +315 -0
  80. package/library/examples/hr-analytics/measures.dax +460 -0
  81. package/library/examples/marketing-analytics/README.md +37 -0
  82. package/library/examples/marketing-analytics/data-model.md +62 -0
  83. package/library/examples/marketing-analytics/measures.dax +110 -0
  84. package/library/examples/retail-analytics/README.md +439 -0
  85. package/library/examples/retail-analytics/data-model.md +288 -0
  86. package/library/examples/retail-analytics/measures.dax +481 -0
  87. package/library/examples/supply-chain/README.md +37 -0
  88. package/library/examples/supply-chain/data-model.md +69 -0
  89. package/library/examples/supply-chain/measures.dax +77 -0
  90. package/library/examples/udf-library/README.md +228 -0
  91. package/library/examples/udf-library/functions.dax +571 -0
  92. package/library/snippets/dax/README.md +292 -0
  93. package/library/snippets/dax/business-domains.md +576 -0
  94. package/library/snippets/dax/calculate-patterns.md +276 -0
  95. package/library/snippets/dax/calculation-groups.md +489 -0
  96. package/library/snippets/dax/error-handling.md +495 -0
  97. package/library/snippets/dax/iterators-and-aggregations.md +474 -0
  98. package/library/snippets/dax/kpis-and-metrics.md +293 -0
  99. package/library/snippets/dax/rankings-and-topn.md +235 -0
  100. package/library/snippets/dax/security-patterns.md +413 -0
  101. package/library/snippets/dax/text-and-formatting.md +316 -0
  102. package/library/snippets/dax/time-intelligence.md +196 -0
  103. package/library/snippets/dax/user-defined-functions.md +477 -0
  104. package/library/snippets/dax/virtual-tables.md +546 -0
  105. package/library/snippets/excel-formulas/README.md +84 -0
  106. package/library/snippets/excel-formulas/aggregations.md +330 -0
  107. package/library/snippets/excel-formulas/dates-and-times.md +361 -0
  108. package/library/snippets/excel-formulas/dynamic-arrays.md +314 -0
  109. package/library/snippets/excel-formulas/lookups.md +169 -0
  110. package/library/snippets/excel-formulas/text-functions.md +363 -0
  111. package/library/snippets/governance/naming-conventions.md +97 -0
  112. package/library/snippets/governance/review-checklists.md +107 -0
  113. package/library/snippets/power-query/README.md +389 -0
  114. package/library/snippets/power-query/api-integration.md +707 -0
  115. package/library/snippets/power-query/connections.md +434 -0
  116. package/library/snippets/power-query/data-cleaning.md +298 -0
  117. package/library/snippets/power-query/error-handling.md +526 -0
  118. package/library/snippets/power-query/parameters.md +350 -0
  119. package/library/snippets/power-query/performance.md +506 -0
  120. package/library/snippets/power-query/transformations.md +330 -0
  121. package/library/snippets/report-design/accessibility.md +78 -0
  122. package/library/snippets/report-design/chart-selection.md +54 -0
  123. package/library/snippets/report-design/layout-patterns.md +87 -0
  124. package/library/templates/data-models/README.md +93 -0
  125. package/library/templates/data-models/finance-model.md +627 -0
  126. package/library/templates/data-models/retail-star-schema.md +473 -0
  127. package/library/templates/excel/README.md +83 -0
  128. package/library/templates/excel/budget-tracker.md +432 -0
  129. package/library/templates/excel/data-entry-form.md +533 -0
  130. package/library/templates/power-bi/README.md +72 -0
  131. package/library/templates/power-bi/finance-report.md +449 -0
  132. package/library/templates/power-bi/kpi-scorecard.md +461 -0
  133. package/library/templates/power-bi/sales-dashboard.md +281 -0
  134. package/library/themes/excel/README.md +436 -0
  135. package/library/themes/power-bi/README.md +271 -0
  136. package/library/themes/power-bi/accessible.json +307 -0
  137. package/library/themes/power-bi/bi-superpowers-default.json +858 -0
  138. package/library/themes/power-bi/corporate-blue.json +291 -0
  139. package/library/themes/power-bi/dark-mode.json +291 -0
  140. package/library/themes/power-bi/minimal.json +292 -0
  141. package/library/themes/power-bi/print-friendly.json +309 -0
  142. package/package.json +93 -0
  143. package/skills/contributions/SKILL.md +267 -0
  144. package/skills/data-model-design/SKILL.md +470 -0
  145. package/skills/data-modeling/SKILL.md +254 -0
  146. package/skills/data-quality/SKILL.md +664 -0
  147. package/skills/dax/SKILL.md +708 -0
  148. package/skills/dax-doctor/SKILL.md +250 -0
  149. package/skills/dax-udf/SKILL.md +489 -0
  150. package/skills/deployment/SKILL.md +320 -0
  151. package/skills/excel-formulas/SKILL.md +463 -0
  152. package/skills/fabric-scripts/SKILL.md +454 -0
  153. package/skills/fast-standard/SKILL.md +509 -0
  154. package/skills/governance/SKILL.md +205 -0
  155. package/skills/migration-assistant/SKILL.md +292 -0
  156. package/skills/model-documenter/SKILL.md +244 -0
  157. package/skills/pbi-connect/SKILL.md +241 -0
  158. package/skills/power-query/SKILL.md +406 -0
  159. package/skills/project-kickoff/SKILL.md +907 -0
  160. package/skills/query-performance/SKILL.md +480 -0
  161. package/skills/report-design/SKILL.md +207 -0
  162. package/skills/report-layout/SKILL.md +298 -0
  163. package/skills/rls-design/SKILL.md +535 -0
  164. package/skills/semantic-model/SKILL.md +237 -0
  165. package/skills/testing-validation/SKILL.md +643 -0
  166. package/skills/theme-tweaker/SKILL.md +626 -0
  167. package/src/content/base.md +237 -0
  168. package/src/content/mcp-requirements.json +69 -0
  169. package/src/content/routing.md +203 -0
  170. package/src/content/skills/contributions.md +259 -0
  171. package/src/content/skills/data-model-design.md +462 -0
  172. package/src/content/skills/data-modeling.md +246 -0
  173. package/src/content/skills/data-quality.md +656 -0
  174. package/src/content/skills/dax-doctor.md +242 -0
  175. package/src/content/skills/dax-udf.md +481 -0
  176. package/src/content/skills/dax.md +700 -0
  177. package/src/content/skills/deployment.md +312 -0
  178. package/src/content/skills/excel-formulas.md +455 -0
  179. package/src/content/skills/fabric-scripts.md +446 -0
  180. package/src/content/skills/fast-standard.md +501 -0
  181. package/src/content/skills/governance.md +197 -0
  182. package/src/content/skills/migration-assistant.md +284 -0
  183. package/src/content/skills/model-documenter.md +236 -0
  184. package/src/content/skills/pbi-connect.md +233 -0
  185. package/src/content/skills/power-query.md +398 -0
  186. package/src/content/skills/project-kickoff.md +899 -0
  187. package/src/content/skills/query-performance.md +472 -0
  188. package/src/content/skills/report-design.md +199 -0
  189. package/src/content/skills/report-layout.md +290 -0
  190. package/src/content/skills/rls-design.md +527 -0
  191. package/src/content/skills/semantic-model.md +229 -0
  192. package/src/content/skills/testing-validation.md +635 -0
  193. package/src/content/skills/theme-tweaker.md +618 -0
@@ -0,0 +1,643 @@
1
+ ---
2
+ name: "testing-validation"
3
+ description: "Use when the user asks about Testing & Validation Skill, especially phrases like \"test\", \"unit test DAX\", \"regression test\", \"deployment checklist\", \"data reconciliation\", \"pruebas\"."
4
+ version: "1.0.0"
5
+ ---
6
+
7
+ <!-- Generated by BI Agent Superpowers. Edit src/content/skills/testing-validation.md instead. -->
8
+
9
+ # Testing & Validation Skill
10
+
11
+ ## Trigger
12
+ Activate this skill when user mentions:
13
+ - "test", "testing", "validation", "verify", "QA"
14
+ - "unit test DAX", "test measures", "validate data"
15
+ - "regression test", "before/after comparison"
16
+ - "deployment checklist", "release testing"
17
+ - "data reconciliation", "source comparison"
18
+ - "pruebas", "validación", "verificar datos"
19
+
20
+ ## Identity
21
+ You are a **BI Testing Specialist** who helps users validate their Power BI models, DAX measures, and data transformations. You guide users through systematic testing approaches to ensure data accuracy, measure correctness, and model reliability before deployment.
22
+
23
+ ## MANDATORY RULES
24
+ 1. **TEST BEFORE DEPLOY.** Never skip validation steps.
25
+ 2. **DOCUMENT EXPECTED RESULTS.** Tests need success criteria.
26
+ 3. **COMPARE TO SOURCE.** Always validate against authoritative source.
27
+ 4. **REGRESSION MATTERS.** Existing functionality must still work.
28
+ 5. **AUTOMATE WHERE POSSIBLE.** Manual tests don't scale.
29
+
30
+ ---
31
+
32
+ ## PHASE 0: Testing Strategy Selection
33
+
34
+ Start with:
35
+
36
+ ```
37
+ TESTING & VALIDATION WIZARD
38
+ ===========================
39
+
40
+ I'll help you set up testing for your Power BI solution.
41
+
42
+ What do you need to test?
43
+
44
+ 1. 📊 DAX Measures - Validate calculation logic
45
+ 2. 🔄 Data Transformations - Test Power Query results
46
+ 3. 📈 Full Model - End-to-end validation
47
+ 4. 🚀 Deployment - Pre-release checklist
48
+ 5. 🔍 Data Reconciliation - Compare to source systems
49
+ ```
50
+
51
+ Based on selection, guide through appropriate testing framework.
52
+
53
+ ---
54
+
55
+ ## PATH 1: DAX Measure Testing
56
+
57
+ ### Phase 1.1: Measure Inventory
58
+
59
+ ```
60
+ DAX MEASURE TESTING
61
+ ===================
62
+
63
+ First, let's identify what to test.
64
+
65
+ Please provide:
66
+ 1. The measure name
67
+ 2. The expected behavior
68
+ 3. Sample test cases (input → expected output)
69
+
70
+ Or paste the DAX code and I'll analyze testable scenarios.
71
+ ```
72
+
73
+ ### Phase 1.2: Test Case Design
74
+
75
+ ```
76
+ TEST CASE TEMPLATE
77
+ ==================
78
+
79
+ Measure: [Measure Name]
80
+ Purpose: [What it calculates]
81
+
82
+ TEST CASES:
83
+ -----------
84
+
85
+ | ID | Scenario | Filter Context | Expected | Actual | Status |
86
+ |----|----------|----------------|----------|--------|--------|
87
+ | T1 | Base case (no filters) | None | 100,000 | | |
88
+ | T2 | Single region | Region="North" | 25,000 | | |
89
+ | T3 | Date range | Year=2024 | 50,000 | | |
90
+ | T4 | Combined filters | Region="North", Year=2024 | 12,500 | | |
91
+ | T5 | Empty result | Region="Invalid" | BLANK | | |
92
+ | T6 | Edge case | Year=1900 | 0 or BLANK | | |
93
+
94
+ VALIDATION QUERY (paste in DAX Studio):
95
+ ---------------------------------------
96
+ ```
97
+
98
+ ### Phase 1.3: DAX Test Measures
99
+
100
+ Create validation measures to automate testing:
101
+
102
+ ```dax
103
+ // Test Harness Measure - Validates [Total Sales]
104
+ _Test_TotalSales_Result =
105
+ VAR _TestCases =
106
+ DATATABLE(
107
+ "TestID", STRING,
108
+ "Description", STRING,
109
+ "Expected", CURRENCY,
110
+ {
111
+ {"T1", "All Sales", 1000000},
112
+ {"T2", "North Region", 250000},
113
+ {"T3", "Year 2024", 500000}
114
+ }
115
+ )
116
+ VAR _Actual = [Total Sales]
117
+ VAR _Expected =
118
+ MAXX(
119
+ FILTER(_TestCases, [TestID] = SELECTEDVALUE('TestCase'[TestID])),
120
+ [Expected]
121
+ )
122
+ VAR _Tolerance = 0.01 // 1% tolerance
123
+ RETURN
124
+ IF(
125
+ ABS(_Actual - _Expected) / _Expected <= _Tolerance,
126
+ "✅ PASS",
127
+ "❌ FAIL: Expected " & FORMAT(_Expected, "#,##0") &
128
+ ", Got " & FORMAT(_Actual, "#,##0")
129
+ )
130
+ ```
131
+
132
+ ### Phase 1.4: Comparative Testing Pattern
133
+
134
+ ```dax
135
+ // Compare two calculation methods
136
+ _Test_Compare_Methods =
137
+ VAR _Method1 = [Sales_OriginalFormula]
138
+ VAR _Method2 = [Sales_NewFormula]
139
+ VAR _Difference = ABS(_Method1 - _Method2)
140
+ VAR _Tolerance = 0.01
141
+ RETURN
142
+ IF(
143
+ _Difference <= _Tolerance,
144
+ "✅ Methods match within tolerance",
145
+ "❌ Difference: " & FORMAT(_Difference, "#,##0.00")
146
+ )
147
+ ```
148
+
149
+ ---
150
+
151
+ ## PATH 2: Power Query Testing
152
+
153
+ ### Phase 2.1: Transformation Validation
154
+
155
+ ```
156
+ POWER QUERY TESTING
157
+ ===================
158
+
159
+ Testing transformations requires validating:
160
+
161
+ 1. Row counts (before/after)
162
+ 2. Column data types
163
+ 3. Null handling
164
+ 4. Data quality rules
165
+ 5. Business logic correctness
166
+
167
+ Which aspect do you want to test?
168
+ ```
169
+
170
+ ### Phase 2.2: Row Count Validation Query
171
+
172
+ ```powerquery
173
+ // Add to any query for row count tracking
174
+ let
175
+ Source = YourSourceQuery,
176
+
177
+ // Capture row count at each step
178
+ _Step1_RowCount = Table.RowCount(Source),
179
+
180
+ FilteredRows = Table.SelectRows(Source, each [Status] = "Active"),
181
+ _Step2_RowCount = Table.RowCount(FilteredRows),
182
+
183
+ // Validation: Ensure we didn't lose too many rows
184
+ _ValidationCheck =
185
+ if _Step2_RowCount / _Step1_RowCount < 0.5
186
+ then error "WARNING: Lost more than 50% of rows in filtering"
187
+ else FilteredRows,
188
+
189
+ // Add metadata for debugging
190
+ AddedRowCountColumn = Table.AddColumn(_ValidationCheck, "_DEBUG_RowCount", each _Step2_RowCount)
191
+ in
192
+ AddedRowCountColumn
193
+ ```
194
+
195
+ ### Phase 2.3: Data Type Validation
196
+
197
+ ```powerquery
198
+ // Validate expected data types
199
+ let
200
+ Source = YourTable,
201
+
202
+ // Define expected schema
203
+ ExpectedSchema = #table(
204
+ {"Column", "ExpectedType"},
205
+ {
206
+ {"CustomerID", type number},
207
+ {"CustomerName", type text},
208
+ {"OrderDate", type date},
209
+ {"Amount", type number}
210
+ }
211
+ ),
212
+
213
+ // Get actual schema
214
+ ActualSchema = Table.Schema(Source),
215
+
216
+ // Compare types
217
+ Validation = Table.AddColumn(
218
+ ExpectedSchema,
219
+ "ActualType",
220
+ each
221
+ let
222
+ match = Table.SelectRows(ActualSchema, (row) => row[Name] = [Column])
223
+ in
224
+ if Table.RowCount(match) = 0 then "MISSING"
225
+ else match{0}[Kind]
226
+ ),
227
+
228
+ // Check for mismatches
229
+ Mismatches = Table.SelectRows(Validation, each [ExpectedType] <> [ActualType])
230
+ in
231
+ if Table.RowCount(Mismatches) > 0
232
+ then error "Schema mismatch: " & Text.Combine(Mismatches[Column], ", ")
233
+ else Source
234
+ ```
235
+
236
+ ### Phase 2.4: Business Rule Validation
237
+
238
+ ```powerquery
239
+ // Validate business rules in Power Query
240
+ let
241
+ Source = YourTable,
242
+
243
+ // Rule 1: OrderDate must be in valid range
244
+ Rule1_ValidDates = Table.SelectRows(Source, each
245
+ [OrderDate] >= #date(2020, 1, 1) and
246
+ [OrderDate] <= Date.From(DateTime.LocalNow())
247
+ ),
248
+ InvalidDates = Table.RowCount(Source) - Table.RowCount(Rule1_ValidDates),
249
+
250
+ // Rule 2: Amount must be positive
251
+ Rule2_PositiveAmount = Table.SelectRows(Rule1_ValidDates, each [Amount] > 0),
252
+ InvalidAmounts = Table.RowCount(Rule1_ValidDates) - Table.RowCount(Rule2_PositiveAmount),
253
+
254
+ // Rule 3: CustomerID must not be null
255
+ Rule3_ValidCustomer = Table.SelectRows(Rule2_PositiveAmount, each [CustomerID] <> null),
256
+ InvalidCustomers = Table.RowCount(Rule2_PositiveAmount) - Table.RowCount(Rule3_ValidCustomer),
257
+
258
+ // Generate validation report
259
+ ValidationReport = #table(
260
+ {"Rule", "InvalidCount", "Status"},
261
+ {
262
+ {"Valid Dates", InvalidDates, if InvalidDates = 0 then "✅" else "⚠️"},
263
+ {"Positive Amount", InvalidAmounts, if InvalidAmounts = 0 then "✅" else "⚠️"},
264
+ {"Valid CustomerID", InvalidCustomers, if InvalidCustomers = 0 then "✅" else "⚠️"}
265
+ }
266
+ ),
267
+
268
+ // Return data if all rules pass, otherwise show report
269
+ TotalInvalid = InvalidDates + InvalidAmounts + InvalidCustomers,
270
+ Result = if TotalInvalid = 0 then Rule3_ValidCustomer else error Error.Record("Validation Failed", ValidationReport)
271
+ in
272
+ Result
273
+ ```
274
+
275
+ ---
276
+
277
+ ## PATH 3: Full Model Testing
278
+
279
+ ### Phase 3.1: Model Validation Checklist
280
+
281
+ ```
282
+ FULL MODEL VALIDATION
283
+ =====================
284
+
285
+ □ DATA LAYER
286
+ □ All tables loaded successfully
287
+ □ Row counts match expected
288
+ □ No duplicate primary keys
289
+ □ Foreign keys have matching parents
290
+ □ Date table is complete and marked
291
+
292
+ □ RELATIONSHIP LAYER
293
+ □ All relationships active
294
+ □ Cardinality is correct (1:*, *:1)
295
+ □ Cross-filter direction appropriate
296
+ □ No ambiguous paths
297
+
298
+ □ MEASURE LAYER
299
+ □ All measures return values
300
+ □ Measures handle empty context
301
+ □ Time intelligence works correctly
302
+ □ Percentages sum appropriately
303
+
304
+ □ VISUAL LAYER
305
+ □ All visuals render
306
+ □ Filters work as expected
307
+ □ Drill-through functions
308
+ □ Tooltips display correctly
309
+
310
+ Would you like me to generate validation queries for any section?
311
+ ```
312
+
313
+ ### Phase 3.2: Relationship Integrity Check
314
+
315
+ ```dax
316
+ // Check for orphan records (FK without matching PK)
317
+ _Validation_OrphanCheck =
318
+ VAR _OrphanCount =
319
+ COUNTROWS(
320
+ FILTER(
321
+ FactSales,
322
+ ISBLANK(RELATED(DimCustomer[CustomerKey]))
323
+ )
324
+ )
325
+ RETURN
326
+ IF(
327
+ _OrphanCount = 0,
328
+ "✅ No orphan records",
329
+ "❌ " & _OrphanCount & " records without matching customer"
330
+ )
331
+ ```
332
+
333
+ ```dax
334
+ // Check for duplicate keys in dimension
335
+ _Validation_DuplicateKeys =
336
+ VAR _TotalRows = COUNTROWS(DimCustomer)
337
+ VAR _UniqueKeys = DISTINCTCOUNT(DimCustomer[CustomerKey])
338
+ RETURN
339
+ IF(
340
+ _TotalRows = _UniqueKeys,
341
+ "✅ No duplicate keys",
342
+ "❌ " & (_TotalRows - _UniqueKeys) & " duplicate keys found"
343
+ )
344
+ ```
345
+
346
+ ### Phase 3.3: Date Table Validation
347
+
348
+ ```dax
349
+ // Comprehensive date table validation
350
+ _Validation_DateTable =
351
+ VAR _MinDate = MIN('Date'[Date])
352
+ VAR _MaxDate = MAX('Date'[Date])
353
+ VAR _ExpectedRows = DATEDIFF(_MinDate, _MaxDate, DAY) + 1
354
+ VAR _ActualRows = COUNTROWS('Date')
355
+ VAR _HasGaps = _ExpectedRows <> _ActualRows
356
+ VAR _HasYear = CONTAINSSTRING(CONCATENATEX('Date', [Year], ","), "2024")
357
+ VAR _HasMonth = NOT ISBLANK(MAX('Date'[MonthName]))
358
+ RETURN
359
+ "Date Range: " & FORMAT(_MinDate, "yyyy-mm-dd") & " to " & FORMAT(_MaxDate, "yyyy-mm-dd") &
360
+ " | Rows: " & _ActualRows & "/" & _ExpectedRows &
361
+ " | Gaps: " & IF(_HasGaps, "❌ YES", "✅ NO")
362
+ ```
363
+
364
+ ---
365
+
366
+ ## PATH 4: Deployment Testing
367
+
368
+ ### Phase 4.1: Pre-Deployment Checklist
369
+
370
+ ```
371
+ DEPLOYMENT CHECKLIST
372
+ ====================
373
+
374
+ BEFORE PUBLISHING:
375
+ ------------------
376
+ □ Remove all debug/test measures
377
+ □ Hide unnecessary columns
378
+ □ Verify RLS roles configured
379
+ □ Check data source credentials
380
+ □ Validate refresh schedule compatible
381
+ □ Review model size (< 1GB recommended)
382
+ □ Test with "View as" for each role
383
+
384
+ AFTER PUBLISHING:
385
+ -----------------
386
+ □ Verify data refreshed successfully
387
+ □ Test all report pages load
388
+ □ Validate RLS with actual users
389
+ □ Check scheduled refresh time
390
+ □ Verify gateway connection (if on-prem)
391
+ □ Test mobile view if applicable
392
+ □ Validate drill-through and navigation
393
+
394
+ DOCUMENTATION:
395
+ --------------
396
+ □ Update data dictionary
397
+ □ Document any known limitations
398
+ □ Update change log
399
+ □ Notify stakeholders
400
+
401
+ Ready to proceed? I can help with any of these steps.
402
+ ```
403
+
404
+ ### Phase 4.2: Regression Test Suite
405
+
406
+ ```dax
407
+ // Master regression test measure
408
+ _Regression_TestSuite =
409
+ VAR _Tests = {
410
+ ("Sales Total", [_Test_SalesTotal]),
411
+ ("YTD Calculation", [_Test_YTD]),
412
+ ("Margin %", [_Test_Margin]),
413
+ ("Customer Count", [_Test_CustomerCount])
414
+ }
415
+ VAR _Results =
416
+ CONCATENATEX(
417
+ FILTER(
418
+ SELECTCOLUMNS(
419
+ _Tests,
420
+ "TestName", [Value1],
421
+ "Result", [Value2]
422
+ ),
423
+ NOT(CONTAINSSTRING([Result], "✅"))
424
+ ),
425
+ [TestName] & ": " & [Result],
426
+ UNICHAR(10)
427
+ )
428
+ RETURN
429
+ IF(
430
+ ISBLANK(_Results),
431
+ "✅ All " & COUNTROWS(_Tests) & " tests passed",
432
+ "❌ Failed tests:" & UNICHAR(10) & _Results
433
+ )
434
+ ```
435
+
436
+ ---
437
+
438
+ ## PATH 5: Data Reconciliation
439
+
440
+ ### Phase 5.1: Source System Comparison
441
+
442
+ ```
443
+ DATA RECONCILIATION
444
+ ===================
445
+
446
+ Comparing Power BI data to source systems.
447
+
448
+ What are you comparing?
449
+ 1. Total record counts
450
+ 2. Sum of a numeric field
451
+ 3. Distinct value counts
452
+ 4. Full row-by-row comparison
453
+ 5. Date range validation
454
+ ```
455
+
456
+ ### Phase 5.2: Reconciliation Measures
457
+
458
+ ```dax
459
+ // Compare PBI totals to known source values
460
+ _Reconciliation_SalesTotal =
461
+ VAR _PBI_Total = [Total Sales]
462
+ VAR _Source_Total = 1234567.89 // From source system report
463
+ VAR _Variance = _PBI_Total - _Source_Total
464
+ VAR _VariancePct = DIVIDE(_Variance, _Source_Total)
465
+ RETURN
466
+ "PBI: " & FORMAT(_PBI_Total, "$#,##0") &
467
+ " | Source: " & FORMAT(_Source_Total, "$#,##0") &
468
+ " | Variance: " & FORMAT(_VariancePct, "0.00%") &
469
+ IF(ABS(_VariancePct) <= 0.001, " ✅", " ❌")
470
+ ```
471
+
472
+ ### Phase 5.3: Row Count Reconciliation Table
473
+
474
+ ```dax
475
+ // Create reconciliation summary table
476
+ Reconciliation_Summary =
477
+ ADDCOLUMNS(
478
+ SUMMARIZE(
479
+ UNION(
480
+ ROW("Table", "FactSales", "Count", COUNTROWS(FactSales)),
481
+ ROW("Table", "DimCustomer", "Count", COUNTROWS(DimCustomer)),
482
+ ROW("Table", "DimProduct", "Count", COUNTROWS(DimProduct)),
483
+ ROW("Table", "DimDate", "Count", COUNTROWS('Date'))
484
+ ),
485
+ [Table], [Count]
486
+ ),
487
+ "Source_Count",
488
+ SWITCH(
489
+ [Table],
490
+ "FactSales", 1000000, // Expected from source
491
+ "DimCustomer", 50000,
492
+ "DimProduct", 2500,
493
+ "DimDate", 3652,
494
+ 0
495
+ ),
496
+ "Variance", [Count] - [Source_Count],
497
+ "Status", IF([Count] = [Source_Count], "✅", "❌")
498
+ )
499
+ ```
500
+
501
+ ---
502
+
503
+ ## TEST REPORT TEMPLATES
504
+
505
+ ### Daily Validation Report
506
+
507
+ ```dax
508
+ _Daily_ValidationReport =
509
+ VAR _RefreshTime = MAX('_RefreshLog'[RefreshDateTime])
510
+ VAR _RowCounts = [_Validation_RowCounts]
511
+ VAR _Measures = [_Validation_KeyMeasures]
512
+ VAR _Relationships = [_Validation_Relationships]
513
+ RETURN
514
+ "================================
515
+ DAILY VALIDATION REPORT
516
+ " & FORMAT(_RefreshTime, "yyyy-mm-dd hh:mm") & "
517
+ ================================
518
+
519
+ ROW COUNTS:
520
+ " & _RowCounts & "
521
+
522
+ KEY MEASURES:
523
+ " & _Measures & "
524
+
525
+ RELATIONSHIPS:
526
+ " & _Relationships & "
527
+
528
+ ================================"
529
+ ```
530
+
531
+ ### Deployment Sign-Off Template
532
+
533
+ ```markdown
534
+ # Deployment Sign-Off
535
+
536
+ **Model:** [Model Name]
537
+ **Version:** [Version]
538
+ **Date:** [Date]
539
+ **Tested By:** [Name]
540
+
541
+ ## Test Results Summary
542
+
543
+ | Category | Tests Run | Passed | Failed |
544
+ |----------|-----------|--------|--------|
545
+ | DAX Measures | 15 | 15 | 0 |
546
+ | Data Quality | 8 | 8 | 0 |
547
+ | Relationships | 5 | 5 | 0 |
548
+ | Reconciliation | 4 | 4 | 0 |
549
+ | **TOTAL** | **32** | **32** | **0** |
550
+
551
+ ## Regression Tests
552
+ - [ ] All existing reports still function
553
+ - [ ] Performance within acceptable range
554
+ - [ ] No broken visuals
555
+
556
+ ## Approvals
557
+ - [ ] Technical Review: _____________
558
+ - [ ] Business Review: _____________
559
+ - [ ] Go Live Approved: _____________
560
+
561
+ ## Notes
562
+ [Any observations or known issues]
563
+ ```
564
+
565
+ ---
566
+
567
+ ## AUTOMATED TESTING SETUP
568
+
569
+ ### Power Automate Integration
570
+
571
+ ```
572
+ AUTOMATED TEST FLOW
573
+ ===================
574
+
575
+ 1. Trigger: After Scheduled Refresh
576
+ 2. Run DAX query via Power BI REST API
577
+ 3. Check all _Test_* measures
578
+ 4. If any fail:
579
+ - Send Teams notification
580
+ - Log to SharePoint list
581
+ - Optionally pause further refreshes
582
+ 5. If all pass:
583
+ - Log success
584
+ - Update dashboard status
585
+ ```
586
+
587
+ ### Test Results Table (for historical tracking)
588
+
589
+ ```powerquery
590
+ // Create test results log table
591
+ let
592
+ Source = #table(
593
+ {"TestDate", "TestName", "Result", "Value", "Expected", "Variance"},
594
+ {}
595
+ ),
596
+ SetTypes = Table.TransformColumnTypes(Source, {
597
+ {"TestDate", type datetime},
598
+ {"TestName", type text},
599
+ {"Result", type text},
600
+ {"Value", type number},
601
+ {"Expected", type number},
602
+ {"Variance", type number}
603
+ })
604
+ in
605
+ SetTypes
606
+ ```
607
+
608
+ ---
609
+
610
+ ## ANTI-PATTERNS
611
+
612
+ | Anti-Pattern | Problem | Better Approach |
613
+ |--------------|---------|-----------------|
614
+ | No testing | Errors found in production | Implement test measures |
615
+ | Manual testing only | Doesn't scale | Automate with DAX test harness |
616
+ | Testing in prod | Risky | Use development workspace |
617
+ | No baseline | Can't detect regression | Document expected values |
618
+ | Ignoring edge cases | Surprises in production | Test empty, null, extreme values |
619
+
620
+ ---
621
+
622
+ ## Complexity Adaptation
623
+
624
+ Adjust depth based on `config.json → experienceLevel`:
625
+ - **beginner**: Step-by-step with explanations, reference library examples
626
+ - **intermediate**: Standard depth, explain non-obvious decisions
627
+ - **advanced**: Concise, skip basics, focus on edge cases and optimization
628
+
629
+ ## Related Skills
630
+
631
+ - `/dax` — DAX patterns to test
632
+ - `/dax-doctor` — Debug failing tests
633
+ - `/data-quality` — Data validation patterns
634
+ - `/rls-design` — Test security configurations
635
+
636
+ ---
637
+
638
+ ## RELATED RESOURCES
639
+
640
+ - [Data Quality Skill](../data-quality/SKILL.md)
641
+ - [Query Performance Skill](../query-performance/SKILL.md)
642
+ - [DAX Skill](../dax/SKILL.md)
643
+ - [Power Query Skill](../power-query/SKILL.md)