@runcofactor/cli 0.15.1 → 0.16.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 (123) hide show
  1. package/dist/{account-62I7FG5G.js → account-ZMV7NEFM.js} +4 -4
  2. package/dist/account-ZMV7NEFM.js.map +1 -0
  3. package/dist/{api-catalog-CAJUASVC.js → api-catalog-6HNOGVPA.js} +3 -3
  4. package/dist/{attachment-RL4AZUJE.js → attachment-QAHR54HQ.js} +3 -3
  5. package/dist/{augmentor-GAF3MFY6.js → augmentor-7T3L6ZR4.js} +3 -3
  6. package/dist/{chunk-26U3DGUM.js → chunk-7YJTQCPX.js} +3 -5
  7. package/dist/chunk-7YJTQCPX.js.map +1 -0
  8. package/dist/{chunk-PXFDH6YL.js → chunk-A4ISG3VX.js} +55 -15
  9. package/dist/{chunk-PXFDH6YL.js.map → chunk-A4ISG3VX.js.map} +1 -1
  10. package/dist/{chunk-5R4HMSNX.js → chunk-AI3Y3AZH.js} +24834 -24813
  11. package/dist/chunk-AI3Y3AZH.js.map +1 -0
  12. package/dist/{chunk-HKQ5XQAQ.js → chunk-CEXV3MOC.js} +3 -3
  13. package/dist/{chunk-VKBTI5EF.js → chunk-D6AVOPOS.js} +2 -2
  14. package/dist/{chunk-ZXRVFFCY.js → chunk-DT2CEH2V.js} +2 -2
  15. package/dist/{chunk-IWKJQZJQ.js → chunk-GZVCNYR4.js} +55 -55
  16. package/dist/chunk-GZVCNYR4.js.map +1 -0
  17. package/dist/{chunk-CJEKEW7R.js → chunk-LFFWD5JZ.js} +2 -2
  18. package/dist/{chunk-UZ2ZA5A6.js → chunk-RGDIVW3O.js} +2 -2
  19. package/dist/{chunk-CFJXYPTF.js → chunk-UAJUZLDE.js} +11 -3
  20. package/dist/chunk-UAJUZLDE.js.map +1 -0
  21. package/dist/{credential-JGVSEGVH.js → credential-X6QKX473.js} +3 -3
  22. package/dist/{credential-template-CWWMOKB2.js → credential-template-GD3D4MBI.js} +3 -3
  23. package/dist/{debug-workflow-BXRU72YZ.js → debug-workflow-AAEOAME2.js} +6 -6
  24. package/dist/{src-CV57ZD6I.js → dist-QLTVBUMD.js} +7 -9
  25. package/dist/{docs-PVBXPTGR.js → docs-BVUEXBY3.js} +3 -3
  26. package/dist/{environment-WZKIO3R3.js → environment-WE7VVE6I.js} +3 -3
  27. package/dist/{feature-flag-K5REGGDY.js → feature-flag-VJO2TJFT.js} +9 -8
  28. package/dist/feature-flag-VJO2TJFT.js.map +1 -0
  29. package/dist/index.js +129 -44
  30. package/dist/index.js.map +1 -1
  31. package/dist/{init-FFUZO5D7.js → init-RQHHKJJD.js} +8 -8
  32. package/dist/{install-XRKEQAFZ.js → install-CQLHNZ6U.js} +3 -3
  33. package/dist/{issues-I3V6GEXU.js → issues-HK2JA5JS.js} +3 -3
  34. package/dist/{knobs-6WLJMB44.js → knobs-ETJAV6YM.js} +3 -3
  35. package/dist/{list-PHC7VYNS.js → list-F6DGGW3Z.js} +3 -3
  36. package/dist/{local-VGYRSW22.js → local-CMAY54I5.js} +5 -5
  37. package/dist/{login-QPU2BKG2.js → login-6CKG664C.js} +8 -8
  38. package/dist/{mcp-LA452TOA.js → mcp-GC2WOOZO.js} +5 -6
  39. package/dist/{mcp-LA452TOA.js.map → mcp-GC2WOOZO.js.map} +1 -1
  40. package/dist/metrics-IXICURAA.js +367 -0
  41. package/dist/metrics-IXICURAA.js.map +1 -0
  42. package/dist/{product-RSZV5HMB.js → product-BUJWPYKB.js} +4 -3
  43. package/dist/product-BUJWPYKB.js.map +1 -0
  44. package/dist/{property-YP4GHQAR.js → property-4EXPWRNT.js} +3 -3
  45. package/dist/{record-KWKHP2ZY.js → record-HL4QA7OX.js} +4 -4
  46. package/dist/{record-KWKHP2ZY.js.map → record-HL4QA7OX.js.map} +1 -1
  47. package/dist/{release-NDRHPW6V.js → release-2SMK5Y3V.js} +3 -3
  48. package/dist/{sandbox-OOCANWOG.js → sandbox-ORAPKOH3.js} +3 -3
  49. package/dist/{scenarios-2HRLCGFY.js → scenarios-DM5FDCAF.js} +3 -3
  50. package/dist/{session-M4ULYDYP.js → session-X6IYGWYG.js} +14 -16
  51. package/dist/{session-M4ULYDYP.js.map → session-X6IYGWYG.js.map} +1 -1
  52. package/dist/{skill-4DGPRDUC.js → skill-ZU5V2EE5.js} +24 -14
  53. package/dist/skill-ZU5V2EE5.js.map +1 -0
  54. package/dist/skills/optimize-cache/SKILL.md +9 -3
  55. package/dist/{spec-XZ2TKUFZ.js → spec-KO5QD6AY.js} +3 -3
  56. package/dist/{src-HL7HEJIW.js → src-DSD34JIX.js} +2 -2
  57. package/dist/{src-2FK3JHGW.js → src-HTGNKBUF.js} +15 -7
  58. package/dist/{src-2FK3JHGW.js.map → src-HTGNKBUF.js.map} +1 -1
  59. package/dist/{src-OU7544PM.js → src-PDYXACRP.js} +2 -2
  60. package/dist/{start-IYKF3C3X.js → start-2ECN4LX5.js} +6 -6
  61. package/dist/{tag-T45MMSCH.js → tag-R5I72HJ6.js} +4 -4
  62. package/dist/{task-MCUHAVTD.js → task-V3JMSJIM.js} +3 -3
  63. package/dist/{test-suite-BICBRSBP.js → test-suite-NOYVK6YX.js} +5 -5
  64. package/dist/{trace-2BAPMYAS.js → trace-NOYEKNO4.js} +4 -5
  65. package/dist/{triage-M3RZ2ASB.js → triage-4RFATHBE.js} +4 -4
  66. package/dist/utilities-3WMXE743.js +441 -0
  67. package/dist/utilities-3WMXE743.js.map +1 -0
  68. package/dist/{workflow-4J23FV7K.js → workflow-DC7WOTTW.js} +13 -17
  69. package/dist/workflow-DC7WOTTW.js.map +1 -0
  70. package/dist/{workflow-cache-XPSK6KC7.js → workflow-cache-SDSI6SMF.js} +6 -6
  71. package/dist/{workflow-cache-XPSK6KC7.js.map → workflow-cache-SDSI6SMF.js.map} +1 -1
  72. package/dist/{workflow-debug-W4USZH35.js → workflow-debug-6UQYP67Q.js} +6 -7
  73. package/dist/{workflow-debug-W4USZH35.js.map → workflow-debug-6UQYP67Q.js.map} +1 -1
  74. package/dist/{workflow-proposals-5E3DTYZB.js → workflow-proposals-67AVGMHX.js} +6 -6
  75. package/package.json +1 -1
  76. package/dist/account-62I7FG5G.js.map +0 -1
  77. package/dist/chunk-26U3DGUM.js.map +0 -1
  78. package/dist/chunk-5R4HMSNX.js.map +0 -1
  79. package/dist/chunk-CFJXYPTF.js.map +0 -1
  80. package/dist/chunk-IWKJQZJQ.js.map +0 -1
  81. package/dist/chunk-KRWRUU6R.js +0 -114
  82. package/dist/chunk-KRWRUU6R.js.map +0 -1
  83. package/dist/feature-flag-K5REGGDY.js.map +0 -1
  84. package/dist/pdf-extract-YHE54XU4.js +0 -13
  85. package/dist/product-RSZV5HMB.js.map +0 -1
  86. package/dist/skill-4DGPRDUC.js.map +0 -1
  87. package/dist/triage-M3RZ2ASB.js.map +0 -1
  88. package/dist/workflow-4J23FV7K.js.map +0 -1
  89. /package/dist/{api-catalog-CAJUASVC.js.map → api-catalog-6HNOGVPA.js.map} +0 -0
  90. /package/dist/{attachment-RL4AZUJE.js.map → attachment-QAHR54HQ.js.map} +0 -0
  91. /package/dist/{augmentor-GAF3MFY6.js.map → augmentor-7T3L6ZR4.js.map} +0 -0
  92. /package/dist/{chunk-HKQ5XQAQ.js.map → chunk-CEXV3MOC.js.map} +0 -0
  93. /package/dist/{chunk-VKBTI5EF.js.map → chunk-D6AVOPOS.js.map} +0 -0
  94. /package/dist/{chunk-ZXRVFFCY.js.map → chunk-DT2CEH2V.js.map} +0 -0
  95. /package/dist/{chunk-CJEKEW7R.js.map → chunk-LFFWD5JZ.js.map} +0 -0
  96. /package/dist/{chunk-UZ2ZA5A6.js.map → chunk-RGDIVW3O.js.map} +0 -0
  97. /package/dist/{credential-JGVSEGVH.js.map → credential-X6QKX473.js.map} +0 -0
  98. /package/dist/{credential-template-CWWMOKB2.js.map → credential-template-GD3D4MBI.js.map} +0 -0
  99. /package/dist/{debug-workflow-BXRU72YZ.js.map → debug-workflow-AAEOAME2.js.map} +0 -0
  100. /package/dist/{pdf-extract-YHE54XU4.js.map → dist-QLTVBUMD.js.map} +0 -0
  101. /package/dist/{docs-PVBXPTGR.js.map → docs-BVUEXBY3.js.map} +0 -0
  102. /package/dist/{environment-WZKIO3R3.js.map → environment-WE7VVE6I.js.map} +0 -0
  103. /package/dist/{init-FFUZO5D7.js.map → init-RQHHKJJD.js.map} +0 -0
  104. /package/dist/{install-XRKEQAFZ.js.map → install-CQLHNZ6U.js.map} +0 -0
  105. /package/dist/{issues-I3V6GEXU.js.map → issues-HK2JA5JS.js.map} +0 -0
  106. /package/dist/{knobs-6WLJMB44.js.map → knobs-ETJAV6YM.js.map} +0 -0
  107. /package/dist/{list-PHC7VYNS.js.map → list-F6DGGW3Z.js.map} +0 -0
  108. /package/dist/{local-VGYRSW22.js.map → local-CMAY54I5.js.map} +0 -0
  109. /package/dist/{login-QPU2BKG2.js.map → login-6CKG664C.js.map} +0 -0
  110. /package/dist/{property-YP4GHQAR.js.map → property-4EXPWRNT.js.map} +0 -0
  111. /package/dist/{release-NDRHPW6V.js.map → release-2SMK5Y3V.js.map} +0 -0
  112. /package/dist/{sandbox-OOCANWOG.js.map → sandbox-ORAPKOH3.js.map} +0 -0
  113. /package/dist/{scenarios-2HRLCGFY.js.map → scenarios-DM5FDCAF.js.map} +0 -0
  114. /package/dist/{spec-XZ2TKUFZ.js.map → spec-KO5QD6AY.js.map} +0 -0
  115. /package/dist/{src-HL7HEJIW.js.map → src-DSD34JIX.js.map} +0 -0
  116. /package/dist/{src-CV57ZD6I.js.map → src-PDYXACRP.js.map} +0 -0
  117. /package/dist/{start-IYKF3C3X.js.map → start-2ECN4LX5.js.map} +0 -0
  118. /package/dist/{src-OU7544PM.js.map → tag-R5I72HJ6.js.map} +0 -0
  119. /package/dist/{task-MCUHAVTD.js.map → task-V3JMSJIM.js.map} +0 -0
  120. /package/dist/{test-suite-BICBRSBP.js.map → test-suite-NOYVK6YX.js.map} +0 -0
  121. /package/dist/{tag-T45MMSCH.js.map → trace-NOYEKNO4.js.map} +0 -0
  122. /package/dist/{trace-2BAPMYAS.js.map → triage-4RFATHBE.js.map} +0 -0
  123. /package/dist/{workflow-proposals-5E3DTYZB.js.map → workflow-proposals-67AVGMHX.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../workflow-cache/src/logger.ts","../../workflow-cache/src/node-hash.ts","../../workflow-cache/src/build-locator.ts","../../workflow-cache/src/snapshot-parser.ts","../../workflow-cache/src/locator-parser.ts","../../workflow-cache/src/element-resolver.ts","../../workflow-cache/src/selector-derivation.ts","../../workflow-cache/src/cached-action-assembly.ts","../../workflow-cache/src/optimizer/headless-session.ts","../../workflow-cache/src/optimizer/trace-node-segmenter.ts","../../workflow-cache/src/optimizer/substrate-materializer.ts","../../workflow-cache/src/optimizer/locator-verifier.ts","../../workflow-cache/src/optimizer/augmentor-verifier.ts","../../workflow-cache/src/optimizer/action-synthesizer.ts","../../workflow-cache/src/optimizer/recipe.ts","../../workflow-cache/src/macros/types.ts","../../workflow-cache/src/macros/registry.ts","../../workflow-cache/src/macros/resolver.ts"],"sourcesContent":["/**\n * Workflow-Cache Logger\n *\n * The package must work in any environment (server, CLI), so logging goes\n * through the environment-agnostic `BrowserLogger` interface from\n * `@chatsdet/browser-core` instead of importing pino directly.\n *\n * - Cloud (apps/api): call `setWorkflowCacheLogger(pinoToBrowserLogger(...))`\n * once at boot so package logs flow into the structured pino pipeline.\n * - CLI (canary-cli): the `consoleLogger` default applies.\n *\n * `createLogger(bindings)` mirrors the apps/api pino-logger call shape\n * (`logger.info(message, payload?)`) so moved modules only change their\n * import path.\n *\n * @module logger\n */\n\nimport { consoleLogger, type BrowserLogger } from '@chatsdet/browser-core';\n\nlet activeLogger: BrowserLogger = consoleLogger;\n\n/** Install an environment-specific logger (e.g. a pino adapter on the server). */\nexport function setWorkflowCacheLogger(logger: BrowserLogger): void {\n activeLogger = logger;\n}\n\n/**\n * Create a logger that merges `bindings` into every payload and delegates to\n * the active environment logger. Same `(message, payload?)` call shape as the\n * apps/api `createLogger`.\n */\nexport function createLogger(bindings?: Record<string, unknown>): BrowserLogger {\n if (!bindings || Object.keys(bindings).length === 0) {\n return {\n debug: (msg, data) => activeLogger.debug(msg, data),\n info: (msg, data) => activeLogger.info(msg, data),\n warn: (msg, data) => activeLogger.warn(msg, data),\n error: (msg, data) => activeLogger.error(msg, data),\n };\n }\n const merge = (data?: Record<string, unknown>) => ({ ...bindings, ...data });\n return {\n debug: (msg, data) => activeLogger.debug(msg, merge(data)),\n info: (msg, data) => activeLogger.info(msg, merge(data)),\n warn: (msg, data) => activeLogger.warn(msg, merge(data)),\n error: (msg, data) => activeLogger.error(msg, merge(data)),\n };\n}\n","/**\n * Node Hash Algorithm\n *\n * Generates deterministic hashes for workflow nodes based on their semantic content.\n * Used for cache lookup - nodes with the same hash produce the same behavior.\n *\n * This module holds the pure hash algorithm (`NodeHashInput` → hash string).\n * Extracting a `NodeHashInput` from a live `WorkflowNodeContext` is a server\n * concern and lives in `apps/api/src/workflows/helpers/node-hash.ts`.\n *\n * Hash versions:\n * - v1: Initial version (2026-01-15) - proper deep key sorting\n * - v2 (current default): Added `playbookSteps` (order+action+target) to\n * input for action/assertion nodes.\n * - v3 (per-org, behind `workflow.recipe-v3`): pure node identity — drops\n * `playbookSteps` (the playbook is no longer part of its own cache key; it\n * rewrites in place on the identity row) and drops the vestigial\n * `inlineAssertions[].severity` (folding its deferred removal into a\n * re-mint that is already happening — see the NodeHashInput comment).\n * Selected per-org at the callsites via `generateNodeHashV3`, NOT a global\n * `HASH_VERSION` bump — see specs/workflow-versioning-pin-and-playbook.md.\n *\n * Note: Changing the hash algorithm will cause existing caches to miss.\n * This is acceptable - caches will repopulate on next execution.\n *\n * @module\n * @see /docs/workflow-node-cache.md for caching design\n */\n\nimport { createHash } from 'crypto';\n\n/** Current hash version - increment if hash algorithm changes */\nconst HASH_VERSION = 'v2';\n\n/**\n * Recursively sort object keys for deterministic JSON serialization.\n * Handles nested objects and arrays.\n */\nexport function sortObjectKeys(obj: unknown): unknown {\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys);\n }\n if (obj !== null && typeof obj === 'object') {\n const sorted = Object.keys(obj as Record<string, unknown>)\n .sort()\n .reduce(\n (acc, key) => {\n acc[key] = sortObjectKeys((obj as Record<string, unknown>)[key]);\n return acc;\n },\n {} as Record<string, unknown>\n );\n return sorted;\n }\n return obj;\n}\n\n/**\n * Input data for generating a node hash.\n * Only includes fields that affect node behavior (excludes cosmetic fields).\n */\nexport interface NodeHashInput {\n nodeType: string;\n /** Primary description/condition based on node type */\n description?: string;\n /** Action node title (separate from description for stable hashing) */\n title?: string | null;\n /** URL the node operates on */\n pageUrl?: string;\n /** Data requirements for action nodes (name + type) */\n dataRequirements?: Array<{ name: string; type?: string }>;\n /** Playbook steps for playbook-capable nodes (order + action + target) — cached actions are replayed 1:1 against these, so a mismatch must miss */\n playbookSteps?: Array<{ order: number; action: string; target: string }>;\n /**\n * Inline assertions for action nodes (`id` excluded — random UUID would cause\n * spurious invalidation).\n *\n * `severity` is vestigial here: replay resolves it authoritatively from current\n * node config (cache/replay.ts), treating the cached value as advisory, so it\n * does not affect replayed behavior and ideally would not be hashed. It is kept\n * only because dropping it standalone re-mints ~29% of action caches for no\n * behavioral gain. If the hash algorithm ever changes for another reason, drop\n * `severity` then too — folding the re-mint into one that is already happening.\n */\n inlineAssertions?: Array<{ condition: string; severity: string; agentic?: boolean }>;\n}\n\n/**\n * Generate a deterministic hash for a node based on its semantic content.\n * Uses SHA-256 truncated to 16 characters with a version prefix.\n *\n * Format: \"v2:abc123...\" (version prefix + 16 hex characters)\n *\n * @param input - Node hash input (from extractHashInput or constructed manually)\n * @returns Deterministic hash string with version prefix\n */\nexport function generateNodeHash(input: NodeHashInput): string {\n return hashWithPrefix(input, HASH_VERSION);\n}\n\n/**\n * v3: pure node-identity hash (per-org, behind `workflow.recipe-v3`).\n *\n * Accepts the same `NodeHashInput` as v2 and drops the non-identity fields\n * itself, so callers don't need a parallel extraction path:\n * - `playbookSteps` — derived content; lives on the identity row and\n * updates in place rather than moving the row.\n * - `inlineAssertions[].severity` — replay resolves severity from current\n * node config; hashing it only caused spurious re-mints.\n */\nexport function generateNodeHashV3(input: NodeHashInput): string {\n const { playbookSteps: _playbookSteps, inlineAssertions, ...identity } = input;\n const v3Input: Omit<NodeHashInput, 'playbookSteps' | 'inlineAssertions'> & {\n inlineAssertions?: Array<{ condition: string; agentic?: boolean }>;\n } = {\n ...identity,\n ...(inlineAssertions\n ? {\n inlineAssertions: inlineAssertions.map(({ condition, agentic }) => ({\n condition,\n ...(agentic !== undefined ? { agentic } : {}),\n })),\n }\n : {}),\n };\n return hashWithPrefix(v3Input, 'v3');\n}\n\nfunction hashWithPrefix(input: unknown, version: string): string {\n // Deep-sort all keys for consistent serialization regardless of property order\n const sortedInput = sortObjectKeys(input);\n const stableJson = JSON.stringify(sortedInput);\n\n // Generate SHA-256 hash, truncate to 16 chars for reasonable uniqueness\n const hash = createHash('sha256').update(stableJson).digest('hex').slice(0, 16);\n\n // Include version prefix for future algorithm changes\n return `${version}:${hash}`;\n}\n","/**\n * Substrate-v2 deterministic locator algorithm.\n *\n * `buildLocator(snapshot, ref, variableValues) -> SelectorStrategy` is a pure\n * function: it consumes a parsed substrate, an ephemeral ref, and the workflow\n * variable bag, and emits a {@link SelectorStrategy} ready for cache replay.\n * No live DOM access, no Effect, no I/O.\n *\n * See `docs/api/services/snapshot-substrate.md` for the design rationale and\n * predicate ladder.\n *\n * **Ancestor scoping (implementation note):** ancestor scoping is flattened to\n * a single identifiable anchor (via {@link isAncestorIdentifiable}) plus an\n * optional `parentChain` of intermediate ancestors, falling through to the\n * indexed-fallback when no anchor is identifiable.\n *\n * @module\n */\n\nimport type {\n ParentContext,\n ParentContextNode,\n ParentContextDynamicText,\n RoleSelector,\n SelectorStrategy,\n FrameContext,\n} from '@chatsdet/types';\nimport {\n isVolatileIdentifier,\n stableIdentifierPrefix,\n stableAttrSelector,\n} from '@chatsdet/types';\nimport type { SnapshotElement, SnapshotElementSource } from '@chatsdet/browser-core';\n\n/**\n * A binding chosen during the templating pass. Surfaces every variable\n * substitution `buildLocator` made so callers can log decisions for review.\n */\nexport interface VariableBinding {\n /** Variable key (e.g. `customer_name`). */\n key: string;\n /** Literal value at recording time. */\n value: string;\n /** Substrate field where the match landed. */\n field: TemplatedField;\n /** Number of nodes whose value was rewritten with this binding. */\n occurrences: number;\n}\n\nexport interface BuildLocatorResult {\n selectors: SelectorStrategy;\n /** Predicate name that produced the locator, for logging/metrics. */\n predicate: string;\n /** Variable bindings used while templating. */\n bindings: VariableBinding[];\n /**\n * True when no predicate produced a snapshot-unique match and we fell\n * through to the indexed fallback. Recording middleware uses this to decide\n * whether to enqueue a selector-agent task.\n */\n irreducible: boolean;\n}\n\ntype TemplatedField = 'text' | 'aria-label' | 'placeholder' | 'value';\n\n/** Field a predicate reads — used by the source-durability gate. */\ntype PredicateField = 'text' | 'aria-label' | 'placeholder' | 'src' | 'data-field';\n\nconst REPEATING_ANCESTOR_ROLES = new Set([\n 'row',\n 'listitem',\n 'gridcell',\n 'article',\n 'option',\n 'treeitem',\n]);\n\ninterface NormalizedNode {\n el: SnapshotElement;\n /** Templated accessible name (`text`), with variable values replaced by `{{key}}`. */\n textTemplate?: string;\n /** Templated `aria-label` attribute. */\n ariaLabelTemplate?: string;\n /** Templated `placeholder` attribute. */\n placeholderTemplate?: string;\n /** Templated `value`/`inputValue`. */\n valueTemplate?: string;\n /** Bindings applied to this node (subset of the global bag). */\n bindings: VariableBinding[];\n /** Parent in the normalized tree, or null for roots. */\n parent: NormalizedNode | null;\n /** Refs of all descendants (including self). Built once during flatten. */\n descendantRefs: Set<string>;\n}\n\n/**\n * Build a {@link SelectorStrategy} for `ref` from the parsed substrate.\n * Returns the strategy plus diagnostics. Callers should pass the same\n * `variableValues` that recording will pass at replay.\n */\nexport function buildLocator(\n snapshot: SnapshotElement[],\n ref: string,\n variableValues: Record<string, string> = {}\n): BuildLocatorResult {\n const { flat, byRef } = flatten(snapshot);\n const target = byRef.get(ref);\n if (!target) {\n return {\n selectors: {},\n predicate: 'none',\n bindings: [],\n irreducible: true,\n };\n }\n\n // Pass 1 — variable templating across the whole snapshot. Uniqueness\n // checks must scan templates so multiple rows that differ only in the\n // bound variable collapse into one match.\n const allBindings = templateAll(flat, variableValues);\n\n // Pass 2 — precompute uniqueness lookup tables for the identifiability\n // check. Built once; each ancestor probe is O(1).\n const identityIndex = buildIdentityIndex(flat);\n\n // Pass 3 — predicate ladder. First predicate that's globally unique\n // wins. If none unique, recurse under each ancestor closest-first\n // looking for predicate+scope that's unique within the subtree and\n // resolves back to the target.\n const frameContext = frameContextFor(target.el);\n const baseDynamicText = buildDynamicText(target);\n const ancestors = ancestorChain(target);\n\n // Custom-augmentor durable anchor — special-cased FIRST. A custom augmentor's\n // verified `stableAnchor` is a complete CSS selector, built only from\n // pre-existing (non-injected) attributes and proven to resolve uniquely to\n // the target. It is the authoritative locator for an augmented ref; emit it\n // directly. Without this the injected role/name are provenance-blocked\n // (`augmented:dom-mutation`) and the ref would fall through to irreducible.\n //\n // Replay safety: this becomes a plain `{ css }` strategy resolved through the\n // shared `resolveElement` on the replay path, which enforces the strict-cache-\n // replay uniqueness invariant (count===1, rejecting multi-match rather than\n // `.first()`). So a DOM that drifted since authoring can't silently click the\n // wrong element — the anchor is no riskier than any other cached CSS locator.\n const augmentorAnchor = target.el.augmentorAnchor;\n if (augmentorAnchor) {\n return {\n selectors: applyContexts({ css: augmentorAnchor }, frameContext, baseDynamicText),\n predicate: 'augmentorAnchor',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n // testId is special-cased: each testId is independent, so we pick the\n // first one that's globally unique rather than running the predicate\n // ladder on a set-overlap match.\n const uniqueTestId = pickUniqueTestId(target, flat);\n if (uniqueTestId) {\n return {\n selectors: applyContexts({ testId: uniqueTestId }, frameContext, baseDynamicText),\n predicate: 'testId',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n // iconClass is also special-cased: an icon-only control whose <svg> carries\n // a stable lucide class (e.g. `lucide-sliders-horizontal`) has no\n // accessible name in the substrate, so the role+name ladder cannot apply.\n // The DOM grounding is the icon class itself; emit a CSS `:has()` anchor\n // when it's globally unique for the target's role.\n const uniqueIconClass = pickUniqueIconClass(target, flat);\n if (uniqueIconClass) {\n const role: RoleSelector = { role: target.el.role };\n return {\n selectors: applyContexts(\n { role, css: roleScopedCss(target.el.role, `:has(svg.${uniqueIconClass})`) },\n frameContext,\n baseDynamicText\n ),\n predicate: 'iconClass',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n // semanticClass: a target whose own className carries a meaningful token\n // (e.g. `delete-btn`, `IconButton-filter`) that's globally unique for the\n // role. CSS class selectors are valid Playwright locators; the substrate\n // carries the raw class via `[~semantic-class=…]` and the algorithm\n // anchors on it before falling through to the role+name ladder.\n const uniqueSemanticClass = pickUniqueSemanticClass(target, flat);\n if (uniqueSemanticClass) {\n const role: RoleSelector = { role: target.el.role };\n return {\n selectors: applyContexts(\n { role, css: roleScopedCss(target.el.role, `.${uniqueSemanticClass}`) },\n frameContext,\n baseDynamicText\n ),\n predicate: 'semanticClass',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n const volatileTestIdText = buildVolatileTestIdTextSelector(target, flat);\n if (volatileTestIdText) {\n return {\n selectors: applyContexts(volatileTestIdText, frameContext, baseDynamicText),\n predicate: 'volatileTestId+containsText',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n for (const p of PREDICATES) {\n if (!p.applies(target)) continue;\n if (isPredicateBlockedBySource(p, target)) continue;\n\n // Global uniqueness — count and short-circuit at 2.\n const matches = uniquenessMatches(flat, target, p);\n if (matches === 1) {\n const sel = p.toStrategy(target, flat);\n return {\n selectors: applyContexts(sel, frameContext, baseDynamicText),\n predicate: p.name,\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n const rowVariableScope = findRowVariableScope({\n flat,\n target,\n predicate: p,\n ancestors,\n variableValues,\n });\n if (rowVariableScope) {\n const inner = p.toStrategy(target, flat);\n const parentContext = parentContextFor(\n rowVariableScope.anchor,\n rowVariableScope.innerAncestors,\n {\n containsText: rowVariableScope.value,\n containsTextDynamic: {\n source: 'workflowState',\n key: rowVariableScope.key,\n originalText: rowVariableScope.value,\n },\n }\n );\n return {\n selectors: applyContexts(\n { ...inner, parentContext },\n frameContext,\n baseDynamicText\n ),\n predicate: `${p.name}+row-variable`,\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n // Try scoping under each ancestor (closest-first). The scope must be\n // unique within the ancestor's subtree AND the ancestor itself must be\n // identifiable in the wider snapshot (so the chain resolves end-to-end\n // at replay). Prefer the ancestor's globally-unique stable id (data-id /\n // test-id) — a structural, NON-ordinal anchor that also identifies nameless\n // ancestors (a `__new__` draft row, a hard-coded test-id panel) — and emit\n // it as `parentContext.css`; otherwise identify the ancestor by role+name\n // / durable child text.\n for (let i = ancestors.length - 1; i >= 0; i--) {\n const anchor = ancestors[i];\n const sub = uniquenessMatchesScoped(flat, target, p, anchor);\n if (sub !== 1) continue;\n\n const idSelector = uniqueStableIdSelector(anchor, flat);\n if (idSelector) {\n return {\n selectors: applyContexts(\n { ...p.toStrategy(target, flat), parentContext: { css: idSelector } },\n frameContext,\n baseDynamicText\n ),\n predicate: `${p.name}+stable-id-ancestor`,\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n if (!isAncestorIdentifiable(anchor, identityIndex, target)) continue;\n const inner = p.toStrategy(target, flat);\n const parentContext = parentContextFor(anchor, ancestors.slice(i + 1));\n return {\n selectors: applyContexts(\n { ...inner, parentContext },\n frameContext,\n baseDynamicText\n ),\n predicate: `${p.name}+ancestor`,\n bindings: allBindings,\n irreducible: false,\n };\n }\n }\n\n const rowScopedOrdinal = buildRowScopedOrdinalLocator({\n target,\n ancestors,\n variableValues,\n });\n if (rowScopedOrdinal) {\n return {\n selectors: applyContexts(\n {\n role: { role: target.el.role },\n playwrightLocator: rowScopedOrdinal.locator,\n playwrightLocatorCandidates: {\n deterministic: {\n locator: rowScopedOrdinal.locator,\n usesVariableBinding: true,\n boundVariableKey: rowScopedOrdinal.key,\n },\n },\n parentContext: parentContextFor(rowScopedOrdinal.anchor, rowScopedOrdinal.innerAncestors, {\n containsText: rowScopedOrdinal.value,\n containsTextDynamic: {\n source: 'workflowState',\n key: rowScopedOrdinal.key,\n originalText: rowScopedOrdinal.value,\n },\n }),\n },\n frameContext,\n baseDynamicText\n ),\n predicate: 'row-variable+scoped-button-index',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n // Clone-index disambiguation: when role+name matches N > 1 nodes and all\n // matches live in byte-identical subtrees under a common non-list parent,\n // they are UI clones (e.g. responsive-layout duplicates), not data rows.\n // Ordinal disambiguation is safe here because the matches carry no\n // information difference — picking nth(N) deterministically clicks the\n // same DOM element each replay. Distinguishes \"Telerik dashboard widget\n // duplicated at 4 breakpoints\" from \"table with 4 rows of patient data.\"\n const cloneIndex = buildCloneIndexLocator({ flat, target });\n if (cloneIndex) {\n const role: RoleSelector = { role: target.el.role };\n const name = target.textTemplate ?? target.el.text;\n if (name) role.name = name;\n return {\n selectors: applyContexts(\n { role, playwrightLocator: cloneIndex.locator },\n frameContext,\n baseDynamicText\n ),\n predicate: 'role+name+clone-index',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n return {\n selectors: applyContexts(indexedFallback(target), frameContext, baseDynamicText),\n predicate: 'indexed-fallback',\n bindings: allBindings,\n irreducible: true,\n };\n}\n\n/**\n * Roles whose containers carry data-row semantics. When a shared ancestor of\n * the role+name matches has one of these roles, ordinal disambiguation is\n * brittle because list/grid contents are usually data-driven and reorder\n * with sorts, filters, or inserts. Keeps clone-index safe for static UI\n * duplication (dashboards, side-by-side panels) while ceding data lists\n * to indexed-fallback + irreducible.\n */\nconst LIST_ROLES: ReadonlySet<string> = new Set([\n 'list',\n 'listbox',\n 'grid',\n 'tree',\n 'treegrid',\n 'table',\n 'tbody',\n 'thead',\n 'rowgroup',\n 'row',\n 'menu',\n 'menubar',\n]);\n\ninterface CloneIndexLocator {\n locator: string;\n ordinal: number;\n}\n\n/**\n * Build a `role+name+clone-index` locator when all role+name matches are\n * structurally identical clones under a non-list common parent. Returns\n * `null` if the safety conditions don't hold — caller falls through to\n * indexed-fallback + irreducible.\n *\n * Safety contract:\n * 1. ≥2 global matches for the target's (role, name).\n * 2. Each match has a \"card\" (lowest ancestor containing only that match),\n * and all cards are siblings under a single common parent.\n * 3. No ancestor between the common parent and the document root has a\n * list/grid/table-style role.\n * 4. All cards' subtree text fingerprints (recursive role+text walk) are\n * byte-identical — proves the matches carry no distinguishing data.\n */\nfunction buildCloneIndexLocator(args: {\n flat: NormalizedNode[];\n target: NormalizedNode;\n}): CloneIndexLocator | null {\n const { flat, target } = args;\n if (!target.el.role) return null;\n const targetName = target.textTemplate ?? target.el.text;\n if (!targetName) return null;\n\n // Find all global matches for role+name in flatten/DOM order.\n const matches = flat.filter(\n (n) => n.el.role === target.el.role && (n.textTemplate ?? n.el.text) === targetName\n );\n if (matches.length < 2) return null;\n\n // Each match's \"card\" = lowest ancestor whose subtree contains ONLY that\n // match among `matches`. Walking up stops as soon as another match enters\n // the subtree.\n const cards: NormalizedNode[] = [];\n for (const m of matches) {\n const card = nearestCloneCard(m, matches);\n if (!card) return null;\n cards.push(card);\n }\n\n // All cards must share a single common parent (siblings of one another).\n const parents = new Set<NormalizedNode | null>(cards.map((c) => c.parent));\n if (parents.size !== 1) return null;\n const commonParent = [...parents][0];\n if (!commonParent) return null;\n\n // No list-role ancestor in the chain from the common parent up.\n for (let p: NormalizedNode | null = commonParent; p; p = p.parent) {\n if (LIST_ROLES.has(p.el.role)) return null;\n }\n\n // All cards must have byte-identical subtree text fingerprints.\n const reference = subtreeTextFingerprint(cards[0].el);\n for (let i = 1; i < cards.length; i++) {\n if (subtreeTextFingerprint(cards[i].el) !== reference) return null;\n }\n\n const ordinal = matches.indexOf(target);\n if (ordinal < 0) return null;\n\n const locator = `getByRole('${escapeLocatorString(target.el.role)}', { name: '${escapeLocatorString(targetName)}' }).nth(${ordinal})`;\n return { locator, ordinal };\n}\n\nfunction nearestCloneCard(\n match: NormalizedNode,\n allMatches: NormalizedNode[]\n): NormalizedNode | null {\n const otherRefs = new Set(allMatches.filter((m) => m !== match).map((m) => m.el.ref));\n let candidate: NormalizedNode | null = match;\n let node: NormalizedNode | null = match.parent;\n while (node) {\n let containsOther = false;\n for (const ref of otherRefs) {\n if (node.descendantRefs.has(ref)) {\n containsOther = true;\n break;\n }\n }\n if (containsOther) break;\n candidate = node;\n node = node.parent;\n }\n return candidate;\n}\n\n/**\n * Recursive role+text walk of a subtree, ignoring refs and attributes.\n * Two clones of the same UI component produce identical fingerprints; two\n * data rows produce different fingerprints (their content varies).\n */\nfunction subtreeTextFingerprint(el: SnapshotElement): string {\n // Capture every text-bearing slot the snapshot parser uses:\n // `text` — accessible name (button \"Edit\", link \"Home\", etc.)\n // `inputValue` — generic-with-content (`- generic [ref=e1]: Hello`) and\n // textbox/combobox current value\n // `url` — link href when present\n // Attributes are intentionally excluded: clones can carry different ref-derived\n // attributes (test-id, data-id) without being information-distinct from a user's\n // perspective. Text/inputValue/url are the dimensions that actually distinguish\n // a \"data row\" from a \"UI clone.\"\n const parts: string[] = [];\n const walk = (node: SnapshotElement): void => {\n const slots: string[] = [node.role];\n if (node.text) slots.push(`t=${node.text}`);\n if (node.inputValue) slots.push(`v=${node.inputValue}`);\n if (node.url) slots.push(`u=${node.url}`);\n parts.push(slots.join(':'));\n for (const c of node.children) walk(c);\n };\n walk(el);\n return parts.join('|');\n}\n\ninterface RowScopedOrdinalLocator {\n locator: string;\n anchor: NormalizedNode;\n innerAncestors: NormalizedNode[];\n key: string;\n value: string;\n}\n\nfunction buildRowScopedOrdinalLocator(args: {\n target: NormalizedNode;\n ancestors: NormalizedNode[];\n variableValues: Record<string, string>;\n}): RowScopedOrdinalLocator | null {\n const targetLabel =\n args.target.textTemplate ??\n args.target.el.text ??\n args.target.ariaLabelTemplate ??\n args.target.el.attributes['aria-label'];\n if (args.target.el.role !== 'button' || targetLabel) return null;\n\n const entries = Object.entries(args.variableValues)\n .filter(([, value]) => typeof value === 'string' && value.length >= MIN_TEMPLATING_LENGTH)\n .sort((a, b) => b[1].length - a[1].length);\n if (entries.length === 0) return null;\n\n for (let i = args.ancestors.length - 1; i >= 0; i--) {\n const anchor = args.ancestors[i];\n if (!REPEATING_ANCESTOR_ROLES.has(anchor.el.role)) continue;\n const anchorText = collectSubtreeText(anchor.el);\n const match = entries.find(([, value]) => textContainsValue(anchorText, value));\n if (!match) continue;\n const buttonRefs = collectRoleRefs(anchor.el, 'button');\n const ordinal = buttonRefs.indexOf(args.target.el.ref);\n if (ordinal < 0) continue;\n const [key, value] = match;\n return {\n locator: `getByRole('${escapeLocatorString(anchor.el.role)}').filter({ hasText: '{{var.${key}}}' }).getByRole('button').nth(${ordinal})`,\n anchor,\n innerAncestors: args.ancestors.slice(i + 1),\n key,\n value,\n };\n }\n\n return null;\n}\n\nfunction collectRoleRefs(el: SnapshotElement, role: string): string[] {\n const refs: string[] = [];\n const walk = (node: SnapshotElement): void => {\n if (node.role === role && node.ref) refs.push(node.ref);\n for (const child of node.children) walk(child);\n };\n walk(el);\n return refs;\n}\n\nfunction escapeLocatorString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Templating\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Minimum length for a variable value to be templated. Short values (e.g. \"1\", \"OK\") are too lossy. */\nconst MIN_TEMPLATING_LENGTH = 3;\n\ninterface CompiledBinding {\n key: string;\n value: string;\n /** Word-boundary-aware regex, used for both check and replace. */\n regex: RegExp;\n}\n\nfunction templateAll(\n flat: NormalizedNode[],\n variableValues: Record<string, string>\n): VariableBinding[] {\n const summary = new Map<string, VariableBinding>();\n const compiled: CompiledBinding[] = Object.entries(variableValues)\n .filter(([, v]) => typeof v === 'string' && v.length >= MIN_TEMPLATING_LENGTH)\n .map(([key, value]) => ({\n key,\n value,\n regex: new RegExp(`(^|\\\\W)${escapeRegex(value)}(?=\\\\W|$)`, 'g'),\n }));\n if (compiled.length === 0) return [];\n\n for (const node of flat) {\n templateField(node, 'text', node.el.text, (v) => {\n node.textTemplate = v;\n }, compiled, summary);\n templateField(\n node,\n 'aria-label',\n node.el.attributes['aria-label'],\n (v) => {\n node.ariaLabelTemplate = v;\n },\n compiled,\n summary\n );\n templateField(\n node,\n 'placeholder',\n node.el.attributes['placeholder'],\n (v) => {\n node.placeholderTemplate = v;\n },\n compiled,\n summary\n );\n templateField(\n node,\n 'value',\n node.el.inputValue ?? node.el.attributes['value'],\n (v) => {\n node.valueTemplate = v;\n },\n compiled,\n summary\n );\n }\n\n return Array.from(summary.values());\n}\n\nfunction templateField(\n node: NormalizedNode,\n field: TemplatedField,\n original: string | undefined,\n set: (templated: string) => void,\n compiled: CompiledBinding[],\n summary: Map<string, VariableBinding>\n): void {\n if (!original) return;\n let templated = original;\n const local: VariableBinding[] = [];\n for (const b of compiled) {\n b.regex.lastIndex = 0;\n let occurrences = 0;\n // Word-boundary-aware replace: the regex captures the boundary char on\n // the left so we preserve it in the replacement; the right boundary is\n // a lookahead so it isn't consumed.\n const next = templated.replace(b.regex, (_match, lead: string) => {\n occurrences++;\n return `${lead}{{${b.key}}}`;\n });\n if (occurrences > 0 && next !== templated) {\n templated = next;\n local.push({ key: b.key, value: b.value, field, occurrences });\n }\n }\n if (templated !== original) {\n set(templated);\n for (const b of local) {\n node.bindings.push(b);\n const k = `${b.key}|${b.field}`;\n const existing = summary.get(k);\n if (existing) existing.occurrences += b.occurrences;\n else summary.set(k, { ...b });\n }\n }\n}\n\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Predicate ladder\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface Predicate {\n name: string;\n /** Substrate field this predicate reads — used to look up the durability source. */\n field: PredicateField;\n applies: (target: NormalizedNode) => boolean;\n /** Match function: returns true if `candidate` would be a match for the target's predicate values. */\n match: (target: NormalizedNode, candidate: NormalizedNode) => boolean;\n toStrategy: (target: NormalizedNode, flat: NormalizedNode[]) => SelectorStrategy;\n}\n\nconst DOM_MUTATION_SOURCES: ReadonlySet<SnapshotElementSource> = new Set([\n 'augmented:dom-mutation',\n]);\n\n/**\n * Look up the provenance for the field a predicate reads, and return true\n * when that source is too low-durability to use. Stable testIds are handled\n * before the predicate ladder.\n */\nfunction isPredicateBlockedBySource(p: Predicate, target: NormalizedNode): boolean {\n const source =\n p.field === 'text'\n ? target.el.nameSource\n : target.el.attributeSources?.[p.field];\n if (!source) return false;\n return DOM_MUTATION_SOURCES.has(source);\n}\n\n/**\n * Walk the target's testIds and return the first one that's globally unique.\n * Each testId is independent, so set-overlap uniqueness (the regular predicate\n * ladder) doesn't fit — a target with `[shared, unique]` testIds shouldn't\n * fall through just because `shared` is duplicated.\n */\nfunction pickUniqueTestId(target: NormalizedNode, flat: NormalizedNode[]): string | null {\n const ids = stableTestIds(target);\n for (const id of ids) {\n let count = 0;\n for (const n of flat) {\n if (n.el.cssHints?.testIds?.includes(id)) {\n count++;\n if (count > 1) break;\n }\n }\n if (count === 1) return id;\n }\n return null;\n}\n\nfunction stableTestIds(target: NormalizedNode): string[] {\n // Stability = survives a re-seed. Seeded ids (UUID/ULID/entity numbers) are\n // volatile even when unique in the recording snapshot. Canonical rule lives in\n // `@chatsdet/types` (`classifyIdentifier`).\n return (target.el.cssHints?.testIds ?? []).filter((id) => !isVolatileIdentifier(id));\n}\n\nfunction buildVolatileTestIdTextSelector(\n target: NormalizedNode,\n flat: NormalizedNode[]\n): SelectorStrategy | null {\n const ids = target.el.cssHints?.testIds ?? [];\n const textParts = collectVolatileTestIdTextParts(target);\n if (textParts.length === 0) return null;\n\n for (const id of ids) {\n const prefix = stableIdentifierPrefix(id);\n const selectorBase = prefix\n ? `[data-testid^=\"${escapeCssString(prefix)}\"]`\n : '[data-testid]';\n\n let count = 0;\n for (const n of flat) {\n const candidateIds = n.el.cssHints?.testIds ?? [];\n const matchingCandidate = prefix\n ? candidateIds.some((candidateId) => candidateId.startsWith(prefix))\n : candidateIds.some((candidateId) => isVolatileIdentifier(candidateId));\n if (!matchingCandidate) continue;\n const candidateTexts = collectTargetVisibleTexts(n);\n if (!textParts.every((part) => candidateTexts.includes(part))) continue;\n count++;\n if (count > 1) break;\n }\n if (count === 1) {\n const textFilters = textParts\n .map((part) =>\n prefix ? `:has-text(\"${escapeCssString(part)}\")` : `:has(:text-is(\"${escapeCssString(part)}\"))`\n )\n .join('');\n return {\n css: `${selectorBase}${textFilters}`,\n containsText: textParts,\n };\n }\n }\n\n return null;\n}\n\nfunction escapeCssString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n\n/**\n * ARIA role → HTML tag(s) that imply that role natively. Used to build\n * CSS selectors that match both the implicit-role and explicit-role\n * forms (`<button class=\"foo\">` AND `<div role=\"button\" class=\"foo\">`).\n *\n * **Why this matters:** the resolver skips a nameless role selector\n * when a CSS fallback is present (`element-resolver.ts:1487`), so the\n * CSS must work standalone. A naive `${role}.${cls}` selector emits\n * things like `generic.foo` (no `<generic>` tag exists in HTML) or\n * `link.foo` (`<link>` is for stylesheets, not clickables). The result\n * is a CSS that matches zero DOM nodes and replay fails.\n *\n * Roles without a stable implicit tag (`generic`, `switch`,\n * `menuitem`) get only the explicit `[role=\"...\"]` form, which is\n * usually missing from the DOM (those roles are inferred). Callers\n * fall back to class-only selectors in that case (see roleScopedCss).\n */\nconst ROLE_TO_IMPLICIT_TAGS: Record<string, readonly string[]> = {\n button: ['button'],\n link: ['a'],\n img: ['img'],\n textbox: ['input', 'textarea'],\n combobox: ['select'],\n checkbox: ['input'],\n radio: ['input'],\n};\n\n/**\n * Build a CSS selector that matches an ARIA role's implicit-tag forms\n * AND its explicit `[role=\"...\"]` form, joined by comma. The `suffix`\n * is appended to each branch (e.g. `.foo`, `[src*=\"x\"]`, `:has(svg.y)`).\n *\n * For roles with no implicit-tag mapping (`generic`, etc.), returns\n * just the suffix — caller relies on substrate uniqueness because\n * tagging would emit a selector that matches nothing.\n */\nfunction roleScopedCss(role: string, suffix: string): string {\n const implicit = ROLE_TO_IMPLICIT_TAGS[role] ?? [];\n if (implicit.length === 0) {\n // No reliable tag anchor; emit class-only / attr-only selector.\n // Trim leading `:` from `:has(...)` style suffixes — without a\n // leftmost subject `:has(...)` is invalid, so we fall back to `*`.\n return suffix.startsWith(':') ? `*${suffix}` : suffix;\n }\n const parts = [...implicit.map((t) => `${t}${suffix}`), `[role=\"${role}\"]${suffix}`];\n return parts.join(', ');\n}\n\n/**\n * Return the target's icon class iff it's globally unique among same-role\n * nodes. Combined with the role tag, this produces a stable\n * `role:has(svg.<iconClass>)` selector for icon-only controls without an\n * accessible name.\n */\nfunction pickUniqueIconClass(target: NormalizedNode, flat: NormalizedNode[]): string | null {\n const cls = target.el.iconClass;\n if (!cls) return null;\n let count = 0;\n for (const n of flat) {\n if (n.el.role === target.el.role && n.el.iconClass === cls) {\n count++;\n if (count > 1) return null;\n }\n }\n return count === 1 ? cls : null;\n}\n\n/**\n * Return the target's semantic class iff it's globally unique among same-role\n * nodes. Combined with the role tag, this produces a stable `role.<class>`\n * CSS selector for controls labeled by `extractSemanticHint(className)`.\n *\n * The class token has already passed the augmenter's noise filter (rejects\n * Tailwind utilities, styled-component hashes, CSS-in-JS hashes), so reaching\n * this helper means the substrate already carries a stable, semantic token.\n */\nfunction pickUniqueSemanticClass(target: NormalizedNode, flat: NormalizedNode[]): string | null {\n const cls = target.el.semanticClass;\n if (!cls) return null;\n let count = 0;\n for (const n of flat) {\n if (n.el.role === target.el.role && n.el.semanticClass === cls) {\n count++;\n if (count > 1) return null;\n }\n }\n return count === 1 ? cls : null;\n}\n\n/**\n * Pick a stable filename-ish substring from a `src` URL for use in\n * `img[src*=\"<segment>\"]` selectors. Strips query/hash and any path prefix;\n * keeps the last path segment. Returns null for empty / data-URLs / values\n * too short to disambiguate (`<8 chars`).\n */\nfunction srcCssSegment(src: string | undefined): string | null {\n if (!src) return null;\n if (src.startsWith('data:')) return null;\n // Drop query + fragment.\n let cleaned = src.split('?')[0].split('#')[0];\n // Take last path segment.\n const slash = cleaned.lastIndexOf('/');\n if (slash >= 0) cleaned = cleaned.slice(slash + 1);\n cleaned = cleaned.trim();\n if (cleaned.length < 8) return null;\n return cleaned;\n}\n\nconst rolePlusNamePredicate: Predicate = {\n name: 'role+name',\n field: 'text',\n applies: (t) => Boolean(t.el.role && (t.textTemplate ?? t.el.text)),\n match: (t, c) => {\n if (c.el.role !== t.el.role) return false;\n const tn = t.textTemplate ?? t.el.text;\n const cn = c.textTemplate ?? c.el.text;\n return Boolean(tn) && tn === cn;\n },\n toStrategy: (t) => {\n const role: RoleSelector = { role: t.el.role };\n const name = t.textTemplate ?? t.el.text;\n if (name) role.name = name;\n return { role };\n },\n};\n\nfunction placeholderValue(t: NormalizedNode): string | undefined {\n return inferredPlaceholderValue(t) ?? t.placeholderTemplate ?? t.el.attributes['placeholder'];\n}\n\nfunction inferredPlaceholderValue(t: NormalizedNode): string | undefined {\n // Playwright's aria snapshot can render placeholder-only inputs as\n // `textbox \"Search\": <value>`. That text is not a durable accessible name\n // for replay, so prefer a placeholder locator when the field is actively\n // value-bearing and the text looks like a search/filter placeholder.\n const text = t.textTemplate ?? t.el.text;\n if (\n t.el.role === 'textbox' &&\n text &&\n (t.valueTemplate ?? t.el.inputValue ?? t.el.attributes['value']) &&\n /^(search|filter|find)$/i.test(text.trim())\n ) {\n return text;\n }\n\n return undefined;\n}\n\nconst ariaLabelPredicate: Predicate = {\n name: 'ariaLabel',\n field: 'aria-label',\n applies: (t) => Boolean(t.ariaLabelTemplate ?? t.el.attributes['aria-label']),\n match: (t, c) => {\n const tl = t.ariaLabelTemplate ?? t.el.attributes['aria-label'];\n const cl = c.ariaLabelTemplate ?? c.el.attributes['aria-label'];\n return Boolean(tl) && tl === cl;\n },\n toStrategy: (t) => ({\n ariaLabel: t.ariaLabelTemplate ?? t.el.attributes['aria-label'],\n }),\n};\n\nconst placeholderPredicate: Predicate = {\n name: 'placeholder',\n field: 'placeholder',\n applies: (t) => Boolean(placeholderValue(t)),\n match: (t, c) => {\n const tp = placeholderValue(t);\n const cp = placeholderValue(c);\n return Boolean(tp) && tp === cp;\n },\n toStrategy: (t) => ({\n placeholder: placeholderValue(t),\n }),\n};\n\nconst inferredPlaceholderPredicate: Predicate = {\n ...placeholderPredicate,\n applies: (t) => Boolean(inferredPlaceholderValue(t)),\n match: (t, c) => {\n const tp = inferredPlaceholderValue(t);\n const cp = inferredPlaceholderValue(c);\n return Boolean(tp) && tp === cp;\n },\n};\n\n/**\n * Anchor an `img` role on a substring of its `src` attribute. Last-resort\n * before role+containsText for unlabeled clickable images: the agent saw the\n * image's filename-derived label in render, but the substrate only carries\n * the raw `src`. We emit `img[src*=\"<filename>\"]` so the locator still\n * grounds on a DOM-verifiable signal rather than tree-position.\n */\nconst imgSrcPredicate: Predicate = {\n name: 'imgSrc',\n field: 'src',\n applies: (t) => t.el.role === 'img' && Boolean(srcCssSegment(t.el.attributes['src'])),\n match: (t, c) => {\n if (c.el.role !== 'img') return false;\n const ts = srcCssSegment(t.el.attributes['src']);\n const cs = srcCssSegment(c.el.attributes['src']);\n return Boolean(ts) && ts === cs;\n },\n toStrategy: (t) => {\n const seg = srcCssSegment(t.el.attributes['src']) ?? '';\n return {\n role: { role: 'img' },\n css: roleScopedCss('img', `[src*=\"${seg}\"]`),\n };\n },\n};\n\n/**\n * Anchor a grid cell on its `data-field` token (e.g. a MUI DataGrid editable\n * cell's `house_rate::GroupA`). A `data-field` is unique within a row but\n * repeats across rows, so this predicate is never globally unique — it relies\n * on the ladder's ancestor/row-variable scoping to bind it to a specific row.\n * That keeps it a stable, DOM-verifiable, NON-ordinal anchor: the right fix for\n * nameless editable cells the agent would otherwise only reach by coordinates.\n */\nconst dataFieldPredicate: Predicate = {\n name: 'dataField',\n field: 'data-field',\n applies: (t) => Boolean(t.el.dataField),\n match: (t, c) => Boolean(t.el.dataField) && c.el.dataField === t.el.dataField,\n // No bare `role` (a gridcell role is non-unique and the resolver tries role\n // before css). The `[data-field=…]` css IS the anchor; it resolves scoped\n // under the parentContext (row id / row-variable) the ladder attaches.\n toStrategy: (t) => ({\n css: roleScopedCss(t.el.role, `[data-field=\"${cssAttrEscape(t.el.dataField ?? '')}\"]`),\n }),\n};\n\nfunction cssAttrEscape(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n\n/**\n * Stable id selectors for an element, from intentional entity-id attributes\n * only (`data-id`, `data-testid`). Generic `id` is deliberately excluded — it's\n * too often framework-generated (`mui-…`, React `:r3:`) to trust as an anchor.\n * Stability is decided by the canonical `stableAttrSelector` in `@chatsdet/types`\n * (a seeded entity number/id yields a `^prefix` or nothing, never an exact id).\n */\nfunction elementStableIdSelectors(el: NormalizedNode['el']): string[] {\n const out: string[] = [];\n const dataId = el.cssHints?.dataId;\n const fromDataId = dataId ? stableAttrSelector('data-id', dataId) : null;\n if (fromDataId) out.push(fromDataId);\n for (const tid of el.cssHints?.testIds ?? []) {\n const s = stableAttrSelector('data-testid', tid);\n if (s) out.push(s);\n }\n return out;\n}\n\n/**\n * Count nodes that the stable-id `selector` would actually MATCH (cap at 2) —\n * by attribute semantics, not classified-string equality. A prefix selector\n * `[data-id^=\"__new__\"]` matches `__new__template` too, even though that sibling\n * classifies to an exact selector; counting by `includes(selector)` would miss\n * it and wrongly mark the ancestor unique.\n */\nfunction countNodesMatchingStableSelector(flat: NormalizedNode[], selector: string): number {\n const m = /^\\[(data-id|data-testid)(\\^?)=\"(.*)\"\\]$/.exec(selector);\n if (!m) return 0;\n const [, attr, op, escaped] = m;\n // Reverse `cssAttrEscape` (escape order was `\\` then `\"`).\n const value = escaped.replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, '\\\\');\n const valuesOf = (el: NormalizedNode['el']): string[] =>\n attr === 'data-id'\n ? el.cssHints?.dataId\n ? [el.cssHints.dataId]\n : []\n : (el.cssHints?.testIds ?? []);\n\n let n = 0;\n for (const node of flat) {\n const vals = valuesOf(node.el);\n const hit =\n op === '^' ? vals.some((v) => v.startsWith(value)) : vals.some((v) => v === value);\n if (hit) {\n n++;\n if (n > 1) break;\n }\n }\n return n;\n}\n\n/**\n * The ancestor's globally-unique stable-id selector (`[data-id^=\"__new__\"]`,\n * `[data-testid=\"settings-panel\"]`, …), or null. This is how the per-predicate\n * `+ancestor` scope identifies a nameless ancestor by its durable entity id —\n * a structural, NON-ordinal anchor (`__new__` draft row, a hard-coded test-id\n * panel) — emitted as `parentContext.css` so the resolver scopes the target\n * (role or css) under it. Seeded ids reduce to a non-unique prefix and are\n * rejected here.\n */\nfunction uniqueStableIdSelector(anchor: NormalizedNode, flat: NormalizedNode[]): string | null {\n for (const selector of elementStableIdSelectors(anchor.el)) {\n if (countNodesMatchingStableSelector(flat, selector) === 1) return selector;\n }\n return null;\n}\n\nconst roleContainsTextPredicate: Predicate = {\n name: 'role+containsText',\n field: 'text',\n applies: (t) => {\n if (!t.el.role) return false;\n if (t.textTemplate ?? t.el.text) return false;\n return collectChildrenTexts(t.el).length > 0;\n },\n // Exact-set equality (sorted) — a candidate that's a strict superset of\n // the target's child texts must NOT match, otherwise uniqueness collapses.\n match: (t, c) => {\n if (c.el.role !== t.el.role) return false;\n const targetTexts = collectChildrenTexts(t.el).slice().sort();\n const candidateTexts = collectChildrenTexts(c.el).slice().sort();\n if (targetTexts.length !== candidateTexts.length) return false;\n return targetTexts.every((tx, i) => tx === candidateTexts[i]);\n },\n toStrategy: (t) => {\n const containsText = collectChildrenTexts(t.el).slice(0, 3);\n return {\n role: { role: t.el.role },\n containsText,\n };\n },\n};\n\n// testId is checked separately by `pickUniqueTestId` before this ladder runs.\n// Same for iconClass and semanticClass (pre-ladder pickers).\nconst PREDICATES: ReadonlyArray<Predicate> = [\n inferredPlaceholderPredicate,\n rolePlusNamePredicate,\n ariaLabelPredicate,\n placeholderPredicate,\n imgSrcPredicate,\n dataFieldPredicate,\n roleContainsTextPredicate,\n];\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface FlattenResult {\n flat: NormalizedNode[];\n byRef: Map<string, NormalizedNode>;\n}\n\nfunction flatten(roots: SnapshotElement[]): FlattenResult {\n const flat: NormalizedNode[] = [];\n const byRef = new Map<string, NormalizedNode>();\n function walk(el: SnapshotElement, parent: NormalizedNode | null): NormalizedNode {\n const node: NormalizedNode = {\n el,\n bindings: [],\n parent,\n descendantRefs: new Set(),\n };\n flat.push(node);\n if (el.ref) byRef.set(el.ref, node);\n for (const child of el.children) {\n const childNode = walk(child, node);\n // Bubble the child's descendant set up.\n node.descendantRefs.add(childNode.el.ref);\n for (const r of childNode.descendantRefs) node.descendantRefs.add(r);\n }\n return node;\n }\n for (const root of roots) walk(root, null);\n return { flat, byRef };\n}\n\nfunction ancestorChain(node: NormalizedNode): NormalizedNode[] {\n const chain: NormalizedNode[] = [];\n let cur = node.parent;\n while (cur) {\n chain.push(cur);\n cur = cur.parent;\n }\n // We want innermost-last (so closest-first iteration is i = length-1 → 0)\n // but the walk above produces innermost-first; reverse it for that contract.\n return chain.reverse();\n}\n\n/** Count predicate matches across the whole flat list, short-circuiting at 2. */\nfunction uniquenessMatches(\n flat: NormalizedNode[],\n target: NormalizedNode,\n p: Predicate\n): number {\n let count = 0;\n for (const n of flat) {\n if (p.match(target, n)) {\n count++;\n if (count > 1) return count;\n }\n }\n return count;\n}\n\n/**\n * Count predicate matches inside `anchor`'s subtree, short-circuiting at 2.\n * Uses the `descendantRefs` set computed during flatten so we don't re-walk.\n */\nfunction uniquenessMatchesScoped(\n flat: NormalizedNode[],\n target: NormalizedNode,\n p: Predicate,\n anchor: NormalizedNode\n): number {\n let count = 0;\n for (const n of flat) {\n if (n === anchor) continue;\n if (!anchor.descendantRefs.has(n.el.ref)) continue;\n if (p.match(target, n)) {\n count++;\n if (count > 1) return count;\n }\n }\n return count;\n}\n\ninterface IdentityIndex {\n /** `${role}|${templatedName}` → count. */\n byRoleName: Map<string, number>;\n /** `${role}|${first durable child text}` → count for nameless containers. */\n byRoleChildText: Map<string, number>;\n /** templated aria-label → count. */\n byAriaLabel: Map<string, number>;\n}\n\nfunction buildIdentityIndex(flat: NormalizedNode[]): IdentityIndex {\n const byRoleName = new Map<string, number>();\n const byRoleChildText = new Map<string, number>();\n const byAriaLabel = new Map<string, number>();\n for (const n of flat) {\n const name = n.textTemplate ?? n.el.text;\n if (n.el.role && name) {\n const k = `${n.el.role}|${name}`;\n byRoleName.set(k, (byRoleName.get(k) ?? 0) + 1);\n }\n const childText = n.el.role && !name ? firstDurableAncestorChildText(n.el) : null;\n if (n.el.role && childText) {\n const k = `${n.el.role}|${childText}`;\n byRoleChildText.set(k, (byRoleChildText.get(k) ?? 0) + 1);\n }\n const ariaLabel = n.ariaLabelTemplate ?? n.el.attributes['aria-label'];\n if (ariaLabel) {\n byAriaLabel.set(ariaLabel, (byAriaLabel.get(ariaLabel) ?? 0) + 1);\n }\n }\n return { byRoleName, byRoleChildText, byAriaLabel };\n}\n\n/**\n * An ancestor is identifiable when its (role, templated name) pair is unique\n * across the snapshot, when it carries a testId, or when its aria-label is\n * unique. Without identifiability, the parentContext we build from it would\n * itself be ambiguous, defeating the disambiguation step.\n */\nfunction isAncestorIdentifiable(\n anchor: NormalizedNode,\n idx: IdentityIndex,\n target: NormalizedNode\n): boolean {\n // NOTE: stable id/test-id identification is handled by the caller via\n // `uniqueStableIdSelector` (which also enforces global uniqueness and emits\n // the id as `parentContext.css`). This function only covers role+name / child\n // text / aria-label identification.\n const role = anchor.el.role;\n if (role) {\n const name = anchor.textTemplate ?? anchor.el.text;\n if (name && idx.byRoleName.get(`${role}|${name}`) === 1) return true;\n const childText = !name ? firstDurableAncestorChildText(anchor.el) : null;\n const targetText = target.textTemplate ?? target.el.text;\n if (\n childText &&\n childText !== targetText &&\n idx.byRoleChildText.get(`${role}|${childText}`) === 1\n ) {\n return true;\n }\n }\n const ariaLabel = anchor.ariaLabelTemplate ?? anchor.el.attributes['aria-label'];\n if (ariaLabel && idx.byAriaLabel.get(ariaLabel) === 1) return true;\n return false;\n}\n\nfunction collectChildrenTexts(el: SnapshotElement): string[] {\n const texts: string[] = [];\n function walk(e: SnapshotElement) {\n if (e.text) texts.push(e.text);\n if (e.inputValue) texts.push(e.inputValue);\n for (const c of e.children) walk(c);\n }\n for (const c of el.children) walk(c);\n return texts;\n}\n\nfunction collectTargetVisibleTexts(target: NormalizedNode): string[] {\n const ownText = target.textTemplate ?? target.el.text;\n if (ownText) return [ownText];\n if (target.el.inputValue) return [target.el.inputValue];\n return collectChildrenTexts(target.el);\n}\n\nfunction firstDurableAncestorChildText(el: SnapshotElement): string | null {\n return collectChildrenTexts(el).find(isDurableAncestorChildText) ?? null;\n}\n\nfunction isDurableAncestorChildText(text: string): boolean {\n const trimmed = text.trim();\n // Keep this intentionally narrow; arbitrary row/card text is often data,\n // not a stable structural label for ancestor scoping.\n return /^(Section|Step)\\s+\\d+\\s*:/i.test(trimmed);\n}\n\nfunction collectVolatileTestIdTextParts(target: NormalizedNode): string[] {\n const ownText = target.textTemplate ?? target.el.text;\n if (ownText) return [ownText];\n if (target.el.inputValue) return [target.el.inputValue];\n\n const childTexts = collectChildrenTexts(target.el);\n const durableChildTexts = childTexts.filter(isDurableVolatileTestIdChildText);\n return (durableChildTexts.length > 0 ? durableChildTexts : childTexts).slice(0, 3);\n}\n\nfunction isDurableVolatileTestIdChildText(text: string): boolean {\n return text.trim().length > 1;\n}\n\ninterface RowVariableScope {\n anchor: NormalizedNode;\n innerAncestors: NormalizedNode[];\n key: string;\n value: string;\n}\n\nfunction findRowVariableScope(args: {\n flat: NormalizedNode[];\n target: NormalizedNode;\n predicate: Predicate;\n ancestors: NormalizedNode[];\n variableValues: Record<string, string>;\n}): RowVariableScope | null {\n const entries = Object.entries(args.variableValues)\n .filter(([, value]) => typeof value === 'string' && value.length >= MIN_TEMPLATING_LENGTH)\n .sort((a, b) => b[1].length - a[1].length);\n if (entries.length === 0) return null;\n\n for (let i = args.ancestors.length - 1; i >= 0; i--) {\n const anchor = args.ancestors[i];\n if (!REPEATING_ANCESTOR_ROLES.has(anchor.el.role)) continue;\n if (uniquenessMatchesScoped(args.flat, args.target, args.predicate, anchor) !== 1) {\n continue;\n }\n\n const anchorText = collectSubtreeText(anchor.el);\n for (const [key, value] of entries) {\n if (!textContainsValue(anchorText, value)) continue;\n return {\n anchor,\n innerAncestors: args.ancestors.slice(i + 1),\n key,\n value,\n };\n }\n }\n\n return null;\n}\n\nfunction collectSubtreeText(el: SnapshotElement): string {\n const parts: string[] = [];\n function walk(node: SnapshotElement) {\n if (node.text) parts.push(node.text);\n if (node.inputValue) parts.push(node.inputValue);\n const ariaLabel = node.attributes['aria-label'];\n if (ariaLabel) parts.push(ariaLabel);\n for (const child of node.children) walk(child);\n }\n walk(el);\n return parts.join(' ');\n}\n\nfunction textContainsValue(text: string, value: string): boolean {\n const pattern = new RegExp(`(^|\\\\W)${escapeRegex(value)}(?=\\\\W|$)`);\n return pattern.test(text);\n}\n\nfunction frameContextFor(el: SnapshotElement): FrameContext | undefined {\n const sel = el.frameSelector;\n if (!sel) return undefined;\n return { type: 'iframe', selector: sel };\n}\n\n/**\n * Build a `parentContext` rooted at `anchor` and including any intermediate\n * ancestors between `anchor` and the target. The `parentChain` is innermost-\n * to-outermost per the {@link ParentContext} contract.\n */\nfunction parentContextFor(\n anchor: NormalizedNode,\n inner: NormalizedNode[],\n override?: {\n containsText?: string;\n containsTextDynamic?: ParentContextDynamicText;\n }\n): ParentContext {\n const ctx: ParentContext = { role: anchor.el.role };\n const anchorName = override?.containsText ? undefined : anchor.textTemplate ?? anchor.el.text;\n if (anchorName) ctx.name = anchorName;\n if (override?.containsText) {\n ctx.containsText = override.containsText;\n if (override.containsTextDynamic) {\n ctx.containsTextDynamic = override.containsTextDynamic;\n }\n } else if (!anchorName) {\n const childTexts = collectChildrenTexts(anchor.el);\n if (childTexts.length > 0) ctx.containsText = childTexts[0];\n }\n if (inner.length > 0) {\n // Innermost-to-outermost.\n // Row-variable scopes intentionally stop at the row. Resolving\n // `row.filter({ hasText }).locator(button)` is more reliable than adding\n // intermediate cells, which often duplicate the action button's name.\n if (!override?.containsText) {\n ctx.parentChain = inner\n .slice()\n .reverse()\n .map((n) => {\n const node: ParentContextNode = { role: n.el.role };\n const name = n.textTemplate ?? n.el.text;\n if (name) node.name = name;\n return node;\n });\n }\n }\n return ctx;\n}\n\nfunction indexedFallback(target: NormalizedNode): SelectorStrategy {\n // `siblingRoleIndex` is intentionally NOT mapped to `SelectorStrategy.itemIndex`\n // — that field is documented as a DOM `data-item-index` value and replay\n // will probe it as such. The selector-agent (or step-6 logging) handles\n // ambiguous fallbacks via the `irreducible` flag.\n const role: RoleSelector = { role: target.el.role };\n const name = target.textTemplate ?? target.el.text;\n if (name) role.name = name;\n return { role };\n}\n\nfunction applyContexts(\n base: SelectorStrategy,\n frame: FrameContext | undefined,\n dynamic: SelectorStrategy['dynamicText']\n): SelectorStrategy {\n const out: SelectorStrategy = { ...base };\n if (frame) out.frameContext = frame;\n if (dynamic) out.dynamicText = dynamic;\n return out;\n}\n\nfunction buildDynamicText(target: NormalizedNode): SelectorStrategy['dynamicText'] {\n // Surface a dynamicText hint when the target's accessible name was rewritten.\n // When multiple bindings touched the text, pick the one with the longest\n // value (most-specific) so legacy replay paths get the strongest hint.\n const textBindings = target.bindings.filter((b) => b.field === 'text');\n if (textBindings.length === 0) return undefined;\n const original = target.el.text;\n if (!original) return undefined;\n const chosen = textBindings.slice().sort((a, b) => b.value.length - a.value.length)[0];\n return {\n source: 'workflowState',\n key: chosen.key,\n originalText: original,\n };\n}\n","/**\n * Snapshot Parser\n *\n * Parses Playwright's accessibility snapshot YAML-like format to extract\n * element information for stable selector derivation.\n *\n * The snapshot format from Playwright's `ariaSnapshot({ mode: 'ai' })` looks like:\n * ```yaml\n * - navigation \"Main\":\n * - link \"Home\" [ref=e1]\n * - link \"About\" [ref=e2]\n * - main:\n * - heading \"Welcome\" [level=1] [ref=e3]\n * - paragraph:\n * - text \"Hello world\"\n * - button \"Submit\" [ref=e4]\n * ```\n */\n\nimport type { ElementInfo, FrameContext } from '@chatsdet/types';\n\n/**\n * Line parsed from the snapshot YAML.\n */\nexport interface ParsedLine {\n indent: number;\n role: string;\n name?: string;\n ref?: string;\n centerX?: number;\n centerY?: number;\n attributes: Record<string, string>;\n text?: string;\n}\n\n/**\n * Parse a single line from the snapshot.\n */\nfunction parseLine(line: string): ParsedLine | null {\n if (!line.trim()) return null;\n\n // Calculate indent (2 spaces per level)\n const indent = line.search(/\\S/);\n const content = line.trim();\n\n // Skip empty or dash-only lines\n if (!content || content === '-') return null;\n\n // Remove leading dash if present\n let cleanContent = content.startsWith('- ') ? content.slice(2) : content;\n if (!cleanContent) return null;\n\n // Strip YAML single-quote wrapping. When element text contains colons\n // (e.g. \"Rows per page: 25\"), YAML serializes the element key as:\n // 'combobox \"Rows per page: 25\" [ref=e542]': \"25\"\n // Unwrap only the quoted key and preserve any trailing input value.\n if (cleanContent.startsWith(\"'\")) {\n const quotedKeyEnd = cleanContent.indexOf(\"':\");\n if (quotedKeyEnd !== -1) {\n cleanContent = cleanContent.slice(1, quotedKeyEnd) + cleanContent.slice(quotedKeyEnd + 1);\n } else if (cleanContent.endsWith(\"'\")) {\n cleanContent = cleanContent.slice(1, -1);\n }\n }\n\n // Extract ref and optional center coordinates: [ref=e1] or [ref=e1 center=450,320]\n const refMatch = cleanContent.match(/\\[ref=(\\w+)(?:\\s+center=(\\d+),(\\d+))?\\]/);\n const ref = refMatch?.[1];\n const centerX = refMatch?.[2] ? parseInt(refMatch[2], 10) : undefined;\n const centerY = refMatch?.[3] ? parseInt(refMatch[3], 10) : undefined;\n\n // Remove all bracket attributes for cleaner parsing\n const withoutBrackets = cleanContent.replace(/\\s*\\[[^\\]]+\\]/g, '').trim();\n\n // Handle sub-property lines like `/placeholder: Enter name`\n if (cleanContent.startsWith('/')) {\n const colonIdx = cleanContent.indexOf(':');\n if (colonIdx !== -1) {\n const key = cleanContent.slice(1, colonIdx).trim();\n const value = cleanContent.slice(colonIdx + 1).trim();\n return { indent, role: '_property', attributes: { [key]: value } };\n }\n }\n\n // Handle text content lines (no role, just text)\n if (withoutBrackets.startsWith('\"') && withoutBrackets.endsWith('\"')) {\n return {\n indent,\n role: 'text',\n text: withoutBrackets.slice(1, -1),\n attributes: {},\n };\n }\n\n // Parse role and optional name: `button \"Submit\"` or `button:`\n // Also handles `text \"content\"` format and inline text after colon: `button \"X\": Click me`\n const roleNameMatch = withoutBrackets.match(/^(\\w+)(?:\\s+\"([^\"]+)\")?(?::(?:\\s+(.+))?)?$/);\n if (!roleNameMatch) {\n // Might be a plain text node or malformed line\n return {\n indent,\n role: 'generic',\n text: withoutBrackets,\n attributes: {},\n };\n }\n\n const role = roleNameMatch[1];\n const name = roleNameMatch[2];\n const inlineText = roleNameMatch[3];\n\n // Extract other attributes\n const attributes: Record<string, string> = {};\n const attrMatches = cleanContent.matchAll(/\\[(\\w+)=([^\\]]+)\\]/g);\n for (const match of attrMatches) {\n const [, key, value] = match;\n if (key !== 'ref') {\n attributes[key] = value;\n }\n }\n\n return {\n indent,\n role,\n name,\n ref,\n centerX,\n centerY,\n attributes,\n text: inlineText,\n };\n}\n\n/**\n * Collect sub-property lines (e.g. `/placeholder: ...`) from children of an element.\n */\nfunction collectSubProperties(\n elementIndex: number,\n allParsed: ParsedLine[],\n elementIndent: number\n): Record<string, string> {\n const props: Record<string, string> = {};\n for (let i = elementIndex + 1; i < allParsed.length; i++) {\n if (allParsed[i].indent <= elementIndent) break;\n if (allParsed[i].role === '_property') {\n Object.assign(props, allParsed[i].attributes);\n }\n }\n return props;\n}\n\n/** Roles where child headings typically name the container */\nconst UNIQUE_ROLES = ['dialog', 'alertdialog', 'form', 'article', 'region'];\n\n/**\n * Select the best parent for disambiguation.\n * Prefers unique roles (dialog) and named elements over unnamed ones.\n *\n * @param parentStack - Stack of parent elements from root to closest\n * @returns The best parent for disambiguation, or undefined if none suitable\n */\nfunction selectBestParent(parentStack: ParsedLine[]): ParsedLine | undefined {\n const reversed = [...parentStack].reverse();\n\n // First: prefer unique roles WITH names (most specific)\n for (const p of reversed) {\n if (UNIQUE_ROLES.includes(p.role) && p.name) {\n return p;\n }\n }\n\n // Second: prefer any named parent (more specific than unnamed)\n for (const p of reversed) {\n if (p.name && p.role !== 'generic' && p.role !== 'paragraph' && p.role !== 'text') {\n return p;\n }\n }\n\n // Third: prefer unique roles even without names\n for (const p of reversed) {\n if (UNIQUE_ROLES.includes(p.role)) {\n return p;\n }\n }\n\n // Last resort: any non-generic parent\n return reversed.find((p) => p.role !== 'generic' && p.role !== 'paragraph' && p.role !== 'text');\n}\n\n/**\n * Enrich an unnamed element with text from its direct child paragraph or heading.\n *\n * When an element (e.g. an `article`) has no `accessibleName` and no inline\n * `text`, scans immediate children (indent = parent indent + 2) for `paragraph`\n * or `heading` elements with a `name` or `text` property. Returns the first\n * match so it can be used as `textContent` for selector derivation.\n */\nfunction enrichElementWithChildText(\n elementIndex: number,\n allParsed: ParsedLine[],\n elementIndent: number\n): string | undefined {\n for (let i = elementIndex + 1; i < allParsed.length; i++) {\n const child = allParsed[i];\n // Exited the element's scope\n if (child.indent <= elementIndent) break;\n // Only consider direct children (one level deeper)\n if (child.indent !== elementIndent + 2) continue;\n if ((child.role === 'paragraph' || child.role === 'heading') && (child.name || child.text)) {\n return child.name || child.text;\n }\n }\n return undefined;\n}\n\n/**\n * Enrich an unnamed container parent with a child heading's name.\n *\n * When selectBestParent picks a UNIQUE_ROLE parent (article, region, form, dialog)\n * that has no accessible name of its own, scans child lines within that parent's\n * indentation scope for a heading element and uses the first heading's name.\n *\n * @param parent - The selected parent ParsedLine (must have no name)\n * @param parentLineIndex - Index of the parent in allLines\n * @param allLines - All parsed lines in the snapshot\n * @returns The heading name and flag, or undefined if no heading found\n */\nfunction enrichParentWithChildHeading(\n parent: ParsedLine,\n parentLineIndex: number,\n allLines: ParsedLine[]\n): { name: string; nameFromHeading: true } | undefined {\n // Only enrich unnamed UNIQUE_ROLE parents\n if (parent.name || !UNIQUE_ROLES.includes(parent.role)) {\n return undefined;\n }\n\n // Scan child lines (deeper indentation) within this parent's scope\n for (let i = parentLineIndex + 1; i < allLines.length; i++) {\n const child = allLines[i];\n // If we've exited the parent's scope (same or lower indent), stop\n if (child.indent <= parent.indent) break;\n // Look for a heading with a name\n if (child.role === 'heading' && child.name) {\n return { name: child.name, nameFromHeading: true };\n }\n }\n\n return undefined;\n}\n\n/**\n * Scan direct children of an element for an `img` role with a name (alt text).\n * Returns the first child img name found, or undefined.\n *\n * In the snapshot, img children appear as:\n * - img \"Alt text\" [ref=eN]\n * at indent = elementIndent + 2 (direct children).\n */\nfunction findChildImgAlt(\n elementIndex: number,\n allParsed: ParsedLine[],\n elementIndent: number\n): string | undefined {\n for (let i = elementIndex + 1; i < allParsed.length; i++) {\n const child = allParsed[i];\n // Exited the element's scope\n if (child.indent <= elementIndent) break;\n // Only consider direct children (one level deeper)\n if (child.indent !== elementIndent + 2) continue;\n if (child.role === 'img' && child.name) {\n return child.name;\n }\n }\n return undefined;\n}\n\n/**\n * Detect if a target element is inside an iframe ancestor.\n *\n * Walks the parent stack to find the nearest `iframe` role. Since the snapshot\n * YAML doesn't include CSS class/id information for iframes, we build a\n * convention-based selector:\n * - If the iframe has a `name` attribute → `iframe[name=\"...\"]`\n * - If only one iframe exists in the entire snapshot → `iframe`\n * - Otherwise → `iframe` (best effort; DOM metadata enrichment may refine this)\n *\n * @param parentStack - Parent elements from root to closest ancestor\n * @param totalIframeCount - Total number of iframe nodes in the full snapshot\n * @returns FrameContext if inside an iframe, undefined otherwise\n */\nfunction detectIframeAncestor(\n parentStack: Array<{ line: ParsedLine; allParsedIndex: number }>,\n _totalIframeCount: number\n): FrameContext | undefined {\n // Walk from closest ancestor outward to find the nearest iframe\n for (let i = parentStack.length - 1; i >= 0; i--) {\n const parent = parentStack[i].line;\n if (parent.role === 'iframe') {\n let selector = 'iframe';\n\n // Use name attribute if available for specificity\n if (parent.name) {\n selector = `iframe[name=\"${parent.name}\"]`;\n } else if (parent.attributes['name']) {\n selector = `iframe[name=\"${parent.attributes['name']}\"]`;\n }\n // When there's only one iframe, bare `iframe` is sufficient\n\n return {\n type: 'iframe',\n selector,\n name: parent.name ?? parent.attributes['name'],\n };\n }\n }\n return undefined;\n}\n\n/**\n * Count the total number of iframe elements in parsed lines.\n */\nfunction countIframes(allParsed: ParsedLine[]): number {\n let count = 0;\n for (const line of allParsed) {\n if (line.role === 'iframe') count++;\n }\n return count;\n}\n\n/**\n * Build an ElementInfo from an AncestorChainResult.\n *\n * Applies all enrichment steps: iframe detection, parent selection,\n * heading enrichment, child text/img enrichment, and sub-property collection.\n */\nfunction ancestorChainToElementInfo(result: AncestorChainResult): ElementInfo {\n const { element, elementIndex, ancestors, allParsed, subProperties } = result;\n\n // Detect iframe ancestor for frameContext\n const parentStack = ancestors.map((a) => ({ line: a.line, allParsedIndex: a.index }));\n const totalIframeCount = countIframes(allParsed);\n const frameContext = detectIframeAncestor(parentStack, totalIframeCount);\n\n // Find the most relevant parent using smart selection\n const relevantParent = selectBestParent(ancestors.map((a) => a.line));\n\n // Enrich unnamed container parents with child heading name\n let parentName = relevantParent?.name;\n let parentNameFromHeading: boolean | undefined;\n\n if (relevantParent && !relevantParent.name) {\n const ancestorEntry = ancestors.find((a) => a.line === relevantParent);\n if (ancestorEntry) {\n const headingInfo = enrichParentWithChildHeading(\n relevantParent,\n ancestorEntry.index,\n allParsed\n );\n if (headingInfo) {\n parentName = headingInfo.name;\n parentNameFromHeading = headingInfo.nameFromHeading;\n }\n }\n }\n\n // Enrich unnamed elements with child text content\n let textContent = element.text ?? element.name;\n if (!textContent && !element.name) {\n textContent = enrichElementWithChildText(elementIndex, allParsed, element.indent);\n }\n\n // Find child img alt text for disambiguation of generic containers\n const childImgAlt = findChildImgAlt(elementIndex, allParsed, element.indent);\n\n return {\n ref: element.ref!,\n role: element.role,\n accessibleName: element.name,\n textContent,\n ariaLabel: element.attributes['aria-label'],\n placeholder: subProperties['placeholder'],\n parentRole: relevantParent?.role,\n parentName,\n parentNameFromHeading,\n centerX: element.centerX,\n centerY: element.centerY,\n childImgAlt,\n frameContext,\n };\n}\n\n/**\n * Find element info by ref in the snapshot.\n *\n * Walks through the snapshot lines to find the element with the given ref,\n * also collecting parent context for disambiguation.\n *\n * @param snapshotYaml - The YAML-like snapshot string\n * @param targetRef - The ref to find (e.g., 'e1', 'e5')\n * @returns Element info if found, null otherwise\n */\nexport function findElementByRef(snapshotYaml: string, targetRef: string): ElementInfo | null {\n const result = findElementWithAncestors(snapshotYaml, targetRef);\n if (!result) return null;\n return ancestorChainToElementInfo(result);\n}\n\n/**\n * Result of finding an element with its full ancestor chain.\n * Used by the deterministic locator builder to construct compositional\n * locator chains with scoping (dialog, row, container).\n */\nexport interface AncestorEntry {\n line: ParsedLine;\n index: number;\n}\n\nexport interface AncestorChainResult {\n /** The target element */\n element: ParsedLine;\n /** Index of the target in allParsed */\n elementIndex: number;\n /** Ancestors from root to closest parent (does not include target), with indices */\n ancestors: AncestorEntry[];\n /** All parsed lines from the snapshot */\n allParsed: ParsedLine[];\n /** Sub-properties collected from target's children (e.g. placeholder) */\n subProperties: Record<string, string>;\n}\n\n/**\n * Find an element by ref and return it with its full ancestor chain.\n *\n * Unlike findElementByRef() which returns a flattened ElementInfo with\n * only the \"best\" parent, this returns the complete ancestor stack so\n * callers can analyze the full hierarchy for scoping decisions.\n *\n * @param snapshotYaml - The YAML-like snapshot string\n * @param targetRef - The ref to find (e.g., 'e1', 'e5')\n * @returns Ancestor chain result, or null if ref not found\n */\nexport function findElementWithAncestors(\n snapshotYaml: string,\n targetRef: string\n): AncestorChainResult | null {\n const rawLines = snapshotYaml.split('\\n');\n\n const allParsed: ParsedLine[] = [];\n for (const line of rawLines) {\n const parsed = parseLine(line);\n if (parsed) allParsed.push(parsed);\n }\n\n const parentStack: Array<{ line: ParsedLine; allParsedIndex: number }> = [];\n let targetElement: ParsedLine | null = null;\n let targetIdx = -1;\n\n for (let idx = 0; idx < allParsed.length; idx++) {\n const parsed = allParsed[idx];\n\n while (\n parentStack.length > 0 &&\n parentStack[parentStack.length - 1].line.indent >= parsed.indent\n ) {\n parentStack.pop();\n }\n\n if (parsed.ref === targetRef) {\n targetElement = parsed;\n targetIdx = idx;\n break;\n }\n\n if (parsed.role !== 'text') {\n parentStack.push({ line: parsed, allParsedIndex: idx });\n }\n }\n\n if (!targetElement) {\n return null;\n }\n\n const subProperties = collectSubProperties(targetIdx, allParsed, targetElement.indent);\n\n return {\n element: targetElement,\n elementIndex: targetIdx,\n ancestors: parentStack.map((p) => ({ line: p.line, index: p.allParsedIndex })),\n allParsed,\n subProperties,\n };\n}\n\n/**\n * Extract all elements with refs from the snapshot.\n * Useful for debugging and testing.\n *\n * @param snapshotYaml - The YAML-like snapshot string\n * @returns Array of element info for all elements with refs\n */\nexport function extractAllElements(snapshotYaml: string): ElementInfo[] {\n const rawLines = snapshotYaml.split('\\n');\n\n const allParsed: ParsedLine[] = [];\n for (const line of rawLines) {\n const parsed = parseLine(line);\n if (parsed) allParsed.push(parsed);\n }\n\n const parentStack: Array<{ line: ParsedLine; allParsedIndex: number }> = [];\n const elements: ElementInfo[] = [];\n\n for (let idx = 0; idx < allParsed.length; idx++) {\n const parsed = allParsed[idx];\n\n while (\n parentStack.length > 0 &&\n parentStack[parentStack.length - 1].line.indent >= parsed.indent\n ) {\n parentStack.pop();\n }\n\n if (parsed.ref) {\n const subProperties = collectSubProperties(idx, allParsed, parsed.indent);\n elements.push(\n ancestorChainToElementInfo({\n element: parsed,\n elementIndex: idx,\n ancestors: parentStack.map((p) => ({ line: p.line, index: p.allParsedIndex })),\n allParsed,\n subProperties,\n })\n );\n }\n\n if (parsed.role !== 'text') {\n parentStack.push({ line: parsed, allParsedIndex: idx });\n }\n }\n\n return elements;\n}\n\n/**\n * Known ARIA roles used to split description strings into (name, role) pairs.\n * Ordered by specificity (longer roles first to avoid partial matches).\n */\nconst KNOWN_ROLES = [\n 'progressbar',\n 'scrollbar',\n 'separator',\n 'alertdialog',\n 'navigation',\n 'application',\n 'radiogroup',\n 'tabpanel',\n 'textbox',\n 'combobox',\n 'checkbox',\n 'treeitem',\n 'menuitem',\n 'listitem',\n 'toolbar',\n 'tooltip',\n 'heading',\n 'spinbutton',\n 'article',\n 'button',\n 'dialog',\n 'figure',\n 'banner',\n 'region',\n 'search',\n 'status',\n 'switch',\n 'slider',\n 'option',\n 'select',\n 'meter',\n 'radio',\n 'table',\n 'timer',\n 'group',\n 'alert',\n 'grid',\n 'form',\n 'cell',\n 'link',\n 'list',\n 'menu',\n 'note',\n 'main',\n 'tree',\n 'tab',\n 'row',\n 'img',\n 'log',\n];\n\n/**\n * Parse an element description into a (name, role) pair.\n *\n * Supports two patterns:\n * - `\"<name> <role>\"` — e.g., `\"Customer No. combobox\"` → name=`\"Customer No.\"`, role=`\"combobox\"`\n * - `\"<role> <name>\"` — e.g., `\"button Save\"` → name=`\"Save\"`, role=`\"button\"`\n *\n * @returns { name, role } if a known role was found, or { name: description } with no role\n */\nfunction parseDescription(description: string): { name: string; role?: string } {\n const trimmed = description.trim();\n if (!trimmed) return { name: '' };\n\n const lower = trimmed.toLowerCase();\n\n // Try suffix match: \"<name> <role>\" (most common: \"Customer No. combobox\")\n for (const role of KNOWN_ROLES) {\n if (lower.endsWith(' ' + role)) {\n const name = trimmed.slice(0, -(role.length + 1)).trim();\n if (name) return { name, role };\n }\n }\n\n // Try prefix match: \"<role> <name>\" (e.g., \"button Save\")\n for (const role of KNOWN_ROLES) {\n if (lower.startsWith(role + ' ')) {\n const name = trimmed.slice(role.length + 1).trim();\n if (name) return { name, role };\n }\n }\n\n // No role extracted — treat entire string as the name\n return { name: trimmed };\n}\n\n/**\n * Find an element in the snapshot matching a text description.\n *\n * Used when the agent clicks by description only (no ref, no coordinates).\n * Searches all elements with refs and scores them by how well they match\n * the description's role and name.\n *\n * Returns the best match **only if it is unique** at the highest score.\n * Returns `null` if no match, ambiguous (multiple matches at same score),\n * or the description is empty.\n *\n * @param snapshotYaml - The YAML-like snapshot string\n * @param description - Element description like \"Customer No. combobox\"\n * @returns Element info if a unique match is found, null otherwise\n */\nexport function findElementByDescription(\n snapshotYaml: string,\n description: string\n): ElementInfo | null {\n if (!description?.trim()) return null;\n\n const { name, role } = parseDescription(description);\n if (!name) return null;\n\n const elements = extractAllElements(snapshotYaml);\n if (elements.length === 0) return null;\n\n const nameLower = name.toLowerCase();\n\n // Score each element\n const scored: Array<{ element: ElementInfo; score: number }> = [];\n\n for (const el of elements) {\n const elNameLower = (el.accessibleName ?? '').toLowerCase();\n const elRoleLower = (el.role ?? '').toLowerCase();\n\n let score = 0;\n\n if (role) {\n const roleMatches = elRoleLower === role;\n const nameExact = elNameLower === nameLower;\n const nameSubstring = elNameLower.includes(nameLower) || nameLower.includes(elNameLower);\n\n if (roleMatches && nameExact) {\n score = 100; // Exact role + name match\n } else if (roleMatches && nameSubstring && elNameLower.length > 0) {\n score = 80; // Role matches + name is substring\n }\n } else {\n // No role extracted — match on name only\n if (elNameLower === nameLower) {\n score = 60; // Name-only exact match\n } else if (elNameLower.includes(nameLower) || nameLower.includes(elNameLower)) {\n score = 50; // Name-only substring match\n } else {\n // Word-overlap: extract content words and check if any significant\n // description words appear in the element's accessible name.\n // Handles agent descriptions like \"'Camera' sensor type tile (camera icon)\"\n // matching element names like \"Camera Edge or RTSP video source\".\n const descWords = extractContentWords(nameLower);\n if (descWords.length > 0 && elNameLower.length > 0) {\n const elWords = new Set(extractContentWords(elNameLower));\n const matches = descWords.filter((w) => elWords.has(w));\n if (matches.length > 0) {\n score = 30 + Math.min(10, matches.length * 5); // 35-40 based on overlap\n }\n }\n }\n }\n\n if (score > 0) {\n scored.push({ element: el, score });\n }\n }\n\n if (scored.length === 0) return null;\n\n // Find highest score\n const maxScore = Math.max(...scored.map((s) => s.score));\n const topMatches = scored.filter((s) => s.score === maxScore);\n\n // Only return if the match is unique at the highest score level\n if (topMatches.length !== 1) return null;\n\n return topMatches[0].element;\n}\n\n/**\n * Common UI descriptor words that agents use but don't appear in accessible names.\n * Excluded from word-overlap matching to reduce false positives.\n */\nconst UI_DESCRIPTOR_WORDS = new Set([\n 'tile',\n 'icon',\n 'card',\n 'widget',\n 'panel',\n 'section',\n 'area',\n 'block',\n 'element',\n 'component',\n 'item',\n 'container',\n 'wrapper',\n 'field',\n 'input',\n 'type',\n 'sensor',\n 'option',\n 'entry',\n 'row',\n 'column',\n]);\n\n/**\n * Extract significant content words from a description or element name.\n * Strips quotes, parenthetical suffixes, and common UI descriptor words.\n * Returns lowercase words of 3+ characters.\n */\nfunction extractContentWords(text: string): string[] {\n // Strip parenthetical suffixes like \"(camera icon)\" and quoted segments like 'Camera'\n const cleaned = text\n .replace(/\\([^)]*\\)/g, ' ') // Remove parenthetical groups\n .replace(/['\"]/g, ' '); // Remove quotes\n return cleaned\n .split(/\\s+/)\n .map((w) => w.replace(/[^a-z0-9]/g, ''))\n .filter((w) => w.length >= 3 && !UI_DESCRIPTOR_WORDS.has(w));\n}\n\n/**\n * Check if a snapshot contains a specific ref.\n * Fast check without full parsing.\n * Handles both formats: [ref=e1] and [ref=e1 center=450,320]\n *\n * @param snapshotYaml - The YAML-like snapshot string\n * @param ref - The ref to check for\n * @returns true if ref exists in snapshot\n */\nexport function hasRef(snapshotYaml: string, ref: string): boolean {\n // Match [ref=X] or [ref=X center=...] format\n const pattern = new RegExp(`\\\\[ref=${ref}(?:\\\\s|\\\\])`);\n return pattern.test(snapshotYaml);\n}\n\n/**\n * Count the number of element refs in a snapshot.\n * Useful for diagnostics.\n * Handles both formats: [ref=e1] and [ref=e1 center=450,320]\n *\n * @param snapshotYaml - The YAML-like snapshot string\n * @returns Number of refs in the snapshot\n */\nexport function countRefs(snapshotYaml: string): number {\n // Match [ref=X] or [ref=X center=...] format\n const matches = snapshotYaml.match(/\\[ref=\\w+(?:\\s+center=\\d+,\\d+)?\\]/g);\n return matches?.length ?? 0;\n}\n","/**\n * Safe Playwright Locator Chain Parser\n *\n * Parses and evaluates Playwright locator chain strings authored by the\n * cache selector agent. Only allows a strict allowlist of Playwright\n * locator methods — no evaluate(), no arbitrary JS execution.\n *\n * @module workflows/cache/selector-agent/locator-parser\n * @see docs/api/services/workflow-action-cache.md\n */\n\nimport type { Page, Locator } from 'playwright';\nimport { createLogger } from './logger.js';\n\nlet _logger: ReturnType<typeof createLogger> | null = null;\nconst getLogger = () => {\n if (!_logger) {\n _logger = createLogger({ module: 'LocatorParser' });\n }\n return _logger;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Allowlisted Playwright methods\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Methods that can be called on Page to produce a Locator.\n */\nconst PAGE_METHODS = new Set([\n 'getByRole',\n 'getByText',\n 'getByLabel',\n 'getByTestId',\n 'getByPlaceholder',\n 'locator',\n]);\n\n/**\n * Methods that can be chained on a Locator to refine it.\n */\nconst LOCATOR_METHODS = new Set([\n 'getByRole',\n 'getByText',\n 'getByLabel',\n 'getByTestId',\n 'getByPlaceholder',\n 'filter',\n 'locator',\n 'nth',\n 'first',\n 'last',\n]);\n\n/**\n * A parsed method call in a locator chain.\n */\ninterface LocatorMethodCall {\n method: string;\n args: unknown[];\n}\n\nconst PRIVATE_USE_GLYPH_RE = /[\\uE000-\\uF8FF]/g;\nconst HAS_PRIVATE_USE_GLYPH_RE = /[\\uE000-\\uF8FF]/;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Variable Hydration\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Replace {{var.key}} placeholders with actual values from the variable registry.\n */\n/**\n * Escape a value for safe insertion into a single-quoted locator string context.\n * Backslashes and single quotes must be escaped to avoid breaking the locator syntax.\n */\nfunction escapeForLocatorString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\n/**\n * Replace {{var.key}} placeholders with actual values from the variable registry.\n * Values are escaped for the locator string context so that quotes and backslashes\n * in the variable value don't produce invalid locator syntax.\n */\nexport function hydrateLocatorVariables(\n locatorStr: string,\n variableValues: Record<string, string>\n): string {\n return locatorStr.replace(/\\{\\{var\\.([a-zA-Z0-9_]+)\\}\\}/g, (_match, key: string) => {\n const value = variableValues[key];\n if (value === undefined) {\n getLogger().warn('[LocatorParser] Variable placeholder not found in values', { key });\n return `{{var.${key}}}`;\n }\n return escapeForLocatorString(value);\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Locator String Parser\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Parse a Playwright locator chain string into a sequence of method calls.\n *\n * Handles strings like:\n * getByRole('row').filter({ hasText: 'Alpha' }).getByRole('button', { name: 'Edit' })\n * getByText('Submit')\n * locator('table').getByRole('row').nth(2)\n *\n * @throws Error if the string contains disallowed methods or is malformed\n */\nexport function parseLocatorChain(locatorStr: string): LocatorMethodCall[] {\n const calls: LocatorMethodCall[] = [];\n let remaining = locatorStr.trim();\n\n if (!remaining) {\n throw new Error('Empty locator string');\n }\n\n while (remaining.length > 0) {\n // Match method name\n const methodMatch = remaining.match(/^\\.?([a-zA-Z]+)\\s*\\(/);\n if (!methodMatch) {\n throw new Error(`Invalid locator syntax at: \"${remaining.slice(0, 50)}\"`);\n }\n\n const method = methodMatch[1];\n\n // Validate method is allowlisted\n const isFirstCall = calls.length === 0;\n const allowedSet = isFirstCall ? PAGE_METHODS : LOCATOR_METHODS;\n if (!allowedSet.has(method)) {\n throw new Error(`Disallowed method \"${method}\". Allowed: ${[...allowedSet].join(', ')}`);\n }\n\n // Find the matching closing paren, handling nested parens and strings\n const argsStart = methodMatch[0].length;\n remaining = remaining.slice(argsStart);\n const { args, rest } = extractArgs(remaining);\n\n calls.push({ method, args });\n remaining = rest.trim();\n\n // Handle .first() and .last() — no-arg chainable\n if (remaining.startsWith('.')) {\n const noArgMatch = remaining.match(/^\\.(first|last)\\b(?!\\s*\\()/);\n if (noArgMatch) {\n const noArgMethod = noArgMatch[1];\n if (!LOCATOR_METHODS.has(noArgMethod)) {\n throw new Error(`Disallowed method \"${noArgMethod}\"`);\n }\n calls.push({ method: noArgMethod, args: [] });\n remaining = remaining.slice(noArgMatch[0].length).trim();\n }\n }\n }\n\n if (calls.length === 0) {\n throw new Error('No valid method calls found in locator string');\n }\n\n return calls;\n}\n\n/**\n * Extract arguments from a parenthesized argument list.\n * Returns parsed args and the remaining string after the closing paren.\n */\nfunction extractArgs(input: string): { args: unknown[]; rest: string } {\n let depth = 1;\n let i = 0;\n let inString: \"'\" | '\"' | '`' | null = null;\n let escaped = false;\n\n while (i < input.length && depth > 0) {\n const ch = input[i];\n\n if (escaped) {\n escaped = false;\n i++;\n continue;\n }\n\n if (ch === '\\\\') {\n escaped = true;\n i++;\n continue;\n }\n\n if (inString) {\n if (ch === inString) {\n inString = null;\n }\n } else {\n if (ch === \"'\" || ch === '\"' || ch === '`') {\n inString = ch;\n } else if (ch === '(') {\n depth++;\n } else if (ch === ')') {\n depth--;\n if (depth === 0) break;\n }\n }\n\n i++;\n }\n\n if (depth !== 0) {\n throw new Error('Unmatched parenthesis in locator string');\n }\n\n const argsStr = input.slice(0, i).trim();\n const rest = input.slice(i + 1); // skip closing paren\n\n if (!argsStr) {\n return { args: [], rest };\n }\n\n // Parse the argument string as JSON-compatible values\n const args = parseArgsList(argsStr);\n return { args, rest };\n}\n\n/**\n * Parse a comma-separated argument list into JS values.\n * Handles: strings, numbers, booleans, objects (like { hasText: 'foo', name: 'bar' })\n */\nfunction parseArgsList(argsStr: string): unknown[] {\n const args: unknown[] = [];\n let remaining = argsStr.trim();\n\n while (remaining.length > 0) {\n remaining = remaining.trim();\n if (remaining.startsWith(',')) {\n remaining = remaining.slice(1).trim();\n }\n if (!remaining) break;\n\n if (remaining.startsWith('{')) {\n // Object argument\n const { value, rest } = parseObjectArg(remaining);\n args.push(value);\n remaining = rest;\n } else if (remaining.startsWith(\"'\") || remaining.startsWith('\"')) {\n // String argument\n const quote = remaining[0];\n let end = 1;\n while (end < remaining.length) {\n if (remaining[end] === '\\\\') {\n end += 2;\n continue;\n }\n if (remaining[end] === quote) break;\n end++;\n }\n const str = remaining.slice(1, end).replace(/\\\\'/g, \"'\").replace(/\\\\\"/g, '\"');\n args.push(str);\n remaining = remaining.slice(end + 1).trim();\n } else if (/^-?\\d/.test(remaining)) {\n // Number argument\n const numMatch = remaining.match(/^-?\\d+/);\n if (numMatch) {\n args.push(parseInt(numMatch[0], 10));\n remaining = remaining.slice(numMatch[0].length).trim();\n }\n } else if (remaining.startsWith('true')) {\n args.push(true);\n remaining = remaining.slice(4).trim();\n } else if (remaining.startsWith('false')) {\n args.push(false);\n remaining = remaining.slice(5).trim();\n } else if (remaining.startsWith('/')) {\n // RegExp argument — parse /pattern/flags\n const regexMatch = remaining.match(/^\\/([^/]+)\\/([gimsuy]*)/);\n if (regexMatch) {\n args.push(new RegExp(regexMatch[1], regexMatch[2]));\n remaining = remaining.slice(regexMatch[0].length).trim();\n } else {\n throw new Error(`Invalid argument at: \"${remaining.slice(0, 30)}\"`);\n }\n } else {\n throw new Error(`Invalid argument at: \"${remaining.slice(0, 30)}\"`);\n }\n }\n\n return args;\n}\n\n/**\n * Parse a JS-like object literal: { key: value, key2: value2 }\n */\nfunction parseObjectArg(input: string): { value: Record<string, unknown>; rest: string } {\n let depth = 1;\n let i = 1; // skip opening {\n let inString: \"'\" | '\"' | null = null;\n\n while (i < input.length && depth > 0) {\n const ch = input[i];\n if (inString) {\n if (ch === '\\\\') {\n i += 2;\n continue;\n }\n if (ch === inString) inString = null;\n } else {\n if (ch === \"'\" || ch === '\"') inString = ch;\n else if (ch === '{') depth++;\n else if (ch === '}') depth--;\n }\n if (depth > 0) i++;\n }\n\n const objStr = input.slice(1, i).trim();\n const rest = input.slice(i + 1);\n\n // Parse key-value pairs\n const obj: Record<string, unknown> = {};\n const pairs = splitObjectPairs(objStr);\n\n for (const pair of pairs) {\n const colonIdx = pair.indexOf(':');\n if (colonIdx === -1) continue;\n\n const key = pair\n .slice(0, colonIdx)\n .trim()\n .replace(/^['\"]|['\"]$/g, '');\n const rawValue = pair.slice(colonIdx + 1).trim();\n\n if (rawValue.startsWith(\"'\") || rawValue.startsWith('\"')) {\n const q = rawValue[0];\n let end = 1;\n while (end < rawValue.length && rawValue[end] !== q) {\n if (rawValue[end] === '\\\\') end++;\n end++;\n }\n obj[key] = rawValue.slice(1, end).replace(/\\\\'/g, \"'\").replace(/\\\\\"/g, '\"');\n } else if (rawValue.startsWith('/')) {\n const regexMatch = rawValue.match(/^\\/([^/]+)\\/([gimsuy]*)/);\n if (regexMatch) {\n obj[key] = new RegExp(regexMatch[1], regexMatch[2]);\n }\n } else if (rawValue === 'true') {\n obj[key] = true;\n } else if (rawValue === 'false') {\n obj[key] = false;\n } else if (/^-?\\d+$/.test(rawValue)) {\n obj[key] = parseInt(rawValue, 10);\n } else {\n obj[key] = rawValue;\n }\n }\n\n return { value: obj, rest };\n}\n\n/**\n * Split object key-value pairs by commas, respecting nested strings.\n */\nfunction splitObjectPairs(objStr: string): string[] {\n const pairs: string[] = [];\n let current = '';\n let inString: \"'\" | '\"' | null = null;\n\n for (let i = 0; i < objStr.length; i++) {\n const ch = objStr[i];\n if (inString) {\n if (ch === '\\\\') {\n current += ch + (objStr[i + 1] ?? '');\n i++;\n continue;\n }\n if (ch === inString) inString = null;\n } else {\n if (ch === \"'\" || ch === '\"') inString = ch;\n else if (ch === ',') {\n if (current.trim()) pairs.push(current.trim());\n current = '';\n continue;\n }\n }\n current += ch;\n }\n\n if (current.trim()) pairs.push(current.trim());\n return pairs;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Locator Chain Evaluator\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Evaluate a parsed locator chain against a Playwright Page, returning a Locator.\n *\n * @param page - Playwright Page to evaluate against\n * @param calls - Parsed method calls from parseLocatorChain()\n * @returns Playwright Locator\n */\nfunction evaluateLocatorCalls(page: Page, calls: LocatorMethodCall[]): Locator {\n if (calls.length === 0) {\n throw new Error('Empty locator chain');\n }\n\n // First call is on the Page\n const firstCall = calls[0];\n let locator = callMethod(page, firstCall.method, firstCall.args) as Locator;\n\n // Subsequent calls are on the Locator\n for (let i = 1; i < calls.length; i++) {\n locator = callMethod(locator, calls[i].method, calls[i].args) as Locator;\n }\n\n return locator;\n}\n\n/**\n * Parse, hydrate variables, and evaluate a locator chain string.\n * This is the main entry point for resolving agentic locators.\n *\n * @param page - Playwright Page\n * @param locatorStr - Raw locator chain string (may contain {{var.key}} placeholders)\n * @param variableValues - Variable values for placeholder hydration\n * @returns Playwright Locator\n */\nexport function evaluateLocatorChain(\n page: Page,\n locatorStr: string,\n variableValues?: Record<string, string>\n): Locator {\n const hydrated = variableValues\n ? hydrateLocatorVariables(locatorStr, variableValues)\n : locatorStr;\n const calls = parseLocatorChain(hydrated);\n return evaluateLocatorCalls(page, calls);\n}\n\n/**\n * Call a method on a Page or Locator with the given args.\n * Only allows methods from the allowlist.\n */\nfunction callMethod(target: Page | Locator, method: string, args: unknown[]): Locator {\n const fn = (target as unknown as Record<string, unknown>)[method];\n if (typeof fn !== 'function') {\n throw new Error(`Method \"${method}\" not found on target`);\n }\n return Reflect.apply(fn, target, normalizeLocatorArgsForIconGlyphs(method, args)) as Locator;\n}\n\nexport function normalizeLocatorArgsForIconGlyphs(method: string, args: unknown[]): unknown[] {\n if (method === 'getByRole') {\n const [role, options, ...rest] = args;\n if (!isRecord(options)) return args;\n return [\n role,\n {\n ...options,\n name: iconGlyphTolerantPattern(options.name),\n },\n ...rest,\n ];\n }\n\n if (method === 'filter') {\n const [options, ...rest] = args;\n if (!isRecord(options)) return args;\n return [\n {\n ...options,\n hasText: iconGlyphTolerantPattern(options.hasText),\n },\n ...rest,\n ];\n }\n\n if (method === 'getByText' || method === 'getByLabel') {\n const [text, ...rest] = args;\n return [iconGlyphTolerantPattern(text), ...rest];\n }\n\n return args;\n}\n\nfunction iconGlyphTolerantPattern(value: unknown): unknown {\n if (typeof value !== 'string' || !HAS_PRIVATE_USE_GLYPH_RE.test(value)) return value;\n\n const readable = value.replace(PRIVATE_USE_GLYPH_RE, ' ').replace(/\\s+/g, ' ').trim();\n if (!readable) return value;\n\n const tokens = readable.split(/\\s+/).map(escapeRegex);\n return new RegExp(tokens.join('[\\\\s\\\\uE000-\\\\uF8FF]+'), 'i');\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction escapeRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Strip `.filter({ ... })` clauses from a Playwright locator chain string.\n * Returns the stripped string, or null if no `.filter(` was found.\n *\n * Example:\n * \"getByRole('dialog').getByRole('combobox').filter({ hasText: 'foo' })\"\n * → \"getByRole('dialog').getByRole('combobox')\"\n */\nexport function stripFilterClauses(locatorStr: string): string | null {\n // Match .filter( followed by balanced parens\n const filterPattern = /\\.filter\\s*\\(/g;\n let match: RegExpExecArray | null;\n let result = locatorStr;\n let found = false;\n\n // Process from right to left to preserve indices\n const matches: { start: number; end: number }[] = [];\n while ((match = filterPattern.exec(locatorStr)) !== null) {\n // Find the matching closing paren\n const argsStart = match.index + match[0].length;\n let depth = 1;\n let i = argsStart;\n let inString: \"'\" | '\"' | '`' | null = null;\n let escaped = false;\n\n while (i < locatorStr.length && depth > 0) {\n const ch = locatorStr[i];\n if (escaped) {\n escaped = false;\n i++;\n continue;\n }\n if (ch === '\\\\') {\n escaped = true;\n i++;\n continue;\n }\n if (inString) {\n if (ch === inString) inString = null;\n } else {\n if (ch === \"'\" || ch === '\"' || ch === '`') inString = ch;\n else if (ch === '(') depth++;\n else if (ch === ')') {\n depth--;\n if (depth === 0) break;\n }\n }\n i++;\n }\n\n if (depth === 0) {\n matches.push({ start: match.index, end: i + 1 });\n found = true;\n }\n }\n\n if (!found) return null;\n\n // Remove matches from right to left\n for (let j = matches.length - 1; j >= 0; j--) {\n const { start, end } = matches[j];\n result = result.slice(0, start) + result.slice(end);\n }\n\n // Trim trailing dots\n result = result.replace(/\\.$/, '');\n\n return result || null;\n}\n\n/**\n * Validate that a locator string only uses allowed methods.\n * Returns true if valid, throws Error with details if not.\n */\nexport function validateLocatorString(locatorStr: string): boolean {\n parseLocatorChain(locatorStr); // throws on invalid\n return true;\n}\n","/**\n * Shared Element Resolver\n *\n * Extracts the element resolution logic used by both cache replay and recording\n * verification into a single shared module. This guarantees that recording\n * verification and replay use the exact same resolution algorithm — if a selector\n * verifies during recording, it will resolve identically during replay.\n *\n * @module workflows/cache/element-resolver\n * @see docs/api/services/workflow-action-cache.md\n */\n\nimport type { Page, Locator } from 'playwright';\nimport type { SelectorStrategy, SelectorAuthor } from '@chatsdet/types';\nimport { createLogger } from './logger.js';\nimport { evaluateLocatorChain, stripFilterClauses } from './locator-parser.js';\n\nlet _logger: ReturnType<typeof createLogger> | null = null;\nconst logger = () => {\n if (!_logger) {\n _logger = createLogger({ module: 'ElementResolver' });\n }\n return _logger;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Constants\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Short timeout for element resolution checks (5 seconds).\n * Cache replay should fail fast if elements aren't immediately available.\n */\nexport const RESOLVE_TIMEOUT_MS = 5000;\n\n/**\n * Longer timeout for visibility waits (15 seconds).\n * During multi-action cache replay, target apps may re-render between actions,\n * causing elements to be briefly hidden during React/framework re-renders.\n * This gives 3x more patience than RESOLVE_TIMEOUT_MS for transient render states.\n */\nconst VISIBILITY_TIMEOUT_MS = 15000;\n\n/**\n * Quick visibility check before the bounding-box escape hatch (2 seconds).\n * Most elements are visible immediately or within a few hundred ms. If Playwright\n * reports \"resolved to hidden\" within this window, we check for rendered dimensions\n * before committing to the full VISIBILITY_TIMEOUT_MS wait.\n */\nconst VISIBILITY_QUICK_CHECK_MS = 2000;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Locator context — either page or frame locator.\n * Used to support elements inside iframes.\n */\nexport type LocatorContext = Page | ReturnType<Page['frameLocator']>;\n\n/**\n * Resolution mode:\n * - 'replay': throws on failure (used during cache replay)\n * - 'verify': returns null on failure (used during recording verification)\n */\nexport type ResolveMode = 'replay' | 'verify';\n\n/**\n * Options for element resolution.\n */\n/**\n * Timing info reported by the onTiming callback during element resolution.\n */\nexport interface ElementResolutionTiming {\n /** Total time in resolveElement */\n totalMs: number;\n /** Time spent in verifyElementReady visibility wait */\n visibilityWaitMs: number;\n /** Time spent waiting for element position to stabilize (animations/transitions) */\n stabilityWaitMs: number;\n /** Which selector strategy resolved the element */\n selectorUsed: string;\n /**\n * Locator author that resolved the element, derived from the strategy label.\n * 'agentic' for the selector-agent-authored Playwright locator (and its\n * filter-stripped fallback); 'deterministic' for role/testId/label/text/css.\n */\n selectorAuthor: SelectorAuthor;\n}\n\n/**\n * Classify a resolver strategy label into its locator author. The agentic\n * Playwright locator is always tagged `(agentic)`; its filter-stripped fallback\n * derives from the same author. Everything else (testId/role/label/text/css and\n * the explicit `candidate (deterministic)`) is deterministic.\n */\nexport function classifySelectorAuthor(selectorName: string): SelectorAuthor {\n return /\\(agentic\\)/.test(selectorName) || selectorName.includes('filter-stripped')\n ? 'agentic'\n : 'deterministic';\n}\n\nexport interface ResolveElementOptions {\n /**\n * Resolution mode. Defaults to 'replay'.\n */\n mode?: ResolveMode;\n /**\n * When true, validates that the resolved element is a select/combobox.\n * Falls back to finding select elements near matching text if needed.\n */\n requireSelectElement?: boolean;\n /**\n * Variable values for structural fallback when hydrated selectors fail.\n * Used with dynamicText annotation for a last-resort role+hasText lookup.\n */\n variableValues?: Record<string, string>;\n /**\n * Optional callback reporting timing breakdown after element resolution.\n * Called once when an element is successfully resolved, before returning.\n */\n onTiming?: (timing: ElementResolutionTiming) => void;\n /**\n * The type of action being resolved (e.g. 'click', 'type').\n * When set to 'click', text disambiguation will prefer interactive elements\n * (combobox, button, link, etc.) over labels/static text.\n */\n actionType?: string;\n /**\n * When true, disables fallback heuristics that could produce false-positive matches:\n * multi-match `.first()`, filter stripping, positional index trust, bounding-box\n * escape hatch, and fallback to weaker selectors when playwrightLocator fails.\n * @see docs/api/services/strict-cache-replay.md\n */\n strictMode?: boolean;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Data attribute extraction for disambiguation\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface DisambiguationAttrs {\n itemIndex: number;\n rowIndex: number;\n automationId: string | null;\n}\n\n/**\n * Batch-extract disambiguation attrs for all matched elements in a single\n * round-trip using evaluateAll(). Returns up to `limit` results.\n *\n * The aria-rowindex walk checks the element itself then walks up to 10\n * ancestors — many grid UIs (BC Dynamics) put `aria-rowindex` on the\n * `<tr>` parent rather than the cell/input.\n */\nconst extractDisambiguationAttrsBatch = (\n locator: Locator,\n limit: number\n): Promise<DisambiguationAttrs[]> =>\n locator.evaluateAll((elements, max) => {\n const getRowIndex = (node: Element): number => {\n let c: Element | null = node;\n let depth = 0;\n while (c && depth < 10) {\n const ri = c.getAttribute('aria-rowindex');\n if (ri) return parseInt(ri, 10);\n c = c.parentElement;\n depth++;\n }\n return NaN;\n };\n\n return elements.slice(0, max).map((el) => ({\n itemIndex: parseInt(\n el.getAttribute('data-item-index') ?? el.getAttribute('data-selection-index') ?? '',\n 10\n ),\n rowIndex: getRowIndex(el),\n automationId: el.getAttribute('data-automationid'),\n }));\n }, Math.min(limit, 10));\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dialog-scoped filtering for modal disambiguation\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * When multiple elements match and a visible dialog/modal is open, filter\n * to elements inside the dialog. This prevents sidebar/background elements\n * from being selected when a modal field with the same label is the target.\n *\n * Returns a narrowed locator + count if dialog scoping helped, or null if\n * no visible dialog was found or scoping didn't reduce matches.\n */\nconst filterToVisibleDialog = async (\n page: Page,\n candidateLocator: Locator,\n currentCount: number\n): Promise<{ locator: Locator; count: number } | null> => {\n try {\n // Find visible dialog elements — matches the same roles that discoverParentContext\n // captures at recording time (SEMANTIC_ROLES includes 'dialog' and 'alertdialog')\n const dialogLocator = page.locator(\n '[role=\"dialog\"]:visible, [role=\"alertdialog\"]:visible, dialog[open]'\n );\n const dialogCount = await Promise.race([\n dialogLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Dialog check timed out')), 2000)\n ),\n ]);\n\n if (dialogCount === 0) return null;\n\n // Use the first visible dialog as the scoping container\n const dialog = dialogLocator.first();\n const scopedLocator = dialog.locator(candidateLocator);\n const scopedCount = await Promise.race([\n scopedLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Dialog scoped count timed out')), 2000)\n ),\n ]);\n\n // Only useful if we narrowed the set\n if (scopedCount > 0 && scopedCount < currentCount) {\n logger().debug('[ElementResolver] Dialog scoping narrowed matches', {\n originalCount: currentCount,\n scopedCount,\n });\n return { locator: scopedLocator, count: scopedCount };\n }\n\n return null;\n } catch {\n return null;\n }\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Role compatibility for text fallback validation\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Map of expected roles to compatible actual roles.\n * Used to validate text-fallback matches when the primary role selector failed.\n * Handles common patterns like Dynamics 365 combobox exposing as textbox.\n * Unmapped roles are permissive (no validation applied).\n */\nconst COMPATIBLE_ROLES: Record<string, Set<string>> = {\n combobox: new Set(['combobox', 'textbox', 'searchbox', 'listbox']),\n textbox: new Set(['textbox', 'combobox', 'searchbox']),\n searchbox: new Set(['searchbox', 'textbox', 'combobox']),\n listbox: new Set(['listbox', 'combobox']),\n button: new Set(['button', 'menuitem', 'link', 'tab']),\n link: new Set(['link', 'button']),\n checkbox: new Set(['checkbox', 'switch']),\n switch: new Set(['switch', 'checkbox']),\n};\n\n/**\n * Implicit ARIA role mapping for common HTML tags.\n */\nconst TAG_TO_IMPLICIT_ROLE: Record<string, string> = {\n input: 'textbox',\n textarea: 'textbox',\n select: 'listbox',\n button: 'button',\n a: 'link',\n};\n\n/**\n * Roles considered interactive for click-action disambiguation.\n * When text fallback matches multiple elements and the action is a click,\n * we prefer elements with these roles over labels/static text.\n */\nconst INTERACTIVE_ROLES = new Set([\n 'button',\n 'link',\n 'combobox',\n 'menuitem',\n 'checkbox',\n 'switch',\n 'tab',\n 'textbox',\n 'searchbox',\n 'option',\n 'menuitemcheckbox',\n 'menuitemradio',\n 'radio',\n 'spinbutton',\n]);\n\n/**\n * Interactive HTML tags (implicit interactive role via tag name).\n */\nconst INTERACTIVE_TAGS = new Set(['button', 'a', 'input', 'select', 'textarea']);\n\n/**\n * Check whether an element has an interactive role (explicit or implicit).\n * Used during text disambiguation to prefer clickable elements over labels.\n */\nexport const isInteractiveElement = async (locator: Locator): Promise<boolean> => {\n try {\n const { role, tag } = await locator.evaluate((el) => ({\n role: el.getAttribute('role'),\n tag: el.tagName.toLowerCase(),\n }));\n if (role && INTERACTIVE_ROLES.has(role)) return true;\n if (INTERACTIVE_TAGS.has(tag)) return true;\n const implicitRole = TAG_TO_IMPLICIT_ROLE[tag];\n if (implicitRole && INTERACTIVE_ROLES.has(implicitRole)) return true;\n return false;\n } catch {\n return false;\n }\n};\n\n/**\n * Roles considered typeable for type-action disambiguation.\n * When text fallback matches multiple elements and the action is a type,\n * we prefer elements with these roles over labels/static text.\n */\nconst TYPEABLE_ROLES = new Set(['textbox', 'searchbox', 'spinbutton', 'combobox']);\nconst TYPEABLE_TAGS = new Set(['input', 'textarea', 'select']);\n\n/**\n * Check whether an element is typeable (can receive keyboard input).\n * Used during text disambiguation to prefer input fields over labels for type actions.\n */\nconst isTypeableElement = async (locator: Locator): Promise<boolean> => {\n try {\n const { role, tag, contentEditable } = await locator.evaluate((el) => ({\n role: el.getAttribute('role'),\n tag: el.tagName.toLowerCase(),\n contentEditable: (el as HTMLElement).isContentEditable,\n }));\n if (contentEditable) return true;\n if (role && TYPEABLE_ROLES.has(role)) return true;\n if (TYPEABLE_TAGS.has(tag)) return true;\n return false;\n } catch {\n return false;\n }\n};\n\n/**\n * Check whether a resolved element's actual role is compatible with the expected role.\n *\n * - Returns `true` if the element has a compatible role (explicit or implicit).\n * - Returns `false` if the element has no discernible role (generic div/span).\n * - Returns `true` for unmapped expected roles (permissive — no validation).\n * - Returns `true` on evaluation errors (fail-open to avoid false rejections).\n */\nexport const isRoleCompatible = async (\n locator: Locator,\n expectedRole: string\n): Promise<boolean> => {\n const compatibleSet = COMPATIBLE_ROLES[expectedRole];\n if (!compatibleSet) {\n // Unmapped role — no validation, allow through\n return true;\n }\n\n try {\n const { role, tag } = await locator.evaluate((el) => ({\n role: el.getAttribute('role'),\n tag: el.tagName.toLowerCase(),\n }));\n\n const actualRole = role ?? TAG_TO_IMPLICIT_ROLE[tag];\n\n if (!actualRole) {\n // No discernible role (generic div/span) — reject\n return false;\n }\n\n return compatibleSet.has(actualRole);\n } catch {\n // Evaluation failed — fail-open\n return true;\n }\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Text normalization helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Normalize text used for selector matching.\n * Strips private use glyphs, normalizes whitespace.\n */\nexport const normalizeMatchText = (value: string): string => {\n return value\n .replace(/[\\uE000-\\uF8FF]/g, '')\n .replace(/\\u00a0/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n};\n\n/**\n * Extract the primary text from a concatenated accessible name.\n * E.g., \"Sales Quotes Lists Not bookmarked\" -> \"Sales Quotes\"\n *\n * Common patterns in concatenated names:\n * - \"Primary Text Lists/Reports/etc\"\n * - \"Primary Text Not bookmarked/Bookmarked\"\n */\nexport const extractPrimaryText = (fullText: string): string | null => {\n if (!fullText) return null;\n\n const normalized = normalizeMatchText(fullText);\n if (!normalized) return null;\n\n // Common suffixes that indicate concatenated text\n const suffixPatterns = [\n /\\s+(Lists?|Reports?|Tasks?|Pages?|Archive)\\b.*$/i,\n /\\s+Not bookmarked$/i,\n /\\s+Bookmarked$/i,\n /\\s+-\\s+Microsoft.*$/i,\n ];\n\n let primaryText = normalized;\n for (const pattern of suffixPatterns) {\n primaryText = primaryText.replace(pattern, '');\n }\n\n // Only return if we actually shortened it and have something meaningful left\n if (primaryText !== normalized && primaryText.trim().length >= 3) {\n return primaryText.trim();\n }\n\n return null;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Element helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Find the first visible element from a locator that matches multiple elements.\n * Returns the locator for the first visible element, or null if none are visible.\n */\nexport const findFirstVisibleElement = async (\n locator: Locator,\n count: number,\n timeoutMs: number = RESOLVE_TIMEOUT_MS\n): Promise<Locator | null> => {\n const limit = Math.min(count, 10);\n\n // Check all candidates in parallel instead of sequentially\n const results = await Promise.all(\n Array.from({ length: limit }, (_, i) => {\n const nth = locator.nth(i);\n return Promise.race([\n nth.isVisible(),\n new Promise<boolean>((_, reject) =>\n setTimeout(() => reject(new Error('Visibility check timed out')), timeoutMs)\n ),\n ]).catch(() => false);\n })\n );\n\n const firstVisibleIndex = results.indexOf(true);\n if (firstVisibleIndex >= 0) {\n logger().debug('[ElementResolver] Found visible element at index', { index: firstVisibleIndex });\n return locator.nth(firstVisibleIndex);\n }\n return null;\n};\n\n/**\n * Bounding-box escape hatch: check if an element has real rendered dimensions\n * despite Playwright reporting it as \"hidden\". Returns true if the element\n * should be accepted as usable, false otherwise.\n *\n * This handles CSS edge cases (ancestor opacity:0 during transitions,\n * visibility:hidden overridden by child, clip-path, transparent overlays)\n * where the element is visually present and interactable.\n */\nconst checkBoundingBoxEscapeHatch = async (\n locator: Locator,\n selectorDesc: string\n): Promise<boolean> => {\n try {\n const diagnostics = await locator.evaluate((el) => {\n const cs = window.getComputedStyle(el);\n const r = el.getBoundingClientRect();\n const ancestors: Array<{\n tag: string;\n role: string | null;\n vis: string;\n disp: string;\n opa: string;\n h: number;\n }> = [];\n let parent = el.parentElement;\n while (parent && ancestors.length < 10) {\n const pcs = window.getComputedStyle(parent);\n const pr = parent.getBoundingClientRect();\n if (\n pcs.visibility === 'hidden' ||\n pcs.display === 'none' ||\n pcs.opacity === '0' ||\n pr.height === 0\n ) {\n ancestors.push({\n tag: parent.tagName,\n role: parent.getAttribute('role'),\n vis: pcs.visibility,\n disp: pcs.display,\n opa: pcs.opacity,\n h: Math.round(pr.height),\n });\n }\n parent = parent.parentElement;\n }\n return {\n visibility: cs.visibility,\n display: cs.display,\n opacity: cs.opacity,\n width: Math.round(r.width),\n height: Math.round(r.height),\n hiddenAncestors: ancestors,\n };\n });\n\n if (diagnostics.width > 0 && diagnostics.height > 0 && diagnostics.display !== 'none') {\n logger().warn(\n '[ElementResolver] Element reported hidden but has rendered dimensions, accepting',\n {\n selectorDesc,\n width: diagnostics.width,\n height: diagnostics.height,\n visibility: diagnostics.visibility,\n opacity: diagnostics.opacity,\n hiddenAncestorCount: diagnostics.hiddenAncestors.length,\n }\n );\n return true;\n }\n\n logger().warn('[ElementResolver] Element hidden diagnostics', {\n selectorDesc,\n diagnostics,\n });\n return false;\n } catch {\n // Element may have been detached — best-effort\n return false;\n }\n};\n\n/** Helper: returns true when the error message indicates the element was found but hidden */\nconst isResolvedToHidden = (message: string): boolean =>\n message.includes('resolved to hidden') || message.includes('not visible');\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Position Stability\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Maximum time to wait for an element's position to stabilize */\nconst STABILITY_MAX_WAIT_MS = 1000;\n/** Threshold in pixels — movement below this is considered stable */\nconst STABILITY_THRESHOLD_PX = 1;\n\n/**\n * Wait until an element's bounding box stops moving.\n *\n * Catches CSS animations/transitions completing on dropdown menus, popovers,\n * and slide-in panels. Uses a single in-browser rAF loop instead of polling\n * via CDP round-trips (~20 round-trips → 1).\n *\n * @returns milliseconds spent waiting for stability\n */\nconst waitForPositionStability = async (\n locator: Locator,\n selectorDesc: string\n): Promise<number> => {\n const startMs = Date.now();\n try {\n const result = await locator.evaluate(\n (el, { maxWaitMs, thresholdPx }) => {\n return new Promise<{ elapsed: number; stable: boolean }>((resolve) => {\n const start = performance.now();\n let prevRect = el.getBoundingClientRect();\n // Require 3 consecutive stable frames (~48ms at 60fps) to match\n // the spirit of the old 50ms polling interval and avoid false\n // positives from easing curves that briefly plateau.\n let stableFrames = 0;\n const REQUIRED_STABLE_FRAMES = 3;\n\n const check = () => {\n const elapsed = performance.now() - start;\n if (elapsed >= maxWaitMs) {\n resolve({ elapsed: Math.round(elapsed), stable: false });\n return;\n }\n\n const currRect = el.getBoundingClientRect();\n const dx = Math.abs(currRect.x - prevRect.x);\n const dy = Math.abs(currRect.y - prevRect.y);\n const dw = Math.abs(currRect.width - prevRect.width);\n const dh = Math.abs(currRect.height - prevRect.height);\n\n if (\n dx <= thresholdPx &&\n dy <= thresholdPx &&\n dw <= thresholdPx &&\n dh <= thresholdPx\n ) {\n stableFrames++;\n if (stableFrames >= REQUIRED_STABLE_FRAMES) {\n resolve({ elapsed: Math.round(elapsed), stable: true });\n return;\n }\n } else {\n stableFrames = 0;\n }\n\n prevRect = currRect;\n requestAnimationFrame(check);\n };\n\n // Wait one frame before first comparison\n requestAnimationFrame(check);\n });\n },\n { maxWaitMs: STABILITY_MAX_WAIT_MS, thresholdPx: STABILITY_THRESHOLD_PX }\n );\n\n const elapsed = Date.now() - startMs;\n if (!result.stable) {\n logger().warn('[ElementResolver] Element position did not stabilize within timeout', {\n selectorDesc,\n stabilityWaitMs: elapsed,\n });\n } else if (result.elapsed > 60) {\n logger().debug('[ElementResolver] Element position stabilized', {\n selectorDesc,\n stabilityWaitMs: elapsed,\n });\n }\n return elapsed;\n } catch {\n // Element detached or navigated away — not worth blocking\n return Date.now() - startMs;\n }\n};\n\n/**\n * Verify an element is visible and attached to DOM before returning.\n *\n * Uses a two-phase approach:\n * 1. Quick visibility check (2s) — catches most elements that are immediately visible.\n * 2. If the element was found but Playwright reports \"hidden\", run a bounding-box\n * escape hatch — if the element has real rendered dimensions it's accepted\n * immediately (~2s total instead of 15s).\n * 3. If the escape hatch doesn't apply (element genuinely has no dimensions),\n * wait the remaining time for it to become visible (covers React re-renders,\n * lazy-loaded content, CSS transitions that are legitimately completing).\n *\n * @param locator - The element locator\n * @param selectorDesc - Description of the selector for error messages\n * @param strict - If true (default), throws on timeout. If false, only logs warning.\n */\nexport const verifyElementReady = async (\n locator: Locator,\n selectorDesc: string,\n strict = true,\n onStabilityWait?: (ms: number) => void,\n strictMode = false\n): Promise<boolean> => {\n /** Wait for position stability and report timing before returning ready */\n const stableReturn = async (): Promise<true> => {\n const ms = await waitForPositionStability(locator, selectorDesc);\n onStabilityWait?.(ms);\n return true;\n };\n\n // ── Phase 1: Quick visibility check ──\n try {\n await locator.waitFor({ state: 'visible', timeout: VISIBILITY_QUICK_CHECK_MS });\n return stableReturn();\n } catch (quickErr) {\n const quickMsg = quickErr instanceof Error ? quickErr.message : String(quickErr);\n\n // Element exists but Playwright says \"hidden\" — try bounding-box escape hatch\n // before committing to a long wait.\n // V13: In strict mode, skip the escape hatch — trust Playwright's visibility check.\n if (isResolvedToHidden(quickMsg)) {\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] Skipping bounding-box escape hatch', {\n strictMode: true,\n rejection: 'escape_hatch_skipped',\n selectorDesc,\n });\n } else if (await checkBoundingBoxEscapeHatch(locator, selectorDesc)) {\n return stableReturn();\n }\n // Element genuinely has no rendered dimensions — fall through to extended wait\n logger().debug(\n '[ElementResolver] Element hidden with no dimensions after quick check, continuing wait',\n {\n selectorDesc,\n }\n );\n }\n }\n\n // ── Phase 2: Extended wait for elements that need more time to appear ──\n // Covers: elements hidden during React/framework re-renders, lazy-loaded content, etc.\n try {\n const remainingMs = Math.max(VISIBILITY_TIMEOUT_MS - VISIBILITY_QUICK_CHECK_MS, 1000);\n await locator.waitFor({ state: 'visible', timeout: remainingMs });\n return stableReturn();\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n\n // Final escape hatch — element may have appeared during the wait but\n // still reports \"hidden\" due to CSS issues.\n // V13: In strict mode, skip the escape hatch.\n if (isResolvedToHidden(message)) {\n if (!strictMode && await checkBoundingBoxEscapeHatch(locator, selectorDesc)) {\n return stableReturn();\n }\n }\n\n if (strict) {\n throw new Error(`Element not ready (${selectorDesc}): ${message}`);\n }\n logger().debug('[ElementResolver] Element visibility check failed (non-strict)', {\n selectorDesc,\n error: message,\n });\n return false;\n }\n};\n\n/**\n * Validate that a locator points to a select element.\n * Returns true if it's a select/combobox, false otherwise.\n */\nexport const isSelectElement = async (locator: Locator): Promise<boolean> => {\n try {\n const { tagName, role } = await locator.evaluate((el) => ({\n tagName: el.tagName.toLowerCase(),\n role: el.getAttribute('role'),\n }));\n return tagName === 'select' || role === 'combobox' || role === 'listbox';\n } catch {\n return false;\n }\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Frame locator helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Get all frame locators from a page for searching within iframes.\n * Uses specific selectors to avoid strict mode violations when multiple iframes exist.\n */\nexport const getFrameLocators = (\n page: Page\n): Array<{ name: string; locator: ReturnType<Page['frameLocator']> }> => {\n return [\n { name: 'iframe:main', locator: page.frameLocator('iframe.designer-client-frame') },\n { name: 'iframe:first', locator: page.frameLocator('iframe').first() },\n { name: 'iframe:nth(0)', locator: page.frameLocator('iframe').nth(0) },\n { name: 'iframe:nth(1)', locator: page.frameLocator('iframe').nth(1) },\n ];\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Lightweight resolution (for overlay checking)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Lightweight element resolution for overlay checking (no verification).\n * Only tries fast selector strategies to minimize overhead.\n */\nexport const resolveElementForCheck = async (\n page: Page,\n selectors: SelectorStrategy\n): Promise<Locator | null> => {\n try {\n if (selectors.testId) {\n const loc = page.getByTestId(selectors.testId);\n if ((await loc.count()) > 0) return loc.first();\n }\n if (selectors.role) {\n const loc = page.getByRole(\n selectors.role.role as Parameters<Page['getByRole']>[0],\n selectors.role.name ? { name: selectors.role.name } : undefined\n );\n if ((await loc.count()) > 0) return loc.first();\n }\n } catch {\n // Ignore errors - this is best-effort\n }\n return null;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Parent-scoped context helper\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Build a list of parent-scoped search contexts for a given page/frame context.\n * When parentContext is available, returns scoped contexts first (role chain, CSS),\n * then the unscoped context as a final fallback. This ensures text/label selectors\n * resolve within the correct container (e.g., dialog) before searching the full page.\n */\ntype ParentContextChainNode = {\n role: string;\n name?: string;\n css?: string;\n nameFromHeading?: boolean;\n containsText?: string;\n};\n\ntype ParentContextInput = {\n role?: string;\n name?: string;\n css?: string;\n nameFromHeading?: boolean;\n containsText?: string;\n parentChain?: ParentContextChainNode[];\n};\n\nfunction getParentScopedContexts(\n context: LocatorContext,\n parentContext: ParentContextInput | undefined\n): Array<{ searchCtx: LocatorContext | Locator; scopeLabel: string }> {\n if (!parentContext) return [{ searchCtx: context, scopeLabel: '' }];\n\n const result: Array<{ searchCtx: LocatorContext | Locator; scopeLabel: string }> = [];\n\n if (parentContext.parentChain?.length) {\n let parent: Locator | undefined;\n for (const ancestor of [...parentContext.parentChain].reverse()) {\n let ancestorLocator: Locator =\n ancestor.nameFromHeading && ancestor.name\n ? context\n .getByRole(ancestor.role as Parameters<Page['getByRole']>[0])\n .filter({ has: context.getByRole('heading', { name: ancestor.name }) })\n : context.getByRole(\n ancestor.role as Parameters<Page['getByRole']>[0],\n ancestor.name ? { name: ancestor.name } : undefined\n );\n if (ancestor.containsText) {\n ancestorLocator = ancestorLocator.filter({ hasText: ancestor.containsText });\n }\n parent = parent ? parent.locator(ancestorLocator) : ancestorLocator;\n }\n if (parent) result.push({ searchCtx: parent, scopeLabel: ` [parent-chain]` });\n } else if (parentContext.role) {\n let parentLocator: Locator =\n parentContext.nameFromHeading && parentContext.name\n ? context\n .getByRole(parentContext.role as Parameters<Page['getByRole']>[0])\n .filter({ has: context.getByRole('heading', { name: parentContext.name }) })\n : context.getByRole(\n parentContext.role as Parameters<Page['getByRole']>[0],\n parentContext.name ? { name: parentContext.name } : undefined\n );\n if (parentContext.containsText) {\n parentLocator = parentLocator.filter({ hasText: parentContext.containsText });\n }\n const label = parentContext.containsText\n ? ` [parent:${parentContext.role}~\"${parentContext.containsText}\"]`\n : ` [parent:${parentContext.role}]`;\n result.push({ searchCtx: parentLocator, scopeLabel: label });\n }\n\n if (parentContext.css) {\n result.push({ searchCtx: context.locator(parentContext.css), scopeLabel: ` [parent-css]` });\n }\n\n // Always include unscoped as final fallback\n result.push({ searchCtx: context, scopeLabel: '' });\n\n return result;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Role selector resolution\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Try to find an element using role selector within a context (page or frame).\n * Returns the locator if found, null otherwise.\n *\n * Attempts in order:\n * 1. Full name with parent context\n * 2. Full name without parent context\n * 3. Partial/primary text extracted from name (for concatenated accessible names)\n */\nexport const tryRoleSelector = async (\n context: LocatorContext,\n selectors: SelectorStrategy,\n contextName: string,\n strictMode = false\n): Promise<{ locator: Locator; selectorDesc: string } | null> => {\n if (!selectors.role) return null;\n\n const { role, name, exact } = selectors.role;\n const normalizedName = name ? normalizeMatchText(name) : undefined;\n const textFilterRoles = new Set([\n 'row',\n 'listitem',\n 'option',\n 'menuitem',\n 'treeitem',\n 'gridcell',\n 'article',\n ]);\n const normalizedContainsText = selectors.containsText?.map((part) => normalizeMatchText(part));\n const containsTextFallback =\n !normalizedContainsText && role && textFilterRoles.has(role) && normalizedName\n ? [normalizedName]\n : undefined;\n const activeContainsText = normalizedContainsText ?? containsTextFallback;\n\n const applyContainsText = (locator: Locator): Locator => {\n if (!activeContainsText || activeContainsText.length === 0) return locator;\n let filtered = locator;\n for (const part of activeContainsText) {\n if (!part) continue;\n filtered = filtered.filter({ hasText: part });\n }\n return filtered;\n };\n\n /**\n * Helper to try a specific name value and return locator if found.\n */\n const tryWithName = async (\n searchName: string | undefined,\n variant: string\n ): Promise<{ locator: Locator; selectorDesc: string } | null> => {\n const locatorOpts = searchName ? { name: searchName, exact: exact ?? false } : undefined;\n const baseLocator = context.getByRole(role as Parameters<Page['getByRole']>[0], locatorOpts);\n const locator = applyContainsText(baseLocator);\n\n // Build candidate locator scopes in precedence order:\n // 1) parent role/chain (if present)\n // 2) parent CSS (if present)\n // 3) no parent fallback\n const candidates: Array<{ scopedLocator: Locator; suffix: string }> = [];\n const hasParentScope = !!(\n selectors.parentContext?.parentChain?.length ||\n selectors.parentContext?.role ||\n selectors.parentContext?.css\n );\n\n if (selectors.parentContext?.parentChain?.length) {\n let parentScoped = locator;\n for (const ancestor of [...selectors.parentContext.parentChain].reverse()) {\n let parentLocator: Locator;\n if (ancestor.nameFromHeading && ancestor.name) {\n parentLocator = context\n .getByRole(ancestor.role as Parameters<Page['getByRole']>[0])\n .filter({ has: context.getByRole('heading', { name: ancestor.name }) });\n } else {\n parentLocator = context.getByRole(\n ancestor.role as Parameters<Page['getByRole']>[0],\n ancestor.name ? { name: ancestor.name } : undefined\n );\n }\n if (ancestor.containsText) {\n parentLocator = parentLocator.filter({ hasText: ancestor.containsText });\n }\n parentScoped = parentLocator.locator(parentScoped);\n }\n candidates.push({ scopedLocator: parentScoped, suffix: '' });\n } else if (selectors.parentContext?.role) {\n let parentLocator: Locator;\n if (selectors.parentContext.nameFromHeading && selectors.parentContext.name) {\n parentLocator = context\n .getByRole(selectors.parentContext.role as Parameters<Page['getByRole']>[0])\n .filter({ has: context.getByRole('heading', { name: selectors.parentContext.name }) });\n } else {\n parentLocator = context.getByRole(\n selectors.parentContext.role as Parameters<Page['getByRole']>[0],\n selectors.parentContext.name ? { name: selectors.parentContext.name } : undefined\n );\n }\n if (selectors.parentContext.containsText) {\n parentLocator = parentLocator.filter({ hasText: selectors.parentContext.containsText });\n }\n candidates.push({ scopedLocator: parentLocator.locator(locator), suffix: '' });\n }\n\n if (selectors.parentContext?.css) {\n const cssParentLocator = context.locator(selectors.parentContext.css);\n candidates.push({\n scopedLocator: cssParentLocator.locator(locator),\n suffix: ' - css parent',\n });\n }\n\n if (hasParentScope) {\n candidates.push({ scopedLocator: locator, suffix: ' - no parent' });\n } else {\n candidates.push({ scopedLocator: locator, suffix: '' });\n }\n\n // Check element count with timeout protection\n try {\n for (const candidate of candidates) {\n const count = await Promise.race([\n candidate.scopedLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Count check timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n\n if (count === 0) {\n continue;\n }\n\n const selectorDesc = `Role selector (${role}: \"${searchName ?? ''}\"${candidate.suffix}${variant ? ` ${variant}` : ''}${contextName ? ` in ${contextName}` : ''})`;\n\n if (count === 1) {\n return { locator: candidate.scopedLocator.first(), selectorDesc };\n }\n\n // Multiple matches - try disambiguation strategies\n logger().debug('[ElementResolver] Multiple role matches, trying disambiguation', {\n role,\n name: searchName,\n count,\n context: contextName,\n hasItemIndex: selectors.itemIndex !== undefined,\n hasRowIndex: selectors.rowIndex !== undefined,\n hasMatchIndex: selectors.parentContext?.matchIndex !== undefined,\n });\n\n // Strategy 1: Try data attribute matching (most deterministic)\n if (\n selectors.itemIndex !== undefined ||\n selectors.rowIndex !== undefined ||\n selectors.automationId\n ) {\n try {\n const allAttrs = await extractDisambiguationAttrsBatch(candidate.scopedLocator, count);\n for (let i = 0; i < allAttrs.length; i++) {\n const attrs = allAttrs[i];\n const matches =\n (selectors.itemIndex !== undefined && attrs.itemIndex === selectors.itemIndex) ||\n (selectors.rowIndex !== undefined && attrs.rowIndex === selectors.rowIndex) ||\n (selectors.automationId && attrs.automationId === selectors.automationId);\n\n if (matches) {\n logger().debug('[ElementResolver] Found element by data attributes', {\n index: i,\n attrs,\n });\n return {\n locator: candidate.scopedLocator.nth(i),\n selectorDesc: `${selectorDesc} [data-attr]`,\n };\n }\n }\n } catch {\n // Fall through to next strategy\n }\n }\n\n // Strategy 2: Use matchIndex fallback\n if (selectors.parentContext?.matchIndex !== undefined) {\n const matchIndex = selectors.parentContext.matchIndex;\n if (matchIndex < count) {\n const indexed = candidate.scopedLocator.nth(matchIndex);\n\n // Verify with text content if available\n if (selectors.containsText?.length) {\n try {\n const text = await indexed.textContent();\n const hasExpectedText = selectors.containsText.every((t) => text?.includes(t));\n if (hasExpectedText) {\n logger().debug(\n '[ElementResolver] Found element by matchIndex with text verification',\n {\n matchIndex,\n }\n );\n return {\n locator: indexed,\n selectorDesc: `${selectorDesc} [index:${matchIndex}]`,\n };\n }\n } catch {\n // V4: In strict mode, if text verification fails, don't trust the index\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] matchIndex text verification failed, rejecting', {\n strictMode: true,\n rejection: 'index_fallback',\n matchIndex,\n role,\n name: searchName,\n });\n return null;\n }\n // Fall through to use index anyway\n }\n }\n\n // V4: In strict mode, don't trust bare positional index without text verification\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] Rejecting matchIndex without text verification', {\n strictMode: true,\n rejection: 'index_fallback',\n matchIndex,\n role,\n name: searchName,\n count,\n });\n return null;\n }\n\n // Trust the index\n logger().debug('[ElementResolver] Using matchIndex fallback', { matchIndex });\n return { locator: indexed, selectorDesc: `${selectorDesc} [index:${matchIndex}]` };\n }\n }\n\n // No disambiguation succeeded - treat as selector miss\n logger().warn('[ElementResolver] No disambiguation succeeded, treating as selector miss', {\n role,\n name: searchName,\n count,\n });\n return null;\n }\n } catch (err) {\n logger().debug('[ElementResolver] Role selector variant failed', {\n context: contextName,\n variant,\n searchName,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n return null;\n };\n\n // Try 1: Full name (original)\n const fullResult = await tryWithName(normalizedName ?? name, '');\n if (fullResult) return fullResult;\n\n // Try role-only with containsText if name match failed\n if (activeContainsText && activeContainsText.length > 0) {\n const roleOnlyResult = await tryWithName(undefined, '[containsText]');\n if (roleOnlyResult) return roleOnlyResult;\n }\n\n // Try 2: Extract primary text from concatenated name\n if (name) {\n const primaryText = extractPrimaryText(normalizedName ?? name);\n if (primaryText) {\n logger().debug('[ElementResolver] Trying partial text match', {\n role,\n originalName: normalizedName ?? name,\n primaryText,\n context: contextName,\n });\n const partialResult = await tryWithName(primaryText, '[partial]');\n if (partialResult) return partialResult;\n }\n }\n\n return null;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Main element resolution\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Resolve an element using selector fallback chain.\n *\n * Tries selectors in priority order:\n * 1. data-testid\n * 2. Role + name (most stable)\n * 3. Label text (getByLabel)\n * 4. Placeholder text\n * 5. Text content (with label fallback for selects)\n * 6. CSS selector (fallback)\n *\n * Also searches within iframes if element not found on main page.\n * Before returning, verifies the element is visible and attached.\n *\n * Supports two modes:\n * - 'replay' (default): throws Error if element cannot be found\n * - 'verify': returns null if element cannot be found (for recording verification)\n *\n * @param page - Playwright page\n * @param selectors - Selector strategy from cached action\n * @param _timeoutMs - Timeout for locator operations (unused, using RESOLVE_TIMEOUT_MS)\n * @param options - Optional configuration\n * @returns Locator for the element (or null in verify mode)\n * @throws Error if element cannot be found (replay mode only)\n */\nexport async function resolveElement(\n page: Page,\n selectors: SelectorStrategy,\n _timeoutMs: number,\n options?: ResolveElementOptions\n): Promise<Locator>;\nexport async function resolveElement(\n page: Page,\n selectors: SelectorStrategy,\n _timeoutMs: number,\n options: ResolveElementOptions & { mode: 'verify' }\n): Promise<Locator | null>;\nexport async function resolveElement(\n page: Page,\n selectors: SelectorStrategy,\n _timeoutMs: number,\n options?: ResolveElementOptions\n): Promise<Locator | null> {\n const resolveStartMs = Date.now();\n const mode = options?.mode ?? 'replay';\n const actionType = options?.actionType;\n const strictMode = options?.strictMode ?? false;\n const errors: string[] = [];\n const requireSelect = options?.requireSelectElement ?? false;\n const elementTypeName = requireSelect ? 'select element' : 'element';\n\n logger().debug('[ElementResolver] Resolving element', {\n mode,\n hasTestId: !!selectors.testId,\n testId: selectors.testId,\n hasRole: !!selectors.role,\n role: selectors.role?.role,\n name: selectors.role?.name,\n hasAriaLabel: !!selectors.ariaLabel,\n hasPlaceholder: !!selectors.placeholder,\n hasText: !!selectors.text,\n hasContainsText: !!selectors.containsText?.length,\n hasParentContext: !!selectors.parentContext,\n parentRole: selectors.parentContext?.role,\n hasFrameContext: !!selectors.frameContext,\n frameSelector: selectors.frameContext?.selector,\n });\n\n /**\n * Helper to validate element if select is required, then verify visibility.\n * Returns the locator if valid, null if validation fails.\n */\n const validateAndReturn = async (\n locator: Locator,\n selectorName: string\n ): Promise<Locator | null> => {\n let capturedStabilityMs = 0;\n const onStabilityWait = (ms: number) => {\n capturedStabilityMs = ms;\n };\n\n if (requireSelect) {\n if (await isSelectElement(locator)) {\n const visStart = Date.now();\n await verifyElementReady(locator, selectorName, true, onStabilityWait, strictMode);\n const visibilityWaitMs = Date.now() - visStart;\n options?.onTiming?.({\n totalMs: Date.now() - resolveStartMs,\n visibilityWaitMs,\n stabilityWaitMs: capturedStabilityMs,\n selectorUsed: selectorName,\n selectorAuthor: classifySelectorAuthor(selectorName),\n });\n logger().debug('[ElementResolver] Resolved select element', { selector: selectorName });\n return locator;\n }\n errors.push(`${selectorName} found element but it's not a select`);\n return null;\n }\n const visStart = Date.now();\n await verifyElementReady(locator, selectorName, true, onStabilityWait, strictMode);\n const visibilityWaitMs = Date.now() - visStart;\n options?.onTiming?.({\n totalMs: Date.now() - resolveStartMs,\n visibilityWaitMs,\n stabilityWaitMs: capturedStabilityMs,\n selectorUsed: selectorName,\n selectorAuthor: classifySelectorAuthor(selectorName),\n });\n logger().debug('[ElementResolver] Resolved element', { selector: selectorName });\n return locator;\n };\n\n // Build list of contexts to search\n const contexts: Array<{ name: string; context: LocatorContext }> = [];\n\n if (selectors.frameContext) {\n const frameSelector = selectors.frameContext.selector;\n const frameName = selectors.frameContext.name ?? selectors.frameContext.id ?? frameSelector;\n logger().debug('[ElementResolver] Using recorded frame context', {\n frameSelector,\n frameType: selectors.frameContext.type,\n });\n contexts.push({\n name: `recorded-frame:${frameName}`,\n context: page.frameLocator(frameSelector),\n });\n // Fallback: also try generic frame locators in case recorded selector is stale\n for (const { name, locator } of getFrameLocators(page)) {\n // Skip the main iframe shortcut when the recorded selector already targets it\n if (name === 'iframe:main' && frameSelector === 'iframe.designer-client-frame') continue;\n contexts.push({ name, context: locator });\n }\n } else {\n contexts.push({ name: 'page', context: page });\n for (const { name, locator } of getFrameLocators(page)) {\n contexts.push({ name, context: locator });\n }\n }\n\n const hasAlternatePlaywrightLocator = Boolean(\n selectors.playwrightLocatorCandidates &&\n Object.values(selectors.playwrightLocatorCandidates).some(\n (candidate) =>\n typeof candidate?.locator === 'string' &&\n candidate.locator.trim().length > 0 &&\n candidate.locator !== selectors.playwrightLocator\n )\n );\n\n let primaryPlaywrightLocatorForRetry: Locator | null = null;\n let shouldRetryPrimaryAfterCandidates = false;\n const retryPrimaryPlaywrightLocator = async (\n locator: Locator,\n locatorSource: string\n ): Promise<Locator | null> => {\n // Retry original locator with short poll to allow async auto-fill to propagate.\n const RETRY_TIMEOUT_MS = 2000;\n const RETRY_POLL_MS = 200;\n const retryStart = Date.now();\n while (Date.now() - retryStart < RETRY_TIMEOUT_MS) {\n await new Promise((r) => setTimeout(r, RETRY_POLL_MS));\n try {\n const retryCount = await locator.count();\n if (retryCount === 1) {\n logger().info('[ElementResolver] PlaywrightLocator resolved after auto-fill retry', {\n locator: locatorSource,\n waitedMs: Date.now() - retryStart,\n });\n const validated = await validateAndReturn(\n locator,\n 'PlaywrightLocator (auto-fill retry)'\n );\n if (validated) return validated;\n break;\n } else if (retryCount > 1) {\n break; // Multiple matches — stop retrying, fall through\n }\n } catch {\n break; // Error during retry — stop\n }\n }\n return null;\n };\n\n // Try playwrightLocator first (highest confidence — authored by selector agent)\n if (selectors.playwrightLocator) {\n try {\n const variableValues = options?.variableValues ?? {};\n const locator = evaluateLocatorChain(page, selectors.playwrightLocator, variableValues);\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error('PlaywrightLocator count timed out')),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n if (count === 1) {\n const validated = await validateAndReturn(locator, 'PlaywrightLocator (agentic)');\n if (validated) return validated;\n } else if (count > 1) {\n // V1: In strict mode, multi-match is an immediate failure — don't guess with .first()\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] PlaywrightLocator matched multiple elements', {\n strictMode: true,\n rejection: 'multi_match',\n selectorDesc: 'PlaywrightLocator (agentic)',\n matchCount: count,\n locator: selectors.playwrightLocator,\n });\n errors.push(`PlaywrightLocator matched ${count} elements`);\n } else {\n // Try first visible element\n const first = locator.first();\n const isVis = await first.isVisible().catch(() => false);\n if (isVis) {\n const validated = await validateAndReturn(\n first,\n 'PlaywrightLocator (agentic, first visible)'\n );\n if (validated) return validated;\n }\n errors.push(`PlaywrightLocator matched ${count} elements`);\n }\n } else {\n // V3: In strict mode, don't strip filters — they were authored for a reason\n if (!strictMode) {\n // 0 matches — try stripping .filter() clauses (auto-fill may not have propagated)\n const stripped = stripFilterClauses(selectors.playwrightLocator!);\n if (stripped) {\n try {\n const strippedLocator = evaluateLocatorChain(page, stripped, variableValues);\n const strippedCount = await Promise.race([\n strippedLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error('Stripped locator count timed out')),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n if (strippedCount === 1) {\n logger().warn('[ElementResolver] PlaywrightLocator resolved after stripping filter', {\n original: selectors.playwrightLocator,\n stripped,\n });\n const validated = await validateAndReturn(\n strippedLocator,\n 'PlaywrightLocator (filter-stripped)'\n );\n if (validated) return validated;\n }\n } catch {\n // Stripped locator also failed — fall through\n }\n }\n } else {\n logger().warn('[ElementResolver] [strict] Skipping filter stripping for PlaywrightLocator', {\n strictMode: true,\n rejection: 'filter_stripped',\n locator: selectors.playwrightLocator,\n });\n }\n\n if (!hasAlternatePlaywrightLocator) {\n const retried = await retryPrimaryPlaywrightLocator(\n locator,\n selectors.playwrightLocator\n );\n if (retried) return retried;\n } else {\n primaryPlaywrightLocatorForRetry = locator;\n shouldRetryPrimaryAfterCandidates = true;\n }\n\n errors.push('PlaywrightLocator matched 0 elements');\n }\n } catch (err) {\n errors.push(`PlaywrightLocator failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // V14: In strict mode, if playwrightLocator exists and failed, don't fall through\n // to weaker heuristic selectors that may match a different element\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] PlaywrightLocator failed, not falling through to heuristic selectors', {\n strictMode: true,\n rejection: 'locator_fallback_blocked',\n locator: selectors.playwrightLocator,\n errors,\n });\n }\n // Fall through to other strategies (only in non-strict mode)\n }\n\n const triedCandidateLocators = new Set<string>(\n selectors.playwrightLocator ? [selectors.playwrightLocator] : []\n );\n if (selectors.playwrightLocatorCandidates) {\n const candidateEntries = Object.entries(selectors.playwrightLocatorCandidates).filter(\n (entry): entry is [string, { locator: string }] =>\n typeof entry[1]?.locator === 'string' &&\n entry[1].locator.trim().length > 0 &&\n !triedCandidateLocators.has(entry[1].locator)\n );\n\n for (const [author, candidate] of candidateEntries) {\n triedCandidateLocators.add(candidate.locator);\n const selectorDesc = `PlaywrightLocator candidate (${author})`;\n try {\n const variableValues = options?.variableValues ?? {};\n const locator = evaluateLocatorChain(page, candidate.locator, variableValues);\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error(`${selectorDesc} count timed out`)),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n\n if (count === 1) {\n const validated = await validateAndReturn(locator, selectorDesc);\n if (validated) return validated;\n } else if (count > 1) {\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] PlaywrightLocator candidate matched multiple elements', {\n strictMode: true,\n rejection: 'multi_match',\n selectorDesc,\n matchCount: count,\n locator: candidate.locator,\n });\n errors.push(`${selectorDesc} matched ${count} elements`);\n } else {\n const first = locator.first();\n const isVis = await first.isVisible().catch(() => false);\n if (isVis) {\n const validated = await validateAndReturn(\n first,\n `${selectorDesc} (first visible)`\n );\n if (validated) return validated;\n }\n errors.push(`${selectorDesc} matched ${count} elements`);\n }\n } else {\n errors.push(`${selectorDesc} matched 0 elements`);\n }\n } catch (err) {\n errors.push(\n `${selectorDesc} failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n }\n\n if (\n shouldRetryPrimaryAfterCandidates &&\n primaryPlaywrightLocatorForRetry &&\n selectors.playwrightLocator\n ) {\n const retried = await retryPrimaryPlaywrightLocator(\n primaryPlaywrightLocatorForRetry,\n selectors.playwrightLocator\n );\n if (retried) return retried;\n }\n\n // V14: In strict mode, if playwrightLocator was present and failed, skip all heuristic fallbacks.\n // Heuristic selectors are less specific and may match a different element.\n const skipHeuristicFallbacks = strictMode && !!selectors.playwrightLocator;\n\n // Try data-testid selector first (across all contexts)\n if (selectors.testId && !skipHeuristicFallbacks) {\n for (const { name: contextName, context } of contexts) {\n try {\n const locator = context.getByTestId(selectors.testId);\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('TestId count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n // V2: Split single-match from multi-match. Single match is always accepted.\n // Multi-match: strict mode fails, non-strict picks .first() (legacy behavior).\n if (count === 1) {\n const validated = await validateAndReturn(locator.first(), `TestId selector (in ${contextName})`);\n if (validated) return validated;\n } else if (count > 1) {\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] TestId matched multiple elements', {\n strictMode: true,\n rejection: 'multi_match',\n selectorDesc: `TestId (\"${selectors.testId}\")`,\n matchCount: count,\n });\n errors.push(`TestId selector (\"${selectors.testId}\") matched ${count} elements`);\n } else {\n const first = locator.first();\n const validated = await validateAndReturn(first, `TestId selector (in ${contextName})`);\n if (validated) return validated;\n }\n }\n } catch (err) {\n if (contextName === 'page') {\n errors.push(\n `TestId selector failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n }\n\n if (!errors.some((e) => e.includes('TestId selector'))) {\n errors.push(`TestId selector (\"${selectors.testId}\") found no matches`);\n }\n }\n\n // Skip nameless role selectors when a CSS ID selector is available — the role\n // selector with only matchIndex is too fragile for inputs without accessible names\n const hasNamelessRole = selectors.role && !selectors.role.name;\n const hasNoParentScope =\n !selectors.parentContext?.role &&\n !selectors.parentContext?.css &&\n !selectors.parentContext?.parentChain?.length;\n const hasCSSFallback = !!selectors.css;\n const skipFragileRole = hasNamelessRole && hasNoParentScope && hasCSSFallback;\n\n // Try role-based selector (across all contexts)\n if (skipFragileRole) {\n logger().debug('[ElementResolver] Skipping nameless role selector in favor of CSS fallback', {\n role: selectors.role!.role,\n css: selectors.css,\n });\n }\n if (selectors.role && !skipFragileRole && !skipHeuristicFallbacks) {\n for (const { name: contextName, context } of contexts) {\n try {\n const result = await tryRoleSelector(context, selectors, contextName, strictMode);\n if (result) {\n const validated = await validateAndReturn(result.locator, result.selectorDesc);\n if (validated) return validated;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n errors.push(`Role selector failed in ${contextName}: ${msg}`);\n }\n }\n\n if (errors.length === 0) {\n errors.push(\n `Role selector (${selectors.role.role}${selectors.role.name ? `: \"${selectors.role.name}\"` : ''}) found no matches in page or frames`\n );\n }\n\n // CSS-based role fallback: when getByRole fails, try [role=\"...\"] with containsText filter\n if (selectors.containsText?.length) {\n logger().debug(\n '[ElementResolver] Trying CSS-based role selector fallback with containsText',\n {\n role: selectors.role.role,\n containsText: selectors.containsText,\n }\n );\n\n for (const { name: contextName, context } of contexts) {\n try {\n let cssRoleLocator = context.locator(`[role=\"${selectors.role.role}\"]`);\n for (const textPart of selectors.containsText) {\n if (textPart) {\n cssRoleLocator = cssRoleLocator.filter({ hasText: textPart });\n }\n }\n\n const count = await Promise.race([\n cssRoleLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('CSS role count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n\n if (count > 0) {\n const selectorDesc = `CSS role selector ([role=\"${selectors.role.role}\"] with containsText in ${contextName})`;\n\n if (count > 1) {\n logger().debug('[ElementResolver] Multiple CSS role matches, finding visible', {\n count,\n });\n const visibleElement = await findFirstVisibleElement(cssRoleLocator, count);\n if (visibleElement) {\n const validated = await validateAndReturn(\n visibleElement,\n `${selectorDesc} [visible]`\n );\n if (validated) return validated;\n }\n }\n\n const first = cssRoleLocator.first();\n const validated = await validateAndReturn(first, selectorDesc);\n if (validated) return validated;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger().debug('[ElementResolver] CSS role selector fallback failed', {\n context: contextName,\n error: msg,\n });\n }\n }\n }\n }\n\n // Try text selector (page only - frames already covered by role)\n if (selectors.text && !skipHeuristicFallbacks) {\n const normalizedText = normalizeMatchText(selectors.text.text);\n const { exact } = selectors.text;\n if (!normalizedText) {\n logger().debug('[ElementResolver] Skipping text selector due to empty normalized text');\n errors.push('Text selector skipped due to empty normalized text');\n } else {\n // For select elements, try getByLabel first (common pattern for labeled selects)\n if (requireSelect) {\n const selectScopedContexts = getParentScopedContexts(page, selectors.parentContext);\n for (const { searchCtx, scopeLabel } of selectScopedContexts) {\n try {\n const labelLocator = searchCtx.getByLabel(normalizedText, { exact: false });\n const count = await Promise.race([\n labelLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Label count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n if (count > 0) {\n const first = labelLocator.first();\n const validated = await validateAndReturn(first, `Label selector${scopeLabel}`);\n if (validated) return validated;\n }\n } catch (err) {\n errors.push(\n `Label selector${scopeLabel} failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n\n // Try finding a select associated with text via structure\n try {\n const selectNearText = searchCtx.locator(`select`).filter({\n has: searchCtx.locator(`..`).filter({ hasText: normalizedText }),\n });\n const selectCount = await Promise.race([\n selectNearText.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error('Select near text timed out')),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n if (selectCount > 0) {\n await verifyElementReady(selectNearText.first(), `Select near text${scopeLabel}`, true, undefined, strictMode);\n return selectNearText.first();\n }\n } catch {\n // Ignore - just a fallback attempt\n }\n }\n }\n\n // Build list of text variants to try: full text first, then primary text if different\n const textVariants: Array<{ searchText: string; variant: string }> = [\n { searchText: normalizedText, variant: '' },\n ];\n\n const primaryText = extractPrimaryText(normalizedText);\n if (primaryText) {\n textVariants.push({ searchText: primaryText, variant: '[partial]' });\n }\n\n // Try text selector variants in page and frames\n let fallbackLocator: { locator: Locator; desc: string } | null = null;\n\n for (const { searchText, variant } of textVariants) {\n for (const { name: contextName, context } of contexts) {\n const scopedContexts = getParentScopedContexts(context, selectors.parentContext);\n for (const { searchCtx, scopeLabel } of scopedContexts) {\n try {\n const locator = searchCtx.getByText(searchText, { exact: exact ?? false });\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Text count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n if (count > 0) {\n const selectorDesc = `Text selector (\"${searchText}\"${variant ? ` ${variant}` : ''}${scopeLabel} in ${contextName})`;\n\n if (scopeLabel) {\n logger().debug('[ElementResolver] Text selector parent-scoped', {\n parentRole: selectors.parentContext?.role,\n searchText,\n scopedCount: count,\n scopeLabel,\n });\n }\n\n if (count > 1) {\n let disambigLocator = locator;\n let disambigCount = count;\n\n logger().debug('[ElementResolver] Multiple text matches, trying disambiguation', {\n text: searchText,\n count,\n context: contextName,\n variant,\n scopeLabel,\n hasItemIndex: selectors.itemIndex !== undefined,\n hasRowIndex: selectors.rowIndex !== undefined,\n hasMatchIndex: selectors.parentContext?.matchIndex !== undefined,\n });\n\n // Strategy 0: Auto-scope to visible dialog when no parentContext\n if (!selectors.parentContext && !scopeLabel) {\n const dialogScoped = await filterToVisibleDialog(\n page,\n disambigLocator,\n disambigCount\n );\n if (dialogScoped && dialogScoped.count === 1) {\n const validated = await validateAndReturn(\n dialogScoped.locator.first(),\n `${selectorDesc} [dialog-scoped]`\n );\n if (validated) return validated;\n } else if (dialogScoped && dialogScoped.count > 0 && !strictMode) {\n // V10: In strict mode, only accept dialog scoping if it narrows to exactly 1\n disambigLocator = dialogScoped.locator;\n disambigCount = dialogScoped.count;\n }\n }\n\n // Strategy 1: Try data attribute matching (most deterministic)\n if (\n selectors.itemIndex !== undefined ||\n selectors.rowIndex !== undefined ||\n selectors.automationId\n ) {\n try {\n const allAttrs = await extractDisambiguationAttrsBatch(\n disambigLocator,\n disambigCount\n );\n for (let i = 0; i < allAttrs.length; i++) {\n const attrs = allAttrs[i];\n const matches =\n (selectors.itemIndex !== undefined &&\n attrs.itemIndex === selectors.itemIndex) ||\n (selectors.rowIndex !== undefined &&\n attrs.rowIndex === selectors.rowIndex) ||\n (selectors.automationId && attrs.automationId === selectors.automationId);\n\n if (matches) {\n const nth = disambigLocator.nth(i);\n // Validate role compatibility when role selector was attempted\n if (\n selectors.role &&\n !(await isRoleCompatible(nth, selectors.role.role))\n ) {\n logger().warn(\n '[ElementResolver] Text match rejected - incompatible role (data-attr)',\n {\n expectedRole: selectors.role.role,\n index: i,\n }\n );\n continue;\n }\n logger().debug(\n '[ElementResolver] Found text element by data attributes',\n { index: i, attrs }\n );\n const validated = await validateAndReturn(\n nth,\n `${selectorDesc} [data-attr]`\n );\n if (validated) return validated;\n }\n }\n } catch {\n // Fall through to next strategy\n }\n }\n\n // Strategy 2: Use matchIndex fallback\n if (selectors.parentContext?.matchIndex !== undefined) {\n const matchIndex = selectors.parentContext.matchIndex;\n if (matchIndex < disambigCount) {\n const indexed = disambigLocator.nth(matchIndex);\n // Validate role compatibility when role selector was attempted\n if (\n selectors.role &&\n !(await isRoleCompatible(indexed, selectors.role.role))\n ) {\n logger().warn(\n '[ElementResolver] Text match rejected - incompatible role (matchIndex)',\n {\n expectedRole: selectors.role.role,\n matchIndex,\n }\n );\n } else {\n logger().debug('[ElementResolver] Using text selector matchIndex', {\n matchIndex,\n });\n const validated = await validateAndReturn(\n indexed,\n `${selectorDesc} [index:${matchIndex}]`\n );\n if (validated) return validated;\n }\n }\n }\n\n // Strategy 2b: Prefer interactive element for click actions\n // When text matches both a label and an interactive element (e.g. combobox),\n // clicking the label won't open the combobox — prefer the interactive one.\n if (actionType === 'click') {\n const interactiveMatches: Locator[] = [];\n for (let i = 0; i < Math.min(disambigCount, 10); i++) {\n const nth = disambigLocator.nth(i);\n const isVis = await nth.isVisible().catch(() => false);\n if (!isVis) continue;\n if (await isInteractiveElement(nth)) {\n interactiveMatches.push(nth);\n }\n }\n if (interactiveMatches.length === 1) {\n logger().info(\n '[ElementResolver] Text disambiguation: preferring interactive element for click action',\n {\n text: searchText,\n count,\n interactiveCount: 1,\n }\n );\n const validated = await validateAndReturn(\n interactiveMatches[0]!,\n `${selectorDesc} [interactive-click]`\n );\n if (validated) return validated;\n } else if (interactiveMatches.length > 1) {\n logger().debug(\n '[ElementResolver] Text disambiguation: multiple interactive elements, falling through',\n {\n text: searchText,\n interactiveCount: interactiveMatches.length,\n }\n );\n }\n }\n\n // Strategy 2c: Prefer typeable element for type actions\n // When text matches both a label and a typeable element (e.g. textarea),\n // typing into the label won't work — prefer the typeable one.\n if (actionType === 'type') {\n const typeableMatches: Locator[] = [];\n for (let i = 0; i < Math.min(disambigCount, 10); i++) {\n const nth = disambigLocator.nth(i);\n const isVis = await nth.isVisible().catch(() => false);\n if (!isVis) continue;\n if (await isTypeableElement(nth)) {\n typeableMatches.push(nth);\n }\n }\n if (typeableMatches.length === 1) {\n logger().info(\n '[ElementResolver] Text disambiguation: preferring typeable element for type action',\n {\n text: searchText,\n count,\n typeableCount: 1,\n }\n );\n const validated = await validateAndReturn(\n typeableMatches[0]!,\n `${selectorDesc} [typeable-type]`\n );\n if (validated) return validated;\n } else if (typeableMatches.length > 1) {\n logger().debug(\n '[ElementResolver] Text disambiguation: multiple typeable elements, falling through',\n {\n text: searchText,\n typeableCount: typeableMatches.length,\n }\n );\n }\n }\n\n // Strategy 3: Find first visible element\n const visibleElement = await findFirstVisibleElement(\n disambigLocator,\n disambigCount\n );\n if (visibleElement) {\n // Validate role compatibility when role selector was attempted\n if (\n selectors.role &&\n !(await isRoleCompatible(visibleElement, selectors.role.role))\n ) {\n logger().warn(\n '[ElementResolver] Text match rejected - incompatible role (visible)',\n {\n expectedRole: selectors.role.role,\n }\n );\n } else {\n const validated = await validateAndReturn(\n visibleElement,\n `${selectorDesc} [visible]`\n );\n if (validated) return validated;\n }\n } else {\n logger().debug(\n '[ElementResolver] No visible elements found among matches, trying first anyway',\n {\n text: searchText,\n count: disambigCount,\n }\n );\n }\n }\n\n // Single match or fallback to first\n const first = locator.first();\n // Validate role compatibility when role selector was attempted\n if (selectors.role && !(await isRoleCompatible(first, selectors.role.role))) {\n logger().warn('[ElementResolver] Text match rejected - incompatible role', {\n expectedRole: selectors.role.role,\n text: searchText,\n context: contextName,\n });\n continue;\n }\n const validated = await validateAndReturn(first, selectorDesc);\n if (validated) return validated;\n }\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n if (contextName === 'page' && !variant) {\n errors.push(`Text selector failed: ${errorMsg}`);\n } else if (errorMsg.includes('not ready') || errorMsg.includes('Timeout')) {\n logger().debug('[ElementResolver] Text selector visibility check failed', {\n text: searchText,\n context: contextName,\n variant,\n error: errorMsg,\n });\n errors.push(\n `Text selector (${searchText}${variant} in ${contextName}) visibility failed`\n );\n\n if (contextName.includes('iframe')) {\n const fallbackSelector = `Text selector (\"${searchText}\"${variant ? ` ${variant}` : ''} in ${contextName})`;\n const loc = context.getByText(searchText, { exact: false });\n fallbackLocator = {\n locator: loc.first(),\n desc: `${fallbackSelector} [fallback]`,\n };\n }\n }\n }\n }\n }\n }\n\n // If we have a fallback locator from iframe partial match, try it without strict visibility\n if (fallbackLocator && !requireSelect) {\n logger().info('[ElementResolver] Trying fallback locator from iframe partial match', {\n desc: fallbackLocator.desc,\n });\n try {\n const isReady = await verifyElementReady(\n fallbackLocator.locator,\n fallbackLocator.desc,\n false,\n undefined,\n strictMode\n );\n if (!isReady) {\n logger().warn(\n '[ElementResolver] Fallback locator visibility check failed, proceeding anyway'\n );\n }\n logger().debug('[ElementResolver] Resolved element via fallback', {\n selector: fallbackLocator.desc,\n });\n return fallbackLocator.locator;\n } catch (err) {\n errors.push(\n `Fallback locator failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n if (!errors.some((e) => e.includes('Text selector'))) {\n errors.push(`Text selector (\"${normalizedText}\") found no matches`);\n }\n }\n }\n\n // Try ARIA label (page and frames)\n // Use exact matching to avoid substring false positives (e.g. \"Location Code\"\n // matching \"Open menu for Location Code\"). Falls back to inexact if exact finds nothing.\n if (selectors.ariaLabel && !skipHeuristicFallbacks) {\n for (const { name: contextName, context } of contexts) {\n try {\n let locator = context.getByLabel(selectors.ariaLabel, { exact: true });\n const exactCount = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error('ARIA label exact count timed out')),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n if (exactCount === 0) {\n locator = context.getByLabel(selectors.ariaLabel);\n }\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('ARIA label count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n if (count > 0) {\n const selectorDesc = `ARIA label selector (\"${selectors.ariaLabel}\" in ${contextName})`;\n\n if (count === 1) {\n const validated = await validateAndReturn(locator.first(), selectorDesc);\n if (validated) return validated;\n } else {\n // Multiple matches — try disambiguation strategies\n let ariaDisambigLocator = locator;\n let ariaDisambigCount = count;\n\n logger().debug('[ElementResolver] Multiple ARIA label matches, trying disambiguation', {\n ariaLabel: selectors.ariaLabel,\n count,\n context: contextName,\n hasChildFilter: !!selectors.childFilter,\n hasItemIndex: selectors.itemIndex !== undefined,\n hasMatchIndex: selectors.parentContext?.matchIndex !== undefined,\n });\n\n // Strategy 0: Auto-scope to visible dialog when no parentContext\n if (!selectors.parentContext) {\n const dialogScoped = await filterToVisibleDialog(\n page,\n ariaDisambigLocator,\n ariaDisambigCount\n );\n if (dialogScoped && dialogScoped.count === 1) {\n const validated = await validateAndReturn(\n dialogScoped.locator.first(),\n `${selectorDesc} [dialog-scoped]`\n );\n if (validated) return validated;\n } else if (dialogScoped && dialogScoped.count > 0 && !strictMode) {\n // V10: In strict mode, only accept dialog scoping if it narrows to exactly 1\n ariaDisambigLocator = dialogScoped.locator;\n ariaDisambigCount = dialogScoped.count;\n }\n }\n\n // Strategy 1: Try childFilter disambiguation (e.g., filter by child img alt text)\n if (selectors.childFilter) {\n const filtered = ariaDisambigLocator.filter({\n has: context.getByRole(\n selectors.childFilter.role as Parameters<Page['getByRole']>[0],\n { name: selectors.childFilter.name }\n ),\n });\n const filteredCount = await Promise.race([\n filtered.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error('childFilter count timed out')),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n if (filteredCount === 1) {\n const validated = await validateAndReturn(\n filtered.first(),\n `${selectorDesc} [childFilter]`\n );\n if (validated) return validated;\n }\n }\n\n // Strategy 2: Try data attribute matching\n if (\n selectors.itemIndex !== undefined ||\n selectors.rowIndex !== undefined ||\n selectors.automationId\n ) {\n try {\n const allAttrs = await extractDisambiguationAttrsBatch(\n ariaDisambigLocator,\n ariaDisambigCount\n );\n for (let i = 0; i < allAttrs.length; i++) {\n const attrs = allAttrs[i];\n const matches =\n (selectors.itemIndex !== undefined &&\n attrs.itemIndex === selectors.itemIndex) ||\n (selectors.rowIndex !== undefined && attrs.rowIndex === selectors.rowIndex) ||\n (selectors.automationId && attrs.automationId === selectors.automationId);\n\n if (matches) {\n logger().debug(\n '[ElementResolver] Found ARIA label element by data attributes',\n { index: i, attrs }\n );\n const validated = await validateAndReturn(\n ariaDisambigLocator.nth(i),\n `${selectorDesc} [data-attr]`\n );\n if (validated) return validated;\n }\n }\n } catch {\n // Fall through to next strategy\n }\n }\n\n // Strategy 3: Use matchIndex fallback\n if (selectors.parentContext?.matchIndex !== undefined) {\n const matchIndex = selectors.parentContext.matchIndex;\n if (matchIndex < ariaDisambigCount) {\n const indexed = ariaDisambigLocator.nth(matchIndex);\n logger().debug('[ElementResolver] Using ARIA label matchIndex', { matchIndex });\n const validated = await validateAndReturn(\n indexed,\n `${selectorDesc} [index:${matchIndex}]`\n );\n if (validated) return validated;\n }\n }\n\n // In verify mode, treat as selector miss so discoverParentContext\n // can try to find a narrower parent scope. In replay mode, pick the\n // first visible match as a best-effort (better than failing outright).\n if (mode === 'verify') {\n logger().warn(\n '[ElementResolver] No ARIA label disambiguation succeeded (verify mode, treating as miss)',\n {\n ariaLabel: selectors.ariaLabel,\n count: ariaDisambigCount,\n }\n );\n } else {\n const visibleElement = await findFirstVisibleElement(\n ariaDisambigLocator,\n ariaDisambigCount\n );\n if (visibleElement) {\n logger().warn(\n '[ElementResolver] No ARIA label disambiguation succeeded, using first visible (replay mode)',\n {\n ariaLabel: selectors.ariaLabel,\n count: ariaDisambigCount,\n }\n );\n const validated = await validateAndReturn(\n visibleElement,\n `${selectorDesc} [visible]`\n );\n if (validated) return validated;\n }\n logger().warn('[ElementResolver] No ARIA label disambiguation succeeded', {\n ariaLabel: selectors.ariaLabel,\n count: ariaDisambigCount,\n });\n }\n }\n }\n } catch (err) {\n if (contextName === 'page') {\n errors.push(\n `ARIA label selector failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n }\n\n if (!errors.some((e) => e.includes('ARIA label'))) {\n errors.push(`ARIA label selector (\"${selectors.ariaLabel}\") found no matches`);\n }\n }\n\n // Try placeholder text (page and frames)\n if (selectors.placeholder && !skipHeuristicFallbacks) {\n for (const { name: contextName, context } of contexts) {\n try {\n const locator = context.getByPlaceholder(selectors.placeholder, { exact: false });\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Placeholder count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n if (count > 0) {\n const first = locator.first();\n const validated = await validateAndReturn(\n first,\n `Placeholder selector (in ${contextName})`\n );\n if (validated) return validated;\n }\n } catch (err) {\n if (contextName === 'page') {\n errors.push(\n `Placeholder selector failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n }\n\n if (!errors.some((e) => e.includes('Placeholder selector'))) {\n errors.push(`Placeholder selector (\"${selectors.placeholder}\") found no matches`);\n }\n }\n\n // Try CSS selector as a last resort. Search the same page+frame `contexts` as\n // the role/text paths (so a target captured inside an iframe resolves in the\n // frame, not the top page), and honor the full parentContext (role /\n // containsText / css scopes) within each — mirroring the text-selector path.\n // Without this, a `css` anchor like `[data-field=\"…\"]` that's only unique\n // within an ancestor would match globally and pick the wrong element.\n if (selectors.css && !skipHeuristicFallbacks) {\n const pc = selectors.parentContext;\n // A scoped css anchor (stable-id / row-variable / ancestor) exists ONLY to\n // single out one target within its scope. For those, `count !== 1` is an\n // ambiguity — treat it as a miss (fall back to the agent), never pick-first\n // and never widen to the global page. Unscoped, globally-unique css\n // predicates (semanticClass / iconClass / imgSrc) keep the legacy\n // pick-first behavior.\n const scoped = Boolean(pc && (pc.css || pc.role || pc.containsText || pc.parentChain?.length));\n\n for (const { name: contextName, context } of contexts) {\n const cssScopes = getParentScopedContexts(context, selectors.parentContext);\n for (const { searchCtx, scopeLabel } of cssScopes) {\n // Never search the unscoped/global page for a scoped anchor.\n if (scoped && scopeLabel === '') continue;\n try {\n const locator = searchCtx.locator(selectors.css);\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('CSS count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n\n if (scoped) {\n if (count === 1) {\n const validated = await validateAndReturn(\n locator.first(),\n `CSS selector${scopeLabel} (in ${contextName})`\n );\n if (validated) return validated;\n } else if (count > 1) {\n errors.push(\n `CSS selector${scopeLabel} (in ${contextName}) ambiguous — ${count} matches; treating as miss`\n );\n }\n continue;\n }\n\n if (count > 1) {\n // Multiple CSS matches — try visible element first (handles hidden duplicates)\n const visibleElement = await findFirstVisibleElement(locator, count);\n if (visibleElement) {\n const validated = await validateAndReturn(\n visibleElement,\n `CSS selector (in ${contextName}) [visible]`\n );\n if (validated) return validated;\n }\n }\n if (count > 0) {\n const validated = await validateAndReturn(locator.first(), `CSS selector (in ${contextName})`);\n if (validated) return validated;\n }\n } catch (err) {\n errors.push(\n `CSS selector${scopeLabel} (in ${contextName}) failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n }\n errors.push(`CSS selector (\"${selectors.css}\") found no matches`);\n }\n\n // Structural fallback: for dynamic text selectors, try role + hasText with current value\n if (selectors.dynamicText && options?.variableValues && selectors.role && !requireSelect && !skipHeuristicFallbacks) {\n const { key } = selectors.dynamicText;\n const currentValue = options.variableValues[key];\n\n if (currentValue) {\n logger().debug('[ElementResolver] Trying structural fallback for dynamic text', {\n role: selectors.role.role,\n currentValue,\n });\n\n for (const { name: contextName, context } of contexts) {\n try {\n const roleLocator = context.getByRole(\n selectors.role.role as Parameters<Page['getByRole']>[0]\n );\n const filtered = roleLocator.filter({ hasText: currentValue });\n const count = await Promise.race([\n filtered.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error('Dynamic fallback count timed out')),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n\n if (count > 0) {\n const first = filtered.first();\n const isReady = await verifyElementReady(\n first,\n `Dynamic fallback (${selectors.role.role} hasText:${currentValue} in ${contextName})`,\n false,\n undefined,\n strictMode\n );\n if (isReady) {\n logger().info('[ElementResolver] Resolved via dynamic text structural fallback', {\n role: selectors.role.role,\n currentValue,\n context: contextName,\n });\n return first;\n }\n }\n } catch (err) {\n logger().debug('[ElementResolver] Dynamic fallback failed for context', {\n context: contextName,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n }\n }\n\n // Resolution failed — build structured diagnostics\n const totalDurationMs = Date.now() - resolveStartMs;\n const strategies: Array<{ type: string; tried: boolean; result: string }> = [\n {\n type: 'testId',\n tried: !!selectors.testId,\n result: selectors.testId\n ? (errors.find((e) => e.includes('TestId')) ?? 'no matches')\n : 'not available',\n },\n {\n type: 'role',\n tried: !!selectors.role,\n result: selectors.role\n ? (errors.find((e) => e.includes('Role selector')) ?? 'no matches')\n : 'not available',\n },\n {\n type: 'text',\n tried: !!selectors.text,\n result: selectors.text\n ? (errors.find((e) => e.includes('Text selector')) ?? 'no matches')\n : 'not available',\n },\n {\n type: 'ariaLabel',\n tried: !!selectors.ariaLabel,\n result: selectors.ariaLabel\n ? (errors.find((e) => e.includes('ARIA label')) ?? 'no matches')\n : 'not available',\n },\n {\n type: 'placeholder',\n tried: !!selectors.placeholder,\n result: selectors.placeholder\n ? (errors.find((e) => e.includes('Placeholder')) ?? 'no matches')\n : 'not available',\n },\n {\n type: 'css',\n tried: !!selectors.css,\n result: selectors.css\n ? (errors.find((e) => e.includes('CSS selector')) ?? 'no matches')\n : 'not available',\n },\n ];\n\n const errorMsg = `Could not find ${elementTypeName} with any selector strategy. Tried: ${errors.join('; ')}`;\n\n if (mode === 'verify') {\n logger().debug('[ElementResolver] Element resolution failed (verify mode)', {\n strategies: strategies.filter((s) => s.tried),\n totalDurationMs,\n });\n return null;\n }\n\n logger().error('[ElementResolver] Element resolution failed', {\n strategies,\n totalDurationMs,\n selectorSummary: {\n testId: selectors.testId,\n role: selectors.role?.role,\n roleName: selectors.role?.name,\n parentContext: selectors.parentContext?.role,\n parentContextCss: selectors.parentContext?.css,\n text: selectors.text?.text,\n ariaLabel: selectors.ariaLabel,\n },\n });\n throw new Error(errorMsg);\n}\n","/**\n * Selector Derivation\n *\n * Derives stable selectors from Playwright accessibility snapshots.\n * These selectors can be used to locate elements during cache replay\n * even though the ephemeral refs have changed.\n *\n * Selector priority (tried in order during replay):\n * 1. data-testid (most stable when available)\n * 2. Role + name (a11y-focused apps)\n * 3. Label text (getByLabel)\n * 4. Placeholder text\n * 5. Text content\n * 6. CSS selector (fallback, least stable)\n *\n * @module workflows/cache/selector-derivation\n * @see docs/cache-replay.md\n */\n\nimport type { Page, Locator } from 'playwright';\nimport type {\n SelectorStrategy,\n ElementInfo,\n ParentContext,\n ParentContextDynamicText,\n FrameContext,\n} from '@chatsdet/types';\nimport { createLogger } from './logger.js';\nimport { resolveElement, type LocatorContext } from './element-resolver.js';\n\n// Lazy logger to avoid env validation at module load time (for tests)\nlet _logger: ReturnType<typeof createLogger> | null = null;\nconst getLogger = () => {\n if (!_logger) {\n _logger = createLogger({ module: 'SelectorDerivation' });\n }\n return _logger;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Selector Verification Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Result of verifying a single selector type\n */\ninterface SelectorVerificationResult {\n /** The selector type that was verified */\n selectorType: 'testId' | 'role' | 'ariaLabel' | 'placeholder' | 'text';\n /** Whether the selector was successfully verified */\n verified: boolean;\n /** Number of elements that matched the selector */\n matchCount: number;\n /** Whether the resolved element coordinates match the original */\n coordinatesMatch: boolean;\n /** Original element center coordinates */\n originalCoords?: { x: number; y: number };\n /** Resolved element center coordinates */\n resolvedCoords?: { x: number; y: number };\n /** Reason for rejection (if not verified) */\n reason?: string;\n /** Parent context if disambiguation was needed */\n parentContext?: ParentContext;\n}\n\n/**\n * Result of verifying all selectors for an element\n */\ninterface SelectorVerificationSummary {\n /** Selectors that passed verification (only verified selectors included) */\n verifiedSelectors: SelectorStrategy;\n /** Individual verification results for each selector type */\n results: SelectorVerificationResult[];\n /** Whether any selector was successfully verified */\n anyVerified: boolean;\n}\n\n/**\n * Options for selector verification\n */\ninterface SelectorVerificationOptions {\n /** @deprecated No longer used — DOM identity comparison replaced coordinates */\n tolerancePx?: number;\n /** Max depth for parent scope search (default: 5) */\n maxParentDepth?: number;\n /** Timeout in ms for locator operations (default: 5000) */\n timeoutMs?: number;\n /**\n * For typeable/form controls, skip weak text selector probing once a stronger\n * selector is available. This prevents form labels/icons from becoming\n * expensive getByText() candidates during recording.\n */\n skipTextWhenStrong?: boolean;\n}\n\ntype SelectorType = 'testId' | 'role' | 'ariaLabel' | 'placeholder' | 'text';\n\n/**\n * Roles eligible for ariaLabel fallback from accessibleName.\n * These are interactive/input roles that commonly use aria-labelledby for\n * labeling and where getByRole name matching can be unreliable.\n */\nconst LABEL_FALLBACK_ROLES = new Set([\n 'combobox',\n 'textbox',\n 'searchbox',\n 'listbox',\n 'spinbutton',\n 'slider',\n 'switch',\n 'checkbox',\n 'radio',\n 'menuitemcheckbox',\n 'menuitemradio',\n 'generic',\n 'none',\n 'presentation',\n]);\n\nconst TYPEABLE_SELECTOR_ROLES = new Set(['textbox', 'searchbox', 'spinbutton', 'combobox', 'input']);\n\nconst stripPrivateUseGlyphs = (value: string): string => value.replace(/[\\uE000-\\uF8FF]/g, '');\n\nconst normalizeText = (value: string): string =>\n stripPrivateUseGlyphs(value).replace(/\\s+/g, ' ').trim();\n\nconst escapeCssAttributeValue = (value: string): string =>\n value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n\nconst buildFormParentCss = (opts: { name?: string | null; id?: string | null }): string => {\n if (opts.name && opts.name.trim().length > 0) {\n return `form[name=\"${escapeCssAttributeValue(opts.name.trim())}\"]`;\n }\n if (opts.id && opts.id.trim().length > 0) {\n return `form[id=\"${escapeCssAttributeValue(opts.id.trim())}\"]`;\n }\n return 'form';\n};\n\nconst stripNoiseSuffixes = (value: string): string =>\n value\n .replace(/\\s+Not bookmarked$/i, '')\n .replace(/\\s+Bookmarked$/i, '')\n .replace(/\\s+\\u2026$/i, '')\n .replace(/\\s+…$/i, '')\n .trim();\n\nconst buildContainsText = (elementInfo: ElementInfo): string[] | undefined => {\n const raw = elementInfo.textContent || elementInfo.accessibleName;\n if (!raw) return undefined;\n const normalized = stripNoiseSuffixes(normalizeText(raw));\n if (!normalized || normalized.length < 3) return undefined;\n return [normalized];\n};\n\n/**\n * Derive stable selectors from an element's info.\n *\n * @param elementInfo - Element info extracted from snapshot\n * @returns Selector strategy with multiple fallback selectors\n */\nexport function deriveSelectorsFromElementInfo(elementInfo: ElementInfo): SelectorStrategy {\n const selectors: SelectorStrategy = {};\n\n // 0. data-testid selector (most stable when available)\n if (elementInfo.dataTestId) {\n selectors.testId = elementInfo.dataTestId;\n }\n\n const roleName = elementInfo.accessibleName || elementInfo.labelText || elementInfo.ariaLabel;\n\n // 1. Role-based selector (most stable)\n if (\n elementInfo.role &&\n elementInfo.role !== 'generic' &&\n elementInfo.role !== 'text' &&\n elementInfo.role !== 'none' &&\n elementInfo.role !== 'presentation'\n ) {\n selectors.role = {\n role: elementInfo.role,\n name: roleName,\n // Use non-exact matching for resilience to whitespace differences\n exact: roleName ? false : undefined,\n };\n }\n\n const containsText = buildContainsText(elementInfo);\n if (\n containsText &&\n elementInfo.role &&\n ['row', 'listitem', 'option', 'menuitem', 'treeitem', 'gridcell', 'article'].includes(\n elementInfo.role\n )\n ) {\n selectors.containsText = containsText;\n }\n\n // 2. Label selector (covers aria-label, <label> text, and aria-labelledby)\n if (elementInfo.labelText || elementInfo.ariaLabel) {\n selectors.ariaLabel = elementInfo.labelText || elementInfo.ariaLabel;\n } else if (\n elementInfo.accessibleName &&\n elementInfo.accessibleName.length >= 3 &&\n elementInfo.role &&\n LABEL_FALLBACK_ROLES.has(elementInfo.role)\n ) {\n // For interactive/input roles that commonly use aria-labelledby for labeling,\n // fall back to the computed accessible name. getByLabel() uses DOM label\n // relationships which is a genuinely different matching mechanism than\n // getByRole(), providing resilience when one fails (e.g. Dynamics 365\n // comboboxes using aria-labelledby).\n selectors.ariaLabel = elementInfo.accessibleName;\n }\n\n // 3. Placeholder selector (inputs)\n if (elementInfo.placeholder) {\n selectors.placeholder = elementInfo.placeholder;\n }\n\n // 4. Text content selector (visible text)\n // Apply same 3-char minimum as buildContainsText to avoid short-string false positives\n if (elementInfo.textContent) {\n const normalizedForLength = normalizeText(elementInfo.textContent);\n if (normalizedForLength.length >= 3) {\n selectors.text = {\n text: elementInfo.textContent,\n exact: false, // Allow partial match for robustness\n };\n }\n }\n\n // 5. Parent context for disambiguation\n if (elementInfo.parentRole || elementInfo.parentName) {\n const parentCss = elementInfo.parentRole === 'form' ? 'form' : undefined;\n selectors.parentContext = {\n role: elementInfo.parentRole,\n name: elementInfo.parentName,\n css: parentCss,\n nameFromHeading: elementInfo.parentNameFromHeading || undefined,\n };\n }\n\n // 6. Frame context for elements inside iframes\n if (elementInfo.frameContext) {\n selectors.frameContext = elementInfo.frameContext;\n }\n\n // 7. Data attributes for list/table disambiguation\n if (elementInfo.itemIndex !== undefined) {\n selectors.itemIndex = elementInfo.itemIndex;\n }\n if (elementInfo.ariaRowIndex !== undefined) {\n selectors.rowIndex = elementInfo.ariaRowIndex;\n }\n if (elementInfo.automationId) {\n selectors.automationId = elementInfo.automationId;\n }\n\n // 8. Child filter for disambiguation (e.g., child img alt text)\n if (elementInfo.childImgAlt) {\n selectors.childFilter = { role: 'img', name: elementInfo.childImgAlt };\n }\n\n return selectors;\n}\n\nexport { buildLocatorString } from '@chatsdet/recording';\n\n\n/**\n * Sanitize tool arguments for caching.\n *\n * Removes ephemeral refs and other non-stable data.\n *\n * @param args - Original tool arguments\n * @returns Sanitized arguments safe for caching\n */\nexport function sanitizeArgsForCache(args: Record<string, unknown>): Record<string, unknown> {\n const sanitized: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(args)) {\n // Skip ephemeral refs - these will be resolved via selectors during replay\n if (key === 'ref' || key === 'startRef' || key === 'endRef') {\n continue;\n }\n\n // Skip signal and timeout options - these are runtime-specific\n if (key === 'signal' || key === 'timeoutMs') {\n continue;\n }\n\n // Deep clone arrays (like fields in fillForm)\n if (Array.isArray(value)) {\n sanitized[key] = value.map((item) => {\n if (typeof item === 'object' && item !== null) {\n return sanitizeArgsForCache(item as Record<string, unknown>);\n }\n return item;\n });\n continue;\n }\n\n // Keep other values\n sanitized[key] = value;\n }\n\n return sanitized;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Selector Verification\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Default configuration for selector verification\n */\nconst DEFAULT_VERIFICATION_OPTIONS: Required<SelectorVerificationOptions> = {\n tolerancePx: 10,\n maxParentDepth: 5,\n timeoutMs: 5000,\n skipTextWhenStrong: false,\n};\n\n/**\n * Semantic roles that make good scoping parents for disambiguation\n */\nconst SEMANTIC_PARENT_ROLES = [\n 'dialog',\n 'form',\n 'region',\n 'navigation',\n 'main',\n 'article',\n 'section',\n 'complementary',\n 'banner',\n 'contentinfo',\n 'alertdialog',\n 'menu',\n 'menubar',\n 'tablist',\n 'tabpanel',\n 'toolbar',\n 'treegrid',\n 'grid',\n 'listbox',\n];\n\n/**\n * Compare two Playwright locators by DOM identity.\n *\n * Uses page.evaluate to check `a === b` in the browser.\n * Returns false on any failure (timeout, detached element, etc.).\n */\nasync function isSameDOMElement(\n page: Page,\n locatorA: Locator,\n locatorB: Locator,\n timeoutMs: number\n): Promise<boolean> {\n let handleA: Awaited<ReturnType<Locator['elementHandle']>> | null = null;\n let handleB: Awaited<ReturnType<Locator['elementHandle']>> | null = null;\n try {\n [handleA, handleB] = await Promise.race([\n Promise.all([locatorA.elementHandle(), locatorB.elementHandle()]),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('elementHandle timeout')), timeoutMs)\n ),\n ]);\n if (!handleA || !handleB) return false;\n const same = await page.evaluate(([a, b]) => a === b, [handleA, handleB] as const);\n return same;\n } catch {\n return false;\n } finally {\n await handleA?.dispose().catch(() => {});\n await handleB?.dispose().catch(() => {});\n }\n}\n\n/**\n * Build a minimal SelectorStrategy containing only the specified selector type.\n * Preserves data attributes, frame context, and existing parent context for\n * disambiguation, so the shared resolver exercises the exact same code path as replay.\n */\nfunction buildMinimalStrategy(\n selectors: SelectorStrategy,\n selectorType: SelectorType,\n parentContextOverride?: ParentContext\n): SelectorStrategy | null {\n const strategy: SelectorStrategy = {};\n\n switch (selectorType) {\n case 'testId':\n if (!selectors.testId) return null;\n strategy.testId = selectors.testId;\n break;\n case 'role':\n if (!selectors.role) return null;\n strategy.role = { ...selectors.role };\n if (selectors.containsText) strategy.containsText = [...selectors.containsText];\n break;\n case 'ariaLabel':\n if (!selectors.ariaLabel) return null;\n strategy.ariaLabel = selectors.ariaLabel;\n break;\n case 'placeholder':\n if (!selectors.placeholder) return null;\n strategy.placeholder = selectors.placeholder;\n break;\n case 'text':\n if (!selectors.text) return null;\n strategy.text = { ...selectors.text };\n break;\n }\n\n // Preserve data attributes for disambiguation\n if (selectors.itemIndex !== undefined) strategy.itemIndex = selectors.itemIndex;\n if (selectors.rowIndex !== undefined) strategy.rowIndex = selectors.rowIndex;\n if (selectors.automationId) strategy.automationId = selectors.automationId;\n if (selectors.frameContext) strategy.frameContext = selectors.frameContext;\n if (selectors.childFilter) strategy.childFilter = selectors.childFilter;\n\n // Use override or existing parent context\n if (parentContextOverride) {\n strategy.parentContext = parentContextOverride;\n } else if (selectors.parentContext) {\n strategy.parentContext = selectors.parentContext;\n }\n\n return strategy;\n}\n\nconst hasStrongFormSelector = (selectors: SelectorStrategy): boolean =>\n Boolean(\n selectors.testId ||\n (selectors.role?.role &&\n TYPEABLE_SELECTOR_ROLES.has(selectors.role.role) &&\n selectors.role.name) ||\n selectors.ariaLabel ||\n selectors.placeholder\n );\n\nconst shouldSkipTextVerification = (\n selectors: SelectorStrategy,\n options: Pick<SelectorVerificationOptions, 'skipTextWhenStrong'>\n): boolean =>\n Boolean(\n options.skipTextWhenStrong &&\n selectors.text &&\n selectors.role?.role &&\n TYPEABLE_SELECTOR_ROLES.has(selectors.role.role) &&\n hasStrongFormSelector(selectors)\n );\n\nexport function getSelectorTypesForVerification(\n selectors: SelectorStrategy,\n options: Pick<SelectorVerificationOptions, 'skipTextWhenStrong'> = {}\n): SelectorType[] {\n const selectorTypes: SelectorType[] = ['testId', 'role', 'ariaLabel', 'placeholder'];\n if (!shouldSkipTextVerification(selectors, options)) {\n selectorTypes.push('text');\n }\n return selectorTypes;\n}\n\n/**\n * Walk up from the target element to the nearest row-like ancestor and\n * propose candidate text tokens that would uniquely identify that row.\n *\n * Returns the row's ARIA role plus a ranked list of text candidates to try\n * as `.filter({ hasText: … })` anchors. Callers should verify each candidate\n * against the actual selector before committing it.\n */\nasync function findRowAnchor(\n originalLocator: Locator,\n timeoutMs: number\n): Promise<{ role: string; candidates: string[] } | null> {\n try {\n const result = await Promise.race([\n originalLocator.evaluate((el) => {\n const ROW_ROLES = new Set([\n 'row',\n 'listitem',\n 'gridcell',\n 'cell',\n 'treeitem',\n 'option',\n ]);\n const implicitRoleFor = (tag: string): string | null => {\n switch (tag) {\n case 'tr':\n return 'row';\n case 'li':\n return 'listitem';\n case 'td':\n return 'cell';\n case 'th':\n return 'cell';\n default:\n return null;\n }\n };\n\n // Walk up to find the nearest row-like ancestor.\n let current: Element | null = el.parentElement;\n let rowEl: Element | null = null;\n let rowRole: string | null = null;\n while (current) {\n const roleAttr = current.getAttribute('role');\n const tag = current.tagName.toLowerCase();\n const role = roleAttr || implicitRoleFor(tag);\n if (role && ROW_ROLES.has(role)) {\n rowEl = current;\n rowRole = role;\n break;\n }\n current = current.parentElement;\n }\n if (!rowEl || !rowRole) return null;\n\n const targetText = (el.textContent || '').trim().toLowerCase();\n const ariaLabel = rowEl.getAttribute('aria-label')?.trim();\n\n // Collect candidate text tokens from row descendants, excluding the\n // target element's own subtree.\n const texts: string[] = [];\n const seen = new Set<string>();\n const pushText = (raw: string | null | undefined) => {\n if (!raw) return;\n const t = raw.trim();\n if (t.length < 3) return;\n if (t.length > 120) return;\n const key = t.toLowerCase();\n if (key === targetText) return;\n if (targetText.length > 0 && key.includes(targetText)) return;\n if (targetText.length > 0 && targetText.includes(key)) return;\n if (seen.has(key)) return;\n seen.add(key);\n texts.push(t);\n };\n\n if (ariaLabel) pushText(ariaLabel);\n\n // Prefer cell-level descendants first; they tend to carry the\n // distinguishing value (e.g. a variable name).\n const cellSelectors = [\n '[role=\"gridcell\"]',\n '[role=\"cell\"]',\n '[role=\"rowheader\"]',\n 'th',\n 'td',\n ];\n for (const sel of cellSelectors) {\n for (const cell of Array.from(rowEl.querySelectorAll(sel))) {\n if (el.contains(cell) || cell.contains(el)) continue;\n pushText(cell.textContent);\n if (texts.length >= 4) break;\n }\n if (texts.length >= 4) break;\n }\n\n // Fall back to any visible text nodes not inside the target.\n if (texts.length === 0) {\n const walker = document.createTreeWalker(rowEl, NodeFilter.SHOW_TEXT, {\n acceptNode(node) {\n if (!node.textContent || !node.textContent.trim()) {\n return NodeFilter.FILTER_REJECT;\n }\n let ancestor: Node | null = node;\n while (ancestor) {\n if (ancestor === el) return NodeFilter.FILTER_REJECT;\n ancestor = ancestor.parentNode;\n }\n return NodeFilter.FILTER_ACCEPT;\n },\n });\n let node = walker.nextNode();\n while (node && texts.length < 4) {\n pushText(node.textContent);\n node = walker.nextNode();\n }\n }\n\n return { role: rowRole, candidates: texts };\n }),\n new Promise<null>((_, reject) =>\n setTimeout(() => reject(new Error('findRowAnchor timeout')), timeoutMs)\n ),\n ]);\n\n if (!result) return null;\n const normalizedCandidates = result.candidates\n .map((raw) => stripNoiseSuffixes(normalizeText(raw)))\n .filter((t): t is string => !!t && t.length >= 3)\n // Prefer shorter, distinctive tokens over long blobs.\n .sort((a, b) => a.length - b.length)\n .slice(0, 4);\n if (normalizedCandidates.length === 0) return null;\n return { role: result.role, candidates: normalizedCandidates };\n } catch {\n return null;\n }\n}\n\n/**\n * Try to discover a parent context that disambiguates the selector.\n *\n * Walks DOM ancestry of all matching elements to find a semantic parent scope\n * that makes the selector unique. Uses the shared resolver to verify each\n * candidate, ensuring the same code path as replay.\n *\n * @param page - Playwright page\n * @param selectors - The selector strategy being verified\n * @param selectorType - Which selector type to scope\n * @param originalLocator - Locator for the original element (via aria-ref)\n * @param options - Verification options\n * @returns Parent context, or null\n */\nasync function discoverParentContext(\n page: Page,\n selectors: SelectorStrategy,\n selectorType: 'testId' | 'role' | 'ariaLabel' | 'placeholder' | 'text',\n originalLocator: Locator,\n options: Required<SelectorVerificationOptions>\n): Promise<{\n parentContext: ParentContext;\n} | null> {\n const { timeoutMs, maxParentDepth } = options;\n const logger = getLogger();\n\n // Determine the correct context: use frame locator for iframe-scoped selectors\n const context: LocatorContext = selectors.frameContext?.selector\n ? page.frameLocator(selectors.frameContext.selector)\n : page;\n\n // Strategy 0: Row-anchor scoping. When the target sits inside a row-like\n // ancestor (role=row/listitem/gridcell/treeitem/option), prefer anchoring\n // to that row using a unique text token inside it. This is almost always\n // more stable than the nearest landmark (main/form/region), which is what\n // Strategy 1 would otherwise pick.\n try {\n const rowCandidate = await findRowAnchor(originalLocator, timeoutMs);\n if (rowCandidate && rowCandidate.candidates.length > 0) {\n for (const candidateText of rowCandidate.candidates) {\n const candidateParent: ParentContext = {\n role: rowCandidate.role,\n containsText: candidateText,\n };\n const strategyWithParent = buildMinimalStrategy(selectors, selectorType, candidateParent);\n if (!strategyWithParent) continue;\n try {\n const resolved = await resolveElement(page, strategyWithParent, timeoutMs, {\n mode: 'verify',\n });\n if (!resolved) continue;\n const isSame = await isSameDOMElement(page, originalLocator, resolved, timeoutMs);\n if (!isSame) continue;\n logger.debug('[SelectorDerivation] Found unique row anchor', {\n selectorType,\n parentContext: candidateParent,\n });\n return { parentContext: candidateParent };\n } catch {\n continue;\n }\n }\n }\n } catch (err) {\n logger.debug('[SelectorDerivation] Row-anchor strategy error', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n // Strategy 1: Simple parent scoping - try each semantic parent role\n try {\n for (const parentRole of SEMANTIC_PARENT_ROLES) {\n const parentLocators = context.getByRole(parentRole as Parameters<Page['getByRole']>[0]);\n\n let parentCount: number;\n try {\n parentCount = await Promise.race([\n parentLocators.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Count timeout')), timeoutMs)\n ),\n ]);\n } catch {\n continue;\n }\n\n for (let i = 0; i < parentCount; i++) {\n const parentLocator = parentLocators.nth(i);\n\n try {\n // Check if original element is a DOM descendant of this parent\n let origHandle: Awaited<ReturnType<Locator['elementHandle']>> | null = null;\n let parentHandle: Awaited<ReturnType<Locator['elementHandle']>> | null = null;\n let isWithinParent = false;\n try {\n [parentHandle, origHandle] = await Promise.race([\n Promise.all([parentLocator.elementHandle(), originalLocator.elementHandle()]),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('elementHandle timeout')), timeoutMs)\n ),\n ]);\n if (parentHandle && origHandle) {\n isWithinParent = await page.evaluate(([p, c]) => p.contains(c), [\n parentHandle,\n origHandle,\n ] as const);\n }\n } catch {\n isWithinParent = false;\n } finally {\n await parentHandle?.dispose().catch(() => {});\n await origHandle?.dispose().catch(() => {});\n }\n\n if (!isWithinParent) continue;\n\n // Get parent's accessible name\n let parentName: string | undefined;\n let nameFromHeading: boolean | undefined;\n try {\n parentName = (await parentLocator.getAttribute('aria-label')) ?? undefined;\n if (!parentName) {\n const innerText = await parentLocator.evaluate((el) => {\n const legend = el.querySelector('legend');\n if (legend) return { text: legend.textContent?.trim(), fromHeading: false };\n const heading = el.querySelector('h1, h2, h3, h4, h5, h6');\n if (heading) return { text: heading.textContent?.trim(), fromHeading: true };\n return undefined;\n });\n if (innerText?.text) {\n parentName = innerText.text;\n nameFromHeading = innerText.fromHeading || undefined;\n }\n }\n } catch {\n // Ignore\n }\n\n // Build strategy with this parent context and try resolveElement\n let parentCss: string | undefined;\n if (parentRole === 'form') {\n const formMeta = await parentLocator\n .evaluate((el) => {\n if (el.tagName.toLowerCase() !== 'form') return null;\n return {\n name: el.getAttribute('name'),\n id: el.getAttribute('id'),\n };\n })\n .catch(() => null);\n parentCss = buildFormParentCss({\n name: formMeta?.name,\n id: formMeta?.id,\n });\n }\n\n const candidateParent: ParentContext = {\n role: parentRole,\n name: parentName,\n ...(parentCss ? { css: parentCss } : {}),\n nameFromHeading,\n };\n const strategyWithParent = buildMinimalStrategy(selectors, selectorType, candidateParent);\n if (!strategyWithParent) continue;\n\n // If resolveElement returns a locator, verify it's the SAME element as the original target.\n // This prevents accepting a parent scope where the selector resolves but to the wrong element.\n const resolved = await resolveElement(page, strategyWithParent, timeoutMs, {\n mode: 'verify',\n });\n if (resolved) {\n const isSame = await isSameDOMElement(page, originalLocator, resolved, timeoutMs);\n if (!isSame) {\n logger.debug(\n '[SelectorDerivation] Parent-scoped selector resolved to wrong element, skipping',\n {\n selectorType,\n parentContext: candidateParent,\n }\n );\n continue;\n }\n logger.debug('[SelectorDerivation] Found unique parent via simple scoping', {\n selectorType,\n parentContext: candidateParent,\n });\n return { parentContext: candidateParent };\n }\n } catch {\n continue;\n }\n }\n }\n } catch (err) {\n logger.debug('[SelectorDerivation] Error in simple parent scoping', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n // Strategy 2: Recursive parent chain from DOM ancestry\n // Build a basic locator for counting and ancestry extraction\n const minimalStrategy = buildMinimalStrategy(selectors, selectorType);\n if (!minimalStrategy) return null;\n\n // We need a raw locator for DOM introspection (ancestry extraction).\n // Build one in the correct context (frame or page) for this purpose.\n let rawLocator: Locator | null = null;\n switch (selectorType) {\n case 'testId':\n if (selectors.testId) rawLocator = context.getByTestId(selectors.testId);\n break;\n case 'role':\n if (selectors.role) {\n const { role, name, exact } = selectors.role;\n rawLocator = context.getByRole(\n role as Parameters<Page['getByRole']>[0],\n name ? { name, exact: exact ?? false } : undefined\n );\n }\n break;\n case 'ariaLabel':\n if (selectors.ariaLabel) rawLocator = context.getByLabel(selectors.ariaLabel);\n break;\n case 'placeholder':\n if (selectors.placeholder) rawLocator = context.getByPlaceholder(selectors.placeholder);\n break;\n case 'text':\n if (selectors.text)\n rawLocator = context.getByText(selectors.text.text, {\n exact: selectors.text.exact ?? false,\n });\n break;\n }\n\n if (!rawLocator) return null;\n\n let count: number;\n try {\n count = await Promise.race([\n rawLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Count timeout')), timeoutMs)\n ),\n ]);\n } catch {\n return null;\n }\n\n if (count <= 1) return null;\n\n // Identify which match is the target using DOM identity comparison,\n // and build ancestry for each matching element\n const elementAncestries: Array<{\n index: number;\n isTarget: boolean;\n ancestors: Array<{ role: string; name?: string; css?: string; nameFromHeading?: boolean }>;\n }> = [];\n\n for (let i = 0; i < Math.min(count, 10); i++) {\n const nth = rawLocator.nth(i);\n try {\n // Use DOM identity to identify the target element (replaces coordinate comparison)\n const isTarget = await isSameDOMElement(page, originalLocator, nth, timeoutMs);\n\n const ancestry = await nth.evaluate((el) => {\n const SEMANTIC_ROLES = [\n 'dialog',\n 'form',\n 'region',\n 'navigation',\n 'main',\n 'article',\n 'section',\n 'complementary',\n 'listbox',\n 'grid',\n 'tree',\n 'menu',\n 'tabpanel',\n 'toolbar',\n 'treegrid',\n 'banner',\n 'contentinfo',\n 'alertdialog',\n 'menubar',\n 'tablist',\n ];\n const parents: Array<{\n role: string | null;\n name: string | null;\n css: string | null;\n nameFromHeading: boolean;\n }> = [];\n let current = el.parentElement;\n while (current && parents.length < 10) {\n const roleAttr = current.getAttribute('role');\n const tagName = current.tagName.toLowerCase();\n const implicitRole =\n tagName === 'nav'\n ? 'navigation'\n : tagName === 'main'\n ? 'main'\n : tagName === 'form'\n ? 'form'\n : tagName === 'dialog'\n ? 'dialog'\n : tagName === 'article'\n ? 'article'\n : tagName === 'section'\n ? 'region'\n : tagName === 'aside'\n ? 'complementary'\n : tagName === 'header'\n ? 'banner'\n : tagName === 'footer'\n ? 'contentinfo'\n : null;\n const role = roleAttr || implicitRole;\n\n if (role && SEMANTIC_ROLES.includes(role)) {\n const ariaLabel = current.getAttribute('aria-label');\n let name = ariaLabel;\n let css: string | null = null;\n let nameFromHeading = false;\n if (!name) {\n const heading = current.querySelector('legend,h1,h2,h3,h4,h5,h6');\n if (heading) {\n name = heading.textContent?.trim() || null;\n nameFromHeading = true;\n }\n }\n if (role === 'form') {\n const escapeAttr = (value: string): string =>\n value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n const formName = current.getAttribute('name');\n const formId = current.getAttribute('id');\n css =\n formName && formName.trim().length > 0\n ? `form[name=\"${escapeAttr(formName.trim())}\"]`\n : formId && formId.trim().length > 0\n ? `form[id=\"${escapeAttr(formId.trim())}\"]`\n : 'form';\n }\n parents.push({ role, name, css, nameFromHeading });\n }\n current = current.parentElement;\n }\n return parents;\n });\n\n elementAncestries.push({\n index: i,\n isTarget,\n ancestors: ancestry\n .filter((a) => a.role)\n .map((a) => ({\n role: a.role!,\n name: a.name || undefined,\n css: a.css || undefined,\n nameFromHeading: a.nameFromHeading || undefined,\n })),\n });\n } catch {\n continue;\n }\n }\n\n const targetEl = elementAncestries.find((e) => e.isTarget);\n if (!targetEl) {\n logger.warn('[SelectorDerivation] Target not found by DOM identity in ancestry search');\n return null;\n }\n\n // Try each depth level to find unique parent scope\n for (let depth = 0; depth < maxParentDepth; depth++) {\n const targetAncestor = targetEl.ancestors[depth];\n if (!targetAncestor) break;\n\n const parentChain = targetEl.ancestors.slice(0, depth + 1);\n\n // Build strategy with this parent chain and verify via shared resolver\n const candidateParent: ParentContext = {\n role: parentChain[0]?.role,\n name: parentChain[0]?.name,\n css: parentChain[0]?.css,\n nameFromHeading: parentChain[0]?.nameFromHeading,\n parentChain,\n };\n\n const strategyWithChain = buildMinimalStrategy(selectors, selectorType, candidateParent);\n if (!strategyWithChain) continue;\n\n try {\n // If resolveElement returns a locator, the chain-scoped selector is unique — verified\n const resolved = await resolveElement(page, strategyWithChain, timeoutMs, { mode: 'verify' });\n if (resolved) {\n logger.debug('[SelectorDerivation] Found unique parent chain via recursive search', {\n depth,\n parentChain,\n });\n return { parentContext: candidateParent };\n }\n } catch {\n continue;\n }\n }\n\n // No unique parent found - fall back to matchIndex\n logger.warn('[SelectorDerivation] No unique parent found, using matchIndex fallback', {\n targetIndex: targetEl.index,\n matchCount: count,\n });\n return {\n parentContext: { matchIndex: targetEl.index },\n };\n}\n\n/**\n * Probe an element's DOM for a child SVG with a `data-icon` attribute and build\n * a CSS selector that identifies the element on the page.\n *\n * - If the selector matches exactly 1 element, returns the CSS selector as-is.\n * - If it matches 2+ elements (≤10), identifies the original element's index\n * among matches and appends Playwright's `>> nth=N` for disambiguation.\n * - Returns undefined if the probe fails or can't disambiguate.\n */\nasync function probeChildIconCSS(\n page: Page,\n originalLocator: Locator,\n role: string\n): Promise<string | undefined> {\n const logger = getLogger();\n\n const iconAttr = await originalLocator\n .evaluate((el) => {\n const svg = el.querySelector('svg[data-icon]');\n return svg?.getAttribute('data-icon') ?? null;\n })\n .catch(() => null);\n\n if (!iconAttr) return undefined;\n\n const baseSelector = `${role}:has(svg[data-icon=\"${iconAttr}\"])`;\n\n try {\n const count = await page.locator(baseSelector).count();\n\n if (count === 1) {\n logger.debug('[SelectorDerivation] probeChildIconCSS found unique selector', {\n css: baseSelector,\n });\n return baseSelector;\n }\n\n if (count >= 2 && count <= 10) {\n // Multiple matches — find the original element's index among them.\n // Mark the original with a temporary attribute, then scan matches.\n const MARKER = '__probe_target__';\n await originalLocator.evaluate((el, attr) => el.setAttribute(attr, '1'), MARKER);\n\n try {\n const matches = page.locator(baseSelector);\n for (let i = 0; i < count; i++) {\n const hasMarker = await matches\n .nth(i)\n .evaluate((el, attr) => el.hasAttribute(attr), MARKER);\n if (hasMarker) {\n const nthSelector = `${baseSelector} >> nth=${i}`;\n logger.debug('[SelectorDerivation] probeChildIconCSS disambiguated via nth', {\n css: nthSelector,\n matchCount: count,\n index: i,\n });\n return nthSelector;\n }\n }\n } finally {\n await originalLocator\n .evaluate((el, attr) => el.removeAttribute(attr), MARKER)\n .catch(() => {});\n }\n }\n\n logger.debug('[SelectorDerivation] probeChildIconCSS could not disambiguate', {\n css: baseSelector,\n count,\n });\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Probe for a CSS selector based on the element's `id` attribute (or a child's `id`).\n *\n * Works for SVG shapes, chart segments, diagrams, and other elements\n * identified by `id` but lacking ARIA attributes in the original DOM.\n *\n * Disambiguation follows the same marker+nth pattern as probeChildIconCSS:\n * - If the selector matches exactly 1 element, returns the CSS selector as-is.\n * - If it matches 2–10 elements, identifies the original element's index\n * among matches and appends Playwright's `>> nth=N` for disambiguation.\n * - Returns undefined if the probe fails or can't disambiguate.\n */\nexport async function probeElementIdCSS(\n page: Page,\n originalLocator: Locator\n): Promise<string | undefined> {\n const logger = getLogger();\n\n const elementId = await originalLocator\n .evaluate((el) => {\n if (el.id) return el.id;\n const child = el.querySelector('[id]');\n return child?.id ?? null;\n })\n .catch(() => null);\n\n if (!elementId) return undefined;\n\n const baseSelector = `[id=\"${elementId}\"]`;\n\n try {\n const count = await page.locator(baseSelector).count();\n\n if (count === 1) {\n logger.debug('[SelectorDerivation] probeElementIdCSS found unique selector', {\n css: baseSelector,\n });\n return baseSelector;\n }\n\n if (count >= 2 && count <= 10) {\n // Check if only 1 match is visible — return clean selector without nth\n const allMatches = page.locator(baseSelector);\n let visibleCount = 0;\n let targetIsOnlyVisible = false;\n\n for (let i = 0; i < count; i++) {\n const isVis = await allMatches\n .nth(i)\n .isVisible()\n .catch(() => false);\n if (isVis) {\n visibleCount++;\n if (visibleCount > 1) break; // multiple visible — skip to nth fallback\n // Check if this visible element is the original target\n const VIS_MARKER = '__vis_probe__';\n await originalLocator.evaluate((el, attr) => el.setAttribute(attr, '1'), VIS_MARKER);\n const isTarget = await allMatches\n .nth(i)\n .evaluate((el, attr) => el.hasAttribute(attr), VIS_MARKER)\n .catch(() => false);\n await originalLocator\n .evaluate((el, attr) => el.removeAttribute(attr), VIS_MARKER)\n .catch(() => {});\n if (isTarget) targetIsOnlyVisible = true;\n }\n }\n\n if (visibleCount === 1 && targetIsOnlyVisible) {\n logger.debug('[SelectorDerivation] probeElementIdCSS: single visible among duplicates', {\n css: baseSelector,\n matchCount: count,\n });\n return baseSelector; // Clean selector — element-resolver picks the visible one\n }\n\n // Fallback: disambiguate via nth index using marker\n const MARKER = '__probe_target__';\n await originalLocator.evaluate((el, attr) => el.setAttribute(attr, '1'), MARKER);\n\n try {\n const matches = page.locator(baseSelector);\n for (let i = 0; i < count; i++) {\n const hasMarker = await matches\n .nth(i)\n .evaluate((el, attr) => el.hasAttribute(attr), MARKER);\n if (hasMarker) {\n const nthSelector = `${baseSelector} >> nth=${i}`;\n logger.debug('[SelectorDerivation] probeElementIdCSS disambiguated via nth', {\n css: nthSelector,\n matchCount: count,\n index: i,\n });\n return nthSelector;\n }\n }\n } finally {\n await originalLocator\n .evaluate((el, attr) => el.removeAttribute(attr), MARKER)\n .catch(() => {});\n }\n }\n\n logger.debug('[SelectorDerivation] probeElementIdCSS could not disambiguate', {\n css: baseSelector,\n count,\n });\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Probe for a CSS selector based on the element's `title` attribute.\n *\n * Works for icon-only elements (e.g., `<a title=\"Quick create\">`) whose\n * accessible name comes from the `title` attribute but isn't captured in\n * the a11y snapshot (Playwright renders them as empty-name elements).\n *\n * Disambiguation follows the same marker+nth pattern as probeChildIconCSS:\n * - If the selector matches exactly 1 element, returns the CSS selector as-is.\n * - If it matches 2–10 elements, identifies the original element's index\n * among matches and appends Playwright's `>> nth=N` for disambiguation.\n * - Returns undefined if the probe fails or can't disambiguate.\n */\nasync function probeTitleCSS(page: Page, originalLocator: Locator): Promise<string | undefined> {\n const logger = getLogger();\n\n const titleAttr = await originalLocator\n .evaluate((el) => el.getAttribute('title'))\n .catch(() => null);\n\n if (!titleAttr) return undefined;\n\n const baseSelector = `[title=\"${titleAttr}\"]`;\n\n try {\n const count = await page.locator(baseSelector).count();\n\n if (count === 1) {\n logger.debug('[SelectorDerivation] probeTitleCSS found unique selector', {\n css: baseSelector,\n });\n return baseSelector;\n }\n\n if (count >= 2 && count <= 10) {\n const MARKER = '__probe_target__';\n await originalLocator.evaluate((el, attr) => el.setAttribute(attr, '1'), MARKER);\n\n try {\n const matches = page.locator(baseSelector);\n for (let i = 0; i < count; i++) {\n const hasMarker = await matches\n .nth(i)\n .evaluate((el, attr) => el.hasAttribute(attr), MARKER);\n if (hasMarker) {\n const nthSelector = `${baseSelector} >> nth=${i}`;\n logger.debug('[SelectorDerivation] probeTitleCSS disambiguated via nth', {\n css: nthSelector,\n matchCount: count,\n index: i,\n });\n return nthSelector;\n }\n }\n } finally {\n await originalLocator\n .evaluate((el, attr) => el.removeAttribute(attr), MARKER)\n .catch(() => {});\n }\n }\n\n logger.debug('[SelectorDerivation] probeTitleCSS could not disambiguate', {\n css: baseSelector,\n count,\n });\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Iframe Selector Resolution\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Probe the live DOM to resolve a generic 'iframe' frameContext into a\n * specific CSS selector (id, name, class, nth-of-type).\n *\n * Uses the element's own frame to walk up to the <iframe> host element\n * and extract identifying attributes — same approach as\n * DirectPlaywrightClient.extractElementMetadata's detectFrameContext.\n *\n * @param page - Playwright page\n * @param elementLocator - Locator for an element inside the iframe (e.g., via aria-ref)\n * @param timeoutMs - Timeout for the DOM probe (default: 5000)\n * @returns FrameContext with specific selector, or null if not in an iframe / probe fails\n */\nexport async function resolveSpecificIframeSelector(\n page: Page,\n elementLocator: Locator,\n timeoutMs = 5000\n): Promise<FrameContext | null> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const result = await Promise.race([\n elementLocator.evaluate((el) => {\n const win = el.ownerDocument.defaultView;\n if (!win || win === win.top) {\n return null; // Not in an iframe\n }\n\n const frameElement = win.frameElement as HTMLIFrameElement | null;\n if (!frameElement) {\n return null;\n }\n\n // Build the best selector for the iframe (same priority as detectFrameContext)\n const frameId = frameElement.id;\n const frameName = frameElement.name;\n const frameClass = frameElement.className;\n\n let selector: string;\n if (frameId) {\n selector = `iframe#${CSS.escape(frameId)}`;\n } else if (frameName) {\n selector = `iframe[name=\"${CSS.escape(frameName)}\"]`;\n } else if (frameClass && typeof frameClass === 'string') {\n const firstClass = frameClass.split(/\\s+/).filter(Boolean)[0];\n if (firstClass) {\n selector = `iframe.${CSS.escape(firstClass)}`;\n } else {\n selector = 'iframe';\n }\n } else {\n // Fallback: try to find index among direct iframe siblings\n const siblings = frameElement.parentElement\n ? Array.from(frameElement.parentElement.children).filter((c) => c.tagName === 'IFRAME')\n : [];\n if (siblings.length > 1) {\n const index = siblings.indexOf(frameElement);\n selector = `iframe:nth-of-type(${index + 1})`;\n } else {\n selector = 'iframe';\n }\n }\n\n return {\n type: 'iframe' as const,\n selector,\n name: frameName || undefined,\n id: frameId || undefined,\n };\n }),\n new Promise<null>((_, reject) => {\n timer = setTimeout(\n () => reject(new Error('resolveSpecificIframeSelector timeout')),\n timeoutMs\n );\n }),\n ]);\n\n return result;\n } catch (err) {\n getLogger().debug('[SelectorDerivation] resolveSpecificIframeSelector failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Probe ancestor elements for `aria-rowindex`.\n *\n * Many grid-based UIs (e.g., BC Dynamics) put `aria-rowindex` on the `<tr>` parent\n * rather than on the cell/input itself. The snapshot parser only captures the element's\n * own attributes, so this probe walks up to find the nearest ancestor row index.\n *\n * @param elementLocator - Locator for the target element\n * @param timeoutMs - Timeout for the DOM probe (default: 3000)\n * @returns The aria-rowindex value, or undefined if not found\n */\nexport async function probeAncestorRowIndex(\n elementLocator: Locator,\n timeoutMs = 3000\n): Promise<number | undefined> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const result = await Promise.race([\n elementLocator.evaluate((el) => {\n // Check element itself first\n const own = el.getAttribute('aria-rowindex');\n if (own) return parseInt(own, 10);\n\n // Walk up ancestors (max 10 levels)\n let current = el.parentElement;\n let depth = 0;\n while (current && depth < 10) {\n const ri = current.getAttribute('aria-rowindex');\n if (ri) return parseInt(ri, 10);\n current = current.parentElement;\n depth++;\n }\n return undefined;\n }),\n new Promise<undefined>((_, reject) => {\n timer = setTimeout(() => reject(new Error('probeAncestorRowIndex timeout')), timeoutMs);\n }),\n ]);\n\n if (result !== undefined && !isNaN(result)) {\n return result;\n }\n return undefined;\n } catch (err) {\n getLogger().debug('[SelectorDerivation] probeAncestorRowIndex failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n return undefined;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Verify a single selector type against the page using the shared element resolver.\n *\n * This ensures verification exercises the **exact same code path** as replay:\n * same serialized SelectorStrategy JSON → same resolveElement() function.\n *\n * If resolveElement returns a single-match Locator, the selector is considered\n * verified immediately — no coordinate comparison needed because the page\n * hasn't changed between derivation and verification (both happen in the BEFORE\n * phase of the same action).\n *\n * @param page - Playwright page\n * @param selectors - Full selector strategy\n * @param selectorType - Which selector to verify\n * @param originalLocator - Locator for the original element (via aria-ref)\n * @param options - Verification options\n * @returns Verification result for this selector type\n */\nasync function verifySingleSelector(\n page: Page,\n selectors: SelectorStrategy,\n selectorType: SelectorType,\n originalLocator: Locator,\n options: Required<SelectorVerificationOptions>\n): Promise<SelectorVerificationResult> {\n const { timeoutMs } = options;\n const logger = getLogger();\n\n const result: SelectorVerificationResult = {\n selectorType,\n verified: false,\n matchCount: 0,\n coordinatesMatch: false,\n };\n\n // Build a minimal strategy with just this selector type\n const minimalStrategy = buildMinimalStrategy(selectors, selectorType);\n if (!minimalStrategy) {\n result.reason = `No ${selectorType} selector available`;\n return result;\n }\n\n try {\n // Dry-run the shared resolver in verify mode — same code path as replay\n const resolved = await resolveElement(page, minimalStrategy, timeoutMs, { mode: 'verify' });\n\n if (resolved) {\n // resolveElement returned a single-match Locator. The selector uniquely\n // resolved on the same page state, so it IS the correct element.\n result.matchCount = 1;\n result.coordinatesMatch = true;\n result.verified = true;\n return result;\n }\n\n // Resolution returned null — selector didn't uniquely resolve.\n // Try to discover a parent context that disambiguates.\n logger.debug('[SelectorDerivation] Initial resolution failed, trying parent disambiguation', {\n selectorType,\n });\n\n // Try data attribute disambiguation first (most deterministic)\n if (selectors.itemIndex !== undefined || selectors.rowIndex !== undefined) {\n // Data attributes are already included in the minimal strategy.\n // If resolveElement returned null with them, they didn't help.\n // We still record this for the result.\n logger.debug('[SelectorDerivation] Data attributes present but did not disambiguate', {\n selectorType,\n itemIndex: selectors.itemIndex,\n rowIndex: selectors.rowIndex,\n });\n }\n\n // Try parent context discovery (uses DOM identity for target identification)\n const parentResult = await discoverParentContext(\n page,\n selectors,\n selectorType,\n originalLocator,\n options\n );\n\n if (parentResult) {\n result.verified = true;\n result.coordinatesMatch = true;\n result.parentContext = parentResult.parentContext;\n return result;\n }\n\n result.reason = 'Resolution failed — no disambiguation strategy succeeded';\n return result;\n } catch (err) {\n result.reason = `Verification failed: ${err instanceof Error ? err.message : String(err)}`;\n return result;\n }\n}\n\n/**\n * Verify derived selectors against the actual page state.\n *\n * This function takes selectors derived from element metadata and verifies\n * them against the live page. For each selector type:\n * 1. Build a Playwright locator\n * 2. Count matching elements\n * 3. If count === 1, verify coordinates match within tolerance\n * 4. If count > 1, try to find a parent scope that makes it unique\n * 5. If count === 0, reject this selector type\n *\n * Returns only the selectors that were successfully verified, with\n * parent context added where disambiguation was needed.\n *\n * @param page - Playwright page to verify against\n * @param selectors - Selector strategy from element metadata\n * @param originalLocator - Locator for the original element (via aria-ref)\n * @param options - Verification options\n * @returns Verified selectors and detailed results\n */\nexport async function verifySelectorAgainstRef(\n page: Page,\n selectors: SelectorStrategy,\n originalLocator: Locator,\n options: SelectorVerificationOptions = {}\n): Promise<SelectorVerificationSummary> {\n const opts: Required<SelectorVerificationOptions> = {\n ...DEFAULT_VERIFICATION_OPTIONS,\n ...options,\n };\n\n const results: SelectorVerificationResult[] = [];\n const verifiedSelectors: SelectorStrategy = {};\n\n // Selector types to verify, in priority order.\n const selectorTypes = getSelectorTypesForVerification(selectors, opts);\n\n if (opts.skipTextWhenStrong && selectors.text && !selectorTypes.includes('text')) {\n getLogger().debug('[SelectorDerivation] Skipping weak text verification for form control', {\n role: selectors.role?.role,\n hasTestId: !!selectors.testId,\n hasRoleName: !!selectors.role?.name,\n hasAriaLabel: !!selectors.ariaLabel,\n hasPlaceholder: !!selectors.placeholder,\n });\n }\n\n for (const selectorType of selectorTypes) {\n const result = await verifySingleSelector(page, selectors, selectorType, originalLocator, opts);\n results.push(result);\n\n if (result.verified) {\n // Add verified selector to result\n switch (selectorType) {\n case 'testId':\n if (selectors.testId) verifiedSelectors.testId = selectors.testId;\n break;\n case 'role':\n if (selectors.role) verifiedSelectors.role = { ...selectors.role };\n if (selectors.containsText) verifiedSelectors.containsText = [...selectors.containsText];\n break;\n case 'ariaLabel':\n if (selectors.ariaLabel) verifiedSelectors.ariaLabel = selectors.ariaLabel;\n break;\n case 'placeholder':\n if (selectors.placeholder) verifiedSelectors.placeholder = selectors.placeholder;\n break;\n case 'text':\n if (selectors.text) verifiedSelectors.text = { ...selectors.text };\n break;\n }\n\n // Add parent context if disambiguation was needed\n if (result.parentContext) {\n verifiedSelectors.parentContext = result.parentContext;\n }\n }\n }\n\n let anyVerified = results.some((r) => r.verified);\n\n // Last-resort fallback: probe for icon-only button CSS selector.\n // When all standard selectors fail (icon-only buttons have no name/text),\n // check if the element contains an SVG with a data-icon attribute and\n // build a CSS selector from it. Uses Playwright's >> nth=N syntax for\n // disambiguation when multiple elements share the same icon.\n if (!anyVerified && selectors.role) {\n const cssSelector = await probeChildIconCSS(page, originalLocator, selectors.role.role);\n if (cssSelector) {\n verifiedSelectors.css = cssSelector;\n anyVerified = true;\n\n getLogger().debug('[SelectorDerivation] Icon CSS probe succeeded as last resort', {\n css: cssSelector,\n });\n }\n }\n\n // Proactively capture CSS id selector when available, even if other selectors verified.\n // Provides defense-in-depth for cases where text/role selectors match ambiguously at replay time.\n if (anyVerified && !verifiedSelectors.css) {\n try {\n const cssSelector = await probeElementIdCSS(page, originalLocator);\n if (cssSelector) {\n verifiedSelectors.css = cssSelector;\n getLogger().debug('[SelectorDerivation] Proactive element ID CSS probe succeeded', {\n css: cssSelector,\n });\n }\n } catch {\n // Non-fatal: proactive probe is best-effort\n }\n }\n\n // Last-resort fallback: probe for element id CSS selector.\n // Works for SVG shapes, chart segments, diagrams, and other elements\n // identified by `id` but lacking ARIA attributes in the original DOM.\n if (!anyVerified) {\n const cssSelector = await probeElementIdCSS(page, originalLocator);\n if (cssSelector) {\n verifiedSelectors.css = cssSelector;\n anyVerified = true;\n\n getLogger().debug('[SelectorDerivation] Element ID CSS probe succeeded as last resort', {\n css: cssSelector,\n });\n }\n }\n\n // Last-resort fallback: probe for title attribute CSS selector.\n // Works for icon-only elements whose accessible name comes from the\n // `title` attribute but isn't captured in the a11y snapshot.\n if (!anyVerified) {\n const cssSelector = await probeTitleCSS(page, originalLocator);\n if (cssSelector) {\n verifiedSelectors.css = cssSelector;\n anyVerified = true;\n\n getLogger().debug('[SelectorDerivation] Title CSS probe succeeded as last resort', {\n css: cssSelector,\n });\n }\n }\n\n // Preserve original parentContext if any selector was verified with it.\n // Verification uses it via buildMinimalStrategy, but the result only\n // reports parentContext when discoverParentContext discovers a NEW one.\n if (anyVerified && selectors.parentContext && !verifiedSelectors.parentContext) {\n verifiedSelectors.parentContext = selectors.parentContext;\n }\n\n // Preserve frameContext in verified selectors if present\n // This ensures replay knows which frame to search in\n if (anyVerified && selectors.frameContext) {\n verifiedSelectors.frameContext = selectors.frameContext;\n }\n\n // Preserve childFilter for disambiguation during replay\n if (anyVerified && selectors.childFilter) {\n verifiedSelectors.childFilter = selectors.childFilter;\n }\n\n // Preserve data attributes for list/table disambiguation during replay\n if (anyVerified && selectors.rowIndex !== undefined) {\n verifiedSelectors.rowIndex = selectors.rowIndex;\n }\n if (anyVerified && selectors.itemIndex !== undefined) {\n verifiedSelectors.itemIndex = selectors.itemIndex;\n }\n if (anyVerified && selectors.automationId) {\n verifiedSelectors.automationId = selectors.automationId;\n }\n\n getLogger().debug('[SelectorDerivation] Verification complete', {\n verified: results.filter((r) => r.verified).map((r) => r.selectorType),\n rejected: results\n .filter((r) => !r.verified)\n .map((r) => ({\n type: r.selectorType,\n reason: r.reason,\n })),\n anyVerified,\n hasParentContext: !!verifiedSelectors.parentContext,\n hasFrameContext: !!selectors.frameContext,\n frameSelector: selectors.frameContext?.selector,\n });\n\n return {\n verifiedSelectors,\n results,\n anyVerified,\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dynamic Text Detection & Hydration\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Minimum character length for a dynamic value to be considered for templatization */\nconst DYNAMIC_TEXT_MIN_LENGTH = 3;\n\n/**\n * Minimum ratio of (dynamic value length / selector text length) for a match\n * to be considered distinctive. Prevents common short words like \"Open\" from\n * being annotated as dynamic when they appear in longer selector text.\n * Values >= DYNAMIC_TEXT_DISTINCTIVE_LENGTH bypass the ratio check.\n */\nconst DYNAMIC_TEXT_MIN_RATIO = 0.4;\nconst DYNAMIC_TEXT_DISTINCTIVE_LENGTH = 8;\n\n/**\n * Map of dynamic value source types and their keys.\n * Used internally by detectDynamicText.\n */\ntype DynamicValueEntry = {\n source: 'inputValue';\n key: string;\n value: string;\n};\n\n/**\n * Build a flat list of dynamic value entries from variable values.\n * Only includes string values above the minimum length threshold.\n * Source is always 'inputValue' — the VariableRegistry is now the single\n * source of truth and no longer distinguishes ws: prefixed keys.\n */\nfunction buildDynamicValueEntries(variableValues: Record<string, string>): DynamicValueEntry[] {\n const entries: DynamicValueEntry[] = [];\n\n for (const [key, value] of Object.entries(variableValues)) {\n if (typeof value !== 'string' || value.length < DYNAMIC_TEXT_MIN_LENGTH) continue;\n entries.push({ source: 'inputValue', key, value });\n }\n\n // Sort by value length descending so longer matches take precedence\n entries.sort((a, b) => b.value.length - a.value.length);\n return entries;\n}\n\n/**\n * Collect all text-bearing fields from a SelectorStrategy for scanning.\n */\nfunction collectSelectorTexts(selectors: SelectorStrategy): string[] {\n const texts: string[] = [];\n if (selectors.role?.name) texts.push(selectors.role.name);\n if (selectors.text?.text) texts.push(selectors.text.text);\n if (selectors.ariaLabel) texts.push(selectors.ariaLabel);\n if (selectors.containsText) {\n for (const t of selectors.containsText) {\n if (t) texts.push(t);\n }\n }\n return texts;\n}\n\n/**\n * Detect if a selector contains dynamic text from known dynamic values.\n *\n * Scans text-bearing selector fields (role.name, text.text, containsText[], ariaLabel)\n * against a map of known variable values from the VariableRegistry.\n *\n * @param selectors - The selector strategy to scan\n * @param variableValues - Flat key→value map from the VariableRegistry\n * @returns The dynamicText annotation if a match is found, undefined otherwise\n */\nexport function detectDynamicText(\n selectors: SelectorStrategy,\n variableValues: Record<string, string>\n): SelectorStrategy['dynamicText'] | undefined {\n if (!variableValues || Object.keys(variableValues).length === 0) return undefined;\n\n const entries = buildDynamicValueEntries(variableValues);\n if (entries.length === 0) return undefined;\n\n const selectorTexts = collectSelectorTexts(selectors);\n if (selectorTexts.length === 0) return undefined;\n\n // Check each dynamic value against each selector text field.\n // To avoid false positives from common short words (e.g., \"Open\" matching\n // \"Open settings\"), we require the value to either be long enough to be\n // distinctive on its own (>= DYNAMIC_TEXT_DISTINCTIVE_LENGTH) or to cover\n // a significant portion of the selector text (>= DYNAMIC_TEXT_MIN_RATIO).\n for (const entry of entries) {\n const isDistinctiveLength = entry.value.length >= DYNAMIC_TEXT_DISTINCTIVE_LENGTH;\n for (const selectorText of selectorTexts) {\n if (!selectorText.includes(entry.value)) continue;\n if (\n isDistinctiveLength ||\n entry.value.length / selectorText.length >= DYNAMIC_TEXT_MIN_RATIO\n ) {\n return {\n source: entry.source,\n key: entry.key,\n originalText: entry.value,\n };\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Compute the length of the common prefix between two strings.\n */\nfunction commonPrefixLength(a: string, b: string): number {\n let i = 0;\n while (i < a.length && i < b.length && a[i] === b[i]) i++;\n return i;\n}\n\n/**\n * Check if a single field value is a \"chimera\" — compiled from mixed run data.\n *\n * Returns true when `originalText` is a strict substring of `fieldValue`,\n * AND the remaining text (field minus originalText) shares a significant\n * common prefix (≥3 chars) with `currentValue`, suggesting the leftover\n * text is a stale version of the same dynamic variable from a different run.\n */\nfunction isChimeraFieldValue(\n fieldValue: string,\n originalText: string,\n currentValue: string\n): boolean {\n if (fieldValue === originalText) return false;\n if (!fieldValue.includes(originalText)) return false;\n\n const remaining = fieldValue.replace(originalText, '').trim();\n if (!remaining) return false;\n\n const minPrefixLen = Math.min(3, currentValue.length);\n return commonPrefixLength(remaining, currentValue) >= minPrefixLen;\n}\n\n/**\n * Check if ANY text field in the selector strategy contains chimera text.\n */\nfunction hasChimeraField(\n selectors: SelectorStrategy,\n originalText: string,\n currentValue: string\n): boolean {\n if (selectors.role?.name && isChimeraFieldValue(selectors.role.name, originalText, currentValue))\n return true;\n if (selectors.text?.text && isChimeraFieldValue(selectors.text.text, originalText, currentValue))\n return true;\n if (selectors.ariaLabel && isChimeraFieldValue(selectors.ariaLabel, originalText, currentValue))\n return true;\n if (selectors.containsText?.some((t) => t && isChimeraFieldValue(t, originalText, currentValue)))\n return true;\n return false;\n}\n\n/**\n * Replace all occurrences of `originalText` with `newText` in text-bearing selector fields.\n * Returns a new SelectorStrategy (does not mutate the input).\n *\n * When `fullFieldReplacement` is true, any field that contains `originalText` as a\n * strict substring (field !== originalText) gets replaced entirely with `newText`.\n * This prevents chimera text from partial `dynamicText.originalText` values — e.g.,\n * \"Matter vbEDNKOWbf- Matter ag7gOOHnZA\" where only \"Matter ag7gOOHnZA\" was tracked\n * would produce \"Matter vbEDNKOWbf- Matter wNxa4WJtqA\" (stale prefix + new suffix).\n */\nfunction replaceTextInSelectors(\n selectors: SelectorStrategy,\n originalText: string,\n newText: string,\n fullFieldReplacement = false\n): SelectorStrategy {\n const result: SelectorStrategy = { ...selectors };\n\n // Escape special regex characters in the original text\n const escaped = originalText.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const regex = new RegExp(escaped, 'g');\n\n const replaceField = (fieldValue: string): string => {\n if (!fieldValue.includes(originalText)) return fieldValue;\n // If full-field replacement is on and originalText is a strict substring,\n // replace the entire field value to avoid chimera text\n if (fullFieldReplacement && fieldValue !== originalText) {\n return newText;\n }\n return fieldValue.replace(regex, newText);\n };\n\n if (result.role?.name && result.role.name.includes(originalText)) {\n result.role = { ...result.role, name: replaceField(result.role.name) };\n }\n\n if (result.text?.text && result.text.text.includes(originalText)) {\n result.text = { ...result.text, text: replaceField(result.text.text) };\n }\n\n if (result.ariaLabel && result.ariaLabel.includes(originalText)) {\n result.ariaLabel = replaceField(result.ariaLabel);\n }\n\n if (result.containsText) {\n result.containsText = result.containsText.map((t) =>\n t && t.includes(originalText) ? replaceField(t) : t\n );\n }\n\n return result;\n}\n\n/**\n * Hydrate dynamic selectors at replay time.\n *\n * If the selector has a `dynamicText` annotation, replaces the `originalText`\n * with the current value from `variableValues[key]` in all text-bearing fields.\n * Returns a new SelectorStrategy (does not mutate the input).\n *\n * Returns the original selectors unchanged if no `dynamicText` annotation\n * is present or the key is not found in variableValues (backward compatible).\n *\n * Old cached actions with `source: 'workflowState'` still resolve because the\n * VariableRegistry seeds workflowState values under their plain key.\n *\n * @param selectors - The selector strategy to hydrate\n * @param variableValues - Flat key→value map from the VariableRegistry\n * @returns Hydrated selector strategy\n */\n/**\n * Hydrate any `containsTextDynamic` bindings on parent-context nodes by\n * replacing their `containsText` with the current variable value. Returns\n * a new SelectorStrategy when anything changed, otherwise the input.\n */\nfunction hydrateParentContextDynamicText(\n selectors: SelectorStrategy,\n variableValues: Record<string, string>\n): SelectorStrategy {\n const pc = selectors.parentContext;\n if (!pc) return selectors;\n\n const applyBinding = (\n text: string | undefined,\n binding: ParentContextDynamicText | undefined\n ): { text: string | undefined; nextBinding: ParentContextDynamicText | undefined } => {\n if (!binding || !text) return { text, nextBinding: binding };\n const currentValue = variableValues[binding.key];\n if (!currentValue || currentValue === binding.originalText) {\n return { text, nextBinding: binding };\n }\n const hydratedText = text.includes(binding.originalText)\n ? text.split(binding.originalText).join(currentValue)\n : currentValue;\n return {\n text: hydratedText,\n nextBinding: { ...binding, originalText: currentValue },\n };\n };\n\n let changed = false;\n const nextPc: ParentContext = { ...pc };\n\n if (pc.containsTextDynamic) {\n const { text, nextBinding } = applyBinding(pc.containsText, pc.containsTextDynamic);\n if (text !== pc.containsText || nextBinding !== pc.containsTextDynamic) {\n nextPc.containsText = text;\n nextPc.containsTextDynamic = nextBinding;\n changed = true;\n }\n }\n\n if (pc.parentChain?.length) {\n const nextChain = pc.parentChain.map((node) => {\n if (!node.containsTextDynamic) return node;\n const { text, nextBinding } = applyBinding(node.containsText, node.containsTextDynamic);\n if (text === node.containsText && nextBinding === node.containsTextDynamic) return node;\n changed = true;\n return { ...node, containsText: text, containsTextDynamic: nextBinding };\n });\n nextPc.parentChain = nextChain;\n }\n\n if (!changed) return selectors;\n return { ...selectors, parentContext: nextPc };\n}\n\nexport function hydrateDynamicSelectors(\n selectors: SelectorStrategy,\n variableValues: Record<string, string>\n): SelectorStrategy {\n const withHydratedParent = hydrateParentContextDynamicText(selectors, variableValues);\n let hydrated = withHydratedParent;\n\n if (withHydratedParent.playwrightLocator) {\n hydrated = {\n ...hydrated,\n playwrightLocator: hydratePlaywrightLocatorVariables(\n withHydratedParent.playwrightLocator,\n variableValues\n ),\n };\n }\n if (withHydratedParent.playwrightLocatorCandidates) {\n hydrated = {\n ...hydrated,\n playwrightLocatorCandidates: Object.fromEntries(\n Object.entries(withHydratedParent.playwrightLocatorCandidates).map(([author, candidate]) => [\n author,\n candidate?.locator\n ? {\n ...candidate,\n locator: hydratePlaywrightLocatorVariables(candidate.locator, variableValues),\n }\n : candidate,\n ])\n ) as SelectorStrategy['playwrightLocatorCandidates'],\n };\n }\n\n const dynamicText = hydrated.dynamicText;\n if (!dynamicText) return hydrated;\n\n const { key, originalText } = dynamicText;\n selectors = hydrated;\n\n // Look up by plain key — VariableRegistry is the single source of truth.\n // Old cached actions with source='workflowState' still resolve because the\n // registry seeds workflowState string values under their plain key.\n const currentValue = variableValues[key];\n\n if (!currentValue || currentValue === originalText) {\n // No substitution needed (value unchanged or missing)\n return selectors;\n }\n\n // Detect chimera fields: when originalText is a strict substring of a field,\n // AND the remaining text (field minus originalText) shares a common prefix\n // with currentValue, it means the field was compiled from mixed run data.\n // E.g., field=\"Matter vbEDNKOWbf- Matter ag7gOOHnZA\", originalText=\"Matter ag7gOOHnZA\",\n // currentValue=\"Matter wNxa4WJtqA\" → remaining=\"Matter vbEDNKOWbf-\" shares prefix \"Matter \"\n // with currentValue → chimera detected → replace whole field.\n const hasChimera = hasChimeraField(selectors, originalText, currentValue);\n\n if (hasChimera) {\n getLogger().warn(\n '[SelectorDerivation] Full-field replacement triggered due to stale surrounding text',\n {\n key,\n originalText,\n currentValue,\n roleName: selectors.role?.name,\n textText: selectors.text?.text,\n }\n );\n }\n\n const nextSelectors = replaceTextInSelectors(selectors, originalText, currentValue, hasChimera);\n\n // Update the dynamicText annotation with the new originalText for tracking\n nextSelectors.dynamicText = {\n ...dynamicText,\n originalText: currentValue,\n };\n\n return nextSelectors;\n}\n\nfunction hydratePlaywrightLocatorVariables(\n locator: string,\n variableValues: Record<string, string>\n): string {\n return locator.replace(/\\{\\{var\\.([a-zA-Z0-9_]+)\\}\\}/g, (match, key: string) => {\n const value = variableValues[key];\n if (value === undefined) return match;\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n });\n}\n","/**\n * Cached Action Assembly\n *\n * Converts recorded `CachedActionRecord[]` to storable `CachedAction[]` in two\n * passes: macro bindings (so `$RANDOM_STRING`, `$SEQUENCE`, etc. re-resolve at\n * replay) and variable parameterization (`$var.<key>` tokens so the cache\n * replays across runs with different seed values).\n *\n * @module workflows/cache/cached-action-assembly\n * @see docs/api/services/workflow-action-cache.md\n */\n\nimport type { AssertionSpec, CachedAction, CachedActionType } from '@chatsdet/types';\nimport type { CachedActionRecord } from './types.js';\nimport type { MacroResolutionLog } from './macros/types.js';\n\nconst isActionWithTextBindings = (\n actionType: string\n): actionType is 'type' | 'fill_form' | 'assert' =>\n actionType === 'type' || actionType === 'fill_form' || actionType === 'assert';\n\nconst TEXT_ASSERTION_TYPES = new Set<AssertionSpec['type']>(['text_present', 'text_absent']);\n\nconst unwrapAccidentalTextAssertionQuotes = (\n value: string,\n assertionType: AssertionSpec['type'],\n field: 'condition' | 'expected'\n): string => {\n if (field !== 'condition' || !TEXT_ASSERTION_TYPES.has(assertionType)) return value;\n const trimmed = value.trim();\n if (trimmed.length < 2) return value;\n\n const first = trimmed[0];\n const last = trimmed[trimmed.length - 1];\n if ((first !== '\"' && first !== \"'\") || last !== first) return value;\n\n return trimmed.slice(1, -1);\n};\n\nconst findMacroExpressionForValue = (\n value: string,\n macroResolutionLog: MacroResolutionLog | undefined,\n agentMacroResolutions: Map<string, string> | undefined\n): string | undefined => {\n if (macroResolutionLog) {\n for (const [, { expression, resolved }] of macroResolutionLog.entries()) {\n if (value === resolved) {\n return expression;\n }\n }\n }\n\n return agentMacroResolutions?.get(value);\n};\n\nconst buildMacroBindingsForAction = (opts: {\n action: CachedActionRecord;\n macroResolutionLog?: MacroResolutionLog;\n agentMacroResolutions?: Map<string, string>;\n}): Record<string, string> | undefined => {\n const { action, macroResolutionLog, agentMacroResolutions } = opts;\n if (!isActionWithTextBindings(action.actionType)) return undefined;\n\n const macroBindings: Record<string, string> = {};\n\n const rawText = action.args?.text ?? action.args?.value;\n const textArg = typeof rawText === 'string' ? rawText : undefined;\n if (textArg) {\n const textExpression = findMacroExpressionForValue(\n textArg,\n macroResolutionLog,\n agentMacroResolutions\n );\n if (textExpression) {\n macroBindings.text = textExpression;\n }\n }\n\n const fields = Array.isArray(action.args?.fields)\n ? (action.args.fields as Array<{ value?: unknown }>)\n : undefined;\n if (fields) {\n for (let fi = 0; fi < fields.length; fi++) {\n const rawValue = fields[fi]?.value;\n if (typeof rawValue !== 'string' || rawValue.length === 0) continue;\n\n const expression = findMacroExpressionForValue(\n rawValue,\n macroResolutionLog,\n agentMacroResolutions\n );\n if (expression) {\n macroBindings[`fields.${fi}.value`] = expression;\n }\n }\n }\n\n const assertionCondition =\n action.actionType === 'assert' && typeof action.assertion?.condition === 'string'\n ? action.assertion.condition\n : undefined;\n if (assertionCondition) {\n const conditionExpression = findMacroExpressionForValue(\n assertionCondition,\n macroResolutionLog,\n agentMacroResolutions\n );\n if (conditionExpression) {\n macroBindings['assertion.condition'] = conditionExpression;\n }\n }\n\n const assertionExpected =\n action.actionType === 'assert' && typeof action.assertion?.expected === 'string'\n ? action.assertion.expected\n : undefined;\n if (assertionExpected) {\n const expectedExpression = findMacroExpressionForValue(\n assertionExpected,\n macroResolutionLog,\n agentMacroResolutions\n );\n if (expectedExpression) {\n macroBindings['assertion.expected'] = expectedExpression;\n }\n }\n\n return Object.keys(macroBindings).length > 0 ? macroBindings : undefined;\n};\n\n/** Match `$var.key_name` — the syntax the agent uses to reference variables */\nconst VAR_REF_EXACT = /^\\$var\\.(\\w+)$/;\n\n/**\n * Version of the cache compiler/parameterizer. Stamped into `compilationMeta`\n * on every save. Read by `invalidateStaleCompilerVersionsForWorkflow` (in the\n * workflow-node-cache repo) to sweep pre-version caches on terminal run\n * failure.\n *\n * **Bump only for correctness-level rewrites** — i.e. when the parameterizer\n * produces different output such that old caches are now semantically wrong\n * (e.g. commit 82fff150, which added navigate-URL templating so caches from\n * before it baked in concrete UUIDs). Purely additive rewrites (new capability\n * that doesn't invalidate old output) must NOT bump this, or we'll mass-clear\n * correct caches on every unrelated run failure. If per-feature gating is ever\n * needed, introduce a sibling `compilerFeatures` bitfield rather than abusing\n * the version number.\n *\n * Never decrement. Never set below 2 (v1 = pre-navigate-URL-templating).\n */\nexport const CACHE_COMPILER_VERSION = 3;\n\n/**\n * Minimum length for a variable value to be eligible for substring replacement\n * inside URLs and JS expressions. UUIDs (36 chars) and generated slugs like\n * `workflow-v5hFkKrphKGw` (21 chars) clear this easily; short user-provided\n * values (e.g. \"ok\", \"42\") are held back to avoid false positives. The existing\n * 3-char exact-match threshold below is preserved for text/fill_form/assert.\n */\nconst SUBSTRING_MIN_VALUE_LEN = 8;\n\nconst escapeRegex = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\nconst STRING_LITERAL = /'(?:\\\\.|[^'\\\\])*'|\"(?:\\\\.|[^\"\\\\])*\"/g;\n\n/**\n * Replace any occurrence of a known variable value in a plain string with\n * `$var.<key>`. Used for navigate URLs. Longest-first so that a longer value\n * consumes its substrings before a shorter one can match them.\n */\nexport function replaceVariableValuesInString(\n input: string,\n sortedEntries: Array<[string, string]>\n): string {\n let out = input;\n for (const [key, value] of sortedEntries) {\n if (!value || out.indexOf(value) === -1) continue;\n out = out.replace(new RegExp(escapeRegex(value), 'g'), `$var.${key}`);\n }\n return out;\n}\n\n/**\n * Replace variable values embedded inside JS string literals with tokens that\n * `resolveAssertionConditionForReplay` will expand back via `JSON.stringify`.\n *\n * Given `\"Array.from(...).includes('workflow-xyz')\"` and `{ workflow_name: 'workflow-xyz' }`,\n * emits `\"Array.from(...).includes($var.workflow_name)\"` — the bare token, so\n * replay substitutes `\"workflow-xyz\"` (a valid JS string literal).\n *\n * For substring occurrences inside a larger string literal, splits into\n * concatenation: `'/flows/d036830d-…'` → `'/flows/' + $var.workflow_id`.\n * At replay, this becomes `'/flows/' + \"d036830d-…\"` — valid JS.\n *\n * Only single- and double-quoted string literals are scanned. Template literals\n * (backticks) and non-string regions are passed through unchanged.\n */\nexport function replaceVariableValuesInJsExpression(\n js: string,\n sortedEntries: Array<[string, string]>\n): string {\n if (sortedEntries.length === 0) return js;\n\n return js.replace(STRING_LITERAL, (literal) =>\n rewriteStringLiteralInner(literal.slice(1, -1), literal[0], sortedEntries)\n );\n}\n\n/**\n * True if the string ends with an odd number of backslashes. Re-wrapping such a\n * segment in a same-type quote would produce `…\\'` or `…\\\"`, escaping the\n * closing quote we add and producing malformed JS. Segments with an even run\n * (including zero) re-wrap safely — `\\\\` is an escaped backslash, not an\n * escape of whatever follows.\n */\nfunction endsWithOddBackslashes(s: string): boolean {\n let count = 0;\n for (let i = s.length - 1; i >= 0 && s[i] === '\\\\'; i--) count++;\n return count % 2 === 1;\n}\n\nfunction rewriteStringLiteralInner(\n inner: string,\n quote: string,\n sortedEntries: Array<[string, string]>\n): string {\n for (const [key, value] of sortedEntries) {\n if (!value || inner.indexOf(value) === -1) continue;\n\n if (inner === value) return `$var.${key}`;\n\n const parts = inner.split(value);\n // Refuse to rewrite if any non-empty segment ends with an odd trailing\n // backslash run — the emitted `${quote}${segment}${quote}` would have its\n // closing quote escaped and produce unparseable JS. Leave this literal\n // alone for this variable and let the next entry try.\n if (parts.some((p) => p.length > 0 && endsWithOddBackslashes(p))) continue;\n\n const pieces: string[] = [];\n for (let i = 0; i < parts.length; i++) {\n const segment = parts[i];\n if (segment.length > 0) pieces.push(`${quote}${segment}${quote}`);\n if (i < parts.length - 1) pieces.push(`$var.${key}`);\n }\n const rebuilt = pieces.join(' + ');\n // Recurse with the remaining entries so other variable values can rewrite\n // the newly-created sub-literals.\n return replaceVariableValuesInJsExpression(\n rebuilt,\n sortedEntries.filter(([k]) => k !== key)\n );\n }\n return `${quote}${inner}${quote}`;\n}\n\n/**\n * Try to resolve a text value to a variable key. Checks:\n * 1. Literal `$var.key_name` pattern (agent typed the reference directly)\n * 2. Exact value match against known variable values (longest first)\n */\nconst matchVariableKey = (\n text: string,\n variableKeys: Set<string>,\n sortedEntries: Array<[string, string]>\n): string | undefined => {\n // 1. Agent typed the $var. reference literally\n const refMatch = VAR_REF_EXACT.exec(text);\n if (refMatch && variableKeys.has(refMatch[1])) {\n return refMatch[1];\n }\n\n // 2. Exact value match\n if (text.length >= 3) {\n for (const [varKey, varValue] of sortedEntries) {\n if (text === varValue) return varKey;\n }\n }\n\n return undefined;\n};\n\nconst buildVariableRewriteContext = (variableValues: Record<string, string>) => {\n const keys = new Set(Object.keys(variableValues));\n const sorted = Object.entries(variableValues)\n .filter(([, v]) => v.length >= 3)\n .sort(([, a], [, b]) => b.length - a.length);\n const substringEntries = sorted.filter(([, v]) => v.length >= SUBSTRING_MIN_VALUE_LEN);\n return { keys, sorted, substringEntries };\n};\n\nconst rewriteAssertionStringForStorage = (opts: {\n value: string;\n field: 'condition' | 'expected';\n assertionType: AssertionSpec['type'];\n keys: Set<string>;\n sortedEntries: Array<[string, string]>;\n substringEntries: Array<[string, string]>;\n macroResolutionLog?: MacroResolutionLog;\n agentMacroResolutions?: Map<string, string>;\n}): string => {\n const {\n field,\n assertionType,\n keys,\n sortedEntries,\n substringEntries,\n macroResolutionLog,\n agentMacroResolutions,\n } = opts;\n const value = unwrapAccidentalTextAssertionQuotes(opts.value, assertionType, field);\n\n const macroExpression = findMacroExpressionForValue(\n value,\n macroResolutionLog,\n agentMacroResolutions\n );\n if (macroExpression) {\n return macroExpression;\n }\n\n if (field === 'condition' && assertionType === 'evaluate' && substringEntries.length > 0) {\n return replaceVariableValuesInJsExpression(value, substringEntries);\n }\n\n const exactVariableKey = matchVariableKey(value, keys, sortedEntries);\n if (exactVariableKey) {\n return `$var.${exactVariableKey}`;\n }\n\n if (substringEntries.length > 0) {\n return replaceVariableValuesInString(value, substringEntries);\n }\n\n return value;\n};\n\nexport function normalizeAssertionSpecForStorage(opts: {\n assertion: AssertionSpec;\n variableValues?: Record<string, string>;\n macroResolutionLog?: MacroResolutionLog;\n agentMacroResolutions?: Map<string, string>;\n}): AssertionSpec {\n const { assertion, variableValues, macroResolutionLog, agentMacroResolutions } = opts;\n\n const hasStringExpected = typeof assertion.expected === 'string';\n const shouldCheckMacros =\n macroResolutionLog !== undefined || agentMacroResolutions !== undefined;\n const shouldCheckVariables =\n variableValues !== undefined && Object.keys(variableValues).length > 0;\n\n if (!shouldCheckMacros && !shouldCheckVariables) {\n return assertion;\n }\n\n const rewriteContext = shouldCheckVariables\n ? buildVariableRewriteContext(variableValues)\n : { keys: new Set<string>(), sorted: [] as Array<[string, string]>, substringEntries: [] as Array<[string, string]> };\n\n const rewrittenCondition = rewriteAssertionStringForStorage({\n value: assertion.condition,\n field: 'condition',\n assertionType: assertion.type,\n keys: rewriteContext.keys,\n sortedEntries: rewriteContext.sorted,\n substringEntries: rewriteContext.substringEntries,\n macroResolutionLog,\n agentMacroResolutions,\n });\n\n const rewrittenExpected = hasStringExpected\n ? rewriteAssertionStringForStorage({\n value: assertion.expected as string,\n field: 'expected',\n assertionType: assertion.type,\n keys: rewriteContext.keys,\n sortedEntries: rewriteContext.sorted,\n substringEntries: rewriteContext.substringEntries,\n macroResolutionLog,\n agentMacroResolutions,\n })\n : assertion.expected;\n\n if (\n rewrittenCondition === assertion.condition &&\n rewrittenExpected === assertion.expected\n ) {\n return assertion;\n }\n\n return {\n ...assertion,\n condition: rewrittenCondition,\n ...(hasStringExpected ? { expected: rewrittenExpected } : {}),\n };\n}\n\n/**\n * Post-hoc safety net: scan assembled CachedActions for fill/type values that\n * match known variable values (or literal `$var.` references) and assign\n * `variableKey`/`variableBindings` bindings when the live recording middleware\n * missed them.\n */\nexport function parameterizeActionsWithVariables(\n actions: CachedAction[],\n variableValues: Record<string, string>\n): CachedAction[] {\n const { keys, sorted, substringEntries } = buildVariableRewriteContext(variableValues);\n\n if (keys.size === 0) return actions;\n\n return actions.map((action) => {\n const normalizedAssertion =\n action.actionType === 'assert' && action.assertion\n ? normalizeAssertionSpecForStorage({\n assertion: action.assertion,\n variableValues,\n })\n : action.assertion;\n const actionWithNormalizedAssertion =\n normalizedAssertion && normalizedAssertion !== action.assertion\n ? {\n ...action,\n assertion: normalizedAssertion,\n }\n : action;\n\n // --- type/assert: set variableKey if not already set ---\n if (\n (actionWithNormalizedAssertion.actionType === 'type' ||\n actionWithNormalizedAssertion.actionType === 'assert') &&\n !actionWithNormalizedAssertion.variableKey\n ) {\n const text =\n actionWithNormalizedAssertion.actionType === 'assert'\n ? actionWithNormalizedAssertion.assertion?.condition\n : (actionWithNormalizedAssertion.args?.text ?? actionWithNormalizedAssertion.args?.value);\n if (typeof text === 'string') {\n const varKey = matchVariableKey(text, keys, sorted);\n if (varKey) {\n return { ...actionWithNormalizedAssertion, variableKey: varKey };\n }\n }\n }\n\n // --- fill_form: set variableBindings for unbound fields ---\n if (\n actionWithNormalizedAssertion.actionType === 'fill_form' &&\n Array.isArray(actionWithNormalizedAssertion.args?.fields)\n ) {\n const existingBindings = actionWithNormalizedAssertion.variableBindings ?? {};\n const newBindings: Record<string, string> = { ...existingBindings };\n let changed = false;\n for (let fi = 0; fi < actionWithNormalizedAssertion.args.fields.length; fi++) {\n const bindingKey = `fields.${fi}.value`;\n if (existingBindings[bindingKey]) continue;\n const fieldValue = (actionWithNormalizedAssertion.args.fields as Array<{ value?: unknown }>)[fi]\n ?.value;\n if (typeof fieldValue !== 'string') continue;\n const varKey = matchVariableKey(fieldValue, keys, sorted);\n if (varKey) {\n newBindings[bindingKey] = varKey;\n changed = true;\n }\n }\n if (changed) {\n return { ...actionWithNormalizedAssertion, variableBindings: newBindings };\n }\n }\n\n // --- navigate: rewrite substring occurrences of variable values in args.url\n // with `$var.<key>` tokens. Replay expands via resolveUrlForReplay. ---\n if (\n actionWithNormalizedAssertion.actionType === 'navigate' &&\n typeof actionWithNormalizedAssertion.args?.url === 'string' &&\n substringEntries.length > 0\n ) {\n const rewritten = replaceVariableValuesInString(\n actionWithNormalizedAssertion.args.url,\n substringEntries\n );\n if (rewritten !== actionWithNormalizedAssertion.args.url) {\n return {\n ...actionWithNormalizedAssertion,\n args: { ...actionWithNormalizedAssertion.args, url: rewritten },\n };\n }\n }\n\n // --- assert with evaluate: rewrite concrete variable values embedded in\n // the JS condition. resolveAssertionConditionForReplay expands $var.X\n // back via JSON.stringify at replay, yielding valid JS. ---\n if (\n actionWithNormalizedAssertion.actionType === 'assert' &&\n actionWithNormalizedAssertion.assertion?.type === 'evaluate' &&\n typeof actionWithNormalizedAssertion.assertion.condition === 'string' &&\n substringEntries.length > 0\n ) {\n const { condition } = actionWithNormalizedAssertion.assertion;\n const rewrittenCondition = replaceVariableValuesInJsExpression(condition, substringEntries);\n\n const argsValue = actionWithNormalizedAssertion.args?.value;\n const rewrittenArgsValue =\n typeof argsValue === 'string'\n ? replaceVariableValuesInJsExpression(argsValue, substringEntries)\n : argsValue;\n\n if (rewrittenCondition !== condition || rewrittenArgsValue !== argsValue) {\n return {\n ...actionWithNormalizedAssertion,\n assertion: {\n ...actionWithNormalizedAssertion.assertion,\n condition: rewrittenCondition,\n },\n args:\n typeof rewrittenArgsValue === 'string'\n ? { ...actionWithNormalizedAssertion.args, value: rewrittenArgsValue }\n : actionWithNormalizedAssertion.args,\n };\n }\n }\n\n return actionWithNormalizedAssertion;\n });\n}\n\n/**\n * Count the substring-substitution rewrites performed by\n * `parameterizeActionsWithVariables` between an input and output action array.\n * Only covers the navigate-URL and evaluate-assert branches — the pre-existing\n * type/assert/fill_form variable-key bindings are intentionally excluded\n * because they don't mutate user-visible action content.\n *\n * Arrays are expected to be the same length and in the same order (the\n * parameterize function is a 1:1 map).\n */\nexport function countVariableRewrites(\n before: CachedAction[],\n after: CachedAction[]\n): { navigateUrlRewrites: number; evaluateAssertRewrites: number } {\n let navigateUrlRewrites = 0;\n let evaluateAssertRewrites = 0;\n const n = Math.min(before.length, after.length);\n for (let i = 0; i < n; i++) {\n const b = before[i];\n const a = after[i];\n if (a.actionType === 'navigate' && b.args?.url !== a.args?.url) {\n navigateUrlRewrites++;\n }\n if (\n a.actionType === 'assert' &&\n a.assertion?.type === 'evaluate' &&\n b.assertion?.condition !== a.assertion?.condition\n ) {\n evaluateAssertRewrites++;\n }\n }\n return { navigateUrlRewrites, evaluateAssertRewrites };\n}\n\ninterface AssembleCachedActionsOptions {\n actions: CachedActionRecord[];\n macroResolutionLog?: MacroResolutionLog;\n agentMacroResolutions?: Map<string, string>;\n}\n\n/**\n * Convert runtime-recorded actions into persisted cache actions, preserving\n * macro source expressions through `macroBindings` when available.\n */\nexport function assembleCachedActionsForStorage(\n opts: AssembleCachedActionsOptions\n): CachedAction[] {\n const { actions, macroResolutionLog, agentMacroResolutions } = opts;\n\n return actions.map((action) => {\n const macroBindings = buildMacroBindingsForAction({\n action,\n macroResolutionLog,\n agentMacroResolutions,\n });\n\n return {\n index: action.index,\n toolName: action.toolName,\n actionType: action.actionType as CachedActionType,\n nodeId: action.nodeId,\n selectors: action.selectors,\n args: action.args,\n elementDescription: action.elementDescription,\n waitBefore: action.waitBefore,\n assertion:\n action.actionType === 'assert' && action.assertion\n ? normalizeAssertionSpecForStorage({\n assertion: action.assertion,\n macroResolutionLog,\n agentMacroResolutions,\n })\n : action.assertion,\n requiresAgent: action.requiresAgent,\n selectorAuthor: action.selectorAuthor,\n isAnnotation: action.isAnnotation,\n annotationType: action.annotationType,\n annotationColor: action.annotationColor,\n ...(macroBindings && { macroBindings }),\n ...(action.variableKey && { variableKey: action.variableKey }),\n ...(action.variableBindings && { variableBindings: action.variableBindings }),\n };\n });\n}\n","/**\n * Headless DOM Session\n *\n * One shared Chromium session for offline substrate capture and locator\n * verification. Substrate capture and verification MUST share one rendering\n * environment — viewport, screen, UA — or responsive/UA-dependent DOM\n * differences shift the aria-ref table between captures. Centralizing the\n * lifecycle here guarantees that invariant and halves the per-job Chromium\n * footprint versus each consumer owning a browser.\n *\n * The environment matches the scenario suite exactly: Desktop Chrome\n * descriptor + load-event hydration (`waitForTraceDomHydration`).\n *\n * Defense-in-depth: all http(s) requests are aborted on the context. Pages\n * are trace-reconstructed customer HTML loaded via `file://`; Chromium\n * already blocks file→file fetch/XHR by default, and the abort rule removes\n * the remaining network egress surface for hostile page scripts.\n *\n * @module optimizer/headless-session\n */\n\nimport { chromium, devices, type Browser, type BrowserContext, type Page } from 'playwright';\n\nexport class HeadlessDomSession {\n private browser: Browser | null = null;\n private context: BrowserContext | null = null;\n\n async page(): Promise<Page> {\n if (!this.context) {\n // Atomic init: never leave a launched browser without a context — a\n // half-open state would leak the process (close() nulls both) and make\n // the `context` access below unsound.\n const browser = await chromium.launch({ headless: true });\n try {\n const context = await browser.newContext({ ...devices['Desktop Chrome'] });\n await context.route(/^https?:/, (route) => route.abort());\n this.browser = browser;\n this.context = context;\n } catch (err) {\n await browser.close().catch(() => undefined);\n throw err;\n }\n }\n return this.context.newPage();\n }\n\n async close(): Promise<void> {\n await this.context?.close().catch(() => undefined);\n await this.browser?.close().catch(() => undefined);\n this.context = null;\n this.browser = null;\n }\n}\n","/**\n * Trace Node Segmenter\n *\n * Groups Playwright trace actions into per-workflow-node windows using the\n * named `tracing.group()` spans the executor opens around each step:\n *\n * - `Step N: <label>` — agent-executed node (the harvest target)\n * - `Cache Replay N: <name>` — replayed node. Still harvestable: L2 gap\n * healing and recovery actions are recorded INSIDE this group, so a step\n * that replayed with `l2_gap`/`recovery` healing carries its live agent\n * work here, not in a `Step N:` group. (Legacy traces omit the number.)\n * - `Canary Internal: <op>` — plumbing (snapshot capture, element resolution)\n *\n * Tolerant by design: failure-path traces leave the failing step's group\n * unclosed (no `after` event), so an open-ended group extends to the next\n * top-level group's start (or the end of the trace). Actions are assigned by\n * `parentId` containment when present, with a start-time window fallback.\n *\n * @module optimizer/trace-node-segmenter\n */\n\nimport type { TraceAction, TraceGroup } from '@chatsdet/trace-tools';\n\nexport type NodeSegmentKind = 'agent-step' | 'cache-replay';\n\nexport interface NodeSegment {\n kind: NodeSegmentKind;\n /** 1-based step number parsed from the `Step N:` / `Cache Replay N:` group name. */\n stepNumber?: number;\n /** Human label from the group name (node label or replayed node name). */\n label: string;\n /** The group's callId — actions inside carry it (transitively) as parentId. */\n groupCallId: string;\n startTime: number;\n /** Open-ended (failure path) segments extend to the next segment's start. */\n endTime?: number;\n /**\n * Trace actions inside this segment, with their index into the full\n * `parseTraceActions` array (the index `reconstructSnapshots` expects).\n */\n actions: Array<{ index: number; action: TraceAction }>;\n}\n\nconst STEP_GROUP = /^Step (\\d+): (.*)$/;\n// The step number is optional: traces recorded before the replay handler\n// numbered its groups carry the bare `Cache Replay: <name>` form.\nconst CACHE_REPLAY_GROUP = /^Cache Replay(?: (\\d+))?: (.*)$/;\nconst INTERNAL_GROUP_PREFIX = 'Canary Internal:';\n\n/**\n * Segment a run's trace actions into per-node windows.\n *\n * @param groups - from `parseTraceGroups(traceZipPath)`\n * @param actions - from `parseTraceActions(traceZipPath)` (indices must match)\n */\nexport function segmentTraceByNode(groups: TraceGroup[], actions: TraceAction[]): NodeSegment[] {\n // Top-level node groups only — internal groups nest inside step groups and\n // are excluded; their actions still belong to the enclosing step.\n const nodeGroups = groups.filter(\n (g) =>\n !g.name.startsWith(INTERNAL_GROUP_PREFIX) &&\n (STEP_GROUP.test(g.name) || CACHE_REPLAY_GROUP.test(g.name))\n );\n\n // Close open-ended groups at the next node group's start so a failure-path\n // trace (unclosed final group) still yields a usable window.\n const sorted = [...nodeGroups].sort((a, b) => a.startTime - b.startTime);\n const segments: NodeSegment[] = sorted.map((g, idx) => {\n const stepMatch = STEP_GROUP.exec(g.name);\n const replayMatch = CACHE_REPLAY_GROUP.exec(g.name);\n const effectiveEnd = g.endTime ?? sorted[idx + 1]?.startTime;\n const stepNumberRaw = stepMatch ? stepMatch[1] : replayMatch?.[1];\n return {\n kind: stepMatch ? ('agent-step' as const) : ('cache-replay' as const),\n stepNumber: stepNumberRaw !== undefined ? Number(stepNumberRaw) : undefined,\n label: stepMatch ? stepMatch[2]! : replayMatch![2]!,\n groupCallId: g.callId,\n startTime: g.startTime,\n endTime: effectiveEnd,\n actions: [],\n };\n });\n\n if (segments.length === 0) return segments;\n\n // parentId chain: group callId -> enclosing node-group callId (internal\n // groups resolve through their parents).\n const groupById = new Map(groups.map((g) => [g.callId, g]));\n const nodeGroupIds = new Set(segments.map((s) => s.groupCallId));\n const resolveNodeGroup = (parentId: string | undefined): string | undefined => {\n let current = parentId;\n // Bounded walk — trace group nesting is shallow; guard against cycles.\n for (let hops = 0; current && hops < 16; hops++) {\n if (nodeGroupIds.has(current)) return current;\n current = groupById.get(current)?.parentId;\n }\n return undefined;\n };\n\n const segmentByGroupId = new Map(segments.map((s) => [s.groupCallId, s]));\n for (let i = 0; i < actions.length; i++) {\n const action = actions[i]!;\n const byParent = resolveNodeGroup(action.parentId);\n if (byParent) {\n segmentByGroupId.get(byParent)!.actions.push({ index: i, action });\n continue;\n }\n // Fallback: start-time window (covers traces recorded before parentId\n // capture, and actions Playwright didn't parent into the group).\n const within = segments.find(\n (s) =>\n action.startTime >= s.startTime && (s.endTime === undefined || action.startTime < s.endTime)\n );\n within?.actions.push({ index: i, action });\n }\n\n return segments;\n}\n\n/** One run step, in `orderIndex` order, for segment→node resolution. */\nexport interface SegmentResolutionStep {\n nodeId: string | null;\n /** Display label as the executor derives it (the same string the trace group title used). */\n label: string;\n}\n\n/**\n * Resolve each segment to its workflow node id, in segment order.\n *\n * Numbered segments (`Step N:` / `Cache Replay N:`) resolve positionally via\n * `steps[N-1]`. Legacy un-numbered cache-replay segments fall back to label\n * matching, consuming steps forward-only so repeated labels map to successive\n * steps and a renamed/unknown label resolves to `null` rather than a wrong\n * node. Numbered segments advance the matching cursor past their own step.\n */\nexport function resolveSegmentNodeIds(\n segments: ReadonlyArray<Pick<NodeSegment, 'kind' | 'stepNumber' | 'label'>>,\n steps: ReadonlyArray<SegmentResolutionStep>\n): Array<string | null> {\n let cursor = 0;\n return segments.map((segment) => {\n if (segment.stepNumber !== undefined) {\n const idx = segment.stepNumber - 1;\n cursor = Math.max(cursor, idx + 1);\n return steps[idx]?.nodeId ?? null;\n }\n for (let j = cursor; j < steps.length; j++) {\n if (steps[j]!.label === segment.label) {\n cursor = j + 1;\n return steps[j]!.nodeId;\n }\n }\n return null;\n });\n}\n","/**\n * Substrate Materializer\n *\n * Lazily reconstructs a single trace action's DOM (Playwright trace viewer\n * decode) and captures a production substrate-v2 snapshot from it in a\n * headless page — the offline equivalent of the live capture path.\n *\n * Expensive (decodes the trace + drives a headless browser), so results are\n * memoized per (traceZipPath, actionIndex, phase) and the reconstructed\n * dom.html is persisted next to the substrate for the locator verifier.\n *\n * @module optimizer/substrate-materializer\n */\n\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n parseTraceActions,\n reconstructSnapshots,\n toMutationIndex,\n type TraceAction,\n} from '@chatsdet/trace-tools';\nimport { captureSubstrateV2, type BrowserLogger } from '@chatsdet/browser-core';\nimport { createLogger } from '../logger.js';\nimport { HeadlessDomSession } from './headless-session.js';\n\nconst logger = createLogger({ module: 'SubstrateMaterializer' });\n\nexport interface MaterializedSubstrate {\n /** Production substrate-v2 yaml captured over the reconstructed DOM. */\n substrateYaml: string;\n /** Path to the persisted substrate yaml. */\n substratePath: string;\n /** Path to the persisted self-contained dom.html (verifier input). */\n domPath: string;\n actionIndex: number;\n phase: 'before' | 'after';\n}\n\nexport interface SubstrateMaterializerOptions {\n traceZipPath: string;\n /** Output root; files land under `<outDir>/<actionIndex>.<phase>.*`. */\n outDir: string;\n logger?: BrowserLogger;\n /**\n * Shared headless session — pass the same instance to the LocatorVerifier\n * so capture and verification render identically (and one Chromium serves\n * both). When omitted the materializer owns (and closes) its own.\n */\n session?: HeadlessDomSession;\n}\n\n/**\n * Memoizing materializer bound to one trace + output dir. Shares one headless\n * browser across calls; `close()` must run when the session ends.\n */\nexport class SubstrateMaterializer {\n private readonly cache = new Map<string, MaterializedSubstrate>();\n\n private readonly session: HeadlessDomSession;\n private readonly ownsSession: boolean;\n /** Parsed trace actions in `actions.jsonl` order — lazy, parsed once. */\n private allActions: TraceAction[] | null = null;\n\n constructor(private readonly opts: SubstrateMaterializerOptions) {\n this.session = opts.session ?? new HeadlessDomSession();\n this.ownsSession = !opts.session;\n }\n\n /**\n * Reconstruct one action's snapshot and capture substrate-v2 over it.\n * `phase: 'before'` is the page state the action targeted (locator input);\n * `'after'` is its result (the next action's context).\n *\n * `actionIndex` is the action's position in `parseTraceActions` order — the\n * SAME index space as the workspace's `browser/actions.jsonl` and\n * `optimizer/segments.json` actionIndices. The mutation-filtered index the\n * snapshot reconstructor uses internally is remapped here; observation\n * actions (screenshots) are rejected with a self-correcting error.\n */\n async materialize(\n actionIndex: number,\n phase: 'before' | 'after' = 'before'\n ): Promise<MaterializedSubstrate> {\n const key = `${actionIndex}:${phase}`;\n const hit = this.cache.get(key);\n if (hit) return hit;\n\n this.allActions ??= parseTraceActions(this.opts.traceZipPath);\n const resolved = toMutationIndex(this.allActions, actionIndex);\n if (!resolved.ok) {\n throw new Error(resolved.reason);\n }\n\n const results = await reconstructSnapshots({\n traceZipPath: this.opts.traceZipPath,\n includeScreenshots: false,\n includeHtml: true,\n filter: phase,\n raw: false,\n actionIndex: resolved.mutationIndex,\n });\n const snapshot = results.find((r) => r.phase === phase && r.html);\n if (!snapshot?.html) {\n throw new Error(\n `No ${phase}-snapshot HTML reconstructable for trace action ${actionIndex} — ` +\n `the action may predate page load or the trace omitted its snapshot`\n );\n }\n\n await mkdir(this.opts.outDir, { recursive: true });\n // Resolve to an absolute path: callers may pass a relative outDir (e.g. the\n // CLI `--workspace ./dir`), and `file://<relative>` is an invalid URL that\n // fails `page.goto`. Absolute paths also make the returned dom/substrate\n // paths safe for the downstream locator verifier regardless of its cwd.\n const domPath = path.resolve(this.opts.outDir, `${actionIndex}.${phase}.dom.html`);\n await writeFile(domPath, snapshot.html, 'utf-8');\n\n const page = await this.session.page();\n try {\n await page.goto(pathToFileURL(domPath).href, { waitUntil: 'load' });\n await waitForTraceDomHydration(page);\n const substrateYaml = await captureSubstrateV2(page, this.opts.logger ?? logger);\n const substratePath = path.resolve(this.opts.outDir, `${actionIndex}.${phase}.substrate.v2.yaml`);\n await writeFile(substratePath, substrateYaml, 'utf-8');\n\n const out: MaterializedSubstrate = {\n substrateYaml,\n substratePath,\n domPath,\n actionIndex,\n phase,\n };\n this.cache.set(key, out);\n return out;\n } finally {\n await page.close().catch(() => undefined);\n }\n }\n\n async close(): Promise<void> {\n if (this.ownsSession) await this.session.close();\n }\n}\n\n/**\n * Trace-rendered HTML installs load/DOMContentLoaded handlers that restore\n * values, scroll positions, canvas placeholders, and visibility. Two frames\n * gives those handlers a stable post-load accessibility tree before refs are\n * materialized. (Same wait the scenario-suite locator runner uses.)\n */\nexport async function waitForTraceDomHydration(page: {\n evaluate: (fn: () => Promise<void>) => Promise<void>;\n}): Promise<void> {\n await page.evaluate(\n () =>\n new Promise<void>((resolve) => {\n requestAnimationFrame(() => requestAnimationFrame(() => resolve()));\n })\n );\n}\n","/**\n * Offline Locator Verifier\n *\n * Verifies a `SelectorStrategy` against a trace-reconstructed DOM without\n * touching the live application — the same bar the scenario suite's locator\n * runner enforces (`apps/api/tests/scenarios/runner.locator.pw.ts`), lifted\n * into an importable library:\n *\n * 1. Load the reconstructed dom.html in a headless page and let the trace\n * viewer's restore handlers settle.\n * 2. Materialize Playwright's internal aria-ref table via `ariaSnapshot`.\n * 3. Capture the ground-truth handle for the recorded target ref.\n * 4. Resolve the candidate strategy through the production `resolveElement`\n * (verify mode) and require handle identity with the ground truth.\n * 5. Reject strategies that lean on volatile identifier tokens (seeded entity\n * ids, framework-generated class hashes) via the shared classifier.\n *\n * A locator that fails here must degrade to a gap — never ship unverified.\n *\n * @module optimizer/locator-verifier\n */\n\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { SelectorStrategy } from '@chatsdet/types';\nimport { isVolatileIdentifier, stableIdentifierPrefix } from '@chatsdet/types';\nimport { resolveElement } from '../element-resolver.js';\nimport { hydrateDynamicSelectors } from '../selector-derivation.js';\nimport { waitForTraceDomHydration } from './substrate-materializer.js';\nimport { HeadlessDomSession } from './headless-session.js';\n\nexport interface LocatorVerification {\n /** Strategy resolved to exactly one element. */\n resolvesUniquely: boolean;\n /** Resolved element is the recorded target (handle identity). */\n matchesTarget: boolean;\n /** No identifying token classified as volatile. */\n volatileTokenClean: boolean;\n /** Volatile tokens found, for the agent to reason about. */\n volatileTokens: string[];\n /** All three checks passed. */\n verdict: boolean;\n /** Failure detail when verdict is false. */\n reason?: string;\n}\n\nconst RESOLVE_TIMEOUT_MS = 5_000;\n\n/**\n * Collect the identifying string tokens a strategy leans on, for the volatile\n * classifier. Role/label/text predicates are human-facing content (volatility\n * there is the variable-binding system's job); this pass guards the\n * machine-facing anchors: test ids, css hints, automation ids, and raw\n * locator chains.\n */\nfunction identifyingTokens(strategy: SelectorStrategy): string[] {\n const tokens: string[] = [];\n if (strategy.testId) tokens.push(strategy.testId);\n if (strategy.automationId) tokens.push(strategy.automationId);\n if (strategy.css) {\n // Class tokens and attribute values inside the css hint.\n for (const cls of strategy.css.matchAll(/\\.([A-Za-z0-9_-]+)/g)) tokens.push(cls[1]!);\n for (const attr of strategy.css.matchAll(/\\[[^\\]=]+=\"([^\"]+)\"\\]/g)) tokens.push(attr[1]!);\n }\n if (strategy.playwrightLocator) {\n for (const tid of strategy.playwrightLocator.matchAll(/getByTestId\\('([^']+)'\\)/g)) {\n tokens.push(tid[1]!);\n }\n }\n return tokens;\n}\n\nexport function classifyStrategyTokens(strategy: SelectorStrategy): {\n volatileTokenClean: boolean;\n volatileTokens: string[];\n} {\n const volatileTokens = identifyingTokens(strategy).filter(\n // A token with a stable prefix (e.g. `__new__<ts>`) is usable via prefix\n // matching — only fully-volatile tokens fail the pass.\n (t) => isVolatileIdentifier(t) && stableIdentifierPrefix(t) === null\n );\n return { volatileTokenClean: volatileTokens.length === 0, volatileTokens };\n}\n\nexport interface VerifyLocatorOptions {\n /** Path to the trace-reconstructed, self-contained dom.html. */\n domPath: string;\n /** The recorded target's aria-ref in the substrate captured over this DOM. */\n targetRef: string;\n strategy: SelectorStrategy;\n /** Variable values for hydrating dynamic selectors before resolution. */\n variableValues?: Record<string, string>;\n}\n\n/**\n * Shared-browser verifier bound to one optimization session. `close()` must\n * run when the session ends.\n */\nexport class LocatorVerifier {\n private readonly session: HeadlessDomSession;\n private readonly ownsSession: boolean;\n\n constructor(opts?: { session?: HeadlessDomSession }) {\n this.session = opts?.session ?? new HeadlessDomSession();\n this.ownsSession = !opts?.session;\n }\n\n async verify(opts: VerifyLocatorOptions): Promise<LocatorVerification> {\n const tokenPass = classifyStrategyTokens(opts.strategy);\n\n const page = await this.session.page();\n try {\n await page.goto(pathToFileURL(path.resolve(opts.domPath)).href, { waitUntil: 'load' });\n await waitForTraceDomHydration(page);\n\n // Materialize Playwright's internal ref table for this page so the\n // `aria-ref=` selector engine can resolve refs the substrate yaml points\n // at. ariaSnapshot itself does not write a DOM `aria-ref` attribute;\n // refs only exist within Playwright's snapshot engine.\n await page.ariaSnapshot({ mode: 'ai' });\n\n // Ground-truth handle immediately after the snapshot that created the\n // ref table — later locator probes can refresh refs.\n const truth = page.locator(`aria-ref=${opts.targetRef}`);\n const truthHandle = await truth.elementHandle({ timeout: RESOLVE_TIMEOUT_MS }).catch(() => null);\n if (!truthHandle) {\n return {\n resolvesUniquely: false,\n matchesTarget: false,\n ...tokenPass,\n verdict: false,\n reason: `target ref ${opts.targetRef} not present in the reconstructed DOM`,\n };\n }\n\n const hydrated =\n opts.variableValues && Object.keys(opts.variableValues).length > 0\n ? hydrateDynamicSelectors(opts.strategy, opts.variableValues)\n : opts.strategy;\n\n const resolved = await resolveElement(page, hydrated, RESOLVE_TIMEOUT_MS, {\n mode: 'verify',\n }).catch(() => null);\n if (!resolved) {\n await truthHandle.dispose().catch(() => undefined);\n return {\n resolvesUniquely: false,\n matchesTarget: false,\n ...tokenPass,\n verdict: false,\n reason: 'strategy did not resolve to a unique element',\n };\n }\n\n const resolvedHandle = await resolved\n .elementHandle({ timeout: RESOLVE_TIMEOUT_MS })\n .catch(() => null);\n let matchesTarget = false;\n try {\n if (resolvedHandle) {\n matchesTarget = await page.evaluate(\n ([a, b]) => a === b,\n [resolvedHandle, truthHandle] as const\n );\n }\n } finally {\n await resolvedHandle?.dispose().catch(() => undefined);\n await truthHandle.dispose().catch(() => undefined);\n }\n\n const verdict = matchesTarget && tokenPass.volatileTokenClean;\n return {\n resolvesUniquely: true,\n matchesTarget,\n ...tokenPass,\n verdict,\n reason: verdict\n ? undefined\n : !matchesTarget\n ? 'strategy resolved a different element than the recorded target'\n : `volatile identifier tokens: ${tokenPass.volatileTokens.join(', ')}`,\n };\n } finally {\n await page.close().catch(() => undefined);\n }\n }\n\n async close(): Promise<void> {\n if (this.ownsSession) await this.session.close();\n }\n}\n","/**\n * Augmentor Verifier\n *\n * The offline proof that a candidate custom augmentor actually heals a\n * semantic-snapshot blind spot — and does so cache-safely. Runs the SAME\n * engine the live runtime uses (`applyCustomAugmentors` from browser-core)\n * against a reconstructed DOM in a headless page, then gathers OBSERVABLE\n * evidence rather than trusting assertions:\n *\n * 1. baseline — capture substrate-v2; confirm the target (role,name)\n * elements are ABSENT (the blind spot reproduces);\n * 2. execute — run the validated collector for real (querySelectorAll →\n * collector(el) → setAttribute role/aria-label/data-augmentor-id);\n * 3. reappear — re-capture; confirm the previously-absent elements now\n * appear as real refs;\n * 4. targeting — resolve each new `aria-ref` back to a DOM node and confirm\n * it carries our `data-augmentor-id` (a click on the ref lands\n * on the intended element);\n * 5. cache-safe — strip the injected attributes and confirm each declared\n * `stableAnchor` still resolves UNIQUELY to its target, so a\n * cached locator can never depend on an injected attribute.\n *\n * Shares the headless Chromium with the {@link SubstrateMaterializer} /\n * {@link LocatorVerifier} so capture and verification render identically.\n *\n * @module optimizer/augmentor-verifier\n */\n\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n applyCustomAugmentors,\n captureSubstrateV2,\n parseSnapshot,\n type SnapshotElement,\n} from '@chatsdet/browser-core';\nimport type { AugmentorDefinition } from '@chatsdet/augmentor-core';\nimport { createLogger } from '../logger.js';\nimport { HeadlessDomSession } from './headless-session.js';\nimport { waitForTraceDomHydration } from './substrate-materializer.js';\n\nconst logger = createLogger({ module: 'AugmentorVerifier' });\n\nexport interface AugmentorVerificationResult {\n /** All gates passed: blind spot reproduced, healed, targetable, cache-safe. */\n verified: boolean;\n /** The target (role,name) elements were absent in the un-augmented snapshot. */\n baselineAbsent: boolean;\n /** Elements the collector annotated. */\n elementsAnnotated: number;\n /** Engine-reported invariant (count within [min,max]) for this run. */\n invariantPassed: boolean;\n /** The collector threw / timed out in the page. */\n errored: boolean;\n errorMessage?: string;\n /** Sample of the new refs that appeared (for the agent to eyeball). */\n sampleRefs: string[];\n /** Every sampled new ref resolved to an element carrying our data-augmentor-id. */\n refsResolveToTargets: boolean;\n /** Every declared stableAnchor resolves uniquely to its target post-strip. */\n cacheSafe: boolean;\n /** Annotated elements that declared no stableAnchor (perception-only, non-cacheable). */\n anchorlessCount: number;\n /** Collector wall-clock in the page. */\n durationMs: number;\n /** Human-readable reasons for any failed gate (the agent iterates on these). */\n issues: string[];\n}\n\nexport interface VerifyAugmentorOptions {\n /** Path to a reconstructed self-contained dom.html (from SubstrateMaterializer). */\n domPath: string;\n /** The candidate augmentor (id is used as the data-augmentor-id marker). */\n augmentor: AugmentorDefinition;\n}\n\n/** Flatten a parsed substrate tree to (role, name) → ref entries. */\nfunction flatten(roots: SnapshotElement[]): SnapshotElement[] {\n const out: SnapshotElement[] = [];\n const walk = (n: SnapshotElement): void => {\n out.push(n);\n for (const c of n.children) walk(c);\n };\n for (const r of roots) walk(r);\n return out;\n}\n\nconst key = (role: string, name: string | undefined): string => `${role}\\u0000${name ?? ''}`;\n\n/**\n * Offline verifier bound to one headless session. Pass the same session as the\n * materializer so the DOM renders identically; `close()` if this owns it.\n */\nexport class AugmentorVerifier {\n private readonly session: HeadlessDomSession;\n private readonly ownsSession: boolean;\n\n constructor(opts?: { session?: HeadlessDomSession }) {\n this.session = opts?.session ?? new HeadlessDomSession();\n this.ownsSession = !opts?.session;\n }\n\n async verify(opts: VerifyAugmentorOptions): Promise<AugmentorVerificationResult> {\n const { domPath, augmentor } = opts;\n const issues: string[] = [];\n const page = await this.session.page();\n try {\n await page.goto(pathToFileURL(path.resolve(domPath)).href, { waitUntil: 'load' });\n await waitForTraceDomHydration(page);\n\n // 1. Baseline — the blind spot must reproduce here.\n const baselineYaml = await captureSubstrateV2(page, logger);\n const baselineKeys = new Set(flatten(parseSnapshot(baselineYaml)).map((e) => key(e.role, e.text)));\n\n // 2. Execute the real engine (mutates the page in place).\n const pass = await applyCustomAugmentors(page, [augmentor], logger);\n const exec = pass.executions[0];\n const elementsAnnotated = exec?.elementsAnnotated ?? 0;\n const errored = exec?.errored ?? false;\n const invariantPassed = exec?.invariantPassed ?? false;\n const durationMs = exec?.durationMs ?? 0;\n if (errored) {\n issues.push(`collector errored in page: ${exec?.errorMessage ?? 'unknown'}`);\n }\n if (elementsAnnotated === 0) {\n issues.push('collector annotated 0 elements — matchSelector found nothing, or every descriptor was rejected');\n }\n\n // 3. Re-capture — the healed elements must now appear as real refs.\n const augmentedYaml = await captureSubstrateV2(page, logger);\n const augmentedEls = flatten(parseSnapshot(augmentedYaml));\n const annotatedKeys = new Set(pass.annotations.map((a) => key(a.role, a.name)));\n const newEls = augmentedEls.filter(\n (e) => annotatedKeys.has(key(e.role, e.text)) && !baselineKeys.has(key(e.role, e.text))\n );\n const baselineAbsent = pass.annotations.length > 0 && newEls.length > 0;\n if (!baselineAbsent && pass.annotations.length > 0) {\n issues.push(\n 'annotated (role,name) pairs were already present in the un-augmented snapshot — ' +\n 'this augmentor heals nothing (or the names are not distinctive)'\n );\n }\n // Targeting is a SAMPLE: we resolve the first 8 new refs, not all of them.\n // A collector that annotates many elements but mis-targets one past the\n // sample window can still pass — acceptable for a perception aid.\n const sampleRefs = newEls.slice(0, 8).map((e) => e.ref);\n\n // 4. Targeting — each sampled new ref must resolve to an augmented element.\n // Independent reads against a now-static page — resolve them concurrently.\n const targeting = await Promise.all(\n sampleRefs.map(async (ref) => {\n try {\n const handle = await page.$(`aria-ref=${ref}`);\n const augId = handle\n ? await handle.getAttribute('data-augmentor-id').catch(() => null)\n : null;\n await handle?.dispose();\n if (augId !== augmentor.id) {\n return `ref ${ref} did not resolve to an augmentor-annotated element`;\n }\n return null;\n } catch (err) {\n return `ref ${ref} could not be resolved: ${err instanceof Error ? err.message : String(err)}`;\n }\n })\n );\n const targetingIssues = targeting.filter((i): i is string => i !== null);\n for (const i of targetingIssues) issues.push(i);\n const refsResolveToTargets = sampleRefs.length > 0 && targetingIssues.length === 0;\n\n // 5. Cache-safety — strip the injected attributes and confirm each declared\n // stableAnchor still resolves uniquely to its own target. This is what\n // lets the live cache anchor on durable, un-injected signals.\n const cacheCheck = await page.evaluate(() => {\n const els = Array.from(document.querySelectorAll('[data-augmentor-id]'));\n let anchorless = 0;\n const failures: string[] = [];\n // Mark targets before stripping so we can re-identify them.\n els.forEach((el, i) => el.setAttribute('data-aug-verify-idx', String(i)));\n const anchors = els.map((el) => el.getAttribute('data-augmentor-anchor'));\n // Strip everything the engine injected (keep only the temp verify marker).\n for (const el of els) {\n el.removeAttribute('role');\n el.removeAttribute('aria-label');\n el.removeAttribute('aria-disabled');\n el.removeAttribute('data-augmentor-id');\n el.removeAttribute('data-augmentor-anchor');\n }\n els.forEach((el, i) => {\n const anchor = anchors[i];\n if (!anchor) {\n anchorless++;\n return;\n }\n // Bound the selector the page evaluates — a pathologically long /\n // deeply-combinated stableAnchor could otherwise spin CPU here.\n if (anchor.length > 500) {\n failures.push(`stableAnchor #${i} exceeds 500 chars — too complex to be durable: ${anchor.slice(0, 80)}…`);\n return;\n }\n let matches: Element[] = [];\n try {\n matches = Array.from(document.querySelectorAll(anchor));\n } catch {\n failures.push(`stableAnchor #${i} is not a valid selector: ${anchor}`);\n return;\n }\n if (matches.length !== 1) {\n failures.push(`stableAnchor #${i} matched ${matches.length} elements (want exactly 1): ${anchor}`);\n } else if (matches[0]?.getAttribute('data-aug-verify-idx') !== String(i)) {\n failures.push(`stableAnchor #${i} resolved to a different element than its target: ${anchor}`);\n }\n });\n return { anchorless, failures };\n });\n for (const f of cacheCheck.failures) issues.push(f);\n const cacheSafe = cacheCheck.failures.length === 0;\n if (cacheCheck.anchorless > 0) {\n issues.push(\n `${cacheCheck.anchorless} annotated element(s) declared no stableAnchor — they will be ` +\n 'visible to the agent but their locators stay irreducible (workflow-variable / L3 disambiguation)'\n );\n }\n\n const verified =\n baselineAbsent &&\n !errored &&\n invariantPassed &&\n elementsAnnotated > 0 &&\n refsResolveToTargets &&\n cacheSafe;\n\n return {\n verified,\n baselineAbsent,\n elementsAnnotated,\n invariantPassed,\n errored,\n errorMessage: exec?.errorMessage,\n sampleRefs,\n refsResolveToTargets,\n cacheSafe,\n anchorlessCount: cacheCheck.anchorless,\n durationMs,\n issues,\n };\n } finally {\n await page.close().catch(() => undefined);\n }\n }\n\n async close(): Promise<void> {\n if (this.ownsSession) await this.session.close();\n }\n}\n","/**\n * Action Synthesizer\n *\n * Converts an optimizer-authored per-step action plan into storable\n * `CachedAction[]` by routing through the SAME assembly functions the live\n * recording path uses (`assembleCachedActionsForStorage` +\n * `parameterizeActionsWithVariables`) — no parallel token logic.\n *\n * The plan carries the literal values observed in the trace; macro and\n * variable provenance from the run records lets the canonical assembly\n * reverse-map literals into `macroBindings` and `$var.X` bindings so the\n * recipe replays correctly on future runs with fresh values.\n *\n * @module optimizer/action-synthesizer\n */\n\nimport type { AssertionSpec, CachedAction, SelectorStrategy } from '@chatsdet/types';\nimport type { CachedActionRecord } from '../types.js';\nimport type { MacroResolutionLog } from '../macros/types.js';\nimport {\n assembleCachedActionsForStorage,\n parameterizeActionsWithVariables,\n} from '../cached-action-assembly.js';\n\n/**\n * One browser action on a node's most-direct path, as authored by the\n * optimizer agent. Values in `args` are the literals observed in the trace —\n * provenance mapping back to variables/macros is this module's job, not the\n * agent's.\n */\nexport interface PlannedBrowserAction {\n /** 1-based playbook step this action fulfills. */\n stepOrder: number;\n /** Tool name as the live agent would have called it (e.g. 'browser_click'). */\n toolName: string;\n /** Normalized action type (click | type | select_option | navigate | assert | …). */\n actionType: string;\n /** Literal tool args as observed in the trace (sanitized — no ephemeral refs). */\n args: Record<string, unknown>;\n /** Offline-verified selector strategy for the target element. */\n selectors?: SelectorStrategy;\n /** Human-readable target description. */\n elementDescription?: string;\n /** Assertion spec for assertion steps. */\n assertion?: AssertionSpec;\n}\n\n/**\n * Action types whose replay resolves a target element and therefore requires\n * a verified selector. Everything else (navigate, wait_for, assert, capture,\n * evaluate, screenshot, resize, scroll, …) replays without one.\n */\nconst ELEMENT_TARGET_ACTION_TYPES = new Set([\n 'click',\n 'type',\n 'select_option',\n 'fill_form',\n 'hover',\n 'drag',\n 'file_upload',\n 'move',\n]);\n\nexport interface SynthesizeActionsOptions {\n nodeId: string;\n planned: PlannedBrowserAction[];\n /** Macro provenance from the run records (expression → resolved value, keyed by input field). */\n macroResolutionLog?: MacroResolutionLog;\n /** Ad-hoc macro resolutions the agent rolled mid-run (resolved value → expression). */\n agentMacroResolutions?: Map<string, string>;\n /** Variable values in effect during the source run (for `$var.X` reverse-mapping). */\n variableValues?: Record<string, string>;\n}\n\n/**\n * Build storable `CachedAction[]` from the optimizer's plan via the canonical\n * assembly pipeline. Action indices are assigned by plan position.\n */\nexport function synthesizeCachedActions(opts: SynthesizeActionsOptions): CachedAction[] {\n const records: CachedActionRecord[] = opts.planned.map((p, i) => ({\n index: i,\n toolName: p.toolName,\n actionType: p.actionType,\n nodeId: opts.nodeId,\n selectors: p.selectors,\n args: p.args,\n elementDescription: p.elementDescription,\n assertion: p.assertion,\n // Only element-targeting actions need a selector; selectorless\n // deterministic actions (navigate, wait_for, assert, capture, …) must\n // replay structurally — flagging them requiresAgent would make step-driven\n // replay treat the whole step as a gap and wake the healing agent.\n requiresAgent: ELEMENT_TARGET_ACTION_TYPES.has(p.actionType) && !p.selectors,\n selectorAuthor: p.selectors ? ('deterministic' as const) : undefined,\n }));\n\n const assembled = assembleCachedActionsForStorage({\n actions: records,\n macroResolutionLog: opts.macroResolutionLog,\n agentMacroResolutions: opts.agentMacroResolutions,\n });\n\n return opts.variableValues && Object.keys(opts.variableValues).length > 0\n ? parameterizeActionsWithVariables(assembled, opts.variableValues)\n : assembled;\n}\n","/**\n * Cache Recipe Builder\n *\n * Pure constructor for the optimizer's commit payload: validates the authored\n * playbook + action plan, synthesizes storable actions through the canonical\n * assembly, aligns compiled entries to playbook order, and enforces the\n * lossless-token rule (every variable/macro the node depends on survives into\n * the recipe verbatim).\n *\n * Deliberately hash-free: the node hash is recomputed SERVER-side at commit\n * (`commit-node-cache.ts`) from the node context with this playbook applied —\n * a client-supplied hash is never trusted.\n *\n * @module optimizer/recipe\n */\n\nimport type { CachedAction, PlaybookStep } from '@chatsdet/types';\nimport type { StoredCompiledEntry } from '../types.js';\nimport { synthesizeCachedActions, type PlannedBrowserAction } from './action-synthesizer.js';\nimport type { MacroResolutionLog } from '../macros/types.js';\nimport { MACRO_PATTERN } from '@chatsdet/types';\n\n/** Steps the optimizer marks as agent-handled at replay (non-browser effects, unverifiable locators). */\nexport interface PlannedGap {\n stepOrder: number;\n /** Why this step is a gap (surfaced in compilation meta + agent prompt at replay). */\n reason: string;\n}\n\nexport interface BuildRecipeOptions {\n nodeId: string;\n /** Most-direct-path playbook (core actions only, tokens verbatim). */\n playbookSteps: PlaybookStep[];\n /** Browser actions fulfilling playbook steps (literal values; provenance mapped here). */\n plannedActions: PlannedBrowserAction[];\n /** Steps without a cached action (non-browser effects, unverifiable locators). */\n gaps: PlannedGap[];\n /** Macro provenance from run records. */\n macroResolutionLog?: MacroResolutionLog;\n agentMacroResolutions?: Map<string, string>;\n /** Variable values in effect during the source run. */\n variableValues?: Record<string, string>;\n /**\n * Tokens the node's previous recipe/playbook depended on (`$var.x`,\n * `$EMAIL()`, …). The new recipe must still reference every one of them —\n * a dropped token means the optimizer inlined a run-specific value.\n */\n requiredTokens?: string[];\n}\n\nexport interface CacheRecipe {\n playbookSteps: PlaybookStep[];\n actionsJson: CachedAction[];\n compiledEntriesJson: StoredCompiledEntry[];\n /** Gap reasons keyed by step order (for compilation meta / diagnostics). */\n gapReasons: Record<number, string>;\n}\n\nexport class RecipeValidationError extends Error {\n readonly _tag = 'RecipeValidationError';\n constructor(\n message: string,\n readonly issues: string[]\n ) {\n // Issues inline in the message — agents and CLI users see the actionable\n // detail without unwrapping the error object.\n super(issues.length > 0 ? `${message}: ${issues.join('; ')}` : message);\n this.name = 'RecipeValidationError';\n }\n}\n\nconst VAR_TOKEN = /\\$var\\.[A-Za-z0-9_.]+/g;\n// Fresh instance of the shared macro pattern — module-level, hoisted out of the\n// visitor. Safe with matchAll (which clones and never mutates lastIndex).\nconst MACRO_TOKEN = new RegExp(MACRO_PATTERN.source, 'g');\n\n/** Collect `$var.x` and `$MACRO()` tokens appearing anywhere in a JSON value. */\nexport function collectTokens(value: unknown): Set<string> {\n const out = new Set<string>();\n const visit = (v: unknown): void => {\n if (typeof v === 'string') {\n for (const m of v.matchAll(VAR_TOKEN)) out.add(m[0]);\n for (const m of v.matchAll(MACRO_TOKEN)) out.add(m[0]);\n } else if (Array.isArray(v)) {\n v.forEach(visit);\n } else if (v && typeof v === 'object') {\n Object.values(v).forEach(visit);\n }\n };\n visit(value);\n return out;\n}\n\n/**\n * Build and validate the commit payload. Throws `RecipeValidationError` when\n * the plan is structurally unsound or drops a required token — the optimizer\n * agent reads the issues and retries.\n */\nexport function buildCacheRecipe(opts: BuildRecipeOptions): CacheRecipe {\n const issues: string[] = [];\n\n // ── Structural alignment ──\n const orders = opts.playbookSteps.map((s) => s.order).sort((a, b) => a - b);\n const expected = Array.from({ length: orders.length }, (_, i) => i + 1);\n if (orders.length === 0) issues.push('playbookSteps is empty');\n if (JSON.stringify(orders) !== JSON.stringify(expected)) {\n issues.push(`playbook step orders must be contiguous from 1; got [${orders.join(', ')}]`);\n }\n\n const actionByOrder = new Map<number, PlannedBrowserAction>();\n for (const a of opts.plannedActions) {\n if (actionByOrder.has(a.stepOrder)) {\n issues.push(`step ${a.stepOrder} has more than one planned action (one action per step)`);\n }\n actionByOrder.set(a.stepOrder, a);\n }\n const gapByOrder = new Map(opts.gaps.map((g) => [g.stepOrder, g]));\n\n for (const step of opts.playbookSteps) {\n const hasAction = actionByOrder.has(step.order);\n const hasGap = gapByOrder.has(step.order);\n if (hasAction && hasGap) issues.push(`step ${step.order} is both a cached action and a gap`);\n if (!hasAction && !hasGap) {\n issues.push(`step ${step.order} (\"${step.target}\") has neither a planned action nor a gap`);\n }\n }\n for (const order of [...actionByOrder.keys(), ...gapByOrder.keys()]) {\n if (!opts.playbookSteps.some((s) => s.order === order)) {\n issues.push(`planned action/gap references step ${order} which is not in the playbook`);\n }\n }\n\n if (issues.length > 0) {\n throw new RecipeValidationError('Recipe plan is structurally unsound', issues);\n }\n\n // ── Synthesis through the canonical assembly ──\n const ordered = [...actionByOrder.entries()].sort((a, b) => a[0] - b[0]);\n const actionsJson = synthesizeCachedActions({\n nodeId: opts.nodeId,\n planned: ordered.map(([, a]) => a),\n macroResolutionLog: opts.macroResolutionLog,\n agentMacroResolutions: opts.agentMacroResolutions,\n variableValues: opts.variableValues,\n });\n const actionIndexByOrder = new Map(ordered.map(([order], i) => [order, i]));\n\n // ── Lossless-token check ──\n // Tokens must survive into the playbook or the parameterized actions\n // (macro provenance lands as macroBindings, variable provenance as\n // variableKey/variableBindings or $var literals).\n if (opts.requiredTokens?.length) {\n const present = collectTokens({ playbook: opts.playbookSteps, actions: actionsJson });\n const bindingKeys = new Set<string>();\n for (const a of actionsJson) {\n if (a.variableKey) bindingKeys.add(`$var.${a.variableKey}`);\n for (const key of Object.values(a.variableBindings ?? {})) bindingKeys.add(`$var.${key}`);\n for (const expr of Object.values(a.macroBindings ?? {})) bindingKeys.add(expr);\n // A capture PRODUCES its variable — the strongest possible way for a\n // recipe to preserve `$var.<saveAs>`.\n if (a.actionType === 'capture' && typeof a.args?.saveAs === 'string' && a.args.saveAs) {\n bindingKeys.add(`$var.${a.args.saveAs}`);\n }\n }\n const missing = opts.requiredTokens.filter((t) => !present.has(t) && !bindingKeys.has(t));\n if (missing.length > 0) {\n throw new RecipeValidationError(\n 'Recipe drops required variable/macro tokens — run-specific values were inlined',\n missing.map((t) => `missing token: ${t}`)\n );\n }\n }\n\n // ── Compiled entries aligned to playbook order ──\n const gapReasons: Record<number, string> = {};\n const compiledEntriesJson: StoredCompiledEntry[] = opts.playbookSteps\n .slice()\n .sort((a, b) => a.order - b.order)\n .map((step) => {\n const gap = gapByOrder.get(step.order);\n if (gap) {\n gapReasons[step.order] = gap.reason;\n return { type: 'gap' as const, stepOrder: step.order };\n }\n return {\n type: 'cached' as const,\n stepOrder: step.order,\n actionIndices: [actionIndexByOrder.get(step.order)!],\n };\n });\n\n return { playbookSteps: opts.playbookSteps, actionsJson, compiledEntriesJson, gapReasons };\n}\n","/**\n * Macro resolver types.\n *\n * @module macros/types\n */\n\n/** Mutable context shared across a single workflow run for stateful macros like $SEQUENCE(). */\nexport interface MacroResolutionContext {\n /** Per-name counters for $SEQUENCE() — resets between runs. */\n sequenceCounters: Map<string, number>;\n /** Cached LLM resolutions for $AI(prompt), keyed by stripped prompt — populated by the AI prepass before sync resolution. */\n aiResolutions: Map<string, string>;\n}\n\n/** Record of a single macro resolution (expression → resolved value). */\nexport interface MacroResolution {\n /** Original macro expression, e.g. \"$UUID()\" */\n expression: string;\n /** Resolved output, e.g. \"a1b2c3d4-...\" */\n resolved: string;\n}\n\n/**\n * Maps input field names to their macro resolutions.\n * Used by cache recording to map resolved values back to expressions.\n */\nexport type MacroResolutionLog = Map<string, MacroResolution>;\n\nexport class MacroUnknownError extends Error {\n readonly _tag = 'MacroUnknownError';\n constructor(macroName: string) {\n super(`Unknown macro: $${macroName}()`);\n this.name = 'MacroUnknownError';\n }\n}\n\nexport class MacroArgError extends Error {\n readonly _tag = 'MacroArgError';\n constructor(macroName: string, message: string) {\n super(`$${macroName}(): ${message}`);\n this.name = 'MacroArgError';\n }\n}\n","/**\n * Built-in macro definitions.\n *\n * @module macros/registry\n *\n * Each macro is a pure function that takes parsed args and a resolution context,\n * returning a string. No Effect dependency — these are synchronous utilities.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { MacroResolutionContext } from './types.js';\nimport { MacroArgError } from './types.js';\n\ntype MacroFn = (args: string[], ctx: MacroResolutionContext) => string;\n\nconst FIRST_NAMES = [\n 'Jordan',\n 'Alex',\n 'Taylor',\n 'Morgan',\n 'Casey',\n 'Riley',\n 'Quinn',\n 'Avery',\n 'Cameron',\n 'Dakota',\n 'Sage',\n 'Rowan',\n 'Hayden',\n 'Finley',\n 'Emery',\n 'Reese',\n 'Charlie',\n 'Drew',\n 'Blake',\n 'Skyler',\n];\n\nconst LAST_NAMES = [\n 'Chen',\n 'Smith',\n 'Patel',\n 'Kim',\n 'Garcia',\n 'Johnson',\n 'Williams',\n 'Brown',\n 'Jones',\n 'Miller',\n 'Davis',\n 'Wilson',\n 'Moore',\n 'Taylor',\n 'Anderson',\n 'Thomas',\n 'Jackson',\n 'White',\n 'Harris',\n 'Martin',\n];\n\nconst ALPHANUMERIC = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\n\nfunction randomAlphanumeric(length: number): string {\n let result = '';\n for (let i = 0; i < length; i++) {\n result += ALPHANUMERIC[Math.floor(Math.random() * ALPHANUMERIC.length)];\n }\n return result;\n}\n\nfunction randomItem<T>(arr: readonly T[]): T {\n return arr[Math.floor(Math.random() * arr.length)]!;\n}\n\nfunction formatDate(d: Date): string {\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;\n}\n\nfunction parseIntArg(macroName: string, argName: string, value: string): number {\n const trimmed = value.trim();\n const parsed = Number(trimmed);\n if (!Number.isInteger(parsed)) {\n throw new MacroArgError(macroName, `${argName} must be an integer, got \"${trimmed}\"`);\n }\n return parsed;\n}\n\nconst BUILTIN_MACROS: Record<string, MacroFn> = {\n UUID: () => randomUUID(),\n\n NOW: () => new Date().toISOString(),\n\n TODAY: () => formatDate(new Date()),\n\n DATE: (args) => {\n if (args.length !== 1) {\n throw new MacroArgError('DATE', `expected 1 arg (days), got ${args.length}`);\n }\n const days = parseIntArg('DATE', 'days', args[0]!);\n const d = new Date();\n d.setDate(d.getDate() + days);\n return formatDate(d);\n },\n\n TIMESTAMP: () => String(Date.now()),\n\n RANDOM_INT: (args, _ctx) => {\n if (args.length !== 2) {\n throw new MacroArgError('RANDOM_INT', `expected 2 args (min, max), got ${args.length}`);\n }\n const min = parseIntArg('RANDOM_INT', 'min', args[0]!);\n const max = parseIntArg('RANDOM_INT', 'max', args[1]!);\n if (min > max) {\n throw new MacroArgError('RANDOM_INT', `min (${min}) must be <= max (${max})`);\n }\n return String(Math.floor(Math.random() * (max - min + 1)) + min);\n },\n\n RANDOM_STRING: (args) => {\n if (args.length !== 1) {\n throw new MacroArgError('RANDOM_STRING', `expected 1 arg (length), got ${args.length}`);\n }\n const length = parseIntArg('RANDOM_STRING', 'length', args[0]!);\n if (length < 1 || length > 1000) {\n throw new MacroArgError('RANDOM_STRING', `length must be 1–1000, got ${length}`);\n }\n return randomAlphanumeric(length);\n },\n\n EMAIL: () => {\n const id = randomAlphanumeric(8).toLowerCase();\n return `test-${id}@example-test.com`;\n },\n\n FIRST_NAME: () => randomItem(FIRST_NAMES),\n\n LAST_NAME: () => randomItem(LAST_NAMES),\n\n PHONE: () => {\n const rand = () => Math.floor(Math.random() * 10);\n // Generate +1-555-XXX-XXXX (555 ensures non-real number)\n return `+1-555-${rand()}${rand()}${rand()}-${rand()}${rand()}${rand()}${rand()}`;\n },\n\n SEQUENCE: (args, ctx) => {\n if (args.length !== 1) {\n throw new MacroArgError('SEQUENCE', `expected 1 arg (name), got ${args.length}`);\n }\n const name = stripQuotes(args[0]!);\n if (!name) {\n throw new MacroArgError('SEQUENCE', 'name cannot be empty');\n }\n const current = ctx.sequenceCounters.get(name) ?? 0;\n const next = current + 1;\n ctx.sequenceCounters.set(name, next);\n return String(next);\n },\n\n AI: (args, ctx) => {\n if (args.length !== 1) {\n throw new MacroArgError('AI', `expected 1 arg (prompt), got ${args.length}`);\n }\n const prompt = stripQuotes(args[0]!);\n if (!prompt) {\n throw new MacroArgError('AI', 'prompt cannot be empty');\n }\n const cached = ctx.aiResolutions.get(prompt);\n if (cached === undefined) {\n throw new MacroArgError(\n 'AI',\n `no cached resolution for prompt \"${prompt}\" — the AI prepass must run before sync resolution`\n );\n }\n return cached;\n },\n};\n\n/** Strip surrounding single or double quotes (and trim) from a macro arg. Exported for the AI prepass. */\nexport function stripQuotes(value: string): string {\n return value.trim().replace(/^[\"']|[\"']$/g, '');\n}\n\n/** Look up a built-in macro function by name. Returns undefined if not found. */\nexport function getMacro(name: string): MacroFn | undefined {\n return BUILTIN_MACROS[name];\n}\n\n/** All registered macro names. */\nexport function getMacroNames(): string[] {\n return Object.keys(BUILTIN_MACROS);\n}\n","/**\n * Macro resolution engine.\n *\n * @module macros/resolver\n *\n * Pure utility functions for detecting, extracting, and resolving macro\n * expressions in strings. No Effect dependency.\n */\n\nimport { MACRO_PATTERN } from '@chatsdet/types';\nimport type { MacroResolutionContext, MacroResolutionLog } from './types.js';\nimport { MacroUnknownError } from './types.js';\nimport { getMacro } from './registry.js';\n\n/** Create a fresh resolution context for a new workflow run. */\nexport function createMacroContext(): MacroResolutionContext {\n return { sequenceCounters: new Map(), aiResolutions: new Map() };\n}\n\n/** Fast check: does the value contain at least one macro expression? */\nexport function containsMacro(value: string): boolean {\n // Reset lastIndex since MACRO_PATTERN has the global flag\n MACRO_PATTERN.lastIndex = 0;\n return MACRO_PATTERN.test(value);\n}\n\n/** Extract all macro expressions from a string (e.g. [\"$UUID()\", \"$EMAIL()\"]). */\nexport function extractMacroExpressions(value: string): string[] {\n MACRO_PATTERN.lastIndex = 0;\n const results: string[] = [];\n let match: RegExpExecArray | null;\n while ((match = MACRO_PATTERN.exec(value)) !== null) {\n results.push(match[0]);\n }\n return results;\n}\n\n/**\n * Resolve all macro expressions in a string, returning the result with\n * macros replaced by their generated values.\n *\n * Escaped macros (\\$MACRO()) are preserved as literal $MACRO().\n *\n * @throws MacroUnknownError if an unrecognized macro name is encountered\n * @throws MacroArgError if macro arguments are invalid\n */\nexport function resolveMacros(value: string, ctx: MacroResolutionContext): string {\n MACRO_PATTERN.lastIndex = 0;\n const result = value.replace(MACRO_PATTERN, (fullMatch, name: string, argsStr: string) => {\n const macroFn = getMacro(name);\n if (!macroFn) {\n throw new MacroUnknownError(name);\n }\n const args = argsStr.length > 0 ? argsStr.split(',') : [];\n return macroFn(args, ctx);\n });\n\n // Unescape \\$ → $\n return result.replace(/\\\\\\$/g, '$');\n}\n\n/**\n * Resolve macros in all values of a Record<string, string>.\n * Returns the resolved map and a log of what was resolved.\n */\nexport function resolveMacrosInRecord(\n values: Record<string, string>,\n ctx: MacroResolutionContext,\n): {\n resolved: Record<string, string>;\n log: Map<string, { expression: string; resolved: string }>;\n} {\n const resolved: Record<string, string> = {};\n const log = new Map<string, { expression: string; resolved: string }>();\n\n for (const [key, value] of Object.entries(values)) {\n if (containsMacro(value)) {\n const resolvedValue = resolveMacros(value, ctx);\n resolved[key] = resolvedValue;\n log.set(key, { expression: value, resolved: resolvedValue });\n } else {\n resolved[key] = value;\n }\n }\n\n return { resolved, log };\n}\n\n/**\n * Resolve macros in a node's inputValues and update workflowState.\n * Returns the resolved inputValues and a resolution log.\n */\nexport function resolveNodeInputMacros(\n inputValues: Record<string, string> | undefined,\n ctx: MacroResolutionContext,\n workflowState: Record<string, unknown>,\n): {\n resolvedValues: Record<string, string> | undefined;\n macroResolutionLog: MacroResolutionLog | undefined;\n} {\n if (!inputValues) return { resolvedValues: undefined, macroResolutionLog: undefined };\n\n const hasMacros = Object.values(inputValues).some((v) => containsMacro(v));\n if (!hasMacros) return { resolvedValues: inputValues, macroResolutionLog: undefined };\n\n const { resolved, log } = resolveMacrosInRecord(inputValues, ctx);\n for (const [key, { resolved: val }] of log.entries()) {\n workflowState[`macro:${key}`] = val;\n }\n return { resolvedValues: resolved, macroResolutionLog: log };\n}\n"],"mappings":"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","names":["logger","key","value","key","key","key","escapeRegex","_logger","_","elapsed","visStart","visibilityWaitMs","validated","errorMsg","key","_logger","getLogger","key","node","logger","escapeRegex","key","logger","key","path","pathToFileURL","RESOLVE_TIMEOUT_MS","pathToFileURL","path","path","pathToFileURL","logger","flatten","pathToFileURL","path","key","key"]}
1
+ {"version":3,"sources":["../../workflow-cache/src/logger.ts","../../workflow-cache/src/node-hash.ts","../../workflow-cache/src/build-locator.ts","../../workflow-cache/src/snapshot-parser.ts","../../workflow-cache/src/locator-parser.ts","../../workflow-cache/src/element-resolver.ts","../../workflow-cache/src/selector-derivation.ts","../../workflow-cache/src/cached-action-assembly.ts","../../workflow-cache/src/optimizer/headless-session.ts","../../workflow-cache/src/optimizer/trace-node-segmenter.ts","../../workflow-cache/src/optimizer/substrate-materializer.ts","../../workflow-cache/src/optimizer/locator-verifier.ts","../../workflow-cache/src/optimizer/augmentor-verifier.ts","../../workflow-cache/src/optimizer/action-synthesizer.ts","../../workflow-cache/src/optimizer/recipe.ts","../../workflow-cache/src/macros/types.ts","../../workflow-cache/src/macros/registry.ts","../../workflow-cache/src/macros/resolver.ts"],"sourcesContent":["/**\n * Workflow-Cache Logger\n *\n * The package must work in any environment (server, CLI), so logging goes\n * through the environment-agnostic `BrowserLogger` interface from\n * `@chatsdet/browser-core` instead of importing pino directly.\n *\n * - Cloud (apps/api): call `setWorkflowCacheLogger(pinoToBrowserLogger(...))`\n * once at boot so package logs flow into the structured pino pipeline.\n * - CLI (canary-cli): the `consoleLogger` default applies.\n *\n * `createLogger(bindings)` mirrors the apps/api pino-logger call shape\n * (`logger.info(message, payload?)`) so moved modules only change their\n * import path.\n *\n * @module logger\n */\n\nimport { consoleLogger, type BrowserLogger } from '@chatsdet/browser-core';\n\nlet activeLogger: BrowserLogger = consoleLogger;\n\n/** Install an environment-specific logger (e.g. a pino adapter on the server). */\nexport function setWorkflowCacheLogger(logger: BrowserLogger): void {\n activeLogger = logger;\n}\n\n/**\n * Create a logger that merges `bindings` into every payload and delegates to\n * the active environment logger. Same `(message, payload?)` call shape as the\n * apps/api `createLogger`.\n */\nexport function createLogger(bindings?: Record<string, unknown>): BrowserLogger {\n if (!bindings || Object.keys(bindings).length === 0) {\n return {\n debug: (msg, data) => activeLogger.debug(msg, data),\n info: (msg, data) => activeLogger.info(msg, data),\n warn: (msg, data) => activeLogger.warn(msg, data),\n error: (msg, data) => activeLogger.error(msg, data),\n };\n }\n const merge = (data?: Record<string, unknown>) => ({ ...bindings, ...data });\n return {\n debug: (msg, data) => activeLogger.debug(msg, merge(data)),\n info: (msg, data) => activeLogger.info(msg, merge(data)),\n warn: (msg, data) => activeLogger.warn(msg, merge(data)),\n error: (msg, data) => activeLogger.error(msg, merge(data)),\n };\n}\n","/**\n * Node Hash Algorithm\n *\n * Generates deterministic hashes for workflow nodes based on their semantic content.\n * Used for cache lookup - nodes with the same hash produce the same behavior.\n *\n * This module holds the pure hash algorithm (`NodeHashInput` → hash string).\n * Extracting a `NodeHashInput` from a live `WorkflowNodeContext` is a server\n * concern and lives in `apps/api/src/workflows/helpers/node-hash.ts`.\n *\n * Hash versions:\n * - v1: Initial version (2026-01-15) - proper deep key sorting\n * - v2 (current default): Added `playbookSteps` (order+action+target) to\n * input for action/assertion nodes.\n * - v3 (per-org, behind `workflow.recipe-v3`): pure node identity — drops\n * `playbookSteps` (the playbook is no longer part of its own cache key; it\n * rewrites in place on the identity row) and drops the vestigial\n * `inlineAssertions[].severity` (folding its deferred removal into a\n * re-mint that is already happening — see the NodeHashInput comment).\n * Selected per-org at the callsites via `generateNodeHashV3`, NOT a global\n * `HASH_VERSION` bump — see specs/workflow-versioning-pin-and-playbook.md.\n *\n * Note: Changing the hash algorithm will cause existing caches to miss.\n * This is acceptable - caches will repopulate on next execution.\n *\n * @module\n * @see /docs/workflow-node-cache.md for caching design\n */\n\nimport { createHash } from 'crypto';\n\n/** Current hash version - increment if hash algorithm changes */\nconst HASH_VERSION = 'v2';\n\n/**\n * Recursively sort object keys for deterministic JSON serialization.\n * Handles nested objects and arrays.\n */\nexport function sortObjectKeys(obj: unknown): unknown {\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys);\n }\n if (obj !== null && typeof obj === 'object') {\n const sorted = Object.keys(obj as Record<string, unknown>)\n .sort()\n .reduce(\n (acc, key) => {\n acc[key] = sortObjectKeys((obj as Record<string, unknown>)[key]);\n return acc;\n },\n {} as Record<string, unknown>\n );\n return sorted;\n }\n return obj;\n}\n\n/**\n * Input data for generating a node hash.\n * Only includes fields that affect node behavior (excludes cosmetic fields).\n */\nexport interface NodeHashInput {\n nodeType: string;\n /** Primary description/condition based on node type */\n description?: string;\n /** Action node title (separate from description for stable hashing) */\n title?: string | null;\n /** URL the node operates on */\n pageUrl?: string;\n /** Data requirements for action nodes (name + type) */\n dataRequirements?: Array<{ name: string; type?: string }>;\n /** Playbook steps for playbook-capable nodes (order + action + target) — cached actions are replayed 1:1 against these, so a mismatch must miss */\n playbookSteps?: Array<{ order: number; action: string; target: string }>;\n /**\n * Inline assertions for action nodes (`id` excluded — random UUID would cause\n * spurious invalidation).\n *\n * `severity` is vestigial here: replay resolves it authoritatively from current\n * node config (cache/replay.ts), treating the cached value as advisory, so it\n * does not affect replayed behavior and ideally would not be hashed. It is kept\n * only because dropping it standalone re-mints ~29% of action caches for no\n * behavioral gain. If the hash algorithm ever changes for another reason, drop\n * `severity` then too — folding the re-mint into one that is already happening.\n */\n inlineAssertions?: Array<{ condition: string; severity: string; agentic?: boolean }>;\n}\n\n/**\n * Generate a deterministic hash for a node based on its semantic content.\n * Uses SHA-256 truncated to 16 characters with a version prefix.\n *\n * Format: \"v2:abc123...\" (version prefix + 16 hex characters)\n *\n * @param input - Node hash input (from extractHashInput or constructed manually)\n * @returns Deterministic hash string with version prefix\n */\nexport function generateNodeHash(input: NodeHashInput): string {\n return hashWithPrefix(input, HASH_VERSION);\n}\n\n/**\n * v3: pure node-identity hash (per-org, behind `workflow.recipe-v3`).\n *\n * Accepts the same `NodeHashInput` as v2 and drops the non-identity fields\n * itself, so callers don't need a parallel extraction path:\n * - `playbookSteps` — derived content; lives on the identity row and\n * updates in place rather than moving the row.\n * - `inlineAssertions[].severity` — replay resolves severity from current\n * node config; hashing it only caused spurious re-mints.\n */\nexport function generateNodeHashV3(input: NodeHashInput): string {\n const { playbookSteps: _playbookSteps, inlineAssertions, ...identity } = input;\n const v3Input: Omit<NodeHashInput, 'playbookSteps' | 'inlineAssertions'> & {\n inlineAssertions?: Array<{ condition: string; agentic?: boolean }>;\n } = {\n ...identity,\n ...(inlineAssertions\n ? {\n inlineAssertions: inlineAssertions.map(({ condition, agentic }) => ({\n condition,\n ...(agentic !== undefined ? { agentic } : {}),\n })),\n }\n : {}),\n };\n return hashWithPrefix(v3Input, 'v3');\n}\n\nfunction hashWithPrefix(input: unknown, version: string): string {\n // Deep-sort all keys for consistent serialization regardless of property order\n const sortedInput = sortObjectKeys(input);\n const stableJson = JSON.stringify(sortedInput);\n\n // Generate SHA-256 hash, truncate to 16 chars for reasonable uniqueness\n const hash = createHash('sha256').update(stableJson).digest('hex').slice(0, 16);\n\n // Include version prefix for future algorithm changes\n return `${version}:${hash}`;\n}\n","/**\n * Substrate-v2 deterministic locator algorithm.\n *\n * `buildLocator(snapshot, ref, variableValues) -> SelectorStrategy` is a pure\n * function: it consumes a parsed substrate, an ephemeral ref, and the workflow\n * variable bag, and emits a {@link SelectorStrategy} ready for cache replay.\n * No live DOM access, no Effect, no I/O.\n *\n * See `docs/api/services/snapshot-substrate.md` for the design rationale and\n * predicate ladder.\n *\n * **Ancestor scoping (implementation note):** ancestor scoping is flattened to\n * a single identifiable anchor (via {@link isAncestorIdentifiable}) plus an\n * optional `parentChain` of intermediate ancestors, falling through to the\n * indexed-fallback when no anchor is identifiable.\n *\n * @module\n */\n\nimport type {\n ParentContext,\n ParentContextNode,\n ParentContextDynamicText,\n RoleSelector,\n SelectorStrategy,\n FrameContext,\n} from '@chatsdet/types';\nimport {\n isVolatileIdentifier,\n stableIdentifierPrefix,\n stableAttrSelector,\n} from '@chatsdet/types';\nimport type { SnapshotElement, SnapshotElementSource } from '@chatsdet/browser-core';\n\n/**\n * A binding chosen during the templating pass. Surfaces every variable\n * substitution `buildLocator` made so callers can log decisions for review.\n */\nexport interface VariableBinding {\n /** Variable key (e.g. `customer_name`). */\n key: string;\n /** Literal value at recording time. */\n value: string;\n /** Substrate field where the match landed. */\n field: TemplatedField;\n /** Number of nodes whose value was rewritten with this binding. */\n occurrences: number;\n}\n\nexport interface BuildLocatorResult {\n selectors: SelectorStrategy;\n /** Predicate name that produced the locator, for logging/metrics. */\n predicate: string;\n /** Variable bindings used while templating. */\n bindings: VariableBinding[];\n /**\n * True when no predicate produced a snapshot-unique match and we fell\n * through to the indexed fallback. Recording middleware uses this to decide\n * whether to enqueue a selector-agent task.\n */\n irreducible: boolean;\n}\n\ntype TemplatedField = 'text' | 'aria-label' | 'placeholder' | 'value';\n\n/** Field a predicate reads — used by the source-durability gate. */\ntype PredicateField = 'text' | 'aria-label' | 'placeholder' | 'src' | 'data-field';\n\nconst REPEATING_ANCESTOR_ROLES = new Set([\n 'row',\n 'listitem',\n 'gridcell',\n 'article',\n 'option',\n 'treeitem',\n]);\n\ninterface NormalizedNode {\n el: SnapshotElement;\n /** Templated accessible name (`text`), with variable values replaced by `{{key}}`. */\n textTemplate?: string;\n /** Templated `aria-label` attribute. */\n ariaLabelTemplate?: string;\n /** Templated `placeholder` attribute. */\n placeholderTemplate?: string;\n /** Templated `value`/`inputValue`. */\n valueTemplate?: string;\n /** Bindings applied to this node (subset of the global bag). */\n bindings: VariableBinding[];\n /** Parent in the normalized tree, or null for roots. */\n parent: NormalizedNode | null;\n /** Refs of all descendants (including self). Built once during flatten. */\n descendantRefs: Set<string>;\n}\n\n/**\n * Build a {@link SelectorStrategy} for `ref` from the parsed substrate.\n * Returns the strategy plus diagnostics. Callers should pass the same\n * `variableValues` that recording will pass at replay.\n */\nexport function buildLocator(\n snapshot: SnapshotElement[],\n ref: string,\n variableValues: Record<string, string> = {}\n): BuildLocatorResult {\n const { flat, byRef } = flatten(snapshot);\n const target = byRef.get(ref);\n if (!target) {\n return {\n selectors: {},\n predicate: 'none',\n bindings: [],\n irreducible: true,\n };\n }\n\n // Pass 1 — variable templating across the whole snapshot. Uniqueness\n // checks must scan templates so multiple rows that differ only in the\n // bound variable collapse into one match.\n const allBindings = templateAll(flat, variableValues);\n\n // Pass 2 — precompute uniqueness lookup tables for the identifiability\n // check. Built once; each ancestor probe is O(1).\n const identityIndex = buildIdentityIndex(flat);\n\n // Pass 3 — predicate ladder. First predicate that's globally unique\n // wins. If none unique, recurse under each ancestor closest-first\n // looking for predicate+scope that's unique within the subtree and\n // resolves back to the target.\n const frameContext = frameContextFor(target.el);\n const baseDynamicText = buildDynamicText(target);\n const ancestors = ancestorChain(target);\n\n // Custom-augmentor durable anchor — special-cased FIRST. A custom augmentor's\n // verified `stableAnchor` is a complete CSS selector, built only from\n // pre-existing (non-injected) attributes and proven to resolve uniquely to\n // the target. It is the authoritative locator for an augmented ref; emit it\n // directly. Without this the injected role/name are provenance-blocked\n // (`augmented:dom-mutation`) and the ref would fall through to irreducible.\n //\n // Replay safety: this becomes a plain `{ css }` strategy resolved through the\n // shared `resolveElement` on the replay path, which enforces the strict-cache-\n // replay uniqueness invariant (count===1, rejecting multi-match rather than\n // `.first()`). So a DOM that drifted since authoring can't silently click the\n // wrong element — the anchor is no riskier than any other cached CSS locator.\n const augmentorAnchor = target.el.augmentorAnchor;\n if (augmentorAnchor) {\n return {\n selectors: applyContexts({ css: augmentorAnchor }, frameContext, baseDynamicText),\n predicate: 'augmentorAnchor',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n // testId is special-cased: each testId is independent, so we pick the\n // first one that's globally unique rather than running the predicate\n // ladder on a set-overlap match.\n const uniqueTestId = pickUniqueTestId(target, flat);\n if (uniqueTestId) {\n return {\n selectors: applyContexts({ testId: uniqueTestId }, frameContext, baseDynamicText),\n predicate: 'testId',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n // iconClass is also special-cased: an icon-only control whose <svg> carries\n // a stable lucide class (e.g. `lucide-sliders-horizontal`) has no\n // accessible name in the substrate, so the role+name ladder cannot apply.\n // The DOM grounding is the icon class itself; emit a CSS `:has()` anchor\n // when it's globally unique for the target's role.\n const uniqueIconClass = pickUniqueIconClass(target, flat);\n if (uniqueIconClass) {\n const role: RoleSelector = { role: target.el.role };\n return {\n selectors: applyContexts(\n { role, css: roleScopedCss(target.el.role, `:has(svg.${uniqueIconClass})`) },\n frameContext,\n baseDynamicText\n ),\n predicate: 'iconClass',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n // semanticClass: a target whose own className carries a meaningful token\n // (e.g. `delete-btn`, `IconButton-filter`) that's globally unique for the\n // role. CSS class selectors are valid Playwright locators; the substrate\n // carries the raw class via `[~semantic-class=…]` and the algorithm\n // anchors on it before falling through to the role+name ladder.\n const uniqueSemanticClass = pickUniqueSemanticClass(target, flat);\n if (uniqueSemanticClass) {\n const role: RoleSelector = { role: target.el.role };\n return {\n selectors: applyContexts(\n { role, css: roleScopedCss(target.el.role, `.${uniqueSemanticClass}`) },\n frameContext,\n baseDynamicText\n ),\n predicate: 'semanticClass',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n const volatileTestIdText = buildVolatileTestIdTextSelector(target, flat);\n if (volatileTestIdText) {\n return {\n selectors: applyContexts(volatileTestIdText, frameContext, baseDynamicText),\n predicate: 'volatileTestId+containsText',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n for (const p of PREDICATES) {\n if (!p.applies(target)) continue;\n if (isPredicateBlockedBySource(p, target)) continue;\n\n // Global uniqueness — count and short-circuit at 2.\n const matches = uniquenessMatches(flat, target, p);\n if (matches === 1) {\n const sel = p.toStrategy(target, flat);\n return {\n selectors: applyContexts(sel, frameContext, baseDynamicText),\n predicate: p.name,\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n const rowVariableScope = findRowVariableScope({\n flat,\n target,\n predicate: p,\n ancestors,\n variableValues,\n });\n if (rowVariableScope) {\n const inner = p.toStrategy(target, flat);\n const parentContext = parentContextFor(\n rowVariableScope.anchor,\n rowVariableScope.innerAncestors,\n {\n containsText: rowVariableScope.value,\n containsTextDynamic: {\n source: 'workflowState',\n key: rowVariableScope.key,\n originalText: rowVariableScope.value,\n },\n }\n );\n return {\n selectors: applyContexts(\n { ...inner, parentContext },\n frameContext,\n baseDynamicText\n ),\n predicate: `${p.name}+row-variable`,\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n // Try scoping under each ancestor (closest-first). The scope must be\n // unique within the ancestor's subtree AND the ancestor itself must be\n // identifiable in the wider snapshot (so the chain resolves end-to-end\n // at replay). Prefer the ancestor's globally-unique stable id (data-id /\n // test-id) — a structural, NON-ordinal anchor that also identifies nameless\n // ancestors (a `__new__` draft row, a hard-coded test-id panel) — and emit\n // it as `parentContext.css`; otherwise identify the ancestor by role+name\n // / durable child text.\n for (let i = ancestors.length - 1; i >= 0; i--) {\n const anchor = ancestors[i];\n const sub = uniquenessMatchesScoped(flat, target, p, anchor);\n if (sub !== 1) continue;\n\n const idSelector = uniqueStableIdSelector(anchor, flat);\n if (idSelector) {\n return {\n selectors: applyContexts(\n { ...p.toStrategy(target, flat), parentContext: { css: idSelector } },\n frameContext,\n baseDynamicText\n ),\n predicate: `${p.name}+stable-id-ancestor`,\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n if (!isAncestorIdentifiable(anchor, identityIndex, target)) continue;\n const inner = p.toStrategy(target, flat);\n const parentContext = parentContextFor(anchor, ancestors.slice(i + 1));\n return {\n selectors: applyContexts(\n { ...inner, parentContext },\n frameContext,\n baseDynamicText\n ),\n predicate: `${p.name}+ancestor`,\n bindings: allBindings,\n irreducible: false,\n };\n }\n }\n\n const rowScopedOrdinal = buildRowScopedOrdinalLocator({\n target,\n ancestors,\n variableValues,\n });\n if (rowScopedOrdinal) {\n return {\n selectors: applyContexts(\n {\n role: { role: target.el.role },\n playwrightLocator: rowScopedOrdinal.locator,\n playwrightLocatorCandidates: {\n deterministic: {\n locator: rowScopedOrdinal.locator,\n usesVariableBinding: true,\n boundVariableKey: rowScopedOrdinal.key,\n },\n },\n parentContext: parentContextFor(rowScopedOrdinal.anchor, rowScopedOrdinal.innerAncestors, {\n containsText: rowScopedOrdinal.value,\n containsTextDynamic: {\n source: 'workflowState',\n key: rowScopedOrdinal.key,\n originalText: rowScopedOrdinal.value,\n },\n }),\n },\n frameContext,\n baseDynamicText\n ),\n predicate: 'row-variable+scoped-button-index',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n // Clone-index disambiguation: when role+name matches N > 1 nodes and all\n // matches live in byte-identical subtrees under a common non-list parent,\n // they are UI clones (e.g. responsive-layout duplicates), not data rows.\n // Ordinal disambiguation is safe here because the matches carry no\n // information difference — picking nth(N) deterministically clicks the\n // same DOM element each replay. Distinguishes \"Telerik dashboard widget\n // duplicated at 4 breakpoints\" from \"table with 4 rows of patient data.\"\n const cloneIndex = buildCloneIndexLocator({ flat, target });\n if (cloneIndex) {\n const role: RoleSelector = { role: target.el.role };\n const name = target.textTemplate ?? target.el.text;\n if (name) role.name = name;\n return {\n selectors: applyContexts(\n { role, playwrightLocator: cloneIndex.locator },\n frameContext,\n baseDynamicText\n ),\n predicate: 'role+name+clone-index',\n bindings: allBindings,\n irreducible: false,\n };\n }\n\n return {\n selectors: applyContexts(indexedFallback(target), frameContext, baseDynamicText),\n predicate: 'indexed-fallback',\n bindings: allBindings,\n irreducible: true,\n };\n}\n\n/**\n * Roles whose containers carry data-row semantics. When a shared ancestor of\n * the role+name matches has one of these roles, ordinal disambiguation is\n * brittle because list/grid contents are usually data-driven and reorder\n * with sorts, filters, or inserts. Keeps clone-index safe for static UI\n * duplication (dashboards, side-by-side panels) while ceding data lists\n * to indexed-fallback + irreducible.\n */\nconst LIST_ROLES: ReadonlySet<string> = new Set([\n 'list',\n 'listbox',\n 'grid',\n 'tree',\n 'treegrid',\n 'table',\n 'tbody',\n 'thead',\n 'rowgroup',\n 'row',\n 'menu',\n 'menubar',\n]);\n\ninterface CloneIndexLocator {\n locator: string;\n ordinal: number;\n}\n\n/**\n * Build a `role+name+clone-index` locator when all role+name matches are\n * structurally identical clones under a non-list common parent. Returns\n * `null` if the safety conditions don't hold — caller falls through to\n * indexed-fallback + irreducible.\n *\n * Safety contract:\n * 1. ≥2 global matches for the target's (role, name).\n * 2. Each match has a \"card\" (lowest ancestor containing only that match),\n * and all cards are siblings under a single common parent.\n * 3. No ancestor between the common parent and the document root has a\n * list/grid/table-style role.\n * 4. All cards' subtree text fingerprints (recursive role+text walk) are\n * byte-identical — proves the matches carry no distinguishing data.\n */\nfunction buildCloneIndexLocator(args: {\n flat: NormalizedNode[];\n target: NormalizedNode;\n}): CloneIndexLocator | null {\n const { flat, target } = args;\n if (!target.el.role) return null;\n const targetName = target.textTemplate ?? target.el.text;\n if (!targetName) return null;\n\n // Find all global matches for role+name in flatten/DOM order.\n const matches = flat.filter(\n (n) => n.el.role === target.el.role && (n.textTemplate ?? n.el.text) === targetName\n );\n if (matches.length < 2) return null;\n\n // Each match's \"card\" = lowest ancestor whose subtree contains ONLY that\n // match among `matches`. Walking up stops as soon as another match enters\n // the subtree.\n const cards: NormalizedNode[] = [];\n for (const m of matches) {\n const card = nearestCloneCard(m, matches);\n if (!card) return null;\n cards.push(card);\n }\n\n // All cards must share a single common parent (siblings of one another).\n const parents = new Set<NormalizedNode | null>(cards.map((c) => c.parent));\n if (parents.size !== 1) return null;\n const commonParent = [...parents][0];\n if (!commonParent) return null;\n\n // No list-role ancestor in the chain from the common parent up.\n for (let p: NormalizedNode | null = commonParent; p; p = p.parent) {\n if (LIST_ROLES.has(p.el.role)) return null;\n }\n\n // All cards must have byte-identical subtree text fingerprints.\n const reference = subtreeTextFingerprint(cards[0].el);\n for (let i = 1; i < cards.length; i++) {\n if (subtreeTextFingerprint(cards[i].el) !== reference) return null;\n }\n\n const ordinal = matches.indexOf(target);\n if (ordinal < 0) return null;\n\n const locator = `getByRole('${escapeLocatorString(target.el.role)}', { name: '${escapeLocatorString(targetName)}' }).nth(${ordinal})`;\n return { locator, ordinal };\n}\n\nfunction nearestCloneCard(\n match: NormalizedNode,\n allMatches: NormalizedNode[]\n): NormalizedNode | null {\n const otherRefs = new Set(allMatches.filter((m) => m !== match).map((m) => m.el.ref));\n let candidate: NormalizedNode | null = match;\n let node: NormalizedNode | null = match.parent;\n while (node) {\n let containsOther = false;\n for (const ref of otherRefs) {\n if (node.descendantRefs.has(ref)) {\n containsOther = true;\n break;\n }\n }\n if (containsOther) break;\n candidate = node;\n node = node.parent;\n }\n return candidate;\n}\n\n/**\n * Recursive role+text walk of a subtree, ignoring refs and attributes.\n * Two clones of the same UI component produce identical fingerprints; two\n * data rows produce different fingerprints (their content varies).\n */\nfunction subtreeTextFingerprint(el: SnapshotElement): string {\n // Capture every text-bearing slot the snapshot parser uses:\n // `text` — accessible name (button \"Edit\", link \"Home\", etc.)\n // `inputValue` — generic-with-content (`- generic [ref=e1]: Hello`) and\n // textbox/combobox current value\n // `url` — link href when present\n // Attributes are intentionally excluded: clones can carry different ref-derived\n // attributes (test-id, data-id) without being information-distinct from a user's\n // perspective. Text/inputValue/url are the dimensions that actually distinguish\n // a \"data row\" from a \"UI clone.\"\n const parts: string[] = [];\n const walk = (node: SnapshotElement): void => {\n const slots: string[] = [node.role];\n if (node.text) slots.push(`t=${node.text}`);\n if (node.inputValue) slots.push(`v=${node.inputValue}`);\n if (node.url) slots.push(`u=${node.url}`);\n parts.push(slots.join(':'));\n for (const c of node.children) walk(c);\n };\n walk(el);\n return parts.join('|');\n}\n\ninterface RowScopedOrdinalLocator {\n locator: string;\n anchor: NormalizedNode;\n innerAncestors: NormalizedNode[];\n key: string;\n value: string;\n}\n\nfunction buildRowScopedOrdinalLocator(args: {\n target: NormalizedNode;\n ancestors: NormalizedNode[];\n variableValues: Record<string, string>;\n}): RowScopedOrdinalLocator | null {\n const targetLabel =\n args.target.textTemplate ??\n args.target.el.text ??\n args.target.ariaLabelTemplate ??\n args.target.el.attributes['aria-label'];\n if (args.target.el.role !== 'button' || targetLabel) return null;\n\n const entries = Object.entries(args.variableValues)\n .filter(([, value]) => typeof value === 'string' && value.length >= MIN_TEMPLATING_LENGTH)\n .sort((a, b) => b[1].length - a[1].length);\n if (entries.length === 0) return null;\n\n for (let i = args.ancestors.length - 1; i >= 0; i--) {\n const anchor = args.ancestors[i];\n if (!REPEATING_ANCESTOR_ROLES.has(anchor.el.role)) continue;\n const anchorText = collectSubtreeText(anchor.el);\n const match = entries.find(([, value]) => textContainsValue(anchorText, value));\n if (!match) continue;\n const buttonRefs = collectRoleRefs(anchor.el, 'button');\n const ordinal = buttonRefs.indexOf(args.target.el.ref);\n if (ordinal < 0) continue;\n const [key, value] = match;\n return {\n locator: `getByRole('${escapeLocatorString(anchor.el.role)}').filter({ hasText: '{{var.${key}}}' }).getByRole('button').nth(${ordinal})`,\n anchor,\n innerAncestors: args.ancestors.slice(i + 1),\n key,\n value,\n };\n }\n\n return null;\n}\n\nfunction collectRoleRefs(el: SnapshotElement, role: string): string[] {\n const refs: string[] = [];\n const walk = (node: SnapshotElement): void => {\n if (node.role === role && node.ref) refs.push(node.ref);\n for (const child of node.children) walk(child);\n };\n walk(el);\n return refs;\n}\n\nfunction escapeLocatorString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Templating\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Minimum length for a variable value to be templated. Short values (e.g. \"1\", \"OK\") are too lossy. */\nconst MIN_TEMPLATING_LENGTH = 3;\n\ninterface CompiledBinding {\n key: string;\n value: string;\n /** Word-boundary-aware regex, used for both check and replace. */\n regex: RegExp;\n}\n\nfunction templateAll(\n flat: NormalizedNode[],\n variableValues: Record<string, string>\n): VariableBinding[] {\n const summary = new Map<string, VariableBinding>();\n const compiled: CompiledBinding[] = Object.entries(variableValues)\n .filter(([, v]) => typeof v === 'string' && v.length >= MIN_TEMPLATING_LENGTH)\n .map(([key, value]) => ({\n key,\n value,\n regex: new RegExp(`(^|\\\\W)${escapeRegex(value)}(?=\\\\W|$)`, 'g'),\n }));\n if (compiled.length === 0) return [];\n\n for (const node of flat) {\n templateField(node, 'text', node.el.text, (v) => {\n node.textTemplate = v;\n }, compiled, summary);\n templateField(\n node,\n 'aria-label',\n node.el.attributes['aria-label'],\n (v) => {\n node.ariaLabelTemplate = v;\n },\n compiled,\n summary\n );\n templateField(\n node,\n 'placeholder',\n node.el.attributes['placeholder'],\n (v) => {\n node.placeholderTemplate = v;\n },\n compiled,\n summary\n );\n templateField(\n node,\n 'value',\n node.el.inputValue ?? node.el.attributes['value'],\n (v) => {\n node.valueTemplate = v;\n },\n compiled,\n summary\n );\n }\n\n return Array.from(summary.values());\n}\n\nfunction templateField(\n node: NormalizedNode,\n field: TemplatedField,\n original: string | undefined,\n set: (templated: string) => void,\n compiled: CompiledBinding[],\n summary: Map<string, VariableBinding>\n): void {\n if (!original) return;\n let templated = original;\n const local: VariableBinding[] = [];\n for (const b of compiled) {\n b.regex.lastIndex = 0;\n let occurrences = 0;\n // Word-boundary-aware replace: the regex captures the boundary char on\n // the left so we preserve it in the replacement; the right boundary is\n // a lookahead so it isn't consumed.\n const next = templated.replace(b.regex, (_match, lead: string) => {\n occurrences++;\n return `${lead}{{${b.key}}}`;\n });\n if (occurrences > 0 && next !== templated) {\n templated = next;\n local.push({ key: b.key, value: b.value, field, occurrences });\n }\n }\n if (templated !== original) {\n set(templated);\n for (const b of local) {\n node.bindings.push(b);\n const k = `${b.key}|${b.field}`;\n const existing = summary.get(k);\n if (existing) existing.occurrences += b.occurrences;\n else summary.set(k, { ...b });\n }\n }\n}\n\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Predicate ladder\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface Predicate {\n name: string;\n /** Substrate field this predicate reads — used to look up the durability source. */\n field: PredicateField;\n applies: (target: NormalizedNode) => boolean;\n /** Match function: returns true if `candidate` would be a match for the target's predicate values. */\n match: (target: NormalizedNode, candidate: NormalizedNode) => boolean;\n toStrategy: (target: NormalizedNode, flat: NormalizedNode[]) => SelectorStrategy;\n}\n\nconst DOM_MUTATION_SOURCES: ReadonlySet<SnapshotElementSource> = new Set([\n 'augmented:dom-mutation',\n]);\n\n/**\n * Look up the provenance for the field a predicate reads, and return true\n * when that source is too low-durability to use. Stable testIds are handled\n * before the predicate ladder.\n */\nfunction isPredicateBlockedBySource(p: Predicate, target: NormalizedNode): boolean {\n const source =\n p.field === 'text'\n ? target.el.nameSource\n : target.el.attributeSources?.[p.field];\n if (!source) return false;\n return DOM_MUTATION_SOURCES.has(source);\n}\n\n/**\n * Walk the target's testIds and return the first one that's globally unique.\n * Each testId is independent, so set-overlap uniqueness (the regular predicate\n * ladder) doesn't fit — a target with `[shared, unique]` testIds shouldn't\n * fall through just because `shared` is duplicated.\n */\nfunction pickUniqueTestId(target: NormalizedNode, flat: NormalizedNode[]): string | null {\n const ids = stableTestIds(target);\n for (const id of ids) {\n let count = 0;\n for (const n of flat) {\n if (n.el.cssHints?.testIds?.includes(id)) {\n count++;\n if (count > 1) break;\n }\n }\n if (count === 1) return id;\n }\n return null;\n}\n\nfunction stableTestIds(target: NormalizedNode): string[] {\n // Stability = survives a re-seed. Seeded ids (UUID/ULID/entity numbers) are\n // volatile even when unique in the recording snapshot. Canonical rule lives in\n // `@chatsdet/types` (`classifyIdentifier`).\n return (target.el.cssHints?.testIds ?? []).filter((id) => !isVolatileIdentifier(id));\n}\n\nfunction buildVolatileTestIdTextSelector(\n target: NormalizedNode,\n flat: NormalizedNode[]\n): SelectorStrategy | null {\n const ids = target.el.cssHints?.testIds ?? [];\n const textParts = collectVolatileTestIdTextParts(target);\n if (textParts.length === 0) return null;\n\n for (const id of ids) {\n const prefix = stableIdentifierPrefix(id);\n const selectorBase = prefix\n ? `[data-testid^=\"${escapeCssString(prefix)}\"]`\n : '[data-testid]';\n\n let count = 0;\n for (const n of flat) {\n const candidateIds = n.el.cssHints?.testIds ?? [];\n const matchingCandidate = prefix\n ? candidateIds.some((candidateId) => candidateId.startsWith(prefix))\n : candidateIds.some((candidateId) => isVolatileIdentifier(candidateId));\n if (!matchingCandidate) continue;\n const candidateTexts = collectTargetVisibleTexts(n);\n if (!textParts.every((part) => candidateTexts.includes(part))) continue;\n count++;\n if (count > 1) break;\n }\n if (count === 1) {\n const textFilters = textParts\n .map((part) =>\n prefix ? `:has-text(\"${escapeCssString(part)}\")` : `:has(:text-is(\"${escapeCssString(part)}\"))`\n )\n .join('');\n return {\n css: `${selectorBase}${textFilters}`,\n containsText: textParts,\n };\n }\n }\n\n return null;\n}\n\nfunction escapeCssString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n\n/**\n * ARIA role → HTML tag(s) that imply that role natively. Used to build\n * CSS selectors that match both the implicit-role and explicit-role\n * forms (`<button class=\"foo\">` AND `<div role=\"button\" class=\"foo\">`).\n *\n * **Why this matters:** the resolver skips a nameless role selector\n * when a CSS fallback is present (`element-resolver.ts:1487`), so the\n * CSS must work standalone. A naive `${role}.${cls}` selector emits\n * things like `generic.foo` (no `<generic>` tag exists in HTML) or\n * `link.foo` (`<link>` is for stylesheets, not clickables). The result\n * is a CSS that matches zero DOM nodes and replay fails.\n *\n * Roles without a stable implicit tag (`generic`, `switch`,\n * `menuitem`) get only the explicit `[role=\"...\"]` form, which is\n * usually missing from the DOM (those roles are inferred). Callers\n * fall back to class-only selectors in that case (see roleScopedCss).\n */\nconst ROLE_TO_IMPLICIT_TAGS: Record<string, readonly string[]> = {\n button: ['button'],\n link: ['a'],\n img: ['img'],\n textbox: ['input', 'textarea'],\n combobox: ['select'],\n checkbox: ['input'],\n radio: ['input'],\n};\n\n/**\n * Build a CSS selector that matches an ARIA role's implicit-tag forms\n * AND its explicit `[role=\"...\"]` form, joined by comma. The `suffix`\n * is appended to each branch (e.g. `.foo`, `[src*=\"x\"]`, `:has(svg.y)`).\n *\n * For roles with no implicit-tag mapping (`generic`, etc.), returns\n * just the suffix — caller relies on substrate uniqueness because\n * tagging would emit a selector that matches nothing.\n */\nfunction roleScopedCss(role: string, suffix: string): string {\n const implicit = ROLE_TO_IMPLICIT_TAGS[role] ?? [];\n if (implicit.length === 0) {\n // No reliable tag anchor; emit class-only / attr-only selector.\n // Trim leading `:` from `:has(...)` style suffixes — without a\n // leftmost subject `:has(...)` is invalid, so we fall back to `*`.\n return suffix.startsWith(':') ? `*${suffix}` : suffix;\n }\n const parts = [...implicit.map((t) => `${t}${suffix}`), `[role=\"${role}\"]${suffix}`];\n return parts.join(', ');\n}\n\n/**\n * Return the target's icon class iff it's globally unique among same-role\n * nodes. Combined with the role tag, this produces a stable\n * `role:has(svg.<iconClass>)` selector for icon-only controls without an\n * accessible name.\n */\nfunction pickUniqueIconClass(target: NormalizedNode, flat: NormalizedNode[]): string | null {\n const cls = target.el.iconClass;\n if (!cls) return null;\n let count = 0;\n for (const n of flat) {\n if (n.el.role === target.el.role && n.el.iconClass === cls) {\n count++;\n if (count > 1) return null;\n }\n }\n return count === 1 ? cls : null;\n}\n\n/**\n * Return the target's semantic class iff it's globally unique among same-role\n * nodes. Combined with the role tag, this produces a stable `role.<class>`\n * CSS selector for controls labeled by `extractSemanticHint(className)`.\n *\n * The class token has already passed the augmenter's noise filter (rejects\n * Tailwind utilities, styled-component hashes, CSS-in-JS hashes), so reaching\n * this helper means the substrate already carries a stable, semantic token.\n */\nfunction pickUniqueSemanticClass(target: NormalizedNode, flat: NormalizedNode[]): string | null {\n const cls = target.el.semanticClass;\n if (!cls) return null;\n let count = 0;\n for (const n of flat) {\n if (n.el.role === target.el.role && n.el.semanticClass === cls) {\n count++;\n if (count > 1) return null;\n }\n }\n return count === 1 ? cls : null;\n}\n\n/**\n * Pick a stable filename-ish substring from a `src` URL for use in\n * `img[src*=\"<segment>\"]` selectors. Strips query/hash and any path prefix;\n * keeps the last path segment. Returns null for empty / data-URLs / values\n * too short to disambiguate (`<8 chars`).\n */\nfunction srcCssSegment(src: string | undefined): string | null {\n if (!src) return null;\n if (src.startsWith('data:')) return null;\n // Drop query + fragment.\n let cleaned = src.split('?')[0].split('#')[0];\n // Take last path segment.\n const slash = cleaned.lastIndexOf('/');\n if (slash >= 0) cleaned = cleaned.slice(slash + 1);\n cleaned = cleaned.trim();\n if (cleaned.length < 8) return null;\n return cleaned;\n}\n\nconst rolePlusNamePredicate: Predicate = {\n name: 'role+name',\n field: 'text',\n applies: (t) => Boolean(t.el.role && (t.textTemplate ?? t.el.text)),\n match: (t, c) => {\n if (c.el.role !== t.el.role) return false;\n const tn = t.textTemplate ?? t.el.text;\n const cn = c.textTemplate ?? c.el.text;\n return Boolean(tn) && tn === cn;\n },\n toStrategy: (t) => {\n const role: RoleSelector = { role: t.el.role };\n const name = t.textTemplate ?? t.el.text;\n if (name) role.name = name;\n return { role };\n },\n};\n\nfunction placeholderValue(t: NormalizedNode): string | undefined {\n return inferredPlaceholderValue(t) ?? t.placeholderTemplate ?? t.el.attributes['placeholder'];\n}\n\nfunction inferredPlaceholderValue(t: NormalizedNode): string | undefined {\n // Playwright's aria snapshot can render placeholder-only inputs as\n // `textbox \"Search\": <value>`. That text is not a durable accessible name\n // for replay, so prefer a placeholder locator when the field is actively\n // value-bearing and the text looks like a search/filter placeholder.\n const text = t.textTemplate ?? t.el.text;\n if (\n t.el.role === 'textbox' &&\n text &&\n (t.valueTemplate ?? t.el.inputValue ?? t.el.attributes['value']) &&\n /^(search|filter|find)$/i.test(text.trim())\n ) {\n return text;\n }\n\n return undefined;\n}\n\nconst ariaLabelPredicate: Predicate = {\n name: 'ariaLabel',\n field: 'aria-label',\n applies: (t) => Boolean(t.ariaLabelTemplate ?? t.el.attributes['aria-label']),\n match: (t, c) => {\n const tl = t.ariaLabelTemplate ?? t.el.attributes['aria-label'];\n const cl = c.ariaLabelTemplate ?? c.el.attributes['aria-label'];\n return Boolean(tl) && tl === cl;\n },\n toStrategy: (t) => ({\n ariaLabel: t.ariaLabelTemplate ?? t.el.attributes['aria-label'],\n }),\n};\n\nconst placeholderPredicate: Predicate = {\n name: 'placeholder',\n field: 'placeholder',\n applies: (t) => Boolean(placeholderValue(t)),\n match: (t, c) => {\n const tp = placeholderValue(t);\n const cp = placeholderValue(c);\n return Boolean(tp) && tp === cp;\n },\n toStrategy: (t) => ({\n placeholder: placeholderValue(t),\n }),\n};\n\nconst inferredPlaceholderPredicate: Predicate = {\n ...placeholderPredicate,\n applies: (t) => Boolean(inferredPlaceholderValue(t)),\n match: (t, c) => {\n const tp = inferredPlaceholderValue(t);\n const cp = inferredPlaceholderValue(c);\n return Boolean(tp) && tp === cp;\n },\n};\n\n/**\n * Anchor an `img` role on a substring of its `src` attribute. Last-resort\n * before role+containsText for unlabeled clickable images: the agent saw the\n * image's filename-derived label in render, but the substrate only carries\n * the raw `src`. We emit `img[src*=\"<filename>\"]` so the locator still\n * grounds on a DOM-verifiable signal rather than tree-position.\n */\nconst imgSrcPredicate: Predicate = {\n name: 'imgSrc',\n field: 'src',\n applies: (t) => t.el.role === 'img' && Boolean(srcCssSegment(t.el.attributes['src'])),\n match: (t, c) => {\n if (c.el.role !== 'img') return false;\n const ts = srcCssSegment(t.el.attributes['src']);\n const cs = srcCssSegment(c.el.attributes['src']);\n return Boolean(ts) && ts === cs;\n },\n toStrategy: (t) => {\n const seg = srcCssSegment(t.el.attributes['src']) ?? '';\n return {\n role: { role: 'img' },\n css: roleScopedCss('img', `[src*=\"${seg}\"]`),\n };\n },\n};\n\n/**\n * Anchor a grid cell on its `data-field` token (e.g. a MUI DataGrid editable\n * cell's `house_rate::GroupA`). A `data-field` is unique within a row but\n * repeats across rows, so this predicate is never globally unique — it relies\n * on the ladder's ancestor/row-variable scoping to bind it to a specific row.\n * That keeps it a stable, DOM-verifiable, NON-ordinal anchor: the right fix for\n * nameless editable cells the agent would otherwise only reach by coordinates.\n */\nconst dataFieldPredicate: Predicate = {\n name: 'dataField',\n field: 'data-field',\n applies: (t) => Boolean(t.el.dataField),\n match: (t, c) => Boolean(t.el.dataField) && c.el.dataField === t.el.dataField,\n // No bare `role` (a gridcell role is non-unique and the resolver tries role\n // before css). The `[data-field=…]` css IS the anchor; it resolves scoped\n // under the parentContext (row id / row-variable) the ladder attaches.\n toStrategy: (t) => ({\n css: roleScopedCss(t.el.role, `[data-field=\"${cssAttrEscape(t.el.dataField ?? '')}\"]`),\n }),\n};\n\nfunction cssAttrEscape(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n\n/**\n * Stable id selectors for an element, from intentional entity-id attributes\n * only (`data-id`, `data-testid`). Generic `id` is deliberately excluded — it's\n * too often framework-generated (`mui-…`, React `:r3:`) to trust as an anchor.\n * Stability is decided by the canonical `stableAttrSelector` in `@chatsdet/types`\n * (a seeded entity number/id yields a `^prefix` or nothing, never an exact id).\n */\nfunction elementStableIdSelectors(el: NormalizedNode['el']): string[] {\n const out: string[] = [];\n const dataId = el.cssHints?.dataId;\n const fromDataId = dataId ? stableAttrSelector('data-id', dataId) : null;\n if (fromDataId) out.push(fromDataId);\n for (const tid of el.cssHints?.testIds ?? []) {\n const s = stableAttrSelector('data-testid', tid);\n if (s) out.push(s);\n }\n return out;\n}\n\n/**\n * Count nodes that the stable-id `selector` would actually MATCH (cap at 2) —\n * by attribute semantics, not classified-string equality. A prefix selector\n * `[data-id^=\"__new__\"]` matches `__new__template` too, even though that sibling\n * classifies to an exact selector; counting by `includes(selector)` would miss\n * it and wrongly mark the ancestor unique.\n */\nfunction countNodesMatchingStableSelector(flat: NormalizedNode[], selector: string): number {\n const m = /^\\[(data-id|data-testid)(\\^?)=\"(.*)\"\\]$/.exec(selector);\n if (!m) return 0;\n const [, attr, op, escaped] = m;\n // Reverse `cssAttrEscape` (escape order was `\\` then `\"`).\n const value = escaped.replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, '\\\\');\n const valuesOf = (el: NormalizedNode['el']): string[] =>\n attr === 'data-id'\n ? el.cssHints?.dataId\n ? [el.cssHints.dataId]\n : []\n : (el.cssHints?.testIds ?? []);\n\n let n = 0;\n for (const node of flat) {\n const vals = valuesOf(node.el);\n const hit =\n op === '^' ? vals.some((v) => v.startsWith(value)) : vals.some((v) => v === value);\n if (hit) {\n n++;\n if (n > 1) break;\n }\n }\n return n;\n}\n\n/**\n * The ancestor's globally-unique stable-id selector (`[data-id^=\"__new__\"]`,\n * `[data-testid=\"settings-panel\"]`, …), or null. This is how the per-predicate\n * `+ancestor` scope identifies a nameless ancestor by its durable entity id —\n * a structural, NON-ordinal anchor (`__new__` draft row, a hard-coded test-id\n * panel) — emitted as `parentContext.css` so the resolver scopes the target\n * (role or css) under it. Seeded ids reduce to a non-unique prefix and are\n * rejected here.\n */\nfunction uniqueStableIdSelector(anchor: NormalizedNode, flat: NormalizedNode[]): string | null {\n for (const selector of elementStableIdSelectors(anchor.el)) {\n if (countNodesMatchingStableSelector(flat, selector) === 1) return selector;\n }\n return null;\n}\n\nconst roleContainsTextPredicate: Predicate = {\n name: 'role+containsText',\n field: 'text',\n applies: (t) => {\n if (!t.el.role) return false;\n if (t.textTemplate ?? t.el.text) return false;\n return collectChildrenTexts(t.el).length > 0;\n },\n // Exact-set equality (sorted) — a candidate that's a strict superset of\n // the target's child texts must NOT match, otherwise uniqueness collapses.\n match: (t, c) => {\n if (c.el.role !== t.el.role) return false;\n const targetTexts = collectChildrenTexts(t.el).slice().sort();\n const candidateTexts = collectChildrenTexts(c.el).slice().sort();\n if (targetTexts.length !== candidateTexts.length) return false;\n return targetTexts.every((tx, i) => tx === candidateTexts[i]);\n },\n toStrategy: (t) => {\n const containsText = collectChildrenTexts(t.el).slice(0, 3);\n return {\n role: { role: t.el.role },\n containsText,\n };\n },\n};\n\n// testId is checked separately by `pickUniqueTestId` before this ladder runs.\n// Same for iconClass and semanticClass (pre-ladder pickers).\nconst PREDICATES: ReadonlyArray<Predicate> = [\n inferredPlaceholderPredicate,\n rolePlusNamePredicate,\n ariaLabelPredicate,\n placeholderPredicate,\n imgSrcPredicate,\n dataFieldPredicate,\n roleContainsTextPredicate,\n];\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface FlattenResult {\n flat: NormalizedNode[];\n byRef: Map<string, NormalizedNode>;\n}\n\nfunction flatten(roots: SnapshotElement[]): FlattenResult {\n const flat: NormalizedNode[] = [];\n const byRef = new Map<string, NormalizedNode>();\n function walk(el: SnapshotElement, parent: NormalizedNode | null): NormalizedNode {\n const node: NormalizedNode = {\n el,\n bindings: [],\n parent,\n descendantRefs: new Set(),\n };\n flat.push(node);\n if (el.ref) byRef.set(el.ref, node);\n for (const child of el.children) {\n const childNode = walk(child, node);\n // Bubble the child's descendant set up.\n node.descendantRefs.add(childNode.el.ref);\n for (const r of childNode.descendantRefs) node.descendantRefs.add(r);\n }\n return node;\n }\n for (const root of roots) walk(root, null);\n return { flat, byRef };\n}\n\nfunction ancestorChain(node: NormalizedNode): NormalizedNode[] {\n const chain: NormalizedNode[] = [];\n let cur = node.parent;\n while (cur) {\n chain.push(cur);\n cur = cur.parent;\n }\n // We want innermost-last (so closest-first iteration is i = length-1 → 0)\n // but the walk above produces innermost-first; reverse it for that contract.\n return chain.reverse();\n}\n\n/** Count predicate matches across the whole flat list, short-circuiting at 2. */\nfunction uniquenessMatches(\n flat: NormalizedNode[],\n target: NormalizedNode,\n p: Predicate\n): number {\n let count = 0;\n for (const n of flat) {\n if (p.match(target, n)) {\n count++;\n if (count > 1) return count;\n }\n }\n return count;\n}\n\n/**\n * Count predicate matches inside `anchor`'s subtree, short-circuiting at 2.\n * Uses the `descendantRefs` set computed during flatten so we don't re-walk.\n */\nfunction uniquenessMatchesScoped(\n flat: NormalizedNode[],\n target: NormalizedNode,\n p: Predicate,\n anchor: NormalizedNode\n): number {\n let count = 0;\n for (const n of flat) {\n if (n === anchor) continue;\n if (!anchor.descendantRefs.has(n.el.ref)) continue;\n if (p.match(target, n)) {\n count++;\n if (count > 1) return count;\n }\n }\n return count;\n}\n\ninterface IdentityIndex {\n /** `${role}|${templatedName}` → count. */\n byRoleName: Map<string, number>;\n /** `${role}|${first durable child text}` → count for nameless containers. */\n byRoleChildText: Map<string, number>;\n /** templated aria-label → count. */\n byAriaLabel: Map<string, number>;\n}\n\nfunction buildIdentityIndex(flat: NormalizedNode[]): IdentityIndex {\n const byRoleName = new Map<string, number>();\n const byRoleChildText = new Map<string, number>();\n const byAriaLabel = new Map<string, number>();\n for (const n of flat) {\n const name = n.textTemplate ?? n.el.text;\n if (n.el.role && name) {\n const k = `${n.el.role}|${name}`;\n byRoleName.set(k, (byRoleName.get(k) ?? 0) + 1);\n }\n const childText = n.el.role && !name ? firstDurableAncestorChildText(n.el) : null;\n if (n.el.role && childText) {\n const k = `${n.el.role}|${childText}`;\n byRoleChildText.set(k, (byRoleChildText.get(k) ?? 0) + 1);\n }\n const ariaLabel = n.ariaLabelTemplate ?? n.el.attributes['aria-label'];\n if (ariaLabel) {\n byAriaLabel.set(ariaLabel, (byAriaLabel.get(ariaLabel) ?? 0) + 1);\n }\n }\n return { byRoleName, byRoleChildText, byAriaLabel };\n}\n\n/**\n * An ancestor is identifiable when its (role, templated name) pair is unique\n * across the snapshot, when it carries a testId, or when its aria-label is\n * unique. Without identifiability, the parentContext we build from it would\n * itself be ambiguous, defeating the disambiguation step.\n */\nfunction isAncestorIdentifiable(\n anchor: NormalizedNode,\n idx: IdentityIndex,\n target: NormalizedNode\n): boolean {\n // NOTE: stable id/test-id identification is handled by the caller via\n // `uniqueStableIdSelector` (which also enforces global uniqueness and emits\n // the id as `parentContext.css`). This function only covers role+name / child\n // text / aria-label identification.\n const role = anchor.el.role;\n if (role) {\n const name = anchor.textTemplate ?? anchor.el.text;\n if (name && idx.byRoleName.get(`${role}|${name}`) === 1) return true;\n const childText = !name ? firstDurableAncestorChildText(anchor.el) : null;\n const targetText = target.textTemplate ?? target.el.text;\n if (\n childText &&\n childText !== targetText &&\n idx.byRoleChildText.get(`${role}|${childText}`) === 1\n ) {\n return true;\n }\n }\n const ariaLabel = anchor.ariaLabelTemplate ?? anchor.el.attributes['aria-label'];\n if (ariaLabel && idx.byAriaLabel.get(ariaLabel) === 1) return true;\n return false;\n}\n\nfunction collectChildrenTexts(el: SnapshotElement): string[] {\n const texts: string[] = [];\n function walk(e: SnapshotElement) {\n if (e.text) texts.push(e.text);\n if (e.inputValue) texts.push(e.inputValue);\n for (const c of e.children) walk(c);\n }\n for (const c of el.children) walk(c);\n return texts;\n}\n\nfunction collectTargetVisibleTexts(target: NormalizedNode): string[] {\n const ownText = target.textTemplate ?? target.el.text;\n if (ownText) return [ownText];\n if (target.el.inputValue) return [target.el.inputValue];\n return collectChildrenTexts(target.el);\n}\n\nfunction firstDurableAncestorChildText(el: SnapshotElement): string | null {\n return collectChildrenTexts(el).find(isDurableAncestorChildText) ?? null;\n}\n\nfunction isDurableAncestorChildText(text: string): boolean {\n const trimmed = text.trim();\n // Keep this intentionally narrow; arbitrary row/card text is often data,\n // not a stable structural label for ancestor scoping.\n return /^(Section|Step)\\s+\\d+\\s*:/i.test(trimmed);\n}\n\nfunction collectVolatileTestIdTextParts(target: NormalizedNode): string[] {\n const ownText = target.textTemplate ?? target.el.text;\n if (ownText) return [ownText];\n if (target.el.inputValue) return [target.el.inputValue];\n\n const childTexts = collectChildrenTexts(target.el);\n const durableChildTexts = childTexts.filter(isDurableVolatileTestIdChildText);\n return (durableChildTexts.length > 0 ? durableChildTexts : childTexts).slice(0, 3);\n}\n\nfunction isDurableVolatileTestIdChildText(text: string): boolean {\n return text.trim().length > 1;\n}\n\ninterface RowVariableScope {\n anchor: NormalizedNode;\n innerAncestors: NormalizedNode[];\n key: string;\n value: string;\n}\n\nfunction findRowVariableScope(args: {\n flat: NormalizedNode[];\n target: NormalizedNode;\n predicate: Predicate;\n ancestors: NormalizedNode[];\n variableValues: Record<string, string>;\n}): RowVariableScope | null {\n const entries = Object.entries(args.variableValues)\n .filter(([, value]) => typeof value === 'string' && value.length >= MIN_TEMPLATING_LENGTH)\n .sort((a, b) => b[1].length - a[1].length);\n if (entries.length === 0) return null;\n\n for (let i = args.ancestors.length - 1; i >= 0; i--) {\n const anchor = args.ancestors[i];\n if (!REPEATING_ANCESTOR_ROLES.has(anchor.el.role)) continue;\n if (uniquenessMatchesScoped(args.flat, args.target, args.predicate, anchor) !== 1) {\n continue;\n }\n\n const anchorText = collectSubtreeText(anchor.el);\n for (const [key, value] of entries) {\n if (!textContainsValue(anchorText, value)) continue;\n return {\n anchor,\n innerAncestors: args.ancestors.slice(i + 1),\n key,\n value,\n };\n }\n }\n\n return null;\n}\n\nfunction collectSubtreeText(el: SnapshotElement): string {\n const parts: string[] = [];\n function walk(node: SnapshotElement) {\n if (node.text) parts.push(node.text);\n if (node.inputValue) parts.push(node.inputValue);\n const ariaLabel = node.attributes['aria-label'];\n if (ariaLabel) parts.push(ariaLabel);\n for (const child of node.children) walk(child);\n }\n walk(el);\n return parts.join(' ');\n}\n\nfunction textContainsValue(text: string, value: string): boolean {\n const pattern = new RegExp(`(^|\\\\W)${escapeRegex(value)}(?=\\\\W|$)`);\n return pattern.test(text);\n}\n\nfunction frameContextFor(el: SnapshotElement): FrameContext | undefined {\n const sel = el.frameSelector;\n if (!sel) return undefined;\n return { type: 'iframe', selector: sel };\n}\n\n/**\n * Build a `parentContext` rooted at `anchor` and including any intermediate\n * ancestors between `anchor` and the target. The `parentChain` is innermost-\n * to-outermost per the {@link ParentContext} contract.\n */\nfunction parentContextFor(\n anchor: NormalizedNode,\n inner: NormalizedNode[],\n override?: {\n containsText?: string;\n containsTextDynamic?: ParentContextDynamicText;\n }\n): ParentContext {\n const ctx: ParentContext = { role: anchor.el.role };\n const anchorName = override?.containsText ? undefined : anchor.textTemplate ?? anchor.el.text;\n if (anchorName) ctx.name = anchorName;\n if (override?.containsText) {\n ctx.containsText = override.containsText;\n if (override.containsTextDynamic) {\n ctx.containsTextDynamic = override.containsTextDynamic;\n }\n } else if (!anchorName) {\n const childTexts = collectChildrenTexts(anchor.el);\n if (childTexts.length > 0) ctx.containsText = childTexts[0];\n }\n if (inner.length > 0) {\n // Innermost-to-outermost.\n // Row-variable scopes intentionally stop at the row. Resolving\n // `row.filter({ hasText }).locator(button)` is more reliable than adding\n // intermediate cells, which often duplicate the action button's name.\n if (!override?.containsText) {\n ctx.parentChain = inner\n .slice()\n .reverse()\n .map((n) => {\n const node: ParentContextNode = { role: n.el.role };\n const name = n.textTemplate ?? n.el.text;\n if (name) node.name = name;\n return node;\n });\n }\n }\n return ctx;\n}\n\nfunction indexedFallback(target: NormalizedNode): SelectorStrategy {\n // `siblingRoleIndex` is intentionally NOT mapped to `SelectorStrategy.itemIndex`\n // — that field is documented as a DOM `data-item-index` value and replay\n // will probe it as such. The selector-agent (or step-6 logging) handles\n // ambiguous fallbacks via the `irreducible` flag.\n const role: RoleSelector = { role: target.el.role };\n const name = target.textTemplate ?? target.el.text;\n if (name) role.name = name;\n return { role };\n}\n\nfunction applyContexts(\n base: SelectorStrategy,\n frame: FrameContext | undefined,\n dynamic: SelectorStrategy['dynamicText']\n): SelectorStrategy {\n const out: SelectorStrategy = { ...base };\n if (frame) out.frameContext = frame;\n if (dynamic) out.dynamicText = dynamic;\n return out;\n}\n\nfunction buildDynamicText(target: NormalizedNode): SelectorStrategy['dynamicText'] {\n // Surface a dynamicText hint when the target's accessible name was rewritten.\n // When multiple bindings touched the text, pick the one with the longest\n // value (most-specific) so legacy replay paths get the strongest hint.\n const textBindings = target.bindings.filter((b) => b.field === 'text');\n if (textBindings.length === 0) return undefined;\n const original = target.el.text;\n if (!original) return undefined;\n const chosen = textBindings.slice().sort((a, b) => b.value.length - a.value.length)[0];\n return {\n source: 'workflowState',\n key: chosen.key,\n originalText: original,\n };\n}\n","/**\n * Snapshot Parser\n *\n * Parses Playwright's accessibility snapshot YAML-like format to extract\n * element information for stable selector derivation.\n *\n * The snapshot format from Playwright's `ariaSnapshot({ mode: 'ai' })` looks like:\n * ```yaml\n * - navigation \"Main\":\n * - link \"Home\" [ref=e1]\n * - link \"About\" [ref=e2]\n * - main:\n * - heading \"Welcome\" [level=1] [ref=e3]\n * - paragraph:\n * - text \"Hello world\"\n * - button \"Submit\" [ref=e4]\n * ```\n */\n\nimport type { ElementInfo, FrameContext } from '@chatsdet/types';\n\n/**\n * Line parsed from the snapshot YAML.\n */\nexport interface ParsedLine {\n indent: number;\n role: string;\n name?: string;\n ref?: string;\n centerX?: number;\n centerY?: number;\n attributes: Record<string, string>;\n text?: string;\n}\n\n/**\n * Parse a single line from the snapshot.\n */\nfunction parseLine(line: string): ParsedLine | null {\n if (!line.trim()) return null;\n\n // Calculate indent (2 spaces per level)\n const indent = line.search(/\\S/);\n const content = line.trim();\n\n // Skip empty or dash-only lines\n if (!content || content === '-') return null;\n\n // Remove leading dash if present\n let cleanContent = content.startsWith('- ') ? content.slice(2) : content;\n if (!cleanContent) return null;\n\n // Strip YAML single-quote wrapping. When element text contains colons\n // (e.g. \"Rows per page: 25\"), YAML serializes the element key as:\n // 'combobox \"Rows per page: 25\" [ref=e542]': \"25\"\n // Unwrap only the quoted key and preserve any trailing input value.\n if (cleanContent.startsWith(\"'\")) {\n const quotedKeyEnd = cleanContent.indexOf(\"':\");\n if (quotedKeyEnd !== -1) {\n cleanContent = cleanContent.slice(1, quotedKeyEnd) + cleanContent.slice(quotedKeyEnd + 1);\n } else if (cleanContent.endsWith(\"'\")) {\n cleanContent = cleanContent.slice(1, -1);\n }\n }\n\n // Extract ref and optional center coordinates: [ref=e1] or [ref=e1 center=450,320]\n const refMatch = cleanContent.match(/\\[ref=(\\w+)(?:\\s+center=(\\d+),(\\d+))?\\]/);\n const ref = refMatch?.[1];\n const centerX = refMatch?.[2] ? parseInt(refMatch[2], 10) : undefined;\n const centerY = refMatch?.[3] ? parseInt(refMatch[3], 10) : undefined;\n\n // Remove all bracket attributes for cleaner parsing\n const withoutBrackets = cleanContent.replace(/\\s*\\[[^\\]]+\\]/g, '').trim();\n\n // Handle sub-property lines like `/placeholder: Enter name`\n if (cleanContent.startsWith('/')) {\n const colonIdx = cleanContent.indexOf(':');\n if (colonIdx !== -1) {\n const key = cleanContent.slice(1, colonIdx).trim();\n const value = cleanContent.slice(colonIdx + 1).trim();\n return { indent, role: '_property', attributes: { [key]: value } };\n }\n }\n\n // Handle text content lines (no role, just text)\n if (withoutBrackets.startsWith('\"') && withoutBrackets.endsWith('\"')) {\n return {\n indent,\n role: 'text',\n text: withoutBrackets.slice(1, -1),\n attributes: {},\n };\n }\n\n // Parse role and optional name: `button \"Submit\"` or `button:`\n // Also handles `text \"content\"` format and inline text after colon: `button \"X\": Click me`\n const roleNameMatch = withoutBrackets.match(/^(\\w+)(?:\\s+\"([^\"]+)\")?(?::(?:\\s+(.+))?)?$/);\n if (!roleNameMatch) {\n // Might be a plain text node or malformed line\n return {\n indent,\n role: 'generic',\n text: withoutBrackets,\n attributes: {},\n };\n }\n\n const role = roleNameMatch[1];\n const name = roleNameMatch[2];\n const inlineText = roleNameMatch[3];\n\n // Extract other attributes\n const attributes: Record<string, string> = {};\n const attrMatches = cleanContent.matchAll(/\\[(\\w+)=([^\\]]+)\\]/g);\n for (const match of attrMatches) {\n const [, key, value] = match;\n if (key !== 'ref') {\n attributes[key] = value;\n }\n }\n\n return {\n indent,\n role,\n name,\n ref,\n centerX,\n centerY,\n attributes,\n text: inlineText,\n };\n}\n\n/**\n * Collect sub-property lines (e.g. `/placeholder: ...`) from children of an element.\n */\nfunction collectSubProperties(\n elementIndex: number,\n allParsed: ParsedLine[],\n elementIndent: number\n): Record<string, string> {\n const props: Record<string, string> = {};\n for (let i = elementIndex + 1; i < allParsed.length; i++) {\n if (allParsed[i].indent <= elementIndent) break;\n if (allParsed[i].role === '_property') {\n Object.assign(props, allParsed[i].attributes);\n }\n }\n return props;\n}\n\n/** Roles where child headings typically name the container */\nconst UNIQUE_ROLES = ['dialog', 'alertdialog', 'form', 'article', 'region'];\n\n/**\n * Select the best parent for disambiguation.\n * Prefers unique roles (dialog) and named elements over unnamed ones.\n *\n * @param parentStack - Stack of parent elements from root to closest\n * @returns The best parent for disambiguation, or undefined if none suitable\n */\nfunction selectBestParent(parentStack: ParsedLine[]): ParsedLine | undefined {\n const reversed = [...parentStack].reverse();\n\n // First: prefer unique roles WITH names (most specific)\n for (const p of reversed) {\n if (UNIQUE_ROLES.includes(p.role) && p.name) {\n return p;\n }\n }\n\n // Second: prefer any named parent (more specific than unnamed)\n for (const p of reversed) {\n if (p.name && p.role !== 'generic' && p.role !== 'paragraph' && p.role !== 'text') {\n return p;\n }\n }\n\n // Third: prefer unique roles even without names\n for (const p of reversed) {\n if (UNIQUE_ROLES.includes(p.role)) {\n return p;\n }\n }\n\n // Last resort: any non-generic parent\n return reversed.find((p) => p.role !== 'generic' && p.role !== 'paragraph' && p.role !== 'text');\n}\n\n/**\n * Enrich an unnamed element with text from its direct child paragraph or heading.\n *\n * When an element (e.g. an `article`) has no `accessibleName` and no inline\n * `text`, scans immediate children (indent = parent indent + 2) for `paragraph`\n * or `heading` elements with a `name` or `text` property. Returns the first\n * match so it can be used as `textContent` for selector derivation.\n */\nfunction enrichElementWithChildText(\n elementIndex: number,\n allParsed: ParsedLine[],\n elementIndent: number\n): string | undefined {\n for (let i = elementIndex + 1; i < allParsed.length; i++) {\n const child = allParsed[i];\n // Exited the element's scope\n if (child.indent <= elementIndent) break;\n // Only consider direct children (one level deeper)\n if (child.indent !== elementIndent + 2) continue;\n if ((child.role === 'paragraph' || child.role === 'heading') && (child.name || child.text)) {\n return child.name || child.text;\n }\n }\n return undefined;\n}\n\n/**\n * Enrich an unnamed container parent with a child heading's name.\n *\n * When selectBestParent picks a UNIQUE_ROLE parent (article, region, form, dialog)\n * that has no accessible name of its own, scans child lines within that parent's\n * indentation scope for a heading element and uses the first heading's name.\n *\n * @param parent - The selected parent ParsedLine (must have no name)\n * @param parentLineIndex - Index of the parent in allLines\n * @param allLines - All parsed lines in the snapshot\n * @returns The heading name and flag, or undefined if no heading found\n */\nfunction enrichParentWithChildHeading(\n parent: ParsedLine,\n parentLineIndex: number,\n allLines: ParsedLine[]\n): { name: string; nameFromHeading: true } | undefined {\n // Only enrich unnamed UNIQUE_ROLE parents\n if (parent.name || !UNIQUE_ROLES.includes(parent.role)) {\n return undefined;\n }\n\n // Scan child lines (deeper indentation) within this parent's scope\n for (let i = parentLineIndex + 1; i < allLines.length; i++) {\n const child = allLines[i];\n // If we've exited the parent's scope (same or lower indent), stop\n if (child.indent <= parent.indent) break;\n // Look for a heading with a name\n if (child.role === 'heading' && child.name) {\n return { name: child.name, nameFromHeading: true };\n }\n }\n\n return undefined;\n}\n\n/**\n * Scan direct children of an element for an `img` role with a name (alt text).\n * Returns the first child img name found, or undefined.\n *\n * In the snapshot, img children appear as:\n * - img \"Alt text\" [ref=eN]\n * at indent = elementIndent + 2 (direct children).\n */\nfunction findChildImgAlt(\n elementIndex: number,\n allParsed: ParsedLine[],\n elementIndent: number\n): string | undefined {\n for (let i = elementIndex + 1; i < allParsed.length; i++) {\n const child = allParsed[i];\n // Exited the element's scope\n if (child.indent <= elementIndent) break;\n // Only consider direct children (one level deeper)\n if (child.indent !== elementIndent + 2) continue;\n if (child.role === 'img' && child.name) {\n return child.name;\n }\n }\n return undefined;\n}\n\n/**\n * Detect if a target element is inside an iframe ancestor.\n *\n * Walks the parent stack to find the nearest `iframe` role. Since the snapshot\n * YAML doesn't include CSS class/id information for iframes, we build a\n * convention-based selector:\n * - If the iframe has a `name` attribute → `iframe[name=\"...\"]`\n * - If only one iframe exists in the entire snapshot → `iframe`\n * - Otherwise → `iframe` (best effort; DOM metadata enrichment may refine this)\n *\n * @param parentStack - Parent elements from root to closest ancestor\n * @param totalIframeCount - Total number of iframe nodes in the full snapshot\n * @returns FrameContext if inside an iframe, undefined otherwise\n */\nfunction detectIframeAncestor(\n parentStack: Array<{ line: ParsedLine; allParsedIndex: number }>,\n _totalIframeCount: number\n): FrameContext | undefined {\n // Walk from closest ancestor outward to find the nearest iframe\n for (let i = parentStack.length - 1; i >= 0; i--) {\n const parent = parentStack[i].line;\n if (parent.role === 'iframe') {\n let selector = 'iframe';\n\n // Use name attribute if available for specificity\n if (parent.name) {\n selector = `iframe[name=\"${parent.name}\"]`;\n } else if (parent.attributes['name']) {\n selector = `iframe[name=\"${parent.attributes['name']}\"]`;\n }\n // When there's only one iframe, bare `iframe` is sufficient\n\n return {\n type: 'iframe',\n selector,\n name: parent.name ?? parent.attributes['name'],\n };\n }\n }\n return undefined;\n}\n\n/**\n * Count the total number of iframe elements in parsed lines.\n */\nfunction countIframes(allParsed: ParsedLine[]): number {\n let count = 0;\n for (const line of allParsed) {\n if (line.role === 'iframe') count++;\n }\n return count;\n}\n\n/**\n * Build an ElementInfo from an AncestorChainResult.\n *\n * Applies all enrichment steps: iframe detection, parent selection,\n * heading enrichment, child text/img enrichment, and sub-property collection.\n */\nfunction ancestorChainToElementInfo(result: AncestorChainResult): ElementInfo {\n const { element, elementIndex, ancestors, allParsed, subProperties } = result;\n\n // Detect iframe ancestor for frameContext\n const parentStack = ancestors.map((a) => ({ line: a.line, allParsedIndex: a.index }));\n const totalIframeCount = countIframes(allParsed);\n const frameContext = detectIframeAncestor(parentStack, totalIframeCount);\n\n // Find the most relevant parent using smart selection\n const relevantParent = selectBestParent(ancestors.map((a) => a.line));\n\n // Enrich unnamed container parents with child heading name\n let parentName = relevantParent?.name;\n let parentNameFromHeading: boolean | undefined;\n\n if (relevantParent && !relevantParent.name) {\n const ancestorEntry = ancestors.find((a) => a.line === relevantParent);\n if (ancestorEntry) {\n const headingInfo = enrichParentWithChildHeading(\n relevantParent,\n ancestorEntry.index,\n allParsed\n );\n if (headingInfo) {\n parentName = headingInfo.name;\n parentNameFromHeading = headingInfo.nameFromHeading;\n }\n }\n }\n\n // Enrich unnamed elements with child text content\n let textContent = element.text ?? element.name;\n if (!textContent && !element.name) {\n textContent = enrichElementWithChildText(elementIndex, allParsed, element.indent);\n }\n\n // Find child img alt text for disambiguation of generic containers\n const childImgAlt = findChildImgAlt(elementIndex, allParsed, element.indent);\n\n return {\n ref: element.ref!,\n role: element.role,\n accessibleName: element.name,\n textContent,\n ariaLabel: element.attributes['aria-label'],\n placeholder: subProperties['placeholder'],\n parentRole: relevantParent?.role,\n parentName,\n parentNameFromHeading,\n centerX: element.centerX,\n centerY: element.centerY,\n childImgAlt,\n frameContext,\n };\n}\n\n/**\n * Find element info by ref in the snapshot.\n *\n * Walks through the snapshot lines to find the element with the given ref,\n * also collecting parent context for disambiguation.\n *\n * @param snapshotYaml - The YAML-like snapshot string\n * @param targetRef - The ref to find (e.g., 'e1', 'e5')\n * @returns Element info if found, null otherwise\n */\nexport function findElementByRef(snapshotYaml: string, targetRef: string): ElementInfo | null {\n const result = findElementWithAncestors(snapshotYaml, targetRef);\n if (!result) return null;\n return ancestorChainToElementInfo(result);\n}\n\n/**\n * Result of finding an element with its full ancestor chain.\n * Used by the deterministic locator builder to construct compositional\n * locator chains with scoping (dialog, row, container).\n */\nexport interface AncestorEntry {\n line: ParsedLine;\n index: number;\n}\n\nexport interface AncestorChainResult {\n /** The target element */\n element: ParsedLine;\n /** Index of the target in allParsed */\n elementIndex: number;\n /** Ancestors from root to closest parent (does not include target), with indices */\n ancestors: AncestorEntry[];\n /** All parsed lines from the snapshot */\n allParsed: ParsedLine[];\n /** Sub-properties collected from target's children (e.g. placeholder) */\n subProperties: Record<string, string>;\n}\n\n/**\n * Find an element by ref and return it with its full ancestor chain.\n *\n * Unlike findElementByRef() which returns a flattened ElementInfo with\n * only the \"best\" parent, this returns the complete ancestor stack so\n * callers can analyze the full hierarchy for scoping decisions.\n *\n * @param snapshotYaml - The YAML-like snapshot string\n * @param targetRef - The ref to find (e.g., 'e1', 'e5')\n * @returns Ancestor chain result, or null if ref not found\n */\nexport function findElementWithAncestors(\n snapshotYaml: string,\n targetRef: string\n): AncestorChainResult | null {\n const rawLines = snapshotYaml.split('\\n');\n\n const allParsed: ParsedLine[] = [];\n for (const line of rawLines) {\n const parsed = parseLine(line);\n if (parsed) allParsed.push(parsed);\n }\n\n const parentStack: Array<{ line: ParsedLine; allParsedIndex: number }> = [];\n let targetElement: ParsedLine | null = null;\n let targetIdx = -1;\n\n for (let idx = 0; idx < allParsed.length; idx++) {\n const parsed = allParsed[idx];\n\n while (\n parentStack.length > 0 &&\n parentStack[parentStack.length - 1].line.indent >= parsed.indent\n ) {\n parentStack.pop();\n }\n\n if (parsed.ref === targetRef) {\n targetElement = parsed;\n targetIdx = idx;\n break;\n }\n\n if (parsed.role !== 'text') {\n parentStack.push({ line: parsed, allParsedIndex: idx });\n }\n }\n\n if (!targetElement) {\n return null;\n }\n\n const subProperties = collectSubProperties(targetIdx, allParsed, targetElement.indent);\n\n return {\n element: targetElement,\n elementIndex: targetIdx,\n ancestors: parentStack.map((p) => ({ line: p.line, index: p.allParsedIndex })),\n allParsed,\n subProperties,\n };\n}\n\n/**\n * Extract all elements with refs from the snapshot.\n * Useful for debugging and testing.\n *\n * @param snapshotYaml - The YAML-like snapshot string\n * @returns Array of element info for all elements with refs\n */\nexport function extractAllElements(snapshotYaml: string): ElementInfo[] {\n const rawLines = snapshotYaml.split('\\n');\n\n const allParsed: ParsedLine[] = [];\n for (const line of rawLines) {\n const parsed = parseLine(line);\n if (parsed) allParsed.push(parsed);\n }\n\n const parentStack: Array<{ line: ParsedLine; allParsedIndex: number }> = [];\n const elements: ElementInfo[] = [];\n\n for (let idx = 0; idx < allParsed.length; idx++) {\n const parsed = allParsed[idx];\n\n while (\n parentStack.length > 0 &&\n parentStack[parentStack.length - 1].line.indent >= parsed.indent\n ) {\n parentStack.pop();\n }\n\n if (parsed.ref) {\n const subProperties = collectSubProperties(idx, allParsed, parsed.indent);\n elements.push(\n ancestorChainToElementInfo({\n element: parsed,\n elementIndex: idx,\n ancestors: parentStack.map((p) => ({ line: p.line, index: p.allParsedIndex })),\n allParsed,\n subProperties,\n })\n );\n }\n\n if (parsed.role !== 'text') {\n parentStack.push({ line: parsed, allParsedIndex: idx });\n }\n }\n\n return elements;\n}\n\n/**\n * Known ARIA roles used to split description strings into (name, role) pairs.\n * Ordered by specificity (longer roles first to avoid partial matches).\n */\nconst KNOWN_ROLES = [\n 'progressbar',\n 'scrollbar',\n 'separator',\n 'alertdialog',\n 'navigation',\n 'application',\n 'radiogroup',\n 'tabpanel',\n 'textbox',\n 'combobox',\n 'checkbox',\n 'treeitem',\n 'menuitem',\n 'listitem',\n 'toolbar',\n 'tooltip',\n 'heading',\n 'spinbutton',\n 'article',\n 'button',\n 'dialog',\n 'figure',\n 'banner',\n 'region',\n 'search',\n 'status',\n 'switch',\n 'slider',\n 'option',\n 'select',\n 'meter',\n 'radio',\n 'table',\n 'timer',\n 'group',\n 'alert',\n 'grid',\n 'form',\n 'cell',\n 'link',\n 'list',\n 'menu',\n 'note',\n 'main',\n 'tree',\n 'tab',\n 'row',\n 'img',\n 'log',\n];\n\n/**\n * Parse an element description into a (name, role) pair.\n *\n * Supports two patterns:\n * - `\"<name> <role>\"` — e.g., `\"Customer No. combobox\"` → name=`\"Customer No.\"`, role=`\"combobox\"`\n * - `\"<role> <name>\"` — e.g., `\"button Save\"` → name=`\"Save\"`, role=`\"button\"`\n *\n * @returns { name, role } if a known role was found, or { name: description } with no role\n */\nfunction parseDescription(description: string): { name: string; role?: string } {\n const trimmed = description.trim();\n if (!trimmed) return { name: '' };\n\n const lower = trimmed.toLowerCase();\n\n // Try suffix match: \"<name> <role>\" (most common: \"Customer No. combobox\")\n for (const role of KNOWN_ROLES) {\n if (lower.endsWith(' ' + role)) {\n const name = trimmed.slice(0, -(role.length + 1)).trim();\n if (name) return { name, role };\n }\n }\n\n // Try prefix match: \"<role> <name>\" (e.g., \"button Save\")\n for (const role of KNOWN_ROLES) {\n if (lower.startsWith(role + ' ')) {\n const name = trimmed.slice(role.length + 1).trim();\n if (name) return { name, role };\n }\n }\n\n // No role extracted — treat entire string as the name\n return { name: trimmed };\n}\n\n/**\n * Find an element in the snapshot matching a text description.\n *\n * Used when the agent clicks by description only (no ref, no coordinates).\n * Searches all elements with refs and scores them by how well they match\n * the description's role and name.\n *\n * Returns the best match **only if it is unique** at the highest score.\n * Returns `null` if no match, ambiguous (multiple matches at same score),\n * or the description is empty.\n *\n * @param snapshotYaml - The YAML-like snapshot string\n * @param description - Element description like \"Customer No. combobox\"\n * @returns Element info if a unique match is found, null otherwise\n */\nexport function findElementByDescription(\n snapshotYaml: string,\n description: string\n): ElementInfo | null {\n if (!description?.trim()) return null;\n\n const { name, role } = parseDescription(description);\n if (!name) return null;\n\n const elements = extractAllElements(snapshotYaml);\n if (elements.length === 0) return null;\n\n const nameLower = name.toLowerCase();\n\n // Score each element\n const scored: Array<{ element: ElementInfo; score: number }> = [];\n\n for (const el of elements) {\n const elNameLower = (el.accessibleName ?? '').toLowerCase();\n const elRoleLower = (el.role ?? '').toLowerCase();\n\n let score = 0;\n\n if (role) {\n const roleMatches = elRoleLower === role;\n const nameExact = elNameLower === nameLower;\n const nameSubstring = elNameLower.includes(nameLower) || nameLower.includes(elNameLower);\n\n if (roleMatches && nameExact) {\n score = 100; // Exact role + name match\n } else if (roleMatches && nameSubstring && elNameLower.length > 0) {\n score = 80; // Role matches + name is substring\n }\n } else {\n // No role extracted — match on name only\n if (elNameLower === nameLower) {\n score = 60; // Name-only exact match\n } else if (elNameLower.includes(nameLower) || nameLower.includes(elNameLower)) {\n score = 50; // Name-only substring match\n } else {\n // Word-overlap: extract content words and check if any significant\n // description words appear in the element's accessible name.\n // Handles agent descriptions like \"'Camera' sensor type tile (camera icon)\"\n // matching element names like \"Camera Edge or RTSP video source\".\n const descWords = extractContentWords(nameLower);\n if (descWords.length > 0 && elNameLower.length > 0) {\n const elWords = new Set(extractContentWords(elNameLower));\n const matches = descWords.filter((w) => elWords.has(w));\n if (matches.length > 0) {\n score = 30 + Math.min(10, matches.length * 5); // 35-40 based on overlap\n }\n }\n }\n }\n\n if (score > 0) {\n scored.push({ element: el, score });\n }\n }\n\n if (scored.length === 0) return null;\n\n // Find highest score\n const maxScore = Math.max(...scored.map((s) => s.score));\n const topMatches = scored.filter((s) => s.score === maxScore);\n\n // Only return if the match is unique at the highest score level\n if (topMatches.length !== 1) return null;\n\n return topMatches[0].element;\n}\n\n/**\n * Common UI descriptor words that agents use but don't appear in accessible names.\n * Excluded from word-overlap matching to reduce false positives.\n */\nconst UI_DESCRIPTOR_WORDS = new Set([\n 'tile',\n 'icon',\n 'card',\n 'widget',\n 'panel',\n 'section',\n 'area',\n 'block',\n 'element',\n 'component',\n 'item',\n 'container',\n 'wrapper',\n 'field',\n 'input',\n 'type',\n 'sensor',\n 'option',\n 'entry',\n 'row',\n 'column',\n]);\n\n/**\n * Extract significant content words from a description or element name.\n * Strips quotes, parenthetical suffixes, and common UI descriptor words.\n * Returns lowercase words of 3+ characters.\n */\nfunction extractContentWords(text: string): string[] {\n // Strip parenthetical suffixes like \"(camera icon)\" and quoted segments like 'Camera'\n const cleaned = text\n .replace(/\\([^)]*\\)/g, ' ') // Remove parenthetical groups\n .replace(/['\"]/g, ' '); // Remove quotes\n return cleaned\n .split(/\\s+/)\n .map((w) => w.replace(/[^a-z0-9]/g, ''))\n .filter((w) => w.length >= 3 && !UI_DESCRIPTOR_WORDS.has(w));\n}\n\n/**\n * Check if a snapshot contains a specific ref.\n * Fast check without full parsing.\n * Handles both formats: [ref=e1] and [ref=e1 center=450,320]\n *\n * @param snapshotYaml - The YAML-like snapshot string\n * @param ref - The ref to check for\n * @returns true if ref exists in snapshot\n */\nexport function hasRef(snapshotYaml: string, ref: string): boolean {\n // Match [ref=X] or [ref=X center=...] format\n const pattern = new RegExp(`\\\\[ref=${ref}(?:\\\\s|\\\\])`);\n return pattern.test(snapshotYaml);\n}\n\n/**\n * Count the number of element refs in a snapshot.\n * Useful for diagnostics.\n * Handles both formats: [ref=e1] and [ref=e1 center=450,320]\n *\n * @param snapshotYaml - The YAML-like snapshot string\n * @returns Number of refs in the snapshot\n */\nexport function countRefs(snapshotYaml: string): number {\n // Match [ref=X] or [ref=X center=...] format\n const matches = snapshotYaml.match(/\\[ref=\\w+(?:\\s+center=\\d+,\\d+)?\\]/g);\n return matches?.length ?? 0;\n}\n","/**\n * Safe Playwright Locator Chain Parser\n *\n * Parses and evaluates Playwright locator chain strings authored by the\n * cache selector agent. Only allows a strict allowlist of Playwright\n * locator methods — no evaluate(), no arbitrary JS execution.\n *\n * @module workflows/cache/selector-agent/locator-parser\n * @see docs/api/services/workflow-action-cache.md\n */\n\nimport type { Page, Locator } from 'playwright';\nimport { createLogger } from './logger.js';\n\nlet _logger: ReturnType<typeof createLogger> | null = null;\nconst getLogger = () => {\n if (!_logger) {\n _logger = createLogger({ module: 'LocatorParser' });\n }\n return _logger;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Allowlisted Playwright methods\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Methods that can be called on Page to produce a Locator.\n */\nconst PAGE_METHODS = new Set([\n 'getByRole',\n 'getByText',\n 'getByLabel',\n 'getByTestId',\n 'getByPlaceholder',\n 'locator',\n]);\n\n/**\n * Methods that can be chained on a Locator to refine it.\n */\nconst LOCATOR_METHODS = new Set([\n 'getByRole',\n 'getByText',\n 'getByLabel',\n 'getByTestId',\n 'getByPlaceholder',\n 'filter',\n 'locator',\n 'nth',\n 'first',\n 'last',\n]);\n\n/**\n * A parsed method call in a locator chain.\n */\ninterface LocatorMethodCall {\n method: string;\n args: unknown[];\n}\n\nconst PRIVATE_USE_GLYPH_RE = /[\\uE000-\\uF8FF]/g;\nconst HAS_PRIVATE_USE_GLYPH_RE = /[\\uE000-\\uF8FF]/;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Variable Hydration\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Replace {{var.key}} placeholders with actual values from the variable registry.\n */\n/**\n * Escape a value for safe insertion into a single-quoted locator string context.\n * Backslashes and single quotes must be escaped to avoid breaking the locator syntax.\n */\nfunction escapeForLocatorString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\n/**\n * Replace {{var.key}} placeholders with actual values from the variable registry.\n * Values are escaped for the locator string context so that quotes and backslashes\n * in the variable value don't produce invalid locator syntax.\n */\nexport function hydrateLocatorVariables(\n locatorStr: string,\n variableValues: Record<string, string>\n): string {\n return locatorStr.replace(/\\{\\{var\\.([a-zA-Z0-9_]+)\\}\\}/g, (_match, key: string) => {\n const value = variableValues[key];\n if (value === undefined) {\n getLogger().warn('[LocatorParser] Variable placeholder not found in values', { key });\n return `{{var.${key}}}`;\n }\n return escapeForLocatorString(value);\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Locator String Parser\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Parse a Playwright locator chain string into a sequence of method calls.\n *\n * Handles strings like:\n * getByRole('row').filter({ hasText: 'Alpha' }).getByRole('button', { name: 'Edit' })\n * getByText('Submit')\n * locator('table').getByRole('row').nth(2)\n *\n * @throws Error if the string contains disallowed methods or is malformed\n */\nexport function parseLocatorChain(locatorStr: string): LocatorMethodCall[] {\n const calls: LocatorMethodCall[] = [];\n let remaining = locatorStr.trim();\n\n if (!remaining) {\n throw new Error('Empty locator string');\n }\n\n while (remaining.length > 0) {\n // Match method name\n const methodMatch = remaining.match(/^\\.?([a-zA-Z]+)\\s*\\(/);\n if (!methodMatch) {\n throw new Error(`Invalid locator syntax at: \"${remaining.slice(0, 50)}\"`);\n }\n\n const method = methodMatch[1];\n\n // Validate method is allowlisted\n const isFirstCall = calls.length === 0;\n const allowedSet = isFirstCall ? PAGE_METHODS : LOCATOR_METHODS;\n if (!allowedSet.has(method)) {\n throw new Error(`Disallowed method \"${method}\". Allowed: ${[...allowedSet].join(', ')}`);\n }\n\n // Find the matching closing paren, handling nested parens and strings\n const argsStart = methodMatch[0].length;\n remaining = remaining.slice(argsStart);\n const { args, rest } = extractArgs(remaining);\n\n calls.push({ method, args });\n remaining = rest.trim();\n\n // Handle .first() and .last() — no-arg chainable\n if (remaining.startsWith('.')) {\n const noArgMatch = remaining.match(/^\\.(first|last)\\b(?!\\s*\\()/);\n if (noArgMatch) {\n const noArgMethod = noArgMatch[1];\n if (!LOCATOR_METHODS.has(noArgMethod)) {\n throw new Error(`Disallowed method \"${noArgMethod}\"`);\n }\n calls.push({ method: noArgMethod, args: [] });\n remaining = remaining.slice(noArgMatch[0].length).trim();\n }\n }\n }\n\n if (calls.length === 0) {\n throw new Error('No valid method calls found in locator string');\n }\n\n return calls;\n}\n\n/**\n * Extract arguments from a parenthesized argument list.\n * Returns parsed args and the remaining string after the closing paren.\n */\nfunction extractArgs(input: string): { args: unknown[]; rest: string } {\n let depth = 1;\n let i = 0;\n let inString: \"'\" | '\"' | '`' | null = null;\n let escaped = false;\n\n while (i < input.length && depth > 0) {\n const ch = input[i];\n\n if (escaped) {\n escaped = false;\n i++;\n continue;\n }\n\n if (ch === '\\\\') {\n escaped = true;\n i++;\n continue;\n }\n\n if (inString) {\n if (ch === inString) {\n inString = null;\n }\n } else {\n if (ch === \"'\" || ch === '\"' || ch === '`') {\n inString = ch;\n } else if (ch === '(') {\n depth++;\n } else if (ch === ')') {\n depth--;\n if (depth === 0) break;\n }\n }\n\n i++;\n }\n\n if (depth !== 0) {\n throw new Error('Unmatched parenthesis in locator string');\n }\n\n const argsStr = input.slice(0, i).trim();\n const rest = input.slice(i + 1); // skip closing paren\n\n if (!argsStr) {\n return { args: [], rest };\n }\n\n // Parse the argument string as JSON-compatible values\n const args = parseArgsList(argsStr);\n return { args, rest };\n}\n\n/**\n * Parse a comma-separated argument list into JS values.\n * Handles: strings, numbers, booleans, objects (like { hasText: 'foo', name: 'bar' })\n */\nfunction parseArgsList(argsStr: string): unknown[] {\n const args: unknown[] = [];\n let remaining = argsStr.trim();\n\n while (remaining.length > 0) {\n remaining = remaining.trim();\n if (remaining.startsWith(',')) {\n remaining = remaining.slice(1).trim();\n }\n if (!remaining) break;\n\n if (remaining.startsWith('{')) {\n // Object argument\n const { value, rest } = parseObjectArg(remaining);\n args.push(value);\n remaining = rest;\n } else if (remaining.startsWith(\"'\") || remaining.startsWith('\"')) {\n // String argument\n const quote = remaining[0];\n let end = 1;\n while (end < remaining.length) {\n if (remaining[end] === '\\\\') {\n end += 2;\n continue;\n }\n if (remaining[end] === quote) break;\n end++;\n }\n const str = remaining.slice(1, end).replace(/\\\\'/g, \"'\").replace(/\\\\\"/g, '\"');\n args.push(str);\n remaining = remaining.slice(end + 1).trim();\n } else if (/^-?\\d/.test(remaining)) {\n // Number argument\n const numMatch = remaining.match(/^-?\\d+/);\n if (numMatch) {\n args.push(parseInt(numMatch[0], 10));\n remaining = remaining.slice(numMatch[0].length).trim();\n }\n } else if (remaining.startsWith('true')) {\n args.push(true);\n remaining = remaining.slice(4).trim();\n } else if (remaining.startsWith('false')) {\n args.push(false);\n remaining = remaining.slice(5).trim();\n } else if (remaining.startsWith('/')) {\n // RegExp argument — parse /pattern/flags\n const regexMatch = remaining.match(/^\\/([^/]+)\\/([gimsuy]*)/);\n if (regexMatch) {\n args.push(new RegExp(regexMatch[1], regexMatch[2]));\n remaining = remaining.slice(regexMatch[0].length).trim();\n } else {\n throw new Error(`Invalid argument at: \"${remaining.slice(0, 30)}\"`);\n }\n } else {\n throw new Error(`Invalid argument at: \"${remaining.slice(0, 30)}\"`);\n }\n }\n\n return args;\n}\n\n/**\n * Parse a JS-like object literal: { key: value, key2: value2 }\n */\nfunction parseObjectArg(input: string): { value: Record<string, unknown>; rest: string } {\n let depth = 1;\n let i = 1; // skip opening {\n let inString: \"'\" | '\"' | null = null;\n\n while (i < input.length && depth > 0) {\n const ch = input[i];\n if (inString) {\n if (ch === '\\\\') {\n i += 2;\n continue;\n }\n if (ch === inString) inString = null;\n } else {\n if (ch === \"'\" || ch === '\"') inString = ch;\n else if (ch === '{') depth++;\n else if (ch === '}') depth--;\n }\n if (depth > 0) i++;\n }\n\n const objStr = input.slice(1, i).trim();\n const rest = input.slice(i + 1);\n\n // Parse key-value pairs\n const obj: Record<string, unknown> = {};\n const pairs = splitObjectPairs(objStr);\n\n for (const pair of pairs) {\n const colonIdx = pair.indexOf(':');\n if (colonIdx === -1) continue;\n\n const key = pair\n .slice(0, colonIdx)\n .trim()\n .replace(/^['\"]|['\"]$/g, '');\n const rawValue = pair.slice(colonIdx + 1).trim();\n\n if (rawValue.startsWith(\"'\") || rawValue.startsWith('\"')) {\n const q = rawValue[0];\n let end = 1;\n while (end < rawValue.length && rawValue[end] !== q) {\n if (rawValue[end] === '\\\\') end++;\n end++;\n }\n obj[key] = rawValue.slice(1, end).replace(/\\\\'/g, \"'\").replace(/\\\\\"/g, '\"');\n } else if (rawValue.startsWith('/')) {\n const regexMatch = rawValue.match(/^\\/([^/]+)\\/([gimsuy]*)/);\n if (regexMatch) {\n obj[key] = new RegExp(regexMatch[1], regexMatch[2]);\n }\n } else if (rawValue === 'true') {\n obj[key] = true;\n } else if (rawValue === 'false') {\n obj[key] = false;\n } else if (/^-?\\d+$/.test(rawValue)) {\n obj[key] = parseInt(rawValue, 10);\n } else {\n obj[key] = rawValue;\n }\n }\n\n return { value: obj, rest };\n}\n\n/**\n * Split object key-value pairs by commas, respecting nested strings.\n */\nfunction splitObjectPairs(objStr: string): string[] {\n const pairs: string[] = [];\n let current = '';\n let inString: \"'\" | '\"' | null = null;\n\n for (let i = 0; i < objStr.length; i++) {\n const ch = objStr[i];\n if (inString) {\n if (ch === '\\\\') {\n current += ch + (objStr[i + 1] ?? '');\n i++;\n continue;\n }\n if (ch === inString) inString = null;\n } else {\n if (ch === \"'\" || ch === '\"') inString = ch;\n else if (ch === ',') {\n if (current.trim()) pairs.push(current.trim());\n current = '';\n continue;\n }\n }\n current += ch;\n }\n\n if (current.trim()) pairs.push(current.trim());\n return pairs;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Locator Chain Evaluator\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Evaluate a parsed locator chain against a Playwright Page, returning a Locator.\n *\n * @param page - Playwright Page to evaluate against\n * @param calls - Parsed method calls from parseLocatorChain()\n * @returns Playwright Locator\n */\nfunction evaluateLocatorCalls(page: Page, calls: LocatorMethodCall[]): Locator {\n if (calls.length === 0) {\n throw new Error('Empty locator chain');\n }\n\n // First call is on the Page\n const firstCall = calls[0];\n let locator = callMethod(page, firstCall.method, firstCall.args) as Locator;\n\n // Subsequent calls are on the Locator\n for (let i = 1; i < calls.length; i++) {\n locator = callMethod(locator, calls[i].method, calls[i].args) as Locator;\n }\n\n return locator;\n}\n\n/**\n * Parse, hydrate variables, and evaluate a locator chain string.\n * This is the main entry point for resolving agentic locators.\n *\n * @param page - Playwright Page\n * @param locatorStr - Raw locator chain string (may contain {{var.key}} placeholders)\n * @param variableValues - Variable values for placeholder hydration\n * @returns Playwright Locator\n */\nexport function evaluateLocatorChain(\n page: Page,\n locatorStr: string,\n variableValues?: Record<string, string>\n): Locator {\n const hydrated = variableValues\n ? hydrateLocatorVariables(locatorStr, variableValues)\n : locatorStr;\n const calls = parseLocatorChain(hydrated);\n return evaluateLocatorCalls(page, calls);\n}\n\n/**\n * Call a method on a Page or Locator with the given args.\n * Only allows methods from the allowlist.\n */\nfunction callMethod(target: Page | Locator, method: string, args: unknown[]): Locator {\n const fn = (target as unknown as Record<string, unknown>)[method];\n if (typeof fn !== 'function') {\n throw new Error(`Method \"${method}\" not found on target`);\n }\n return Reflect.apply(fn, target, normalizeLocatorArgsForIconGlyphs(method, args)) as Locator;\n}\n\nexport function normalizeLocatorArgsForIconGlyphs(method: string, args: unknown[]): unknown[] {\n if (method === 'getByRole') {\n const [role, options, ...rest] = args;\n if (!isRecord(options)) return args;\n return [\n role,\n {\n ...options,\n name: iconGlyphTolerantPattern(options.name),\n },\n ...rest,\n ];\n }\n\n if (method === 'filter') {\n const [options, ...rest] = args;\n if (!isRecord(options)) return args;\n return [\n {\n ...options,\n hasText: iconGlyphTolerantPattern(options.hasText),\n },\n ...rest,\n ];\n }\n\n if (method === 'getByText' || method === 'getByLabel') {\n const [text, ...rest] = args;\n return [iconGlyphTolerantPattern(text), ...rest];\n }\n\n return args;\n}\n\nfunction iconGlyphTolerantPattern(value: unknown): unknown {\n if (typeof value !== 'string' || !HAS_PRIVATE_USE_GLYPH_RE.test(value)) return value;\n\n const readable = value.replace(PRIVATE_USE_GLYPH_RE, ' ').replace(/\\s+/g, ' ').trim();\n if (!readable) return value;\n\n const tokens = readable.split(/\\s+/).map(escapeRegex);\n return new RegExp(tokens.join('[\\\\s\\\\uE000-\\\\uF8FF]+'), 'i');\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction escapeRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Strip `.filter({ ... })` clauses from a Playwright locator chain string.\n * Returns the stripped string, or null if no `.filter(` was found.\n *\n * Example:\n * \"getByRole('dialog').getByRole('combobox').filter({ hasText: 'foo' })\"\n * → \"getByRole('dialog').getByRole('combobox')\"\n */\nexport function stripFilterClauses(locatorStr: string): string | null {\n // Match .filter( followed by balanced parens\n const filterPattern = /\\.filter\\s*\\(/g;\n let match: RegExpExecArray | null;\n let result = locatorStr;\n let found = false;\n\n // Process from right to left to preserve indices\n const matches: { start: number; end: number }[] = [];\n while ((match = filterPattern.exec(locatorStr)) !== null) {\n // Find the matching closing paren\n const argsStart = match.index + match[0].length;\n let depth = 1;\n let i = argsStart;\n let inString: \"'\" | '\"' | '`' | null = null;\n let escaped = false;\n\n while (i < locatorStr.length && depth > 0) {\n const ch = locatorStr[i];\n if (escaped) {\n escaped = false;\n i++;\n continue;\n }\n if (ch === '\\\\') {\n escaped = true;\n i++;\n continue;\n }\n if (inString) {\n if (ch === inString) inString = null;\n } else {\n if (ch === \"'\" || ch === '\"' || ch === '`') inString = ch;\n else if (ch === '(') depth++;\n else if (ch === ')') {\n depth--;\n if (depth === 0) break;\n }\n }\n i++;\n }\n\n if (depth === 0) {\n matches.push({ start: match.index, end: i + 1 });\n found = true;\n }\n }\n\n if (!found) return null;\n\n // Remove matches from right to left\n for (let j = matches.length - 1; j >= 0; j--) {\n const { start, end } = matches[j];\n result = result.slice(0, start) + result.slice(end);\n }\n\n // Trim trailing dots\n result = result.replace(/\\.$/, '');\n\n return result || null;\n}\n\n/**\n * Validate that a locator string only uses allowed methods.\n * Returns true if valid, throws Error with details if not.\n */\nexport function validateLocatorString(locatorStr: string): boolean {\n parseLocatorChain(locatorStr); // throws on invalid\n return true;\n}\n","/**\n * Shared Element Resolver\n *\n * Extracts the element resolution logic used by both cache replay and recording\n * verification into a single shared module. This guarantees that recording\n * verification and replay use the exact same resolution algorithm — if a selector\n * verifies during recording, it will resolve identically during replay.\n *\n * @module workflows/cache/element-resolver\n * @see docs/api/services/workflow-action-cache.md\n */\n\nimport type { Page, Locator } from 'playwright';\nimport type { SelectorStrategy, SelectorAuthor } from '@chatsdet/types';\nimport { createLogger } from './logger.js';\nimport { evaluateLocatorChain, stripFilterClauses } from './locator-parser.js';\n\nlet _logger: ReturnType<typeof createLogger> | null = null;\nconst logger = () => {\n if (!_logger) {\n _logger = createLogger({ module: 'ElementResolver' });\n }\n return _logger;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Constants\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Short timeout for element resolution checks (5 seconds).\n * Cache replay should fail fast if elements aren't immediately available.\n */\nexport const RESOLVE_TIMEOUT_MS = 5000;\n\n/**\n * Longer timeout for visibility waits (15 seconds).\n * During multi-action cache replay, target apps may re-render between actions,\n * causing elements to be briefly hidden during React/framework re-renders.\n * This gives 3x more patience than RESOLVE_TIMEOUT_MS for transient render states.\n */\nconst VISIBILITY_TIMEOUT_MS = 15000;\n\n/**\n * Quick visibility check before the bounding-box escape hatch (2 seconds).\n * Most elements are visible immediately or within a few hundred ms. If Playwright\n * reports \"resolved to hidden\" within this window, we check for rendered dimensions\n * before committing to the full VISIBILITY_TIMEOUT_MS wait.\n */\nconst VISIBILITY_QUICK_CHECK_MS = 2000;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Locator context — either page or frame locator.\n * Used to support elements inside iframes.\n */\nexport type LocatorContext = Page | ReturnType<Page['frameLocator']>;\n\n/**\n * Resolution mode:\n * - 'replay': throws on failure (used during cache replay)\n * - 'verify': returns null on failure (used during recording verification)\n */\nexport type ResolveMode = 'replay' | 'verify';\n\n/**\n * Options for element resolution.\n */\n/**\n * Timing info reported by the onTiming callback during element resolution.\n */\nexport interface ElementResolutionTiming {\n /** Total time in resolveElement */\n totalMs: number;\n /** Time spent in verifyElementReady visibility wait */\n visibilityWaitMs: number;\n /** Time spent waiting for element position to stabilize (animations/transitions) */\n stabilityWaitMs: number;\n /** Which selector strategy resolved the element */\n selectorUsed: string;\n /**\n * Locator author that resolved the element, derived from the strategy label.\n * 'agentic' for the selector-agent-authored Playwright locator (and its\n * filter-stripped fallback); 'deterministic' for role/testId/label/text/css.\n */\n selectorAuthor: SelectorAuthor;\n}\n\n/**\n * Classify a resolver strategy label into its locator author. The agentic\n * Playwright locator is always tagged `(agentic)`; its filter-stripped fallback\n * derives from the same author. Everything else (testId/role/label/text/css and\n * the explicit `candidate (deterministic)`) is deterministic.\n */\nexport function classifySelectorAuthor(selectorName: string): SelectorAuthor {\n return /\\(agentic\\)/.test(selectorName) || selectorName.includes('filter-stripped')\n ? 'agentic'\n : 'deterministic';\n}\n\nexport interface ResolveElementOptions {\n /**\n * Resolution mode. Defaults to 'replay'.\n */\n mode?: ResolveMode;\n /**\n * When true, validates that the resolved element is a select/combobox.\n * Falls back to finding select elements near matching text if needed.\n */\n requireSelectElement?: boolean;\n /**\n * Variable values for structural fallback when hydrated selectors fail.\n * Used with dynamicText annotation for a last-resort role+hasText lookup.\n */\n variableValues?: Record<string, string>;\n /**\n * Optional callback reporting timing breakdown after element resolution.\n * Called once when an element is successfully resolved, before returning.\n */\n onTiming?: (timing: ElementResolutionTiming) => void;\n /**\n * The type of action being resolved (e.g. 'click', 'type').\n * When set to 'click', text disambiguation will prefer interactive elements\n * (combobox, button, link, etc.) over labels/static text.\n */\n actionType?: string;\n /**\n * When true, disables fallback heuristics that could produce false-positive matches:\n * multi-match `.first()`, filter stripping, positional index trust, bounding-box\n * escape hatch, and fallback to weaker selectors when playwrightLocator fails.\n * @see docs/api/services/strict-cache-replay.md\n */\n strictMode?: boolean;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Data attribute extraction for disambiguation\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface DisambiguationAttrs {\n itemIndex: number;\n rowIndex: number;\n automationId: string | null;\n}\n\n/**\n * Batch-extract disambiguation attrs for all matched elements in a single\n * round-trip using evaluateAll(). Returns up to `limit` results.\n *\n * The aria-rowindex walk checks the element itself then walks up to 10\n * ancestors — many grid UIs (BC Dynamics) put `aria-rowindex` on the\n * `<tr>` parent rather than the cell/input.\n */\nconst extractDisambiguationAttrsBatch = (\n locator: Locator,\n limit: number\n): Promise<DisambiguationAttrs[]> =>\n locator.evaluateAll((elements, max) => {\n const getRowIndex = (node: Element): number => {\n let c: Element | null = node;\n let depth = 0;\n while (c && depth < 10) {\n const ri = c.getAttribute('aria-rowindex');\n if (ri) return parseInt(ri, 10);\n c = c.parentElement;\n depth++;\n }\n return NaN;\n };\n\n return elements.slice(0, max).map((el) => ({\n itemIndex: parseInt(\n el.getAttribute('data-item-index') ?? el.getAttribute('data-selection-index') ?? '',\n 10\n ),\n rowIndex: getRowIndex(el),\n automationId: el.getAttribute('data-automationid'),\n }));\n }, Math.min(limit, 10));\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dialog-scoped filtering for modal disambiguation\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * When multiple elements match and a visible dialog/modal is open, filter\n * to elements inside the dialog. This prevents sidebar/background elements\n * from being selected when a modal field with the same label is the target.\n *\n * Returns a narrowed locator + count if dialog scoping helped, or null if\n * no visible dialog was found or scoping didn't reduce matches.\n */\nconst filterToVisibleDialog = async (\n page: Page,\n candidateLocator: Locator,\n currentCount: number\n): Promise<{ locator: Locator; count: number } | null> => {\n try {\n // Find visible dialog elements — matches the same roles that discoverParentContext\n // captures at recording time (SEMANTIC_ROLES includes 'dialog' and 'alertdialog')\n const dialogLocator = page.locator(\n '[role=\"dialog\"]:visible, [role=\"alertdialog\"]:visible, dialog[open]'\n );\n const dialogCount = await Promise.race([\n dialogLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Dialog check timed out')), 2000)\n ),\n ]);\n\n if (dialogCount === 0) return null;\n\n // Use the first visible dialog as the scoping container\n const dialog = dialogLocator.first();\n const scopedLocator = dialog.locator(candidateLocator);\n const scopedCount = await Promise.race([\n scopedLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Dialog scoped count timed out')), 2000)\n ),\n ]);\n\n // Only useful if we narrowed the set\n if (scopedCount > 0 && scopedCount < currentCount) {\n logger().debug('[ElementResolver] Dialog scoping narrowed matches', {\n originalCount: currentCount,\n scopedCount,\n });\n return { locator: scopedLocator, count: scopedCount };\n }\n\n return null;\n } catch {\n return null;\n }\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Role compatibility for text fallback validation\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Map of expected roles to compatible actual roles.\n * Used to validate text-fallback matches when the primary role selector failed.\n * Handles common patterns like Dynamics 365 combobox exposing as textbox.\n * Unmapped roles are permissive (no validation applied).\n */\nconst COMPATIBLE_ROLES: Record<string, Set<string>> = {\n combobox: new Set(['combobox', 'textbox', 'searchbox', 'listbox']),\n textbox: new Set(['textbox', 'combobox', 'searchbox']),\n searchbox: new Set(['searchbox', 'textbox', 'combobox']),\n listbox: new Set(['listbox', 'combobox']),\n button: new Set(['button', 'menuitem', 'link', 'tab']),\n link: new Set(['link', 'button']),\n checkbox: new Set(['checkbox', 'switch']),\n switch: new Set(['switch', 'checkbox']),\n};\n\n/**\n * Implicit ARIA role mapping for common HTML tags.\n */\nconst TAG_TO_IMPLICIT_ROLE: Record<string, string> = {\n input: 'textbox',\n textarea: 'textbox',\n select: 'listbox',\n button: 'button',\n a: 'link',\n};\n\n/**\n * Roles considered interactive for click-action disambiguation.\n * When text fallback matches multiple elements and the action is a click,\n * we prefer elements with these roles over labels/static text.\n */\nconst INTERACTIVE_ROLES = new Set([\n 'button',\n 'link',\n 'combobox',\n 'menuitem',\n 'checkbox',\n 'switch',\n 'tab',\n 'textbox',\n 'searchbox',\n 'option',\n 'menuitemcheckbox',\n 'menuitemradio',\n 'radio',\n 'spinbutton',\n]);\n\n/**\n * Interactive HTML tags (implicit interactive role via tag name).\n */\nconst INTERACTIVE_TAGS = new Set(['button', 'a', 'input', 'select', 'textarea']);\n\n/**\n * Check whether an element has an interactive role (explicit or implicit).\n * Used during text disambiguation to prefer clickable elements over labels.\n */\nexport const isInteractiveElement = async (locator: Locator): Promise<boolean> => {\n try {\n const { role, tag } = await locator.evaluate((el) => ({\n role: el.getAttribute('role'),\n tag: el.tagName.toLowerCase(),\n }));\n if (role && INTERACTIVE_ROLES.has(role)) return true;\n if (INTERACTIVE_TAGS.has(tag)) return true;\n const implicitRole = TAG_TO_IMPLICIT_ROLE[tag];\n if (implicitRole && INTERACTIVE_ROLES.has(implicitRole)) return true;\n return false;\n } catch {\n return false;\n }\n};\n\n/**\n * Roles considered typeable for type-action disambiguation.\n * When text fallback matches multiple elements and the action is a type,\n * we prefer elements with these roles over labels/static text.\n */\nconst TYPEABLE_ROLES = new Set(['textbox', 'searchbox', 'spinbutton', 'combobox']);\nconst TYPEABLE_TAGS = new Set(['input', 'textarea', 'select']);\n\n/**\n * Check whether an element is typeable (can receive keyboard input).\n * Used during text disambiguation to prefer input fields over labels for type actions.\n */\nconst isTypeableElement = async (locator: Locator): Promise<boolean> => {\n try {\n const { role, tag, contentEditable } = await locator.evaluate((el) => ({\n role: el.getAttribute('role'),\n tag: el.tagName.toLowerCase(),\n contentEditable: (el as HTMLElement).isContentEditable,\n }));\n if (contentEditable) return true;\n if (role && TYPEABLE_ROLES.has(role)) return true;\n if (TYPEABLE_TAGS.has(tag)) return true;\n return false;\n } catch {\n return false;\n }\n};\n\n/**\n * Check whether a resolved element's actual role is compatible with the expected role.\n *\n * - Returns `true` if the element has a compatible role (explicit or implicit).\n * - Returns `false` if the element has no discernible role (generic div/span).\n * - Returns `true` for unmapped expected roles (permissive — no validation).\n * - Returns `true` on evaluation errors (fail-open to avoid false rejections).\n */\nexport const isRoleCompatible = async (\n locator: Locator,\n expectedRole: string\n): Promise<boolean> => {\n const compatibleSet = COMPATIBLE_ROLES[expectedRole];\n if (!compatibleSet) {\n // Unmapped role — no validation, allow through\n return true;\n }\n\n try {\n const { role, tag } = await locator.evaluate((el) => ({\n role: el.getAttribute('role'),\n tag: el.tagName.toLowerCase(),\n }));\n\n const actualRole = role ?? TAG_TO_IMPLICIT_ROLE[tag];\n\n if (!actualRole) {\n // No discernible role (generic div/span) — reject\n return false;\n }\n\n return compatibleSet.has(actualRole);\n } catch {\n // Evaluation failed — fail-open\n return true;\n }\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Text normalization helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Normalize text used for selector matching.\n * Strips private use glyphs, normalizes whitespace.\n */\nexport const normalizeMatchText = (value: string): string => {\n return value\n .replace(/[\\uE000-\\uF8FF]/g, '')\n .replace(/\\u00a0/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n};\n\n/**\n * Extract the primary text from a concatenated accessible name.\n * E.g., \"Sales Quotes Lists Not bookmarked\" -> \"Sales Quotes\"\n *\n * Common patterns in concatenated names:\n * - \"Primary Text Lists/Reports/etc\"\n * - \"Primary Text Not bookmarked/Bookmarked\"\n */\nexport const extractPrimaryText = (fullText: string): string | null => {\n if (!fullText) return null;\n\n const normalized = normalizeMatchText(fullText);\n if (!normalized) return null;\n\n // Common suffixes that indicate concatenated text\n const suffixPatterns = [\n /\\s+(Lists?|Reports?|Tasks?|Pages?|Archive)\\b.*$/i,\n /\\s+Not bookmarked$/i,\n /\\s+Bookmarked$/i,\n /\\s+-\\s+Microsoft.*$/i,\n ];\n\n let primaryText = normalized;\n for (const pattern of suffixPatterns) {\n primaryText = primaryText.replace(pattern, '');\n }\n\n // Only return if we actually shortened it and have something meaningful left\n if (primaryText !== normalized && primaryText.trim().length >= 3) {\n return primaryText.trim();\n }\n\n return null;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Element helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Find the first visible element from a locator that matches multiple elements.\n * Returns the locator for the first visible element, or null if none are visible.\n */\nexport const findFirstVisibleElement = async (\n locator: Locator,\n count: number,\n timeoutMs: number = RESOLVE_TIMEOUT_MS\n): Promise<Locator | null> => {\n const limit = Math.min(count, 10);\n\n // Check all candidates in parallel instead of sequentially\n const results = await Promise.all(\n Array.from({ length: limit }, (_, i) => {\n const nth = locator.nth(i);\n return Promise.race([\n nth.isVisible(),\n new Promise<boolean>((_, reject) =>\n setTimeout(() => reject(new Error('Visibility check timed out')), timeoutMs)\n ),\n ]).catch(() => false);\n })\n );\n\n const firstVisibleIndex = results.indexOf(true);\n if (firstVisibleIndex >= 0) {\n logger().debug('[ElementResolver] Found visible element at index', { index: firstVisibleIndex });\n return locator.nth(firstVisibleIndex);\n }\n return null;\n};\n\n/**\n * Bounding-box escape hatch: check if an element has real rendered dimensions\n * despite Playwright reporting it as \"hidden\". Returns true if the element\n * should be accepted as usable, false otherwise.\n *\n * This handles CSS edge cases (ancestor opacity:0 during transitions,\n * visibility:hidden overridden by child, clip-path, transparent overlays)\n * where the element is visually present and interactable.\n */\nconst checkBoundingBoxEscapeHatch = async (\n locator: Locator,\n selectorDesc: string\n): Promise<boolean> => {\n try {\n const diagnostics = await locator.evaluate((el) => {\n const cs = window.getComputedStyle(el);\n const r = el.getBoundingClientRect();\n const ancestors: Array<{\n tag: string;\n role: string | null;\n vis: string;\n disp: string;\n opa: string;\n h: number;\n }> = [];\n let parent = el.parentElement;\n while (parent && ancestors.length < 10) {\n const pcs = window.getComputedStyle(parent);\n const pr = parent.getBoundingClientRect();\n if (\n pcs.visibility === 'hidden' ||\n pcs.display === 'none' ||\n pcs.opacity === '0' ||\n pr.height === 0\n ) {\n ancestors.push({\n tag: parent.tagName,\n role: parent.getAttribute('role'),\n vis: pcs.visibility,\n disp: pcs.display,\n opa: pcs.opacity,\n h: Math.round(pr.height),\n });\n }\n parent = parent.parentElement;\n }\n return {\n visibility: cs.visibility,\n display: cs.display,\n opacity: cs.opacity,\n width: Math.round(r.width),\n height: Math.round(r.height),\n hiddenAncestors: ancestors,\n };\n });\n\n if (diagnostics.width > 0 && diagnostics.height > 0 && diagnostics.display !== 'none') {\n logger().warn(\n '[ElementResolver] Element reported hidden but has rendered dimensions, accepting',\n {\n selectorDesc,\n width: diagnostics.width,\n height: diagnostics.height,\n visibility: diagnostics.visibility,\n opacity: diagnostics.opacity,\n hiddenAncestorCount: diagnostics.hiddenAncestors.length,\n }\n );\n return true;\n }\n\n logger().warn('[ElementResolver] Element hidden diagnostics', {\n selectorDesc,\n diagnostics,\n });\n return false;\n } catch {\n // Element may have been detached — best-effort\n return false;\n }\n};\n\n/** Helper: returns true when the error message indicates the element was found but hidden */\nconst isResolvedToHidden = (message: string): boolean =>\n message.includes('resolved to hidden') || message.includes('not visible');\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Position Stability\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Maximum time to wait for an element's position to stabilize */\nconst STABILITY_MAX_WAIT_MS = 1000;\n/** Threshold in pixels — movement below this is considered stable */\nconst STABILITY_THRESHOLD_PX = 1;\n\n/**\n * Wait until an element's bounding box stops moving.\n *\n * Catches CSS animations/transitions completing on dropdown menus, popovers,\n * and slide-in panels. Uses a single in-browser rAF loop instead of polling\n * via CDP round-trips (~20 round-trips → 1).\n *\n * @returns milliseconds spent waiting for stability\n */\nconst waitForPositionStability = async (\n locator: Locator,\n selectorDesc: string\n): Promise<number> => {\n const startMs = Date.now();\n try {\n const result = await locator.evaluate(\n (el, { maxWaitMs, thresholdPx }) => {\n return new Promise<{ elapsed: number; stable: boolean }>((resolve) => {\n const start = performance.now();\n let prevRect = el.getBoundingClientRect();\n // Require 3 consecutive stable frames (~48ms at 60fps) to match\n // the spirit of the old 50ms polling interval and avoid false\n // positives from easing curves that briefly plateau.\n let stableFrames = 0;\n const REQUIRED_STABLE_FRAMES = 3;\n\n const check = () => {\n const elapsed = performance.now() - start;\n if (elapsed >= maxWaitMs) {\n resolve({ elapsed: Math.round(elapsed), stable: false });\n return;\n }\n\n const currRect = el.getBoundingClientRect();\n const dx = Math.abs(currRect.x - prevRect.x);\n const dy = Math.abs(currRect.y - prevRect.y);\n const dw = Math.abs(currRect.width - prevRect.width);\n const dh = Math.abs(currRect.height - prevRect.height);\n\n if (\n dx <= thresholdPx &&\n dy <= thresholdPx &&\n dw <= thresholdPx &&\n dh <= thresholdPx\n ) {\n stableFrames++;\n if (stableFrames >= REQUIRED_STABLE_FRAMES) {\n resolve({ elapsed: Math.round(elapsed), stable: true });\n return;\n }\n } else {\n stableFrames = 0;\n }\n\n prevRect = currRect;\n requestAnimationFrame(check);\n };\n\n // Wait one frame before first comparison\n requestAnimationFrame(check);\n });\n },\n { maxWaitMs: STABILITY_MAX_WAIT_MS, thresholdPx: STABILITY_THRESHOLD_PX }\n );\n\n const elapsed = Date.now() - startMs;\n if (!result.stable) {\n logger().warn('[ElementResolver] Element position did not stabilize within timeout', {\n selectorDesc,\n stabilityWaitMs: elapsed,\n });\n } else if (result.elapsed > 60) {\n logger().debug('[ElementResolver] Element position stabilized', {\n selectorDesc,\n stabilityWaitMs: elapsed,\n });\n }\n return elapsed;\n } catch {\n // Element detached or navigated away — not worth blocking\n return Date.now() - startMs;\n }\n};\n\n/**\n * Verify an element is visible and attached to DOM before returning.\n *\n * Uses a two-phase approach:\n * 1. Quick visibility check (2s) — catches most elements that are immediately visible.\n * 2. If the element was found but Playwright reports \"hidden\", run a bounding-box\n * escape hatch — if the element has real rendered dimensions it's accepted\n * immediately (~2s total instead of 15s).\n * 3. If the escape hatch doesn't apply (element genuinely has no dimensions),\n * wait the remaining time for it to become visible (covers React re-renders,\n * lazy-loaded content, CSS transitions that are legitimately completing).\n *\n * @param locator - The element locator\n * @param selectorDesc - Description of the selector for error messages\n * @param strict - If true (default), throws on timeout. If false, only logs warning.\n */\nexport const verifyElementReady = async (\n locator: Locator,\n selectorDesc: string,\n strict = true,\n onStabilityWait?: (ms: number) => void,\n strictMode = false\n): Promise<boolean> => {\n /** Wait for position stability and report timing before returning ready */\n const stableReturn = async (): Promise<true> => {\n const ms = await waitForPositionStability(locator, selectorDesc);\n onStabilityWait?.(ms);\n return true;\n };\n\n // ── Phase 1: Quick visibility check ──\n try {\n await locator.waitFor({ state: 'visible', timeout: VISIBILITY_QUICK_CHECK_MS });\n return stableReturn();\n } catch (quickErr) {\n const quickMsg = quickErr instanceof Error ? quickErr.message : String(quickErr);\n\n // Element exists but Playwright says \"hidden\" — try bounding-box escape hatch\n // before committing to a long wait.\n // V13: In strict mode, skip the escape hatch — trust Playwright's visibility check.\n if (isResolvedToHidden(quickMsg)) {\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] Skipping bounding-box escape hatch', {\n strictMode: true,\n rejection: 'escape_hatch_skipped',\n selectorDesc,\n });\n } else if (await checkBoundingBoxEscapeHatch(locator, selectorDesc)) {\n return stableReturn();\n }\n // Element genuinely has no rendered dimensions — fall through to extended wait\n logger().debug(\n '[ElementResolver] Element hidden with no dimensions after quick check, continuing wait',\n {\n selectorDesc,\n }\n );\n }\n }\n\n // ── Phase 2: Extended wait for elements that need more time to appear ──\n // Covers: elements hidden during React/framework re-renders, lazy-loaded content, etc.\n try {\n const remainingMs = Math.max(VISIBILITY_TIMEOUT_MS - VISIBILITY_QUICK_CHECK_MS, 1000);\n await locator.waitFor({ state: 'visible', timeout: remainingMs });\n return stableReturn();\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n\n // Final escape hatch — element may have appeared during the wait but\n // still reports \"hidden\" due to CSS issues.\n // V13: In strict mode, skip the escape hatch.\n if (isResolvedToHidden(message)) {\n if (!strictMode && await checkBoundingBoxEscapeHatch(locator, selectorDesc)) {\n return stableReturn();\n }\n }\n\n if (strict) {\n throw new Error(`Element not ready (${selectorDesc}): ${message}`);\n }\n logger().debug('[ElementResolver] Element visibility check failed (non-strict)', {\n selectorDesc,\n error: message,\n });\n return false;\n }\n};\n\n/**\n * Validate that a locator points to a select element.\n * Returns true if it's a select/combobox, false otherwise.\n */\nexport const isSelectElement = async (locator: Locator): Promise<boolean> => {\n try {\n const { tagName, role } = await locator.evaluate((el) => ({\n tagName: el.tagName.toLowerCase(),\n role: el.getAttribute('role'),\n }));\n return tagName === 'select' || role === 'combobox' || role === 'listbox';\n } catch {\n return false;\n }\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Frame locator helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Get all frame locators from a page for searching within iframes.\n * Uses specific selectors to avoid strict mode violations when multiple iframes exist.\n */\nexport const getFrameLocators = (\n page: Page\n): Array<{ name: string; locator: ReturnType<Page['frameLocator']> }> => {\n return [\n { name: 'iframe:main', locator: page.frameLocator('iframe.designer-client-frame') },\n { name: 'iframe:first', locator: page.frameLocator('iframe').first() },\n { name: 'iframe:nth(0)', locator: page.frameLocator('iframe').nth(0) },\n { name: 'iframe:nth(1)', locator: page.frameLocator('iframe').nth(1) },\n ];\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Lightweight resolution (for overlay checking)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Lightweight element resolution for overlay checking (no verification).\n * Only tries fast selector strategies to minimize overhead.\n */\nexport const resolveElementForCheck = async (\n page: Page,\n selectors: SelectorStrategy\n): Promise<Locator | null> => {\n try {\n if (selectors.testId) {\n const loc = page.getByTestId(selectors.testId);\n if ((await loc.count()) > 0) return loc.first();\n }\n if (selectors.role) {\n const loc = page.getByRole(\n selectors.role.role as Parameters<Page['getByRole']>[0],\n selectors.role.name ? { name: selectors.role.name } : undefined\n );\n if ((await loc.count()) > 0) return loc.first();\n }\n } catch {\n // Ignore errors - this is best-effort\n }\n return null;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Parent-scoped context helper\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Build a list of parent-scoped search contexts for a given page/frame context.\n * When parentContext is available, returns scoped contexts first (role chain, CSS),\n * then the unscoped context as a final fallback. This ensures text/label selectors\n * resolve within the correct container (e.g., dialog) before searching the full page.\n */\ntype ParentContextChainNode = {\n role: string;\n name?: string;\n css?: string;\n nameFromHeading?: boolean;\n containsText?: string;\n};\n\ntype ParentContextInput = {\n role?: string;\n name?: string;\n css?: string;\n nameFromHeading?: boolean;\n containsText?: string;\n parentChain?: ParentContextChainNode[];\n};\n\nfunction getParentScopedContexts(\n context: LocatorContext,\n parentContext: ParentContextInput | undefined\n): Array<{ searchCtx: LocatorContext | Locator; scopeLabel: string }> {\n if (!parentContext) return [{ searchCtx: context, scopeLabel: '' }];\n\n const result: Array<{ searchCtx: LocatorContext | Locator; scopeLabel: string }> = [];\n\n if (parentContext.parentChain?.length) {\n let parent: Locator | undefined;\n for (const ancestor of [...parentContext.parentChain].reverse()) {\n let ancestorLocator: Locator =\n ancestor.nameFromHeading && ancestor.name\n ? context\n .getByRole(ancestor.role as Parameters<Page['getByRole']>[0])\n .filter({ has: context.getByRole('heading', { name: ancestor.name }) })\n : context.getByRole(\n ancestor.role as Parameters<Page['getByRole']>[0],\n ancestor.name ? { name: ancestor.name } : undefined\n );\n if (ancestor.containsText) {\n ancestorLocator = ancestorLocator.filter({ hasText: ancestor.containsText });\n }\n parent = parent ? parent.locator(ancestorLocator) : ancestorLocator;\n }\n if (parent) result.push({ searchCtx: parent, scopeLabel: ` [parent-chain]` });\n } else if (parentContext.role) {\n let parentLocator: Locator =\n parentContext.nameFromHeading && parentContext.name\n ? context\n .getByRole(parentContext.role as Parameters<Page['getByRole']>[0])\n .filter({ has: context.getByRole('heading', { name: parentContext.name }) })\n : context.getByRole(\n parentContext.role as Parameters<Page['getByRole']>[0],\n parentContext.name ? { name: parentContext.name } : undefined\n );\n if (parentContext.containsText) {\n parentLocator = parentLocator.filter({ hasText: parentContext.containsText });\n }\n const label = parentContext.containsText\n ? ` [parent:${parentContext.role}~\"${parentContext.containsText}\"]`\n : ` [parent:${parentContext.role}]`;\n result.push({ searchCtx: parentLocator, scopeLabel: label });\n }\n\n if (parentContext.css) {\n result.push({ searchCtx: context.locator(parentContext.css), scopeLabel: ` [parent-css]` });\n }\n\n // Always include unscoped as final fallback\n result.push({ searchCtx: context, scopeLabel: '' });\n\n return result;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Role selector resolution\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Try to find an element using role selector within a context (page or frame).\n * Returns the locator if found, null otherwise.\n *\n * Attempts in order:\n * 1. Full name with parent context\n * 2. Full name without parent context\n * 3. Partial/primary text extracted from name (for concatenated accessible names)\n */\nexport const tryRoleSelector = async (\n context: LocatorContext,\n selectors: SelectorStrategy,\n contextName: string,\n strictMode = false\n): Promise<{ locator: Locator; selectorDesc: string } | null> => {\n if (!selectors.role) return null;\n\n const { role, name, exact } = selectors.role;\n const normalizedName = name ? normalizeMatchText(name) : undefined;\n const textFilterRoles = new Set([\n 'row',\n 'listitem',\n 'option',\n 'menuitem',\n 'treeitem',\n 'gridcell',\n 'article',\n ]);\n const normalizedContainsText = selectors.containsText?.map((part) => normalizeMatchText(part));\n const containsTextFallback =\n !normalizedContainsText && role && textFilterRoles.has(role) && normalizedName\n ? [normalizedName]\n : undefined;\n const activeContainsText = normalizedContainsText ?? containsTextFallback;\n\n const applyContainsText = (locator: Locator): Locator => {\n if (!activeContainsText || activeContainsText.length === 0) return locator;\n let filtered = locator;\n for (const part of activeContainsText) {\n if (!part) continue;\n filtered = filtered.filter({ hasText: part });\n }\n return filtered;\n };\n\n /**\n * Helper to try a specific name value and return locator if found.\n */\n const tryWithName = async (\n searchName: string | undefined,\n variant: string\n ): Promise<{ locator: Locator; selectorDesc: string } | null> => {\n const locatorOpts = searchName ? { name: searchName, exact: exact ?? false } : undefined;\n const baseLocator = context.getByRole(role as Parameters<Page['getByRole']>[0], locatorOpts);\n const locator = applyContainsText(baseLocator);\n\n // Build candidate locator scopes in precedence order:\n // 1) parent role/chain (if present)\n // 2) parent CSS (if present)\n // 3) no parent fallback\n const candidates: Array<{ scopedLocator: Locator; suffix: string }> = [];\n const hasParentScope = !!(\n selectors.parentContext?.parentChain?.length ||\n selectors.parentContext?.role ||\n selectors.parentContext?.css\n );\n\n if (selectors.parentContext?.parentChain?.length) {\n let parentScoped = locator;\n for (const ancestor of [...selectors.parentContext.parentChain].reverse()) {\n let parentLocator: Locator;\n if (ancestor.nameFromHeading && ancestor.name) {\n parentLocator = context\n .getByRole(ancestor.role as Parameters<Page['getByRole']>[0])\n .filter({ has: context.getByRole('heading', { name: ancestor.name }) });\n } else {\n parentLocator = context.getByRole(\n ancestor.role as Parameters<Page['getByRole']>[0],\n ancestor.name ? { name: ancestor.name } : undefined\n );\n }\n if (ancestor.containsText) {\n parentLocator = parentLocator.filter({ hasText: ancestor.containsText });\n }\n parentScoped = parentLocator.locator(parentScoped);\n }\n candidates.push({ scopedLocator: parentScoped, suffix: '' });\n } else if (selectors.parentContext?.role) {\n let parentLocator: Locator;\n if (selectors.parentContext.nameFromHeading && selectors.parentContext.name) {\n parentLocator = context\n .getByRole(selectors.parentContext.role as Parameters<Page['getByRole']>[0])\n .filter({ has: context.getByRole('heading', { name: selectors.parentContext.name }) });\n } else {\n parentLocator = context.getByRole(\n selectors.parentContext.role as Parameters<Page['getByRole']>[0],\n selectors.parentContext.name ? { name: selectors.parentContext.name } : undefined\n );\n }\n if (selectors.parentContext.containsText) {\n parentLocator = parentLocator.filter({ hasText: selectors.parentContext.containsText });\n }\n candidates.push({ scopedLocator: parentLocator.locator(locator), suffix: '' });\n }\n\n if (selectors.parentContext?.css) {\n const cssParentLocator = context.locator(selectors.parentContext.css);\n candidates.push({\n scopedLocator: cssParentLocator.locator(locator),\n suffix: ' - css parent',\n });\n }\n\n if (hasParentScope) {\n candidates.push({ scopedLocator: locator, suffix: ' - no parent' });\n } else {\n candidates.push({ scopedLocator: locator, suffix: '' });\n }\n\n // Check element count with timeout protection\n try {\n for (const candidate of candidates) {\n const count = await Promise.race([\n candidate.scopedLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Count check timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n\n if (count === 0) {\n continue;\n }\n\n const selectorDesc = `Role selector (${role}: \"${searchName ?? ''}\"${candidate.suffix}${variant ? ` ${variant}` : ''}${contextName ? ` in ${contextName}` : ''})`;\n\n if (count === 1) {\n return { locator: candidate.scopedLocator.first(), selectorDesc };\n }\n\n // Multiple matches - try disambiguation strategies\n logger().debug('[ElementResolver] Multiple role matches, trying disambiguation', {\n role,\n name: searchName,\n count,\n context: contextName,\n hasItemIndex: selectors.itemIndex !== undefined,\n hasRowIndex: selectors.rowIndex !== undefined,\n hasMatchIndex: selectors.parentContext?.matchIndex !== undefined,\n });\n\n // Strategy 1: Try data attribute matching (most deterministic)\n if (\n selectors.itemIndex !== undefined ||\n selectors.rowIndex !== undefined ||\n selectors.automationId\n ) {\n try {\n const allAttrs = await extractDisambiguationAttrsBatch(candidate.scopedLocator, count);\n for (let i = 0; i < allAttrs.length; i++) {\n const attrs = allAttrs[i];\n const matches =\n (selectors.itemIndex !== undefined && attrs.itemIndex === selectors.itemIndex) ||\n (selectors.rowIndex !== undefined && attrs.rowIndex === selectors.rowIndex) ||\n (selectors.automationId && attrs.automationId === selectors.automationId);\n\n if (matches) {\n logger().debug('[ElementResolver] Found element by data attributes', {\n index: i,\n attrs,\n });\n return {\n locator: candidate.scopedLocator.nth(i),\n selectorDesc: `${selectorDesc} [data-attr]`,\n };\n }\n }\n } catch {\n // Fall through to next strategy\n }\n }\n\n // Strategy 2: Use matchIndex fallback\n if (selectors.parentContext?.matchIndex !== undefined) {\n const matchIndex = selectors.parentContext.matchIndex;\n if (matchIndex < count) {\n const indexed = candidate.scopedLocator.nth(matchIndex);\n\n // Verify with text content if available\n if (selectors.containsText?.length) {\n try {\n const text = await indexed.textContent();\n const hasExpectedText = selectors.containsText.every((t) => text?.includes(t));\n if (hasExpectedText) {\n logger().debug(\n '[ElementResolver] Found element by matchIndex with text verification',\n {\n matchIndex,\n }\n );\n return {\n locator: indexed,\n selectorDesc: `${selectorDesc} [index:${matchIndex}]`,\n };\n }\n } catch {\n // V4: In strict mode, if text verification fails, don't trust the index\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] matchIndex text verification failed, rejecting', {\n strictMode: true,\n rejection: 'index_fallback',\n matchIndex,\n role,\n name: searchName,\n });\n return null;\n }\n // Fall through to use index anyway\n }\n }\n\n // V4: In strict mode, don't trust bare positional index without text verification\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] Rejecting matchIndex without text verification', {\n strictMode: true,\n rejection: 'index_fallback',\n matchIndex,\n role,\n name: searchName,\n count,\n });\n return null;\n }\n\n // Trust the index\n logger().debug('[ElementResolver] Using matchIndex fallback', { matchIndex });\n return { locator: indexed, selectorDesc: `${selectorDesc} [index:${matchIndex}]` };\n }\n }\n\n // No disambiguation succeeded - treat as selector miss\n logger().warn('[ElementResolver] No disambiguation succeeded, treating as selector miss', {\n role,\n name: searchName,\n count,\n });\n return null;\n }\n } catch (err) {\n logger().debug('[ElementResolver] Role selector variant failed', {\n context: contextName,\n variant,\n searchName,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n return null;\n };\n\n // Try 1: Full name (original)\n const fullResult = await tryWithName(normalizedName ?? name, '');\n if (fullResult) return fullResult;\n\n // Try role-only with containsText if name match failed\n if (activeContainsText && activeContainsText.length > 0) {\n const roleOnlyResult = await tryWithName(undefined, '[containsText]');\n if (roleOnlyResult) return roleOnlyResult;\n }\n\n // Try 2: Extract primary text from concatenated name\n if (name) {\n const primaryText = extractPrimaryText(normalizedName ?? name);\n if (primaryText) {\n logger().debug('[ElementResolver] Trying partial text match', {\n role,\n originalName: normalizedName ?? name,\n primaryText,\n context: contextName,\n });\n const partialResult = await tryWithName(primaryText, '[partial]');\n if (partialResult) return partialResult;\n }\n }\n\n return null;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Main element resolution\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Resolve an element using selector fallback chain.\n *\n * Tries selectors in priority order:\n * 1. data-testid\n * 2. Role + name (most stable)\n * 3. Label text (getByLabel)\n * 4. Placeholder text\n * 5. Text content (with label fallback for selects)\n * 6. CSS selector (fallback)\n *\n * Also searches within iframes if element not found on main page.\n * Before returning, verifies the element is visible and attached.\n *\n * Supports two modes:\n * - 'replay' (default): throws Error if element cannot be found\n * - 'verify': returns null if element cannot be found (for recording verification)\n *\n * @param page - Playwright page\n * @param selectors - Selector strategy from cached action\n * @param _timeoutMs - Timeout for locator operations (unused, using RESOLVE_TIMEOUT_MS)\n * @param options - Optional configuration\n * @returns Locator for the element (or null in verify mode)\n * @throws Error if element cannot be found (replay mode only)\n */\nexport async function resolveElement(\n page: Page,\n selectors: SelectorStrategy,\n _timeoutMs: number,\n options?: ResolveElementOptions\n): Promise<Locator>;\nexport async function resolveElement(\n page: Page,\n selectors: SelectorStrategy,\n _timeoutMs: number,\n options: ResolveElementOptions & { mode: 'verify' }\n): Promise<Locator | null>;\nexport async function resolveElement(\n page: Page,\n selectors: SelectorStrategy,\n _timeoutMs: number,\n options?: ResolveElementOptions\n): Promise<Locator | null> {\n const resolveStartMs = Date.now();\n const mode = options?.mode ?? 'replay';\n const actionType = options?.actionType;\n const strictMode = options?.strictMode ?? false;\n const errors: string[] = [];\n const requireSelect = options?.requireSelectElement ?? false;\n const elementTypeName = requireSelect ? 'select element' : 'element';\n\n logger().debug('[ElementResolver] Resolving element', {\n mode,\n hasTestId: !!selectors.testId,\n testId: selectors.testId,\n hasRole: !!selectors.role,\n role: selectors.role?.role,\n name: selectors.role?.name,\n hasAriaLabel: !!selectors.ariaLabel,\n hasPlaceholder: !!selectors.placeholder,\n hasText: !!selectors.text,\n hasContainsText: !!selectors.containsText?.length,\n hasParentContext: !!selectors.parentContext,\n parentRole: selectors.parentContext?.role,\n hasFrameContext: !!selectors.frameContext,\n frameSelector: selectors.frameContext?.selector,\n });\n\n /**\n * Helper to validate element if select is required, then verify visibility.\n * Returns the locator if valid, null if validation fails.\n */\n const validateAndReturn = async (\n locator: Locator,\n selectorName: string\n ): Promise<Locator | null> => {\n let capturedStabilityMs = 0;\n const onStabilityWait = (ms: number) => {\n capturedStabilityMs = ms;\n };\n\n if (requireSelect) {\n if (await isSelectElement(locator)) {\n const visStart = Date.now();\n await verifyElementReady(locator, selectorName, true, onStabilityWait, strictMode);\n const visibilityWaitMs = Date.now() - visStart;\n options?.onTiming?.({\n totalMs: Date.now() - resolveStartMs,\n visibilityWaitMs,\n stabilityWaitMs: capturedStabilityMs,\n selectorUsed: selectorName,\n selectorAuthor: classifySelectorAuthor(selectorName),\n });\n logger().debug('[ElementResolver] Resolved select element', { selector: selectorName });\n return locator;\n }\n errors.push(`${selectorName} found element but it's not a select`);\n return null;\n }\n const visStart = Date.now();\n await verifyElementReady(locator, selectorName, true, onStabilityWait, strictMode);\n const visibilityWaitMs = Date.now() - visStart;\n options?.onTiming?.({\n totalMs: Date.now() - resolveStartMs,\n visibilityWaitMs,\n stabilityWaitMs: capturedStabilityMs,\n selectorUsed: selectorName,\n selectorAuthor: classifySelectorAuthor(selectorName),\n });\n logger().debug('[ElementResolver] Resolved element', { selector: selectorName });\n return locator;\n };\n\n // Build list of contexts to search\n const contexts: Array<{ name: string; context: LocatorContext }> = [];\n\n if (selectors.frameContext) {\n const frameSelector = selectors.frameContext.selector;\n const frameName = selectors.frameContext.name ?? selectors.frameContext.id ?? frameSelector;\n logger().debug('[ElementResolver] Using recorded frame context', {\n frameSelector,\n frameType: selectors.frameContext.type,\n });\n contexts.push({\n name: `recorded-frame:${frameName}`,\n context: page.frameLocator(frameSelector),\n });\n // Fallback: also try generic frame locators in case recorded selector is stale\n for (const { name, locator } of getFrameLocators(page)) {\n // Skip the main iframe shortcut when the recorded selector already targets it\n if (name === 'iframe:main' && frameSelector === 'iframe.designer-client-frame') continue;\n contexts.push({ name, context: locator });\n }\n } else {\n contexts.push({ name: 'page', context: page });\n for (const { name, locator } of getFrameLocators(page)) {\n contexts.push({ name, context: locator });\n }\n }\n\n const hasAlternatePlaywrightLocator = Boolean(\n selectors.playwrightLocatorCandidates &&\n Object.values(selectors.playwrightLocatorCandidates).some(\n (candidate) =>\n typeof candidate?.locator === 'string' &&\n candidate.locator.trim().length > 0 &&\n candidate.locator !== selectors.playwrightLocator\n )\n );\n\n let primaryPlaywrightLocatorForRetry: Locator | null = null;\n let shouldRetryPrimaryAfterCandidates = false;\n const retryPrimaryPlaywrightLocator = async (\n locator: Locator,\n locatorSource: string\n ): Promise<Locator | null> => {\n // Retry original locator with short poll to allow async auto-fill to propagate.\n const RETRY_TIMEOUT_MS = 2000;\n const RETRY_POLL_MS = 200;\n const retryStart = Date.now();\n while (Date.now() - retryStart < RETRY_TIMEOUT_MS) {\n await new Promise((r) => setTimeout(r, RETRY_POLL_MS));\n try {\n const retryCount = await locator.count();\n if (retryCount === 1) {\n logger().info('[ElementResolver] PlaywrightLocator resolved after auto-fill retry', {\n locator: locatorSource,\n waitedMs: Date.now() - retryStart,\n });\n const validated = await validateAndReturn(\n locator,\n 'PlaywrightLocator (auto-fill retry)'\n );\n if (validated) return validated;\n break;\n } else if (retryCount > 1) {\n break; // Multiple matches — stop retrying, fall through\n }\n } catch {\n break; // Error during retry — stop\n }\n }\n return null;\n };\n\n // Try playwrightLocator first (highest confidence — authored by selector agent)\n if (selectors.playwrightLocator) {\n try {\n const variableValues = options?.variableValues ?? {};\n const locator = evaluateLocatorChain(page, selectors.playwrightLocator, variableValues);\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error('PlaywrightLocator count timed out')),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n if (count === 1) {\n const validated = await validateAndReturn(locator, 'PlaywrightLocator (agentic)');\n if (validated) return validated;\n } else if (count > 1) {\n // V1: In strict mode, multi-match is an immediate failure — don't guess with .first()\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] PlaywrightLocator matched multiple elements', {\n strictMode: true,\n rejection: 'multi_match',\n selectorDesc: 'PlaywrightLocator (agentic)',\n matchCount: count,\n locator: selectors.playwrightLocator,\n });\n errors.push(`PlaywrightLocator matched ${count} elements`);\n } else {\n // Try first visible element\n const first = locator.first();\n const isVis = await first.isVisible().catch(() => false);\n if (isVis) {\n const validated = await validateAndReturn(\n first,\n 'PlaywrightLocator (agentic, first visible)'\n );\n if (validated) return validated;\n }\n errors.push(`PlaywrightLocator matched ${count} elements`);\n }\n } else {\n // V3: In strict mode, don't strip filters — they were authored for a reason\n if (!strictMode) {\n // 0 matches — try stripping .filter() clauses (auto-fill may not have propagated)\n const stripped = stripFilterClauses(selectors.playwrightLocator!);\n if (stripped) {\n try {\n const strippedLocator = evaluateLocatorChain(page, stripped, variableValues);\n const strippedCount = await Promise.race([\n strippedLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error('Stripped locator count timed out')),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n if (strippedCount === 1) {\n logger().warn('[ElementResolver] PlaywrightLocator resolved after stripping filter', {\n original: selectors.playwrightLocator,\n stripped,\n });\n const validated = await validateAndReturn(\n strippedLocator,\n 'PlaywrightLocator (filter-stripped)'\n );\n if (validated) return validated;\n }\n } catch {\n // Stripped locator also failed — fall through\n }\n }\n } else {\n logger().warn('[ElementResolver] [strict] Skipping filter stripping for PlaywrightLocator', {\n strictMode: true,\n rejection: 'filter_stripped',\n locator: selectors.playwrightLocator,\n });\n }\n\n if (!hasAlternatePlaywrightLocator) {\n const retried = await retryPrimaryPlaywrightLocator(\n locator,\n selectors.playwrightLocator\n );\n if (retried) return retried;\n } else {\n primaryPlaywrightLocatorForRetry = locator;\n shouldRetryPrimaryAfterCandidates = true;\n }\n\n errors.push('PlaywrightLocator matched 0 elements');\n }\n } catch (err) {\n errors.push(`PlaywrightLocator failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // V14: In strict mode, if playwrightLocator exists and failed, don't fall through\n // to weaker heuristic selectors that may match a different element\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] PlaywrightLocator failed, not falling through to heuristic selectors', {\n strictMode: true,\n rejection: 'locator_fallback_blocked',\n locator: selectors.playwrightLocator,\n errors,\n });\n }\n // Fall through to other strategies (only in non-strict mode)\n }\n\n const triedCandidateLocators = new Set<string>(\n selectors.playwrightLocator ? [selectors.playwrightLocator] : []\n );\n if (selectors.playwrightLocatorCandidates) {\n const candidateEntries = Object.entries(selectors.playwrightLocatorCandidates).filter(\n (entry): entry is [string, { locator: string }] =>\n typeof entry[1]?.locator === 'string' &&\n entry[1].locator.trim().length > 0 &&\n !triedCandidateLocators.has(entry[1].locator)\n );\n\n for (const [author, candidate] of candidateEntries) {\n triedCandidateLocators.add(candidate.locator);\n const selectorDesc = `PlaywrightLocator candidate (${author})`;\n try {\n const variableValues = options?.variableValues ?? {};\n const locator = evaluateLocatorChain(page, candidate.locator, variableValues);\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error(`${selectorDesc} count timed out`)),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n\n if (count === 1) {\n const validated = await validateAndReturn(locator, selectorDesc);\n if (validated) return validated;\n } else if (count > 1) {\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] PlaywrightLocator candidate matched multiple elements', {\n strictMode: true,\n rejection: 'multi_match',\n selectorDesc,\n matchCount: count,\n locator: candidate.locator,\n });\n errors.push(`${selectorDesc} matched ${count} elements`);\n } else {\n const first = locator.first();\n const isVis = await first.isVisible().catch(() => false);\n if (isVis) {\n const validated = await validateAndReturn(\n first,\n `${selectorDesc} (first visible)`\n );\n if (validated) return validated;\n }\n errors.push(`${selectorDesc} matched ${count} elements`);\n }\n } else {\n errors.push(`${selectorDesc} matched 0 elements`);\n }\n } catch (err) {\n errors.push(\n `${selectorDesc} failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n }\n\n if (\n shouldRetryPrimaryAfterCandidates &&\n primaryPlaywrightLocatorForRetry &&\n selectors.playwrightLocator\n ) {\n const retried = await retryPrimaryPlaywrightLocator(\n primaryPlaywrightLocatorForRetry,\n selectors.playwrightLocator\n );\n if (retried) return retried;\n }\n\n // V14: In strict mode, if playwrightLocator was present and failed, skip all heuristic fallbacks.\n // Heuristic selectors are less specific and may match a different element.\n const skipHeuristicFallbacks = strictMode && !!selectors.playwrightLocator;\n\n // Try data-testid selector first (across all contexts)\n if (selectors.testId && !skipHeuristicFallbacks) {\n for (const { name: contextName, context } of contexts) {\n try {\n const locator = context.getByTestId(selectors.testId);\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('TestId count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n // V2: Split single-match from multi-match. Single match is always accepted.\n // Multi-match: strict mode fails, non-strict picks .first() (legacy behavior).\n if (count === 1) {\n const validated = await validateAndReturn(locator.first(), `TestId selector (in ${contextName})`);\n if (validated) return validated;\n } else if (count > 1) {\n if (strictMode) {\n logger().warn('[ElementResolver] [strict] TestId matched multiple elements', {\n strictMode: true,\n rejection: 'multi_match',\n selectorDesc: `TestId (\"${selectors.testId}\")`,\n matchCount: count,\n });\n errors.push(`TestId selector (\"${selectors.testId}\") matched ${count} elements`);\n } else {\n const first = locator.first();\n const validated = await validateAndReturn(first, `TestId selector (in ${contextName})`);\n if (validated) return validated;\n }\n }\n } catch (err) {\n if (contextName === 'page') {\n errors.push(\n `TestId selector failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n }\n\n if (!errors.some((e) => e.includes('TestId selector'))) {\n errors.push(`TestId selector (\"${selectors.testId}\") found no matches`);\n }\n }\n\n // Skip nameless role selectors when a CSS ID selector is available — the role\n // selector with only matchIndex is too fragile for inputs without accessible names\n const hasNamelessRole = selectors.role && !selectors.role.name;\n const hasNoParentScope =\n !selectors.parentContext?.role &&\n !selectors.parentContext?.css &&\n !selectors.parentContext?.parentChain?.length;\n const hasCSSFallback = !!selectors.css;\n const skipFragileRole = hasNamelessRole && hasNoParentScope && hasCSSFallback;\n\n // Try role-based selector (across all contexts)\n if (skipFragileRole) {\n logger().debug('[ElementResolver] Skipping nameless role selector in favor of CSS fallback', {\n role: selectors.role!.role,\n css: selectors.css,\n });\n }\n if (selectors.role && !skipFragileRole && !skipHeuristicFallbacks) {\n for (const { name: contextName, context } of contexts) {\n try {\n const result = await tryRoleSelector(context, selectors, contextName, strictMode);\n if (result) {\n const validated = await validateAndReturn(result.locator, result.selectorDesc);\n if (validated) return validated;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n errors.push(`Role selector failed in ${contextName}: ${msg}`);\n }\n }\n\n if (errors.length === 0) {\n errors.push(\n `Role selector (${selectors.role.role}${selectors.role.name ? `: \"${selectors.role.name}\"` : ''}) found no matches in page or frames`\n );\n }\n\n // CSS-based role fallback: when getByRole fails, try [role=\"...\"] with containsText filter\n if (selectors.containsText?.length) {\n logger().debug(\n '[ElementResolver] Trying CSS-based role selector fallback with containsText',\n {\n role: selectors.role.role,\n containsText: selectors.containsText,\n }\n );\n\n for (const { name: contextName, context } of contexts) {\n try {\n let cssRoleLocator = context.locator(`[role=\"${selectors.role.role}\"]`);\n for (const textPart of selectors.containsText) {\n if (textPart) {\n cssRoleLocator = cssRoleLocator.filter({ hasText: textPart });\n }\n }\n\n const count = await Promise.race([\n cssRoleLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('CSS role count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n\n if (count > 0) {\n const selectorDesc = `CSS role selector ([role=\"${selectors.role.role}\"] with containsText in ${contextName})`;\n\n if (count > 1) {\n logger().debug('[ElementResolver] Multiple CSS role matches, finding visible', {\n count,\n });\n const visibleElement = await findFirstVisibleElement(cssRoleLocator, count);\n if (visibleElement) {\n const validated = await validateAndReturn(\n visibleElement,\n `${selectorDesc} [visible]`\n );\n if (validated) return validated;\n }\n }\n\n const first = cssRoleLocator.first();\n const validated = await validateAndReturn(first, selectorDesc);\n if (validated) return validated;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger().debug('[ElementResolver] CSS role selector fallback failed', {\n context: contextName,\n error: msg,\n });\n }\n }\n }\n }\n\n // Try text selector (page only - frames already covered by role)\n if (selectors.text && !skipHeuristicFallbacks) {\n const normalizedText = normalizeMatchText(selectors.text.text);\n const { exact } = selectors.text;\n if (!normalizedText) {\n logger().debug('[ElementResolver] Skipping text selector due to empty normalized text');\n errors.push('Text selector skipped due to empty normalized text');\n } else {\n // For select elements, try getByLabel first (common pattern for labeled selects)\n if (requireSelect) {\n const selectScopedContexts = getParentScopedContexts(page, selectors.parentContext);\n for (const { searchCtx, scopeLabel } of selectScopedContexts) {\n try {\n const labelLocator = searchCtx.getByLabel(normalizedText, { exact: false });\n const count = await Promise.race([\n labelLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Label count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n if (count > 0) {\n const first = labelLocator.first();\n const validated = await validateAndReturn(first, `Label selector${scopeLabel}`);\n if (validated) return validated;\n }\n } catch (err) {\n errors.push(\n `Label selector${scopeLabel} failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n\n // Try finding a select associated with text via structure\n try {\n const selectNearText = searchCtx.locator(`select`).filter({\n has: searchCtx.locator(`..`).filter({ hasText: normalizedText }),\n });\n const selectCount = await Promise.race([\n selectNearText.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error('Select near text timed out')),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n if (selectCount > 0) {\n await verifyElementReady(selectNearText.first(), `Select near text${scopeLabel}`, true, undefined, strictMode);\n return selectNearText.first();\n }\n } catch {\n // Ignore - just a fallback attempt\n }\n }\n }\n\n // Build list of text variants to try: full text first, then primary text if different\n const textVariants: Array<{ searchText: string; variant: string }> = [\n { searchText: normalizedText, variant: '' },\n ];\n\n const primaryText = extractPrimaryText(normalizedText);\n if (primaryText) {\n textVariants.push({ searchText: primaryText, variant: '[partial]' });\n }\n\n // Try text selector variants in page and frames\n let fallbackLocator: { locator: Locator; desc: string } | null = null;\n\n for (const { searchText, variant } of textVariants) {\n for (const { name: contextName, context } of contexts) {\n const scopedContexts = getParentScopedContexts(context, selectors.parentContext);\n for (const { searchCtx, scopeLabel } of scopedContexts) {\n try {\n const locator = searchCtx.getByText(searchText, { exact: exact ?? false });\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Text count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n if (count > 0) {\n const selectorDesc = `Text selector (\"${searchText}\"${variant ? ` ${variant}` : ''}${scopeLabel} in ${contextName})`;\n\n if (scopeLabel) {\n logger().debug('[ElementResolver] Text selector parent-scoped', {\n parentRole: selectors.parentContext?.role,\n searchText,\n scopedCount: count,\n scopeLabel,\n });\n }\n\n if (count > 1) {\n let disambigLocator = locator;\n let disambigCount = count;\n\n logger().debug('[ElementResolver] Multiple text matches, trying disambiguation', {\n text: searchText,\n count,\n context: contextName,\n variant,\n scopeLabel,\n hasItemIndex: selectors.itemIndex !== undefined,\n hasRowIndex: selectors.rowIndex !== undefined,\n hasMatchIndex: selectors.parentContext?.matchIndex !== undefined,\n });\n\n // Strategy 0: Auto-scope to visible dialog when no parentContext\n if (!selectors.parentContext && !scopeLabel) {\n const dialogScoped = await filterToVisibleDialog(\n page,\n disambigLocator,\n disambigCount\n );\n if (dialogScoped && dialogScoped.count === 1) {\n const validated = await validateAndReturn(\n dialogScoped.locator.first(),\n `${selectorDesc} [dialog-scoped]`\n );\n if (validated) return validated;\n } else if (dialogScoped && dialogScoped.count > 0 && !strictMode) {\n // V10: In strict mode, only accept dialog scoping if it narrows to exactly 1\n disambigLocator = dialogScoped.locator;\n disambigCount = dialogScoped.count;\n }\n }\n\n // Strategy 1: Try data attribute matching (most deterministic)\n if (\n selectors.itemIndex !== undefined ||\n selectors.rowIndex !== undefined ||\n selectors.automationId\n ) {\n try {\n const allAttrs = await extractDisambiguationAttrsBatch(\n disambigLocator,\n disambigCount\n );\n for (let i = 0; i < allAttrs.length; i++) {\n const attrs = allAttrs[i];\n const matches =\n (selectors.itemIndex !== undefined &&\n attrs.itemIndex === selectors.itemIndex) ||\n (selectors.rowIndex !== undefined &&\n attrs.rowIndex === selectors.rowIndex) ||\n (selectors.automationId && attrs.automationId === selectors.automationId);\n\n if (matches) {\n const nth = disambigLocator.nth(i);\n // Validate role compatibility when role selector was attempted\n if (\n selectors.role &&\n !(await isRoleCompatible(nth, selectors.role.role))\n ) {\n logger().warn(\n '[ElementResolver] Text match rejected - incompatible role (data-attr)',\n {\n expectedRole: selectors.role.role,\n index: i,\n }\n );\n continue;\n }\n logger().debug(\n '[ElementResolver] Found text element by data attributes',\n { index: i, attrs }\n );\n const validated = await validateAndReturn(\n nth,\n `${selectorDesc} [data-attr]`\n );\n if (validated) return validated;\n }\n }\n } catch {\n // Fall through to next strategy\n }\n }\n\n // Strategy 2: Use matchIndex fallback\n if (selectors.parentContext?.matchIndex !== undefined) {\n const matchIndex = selectors.parentContext.matchIndex;\n if (matchIndex < disambigCount) {\n const indexed = disambigLocator.nth(matchIndex);\n // Validate role compatibility when role selector was attempted\n if (\n selectors.role &&\n !(await isRoleCompatible(indexed, selectors.role.role))\n ) {\n logger().warn(\n '[ElementResolver] Text match rejected - incompatible role (matchIndex)',\n {\n expectedRole: selectors.role.role,\n matchIndex,\n }\n );\n } else {\n logger().debug('[ElementResolver] Using text selector matchIndex', {\n matchIndex,\n });\n const validated = await validateAndReturn(\n indexed,\n `${selectorDesc} [index:${matchIndex}]`\n );\n if (validated) return validated;\n }\n }\n }\n\n // Strategy 2b: Prefer interactive element for click actions\n // When text matches both a label and an interactive element (e.g. combobox),\n // clicking the label won't open the combobox — prefer the interactive one.\n if (actionType === 'click') {\n const interactiveMatches: Locator[] = [];\n for (let i = 0; i < Math.min(disambigCount, 10); i++) {\n const nth = disambigLocator.nth(i);\n const isVis = await nth.isVisible().catch(() => false);\n if (!isVis) continue;\n if (await isInteractiveElement(nth)) {\n interactiveMatches.push(nth);\n }\n }\n if (interactiveMatches.length === 1) {\n logger().info(\n '[ElementResolver] Text disambiguation: preferring interactive element for click action',\n {\n text: searchText,\n count,\n interactiveCount: 1,\n }\n );\n const validated = await validateAndReturn(\n interactiveMatches[0]!,\n `${selectorDesc} [interactive-click]`\n );\n if (validated) return validated;\n } else if (interactiveMatches.length > 1) {\n logger().debug(\n '[ElementResolver] Text disambiguation: multiple interactive elements, falling through',\n {\n text: searchText,\n interactiveCount: interactiveMatches.length,\n }\n );\n }\n }\n\n // Strategy 2c: Prefer typeable element for type actions\n // When text matches both a label and a typeable element (e.g. textarea),\n // typing into the label won't work — prefer the typeable one.\n if (actionType === 'type') {\n const typeableMatches: Locator[] = [];\n for (let i = 0; i < Math.min(disambigCount, 10); i++) {\n const nth = disambigLocator.nth(i);\n const isVis = await nth.isVisible().catch(() => false);\n if (!isVis) continue;\n if (await isTypeableElement(nth)) {\n typeableMatches.push(nth);\n }\n }\n if (typeableMatches.length === 1) {\n logger().info(\n '[ElementResolver] Text disambiguation: preferring typeable element for type action',\n {\n text: searchText,\n count,\n typeableCount: 1,\n }\n );\n const validated = await validateAndReturn(\n typeableMatches[0]!,\n `${selectorDesc} [typeable-type]`\n );\n if (validated) return validated;\n } else if (typeableMatches.length > 1) {\n logger().debug(\n '[ElementResolver] Text disambiguation: multiple typeable elements, falling through',\n {\n text: searchText,\n typeableCount: typeableMatches.length,\n }\n );\n }\n }\n\n // Strategy 3: Find first visible element\n const visibleElement = await findFirstVisibleElement(\n disambigLocator,\n disambigCount\n );\n if (visibleElement) {\n // Validate role compatibility when role selector was attempted\n if (\n selectors.role &&\n !(await isRoleCompatible(visibleElement, selectors.role.role))\n ) {\n logger().warn(\n '[ElementResolver] Text match rejected - incompatible role (visible)',\n {\n expectedRole: selectors.role.role,\n }\n );\n } else {\n const validated = await validateAndReturn(\n visibleElement,\n `${selectorDesc} [visible]`\n );\n if (validated) return validated;\n }\n } else {\n logger().debug(\n '[ElementResolver] No visible elements found among matches, trying first anyway',\n {\n text: searchText,\n count: disambigCount,\n }\n );\n }\n }\n\n // Single match or fallback to first\n const first = locator.first();\n // Validate role compatibility when role selector was attempted\n if (selectors.role && !(await isRoleCompatible(first, selectors.role.role))) {\n logger().warn('[ElementResolver] Text match rejected - incompatible role', {\n expectedRole: selectors.role.role,\n text: searchText,\n context: contextName,\n });\n continue;\n }\n const validated = await validateAndReturn(first, selectorDesc);\n if (validated) return validated;\n }\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n if (contextName === 'page' && !variant) {\n errors.push(`Text selector failed: ${errorMsg}`);\n } else if (errorMsg.includes('not ready') || errorMsg.includes('Timeout')) {\n logger().debug('[ElementResolver] Text selector visibility check failed', {\n text: searchText,\n context: contextName,\n variant,\n error: errorMsg,\n });\n errors.push(\n `Text selector (${searchText}${variant} in ${contextName}) visibility failed`\n );\n\n if (contextName.includes('iframe')) {\n const fallbackSelector = `Text selector (\"${searchText}\"${variant ? ` ${variant}` : ''} in ${contextName})`;\n const loc = context.getByText(searchText, { exact: false });\n fallbackLocator = {\n locator: loc.first(),\n desc: `${fallbackSelector} [fallback]`,\n };\n }\n }\n }\n }\n }\n }\n\n // If we have a fallback locator from iframe partial match, try it without strict visibility\n if (fallbackLocator && !requireSelect) {\n logger().info('[ElementResolver] Trying fallback locator from iframe partial match', {\n desc: fallbackLocator.desc,\n });\n try {\n const isReady = await verifyElementReady(\n fallbackLocator.locator,\n fallbackLocator.desc,\n false,\n undefined,\n strictMode\n );\n if (!isReady) {\n logger().warn(\n '[ElementResolver] Fallback locator visibility check failed, proceeding anyway'\n );\n }\n logger().debug('[ElementResolver] Resolved element via fallback', {\n selector: fallbackLocator.desc,\n });\n return fallbackLocator.locator;\n } catch (err) {\n errors.push(\n `Fallback locator failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n if (!errors.some((e) => e.includes('Text selector'))) {\n errors.push(`Text selector (\"${normalizedText}\") found no matches`);\n }\n }\n }\n\n // Try ARIA label (page and frames)\n // Use exact matching to avoid substring false positives (e.g. \"Location Code\"\n // matching \"Open menu for Location Code\"). Falls back to inexact if exact finds nothing.\n if (selectors.ariaLabel && !skipHeuristicFallbacks) {\n for (const { name: contextName, context } of contexts) {\n try {\n let locator = context.getByLabel(selectors.ariaLabel, { exact: true });\n const exactCount = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error('ARIA label exact count timed out')),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n if (exactCount === 0) {\n locator = context.getByLabel(selectors.ariaLabel);\n }\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('ARIA label count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n if (count > 0) {\n const selectorDesc = `ARIA label selector (\"${selectors.ariaLabel}\" in ${contextName})`;\n\n if (count === 1) {\n const validated = await validateAndReturn(locator.first(), selectorDesc);\n if (validated) return validated;\n } else {\n // Multiple matches — try disambiguation strategies\n let ariaDisambigLocator = locator;\n let ariaDisambigCount = count;\n\n logger().debug('[ElementResolver] Multiple ARIA label matches, trying disambiguation', {\n ariaLabel: selectors.ariaLabel,\n count,\n context: contextName,\n hasChildFilter: !!selectors.childFilter,\n hasItemIndex: selectors.itemIndex !== undefined,\n hasMatchIndex: selectors.parentContext?.matchIndex !== undefined,\n });\n\n // Strategy 0: Auto-scope to visible dialog when no parentContext\n if (!selectors.parentContext) {\n const dialogScoped = await filterToVisibleDialog(\n page,\n ariaDisambigLocator,\n ariaDisambigCount\n );\n if (dialogScoped && dialogScoped.count === 1) {\n const validated = await validateAndReturn(\n dialogScoped.locator.first(),\n `${selectorDesc} [dialog-scoped]`\n );\n if (validated) return validated;\n } else if (dialogScoped && dialogScoped.count > 0 && !strictMode) {\n // V10: In strict mode, only accept dialog scoping if it narrows to exactly 1\n ariaDisambigLocator = dialogScoped.locator;\n ariaDisambigCount = dialogScoped.count;\n }\n }\n\n // Strategy 1: Try childFilter disambiguation (e.g., filter by child img alt text)\n if (selectors.childFilter) {\n const filtered = ariaDisambigLocator.filter({\n has: context.getByRole(\n selectors.childFilter.role as Parameters<Page['getByRole']>[0],\n { name: selectors.childFilter.name }\n ),\n });\n const filteredCount = await Promise.race([\n filtered.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error('childFilter count timed out')),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n if (filteredCount === 1) {\n const validated = await validateAndReturn(\n filtered.first(),\n `${selectorDesc} [childFilter]`\n );\n if (validated) return validated;\n }\n }\n\n // Strategy 2: Try data attribute matching\n if (\n selectors.itemIndex !== undefined ||\n selectors.rowIndex !== undefined ||\n selectors.automationId\n ) {\n try {\n const allAttrs = await extractDisambiguationAttrsBatch(\n ariaDisambigLocator,\n ariaDisambigCount\n );\n for (let i = 0; i < allAttrs.length; i++) {\n const attrs = allAttrs[i];\n const matches =\n (selectors.itemIndex !== undefined &&\n attrs.itemIndex === selectors.itemIndex) ||\n (selectors.rowIndex !== undefined && attrs.rowIndex === selectors.rowIndex) ||\n (selectors.automationId && attrs.automationId === selectors.automationId);\n\n if (matches) {\n logger().debug(\n '[ElementResolver] Found ARIA label element by data attributes',\n { index: i, attrs }\n );\n const validated = await validateAndReturn(\n ariaDisambigLocator.nth(i),\n `${selectorDesc} [data-attr]`\n );\n if (validated) return validated;\n }\n }\n } catch {\n // Fall through to next strategy\n }\n }\n\n // Strategy 3: Use matchIndex fallback\n if (selectors.parentContext?.matchIndex !== undefined) {\n const matchIndex = selectors.parentContext.matchIndex;\n if (matchIndex < ariaDisambigCount) {\n const indexed = ariaDisambigLocator.nth(matchIndex);\n logger().debug('[ElementResolver] Using ARIA label matchIndex', { matchIndex });\n const validated = await validateAndReturn(\n indexed,\n `${selectorDesc} [index:${matchIndex}]`\n );\n if (validated) return validated;\n }\n }\n\n // In verify mode, treat as selector miss so discoverParentContext\n // can try to find a narrower parent scope. In replay mode, pick the\n // first visible match as a best-effort (better than failing outright).\n if (mode === 'verify') {\n logger().warn(\n '[ElementResolver] No ARIA label disambiguation succeeded (verify mode, treating as miss)',\n {\n ariaLabel: selectors.ariaLabel,\n count: ariaDisambigCount,\n }\n );\n } else {\n const visibleElement = await findFirstVisibleElement(\n ariaDisambigLocator,\n ariaDisambigCount\n );\n if (visibleElement) {\n logger().warn(\n '[ElementResolver] No ARIA label disambiguation succeeded, using first visible (replay mode)',\n {\n ariaLabel: selectors.ariaLabel,\n count: ariaDisambigCount,\n }\n );\n const validated = await validateAndReturn(\n visibleElement,\n `${selectorDesc} [visible]`\n );\n if (validated) return validated;\n }\n logger().warn('[ElementResolver] No ARIA label disambiguation succeeded', {\n ariaLabel: selectors.ariaLabel,\n count: ariaDisambigCount,\n });\n }\n }\n }\n } catch (err) {\n if (contextName === 'page') {\n errors.push(\n `ARIA label selector failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n }\n\n if (!errors.some((e) => e.includes('ARIA label'))) {\n errors.push(`ARIA label selector (\"${selectors.ariaLabel}\") found no matches`);\n }\n }\n\n // Try placeholder text (page and frames)\n if (selectors.placeholder && !skipHeuristicFallbacks) {\n for (const { name: contextName, context } of contexts) {\n try {\n const locator = context.getByPlaceholder(selectors.placeholder, { exact: false });\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Placeholder count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n if (count > 0) {\n const first = locator.first();\n const validated = await validateAndReturn(\n first,\n `Placeholder selector (in ${contextName})`\n );\n if (validated) return validated;\n }\n } catch (err) {\n if (contextName === 'page') {\n errors.push(\n `Placeholder selector failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n }\n\n if (!errors.some((e) => e.includes('Placeholder selector'))) {\n errors.push(`Placeholder selector (\"${selectors.placeholder}\") found no matches`);\n }\n }\n\n // Try CSS selector as a last resort. Search the same page+frame `contexts` as\n // the role/text paths (so a target captured inside an iframe resolves in the\n // frame, not the top page), and honor the full parentContext (role /\n // containsText / css scopes) within each — mirroring the text-selector path.\n // Without this, a `css` anchor like `[data-field=\"…\"]` that's only unique\n // within an ancestor would match globally and pick the wrong element.\n if (selectors.css && !skipHeuristicFallbacks) {\n const pc = selectors.parentContext;\n // A scoped css anchor (stable-id / row-variable / ancestor) exists ONLY to\n // single out one target within its scope. For those, `count !== 1` is an\n // ambiguity — treat it as a miss (fall back to the agent), never pick-first\n // and never widen to the global page. Unscoped, globally-unique css\n // predicates (semanticClass / iconClass / imgSrc) keep the legacy\n // pick-first behavior.\n const scoped = Boolean(pc && (pc.css || pc.role || pc.containsText || pc.parentChain?.length));\n\n for (const { name: contextName, context } of contexts) {\n const cssScopes = getParentScopedContexts(context, selectors.parentContext);\n for (const { searchCtx, scopeLabel } of cssScopes) {\n // Never search the unscoped/global page for a scoped anchor.\n if (scoped && scopeLabel === '') continue;\n try {\n const locator = searchCtx.locator(selectors.css);\n const count = await Promise.race([\n locator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('CSS count timed out')), RESOLVE_TIMEOUT_MS)\n ),\n ]);\n\n if (scoped) {\n if (count === 1) {\n const validated = await validateAndReturn(\n locator.first(),\n `CSS selector${scopeLabel} (in ${contextName})`\n );\n if (validated) return validated;\n } else if (count > 1) {\n errors.push(\n `CSS selector${scopeLabel} (in ${contextName}) ambiguous — ${count} matches; treating as miss`\n );\n }\n continue;\n }\n\n if (count > 1) {\n // Multiple CSS matches — try visible element first (handles hidden duplicates)\n const visibleElement = await findFirstVisibleElement(locator, count);\n if (visibleElement) {\n const validated = await validateAndReturn(\n visibleElement,\n `CSS selector (in ${contextName}) [visible]`\n );\n if (validated) return validated;\n }\n }\n if (count > 0) {\n const validated = await validateAndReturn(locator.first(), `CSS selector (in ${contextName})`);\n if (validated) return validated;\n }\n } catch (err) {\n errors.push(\n `CSS selector${scopeLabel} (in ${contextName}) failed: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n }\n errors.push(`CSS selector (\"${selectors.css}\") found no matches`);\n }\n\n // Structural fallback: for dynamic text selectors, try role + hasText with current value\n if (selectors.dynamicText && options?.variableValues && selectors.role && !requireSelect && !skipHeuristicFallbacks) {\n const { key } = selectors.dynamicText;\n const currentValue = options.variableValues[key];\n\n if (currentValue) {\n logger().debug('[ElementResolver] Trying structural fallback for dynamic text', {\n role: selectors.role.role,\n currentValue,\n });\n\n for (const { name: contextName, context } of contexts) {\n try {\n const roleLocator = context.getByRole(\n selectors.role.role as Parameters<Page['getByRole']>[0]\n );\n const filtered = roleLocator.filter({ hasText: currentValue });\n const count = await Promise.race([\n filtered.count(),\n new Promise<number>((_, reject) =>\n setTimeout(\n () => reject(new Error('Dynamic fallback count timed out')),\n RESOLVE_TIMEOUT_MS\n )\n ),\n ]);\n\n if (count > 0) {\n const first = filtered.first();\n const isReady = await verifyElementReady(\n first,\n `Dynamic fallback (${selectors.role.role} hasText:${currentValue} in ${contextName})`,\n false,\n undefined,\n strictMode\n );\n if (isReady) {\n logger().info('[ElementResolver] Resolved via dynamic text structural fallback', {\n role: selectors.role.role,\n currentValue,\n context: contextName,\n });\n return first;\n }\n }\n } catch (err) {\n logger().debug('[ElementResolver] Dynamic fallback failed for context', {\n context: contextName,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n }\n }\n\n // Resolution failed — build structured diagnostics\n const totalDurationMs = Date.now() - resolveStartMs;\n const strategies: Array<{ type: string; tried: boolean; result: string }> = [\n {\n type: 'testId',\n tried: !!selectors.testId,\n result: selectors.testId\n ? (errors.find((e) => e.includes('TestId')) ?? 'no matches')\n : 'not available',\n },\n {\n type: 'role',\n tried: !!selectors.role,\n result: selectors.role\n ? (errors.find((e) => e.includes('Role selector')) ?? 'no matches')\n : 'not available',\n },\n {\n type: 'text',\n tried: !!selectors.text,\n result: selectors.text\n ? (errors.find((e) => e.includes('Text selector')) ?? 'no matches')\n : 'not available',\n },\n {\n type: 'ariaLabel',\n tried: !!selectors.ariaLabel,\n result: selectors.ariaLabel\n ? (errors.find((e) => e.includes('ARIA label')) ?? 'no matches')\n : 'not available',\n },\n {\n type: 'placeholder',\n tried: !!selectors.placeholder,\n result: selectors.placeholder\n ? (errors.find((e) => e.includes('Placeholder')) ?? 'no matches')\n : 'not available',\n },\n {\n type: 'css',\n tried: !!selectors.css,\n result: selectors.css\n ? (errors.find((e) => e.includes('CSS selector')) ?? 'no matches')\n : 'not available',\n },\n ];\n\n const errorMsg = `Could not find ${elementTypeName} with any selector strategy. Tried: ${errors.join('; ')}`;\n\n if (mode === 'verify') {\n logger().debug('[ElementResolver] Element resolution failed (verify mode)', {\n strategies: strategies.filter((s) => s.tried),\n totalDurationMs,\n });\n return null;\n }\n\n logger().error('[ElementResolver] Element resolution failed', {\n strategies,\n totalDurationMs,\n selectorSummary: {\n testId: selectors.testId,\n role: selectors.role?.role,\n roleName: selectors.role?.name,\n parentContext: selectors.parentContext?.role,\n parentContextCss: selectors.parentContext?.css,\n text: selectors.text?.text,\n ariaLabel: selectors.ariaLabel,\n },\n });\n throw new Error(errorMsg);\n}\n","/**\n * Selector Derivation\n *\n * Derives stable selectors from Playwright accessibility snapshots.\n * These selectors can be used to locate elements during cache replay\n * even though the ephemeral refs have changed.\n *\n * Selector priority (tried in order during replay):\n * 1. data-testid (most stable when available)\n * 2. Role + name (a11y-focused apps)\n * 3. Label text (getByLabel)\n * 4. Placeholder text\n * 5. Text content\n * 6. CSS selector (fallback, least stable)\n *\n * @module workflows/cache/selector-derivation\n * @see docs/cache-replay.md\n */\n\nimport type { Page, Locator } from 'playwright';\nimport type {\n SelectorStrategy,\n ElementInfo,\n ParentContext,\n ParentContextDynamicText,\n FrameContext,\n} from '@chatsdet/types';\nimport { createLogger } from './logger.js';\nimport { resolveElement, type LocatorContext } from './element-resolver.js';\n\n// Lazy logger to avoid env validation at module load time (for tests)\nlet _logger: ReturnType<typeof createLogger> | null = null;\nconst getLogger = () => {\n if (!_logger) {\n _logger = createLogger({ module: 'SelectorDerivation' });\n }\n return _logger;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Selector Verification Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Result of verifying a single selector type\n */\ninterface SelectorVerificationResult {\n /** The selector type that was verified */\n selectorType: 'testId' | 'role' | 'ariaLabel' | 'placeholder' | 'text';\n /** Whether the selector was successfully verified */\n verified: boolean;\n /** Number of elements that matched the selector */\n matchCount: number;\n /** Whether the resolved element coordinates match the original */\n coordinatesMatch: boolean;\n /** Original element center coordinates */\n originalCoords?: { x: number; y: number };\n /** Resolved element center coordinates */\n resolvedCoords?: { x: number; y: number };\n /** Reason for rejection (if not verified) */\n reason?: string;\n /** Parent context if disambiguation was needed */\n parentContext?: ParentContext;\n}\n\n/**\n * Result of verifying all selectors for an element\n */\ninterface SelectorVerificationSummary {\n /** Selectors that passed verification (only verified selectors included) */\n verifiedSelectors: SelectorStrategy;\n /** Individual verification results for each selector type */\n results: SelectorVerificationResult[];\n /** Whether any selector was successfully verified */\n anyVerified: boolean;\n}\n\n/**\n * Options for selector verification\n */\ninterface SelectorVerificationOptions {\n /** @deprecated No longer used — DOM identity comparison replaced coordinates */\n tolerancePx?: number;\n /** Max depth for parent scope search (default: 5) */\n maxParentDepth?: number;\n /** Timeout in ms for locator operations (default: 5000) */\n timeoutMs?: number;\n /**\n * For typeable/form controls, skip weak text selector probing once a stronger\n * selector is available. This prevents form labels/icons from becoming\n * expensive getByText() candidates during recording.\n */\n skipTextWhenStrong?: boolean;\n}\n\ntype SelectorType = 'testId' | 'role' | 'ariaLabel' | 'placeholder' | 'text';\n\n/**\n * Roles eligible for ariaLabel fallback from accessibleName.\n * These are interactive/input roles that commonly use aria-labelledby for\n * labeling and where getByRole name matching can be unreliable.\n */\nconst LABEL_FALLBACK_ROLES = new Set([\n 'combobox',\n 'textbox',\n 'searchbox',\n 'listbox',\n 'spinbutton',\n 'slider',\n 'switch',\n 'checkbox',\n 'radio',\n 'menuitemcheckbox',\n 'menuitemradio',\n 'generic',\n 'none',\n 'presentation',\n]);\n\nconst TYPEABLE_SELECTOR_ROLES = new Set(['textbox', 'searchbox', 'spinbutton', 'combobox', 'input']);\n\nconst stripPrivateUseGlyphs = (value: string): string => value.replace(/[\\uE000-\\uF8FF]/g, '');\n\nconst normalizeText = (value: string): string =>\n stripPrivateUseGlyphs(value).replace(/\\s+/g, ' ').trim();\n\nconst escapeCssAttributeValue = (value: string): string =>\n value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n\nconst buildFormParentCss = (opts: { name?: string | null; id?: string | null }): string => {\n if (opts.name && opts.name.trim().length > 0) {\n return `form[name=\"${escapeCssAttributeValue(opts.name.trim())}\"]`;\n }\n if (opts.id && opts.id.trim().length > 0) {\n return `form[id=\"${escapeCssAttributeValue(opts.id.trim())}\"]`;\n }\n return 'form';\n};\n\nconst stripNoiseSuffixes = (value: string): string =>\n value\n .replace(/\\s+Not bookmarked$/i, '')\n .replace(/\\s+Bookmarked$/i, '')\n .replace(/\\s+\\u2026$/i, '')\n .replace(/\\s+…$/i, '')\n .trim();\n\nconst buildContainsText = (elementInfo: ElementInfo): string[] | undefined => {\n const raw = elementInfo.textContent || elementInfo.accessibleName;\n if (!raw) return undefined;\n const normalized = stripNoiseSuffixes(normalizeText(raw));\n if (!normalized || normalized.length < 3) return undefined;\n return [normalized];\n};\n\n/**\n * Derive stable selectors from an element's info.\n *\n * @param elementInfo - Element info extracted from snapshot\n * @returns Selector strategy with multiple fallback selectors\n */\nexport function deriveSelectorsFromElementInfo(elementInfo: ElementInfo): SelectorStrategy {\n const selectors: SelectorStrategy = {};\n\n // 0. data-testid selector (most stable when available)\n if (elementInfo.dataTestId) {\n selectors.testId = elementInfo.dataTestId;\n }\n\n const roleName = elementInfo.accessibleName || elementInfo.labelText || elementInfo.ariaLabel;\n\n // 1. Role-based selector (most stable)\n if (\n elementInfo.role &&\n elementInfo.role !== 'generic' &&\n elementInfo.role !== 'text' &&\n elementInfo.role !== 'none' &&\n elementInfo.role !== 'presentation'\n ) {\n selectors.role = {\n role: elementInfo.role,\n name: roleName,\n // Use non-exact matching for resilience to whitespace differences\n exact: roleName ? false : undefined,\n };\n }\n\n const containsText = buildContainsText(elementInfo);\n if (\n containsText &&\n elementInfo.role &&\n ['row', 'listitem', 'option', 'menuitem', 'treeitem', 'gridcell', 'article'].includes(\n elementInfo.role\n )\n ) {\n selectors.containsText = containsText;\n }\n\n // 2. Label selector (covers aria-label, <label> text, and aria-labelledby)\n if (elementInfo.labelText || elementInfo.ariaLabel) {\n selectors.ariaLabel = elementInfo.labelText || elementInfo.ariaLabel;\n } else if (\n elementInfo.accessibleName &&\n elementInfo.accessibleName.length >= 3 &&\n elementInfo.role &&\n LABEL_FALLBACK_ROLES.has(elementInfo.role)\n ) {\n // For interactive/input roles that commonly use aria-labelledby for labeling,\n // fall back to the computed accessible name. getByLabel() uses DOM label\n // relationships which is a genuinely different matching mechanism than\n // getByRole(), providing resilience when one fails (e.g. Dynamics 365\n // comboboxes using aria-labelledby).\n selectors.ariaLabel = elementInfo.accessibleName;\n }\n\n // 3. Placeholder selector (inputs)\n if (elementInfo.placeholder) {\n selectors.placeholder = elementInfo.placeholder;\n }\n\n // 4. Text content selector (visible text)\n // Apply same 3-char minimum as buildContainsText to avoid short-string false positives\n if (elementInfo.textContent) {\n const normalizedForLength = normalizeText(elementInfo.textContent);\n if (normalizedForLength.length >= 3) {\n selectors.text = {\n text: elementInfo.textContent,\n exact: false, // Allow partial match for robustness\n };\n }\n }\n\n // 5. Parent context for disambiguation\n if (elementInfo.parentRole || elementInfo.parentName) {\n const parentCss = elementInfo.parentRole === 'form' ? 'form' : undefined;\n selectors.parentContext = {\n role: elementInfo.parentRole,\n name: elementInfo.parentName,\n css: parentCss,\n nameFromHeading: elementInfo.parentNameFromHeading || undefined,\n };\n }\n\n // 6. Frame context for elements inside iframes\n if (elementInfo.frameContext) {\n selectors.frameContext = elementInfo.frameContext;\n }\n\n // 7. Data attributes for list/table disambiguation\n if (elementInfo.itemIndex !== undefined) {\n selectors.itemIndex = elementInfo.itemIndex;\n }\n if (elementInfo.ariaRowIndex !== undefined) {\n selectors.rowIndex = elementInfo.ariaRowIndex;\n }\n if (elementInfo.automationId) {\n selectors.automationId = elementInfo.automationId;\n }\n\n // 8. Child filter for disambiguation (e.g., child img alt text)\n if (elementInfo.childImgAlt) {\n selectors.childFilter = { role: 'img', name: elementInfo.childImgAlt };\n }\n\n return selectors;\n}\n\nexport { buildLocatorString } from '@chatsdet/recording';\n\n\n/**\n * Sanitize tool arguments for caching.\n *\n * Removes ephemeral refs and other non-stable data.\n *\n * @param args - Original tool arguments\n * @returns Sanitized arguments safe for caching\n */\nexport function sanitizeArgsForCache(args: Record<string, unknown>): Record<string, unknown> {\n const sanitized: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(args)) {\n // Skip ephemeral refs - these will be resolved via selectors during replay\n if (key === 'ref' || key === 'startRef' || key === 'endRef') {\n continue;\n }\n\n // Skip signal and timeout options - these are runtime-specific\n if (key === 'signal' || key === 'timeoutMs') {\n continue;\n }\n\n // Deep clone arrays (like fields in fillForm)\n if (Array.isArray(value)) {\n sanitized[key] = value.map((item) => {\n if (typeof item === 'object' && item !== null) {\n return sanitizeArgsForCache(item as Record<string, unknown>);\n }\n return item;\n });\n continue;\n }\n\n // Keep other values\n sanitized[key] = value;\n }\n\n return sanitized;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Selector Verification\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Default configuration for selector verification\n */\nconst DEFAULT_VERIFICATION_OPTIONS: Required<SelectorVerificationOptions> = {\n tolerancePx: 10,\n maxParentDepth: 5,\n timeoutMs: 5000,\n skipTextWhenStrong: false,\n};\n\n/**\n * Semantic roles that make good scoping parents for disambiguation\n */\nconst SEMANTIC_PARENT_ROLES = [\n 'dialog',\n 'form',\n 'region',\n 'navigation',\n 'main',\n 'article',\n 'section',\n 'complementary',\n 'banner',\n 'contentinfo',\n 'alertdialog',\n 'menu',\n 'menubar',\n 'tablist',\n 'tabpanel',\n 'toolbar',\n 'treegrid',\n 'grid',\n 'listbox',\n];\n\n/**\n * Compare two Playwright locators by DOM identity.\n *\n * Uses page.evaluate to check `a === b` in the browser.\n * Returns false on any failure (timeout, detached element, etc.).\n */\nasync function isSameDOMElement(\n page: Page,\n locatorA: Locator,\n locatorB: Locator,\n timeoutMs: number\n): Promise<boolean> {\n let handleA: Awaited<ReturnType<Locator['elementHandle']>> | null = null;\n let handleB: Awaited<ReturnType<Locator['elementHandle']>> | null = null;\n try {\n [handleA, handleB] = await Promise.race([\n Promise.all([locatorA.elementHandle(), locatorB.elementHandle()]),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('elementHandle timeout')), timeoutMs)\n ),\n ]);\n if (!handleA || !handleB) return false;\n const same = await page.evaluate(([a, b]) => a === b, [handleA, handleB] as const);\n return same;\n } catch {\n return false;\n } finally {\n await handleA?.dispose().catch(() => {});\n await handleB?.dispose().catch(() => {});\n }\n}\n\n/**\n * Build a minimal SelectorStrategy containing only the specified selector type.\n * Preserves data attributes, frame context, and existing parent context for\n * disambiguation, so the shared resolver exercises the exact same code path as replay.\n */\nfunction buildMinimalStrategy(\n selectors: SelectorStrategy,\n selectorType: SelectorType,\n parentContextOverride?: ParentContext\n): SelectorStrategy | null {\n const strategy: SelectorStrategy = {};\n\n switch (selectorType) {\n case 'testId':\n if (!selectors.testId) return null;\n strategy.testId = selectors.testId;\n break;\n case 'role':\n if (!selectors.role) return null;\n strategy.role = { ...selectors.role };\n if (selectors.containsText) strategy.containsText = [...selectors.containsText];\n break;\n case 'ariaLabel':\n if (!selectors.ariaLabel) return null;\n strategy.ariaLabel = selectors.ariaLabel;\n break;\n case 'placeholder':\n if (!selectors.placeholder) return null;\n strategy.placeholder = selectors.placeholder;\n break;\n case 'text':\n if (!selectors.text) return null;\n strategy.text = { ...selectors.text };\n break;\n }\n\n // Preserve data attributes for disambiguation\n if (selectors.itemIndex !== undefined) strategy.itemIndex = selectors.itemIndex;\n if (selectors.rowIndex !== undefined) strategy.rowIndex = selectors.rowIndex;\n if (selectors.automationId) strategy.automationId = selectors.automationId;\n if (selectors.frameContext) strategy.frameContext = selectors.frameContext;\n if (selectors.childFilter) strategy.childFilter = selectors.childFilter;\n\n // Use override or existing parent context\n if (parentContextOverride) {\n strategy.parentContext = parentContextOverride;\n } else if (selectors.parentContext) {\n strategy.parentContext = selectors.parentContext;\n }\n\n return strategy;\n}\n\nconst hasStrongFormSelector = (selectors: SelectorStrategy): boolean =>\n Boolean(\n selectors.testId ||\n (selectors.role?.role &&\n TYPEABLE_SELECTOR_ROLES.has(selectors.role.role) &&\n selectors.role.name) ||\n selectors.ariaLabel ||\n selectors.placeholder\n );\n\nconst shouldSkipTextVerification = (\n selectors: SelectorStrategy,\n options: Pick<SelectorVerificationOptions, 'skipTextWhenStrong'>\n): boolean =>\n Boolean(\n options.skipTextWhenStrong &&\n selectors.text &&\n selectors.role?.role &&\n TYPEABLE_SELECTOR_ROLES.has(selectors.role.role) &&\n hasStrongFormSelector(selectors)\n );\n\nexport function getSelectorTypesForVerification(\n selectors: SelectorStrategy,\n options: Pick<SelectorVerificationOptions, 'skipTextWhenStrong'> = {}\n): SelectorType[] {\n const selectorTypes: SelectorType[] = ['testId', 'role', 'ariaLabel', 'placeholder'];\n if (!shouldSkipTextVerification(selectors, options)) {\n selectorTypes.push('text');\n }\n return selectorTypes;\n}\n\n/**\n * Walk up from the target element to the nearest row-like ancestor and\n * propose candidate text tokens that would uniquely identify that row.\n *\n * Returns the row's ARIA role plus a ranked list of text candidates to try\n * as `.filter({ hasText: … })` anchors. Callers should verify each candidate\n * against the actual selector before committing it.\n */\nasync function findRowAnchor(\n originalLocator: Locator,\n timeoutMs: number\n): Promise<{ role: string; candidates: string[] } | null> {\n try {\n const result = await Promise.race([\n originalLocator.evaluate((el) => {\n const ROW_ROLES = new Set([\n 'row',\n 'listitem',\n 'gridcell',\n 'cell',\n 'treeitem',\n 'option',\n ]);\n const implicitRoleFor = (tag: string): string | null => {\n switch (tag) {\n case 'tr':\n return 'row';\n case 'li':\n return 'listitem';\n case 'td':\n return 'cell';\n case 'th':\n return 'cell';\n default:\n return null;\n }\n };\n\n // Walk up to find the nearest row-like ancestor.\n let current: Element | null = el.parentElement;\n let rowEl: Element | null = null;\n let rowRole: string | null = null;\n while (current) {\n const roleAttr = current.getAttribute('role');\n const tag = current.tagName.toLowerCase();\n const role = roleAttr || implicitRoleFor(tag);\n if (role && ROW_ROLES.has(role)) {\n rowEl = current;\n rowRole = role;\n break;\n }\n current = current.parentElement;\n }\n if (!rowEl || !rowRole) return null;\n\n const targetText = (el.textContent || '').trim().toLowerCase();\n const ariaLabel = rowEl.getAttribute('aria-label')?.trim();\n\n // Collect candidate text tokens from row descendants, excluding the\n // target element's own subtree.\n const texts: string[] = [];\n const seen = new Set<string>();\n const pushText = (raw: string | null | undefined) => {\n if (!raw) return;\n const t = raw.trim();\n if (t.length < 3) return;\n if (t.length > 120) return;\n const key = t.toLowerCase();\n if (key === targetText) return;\n if (targetText.length > 0 && key.includes(targetText)) return;\n if (targetText.length > 0 && targetText.includes(key)) return;\n if (seen.has(key)) return;\n seen.add(key);\n texts.push(t);\n };\n\n if (ariaLabel) pushText(ariaLabel);\n\n // Prefer cell-level descendants first; they tend to carry the\n // distinguishing value (e.g. a variable name).\n const cellSelectors = [\n '[role=\"gridcell\"]',\n '[role=\"cell\"]',\n '[role=\"rowheader\"]',\n 'th',\n 'td',\n ];\n for (const sel of cellSelectors) {\n for (const cell of Array.from(rowEl.querySelectorAll(sel))) {\n if (el.contains(cell) || cell.contains(el)) continue;\n pushText(cell.textContent);\n if (texts.length >= 4) break;\n }\n if (texts.length >= 4) break;\n }\n\n // Fall back to any visible text nodes not inside the target.\n if (texts.length === 0) {\n const walker = document.createTreeWalker(rowEl, NodeFilter.SHOW_TEXT, {\n acceptNode(node) {\n if (!node.textContent || !node.textContent.trim()) {\n return NodeFilter.FILTER_REJECT;\n }\n let ancestor: Node | null = node;\n while (ancestor) {\n if (ancestor === el) return NodeFilter.FILTER_REJECT;\n ancestor = ancestor.parentNode;\n }\n return NodeFilter.FILTER_ACCEPT;\n },\n });\n let node = walker.nextNode();\n while (node && texts.length < 4) {\n pushText(node.textContent);\n node = walker.nextNode();\n }\n }\n\n return { role: rowRole, candidates: texts };\n }),\n new Promise<null>((_, reject) =>\n setTimeout(() => reject(new Error('findRowAnchor timeout')), timeoutMs)\n ),\n ]);\n\n if (!result) return null;\n const normalizedCandidates = result.candidates\n .map((raw) => stripNoiseSuffixes(normalizeText(raw)))\n .filter((t): t is string => !!t && t.length >= 3)\n // Prefer shorter, distinctive tokens over long blobs.\n .sort((a, b) => a.length - b.length)\n .slice(0, 4);\n if (normalizedCandidates.length === 0) return null;\n return { role: result.role, candidates: normalizedCandidates };\n } catch {\n return null;\n }\n}\n\n/**\n * Try to discover a parent context that disambiguates the selector.\n *\n * Walks DOM ancestry of all matching elements to find a semantic parent scope\n * that makes the selector unique. Uses the shared resolver to verify each\n * candidate, ensuring the same code path as replay.\n *\n * @param page - Playwright page\n * @param selectors - The selector strategy being verified\n * @param selectorType - Which selector type to scope\n * @param originalLocator - Locator for the original element (via aria-ref)\n * @param options - Verification options\n * @returns Parent context, or null\n */\nasync function discoverParentContext(\n page: Page,\n selectors: SelectorStrategy,\n selectorType: 'testId' | 'role' | 'ariaLabel' | 'placeholder' | 'text',\n originalLocator: Locator,\n options: Required<SelectorVerificationOptions>\n): Promise<{\n parentContext: ParentContext;\n} | null> {\n const { timeoutMs, maxParentDepth } = options;\n const logger = getLogger();\n\n // Determine the correct context: use frame locator for iframe-scoped selectors\n const context: LocatorContext = selectors.frameContext?.selector\n ? page.frameLocator(selectors.frameContext.selector)\n : page;\n\n // Strategy 0: Row-anchor scoping. When the target sits inside a row-like\n // ancestor (role=row/listitem/gridcell/treeitem/option), prefer anchoring\n // to that row using a unique text token inside it. This is almost always\n // more stable than the nearest landmark (main/form/region), which is what\n // Strategy 1 would otherwise pick.\n try {\n const rowCandidate = await findRowAnchor(originalLocator, timeoutMs);\n if (rowCandidate && rowCandidate.candidates.length > 0) {\n for (const candidateText of rowCandidate.candidates) {\n const candidateParent: ParentContext = {\n role: rowCandidate.role,\n containsText: candidateText,\n };\n const strategyWithParent = buildMinimalStrategy(selectors, selectorType, candidateParent);\n if (!strategyWithParent) continue;\n try {\n const resolved = await resolveElement(page, strategyWithParent, timeoutMs, {\n mode: 'verify',\n });\n if (!resolved) continue;\n const isSame = await isSameDOMElement(page, originalLocator, resolved, timeoutMs);\n if (!isSame) continue;\n logger.debug('[SelectorDerivation] Found unique row anchor', {\n selectorType,\n parentContext: candidateParent,\n });\n return { parentContext: candidateParent };\n } catch {\n continue;\n }\n }\n }\n } catch (err) {\n logger.debug('[SelectorDerivation] Row-anchor strategy error', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n // Strategy 1: Simple parent scoping - try each semantic parent role\n try {\n for (const parentRole of SEMANTIC_PARENT_ROLES) {\n const parentLocators = context.getByRole(parentRole as Parameters<Page['getByRole']>[0]);\n\n let parentCount: number;\n try {\n parentCount = await Promise.race([\n parentLocators.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Count timeout')), timeoutMs)\n ),\n ]);\n } catch {\n continue;\n }\n\n for (let i = 0; i < parentCount; i++) {\n const parentLocator = parentLocators.nth(i);\n\n try {\n // Check if original element is a DOM descendant of this parent\n let origHandle: Awaited<ReturnType<Locator['elementHandle']>> | null = null;\n let parentHandle: Awaited<ReturnType<Locator['elementHandle']>> | null = null;\n let isWithinParent = false;\n try {\n [parentHandle, origHandle] = await Promise.race([\n Promise.all([parentLocator.elementHandle(), originalLocator.elementHandle()]),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('elementHandle timeout')), timeoutMs)\n ),\n ]);\n if (parentHandle && origHandle) {\n isWithinParent = await page.evaluate(([p, c]) => p.contains(c), [\n parentHandle,\n origHandle,\n ] as const);\n }\n } catch {\n isWithinParent = false;\n } finally {\n await parentHandle?.dispose().catch(() => {});\n await origHandle?.dispose().catch(() => {});\n }\n\n if (!isWithinParent) continue;\n\n // Get parent's accessible name\n let parentName: string | undefined;\n let nameFromHeading: boolean | undefined;\n try {\n parentName = (await parentLocator.getAttribute('aria-label')) ?? undefined;\n if (!parentName) {\n const innerText = await parentLocator.evaluate((el) => {\n const legend = el.querySelector('legend');\n if (legend) return { text: legend.textContent?.trim(), fromHeading: false };\n const heading = el.querySelector('h1, h2, h3, h4, h5, h6');\n if (heading) return { text: heading.textContent?.trim(), fromHeading: true };\n return undefined;\n });\n if (innerText?.text) {\n parentName = innerText.text;\n nameFromHeading = innerText.fromHeading || undefined;\n }\n }\n } catch {\n // Ignore\n }\n\n // Build strategy with this parent context and try resolveElement\n let parentCss: string | undefined;\n if (parentRole === 'form') {\n const formMeta = await parentLocator\n .evaluate((el) => {\n if (el.tagName.toLowerCase() !== 'form') return null;\n return {\n name: el.getAttribute('name'),\n id: el.getAttribute('id'),\n };\n })\n .catch(() => null);\n parentCss = buildFormParentCss({\n name: formMeta?.name,\n id: formMeta?.id,\n });\n }\n\n const candidateParent: ParentContext = {\n role: parentRole,\n name: parentName,\n ...(parentCss ? { css: parentCss } : {}),\n nameFromHeading,\n };\n const strategyWithParent = buildMinimalStrategy(selectors, selectorType, candidateParent);\n if (!strategyWithParent) continue;\n\n // If resolveElement returns a locator, verify it's the SAME element as the original target.\n // This prevents accepting a parent scope where the selector resolves but to the wrong element.\n const resolved = await resolveElement(page, strategyWithParent, timeoutMs, {\n mode: 'verify',\n });\n if (resolved) {\n const isSame = await isSameDOMElement(page, originalLocator, resolved, timeoutMs);\n if (!isSame) {\n logger.debug(\n '[SelectorDerivation] Parent-scoped selector resolved to wrong element, skipping',\n {\n selectorType,\n parentContext: candidateParent,\n }\n );\n continue;\n }\n logger.debug('[SelectorDerivation] Found unique parent via simple scoping', {\n selectorType,\n parentContext: candidateParent,\n });\n return { parentContext: candidateParent };\n }\n } catch {\n continue;\n }\n }\n }\n } catch (err) {\n logger.debug('[SelectorDerivation] Error in simple parent scoping', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n // Strategy 2: Recursive parent chain from DOM ancestry\n // Build a basic locator for counting and ancestry extraction\n const minimalStrategy = buildMinimalStrategy(selectors, selectorType);\n if (!minimalStrategy) return null;\n\n // We need a raw locator for DOM introspection (ancestry extraction).\n // Build one in the correct context (frame or page) for this purpose.\n let rawLocator: Locator | null = null;\n switch (selectorType) {\n case 'testId':\n if (selectors.testId) rawLocator = context.getByTestId(selectors.testId);\n break;\n case 'role':\n if (selectors.role) {\n const { role, name, exact } = selectors.role;\n rawLocator = context.getByRole(\n role as Parameters<Page['getByRole']>[0],\n name ? { name, exact: exact ?? false } : undefined\n );\n }\n break;\n case 'ariaLabel':\n if (selectors.ariaLabel) rawLocator = context.getByLabel(selectors.ariaLabel);\n break;\n case 'placeholder':\n if (selectors.placeholder) rawLocator = context.getByPlaceholder(selectors.placeholder);\n break;\n case 'text':\n if (selectors.text)\n rawLocator = context.getByText(selectors.text.text, {\n exact: selectors.text.exact ?? false,\n });\n break;\n }\n\n if (!rawLocator) return null;\n\n let count: number;\n try {\n count = await Promise.race([\n rawLocator.count(),\n new Promise<number>((_, reject) =>\n setTimeout(() => reject(new Error('Count timeout')), timeoutMs)\n ),\n ]);\n } catch {\n return null;\n }\n\n if (count <= 1) return null;\n\n // Identify which match is the target using DOM identity comparison,\n // and build ancestry for each matching element\n const elementAncestries: Array<{\n index: number;\n isTarget: boolean;\n ancestors: Array<{ role: string; name?: string; css?: string; nameFromHeading?: boolean }>;\n }> = [];\n\n for (let i = 0; i < Math.min(count, 10); i++) {\n const nth = rawLocator.nth(i);\n try {\n // Use DOM identity to identify the target element (replaces coordinate comparison)\n const isTarget = await isSameDOMElement(page, originalLocator, nth, timeoutMs);\n\n const ancestry = await nth.evaluate((el) => {\n const SEMANTIC_ROLES = [\n 'dialog',\n 'form',\n 'region',\n 'navigation',\n 'main',\n 'article',\n 'section',\n 'complementary',\n 'listbox',\n 'grid',\n 'tree',\n 'menu',\n 'tabpanel',\n 'toolbar',\n 'treegrid',\n 'banner',\n 'contentinfo',\n 'alertdialog',\n 'menubar',\n 'tablist',\n ];\n const parents: Array<{\n role: string | null;\n name: string | null;\n css: string | null;\n nameFromHeading: boolean;\n }> = [];\n let current = el.parentElement;\n while (current && parents.length < 10) {\n const roleAttr = current.getAttribute('role');\n const tagName = current.tagName.toLowerCase();\n const implicitRole =\n tagName === 'nav'\n ? 'navigation'\n : tagName === 'main'\n ? 'main'\n : tagName === 'form'\n ? 'form'\n : tagName === 'dialog'\n ? 'dialog'\n : tagName === 'article'\n ? 'article'\n : tagName === 'section'\n ? 'region'\n : tagName === 'aside'\n ? 'complementary'\n : tagName === 'header'\n ? 'banner'\n : tagName === 'footer'\n ? 'contentinfo'\n : null;\n const role = roleAttr || implicitRole;\n\n if (role && SEMANTIC_ROLES.includes(role)) {\n const ariaLabel = current.getAttribute('aria-label');\n let name = ariaLabel;\n let css: string | null = null;\n let nameFromHeading = false;\n if (!name) {\n const heading = current.querySelector('legend,h1,h2,h3,h4,h5,h6');\n if (heading) {\n name = heading.textContent?.trim() || null;\n nameFromHeading = true;\n }\n }\n if (role === 'form') {\n const escapeAttr = (value: string): string =>\n value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n const formName = current.getAttribute('name');\n const formId = current.getAttribute('id');\n css =\n formName && formName.trim().length > 0\n ? `form[name=\"${escapeAttr(formName.trim())}\"]`\n : formId && formId.trim().length > 0\n ? `form[id=\"${escapeAttr(formId.trim())}\"]`\n : 'form';\n }\n parents.push({ role, name, css, nameFromHeading });\n }\n current = current.parentElement;\n }\n return parents;\n });\n\n elementAncestries.push({\n index: i,\n isTarget,\n ancestors: ancestry\n .filter((a) => a.role)\n .map((a) => ({\n role: a.role!,\n name: a.name || undefined,\n css: a.css || undefined,\n nameFromHeading: a.nameFromHeading || undefined,\n })),\n });\n } catch {\n continue;\n }\n }\n\n const targetEl = elementAncestries.find((e) => e.isTarget);\n if (!targetEl) {\n logger.warn('[SelectorDerivation] Target not found by DOM identity in ancestry search');\n return null;\n }\n\n // Try each depth level to find unique parent scope\n for (let depth = 0; depth < maxParentDepth; depth++) {\n const targetAncestor = targetEl.ancestors[depth];\n if (!targetAncestor) break;\n\n const parentChain = targetEl.ancestors.slice(0, depth + 1);\n\n // Build strategy with this parent chain and verify via shared resolver\n const candidateParent: ParentContext = {\n role: parentChain[0]?.role,\n name: parentChain[0]?.name,\n css: parentChain[0]?.css,\n nameFromHeading: parentChain[0]?.nameFromHeading,\n parentChain,\n };\n\n const strategyWithChain = buildMinimalStrategy(selectors, selectorType, candidateParent);\n if (!strategyWithChain) continue;\n\n try {\n // If resolveElement returns a locator, the chain-scoped selector is unique — verified\n const resolved = await resolveElement(page, strategyWithChain, timeoutMs, { mode: 'verify' });\n if (resolved) {\n logger.debug('[SelectorDerivation] Found unique parent chain via recursive search', {\n depth,\n parentChain,\n });\n return { parentContext: candidateParent };\n }\n } catch {\n continue;\n }\n }\n\n // No unique parent found - fall back to matchIndex\n logger.warn('[SelectorDerivation] No unique parent found, using matchIndex fallback', {\n targetIndex: targetEl.index,\n matchCount: count,\n });\n return {\n parentContext: { matchIndex: targetEl.index },\n };\n}\n\n/**\n * Probe an element's DOM for a child SVG with a `data-icon` attribute and build\n * a CSS selector that identifies the element on the page.\n *\n * - If the selector matches exactly 1 element, returns the CSS selector as-is.\n * - If it matches 2+ elements (≤10), identifies the original element's index\n * among matches and appends Playwright's `>> nth=N` for disambiguation.\n * - Returns undefined if the probe fails or can't disambiguate.\n */\nasync function probeChildIconCSS(\n page: Page,\n originalLocator: Locator,\n role: string\n): Promise<string | undefined> {\n const logger = getLogger();\n\n const iconAttr = await originalLocator\n .evaluate((el) => {\n const svg = el.querySelector('svg[data-icon]');\n return svg?.getAttribute('data-icon') ?? null;\n })\n .catch(() => null);\n\n if (!iconAttr) return undefined;\n\n const baseSelector = `${role}:has(svg[data-icon=\"${iconAttr}\"])`;\n\n try {\n const count = await page.locator(baseSelector).count();\n\n if (count === 1) {\n logger.debug('[SelectorDerivation] probeChildIconCSS found unique selector', {\n css: baseSelector,\n });\n return baseSelector;\n }\n\n if (count >= 2 && count <= 10) {\n // Multiple matches — find the original element's index among them.\n // Mark the original with a temporary attribute, then scan matches.\n const MARKER = '__probe_target__';\n await originalLocator.evaluate((el, attr) => el.setAttribute(attr, '1'), MARKER);\n\n try {\n const matches = page.locator(baseSelector);\n for (let i = 0; i < count; i++) {\n const hasMarker = await matches\n .nth(i)\n .evaluate((el, attr) => el.hasAttribute(attr), MARKER);\n if (hasMarker) {\n const nthSelector = `${baseSelector} >> nth=${i}`;\n logger.debug('[SelectorDerivation] probeChildIconCSS disambiguated via nth', {\n css: nthSelector,\n matchCount: count,\n index: i,\n });\n return nthSelector;\n }\n }\n } finally {\n await originalLocator\n .evaluate((el, attr) => el.removeAttribute(attr), MARKER)\n .catch(() => {});\n }\n }\n\n logger.debug('[SelectorDerivation] probeChildIconCSS could not disambiguate', {\n css: baseSelector,\n count,\n });\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Probe for a CSS selector based on the element's `id` attribute (or a child's `id`).\n *\n * Works for SVG shapes, chart segments, diagrams, and other elements\n * identified by `id` but lacking ARIA attributes in the original DOM.\n *\n * Disambiguation follows the same marker+nth pattern as probeChildIconCSS:\n * - If the selector matches exactly 1 element, returns the CSS selector as-is.\n * - If it matches 2–10 elements, identifies the original element's index\n * among matches and appends Playwright's `>> nth=N` for disambiguation.\n * - Returns undefined if the probe fails or can't disambiguate.\n */\nexport async function probeElementIdCSS(\n page: Page,\n originalLocator: Locator\n): Promise<string | undefined> {\n const logger = getLogger();\n\n const elementId = await originalLocator\n .evaluate((el) => {\n if (el.id) return el.id;\n const child = el.querySelector('[id]');\n return child?.id ?? null;\n })\n .catch(() => null);\n\n if (!elementId) return undefined;\n\n const baseSelector = `[id=\"${elementId}\"]`;\n\n try {\n const count = await page.locator(baseSelector).count();\n\n if (count === 1) {\n logger.debug('[SelectorDerivation] probeElementIdCSS found unique selector', {\n css: baseSelector,\n });\n return baseSelector;\n }\n\n if (count >= 2 && count <= 10) {\n // Check if only 1 match is visible — return clean selector without nth\n const allMatches = page.locator(baseSelector);\n let visibleCount = 0;\n let targetIsOnlyVisible = false;\n\n for (let i = 0; i < count; i++) {\n const isVis = await allMatches\n .nth(i)\n .isVisible()\n .catch(() => false);\n if (isVis) {\n visibleCount++;\n if (visibleCount > 1) break; // multiple visible — skip to nth fallback\n // Check if this visible element is the original target\n const VIS_MARKER = '__vis_probe__';\n await originalLocator.evaluate((el, attr) => el.setAttribute(attr, '1'), VIS_MARKER);\n const isTarget = await allMatches\n .nth(i)\n .evaluate((el, attr) => el.hasAttribute(attr), VIS_MARKER)\n .catch(() => false);\n await originalLocator\n .evaluate((el, attr) => el.removeAttribute(attr), VIS_MARKER)\n .catch(() => {});\n if (isTarget) targetIsOnlyVisible = true;\n }\n }\n\n if (visibleCount === 1 && targetIsOnlyVisible) {\n logger.debug('[SelectorDerivation] probeElementIdCSS: single visible among duplicates', {\n css: baseSelector,\n matchCount: count,\n });\n return baseSelector; // Clean selector — element-resolver picks the visible one\n }\n\n // Fallback: disambiguate via nth index using marker\n const MARKER = '__probe_target__';\n await originalLocator.evaluate((el, attr) => el.setAttribute(attr, '1'), MARKER);\n\n try {\n const matches = page.locator(baseSelector);\n for (let i = 0; i < count; i++) {\n const hasMarker = await matches\n .nth(i)\n .evaluate((el, attr) => el.hasAttribute(attr), MARKER);\n if (hasMarker) {\n const nthSelector = `${baseSelector} >> nth=${i}`;\n logger.debug('[SelectorDerivation] probeElementIdCSS disambiguated via nth', {\n css: nthSelector,\n matchCount: count,\n index: i,\n });\n return nthSelector;\n }\n }\n } finally {\n await originalLocator\n .evaluate((el, attr) => el.removeAttribute(attr), MARKER)\n .catch(() => {});\n }\n }\n\n logger.debug('[SelectorDerivation] probeElementIdCSS could not disambiguate', {\n css: baseSelector,\n count,\n });\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Probe for a CSS selector based on the element's `title` attribute.\n *\n * Works for icon-only elements (e.g., `<a title=\"Quick create\">`) whose\n * accessible name comes from the `title` attribute but isn't captured in\n * the a11y snapshot (Playwright renders them as empty-name elements).\n *\n * Disambiguation follows the same marker+nth pattern as probeChildIconCSS:\n * - If the selector matches exactly 1 element, returns the CSS selector as-is.\n * - If it matches 2–10 elements, identifies the original element's index\n * among matches and appends Playwright's `>> nth=N` for disambiguation.\n * - Returns undefined if the probe fails or can't disambiguate.\n */\nasync function probeTitleCSS(page: Page, originalLocator: Locator): Promise<string | undefined> {\n const logger = getLogger();\n\n const titleAttr = await originalLocator\n .evaluate((el) => el.getAttribute('title'))\n .catch(() => null);\n\n if (!titleAttr) return undefined;\n\n const baseSelector = `[title=\"${titleAttr}\"]`;\n\n try {\n const count = await page.locator(baseSelector).count();\n\n if (count === 1) {\n logger.debug('[SelectorDerivation] probeTitleCSS found unique selector', {\n css: baseSelector,\n });\n return baseSelector;\n }\n\n if (count >= 2 && count <= 10) {\n const MARKER = '__probe_target__';\n await originalLocator.evaluate((el, attr) => el.setAttribute(attr, '1'), MARKER);\n\n try {\n const matches = page.locator(baseSelector);\n for (let i = 0; i < count; i++) {\n const hasMarker = await matches\n .nth(i)\n .evaluate((el, attr) => el.hasAttribute(attr), MARKER);\n if (hasMarker) {\n const nthSelector = `${baseSelector} >> nth=${i}`;\n logger.debug('[SelectorDerivation] probeTitleCSS disambiguated via nth', {\n css: nthSelector,\n matchCount: count,\n index: i,\n });\n return nthSelector;\n }\n }\n } finally {\n await originalLocator\n .evaluate((el, attr) => el.removeAttribute(attr), MARKER)\n .catch(() => {});\n }\n }\n\n logger.debug('[SelectorDerivation] probeTitleCSS could not disambiguate', {\n css: baseSelector,\n count,\n });\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Iframe Selector Resolution\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Probe the live DOM to resolve a generic 'iframe' frameContext into a\n * specific CSS selector (id, name, class, nth-of-type).\n *\n * Uses the element's own frame to walk up to the <iframe> host element\n * and extract identifying attributes — same approach as\n * DirectPlaywrightClient.extractElementMetadata's detectFrameContext.\n *\n * @param page - Playwright page\n * @param elementLocator - Locator for an element inside the iframe (e.g., via aria-ref)\n * @param timeoutMs - Timeout for the DOM probe (default: 5000)\n * @returns FrameContext with specific selector, or null if not in an iframe / probe fails\n */\nexport async function resolveSpecificIframeSelector(\n page: Page,\n elementLocator: Locator,\n timeoutMs = 5000\n): Promise<FrameContext | null> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const result = await Promise.race([\n elementLocator.evaluate((el) => {\n const win = el.ownerDocument.defaultView;\n if (!win || win === win.top) {\n return null; // Not in an iframe\n }\n\n const frameElement = win.frameElement as HTMLIFrameElement | null;\n if (!frameElement) {\n return null;\n }\n\n // Build the best selector for the iframe (same priority as detectFrameContext)\n const frameId = frameElement.id;\n const frameName = frameElement.name;\n const frameClass = frameElement.className;\n\n let selector: string;\n if (frameId) {\n selector = `iframe#${CSS.escape(frameId)}`;\n } else if (frameName) {\n selector = `iframe[name=\"${CSS.escape(frameName)}\"]`;\n } else if (frameClass && typeof frameClass === 'string') {\n const firstClass = frameClass.split(/\\s+/).filter(Boolean)[0];\n if (firstClass) {\n selector = `iframe.${CSS.escape(firstClass)}`;\n } else {\n selector = 'iframe';\n }\n } else {\n // Fallback: try to find index among direct iframe siblings\n const siblings = frameElement.parentElement\n ? Array.from(frameElement.parentElement.children).filter((c) => c.tagName === 'IFRAME')\n : [];\n if (siblings.length > 1) {\n const index = siblings.indexOf(frameElement);\n selector = `iframe:nth-of-type(${index + 1})`;\n } else {\n selector = 'iframe';\n }\n }\n\n return {\n type: 'iframe' as const,\n selector,\n name: frameName || undefined,\n id: frameId || undefined,\n };\n }),\n new Promise<null>((_, reject) => {\n timer = setTimeout(\n () => reject(new Error('resolveSpecificIframeSelector timeout')),\n timeoutMs\n );\n }),\n ]);\n\n return result;\n } catch (err) {\n getLogger().debug('[SelectorDerivation] resolveSpecificIframeSelector failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Probe ancestor elements for `aria-rowindex`.\n *\n * Many grid-based UIs (e.g., BC Dynamics) put `aria-rowindex` on the `<tr>` parent\n * rather than on the cell/input itself. The snapshot parser only captures the element's\n * own attributes, so this probe walks up to find the nearest ancestor row index.\n *\n * @param elementLocator - Locator for the target element\n * @param timeoutMs - Timeout for the DOM probe (default: 3000)\n * @returns The aria-rowindex value, or undefined if not found\n */\nexport async function probeAncestorRowIndex(\n elementLocator: Locator,\n timeoutMs = 3000\n): Promise<number | undefined> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const result = await Promise.race([\n elementLocator.evaluate((el) => {\n // Check element itself first\n const own = el.getAttribute('aria-rowindex');\n if (own) return parseInt(own, 10);\n\n // Walk up ancestors (max 10 levels)\n let current = el.parentElement;\n let depth = 0;\n while (current && depth < 10) {\n const ri = current.getAttribute('aria-rowindex');\n if (ri) return parseInt(ri, 10);\n current = current.parentElement;\n depth++;\n }\n return undefined;\n }),\n new Promise<undefined>((_, reject) => {\n timer = setTimeout(() => reject(new Error('probeAncestorRowIndex timeout')), timeoutMs);\n }),\n ]);\n\n if (result !== undefined && !isNaN(result)) {\n return result;\n }\n return undefined;\n } catch (err) {\n getLogger().debug('[SelectorDerivation] probeAncestorRowIndex failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n return undefined;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Verify a single selector type against the page using the shared element resolver.\n *\n * This ensures verification exercises the **exact same code path** as replay:\n * same serialized SelectorStrategy JSON → same resolveElement() function.\n *\n * If resolveElement returns a single-match Locator, the selector is considered\n * verified immediately — no coordinate comparison needed because the page\n * hasn't changed between derivation and verification (both happen in the BEFORE\n * phase of the same action).\n *\n * @param page - Playwright page\n * @param selectors - Full selector strategy\n * @param selectorType - Which selector to verify\n * @param originalLocator - Locator for the original element (via aria-ref)\n * @param options - Verification options\n * @returns Verification result for this selector type\n */\nasync function verifySingleSelector(\n page: Page,\n selectors: SelectorStrategy,\n selectorType: SelectorType,\n originalLocator: Locator,\n options: Required<SelectorVerificationOptions>\n): Promise<SelectorVerificationResult> {\n const { timeoutMs } = options;\n const logger = getLogger();\n\n const result: SelectorVerificationResult = {\n selectorType,\n verified: false,\n matchCount: 0,\n coordinatesMatch: false,\n };\n\n // Build a minimal strategy with just this selector type\n const minimalStrategy = buildMinimalStrategy(selectors, selectorType);\n if (!minimalStrategy) {\n result.reason = `No ${selectorType} selector available`;\n return result;\n }\n\n try {\n // Dry-run the shared resolver in verify mode — same code path as replay\n const resolved = await resolveElement(page, minimalStrategy, timeoutMs, { mode: 'verify' });\n\n if (resolved) {\n // resolveElement returned a single-match Locator. The selector uniquely\n // resolved on the same page state, so it IS the correct element.\n result.matchCount = 1;\n result.coordinatesMatch = true;\n result.verified = true;\n return result;\n }\n\n // Resolution returned null — selector didn't uniquely resolve.\n // Try to discover a parent context that disambiguates.\n logger.debug('[SelectorDerivation] Initial resolution failed, trying parent disambiguation', {\n selectorType,\n });\n\n // Try data attribute disambiguation first (most deterministic)\n if (selectors.itemIndex !== undefined || selectors.rowIndex !== undefined) {\n // Data attributes are already included in the minimal strategy.\n // If resolveElement returned null with them, they didn't help.\n // We still record this for the result.\n logger.debug('[SelectorDerivation] Data attributes present but did not disambiguate', {\n selectorType,\n itemIndex: selectors.itemIndex,\n rowIndex: selectors.rowIndex,\n });\n }\n\n // Try parent context discovery (uses DOM identity for target identification)\n const parentResult = await discoverParentContext(\n page,\n selectors,\n selectorType,\n originalLocator,\n options\n );\n\n if (parentResult) {\n result.verified = true;\n result.coordinatesMatch = true;\n result.parentContext = parentResult.parentContext;\n return result;\n }\n\n result.reason = 'Resolution failed — no disambiguation strategy succeeded';\n return result;\n } catch (err) {\n result.reason = `Verification failed: ${err instanceof Error ? err.message : String(err)}`;\n return result;\n }\n}\n\n/**\n * Verify derived selectors against the actual page state.\n *\n * This function takes selectors derived from element metadata and verifies\n * them against the live page. For each selector type:\n * 1. Build a Playwright locator\n * 2. Count matching elements\n * 3. If count === 1, verify coordinates match within tolerance\n * 4. If count > 1, try to find a parent scope that makes it unique\n * 5. If count === 0, reject this selector type\n *\n * Returns only the selectors that were successfully verified, with\n * parent context added where disambiguation was needed.\n *\n * @param page - Playwright page to verify against\n * @param selectors - Selector strategy from element metadata\n * @param originalLocator - Locator for the original element (via aria-ref)\n * @param options - Verification options\n * @returns Verified selectors and detailed results\n */\nexport async function verifySelectorAgainstRef(\n page: Page,\n selectors: SelectorStrategy,\n originalLocator: Locator,\n options: SelectorVerificationOptions = {}\n): Promise<SelectorVerificationSummary> {\n const opts: Required<SelectorVerificationOptions> = {\n ...DEFAULT_VERIFICATION_OPTIONS,\n ...options,\n };\n\n const results: SelectorVerificationResult[] = [];\n const verifiedSelectors: SelectorStrategy = {};\n\n // Selector types to verify, in priority order.\n const selectorTypes = getSelectorTypesForVerification(selectors, opts);\n\n if (opts.skipTextWhenStrong && selectors.text && !selectorTypes.includes('text')) {\n getLogger().debug('[SelectorDerivation] Skipping weak text verification for form control', {\n role: selectors.role?.role,\n hasTestId: !!selectors.testId,\n hasRoleName: !!selectors.role?.name,\n hasAriaLabel: !!selectors.ariaLabel,\n hasPlaceholder: !!selectors.placeholder,\n });\n }\n\n for (const selectorType of selectorTypes) {\n const result = await verifySingleSelector(page, selectors, selectorType, originalLocator, opts);\n results.push(result);\n\n if (result.verified) {\n // Add verified selector to result\n switch (selectorType) {\n case 'testId':\n if (selectors.testId) verifiedSelectors.testId = selectors.testId;\n break;\n case 'role':\n if (selectors.role) verifiedSelectors.role = { ...selectors.role };\n if (selectors.containsText) verifiedSelectors.containsText = [...selectors.containsText];\n break;\n case 'ariaLabel':\n if (selectors.ariaLabel) verifiedSelectors.ariaLabel = selectors.ariaLabel;\n break;\n case 'placeholder':\n if (selectors.placeholder) verifiedSelectors.placeholder = selectors.placeholder;\n break;\n case 'text':\n if (selectors.text) verifiedSelectors.text = { ...selectors.text };\n break;\n }\n\n // Add parent context if disambiguation was needed\n if (result.parentContext) {\n verifiedSelectors.parentContext = result.parentContext;\n }\n }\n }\n\n let anyVerified = results.some((r) => r.verified);\n\n // Last-resort fallback: probe for icon-only button CSS selector.\n // When all standard selectors fail (icon-only buttons have no name/text),\n // check if the element contains an SVG with a data-icon attribute and\n // build a CSS selector from it. Uses Playwright's >> nth=N syntax for\n // disambiguation when multiple elements share the same icon.\n if (!anyVerified && selectors.role) {\n const cssSelector = await probeChildIconCSS(page, originalLocator, selectors.role.role);\n if (cssSelector) {\n verifiedSelectors.css = cssSelector;\n anyVerified = true;\n\n getLogger().debug('[SelectorDerivation] Icon CSS probe succeeded as last resort', {\n css: cssSelector,\n });\n }\n }\n\n // Proactively capture CSS id selector when available, even if other selectors verified.\n // Provides defense-in-depth for cases where text/role selectors match ambiguously at replay time.\n if (anyVerified && !verifiedSelectors.css) {\n try {\n const cssSelector = await probeElementIdCSS(page, originalLocator);\n if (cssSelector) {\n verifiedSelectors.css = cssSelector;\n getLogger().debug('[SelectorDerivation] Proactive element ID CSS probe succeeded', {\n css: cssSelector,\n });\n }\n } catch {\n // Non-fatal: proactive probe is best-effort\n }\n }\n\n // Last-resort fallback: probe for element id CSS selector.\n // Works for SVG shapes, chart segments, diagrams, and other elements\n // identified by `id` but lacking ARIA attributes in the original DOM.\n if (!anyVerified) {\n const cssSelector = await probeElementIdCSS(page, originalLocator);\n if (cssSelector) {\n verifiedSelectors.css = cssSelector;\n anyVerified = true;\n\n getLogger().debug('[SelectorDerivation] Element ID CSS probe succeeded as last resort', {\n css: cssSelector,\n });\n }\n }\n\n // Last-resort fallback: probe for title attribute CSS selector.\n // Works for icon-only elements whose accessible name comes from the\n // `title` attribute but isn't captured in the a11y snapshot.\n if (!anyVerified) {\n const cssSelector = await probeTitleCSS(page, originalLocator);\n if (cssSelector) {\n verifiedSelectors.css = cssSelector;\n anyVerified = true;\n\n getLogger().debug('[SelectorDerivation] Title CSS probe succeeded as last resort', {\n css: cssSelector,\n });\n }\n }\n\n // Preserve original parentContext if any selector was verified with it.\n // Verification uses it via buildMinimalStrategy, but the result only\n // reports parentContext when discoverParentContext discovers a NEW one.\n if (anyVerified && selectors.parentContext && !verifiedSelectors.parentContext) {\n verifiedSelectors.parentContext = selectors.parentContext;\n }\n\n // Preserve frameContext in verified selectors if present\n // This ensures replay knows which frame to search in\n if (anyVerified && selectors.frameContext) {\n verifiedSelectors.frameContext = selectors.frameContext;\n }\n\n // Preserve childFilter for disambiguation during replay\n if (anyVerified && selectors.childFilter) {\n verifiedSelectors.childFilter = selectors.childFilter;\n }\n\n // Preserve data attributes for list/table disambiguation during replay\n if (anyVerified && selectors.rowIndex !== undefined) {\n verifiedSelectors.rowIndex = selectors.rowIndex;\n }\n if (anyVerified && selectors.itemIndex !== undefined) {\n verifiedSelectors.itemIndex = selectors.itemIndex;\n }\n if (anyVerified && selectors.automationId) {\n verifiedSelectors.automationId = selectors.automationId;\n }\n\n getLogger().debug('[SelectorDerivation] Verification complete', {\n verified: results.filter((r) => r.verified).map((r) => r.selectorType),\n rejected: results\n .filter((r) => !r.verified)\n .map((r) => ({\n type: r.selectorType,\n reason: r.reason,\n })),\n anyVerified,\n hasParentContext: !!verifiedSelectors.parentContext,\n hasFrameContext: !!selectors.frameContext,\n frameSelector: selectors.frameContext?.selector,\n });\n\n return {\n verifiedSelectors,\n results,\n anyVerified,\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dynamic Text Detection & Hydration\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Minimum character length for a dynamic value to be considered for templatization */\nconst DYNAMIC_TEXT_MIN_LENGTH = 3;\n\n/**\n * Minimum ratio of (dynamic value length / selector text length) for a match\n * to be considered distinctive. Prevents common short words like \"Open\" from\n * being annotated as dynamic when they appear in longer selector text.\n * Values >= DYNAMIC_TEXT_DISTINCTIVE_LENGTH bypass the ratio check.\n */\nconst DYNAMIC_TEXT_MIN_RATIO = 0.4;\nconst DYNAMIC_TEXT_DISTINCTIVE_LENGTH = 8;\n\n/**\n * Map of dynamic value source types and their keys.\n * Used internally by detectDynamicText.\n */\ntype DynamicValueEntry = {\n source: 'inputValue';\n key: string;\n value: string;\n};\n\n/**\n * Build a flat list of dynamic value entries from variable values.\n * Only includes string values above the minimum length threshold.\n * Source is always 'inputValue' — the VariableRegistry is now the single\n * source of truth and no longer distinguishes ws: prefixed keys.\n */\nfunction buildDynamicValueEntries(variableValues: Record<string, string>): DynamicValueEntry[] {\n const entries: DynamicValueEntry[] = [];\n\n for (const [key, value] of Object.entries(variableValues)) {\n if (typeof value !== 'string' || value.length < DYNAMIC_TEXT_MIN_LENGTH) continue;\n entries.push({ source: 'inputValue', key, value });\n }\n\n // Sort by value length descending so longer matches take precedence\n entries.sort((a, b) => b.value.length - a.value.length);\n return entries;\n}\n\n/**\n * Collect all text-bearing fields from a SelectorStrategy for scanning.\n */\nfunction collectSelectorTexts(selectors: SelectorStrategy): string[] {\n const texts: string[] = [];\n if (selectors.role?.name) texts.push(selectors.role.name);\n if (selectors.text?.text) texts.push(selectors.text.text);\n if (selectors.ariaLabel) texts.push(selectors.ariaLabel);\n if (selectors.containsText) {\n for (const t of selectors.containsText) {\n if (t) texts.push(t);\n }\n }\n return texts;\n}\n\n/**\n * Detect if a selector contains dynamic text from known dynamic values.\n *\n * Scans text-bearing selector fields (role.name, text.text, containsText[], ariaLabel)\n * against a map of known variable values from the VariableRegistry.\n *\n * @param selectors - The selector strategy to scan\n * @param variableValues - Flat key→value map from the VariableRegistry\n * @returns The dynamicText annotation if a match is found, undefined otherwise\n */\nexport function detectDynamicText(\n selectors: SelectorStrategy,\n variableValues: Record<string, string>\n): SelectorStrategy['dynamicText'] | undefined {\n if (!variableValues || Object.keys(variableValues).length === 0) return undefined;\n\n const entries = buildDynamicValueEntries(variableValues);\n if (entries.length === 0) return undefined;\n\n const selectorTexts = collectSelectorTexts(selectors);\n if (selectorTexts.length === 0) return undefined;\n\n // Check each dynamic value against each selector text field.\n // To avoid false positives from common short words (e.g., \"Open\" matching\n // \"Open settings\"), we require the value to either be long enough to be\n // distinctive on its own (>= DYNAMIC_TEXT_DISTINCTIVE_LENGTH) or to cover\n // a significant portion of the selector text (>= DYNAMIC_TEXT_MIN_RATIO).\n for (const entry of entries) {\n const isDistinctiveLength = entry.value.length >= DYNAMIC_TEXT_DISTINCTIVE_LENGTH;\n for (const selectorText of selectorTexts) {\n if (!selectorText.includes(entry.value)) continue;\n if (\n isDistinctiveLength ||\n entry.value.length / selectorText.length >= DYNAMIC_TEXT_MIN_RATIO\n ) {\n return {\n source: entry.source,\n key: entry.key,\n originalText: entry.value,\n };\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Compute the length of the common prefix between two strings.\n */\nfunction commonPrefixLength(a: string, b: string): number {\n let i = 0;\n while (i < a.length && i < b.length && a[i] === b[i]) i++;\n return i;\n}\n\n/**\n * Check if a single field value is a \"chimera\" — compiled from mixed run data.\n *\n * Returns true when `originalText` is a strict substring of `fieldValue`,\n * AND the remaining text (field minus originalText) shares a significant\n * common prefix (≥3 chars) with `currentValue`, suggesting the leftover\n * text is a stale version of the same dynamic variable from a different run.\n */\nfunction isChimeraFieldValue(\n fieldValue: string,\n originalText: string,\n currentValue: string\n): boolean {\n if (fieldValue === originalText) return false;\n if (!fieldValue.includes(originalText)) return false;\n\n const remaining = fieldValue.replace(originalText, '').trim();\n if (!remaining) return false;\n\n const minPrefixLen = Math.min(3, currentValue.length);\n return commonPrefixLength(remaining, currentValue) >= minPrefixLen;\n}\n\n/**\n * Check if ANY text field in the selector strategy contains chimera text.\n */\nfunction hasChimeraField(\n selectors: SelectorStrategy,\n originalText: string,\n currentValue: string\n): boolean {\n if (selectors.role?.name && isChimeraFieldValue(selectors.role.name, originalText, currentValue))\n return true;\n if (selectors.text?.text && isChimeraFieldValue(selectors.text.text, originalText, currentValue))\n return true;\n if (selectors.ariaLabel && isChimeraFieldValue(selectors.ariaLabel, originalText, currentValue))\n return true;\n if (selectors.containsText?.some((t) => t && isChimeraFieldValue(t, originalText, currentValue)))\n return true;\n return false;\n}\n\n/**\n * Replace all occurrences of `originalText` with `newText` in text-bearing selector fields.\n * Returns a new SelectorStrategy (does not mutate the input).\n *\n * When `fullFieldReplacement` is true, any field that contains `originalText` as a\n * strict substring (field !== originalText) gets replaced entirely with `newText`.\n * This prevents chimera text from partial `dynamicText.originalText` values — e.g.,\n * \"Matter vbEDNKOWbf- Matter ag7gOOHnZA\" where only \"Matter ag7gOOHnZA\" was tracked\n * would produce \"Matter vbEDNKOWbf- Matter wNxa4WJtqA\" (stale prefix + new suffix).\n */\nfunction replaceTextInSelectors(\n selectors: SelectorStrategy,\n originalText: string,\n newText: string,\n fullFieldReplacement = false\n): SelectorStrategy {\n const result: SelectorStrategy = { ...selectors };\n\n // Escape special regex characters in the original text\n const escaped = originalText.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const regex = new RegExp(escaped, 'g');\n\n const replaceField = (fieldValue: string): string => {\n if (!fieldValue.includes(originalText)) return fieldValue;\n // If full-field replacement is on and originalText is a strict substring,\n // replace the entire field value to avoid chimera text\n if (fullFieldReplacement && fieldValue !== originalText) {\n return newText;\n }\n return fieldValue.replace(regex, newText);\n };\n\n if (result.role?.name && result.role.name.includes(originalText)) {\n result.role = { ...result.role, name: replaceField(result.role.name) };\n }\n\n if (result.text?.text && result.text.text.includes(originalText)) {\n result.text = { ...result.text, text: replaceField(result.text.text) };\n }\n\n if (result.ariaLabel && result.ariaLabel.includes(originalText)) {\n result.ariaLabel = replaceField(result.ariaLabel);\n }\n\n if (result.containsText) {\n result.containsText = result.containsText.map((t) =>\n t && t.includes(originalText) ? replaceField(t) : t\n );\n }\n\n return result;\n}\n\n/**\n * Hydrate dynamic selectors at replay time.\n *\n * If the selector has a `dynamicText` annotation, replaces the `originalText`\n * with the current value from `variableValues[key]` in all text-bearing fields.\n * Returns a new SelectorStrategy (does not mutate the input).\n *\n * Returns the original selectors unchanged if no `dynamicText` annotation\n * is present or the key is not found in variableValues (backward compatible).\n *\n * Old cached actions with `source: 'workflowState'` still resolve because the\n * VariableRegistry seeds workflowState values under their plain key.\n *\n * @param selectors - The selector strategy to hydrate\n * @param variableValues - Flat key→value map from the VariableRegistry\n * @returns Hydrated selector strategy\n */\n/**\n * Hydrate any `containsTextDynamic` bindings on parent-context nodes by\n * replacing their `containsText` with the current variable value. Returns\n * a new SelectorStrategy when anything changed, otherwise the input.\n */\nfunction hydrateParentContextDynamicText(\n selectors: SelectorStrategy,\n variableValues: Record<string, string>\n): SelectorStrategy {\n const pc = selectors.parentContext;\n if (!pc) return selectors;\n\n const applyBinding = (\n text: string | undefined,\n binding: ParentContextDynamicText | undefined\n ): { text: string | undefined; nextBinding: ParentContextDynamicText | undefined } => {\n if (!binding || !text) return { text, nextBinding: binding };\n const currentValue = variableValues[binding.key];\n if (!currentValue || currentValue === binding.originalText) {\n return { text, nextBinding: binding };\n }\n const hydratedText = text.includes(binding.originalText)\n ? text.split(binding.originalText).join(currentValue)\n : currentValue;\n return {\n text: hydratedText,\n nextBinding: { ...binding, originalText: currentValue },\n };\n };\n\n let changed = false;\n const nextPc: ParentContext = { ...pc };\n\n if (pc.containsTextDynamic) {\n const { text, nextBinding } = applyBinding(pc.containsText, pc.containsTextDynamic);\n if (text !== pc.containsText || nextBinding !== pc.containsTextDynamic) {\n nextPc.containsText = text;\n nextPc.containsTextDynamic = nextBinding;\n changed = true;\n }\n }\n\n if (pc.parentChain?.length) {\n const nextChain = pc.parentChain.map((node) => {\n if (!node.containsTextDynamic) return node;\n const { text, nextBinding } = applyBinding(node.containsText, node.containsTextDynamic);\n if (text === node.containsText && nextBinding === node.containsTextDynamic) return node;\n changed = true;\n return { ...node, containsText: text, containsTextDynamic: nextBinding };\n });\n nextPc.parentChain = nextChain;\n }\n\n if (!changed) return selectors;\n return { ...selectors, parentContext: nextPc };\n}\n\nexport function hydrateDynamicSelectors(\n selectors: SelectorStrategy,\n variableValues: Record<string, string>\n): SelectorStrategy {\n const withHydratedParent = hydrateParentContextDynamicText(selectors, variableValues);\n let hydrated = withHydratedParent;\n\n if (withHydratedParent.playwrightLocator) {\n hydrated = {\n ...hydrated,\n playwrightLocator: hydratePlaywrightLocatorVariables(\n withHydratedParent.playwrightLocator,\n variableValues\n ),\n };\n }\n if (withHydratedParent.playwrightLocatorCandidates) {\n hydrated = {\n ...hydrated,\n playwrightLocatorCandidates: Object.fromEntries(\n Object.entries(withHydratedParent.playwrightLocatorCandidates).map(([author, candidate]) => [\n author,\n candidate?.locator\n ? {\n ...candidate,\n locator: hydratePlaywrightLocatorVariables(candidate.locator, variableValues),\n }\n : candidate,\n ])\n ) as SelectorStrategy['playwrightLocatorCandidates'],\n };\n }\n\n const dynamicText = hydrated.dynamicText;\n if (!dynamicText) return hydrated;\n\n const { key, originalText } = dynamicText;\n selectors = hydrated;\n\n // Look up by plain key — VariableRegistry is the single source of truth.\n // Old cached actions with source='workflowState' still resolve because the\n // registry seeds workflowState string values under their plain key.\n const currentValue = variableValues[key];\n\n if (!currentValue || currentValue === originalText) {\n // No substitution needed (value unchanged or missing)\n return selectors;\n }\n\n // Detect chimera fields: when originalText is a strict substring of a field,\n // AND the remaining text (field minus originalText) shares a common prefix\n // with currentValue, it means the field was compiled from mixed run data.\n // E.g., field=\"Matter vbEDNKOWbf- Matter ag7gOOHnZA\", originalText=\"Matter ag7gOOHnZA\",\n // currentValue=\"Matter wNxa4WJtqA\" → remaining=\"Matter vbEDNKOWbf-\" shares prefix \"Matter \"\n // with currentValue → chimera detected → replace whole field.\n const hasChimera = hasChimeraField(selectors, originalText, currentValue);\n\n if (hasChimera) {\n getLogger().warn(\n '[SelectorDerivation] Full-field replacement triggered due to stale surrounding text',\n {\n key,\n originalText,\n currentValue,\n roleName: selectors.role?.name,\n textText: selectors.text?.text,\n }\n );\n }\n\n const nextSelectors = replaceTextInSelectors(selectors, originalText, currentValue, hasChimera);\n\n // Update the dynamicText annotation with the new originalText for tracking\n nextSelectors.dynamicText = {\n ...dynamicText,\n originalText: currentValue,\n };\n\n return nextSelectors;\n}\n\nfunction hydratePlaywrightLocatorVariables(\n locator: string,\n variableValues: Record<string, string>\n): string {\n return locator.replace(/\\{\\{var\\.([a-zA-Z0-9_]+)\\}\\}/g, (match, key: string) => {\n const value = variableValues[key];\n if (value === undefined) return match;\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n });\n}\n","/**\n * Cached Action Assembly\n *\n * Converts recorded `CachedActionRecord[]` to storable `CachedAction[]` in two\n * passes: macro bindings (so `$RANDOM_STRING`, `$SEQUENCE`, etc. re-resolve at\n * replay) and variable parameterization (`$var.<key>` tokens so the cache\n * replays across runs with different seed values).\n *\n * @module workflows/cache/cached-action-assembly\n * @see docs/api/services/workflow-action-cache.md\n */\n\nimport type { AssertionSpec, CachedAction, CachedActionType } from '@chatsdet/types';\nimport type { CachedActionRecord } from './types.js';\nimport type { MacroResolutionLog } from './macros/types.js';\n\nconst isActionWithTextBindings = (\n actionType: string\n): actionType is 'type' | 'fill_form' | 'assert' =>\n actionType === 'type' || actionType === 'fill_form' || actionType === 'assert';\n\nconst TEXT_ASSERTION_TYPES = new Set<AssertionSpec['type']>(['text_present', 'text_absent']);\n\nconst unwrapAccidentalTextAssertionQuotes = (\n value: string,\n assertionType: AssertionSpec['type'],\n field: 'condition' | 'expected'\n): string => {\n if (field !== 'condition' || !TEXT_ASSERTION_TYPES.has(assertionType)) return value;\n const trimmed = value.trim();\n if (trimmed.length < 2) return value;\n\n const first = trimmed[0];\n const last = trimmed[trimmed.length - 1];\n if ((first !== '\"' && first !== \"'\") || last !== first) return value;\n\n return trimmed.slice(1, -1);\n};\n\nconst findMacroExpressionForValue = (\n value: string,\n macroResolutionLog: MacroResolutionLog | undefined,\n agentMacroResolutions: Map<string, string> | undefined\n): string | undefined => {\n if (macroResolutionLog) {\n for (const [, { expression, resolved }] of macroResolutionLog.entries()) {\n if (value === resolved) {\n return expression;\n }\n }\n }\n\n return agentMacroResolutions?.get(value);\n};\n\nconst buildMacroBindingsForAction = (opts: {\n action: CachedActionRecord;\n macroResolutionLog?: MacroResolutionLog;\n agentMacroResolutions?: Map<string, string>;\n}): Record<string, string> | undefined => {\n const { action, macroResolutionLog, agentMacroResolutions } = opts;\n if (!isActionWithTextBindings(action.actionType)) return undefined;\n\n const macroBindings: Record<string, string> = {};\n\n const rawText = action.args?.text ?? action.args?.value;\n const textArg = typeof rawText === 'string' ? rawText : undefined;\n if (textArg) {\n const textExpression = findMacroExpressionForValue(\n textArg,\n macroResolutionLog,\n agentMacroResolutions\n );\n if (textExpression) {\n macroBindings.text = textExpression;\n }\n }\n\n const fields = Array.isArray(action.args?.fields)\n ? (action.args.fields as Array<{ value?: unknown }>)\n : undefined;\n if (fields) {\n for (let fi = 0; fi < fields.length; fi++) {\n const rawValue = fields[fi]?.value;\n if (typeof rawValue !== 'string' || rawValue.length === 0) continue;\n\n const expression = findMacroExpressionForValue(\n rawValue,\n macroResolutionLog,\n agentMacroResolutions\n );\n if (expression) {\n macroBindings[`fields.${fi}.value`] = expression;\n }\n }\n }\n\n const assertionCondition =\n action.actionType === 'assert' && typeof action.assertion?.condition === 'string'\n ? action.assertion.condition\n : undefined;\n if (assertionCondition) {\n const conditionExpression = findMacroExpressionForValue(\n assertionCondition,\n macroResolutionLog,\n agentMacroResolutions\n );\n if (conditionExpression) {\n macroBindings['assertion.condition'] = conditionExpression;\n }\n }\n\n const assertionExpected =\n action.actionType === 'assert' && typeof action.assertion?.expected === 'string'\n ? action.assertion.expected\n : undefined;\n if (assertionExpected) {\n const expectedExpression = findMacroExpressionForValue(\n assertionExpected,\n macroResolutionLog,\n agentMacroResolutions\n );\n if (expectedExpression) {\n macroBindings['assertion.expected'] = expectedExpression;\n }\n }\n\n return Object.keys(macroBindings).length > 0 ? macroBindings : undefined;\n};\n\n/** Match `$var.key_name` — the syntax the agent uses to reference variables */\nconst VAR_REF_EXACT = /^\\$var\\.(\\w+)$/;\n\n/**\n * Version of the cache compiler/parameterizer. Stamped into `compilationMeta`\n * on every save. Read by `invalidateStaleCompilerVersionsForWorkflow` (in the\n * workflow-node-cache repo) to sweep pre-version caches on terminal run\n * failure.\n *\n * **Bump only for correctness-level rewrites** — i.e. when the parameterizer\n * produces different output such that old caches are now semantically wrong\n * (e.g. commit 82fff150, which added navigate-URL templating so caches from\n * before it baked in concrete UUIDs). Purely additive rewrites (new capability\n * that doesn't invalidate old output) must NOT bump this, or we'll mass-clear\n * correct caches on every unrelated run failure. If per-feature gating is ever\n * needed, introduce a sibling `compilerFeatures` bitfield rather than abusing\n * the version number.\n *\n * Never decrement. Never set below 2 (v1 = pre-navigate-URL-templating).\n */\nexport const CACHE_COMPILER_VERSION = 3;\n\n/**\n * Minimum length for a variable value to be eligible for substring replacement\n * inside URLs and JS expressions. UUIDs (36 chars) and generated slugs like\n * `workflow-v5hFkKrphKGw` (21 chars) clear this easily; short user-provided\n * values (e.g. \"ok\", \"42\") are held back to avoid false positives. The existing\n * 3-char exact-match threshold below is preserved for text/fill_form/assert.\n */\nconst SUBSTRING_MIN_VALUE_LEN = 8;\n\nconst escapeRegex = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\nconst STRING_LITERAL = /'(?:\\\\.|[^'\\\\])*'|\"(?:\\\\.|[^\"\\\\])*\"/g;\n\n/**\n * Replace any occurrence of a known variable value in a plain string with\n * `$var.<key>`. Used for navigate URLs. Longest-first so that a longer value\n * consumes its substrings before a shorter one can match them.\n */\nexport function replaceVariableValuesInString(\n input: string,\n sortedEntries: Array<[string, string]>\n): string {\n let out = input;\n for (const [key, value] of sortedEntries) {\n if (!value || out.indexOf(value) === -1) continue;\n out = out.replace(new RegExp(escapeRegex(value), 'g'), `$var.${key}`);\n }\n return out;\n}\n\n/**\n * Replace variable values embedded inside JS string literals with tokens that\n * `resolveAssertionConditionForReplay` will expand back via `JSON.stringify`.\n *\n * Given `\"Array.from(...).includes('workflow-xyz')\"` and `{ workflow_name: 'workflow-xyz' }`,\n * emits `\"Array.from(...).includes($var.workflow_name)\"` — the bare token, so\n * replay substitutes `\"workflow-xyz\"` (a valid JS string literal).\n *\n * For substring occurrences inside a larger string literal, splits into\n * concatenation: `'/flows/d036830d-…'` → `'/flows/' + $var.workflow_id`.\n * At replay, this becomes `'/flows/' + \"d036830d-…\"` — valid JS.\n *\n * Only single- and double-quoted string literals are scanned. Template literals\n * (backticks) and non-string regions are passed through unchanged.\n */\nexport function replaceVariableValuesInJsExpression(\n js: string,\n sortedEntries: Array<[string, string]>\n): string {\n if (sortedEntries.length === 0) return js;\n\n return js.replace(STRING_LITERAL, (literal) =>\n rewriteStringLiteralInner(literal.slice(1, -1), literal[0], sortedEntries)\n );\n}\n\n/**\n * True if the string ends with an odd number of backslashes. Re-wrapping such a\n * segment in a same-type quote would produce `…\\'` or `…\\\"`, escaping the\n * closing quote we add and producing malformed JS. Segments with an even run\n * (including zero) re-wrap safely — `\\\\` is an escaped backslash, not an\n * escape of whatever follows.\n */\nfunction endsWithOddBackslashes(s: string): boolean {\n let count = 0;\n for (let i = s.length - 1; i >= 0 && s[i] === '\\\\'; i--) count++;\n return count % 2 === 1;\n}\n\nfunction rewriteStringLiteralInner(\n inner: string,\n quote: string,\n sortedEntries: Array<[string, string]>\n): string {\n for (const [key, value] of sortedEntries) {\n if (!value || inner.indexOf(value) === -1) continue;\n\n if (inner === value) return `$var.${key}`;\n\n const parts = inner.split(value);\n // Refuse to rewrite if any non-empty segment ends with an odd trailing\n // backslash run — the emitted `${quote}${segment}${quote}` would have its\n // closing quote escaped and produce unparseable JS. Leave this literal\n // alone for this variable and let the next entry try.\n if (parts.some((p) => p.length > 0 && endsWithOddBackslashes(p))) continue;\n\n const pieces: string[] = [];\n for (let i = 0; i < parts.length; i++) {\n const segment = parts[i];\n if (segment.length > 0) pieces.push(`${quote}${segment}${quote}`);\n if (i < parts.length - 1) pieces.push(`$var.${key}`);\n }\n const rebuilt = pieces.join(' + ');\n // Recurse with the remaining entries so other variable values can rewrite\n // the newly-created sub-literals.\n return replaceVariableValuesInJsExpression(\n rebuilt,\n sortedEntries.filter(([k]) => k !== key)\n );\n }\n return `${quote}${inner}${quote}`;\n}\n\n/**\n * Try to resolve a text value to a variable key. Checks:\n * 1. Literal `$var.key_name` pattern (agent typed the reference directly)\n * 2. Exact value match against known variable values (longest first)\n */\nconst matchVariableKey = (\n text: string,\n variableKeys: Set<string>,\n sortedEntries: Array<[string, string]>\n): string | undefined => {\n // 1. Agent typed the $var. reference literally\n const refMatch = VAR_REF_EXACT.exec(text);\n if (refMatch && variableKeys.has(refMatch[1])) {\n return refMatch[1];\n }\n\n // 2. Exact value match\n if (text.length >= 3) {\n for (const [varKey, varValue] of sortedEntries) {\n if (text === varValue) return varKey;\n }\n }\n\n return undefined;\n};\n\nconst buildVariableRewriteContext = (variableValues: Record<string, string>) => {\n const keys = new Set(Object.keys(variableValues));\n const sorted = Object.entries(variableValues)\n .filter(([, v]) => v.length >= 3)\n .sort(([, a], [, b]) => b.length - a.length);\n const substringEntries = sorted.filter(([, v]) => v.length >= SUBSTRING_MIN_VALUE_LEN);\n return { keys, sorted, substringEntries };\n};\n\nconst rewriteAssertionStringForStorage = (opts: {\n value: string;\n field: 'condition' | 'expected';\n assertionType: AssertionSpec['type'];\n keys: Set<string>;\n sortedEntries: Array<[string, string]>;\n substringEntries: Array<[string, string]>;\n macroResolutionLog?: MacroResolutionLog;\n agentMacroResolutions?: Map<string, string>;\n}): string => {\n const {\n field,\n assertionType,\n keys,\n sortedEntries,\n substringEntries,\n macroResolutionLog,\n agentMacroResolutions,\n } = opts;\n const value = unwrapAccidentalTextAssertionQuotes(opts.value, assertionType, field);\n\n const macroExpression = findMacroExpressionForValue(\n value,\n macroResolutionLog,\n agentMacroResolutions\n );\n if (macroExpression) {\n return macroExpression;\n }\n\n if (field === 'condition' && assertionType === 'evaluate' && substringEntries.length > 0) {\n return replaceVariableValuesInJsExpression(value, substringEntries);\n }\n\n const exactVariableKey = matchVariableKey(value, keys, sortedEntries);\n if (exactVariableKey) {\n return `$var.${exactVariableKey}`;\n }\n\n if (substringEntries.length > 0) {\n return replaceVariableValuesInString(value, substringEntries);\n }\n\n return value;\n};\n\nexport function normalizeAssertionSpecForStorage(opts: {\n assertion: AssertionSpec;\n variableValues?: Record<string, string>;\n macroResolutionLog?: MacroResolutionLog;\n agentMacroResolutions?: Map<string, string>;\n}): AssertionSpec {\n const { assertion, variableValues, macroResolutionLog, agentMacroResolutions } = opts;\n\n const hasStringExpected = typeof assertion.expected === 'string';\n const shouldCheckMacros =\n macroResolutionLog !== undefined || agentMacroResolutions !== undefined;\n const shouldCheckVariables =\n variableValues !== undefined && Object.keys(variableValues).length > 0;\n\n if (!shouldCheckMacros && !shouldCheckVariables) {\n return assertion;\n }\n\n const rewriteContext = shouldCheckVariables\n ? buildVariableRewriteContext(variableValues)\n : { keys: new Set<string>(), sorted: [] as Array<[string, string]>, substringEntries: [] as Array<[string, string]> };\n\n const rewrittenCondition = rewriteAssertionStringForStorage({\n value: assertion.condition,\n field: 'condition',\n assertionType: assertion.type,\n keys: rewriteContext.keys,\n sortedEntries: rewriteContext.sorted,\n substringEntries: rewriteContext.substringEntries,\n macroResolutionLog,\n agentMacroResolutions,\n });\n\n const rewrittenExpected = hasStringExpected\n ? rewriteAssertionStringForStorage({\n value: assertion.expected as string,\n field: 'expected',\n assertionType: assertion.type,\n keys: rewriteContext.keys,\n sortedEntries: rewriteContext.sorted,\n substringEntries: rewriteContext.substringEntries,\n macroResolutionLog,\n agentMacroResolutions,\n })\n : assertion.expected;\n\n if (\n rewrittenCondition === assertion.condition &&\n rewrittenExpected === assertion.expected\n ) {\n return assertion;\n }\n\n return {\n ...assertion,\n condition: rewrittenCondition,\n ...(hasStringExpected ? { expected: rewrittenExpected } : {}),\n };\n}\n\n/**\n * Post-hoc safety net: scan assembled CachedActions for fill/type values that\n * match known variable values (or literal `$var.` references) and assign\n * `variableKey`/`variableBindings` bindings when the live recording middleware\n * missed them.\n */\nexport function parameterizeActionsWithVariables(\n actions: CachedAction[],\n variableValues: Record<string, string>\n): CachedAction[] {\n const { keys, sorted, substringEntries } = buildVariableRewriteContext(variableValues);\n\n if (keys.size === 0) return actions;\n\n return actions.map((action) => {\n const normalizedAssertion =\n action.actionType === 'assert' && action.assertion\n ? normalizeAssertionSpecForStorage({\n assertion: action.assertion,\n variableValues,\n })\n : action.assertion;\n const actionWithNormalizedAssertion =\n normalizedAssertion && normalizedAssertion !== action.assertion\n ? {\n ...action,\n assertion: normalizedAssertion,\n }\n : action;\n\n // --- type/assert: set variableKey if not already set ---\n if (\n (actionWithNormalizedAssertion.actionType === 'type' ||\n actionWithNormalizedAssertion.actionType === 'assert') &&\n !actionWithNormalizedAssertion.variableKey\n ) {\n const text =\n actionWithNormalizedAssertion.actionType === 'assert'\n ? actionWithNormalizedAssertion.assertion?.condition\n : (actionWithNormalizedAssertion.args?.text ?? actionWithNormalizedAssertion.args?.value);\n if (typeof text === 'string') {\n const varKey = matchVariableKey(text, keys, sorted);\n if (varKey) {\n return { ...actionWithNormalizedAssertion, variableKey: varKey };\n }\n }\n }\n\n // --- fill_form: set variableBindings for unbound fields ---\n if (\n actionWithNormalizedAssertion.actionType === 'fill_form' &&\n Array.isArray(actionWithNormalizedAssertion.args?.fields)\n ) {\n const existingBindings = actionWithNormalizedAssertion.variableBindings ?? {};\n const newBindings: Record<string, string> = { ...existingBindings };\n let changed = false;\n for (let fi = 0; fi < actionWithNormalizedAssertion.args.fields.length; fi++) {\n const bindingKey = `fields.${fi}.value`;\n if (existingBindings[bindingKey]) continue;\n const fieldValue = (actionWithNormalizedAssertion.args.fields as Array<{ value?: unknown }>)[fi]\n ?.value;\n if (typeof fieldValue !== 'string') continue;\n const varKey = matchVariableKey(fieldValue, keys, sorted);\n if (varKey) {\n newBindings[bindingKey] = varKey;\n changed = true;\n }\n }\n if (changed) {\n return { ...actionWithNormalizedAssertion, variableBindings: newBindings };\n }\n }\n\n // --- navigate: rewrite substring occurrences of variable values in args.url\n // with `$var.<key>` tokens. Replay expands via resolveUrlForReplay. ---\n if (\n actionWithNormalizedAssertion.actionType === 'navigate' &&\n typeof actionWithNormalizedAssertion.args?.url === 'string' &&\n substringEntries.length > 0\n ) {\n const rewritten = replaceVariableValuesInString(\n actionWithNormalizedAssertion.args.url,\n substringEntries\n );\n if (rewritten !== actionWithNormalizedAssertion.args.url) {\n return {\n ...actionWithNormalizedAssertion,\n args: { ...actionWithNormalizedAssertion.args, url: rewritten },\n };\n }\n }\n\n // --- assert with evaluate: rewrite concrete variable values embedded in\n // the JS condition. resolveAssertionConditionForReplay expands $var.X\n // back via JSON.stringify at replay, yielding valid JS. ---\n if (\n actionWithNormalizedAssertion.actionType === 'assert' &&\n actionWithNormalizedAssertion.assertion?.type === 'evaluate' &&\n typeof actionWithNormalizedAssertion.assertion.condition === 'string' &&\n substringEntries.length > 0\n ) {\n const { condition } = actionWithNormalizedAssertion.assertion;\n const rewrittenCondition = replaceVariableValuesInJsExpression(condition, substringEntries);\n\n const argsValue = actionWithNormalizedAssertion.args?.value;\n const rewrittenArgsValue =\n typeof argsValue === 'string'\n ? replaceVariableValuesInJsExpression(argsValue, substringEntries)\n : argsValue;\n\n if (rewrittenCondition !== condition || rewrittenArgsValue !== argsValue) {\n return {\n ...actionWithNormalizedAssertion,\n assertion: {\n ...actionWithNormalizedAssertion.assertion,\n condition: rewrittenCondition,\n },\n args:\n typeof rewrittenArgsValue === 'string'\n ? { ...actionWithNormalizedAssertion.args, value: rewrittenArgsValue }\n : actionWithNormalizedAssertion.args,\n };\n }\n }\n\n return actionWithNormalizedAssertion;\n });\n}\n\n/**\n * Count the substring-substitution rewrites performed by\n * `parameterizeActionsWithVariables` between an input and output action array.\n * Only covers the navigate-URL and evaluate-assert branches — the pre-existing\n * type/assert/fill_form variable-key bindings are intentionally excluded\n * because they don't mutate user-visible action content.\n *\n * Arrays are expected to be the same length and in the same order (the\n * parameterize function is a 1:1 map).\n */\nexport function countVariableRewrites(\n before: CachedAction[],\n after: CachedAction[]\n): { navigateUrlRewrites: number; evaluateAssertRewrites: number } {\n let navigateUrlRewrites = 0;\n let evaluateAssertRewrites = 0;\n const n = Math.min(before.length, after.length);\n for (let i = 0; i < n; i++) {\n const b = before[i];\n const a = after[i];\n if (a.actionType === 'navigate' && b.args?.url !== a.args?.url) {\n navigateUrlRewrites++;\n }\n if (\n a.actionType === 'assert' &&\n a.assertion?.type === 'evaluate' &&\n b.assertion?.condition !== a.assertion?.condition\n ) {\n evaluateAssertRewrites++;\n }\n }\n return { navigateUrlRewrites, evaluateAssertRewrites };\n}\n\ninterface AssembleCachedActionsOptions {\n actions: CachedActionRecord[];\n macroResolutionLog?: MacroResolutionLog;\n agentMacroResolutions?: Map<string, string>;\n}\n\n/**\n * Convert runtime-recorded actions into persisted cache actions, preserving\n * macro source expressions through `macroBindings` when available.\n */\nexport function assembleCachedActionsForStorage(\n opts: AssembleCachedActionsOptions\n): CachedAction[] {\n const { actions, macroResolutionLog, agentMacroResolutions } = opts;\n\n return actions.map((action) => {\n const macroBindings = buildMacroBindingsForAction({\n action,\n macroResolutionLog,\n agentMacroResolutions,\n });\n\n return {\n index: action.index,\n toolName: action.toolName,\n actionType: action.actionType as CachedActionType,\n nodeId: action.nodeId,\n selectors: action.selectors,\n args: action.args,\n elementDescription: action.elementDescription,\n waitBefore: action.waitBefore,\n assertion:\n action.actionType === 'assert' && action.assertion\n ? normalizeAssertionSpecForStorage({\n assertion: action.assertion,\n macroResolutionLog,\n agentMacroResolutions,\n })\n : action.assertion,\n requiresAgent: action.requiresAgent,\n selectorAuthor: action.selectorAuthor,\n isAnnotation: action.isAnnotation,\n annotationType: action.annotationType,\n annotationColor: action.annotationColor,\n ...(macroBindings && { macroBindings }),\n ...(action.variableKey && { variableKey: action.variableKey }),\n ...(action.variableBindings && { variableBindings: action.variableBindings }),\n };\n });\n}\n","/**\n * Headless DOM Session\n *\n * One shared Chromium session for offline substrate capture and locator\n * verification. Substrate capture and verification MUST share one rendering\n * environment — viewport, screen, UA — or responsive/UA-dependent DOM\n * differences shift the aria-ref table between captures. Centralizing the\n * lifecycle here guarantees that invariant and halves the per-job Chromium\n * footprint versus each consumer owning a browser.\n *\n * The environment matches the scenario suite exactly: Desktop Chrome\n * descriptor + load-event hydration (`waitForTraceDomHydration`).\n *\n * Defense-in-depth: all http(s) requests are aborted on the context. Pages\n * are trace-reconstructed customer HTML loaded via `file://`; Chromium\n * already blocks file→file fetch/XHR by default, and the abort rule removes\n * the remaining network egress surface for hostile page scripts.\n *\n * @module optimizer/headless-session\n */\n\nimport { chromium, devices, type Browser, type BrowserContext, type Page } from 'playwright';\n\nexport class HeadlessDomSession {\n private browser: Browser | null = null;\n private context: BrowserContext | null = null;\n\n async page(): Promise<Page> {\n if (!this.context) {\n // Atomic init: never leave a launched browser without a context — a\n // half-open state would leak the process (close() nulls both) and make\n // the `context` access below unsound.\n const browser = await chromium.launch({ headless: true });\n try {\n const context = await browser.newContext({ ...devices['Desktop Chrome'] });\n await context.route(/^https?:/, (route) => route.abort());\n this.browser = browser;\n this.context = context;\n } catch (err) {\n await browser.close().catch(() => undefined);\n throw err;\n }\n }\n return this.context.newPage();\n }\n\n async close(): Promise<void> {\n await this.context?.close().catch(() => undefined);\n await this.browser?.close().catch(() => undefined);\n this.context = null;\n this.browser = null;\n }\n}\n","/**\n * Trace Node Segmenter\n *\n * Groups Playwright trace actions into per-workflow-node windows using the\n * named `tracing.group()` spans the executor opens around each step:\n *\n * - `Step N: <label>` — agent-executed node (the harvest target)\n * - `Cache Replay N: <name>` — replayed node. Still harvestable: L2 gap\n * healing and recovery actions are recorded INSIDE this group, so a step\n * that replayed with `l2_gap`/`recovery` healing carries its live agent\n * work here, not in a `Step N:` group. (Legacy traces omit the number.)\n * - `Canary Internal: <op>` — plumbing (snapshot capture, element resolution)\n *\n * Tolerant by design: failure-path traces leave the failing step's group\n * unclosed (no `after` event), so an open-ended group extends to the next\n * top-level group's start (or the end of the trace). Actions are assigned by\n * `parentId` containment when present, with a start-time window fallback.\n *\n * @module optimizer/trace-node-segmenter\n */\n\nimport type { TraceAction, TraceGroup } from '@chatsdet/trace-tools';\n\nexport type NodeSegmentKind = 'agent-step' | 'cache-replay';\n\nexport interface NodeSegment {\n kind: NodeSegmentKind;\n /** 1-based step number parsed from the `Step N:` / `Cache Replay N:` group name. */\n stepNumber?: number;\n /** Human label from the group name (node label or replayed node name). */\n label: string;\n /** The group's callId — actions inside carry it (transitively) as parentId. */\n groupCallId: string;\n startTime: number;\n /** Open-ended (failure path) segments extend to the next segment's start. */\n endTime?: number;\n /**\n * Trace actions inside this segment, with their index into the full\n * `parseTraceActions` array (the index `reconstructSnapshots` expects).\n */\n actions: Array<{ index: number; action: TraceAction }>;\n}\n\nconst STEP_GROUP = /^Step (\\d+): (.*)$/;\n// The step number is optional: traces recorded before the replay handler\n// numbered its groups carry the bare `Cache Replay: <name>` form.\nconst CACHE_REPLAY_GROUP = /^Cache Replay(?: (\\d+))?: (.*)$/;\nconst INTERNAL_GROUP_PREFIX = 'Canary Internal:';\n\n/**\n * Segment a run's trace actions into per-node windows.\n *\n * @param groups - from `parseTraceGroups(traceZipPath)`\n * @param actions - from `parseTraceActions(traceZipPath)` (indices must match)\n */\nexport function segmentTraceByNode(groups: TraceGroup[], actions: TraceAction[]): NodeSegment[] {\n // Top-level node groups only — internal groups nest inside step groups and\n // are excluded; their actions still belong to the enclosing step.\n const nodeGroups = groups.filter(\n (g) =>\n !g.name.startsWith(INTERNAL_GROUP_PREFIX) &&\n (STEP_GROUP.test(g.name) || CACHE_REPLAY_GROUP.test(g.name))\n );\n\n // Close open-ended groups at the next node group's start so a failure-path\n // trace (unclosed final group) still yields a usable window.\n const sorted = [...nodeGroups].sort((a, b) => a.startTime - b.startTime);\n const segments: NodeSegment[] = sorted.map((g, idx) => {\n const stepMatch = STEP_GROUP.exec(g.name);\n const replayMatch = CACHE_REPLAY_GROUP.exec(g.name);\n const effectiveEnd = g.endTime ?? sorted[idx + 1]?.startTime;\n const stepNumberRaw = stepMatch ? stepMatch[1] : replayMatch?.[1];\n return {\n kind: stepMatch ? ('agent-step' as const) : ('cache-replay' as const),\n stepNumber: stepNumberRaw !== undefined ? Number(stepNumberRaw) : undefined,\n label: stepMatch ? stepMatch[2]! : replayMatch![2]!,\n groupCallId: g.callId,\n startTime: g.startTime,\n endTime: effectiveEnd,\n actions: [],\n };\n });\n\n if (segments.length === 0) return segments;\n\n // parentId chain: group callId -> enclosing node-group callId (internal\n // groups resolve through their parents).\n const groupById = new Map(groups.map((g) => [g.callId, g]));\n const nodeGroupIds = new Set(segments.map((s) => s.groupCallId));\n const resolveNodeGroup = (parentId: string | undefined): string | undefined => {\n let current = parentId;\n // Bounded walk — trace group nesting is shallow; guard against cycles.\n for (let hops = 0; current && hops < 16; hops++) {\n if (nodeGroupIds.has(current)) return current;\n current = groupById.get(current)?.parentId;\n }\n return undefined;\n };\n\n const segmentByGroupId = new Map(segments.map((s) => [s.groupCallId, s]));\n for (let i = 0; i < actions.length; i++) {\n const action = actions[i]!;\n const byParent = resolveNodeGroup(action.parentId);\n if (byParent) {\n segmentByGroupId.get(byParent)!.actions.push({ index: i, action });\n continue;\n }\n // Fallback: start-time window (covers traces recorded before parentId\n // capture, and actions Playwright didn't parent into the group).\n const within = segments.find(\n (s) =>\n action.startTime >= s.startTime && (s.endTime === undefined || action.startTime < s.endTime)\n );\n within?.actions.push({ index: i, action });\n }\n\n return segments;\n}\n\n/** One run step, in `orderIndex` order, for segment→node resolution. */\nexport interface SegmentResolutionStep {\n nodeId: string | null;\n /** Display label as the executor derives it (the same string the trace group title used). */\n label: string;\n}\n\n/**\n * Resolve each segment to its workflow node id, in segment order.\n *\n * Numbered segments (`Step N:` / `Cache Replay N:`) resolve positionally via\n * `steps[N-1]`. Legacy un-numbered cache-replay segments fall back to label\n * matching, consuming steps forward-only so repeated labels map to successive\n * steps and a renamed/unknown label resolves to `null` rather than a wrong\n * node. Numbered segments advance the matching cursor past their own step.\n */\nexport function resolveSegmentNodeIds(\n segments: ReadonlyArray<Pick<NodeSegment, 'kind' | 'stepNumber' | 'label'>>,\n steps: ReadonlyArray<SegmentResolutionStep>\n): Array<string | null> {\n let cursor = 0;\n return segments.map((segment) => {\n if (segment.stepNumber !== undefined) {\n const idx = segment.stepNumber - 1;\n cursor = Math.max(cursor, idx + 1);\n return steps[idx]?.nodeId ?? null;\n }\n for (let j = cursor; j < steps.length; j++) {\n if (steps[j]!.label === segment.label) {\n cursor = j + 1;\n return steps[j]!.nodeId;\n }\n }\n return null;\n });\n}\n","/**\n * Substrate Materializer\n *\n * Lazily reconstructs a single trace action's DOM (Playwright trace viewer\n * decode) and captures a production substrate-v2 snapshot from it in a\n * headless page — the offline equivalent of the live capture path.\n *\n * Expensive (decodes the trace + drives a headless browser), so results are\n * memoized per (traceZipPath, actionIndex, phase) and the reconstructed\n * dom.html is persisted next to the substrate for the locator verifier.\n *\n * @module optimizer/substrate-materializer\n */\n\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n parseTraceActions,\n reconstructSnapshots,\n toMutationIndex,\n type TraceAction,\n} from '@chatsdet/trace-tools';\nimport { captureSubstrateV2, type BrowserLogger } from '@chatsdet/browser-core';\nimport { createLogger } from '../logger.js';\nimport { HeadlessDomSession } from './headless-session.js';\n\nconst logger = createLogger({ module: 'SubstrateMaterializer' });\n\nexport interface MaterializedSubstrate {\n /** Production substrate-v2 yaml captured over the reconstructed DOM. */\n substrateYaml: string;\n /** Path to the persisted substrate yaml. */\n substratePath: string;\n /** Path to the persisted self-contained dom.html (verifier input). */\n domPath: string;\n actionIndex: number;\n phase: 'before' | 'after';\n}\n\nexport interface SubstrateMaterializerOptions {\n traceZipPath: string;\n /** Output root; files land under `<outDir>/<actionIndex>.<phase>.*`. */\n outDir: string;\n logger?: BrowserLogger;\n /**\n * Shared headless session — pass the same instance to the LocatorVerifier\n * so capture and verification render identically (and one Chromium serves\n * both). When omitted the materializer owns (and closes) its own.\n */\n session?: HeadlessDomSession;\n}\n\n/**\n * Memoizing materializer bound to one trace + output dir. Shares one headless\n * browser across calls; `close()` must run when the session ends.\n */\nexport class SubstrateMaterializer {\n private readonly cache = new Map<string, MaterializedSubstrate>();\n\n private readonly session: HeadlessDomSession;\n private readonly ownsSession: boolean;\n /** Parsed trace actions in `actions.jsonl` order — lazy, parsed once. */\n private allActions: TraceAction[] | null = null;\n\n constructor(private readonly opts: SubstrateMaterializerOptions) {\n this.session = opts.session ?? new HeadlessDomSession();\n this.ownsSession = !opts.session;\n }\n\n /**\n * Reconstruct one action's snapshot and capture substrate-v2 over it.\n * `phase: 'before'` is the page state the action targeted (locator input);\n * `'after'` is its result (the next action's context).\n *\n * `actionIndex` is the action's position in `parseTraceActions` order — the\n * SAME index space as the workspace's `browser/actions.jsonl` and\n * `optimizer/segments.json` actionIndices. The mutation-filtered index the\n * snapshot reconstructor uses internally is remapped here; observation\n * actions (screenshots) are rejected with a self-correcting error.\n */\n async materialize(\n actionIndex: number,\n phase: 'before' | 'after' = 'before'\n ): Promise<MaterializedSubstrate> {\n const key = `${actionIndex}:${phase}`;\n const hit = this.cache.get(key);\n if (hit) return hit;\n\n this.allActions ??= parseTraceActions(this.opts.traceZipPath);\n const resolved = toMutationIndex(this.allActions, actionIndex);\n if (!resolved.ok) {\n throw new Error(resolved.reason);\n }\n\n const results = await reconstructSnapshots({\n traceZipPath: this.opts.traceZipPath,\n includeScreenshots: false,\n includeHtml: true,\n filter: phase,\n raw: false,\n actionIndex: resolved.mutationIndex,\n });\n const snapshot = results.find((r) => r.phase === phase && r.html);\n if (!snapshot?.html) {\n throw new Error(\n `No ${phase}-snapshot HTML reconstructable for trace action ${actionIndex} — ` +\n `the action may predate page load or the trace omitted its snapshot`\n );\n }\n\n await mkdir(this.opts.outDir, { recursive: true });\n // Resolve to an absolute path: callers may pass a relative outDir (e.g. the\n // CLI `--workspace ./dir`), and `file://<relative>` is an invalid URL that\n // fails `page.goto`. Absolute paths also make the returned dom/substrate\n // paths safe for the downstream locator verifier regardless of its cwd.\n const domPath = path.resolve(this.opts.outDir, `${actionIndex}.${phase}.dom.html`);\n await writeFile(domPath, snapshot.html, 'utf-8');\n\n const page = await this.session.page();\n try {\n await page.goto(pathToFileURL(domPath).href, { waitUntil: 'load' });\n await waitForTraceDomHydration(page);\n const substrateYaml = await captureSubstrateV2(page, this.opts.logger ?? logger);\n const substratePath = path.resolve(this.opts.outDir, `${actionIndex}.${phase}.substrate.v2.yaml`);\n await writeFile(substratePath, substrateYaml, 'utf-8');\n\n const out: MaterializedSubstrate = {\n substrateYaml,\n substratePath,\n domPath,\n actionIndex,\n phase,\n };\n this.cache.set(key, out);\n return out;\n } finally {\n await page.close().catch(() => undefined);\n }\n }\n\n async close(): Promise<void> {\n if (this.ownsSession) await this.session.close();\n }\n}\n\n/**\n * Trace-rendered HTML installs load/DOMContentLoaded handlers that restore\n * values, scroll positions, canvas placeholders, and visibility. Two frames\n * gives those handlers a stable post-load accessibility tree before refs are\n * materialized. (Same wait the scenario-suite locator runner uses.)\n */\nexport async function waitForTraceDomHydration(page: {\n evaluate: (fn: () => Promise<void>) => Promise<void>;\n}): Promise<void> {\n await page.evaluate(\n () =>\n new Promise<void>((resolve) => {\n requestAnimationFrame(() => requestAnimationFrame(() => resolve()));\n })\n );\n}\n","/**\n * Offline Locator Verifier\n *\n * Verifies a `SelectorStrategy` against a trace-reconstructed DOM without\n * touching the live application — the same bar the scenario suite's locator\n * runner enforces (`apps/api/tests/scenarios/runner.locator.pw.ts`), lifted\n * into an importable library:\n *\n * 1. Load the reconstructed dom.html in a headless page and let the trace\n * viewer's restore handlers settle.\n * 2. Materialize Playwright's internal aria-ref table via `ariaSnapshot`.\n * 3. Capture the ground-truth handle for the recorded target ref.\n * 4. Resolve the candidate strategy through the production `resolveElement`\n * (verify mode) and require handle identity with the ground truth.\n * 5. Reject strategies that lean on volatile identifier tokens (seeded entity\n * ids, framework-generated class hashes) via the shared classifier.\n *\n * A locator that fails here must degrade to a gap — never ship unverified.\n *\n * @module optimizer/locator-verifier\n */\n\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { SelectorStrategy } from '@chatsdet/types';\nimport { isVolatileIdentifier, stableIdentifierPrefix } from '@chatsdet/types';\nimport { resolveElement } from '../element-resolver.js';\nimport { hydrateDynamicSelectors } from '../selector-derivation.js';\nimport { waitForTraceDomHydration } from './substrate-materializer.js';\nimport { HeadlessDomSession } from './headless-session.js';\n\nexport interface LocatorVerification {\n /** Strategy resolved to exactly one element. */\n resolvesUniquely: boolean;\n /** Resolved element is the recorded target (handle identity). */\n matchesTarget: boolean;\n /** No identifying token classified as volatile. */\n volatileTokenClean: boolean;\n /** Volatile tokens found, for the agent to reason about. */\n volatileTokens: string[];\n /** All three checks passed. */\n verdict: boolean;\n /** Failure detail when verdict is false. */\n reason?: string;\n}\n\nconst RESOLVE_TIMEOUT_MS = 5_000;\n\n/**\n * Collect the identifying string tokens a strategy leans on, for the volatile\n * classifier. Role/label/text predicates are human-facing content (volatility\n * there is the variable-binding system's job); this pass guards the\n * machine-facing anchors: test ids, css hints, automation ids, and raw\n * locator chains.\n */\nfunction identifyingTokens(strategy: SelectorStrategy): string[] {\n const tokens: string[] = [];\n if (strategy.testId) tokens.push(strategy.testId);\n if (strategy.automationId) tokens.push(strategy.automationId);\n if (strategy.css) {\n // Class tokens and attribute values inside the css hint.\n for (const cls of strategy.css.matchAll(/\\.([A-Za-z0-9_-]+)/g)) tokens.push(cls[1]!);\n for (const attr of strategy.css.matchAll(/\\[[^\\]=]+=\"([^\"]+)\"\\]/g)) tokens.push(attr[1]!);\n }\n if (strategy.playwrightLocator) {\n for (const tid of strategy.playwrightLocator.matchAll(/getByTestId\\('([^']+)'\\)/g)) {\n tokens.push(tid[1]!);\n }\n }\n return tokens;\n}\n\nexport function classifyStrategyTokens(strategy: SelectorStrategy): {\n volatileTokenClean: boolean;\n volatileTokens: string[];\n} {\n const volatileTokens = identifyingTokens(strategy).filter(\n // A token with a stable prefix (e.g. `__new__<ts>`) is usable via prefix\n // matching — only fully-volatile tokens fail the pass.\n (t) => isVolatileIdentifier(t) && stableIdentifierPrefix(t) === null\n );\n return { volatileTokenClean: volatileTokens.length === 0, volatileTokens };\n}\n\nexport interface VerifyLocatorOptions {\n /** Path to the trace-reconstructed, self-contained dom.html. */\n domPath: string;\n /** The recorded target's aria-ref in the substrate captured over this DOM. */\n targetRef: string;\n strategy: SelectorStrategy;\n /** Variable values for hydrating dynamic selectors before resolution. */\n variableValues?: Record<string, string>;\n}\n\n/**\n * Shared-browser verifier bound to one optimization session. `close()` must\n * run when the session ends.\n */\nexport class LocatorVerifier {\n private readonly session: HeadlessDomSession;\n private readonly ownsSession: boolean;\n\n constructor(opts?: { session?: HeadlessDomSession }) {\n this.session = opts?.session ?? new HeadlessDomSession();\n this.ownsSession = !opts?.session;\n }\n\n async verify(opts: VerifyLocatorOptions): Promise<LocatorVerification> {\n const tokenPass = classifyStrategyTokens(opts.strategy);\n\n const page = await this.session.page();\n try {\n await page.goto(pathToFileURL(path.resolve(opts.domPath)).href, { waitUntil: 'load' });\n await waitForTraceDomHydration(page);\n\n // Materialize Playwright's internal ref table for this page so the\n // `aria-ref=` selector engine can resolve refs the substrate yaml points\n // at. ariaSnapshot itself does not write a DOM `aria-ref` attribute;\n // refs only exist within Playwright's snapshot engine.\n await page.ariaSnapshot({ mode: 'ai' });\n\n // Ground-truth handle immediately after the snapshot that created the\n // ref table — later locator probes can refresh refs.\n const truth = page.locator(`aria-ref=${opts.targetRef}`);\n const truthHandle = await truth.elementHandle({ timeout: RESOLVE_TIMEOUT_MS }).catch(() => null);\n if (!truthHandle) {\n return {\n resolvesUniquely: false,\n matchesTarget: false,\n ...tokenPass,\n verdict: false,\n reason: `target ref ${opts.targetRef} not present in the reconstructed DOM`,\n };\n }\n\n const hydrated =\n opts.variableValues && Object.keys(opts.variableValues).length > 0\n ? hydrateDynamicSelectors(opts.strategy, opts.variableValues)\n : opts.strategy;\n\n const resolved = await resolveElement(page, hydrated, RESOLVE_TIMEOUT_MS, {\n mode: 'verify',\n }).catch(() => null);\n if (!resolved) {\n await truthHandle.dispose().catch(() => undefined);\n return {\n resolvesUniquely: false,\n matchesTarget: false,\n ...tokenPass,\n verdict: false,\n reason: 'strategy did not resolve to a unique element',\n };\n }\n\n const resolvedHandle = await resolved\n .elementHandle({ timeout: RESOLVE_TIMEOUT_MS })\n .catch(() => null);\n let matchesTarget = false;\n try {\n if (resolvedHandle) {\n matchesTarget = await page.evaluate(\n ([a, b]) => a === b,\n [resolvedHandle, truthHandle] as const\n );\n }\n } finally {\n await resolvedHandle?.dispose().catch(() => undefined);\n await truthHandle.dispose().catch(() => undefined);\n }\n\n const verdict = matchesTarget && tokenPass.volatileTokenClean;\n return {\n resolvesUniquely: true,\n matchesTarget,\n ...tokenPass,\n verdict,\n reason: verdict\n ? undefined\n : !matchesTarget\n ? 'strategy resolved a different element than the recorded target'\n : `volatile identifier tokens: ${tokenPass.volatileTokens.join(', ')}`,\n };\n } finally {\n await page.close().catch(() => undefined);\n }\n }\n\n async close(): Promise<void> {\n if (this.ownsSession) await this.session.close();\n }\n}\n","/**\n * Augmentor Verifier\n *\n * The offline proof that a candidate custom augmentor actually heals a\n * semantic-snapshot blind spot — and does so cache-safely. Runs the SAME\n * engine the live runtime uses (`applyCustomAugmentors` from browser-core)\n * against a reconstructed DOM in a headless page, then gathers OBSERVABLE\n * evidence rather than trusting assertions:\n *\n * 1. baseline — capture substrate-v2; confirm the target (role,name)\n * elements are ABSENT (the blind spot reproduces);\n * 2. execute — run the validated collector for real (querySelectorAll →\n * collector(el) → setAttribute role/aria-label/data-augmentor-id);\n * 3. reappear — re-capture; confirm the previously-absent elements now\n * appear as real refs;\n * 4. targeting — resolve each new `aria-ref` back to a DOM node and confirm\n * it carries our `data-augmentor-id` (a click on the ref lands\n * on the intended element);\n * 5. cache-safe — strip the injected attributes and confirm each declared\n * `stableAnchor` still resolves UNIQUELY to its target, so a\n * cached locator can never depend on an injected attribute.\n *\n * Shares the headless Chromium with the {@link SubstrateMaterializer} /\n * {@link LocatorVerifier} so capture and verification render identically.\n *\n * @module optimizer/augmentor-verifier\n */\n\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n applyCustomAugmentors,\n captureSubstrateV2,\n parseSnapshot,\n type SnapshotElement,\n} from '@chatsdet/browser-core';\nimport type { AugmentorDefinition } from '@chatsdet/augmentor-core';\nimport { createLogger } from '../logger.js';\nimport { HeadlessDomSession } from './headless-session.js';\nimport { waitForTraceDomHydration } from './substrate-materializer.js';\n\nconst logger = createLogger({ module: 'AugmentorVerifier' });\n\nexport interface AugmentorVerificationResult {\n /** All gates passed: blind spot reproduced, healed, targetable, cache-safe. */\n verified: boolean;\n /** The target (role,name) elements were absent in the un-augmented snapshot. */\n baselineAbsent: boolean;\n /** Elements the collector annotated. */\n elementsAnnotated: number;\n /** Engine-reported invariant (count within [min,max]) for this run. */\n invariantPassed: boolean;\n /** The collector threw / timed out in the page. */\n errored: boolean;\n errorMessage?: string;\n /** Sample of the new refs that appeared (for the agent to eyeball). */\n sampleRefs: string[];\n /** Every sampled new ref resolved to an element carrying our data-augmentor-id. */\n refsResolveToTargets: boolean;\n /** Every declared stableAnchor resolves uniquely to its target post-strip. */\n cacheSafe: boolean;\n /** Annotated elements that declared no stableAnchor (perception-only, non-cacheable). */\n anchorlessCount: number;\n /** Collector wall-clock in the page. */\n durationMs: number;\n /** Human-readable reasons for any failed gate (the agent iterates on these). */\n issues: string[];\n}\n\nexport interface VerifyAugmentorOptions {\n /** Path to a reconstructed self-contained dom.html (from SubstrateMaterializer). */\n domPath: string;\n /** The candidate augmentor (id is used as the data-augmentor-id marker). */\n augmentor: AugmentorDefinition;\n}\n\n/** Flatten a parsed substrate tree to (role, name) → ref entries. */\nfunction flatten(roots: SnapshotElement[]): SnapshotElement[] {\n const out: SnapshotElement[] = [];\n const walk = (n: SnapshotElement): void => {\n out.push(n);\n for (const c of n.children) walk(c);\n };\n for (const r of roots) walk(r);\n return out;\n}\n\nconst key = (role: string, name: string | undefined): string => `${role}\\u0000${name ?? ''}`;\n\n/**\n * Offline verifier bound to one headless session. Pass the same session as the\n * materializer so the DOM renders identically; `close()` if this owns it.\n */\nexport class AugmentorVerifier {\n private readonly session: HeadlessDomSession;\n private readonly ownsSession: boolean;\n\n constructor(opts?: { session?: HeadlessDomSession }) {\n this.session = opts?.session ?? new HeadlessDomSession();\n this.ownsSession = !opts?.session;\n }\n\n async verify(opts: VerifyAugmentorOptions): Promise<AugmentorVerificationResult> {\n const { domPath, augmentor } = opts;\n const issues: string[] = [];\n const page = await this.session.page();\n try {\n await page.goto(pathToFileURL(path.resolve(domPath)).href, { waitUntil: 'load' });\n await waitForTraceDomHydration(page);\n\n // 1. Baseline — the blind spot must reproduce here.\n const baselineYaml = await captureSubstrateV2(page, logger);\n const baselineKeys = new Set(flatten(parseSnapshot(baselineYaml)).map((e) => key(e.role, e.text)));\n\n // 2. Execute the real engine (mutates the page in place).\n const pass = await applyCustomAugmentors(page, [augmentor], logger);\n const exec = pass.executions[0];\n const elementsAnnotated = exec?.elementsAnnotated ?? 0;\n const errored = exec?.errored ?? false;\n const invariantPassed = exec?.invariantPassed ?? false;\n const durationMs = exec?.durationMs ?? 0;\n if (errored) {\n issues.push(`collector errored in page: ${exec?.errorMessage ?? 'unknown'}`);\n }\n if (elementsAnnotated === 0) {\n issues.push('collector annotated 0 elements — matchSelector found nothing, or every descriptor was rejected');\n }\n\n // 3. Re-capture — the healed elements must now appear as real refs.\n const augmentedYaml = await captureSubstrateV2(page, logger);\n const augmentedEls = flatten(parseSnapshot(augmentedYaml));\n const annotatedKeys = new Set(pass.annotations.map((a) => key(a.role, a.name)));\n const newEls = augmentedEls.filter(\n (e) => annotatedKeys.has(key(e.role, e.text)) && !baselineKeys.has(key(e.role, e.text))\n );\n const baselineAbsent = pass.annotations.length > 0 && newEls.length > 0;\n if (!baselineAbsent && pass.annotations.length > 0) {\n issues.push(\n 'annotated (role,name) pairs were already present in the un-augmented snapshot — ' +\n 'this augmentor heals nothing (or the names are not distinctive)'\n );\n }\n // Targeting is a SAMPLE: we resolve the first 8 new refs, not all of them.\n // A collector that annotates many elements but mis-targets one past the\n // sample window can still pass — acceptable for a perception aid.\n const sampleRefs = newEls.slice(0, 8).map((e) => e.ref);\n\n // 4. Targeting — each sampled new ref must resolve to an augmented element.\n // Independent reads against a now-static page — resolve them concurrently.\n const targeting = await Promise.all(\n sampleRefs.map(async (ref) => {\n try {\n const handle = await page.$(`aria-ref=${ref}`);\n const augId = handle\n ? await handle.getAttribute('data-augmentor-id').catch(() => null)\n : null;\n await handle?.dispose();\n if (augId !== augmentor.id) {\n return `ref ${ref} did not resolve to an augmentor-annotated element`;\n }\n return null;\n } catch (err) {\n return `ref ${ref} could not be resolved: ${err instanceof Error ? err.message : String(err)}`;\n }\n })\n );\n const targetingIssues = targeting.filter((i): i is string => i !== null);\n for (const i of targetingIssues) issues.push(i);\n const refsResolveToTargets = sampleRefs.length > 0 && targetingIssues.length === 0;\n\n // 5. Cache-safety — strip the injected attributes and confirm each declared\n // stableAnchor still resolves uniquely to its own target. This is what\n // lets the live cache anchor on durable, un-injected signals.\n const cacheCheck = await page.evaluate(() => {\n const els = Array.from(document.querySelectorAll('[data-augmentor-id]'));\n let anchorless = 0;\n const failures: string[] = [];\n // Mark targets before stripping so we can re-identify them.\n els.forEach((el, i) => el.setAttribute('data-aug-verify-idx', String(i)));\n const anchors = els.map((el) => el.getAttribute('data-augmentor-anchor'));\n // Strip everything the engine injected (keep only the temp verify marker).\n for (const el of els) {\n el.removeAttribute('role');\n el.removeAttribute('aria-label');\n el.removeAttribute('aria-disabled');\n el.removeAttribute('data-augmentor-id');\n el.removeAttribute('data-augmentor-anchor');\n }\n els.forEach((el, i) => {\n const anchor = anchors[i];\n if (!anchor) {\n anchorless++;\n return;\n }\n // Bound the selector the page evaluates — a pathologically long /\n // deeply-combinated stableAnchor could otherwise spin CPU here.\n if (anchor.length > 500) {\n failures.push(`stableAnchor #${i} exceeds 500 chars — too complex to be durable: ${anchor.slice(0, 80)}…`);\n return;\n }\n let matches: Element[] = [];\n try {\n matches = Array.from(document.querySelectorAll(anchor));\n } catch {\n failures.push(`stableAnchor #${i} is not a valid selector: ${anchor}`);\n return;\n }\n if (matches.length !== 1) {\n failures.push(`stableAnchor #${i} matched ${matches.length} elements (want exactly 1): ${anchor}`);\n } else if (matches[0]?.getAttribute('data-aug-verify-idx') !== String(i)) {\n failures.push(`stableAnchor #${i} resolved to a different element than its target: ${anchor}`);\n }\n });\n return { anchorless, failures };\n });\n for (const f of cacheCheck.failures) issues.push(f);\n const cacheSafe = cacheCheck.failures.length === 0;\n if (cacheCheck.anchorless > 0) {\n issues.push(\n `${cacheCheck.anchorless} annotated element(s) declared no stableAnchor — they will be ` +\n 'visible to the agent but their locators stay irreducible (workflow-variable / L3 disambiguation)'\n );\n }\n\n const verified =\n baselineAbsent &&\n !errored &&\n invariantPassed &&\n elementsAnnotated > 0 &&\n refsResolveToTargets &&\n cacheSafe;\n\n return {\n verified,\n baselineAbsent,\n elementsAnnotated,\n invariantPassed,\n errored,\n errorMessage: exec?.errorMessage,\n sampleRefs,\n refsResolveToTargets,\n cacheSafe,\n anchorlessCount: cacheCheck.anchorless,\n durationMs,\n issues,\n };\n } finally {\n await page.close().catch(() => undefined);\n }\n }\n\n async close(): Promise<void> {\n if (this.ownsSession) await this.session.close();\n }\n}\n","/**\n * Action Synthesizer\n *\n * Converts an optimizer-authored per-step action plan into storable\n * `CachedAction[]` by routing through the SAME assembly functions the live\n * recording path uses (`assembleCachedActionsForStorage` +\n * `parameterizeActionsWithVariables`) — no parallel token logic.\n *\n * The plan carries the literal values observed in the trace; macro and\n * variable provenance from the run records lets the canonical assembly\n * reverse-map literals into `macroBindings` and `$var.X` bindings so the\n * recipe replays correctly on future runs with fresh values.\n *\n * @module optimizer/action-synthesizer\n */\n\nimport type { AssertionSpec, CachedAction, SelectorStrategy } from '@chatsdet/types';\nimport type { CachedActionRecord } from '../types.js';\nimport type { MacroResolutionLog } from '../macros/types.js';\nimport {\n assembleCachedActionsForStorage,\n parameterizeActionsWithVariables,\n} from '../cached-action-assembly.js';\n\n/**\n * One browser action on a node's most-direct path, as authored by the\n * optimizer agent. Values in `args` are the literals observed in the trace —\n * provenance mapping back to variables/macros is this module's job, not the\n * agent's.\n */\nexport interface PlannedBrowserAction {\n /** 1-based playbook step this action fulfills. */\n stepOrder: number;\n /** Tool name as the live agent would have called it (e.g. 'browser_click'). */\n toolName: string;\n /** Normalized action type (click | type | select_option | navigate | assert | …). */\n actionType: string;\n /** Literal tool args as observed in the trace (sanitized — no ephemeral refs). */\n args: Record<string, unknown>;\n /** Offline-verified selector strategy for the target element. */\n selectors?: SelectorStrategy;\n /** Human-readable target description. */\n elementDescription?: string;\n /** Assertion spec for assertion steps. */\n assertion?: AssertionSpec;\n}\n\n/**\n * Action types whose replay resolves a target element and therefore requires\n * a verified selector. Everything else (navigate, wait_for, assert, capture,\n * evaluate, screenshot, resize, scroll, …) replays without one.\n */\nconst ELEMENT_TARGET_ACTION_TYPES = new Set([\n 'click',\n 'type',\n 'select_option',\n 'fill_form',\n 'hover',\n 'drag',\n 'file_upload',\n 'move',\n]);\n\nexport interface SynthesizeActionsOptions {\n nodeId: string;\n planned: PlannedBrowserAction[];\n /** Macro provenance from the run records (expression → resolved value, keyed by input field). */\n macroResolutionLog?: MacroResolutionLog;\n /** Ad-hoc macro resolutions the agent rolled mid-run (resolved value → expression). */\n agentMacroResolutions?: Map<string, string>;\n /** Variable values in effect during the source run (for `$var.X` reverse-mapping). */\n variableValues?: Record<string, string>;\n}\n\n/**\n * Build storable `CachedAction[]` from the optimizer's plan via the canonical\n * assembly pipeline. Action indices are assigned by plan position.\n */\nexport function synthesizeCachedActions(opts: SynthesizeActionsOptions): CachedAction[] {\n const records: CachedActionRecord[] = opts.planned.map((p, i) => ({\n index: i,\n toolName: p.toolName,\n actionType: p.actionType,\n nodeId: opts.nodeId,\n selectors: p.selectors,\n args: p.args,\n elementDescription: p.elementDescription,\n assertion: p.assertion,\n // Only element-targeting actions need a selector; selectorless\n // deterministic actions (navigate, wait_for, assert, capture, …) must\n // replay structurally — flagging them requiresAgent would make step-driven\n // replay treat the whole step as a gap and wake the healing agent.\n requiresAgent: ELEMENT_TARGET_ACTION_TYPES.has(p.actionType) && !p.selectors,\n selectorAuthor: p.selectors ? ('deterministic' as const) : undefined,\n }));\n\n const assembled = assembleCachedActionsForStorage({\n actions: records,\n macroResolutionLog: opts.macroResolutionLog,\n agentMacroResolutions: opts.agentMacroResolutions,\n });\n\n return opts.variableValues && Object.keys(opts.variableValues).length > 0\n ? parameterizeActionsWithVariables(assembled, opts.variableValues)\n : assembled;\n}\n","/**\n * Cache Recipe Builder\n *\n * Pure constructor for the optimizer's commit payload: validates the authored\n * playbook + action plan, synthesizes storable actions through the canonical\n * assembly, aligns compiled entries to playbook order, and enforces the\n * lossless-token rule (every variable/macro the node depends on survives into\n * the recipe verbatim).\n *\n * Deliberately hash-free: the node hash is recomputed SERVER-side at commit\n * (`commit-node-cache.ts`) from the node context with this playbook applied —\n * a client-supplied hash is never trusted.\n *\n * @module optimizer/recipe\n */\n\nimport type { CachedAction, PlaybookStep } from '@chatsdet/types';\nimport type { StoredCompiledEntry } from '../types.js';\nimport { synthesizeCachedActions, type PlannedBrowserAction } from './action-synthesizer.js';\nimport type { MacroResolutionLog } from '../macros/types.js';\nimport { MACRO_PATTERN } from '@chatsdet/types';\n\n/** Steps the optimizer marks as agent-handled at replay (non-browser effects, unverifiable locators). */\nexport interface PlannedGap {\n stepOrder: number;\n /** Why this step is a gap (surfaced in compilation meta + agent prompt at replay). */\n reason: string;\n}\n\nexport interface BuildRecipeOptions {\n nodeId: string;\n /** Most-direct-path playbook (core actions only, tokens verbatim). */\n playbookSteps: PlaybookStep[];\n /** Browser actions fulfilling playbook steps (literal values; provenance mapped here). */\n plannedActions: PlannedBrowserAction[];\n /** Steps without a cached action (non-browser effects, unverifiable locators). */\n gaps: PlannedGap[];\n /** Macro provenance from run records. */\n macroResolutionLog?: MacroResolutionLog;\n agentMacroResolutions?: Map<string, string>;\n /** Variable values in effect during the source run. */\n variableValues?: Record<string, string>;\n /**\n * Tokens the node's previous recipe/playbook depended on (`$var.x`,\n * `$EMAIL()`, …). The new recipe must still reference every one of them —\n * a dropped token means the optimizer inlined a run-specific value.\n */\n requiredTokens?: string[];\n}\n\nexport interface CacheRecipe {\n playbookSteps: PlaybookStep[];\n actionsJson: CachedAction[];\n compiledEntriesJson: StoredCompiledEntry[];\n /** Gap reasons keyed by step order (for compilation meta / diagnostics). */\n gapReasons: Record<number, string>;\n}\n\nexport class RecipeValidationError extends Error {\n readonly _tag = 'RecipeValidationError';\n constructor(\n message: string,\n readonly issues: string[]\n ) {\n // Issues inline in the message — agents and CLI users see the actionable\n // detail without unwrapping the error object.\n super(issues.length > 0 ? `${message}: ${issues.join('; ')}` : message);\n this.name = 'RecipeValidationError';\n }\n}\n\nconst VAR_TOKEN = /\\$var\\.[A-Za-z0-9_.]+/g;\n// Fresh instance of the shared macro pattern — module-level, hoisted out of the\n// visitor. Safe with matchAll (which clones and never mutates lastIndex).\nconst MACRO_TOKEN = new RegExp(MACRO_PATTERN.source, 'g');\n\n/** Collect `$var.x` and `$MACRO()` tokens appearing anywhere in a JSON value. */\nexport function collectTokens(value: unknown): Set<string> {\n const out = new Set<string>();\n const visit = (v: unknown): void => {\n if (typeof v === 'string') {\n for (const m of v.matchAll(VAR_TOKEN)) out.add(m[0]);\n for (const m of v.matchAll(MACRO_TOKEN)) out.add(m[0]);\n } else if (Array.isArray(v)) {\n v.forEach(visit);\n } else if (v && typeof v === 'object') {\n Object.values(v).forEach(visit);\n }\n };\n visit(value);\n return out;\n}\n\n/**\n * Build and validate the commit payload. Throws `RecipeValidationError` when\n * the plan is structurally unsound or drops a required token — the optimizer\n * agent reads the issues and retries.\n */\nexport function buildCacheRecipe(opts: BuildRecipeOptions): CacheRecipe {\n const issues: string[] = [];\n\n // ── Structural alignment ──\n const orders = opts.playbookSteps.map((s) => s.order).sort((a, b) => a - b);\n const expected = Array.from({ length: orders.length }, (_, i) => i + 1);\n if (orders.length === 0) issues.push('playbookSteps is empty');\n if (JSON.stringify(orders) !== JSON.stringify(expected)) {\n issues.push(`playbook step orders must be contiguous from 1; got [${orders.join(', ')}]`);\n }\n\n const actionByOrder = new Map<number, PlannedBrowserAction>();\n for (const a of opts.plannedActions) {\n if (actionByOrder.has(a.stepOrder)) {\n issues.push(`step ${a.stepOrder} has more than one planned action (one action per step)`);\n }\n actionByOrder.set(a.stepOrder, a);\n }\n const gapByOrder = new Map(opts.gaps.map((g) => [g.stepOrder, g]));\n\n for (const step of opts.playbookSteps) {\n const hasAction = actionByOrder.has(step.order);\n const hasGap = gapByOrder.has(step.order);\n if (hasAction && hasGap) issues.push(`step ${step.order} is both a cached action and a gap`);\n if (!hasAction && !hasGap) {\n issues.push(`step ${step.order} (\"${step.target}\") has neither a planned action nor a gap`);\n }\n }\n for (const order of [...actionByOrder.keys(), ...gapByOrder.keys()]) {\n if (!opts.playbookSteps.some((s) => s.order === order)) {\n issues.push(`planned action/gap references step ${order} which is not in the playbook`);\n }\n }\n\n if (issues.length > 0) {\n throw new RecipeValidationError('Recipe plan is structurally unsound', issues);\n }\n\n // ── Synthesis through the canonical assembly ──\n const ordered = [...actionByOrder.entries()].sort((a, b) => a[0] - b[0]);\n const actionsJson = synthesizeCachedActions({\n nodeId: opts.nodeId,\n planned: ordered.map(([, a]) => a),\n macroResolutionLog: opts.macroResolutionLog,\n agentMacroResolutions: opts.agentMacroResolutions,\n variableValues: opts.variableValues,\n });\n const selectorlessElementActions = actionsJson\n .map((action, index) => ({ action, stepOrder: ordered[index]?.[0] }))\n .filter(({ action }) => action.requiresAgent);\n if (selectorlessElementActions.length > 0) {\n throw new RecipeValidationError(\n 'Recipe contains cached actions without verified selectors',\n selectorlessElementActions.map(({ action, stepOrder }) => {\n const orderLabel = stepOrder === undefined ? 'unknown step' : `step ${stepOrder}`;\n return `${orderLabel}: ${action.actionType} requires a verified selector; call build_locator or mark the step as a gap`;\n })\n );\n }\n const actionIndexByOrder = new Map(ordered.map(([order], i) => [order, i]));\n\n // ── Lossless-token check ──\n // Tokens must survive into the playbook or the parameterized actions\n // (macro provenance lands as macroBindings, variable provenance as\n // variableKey/variableBindings or $var literals).\n if (opts.requiredTokens?.length) {\n const present = collectTokens({ playbook: opts.playbookSteps, actions: actionsJson });\n const bindingKeys = new Set<string>();\n for (const a of actionsJson) {\n if (a.variableKey) bindingKeys.add(`$var.${a.variableKey}`);\n for (const key of Object.values(a.variableBindings ?? {})) bindingKeys.add(`$var.${key}`);\n for (const expr of Object.values(a.macroBindings ?? {})) bindingKeys.add(expr);\n // A capture PRODUCES its variable — the strongest possible way for a\n // recipe to preserve `$var.<saveAs>`.\n if (a.actionType === 'capture' && typeof a.args?.saveAs === 'string' && a.args.saveAs) {\n bindingKeys.add(`$var.${a.args.saveAs}`);\n }\n }\n const missing = opts.requiredTokens.filter((t) => !present.has(t) && !bindingKeys.has(t));\n if (missing.length > 0) {\n throw new RecipeValidationError(\n 'Recipe drops required variable/macro tokens — run-specific values were inlined',\n missing.map((t) => `missing token: ${t}`)\n );\n }\n }\n\n // ── Compiled entries aligned to playbook order ──\n const gapReasons: Record<number, string> = {};\n const compiledEntriesJson: StoredCompiledEntry[] = opts.playbookSteps\n .slice()\n .sort((a, b) => a.order - b.order)\n .map((step) => {\n const gap = gapByOrder.get(step.order);\n if (gap) {\n gapReasons[step.order] = gap.reason;\n return { type: 'gap' as const, stepOrder: step.order };\n }\n return {\n type: 'cached' as const,\n stepOrder: step.order,\n actionIndices: [actionIndexByOrder.get(step.order)!],\n };\n });\n\n return { playbookSteps: opts.playbookSteps, actionsJson, compiledEntriesJson, gapReasons };\n}\n","/**\n * Macro resolver types.\n *\n * @module macros/types\n */\n\n/** Mutable context shared across a single workflow run for stateful macros like $SEQUENCE(). */\nexport interface MacroResolutionContext {\n /** Per-name counters for $SEQUENCE() — resets between runs. */\n sequenceCounters: Map<string, number>;\n /** Cached LLM resolutions for $AI(prompt), keyed by stripped prompt — populated by the AI prepass before sync resolution. */\n aiResolutions: Map<string, string>;\n}\n\n/** Record of a single macro resolution (expression → resolved value). */\nexport interface MacroResolution {\n /** Original macro expression, e.g. \"$UUID()\" */\n expression: string;\n /** Resolved output, e.g. \"a1b2c3d4-...\" */\n resolved: string;\n}\n\n/**\n * Maps input field names to their macro resolutions.\n * Used by cache recording to map resolved values back to expressions.\n */\nexport type MacroResolutionLog = Map<string, MacroResolution>;\n\nexport class MacroUnknownError extends Error {\n readonly _tag = 'MacroUnknownError';\n constructor(macroName: string) {\n super(`Unknown macro: $${macroName}()`);\n this.name = 'MacroUnknownError';\n }\n}\n\nexport class MacroArgError extends Error {\n readonly _tag = 'MacroArgError';\n constructor(macroName: string, message: string) {\n super(`$${macroName}(): ${message}`);\n this.name = 'MacroArgError';\n }\n}\n","/**\n * Built-in macro definitions.\n *\n * @module macros/registry\n *\n * Each macro is a pure function that takes parsed args and a resolution context,\n * returning a string. No Effect dependency — these are synchronous utilities.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { MacroResolutionContext } from './types.js';\nimport { MacroArgError } from './types.js';\n\ntype MacroFn = (args: string[], ctx: MacroResolutionContext) => string;\n\nconst FIRST_NAMES = [\n 'Jordan',\n 'Alex',\n 'Taylor',\n 'Morgan',\n 'Casey',\n 'Riley',\n 'Quinn',\n 'Avery',\n 'Cameron',\n 'Dakota',\n 'Sage',\n 'Rowan',\n 'Hayden',\n 'Finley',\n 'Emery',\n 'Reese',\n 'Charlie',\n 'Drew',\n 'Blake',\n 'Skyler',\n];\n\nconst LAST_NAMES = [\n 'Chen',\n 'Smith',\n 'Patel',\n 'Kim',\n 'Garcia',\n 'Johnson',\n 'Williams',\n 'Brown',\n 'Jones',\n 'Miller',\n 'Davis',\n 'Wilson',\n 'Moore',\n 'Taylor',\n 'Anderson',\n 'Thomas',\n 'Jackson',\n 'White',\n 'Harris',\n 'Martin',\n];\n\nconst ALPHANUMERIC = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\n\nfunction randomAlphanumeric(length: number): string {\n let result = '';\n for (let i = 0; i < length; i++) {\n result += ALPHANUMERIC[Math.floor(Math.random() * ALPHANUMERIC.length)];\n }\n return result;\n}\n\nfunction randomItem<T>(arr: readonly T[]): T {\n return arr[Math.floor(Math.random() * arr.length)]!;\n}\n\nfunction formatDate(d: Date): string {\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;\n}\n\nfunction parseIntArg(macroName: string, argName: string, value: string): number {\n const trimmed = value.trim();\n const parsed = Number(trimmed);\n if (!Number.isInteger(parsed)) {\n throw new MacroArgError(macroName, `${argName} must be an integer, got \"${trimmed}\"`);\n }\n return parsed;\n}\n\nconst BUILTIN_MACROS: Record<string, MacroFn> = {\n UUID: () => randomUUID(),\n\n NOW: () => new Date().toISOString(),\n\n TODAY: () => formatDate(new Date()),\n\n DATE: (args) => {\n if (args.length !== 1) {\n throw new MacroArgError('DATE', `expected 1 arg (days), got ${args.length}`);\n }\n const days = parseIntArg('DATE', 'days', args[0]!);\n const d = new Date();\n d.setDate(d.getDate() + days);\n return formatDate(d);\n },\n\n TIMESTAMP: () => String(Date.now()),\n\n RANDOM_INT: (args, _ctx) => {\n if (args.length !== 2) {\n throw new MacroArgError('RANDOM_INT', `expected 2 args (min, max), got ${args.length}`);\n }\n const min = parseIntArg('RANDOM_INT', 'min', args[0]!);\n const max = parseIntArg('RANDOM_INT', 'max', args[1]!);\n if (min > max) {\n throw new MacroArgError('RANDOM_INT', `min (${min}) must be <= max (${max})`);\n }\n return String(Math.floor(Math.random() * (max - min + 1)) + min);\n },\n\n RANDOM_STRING: (args) => {\n if (args.length !== 1) {\n throw new MacroArgError('RANDOM_STRING', `expected 1 arg (length), got ${args.length}`);\n }\n const length = parseIntArg('RANDOM_STRING', 'length', args[0]!);\n if (length < 1 || length > 1000) {\n throw new MacroArgError('RANDOM_STRING', `length must be 1–1000, got ${length}`);\n }\n return randomAlphanumeric(length);\n },\n\n EMAIL: () => {\n const id = randomAlphanumeric(8).toLowerCase();\n return `test-${id}@example-test.com`;\n },\n\n FIRST_NAME: () => randomItem(FIRST_NAMES),\n\n LAST_NAME: () => randomItem(LAST_NAMES),\n\n PHONE: () => {\n const rand = () => Math.floor(Math.random() * 10);\n // Generate +1-555-XXX-XXXX (555 ensures non-real number)\n return `+1-555-${rand()}${rand()}${rand()}-${rand()}${rand()}${rand()}${rand()}`;\n },\n\n SEQUENCE: (args, ctx) => {\n if (args.length !== 1) {\n throw new MacroArgError('SEQUENCE', `expected 1 arg (name), got ${args.length}`);\n }\n const name = stripQuotes(args[0]!);\n if (!name) {\n throw new MacroArgError('SEQUENCE', 'name cannot be empty');\n }\n const current = ctx.sequenceCounters.get(name) ?? 0;\n const next = current + 1;\n ctx.sequenceCounters.set(name, next);\n return String(next);\n },\n\n AI: (args, ctx) => {\n if (args.length !== 1) {\n throw new MacroArgError('AI', `expected 1 arg (prompt), got ${args.length}`);\n }\n const prompt = stripQuotes(args[0]!);\n if (!prompt) {\n throw new MacroArgError('AI', 'prompt cannot be empty');\n }\n const cached = ctx.aiResolutions.get(prompt);\n if (cached === undefined) {\n throw new MacroArgError(\n 'AI',\n `no cached resolution for prompt \"${prompt}\" — the AI prepass must run before sync resolution`\n );\n }\n return cached;\n },\n};\n\n/** Strip surrounding single or double quotes (and trim) from a macro arg. Exported for the AI prepass. */\nexport function stripQuotes(value: string): string {\n return value.trim().replace(/^[\"']|[\"']$/g, '');\n}\n\n/** Look up a built-in macro function by name. Returns undefined if not found. */\nexport function getMacro(name: string): MacroFn | undefined {\n return BUILTIN_MACROS[name];\n}\n\n/** All registered macro names. */\nexport function getMacroNames(): string[] {\n return Object.keys(BUILTIN_MACROS);\n}\n","/**\n * Macro resolution engine.\n *\n * @module macros/resolver\n *\n * Pure utility functions for detecting, extracting, and resolving macro\n * expressions in strings. No Effect dependency.\n */\n\nimport { MACRO_PATTERN } from '@chatsdet/types';\nimport type { MacroResolutionContext, MacroResolutionLog } from './types.js';\nimport { MacroUnknownError } from './types.js';\nimport { getMacro } from './registry.js';\n\n/** Create a fresh resolution context for a new workflow run. */\nexport function createMacroContext(): MacroResolutionContext {\n return { sequenceCounters: new Map(), aiResolutions: new Map() };\n}\n\n/** Fast check: does the value contain at least one macro expression? */\nexport function containsMacro(value: string): boolean {\n // Reset lastIndex since MACRO_PATTERN has the global flag\n MACRO_PATTERN.lastIndex = 0;\n return MACRO_PATTERN.test(value);\n}\n\n/** Extract all macro expressions from a string (e.g. [\"$UUID()\", \"$EMAIL()\"]). */\nexport function extractMacroExpressions(value: string): string[] {\n MACRO_PATTERN.lastIndex = 0;\n const results: string[] = [];\n let match: RegExpExecArray | null;\n while ((match = MACRO_PATTERN.exec(value)) !== null) {\n results.push(match[0]);\n }\n return results;\n}\n\n/**\n * Resolve all macro expressions in a string, returning the result with\n * macros replaced by their generated values.\n *\n * Escaped macros (\\$MACRO()) are preserved as literal $MACRO().\n *\n * @throws MacroUnknownError if an unrecognized macro name is encountered\n * @throws MacroArgError if macro arguments are invalid\n */\nexport function resolveMacros(value: string, ctx: MacroResolutionContext): string {\n MACRO_PATTERN.lastIndex = 0;\n const result = value.replace(MACRO_PATTERN, (fullMatch, name: string, argsStr: string) => {\n const macroFn = getMacro(name);\n if (!macroFn) {\n throw new MacroUnknownError(name);\n }\n const args = argsStr.length > 0 ? argsStr.split(',') : [];\n return macroFn(args, ctx);\n });\n\n // Unescape \\$ → $\n return result.replace(/\\\\\\$/g, '$');\n}\n\n/**\n * Resolve macros in all values of a Record<string, string>.\n * Returns the resolved map and a log of what was resolved.\n */\nexport function resolveMacrosInRecord(\n values: Record<string, string>,\n ctx: MacroResolutionContext,\n): {\n resolved: Record<string, string>;\n log: Map<string, { expression: string; resolved: string }>;\n} {\n const resolved: Record<string, string> = {};\n const log = new Map<string, { expression: string; resolved: string }>();\n\n for (const [key, value] of Object.entries(values)) {\n if (containsMacro(value)) {\n const resolvedValue = resolveMacros(value, ctx);\n resolved[key] = resolvedValue;\n log.set(key, { expression: value, resolved: resolvedValue });\n } else {\n resolved[key] = value;\n }\n }\n\n return { resolved, log };\n}\n\n/**\n * Resolve macros in a node's inputValues and update workflowState.\n * Returns the resolved inputValues and a resolution log.\n */\nexport function resolveNodeInputMacros(\n inputValues: Record<string, string> | undefined,\n ctx: MacroResolutionContext,\n workflowState: Record<string, unknown>,\n): {\n resolvedValues: Record<string, string> | undefined;\n macroResolutionLog: MacroResolutionLog | undefined;\n} {\n if (!inputValues) return { resolvedValues: undefined, macroResolutionLog: undefined };\n\n const hasMacros = Object.values(inputValues).some((v) => containsMacro(v));\n if (!hasMacros) return { resolvedValues: inputValues, macroResolutionLog: undefined };\n\n const { resolved, log } = resolveMacrosInRecord(inputValues, ctx);\n for (const [key, { resolved: val }] of log.entries()) {\n workflowState[`macro:${key}`] = val;\n }\n return { resolvedValues: resolved, macroResolutionLog: log };\n}\n"],"mappings":"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","names":["logger","key","value","key","key","key","escapeRegex","_logger","_","elapsed","visStart","visibilityWaitMs","validated","errorMsg","key","_logger","getLogger","key","node","logger","escapeRegex","key","logger","key","path","pathToFileURL","RESOLVE_TIMEOUT_MS","pathToFileURL","path","path","pathToFileURL","logger","flatten","pathToFileURL","path","key","key"]}