@codeyam/codeyam-cli 0.1.0-staging.c9dc00c → 0.1.0-staging.d3e886e

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 (189) hide show
  1. package/analyzer-template/.build-info.json +7 -7
  2. package/analyzer-template/log.txt +3 -3
  3. package/analyzer-template/package.json +1 -1
  4. package/analyzer-template/packages/ai/index.ts +1 -0
  5. package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +14 -0
  6. package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +101 -0
  7. package/analyzer-template/packages/ai/src/lib/astScopes/sharedPatterns.ts +28 -0
  8. package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +6 -0
  9. package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +172 -8
  10. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.ts +70 -19
  11. package/analyzer-template/packages/ai/src/lib/dataStructureChunking.ts +40 -13
  12. package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +32 -5
  13. package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +134 -2
  14. package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionals.ts +359 -142
  15. package/analyzer-template/packages/ai/src/lib/mergeJsonTypeDefinitions.ts +5 -0
  16. package/analyzer-template/packages/ai/src/lib/promptGenerators/collapseNullableObjects.ts +118 -0
  17. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.ts +24 -4
  18. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +18 -0
  19. package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +50 -25
  20. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +153 -76
  21. package/analyzer-template/packages/database/src/lib/kysely/tables/debugReportsTable.ts +1 -1
  22. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.d.ts +1 -1
  23. package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.d.ts.map +1 -1
  24. package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js +93 -2
  25. package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js.map +1 -1
  26. package/analyzer-template/packages/utils/src/lib/fs/rsyncCopy.ts +108 -2
  27. package/analyzer-template/project/constructMockCode.ts +2 -2
  28. package/analyzer-template/project/writeScenarioComponents.ts +14 -0
  29. package/background/src/lib/virtualized/project/constructMockCode.js +2 -2
  30. package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
  31. package/background/src/lib/virtualized/project/writeScenarioComponents.js +10 -0
  32. package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
  33. package/codeyam-cli/scripts/apply-setup.js +1 -1
  34. package/codeyam-cli/src/codeyam-cli.js +18 -2
  35. package/codeyam-cli/src/codeyam-cli.js.map +1 -1
  36. package/codeyam-cli/src/commands/analyze.js +2 -2
  37. package/codeyam-cli/src/commands/analyze.js.map +1 -1
  38. package/codeyam-cli/src/commands/default.js +18 -17
  39. package/codeyam-cli/src/commands/default.js.map +1 -1
  40. package/codeyam-cli/src/commands/init.js +27 -93
  41. package/codeyam-cli/src/commands/init.js.map +1 -1
  42. package/codeyam-cli/src/commands/memory.js +9 -9
  43. package/codeyam-cli/src/commands/memory.js.map +1 -1
  44. package/codeyam-cli/src/commands/setup-simulations.js +1 -1
  45. package/codeyam-cli/src/commands/verify.js +12 -2
  46. package/codeyam-cli/src/commands/verify.js.map +1 -1
  47. package/codeyam-cli/src/utils/__tests__/npmVersionCheck.test.js +179 -0
  48. package/codeyam-cli/src/utils/__tests__/npmVersionCheck.test.js.map +1 -0
  49. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +11 -11
  50. package/codeyam-cli/src/utils/backgroundServer.js +90 -23
  51. package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
  52. package/codeyam-cli/src/utils/generateReport.js +2 -2
  53. package/codeyam-cli/src/utils/install-skills.js +13 -13
  54. package/codeyam-cli/src/utils/labsAutoCheck.js +0 -29
  55. package/codeyam-cli/src/utils/labsAutoCheck.js.map +1 -1
  56. package/codeyam-cli/src/utils/npmVersionCheck.js +76 -0
  57. package/codeyam-cli/src/utils/npmVersionCheck.js.map +1 -0
  58. package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js +4 -4
  59. package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js.map +1 -1
  60. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js +2 -2
  61. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js.map +1 -1
  62. package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js +4 -4
  63. package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js.map +1 -1
  64. package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js +3 -3
  65. package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js.map +1 -1
  66. package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js +23 -23
  67. package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js.map +1 -1
  68. package/codeyam-cli/src/utils/rules/ruleState.js +10 -10
  69. package/codeyam-cli/src/utils/rules/ruleState.js.map +1 -1
  70. package/codeyam-cli/src/utils/rules/staleness.js +6 -6
  71. package/codeyam-cli/src/utils/rules/staleness.js.map +1 -1
  72. package/codeyam-cli/src/utils/serverState.js +37 -10
  73. package/codeyam-cli/src/utils/serverState.js.map +1 -1
  74. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +7 -7
  75. package/codeyam-cli/src/webserver/__tests__/dependency-smoke.test.js +66 -0
  76. package/codeyam-cli/src/webserver/__tests__/dependency-smoke.test.js.map +1 -0
  77. package/codeyam-cli/src/webserver/app/lib/dbNotifier.js.map +1 -1
  78. package/codeyam-cli/src/webserver/backgroundServer.js +26 -7
  79. package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
  80. package/codeyam-cli/src/webserver/bootstrap.js +11 -0
  81. package/codeyam-cli/src/webserver/bootstrap.js.map +1 -1
  82. package/codeyam-cli/src/webserver/build/client/assets/{CopyButton-CA3JxPb7.js → CopyButton-jNYXRRNI.js} +1 -1
  83. package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-B86KKU7e.js → EntityItem-bwuHPyTa.js} +1 -1
  84. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-B5ctlSYt.js → EntityTypeBadge-CvzqMxcu.js} +1 -1
  85. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-BqY8gDAW.js → EntityTypeIcon-BH0XDim7.js} +1 -1
  86. package/codeyam-cli/src/webserver/build/client/assets/{InlineSpinner-ClaLpuOo.js → InlineSpinner-EhOseatT.js} +1 -1
  87. package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-BDhPilK7.js → InteractivePreview-yjIHlOGa.js} +2 -2
  88. package/codeyam-cli/src/webserver/build/client/assets/{LibraryFunctionPreview-VeqEBv9v.js → LibraryFunctionPreview-Cq5o8jL4.js} +1 -1
  89. package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-Bs7Nn1Jr.js → LoadingDots-BvMu2i-g.js} +1 -1
  90. package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-Bm3PmcCz.js → LogViewer-kgBTLoJD.js} +1 -1
  91. package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-C6PKeMYR.js → ReportIssueModal-BzPgx-xO.js} +2 -2
  92. package/codeyam-cli/src/webserver/build/client/assets/{SafeScreenshot-Gq3Ocjo6.js → SafeScreenshot-CwZrv-Ok.js} +1 -1
  93. package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-BNLaXBHR.js → ScenarioViewer-BX2Ny2Qj.js} +2 -2
  94. package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-CiwXDxLh.js → TruncatedFilePath-CDpEprKa.js} +1 -1
  95. package/codeyam-cli/src/webserver/build/client/assets/{_index-B3TDXxnk.js → _index-BRx8ZGZo.js} +1 -1
  96. package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-BtBFH820.js → activity.(_tab)-4S4yPfFw.js} +1 -1
  97. package/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-DHKuQSmR.js +17 -0
  98. package/codeyam-cli/src/webserver/build/client/assets/{book-open-PttOB2SF.js → book-open-D4IPYH_y.js} +1 -1
  99. package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-TJp6ofnp.js → chevron-down-CG65viiV.js} +1 -1
  100. package/codeyam-cli/src/webserver/build/client/assets/{chunk-JZWAC4HX-JE9ZIoBl.js → chunk-JZWAC4HX-DB3aFuEO.js} +9 -9
  101. package/codeyam-cli/src/webserver/build/client/assets/{circle-check-CXhHQYrI.js → circle-check-igfMr5DY.js} +1 -1
  102. package/codeyam-cli/src/webserver/build/client/assets/{copy-6y9ALfGT.js → copy-Coc4o_8c.js} +1 -1
  103. package/codeyam-cli/src/webserver/build/client/assets/{createLucideIcon-Ca9fAY46.js → createLucideIcon-D1zB-pYc.js} +1 -1
  104. package/codeyam-cli/src/webserver/build/client/assets/{dev.empty-C5lqplTC.js → dev.empty-JTAjQ54M.js} +1 -1
  105. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-n38keI1k.js → entity._sha._-B0h9AqE6.js} +2 -2
  106. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-CBoafmVs.js → entity._sha.scenarios._scenarioId.fullscreen-DjLxr2JB.js} +1 -1
  107. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.create-scenario-DGgZjdFg.js → entity._sha_.create-scenario-CtYowLOt.js} +1 -1
  108. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-38yPijoD.js → entity._sha_.edit._scenarioId-PePWg17F.js} +1 -1
  109. package/codeyam-cli/src/webserver/build/client/assets/{entry.client-BSHEfydn.js → entry.client-I-Wo99C_.js} +1 -1
  110. package/codeyam-cli/src/webserver/build/client/assets/{fileTableUtils-DCPhhSMo.js → fileTableUtils-9sMMAiWJ.js} +1 -1
  111. package/codeyam-cli/src/webserver/build/client/assets/{files-0N0YJQv7.js → files-Co65J0s3.js} +1 -1
  112. package/codeyam-cli/src/webserver/build/client/assets/{git-DXnyr8uP.js → git-BdHOxVfg.js} +1 -1
  113. package/codeyam-cli/src/webserver/build/client/assets/globals-CCgBKWy4.css +1 -0
  114. package/codeyam-cli/src/webserver/build/client/assets/{index-ChN9-fAY.js → index-CUM5iXwc.js} +1 -1
  115. package/codeyam-cli/src/webserver/build/client/assets/{index-CcsFv748.js → index-_417gcQW.js} +1 -1
  116. package/codeyam-cli/src/webserver/build/client/assets/labs-BK0C1H1T.js +1 -0
  117. package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-CTqLEAGU.js → loader-circle-TzRHMVog.js} +1 -1
  118. package/codeyam-cli/src/webserver/build/client/assets/manifest-390cb8fa.js +1 -0
  119. package/codeyam-cli/src/webserver/build/client/assets/memory-CzZySbBE.js +78 -0
  120. package/codeyam-cli/src/webserver/build/client/assets/{pause-D6vreykR.js → pause-hjzB7t2z.js} +1 -1
  121. package/codeyam-cli/src/webserver/build/client/assets/root-DnbDhvTU.js +62 -0
  122. package/codeyam-cli/src/webserver/build/client/assets/{search-B8VUL8nl.js → search-DcAwD_Ln.js} +1 -1
  123. package/codeyam-cli/src/webserver/build/client/assets/settings-CclxrcPK.js +1 -0
  124. package/codeyam-cli/src/webserver/build/client/assets/{simulations-CPoAg7Zo.js → simulations-DVNJVQgD.js} +1 -1
  125. package/codeyam-cli/src/webserver/build/client/assets/{terminal-BrCP7uQo.js → terminal-DbEAHMbA.js} +1 -1
  126. package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-BZz2NjYa.js → triangle-alert-CAD5b1o_.js} +1 -1
  127. package/codeyam-cli/src/webserver/build/client/assets/{useCustomSizes-DNwUduNu.js → useCustomSizes-BqgrAzs3.js} +1 -1
  128. package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-COky1GVF.js → useLastLogLine-DAFqfEDH.js} +1 -1
  129. package/codeyam-cli/src/webserver/build/client/assets/{useReportContext-CpZgwliL.js → useReportContext-DZlYx2c4.js} +1 -1
  130. package/codeyam-cli/src/webserver/build/client/assets/{useToast-Bv9JFvUO.js → useToast-ihdMtlf6.js} +1 -1
  131. package/codeyam-cli/src/webserver/build/server/assets/{index-Cz2RkDCa.js → index-CxaRxKVt.js} +1 -1
  132. package/codeyam-cli/src/webserver/build/server/assets/server-build-D4DT0nM_.js +259 -0
  133. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  134. package/codeyam-cli/src/webserver/build-info.json +5 -5
  135. package/codeyam-cli/templates/{codeyam:debug.md → codeyam-debug.md} +1 -1
  136. package/codeyam-cli/templates/{codeyam:diagnose.md → codeyam-diagnose.md} +1 -1
  137. package/codeyam-cli/templates/codeyam-memory-hook.sh +14 -14
  138. package/codeyam-cli/templates/{codeyam:memory.md → codeyam-memory.md} +16 -23
  139. package/codeyam-cli/templates/{codeyam:new-rule.md → codeyam-new-rule.md} +1 -1
  140. package/codeyam-cli/templates/{codeyam:setup.md → codeyam-setup.md} +1 -1
  141. package/codeyam-cli/templates/{codeyam:sim.md → codeyam-sim.md} +1 -1
  142. package/codeyam-cli/templates/{codeyam:test.md → codeyam-test.md} +1 -1
  143. package/codeyam-cli/templates/{codeyam:verify.md → codeyam-verify.md} +1 -1
  144. package/codeyam-cli/templates/rule-reflection-hook.py +5 -5
  145. package/codeyam-cli/templates/rules-instructions.md +11 -15
  146. package/package.json +8 -8
  147. package/packages/ai/index.js +1 -1
  148. package/packages/ai/index.js.map +1 -1
  149. package/packages/ai/src/lib/analyzeScope.js +14 -0
  150. package/packages/ai/src/lib/analyzeScope.js.map +1 -1
  151. package/packages/ai/src/lib/astScopes/processExpression.js +78 -1
  152. package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
  153. package/packages/ai/src/lib/astScopes/sharedPatterns.js +25 -0
  154. package/packages/ai/src/lib/astScopes/sharedPatterns.js.map +1 -1
  155. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +124 -7
  156. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
  157. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js +59 -17
  158. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js.map +1 -1
  159. package/packages/ai/src/lib/dataStructureChunking.js +30 -11
  160. package/packages/ai/src/lib/dataStructureChunking.js.map +1 -1
  161. package/packages/ai/src/lib/generateEntityScenarioData.js +22 -3
  162. package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
  163. package/packages/ai/src/lib/generateExecutionFlows.js +97 -2
  164. package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
  165. package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js +242 -81
  166. package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js.map +1 -1
  167. package/packages/ai/src/lib/mergeJsonTypeDefinitions.js +5 -0
  168. package/packages/ai/src/lib/mergeJsonTypeDefinitions.js.map +1 -1
  169. package/packages/ai/src/lib/promptGenerators/collapseNullableObjects.js +97 -0
  170. package/packages/ai/src/lib/promptGenerators/collapseNullableObjects.js.map +1 -0
  171. package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js +17 -2
  172. package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js.map +1 -1
  173. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +11 -1
  174. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
  175. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +42 -13
  176. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
  177. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +123 -67
  178. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
  179. package/packages/utils/src/lib/fs/rsyncCopy.js +93 -2
  180. package/packages/utils/src/lib/fs/rsyncCopy.js.map +1 -1
  181. package/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-CN61MOMa.js +0 -11
  182. package/codeyam-cli/src/webserver/build/client/assets/api.labs-survey-l0sNRNKZ.js +0 -1
  183. package/codeyam-cli/src/webserver/build/client/assets/globals-EVn6Z9pz.css +0 -1
  184. package/codeyam-cli/src/webserver/build/client/assets/labs-CmBYA0PH.js +0 -1
  185. package/codeyam-cli/src/webserver/build/client/assets/manifest-aa4ff97b.js +0 -1
  186. package/codeyam-cli/src/webserver/build/client/assets/memory-BSlqS1QA.js +0 -81
  187. package/codeyam-cli/src/webserver/build/client/assets/root-DVAbJY8B.js +0 -62
  188. package/codeyam-cli/src/webserver/build/client/assets/settings-BK-cnzp-.js +0 -1
  189. package/codeyam-cli/src/webserver/build/server/assets/server-build-CUVsWicu.js +0 -260
@@ -259,11 +259,15 @@ function cleanSourceDataPath(sourceDataPath: string): string | null {
259
259
  sourceDataPath.match(/\.functionCallReturnValue/g) || []
260
260
  ).length;
261
261
 
262
- // If there are multiple functionCallReturnValue occurrences, this is a chained call
263
- // (e.g., fetch(...).functionCallReturnValue.json().functionCallReturnValue.data)
262
+ // For chained function calls (e.g., fetch().json()) or paths with non-standard
263
+ // fn call patterns, return the original path so findInAttributesMapForPath can
264
+ // try to look it up in fullToShortPathMap. If it doesn't match, the caller
265
+ // falls through to fallback resolution anyway.
264
266
  if (fnCallReturnValues > 1 || emptyFnCalls !== 1) {
265
- // Multiple function calls - return null to use fallback resolution
266
- return null;
267
+ console.log(
268
+ `[cleanSourceDataPath] chained/non-standard path (fnCallRVs=${fnCallReturnValues}, emptyFnCalls=${emptyFnCalls}), returning original: "${sourceDataPath}"`,
269
+ );
270
+ return sourceDataPath;
267
271
  }
268
272
 
269
273
  // Find the "()" which marks the function call
@@ -308,6 +312,85 @@ function stripLengthSuffix(path: string): string {
308
312
  return path;
309
313
  }
310
314
 
315
+ /**
316
+ * Remove contradictory required values from a compound flow.
317
+ *
318
+ * When a lifecycle boolean (like isLoadingAuditData) is traced to a fetch call's
319
+ * return value, a negated condition (!isLoadingAuditData) produces "falsy" on
320
+ * the fetch path. But if another condition in the same compound requires data
321
+ * from a sub-path of that fetch (e.g., topPaths length > 0), the "falsy" on the
322
+ * parent path contradicts it — a null/falsy response has no .json() to call.
323
+ *
324
+ * This function removes "falsy" required values whose attributePath is a prefix
325
+ * of another required value's attributePath. The child data requirement already
326
+ * implies the parent (fetch) succeeded.
327
+ */
328
+ function removeContradictoryFalsyValues(
329
+ requiredValues: ExecutionFlow['requiredValues'],
330
+ ): ExecutionFlow['requiredValues'] {
331
+ return requiredValues.filter((rv) => {
332
+ if (rv.comparison === 'falsy') {
333
+ const hasChildRequirement = requiredValues.some(
334
+ (other) =>
335
+ other !== rv &&
336
+ other.attributePath.startsWith(rv.attributePath + '.'),
337
+ );
338
+ if (hasChildRequirement) {
339
+ return false;
340
+ }
341
+ }
342
+ return true;
343
+ });
344
+ }
345
+
346
+ /**
347
+ * Generate a human-readable description snippet for a required value,
348
+ * incorporating the comparison type so the LLM understands the intent.
349
+ */
350
+ function describeRequiredValue(rv: ExecutionFlow['requiredValues'][0]): string {
351
+ const name = generateNameFromPath(rv.attributePath).toLowerCase();
352
+ switch (rv.comparison) {
353
+ case 'truthy':
354
+ return `${name} is present`;
355
+ case 'falsy':
356
+ return `${name} is absent`;
357
+ case 'length>':
358
+ return rv.value === '0'
359
+ ? `${name} has items`
360
+ : `${name} has more than ${rv.value} items`;
361
+ case 'length<':
362
+ return `${name} has fewer than ${rv.value} items`;
363
+ case 'equals':
364
+ return `${name} is ${rv.value}`;
365
+ case 'exists':
366
+ return `${name} exists`;
367
+ case 'not-exists':
368
+ return `${name} does not exist`;
369
+ default:
370
+ return `${name} is ${rv.value}`;
371
+ }
372
+ }
373
+
374
+ /**
375
+ * Check whether a resolved path has child entries in the fullToShortPathMap.
376
+ *
377
+ * When a lifecycle boolean (e.g., isLoadingAuditData) resolves to a parent path
378
+ * like fetch(...).functionCallReturnValue, and that path has children (like
379
+ * .json().functionCallReturnValue.topPaths), individual truthy/falsy flows on
380
+ * the parent are misleading. Compound flows with specific child requirements
381
+ * provide better guidance for mock data generation.
382
+ */
383
+ function hasChildPathsInMap(
384
+ resolvedPath: string,
385
+ fullToShortPathMap: Record<string, string>,
386
+ ): boolean {
387
+ return Object.keys(fullToShortPathMap).some(
388
+ (fullPath) =>
389
+ fullPath.startsWith(resolvedPath + '.') ||
390
+ fullPath.startsWith(resolvedPath + '['),
391
+ );
392
+ }
393
+
311
394
  /**
312
395
  * Extract the controllable base path from a path that may contain method calls.
313
396
  *
@@ -350,13 +433,16 @@ function extractControllableBase(path: string): string {
350
433
  * The sourceDataPath contains full paths (e.g., "useLoaderData<LoaderData>().functionCallReturnValue.entity.sha")
351
434
  * The fullToShortPathMap maps full paths to short paths
352
435
  */
353
- function findInAttributesMapForPath(
436
+ export function findInAttributesMapForPath(
354
437
  path: string,
355
438
  attributesMap: Record<string, string>,
356
439
  fullToShortPathMap: Record<string, string>,
357
440
  ): string | null {
358
441
  // Direct match in attributesMap (already a short path)
359
442
  if (path in attributesMap) {
443
+ console.log(
444
+ `[findInAttributesMapForPath] "${path}" → DIRECT match in attributesMap`,
445
+ );
360
446
  return path;
361
447
  }
362
448
 
@@ -365,19 +451,31 @@ function findInAttributesMapForPath(
365
451
  if (path in fullToShortPathMap) {
366
452
  const shortPath = fullToShortPathMap[path];
367
453
  if (shortPath in attributesMap) {
454
+ console.log(
455
+ `[findInAttributesMapForPath] "${path}" → fullToShortPathMap match: shortPath="${shortPath}" found in attributesMap`,
456
+ );
368
457
  return path; // Return FULL path to preserve data source context
369
458
  }
459
+ console.log(
460
+ `[findInAttributesMapForPath] "${path}" → fullToShortPathMap match shortPath="${shortPath}" but NOT in attributesMap`,
461
+ );
370
462
  }
371
463
 
372
464
  // Normalized match (array indices [N] → [])
373
465
  const normalizedPath = path.replace(/\[\d+\]/g, '[]');
374
466
  if (normalizedPath !== path) {
375
467
  if (normalizedPath in attributesMap) {
468
+ console.log(
469
+ `[findInAttributesMapForPath] "${path}" → normalized "${normalizedPath}" DIRECT match in attributesMap`,
470
+ );
376
471
  return normalizedPath;
377
472
  }
378
473
  if (normalizedPath in fullToShortPathMap) {
379
474
  const shortPath = fullToShortPathMap[normalizedPath];
380
475
  if (shortPath in attributesMap) {
476
+ console.log(
477
+ `[findInAttributesMapForPath] "${path}" → normalized "${normalizedPath}" fullToShortPathMap match: shortPath="${shortPath}"`,
478
+ );
381
479
  return normalizedPath; // Return normalized FULL path
382
480
  }
383
481
  }
@@ -389,22 +487,75 @@ function findInAttributesMapForPath(
389
487
  // and we need to find matching short path prefix
390
488
  for (const attrPath of Object.keys(attributesMap)) {
391
489
  if (path.startsWith(attrPath + '.') || path.startsWith(attrPath + '[')) {
392
- // The path is a child of a known attribute path
490
+ console.log(
491
+ `[findInAttributesMapForPath] "${path}" → PREFIX match: starts with attributesMap key "${attrPath}"`,
492
+ );
393
493
  return path;
394
494
  }
395
495
  }
396
496
 
397
497
  // Try suffix matching: if the path ends with ".X.Y.Z" and attributesMap has "X.Y.Z"
398
498
  // Return the FULL input path to preserve data source context
399
- for (const attrPath of Object.keys(attributesMap)) {
400
- if (
401
- path.endsWith('.' + attrPath) ||
402
- path.endsWith('.' + attrPath.replace(/\[\d+\]/g, '[]'))
403
- ) {
404
- return path; // Return FULL path, not short attrPath
499
+ // Skip suffix matching for chained function calls (multiple .functionCallReturnValue segments)
500
+ // to avoid false matches: e.g., fetch(...).json().functionCallReturnValue.data falsely matching
501
+ // "data" from a completely different data source like useFetcher
502
+ const fnCallReturnValueCount = (
503
+ path.match(/\.functionCallReturnValue/g) || []
504
+ ).length;
505
+ if (fnCallReturnValueCount <= 1) {
506
+ for (const attrPath of Object.keys(attributesMap)) {
507
+ if (
508
+ path.endsWith('.' + attrPath) ||
509
+ path.endsWith('.' + attrPath.replace(/\[\d+\]/g, '[]'))
510
+ ) {
511
+ console.log(
512
+ `[findInAttributesMapForPath] "${path}" → SUFFIX match: ends with attributesMap key "${attrPath}"`,
513
+ );
514
+ return path; // Return FULL path, not short attrPath
515
+ }
516
+ }
517
+ }
518
+
519
+ // Try child path matching against fullToShortPathMap keys
520
+ // If the path starts with a known full path + '.' or '[', it's a child
521
+ // of a controllable path. Build the equivalent short child path.
522
+ // e.g., path = "fetch(...).fCRV.json().fCRV.topPaths.length"
523
+ // fullToShortPathMap has "fetch(...).fCRV.json().fCRV.topPaths" → "json().fCRV.topPaths"
524
+ // → check if "json().fCRV.topPaths.length" is in attributesMap
525
+ for (const [fullPath, shortPath] of Object.entries(fullToShortPathMap)) {
526
+ if (path.startsWith(fullPath + '.') || path.startsWith(fullPath + '[')) {
527
+ const suffix = path.slice(fullPath.length); // e.g., ".length"
528
+ const shortChildPath = shortPath + suffix;
529
+ if (shortChildPath in attributesMap) {
530
+ console.log(
531
+ `[findInAttributesMapForPath] "${path}" → CHILD of fullToShortPathMap key "${fullPath}": shortChildPath="${shortChildPath}" found in attributesMap`,
532
+ );
533
+ return path; // Return full path to preserve data source context
534
+ }
535
+ // Also check if the base short path is an array and suffix is .length
536
+ if (suffix === '.length' && shortPath in attributesMap) {
537
+ console.log(
538
+ `[findInAttributesMapForPath] "${path}" → CHILD .length of fullToShortPathMap key "${fullPath}": base shortPath="${shortPath}" is in attributesMap (array .length)`,
539
+ );
540
+ return path; // Array .length is controllable via the array
541
+ }
542
+ }
543
+ }
544
+
545
+ // Try parent matching: if the path is a prefix of any fullToShortPathMap key,
546
+ // it's a parent of controllable data and therefore controllable itself
547
+ for (const fullPath of Object.keys(fullToShortPathMap)) {
548
+ if (fullPath.startsWith(path + '.') || fullPath.startsWith(path + '[')) {
549
+ console.log(
550
+ `[findInAttributesMapForPath] "${path}" → PARENT match: fullToShortPathMap key "${fullPath}" starts with this path`,
551
+ );
552
+ return path;
405
553
  }
406
554
  }
407
555
 
556
+ console.log(
557
+ `[findInAttributesMapForPath] "${path}" → NO MATCH (checked ${Object.keys(attributesMap).length} attributesMap keys, ${Object.keys(fullToShortPathMap).length} fullToShortPathMap keys)`,
558
+ );
408
559
  return null;
409
560
  }
410
561
 
@@ -633,7 +784,15 @@ function generateFlowFromCompound(
633
784
  condition.requiredValue?.toString() ??
634
785
  condition.comparedValues?.[0] ??
635
786
  'truthy';
636
- comparison = 'equals';
787
+ // Map comparison operator to flow comparison type
788
+ const op = condition.comparisonOperator;
789
+ if (op === '>' || op === '>=') {
790
+ comparison = 'length>';
791
+ } else if (op === '<' || op === '<=') {
792
+ comparison = 'length<';
793
+ } else {
794
+ comparison = 'equals';
795
+ }
637
796
  }
638
797
 
639
798
  requiredValues.push({
@@ -644,21 +803,32 @@ function generateFlowFromCompound(
644
803
  });
645
804
  }
646
805
 
647
- // Generate a combined ID from all paths
648
- const pathParts = requiredValues
806
+ // Remove contradictory "falsy" values where a child path requires data
807
+ const cleanedValues = removeContradictoryFalsyValues(requiredValues);
808
+
809
+ if (cleanedValues.length === 0) {
810
+ return null;
811
+ }
812
+
813
+ // Generate a combined ID from all paths + values to distinguish different comparisons
814
+ const pathParts = cleanedValues
649
815
  .map((rv) => {
650
816
  const name = generateNameFromPath(rv.attributePath);
651
- return name.toLowerCase().replace(/\s+/g, '-');
817
+ const suffix =
818
+ rv.comparison === 'truthy' || rv.comparison === 'falsy'
819
+ ? `-${rv.comparison}`
820
+ : `-${rv.comparison}-${rv.value}`;
821
+ return name.toLowerCase().replace(/\s+/g, '-') + suffix;
652
822
  })
653
823
  .join('-and-');
654
824
 
655
825
  return {
656
826
  id: `compound-${pathParts}`,
657
- name: requiredValues
827
+ name: cleanedValues
658
828
  .map((rv) => generateNameFromPath(rv.attributePath))
659
829
  .join(' + '),
660
- description: `When ${requiredValues.map((rv) => `${generateNameFromPath(rv.attributePath).toLowerCase()} is ${rv.value}`).join(' and ')}`,
661
- requiredValues,
830
+ description: `When ${cleanedValues.map((rv) => describeRequiredValue(rv)).join(' and ')}`,
831
+ requiredValues: cleanedValues,
662
832
  impact,
663
833
  sourceLocation: {
664
834
  lineNumber: compound.sourceLocation.lineNumber,
@@ -849,6 +1019,22 @@ export default function generateExecutionFlowsFromConditionals(
849
1019
  const flows: ExecutionFlow[] = [];
850
1020
  const seenFlowIds = new Set<string>();
851
1021
 
1022
+ console.log(
1023
+ `[genFlowsFromConditionals] INPUT: ${Object.keys(conditionalUsages).length} conditional paths, ${Object.keys(attributesMap).length} attributesMap entries, ${Object.keys(fullToShortPathMap).length} fullToShortPathMap entries, ${Object.keys(equivalentSignatureVariables).length} equivSigVars, ${compoundConditionals.length} compound conditionals`,
1024
+ );
1025
+ console.log(
1026
+ `[genFlowsFromConditionals] conditionalUsages keys: [${Object.keys(conditionalUsages).join(', ')}]`,
1027
+ );
1028
+ console.log(
1029
+ `[genFlowsFromConditionals] attributesMap keys: [${Object.keys(attributesMap).join(', ')}]`,
1030
+ );
1031
+ console.log(
1032
+ `[genFlowsFromConditionals] fullToShortPathMap: ${JSON.stringify(fullToShortPathMap)}`,
1033
+ );
1034
+ console.log(
1035
+ `[genFlowsFromConditionals] equivalentSignatureVariables: ${JSON.stringify(equivalentSignatureVariables)}`,
1036
+ );
1037
+
852
1038
  // Track normalized resolved paths to prevent duplicate flows
853
1039
  // This handles the case where we have usages for both:
854
1040
  // - "hasNewerVersion" (short path from destructured variable)
@@ -866,9 +1052,16 @@ export default function generateExecutionFlowsFromConditionals(
866
1052
  for (const usage of usages) {
867
1053
  // Skip usages that are part of compound conditionals (handled separately)
868
1054
  if (usage.chainId && compoundChainIds.has(usage.chainId)) {
1055
+ console.log(
1056
+ `[genFlowsFromConditionals] "${usage.path}" SKIP: part of compound conditional chain=${usage.chainId}`,
1057
+ );
869
1058
  continue;
870
1059
  }
871
1060
 
1061
+ console.log(
1062
+ `[genFlowsFromConditionals] --- Processing "${usage.path}" (type=${usage.conditionType}, negated=${usage.isNegated}, sourceDataPath="${usage.sourceDataPath ?? '(none)'}", derivedFrom=${usage.derivedFrom ? JSON.stringify(usage.derivedFrom) : 'none'})`,
1063
+ );
1064
+
872
1065
  // First, try to use pre-computed sourceDataPath if available
873
1066
  let resolvedPath: string | null = null;
874
1067
 
@@ -878,7 +1071,9 @@ export default function generateExecutionFlowsFromConditionals(
878
1071
  // should become "useLoaderData<LoaderData>().functionCallReturnValue.entity.sha"
879
1072
  // Returns null for malformed paths (e.g., chained function calls like fetch().json())
880
1073
  const cleanedPath = cleanSourceDataPath(usage.sourceDataPath);
881
-
1074
+ console.log(
1075
+ `[genFlowsFromConditionals] "${usage.path}" cleanSourceDataPath("${usage.sourceDataPath}") → "${cleanedPath}"`,
1076
+ );
882
1077
  if (cleanedPath) {
883
1078
  // Verify the cleaned path exists in attributesMap
884
1079
  const pathMatch = findInAttributesMapForPath(
@@ -886,6 +1081,9 @@ export default function generateExecutionFlowsFromConditionals(
886
1081
  attributesMap,
887
1082
  fullToShortPathMap,
888
1083
  );
1084
+ console.log(
1085
+ `[genFlowsFromConditionals] "${usage.path}" findInAttributesMapForPath("${cleanedPath}") → ${pathMatch ? `"${pathMatch}"` : 'null (not found)'}`,
1086
+ );
889
1087
  if (pathMatch) {
890
1088
  resolvedPath = pathMatch;
891
1089
  }
@@ -895,13 +1093,18 @@ export default function generateExecutionFlowsFromConditionals(
895
1093
 
896
1094
  // Fall back to resolution via equivalentSignatureVariables
897
1095
  if (!resolvedPath) {
1096
+ console.log(
1097
+ `[genFlowsFromConditionals] "${usage.path}" sourceDataPath resolution failed, trying resolvePathToControllable("${usage.path}")...`,
1098
+ );
898
1099
  const resolution = resolvePathToControllable(
899
1100
  usage.path,
900
1101
  attributesMap,
901
1102
  equivalentSignatureVariables,
902
1103
  fullToShortPathMap,
903
1104
  );
904
-
1105
+ console.log(
1106
+ `[genFlowsFromConditionals] "${usage.path}" resolvePathToControllable → isControllable=${resolution.isControllable}, resolvedPath="${resolution.resolvedPath ?? '(none)'}"`,
1107
+ );
905
1108
  if (resolution.isControllable && resolution.resolvedPath) {
906
1109
  resolvedPath = resolution.resolvedPath;
907
1110
  }
@@ -913,7 +1116,9 @@ export default function generateExecutionFlowsFromConditionals(
913
1116
  if (!resolvedPath && usage.derivedFrom) {
914
1117
  const { operation, sourcePath, sourcePaths, comparedValue } =
915
1118
  usage.derivedFrom;
916
-
1119
+ console.log(
1120
+ `[genFlowsFromConditionals] "${usage.path}" trying derivedFrom: operation=${operation}, sourcePath="${sourcePath ?? '(none)'}", sourcePaths=${sourcePaths ? JSON.stringify(sourcePaths) : '(none)'}, comparedValue="${comparedValue ?? '(none)'}"`,
1121
+ );
917
1122
  // For single-source derivations (notNull, equals, etc.)
918
1123
  if (sourcePath) {
919
1124
  const resolution = resolvePathToControllable(
@@ -922,7 +1127,6 @@ export default function generateExecutionFlowsFromConditionals(
922
1127
  equivalentSignatureVariables,
923
1128
  fullToShortPathMap,
924
1129
  );
925
-
926
1130
  if (resolution.isControllable && resolution.resolvedPath) {
927
1131
  resolvedPath = resolution.resolvedPath;
928
1132
  }
@@ -1218,6 +1422,9 @@ export default function generateExecutionFlowsFromConditionals(
1218
1422
 
1219
1423
  if (!resolvedPath) {
1220
1424
  // Path is not controllable - skip (no invalid flows possible)
1425
+ console.log(
1426
+ `[genFlowsFromConditionals] "${usage.path}" SKIP: not controllable (no resolvedPath after all attempts)`,
1427
+ );
1221
1428
  continue;
1222
1429
  }
1223
1430
 
@@ -1232,10 +1439,33 @@ export default function generateExecutionFlowsFromConditionals(
1232
1439
  // Skip if we've already generated flows for this normalized path
1233
1440
  // This prevents duplicate flows when we have usages for both short and full paths
1234
1441
  if (seenNormalizedPaths.has(normalizedPath)) {
1442
+ console.log(
1443
+ `[genFlowsFromConditionals] "${usage.path}" SKIP: duplicate normalizedPath="${normalizedPath}" (resolvedPath="${resolvedPath}")`,
1444
+ );
1235
1445
  continue;
1236
1446
  }
1237
1447
  seenNormalizedPaths.add(normalizedPath);
1238
1448
 
1449
+ // Skip individual truthy/falsy flows on parent paths that have child data entries.
1450
+ // Lifecycle booleans (like isLoadingAuditData) traced to fetch(...).functionCallReturnValue
1451
+ // produce misleading truthy/falsy flows: "truthy" can't show loading (mock resolves instantly),
1452
+ // "falsy" tells the LLM to return null (breaking .json()). Compound flows with specific child
1453
+ // data requirements provide the correct mock guidance.
1454
+ if (
1455
+ usage.conditionType === 'truthiness' &&
1456
+ resolvedPath &&
1457
+ hasChildPathsInMap(resolvedPath, fullToShortPathMap)
1458
+ ) {
1459
+ console.log(
1460
+ `[genFlowsFromConditionals] "${usage.path}" SKIP: parent path "${resolvedPath}" has child data paths — compound flows will handle this`,
1461
+ );
1462
+ continue;
1463
+ }
1464
+
1465
+ console.log(
1466
+ `[genFlowsFromConditionals] "${usage.path}" RESOLVED → resolvedPath="${resolvedPath}", normalizedPath="${normalizedPath}" — generating flows`,
1467
+ );
1468
+
1239
1469
  // Generate flows for this controllable usage
1240
1470
  const usageFlows = generateFlowsFromUsage(usage, resolvedPath);
1241
1471
 
@@ -1244,6 +1474,9 @@ export default function generateExecutionFlowsFromConditionals(
1244
1474
  if (!seenFlowIds.has(flow.id)) {
1245
1475
  seenFlowIds.add(flow.id);
1246
1476
  flows.push(flow);
1477
+ console.log(
1478
+ `[genFlowsFromConditionals] "${usage.path}" FLOW ADDED: id="${flow.id}", requiredValues=${JSON.stringify(flow.requiredValues.map((rv) => ({ attr: rv.attributePath, val: rv.value })))}`,
1479
+ );
1247
1480
  }
1248
1481
  }
1249
1482
  }
@@ -1297,25 +1530,85 @@ export default function generateExecutionFlowsFromConditionals(
1297
1530
  // Use the first source's path for the resolvedPaths map (for ID generation)
1298
1531
  resolvedPaths.set(condition.path, sources[0].path);
1299
1532
  } else {
1300
- // Derived variable but no controllable sources found
1301
- allControllable = false;
1302
- break;
1533
+ // Derived variable expansion failed try sourceDataPath fallback
1534
+ // This handles cases where the derivation chain goes through useMemo/useState
1535
+ // but the enriched sourceDataPath already traced to the actual data source
1536
+ const usageWithSource = usagesForPath?.find(
1537
+ (u) => u.sourceDataPath,
1538
+ );
1539
+ let derivedFallbackPath: string | null = null;
1540
+
1541
+ if (usageWithSource?.sourceDataPath) {
1542
+ const cleanedPath = cleanSourceDataPath(
1543
+ usageWithSource.sourceDataPath,
1544
+ );
1545
+ if (cleanedPath) {
1546
+ const pathMatch = findInAttributesMapForPath(
1547
+ cleanedPath,
1548
+ attributesMap,
1549
+ fullToShortPathMap,
1550
+ );
1551
+ if (pathMatch) {
1552
+ derivedFallbackPath = pathMatch;
1553
+ }
1554
+ }
1555
+ }
1556
+
1557
+ if (derivedFallbackPath) {
1558
+ resolvedPaths.set(condition.path, derivedFallbackPath);
1559
+ console.log(
1560
+ `[genFlowsFromConditionals] COMPOUND "${condition.path}" derived expansion failed but sourceDataPath fallback resolved → "${derivedFallbackPath}"`,
1561
+ );
1562
+ } else {
1563
+ // Truly not controllable
1564
+ console.log(
1565
+ `[genFlowsFromConditionals] COMPOUND "${condition.path}" derived but no controllable sources and no sourceDataPath fallback → NOT controllable`,
1566
+ );
1567
+ allControllable = false;
1568
+ break;
1569
+ }
1303
1570
  }
1304
1571
  } else {
1305
1572
  // Not a derived variable - resolve directly
1306
- const resolution = resolvePathToControllable(
1307
- condition.path,
1308
- attributesMap,
1309
- equivalentSignatureVariables,
1310
- fullToShortPathMap,
1311
- );
1573
+ // First try sourceDataPath from the usage (same as individual processing)
1574
+ let compoundResolvedPath: string | null = null;
1312
1575
 
1313
- if (!resolution.isControllable || !resolution.resolvedPath) {
1576
+ const usageWithSource = usagesForPath?.find((u) => u.sourceDataPath);
1577
+ if (usageWithSource?.sourceDataPath) {
1578
+ const cleanedPath = cleanSourceDataPath(
1579
+ usageWithSource.sourceDataPath,
1580
+ );
1581
+ if (cleanedPath) {
1582
+ const pathMatch = findInAttributesMapForPath(
1583
+ cleanedPath,
1584
+ attributesMap,
1585
+ fullToShortPathMap,
1586
+ );
1587
+ if (pathMatch) {
1588
+ compoundResolvedPath = pathMatch;
1589
+ }
1590
+ }
1591
+ }
1592
+
1593
+ if (!compoundResolvedPath) {
1594
+ const resolution = resolvePathToControllable(
1595
+ condition.path,
1596
+ attributesMap,
1597
+ equivalentSignatureVariables,
1598
+ fullToShortPathMap,
1599
+ );
1600
+
1601
+ if (resolution.isControllable && resolution.resolvedPath) {
1602
+ compoundResolvedPath = resolution.resolvedPath;
1603
+ }
1604
+ }
1605
+
1606
+ if (!compoundResolvedPath) {
1314
1607
  allControllable = false;
1315
1608
  break;
1316
1609
  }
1317
1610
 
1318
- resolvedPaths.set(condition.path, resolution.resolvedPath);
1611
+ resolvedPaths.set(condition.path, compoundResolvedPath);
1319
1612
  }
1320
1613
  }
1321
1614
 
@@ -1393,7 +1686,14 @@ export default function generateExecutionFlowsFromConditionals(
1393
1686
  condition.requiredValue?.toString() ??
1394
1687
  condition.comparedValues?.[0] ??
1395
1688
  'truthy';
1396
- comparison = 'equals';
1689
+ const op = condition.comparisonOperator;
1690
+ if (op === '>' || op === '>=') {
1691
+ comparison = 'length>';
1692
+ } else if (op === '<' || op === '<=') {
1693
+ comparison = 'length<';
1694
+ } else {
1695
+ comparison = 'equals';
1696
+ }
1397
1697
  }
1398
1698
 
1399
1699
  requiredValues.push({
@@ -1406,24 +1706,31 @@ export default function generateExecutionFlowsFromConditionals(
1406
1706
  }
1407
1707
  }
1408
1708
 
1409
- if (requiredValues.length > 0) {
1709
+ // Remove contradictory "falsy" values where a child path requires data
1710
+ const cleanedValues = removeContradictoryFalsyValues(requiredValues);
1711
+
1712
+ if (cleanedValues.length > 0) {
1410
1713
  const impact: ExecutionFlow['impact'] =
1411
1714
  compound.controlsJsxRendering ? 'high' : 'medium';
1412
1715
 
1413
- // Generate a combined ID from all paths
1414
- const pathParts = requiredValues
1716
+ // Generate a combined ID from all paths + values
1717
+ const pathParts = cleanedValues
1415
1718
  .map((rv) => {
1416
1719
  const name = generateNameFromPath(rv.attributePath);
1417
- return name.toLowerCase().replace(/\s+/g, '-');
1720
+ const suffix =
1721
+ rv.comparison === 'truthy' || rv.comparison === 'falsy'
1722
+ ? `-${rv.comparison}`
1723
+ : `-${rv.comparison}-${rv.value}`;
1724
+ return name.toLowerCase().replace(/\s+/g, '-') + suffix;
1418
1725
  })
1419
1726
  .join('-and-');
1420
1727
 
1421
1728
  const compoundFlow: ExecutionFlow = {
1422
- id: `${pathParts}-${requiredValues.map((rv) => rv.value).join('-')}`,
1423
- name: generateNameFromPath(requiredValues[0].attributePath),
1424
- description: `When ${requiredValues.map((rv) => `${generateNameFromPath(rv.attributePath).toLowerCase()} is ${rv.value}`).join(' and ')}`,
1729
+ id: `${pathParts}`,
1730
+ name: generateNameFromPath(cleanedValues[0].attributePath),
1731
+ description: `When ${cleanedValues.map((rv) => describeRequiredValue(rv)).join(' and ')}`,
1425
1732
  impact,
1426
- requiredValues,
1733
+ requiredValues: cleanedValues,
1427
1734
  sourceLocation: compound.sourceLocation,
1428
1735
  };
1429
1736
 
@@ -1640,9 +1947,6 @@ export default function generateExecutionFlowsFromConditionals(
1640
1947
  childData.conditionalUsages,
1641
1948
  )) {
1642
1949
  for (const usage of usages) {
1643
- // Debug logging (disabled - set to true for troubleshooting child flow resolution)
1644
- const shouldDebugChild = false;
1645
-
1646
1950
  // Skip usages that are part of compound conditionals (handled separately)
1647
1951
  // Fix 33: Only skip if the chainId is in the child's compound conditionals
1648
1952
  if (usage.chainId && childCompoundChainIds.has(usage.chainId)) {
@@ -1657,18 +1961,6 @@ export default function generateExecutionFlowsFromConditionals(
1657
1961
  childPath = usage.derivedFrom.sourcePath;
1658
1962
  }
1659
1963
 
1660
- if (shouldDebugChild) {
1661
- console.log(
1662
- `[DEBUG CHILD ${childName}] Processing usage path: ${usage.path}`,
1663
- );
1664
- console.log(
1665
- `[DEBUG CHILD ${childName}] childPath (after derivedFrom): ${childPath}`,
1666
- );
1667
- console.log(
1668
- `[DEBUG CHILD ${childName}] sourceDataPath: ${usage.sourceDataPath}`,
1669
- );
1670
- }
1671
-
1672
1964
  // Translate the child path to a parent path
1673
1965
  let translatedPath = translateChildPathToParent(
1674
1966
  childPath,
@@ -1677,12 +1969,6 @@ export default function generateExecutionFlowsFromConditionals(
1677
1969
  childName,
1678
1970
  );
1679
1971
 
1680
- if (shouldDebugChild) {
1681
- console.log(
1682
- `[DEBUG CHILD ${childName}] translatedPath (from translateChildPathToParent): ${translatedPath}`,
1683
- );
1684
- }
1685
-
1686
1972
  // If translation failed but we have sourceDataPath, try to extract the prop path from it
1687
1973
  // sourceDataPath format: "ChildName.signature[n].propPath.rest" → extract "propPath.rest"
1688
1974
  if (!translatedPath && usage.sourceDataPath) {
@@ -1691,21 +1977,11 @@ export default function generateExecutionFlowsFromConditionals(
1691
1977
  );
1692
1978
  if (signatureMatch) {
1693
1979
  translatedPath = signatureMatch[1];
1694
- if (shouldDebugChild) {
1695
- console.log(
1696
- `[DEBUG CHILD ${childName}] translatedPath (from sourceDataPath regex): ${translatedPath}`,
1697
- );
1698
- }
1699
1980
  }
1700
1981
  }
1701
1982
 
1702
1983
  if (!translatedPath) {
1703
1984
  // Could not translate - skip this usage
1704
- if (shouldDebugChild) {
1705
- console.log(
1706
- `[DEBUG CHILD ${childName}] SKIPPED - no translation found`,
1707
- );
1708
- }
1709
1985
  continue;
1710
1986
  }
1711
1987
 
@@ -1718,21 +1994,6 @@ export default function generateExecutionFlowsFromConditionals(
1718
1994
  fullToShortPathMap,
1719
1995
  );
1720
1996
 
1721
- if (shouldDebugChild) {
1722
- console.log(
1723
- `[DEBUG CHILD ${childName}] resolvePathToControllable result:`,
1724
- );
1725
- console.log(
1726
- `[DEBUG CHILD ${childName}] isControllable: ${resolution.isControllable}`,
1727
- );
1728
- console.log(
1729
- `[DEBUG CHILD ${childName}] resolvedPath: ${resolution.resolvedPath}`,
1730
- );
1731
- console.log(
1732
- `[DEBUG CHILD ${childName}] chain: ${resolution.resolutionChain.join(' -> ')}`,
1733
- );
1734
- }
1735
-
1736
1997
  // Only create flows for controllable paths (whitelist approach).
1737
1998
  // If the path doesn't resolve to something in attributesMap, skip it.
1738
1999
  // This prevents creating flows for useState values which are not
@@ -1770,32 +2031,11 @@ export default function generateExecutionFlowsFromConditionals(
1770
2031
  }
1771
2032
  }
1772
2033
 
1773
- if (shouldDebugChild) {
1774
- console.log(
1775
- `[DEBUG CHILD ${childName}] useState fallback: looking for URL param`,
1776
- );
1777
- console.log(
1778
- `[DEBUG CHILD ${childName}] useStatePattern: ${useStatePattern}`,
1779
- );
1780
- console.log(
1781
- `[DEBUG CHILD ${childName}] useStateVarName: ${useStateVarName}`,
1782
- );
1783
- }
1784
-
1785
2034
  if (useStateVarName) {
1786
2035
  // Look for a related URL param like "varNameFromUrl"
1787
2036
  const urlParamName = `${useStateVarName}FromUrl`;
1788
2037
  const urlParamPath = equivalentSignatureVariables[urlParamName];
1789
2038
 
1790
- if (shouldDebugChild) {
1791
- console.log(
1792
- `[DEBUG CHILD ${childName}] urlParamName: ${urlParamName}`,
1793
- );
1794
- console.log(
1795
- `[DEBUG CHILD ${childName}] urlParamPath: ${urlParamPath}`,
1796
- );
1797
- }
1798
-
1799
2039
  if (urlParamPath) {
1800
2040
  // For useState values initialized from URL params, use the
1801
2041
  // URL param variable name directly (e.g., "viewModeFromUrl")
@@ -1806,11 +2046,6 @@ export default function generateExecutionFlowsFromConditionals(
1806
2046
  // The flow will use the URL param name as the attributePath,
1807
2047
  // which gets properly resolved when generating mock data.
1808
2048
  resolvedPath = urlParamName;
1809
- if (shouldDebugChild) {
1810
- console.log(
1811
- `[DEBUG CHILD ${childName}] useState fallback SUCCESS: using URL param name ${resolvedPath}`,
1812
- );
1813
- }
1814
2049
  }
1815
2050
  }
1816
2051
  }
@@ -1867,12 +2102,6 @@ export default function generateExecutionFlowsFromConditionals(
1867
2102
  ? childPath.slice(childPropName.length)
1868
2103
  : '';
1869
2104
  resolvedPath = dataSourceResolution.resolvedPath + suffix;
1870
-
1871
- if (shouldDebugChild) {
1872
- console.log(
1873
- `[DEBUG CHILD ${childName}] sourceEquivalencies fallback SUCCESS: using data source ${resolvedPath}`,
1874
- );
1875
- }
1876
2105
  }
1877
2106
  }
1878
2107
  }
@@ -1880,11 +2109,6 @@ export default function generateExecutionFlowsFromConditionals(
1880
2109
 
1881
2110
  // If still not resolved after fallback, skip
1882
2111
  if (!resolvedPath) {
1883
- if (shouldDebugChild) {
1884
- console.log(
1885
- `[DEBUG CHILD ${childName}] SKIPPED - path not controllable`,
1886
- );
1887
- }
1888
2112
  continue;
1889
2113
  }
1890
2114
  }
@@ -1896,11 +2120,6 @@ export default function generateExecutionFlowsFromConditionals(
1896
2120
  );
1897
2121
 
1898
2122
  if (seenNormalizedPaths.has(normalizedPath)) {
1899
- if (shouldDebugChild) {
1900
- console.log(
1901
- `[DEBUG CHILD ${childName}] SKIPPED - duplicate normalized path: ${normalizedPath}`,
1902
- );
1903
- }
1904
2123
  continue;
1905
2124
  }
1906
2125
  seenNormalizedPaths.add(normalizedPath);
@@ -1917,17 +2136,6 @@ export default function generateExecutionFlowsFromConditionals(
1917
2136
  resolvedPath,
1918
2137
  );
1919
2138
 
1920
- if (shouldDebugChild) {
1921
- console.log(
1922
- `[DEBUG CHILD ${childName}] GENERATING ${usageFlows.length} flows with resolvedPath: ${resolvedPath}`,
1923
- );
1924
- for (const f of usageFlows) {
1925
- console.log(
1926
- `[DEBUG CHILD ${childName}] - Flow ID: ${f.id}, path: ${f.requiredValues[0]?.attributePath}`,
1927
- );
1928
- }
1929
- }
1930
-
1931
2139
  // Add gating conditions to each flow
1932
2140
  for (const flow of usageFlows) {
1933
2141
  // Add gating required values to the flow
@@ -2263,5 +2471,14 @@ export default function generateExecutionFlowsFromConditionals(
2263
2471
  }
2264
2472
  }
2265
2473
 
2474
+ console.log(
2475
+ `[genFlowsFromConditionals] RESULT: ${flows.length} total flows generated`,
2476
+ );
2477
+ for (const flow of flows) {
2478
+ console.log(
2479
+ `[genFlowsFromConditionals] FLOW: id="${flow.id}" requiredValues=[${flow.requiredValues.map((rv) => `${rv.attributePath}=${rv.value}`).join(', ')}]`,
2480
+ );
2481
+ }
2482
+
2266
2483
  return flows;
2267
2484
  }