@ansible-flow/core 0.86.0 → 0.88.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 (126) hide show
  1. package/README.md +1 -1
  2. package/dist/ai/describe.js +8 -7
  3. package/dist/ai/handlers.js +27 -25
  4. package/dist/ai/handlers.js.map +1 -1
  5. package/dist/ai/ops.js +8 -7
  6. package/dist/ai/reference.js +2 -2
  7. package/dist/ai/scenarios.js +12 -8
  8. package/dist/awx/import.js +7 -6
  9. package/dist/catalog/draft.d.ts +2 -0
  10. package/dist/catalog/draft.js +23 -4
  11. package/dist/catalog/draft.js.map +2 -2
  12. package/dist/chunks/{chunk-BXHI5EQM.js → chunk-2DT5DOSO.js} +43 -1
  13. package/dist/chunks/chunk-2DT5DOSO.js.map +7 -0
  14. package/dist/chunks/{chunk-DHU774ES.js → chunk-2KB3J3R5.js} +2 -2
  15. package/dist/chunks/{chunk-EAJFZKPB.js → chunk-37FKZNRN.js} +3 -3
  16. package/dist/chunks/{chunk-TPRZZHXA.js → chunk-57KJYXWA.js} +7 -7
  17. package/dist/chunks/{chunk-JTWR3TGG.js → chunk-7ALTNZCI.js} +4 -4
  18. package/dist/chunks/{chunk-UXIXXEIW.js → chunk-APBEHKCF.js} +2 -2
  19. package/dist/chunks/{chunk-ZAYNYPCX.js → chunk-ARA3VJR2.js} +2 -2
  20. package/dist/chunks/{chunk-7GLSXIZ3.js → chunk-BSX6G7QY.js} +5 -5
  21. package/dist/chunks/{chunk-H7Z2FBRD.js → chunk-CATQHJS6.js} +8 -8
  22. package/dist/chunks/{chunk-J7KCGVHU.js → chunk-CCWUUVSG.js} +2 -2
  23. package/dist/chunks/{chunk-C6SQEXL5.js → chunk-CNQ7M7HA.js} +2 -2
  24. package/dist/chunks/{chunk-NT62IE3Y.js → chunk-CNYGDBID.js} +2 -2
  25. package/dist/chunks/chunk-FIKPXL6E.js +23 -0
  26. package/dist/chunks/chunk-FIKPXL6E.js.map +7 -0
  27. package/dist/chunks/{chunk-CM23ODBB.js → chunk-J5LYSQ3L.js} +2 -2
  28. package/dist/chunks/{chunk-72LO6GQE.js → chunk-KXD6FX2Z.js} +2 -2
  29. package/dist/chunks/{chunk-4RMWFRWG.js → chunk-LELKMVJG.js} +45 -7
  30. package/dist/chunks/chunk-LELKMVJG.js.map +7 -0
  31. package/dist/chunks/{chunk-XOPGOWNQ.js → chunk-O5Y3AZ4X.js} +1 -1
  32. package/dist/chunks/chunk-O5Y3AZ4X.js.map +7 -0
  33. package/dist/chunks/{chunk-5XGAGNH5.js → chunk-OGNFHW5O.js} +7 -13
  34. package/dist/chunks/chunk-OGNFHW5O.js.map +7 -0
  35. package/dist/chunks/chunk-OJZSZBHW.js +45 -0
  36. package/dist/chunks/chunk-OJZSZBHW.js.map +7 -0
  37. package/dist/chunks/{chunk-R4MW3DRT.js → chunk-OW32YCZ6.js} +2 -2
  38. package/dist/chunks/{chunk-2QQC4IZ7.js → chunk-PNLY5IWM.js} +8 -8
  39. package/dist/chunks/chunk-PNLY5IWM.js.map +7 -0
  40. package/dist/chunks/{chunk-76T45V37.js → chunk-TBFB7A2Z.js} +5 -1
  41. package/dist/chunks/{chunk-76T45V37.js.map → chunk-TBFB7A2Z.js.map} +2 -2
  42. package/dist/chunks/{chunk-BXJOUAXV.js → chunk-TEJARYAE.js} +3 -3
  43. package/dist/chunks/{chunk-T5UB4MBB.js → chunk-TOTSB4HG.js} +41 -1
  44. package/dist/chunks/chunk-TOTSB4HG.js.map +7 -0
  45. package/dist/chunks/{chunk-MZ6IJWB2.js → chunk-TPMACJFA.js} +4 -4
  46. package/dist/chunks/{chunk-CXVJWFGT.js → chunk-WTVGCMGV.js} +8 -4
  47. package/dist/chunks/chunk-WTVGCMGV.js.map +7 -0
  48. package/dist/chunks/{chunk-6MLYGFT6.js → chunk-XJAMBKE3.js} +6 -2
  49. package/dist/chunks/chunk-XJAMBKE3.js.map +7 -0
  50. package/dist/chunks/{chunk-ABYJBONR.js → chunk-ZXUXX3YY.js} +4 -4
  51. package/dist/engine/binding.js +3 -1
  52. package/dist/engine/bypass.js +4 -2
  53. package/dist/engine/engines.js +9 -5
  54. package/dist/engine/files.js +9 -5
  55. package/dist/engine/optionA.js +8 -4
  56. package/dist/engine/partial.js +3 -1
  57. package/dist/engine/partial.js.map +1 -1
  58. package/dist/engine/preview.js +9 -5
  59. package/dist/engine/preview.js.map +1 -1
  60. package/dist/engine/writePlan.js +12 -9
  61. package/dist/export/drawio.js +3 -3
  62. package/dist/export/layoutCheck.js +3 -3
  63. package/dist/export/scene.js +2 -2
  64. package/dist/export/svg.js +4 -4
  65. package/dist/flow/commands.d.ts +10 -0
  66. package/dist/flow/commands.js +3 -1
  67. package/dist/flow/facts.d.ts +6 -0
  68. package/dist/flow/facts.js +13 -0
  69. package/dist/flow/facts.js.map +7 -0
  70. package/dist/flow/findingCodes.js +1 -1
  71. package/dist/flow/localFiles.d.ts +17 -0
  72. package/dist/flow/localFiles.js +14 -0
  73. package/dist/flow/localFiles.js.map +7 -0
  74. package/dist/flow/save.js +3 -1
  75. package/dist/flow/save.js.map +1 -1
  76. package/dist/flow/validate.js +3 -2
  77. package/dist/import/outline.js +9 -7
  78. package/dist/import/playbook.js +6 -5
  79. package/dist/import/source.js +3 -2
  80. package/dist/lens/caption.js +1 -1
  81. package/dist/lens/data.js +3 -1
  82. package/dist/lens/index.js +11 -9
  83. package/dist/lens/index.js.map +1 -1
  84. package/dist/lens/types.d.ts +2 -0
  85. package/dist/lens/types.js +1 -1
  86. package/dist/messageCheck.js +2 -0
  87. package/dist/messageCheck.js.map +2 -2
  88. package/dist/protocol.d.ts +29 -0
  89. package/dist/run/command.d.ts +13 -4
  90. package/dist/run/command.js +19 -0
  91. package/dist/run/command.js.map +3 -3
  92. package/dist/scenario/live.js +11 -7
  93. package/dist/scenario/simulate.js +10 -6
  94. package/dist/view/flowFacts.js +12 -9
  95. package/dist/view/flowFacts.js.map +1 -1
  96. package/dist/view/route.d.ts +3 -1
  97. package/dist/view/route.js +1 -1
  98. package/dist/view/serverChange.d.ts +23 -0
  99. package/dist/view/serverChange.js +48 -0
  100. package/dist/view/serverChange.js.map +7 -0
  101. package/package.json +1 -1
  102. package/dist/chunks/chunk-2QQC4IZ7.js.map +0 -7
  103. package/dist/chunks/chunk-4RMWFRWG.js.map +0 -7
  104. package/dist/chunks/chunk-5XGAGNH5.js.map +0 -7
  105. package/dist/chunks/chunk-6MLYGFT6.js.map +0 -7
  106. package/dist/chunks/chunk-BXHI5EQM.js.map +0 -7
  107. package/dist/chunks/chunk-CXVJWFGT.js.map +0 -7
  108. package/dist/chunks/chunk-T5UB4MBB.js.map +0 -7
  109. package/dist/chunks/chunk-XOPGOWNQ.js.map +0 -7
  110. /package/dist/chunks/{chunk-DHU774ES.js.map → chunk-2KB3J3R5.js.map} +0 -0
  111. /package/dist/chunks/{chunk-EAJFZKPB.js.map → chunk-37FKZNRN.js.map} +0 -0
  112. /package/dist/chunks/{chunk-TPRZZHXA.js.map → chunk-57KJYXWA.js.map} +0 -0
  113. /package/dist/chunks/{chunk-JTWR3TGG.js.map → chunk-7ALTNZCI.js.map} +0 -0
  114. /package/dist/chunks/{chunk-UXIXXEIW.js.map → chunk-APBEHKCF.js.map} +0 -0
  115. /package/dist/chunks/{chunk-ZAYNYPCX.js.map → chunk-ARA3VJR2.js.map} +0 -0
  116. /package/dist/chunks/{chunk-7GLSXIZ3.js.map → chunk-BSX6G7QY.js.map} +0 -0
  117. /package/dist/chunks/{chunk-H7Z2FBRD.js.map → chunk-CATQHJS6.js.map} +0 -0
  118. /package/dist/chunks/{chunk-J7KCGVHU.js.map → chunk-CCWUUVSG.js.map} +0 -0
  119. /package/dist/chunks/{chunk-C6SQEXL5.js.map → chunk-CNQ7M7HA.js.map} +0 -0
  120. /package/dist/chunks/{chunk-NT62IE3Y.js.map → chunk-CNYGDBID.js.map} +0 -0
  121. /package/dist/chunks/{chunk-CM23ODBB.js.map → chunk-J5LYSQ3L.js.map} +0 -0
  122. /package/dist/chunks/{chunk-72LO6GQE.js.map → chunk-KXD6FX2Z.js.map} +0 -0
  123. /package/dist/chunks/{chunk-R4MW3DRT.js.map → chunk-OW32YCZ6.js.map} +0 -0
  124. /package/dist/chunks/{chunk-BXJOUAXV.js.map → chunk-TEJARYAE.js.map} +0 -0
  125. /package/dist/chunks/{chunk-MZ6IJWB2.js.map → chunk-TPMACJFA.js.map} +0 -0
  126. /package/dist/chunks/{chunk-ABYJBONR.js.map → chunk-ZXUXX3YY.js.map} +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/core/flow/validate.ts"],
4
+ "sourcesContent": ["// Semantic checks on a flow document. Findings carry YAML paths; the host maps them to ranges.\n\nimport type { Path } from '../yaml/parse';\nimport { successors } from './adjacency';\nimport { fedByBubbling, levelTaken, untaken } from './bubbling';\nimport { idGaps, withIds } from './completeIds';\nimport { fromRegister, outputVar, registerName } from './dataNames';\nimport { enclosing, liftOf, resolveFrom, upstreamNodes } from './dataRefs';\nimport { acceptedAll, acceptedOf, checkWhat } from './decisions';\nimport { canDisable, disabledBy, disabledIds } from './disabled';\nimport { durationSeconds } from './duration';\nimport { factSetter, setFactNames } from './facts';\nimport { healPlan } from './heal';\nimport { conditionHasBraces, exprRefs, refsIn, singleRef, templated } from './jinja';\nimport { BARE_PARAMS, keywordReads } from './keywords';\nimport { formatOf } from './migrate';\nimport { buildModel, type FlowModel, ROOT } from './model';\nimport { openFailPorts } from './openPorts';\nimport { isRollback } from './patterns';\nimport { isFailPort, isPortLegal, LEGACY_PORTS, portDirection, portsFor } from './ports';\nimport { refDesign } from './refs';\nimport { rollingObstacles } from './rolling';\nimport type { SchemaIssue } from './schema';\nimport { planSegments } from './segments';\nimport { hasStatus, runtimeKind, statusFor } from './status';\nimport type { FlowDocument, FlowNode, PortRef, Ulid } from './types';\nimport { comparesWholeResult } from './until';\nimport { varNameProblem } from './varNames';\n\nexport type Severity = 'error' | 'warning' | 'info';\n\nexport interface Finding {\n code: string;\n severity: Severity;\n message: string;\n path: Path;\n node?: Ulid;\n port?: string;\n edge?: Ulid;\n /** What the finding is about when a node can have several (a variable name): with the code and\n * the node, what an accepted problem names (AFD-51). */\n subject?: string;\n}\n\nexport function pointerToPath(pointer: string): Path {\n if (pointer === '/' || pointer === '') return [];\n return pointer\n .slice(1)\n .split('/')\n .map((s) => s.replaceAll('~1', '/').replaceAll('~0', '~'))\n .map((s) => (/^[0-9]+$/.test(s) ? Number(s) : s));\n}\n\nfunction label(node: FlowNode | undefined): string {\n return node ? `\"${node.title ?? node.key}\"` : 'unknown node';\n}\n\n/** A YAML true/false written as a boolean or a word (`yes`, `\"false\"`). */\nfunction literal(value: unknown, want: boolean): boolean {\n if (typeof value === 'boolean') return value === want;\n if (typeof value !== 'string') return false;\n const word = value.trim().toLowerCase();\n return want ? ['true', 'yes', 'on'].includes(word) : ['false', 'no', 'off'].includes(word);\n}\n\n/** AFD-211: a step bound with ignore_errors: true or failed_when: false. */\nfunction ignoresErrors(node: FlowNode | undefined): boolean {\n const kw = node?.impl?.keywords;\n return !!kw && (literal(kw.ignore_errors, true) || literal(kw.failed_when, false));\n}\n\nexport interface ValidationResult {\n model: FlowModel;\n findings: Finding[];\n}\n\n/**\n * AFD-242: a disabled node the hosts cannot pass through. It goes on only when exactly one of its\n * main outputs leads somewhere (core/flow/heal); otherwise the hosts that reach it stop there.\n */\nfunction checkDisabled(model: FlowModel, add: (f: Finding) => void): void {\n for (const id of disabledIds(model)) {\n const entry = model.nodes.get(id);\n if (!entry || disabledBy(model, entry.level)) continue;\n if (!canDisable(entry.node)) {\n add({\n code: 'disabled-not-allowed',\n severity: 'error',\n message: `${label(entry.node)} is a ${entry.node.type} node and cannot be disabled`,\n path: [...entry.path, 'disabled'],\n node: id,\n });\n continue;\n }\n const level = model.levels.get(entry.level);\n const into = (level?.edges ?? []).filter((e) => e?.to?.node === id);\n const parent = level?.parent ? model.nodes.get(level.parent)?.node : undefined;\n const entryStep = parent?.subflow?.boundary?.in === id;\n if (into.length === 0 && !entryStep) continue;\n const plan = healPlan(model, [id]);\n const through = plan.wires.length + plan.exits.length + plan.entries.length;\n if (through > 0) continue;\n add({\n code: 'disabled-ends-path',\n severity: 'warning',\n message: `${label(entry.node)} is disabled and does not go on to one next step, so the hosts that reach it stop there: wire its main output, or enable it`,\n path: [...entry.path, 'disabled'],\n node: id,\n });\n }\n}\n\nexport function validateFlow(\n doc: FlowDocument,\n schemaIssues: SchemaIssue[] = [],\n): ValidationResult {\n // A file written by hand may lack IDs (AFD-19): each gap is an error, and every other check runs\n // on the flow with the gaps filled, so the rest of the design is checked as usual.\n const gaps = idGaps(doc);\n const checked = gaps.length > 0 ? withIds(doc) : doc;\n const model = buildModel(checked);\n const findings: Finding[] = schemaIssues.map((i) => ({\n code: i.code ?? 'schema',\n severity: 'error',\n message: i.code ? i.message : `Schema: ${i.message}`,\n path: pointerToPath(i.pointer),\n }));\n const add = (f: Finding) => findings.push(f);\n for (const gap of gaps)\n add({\n code: gap.unresolved ? 'unknown-key' : 'missing-id',\n severity: 'error',\n message: gap.unresolved ? gap.message : `${gap.message}: Complete IDs adds it`,\n path: gap.path,\n });\n\n checkIdentity(model, add);\n checkEdges(model, add);\n checkNodes(model, add);\n checkReferences(model, add);\n checkDecisions(model, add);\n checkUnreachableRollback(model, add);\n checkTargets(model, add);\n checkAnnotations(model, add);\n checkVarNames(model, add);\n\n for (const open of openFailPorts(model)) {\n const entry = model.nodes.get(open.node);\n // AFD-211: a step that ignores its errors fails only where Ansible will not ignore them (an\n // undefined variable, a module that cannot run): still listed, not a warning per step.\n const quiet = open.port === 'failed_hosts' && ignoresErrors(entry?.node);\n add({\n code: 'open-fail-port',\n severity: quiet ? 'info' : 'warning',\n // AFD-72: what happens to the hosts, and the two ways out, in plain words.\n message: quiet\n ? `Open fail port: ${label(entry?.node)} \u00B7 ${open.port} has nowhere to go; the step ignores errors (ignore_errors or failed_when: false), so only an undefined variable or a module that cannot run fails its hosts`\n : `Open fail port: ${label(entry?.node)} \u00B7 ${open.port} has nowhere to go, so its hosts fail the run. Wire a failure pattern to it, or Accept with Reason\u2026 to keep it open`,\n path: entry?.path ?? [],\n node: open.node,\n port: open.port,\n });\n }\n\n checkDisabled(model, add);\n // AFD-242: a disabled node does nothing, so warnings about what it would do (its binding, its\n // open fail ports, its inputs) say nothing useful: only errors and what disabling itself causes.\n const about = new Set(['disabled-ends-path', 'reads-disabled', 'disabled-not-allowed']);\n for (let i = findings.length - 1; i >= 0; i--) {\n const f = findings[i];\n if (f?.node && f.severity !== 'error' && !about.has(f.code) && disabledBy(model, f.node))\n findings.splice(i, 1);\n }\n\n const ids = new Set(model.nodes.keys());\n for (const id of Object.keys(checked.layout ?? {})) {\n if (!ids.has(id)) {\n add({\n code: 'layout-orphan',\n severity: 'info',\n message: `Layout entry for a node that does not exist: ${id}`,\n path: ['layout', id],\n });\n }\n }\n // AFD-51: warnings accepted with a reason (format 2) stay out of the problems.\n const checks = acceptedAll(checked).filter((a) => a.area === 'check');\n // AFD-184: an accepted check no warning matches hides nothing (a wrong key, or fixed since).\n for (const a of checks) {\n const entry = a.node ? model.nodes.get(a.node) : undefined;\n if (!entry) continue;\n if (\n findings.some(\n (f) => f.severity === 'warning' && f.node === a.node && acceptMatches(a.what, f),\n )\n )\n continue;\n findings.push({\n code: 'stale-decision',\n severity: 'warning',\n message: `Accepted problem ${a.what} for ${label(entry.node)} matches no warning: it hides nothing (unaccept it, or accept the key the warning shows)`,\n path: ['decisions', a.index],\n node: a.node,\n });\n }\n const kept = checks.length\n ? findings.filter(\n (f) =>\n f.severity !== 'warning' ||\n !checks.some((a) => a.node === f.node && acceptMatches(a.what, f)),\n )\n : findings;\n return { model, findings: kept };\n}\n\n/**\n * AFD-184: what an accepted check decision covers: its exact key (`<code>:<subject>`, the port\n * for port warnings), or with the code alone every subject of that code on the node.\n */\nexport function acceptMatches(what: string, f: Finding): boolean {\n return what === f.code || what === checkWhat(f.code, f.subject ?? f.port);\n}\n\n/** AFD-184: the `finding` string an accept op takes for a warning (check:<code>[:<subject>]). */\nexport function acceptKey(f: Finding): string {\n return `check:${checkWhat(f.code, f.subject ?? f.port)}`;\n}\n\nfunction checkIdentity(model: FlowModel, add: (f: Finding) => void): void {\n const seen = new Map<string, string>();\n const claim = (id: string | undefined, path: Path) => {\n if (!id) return;\n const where = path.join('.');\n const first = seen.get(id);\n if (first !== undefined) {\n add({\n code: 'duplicate-id',\n severity: 'error',\n message: `Duplicate ID ${id} (also at ${first})`,\n path,\n });\n } else {\n seen.set(id, where);\n }\n };\n claim(model.doc.flow?.id, ['flow', 'id']);\n for (const level of model.levels.values()) {\n const keys = new Map<string, number>();\n level.nodes.forEach((n, i) => {\n if (!n) return;\n claim(n.id, [...level.nodesPath, i, 'id']);\n if (keys.has(n.key)) {\n add({\n code: 'duplicate-key',\n severity: 'error',\n message: `Duplicate key \"${n.key}\" in this level`,\n path: [...level.nodesPath, i, 'key'],\n node: n.id,\n });\n } else {\n keys.set(n.key, i);\n }\n });\n level.edges.forEach((e, i) => {\n claim(e?.id, [...level.edgesPath, i, 'id']);\n });\n // AFD-64: annotations share the ID space (the canvas draws them all), keys are per level.\n const annotationKeys = new Set<string>();\n level.annotations.forEach((a, i) => {\n if (!a) return;\n claim(a.id, [...level.annotationsPath, i, 'id']);\n if (!a.key) return;\n if (annotationKeys.has(a.key))\n add({\n code: 'duplicate-key',\n severity: 'error',\n message: `Duplicate annotation key \"${a.key}\" in this level`,\n path: [...level.annotationsPath, i, 'key'],\n });\n annotationKeys.add(a.key);\n });\n }\n}\n\n/** AFD-64: a Note on a node that is not on its level; annotations in a format 1 file. */\nfunction checkAnnotations(model: FlowModel, add: (f: Finding) => void): void {\n const v2 = formatOf(model.doc) >= 2;\n for (const level of model.levels.values())\n level.annotations.forEach((a, i) => {\n if (!a || typeof a !== 'object') return;\n const path = [...level.annotationsPath, i];\n if (!v2 && i === 0)\n add({\n code: 'annotation-target-missing',\n severity: 'warning',\n message: 'Annotations are format 2: Upgrade Flow Format',\n path: level.annotationsPath,\n });\n if (a.on === undefined) return;\n const target = model.nodes.get(a.on);\n if ((a.kind ?? 'note') !== 'note' || !target || target.level !== level.id)\n add({\n code: 'annotation-target-missing',\n severity: 'warning',\n message:\n (a.kind ?? 'note') !== 'note'\n ? `${a.kind} \"${a.key ?? a.id}\" is on a node, which only a note can be: Detach it`\n : `Note \"${a.key ?? a.id}\" is on a node that is not on its level: Detach it, or attach it again`,\n path: [...path, 'on'],\n subject: a.id,\n });\n });\n}\n\nfunction checkEdges(model: FlowModel, add: (f: Finding) => void): void {\n for (const level of model.levels.values()) {\n const used = new Map<string, Ulid>();\n level.edges.forEach((edge, i) => {\n if (!edge?.from || !edge.to) return;\n const path = [...level.edgesPath, i];\n for (const [end, ref] of [\n ['from', edge.from],\n ['to', edge.to],\n ] as const) {\n const target = model.nodes.get(ref.node);\n if (!target) {\n add({\n code: 'edge-missing-node',\n severity: 'error',\n message: `Edge ${end} refers to a node that does not exist: ${ref.node}`,\n path: [...path, end, 'node'],\n edge: edge.id,\n });\n continue;\n }\n if (target.level !== level.id) {\n add({\n code: 'edge-cross-level',\n severity: 'error',\n message: `Edge ${end} ${label(target.node)} is in another level; use the subflow boundary`,\n path: [...path, end, 'node'],\n edge: edge.id,\n });\n continue;\n }\n const expected = end === 'from' ? 'out' : 'in';\n if (!isPortLegal(target.node, ref.port)) {\n add({\n code: 'edge-bad-port',\n severity: 'error',\n message: `${label(target.node)} (${target.node.type}) has no port \"${ref.port}\"`,\n path: [...path, end, 'port'],\n edge: edge.id,\n });\n } else if (portDirection(ref.port) !== expected) {\n add({\n code: 'edge-direction',\n severity: 'error',\n message: `Edge ${end} uses ${ref.port}, which is an ${portDirection(ref.port)}put port`,\n path: [...path, end, 'port'],\n edge: edge.id,\n });\n } else if (!portsFor(target.node).some((p) => p.name === ref.port)) {\n add({\n code: 'edge-port-not-enabled',\n severity: 'warning',\n message: `Port ${ref.port} of ${label(target.node)} is used but not enabled in ports:`,\n path: [...path, end, 'port'],\n edge: edge.id,\n });\n }\n }\n const fromKey = `${edge.from.node}|${edge.from.port}`;\n if (used.has(fromKey)) {\n add({\n code: 'port-multiple-edges',\n severity: 'error',\n message: `Output port ${edge.from.port} has more than one edge; use a parallel node to fan out`,\n path,\n edge: edge.id,\n });\n } else {\n used.set(fromKey, edge.id);\n }\n });\n }\n}\n\n/**\n * AFD-160: inputs, outputs and registers become Ansible variables. Only the commands checked\n * their names, so a hand- or AI-written `retry-count` reached a play's vars and Ansible refused the\n * playbook; a host_list named `web-servers` read as `web - servers` in the start pattern.\n */\nfunction checkVarNames(model: FlowModel, add: (f: Finding) => void): void {\n const check = (name: string, path: Path, node?: Ulid) => {\n const problem = varNameProblem(name);\n if (problem) add({ code: 'bad-name', severity: 'error', message: problem, path, node });\n };\n for (const name of Object.keys(model.doc.flow?.inputs ?? {}))\n check(name, ['flow', 'inputs', name]);\n for (const { node, path } of model.nodes.values()) {\n for (const side of ['inputs', 'outputs'] as const)\n for (const name of Object.keys(node[side] ?? {})) check(name, [...path, side, name], node.id);\n const register = node.impl?.register;\n if (typeof register === 'string' && register)\n check(register, [...path, 'impl', 'register'], node.id);\n }\n}\n\nfunction checkNodes(model: FlowModel, add: (f: Finding) => void): void {\n const v2 = formatOf(model.doc) >= 2;\n for (const { node, path, level } of model.nodes.values()) {\n for (const p of node.ports ?? []) {\n if (!isPortLegal(node, p)) {\n add({\n code: 'port-not-supported',\n severity: 'warning',\n message: `${label(node)} (${node.type}) does not support port \"${p}\"`,\n path: [...path, 'ports'],\n node: node.id,\n });\n }\n }\n // AFD-54: undo and cancelled were never built; the upgrade removes them and their wires.\n for (const [i, port] of (node.ports ?? []).entries()) {\n if (!LEGACY_PORTS.has(port)) continue;\n add({\n code: 'legacy-port',\n severity: 'warning',\n message: `${label(node)}: the ${port} port was never built (${port === 'undo' ? 'Rollback wires explicit undo steps' : 'a cancelled job routes no host'}); ${formatOf(model.doc) >= 2 ? 'remove it and its wires' : 'Upgrade Flow Format removes it and its wires'}`,\n path: [...path, 'ports', i],\n node: node.id,\n port,\n });\n }\n if (\n node.settings?.inventory_target?.trim() &&\n node.type !== 'task' &&\n node.type !== 'subflow'\n ) {\n add({\n code: 'inventory-target-ignored',\n severity: 'warning',\n message: `${label(node)} (${node.type}) runs on the hosts that arrive: inventory_target applies to tasks and subflows only`,\n path: [...path, 'settings', 'inventory_target'],\n node: node.id,\n });\n }\n const hasInner = (node.subflow?.nodes?.length ?? 0) > 0;\n // Format 2 (AFD-52): the AWX template has one set of credentials and one environment.\n if (v2 && (node.settings?.credential || node.settings?.execution_environment))\n add({\n code: 'setting-on-flow',\n severity: 'warning',\n message: `${label(node)}: credential and execution environment belong to the flow in format 2 (its runtime)`,\n path: [...path, 'settings'],\n node: node.id,\n });\n // AFD-61: Re-import flags the steps whose source task is gone; it never deletes them.\n if (node.origin?.gone)\n add({\n code: 'import-gone',\n severity: 'warning',\n message: `${label(node)}: its task (${node.origin.task}) is no longer in the source: delete the step, or keep it as this flow's own`,\n path: [...path, 'origin'],\n node: node.id,\n });\n // AFD-60: a shared subflow is a copy; edits belong in its source flow.\n if (node.ref && refDesign(node) !== node.ref.design)\n add({\n code: 'shared-edited',\n severity: 'warning',\n message: `${label(node)} was changed here since version ${node.ref.version} of ${node.ref.from}: Update brings the source back over these edits, Unlink keeps them as this flow's own`,\n path: [...path, 'subflow'],\n node: node.id,\n });\n if (node.ref && !v2)\n add({\n code: 'shared-edited',\n severity: 'warning',\n message: `${label(node)}: shared subflows are format 2; Upgrade Flow Format`,\n path: [...path, 'ref'],\n node: node.id,\n });\n // AFD-55: a rolling subflow's steps run in one play; some steps need plays of their own.\n if (node.settings?.rolling !== undefined) {\n if (node.type !== 'subflow')\n add({\n code: 'rolling-unsupported',\n severity: 'warning',\n message: `${label(node)}: rolling batches the steps inside a subflow; on a ${node.type} it does nothing (use serial)`,\n path: [...path, 'settings', 'rolling'],\n node: node.id,\n });\n else\n for (const o of rollingObstacles(model, node))\n add({\n code: 'rolling-unsupported',\n severity: 'error',\n message: `${label(node)} cannot roll: ${label(o.node)}: ${o.why}. Its steps run play by play`,\n path: [...path, 'settings', 'rolling'],\n node: o.node.id,\n });\n }\n // Format 2 (AFD-52): `handler` is called purpose, so it is not read as an Ansible handler.\n if (v2 && node.handler !== undefined)\n add({\n code: 'renamed-field',\n severity: 'warning',\n message: `${label(node)}: handler is called purpose in format 2`,\n path: [...path, 'handler'],\n node: node.id,\n });\n // Format 2 (AFD-52): become_user is a setting, which a subflow passes to its steps.\n if (v2 && node.impl?.keywords && 'become_user' in node.impl.keywords)\n add({\n code: 'keyword-is-setting',\n severity: 'warning',\n message: `${label(node)}: become_user is a setting in format 2 (Execution \u203A Privilege)`,\n path: [...path, 'impl', 'keywords', 'become_user'],\n node: node.id,\n });\n // Format 2 (AFD-50): the status is the one the content gives; a hand edit can still disagree.\n if (v2 && hasStatus(node)) {\n const have = node.status ?? 'draft';\n const want = statusFor(model.doc, node);\n if (have === 'tested' && !node.tested)\n add({\n code: 'tested-without-record',\n severity: 'warning',\n message: `${label(node)} is tested but has no record of the run or the reason`,\n path: [...path, 'status'],\n node: node.id,\n });\n else if (have !== want)\n add({\n code: 'status-out-of-step',\n severity: 'info',\n message: `${label(node)} is ${have}, but what it has makes it ${want}`,\n path: [...path, 'status'],\n node: node.id,\n });\n }\n if (\n !v2 &&\n (node.status === 'implemented' || node.status === 'tested') &&\n !node.impl &&\n !hasInner\n ) {\n add({\n code: 'status-overclaim',\n severity: 'warning',\n message: `${label(node)} is ${node.status} but has no implementation binding`,\n path: [...path, 'status'],\n node: node.id,\n });\n }\n if (\n !v2 &&\n node.status === 'specified' &&\n Object.keys(node.inputs ?? {}).length + Object.keys(node.outputs ?? {}).length === 0\n ) {\n add({\n code: 'status-overclaim',\n severity: 'warning',\n message: `${label(node)} is specified but declares no inputs or outputs`,\n path: [...path, 'status'],\n node: node.id,\n });\n }\n for (const [name, field] of Object.entries(node.inputs ?? {})) {\n if (field?.type === 'host_list') {\n add({\n code: 'host-list-input',\n severity: 'info',\n message: `Input \"${name}\" of ${label(node)}: the hosts arriving on \"in\" are the targets; this host_list is informational`,\n path: [...path, 'inputs', name],\n node: node.id,\n });\n }\n }\n if (node.type === 'approval') checkApprovalSplit(model, node, level, path, add);\n checkEnginePorts(node, path, hasInner, add);\n }\n}\n\n/** Ports the Option A engine cannot drive for this node (ADR-0009, M3 spike). */\nfunction checkEnginePorts(\n node: FlowNode,\n path: Path,\n hasInner: boolean,\n add: (f: Finding) => void,\n): void {\n if (node.type !== 'task' && node.type !== 'subflow') return;\n const enabled = new Set(portsFor(node).map((p) => p.name));\n if (node.impl?.kind === 'role' && !hasInner) {\n for (const port of ['unreachable', 'unchanged']) {\n if (!enabled.has(port)) continue;\n add({\n code: 'port-role-unroutable',\n severity: 'warning',\n message:\n port === 'unreachable'\n ? `${label(node)} runs a role: hosts that become unreachable inside it drop out of the run and cannot take \"unreachable\". Put the connecting step in its own module node or a subflow`\n : `${label(node)} runs a role: Ansible gives no per-host \"changed\" for a role, so \"unchanged\" never fires`,\n path: [...path, 'ports'],\n node: node.id,\n port,\n });\n }\n }\n // AFD-103: a timeout codegen cannot read is left out of the task without a word. AFD-112: a\n // template is read at run time (an approval's: checkTimingInputs).\n const timeout = node.settings?.timeout;\n if (\n !hasInner &&\n timeout !== undefined &&\n String(timeout).trim() &&\n !templated(timeout) &&\n durationSeconds(timeout) === undefined\n ) {\n add({\n code: 'timeout-unreadable',\n severity: 'warning',\n message: `${label(node)} timeout \"${timeout}\" is not a duration (30s, 15m, 1h30m), so the step runs without one`,\n path: [...path, 'settings', 'timeout'],\n node: node.id,\n });\n }\n if (enabled.has('timeout') && !hasInner && !node.settings?.timeout) {\n add({\n code: 'timeout-without-setting',\n severity: 'warning',\n message: `${label(node)} enables \"timeout\" but sets no settings.timeout, so it never fires`,\n path: [...path, 'ports'],\n node: node.id,\n port: 'timeout',\n });\n }\n}\n\nfunction checkTargets(model: FlowModel, add: (f: Finding) => void): void {\n // A list default that is a string (default: edge) is joined letter by letter (AFD-27).\n for (const [name, f] of Object.entries(model.doc.flow?.inputs ?? {}))\n if ((f?.type === 'host_list' || f?.type === 'list') && typeof f.default === 'string')\n add({\n code: 'input-default-type',\n severity: 'warning',\n message: `Flow input ${name} is a ${f.type} but its default is the string \"${f.default}\": write it as a list, [${f.default}]`,\n path: ['flow', 'inputs', name, 'default'],\n });\n const inputs = Object.values(model.doc.flow?.inputs ?? {});\n if (inputs.some((f) => f?.type === 'host_list')) return;\n add({\n code: 'no-targets',\n severity: 'warning',\n message: 'The flow has no host_list input, so start has no hosts and no code can be generated',\n path: ['flow', 'inputs'],\n });\n}\n\nfunction checkApprovalSplit(\n model: FlowModel,\n node: FlowNode,\n levelId: string,\n path: Path,\n add: (f: Finding) => void,\n): void {\n const edges = model.levels.get(levelId)?.edges ?? [];\n const target = (port: string) =>\n edges.find((e) => e?.from?.node === node.id && e.from.port === port)?.to.node;\n const rejected = target('rejected');\n const timeout = target('timeout');\n if (rejected && timeout && rejected !== timeout) {\n add({\n code: 'approval-split',\n severity: 'warning',\n message: `${label(node)}: AWX cannot tell rejected from timeout; both follow one failure path`,\n path,\n node: node.id,\n });\n }\n}\n\n/** Variables every task can read: Ansible's magic and connection variables, loop items, omit. */\nexport const MAGIC_VARS =\n /^(ansible_[a-z0-9_]*|inventory_hostname(_short)?|inventory_dir|inventory_file|hostvars|groups|group_names|play_hosts|playbook_dir|role_path|role_name|omit|item|ansible_loop_var|lookup|query|q|now|range|dict|namespace|loop|afd_[a-z0-9_]*|awx_[a-z0-9_]*|tower_[a-z0-9_]*)$/;\n\nexport function bareParams(impl: NonNullable<FlowNode['impl']>): unknown[] {\n if (impl.kind !== 'module') return [];\n const short = impl.ref.replace(/^ansible\\.(builtin|legacy)\\./, '');\n return (BARE_PARAMS[short] ?? []).map((k) => impl.params?.[k]).filter((v) => v !== undefined);\n}\n\n/**\n * Where a name a node reads could come from, as the fix (AFD-21): the enclosing subflow's input, an\n * upstream output, or an output of a step inside an upstream subflow (which the tools lift).\n */\nfunction hintFor(model: FlowModel, node: FlowNode, level: string, name: string): string {\n for (const sub of enclosing(model, level))\n if (sub.inputs && name in sub.inputs)\n return `; subflow ${sub.key} has it as an input: add input ${name} (from: ${sub.key}.${name})`;\n const upstream = upstreamNodes(model, node.id);\n for (const up of upstream)\n if (up.outputs && name in up.outputs) return `; add input ${name} (from: ${up.key}.${name})`;\n // AFD-287: a fact an earlier step sets with set_fact, not declared as its output yet.\n const setter = factSetter(model, node, name);\n if (setter)\n return `; \"${setter.title}\" sets it (set_fact): use it as an input (quick fix, or the @ picker), which makes it an output there`;\n const inside = (sub: FlowNode, path: string): string | undefined => {\n for (const step of sub.subflow?.nodes ?? []) {\n if (!step?.key) continue;\n if (step.outputs && name in step.outputs) return `${path}/${step.key}`;\n const deeper = step.subflow ? inside(step, `${path}/${step.key}`) : undefined;\n if (deeper) return deeper;\n }\n return undefined;\n };\n for (const up of upstream) {\n const at = up.type === 'subflow' ? inside(up, up.key) : undefined;\n if (at)\n return `; ${at} sets it: add input ${name} from ${at}.${name} with the AI tools or the @ picker, which lift it to ${up.key}`;\n }\n return '';\n}\n\n/**\n * Binding parameters read node inputs (chips, D-26). A read of anything else works only by luck\n * (a flow extra var, another node's fact), and the design does not show the data dependency.\n * Bare expressions (assert `that`) are read too (AFD-21).\n */\nfunction checkBindingVars(\n model: FlowModel,\n node: FlowNode,\n level: string,\n path: Path,\n flowInputs: Set<string>,\n external: Set<string>,\n add: (f: Finding) => void,\n): void {\n const impl = node.impl;\n if (!impl) return;\n const inputs = new Set(Object.keys(node.inputs ?? {}));\n // Task keywords read inputs too (AFD-26); loop variables and task vars are their own names, and\n // changed_when / failed_when may read the step's result.\n const kw = keywordReads(impl);\n const known = new Set([\n ...kw.own,\n ...(impl.kind === 'module' ? [registerName(node)] : []),\n ...setFactNames(impl),\n ...external,\n ]);\n const reads: [Set<string>, Path][] = [\n [\n new Set([...refsIn(impl.params ?? {}), ...exprRefs(bareParams(impl))]),\n [...path, 'impl', 'params'],\n ],\n [new Set([...kw.templated, ...kw.bare]), [...path, 'impl', 'keywords']],\n ];\n const reported = new Set<string>();\n const bindingText = JSON.stringify([impl.params ?? {}, impl.keywords ?? {}]);\n for (const [read, where] of reads)\n for (const name of read) {\n if (inputs.has(name) || known.has(name) || MAGIC_VARS.test(name) || reported.has(name))\n continue;\n reported.add(name);\n const flow = flowInputs.has(name);\n // AFD-185: a value read only with a fallback (| default, is defined) cannot fail the task.\n const optional = !flow && onlyGuarded(bindingText, name);\n add({\n code: 'binding-unknown-var',\n severity: flow || optional ? 'info' : 'warning',\n message: flow\n ? `${label(node)} reads flow input \"${name}\" directly: add it as a node input (from: flow.${name}) to show the dependency`\n : optional\n ? `${label(node)} reads \"${name}\" only with a fallback (default or is defined): fine when nothing sets it; an input, or flow.external_vars, shows where it comes from`\n : `${label(node)} reads \"${name}\", which is not an input of this node${hintFor(model, node, level, name)}`,\n path: where,\n node: node.id,\n subject: name,\n });\n }\n const keywords = impl.keywords && typeof impl.keywords === 'object' ? impl.keywords : undefined;\n if (keywords && Object.keys(keywords).length > 0 && impl.kind === 'playbook')\n add({\n code: 'keyword-ignored',\n severity: 'warning',\n message: `${label(node)} runs a playbook: task keywords cannot apply to import_playbook, so they are ignored`,\n path: [...path, 'impl', 'keywords'],\n node: node.id,\n });\n else if (keywords?.vars !== undefined && impl.kind === 'role')\n add({\n code: 'keyword-ignored',\n severity: 'warning',\n message: `${label(node)} runs a role: role variables belong in params, so keywords.vars is ignored`,\n path: [...path, 'impl', 'keywords', 'vars'],\n node: node.id,\n });\n}\n\n/** Decision conditions and `until` read node inputs too (AFD-21); `until` also the step's result. */\nfunction checkConditions(\n model: FlowModel,\n node: FlowNode,\n level: string,\n path: Path,\n flowInputs: Set<string>,\n external: Set<string>,\n add: (f: Finding) => void,\n): void {\n const inputs = new Set(Object.keys(node.inputs ?? {}));\n const check = (expr: string, where: Path, what: string, result?: string) => {\n for (const name of exprRefs(expr)) {\n if (inputs.has(name) || name === result || MAGIC_VARS.test(name) || external.has(name))\n continue;\n const flow = flowInputs.has(name);\n add({\n code: 'condition-unknown-var',\n severity: flow ? 'info' : 'warning',\n message: flow\n ? `${label(node)} ${what} reads flow input \"${name}\" directly: add it as a node input (from: flow.${name}) to show the dependency`\n : `${label(node)} ${what} reads \"${name}\", which is not ${result ? `its result (${result}) or ` : ''}an input of this node${hintFor(model, node, level, name)}`,\n path: where,\n node: node.id,\n subject: name,\n });\n }\n };\n if (node.type === 'decision' && typeof node.condition === 'string') {\n check(node.condition, [...path, 'condition'], 'condition');\n // AFD-146: the generator puts the condition inside a Jinja expression of its own.\n if (conditionHasBraces(node.condition))\n add({\n code: 'condition-braces',\n severity: 'error',\n message: `${label(node)} condition has {{ }} or {% %} inside it: write it as a when: is written, without them (x == 1, not {{ x }} == 1)`,\n path: [...path, 'condition'],\n node: node.id,\n });\n }\n const until = node.settings?.until;\n if (typeof until !== 'string' || !until.trim()) return;\n if (node.impl?.kind === 'role' || node.impl?.kind === 'playbook')\n add({\n code: 'until-not-module',\n severity: 'warning',\n message: `${label(node)} runs a ${node.impl.kind}: until applies to a module step only, so it is ignored`,\n path: [...path, 'settings', 'until'],\n node: node.id,\n });\n else {\n const result = registerName(node);\n check(until, [...path, 'settings', 'until'], 'until', result);\n // AFD-103 (round 3: R2): the whole result is a dict, so comparing it with a value never holds.\n if (comparesWholeResult(until, result))\n add({\n code: 'until-whole-result',\n severity: 'warning',\n message: `${label(node)} until compares the whole result ${result} with a value, so it never holds: test a field of it, like ${result}.stdout or ${result}.rc`,\n path: [...path, 'settings', 'until'],\n node: node.id,\n });\n }\n}\n\n/** The Timing settings a step may take at run time (AFD-112, round 4: Q4). */\nconst RUN_TIME_TIMING = ['retries', 'delay', 'timeout'] as const;\n\n/**\n * AFD-112 (round 4: Q4): Retries, Delay and Timeout given at run time read the step's inputs, as\n * Until does: a name that is no input is not there when Ansible renders the template, and an\n * input that holds no number fails the task.\n */\nfunction checkTimingInputs(\n model: FlowModel,\n node: FlowNode,\n level: string,\n path: Path,\n flowInputs: Set<string>,\n external: Set<string>,\n add: (f: Finding) => void,\n): void {\n if (node.type === 'approval') {\n const timeout = node.settings?.timeout;\n if (templated(timeout))\n add({\n code: 'timeout-unreadable',\n severity: 'warning',\n message: `${label(node)} timeout \"${timeout}\" is given at run time, but an AWX approval needs a fixed duration (30m, 4h), so it gets none`,\n path: [...path, 'settings', 'timeout'],\n node: node.id,\n });\n return;\n }\n const inputs = node.inputs ?? {};\n for (const key of RUN_TIME_TIMING) {\n const value = node.settings?.[key];\n if (!templated(value)) continue;\n const where = [...path, 'settings', key];\n for (const name of exprRefs(value)) {\n if (name in inputs || MAGIC_VARS.test(name) || external.has(name)) continue;\n const flow = flowInputs.has(name);\n add({\n code: 'setting-unknown-var',\n severity: flow ? 'info' : 'warning',\n message: flow\n ? `${label(node)} ${key} reads flow input \"${name}\" directly: add it as a node input (from: flow.${name}) to show the dependency`\n : `${label(node)} ${key} reads \"${name}\", which is not an input of this node${hintFor(model, node, level, name)}`,\n path: where,\n node: node.id,\n subject: name,\n });\n }\n const one = singleRef(value);\n const type = one ? inputs[one]?.type : undefined;\n if (type && ['boolean', 'list', 'dict', 'host_list'].includes(type))\n add({\n code: 'setting-input-type',\n severity: 'warning',\n message: `${label(node)} ${key} reads ${one}, a ${type.replace('_', ' ')}: Ansible needs a whole number${key === 'retries' ? '' : ' of seconds'} there, so the task fails`,\n path: where,\n node: node.id,\n subject: one,\n });\n }\n}\n\n/**\n * AFD-106 (round 3: R7): a step input that nothing feeds. The participant typed a step's register\n * name into a later step; that step got an input with no `from`, and the flow validated clean while\n * the value never passed the designer's way. A default feeds it; a host list is the targets'; a\n * subflow's input feeds its inner steps.\n */\nfunction checkUnfed(\n model: FlowModel,\n node: FlowNode,\n level: string,\n path: Path,\n name: string,\n flowInputs: Set<string>,\n add: (f: Finding) => void,\n): void {\n if (node.type !== 'task' && node.type !== 'approval') return;\n const field = node.inputs?.[name];\n if (!field || field.default !== undefined || field.optional || field.type === 'host_list') return;\n const flow = flowInputs.has(name);\n const registers = upstreamNodes(model, node.id).find(\n (up) => up.impl?.kind === 'module' && registerName(up) === name,\n );\n const hint = flow\n ? `: flow input \"${name}\" has the same name: set from: flow.${name}`\n : registers\n ? `: ${label(registers)} registers ${name}: make it an output there (Expose as node output) and pick it with @`\n : hintFor(model, node, level, name);\n add({\n code: 'input-unfed',\n severity: flow ? 'info' : 'warning',\n message: `${label(node)} inputs.${name}: nothing gives it a value (no from, no default)${hint}`,\n path: [...path, 'inputs', name],\n node: node.id,\n subject: name,\n });\n}\n\n/** A subflow output without from lifts the inner output of the same name (AFD-21). */\nfunction checkLifts(node: FlowNode, path: Path, add: (f: Finding) => void): void {\n if (node.type !== 'subflow' || !node.subflow?.nodes?.length) return;\n for (const [name, field] of Object.entries(node.outputs ?? {})) {\n if (field?.from) continue;\n const lift = liftOf(node, name);\n if (lift && 'inner' in lift) continue;\n add({\n code: 'subflow-output-unset',\n severity: 'warning',\n message: lift\n ? `Subflow ${label(node)} output ${name}: ${lift.ambiguous.join(' and ')} all have it; name one in from (${lift.ambiguous[0]}.${name})`\n : `Subflow ${label(node)} output ${name}: no inner step has an output ${name}, so nothing sets it; name the inner output it lifts in from (<step>.<output>)`,\n path: [...path, 'outputs', name],\n node: node.id,\n });\n }\n}\n\nfunction checkReferences(model: FlowModel, add: (f: Finding) => void): void {\n const flowInputs = new Set(Object.keys(model.doc.flow?.inputs ?? {}));\n const external = externalVars(model);\n for (const { node, path, level } of model.nodes.values()) {\n for (const side of ['inputs', 'outputs'] as const) {\n for (const [name, field] of Object.entries(node[side] ?? {})) {\n const from = field?.from;\n if (typeof from !== 'string' || !from) {\n if (side === 'inputs') checkUnfed(model, node, level, path, name, flowInputs, add);\n continue;\n }\n const src = resolveFrom(model, node, level, side, from);\n // AFD-242: a disabled step makes nothing; what reads it has no value at run time.\n const off = src.kind === 'output' ? disabledBy(model, src.node.id) : undefined;\n if (off && !disabledBy(model, node.id))\n add({\n code: 'reads-disabled',\n severity: 'warning',\n message: `${label(node)} ${side}.${name} reads \"${from}\", but ${label(off)} is disabled and makes nothing: give it a default, or enable ${label(off)}`,\n path: [...path, side, name, 'from'],\n node: node.id,\n subject: name,\n });\n if (src.kind === 'output' && side === 'inputs') {\n const at: Path = [...path, side, name, 'from'];\n checkCollision(model, node, src.node, src.name, from, at, name, add);\n checkShadowed(model, node, src.node, from, at, name, add);\n if (field.default === undefined && !field.optional && !guarded(node, name))\n checkProducerRuns(model, node, src.node, src.name, from, at, name, add);\n }\n if (src.kind !== 'unresolved') continue;\n add({\n code: 'from-unresolved',\n severity: 'warning',\n message: `${label(node)} ${side}.${name}: \"${from}\" ${src.why}`,\n path: [...path, side, name, 'from'],\n node: node.id,\n subject: name,\n });\n }\n }\n checkLifts(node, path, add);\n }\n checkTopLevelOutcomes(model, add);\n for (const { node, path, level } of model.nodes.values()) {\n checkBindingVars(model, node, level, path, flowInputs, external, add);\n checkConditions(model, node, level, path, flowInputs, external, add);\n checkTimingInputs(model, node, level, path, flowInputs, external, add);\n checkPlaybookDir(node, path, add);\n // AFD-273: who decides is a question only an approval asks.\n if (node.approval && node.type !== 'approval')\n add({\n code: 'approval-fields',\n severity: 'warning',\n message: `\"${node.title}\" is not an approval: its approvers, notify and message mean nothing`,\n path: [...path, 'approval'],\n node: node.id,\n });\n }\n const runtime = model.doc.flow?.runtime?.kind;\n const v2 = formatOf(model.doc) >= 2;\n // AWX workflows split at top-level approvals (AFD-11, ADR-0016).\n const plan = planSegments(model);\n for (const p of plan?.problems ?? [])\n add({\n code: 'awx-segments',\n severity: runtime === 'awx_workflow' ? 'error' : 'warning',\n message: `${p.message}. Local and skeleton runs approve automatically`,\n path: p.node ? (model.nodes.get(p.node)?.path ?? []) : ['nodes'],\n node: p.node,\n });\n if (v2 && runtime)\n add({\n code: 'runtime-kind',\n severity: 'info',\n message: `In format 2 the flow's runtime is worked out from the flow (it is ${runtimeKind(model)}): runtime.kind can go`,\n path: ['flow', 'runtime', 'kind'],\n });\n else if (runtime && runtime !== 'ansible_playbook') {\n const split = !!plan && plan.problems.length === 0 && plan.segments.length > 0;\n const inferred = split ? 'awx_workflow' : 'awx_job';\n if (runtime !== inferred) {\n add({\n code: 'runtime-kind',\n severity: 'info',\n message: `runtime.kind is ${runtime}, but the compiled engine produces ${inferred} for this flow`,\n path: ['flow', 'runtime', 'kind'],\n });\n }\n }\n for (const level of model.levels.values()) {\n if (level.id === ROOT) continue;\n const parent = model.nodes.get(level.parent ?? '')?.node;\n if (parent) checkBoundaryFlow(model, parent, level.nodes, level.edges, add);\n const boundary = parent?.subflow?.boundary;\n if (!parent || !boundary) continue;\n const base = model.nodes.get(parent.id)?.path ?? [];\n const inner = new Set(level.nodes.map((n) => n?.id));\n if (boundary.in && !inner.has(boundary.in)) {\n add({\n code: 'boundary-ref',\n severity: 'warning',\n message: `Subflow ${label(parent)}: boundary.in is not an inner node`,\n path: [...base, 'subflow', 'boundary', 'in'],\n node: parent.id,\n });\n }\n const parentPorts = new Set(portsFor(parent).map((p) => p.name));\n for (const [port, refs] of Object.entries(boundary.outputs ?? {})) {\n if (!parentPorts.has(port)) {\n add({\n code: 'boundary-ref',\n severity: 'warning',\n message: `Subflow ${label(parent)}: boundary output \"${port}\" is not a port of the subflow node`,\n path: [...base, 'subflow', 'boundary', 'outputs', port],\n node: parent.id,\n });\n }\n for (const ref of refs ?? []) {\n const from = level.nodes.find((n) => n?.id === ref?.node);\n if (!from) {\n add({\n code: 'boundary-ref',\n severity: 'warning',\n message: `Subflow ${label(parent)}: boundary output \"${port}\" refers to a node outside the subflow`,\n path: [...base, 'subflow', 'boundary', 'outputs', port],\n node: parent.id,\n });\n } else if (!isPortLegal(from, ref.port) || portDirection(ref.port) !== 'out') {\n add({\n code: 'boundary-ref',\n severity: 'warning',\n message: `Subflow ${label(parent)}: ${label(from)} has no output \"${ref.port}\" to leave through \"${port}\"`,\n path: [...base, 'subflow', 'boundary', 'outputs', port],\n node: parent.id,\n });\n } else if (\n level.edges.some((e) => e?.from?.node === ref.node && e.from.port === ref.port)\n ) {\n add({\n code: 'boundary-ref',\n severity: 'warning',\n message: `Subflow ${label(parent)}: ${label(from)} \u00B7 ${ref.port} is wired inside and also leaves through \"${port}\"`,\n path: [...base, 'subflow', 'boundary', 'outputs', port],\n node: parent.id,\n });\n }\n }\n }\n }\n}\n\n/**\n * 03 \"Subflow boundary\": hosts must be able to enter the inner graph, every enabled output of the\n * subflow must be fed from inside (an exit, or a fail port that bubbles up), and an inner outcome\n * that neither continues inside nor leaves the subflow strands its hosts (D-23).\n */\nfunction checkBoundaryFlow(\n model: FlowModel,\n parent: FlowNode,\n nodes: FlowNode[],\n edges: { from: PortRef; to: PortRef }[],\n add: (f: Finding) => void,\n): void {\n const inner = nodes.filter((n): n is FlowNode => !!n?.id);\n if (inner.length === 0) return;\n const base = model.nodes.get(parent.id)?.path ?? [];\n const boundary = parent.subflow?.boundary;\n if (!boundary?.in) {\n add({\n code: 'boundary-no-entry',\n severity: 'warning',\n message: `Subflow ${label(parent)} has no entry step: hosts reaching it never run its inner steps`,\n path: [...base, 'subflow'],\n node: parent.id,\n });\n }\n const taken = levelTaken(edges, parent);\n for (const port of portsFor(parent)) {\n if (port.direction !== 'out' || port.name === 'cancelled') continue;\n const fed =\n (boundary?.outputs?.[port.name] ?? []).length > 0 ||\n fedByBubbling(parent, port.name, inner, taken);\n if (!fed) {\n add({\n code: 'boundary-port-unfed',\n severity: 'warning',\n message: `Subflow ${label(parent)} \u00B7 ${port.name} is never taken: no inner step leaves through it`,\n path: [...base, 'subflow'],\n node: parent.id,\n port: port.name,\n });\n }\n }\n for (const n of inner) {\n for (const p of portsFor(n)) {\n if (p.direction !== 'out' || p.fail || p.name === 'cancelled') continue;\n if (!untaken(n.id, p.name, taken)) continue;\n add({\n code: 'inner-exit-unmapped',\n severity: 'warning',\n message: `${label(n)} \u00B7 ${p.name} inside ${label(parent)} leads nowhere: its hosts never reach an outer port`,\n path: model.nodes.get(n.id)?.path ?? [],\n node: n.id,\n port: p.name,\n });\n }\n }\n}\n\n/**\n * An outcome on the top level that leads nowhere strands its hosts, as an unmapped inner exit\n * does inside a subflow (AFD-31: warned at every level).\n */\nfunction checkTopLevelOutcomes(model: FlowModel, add: (f: Finding) => void): void {\n const level = model.levels.get(ROOT);\n if (!level) return;\n const wired = new Set(level.edges.map((e) => `${e?.from?.node}|${e?.from?.port}`));\n for (const n of level.nodes) {\n if (!n?.id) continue;\n for (const p of portsFor(n)) {\n if (p.direction !== 'out' || p.fail || p.name === 'cancelled') continue;\n if (wired.has(`${n.id}|${p.name}`)) continue;\n add({\n code: 'success-port-unwired',\n severity: 'warning',\n message: `${label(n)} \u00B7 ${p.name} leads nowhere: its hosts stop there without reaching an end node`,\n path: model.nodes.get(n.id)?.path ?? [],\n node: n.id,\n port: p.name,\n });\n }\n }\n}\n\n/**\n * Every use of an input in the binding goes through `| default(\u2026)`, as the handlers an import\n * writes do (`(x_result | default({})) is changed`): a missing value is expected there.\n */\n/**\n * Every read of `name` in the text goes through `| default` or tests whether it is defined, so a\n * missing value is handled where it is read (AFD-185, AFD-187).\n */\nfunction onlyGuarded(text: string, name: string): boolean {\n const uses = text.match(new RegExp(`\\\\b${name}\\\\b`, 'g'))?.length ?? 0;\n const safe =\n (text.match(new RegExp(`\\\\b${name}\\\\s*\\\\|\\\\s*default\\\\b`, 'g'))?.length ?? 0) +\n (text.match(new RegExp(`\\\\b${name}\\\\s+is\\\\s+(not\\\\s+)?(defined|undefined|none)\\\\b`, 'g'))\n ?.length ?? 0);\n return uses > 0 && uses <= safe;\n}\n\nfunction guarded(node: FlowNode, input: string): boolean {\n // A when (or a list item of it) that tests the input guards the whole step.\n const when = node.impl?.keywords?.when;\n const tests = new RegExp(`\\\\b${input}\\\\s+is\\\\s+defined\\\\b`);\n if ((Array.isArray(when) ? when : [when]).some((w) => typeof w === 'string' && tests.test(w)))\n return true;\n const text = JSON.stringify([\n node.impl?.params ?? {},\n node.impl?.keywords ?? {},\n node.condition ?? '',\n node.settings?.until ?? '',\n ]);\n const uses = text.match(new RegExp(`\\\\b${input}\\\\b`, 'g'))?.length ?? 0;\n const safe =\n (text.match(new RegExp(`\\\\b${input}\\\\s*\\\\|\\\\s*default\\\\b`, 'g'))?.length ?? 0) +\n (text.match(new RegExp(`\\\\b${input}\\\\s+is\\\\s+(not\\\\s+)?(defined|undefined|none)\\\\b`, 'g'))\n ?.length ?? 0);\n return uses > 0 && uses <= safe;\n}\n\n/** The step that really sets a node's output: a subflow output follows its lift inward. */\nfunction producerOf(node: FlowNode, output: string, depth = 0): FlowNode {\n if (node.type !== 'subflow' || depth > 16) return node;\n const lift = liftOf(node, output);\n return lift && 'inner' in lift ? producerOf(lift.inner, lift.output, depth + 1) : node;\n}\n\n/**\n * The host variables steps write, by step: every module step's register, and the variables\n * outputs land in (a register, or the step's own captured variable, AFD-53).\n */\nfunction hostVariables(model: FlowModel): Map<string, Set<Ulid>> {\n const vars = new Map<string, Set<Ulid>>();\n const add = (root: string, id: Ulid) => vars.set(root, (vars.get(root) ?? new Set()).add(id));\n for (const { node } of model.nodes.values()) {\n if (node.type === 'subflow') continue;\n if (node.impl?.kind === 'module') add(registerName(node), node.id);\n for (const out of Object.keys(node.outputs ?? {}))\n add(outputVar(model, node, out).split('.')[0] ?? out, node.id);\n }\n return vars;\n}\n\nconst variablesOf = new WeakMap<FlowModel, Map<string, Set<Ulid>>>();\n\n/**\n * `from: a.result` reads a host variable (AFD-31). Outputs other than registers are captured into\n * the step's own variable (AFD-53); a register is named by the flow, so another step registering the\n * same name, or a flow input (an extra var) of that name, changes what the reader gets: an error.\n */\nfunction checkCollision(\n model: FlowModel,\n reader: FlowNode,\n target: FlowNode,\n output: string,\n from: string,\n path: Path,\n input: string,\n add: (f: Finding) => void,\n): void {\n const producer = producerOf(target, output);\n const root = outputVar(model, target, output).split('.')[0] ?? output;\n let vars = variablesOf.get(model);\n if (!vars) {\n vars = hostVariables(model);\n variablesOf.set(model, vars);\n }\n const others = [...(vars.get(root) ?? [])]\n .filter((id) => id !== producer.id)\n .map((id) => label(model.nodes.get(id)?.node));\n const flowInput = root in (model.doc.flow?.inputs ?? {});\n if (others.length === 0 && !flowInput) return;\n const who = [...(flowInput ? [`the flow input ${root}`] : []), ...others].join(', ');\n add({\n code: 'register-collision',\n severity: 'error',\n message: `${label(reader)} inputs.${input}: \"${from}\" reads the register ${root}, which ${who} also set${others.length + (flowInput ? 1 : 0) > 1 ? '' : 's'}: it reads ${flowInput ? 'the flow input' : 'whichever ran last'}`,\n path,\n node: reader.id,\n });\n}\n\n/** The nodes reachable on a level from `start` over its wires, never passing `skip`. */\nfunction reachable(\n edges: { from: PortRef; to: PortRef }[],\n start: Ulid[],\n skip?: Ulid,\n blocked?: Set<string>,\n): Set<Ulid> {\n const seen = new Set<Ulid>(start.filter((s) => s !== skip));\n const queue = [...seen];\n const open = blocked?.size\n ? edges.filter((e) => !blocked.has(`${e?.from?.node}|${e?.from?.port}`))\n : edges;\n // AFD-162: wires by node, built once per level, instead of every wire per visited node.\n for (let i = 0; i < queue.length; i++)\n for (const to of successors(open, queue[i] as Ulid)) {\n if (to === skip || seen.has(to)) continue;\n seen.add(to);\n queue.push(to);\n }\n return seen;\n}\n\ntype ModelLevel = NonNullable<ReturnType<FlowModel['levels']['get']>>;\n\n/** Where a `from:` is checked: the producer's level, the reader (or the subflow around it) on it. */\nfunction producerPlace(\n model: FlowModel,\n reader: FlowNode,\n producer: FlowNode,\n): { level: ModelLevel; target: Ulid; entries: Ulid[] } | undefined {\n const where = model.nodes.get(producer.id)?.level;\n const level = where ? model.levels.get(where) : undefined;\n if (!level) return undefined;\n let at = model.nodes.get(reader.id);\n while (at && at.level !== where) at = model.nodes.get(at.level);\n if (!at || at.node.id === producer.id) return undefined;\n const parent = level.parent ? model.nodes.get(level.parent)?.node : undefined;\n const entries =\n level.id === ROOT\n ? level.nodes.filter((n) => n?.type === 'start').map((n) => n.id)\n : parent?.subflow?.boundary?.in\n ? [parent.subflow.boundary.in]\n : [];\n return { level, target: at.node.id, entries };\n}\n\n/**\n * AFD-212: whether a step sets a host variable of this name: its register, a set_fact of it, or an\n * output of that name (a step's output is a fact of its own name, AFD-53). Generated plays pass an\n * input as a play var, and Ansible ranks set_fact and register above play vars: once a step has\n * set the input's name, the reader gets that fact, whatever its `from:` names.\n */\nfunction setsName(node: FlowNode, name: string): boolean {\n if (node.type === 'subflow') return false;\n const impl = node.impl;\n if (impl?.kind === 'module' && (registerName(node) === name || setFactNames(impl).includes(name)))\n return true;\n return !!node.outputs && name in node.outputs && !fromRegister(node, name);\n}\n\n/** The steps that set a name, and those with every subflow around them (which may set it). */\ninterface NameSetters {\n sets: Set<Ulid>;\n may: Set<Ulid>;\n}\n\nconst settersByModel = new WeakMap<FlowModel, Map<string, NameSetters>>();\n\nfunction nameSetters(model: FlowModel, name: string): NameSetters {\n let byName = settersByModel.get(model);\n if (!byName) {\n byName = new Map();\n settersByModel.set(model, byName);\n }\n let found = byName.get(name);\n if (!found) {\n found = { sets: new Set(), may: new Set() };\n for (const { node } of model.nodes.values()) {\n if (!setsName(node, name)) continue;\n found.sets.add(node.id);\n for (let at = model.nodes.get(node.id); at; at = model.nodes.get(at.level))\n found.may.add(at.node.id);\n }\n byName.set(name, found);\n }\n return found;\n}\n\n/** Where a node's wires lead from its success ports (not its fail ports). */\nfunction okTargets(level: ModelLevel, node: Ulid): Ulid[] {\n return level.edges\n .filter((e) => e?.from?.node === node && !isFailPort(e.from.port))\n .map((e) => e.to.node);\n}\n\n/**\n * The step a `from:` reads must have run, and succeeded, for every host that gets here (AFD-31):\n * on its level it lies on every path from the entry to the reader (or the subflow holding it), and\n * no path from its fail ports leads there. AFD-212: a step on that level that sets the input's own\n * name does as well, since the reader gets that fact (see setsName).\n */\nfunction checkProducerRuns(\n model: FlowModel,\n reader: FlowNode,\n producer: FlowNode,\n output: string | undefined,\n from: string,\n path: Path,\n input: string,\n add: (f: Finding) => void,\n): void {\n const place = producerPlace(model, reader, producer);\n if (!place) return;\n const { level, target, entries } = place;\n const setters = nameSetters(model, input);\n const others = level.nodes.filter(\n (n): n is FlowNode =>\n !!n &&\n n.id !== producer.id &&\n n.id !== target &&\n (setters.sets.has(n.id) || (n.type === 'subflow' && input in (n.outputs ?? {}))),\n );\n const covers = new Set([producer.id, ...others.map((n) => n.id)]);\n const by = others.length\n ? `${label(producer)} or ${others.map(label).join(', ')} (which set ${input} too)`\n : label(producer);\n const say = (why: string) =>\n add({\n code: 'ref-may-be-undefined',\n severity: 'warning',\n message: `${label(reader)} inputs.${input}: \"${from}\" ${why}: those hosts arrive without the value`,\n path,\n node: reader.id,\n subject: input,\n });\n // AFD-187: a decision that tests the value is defined keeps hosts without it off its true side.\n const guards = definedGuards(level.nodes, [input, ...(output ? [output] : [])]);\n // Past a step that sets the value, a host has it; one that fails in it has what it had before.\n const notRun = new Set(guards);\n const notSet = new Set(guards);\n for (const e of level.edges) {\n if (!e?.from || !covers.has(e.from.node)) continue;\n const key = `${e.from.node}|${e.from.port}`;\n notRun.add(key);\n if (!isFailPort(e.from.port)) notSet.add(key);\n }\n if (entries.length > 0 && reachable(level.edges, entries, undefined, notRun).has(target)) {\n say(`is set by ${by}, which some paths to here do not run`);\n return;\n }\n const failed = level.edges\n .filter((e) => e?.from && covers.has(e.from.node) && isFailPort(e.from.port))\n .map((e) => e.to.node);\n const starts = entries.length > 0 ? entries : failed;\n if (failed.length > 0 && reachable(level.edges, starts, undefined, notSet).has(target))\n say(`is set by ${by}, and hosts that fail in it still get here`);\n}\n\n/**\n * AFD-212: another step sets the input's own name where it wins over the `from:` (see setsName):\n * after the `from:` step when that step sets the name too, else anywhere before the reader.\n */\nfunction checkShadowed(\n model: FlowModel,\n reader: FlowNode,\n producer: FlowNode,\n from: string,\n path: Path,\n input: string,\n add: (f: Finding) => void,\n): void {\n const setters = nameSetters(model, input);\n if (setters.may.size === 0) return;\n const place = producerPlace(model, reader, producer);\n if (!place) return;\n const { level, target, entries } = place;\n const producerSets = setters.may.has(producer.id);\n const before = producerSets\n ? reachable(level.edges, okTargets(level, producer.id))\n : reachable(level.edges, entries);\n const later = level.nodes.filter(\n (n): n is FlowNode =>\n !!n &&\n n.id !== producer.id &&\n n.id !== target &&\n setters.may.has(n.id) &&\n before.has(n.id) &&\n reachable(level.edges, okTargets(level, n.id)).has(target),\n );\n if (later.length === 0) return;\n const names = later.map(label).join(', ');\n add({\n code: 'input-shadowed',\n severity: 'warning',\n message: `${label(reader)} inputs.${input}: \"${from}\" is not what the step reads after ${names}: ${later.length > 1 ? 'they set' : 'it sets'} ${input} too, and a set_fact or register wins over the input, so the step reads the value set last`,\n path,\n node: reader.id,\n subject: input,\n });\n}\n\n/** D-09: you cannot roll back a device you cannot reach. */\nfunction checkUnreachableRollback(model: FlowModel, add: (f: Finding) => void): void {\n for (const { edge, path } of model.edges.values()) {\n if (edge?.from?.port !== 'unreachable') continue;\n const target = model.nodes.get(edge.to?.node)?.node;\n if (!isRollback(target)) continue;\n const source = model.nodes.get(edge.from.node)?.node;\n add({\n code: 'rollback-unreachable',\n severity: 'warning',\n message: `${label(source)} \u00B7 unreachable goes to ${label(target)}: unreachable hosts cannot be rolled back; notify or retry instead`,\n path,\n edge: edge.id,\n });\n }\n}\n\n/**\n * Decisions in either format (AFD-51): each names something that exists and says why. Ports also\n * get the AFD-15 checks (a fail port, one decision, not wired).\n */\nfunction checkDecisions(model: FlowModel, add: (f: Finding) => void): void {\n const seen = new Set<string>();\n (model.doc.decisions ?? []).forEach((d, i) => {\n const a = acceptedOf(d, i);\n if (!a) return;\n const path: Path = ['decisions', i];\n const entry = a.node ? model.nodes.get(a.node) : undefined;\n const what =\n a.area === 'port'\n ? 'Open-on-purpose decision'\n : a.area === 'drift'\n ? 'Ignored drift item'\n : a.area === 'lens'\n ? `Accepted finding ${a.what}`\n : `Accepted problem ${a.what}`;\n if (a.node && !entry) {\n add({\n code: 'stale-decision',\n severity: 'warning',\n message: `${what} refers to a node that does not exist: ${a.node}`,\n path,\n });\n return;\n }\n if (a.area === 'port') {\n if (!entry || !portsFor(entry.node).some((p) => p.name === a.what)) {\n add({\n code: 'stale-decision',\n severity: 'warning',\n message: `Decision refers to a port that does not exist: ${a.node} \u00B7 ${a.what}`,\n path,\n });\n return;\n }\n const id = `${a.node}|${a.what}`;\n if (seen.has(id))\n add({\n code: 'duplicate-decision',\n severity: 'warning',\n message: `${label(entry.node)} \u00B7 ${a.what} has more than one decision`,\n path,\n node: a.node,\n });\n seen.add(id);\n if (!isFailPort(a.what))\n add({\n code: 'decision-not-fail',\n severity: 'info',\n message: `${label(entry.node)} \u00B7 ${a.what} is not a fail port; open on purpose has no effect`,\n path,\n node: a.node,\n });\n const edges = model.levels.get(entry.level)?.edges ?? [];\n if (edges.some((e) => e?.from?.node === a.node && e.from.port === a.what))\n add({\n code: 'decision-on-connected',\n severity: 'info',\n message: `${label(entry.node)} \u00B7 ${a.what} is wired; its open-on-purpose decision has no effect`,\n path,\n node: a.node,\n });\n }\n if (!a.reason?.trim())\n add({\n code: 'decision-no-reason',\n severity: 'warning',\n message:\n a.area === 'port' && entry\n ? `Open-on-purpose decision for ${label(entry.node)} \u00B7 ${a.what} has no reason`\n : `${what}${entry ? ` for ${label(entry.node)}` : ''} has no reason`,\n path,\n ...(a.node ? { node: a.node } : {}),\n });\n });\n}\n\n/**\n * AFD-187: the true ports of decisions that test one of `names` is defined (`x is defined`, not\n * negated): hosts without the value take false there, so paths through true do not count.\n */\nfunction definedGuards(nodes: (FlowNode | undefined)[], names: string[]): Set<string> {\n const out = new Set<string>();\n for (const n of nodes) {\n if (n?.type !== 'decision' || typeof n.condition !== 'string') continue;\n for (const name of names)\n if (new RegExp(`\\\\b${name}\\\\s+is\\\\s+defined\\\\b`).test(n.condition)) out.add(`${n.id}|true`);\n }\n return out;\n}\n\n/** AFD-183: the facts a set_fact step sets, which its own parameters may read (accumulators). */\n/** AFD-185: variables the flow says are set outside it at run time (flow.external_vars). */\nfunction externalVars(model: FlowModel): Set<string> {\n const ext = model.doc.flow?.external_vars;\n return new Set(ext && typeof ext === 'object' ? Object.keys(ext) : []);\n}\n\n/**\n * AFD-176: generated plays run from generated/, so a parameter that reads playbook_dir finds\n * nothing the source kept next to its playbook. afd_repo_root is the repository root.\n */\nfunction checkPlaybookDir(node: FlowNode, path: Path, add: (f: Finding) => void): void {\n const impl = node.impl;\n if (!impl || impl.kind === 'playbook') return;\n if (!/\\bplaybook_dir\\b/.test(JSON.stringify([impl.params ?? null, impl.keywords ?? null])))\n return;\n add({\n code: 'binding-playbook-dir',\n severity: 'warning',\n message: `${label(node)} reads playbook_dir, which is the flow's generated/ folder when it runs: write repository paths from {{ afd_repo_root }}, the repository root the generated play sets`,\n path: [...path, 'impl'],\n node: node.id,\n });\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -192,6 +192,10 @@ var FINDING_CODES = {
192
192
  meaning: "Another step sets the input's own name (set_fact, register, an output of that name) where it runs after the from: step, or before the reader when the from: step does not set that name. The generated play passes the input as a play var, and Ansible ranks set_fact and register above play vars: the step reads the value set last, not the one from: names.",
193
193
  fix: "Rename the input (the binding then reads the new name), or read from: the step that sets the name last. If the value set last is what the step should get, accept it with that reason."
194
194
  },
195
+ "binding-file-missing": {
196
+ meaning: "A step reads a repository file (a template or copy source, a script, a vars file) that is not there. Generated plays read a relative path from the repository root.",
197
+ fix: "Write the path from the repository root (templates/motd.j2), or add the file there."
198
+ },
195
199
  "binding-playbook-dir": {
196
200
  meaning: "A binding reads playbook_dir. Generated plays run from the flow's generated/ folder, so paths next to the source playbook are not found there.",
197
201
  fix: "Write repository paths from {{ afd_repo_root }}, the repository root the generated play sets; a shared task file can use {{ afd_repo_root | default(playbook_dir) }} so it works from the source playbook too."
@@ -326,4 +330,4 @@ var FINDING_CODES = {
326
330
  export {
327
331
  FINDING_CODES
328
332
  };
329
- //# sourceMappingURL=chunk-76T45V37.js.map
333
+ //# sourceMappingURL=chunk-TBFB7A2Z.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/core/flow/findingCodes.ts"],
4
- "sourcesContent": ["// Every problem the designer reports, with what it means and how to fix it (AFD-19): shown by AI\n// tools next to each finding and listed in the skill's generated reference.\nexport interface FindingCode {\n meaning: string;\n fix: string;\n}\n\nexport const FINDING_CODES: Record<string, FindingCode> = {\n schema: {\n meaning: 'The file breaks the flow schema (a field of the wrong type or an unknown field).',\n fix: 'Correct the field named in the message; see the format reference.',\n },\n 'input-default-type': {\n meaning:\n 'A host_list or list flow input has a string default; the generated code joins it letter by letter.',\n fix: 'Write the default as a list: default: [edge] (set_io on flow with field {type: host_list, default: [edge]}).',\n },\n 'keyword-reserved': {\n meaning:\n 'A task keyword in impl.keywords that the flow models itself (register, tags, become, timeout, retries, until, notify, block) or that is no task keyword.',\n fix: 'Move it where the message says (impl.register, settings, a handler step, a subflow), or remove it.',\n },\n 'keyword-ignored': {\n meaning:\n 'Task keywords that cannot apply: on a playbook binding, or vars on a role binding (role variables belong in params).',\n fix: 'Remove them, or bind a module or role; move role variables to params.',\n },\n 'missing-id': {\n meaning:\n 'Written by hand: a node, wire or the flow has no ID, or a reference names a node by key.',\n fix: 'Run Complete IDs (designer banner or quick fix, or flow_complete_ids). Never invent IDs.',\n },\n 'unknown-key': {\n meaning: 'A reference names a key no node has (or several nodes have).',\n fix: 'Use an existing key; inside subflows keys are per level.',\n },\n 'duplicate-id': {\n meaning: 'Two items share an ID.',\n fix: 'Remove the id of the copy and run Complete IDs.',\n },\n 'duplicate-key': {\n meaning: 'Two nodes on one level share a key.',\n fix: 'Rename one (update_node key); from: references follow.',\n },\n 'edge-missing-node': {\n meaning: 'A wire names a node that does not exist.',\n fix: 'Delete the wire or point it at an existing node.',\n },\n 'edge-cross-level': {\n meaning: 'A wire joins nodes on different levels.',\n fix: 'Wires stay on one level; use the subflow entry (set_entry) or an exit (add_exit).',\n },\n 'edge-bad-port': {\n meaning: 'A wire uses a port the node type does not have.',\n fix: 'Use one of the ports of that type (port catalog).',\n },\n 'edge-direction': {\n meaning: 'A wire starts at an input or ends at an output.',\n fix: 'Wires go from an output port to an input port (usually in).',\n },\n 'edge-port-not-enabled': {\n meaning: 'A wire uses an optional port the node has not enabled.',\n fix: 'enable_port for that node and port.',\n },\n 'port-multiple-edges': {\n meaning: 'An output port has more than one wire.',\n fix: 'One wire per output: fan out with a parallel node.',\n },\n 'port-not-supported': {\n meaning: 'The port is enabled on a node type that does not support it.',\n fix: 'disable_port, or change the node type.',\n },\n 'port-role-unroutable': {\n meaning: 'A role binding gives no signal for this port (e.g. unchanged).',\n fix: 'Bind a module instead, or do not use the port.',\n },\n 'open-fail-port': {\n meaning:\n 'A fail port (failed_hosts, unreachable, timeout, rejected) is not wired: its hosts fail the run.',\n fix: 'Wire it to a handler (apply_pattern), or leave_open with a reason.',\n },\n 'decision-no-reason': {\n meaning: 'A port is left open on purpose without a reason.',\n fix: 'Give a reason (leave_open again with reason).',\n },\n 'decision-not-fail': {\n meaning: 'Only fail ports can be left open on purpose.',\n fix: 'reopen it; wire the port instead.',\n },\n 'decision-on-connected': {\n meaning: 'A port marked open on purpose is wired.',\n fix: 'reopen it (the wire decides).',\n },\n 'duplicate-decision': {\n meaning: 'The same port has two decisions.',\n fix: 'Keep one: reopen, then leave_open once.',\n },\n 'annotation-target-missing': {\n meaning:\n 'A note is on a node that is not on its level (or gone), a section or text is on a node, or the file is format 1.',\n fix: 'Detach the note (its menu, or remove `on`), or attach it again; for format 1, Upgrade Flow Format.',\n },\n 'stale-decision': {\n meaning:\n 'A decision refers to a node, port or item that is gone, or an accepted check that no warning matches any more.',\n fix: 'Remove the decision (reopen, or unaccept).',\n },\n 'layout-orphan': {\n meaning: 'A position for a node that does not exist.',\n fix: 'Harmless; tidy_up or a move rewrites positions.',\n },\n 'status-overclaim': {\n meaning: 'A status claims more than the node has (e.g. implemented without impl).',\n fix: 'Lower the status, or add what it needs (contract for specified, impl for implemented).',\n },\n 'setting-on-flow': {\n meaning:\n 'Format 2: credential or execution_environment on a node; the AWX template has one set, on the flow.',\n fix: 'Set them on the flow (runtime.credentials, runtime.execution_environment), or let Set Up AWX Template ask.',\n },\n 'bad-name': {\n meaning:\n 'An input, output or register name Ansible cannot use as a variable: not a letter or _ then letters, digits and _, or a Python or Jinja keyword (in, not, true, none, class).',\n fix: 'Rename it, e.g. retry_count for retry-count; the readers of an output follow a rename made in the designer.',\n },\n 'keyword-is-setting': {\n meaning: 'Format 2: a task keyword the flow now models as a setting (become_user).',\n fix: 'Set it in Execution \u203A Privilege instead; on a subflow it applies to the steps inside.',\n },\n 'renamed-field': {\n meaning:\n 'Format 2: a node keeps a format 1 field name (handler, now purpose: it is not an Ansible handler).',\n fix: 'Rename the key to purpose, or pick the purpose again in Details \u203A General.',\n },\n 'status-out-of-step': {\n meaning:\n 'Format 2: the stored status is not the one the node\u2019s content gives (a hand edit of the file).',\n fix: 'Any edit of the node in the designer sets it again; or write the status the message names.',\n },\n 'tested-without-record': {\n meaning: 'Format 2: a node is tested but has no `tested` record (a run, or a reason).',\n fix: 'Mark Tested\u2026 with a reason, or run the flow; else set the status it has.',\n },\n 'import-gone': {\n meaning:\n 'Re-import from Source found that the task this step was imported from is no longer in the source; the step stays.',\n fix: \"Delete the step, or keep it: remove its origin to make it this flow's own.\",\n },\n 'shared-edited': {\n meaning:\n \"A shared subflow (a copy of another flow's subflow) was changed here, so it no longer matches the version it was copied from; or it sits in a format 1 flow.\",\n fix: \"Edit the source flow and Update, or Unlink to make the copy this flow's own.\",\n },\n 'shared-source': {\n meaning:\n \"A shared subflow's source is missing (the file or the subflow key), is not a .flow.yaml inside the workspace folder, or has a newer version than the copy.\",\n fix: 'Update Shared Subflow for a newer version; fix ref.from or Unlink when the source is gone.',\n },\n 'rolling-unsupported': {\n meaning:\n 'A rolling subflow has a step that needs plays of its own (a subflow, approval, parallel, join, playbook binding, inventory_target, or its own serial or max_fail_percentage), or rolling is set on a node that is not a subflow.',\n fix: 'Move that step out of the subflow, or remove rolling: without it the steps run play by play.',\n },\n 'legacy-port': {\n meaning:\n 'A node has the undo or cancelled port, which were never built: Rollback wires explicit undo steps, and a cancelled job routes no host.',\n fix: 'Upgrade Flow Format removes them and their wires (format 2: remove them); apply Rollback for undo steps.',\n },\n 'timeout-unreadable': {\n meaning:\n 'settings.timeout is not a duration the generated code can read, so the step runs without a timeout. A template ({{ \u2026 }}) is read at run time on a step, but not on an approval, whose AWX template needs a number.',\n fix: 'Write it as 30s, 15m or 1h30m (update_node settings.timeout); on a step, a template of whole seconds reading an input works too.',\n },\n 'timeout-without-setting': {\n meaning: 'The timeout port is enabled but settings.timeout is not set.',\n fix: 'Set settings.timeout (update_node settings).',\n },\n 'inventory-target-ignored': {\n meaning: 'inventory_target is set where it has no effect.',\n fix: 'Remove it, or move it to a task or a subflow without inner steps.',\n },\n 'host-list-input': {\n meaning: 'A node-level host_list input is informational: hosts come from the wire.',\n fix: 'Usually nothing; the arriving hosts decide.',\n },\n 'no-targets': {\n meaning: 'No flow input seeds the hosts entering the start node.',\n fix: 'Add a host_list flow input with targets: true (set_io flow).',\n },\n 'reads-disabled': {\n meaning:\n 'A from: reads an output of a disabled node (or of a step inside a disabled subflow), which runs nothing and so makes nothing.',\n fix: 'Give the input a default, read the value from another step, or enable the node (update_node with disabled: null).',\n },\n 'disabled-ends-path': {\n meaning:\n 'A disabled node the hosts cannot pass through: it does not go on to one next step (no main output is wired, or a decision or parallel has several), so the hosts that reach it stop there.',\n fix: 'Wire exactly one of its main outputs, or enable the node; to take a branching step out, delete it and wire the path by hand.',\n },\n 'disabled-not-allowed': {\n meaning: 'disabled: true on a start or an end node, which are the ends of the path.',\n fix: 'Remove disabled from the node.',\n },\n 'from-unresolved': {\n meaning: 'A from: names nothing this node can read.',\n fix: 'Use <node_key>.<output> of a node that runs before, flow.<input>, or inside a subflow <subflow_key>.<input>; give a path (sub/step.output) to set_io to lift a step inside another subflow.',\n },\n 'register-collision': {\n meaning:\n 'A from: reads a register (impl.register) that another step also registers, or that a flow input also names: the generated code reads whichever ran last, and a flow input always wins.',\n fix: 'Give one of the steps its own register name (Binding \u203A Register result as), or rename the flow input.',\n },\n 'ref-may-be-undefined': {\n meaning:\n \"A from: reads an output of a step that does not run before this one on every path, or that hosts reach after failing in it: some hosts arrive without the value. A step that sets the input's own name (set_fact, register, an output of that name) counts too: the generated play passes the input as a play var, and that fact wins over it.\",\n fix: 'Read it after the paths join on the producing step, or wire the failure path elsewhere. If the step handles a missing value itself (x is defined, | default), guard the read that way or mark the input optional: true; a default makes the value defined, so an \"is defined\" test would always pass.',\n },\n 'input-shadowed': {\n meaning:\n \"Another step sets the input's own name (set_fact, register, an output of that name) where it runs after the from: step, or before the reader when the from: step does not set that name. The generated play passes the input as a play var, and Ansible ranks set_fact and register above play vars: the step reads the value set last, not the one from: names.\",\n fix: 'Rename the input (the binding then reads the new name), or read from: the step that sets the name last. If the value set last is what the step should get, accept it with that reason.',\n },\n 'binding-playbook-dir': {\n meaning:\n \"A binding reads playbook_dir. Generated plays run from the flow's generated/ folder, so paths next to the source playbook are not found there.\",\n fix: 'Write repository paths from {{ afd_repo_root }}, the repository root the generated play sets; a shared task file can use {{ afd_repo_root | default(playbook_dir) }} so it works from the source playbook too.',\n },\n 'binding-unknown-var': {\n meaning: 'A binding parameter (assert that included) uses a variable no input provides.',\n fix: 'Add the input the message names (set_io) or fix the name. A variable set outside the flow at run time (AWX or Kestra extra vars, inventory, a caller) goes into flow.external_vars (update_flow).',\n },\n 'condition-braces': {\n meaning:\n 'A decision condition has {{ }} or {% %} inside it; it is a bare expression, as a when: is, so every host would hit a condition error.',\n fix: 'Write the expression without the braces: x == 1, not {{ x }} == 1.',\n },\n 'condition-unknown-var': {\n meaning:\n 'A decision condition or until uses a variable that is not an input (or, for until, the result).',\n fix: 'Add the input the message names (set_io) or fix the name.',\n },\n 'subflow-output-unset': {\n meaning:\n 'A subflow output names no inner output, and no single inner step has one of that name.',\n fix: 'Set its from to <inner_step>.<output> (set_io).',\n },\n 'input-unfed': {\n meaning:\n 'A step input has no from and no default, so nothing gives it a value; the generated task reads a host variable of that name, if any.',\n fix: 'Set its from to an upstream output or a flow input (set_io), or give it a default; for the result of a step, make it an output there first.',\n },\n 'setting-unknown-var': {\n meaning:\n 'settings.retries, delay or timeout is given at run time ({{ \u2026 }}) and reads a variable that is not an input of the step.',\n fix: 'Add the input the message names (set_io, from: flow.<name>), or use ask_at_run_time, which adds the flow input and the node input.',\n },\n 'setting-input-type': {\n meaning:\n 'settings.retries, delay or timeout reads an input of a type that holds no number (boolean, list, dict, host_list), so the task fails when Ansible renders it.',\n fix: 'Read an integer input (set_io type integer), or write a number.',\n },\n 'until-whole-result': {\n meaning:\n 'settings.until compares the whole registered result with a value (r == \"x\", \"x\" in r); the result is a dict, so the test never holds.',\n fix: 'Test a field of the result, like <register>.stdout or <register>.rc (update_node settings.until).',\n },\n 'until-not-module': {\n meaning: 'settings.until on a role or playbook step, where Ansible cannot retry.',\n fix: 'Move the polling into a module step, or remove until.',\n },\n 'approval-split': {\n meaning: 'Approval outcomes go to different places in a way AWX cannot express.',\n fix: 'Route rejected and timeout the same way.',\n },\n 'approval-fields': {\n meaning:\n 'A node that is not an approval has approval fields (approvers, notify, message): nothing reads them.',\n fix: 'Remove them, or make the node an approval.',\n },\n 'awx-segments': {\n meaning:\n 'Approvals inside subflows, or two that can wait at once, cannot become segments: AWX workflows and Ansible Flow Server wait at top-level approvals, one at a time.',\n fix: 'Keep approvals on the top level, one at a time.',\n },\n 'runtime-kind': {\n meaning:\n 'flow.runtime.kind does not fit the flow (e.g. a job for a flow with approvals); in format 2, it is derived and not written.',\n fix: 'Use awx_workflow with approvals, awx_job without; in format 2, remove it.',\n },\n 'rollback-unreachable': {\n meaning: 'A Rollback node cannot be reached by any failed hosts.',\n fix: 'Wire a fail port to it, or delete it.',\n },\n 'boundary-ref': {\n meaning: 'The subflow entry or an exit names something that is not on its inner level.',\n fix: 'set_entry / add_exit with an inner node of that subflow.',\n },\n 'boundary-no-entry': {\n meaning: 'A subflow has inner steps but no entry: hosts cannot get in.',\n fix: 'set_entry to its first step.',\n },\n 'boundary-port-unfed': {\n meaning: 'A subflow port has wires outside but no inner exit feeds it.',\n fix: 'add_exit from an inner output to that port.',\n },\n 'inner-exit-unmapped': {\n meaning:\n 'A success port of a step inside a subflow is neither wired nor an exit of the subflow: its hosts never reach an outer port.',\n fix: 'Wire it to the next inner step, or add_exit from it to a port of the subflow.',\n },\n 'success-port-unwired': {\n meaning:\n 'A success port on the top level is not wired: its hosts stop there without reaching an end node.',\n fix: 'Wire it to the next step or to an end node (Done).',\n },\n 'codegen-cycle': {\n meaning: 'Wires form a cycle; flows run top-down.',\n fix: 'Remove a wire; retries use apply_pattern retry.',\n },\n 'codegen-no-input': {\n meaning: 'A node gets no hosts: nothing wires into it.',\n fix: 'Wire an output into its in port, or delete it.',\n },\n 'codegen-no-targets': {\n meaning: 'The generated playbook has no hosts to start with.',\n fix: 'Add a host_list flow input with targets: true.',\n },\n 'codegen-playbook-ports': {\n meaning: 'A playbook binding cannot route this port.',\n fix: 'Use ok_hosts/failed_hosts, or bind a role or module.',\n },\n 'codegen-segments': {\n meaning: 'Approval segments cannot be generated for this flow.',\n fix: 'See awx-segments.',\n },\n 'codegen-target-ports': {\n meaning:\n 'A node with inventory_target uses a port that cannot be routed for the arriving hosts.',\n fix: 'Use ok_hosts, failed_hosts or timeout.',\n },\n 'binding-not-in-ee': {\n meaning: 'The bound module or role is not in the execution environment.',\n fix: 'Pick another, or add its collection to the environment.',\n },\n 'binding-removed': { meaning: 'The bound module was removed.', fix: 'Bind its replacement.' },\n 'binding-deprecated': {\n meaning: 'The bound module is deprecated.',\n fix: 'Bind its replacement.',\n },\n 'binding-redirect': {\n meaning: 'The bound name redirects to another module.',\n fix: 'Use the final name.',\n },\n 'binding-unknown-param': {\n meaning: 'A parameter the module does not have.',\n fix: 'Remove or rename it (module docs in the catalog).',\n },\n 'binding-missing-param': {\n meaning: 'A required module parameter is missing.',\n fix: 'Add it to impl.params.',\n },\n 'binding-no-check-mode': {\n meaning: 'The module does not support check mode: skeleton runs skip it.',\n fix: 'Usually fine; real runs only.',\n },\n};\n"],
5
- "mappings": ";AAOO,IAAM,gBAA6C;AAAA,EACxD,QAAQ;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,sBAAsB;AAAA,IACpB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,oBAAoB;AAAA,IAClB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,mBAAmB;AAAA,IACjB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,cAAc;AAAA,IACZ,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,eAAe;AAAA,IACb,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,gBAAgB;AAAA,IACd,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,iBAAiB;AAAA,IACf,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,iBAAiB;AAAA,IACf,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB;AAAA,IAChB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,uBAAuB;AAAA,IACrB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB;AAAA,IAChB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,6BAA6B;AAAA,IAC3B,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB;AAAA,IAChB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,iBAAiB;AAAA,IACf,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,mBAAmB;AAAA,IACjB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,YAAY;AAAA,IACV,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,iBAAiB;AAAA,IACf,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,sBAAsB;AAAA,IACpB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,eAAe;AAAA,IACb,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,iBAAiB;AAAA,IACf,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,iBAAiB;AAAA,IACf,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,uBAAuB;AAAA,IACrB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,eAAe;AAAA,IACb,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,sBAAsB;AAAA,IACpB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,mBAAmB;AAAA,IACjB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,cAAc;AAAA,IACZ,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB;AAAA,IAChB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,sBAAsB;AAAA,IACpB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,mBAAmB;AAAA,IACjB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,sBAAsB;AAAA,IACpB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,wBAAwB;AAAA,IACtB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB;AAAA,IAChB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,wBAAwB;AAAA,IACtB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,uBAAuB;AAAA,IACrB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,oBAAoB;AAAA,IAClB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,yBAAyB;AAAA,IACvB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,wBAAwB;AAAA,IACtB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,eAAe;AAAA,IACb,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,uBAAuB;AAAA,IACrB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,sBAAsB;AAAA,IACpB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,sBAAsB;AAAA,IACpB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB;AAAA,IAChB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,mBAAmB;AAAA,IACjB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,gBAAgB;AAAA,IACd,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,gBAAgB;AAAA,IACd,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,gBAAgB;AAAA,IACd,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,uBAAuB;AAAA,IACrB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,uBAAuB;AAAA,IACrB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,wBAAwB;AAAA,IACtB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,iBAAiB;AAAA,IACf,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,wBAAwB;AAAA,IACtB,SACE;AAAA,IACF,KAAK;AAAA,EACP;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,mBAAmB,EAAE,SAAS,iCAAiC,KAAK,wBAAwB;AAAA,EAC5F,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AACF;",
4
+ "sourcesContent": ["// Every problem the designer reports, with what it means and how to fix it (AFD-19): shown by AI\n// tools next to each finding and listed in the skill's generated reference.\nexport interface FindingCode {\n meaning: string;\n fix: string;\n}\n\nexport const FINDING_CODES: Record<string, FindingCode> = {\n schema: {\n meaning: 'The file breaks the flow schema (a field of the wrong type or an unknown field).',\n fix: 'Correct the field named in the message; see the format reference.',\n },\n 'input-default-type': {\n meaning:\n 'A host_list or list flow input has a string default; the generated code joins it letter by letter.',\n fix: 'Write the default as a list: default: [edge] (set_io on flow with field {type: host_list, default: [edge]}).',\n },\n 'keyword-reserved': {\n meaning:\n 'A task keyword in impl.keywords that the flow models itself (register, tags, become, timeout, retries, until, notify, block) or that is no task keyword.',\n fix: 'Move it where the message says (impl.register, settings, a handler step, a subflow), or remove it.',\n },\n 'keyword-ignored': {\n meaning:\n 'Task keywords that cannot apply: on a playbook binding, or vars on a role binding (role variables belong in params).',\n fix: 'Remove them, or bind a module or role; move role variables to params.',\n },\n 'missing-id': {\n meaning:\n 'Written by hand: a node, wire or the flow has no ID, or a reference names a node by key.',\n fix: 'Run Complete IDs (designer banner or quick fix, or flow_complete_ids). Never invent IDs.',\n },\n 'unknown-key': {\n meaning: 'A reference names a key no node has (or several nodes have).',\n fix: 'Use an existing key; inside subflows keys are per level.',\n },\n 'duplicate-id': {\n meaning: 'Two items share an ID.',\n fix: 'Remove the id of the copy and run Complete IDs.',\n },\n 'duplicate-key': {\n meaning: 'Two nodes on one level share a key.',\n fix: 'Rename one (update_node key); from: references follow.',\n },\n 'edge-missing-node': {\n meaning: 'A wire names a node that does not exist.',\n fix: 'Delete the wire or point it at an existing node.',\n },\n 'edge-cross-level': {\n meaning: 'A wire joins nodes on different levels.',\n fix: 'Wires stay on one level; use the subflow entry (set_entry) or an exit (add_exit).',\n },\n 'edge-bad-port': {\n meaning: 'A wire uses a port the node type does not have.',\n fix: 'Use one of the ports of that type (port catalog).',\n },\n 'edge-direction': {\n meaning: 'A wire starts at an input or ends at an output.',\n fix: 'Wires go from an output port to an input port (usually in).',\n },\n 'edge-port-not-enabled': {\n meaning: 'A wire uses an optional port the node has not enabled.',\n fix: 'enable_port for that node and port.',\n },\n 'port-multiple-edges': {\n meaning: 'An output port has more than one wire.',\n fix: 'One wire per output: fan out with a parallel node.',\n },\n 'port-not-supported': {\n meaning: 'The port is enabled on a node type that does not support it.',\n fix: 'disable_port, or change the node type.',\n },\n 'port-role-unroutable': {\n meaning: 'A role binding gives no signal for this port (e.g. unchanged).',\n fix: 'Bind a module instead, or do not use the port.',\n },\n 'open-fail-port': {\n meaning:\n 'A fail port (failed_hosts, unreachable, timeout, rejected) is not wired: its hosts fail the run.',\n fix: 'Wire it to a handler (apply_pattern), or leave_open with a reason.',\n },\n 'decision-no-reason': {\n meaning: 'A port is left open on purpose without a reason.',\n fix: 'Give a reason (leave_open again with reason).',\n },\n 'decision-not-fail': {\n meaning: 'Only fail ports can be left open on purpose.',\n fix: 'reopen it; wire the port instead.',\n },\n 'decision-on-connected': {\n meaning: 'A port marked open on purpose is wired.',\n fix: 'reopen it (the wire decides).',\n },\n 'duplicate-decision': {\n meaning: 'The same port has two decisions.',\n fix: 'Keep one: reopen, then leave_open once.',\n },\n 'annotation-target-missing': {\n meaning:\n 'A note is on a node that is not on its level (or gone), a section or text is on a node, or the file is format 1.',\n fix: 'Detach the note (its menu, or remove `on`), or attach it again; for format 1, Upgrade Flow Format.',\n },\n 'stale-decision': {\n meaning:\n 'A decision refers to a node, port or item that is gone, or an accepted check that no warning matches any more.',\n fix: 'Remove the decision (reopen, or unaccept).',\n },\n 'layout-orphan': {\n meaning: 'A position for a node that does not exist.',\n fix: 'Harmless; tidy_up or a move rewrites positions.',\n },\n 'status-overclaim': {\n meaning: 'A status claims more than the node has (e.g. implemented without impl).',\n fix: 'Lower the status, or add what it needs (contract for specified, impl for implemented).',\n },\n 'setting-on-flow': {\n meaning:\n 'Format 2: credential or execution_environment on a node; the AWX template has one set, on the flow.',\n fix: 'Set them on the flow (runtime.credentials, runtime.execution_environment), or let Set Up AWX Template ask.',\n },\n 'bad-name': {\n meaning:\n 'An input, output or register name Ansible cannot use as a variable: not a letter or _ then letters, digits and _, or a Python or Jinja keyword (in, not, true, none, class).',\n fix: 'Rename it, e.g. retry_count for retry-count; the readers of an output follow a rename made in the designer.',\n },\n 'keyword-is-setting': {\n meaning: 'Format 2: a task keyword the flow now models as a setting (become_user).',\n fix: 'Set it in Execution \u203A Privilege instead; on a subflow it applies to the steps inside.',\n },\n 'renamed-field': {\n meaning:\n 'Format 2: a node keeps a format 1 field name (handler, now purpose: it is not an Ansible handler).',\n fix: 'Rename the key to purpose, or pick the purpose again in Details \u203A General.',\n },\n 'status-out-of-step': {\n meaning:\n 'Format 2: the stored status is not the one the node\u2019s content gives (a hand edit of the file).',\n fix: 'Any edit of the node in the designer sets it again; or write the status the message names.',\n },\n 'tested-without-record': {\n meaning: 'Format 2: a node is tested but has no `tested` record (a run, or a reason).',\n fix: 'Mark Tested\u2026 with a reason, or run the flow; else set the status it has.',\n },\n 'import-gone': {\n meaning:\n 'Re-import from Source found that the task this step was imported from is no longer in the source; the step stays.',\n fix: \"Delete the step, or keep it: remove its origin to make it this flow's own.\",\n },\n 'shared-edited': {\n meaning:\n \"A shared subflow (a copy of another flow's subflow) was changed here, so it no longer matches the version it was copied from; or it sits in a format 1 flow.\",\n fix: \"Edit the source flow and Update, or Unlink to make the copy this flow's own.\",\n },\n 'shared-source': {\n meaning:\n \"A shared subflow's source is missing (the file or the subflow key), is not a .flow.yaml inside the workspace folder, or has a newer version than the copy.\",\n fix: 'Update Shared Subflow for a newer version; fix ref.from or Unlink when the source is gone.',\n },\n 'rolling-unsupported': {\n meaning:\n 'A rolling subflow has a step that needs plays of its own (a subflow, approval, parallel, join, playbook binding, inventory_target, or its own serial or max_fail_percentage), or rolling is set on a node that is not a subflow.',\n fix: 'Move that step out of the subflow, or remove rolling: without it the steps run play by play.',\n },\n 'legacy-port': {\n meaning:\n 'A node has the undo or cancelled port, which were never built: Rollback wires explicit undo steps, and a cancelled job routes no host.',\n fix: 'Upgrade Flow Format removes them and their wires (format 2: remove them); apply Rollback for undo steps.',\n },\n 'timeout-unreadable': {\n meaning:\n 'settings.timeout is not a duration the generated code can read, so the step runs without a timeout. A template ({{ \u2026 }}) is read at run time on a step, but not on an approval, whose AWX template needs a number.',\n fix: 'Write it as 30s, 15m or 1h30m (update_node settings.timeout); on a step, a template of whole seconds reading an input works too.',\n },\n 'timeout-without-setting': {\n meaning: 'The timeout port is enabled but settings.timeout is not set.',\n fix: 'Set settings.timeout (update_node settings).',\n },\n 'inventory-target-ignored': {\n meaning: 'inventory_target is set where it has no effect.',\n fix: 'Remove it, or move it to a task or a subflow without inner steps.',\n },\n 'host-list-input': {\n meaning: 'A node-level host_list input is informational: hosts come from the wire.',\n fix: 'Usually nothing; the arriving hosts decide.',\n },\n 'no-targets': {\n meaning: 'No flow input seeds the hosts entering the start node.',\n fix: 'Add a host_list flow input with targets: true (set_io flow).',\n },\n 'reads-disabled': {\n meaning:\n 'A from: reads an output of a disabled node (or of a step inside a disabled subflow), which runs nothing and so makes nothing.',\n fix: 'Give the input a default, read the value from another step, or enable the node (update_node with disabled: null).',\n },\n 'disabled-ends-path': {\n meaning:\n 'A disabled node the hosts cannot pass through: it does not go on to one next step (no main output is wired, or a decision or parallel has several), so the hosts that reach it stop there.',\n fix: 'Wire exactly one of its main outputs, or enable the node; to take a branching step out, delete it and wire the path by hand.',\n },\n 'disabled-not-allowed': {\n meaning: 'disabled: true on a start or an end node, which are the ends of the path.',\n fix: 'Remove disabled from the node.',\n },\n 'from-unresolved': {\n meaning: 'A from: names nothing this node can read.',\n fix: 'Use <node_key>.<output> of a node that runs before, flow.<input>, or inside a subflow <subflow_key>.<input>; give a path (sub/step.output) to set_io to lift a step inside another subflow.',\n },\n 'register-collision': {\n meaning:\n 'A from: reads a register (impl.register) that another step also registers, or that a flow input also names: the generated code reads whichever ran last, and a flow input always wins.',\n fix: 'Give one of the steps its own register name (Binding \u203A Register result as), or rename the flow input.',\n },\n 'ref-may-be-undefined': {\n meaning:\n \"A from: reads an output of a step that does not run before this one on every path, or that hosts reach after failing in it: some hosts arrive without the value. A step that sets the input's own name (set_fact, register, an output of that name) counts too: the generated play passes the input as a play var, and that fact wins over it.\",\n fix: 'Read it after the paths join on the producing step, or wire the failure path elsewhere. If the step handles a missing value itself (x is defined, | default), guard the read that way or mark the input optional: true; a default makes the value defined, so an \"is defined\" test would always pass.',\n },\n 'input-shadowed': {\n meaning:\n \"Another step sets the input's own name (set_fact, register, an output of that name) where it runs after the from: step, or before the reader when the from: step does not set that name. The generated play passes the input as a play var, and Ansible ranks set_fact and register above play vars: the step reads the value set last, not the one from: names.\",\n fix: 'Rename the input (the binding then reads the new name), or read from: the step that sets the name last. If the value set last is what the step should get, accept it with that reason.',\n },\n 'binding-file-missing': {\n meaning:\n 'A step reads a repository file (a template or copy source, a script, a vars file) that is not there. Generated plays read a relative path from the repository root.',\n fix: 'Write the path from the repository root (templates/motd.j2), or add the file there.',\n },\n 'binding-playbook-dir': {\n meaning:\n \"A binding reads playbook_dir. Generated plays run from the flow's generated/ folder, so paths next to the source playbook are not found there.\",\n fix: 'Write repository paths from {{ afd_repo_root }}, the repository root the generated play sets; a shared task file can use {{ afd_repo_root | default(playbook_dir) }} so it works from the source playbook too.',\n },\n 'binding-unknown-var': {\n meaning: 'A binding parameter (assert that included) uses a variable no input provides.',\n fix: 'Add the input the message names (set_io) or fix the name. A variable set outside the flow at run time (AWX or Kestra extra vars, inventory, a caller) goes into flow.external_vars (update_flow).',\n },\n 'condition-braces': {\n meaning:\n 'A decision condition has {{ }} or {% %} inside it; it is a bare expression, as a when: is, so every host would hit a condition error.',\n fix: 'Write the expression without the braces: x == 1, not {{ x }} == 1.',\n },\n 'condition-unknown-var': {\n meaning:\n 'A decision condition or until uses a variable that is not an input (or, for until, the result).',\n fix: 'Add the input the message names (set_io) or fix the name.',\n },\n 'subflow-output-unset': {\n meaning:\n 'A subflow output names no inner output, and no single inner step has one of that name.',\n fix: 'Set its from to <inner_step>.<output> (set_io).',\n },\n 'input-unfed': {\n meaning:\n 'A step input has no from and no default, so nothing gives it a value; the generated task reads a host variable of that name, if any.',\n fix: 'Set its from to an upstream output or a flow input (set_io), or give it a default; for the result of a step, make it an output there first.',\n },\n 'setting-unknown-var': {\n meaning:\n 'settings.retries, delay or timeout is given at run time ({{ \u2026 }}) and reads a variable that is not an input of the step.',\n fix: 'Add the input the message names (set_io, from: flow.<name>), or use ask_at_run_time, which adds the flow input and the node input.',\n },\n 'setting-input-type': {\n meaning:\n 'settings.retries, delay or timeout reads an input of a type that holds no number (boolean, list, dict, host_list), so the task fails when Ansible renders it.',\n fix: 'Read an integer input (set_io type integer), or write a number.',\n },\n 'until-whole-result': {\n meaning:\n 'settings.until compares the whole registered result with a value (r == \"x\", \"x\" in r); the result is a dict, so the test never holds.',\n fix: 'Test a field of the result, like <register>.stdout or <register>.rc (update_node settings.until).',\n },\n 'until-not-module': {\n meaning: 'settings.until on a role or playbook step, where Ansible cannot retry.',\n fix: 'Move the polling into a module step, or remove until.',\n },\n 'approval-split': {\n meaning: 'Approval outcomes go to different places in a way AWX cannot express.',\n fix: 'Route rejected and timeout the same way.',\n },\n 'approval-fields': {\n meaning:\n 'A node that is not an approval has approval fields (approvers, notify, message): nothing reads them.',\n fix: 'Remove them, or make the node an approval.',\n },\n 'awx-segments': {\n meaning:\n 'Approvals inside subflows, or two that can wait at once, cannot become segments: AWX workflows and Ansible Flow Server wait at top-level approvals, one at a time.',\n fix: 'Keep approvals on the top level, one at a time.',\n },\n 'runtime-kind': {\n meaning:\n 'flow.runtime.kind does not fit the flow (e.g. a job for a flow with approvals); in format 2, it is derived and not written.',\n fix: 'Use awx_workflow with approvals, awx_job without; in format 2, remove it.',\n },\n 'rollback-unreachable': {\n meaning: 'A Rollback node cannot be reached by any failed hosts.',\n fix: 'Wire a fail port to it, or delete it.',\n },\n 'boundary-ref': {\n meaning: 'The subflow entry or an exit names something that is not on its inner level.',\n fix: 'set_entry / add_exit with an inner node of that subflow.',\n },\n 'boundary-no-entry': {\n meaning: 'A subflow has inner steps but no entry: hosts cannot get in.',\n fix: 'set_entry to its first step.',\n },\n 'boundary-port-unfed': {\n meaning: 'A subflow port has wires outside but no inner exit feeds it.',\n fix: 'add_exit from an inner output to that port.',\n },\n 'inner-exit-unmapped': {\n meaning:\n 'A success port of a step inside a subflow is neither wired nor an exit of the subflow: its hosts never reach an outer port.',\n fix: 'Wire it to the next inner step, or add_exit from it to a port of the subflow.',\n },\n 'success-port-unwired': {\n meaning:\n 'A success port on the top level is not wired: its hosts stop there without reaching an end node.',\n fix: 'Wire it to the next step or to an end node (Done).',\n },\n 'codegen-cycle': {\n meaning: 'Wires form a cycle; flows run top-down.',\n fix: 'Remove a wire; retries use apply_pattern retry.',\n },\n 'codegen-no-input': {\n meaning: 'A node gets no hosts: nothing wires into it.',\n fix: 'Wire an output into its in port, or delete it.',\n },\n 'codegen-no-targets': {\n meaning: 'The generated playbook has no hosts to start with.',\n fix: 'Add a host_list flow input with targets: true.',\n },\n 'codegen-playbook-ports': {\n meaning: 'A playbook binding cannot route this port.',\n fix: 'Use ok_hosts/failed_hosts, or bind a role or module.',\n },\n 'codegen-segments': {\n meaning: 'Approval segments cannot be generated for this flow.',\n fix: 'See awx-segments.',\n },\n 'codegen-target-ports': {\n meaning:\n 'A node with inventory_target uses a port that cannot be routed for the arriving hosts.',\n fix: 'Use ok_hosts, failed_hosts or timeout.',\n },\n 'binding-not-in-ee': {\n meaning: 'The bound module or role is not in the execution environment.',\n fix: 'Pick another, or add its collection to the environment.',\n },\n 'binding-removed': { meaning: 'The bound module was removed.', fix: 'Bind its replacement.' },\n 'binding-deprecated': {\n meaning: 'The bound module is deprecated.',\n fix: 'Bind its replacement.',\n },\n 'binding-redirect': {\n meaning: 'The bound name redirects to another module.',\n fix: 'Use the final name.',\n },\n 'binding-unknown-param': {\n meaning: 'A parameter the module does not have.',\n fix: 'Remove or rename it (module docs in the catalog).',\n },\n 'binding-missing-param': {\n meaning: 'A required module parameter is missing.',\n fix: 'Add it to impl.params.',\n },\n 'binding-no-check-mode': {\n meaning: 'The module does not support check mode: skeleton runs skip it.',\n fix: 'Usually fine; real runs only.',\n },\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-SD6TCN3P.js";
5
5
  import {
6
6
  scenesOf
7
- } from "./chunk-72LO6GQE.js";
7
+ } from "./chunk-KXD6FX2Z.js";
8
8
  import {
9
9
  INSET,
10
10
  inset,
@@ -12,7 +12,7 @@ import {
12
12
  overlaps,
13
13
  pointsOf,
14
14
  segmentHits
15
- } from "./chunk-4RMWFRWG.js";
15
+ } from "./chunk-LELKMVJG.js";
16
16
  import {
17
17
  openFailPorts
18
18
  } from "./chunk-KSM4O2XL.js";
@@ -164,4 +164,4 @@ export {
164
164
  LAYOUT_FIX,
165
165
  flowLayoutProblems
166
166
  };
167
- //# sourceMappingURL=chunk-BXJOUAXV.js.map
167
+ //# sourceMappingURL=chunk-TEJARYAE.js.map
@@ -29,6 +29,9 @@ import {
29
29
  import {
30
30
  migrate
31
31
  } from "./chunk-WISXIO3I.js";
32
+ import {
33
+ setFactNames
34
+ } from "./chunk-FIKPXL6E.js";
32
35
  import {
33
36
  CONTINUES_ON,
34
37
  healPlan,
@@ -2519,6 +2522,43 @@ function planCommand(text, cmd, ctx, parsed) {
2519
2522
  case "setContractField":
2520
2523
  setContractField(tx, cmd, notes);
2521
2524
  break;
2525
+ case "useFact": {
2526
+ const st = state(tx);
2527
+ const setter = nodeAt(st, cmd.setter).node;
2528
+ const reader = nodeAt(st, cmd.reader).node;
2529
+ if (!setFactNames(setter.impl).includes(cmd.name))
2530
+ throw new CommandError("no-fact", `${setter.title} does not set ${cmd.name}`);
2531
+ const from = `${setter.key}.${cmd.name}`;
2532
+ if (!setter.outputs?.[cmd.name])
2533
+ setContractField(
2534
+ tx,
2535
+ {
2536
+ kind: "setContractField",
2537
+ target: cmd.setter,
2538
+ side: "outputs",
2539
+ name: cmd.name,
2540
+ field: { type: "any" }
2541
+ },
2542
+ notes
2543
+ );
2544
+ const inputs = reader.inputs ?? {};
2545
+ if (!Object.values(inputs).some((f) => f?.from === from)) {
2546
+ let name = cmd.name;
2547
+ for (let i = 2; inputs[name] && inputs[name]?.from !== from; i++) name = `${cmd.name}_${i}`;
2548
+ setContractField(
2549
+ tx,
2550
+ {
2551
+ kind: "setContractField",
2552
+ target: cmd.reader,
2553
+ side: "inputs",
2554
+ name,
2555
+ field: { type: "any", from }
2556
+ },
2557
+ notes
2558
+ );
2559
+ }
2560
+ break;
2561
+ }
2522
2562
  case "setBinding":
2523
2563
  setBinding(tx, cmd, notes);
2524
2564
  break;
@@ -2691,4 +2731,4 @@ export {
2691
2731
  implementedAgain,
2692
2732
  planCommand
2693
2733
  };
2694
- //# sourceMappingURL=chunk-T5UB4MBB.js.map
2734
+ //# sourceMappingURL=chunk-TOTSB4HG.js.map