swipium 1.4.0 → 2.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.
- package/CHANGELOG.md +313 -0
- package/README.md +175 -219
- package/THREAT_MODEL.md +223 -47
- package/dist/appMap/automationLink.js +39 -26
- package/dist/appMap/automationLink.js.map +1 -1
- package/dist/appMap/build.js +68 -20
- package/dist/appMap/build.js.map +1 -1
- package/dist/appMap/codeIndex.js +31 -5
- package/dist/appMap/codeIndex.js.map +1 -1
- package/dist/appMap/featureIndex.js +23 -5
- package/dist/appMap/featureIndex.js.map +1 -1
- package/dist/appMap/featureModel.js +44 -8
- package/dist/appMap/featureModel.js.map +1 -1
- package/dist/appMap/firstRunApply.js +24 -6
- package/dist/appMap/firstRunApply.js.map +1 -1
- package/dist/appMap/fsWalk.js +19 -2
- package/dist/appMap/fsWalk.js.map +1 -1
- package/dist/appMap/issues.js +10 -30
- package/dist/appMap/issues.js.map +1 -1
- package/dist/appMap/migrations.js +6 -6
- package/dist/appMap/migrations.js.map +1 -1
- package/dist/appMap/prelaunch.js +2 -2
- package/dist/appMap/prelaunch.js.map +1 -1
- package/dist/appMap/projectRegistry.js +83 -11
- package/dist/appMap/projectRegistry.js.map +1 -1
- package/dist/appMap/provenance.js +2 -2
- package/dist/appMap/provenance.js.map +1 -1
- package/dist/appMap/query.js +21 -5
- package/dist/appMap/query.js.map +1 -1
- package/dist/appMap/runtimeMerge.js +12 -5
- package/dist/appMap/runtimeMerge.js.map +1 -1
- package/dist/appMap/schema.js +1 -1
- package/dist/appMap/schema.js.map +1 -1
- package/dist/appMap/screenMatch.js +6 -2
- package/dist/appMap/screenMatch.js.map +1 -1
- package/dist/appMap/staticScan.js +151 -39
- package/dist/appMap/staticScan.js.map +1 -1
- package/dist/appMap/store.js +58 -85
- package/dist/appMap/store.js.map +1 -1
- package/dist/appMap/tsAstScan.js +34 -12
- package/dist/appMap/tsAstScan.js.map +1 -1
- package/dist/artifacts/bundletool.js +49 -12
- package/dist/artifacts/bundletool.js.map +1 -1
- package/dist/artifacts/resolve.js +41 -14
- package/dist/artifacts/resolve.js.map +1 -1
- package/dist/automation/capabilities.js +112 -30
- package/dist/automation/capabilities.js.map +1 -1
- package/dist/automation/gestures.js +6 -2
- package/dist/automation/gestures.js.map +1 -1
- package/dist/automation/plan.js +71 -23
- package/dist/automation/plan.js.map +1 -1
- package/dist/automation/report.js +15 -5
- package/dist/automation/report.js.map +1 -1
- package/dist/automation/selectors.js +22 -28
- package/dist/automation/selectors.js.map +1 -1
- package/dist/automation/types.js +1 -1
- package/dist/automation/types.js.map +1 -1
- package/dist/automation/waits.js +14 -8
- package/dist/automation/waits.js.map +1 -1
- package/dist/automation/webview.js +9 -3
- package/dist/automation/webview.js.map +1 -1
- package/dist/automationGen/appiumModel.js +16 -8
- package/dist/automationGen/appiumModel.js.map +1 -1
- package/dist/automationGen/ciEmitter.js +6 -6
- package/dist/automationGen/ciEmitter.js.map +1 -1
- package/dist/automationGen/identifiers.js +224 -0
- package/dist/automationGen/identifiers.js.map +1 -0
- package/dist/automationGen/jsEmitter.js +288 -121
- package/dist/automationGen/jsEmitter.js.map +1 -1
- package/dist/automationGen/packagePatch.js +2 -2
- package/dist/automationGen/packagePatch.js.map +1 -1
- package/dist/automationGen/platformResolve.js +36 -0
- package/dist/automationGen/platformResolve.js.map +1 -0
- package/dist/automationGen/projectProfile.js +76 -27
- package/dist/automationGen/projectProfile.js.map +1 -1
- package/dist/automationGen/pythonEmitter.js +278 -107
- package/dist/automationGen/pythonEmitter.js.map +1 -1
- package/dist/automationGen/readmeEmitter.js +7 -6
- package/dist/automationGen/readmeEmitter.js.map +1 -1
- package/dist/automationGen/run.js +388 -0
- package/dist/automationGen/run.js.map +1 -0
- package/dist/automationGen/suitePlan.js +17 -10
- package/dist/automationGen/suitePlan.js.map +1 -1
- package/dist/automationGen/validation.js +52 -12
- package/dist/automationGen/validation.js.map +1 -1
- package/dist/build/parseBuildLog.js +235 -31
- package/dist/build/parseBuildLog.js.map +1 -1
- package/dist/build/plan.js +39 -18
- package/dist/build/plan.js.map +1 -1
- package/dist/ci/preflight.js +13 -4
- package/dist/ci/preflight.js.map +1 -1
- package/dist/cli/gc.js +74 -0
- package/dist/cli/gc.js.map +1 -0
- package/dist/cli/init.js +217 -26
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/main.js +50 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/report.js +218 -0
- package/dist/cli/report.js.map +1 -0
- package/dist/cli/scan.js +36 -15
- package/dist/cli/scan.js.map +1 -1
- package/dist/cli/suite.js +7 -7
- package/dist/cli/suite.js.map +1 -1
- package/dist/cli/verify.js +7 -7
- package/dist/cli/verify.js.map +1 -1
- package/dist/consent/consent.js +162 -5
- package/dist/consent/consent.js.map +1 -1
- package/dist/context/detect.js +55 -18
- package/dist/context/detect.js.map +1 -1
- package/dist/context/findApps.js +22 -8
- package/dist/context/findApps.js.map +1 -1
- package/dist/context/projectRoot.js +174 -19
- package/dist/context/projectRoot.js.map +1 -1
- package/dist/context/scan.js +1 -1
- package/dist/context/scan.js.map +1 -1
- package/dist/core/capabilityGroups.js +90 -0
- package/dist/core/capabilityGroups.js.map +1 -0
- package/dist/core/target.js +10 -8
- package/dist/core/target.js.map +1 -1
- package/dist/core/targetPlan.js +160 -39
- package/dist/core/targetPlan.js.map +1 -1
- package/dist/drivers/DirectDriver.js +317 -43
- package/dist/drivers/DirectDriver.js.map +1 -1
- package/dist/drivers/SimctlDriver.js +124 -8
- package/dist/drivers/SimctlDriver.js.map +1 -1
- package/dist/drivers/WdaDriver.js +365 -55
- package/dist/drivers/WdaDriver.js.map +1 -1
- package/dist/explore/candidates.js +7 -3
- package/dist/explore/candidates.js.map +1 -1
- package/dist/explore/graph.js +15 -6
- package/dist/explore/graph.js.map +1 -1
- package/dist/explore/memory.js +4 -1
- package/dist/explore/memory.js.map +1 -1
- package/dist/explore/planner.js +54 -9
- package/dist/explore/planner.js.map +1 -1
- package/dist/explore/policy.js +11 -6
- package/dist/explore/policy.js.map +1 -1
- package/dist/explore/runner.js +363 -190
- package/dist/explore/runner.js.map +1 -1
- package/dist/explore/signatures.js +4 -2
- package/dist/explore/signatures.js.map +1 -1
- package/dist/explore/suite.js +3 -1
- package/dist/explore/suite.js.map +1 -1
- package/dist/featureTesting/executionBootstrap.js +137 -29
- package/dist/featureTesting/executionBootstrap.js.map +1 -1
- package/dist/featureTesting/featureMap.js +6 -3
- package/dist/featureTesting/featureMap.js.map +1 -1
- package/dist/featureTesting/featureScope.js +101 -20
- package/dist/featureTesting/featureScope.js.map +1 -1
- package/dist/featureTesting/mapFeatureScope.js +44 -15
- package/dist/featureTesting/mapFeatureScope.js.map +1 -1
- package/dist/featureTesting/objectiveModel.js +15 -11
- package/dist/featureTesting/objectiveModel.js.map +1 -1
- package/dist/featureTesting/resultMerge.js +16 -8
- package/dist/featureTesting/resultMerge.js.map +1 -1
- package/dist/featureTesting/sources.js +8 -5
- package/dist/featureTesting/sources.js.map +1 -1
- package/dist/featureTesting/suiteBridge.js +8 -2
- package/dist/featureTesting/suiteBridge.js.map +1 -1
- package/dist/featureTesting/synonyms.js +32 -4
- package/dist/featureTesting/synonyms.js.map +1 -1
- package/dist/featureTesting/testCaseFactory.js +27 -15
- package/dist/featureTesting/testCaseFactory.js.map +1 -1
- package/dist/featureTesting/testPlan.js +34 -12
- package/dist/featureTesting/testPlan.js.map +1 -1
- package/dist/firstRun/authStateMachine.js +1 -1
- package/dist/firstRun/authStateMachine.js.map +1 -1
- package/dist/firstRun/classifyScreen.js +9 -6
- package/dist/firstRun/classifyScreen.js.map +1 -1
- package/dist/firstRun/firstRunPlanner.js +16 -13
- package/dist/firstRun/firstRunPlanner.js.map +1 -1
- package/dist/firstRun/firstRunRunner.js +92 -31
- package/dist/firstRun/firstRunRunner.js.map +1 -1
- package/dist/firstRun/generatedDataPolicy.js +25 -15
- package/dist/firstRun/generatedDataPolicy.js.map +1 -1
- package/dist/firstRun/inputPlanner.js +45 -11
- package/dist/firstRun/inputPlanner.js.map +1 -1
- package/dist/firstRun/onboardingStateMachine.js +1 -1
- package/dist/firstRun/onboardingStateMachine.js.map +1 -1
- package/dist/firstRun/paywallPolicy.js +3 -3
- package/dist/firstRun/paywallPolicy.js.map +1 -1
- package/dist/firstRun/types.js +1 -1
- package/dist/firstRun/types.js.map +1 -1
- package/dist/fixtures/catalog.js +72 -9
- package/dist/fixtures/catalog.js.map +1 -1
- package/dist/fixtures/load.js +50 -0
- package/dist/fixtures/load.js.map +1 -0
- package/dist/flows/discover.js +2 -2
- package/dist/flows/discover.js.map +1 -1
- package/dist/flows/generate.js +68 -17
- package/dist/flows/generate.js.map +1 -1
- package/dist/flows/lint.js +88 -14
- package/dist/flows/lint.js.map +1 -1
- package/dist/flows/pack.js +21 -5
- package/dist/flows/pack.js.map +1 -1
- package/dist/flows/paths.js +57 -0
- package/dist/flows/paths.js.map +1 -0
- package/dist/flows/repair.js +176 -37
- package/dist/flows/repair.js.map +1 -1
- package/dist/flows/run.js +308 -99
- package/dist/flows/run.js.map +1 -1
- package/dist/flows/schema.js +107 -25
- package/dist/flows/schema.js.map +1 -1
- package/dist/flows/seedExec.js +8 -4
- package/dist/flows/seedExec.js.map +1 -1
- package/dist/flows/templates.js +5 -5
- package/dist/index.js +50 -8
- package/dist/index.js.map +1 -1
- package/dist/ios/signing.js +32 -3
- package/dist/ios/signing.js.map +1 -1
- package/dist/issues/classify.js +28 -20
- package/dist/issues/classify.js.map +1 -1
- package/dist/issues/fingerprint.js +35 -9
- package/dist/issues/fingerprint.js.map +1 -1
- package/dist/issues/index.js +93 -46
- package/dist/issues/index.js.map +1 -1
- package/dist/issues/metrics.js +6 -5
- package/dist/issues/metrics.js.map +1 -1
- package/dist/issues/recurrence.js +35 -8
- package/dist/issues/recurrence.js.map +1 -1
- package/dist/issues/report.js +12 -8
- package/dist/issues/report.js.map +1 -1
- package/dist/issues/reportBridge.js +40 -9
- package/dist/issues/reportBridge.js.map +1 -1
- package/dist/issues/schema.js +2 -2
- package/dist/issues/schema.js.map +1 -1
- package/dist/issues/sourceRevision.js +2 -2
- package/dist/issues/sourceRevision.js.map +1 -1
- package/dist/issues/store.js +110 -32
- package/dist/issues/store.js.map +1 -1
- package/dist/lib/abortScope.js +48 -0
- package/dist/lib/abortScope.js.map +1 -0
- package/dist/lib/android.js +84 -8
- package/dist/lib/android.js.map +1 -1
- package/dist/lib/coordSpace.js +1 -1
- package/dist/lib/coordSpace.js.map +1 -1
- package/dist/lib/device.js +53 -12
- package/dist/lib/device.js.map +1 -1
- package/dist/lib/gestures.js +141 -0
- package/dist/lib/gestures.js.map +1 -0
- package/dist/lib/gitignore.js +4 -3
- package/dist/lib/gitignore.js.map +1 -1
- package/dist/lib/image.js +12 -3
- package/dist/lib/image.js.map +1 -1
- package/dist/lib/lockfile.js +399 -0
- package/dist/lib/lockfile.js.map +1 -0
- package/dist/lib/needsInput.js +9 -6
- package/dist/lib/needsInput.js.map +1 -1
- package/dist/lib/png.js +4 -3
- package/dist/lib/png.js.map +1 -1
- package/dist/lib/redact.js +170 -9
- package/dist/lib/redact.js.map +1 -1
- package/dist/lib/result.js +94 -10
- package/dist/lib/result.js.map +1 -1
- package/dist/lib/schemaHash.js +7 -5
- package/dist/lib/schemaHash.js.map +1 -1
- package/dist/lib/sensitive.js +6 -3
- package/dist/lib/sensitive.js.map +1 -1
- package/dist/lib/simctl.js +3 -3
- package/dist/lib/simctl.js.map +1 -1
- package/dist/lib/spawn.js +78 -17
- package/dist/lib/spawn.js.map +1 -1
- package/dist/lib/toolAnnotations.js +114 -0
- package/dist/lib/toolAnnotations.js.map +1 -0
- package/dist/lib/wda.js +321 -25
- package/dist/lib/wda.js.map +1 -1
- package/dist/lib/wdaConfig.js +12 -5
- package/dist/lib/wdaConfig.js.map +1 -1
- package/dist/lib/wdaTune.js +52 -23
- package/dist/lib/wdaTune.js.map +1 -1
- package/dist/mobileAudit/checks.js +150 -28
- package/dist/mobileAudit/checks.js.map +1 -1
- package/dist/mobileAudit/evidence.js +4 -4
- package/dist/mobileAudit/evidence.js.map +1 -1
- package/dist/mobileAudit/profiles.js +121 -20
- package/dist/mobileAudit/profiles.js.map +1 -1
- package/dist/mobileAudit/results.js +9 -4
- package/dist/mobileAudit/results.js.map +1 -1
- package/dist/mobileAudit/runner.js +214 -35
- package/dist/mobileAudit/runner.js.map +1 -1
- package/dist/oracle/auth.js +1 -1
- package/dist/oracle/auth.js.map +1 -1
- package/dist/oracle/failures.js +1085 -145
- package/dist/oracle/failures.js.map +1 -1
- package/dist/oracle/health.js +148 -26
- package/dist/oracle/health.js.map +1 -1
- package/dist/oracle/locator.js +148 -19
- package/dist/oracle/locator.js.map +1 -1
- package/dist/oracle/record.js +3 -3
- package/dist/oracle/record.js.map +1 -1
- package/dist/orchestration/envelope.js +2 -2
- package/dist/orchestration/envelope.js.map +1 -1
- package/dist/orchestration/goal.js +7 -13
- package/dist/orchestration/goal.js.map +1 -1
- package/dist/orchestration/testThis/execute.js +167 -0
- package/dist/orchestration/testThis/execute.js.map +1 -0
- package/dist/orchestration/testThis/pipeline.js +413 -0
- package/dist/orchestration/testThis/pipeline.js.map +1 -0
- package/dist/orchestration/testThis/plan.js +519 -0
- package/dist/orchestration/testThis/plan.js.map +1 -0
- package/dist/orchestration/testThis/sessionIntent.js +72 -0
- package/dist/orchestration/testThis/sessionIntent.js.map +1 -0
- package/dist/orchestration/testThis/terminal.js +136 -0
- package/dist/orchestration/testThis/terminal.js.map +1 -0
- package/dist/orchestration/testThis/types.js +12 -0
- package/dist/orchestration/testThis/types.js.map +1 -0
- package/dist/plan/plan.js +9 -9
- package/dist/plan/plan.js.map +1 -1
- package/dist/prompts/index.js +24 -24
- package/dist/prompts/index.js.map +1 -1
- package/dist/report/coverage.js +0 -1
- package/dist/report/coverage.js.map +1 -1
- package/dist/report/evidence.js.map +1 -1
- package/dist/report/export.js +449 -72
- package/dist/report/export.js.map +1 -1
- package/dist/report/findingsDedupe.js +41 -0
- package/dist/report/findingsDedupe.js.map +1 -0
- package/dist/report/flake.js +13 -14
- package/dist/report/flake.js.map +1 -1
- package/dist/report/history.js +72 -38
- package/dist/report/history.js.map +1 -1
- package/dist/report/policy.js +18 -7
- package/dist/report/policy.js.map +1 -1
- package/dist/report/qaLevel.js +10 -16
- package/dist/report/qaLevel.js.map +1 -1
- package/dist/report/readiness.js +42 -12
- package/dist/report/readiness.js.map +1 -1
- package/dist/report/sarifSources.js +160 -0
- package/dist/report/sarifSources.js.map +1 -0
- package/dist/report/summary.js +2 -2
- package/dist/report/summary.js.map +1 -1
- package/dist/report/testCatalog.js +4 -4
- package/dist/report/testCatalog.js.map +1 -1
- package/dist/report/timing.js +23 -23
- package/dist/report/timing.js.map +1 -1
- package/dist/report/toolHealth.js +124 -0
- package/dist/report/toolHealth.js.map +1 -0
- package/dist/server.js +501 -69
- package/dist/server.js.map +1 -1
- package/dist/services/automationGenerate.js +8 -2
- package/dist/services/automationGenerate.js.map +1 -1
- package/dist/services/build.js +10 -4
- package/dist/services/build.js.map +1 -1
- package/dist/services/flowGenerate.js +75 -0
- package/dist/services/flowGenerate.js.map +1 -0
- package/dist/services/preflight.js +40 -8
- package/dist/services/preflight.js.map +1 -1
- package/dist/services/prepareAndroid.js +92 -18
- package/dist/services/prepareAndroid.js.map +1 -1
- package/dist/services/prepareIos.js +94 -17
- package/dist/services/prepareIos.js.map +1 -1
- package/dist/services/report.js +271 -80
- package/dist/services/report.js.map +1 -1
- package/dist/services/smoke.js +68 -22
- package/dist/services/smoke.js.map +1 -1
- package/dist/services/suiteGenerate.js +43 -6
- package/dist/services/suiteGenerate.js.map +1 -1
- package/dist/services/testSuiteKnowledge.js +78 -33
- package/dist/services/testSuiteKnowledge.js.map +1 -1
- package/dist/session/attach.js +284 -4
- package/dist/session/attach.js.map +1 -1
- package/dist/session/processRegistry.js +433 -0
- package/dist/session/processRegistry.js.map +1 -0
- package/dist/session/progress.js +1 -1
- package/dist/session/progress.js.map +1 -1
- package/dist/session/retention.js +201 -0
- package/dist/session/retention.js.map +1 -0
- package/dist/session/store.js +459 -59
- package/dist/session/store.js.map +1 -1
- package/dist/snapshot/overlays.js +60 -10
- package/dist/snapshot/overlays.js.map +1 -1
- package/dist/snapshot/parse.js +30 -12
- package/dist/snapshot/parse.js.map +1 -1
- package/dist/snapshot/present.js +36 -6
- package/dist/snapshot/present.js.map +1 -1
- package/dist/snapshot/settle.js +39 -9
- package/dist/snapshot/settle.js.map +1 -1
- package/dist/state/consent.js +99 -0
- package/dist/state/consent.js.map +1 -0
- package/dist/state/profile.js +82 -11
- package/dist/state/profile.js.map +1 -1
- package/dist/suite/compile.js +15 -6
- package/dist/suite/compile.js.map +1 -1
- package/dist/suite/lint.js +22 -4
- package/dist/suite/lint.js.map +1 -1
- package/dist/suite/pom.js +75 -44
- package/dist/suite/pom.js.map +1 -1
- package/dist/suite/secretGuard.js +266 -0
- package/dist/suite/secretGuard.js.map +1 -0
- package/dist/suite/testcase.js +15 -11
- package/dist/suite/testcase.js.map +1 -1
- package/dist/testSuite/exporter.js +7 -3
- package/dist/testSuite/exporter.js.map +1 -1
- package/dist/testSuite/generator.js +43 -14
- package/dist/testSuite/generator.js.map +1 -1
- package/dist/testSuite/history.js +1 -1
- package/dist/testSuite/history.js.map +1 -1
- package/dist/testSuite/issueLinks.js +3 -3
- package/dist/testSuite/issueLinks.js.map +1 -1
- package/dist/testSuite/lint.js +4 -4
- package/dist/testSuite/lint.js.map +1 -1
- package/dist/testSuite/merge.js +13 -7
- package/dist/testSuite/merge.js.map +1 -1
- package/dist/testSuite/schema.js +21 -16
- package/dist/testSuite/schema.js.map +1 -1
- package/dist/testSuite/store.js +12 -4
- package/dist/testSuite/store.js.map +1 -1
- package/dist/testSuite/traceability.js +2 -2
- package/dist/testSuite/traceability.js.map +1 -1
- package/dist/tools/act.js +868 -174
- package/dist/tools/act.js.map +1 -1
- package/dist/tools/agent.js +521 -112
- package/dist/tools/agent.js.map +1 -1
- package/dist/tools/appControl.js +82 -19
- package/dist/tools/appControl.js.map +1 -1
- package/dist/tools/appMap.js +393 -189
- package/dist/tools/appMap.js.map +1 -1
- package/dist/tools/build.js +92 -51
- package/dist/tools/build.js.map +1 -1
- package/dist/tools/bundletool.js +141 -40
- package/dist/tools/bundletool.js.map +1 -1
- package/dist/tools/clearOverlay.js +98 -18
- package/dist/tools/clearOverlay.js.map +1 -1
- package/dist/tools/device.js +108 -19
- package/dist/tools/device.js.map +1 -1
- package/dist/tools/doctor.js +98 -35
- package/dist/tools/doctor.js.map +1 -1
- package/dist/tools/explore.js +110 -42
- package/dist/tools/explore.js.map +1 -1
- package/dist/tools/featureTesting.js +152 -130
- package/dist/tools/featureTesting.js.map +1 -1
- package/dist/tools/firstRun.js +94 -66
- package/dist/tools/firstRun.js.map +1 -1
- package/dist/tools/flow.js +347 -132
- package/dist/tools/flow.js.map +1 -1
- package/dist/tools/flowRepair.js +42 -10
- package/dist/tools/flowRepair.js.map +1 -1
- package/dist/tools/generate.js +199 -0
- package/dist/tools/generate.js.map +1 -0
- package/dist/tools/getArtifact.js +37 -8
- package/dist/tools/getArtifact.js.map +1 -1
- package/dist/tools/health.js +17 -12
- package/dist/tools/health.js.map +1 -1
- package/dist/tools/ios.js +148 -194
- package/dist/tools/ios.js.map +1 -1
- package/dist/tools/issues.js +256 -171
- package/dist/tools/issues.js.map +1 -1
- package/dist/tools/jobs.js +55 -11
- package/dist/tools/jobs.js.map +1 -1
- package/dist/tools/metro.js +84 -38
- package/dist/tools/metro.js.map +1 -1
- package/dist/tools/mobileAudit.js +83 -26
- package/dist/tools/mobileAudit.js.map +1 -1
- package/dist/tools/network.js +36 -14
- package/dist/tools/network.js.map +1 -1
- package/dist/tools/note.js +31 -17
- package/dist/tools/note.js.map +1 -1
- package/dist/tools/prepareIosTarget.js +31 -14
- package/dist/tools/prepareIosTarget.js.map +1 -1
- package/dist/tools/prepareTarget.js +193 -47
- package/dist/tools/prepareTarget.js.map +1 -1
- package/dist/tools/report.js +16 -8
- package/dist/tools/report.js.map +1 -1
- package/dist/tools/resolveArtifact.js +12 -12
- package/dist/tools/resolveArtifact.js.map +1 -1
- package/dist/tools/resolveTarget.js +81 -18
- package/dist/tools/resolveTarget.js.map +1 -1
- package/dist/tools/screenRecord.js +85 -20
- package/dist/tools/screenRecord.js.map +1 -1
- package/dist/tools/screenshot.js +42 -18
- package/dist/tools/screenshot.js.map +1 -1
- package/dist/tools/smoke.js +29 -12
- package/dist/tools/smoke.js.map +1 -1
- package/dist/tools/snapshot.js +157 -107
- package/dist/tools/snapshot.js.map +1 -1
- package/dist/tools/startSession.js +117 -84
- package/dist/tools/startSession.js.map +1 -1
- package/dist/tools/suite.js +391 -310
- package/dist/tools/suite.js.map +1 -1
- package/dist/tools/testSuite.js +112 -36
- package/dist/tools/testSuite.js.map +1 -1
- package/dist/tools/testThis.js +35 -802
- package/dist/tools/testThis.js.map +1 -1
- package/dist/tools/visual.js +698 -116
- package/dist/tools/visual.js.map +1 -1
- package/dist/tools/wait.js +9 -23
- package/dist/tools/wait.js.map +1 -1
- package/dist/tools/wda.js +312 -54
- package/dist/tools/wda.js.map +1 -1
- package/dist/version.js +37 -64
- package/dist/version.js.map +1 -1
- package/dist/visual/ocr.js +65 -8
- package/dist/visual/ocr.js.map +1 -1
- package/dist/visual/provider.js +87 -15
- package/dist/visual/provider.js.map +1 -1
- package/docs/README.md +24 -10
- package/docs/ci-reports.md +328 -0
- package/docs/concepts.md +227 -0
- package/docs/flows.md +153 -0
- package/docs/mcp-server.md +210 -104
- package/docs/physical-devices.md +84 -0
- package/docs/tools.md +808 -217
- package/package.json +16 -6
- package/dist/appMap/diff.js +0 -60
- package/dist/appMap/diff.js.map +0 -1
- package/dist/automation/maestroIr.js +0 -282
- package/dist/automation/maestroIr.js.map +0 -1
- package/dist/interop/maestro.js +0 -151
- package/dist/interop/maestro.js.map +0 -1
- package/dist/tools/assertVisual.js +0 -74
- package/dist/tools/assertVisual.js.map +0 -1
- package/dist/tools/automationGenerate.js +0 -394
- package/dist/tools/automationGenerate.js.map +0 -1
- package/dist/tools/capabilities.js +0 -209
- package/dist/tools/capabilities.js.map +0 -1
- package/dist/tools/detectContext.js +0 -41
- package/dist/tools/detectContext.js.map +0 -1
- package/dist/tools/flowGenerate.js +0 -55
- package/dist/tools/flowGenerate.js.map +0 -1
- package/dist/tools/history.js +0 -56
- package/dist/tools/history.js.map +0 -1
- package/dist/tools/idling.js +0 -104
- package/dist/tools/idling.js.map +0 -1
- package/dist/tools/inputCapabilities.js +0 -30
- package/dist/tools/inputCapabilities.js.map +0 -1
- package/dist/tools/locator.js +0 -57
- package/dist/tools/locator.js.map +0 -1
- package/dist/tools/maestro.js +0 -78
- package/dist/tools/maestro.js.map +0 -1
- package/dist/tools/permissions.js +0 -149
- package/dist/tools/permissions.js.map +0 -1
- package/dist/tools/plan.js +0 -49
- package/dist/tools/plan.js.map +0 -1
- package/dist/tools/screenInfo.js +0 -70
- package/dist/tools/screenInfo.js.map +0 -1
- package/dist/tools/seed.js +0 -101
- package/dist/tools/seed.js.map +0 -1
- package/dist/tools/state.js +0 -170
- package/dist/tools/state.js.map +0 -1
- package/dist/tools/visualText.js +0 -61
- package/dist/tools/visualText.js.map +0 -1
package/dist/services/report.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
// Report service (Phase 3.2 Milestone B)
|
|
1
|
+
// Report service (Phase 3.2 Milestone B): the session-report assembly, extracted from the
|
|
2
2
|
// qa_report tool so qa_test_this execute can produce a real report artifact in EVERY terminal
|
|
3
3
|
// state (completed or blocked), not just tell the agent to call qa_report. qa_report is now a thin
|
|
4
4
|
// wrapper around generateSessionReport().
|
|
5
5
|
import { existsSync, writeFileSync } from 'node:fs';
|
|
6
|
-
import { makeRedactor } from '../lib/redact.js';
|
|
6
|
+
import { makeRedactor, redactDeep } from '../lib/redact.js';
|
|
7
|
+
import { inputBindings } from '../suite/secretGuard.js';
|
|
8
|
+
import { dedupeFindings, repeatSuffix } from '../report/findingsDedupe.js';
|
|
9
|
+
import { toolVerdictFor } from '../report/toolHealth.js';
|
|
7
10
|
import { getDriver } from '../session/attach.js';
|
|
8
11
|
import { restoreNetwork } from '../tools/network.js';
|
|
9
12
|
import { releaseAssessment } from '../report/summary.js';
|
|
10
13
|
import { FAILURES, failureForFindingKind, bucketForNoteCategory, ALL_BUCKETS } from '../oracle/failures.js';
|
|
11
|
-
import { inlinePrSummary,
|
|
14
|
+
import { inlinePrSummary, redactReportData, reportPolicyVerdicts, toGithubSummary, toJUnit, toMarkdown, toPlaywrightJson, toSarif, } from '../report/export.js';
|
|
15
|
+
import { applyPolicy, loadPolicy as loadReleasePolicy } from '../report/policy.js';
|
|
16
|
+
import { resolveSarifSources } from '../report/sarifSources.js';
|
|
12
17
|
import { generateFlow } from '../flows/generate.js';
|
|
13
18
|
import { loadProjectConfig } from '../cli/scan.js';
|
|
14
19
|
import { activeRecording } from '../tools/screenRecord.js';
|
|
@@ -32,11 +37,15 @@ import { resolveSourceRevision } from '../issues/sourceRevision.js';
|
|
|
32
37
|
import { loadPolicy as loadIssuePolicy, getIndex as getIssueIndex, readEvents as readIssueEvents } from '../issues/store.js';
|
|
33
38
|
import { computeIssueMetrics } from '../issues/metrics.js';
|
|
34
39
|
import { verifyFixed } from '../issues/index.js';
|
|
35
|
-
import { linkIssueToCase, linkRunIssue, relationshipForCase, runRelationshipFor, verifiedFixedIssuesForRun } from '../testSuite/issueLinks.js';
|
|
40
|
+
import { linkIssueToCase, linkRunIssue, relationshipForCase, runRelationshipFor, verifiedFixedIssuesForRun, } from '../testSuite/issueLinks.js';
|
|
36
41
|
import { saveSuite } from '../testSuite/store.js';
|
|
37
42
|
import { pomForSession } from './suiteGenerate.js';
|
|
38
43
|
import { generateCanonicalCases } from '../testSuite/generator.js';
|
|
39
44
|
import { applyMerge, loadSuite, suiteDelta, runIdFromNow } from '../testSuite/store.js';
|
|
45
|
+
/** Render an *Ms structured value as human-readable seconds for text summaries. */
|
|
46
|
+
function secText(ms) {
|
|
47
|
+
return `${Math.round((ms ?? 0) / 1000)}s`;
|
|
48
|
+
}
|
|
40
49
|
export async function generateSessionReport(sessions, session, options = {}) {
|
|
41
50
|
const { format, baseline, trendRoot } = options;
|
|
42
51
|
const includeCurrentDump = options.includeCurrentDump ?? true;
|
|
@@ -48,7 +57,7 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
48
57
|
if (driver)
|
|
49
58
|
networkRestore = (await restoreNetwork(sessions, session, driver)) ?? undefined;
|
|
50
59
|
else
|
|
51
|
-
networkRestore = 'PENDING
|
|
60
|
+
networkRestore = 'PENDING: Swipium changed the network but no device is attached to restore it';
|
|
52
61
|
}
|
|
53
62
|
// Attach a redacted current dump (best-effort) for triage.
|
|
54
63
|
let dumpUri;
|
|
@@ -63,6 +72,7 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
63
72
|
}
|
|
64
73
|
const finalNetwork = driver ? ((await driver.airplaneOn().catch(() => false)) ? 'offline' : 'online') : 'unknown';
|
|
65
74
|
const high = session.findings.filter((f) => f.severity === 'high');
|
|
75
|
+
const uniqueFindings = dedupeFindings(session.findings);
|
|
66
76
|
const nativeFindings = session.findings.filter((f) => f.layer === 'native');
|
|
67
77
|
const appFindings = session.findings.filter((f) => f.layer === 'app');
|
|
68
78
|
const nativeHealth = nativeFindings.some((f) => f.severity === 'high') ? 'error' : 'OK';
|
|
@@ -79,7 +89,9 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
79
89
|
(a[n.outcome] ??= {})[cat] = (a[n.outcome][cat] ?? 0) + 1;
|
|
80
90
|
return a;
|
|
81
91
|
}, {});
|
|
82
|
-
const visualVerifications = notes
|
|
92
|
+
const visualVerifications = notes
|
|
93
|
+
.filter((n) => n.verifiedVisually)
|
|
94
|
+
.map((n) => ({
|
|
83
95
|
workflow: n.workflow,
|
|
84
96
|
outcome: n.outcome,
|
|
85
97
|
evidenceKind: n.evidenceKind,
|
|
@@ -93,9 +105,9 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
93
105
|
const authState = a.loginPerformed
|
|
94
106
|
? 'login_performed'
|
|
95
107
|
: a.authedAtStart === true && !a.loginScreenSeen
|
|
96
|
-
? 'logged_in_at_start (persisted session
|
|
108
|
+
? 'logged_in_at_start (persisted session, login skipped)'
|
|
97
109
|
: a.loginScreenSeen
|
|
98
|
-
? 'auth_required_not_completed (login screen seen, no login performed
|
|
110
|
+
? 'auth_required_not_completed (login screen seen, no login performed, credentials may be missing)'
|
|
99
111
|
: 'unknown (no auth signal observed)';
|
|
100
112
|
const phaseTimings = phaseTimingsForSession(session);
|
|
101
113
|
const ec = session.envChanges;
|
|
@@ -137,7 +149,13 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
137
149
|
bucketExamples[bucket] ??= `${n.workflow}: ${n.reason ? redact(n.reason) : n.outcome}`;
|
|
138
150
|
}
|
|
139
151
|
const dominantBucket = ALL_BUCKETS.filter((b) => bucketCounts[b] > 0).sort((x, y) => bucketCounts[y] - bucketCounts[x])[0] ?? null;
|
|
140
|
-
const failureBuckets = {
|
|
152
|
+
const failureBuckets = {
|
|
153
|
+
counts: bucketCounts,
|
|
154
|
+
total: totalFailures,
|
|
155
|
+
classifiedPct: totalFailures ? Math.round((classified / totalFailures) * 100) : 100,
|
|
156
|
+
dominant: dominantBucket,
|
|
157
|
+
examples: bucketExamples,
|
|
158
|
+
};
|
|
141
159
|
const blockedCount = outcomeTally.blocked ?? 0;
|
|
142
160
|
const APP_OWNED_FAIL_CATEGORIES = new Set(['app_bug', 'other']);
|
|
143
161
|
const appFailNotes = notes.filter((n) => n.outcome === 'fail' && (n.category == null || APP_OWNED_FAIL_CATEGORIES.has(n.category)));
|
|
@@ -155,14 +173,21 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
155
173
|
blockedCount: blockedCount + toolLimitationFailCount,
|
|
156
174
|
overrideCount: session.envChanges.filter((c) => /OVERRIDE|GUARDRAIL|acknowledgeBundleRisk|allowLaunchWithoutMetro/i.test(c)).length,
|
|
157
175
|
topHighFinding: topHigh ? redact(topHigh.detail) : undefined,
|
|
158
|
-
topFail: topAppFailNote
|
|
176
|
+
topFail: topAppFailNote
|
|
177
|
+
? { workflow: topAppFailNote.workflow, reason: topAppFailNote.reason ? redact(topAppFailNote.reason) : undefined }
|
|
178
|
+
: undefined,
|
|
159
179
|
topBlocked: topBlockedNote ? { workflow: topBlockedNote.workflow, recommendedSetup: topBlockedNote.recommendedSetup } : undefined,
|
|
160
180
|
});
|
|
161
181
|
const outcomesByWorkflow = notes.reduce((acc, n) => {
|
|
162
|
-
acc[n.workflow] = {
|
|
182
|
+
acc[n.workflow] = {
|
|
183
|
+
outcome: n.outcome,
|
|
184
|
+
category: n.category,
|
|
185
|
+
reason: n.reason ? redact(n.reason) : undefined,
|
|
186
|
+
artifactUris: n.artifactUris ?? [],
|
|
187
|
+
};
|
|
163
188
|
return acc;
|
|
164
189
|
}, {});
|
|
165
|
-
const appId = session.appId ??
|
|
190
|
+
const appId = session.appId ?? loadProjectConfig(session.root)?.appId ?? null;
|
|
166
191
|
const wdaConfig = driver instanceof WdaDriver ? loadWdaConfig(session.root) : null;
|
|
167
192
|
const wdaReport = driver instanceof WdaDriver && wdaConfig
|
|
168
193
|
? {
|
|
@@ -174,11 +199,14 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
174
199
|
tuning: { timings: wdaTimingSummary(session), recommendations: wdaRecommendations(wdaConfig, session) },
|
|
175
200
|
}
|
|
176
201
|
: null;
|
|
177
|
-
const readiness = orderReadinessLabels([
|
|
202
|
+
const readiness = orderReadinessLabels([
|
|
203
|
+
...readinessForSession(session, {
|
|
178
204
|
suiteRunnable: options.suite?.suiteRunnable,
|
|
179
205
|
suiteReplayed: false,
|
|
180
206
|
ciReady: false,
|
|
181
|
-
}),
|
|
207
|
+
}),
|
|
208
|
+
...(options.suite?.readinessLabels ?? []),
|
|
209
|
+
]);
|
|
182
210
|
const automationReadiness = automationReadinessForSession(session, {
|
|
183
211
|
suiteRunnable: options.suite?.suiteRunnable,
|
|
184
212
|
suiteReplayed: false,
|
|
@@ -188,8 +216,15 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
188
216
|
const automationBackend = automationBackendForSession(session);
|
|
189
217
|
const passNotes = notes.filter((n) => n.outcome === 'pass').length;
|
|
190
218
|
const appVerdict = (() => {
|
|
191
|
-
if (nativeHealth === 'error' ||
|
|
192
|
-
|
|
219
|
+
if (nativeHealth === 'error' ||
|
|
220
|
+
appHealth === 'error' ||
|
|
221
|
+
high.some((f) => f.layer === 'app' || f.layer === 'native') ||
|
|
222
|
+
appFailCount > 0) {
|
|
223
|
+
const summary = topHigh
|
|
224
|
+
? (redact(topHigh.detail) ?? topHigh.detail)
|
|
225
|
+
: topAppFailNote?.reason
|
|
226
|
+
? (redact(topAppFailNote.reason) ?? topAppFailNote.reason)
|
|
227
|
+
: 'High severity app/native finding or failed app workflow observed.';
|
|
193
228
|
return { status: 'BLOCKED', summary };
|
|
194
229
|
}
|
|
195
230
|
if (appHealth === 'degraded')
|
|
@@ -198,27 +233,26 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
198
233
|
})();
|
|
199
234
|
const coverageVerdict = (() => {
|
|
200
235
|
if (blockedCount > 0 || toolLimitationNotes.length > 0 || session.exploration?.state === 'blocked') {
|
|
201
|
-
const summary = topBlockedNote?.recommendedSetup
|
|
202
|
-
|
|
236
|
+
const summary = topBlockedNote?.recommendedSetup ??
|
|
237
|
+
(toolLimitationNotes.length
|
|
238
|
+
? `A Swipium/tool limitation blocked ${toolLimitationNotes.length} workflow(s); see toolVerdict.`
|
|
239
|
+
: 'A setup or precondition blocker limited coverage.');
|
|
203
240
|
return { status: 'BLOCKED', summary };
|
|
204
241
|
}
|
|
205
242
|
if (!automationBackend.structured) {
|
|
206
|
-
return {
|
|
243
|
+
return {
|
|
244
|
+
status: 'PARTIAL',
|
|
245
|
+
summary: 'Coverage was limited because the active backend is visual-only or lacks structured UI automation.',
|
|
246
|
+
};
|
|
207
247
|
}
|
|
208
248
|
if (passNotes === 0 && !session.exploration && session.recordedActions.length === 0) {
|
|
209
249
|
return { status: 'SMOKE_ONLY', summary: 'Only launch/setup evidence was collected.' };
|
|
210
250
|
}
|
|
211
251
|
return { status: 'COVERED', summary: 'Structured smoke/workflow evidence was collected.' };
|
|
212
252
|
})();
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const first = toolLimitationNotes[0];
|
|
217
|
-
return {
|
|
218
|
-
status: 'BLOCKED',
|
|
219
|
-
summary: `${toolLimitationNotes.length} workflow(s) limited by Swipium/MCP capabilities (for example ${first.workflow}${first.reason ? `: ${redact(first.reason) ?? first.reason}` : ''}). These are tool limitations, not app defects.`,
|
|
220
|
-
};
|
|
221
|
-
})();
|
|
253
|
+
// Tool status reflects recorded tool errors (WDA 404, UNKNOWN…) as well as mcp_limitation notes,
|
|
254
|
+
// never "PASS" after tool errors. Tool health only: it does not change the app verdict.
|
|
255
|
+
const toolVerdict = toolVerdictFor(toolLimitationNotes, session.toolErrors, redact);
|
|
222
256
|
// Single product-facing QA level (Deliverable 6 / §3.11). Derived from the same evidence the
|
|
223
257
|
// report already trusts: readiness labels and health. Honest by construction.
|
|
224
258
|
const qaLevel = deriveQaLevel({
|
|
@@ -232,7 +266,7 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
232
266
|
ciReplayed: readiness.includes('ci_ready'),
|
|
233
267
|
});
|
|
234
268
|
// Universal run test catalog (Deliverable 4 / review #6): documents executed, skipped, blocked,
|
|
235
|
-
// and exploration-promoted workflows for EVERY run
|
|
269
|
+
// and exploration-promoted workflows for EVERY run, even when no suite was generated.
|
|
236
270
|
const suiteReplayStatus = readiness.includes('ci_ready')
|
|
237
271
|
? 'fresh_state'
|
|
238
272
|
: readiness.includes('replayed')
|
|
@@ -252,7 +286,7 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
252
286
|
method: n.method,
|
|
253
287
|
verifiedVisually: n.verifiedVisually,
|
|
254
288
|
})),
|
|
255
|
-
findings:
|
|
289
|
+
findings: uniqueFindings.map((f) => ({ kind: f.kind, severity: f.severity, detail: redact(f.detail) ?? f.detail })),
|
|
256
290
|
exploration: session.exploration
|
|
257
291
|
? {
|
|
258
292
|
screensVisited: session.exploration.summary.screensVisited,
|
|
@@ -268,9 +302,9 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
268
302
|
suiteReplayStatus,
|
|
269
303
|
observed: readiness.includes('observed'),
|
|
270
304
|
});
|
|
271
|
-
// Persistent QA test suite
|
|
305
|
+
// Persistent QA test suite: a report run observes QA knowledge, so update the
|
|
272
306
|
// canonical suite under .swipium/test-suite.json and embed the per-run delta + canonical case ids.
|
|
273
|
-
// Best-effort
|
|
307
|
+
// Best-effort: a suite-merge failure must never break report generation.
|
|
274
308
|
let persistentSuite = null;
|
|
275
309
|
let mergedSuite;
|
|
276
310
|
try {
|
|
@@ -288,7 +322,8 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
288
322
|
now,
|
|
289
323
|
replayStatus: suiteReplayStatus,
|
|
290
324
|
});
|
|
291
|
-
const applied = applyMerge(session.root, incoming,
|
|
325
|
+
const applied = applyMerge(session.root, redactDeep(incoming, redact), // defense in depth: no registered secret reaches test-suite.json / TC-*.yaml
|
|
326
|
+
{ source: 'report', mode: 'update', now, runId: runIdFromNow(now) }, appId ?? undefined);
|
|
292
327
|
mergedSuite = applied.result.suite;
|
|
293
328
|
const delta = suiteDelta(applied.result.suite, applied.result);
|
|
294
329
|
persistentSuite = {
|
|
@@ -301,13 +336,23 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
301
336
|
else {
|
|
302
337
|
const suite = loadSuite(session.root, appId ?? undefined);
|
|
303
338
|
mergedSuite = suite;
|
|
304
|
-
persistentSuite = {
|
|
339
|
+
persistentSuite = {
|
|
340
|
+
totalCases: suite.cases.length,
|
|
341
|
+
created: [],
|
|
342
|
+
updated: [],
|
|
343
|
+
deprecated: [],
|
|
344
|
+
failed: [],
|
|
345
|
+
blocked: [],
|
|
346
|
+
newlyAutomated: [],
|
|
347
|
+
caseIds: suite.cases.map((c) => c.id),
|
|
348
|
+
};
|
|
305
349
|
}
|
|
306
350
|
}
|
|
307
351
|
catch {
|
|
308
352
|
persistentSuite = null;
|
|
309
353
|
}
|
|
310
354
|
const screenshots = session.artifacts.filter((art) => art.kind === 'screenshot');
|
|
355
|
+
const toolErrors = session.toolErrors ?? [];
|
|
311
356
|
const report = {
|
|
312
357
|
sessionId: session.id,
|
|
313
358
|
executiveSummary,
|
|
@@ -333,6 +378,8 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
333
378
|
})),
|
|
334
379
|
workaroundsAttempted: session.workarounds,
|
|
335
380
|
inputsProvided: session.inputs.map((i) => ({ varName: i.varName, secret: i.secret, source: i.source })),
|
|
381
|
+
// Disclose degraded redaction after a server restart (secrets are never persisted).
|
|
382
|
+
redactionDegraded: session.redactionDegraded === true,
|
|
336
383
|
generatedValues: session.generatedValues.map((g) => ({
|
|
337
384
|
...g,
|
|
338
385
|
value: g.secret ? '<redacted>' : redact(g.value),
|
|
@@ -343,15 +390,32 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
343
390
|
finalNetwork,
|
|
344
391
|
networkRestore: networkRestore ?? (session.network ? 'no change pending' : 'unchanged'),
|
|
345
392
|
activeRecording: activeRecording(session.id) ?? null,
|
|
346
|
-
findings
|
|
393
|
+
// Identical findings (same code/kind + screen + message) collapse into one entry with a count.
|
|
394
|
+
findings: dedupeFindings(session.findings).map((f) => {
|
|
347
395
|
const code = f.failureCode ?? failureForFindingKind(f.kind);
|
|
348
396
|
const info = FAILURES[code] ?? FAILURES.UNKNOWN;
|
|
349
|
-
return {
|
|
397
|
+
return {
|
|
398
|
+
...f,
|
|
399
|
+
failureCode: code,
|
|
400
|
+
bucket: info.bucket,
|
|
401
|
+
retrySafe: info.retrySafe,
|
|
402
|
+
nextStep: info.recovery,
|
|
403
|
+
detail: redact(f.detail),
|
|
404
|
+
evidence: f.evidence ? redact(f.evidence) : undefined,
|
|
405
|
+
};
|
|
350
406
|
}),
|
|
407
|
+
findingOccurrences: session.findings.length,
|
|
408
|
+
toolErrors: toolErrors.slice(-50).map((t) => ({ ...t, message: redact(t.message) ?? t.message })),
|
|
351
409
|
highSeverityCount: high.length,
|
|
352
410
|
nativeHealth,
|
|
353
411
|
appHealth,
|
|
354
|
-
appHealthFindings: appFindings.map((f) => ({
|
|
412
|
+
appHealthFindings: appFindings.map((f) => ({
|
|
413
|
+
kind: f.kind,
|
|
414
|
+
severity: f.severity,
|
|
415
|
+
evidence: f.evidence ? redact(f.evidence) : undefined,
|
|
416
|
+
screen: f.screen,
|
|
417
|
+
screenshotUri: f.screenshotUri,
|
|
418
|
+
})),
|
|
355
419
|
testOutcomes: notes.map((n) => ({ ...n, reason: n.reason ? redact(n.reason) : undefined })),
|
|
356
420
|
outcomeTally,
|
|
357
421
|
categoryTally,
|
|
@@ -367,7 +431,7 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
367
431
|
wda: wdaReport,
|
|
368
432
|
ci: { env: !!process.env.CI },
|
|
369
433
|
visualOnly: session.mode === 'visual-fallback',
|
|
370
|
-
// Generated suite (Phase 3.2.1): paths, compiled flows, runnable status
|
|
434
|
+
// Generated suite (Phase 3.2.1): paths, compiled flows, runnable status, so the report (not
|
|
371
435
|
// just the job result) records whether a runnable automation suite was produced.
|
|
372
436
|
generatedSuite: options.suite ?? null,
|
|
373
437
|
// Guided exploration (Phase 3.3 §9.2): screen graph + coverage counts.
|
|
@@ -388,16 +452,36 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
388
452
|
artifacts: session.artifacts.map((art) => ({ uri: art.uri, kind: art.kind, mime: art.mime, label: art.label })),
|
|
389
453
|
counters: session.counters,
|
|
390
454
|
};
|
|
391
|
-
// Issue memory
|
|
455
|
+
// Issue memory: fold this run's findings + app-bug outcomes into the durable
|
|
392
456
|
// `.swipium/issues-log.jsonl`, reopen previously-fixed fingerprints, and attach the issue-memory
|
|
393
|
-
// section (+ recurrence markdown) to the report. Best-effort
|
|
457
|
+
// section (+ recurrence markdown) to the report. Best-effort: the ledger never breaks a report.
|
|
394
458
|
try {
|
|
395
459
|
const platform = driver instanceof WdaDriver ? 'ios' : driver ? 'android' : 'unknown';
|
|
396
460
|
const environment = session.headless !== undefined ? (platform === 'ios' ? 'simulator' : 'emulator') : process.env.CI ? 'ci' : 'unknown';
|
|
397
461
|
const issuePolicy = loadIssuePolicy(session.root);
|
|
398
|
-
const sourceRevision = resolveSourceRevision({
|
|
399
|
-
|
|
400
|
-
|
|
462
|
+
const sourceRevision = resolveSourceRevision({
|
|
463
|
+
env: process.env,
|
|
464
|
+
allowGitMetadataRead: issuePolicy.allowGitMetadataRead,
|
|
465
|
+
root: session.root,
|
|
466
|
+
});
|
|
467
|
+
const bridgeFindings = session.findings.map((f) => ({
|
|
468
|
+
severity: f.severity,
|
|
469
|
+
kind: f.kind,
|
|
470
|
+
detail: redact(f.detail) ?? f.detail,
|
|
471
|
+
layer: f.layer,
|
|
472
|
+
evidence: f.evidence ? redact(f.evidence) : undefined,
|
|
473
|
+
screen: f.screen,
|
|
474
|
+
screenshotUri: f.screenshotUri,
|
|
475
|
+
failureCode: f.failureCode,
|
|
476
|
+
}));
|
|
477
|
+
const bridgeNotes = notes.map((n) => ({
|
|
478
|
+
workflow: n.workflow,
|
|
479
|
+
outcome: n.outcome,
|
|
480
|
+
category: n.category,
|
|
481
|
+
reason: n.reason ? redact(n.reason) : undefined,
|
|
482
|
+
failureCode: n.failureCode,
|
|
483
|
+
artifactUris: n.artifactUris,
|
|
484
|
+
}));
|
|
401
485
|
const issuesNow = new Date().toISOString();
|
|
402
486
|
const bridge = foldRunIntoLedger(session.root, bridgeFindings, bridgeNotes, issuesNow, {
|
|
403
487
|
appId: appId ?? undefined,
|
|
@@ -407,14 +491,16 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
407
491
|
sourceRevision,
|
|
408
492
|
});
|
|
409
493
|
// Link recorded issues to persistent test cases, and verify fixed issues that a PASSING case
|
|
410
|
-
// covers this run
|
|
494
|
+
// covers this run. The case > workflow key is the workflow string the suite generator
|
|
411
495
|
// folds into actualResult.summary.
|
|
412
496
|
let verifiedFixedIds = new Set();
|
|
413
497
|
if (mergedSuite) {
|
|
414
498
|
const idx = getIssueIndex(session.root, issuesNow, appId ?? undefined);
|
|
415
499
|
const recordById = new Map(idx.records.map((r) => [r.issueId, r]));
|
|
416
500
|
const matchCase = (workflow) => workflow
|
|
417
|
-
? mergedSuite.cases.filter((c) => c.actualResult.summary?.toLowerCase().includes(workflow.toLowerCase()) ||
|
|
501
|
+
? mergedSuite.cases.filter((c) => c.actualResult.summary?.toLowerCase().includes(workflow.toLowerCase()) ||
|
|
502
|
+
c.functionality.toLowerCase() === workflow.toLowerCase() ||
|
|
503
|
+
c.title.toLowerCase().includes(workflow.toLowerCase()))
|
|
418
504
|
: [];
|
|
419
505
|
for (const rec of bridge.recorded) {
|
|
420
506
|
const record = recordById.get(rec.issueId);
|
|
@@ -441,14 +527,14 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
441
527
|
verifiedFixedIds = new Set(verified);
|
|
442
528
|
saveSuite(session.root, mergedSuite);
|
|
443
529
|
}
|
|
444
|
-
// Rebuild the section honoring verified-fixed evidence (
|
|
530
|
+
// Rebuild the section honoring verified-fixed evidence (honest fix verification).
|
|
445
531
|
const finalIdx = getIssueIndex(session.root, issuesNow, appId ?? undefined);
|
|
446
532
|
const finalSection = buildReportIssuesSection(finalIdx.records, new Set(bridge.recordedIssueIds), verifiedFixedIds);
|
|
447
533
|
report.issues = finalSection;
|
|
448
534
|
report.issuesMarkdown = issuesSectionToMarkdown(finalSection);
|
|
449
535
|
if (bridge.recurrences.length)
|
|
450
536
|
report.issueRecurrences = bridge.recurrences;
|
|
451
|
-
// Compact quality metrics when enough history exists
|
|
537
|
+
// Compact quality metrics when enough history exists: this run's new/reopened/verified
|
|
452
538
|
// counts + open blocker/high totals + reopen/fix-verification rates.
|
|
453
539
|
const allEvents = readIssueEvents(session.root);
|
|
454
540
|
if (allEvents.length >= 2) {
|
|
@@ -464,15 +550,24 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
464
550
|
avgAgeDays: metrics.avgAgeDays,
|
|
465
551
|
};
|
|
466
552
|
}
|
|
467
|
-
// Refresh app-map issue summaries from the freshly-updated ledger
|
|
468
|
-
// already exists, and WITHOUT a static rescan (runtime_merge load
|
|
553
|
+
// Refresh app-map issue summaries from the freshly-updated ledger, only when a map
|
|
554
|
+
// already exists, and WITHOUT a static rescan (runtime_merge load > apply summaries > save).
|
|
469
555
|
if (existsSync(appMapPath(session.root))) {
|
|
470
556
|
buildAppMap(session.root, { mode: 'runtime_merge', at: issuesNow, includeCodeIndex: false, persist: true });
|
|
471
557
|
}
|
|
472
558
|
}
|
|
473
559
|
catch {
|
|
474
|
-
/* best-effort
|
|
560
|
+
/* best-effort: issue ledger is additive, never blocks the report */
|
|
475
561
|
}
|
|
562
|
+
// B9: deep-redact the WHOLE report (steps, nextStep, missingPrecondition, workflow names, issue
|
|
563
|
+
// markdown, …) with the session redactor before it is persisted or rendered into any export.
|
|
564
|
+
// Escaping in JUnit/SARIF/Markdown would otherwise turn a secret into text redaction can't match.
|
|
565
|
+
// Replace the fields rather than merge: a top-level key that itself redacts to a different
|
|
566
|
+
// spelling must not survive in its raw form next to the redacted copy.
|
|
567
|
+
const redactedReport = redactReportData(report, redact);
|
|
568
|
+
for (const k of Object.keys(report))
|
|
569
|
+
delete report[k];
|
|
570
|
+
Object.assign(report, redactedReport);
|
|
476
571
|
const prSummary = { text: inlinePrSummary(report) };
|
|
477
572
|
report.prSummary = prSummary;
|
|
478
573
|
const reportUri = sessions.saveArtifact(session, 'report', `report-${Date.now()}.json`, JSON.stringify(report, null, 2), 'application/json');
|
|
@@ -481,12 +576,26 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
481
576
|
if ((baseline || trendRoot) && reportRec) {
|
|
482
577
|
try {
|
|
483
578
|
const pr = buildPrSummary(reportRec.path, { baselinePath: baseline, trendRoot: trendRoot ?? session.root });
|
|
484
|
-
reportLinks = {
|
|
579
|
+
reportLinks = {
|
|
580
|
+
current: reportUri,
|
|
581
|
+
currentPath: reportRec.path,
|
|
582
|
+
baseline: baseline ?? null,
|
|
583
|
+
trendRoot: trendRoot ?? session.root,
|
|
584
|
+
comparison: pr.comparison ?? null,
|
|
585
|
+
knownFlaky: pr.knownFlaky,
|
|
586
|
+
prSummary: pr,
|
|
587
|
+
};
|
|
485
588
|
report.reportLinks = reportLinks;
|
|
486
589
|
writeFileSync(reportRec.path, JSON.stringify(report, null, 2));
|
|
487
590
|
}
|
|
488
591
|
catch (e) {
|
|
489
|
-
reportLinks = {
|
|
592
|
+
reportLinks = {
|
|
593
|
+
current: reportUri,
|
|
594
|
+
currentPath: reportRec.path,
|
|
595
|
+
baseline: baseline ?? null,
|
|
596
|
+
trendRoot: trendRoot ?? session.root,
|
|
597
|
+
error: String(e.message ?? e),
|
|
598
|
+
};
|
|
490
599
|
report.reportLinks = reportLinks;
|
|
491
600
|
writeFileSync(reportRec.path, JSON.stringify(report, null, 2));
|
|
492
601
|
}
|
|
@@ -502,15 +611,49 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
502
611
|
flowExportSkipped = true;
|
|
503
612
|
}
|
|
504
613
|
else {
|
|
505
|
-
const gen = generateFlow(session.recordedActions, {
|
|
614
|
+
const gen = generateFlow(session.recordedActions, {
|
|
615
|
+
name: `${(appId ?? 'app').split('.').pop()}-recorded`,
|
|
616
|
+
appId: appId ?? undefined,
|
|
617
|
+
secrets: session.secrets,
|
|
618
|
+
inputs: inputBindings(session),
|
|
619
|
+
});
|
|
506
620
|
exportUri = sessions.saveArtifact(session, 'flow', `recorded-${Date.now()}.yaml`, gen.yaml, 'text/yaml', `flow drafted from the run (durability ${gen.durability.grade})`);
|
|
507
621
|
}
|
|
508
622
|
}
|
|
509
623
|
else {
|
|
510
624
|
const data = report;
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
625
|
+
// CI formats (junit/sarif/github-summary) carry a release-gate verdict: map the report's
|
|
626
|
+
// failures onto policy FlowVerdicts, then let .swipium/policy.json (blockOn/warnOn/
|
|
627
|
+
// ignoreKnown) decide pass/fail. With no policy file, ANY failure blocks (applyPolicy).
|
|
628
|
+
const ciFormat = format === 'junit' || format === 'sarif' || format === 'github-summary';
|
|
629
|
+
const policy = ciFormat
|
|
630
|
+
? applyPolicy(reportPolicyVerdicts(data), loadReleasePolicy(session.root))
|
|
631
|
+
: undefined;
|
|
632
|
+
const body = format === 'markdown'
|
|
633
|
+
? toMarkdown(data)
|
|
634
|
+
: format === 'playwright'
|
|
635
|
+
? toPlaywrightJson(data)
|
|
636
|
+
: format === 'sarif'
|
|
637
|
+
? toSarif(data, policy, { sources: resolveSarifSources(session.root, data) })
|
|
638
|
+
: format === 'github-summary'
|
|
639
|
+
? toGithubSummary(data, policy)
|
|
640
|
+
: toJUnit(data, policy);
|
|
641
|
+
const ext = format === 'markdown'
|
|
642
|
+
? 'md'
|
|
643
|
+
: format === 'playwright'
|
|
644
|
+
? 'playwright.json'
|
|
645
|
+
: format === 'sarif'
|
|
646
|
+
? 'sarif.json'
|
|
647
|
+
: format === 'github-summary'
|
|
648
|
+
? 'summary.md'
|
|
649
|
+
: 'xml';
|
|
650
|
+
const mime = format === 'markdown' || format === 'github-summary'
|
|
651
|
+
? 'text/markdown'
|
|
652
|
+
: format === 'playwright'
|
|
653
|
+
? 'application/json'
|
|
654
|
+
: format === 'sarif'
|
|
655
|
+
? 'application/sarif+json'
|
|
656
|
+
: 'application/xml';
|
|
514
657
|
exportUri = sessions.saveArtifact(session, 'report', `report-${Date.now()}.${ext}`, body, mime);
|
|
515
658
|
}
|
|
516
659
|
}
|
|
@@ -518,55 +661,92 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
518
661
|
const manifestUri = sessions.saveArtifact(session, 'manifest', `manifest-${Date.now()}.json`, JSON.stringify(manifest, null, 2), 'application/json', 'artifact manifest with SHA-256 hashes');
|
|
519
662
|
const noteSummaryLines = notes.map((n) => {
|
|
520
663
|
const ev = evidenceByWorkflow.get(n.workflow);
|
|
521
|
-
return ` • ${n.workflow}: ${n.outcome}${ev ? ` (evidence=${ev.kind}/${ev.authority})` : ''}${n.category ? ` [${n.category}]` : ''}${n.missingPrecondition ? `
|
|
664
|
+
return ` • ${n.workflow}: ${n.outcome}${ev ? ` (evidence=${ev.kind}/${ev.authority})` : ''}${n.category ? ` [${n.category}]` : ''}${n.missingPrecondition ? ` (missing: ${n.missingPrecondition})` : n.reason ? `: ${redact(n.reason)}` : ''}${n.recommendedSetup ? ` · setup: ${n.recommendedSetup}` : ''}`;
|
|
522
665
|
});
|
|
523
666
|
const lines = [
|
|
524
|
-
`Report for ${session.id}
|
|
525
|
-
`RELEASE RISK: ${executiveSummary.risk.toUpperCase()}
|
|
667
|
+
`Report for ${session.id}: app=${report.appId} device=${report.device}`,
|
|
668
|
+
`RELEASE RISK: ${executiveSummary.risk.toUpperCase()}: ${executiveSummary.nextAction}`,
|
|
526
669
|
`App status: ${appVerdict.status} - ${appVerdict.summary}`,
|
|
527
670
|
`Coverage status: ${coverageVerdict.status} - ${coverageVerdict.summary}`,
|
|
528
671
|
`Tool status: ${toolVerdict.status} - ${toolVerdict.summary}`,
|
|
529
672
|
`PR summary:\n${prSummary.text}`,
|
|
530
673
|
`backend: ${report.automationBackend.description} (${report.automationBackend.mode})`,
|
|
531
|
-
`QA level: ${qaLevel.level.toUpperCase()}
|
|
674
|
+
`QA level: ${qaLevel.level.toUpperCase()}: ${qaLevel.rationale}${qaLevel.next ? ` · next: ${qaLevel.next} (${qaLevel.nextRequirement})` : ''}`,
|
|
532
675
|
qaLevel.notes.length ? `QA level notes:\n ${qaLevel.notes.join('\n ')}` : '',
|
|
533
676
|
`automation readiness: ${automationReadiness.grade} (${automationReadiness.score}/100, durable locators ${automationReadiness.locatorCoverage.durablePct}%)`,
|
|
534
|
-
`test catalog: ${runTestCatalog.total} case(s)
|
|
535
|
-
|
|
536
|
-
|
|
677
|
+
`test catalog: ${runTestCatalog.total} case(s): ${Object.entries(runTestCatalog.counts)
|
|
678
|
+
.filter(([, v]) => v)
|
|
679
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
680
|
+
.join(' ') || 'none'}`,
|
|
681
|
+
automationReadiness.topFixes.length
|
|
682
|
+
? `top readiness fixes:\n ${automationReadiness.topFixes.join('\n ')}`
|
|
683
|
+
: 'top readiness fixes: none',
|
|
684
|
+
`${report.coverage}${report.visualOnly ? ' · VISUAL-ONLY (structured snapshots were poor, see screenshots)' : ''}`,
|
|
537
685
|
`emulator display: ${report.emulatorDisplay}`,
|
|
538
686
|
`network: ${finalNetwork}${networkRestore ? ` (${networkRestore})` : session.network?.changed ? ' ⚠ Swipium changed it and did NOT restore' : ''}`,
|
|
539
|
-
report.activeRecording
|
|
687
|
+
report.activeRecording
|
|
688
|
+
? `A screen recording is still active (${report.activeRecording.backend}, ~${report.activeRecording.seconds}s). It will be stopped on shutdown.`
|
|
689
|
+
: '',
|
|
540
690
|
session.envChanges.length ? `environment changes:\n ${session.envChanges.join('\n ')}` : 'environment changes: none',
|
|
541
|
-
session.mutations.length
|
|
542
|
-
|
|
691
|
+
session.mutations.length
|
|
692
|
+
? `mutation ledger: ${session.mutations.length} record(s), ${session.mutations.filter((m) => m.status === 'executed').length} executed, ${session.mutations.filter((m) => m.status === 'refused' || m.status === 'blocked').length} refused/blocked`
|
|
693
|
+
: 'mutation ledger: none',
|
|
694
|
+
report.guardrailOverrides.length
|
|
695
|
+
? `⚠ guardrail overrides used:\n ${report.guardrailOverrides.join('\n ')}`
|
|
696
|
+
: 'guardrail overrides: none',
|
|
543
697
|
session.workarounds.length ? `workarounds attempted:\n ${session.workarounds.join('\n ')}` : '',
|
|
544
|
-
session.inputs.length
|
|
545
|
-
|
|
698
|
+
session.inputs.length
|
|
699
|
+
? `inputs provided (redacted): ${session.inputs.map((i) => `${i.varName}${i.secret ? '🔒' : ''}`).join(', ')}`
|
|
700
|
+
: '',
|
|
701
|
+
session.redactionDegraded
|
|
702
|
+
? '⚠ redaction degraded: this session was restored after a server restart. Secrets registered before the restart are no longer in the redaction set, so artifacts written since may contain those values unredacted'
|
|
703
|
+
: '',
|
|
704
|
+
session.generatedValues.length
|
|
705
|
+
? `generated test data: ${session.generatedValues.map((g) => `${g.fixture}.${g.field}=${g.secret ? '<redacted>' : redact(g.value)} (${g.generator})`).join(', ')}`
|
|
706
|
+
: '',
|
|
546
707
|
options.suite
|
|
547
708
|
? options.suite.generated
|
|
548
|
-
? `generated suite "${options.suite.name}": ${(options.suite.compiledFlows ?? []).filter((c) => c.ok).length}/${(options.suite.compiledFlows ?? []).length} runnable flow(s), runnable=${options.suite.suiteRunnable}, readiness=${(options.suite.readinessLabels ?? []).join('
|
|
709
|
+
? `generated suite "${options.suite.name}": ${(options.suite.compiledFlows ?? []).filter((c) => c.ok).length}/${(options.suite.compiledFlows ?? []).length} runnable flow(s), runnable=${options.suite.suiteRunnable}, readiness=${(options.suite.readinessLabels ?? []).join(' > ') || 'unknown'} (${(options.suite.written ?? []).length} files)`
|
|
549
710
|
: `suite generation skipped: ${options.suite.skippedReason}`
|
|
550
711
|
: '',
|
|
551
712
|
session.exploration
|
|
552
713
|
? `exploration: ${session.exploration.summary.screensVisited} screens, ${session.exploration.summary.workflowsFound} transitions, ${session.exploration.summary.visualOnlyScreens} visual-only, ${session.exploration.summary.unsafeActionsSkipped} unsafe skipped, ${session.exploration.summary.appErrors} app errors (graph: ${session.exploration.graphUri})`
|
|
553
714
|
: '',
|
|
554
715
|
`destructive/bundle-risk guardrail: ${destructiveGuardrail.status}`,
|
|
555
|
-
`health
|
|
556
|
-
wdaReport
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
716
|
+
`health: native: ${nativeHealth === 'OK' ? '✅ OK' : '❌ error'} · app: ${appHealth === 'OK' ? '✅ OK' : appHealth === 'degraded' ? '⚠ degraded' : '❌ error'}`,
|
|
717
|
+
wdaReport
|
|
718
|
+
? `wda: ${wdaReport.status.reachable ? 'reachable' : 'unreachable'} ${wdaReport.webDriverAgentUrl} device=${wdaReport.device ?? 'unknown'}`
|
|
719
|
+
: '',
|
|
720
|
+
`findings: ${uniqueFindings.length} unique (${session.findings.length} occurrence(s), high: ${high.length})`,
|
|
721
|
+
toolErrors.length
|
|
722
|
+
? `tool errors: ${toolVerdict.toolErrorCount}: ${Object.entries(toolVerdict.toolErrorsByCode)
|
|
723
|
+
.map(([c, n]) => `${c}×${n}`)
|
|
724
|
+
.join(', ')}`
|
|
725
|
+
: '',
|
|
726
|
+
totalFailures
|
|
727
|
+
? `failures by bucket: ${ALL_BUCKETS.filter((b) => bucketCounts[b])
|
|
728
|
+
.map((b) => `${b}=${bucketCounts[b]}`)
|
|
729
|
+
.join(' ')} (${failureBuckets.classifiedPct}% classified${dominantBucket ? `, mostly ${dominantBucket}` : ''})`
|
|
730
|
+
: '',
|
|
731
|
+
notes.length
|
|
732
|
+
? `evidence taxonomy: structured=${evidenceTaxonomy.counts.structured_locator} ocr=${evidenceTaxonomy.counts.ocr_locator} visual=${evidenceTaxonomy.counts.visual_match} ai_visual=${evidenceTaxonomy.counts.ai_visual_evidence} manual=${evidenceTaxonomy.counts.manual_review} calibration=${evidenceTaxonomy.calibration.status}`
|
|
733
|
+
: '',
|
|
734
|
+
...uniqueFindings.map((f) => ` [${f.severity}] ${f.layer ?? '?'}/${f.kind}: ${redact(f.detail)}${f.evidence ? `: "${redact(f.evidence)}"` : ''}${f.screenshotUri ? ` (${f.screenshotUri})` : ''}${repeatSuffix(f)}`),
|
|
735
|
+
notes.length
|
|
736
|
+
? `test outcomes: ${Object.entries(outcomeTally)
|
|
737
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
738
|
+
.join(' ')}`
|
|
739
|
+
: 'test outcomes: none recorded (qa_note)',
|
|
562
740
|
...noteSummaryLines,
|
|
563
741
|
persistentSuite
|
|
564
|
-
? `persistent suite: ${persistentSuite.totalCases} case(s)
|
|
742
|
+
? `persistent suite: ${persistentSuite.totalCases} case(s): +${persistentSuite.created.length} created, ~${persistentSuite.updated.length} updated, -${persistentSuite.deprecated.length} deprecated, ${persistentSuite.failed.length} failed, ${persistentSuite.blocked.length} blocked, ${persistentSuite.newlyAutomated.length} newly automated`
|
|
565
743
|
: '',
|
|
566
744
|
`auth: ${authState}`,
|
|
567
745
|
session.fixtures.length ? `declared preconditions: ${session.fixtures.map((f) => f.name).join(', ')}` : '',
|
|
568
|
-
`timing: total=${phaseTimings.
|
|
569
|
-
reportLinks
|
|
746
|
+
`timing: total=${secText(phaseTimings.totalMs)} setup=${secText(phaseTimings.setupMs)} active=${secText(phaseTimings.activeMs)}${phaseTimings.timeToLoginMs != null ? ` toLogin=${secText(phaseTimings.timeToLoginMs)}` : ''}${phaseTimings.diagnostics.waitMs != null ? ` wait=${secText(phaseTimings.diagnostics.waitMs)}` : ''}${phaseTimings.diagnostics.flowRuntimeMs != null ? ` flows=${secText(phaseTimings.diagnostics.flowRuntimeMs)}` : ''}${session.budgetProfile ? ` (profile=${session.budgetProfile})` : ''}`,
|
|
747
|
+
reportLinks
|
|
748
|
+
? `report links: baseline=${baseline ?? 'none'} trend=${trendRoot ?? session.root}${typeof reportLinks.comparison === 'string' ? ` comparison=${reportLinks.comparison}` : ''}`
|
|
749
|
+
: '',
|
|
570
750
|
`artifacts: ${session.artifacts.length} (${screenshots.length} screenshots)`,
|
|
571
751
|
...session.artifacts.map((art) => ` ${art.uri} (${art.kind}${art.label ? `: ${art.label}` : ''})`),
|
|
572
752
|
dumpUri ? `current dump: ${dumpUri}` : '',
|
|
@@ -574,6 +754,17 @@ export async function generateSessionReport(sessions, session, options = {}) {
|
|
|
574
754
|
`manifest: ${manifestUri}`,
|
|
575
755
|
exportUri && exportUri !== reportUri ? `${format} export: ${exportUri}` : '',
|
|
576
756
|
].filter(Boolean);
|
|
577
|
-
return {
|
|
757
|
+
return {
|
|
758
|
+
report,
|
|
759
|
+
reportUri,
|
|
760
|
+
manifestUri,
|
|
761
|
+
manifest,
|
|
762
|
+
dumpUri,
|
|
763
|
+
reportLinks,
|
|
764
|
+
exportUri,
|
|
765
|
+
exportFormat: exportUri ? format : undefined,
|
|
766
|
+
summaryText: redact(lines.join('\n')) ?? '',
|
|
767
|
+
flowExportSkipped,
|
|
768
|
+
};
|
|
578
769
|
}
|
|
579
770
|
//# sourceMappingURL=report.js.map
|