swipium 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (387) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +295 -0
  3. package/dist/appMap/automationLink.js +74 -0
  4. package/dist/appMap/automationLink.js.map +1 -0
  5. package/dist/appMap/build.js +193 -0
  6. package/dist/appMap/build.js.map +1 -0
  7. package/dist/appMap/codeIndex.js +73 -0
  8. package/dist/appMap/codeIndex.js.map +1 -0
  9. package/dist/appMap/featureModel.js +83 -0
  10. package/dist/appMap/featureModel.js.map +1 -0
  11. package/dist/appMap/firstRunApply.js +131 -0
  12. package/dist/appMap/firstRunApply.js.map +1 -0
  13. package/dist/appMap/fsWalk.js +75 -0
  14. package/dist/appMap/fsWalk.js.map +1 -0
  15. package/dist/appMap/issues.js +227 -0
  16. package/dist/appMap/issues.js.map +1 -0
  17. package/dist/appMap/migrations.js +87 -0
  18. package/dist/appMap/migrations.js.map +1 -0
  19. package/dist/appMap/prelaunch.js +66 -0
  20. package/dist/appMap/prelaunch.js.map +1 -0
  21. package/dist/appMap/projectRegistry.js +70 -0
  22. package/dist/appMap/projectRegistry.js.map +1 -0
  23. package/dist/appMap/provenance.js +52 -0
  24. package/dist/appMap/provenance.js.map +1 -0
  25. package/dist/appMap/query.js +118 -0
  26. package/dist/appMap/query.js.map +1 -0
  27. package/dist/appMap/runtimeMerge.js +207 -0
  28. package/dist/appMap/runtimeMerge.js.map +1 -0
  29. package/dist/appMap/schema.js +65 -0
  30. package/dist/appMap/schema.js.map +1 -0
  31. package/dist/appMap/screenMatch.js +75 -0
  32. package/dist/appMap/screenMatch.js.map +1 -0
  33. package/dist/appMap/staticScan.js +614 -0
  34. package/dist/appMap/staticScan.js.map +1 -0
  35. package/dist/appMap/store.js +173 -0
  36. package/dist/appMap/store.js.map +1 -0
  37. package/dist/appMap/tsAstScan.js +184 -0
  38. package/dist/appMap/tsAstScan.js.map +1 -0
  39. package/dist/artifacts/bundletool.js +199 -0
  40. package/dist/artifacts/bundletool.js.map +1 -0
  41. package/dist/artifacts/resolve.js +388 -0
  42. package/dist/artifacts/resolve.js.map +1 -0
  43. package/dist/automationGen/appiumModel.js +129 -0
  44. package/dist/automationGen/appiumModel.js.map +1 -0
  45. package/dist/automationGen/ciEmitter.js +80 -0
  46. package/dist/automationGen/ciEmitter.js.map +1 -0
  47. package/dist/automationGen/jsEmitter.js +440 -0
  48. package/dist/automationGen/jsEmitter.js.map +1 -0
  49. package/dist/automationGen/packagePatch.js +56 -0
  50. package/dist/automationGen/packagePatch.js.map +1 -0
  51. package/dist/automationGen/projectProfile.js +317 -0
  52. package/dist/automationGen/projectProfile.js.map +1 -0
  53. package/dist/automationGen/pythonEmitter.js +386 -0
  54. package/dist/automationGen/pythonEmitter.js.map +1 -0
  55. package/dist/automationGen/readmeEmitter.js +66 -0
  56. package/dist/automationGen/readmeEmitter.js.map +1 -0
  57. package/dist/automationGen/suitePlan.js +94 -0
  58. package/dist/automationGen/suitePlan.js.map +1 -0
  59. package/dist/automationGen/validation.js +150 -0
  60. package/dist/automationGen/validation.js.map +1 -0
  61. package/dist/build/parseBuildLog.js +119 -0
  62. package/dist/build/parseBuildLog.js.map +1 -0
  63. package/dist/build/plan.js +150 -0
  64. package/dist/build/plan.js.map +1 -0
  65. package/dist/ci/preflight.js +85 -0
  66. package/dist/ci/preflight.js.map +1 -0
  67. package/dist/cli/init.js +105 -0
  68. package/dist/cli/init.js.map +1 -0
  69. package/dist/cli/scan.js +85 -0
  70. package/dist/cli/scan.js.map +1 -0
  71. package/dist/cli/suite.js +85 -0
  72. package/dist/cli/suite.js.map +1 -0
  73. package/dist/cli/verify.js +62 -0
  74. package/dist/cli/verify.js.map +1 -0
  75. package/dist/consent/consent.js +43 -0
  76. package/dist/consent/consent.js.map +1 -0
  77. package/dist/context/detect.js +156 -0
  78. package/dist/context/detect.js.map +1 -0
  79. package/dist/context/findApps.js +198 -0
  80. package/dist/context/findApps.js.map +1 -0
  81. package/dist/context/projectRoot.js +41 -0
  82. package/dist/context/projectRoot.js.map +1 -0
  83. package/dist/context/scan.js +167 -0
  84. package/dist/context/scan.js.map +1 -0
  85. package/dist/core/target.js +115 -0
  86. package/dist/core/target.js.map +1 -0
  87. package/dist/core/targetPlan.js +140 -0
  88. package/dist/core/targetPlan.js.map +1 -0
  89. package/dist/drivers/DirectDriver.js +228 -0
  90. package/dist/drivers/DirectDriver.js.map +1 -0
  91. package/dist/drivers/Driver.js +4 -0
  92. package/dist/drivers/Driver.js.map +1 -0
  93. package/dist/drivers/SimctlDriver.js +127 -0
  94. package/dist/drivers/SimctlDriver.js.map +1 -0
  95. package/dist/drivers/WdaDriver.js +250 -0
  96. package/dist/drivers/WdaDriver.js.map +1 -0
  97. package/dist/explore/candidates.js +93 -0
  98. package/dist/explore/candidates.js.map +1 -0
  99. package/dist/explore/graph.js +116 -0
  100. package/dist/explore/graph.js.map +1 -0
  101. package/dist/explore/memory.js +35 -0
  102. package/dist/explore/memory.js.map +1 -0
  103. package/dist/explore/planner.js +105 -0
  104. package/dist/explore/planner.js.map +1 -0
  105. package/dist/explore/policy.js +85 -0
  106. package/dist/explore/policy.js.map +1 -0
  107. package/dist/explore/runner.js +475 -0
  108. package/dist/explore/runner.js.map +1 -0
  109. package/dist/explore/signatures.js +35 -0
  110. package/dist/explore/signatures.js.map +1 -0
  111. package/dist/explore/suite.js +55 -0
  112. package/dist/explore/suite.js.map +1 -0
  113. package/dist/featureTesting/executionBootstrap.js +140 -0
  114. package/dist/featureTesting/executionBootstrap.js.map +1 -0
  115. package/dist/firstRun/authStateMachine.js +83 -0
  116. package/dist/firstRun/authStateMachine.js.map +1 -0
  117. package/dist/firstRun/classifyScreen.js +201 -0
  118. package/dist/firstRun/classifyScreen.js.map +1 -0
  119. package/dist/firstRun/firstRunPlanner.js +207 -0
  120. package/dist/firstRun/firstRunPlanner.js.map +1 -0
  121. package/dist/firstRun/firstRunRunner.js +331 -0
  122. package/dist/firstRun/firstRunRunner.js.map +1 -0
  123. package/dist/firstRun/generatedDataPolicy.js +215 -0
  124. package/dist/firstRun/generatedDataPolicy.js.map +1 -0
  125. package/dist/firstRun/inputPlanner.js +67 -0
  126. package/dist/firstRun/inputPlanner.js.map +1 -0
  127. package/dist/firstRun/onboardingStateMachine.js +46 -0
  128. package/dist/firstRun/onboardingStateMachine.js.map +1 -0
  129. package/dist/firstRun/paywallPolicy.js +54 -0
  130. package/dist/firstRun/paywallPolicy.js.map +1 -0
  131. package/dist/firstRun/types.js +7 -0
  132. package/dist/firstRun/types.js.map +1 -0
  133. package/dist/fixtures/catalog.js +131 -0
  134. package/dist/fixtures/catalog.js.map +1 -0
  135. package/dist/flows/discover.js +18 -0
  136. package/dist/flows/discover.js.map +1 -0
  137. package/dist/flows/generate.js +211 -0
  138. package/dist/flows/generate.js.map +1 -0
  139. package/dist/flows/lint.js +97 -0
  140. package/dist/flows/lint.js.map +1 -0
  141. package/dist/flows/pack.js +68 -0
  142. package/dist/flows/pack.js.map +1 -0
  143. package/dist/flows/run.js +738 -0
  144. package/dist/flows/run.js.map +1 -0
  145. package/dist/flows/schema.js +240 -0
  146. package/dist/flows/schema.js.map +1 -0
  147. package/dist/flows/seedExec.js +108 -0
  148. package/dist/flows/seedExec.js.map +1 -0
  149. package/dist/flows/templates.js +155 -0
  150. package/dist/flows/templates.js.map +1 -0
  151. package/dist/flows/waitGuards.js +12 -0
  152. package/dist/flows/waitGuards.js.map +1 -0
  153. package/dist/index.js +33 -0
  154. package/dist/index.js.map +1 -0
  155. package/dist/ios/signing.js +182 -0
  156. package/dist/ios/signing.js.map +1 -0
  157. package/dist/issues/classify.js +186 -0
  158. package/dist/issues/classify.js.map +1 -0
  159. package/dist/issues/fingerprint.js +130 -0
  160. package/dist/issues/fingerprint.js.map +1 -0
  161. package/dist/issues/index.js +240 -0
  162. package/dist/issues/index.js.map +1 -0
  163. package/dist/issues/metrics.js +155 -0
  164. package/dist/issues/metrics.js.map +1 -0
  165. package/dist/issues/recurrence.js +193 -0
  166. package/dist/issues/recurrence.js.map +1 -0
  167. package/dist/issues/report.js +110 -0
  168. package/dist/issues/report.js.map +1 -0
  169. package/dist/issues/reportBridge.js +119 -0
  170. package/dist/issues/reportBridge.js.map +1 -0
  171. package/dist/issues/schema.js +90 -0
  172. package/dist/issues/schema.js.map +1 -0
  173. package/dist/issues/sourceRevision.js +108 -0
  174. package/dist/issues/sourceRevision.js.map +1 -0
  175. package/dist/issues/store.js +155 -0
  176. package/dist/issues/store.js.map +1 -0
  177. package/dist/lib/android.js +278 -0
  178. package/dist/lib/android.js.map +1 -0
  179. package/dist/lib/commandTemplate.js +55 -0
  180. package/dist/lib/commandTemplate.js.map +1 -0
  181. package/dist/lib/coordSpace.js +23 -0
  182. package/dist/lib/coordSpace.js.map +1 -0
  183. package/dist/lib/device.js +87 -0
  184. package/dist/lib/device.js.map +1 -0
  185. package/dist/lib/gitignore.js +22 -0
  186. package/dist/lib/gitignore.js.map +1 -0
  187. package/dist/lib/image.js +97 -0
  188. package/dist/lib/image.js.map +1 -0
  189. package/dist/lib/logger.js +8 -0
  190. package/dist/lib/logger.js.map +1 -0
  191. package/dist/lib/metroState.js +45 -0
  192. package/dist/lib/metroState.js.map +1 -0
  193. package/dist/lib/needsInput.js +201 -0
  194. package/dist/lib/needsInput.js.map +1 -0
  195. package/dist/lib/png.js +103 -0
  196. package/dist/lib/png.js.map +1 -0
  197. package/dist/lib/redact.js +21 -0
  198. package/dist/lib/redact.js.map +1 -0
  199. package/dist/lib/result.js +87 -0
  200. package/dist/lib/result.js.map +1 -0
  201. package/dist/lib/schemaHash.js +65 -0
  202. package/dist/lib/schemaHash.js.map +1 -0
  203. package/dist/lib/sensitive.js +13 -0
  204. package/dist/lib/sensitive.js.map +1 -0
  205. package/dist/lib/simctl.js +149 -0
  206. package/dist/lib/simctl.js.map +1 -0
  207. package/dist/lib/spawn.js +144 -0
  208. package/dist/lib/spawn.js.map +1 -0
  209. package/dist/lib/wda.js +347 -0
  210. package/dist/lib/wda.js.map +1 -0
  211. package/dist/lib/wdaConfig.js +69 -0
  212. package/dist/lib/wdaConfig.js.map +1 -0
  213. package/dist/lib/wdaTune.js +58 -0
  214. package/dist/lib/wdaTune.js.map +1 -0
  215. package/dist/oracle/auth.js +22 -0
  216. package/dist/oracle/auth.js.map +1 -0
  217. package/dist/oracle/failures.js +193 -0
  218. package/dist/oracle/failures.js.map +1 -0
  219. package/dist/oracle/health.js +123 -0
  220. package/dist/oracle/health.js.map +1 -0
  221. package/dist/oracle/record.js +36 -0
  222. package/dist/oracle/record.js.map +1 -0
  223. package/dist/orchestration/envelope.js +52 -0
  224. package/dist/orchestration/envelope.js.map +1 -0
  225. package/dist/orchestration/goal.js +98 -0
  226. package/dist/orchestration/goal.js.map +1 -0
  227. package/dist/plan/plan.js +124 -0
  228. package/dist/plan/plan.js.map +1 -0
  229. package/dist/prompts/index.js +63 -0
  230. package/dist/prompts/index.js.map +1 -0
  231. package/dist/report/artifactManifest.js +44 -0
  232. package/dist/report/artifactManifest.js.map +1 -0
  233. package/dist/report/coverage.js +60 -0
  234. package/dist/report/coverage.js.map +1 -0
  235. package/dist/report/evidence.js +84 -0
  236. package/dist/report/evidence.js.map +1 -0
  237. package/dist/report/export.js +447 -0
  238. package/dist/report/export.js.map +1 -0
  239. package/dist/report/flake.js +61 -0
  240. package/dist/report/flake.js.map +1 -0
  241. package/dist/report/history.js +564 -0
  242. package/dist/report/history.js.map +1 -0
  243. package/dist/report/policy.js +98 -0
  244. package/dist/report/policy.js.map +1 -0
  245. package/dist/report/qaLevel.js +96 -0
  246. package/dist/report/qaLevel.js.map +1 -0
  247. package/dist/report/readiness.js +213 -0
  248. package/dist/report/readiness.js.map +1 -0
  249. package/dist/report/summary.js +42 -0
  250. package/dist/report/summary.js.map +1 -0
  251. package/dist/report/testCatalog.js +93 -0
  252. package/dist/report/testCatalog.js.map +1 -0
  253. package/dist/report/timing.js +37 -0
  254. package/dist/report/timing.js.map +1 -0
  255. package/dist/server.js +180 -0
  256. package/dist/server.js.map +1 -0
  257. package/dist/services/automationGenerate.js +60 -0
  258. package/dist/services/automationGenerate.js.map +1 -0
  259. package/dist/services/build.js +66 -0
  260. package/dist/services/build.js.map +1 -0
  261. package/dist/services/preflight.js +51 -0
  262. package/dist/services/preflight.js.map +1 -0
  263. package/dist/services/prepareAndroid.js +183 -0
  264. package/dist/services/prepareAndroid.js.map +1 -0
  265. package/dist/services/prepareIos.js +162 -0
  266. package/dist/services/prepareIos.js.map +1 -0
  267. package/dist/services/report.js +537 -0
  268. package/dist/services/report.js.map +1 -0
  269. package/dist/services/smoke.js +120 -0
  270. package/dist/services/smoke.js.map +1 -0
  271. package/dist/services/suiteGenerate.js +123 -0
  272. package/dist/services/suiteGenerate.js.map +1 -0
  273. package/dist/services/testSuiteKnowledge.js +150 -0
  274. package/dist/services/testSuiteKnowledge.js.map +1 -0
  275. package/dist/session/attach.js +47 -0
  276. package/dist/session/attach.js.map +1 -0
  277. package/dist/session/progress.js +56 -0
  278. package/dist/session/progress.js.map +1 -0
  279. package/dist/session/store.js +329 -0
  280. package/dist/session/store.js.map +1 -0
  281. package/dist/snapshot/overlays.js +132 -0
  282. package/dist/snapshot/overlays.js.map +1 -0
  283. package/dist/snapshot/parse.js +204 -0
  284. package/dist/snapshot/parse.js.map +1 -0
  285. package/dist/snapshot/present.js +12 -0
  286. package/dist/snapshot/present.js.map +1 -0
  287. package/dist/snapshot/settle.js +36 -0
  288. package/dist/snapshot/settle.js.map +1 -0
  289. package/dist/state/profile.js +318 -0
  290. package/dist/state/profile.js.map +1 -0
  291. package/dist/suite/compile.js +176 -0
  292. package/dist/suite/compile.js.map +1 -0
  293. package/dist/suite/lint.js +45 -0
  294. package/dist/suite/lint.js.map +1 -0
  295. package/dist/suite/pom.js +285 -0
  296. package/dist/suite/pom.js.map +1 -0
  297. package/dist/suite/testcase.js +87 -0
  298. package/dist/suite/testcase.js.map +1 -0
  299. package/dist/testSuite/generator.js +222 -0
  300. package/dist/testSuite/generator.js.map +1 -0
  301. package/dist/testSuite/history.js +44 -0
  302. package/dist/testSuite/history.js.map +1 -0
  303. package/dist/testSuite/issueLinks.js +96 -0
  304. package/dist/testSuite/issueLinks.js.map +1 -0
  305. package/dist/testSuite/merge.js +190 -0
  306. package/dist/testSuite/merge.js.map +1 -0
  307. package/dist/testSuite/schema.js +86 -0
  308. package/dist/testSuite/schema.js.map +1 -0
  309. package/dist/testSuite/store.js +116 -0
  310. package/dist/testSuite/store.js.map +1 -0
  311. package/dist/testSuite/traceability.js +55 -0
  312. package/dist/testSuite/traceability.js.map +1 -0
  313. package/dist/tools/act.js +457 -0
  314. package/dist/tools/act.js.map +1 -0
  315. package/dist/tools/agent.js +225 -0
  316. package/dist/tools/agent.js.map +1 -0
  317. package/dist/tools/appMap.js +317 -0
  318. package/dist/tools/appMap.js.map +1 -0
  319. package/dist/tools/assertVisual.js +74 -0
  320. package/dist/tools/assertVisual.js.map +1 -0
  321. package/dist/tools/automationGenerate.js +394 -0
  322. package/dist/tools/automationGenerate.js.map +1 -0
  323. package/dist/tools/capabilities.js +114 -0
  324. package/dist/tools/capabilities.js.map +1 -0
  325. package/dist/tools/clearOverlay.js +150 -0
  326. package/dist/tools/clearOverlay.js.map +1 -0
  327. package/dist/tools/detectContext.js +41 -0
  328. package/dist/tools/detectContext.js.map +1 -0
  329. package/dist/tools/doctor.js +116 -0
  330. package/dist/tools/doctor.js.map +1 -0
  331. package/dist/tools/explore.js +289 -0
  332. package/dist/tools/explore.js.map +1 -0
  333. package/dist/tools/firstRun.js +136 -0
  334. package/dist/tools/firstRun.js.map +1 -0
  335. package/dist/tools/flow.js +331 -0
  336. package/dist/tools/flow.js.map +1 -0
  337. package/dist/tools/flowGenerate.js +55 -0
  338. package/dist/tools/flowGenerate.js.map +1 -0
  339. package/dist/tools/getArtifact.js +39 -0
  340. package/dist/tools/getArtifact.js.map +1 -0
  341. package/dist/tools/health.js +41 -0
  342. package/dist/tools/health.js.map +1 -0
  343. package/dist/tools/ios.js +492 -0
  344. package/dist/tools/ios.js.map +1 -0
  345. package/dist/tools/jobs.js +20 -0
  346. package/dist/tools/jobs.js.map +1 -0
  347. package/dist/tools/network.js +50 -0
  348. package/dist/tools/network.js.map +1 -0
  349. package/dist/tools/note.js +69 -0
  350. package/dist/tools/note.js.map +1 -0
  351. package/dist/tools/plan.js +49 -0
  352. package/dist/tools/plan.js.map +1 -0
  353. package/dist/tools/prepareIosTarget.js +99 -0
  354. package/dist/tools/prepareIosTarget.js.map +1 -0
  355. package/dist/tools/prepareTarget.js +257 -0
  356. package/dist/tools/prepareTarget.js.map +1 -0
  357. package/dist/tools/report.js +42 -0
  358. package/dist/tools/report.js.map +1 -0
  359. package/dist/tools/screenRecord.js +24 -0
  360. package/dist/tools/screenRecord.js.map +1 -0
  361. package/dist/tools/screenshot.js +63 -0
  362. package/dist/tools/screenshot.js.map +1 -0
  363. package/dist/tools/smoke.js +39 -0
  364. package/dist/tools/smoke.js.map +1 -0
  365. package/dist/tools/snapshot.js +129 -0
  366. package/dist/tools/snapshot.js.map +1 -0
  367. package/dist/tools/startSession.js +169 -0
  368. package/dist/tools/startSession.js.map +1 -0
  369. package/dist/tools/state.js +87 -0
  370. package/dist/tools/state.js.map +1 -0
  371. package/dist/tools/suite.js +412 -0
  372. package/dist/tools/suite.js.map +1 -0
  373. package/dist/tools/testThis.js +774 -0
  374. package/dist/tools/testThis.js.map +1 -0
  375. package/dist/tools/wda.js +477 -0
  376. package/dist/tools/wda.js.map +1 -0
  377. package/dist/version.js +62 -0
  378. package/dist/version.js.map +1 -0
  379. package/dist/visual/ocr.js +72 -0
  380. package/dist/visual/ocr.js.map +1 -0
  381. package/dist/visual/provider.js +75 -0
  382. package/dist/visual/provider.js.map +1 -0
  383. package/docs/README.md +19 -0
  384. package/docs/assets/swipium-lockup-ink-on-light.png +0 -0
  385. package/docs/mcp-server.md +135 -0
  386. package/docs/tools.md +130 -0
  387. package/package.json +70 -0
@@ -0,0 +1,60 @@
1
+ function driverKind(driver) {
2
+ return driver?.kind;
3
+ }
4
+ export function coverageForSession(session) {
5
+ const device = session.device ?? session.driver?.currentDevice?.();
6
+ const kind = driverKind(session.driver);
7
+ if (kind === 'direct') {
8
+ if (!device)
9
+ return 'Android emulator target unknown';
10
+ return device.startsWith('emulator-') ? 'Android Emulator only' : 'Android physical device is outside public v1 scope';
11
+ }
12
+ if (kind === 'simulator')
13
+ return 'iOS Simulator visual coverage';
14
+ if (kind === 'wda')
15
+ return 'iOS Simulator structured WDA coverage';
16
+ return 'emulator/simulator coverage only';
17
+ }
18
+ export function automationBackendForSession(session) {
19
+ const device = session.device ?? session.driver?.currentDevice?.();
20
+ const kind = driverKind(session.driver);
21
+ if (kind === 'direct') {
22
+ return {
23
+ kind,
24
+ mode: 'android-emulator-structured-adb',
25
+ structured: true,
26
+ description: 'Android structured ADB/UIAutomator on an emulator',
27
+ };
28
+ }
29
+ if (kind === 'remote') {
30
+ return {
31
+ kind,
32
+ mode: 'remote-structured',
33
+ structured: true,
34
+ description: 'Remote structured automation backend',
35
+ };
36
+ }
37
+ if (kind === 'simulator') {
38
+ return {
39
+ kind,
40
+ mode: 'ios-simulator-visual-simctl',
41
+ structured: false,
42
+ description: 'iOS Simulator visual-only simctl backend; structured taps, typing, and snapshots require WDA',
43
+ };
44
+ }
45
+ if (kind === 'wda') {
46
+ return {
47
+ kind,
48
+ mode: 'ios-simulator-structured-wda',
49
+ structured: true,
50
+ description: 'iOS Simulator structured WebDriverAgent backend',
51
+ };
52
+ }
53
+ return {
54
+ kind: 'unknown',
55
+ mode: 'unknown',
56
+ structured: false,
57
+ description: 'No automation backend was selected',
58
+ };
59
+ }
60
+ //# sourceMappingURL=coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/report/coverage.ts"],"names":[],"mappings":"AAUA,SAAS,UAAU,CAAC,MAA0B;IAC5C,OAAO,MAAM,EAAE,IAAI,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAA2C;IAC5E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,CAAC;IACnE,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM;YAAE,OAAO,iCAAiC,CAAC;QACtD,OAAO,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,oDAAoD,CAAC;IACzH,CAAC;IACD,IAAI,IAAI,KAAK,WAAW;QAAE,OAAO,+BAA+B,CAAC;IACjE,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,uCAAuC,CAAC;IACnE,OAAO,kCAAkC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,OAA2C;IACrF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,CAAC;IACnE,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO;YACL,IAAI;YACJ,IAAI,EAAE,iCAAiC;YACvC,UAAU,EAAE,IAAI;YAChB,WAAW,EAAE,mDAAmD;SACjE,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO;YACL,IAAI;YACJ,IAAI,EAAE,mBAAmB;YACzB,UAAU,EAAE,IAAI;YAChB,WAAW,EAAE,sCAAsC;SACpD,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,OAAO;YACL,IAAI;YACJ,IAAI,EAAE,6BAA6B;YACnC,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,8FAA8F;SAC5G,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,OAAO;YACL,IAAI;YACJ,IAAI,EAAE,8BAA8B;YACpC,UAAU,EAAE,IAAI;YAChB,WAAW,EAAE,iDAAiD;SAC/D,CAAC;IACJ,CAAC;IACD,OAAO;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,KAAK;QACjB,WAAW,EAAE,oCAAoC;KAClD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,84 @@
1
+ const EVIDENCE_KINDS = ['structured_locator', 'ocr_locator', 'visual_match', 'ai_visual_evidence', 'manual_review'];
2
+ const AUTHORITIES = ['deterministic', 'probabilistic', 'manual'];
3
+ function emptyCounts() {
4
+ return Object.fromEntries(EVIDENCE_KINDS.map((kind) => [kind, 0]));
5
+ }
6
+ function emptyAuthorityCounts() {
7
+ return Object.fromEntries(AUTHORITIES.map((authority) => [authority, 0]));
8
+ }
9
+ function isAiVisualWorkflow(workflow) {
10
+ return /(^|[_:\-\s])ai[_:\-\s]?visual/i.test(workflow);
11
+ }
12
+ export function evidenceKindForNote(note) {
13
+ if (note.evidenceKind === 'structured_locator' || note.method === 'structured')
14
+ return 'structured_locator';
15
+ if (note.evidenceKind === 'ai_visual_evidence')
16
+ return 'ai_visual_evidence';
17
+ if (note.evidenceKind === 'ocr_locator' || note.evidenceKind === 'ocr_text' || note.method === 'ocr')
18
+ return 'ocr_locator';
19
+ if (note.evidenceKind === 'visual_match' || note.method === 'visual' || note.verifiedVisually)
20
+ return isAiVisualWorkflow(note.workflow) ? 'ai_visual_evidence' : 'visual_match';
21
+ if (isAiVisualWorkflow(note.workflow))
22
+ return 'ai_visual_evidence';
23
+ return 'manual_review';
24
+ }
25
+ export function evidenceAuthority(kind) {
26
+ if (kind === 'structured_locator')
27
+ return 'deterministic';
28
+ if (kind === 'manual_review')
29
+ return 'manual';
30
+ return 'probabilistic';
31
+ }
32
+ function warningForKind(kind) {
33
+ if (kind === 'ocr_locator')
34
+ return 'OCR evidence is probabilistic; use structured locators before CI promotion.';
35
+ if (kind === 'visual_match')
36
+ return 'Visual screenshot evidence is probabilistic; keep it separate from structured assertions.';
37
+ if (kind === 'ai_visual_evidence')
38
+ return 'AI visual evidence is probabilistic and requires calibration against a dogfood corpus.';
39
+ if (kind === 'manual_review')
40
+ return 'No structured, OCR, or visual method label was recorded; review this evidence manually.';
41
+ return undefined;
42
+ }
43
+ export function evidenceAssessmentForNote(note) {
44
+ const kind = evidenceKindForNote(note);
45
+ return {
46
+ workflow: note.workflow,
47
+ outcome: note.outcome,
48
+ kind,
49
+ authority: evidenceAuthority(kind),
50
+ method: note.method ?? 'unlabeled',
51
+ artifactUris: note.artifactUris ?? [],
52
+ confidence: note.confidence,
53
+ minConfidence: note.minConfidence,
54
+ decision: note.decision,
55
+ warning: warningForKind(kind),
56
+ };
57
+ }
58
+ export function evidenceTaxonomyForNotes(notes) {
59
+ const assessments = notes.map(evidenceAssessmentForNote);
60
+ const counts = emptyCounts();
61
+ const byAuthority = emptyAuthorityCounts();
62
+ for (const assessment of assessments) {
63
+ counts[assessment.kind]++;
64
+ byAuthority[assessment.authority]++;
65
+ }
66
+ const hasProbabilistic = byAuthority.probabilistic > 0;
67
+ return {
68
+ schema: 'swipium.evidence.taxonomy.v1',
69
+ counts,
70
+ byAuthority,
71
+ assessments,
72
+ calibration: hasProbabilistic
73
+ ? {
74
+ status: 'required_missing',
75
+ requiredCorpus: 'dogfood-nightly',
76
+ note: 'Probabilistic visual/OCR/AI visual evidence requires confidence calibration in the dogfood corpus before it can be used as a release authority.',
77
+ }
78
+ : {
79
+ status: 'not_required',
80
+ note: 'No probabilistic visual/OCR/AI visual evidence was recorded in this report.',
81
+ },
82
+ };
83
+ }
84
+ //# sourceMappingURL=evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/report/evidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,447 @@
1
+ // Report 2.0 exporters (PHASE3-PLAN §3.5). Turn the assembled report into formats a developer
2
+ // can use without the agent transcript: an issue-ready Markdown doc and a CI-ready JUnit XML.
3
+ // (a third-party-format exporter is deferred — out of scope here.)
4
+ //
5
+ // These consume the already-redacted report object, so no secret ever reaches an export.
6
+ import { evidenceTaxonomyForNotes } from './evidence.js';
7
+ function playwrightStatus(outcome) {
8
+ if (outcome === 'pass')
9
+ return 'passed';
10
+ if (outcome === 'fail')
11
+ return 'failed';
12
+ return 'skipped';
13
+ }
14
+ function playwrightDuration(n) {
15
+ const sec = n.steps?.reduce((sum, s) => sum + (s.durationSec ?? 0), 0) ?? 0;
16
+ return Math.round(sec * 1000);
17
+ }
18
+ function playwrightAttachments(n) {
19
+ return (n.artifactUris ?? []).map((uri, i) => ({
20
+ name: `artifact-${i + 1}`,
21
+ contentType: uri.match(/\.(png|jpg|jpeg|webp)$/i) ? 'image/*' : 'application/octet-stream',
22
+ path: uri,
23
+ }));
24
+ }
25
+ export function toPlaywrightJson(r) {
26
+ const generatedAt = new Date().toISOString();
27
+ const evidenceTaxonomy = r.evidenceTaxonomy ?? evidenceTaxonomyForNotes(r.testOutcomes);
28
+ const evidenceByWorkflow = new Map(evidenceTaxonomy.assessments.map((a) => [a.workflow, a]));
29
+ const specs = r.testOutcomes.map((n) => {
30
+ const status = playwrightStatus(n.outcome);
31
+ const message = [n.category, n.reason, n.missingPrecondition, n.recommendedSetup].filter(Boolean).join(': ') || n.outcome;
32
+ const evidence = evidenceByWorkflow.get(n.workflow);
33
+ return {
34
+ title: n.workflow,
35
+ ok: status === 'passed',
36
+ tags: [n.category, n.outcome, evidence?.kind, evidence?.authority].filter(Boolean),
37
+ tests: [{
38
+ timeout: 0,
39
+ expectedStatus: 'passed',
40
+ projectName: r.automationBackend?.mode ?? 'swipium',
41
+ results: [{
42
+ workerIndex: 0,
43
+ status,
44
+ duration: playwrightDuration(n),
45
+ errors: status === 'failed' ? [{ message }] : [],
46
+ attachments: playwrightAttachments(n),
47
+ stdout: [],
48
+ stderr: [],
49
+ retry: 0,
50
+ startTime: generatedAt,
51
+ }],
52
+ status,
53
+ annotations: [
54
+ ...(status === 'skipped' ? [{ type: n.outcome, description: message }] : []),
55
+ ...(evidence?.warning ? [{ type: 'evidence', description: evidence.warning }] : []),
56
+ ],
57
+ }],
58
+ file: `swipium://${r.sessionId}/${n.workflow}`,
59
+ line: 1,
60
+ column: 1,
61
+ };
62
+ });
63
+ const findingSpecs = r.findings.map((f, i) => ({
64
+ title: `${f.failureCode ?? f.kind}: ${f.detail}`,
65
+ ok: f.severity !== 'high',
66
+ tags: [f.bucket, f.severity, f.layer].filter(Boolean),
67
+ tests: [{
68
+ timeout: 0,
69
+ expectedStatus: 'passed',
70
+ projectName: r.automationBackend?.mode ?? 'swipium',
71
+ results: [{
72
+ workerIndex: 0,
73
+ status: f.severity === 'high' ? 'failed' : 'passed',
74
+ duration: 0,
75
+ errors: f.severity === 'high' ? [{ message: f.detail, location: { file: f.screenshotUri ?? `swipium://${r.sessionId}/finding/${i + 1}`, line: 1, column: 1 } }] : [],
76
+ attachments: f.screenshotUri ? [{ name: 'screenshot', contentType: 'image/*', path: f.screenshotUri }] : [],
77
+ stdout: [],
78
+ stderr: [],
79
+ retry: 0,
80
+ startTime: generatedAt,
81
+ }],
82
+ status: f.severity === 'high' ? 'failed' : 'passed',
83
+ annotations: f.nextStep ? [{ type: 'nextStep', description: f.nextStep }] : [],
84
+ }],
85
+ file: f.screenshotUri ?? `swipium://${r.sessionId}/finding/${i + 1}`,
86
+ line: 1,
87
+ column: 1,
88
+ }));
89
+ const allSpecs = [...specs, ...findingSpecs];
90
+ const failed = allSpecs.filter((s) => !s.ok).length;
91
+ const skipped = r.testOutcomes.filter((n) => playwrightStatus(n.outcome) === 'skipped').length;
92
+ const payload = {
93
+ schema: 'swipium.playwright.report.v1',
94
+ generatedAt,
95
+ config: {
96
+ rootDir: '.',
97
+ metadata: {
98
+ swipium: {
99
+ sessionId: r.sessionId,
100
+ appId: r.appId,
101
+ device: r.device,
102
+ coverage: r.coverage,
103
+ releaseRisk: r.executiveSummary.risk,
104
+ nextAction: r.executiveSummary.nextAction,
105
+ automationBackend: r.automationBackend ?? null,
106
+ readiness: r.readiness ?? [],
107
+ wda: r.wda ?? null,
108
+ automationReadiness: r.automationReadiness ?? null,
109
+ evidenceTaxonomy,
110
+ mutationLedger: r.mutationLedger ?? [],
111
+ flakeClassification: r.flakeClassification ?? null,
112
+ },
113
+ },
114
+ projects: [{ name: r.automationBackend?.mode ?? 'swipium' }],
115
+ },
116
+ suites: [{
117
+ title: `Swipium ${r.appId ?? 'app'}`,
118
+ file: `swipium://${r.sessionId}/report`,
119
+ specs: allSpecs,
120
+ }],
121
+ stats: {
122
+ expected: allSpecs.length - failed - skipped,
123
+ skipped,
124
+ unexpected: failed,
125
+ flaky: r.flakeClassification?.classification === 'flaky' ? 1 : 0,
126
+ duration: Math.round((r.phaseTimings.totalSec ?? 0) * 1000),
127
+ },
128
+ errors: failed ? [{ message: r.executiveSummary.nextAction }] : [],
129
+ };
130
+ return JSON.stringify(payload, null, 2);
131
+ }
132
+ const RISK_BADGE = { ship: '🟢 SHIP', caution: '🟡 CAUTION', block: '🔴 BLOCK' };
133
+ const OUTCOME_MARK = { pass: '✅', fail: '❌', blocked: '⛔', skipped: '⏭️', not_applicable: '➖' };
134
+ function statusWord(risk) {
135
+ return risk === 'block' ? 'BLOCK' : risk === 'caution' ? 'CAUTION' : 'SHIP';
136
+ }
137
+ function firstReportProblem(r) {
138
+ const failed = r.testOutcomes.find((o) => o.outcome === 'fail' || o.outcome === 'blocked');
139
+ if (failed) {
140
+ return {
141
+ workflow: failed.workflow,
142
+ reason: failed.reason ?? failed.missingPrecondition ?? failed.category ?? failed.outcome,
143
+ category: failed.category,
144
+ evidence: failed.artifactUris,
145
+ };
146
+ }
147
+ const finding = r.findings.find((f) => f.severity === 'high') ?? r.findings[0];
148
+ if (!finding)
149
+ return null;
150
+ return {
151
+ reason: finding.detail,
152
+ category: finding.failureCode ?? finding.kind,
153
+ evidence: [finding.screenshotUri].filter((x) => !!x),
154
+ };
155
+ }
156
+ function likelyReportCategory(problem, r) {
157
+ const raw = `${problem?.category ?? ''} ${problem?.reason ?? ''}`.toLowerCase();
158
+ if (/accessibility|identifier|locator|element|not found|missing/.test(raw))
159
+ return 'automation readiness';
160
+ if (/wda|simulator|emulator|device|install|network|fixture|seed|permission|toolchain/.test(raw))
161
+ return 'environment/setup';
162
+ if (r.appHealth !== 'OK' || /assert|visible|crash|error|redbox|logbox/.test(raw))
163
+ return 'app regression';
164
+ return 'unknown';
165
+ }
166
+ function evidenceSummary(r, problem) {
167
+ const kinds = new Set();
168
+ const uris = [...(problem?.evidence ?? []), ...r.artifacts.map((a) => a.uri)];
169
+ for (const a of r.artifacts) {
170
+ if (a.kind === 'screenshot')
171
+ kinds.add('screenshot');
172
+ else if (a.kind === 'recording')
173
+ kinds.add('video');
174
+ else if (a.kind === 'dump')
175
+ kinds.add('UI tree');
176
+ else if (['logs', 'logcat', 'metro', 'wda'].includes(a.kind))
177
+ kinds.add('logs');
178
+ else
179
+ kinds.add(a.kind);
180
+ }
181
+ return kinds.size ? `${[...kinds].join(', ')} (${uris.slice(0, 5).join(', ')})` : uris.slice(0, 5).join(', ') || 'none recorded';
182
+ }
183
+ function tableCell(s) {
184
+ return s.replace(/\|/g, '\\|');
185
+ }
186
+ function compactValue(value, maxLength = 180) {
187
+ if (value == null)
188
+ return '—';
189
+ let raw;
190
+ try {
191
+ raw = typeof value === 'string' ? value : JSON.stringify(value);
192
+ }
193
+ catch {
194
+ raw = String(value);
195
+ }
196
+ if (!raw)
197
+ return '—';
198
+ return raw.length > maxLength ? `${raw.slice(0, Math.max(0, maxLength - 1))}…` : raw;
199
+ }
200
+ function mutationTime(at) {
201
+ return typeof at === 'number' && Number.isFinite(at) ? new Date(at).toISOString() : '—';
202
+ }
203
+ function mutationConsentSummary(m) {
204
+ if (!m.consent)
205
+ return 'not recorded';
206
+ if (!m.consent.required)
207
+ return 'not required';
208
+ const approval = m.consent.approved ? 'approved' : 'not approved';
209
+ return m.consent.consentId ? `${approval} (${m.consent.consentId})` : approval;
210
+ }
211
+ function mutationEvidenceSummary(m) {
212
+ const parts = [
213
+ m.ledgerUri ? `[ledger](${m.ledgerUri})` : '',
214
+ m.consent?.payloadHash ? `payload ${m.consent.payloadHash.slice(0, 12)}` : '',
215
+ ].filter(Boolean);
216
+ return parts.length ? parts.join('; ') : '—';
217
+ }
218
+ export function inlinePrSummary(r) {
219
+ const problem = firstReportProblem(r);
220
+ const reason = problem ? `${problem.workflow ? `${problem.workflow}: ` : ''}${problem.reason}` : r.executiveSummary.reasons[0] ?? 'No blocking failures detected.';
221
+ const category = likelyReportCategory(problem, r);
222
+ const lines = [
223
+ `Swipium: ${statusWord(r.executiveSummary.risk)}`,
224
+ `Reason: ${reason}.`,
225
+ `Native health: ${r.nativeHealth}. App health: ${r.appHealth}.`,
226
+ ];
227
+ if (r.automationBackend)
228
+ lines.push(`Backend: ${r.automationBackend.description}.`);
229
+ if (r.readiness?.length)
230
+ lines.push(`Readiness: ${r.readiness.join(' → ')}.`);
231
+ if (r.automationReadiness)
232
+ lines.push(`Automation readiness: ${r.automationReadiness.grade} (${r.automationReadiness.score}/100).`);
233
+ lines.push(`Likely category: ${category}.`, `Evidence: ${evidenceSummary(r, problem)}.`, `Next action: ${r.executiveSummary.nextAction}`);
234
+ return lines.join('\n');
235
+ }
236
+ export function toMarkdown(r) {
237
+ const L = [];
238
+ const evidenceTaxonomy = r.evidenceTaxonomy ?? evidenceTaxonomyForNotes(r.testOutcomes);
239
+ L.push(`# QA report — ${r.appId ?? 'app'}`);
240
+ L.push('');
241
+ L.push('## PR summary', '');
242
+ L.push('```text');
243
+ L.push(inlinePrSummary(r));
244
+ L.push('```');
245
+ L.push('');
246
+ L.push(`**Release risk: ${RISK_BADGE[r.executiveSummary.risk] ?? r.executiveSummary.risk.toUpperCase()}**`);
247
+ L.push('');
248
+ L.push(`**Next action:** ${r.executiveSummary.nextAction}`);
249
+ if (r.executiveSummary.reasons.length) {
250
+ L.push('');
251
+ for (const reason of r.executiveSummary.reasons)
252
+ L.push(`- ${reason}`);
253
+ }
254
+ // Issue memory (SWIPIUM-REQ-07): durable, cross-run issue ledger summary + recurrence warnings.
255
+ if (r.issuesMarkdown) {
256
+ L.push('');
257
+ L.push(r.issuesMarkdown);
258
+ }
259
+ L.push('');
260
+ L.push(`> ${r.coverage}. Session \`${r.sessionId}\` on \`${r.device ?? 'device'}\`.`);
261
+ if (r.automationBackend) {
262
+ L.push(`> Backend: ${r.automationBackend.description} (${r.automationBackend.mode}; structured=${r.automationBackend.structured ? 'yes' : 'no'}).`);
263
+ }
264
+ if (r.readiness?.length) {
265
+ L.push('', '## Capability readiness', '');
266
+ L.push(`- Labels: ${r.readiness.join(' → ')}.`);
267
+ L.push(`- Highest: ${r.readiness.at(-1)}.`);
268
+ }
269
+ if (r.wda) {
270
+ const state = r.wda.status?.reachable ? (r.wda.status.ready === false ? 'reachable/not-ready' : 'reachable') : 'unreachable';
271
+ L.push(`> WDA: ${state} at ${r.wda.webDriverAgentUrl}; device=${r.wda.device ?? 'unknown'}; session=${r.wda.wdaSessionId ?? 'none'}.`);
272
+ }
273
+ if (r.wda?.tuning?.recommendations?.length) {
274
+ L.push('', '## WDA tuning', '');
275
+ for (const rec of r.wda.tuning.recommendations) {
276
+ L.push(`- \`${tableCell(rec.setting)}\` = \`${tableCell(compactValue(rec.value, 80))}\`${rec.failureCode ? ` (${rec.failureCode})` : ''}: ${tableCell(rec.reason)}`);
277
+ }
278
+ }
279
+ if (r.automationReadiness) {
280
+ const ar = r.automationReadiness;
281
+ L.push('', '## Automation readiness', '');
282
+ L.push(`- Grade: ${ar.grade} (${ar.score}/100).`);
283
+ L.push(`- Durable locator coverage: ${ar.locatorCoverage.durablePct}% (${ar.locatorCoverage.durableActions}/${ar.locatorCoverage.totalActions}); native-or-durable ${ar.locatorCoverage.nativeOrDurablePct}%.`);
284
+ L.push(`- Labels: ${ar.labels.length ? ar.labels.join(', ') : 'none'}.`);
285
+ if (ar.topFixes.length) {
286
+ L.push('- Top fixes:');
287
+ for (const fix of ar.topFixes.slice(0, 10))
288
+ L.push(` - ${fix}`);
289
+ }
290
+ if (ar.workflowGrades.length) {
291
+ L.push('', '| Workflow | Grade | Outcome | Evidence | Fix |');
292
+ L.push('| --- | --- | --- | --- | --- |');
293
+ for (const w of ar.workflowGrades)
294
+ L.push(`| ${w.workflow} | ${w.grade} | ${w.outcome} | ${w.evidence} | ${(w.fix ?? '-').replace(/\|/g, '\\|')} |`);
295
+ }
296
+ if (ar.screenGrades.length) {
297
+ L.push('', '| Screen | Grade | Durable locators | Weak actions | Fixes |');
298
+ L.push('| --- | --- | ---: | ---: | --- |');
299
+ for (const s of ar.screenGrades)
300
+ L.push(`| ${s.screen} | ${s.grade} | ${s.durableLocatorPct}% | ${s.weakActions} | ${(s.fixes.join('; ') || '-').replace(/\|/g, '\\|')} |`);
301
+ }
302
+ if (ar.prComments.length) {
303
+ L.push('', '### Suggested PR comments', '');
304
+ for (const c of ar.prComments)
305
+ L.push(`- [${c.severity}] ${c.body}`);
306
+ }
307
+ }
308
+ L.push('', '## Health', '');
309
+ L.push(`- Native: ${r.nativeHealth === 'OK' ? '✅ OK' : '❌ error'}`);
310
+ L.push(`- App: ${r.appHealth === 'OK' ? '✅ OK' : r.appHealth === 'degraded' ? '⚠️ degraded' : '❌ error'}`);
311
+ L.push(`- Auth: ${r.authState}`);
312
+ if (r.testOutcomes.length) {
313
+ L.push('', '## Workflows', '');
314
+ L.push('| Workflow | Outcome | Notes |');
315
+ L.push('| --- | --- | --- |');
316
+ for (const n of r.testOutcomes) {
317
+ const detail = [n.category, n.reason, n.missingPrecondition ? `missing: ${n.missingPrecondition}` : '', n.recommendedSetup ? `setup: ${n.recommendedSetup}` : '']
318
+ .filter(Boolean)
319
+ .join('; ')
320
+ .replace(/\|/g, '\\|');
321
+ L.push(`| ${n.workflow} | ${OUTCOME_MARK[n.outcome] ?? ''} ${n.outcome} | ${detail || '—'} |`);
322
+ }
323
+ L.push('', '## Evidence quality', '');
324
+ L.push(`- Deterministic structured locator: ${evidenceTaxonomy.counts.structured_locator}.`);
325
+ L.push(`- Probabilistic visual/OCR/AI evidence: ${evidenceTaxonomy.byAuthority.probabilistic}.`);
326
+ L.push(`- Manual review evidence: ${evidenceTaxonomy.counts.manual_review}.`);
327
+ L.push(`- Calibration: ${evidenceTaxonomy.calibration.status}${evidenceTaxonomy.calibration.requiredCorpus ? ` (${evidenceTaxonomy.calibration.requiredCorpus})` : ''}. ${evidenceTaxonomy.calibration.note}`);
328
+ L.push('', '| Workflow | Evidence | Authority | Notes |');
329
+ L.push('| --- | --- | --- | --- |');
330
+ for (const ev of evidenceTaxonomy.assessments) {
331
+ L.push(`| ${tableCell(ev.workflow)} | ${ev.kind} | ${ev.authority} | ${ev.warning ? tableCell(ev.warning) : '—'} |`);
332
+ }
333
+ }
334
+ if (r.flakeClassification && r.flakeClassification.repeat > 1) {
335
+ const f = r.flakeClassification;
336
+ L.push('', '## Flake classification', '');
337
+ L.push(`- ${f.classification}: ${f.passed}/${f.repeat} passed (${f.passRate}%).`);
338
+ L.push(`- Triage: ${f.triage.likelyCause} (${f.triage.confidence} confidence). ${f.triage.nextStep}`);
339
+ for (const ev of f.triage.evidence)
340
+ L.push(` - ${ev}`);
341
+ }
342
+ if (r.generatedValues?.length) {
343
+ L.push('', '## Generated test data', '');
344
+ L.push('| Fixture | Field | Generator | Variable | Value | Evidence |');
345
+ L.push('| --- | --- | --- | --- | --- | --- |');
346
+ for (const g of r.generatedValues) {
347
+ L.push(`| ${tableCell(g.fixture)} | ${tableCell(g.field)} | ${tableCell(g.generator)} | \`${tableCell(g.varName)}\` | ${g.secret ? '<redacted>' : tableCell(g.value)} | ${g.artifactUri ? `[artifact](${g.artifactUri})` : '—'} |`);
348
+ }
349
+ }
350
+ if (r.findings.length) {
351
+ L.push('', '## Findings', '');
352
+ for (const f of r.findings) {
353
+ const code = f.failureCode ? ` \`${f.failureCode}\`` : '';
354
+ const bucket = f.bucket ? ` ${f.bucket}` : '';
355
+ const retry = f.retrySafe == null ? '' : ` retrySafe=${f.retrySafe}`;
356
+ const next = f.nextStep ? ` Next: ${f.nextStep}` : '';
357
+ L.push(`- **[${f.severity}]**${code}${bucket}${retry} ${f.layer ?? '?'}/${f.kind}: ${f.detail}${f.evidence ? ` — _"${f.evidence}"_` : ''}${f.screenshotUri ? ` ([screenshot](${f.screenshotUri}))` : ''}${next}`);
358
+ }
359
+ }
360
+ if (r.environmentChanges.length || r.guardrailOverrides.length) {
361
+ L.push('', '## Environment', '');
362
+ L.push(`- Network at end: ${r.finalNetwork} (${r.networkRestore})`);
363
+ if (r.guardrailOverrides.length)
364
+ L.push(`- ⚠️ Guardrail overrides: ${r.guardrailOverrides.length}`);
365
+ for (const c of r.environmentChanges)
366
+ L.push(` - ${c}`);
367
+ }
368
+ if (r.ciMutations?.length) {
369
+ L.push('', '## CI mutations', '');
370
+ for (const c of r.ciMutations)
371
+ L.push(`- ${c}`);
372
+ }
373
+ if (r.mutationLedger?.length) {
374
+ L.push('', '## Mutation ledger', '');
375
+ L.push('| Time | Tool | Action | Risk | Status | Consent | Evidence | Target / detail |');
376
+ L.push('| --- | --- | --- | --- | --- | --- | --- | --- |');
377
+ for (const m of r.mutationLedger) {
378
+ const targetDetail = [compactValue(m.target), m.detail ? compactValue(m.detail) : '']
379
+ .filter((part) => part && part !== '—')
380
+ .join('; ') || '—';
381
+ L.push(`| ${tableCell(mutationTime(m.at))} | ${tableCell(m.tool)} | ${tableCell(m.action)} | ${tableCell(m.risk)} | ${tableCell(m.status)} | ${tableCell(mutationConsentSummary(m))} | ${tableCell(mutationEvidenceSummary(m))} | ${tableCell(targetDetail)} |`);
382
+ }
383
+ }
384
+ L.push('', '## Timing & artifacts', '');
385
+ L.push(`- Total ${r.phaseTimings.totalSec}s · setup ${r.phaseTimings.setupSec}s · active ${r.phaseTimings.activeSec}s${r.phaseTimings.timeToLoginSec != null ? ` · to-login ${r.phaseTimings.timeToLoginSec}s` : ''}`);
386
+ const d = r.phaseTimings.diagnostics;
387
+ if (d) {
388
+ const parts = [
389
+ d.simulatorBootSec != null ? `boot ${d.simulatorBootSec}s` : '',
390
+ d.appInstallSec != null ? `install ${d.appInstallSec}s` : '',
391
+ d.appLaunchSec != null ? `launch ${d.appLaunchSec}s` : '',
392
+ d.wdaBuildSec != null ? `WDA build ${d.wdaBuildSec}s` : '',
393
+ d.wdaStartSec != null ? `WDA start ${d.wdaStartSec}s` : '',
394
+ d.wdaReuseCheckSec != null ? `WDA reuse check ${d.wdaReuseCheckSec}s` : '',
395
+ d.wdaStartupWaitSec != null ? `WDA ready wait ${d.wdaStartupWaitSec}s` : '',
396
+ d.wdaSessionCreateSec != null ? `WDA session ${d.wdaSessionCreateSec}s` : '',
397
+ d.wdaSourceSec != null ? `WDA source ${d.wdaSourceSec}s` : '',
398
+ d.wdaFindElementSec != null ? `WDA find ${d.wdaFindElementSec}s` : '',
399
+ d.wdaTapSec != null ? `WDA tap ${d.wdaTapSec}s` : '',
400
+ d.wdaTypeSec != null ? `WDA type ${d.wdaTypeSec}s` : '',
401
+ d.wdaClearSec != null ? `WDA clear ${d.wdaClearSec}s` : '',
402
+ d.wdaScreenshotSec != null ? `WDA screenshot ${d.wdaScreenshotSec}s` : '',
403
+ d.flowRuntimeSec != null ? `flows ${d.flowRuntimeSec}s` : '',
404
+ d.waitSec != null ? `wait ${d.waitSec}s` : '',
405
+ d.screenshotCount != null ? `screenshots ${d.screenshotCount}` : '',
406
+ ].filter(Boolean);
407
+ if (parts.length)
408
+ L.push(`- Diagnostics: ${parts.join(' · ')}`);
409
+ }
410
+ L.push(`- ${r.artifacts.length} artifact(s):`);
411
+ for (const a of r.artifacts)
412
+ L.push(` - \`${a.uri}\` (${a.kind}${a.label ? `: ${a.label}` : ''})`);
413
+ L.push('', '---', '_Generated by Swipium._');
414
+ return L.join('\n');
415
+ }
416
+ function xmlEscape(s) {
417
+ return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
418
+ }
419
+ export function toJUnit(r) {
420
+ // One <testcase> per recorded outcome. fail → <failure>; blocked/skipped/not_applicable → <skipped>.
421
+ const cases = r.testOutcomes;
422
+ const failures = cases.filter((n) => n.outcome === 'fail').length;
423
+ const skipped = cases.filter((n) => n.outcome === 'blocked' || n.outcome === 'skipped' || n.outcome === 'not_applicable').length;
424
+ const suiteName = `swipium.${r.appId ?? 'app'}`;
425
+ const lines = ['<?xml version="1.0" encoding="UTF-8"?>'];
426
+ lines.push(`<testsuite name="${xmlEscape(suiteName)}" tests="${cases.length}" failures="${failures}" skipped="${skipped}" time="${r.phaseTimings.totalSec ?? 0}">`);
427
+ for (const n of cases) {
428
+ const name = xmlEscape(n.workflow);
429
+ const msg = xmlEscape([n.category, n.reason, n.missingPrecondition].filter(Boolean).join(': ') || n.outcome);
430
+ if (n.outcome === 'fail') {
431
+ lines.push(` <testcase name="${name}" classname="${xmlEscape(suiteName)}">`);
432
+ lines.push(` <failure message="${msg}"></failure>`);
433
+ lines.push(` </testcase>`);
434
+ }
435
+ else if (n.outcome === 'blocked' || n.outcome === 'skipped' || n.outcome === 'not_applicable') {
436
+ lines.push(` <testcase name="${name}" classname="${xmlEscape(suiteName)}">`);
437
+ lines.push(` <skipped message="${msg}"></skipped>`);
438
+ lines.push(` </testcase>`);
439
+ }
440
+ else {
441
+ lines.push(` <testcase name="${name}" classname="${xmlEscape(suiteName)}"></testcase>`);
442
+ }
443
+ }
444
+ lines.push('</testsuite>');
445
+ return lines.join('\n');
446
+ }
447
+ //# sourceMappingURL=export.js.map