@sun-asterisk/sungen 3.2.28 → 3.2.30
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/dist/capabilities/discover.d.ts +29 -0
- package/dist/capabilities/discover.d.ts.map +1 -1
- package/dist/capabilities/discover.js +144 -10
- package/dist/capabilities/discover.js.map +1 -1
- package/dist/capabilities/registry.d.ts +18 -0
- package/dist/capabilities/registry.d.ts.map +1 -1
- package/dist/capabilities/registry.js +25 -0
- package/dist/capabilities/registry.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +9 -0
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/capability.js +1 -1
- package/dist/cli/commands/capability.js.map +1 -1
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +2 -1
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +6 -2
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/inspect.js +1 -1
- package/dist/cli/commands/inspect.js.map +1 -1
- package/dist/cli/commands/results-merge.d.ts.map +1 -1
- package/dist/cli/commands/results-merge.js +9 -2
- package/dist/cli/commands/results-merge.js.map +1 -1
- package/dist/cli/commands/results-sanitize.d.ts +24 -0
- package/dist/cli/commands/results-sanitize.d.ts.map +1 -0
- package/dist/cli/commands/results-sanitize.js +126 -0
- package/dist/cli/commands/results-sanitize.js.map +1 -0
- package/dist/cli/commands/script-check.d.ts.map +1 -1
- package/dist/cli/commands/script-check.js +3 -1
- package/dist/cli/commands/script-check.js.map +1 -1
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +3 -0
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/dashboard/templates/index.html +1 -1
- package/dist/exporters/api-testcase-formatter.d.ts +3 -6
- package/dist/exporters/api-testcase-formatter.d.ts.map +1 -1
- package/dist/exporters/api-testcase-formatter.js +7 -10
- package/dist/exporters/api-testcase-formatter.js.map +1 -1
- package/dist/exporters/feature-parser.d.ts +1 -1
- package/dist/exporters/feature-parser.js +1 -1
- package/dist/exporters/matrix/build.d.ts.map +1 -1
- package/dist/exporters/matrix/build.js +18 -3
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/item-labels.d.ts +35 -0
- package/dist/exporters/matrix/item-labels.d.ts.map +1 -0
- package/dist/exporters/matrix/item-labels.js +90 -0
- package/dist/exporters/matrix/item-labels.js.map +1 -0
- package/dist/exporters/matrix/render-coverage-sheet.d.ts +14 -0
- package/dist/exporters/matrix/render-coverage-sheet.d.ts.map +1 -0
- package/dist/exporters/matrix/render-coverage-sheet.js +162 -0
- package/dist/exporters/matrix/render-coverage-sheet.js.map +1 -0
- package/dist/exporters/matrix/render-csv.d.ts.map +1 -1
- package/dist/exporters/matrix/render-csv.js +3 -1
- package/dist/exporters/matrix/render-csv.js.map +1 -1
- package/dist/exporters/matrix/render-overview-sheet.d.ts +20 -0
- package/dist/exporters/matrix/render-overview-sheet.d.ts.map +1 -0
- package/dist/exporters/matrix/render-overview-sheet.js +32 -0
- package/dist/exporters/matrix/render-overview-sheet.js.map +1 -0
- package/dist/exporters/matrix/render-testcase-sheet.d.ts +30 -0
- package/dist/exporters/matrix/render-testcase-sheet.d.ts.map +1 -0
- package/dist/exporters/matrix/render-testcase-sheet.js +156 -0
- package/dist/exporters/matrix/render-testcase-sheet.js.map +1 -0
- package/dist/exporters/matrix/render-xlsx.d.ts +41 -31
- package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
- package/dist/exporters/matrix/render-xlsx.js +72 -425
- package/dist/exporters/matrix/render-xlsx.js.map +1 -1
- package/dist/exporters/matrix/result-totals.d.ts +23 -0
- package/dist/exporters/matrix/result-totals.d.ts.map +1 -0
- package/dist/exporters/matrix/result-totals.js +21 -0
- package/dist/exporters/matrix/result-totals.js.map +1 -0
- package/dist/exporters/matrix/testcase-summary-band.d.ts +30 -0
- package/dist/exporters/matrix/testcase-summary-band.d.ts.map +1 -0
- package/dist/exporters/matrix/testcase-summary-band.js +71 -0
- package/dist/exporters/matrix/testcase-summary-band.js.map +1 -0
- package/dist/exporters/matrix/wording.d.ts.map +1 -1
- package/dist/exporters/matrix/wording.js +13 -0
- package/dist/exporters/matrix/wording.js.map +1 -1
- package/dist/exporters/matrix/xlsx-cells.d.ts +38 -0
- package/dist/exporters/matrix/xlsx-cells.d.ts.map +1 -0
- package/dist/exporters/matrix/xlsx-cells.js +52 -0
- package/dist/exporters/matrix/xlsx-cells.js.map +1 -0
- package/dist/exporters/qa-env-secret-denylist.js +2 -2
- package/dist/exporters/qa-env-secret-denylist.js.map +1 -1
- package/dist/exporters/report-path-sanitizer.d.ts +38 -0
- package/dist/exporters/report-path-sanitizer.d.ts.map +1 -0
- package/dist/exporters/report-path-sanitizer.js +137 -0
- package/dist/exporters/report-path-sanitizer.js.map +1 -0
- package/dist/exporters/result-variants.d.ts.map +1 -1
- package/dist/exporters/result-variants.js +2 -1
- package/dist/exporters/result-variants.js.map +1 -1
- package/dist/exporters/sensitive-key.d.ts +31 -0
- package/dist/exporters/sensitive-key.d.ts.map +1 -0
- package/dist/exporters/sensitive-key.js +50 -0
- package/dist/exporters/sensitive-key.js.map +1 -0
- package/dist/exporters/test-data-resolver.d.ts +4 -1
- package/dist/exporters/test-data-resolver.d.ts.map +1 -1
- package/dist/exporters/test-data-resolver.js +12 -2
- package/dist/exporters/test-data-resolver.js.map +1 -1
- package/dist/exporters/xlsx-report-builder.d.ts +12 -1
- package/dist/exporters/xlsx-report-builder.d.ts.map +1 -1
- package/dist/exporters/xlsx-report-builder.js +10 -2
- package/dist/exporters/xlsx-report-builder.js.map +1 -1
- package/dist/generators/gherkin-parser/index.d.ts +10 -0
- package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
- package/dist/generators/gherkin-parser/index.js +20 -12
- package/dist/generators/gherkin-parser/index.js.map +1 -1
- package/dist/generators/gherkin-parser/parent-scope-clause.d.ts +54 -0
- package/dist/generators/gherkin-parser/parent-scope-clause.d.ts.map +1 -0
- package/dist/generators/gherkin-parser/parent-scope-clause.js +109 -0
- package/dist/generators/gherkin-parser/parent-scope-clause.js.map +1 -0
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts +23 -18
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts +4 -19
- package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/appium/appium-adapter.js.map +1 -1
- package/dist/generators/test-generator/adapters/appium/os-support.d.ts +53 -0
- package/dist/generators/test-generator/adapters/appium/os-support.d.ts.map +1 -0
- package/dist/generators/test-generator/adapters/appium/os-support.js +200 -0
- package/dist/generators/test-generator/adapters/appium/os-support.js.map +1 -0
- package/dist/generators/test-generator/adapters/appium/templates/after-all.hbs +18 -0
- package/dist/generators/test-generator/adapters/appium/templates/after-each.hbs +18 -0
- package/dist/generators/test-generator/adapters/appium/templates/before-all.hbs +18 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/alert-fill-action.hbs +9 -2
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/capture-variable.hbs +24 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/click-at-position-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/click-element-with-text.hbs +1 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/double-click-action.hbs +7 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/frame-enter-action.hbs +3 -6
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/hover-action.hbs +6 -2
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/hover-element-with-text.hbs +4 -3
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/table-paginate-action.hbs +3 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/unknown-element-action.hbs +9 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/have-value-assertion.hbs +34 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +14 -6
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/visible-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/go-back-action.hbs +21 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/long-press-action.hbs +4 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/pinch-zoom-action.hbs +4 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/set-geolocation-action.hbs +16 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/partials/locator.hbs +9 -1
- package/dist/generators/test-generator/adapters/appium/templates/test-file.hbs +62 -23
- package/dist/generators/test-generator/adapters/index.d.ts +1 -1
- package/dist/generators/test-generator/adapters/index.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +4 -19
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/after-all.hbs +19 -1
- package/dist/generators/test-generator/adapters/playwright/templates/after-each.hbs +18 -0
- package/dist/generators/test-generator/adapters/playwright/templates/before-all.hbs +19 -1
- package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/check-action.hbs +6 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-at-position-action.hbs +23 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/expand-action.hbs +8 -8
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/fill-editor-action.hbs +7 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row-nth.hbs +7 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +7 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-paginate-action.hbs +5 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/uncheck-action.hbs +3 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/unknown-element-action.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-page.hbs +18 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-assertion.hbs +32 -4
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-element.hbs +5 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +5 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +13 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +2 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +2 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/selected-assertion.hbs +21 -3
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +20 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +4 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +4 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +4 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +12 -4
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +14 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +3 -3
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/checked-opts.hbs +8 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +8 -8
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-nth.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/id.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/testid.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +8 -8
- package/dist/generators/test-generator/adapters/playwright/templates/test-file.hbs +10 -8
- package/dist/generators/test-generator/code-generator.d.ts +37 -0
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +165 -40
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/diagnostics.d.ts +116 -6
- package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
- package/dist/generators/test-generator/diagnostics.js +115 -5
- package/dist/generators/test-generator/diagnostics.js.map +1 -1
- package/dist/generators/test-generator/patterns/index.d.ts +57 -11
- package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/index.js +163 -21
- package/dist/generators/test-generator/patterns/index.js.map +1 -1
- package/dist/generators/test-generator/patterns/types.d.ts +8 -0
- package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/with-parent-scope.d.ts +18 -0
- package/dist/generators/test-generator/patterns/with-parent-scope.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/with-parent-scope.js +40 -0
- package/dist/generators/test-generator/patterns/with-parent-scope.js.map +1 -0
- package/dist/generators/test-generator/step-mapper.d.ts +103 -10
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +266 -45
- package/dist/generators/test-generator/step-mapper.js.map +1 -1
- package/dist/generators/test-generator/template-engine.d.ts +4 -19
- package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
- package/dist/generators/test-generator/template-engine.js +17 -12
- package/dist/generators/test-generator/template-engine.js.map +1 -1
- package/dist/generators/test-generator/utils/data-resolver.d.ts +7 -0
- package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/data-resolver.js +19 -2
- package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
- package/dist/generators/test-generator/utils/dialog-scope-identity.d.ts +41 -0
- package/dist/generators/test-generator/utils/dialog-scope-identity.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/dialog-scope-identity.js +61 -0
- package/dist/generators/test-generator/utils/dialog-scope-identity.js.map +1 -0
- package/dist/generators/test-generator/utils/escape-js-string.d.ts +17 -0
- package/dist/generators/test-generator/utils/escape-js-string.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/escape-js-string.js +29 -0
- package/dist/generators/test-generator/utils/escape-js-string.js.map +1 -0
- package/dist/generators/test-generator/utils/nearest-match.d.ts +24 -0
- package/dist/generators/test-generator/utils/nearest-match.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/nearest-match.js +56 -0
- package/dist/generators/test-generator/utils/nearest-match.js.map +1 -0
- package/dist/generators/test-generator/utils/selector-entry-fields.d.ts +58 -0
- package/dist/generators/test-generator/utils/selector-entry-fields.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/selector-entry-fields.js +119 -0
- package/dist/generators/test-generator/utils/selector-entry-fields.js.map +1 -0
- package/dist/generators/test-generator/utils/selector-entry-walk.d.ts +25 -0
- package/dist/generators/test-generator/utils/selector-entry-walk.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/selector-entry-walk.js +54 -0
- package/dist/generators/test-generator/utils/selector-entry-walk.js.map +1 -0
- package/dist/generators/test-generator/utils/selector-nth-validation.d.ts +59 -0
- package/dist/generators/test-generator/utils/selector-nth-validation.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/selector-nth-validation.js +91 -0
- package/dist/generators/test-generator/utils/selector-nth-validation.js.map +1 -0
- package/dist/generators/test-generator/utils/selector-resolver.d.ts +53 -2
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +273 -27
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-type-validation.d.ts +51 -0
- package/dist/generators/test-generator/utils/selector-type-validation.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/selector-type-validation.js +77 -0
- package/dist/generators/test-generator/utils/selector-type-validation.js.map +1 -0
- package/dist/harness/audit.d.ts +3 -1
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +51 -28
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/capability-plan.d.ts +4 -0
- package/dist/harness/capability-plan.d.ts.map +1 -1
- package/dist/harness/capability-plan.js +32 -2
- package/dist/harness/capability-plan.js.map +1 -1
- package/dist/harness/catalog/drivers.yaml +1 -1
- package/dist/harness/catalog/universal-viewpoints.yaml +145 -0
- package/dist/harness/data-driven-lint.d.ts.map +1 -1
- package/dist/harness/data-driven-lint.js +217 -33
- package/dist/harness/data-driven-lint.js.map +1 -1
- package/dist/harness/parse.d.ts +6 -0
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +1 -1
- package/dist/harness/parse.js.map +1 -1
- package/dist/harness/repair.d.ts.map +1 -1
- package/dist/harness/repair.js +8 -1
- package/dist/harness/repair.js.map +1 -1
- package/dist/harness/script-check.d.ts +2 -2
- package/dist/harness/script-check.d.ts.map +1 -1
- package/dist/harness/script-check.js +186 -25
- package/dist/harness/script-check.js.map +1 -1
- package/dist/harness/sensors.d.ts +48 -0
- package/dist/harness/sensors.d.ts.map +1 -1
- package/dist/harness/sensors.js +26 -1
- package/dist/harness/sensors.js.map +1 -1
- package/dist/harness/viewpoint-ledger.d.ts +10 -0
- package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
- package/dist/harness/viewpoint-ledger.js +23 -2
- package/dist/harness/viewpoint-ledger.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/orchestrator/project-initializer.d.ts +6 -0
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +16 -0
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/report-sanitize-reporter-install.d.ts +24 -0
- package/dist/orchestrator/report-sanitize-reporter-install.d.ts.map +1 -0
- package/dist/orchestrator/report-sanitize-reporter-install.js +161 -0
- package/dist/orchestrator/report-sanitize-reporter-install.js.map +1 -0
- package/dist/orchestrator/templates/ai-src/commands/delivery.md +4 -3
- package/dist/orchestrator/templates/ai-src/commands/run-test.md +9 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +10 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +14 -5
- package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +62 -3
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +126 -11
- package/dist/orchestrator/templates/ai-src/skills/sungen-mobile-gestures/SKILL.md +16 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +12 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +19 -5
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +88 -2
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +62 -5
- package/dist/orchestrator/templates/ai-src/skills/sungen-test-design-techniques/SKILL.md +13 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +59 -10
- package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-f-mobile-native.md +419 -0
- package/dist/orchestrator/templates/playwright.config.ts +7 -0
- package/dist/orchestrator/templates/readme.md +1 -1
- package/dist/orchestrator/templates/specs-checked-state.d.ts +83 -0
- package/dist/orchestrator/templates/specs-checked-state.d.ts.map +1 -0
- package/dist/orchestrator/templates/specs-checked-state.js +261 -0
- package/dist/orchestrator/templates/specs-checked-state.js.map +1 -0
- package/dist/orchestrator/templates/specs-checked-state.ts +324 -0
- package/dist/orchestrator/templates/specs-pw-shape-reporter.ts +0 -0
- package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.d.ts +36 -0
- package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.d.ts.map +1 -0
- package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.js +155 -0
- package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.js.map +1 -0
- package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.ts +142 -0
- package/dist/orchestrator/templates/specs-url-assert.d.ts +50 -25
- package/dist/orchestrator/templates/specs-url-assert.d.ts.map +1 -1
- package/dist/orchestrator/templates/specs-url-assert.js +65 -24
- package/dist/orchestrator/templates/specs-url-assert.js.map +1 -1
- package/dist/orchestrator/templates/specs-url-assert.ts +101 -28
- package/dist/orchestrator/templates/wdio.conf.ts +105 -1
- package/dist/utils/selector-types.d.ts +43 -1
- package/dist/utils/selector-types.d.ts.map +1 -1
- package/dist/utils/selector-types.js +51 -7
- package/dist/utils/selector-types.js.map +1 -1
- package/package.json +3 -3
- package/src/capabilities/discover.ts +146 -10
- package/src/capabilities/registry.ts +30 -0
- package/src/cli/commands/audit.ts +9 -0
- package/src/cli/commands/capability.ts +1 -1
- package/src/cli/commands/delivery.ts +2 -1
- package/src/cli/commands/generate.ts +5 -2
- package/src/cli/commands/inspect.ts +1 -1
- package/src/cli/commands/results-merge.ts +9 -2
- package/src/cli/commands/results-sanitize.ts +98 -0
- package/src/cli/commands/script-check.ts +3 -1
- package/src/cli/commands/update.ts +3 -0
- package/src/dashboard/templates/index.html +1 -1
- package/src/exporters/api-testcase-formatter.ts +5 -7
- package/src/exporters/feature-parser.ts +1 -1
- package/src/exporters/matrix/build.ts +17 -3
- package/src/exporters/matrix/item-labels.ts +78 -0
- package/src/exporters/matrix/render-coverage-sheet.ts +170 -0
- package/src/exporters/matrix/render-csv.ts +3 -1
- package/src/exporters/matrix/render-overview-sheet.ts +51 -0
- package/src/exporters/matrix/render-testcase-sheet.ts +178 -0
- package/src/exporters/matrix/render-xlsx.ts +67 -448
- package/src/exporters/matrix/result-totals.ts +37 -0
- package/src/exporters/matrix/testcase-summary-band.ts +74 -0
- package/src/exporters/matrix/wording.ts +13 -0
- package/src/exporters/matrix/xlsx-cells.ts +56 -0
- package/src/exporters/qa-env-secret-denylist.ts +1 -1
- package/src/exporters/report-path-sanitizer.ts +144 -0
- package/src/exporters/result-variants.ts +2 -1
- package/src/exporters/sensitive-key.ts +48 -0
- package/src/exporters/test-data-resolver.ts +12 -2
- package/src/exporters/xlsx-report-builder.ts +16 -2
- package/src/generators/gherkin-parser/index.ts +22 -11
- package/src/generators/gherkin-parser/parent-scope-clause.ts +130 -0
- package/src/generators/test-generator/adapters/adapter-interface.ts +25 -3
- package/src/generators/test-generator/adapters/appium/appium-adapter.ts +4 -4
- package/src/generators/test-generator/adapters/appium/os-support.ts +176 -0
- package/src/generators/test-generator/adapters/appium/templates/after-all.hbs +18 -0
- package/src/generators/test-generator/adapters/appium/templates/after-each.hbs +18 -0
- package/src/generators/test-generator/adapters/appium/templates/before-all.hbs +18 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/alert-fill-action.hbs +9 -2
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/capture-variable.hbs +24 -1
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/click-at-position-action.hbs +1 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/click-element-with-text.hbs +1 -1
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/double-click-action.hbs +7 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/frame-enter-action.hbs +3 -6
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/hover-action.hbs +6 -2
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/hover-element-with-text.hbs +4 -3
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/table-paginate-action.hbs +3 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/unknown-element-action.hbs +9 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/have-value-assertion.hbs +34 -1
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +14 -6
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/visible-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/appium/templates/steps/gestures/go-back-action.hbs +21 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/gestures/long-press-action.hbs +4 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/gestures/pinch-zoom-action.hbs +4 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/gestures/set-geolocation-action.hbs +16 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/partials/locator.hbs +9 -1
- package/src/generators/test-generator/adapters/appium/templates/test-file.hbs +62 -23
- package/src/generators/test-generator/adapters/index.ts +1 -1
- package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +4 -4
- package/src/generators/test-generator/adapters/playwright/templates/after-all.hbs +19 -1
- package/src/generators/test-generator/adapters/playwright/templates/after-each.hbs +18 -0
- package/src/generators/test-generator/adapters/playwright/templates/before-all.hbs +19 -1
- package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/check-action.hbs +6 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-at-position-action.hbs +23 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/expand-action.hbs +8 -8
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/fill-editor-action.hbs +7 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row-nth.hbs +7 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +7 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-paginate-action.hbs +5 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/uncheck-action.hbs +3 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/unknown-element-action.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-page.hbs +18 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-assertion.hbs +32 -4
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-element.hbs +5 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +5 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +13 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +2 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +2 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/selected-assertion.hbs +21 -3
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +20 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +4 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +4 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +4 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +12 -4
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +14 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +3 -3
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/checked-opts.hbs +8 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +8 -8
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-nth.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/id.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/testid.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +8 -8
- package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +10 -8
- package/src/generators/test-generator/code-generator.ts +181 -46
- package/src/generators/test-generator/diagnostics.ts +117 -6
- package/src/generators/test-generator/patterns/index.ts +175 -24
- package/src/generators/test-generator/patterns/types.ts +8 -0
- package/src/generators/test-generator/patterns/with-parent-scope.ts +41 -0
- package/src/generators/test-generator/step-mapper.ts +277 -43
- package/src/generators/test-generator/template-engine.ts +21 -21
- package/src/generators/test-generator/utils/data-resolver.ts +23 -2
- package/src/generators/test-generator/utils/dialog-scope-identity.ts +71 -0
- package/src/generators/test-generator/utils/escape-js-string.ts +24 -0
- package/src/generators/test-generator/utils/nearest-match.ts +55 -0
- package/src/generators/test-generator/utils/selector-entry-fields.ts +131 -0
- package/src/generators/test-generator/utils/selector-entry-walk.ts +58 -0
- package/src/generators/test-generator/utils/selector-nth-validation.ts +99 -0
- package/src/generators/test-generator/utils/selector-resolver.ts +333 -28
- package/src/generators/test-generator/utils/selector-type-validation.ts +87 -0
- package/src/harness/audit.ts +55 -30
- package/src/harness/capability-plan.ts +33 -1
- package/src/harness/catalog/drivers.yaml +1 -1
- package/src/harness/catalog/universal-viewpoints.yaml +145 -0
- package/src/harness/data-driven-lint.ts +192 -32
- package/src/harness/parse.ts +7 -1
- package/src/harness/repair.ts +8 -1
- package/src/harness/script-check.ts +186 -21
- package/src/harness/sensors.ts +75 -1
- package/src/harness/viewpoint-ledger.ts +26 -5
- package/src/index.ts +7 -0
- package/src/orchestrator/project-initializer.ts +17 -0
- package/src/orchestrator/report-sanitize-reporter-install.ts +109 -0
- package/src/orchestrator/templates/ai-src/commands/delivery.md +4 -3
- package/src/orchestrator/templates/ai-src/commands/run-test.md +9 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +10 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +14 -5
- package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +62 -3
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +126 -11
- package/src/orchestrator/templates/ai-src/skills/sungen-mobile-gestures/SKILL.md +16 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +12 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +19 -5
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +88 -2
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +62 -5
- package/src/orchestrator/templates/ai-src/skills/sungen-test-design-techniques/SKILL.md +13 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +59 -10
- package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-f-mobile-native.md +419 -0
- package/src/orchestrator/templates/playwright.config.ts +7 -0
- package/src/orchestrator/templates/readme.md +1 -1
- package/src/orchestrator/templates/specs-checked-state.ts +324 -0
- package/src/orchestrator/templates/specs-pw-shape-reporter.ts +0 -0
- package/src/orchestrator/templates/specs-report-path-sanitize-reporter.ts +142 -0
- package/src/orchestrator/templates/specs-url-assert.ts +101 -28
- package/src/orchestrator/templates/wdio.conf.ts +105 -1
- package/src/utils/selector-types.ts +54 -5
package/src/harness/audit.ts
CHANGED
|
@@ -13,20 +13,20 @@ import { checkViewpointBaseline, ViewpointBaseline } from './viewpoint-baseline'
|
|
|
13
13
|
import { flowQuality, statefulDepthFor, continuityGaps, flowInventory, misfiledPhases, FlowQualityResult, InventoryResult } from './flow-contract';
|
|
14
14
|
import { featureFilesFor } from './unit-paths';
|
|
15
15
|
import {
|
|
16
|
-
loadCatalog, viewpointGate, assertionDepth, dataThemesFor, depthThresholdFor, coverageBalance, duplicateClusters, traceability, claimProof, taxonomyLint,
|
|
16
|
+
loadCatalog, viewpointGate, assertionDepth, dataThemesFor, depthThresholdFor, coverageBalance, duplicateClusters, scenarioIdReuse, ReusedScenarioId, traceability, claimProof, taxonomyLint,
|
|
17
17
|
automatableManual, flowCoveredThemes, flowRegressionDepth, oracleStrength, declaredPageType,
|
|
18
18
|
numericClaimGaps, priorityMismatches,
|
|
19
19
|
GateResult, DepthResult, BalanceResult, DuplicateResult, TraceResult, ClaimProofResult, TaxonomyResult, Catalog, AutomatableManualResult, FlowDepthResult, OracleStrengthResult,
|
|
20
20
|
} from './sensors';
|
|
21
21
|
import { loadFlowScenarios } from './flow-check';
|
|
22
|
-
import { manualReasonMismatches, MANUAL_REASONS, buildPlan } from './capability-plan';
|
|
22
|
+
import { manualReasonMismatches, MANUAL_REASONS, buildPlan, KEEP_REASON_CODES, MANUAL_REASON_RANGE } from './capability-plan';
|
|
23
23
|
import { readCapabilities, verificationScopeFindings } from './capability';
|
|
24
24
|
import { readIntent, projectRootFromScreenDir, IntentProfile } from './intent';
|
|
25
25
|
import { getProvenance, Provenance } from './provenance';
|
|
26
26
|
import { specCoverage, SpecCoverageResult, parseSpecClauses, restatedRequirementSources } from './spec-coverage';
|
|
27
27
|
import { downstreamScope, manualOracle, readText, DownstreamResult, ManualOracleResult,
|
|
28
28
|
negativeSideEffect, sourceBacked, crossArtifactOwnership, isolationRisk, serialCascadeRisk } from './quality-gates';
|
|
29
|
-
import { viewpointLedger, parseViewpointItems, browserGestureSubstitutions, viewpointIntegrity, LedgerResult } from './viewpoint-ledger';
|
|
29
|
+
import { viewpointLedger, parseViewpointItems, browserGestureSubstitutions, substitutionRemedy, viewpointIntegrity, LedgerResult } from './viewpoint-ledger';
|
|
30
30
|
import { specBranches, unenumeratedBranches, sameOracleClusters, permissionPairGaps, awaitingSeedData, unconsideredRisks, MULTI_SCREEN_RISKS } from './spec-branches';
|
|
31
31
|
const MULTI_SCREEN_RISK_COUNT = MULTI_SCREEN_RISKS.length;
|
|
32
32
|
import { capabilityRegistry } from '../capabilities/registry';
|
|
@@ -45,6 +45,8 @@ export interface AuditReport {
|
|
|
45
45
|
duplicates: DuplicateResult;
|
|
46
46
|
trace: TraceResult;
|
|
47
47
|
taxonomyMismatch: boolean; // scenarios use IDs not in the project's test-viewpoint.md
|
|
48
|
+
/** #694 — two different scenarios in one .feature carrying the same VP id. Gate-blocking. */
|
|
49
|
+
reusedScenarioIds: ReusedScenarioId[];
|
|
48
50
|
downstream: DownstreamResult; // downstream screens referenced but under-covered
|
|
49
51
|
manualOracle: ManualOracleResult; // @manual scenarios lacking setup/action/oracle
|
|
50
52
|
automatableManual: AutomatableManualResult; // @manual that is actually automatable (deferred, not judgment) — TQ-2
|
|
@@ -460,30 +462,15 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
|
|
|
460
462
|
if (!flowQ.contract!.minimalGuarantee) {
|
|
461
463
|
findings.push('FLOW-GUARANTEE-MISSING: the contract declares no `minimalGuarantee:` — the postcondition that must hold in EVERY flow, including failure ("no second account for the same email", "no verification mail on a rejected submit"). Exception/guard scenarios have nothing to assert against without it; add it (and `successGuarantee:` for the goal-reached side).');
|
|
462
464
|
}
|
|
463
|
-
// #599 — integrity of the DECLARATION itself: three ways it can be internally wrong while
|
|
464
|
-
// every coverage number still reads well.
|
|
465
|
-
{
|
|
466
|
-
const testDataDir = path.join(screenDir, 'test-data');
|
|
467
|
-
const extra: Array<{ label: string; text: string }> = [];
|
|
468
|
-
try {
|
|
469
|
-
for (const f of fs.readdirSync(testDataDir).filter((x) => x.endsWith('.yaml'))) {
|
|
470
|
-
extra.push({ label: `test-data/${f}`, text: readTextFile(path.join(testDataDir, f)) ?? '' });
|
|
471
|
-
}
|
|
472
|
-
} catch { /* api units and fresh scaffolds carry none */ }
|
|
473
|
-
const vi = viewpointIntegrity(viewpointPath, scenarios.map((sc) => sc.vpId ?? '').filter(Boolean), extra);
|
|
474
|
-
for (const d of vi.duplicateIds.slice(0, 4)) {
|
|
475
|
-
findings.push(`VIEWPOINT-ID-REUSED: "${d.id}" labels ${d.count} different claims (${d.texts.map((t) => `"${t.slice(0, 44)}…"`).join(' · ')}). The ledger then counts ${d.count} items while traceability sees ONE id, so both the coverage arithmetic and "which test proves this?" go wrong — and neither number looks suspicious. Give each atomic claim its own id; several ids may share a flow.`);
|
|
476
|
-
}
|
|
477
|
-
for (const d of vi.danglingRefs.slice(0, 5)) {
|
|
478
|
-
findings.push(`TRACE-REF-DANGLING: ${d.where} cites "${d.ref}", which no scenario carries. Nothing breaks at runtime, so a wrong pointer survives every refactor and quietly misleads the next maintainer. Fix the reference, or the scenario id it was meant to name.`);
|
|
479
|
-
}
|
|
480
|
-
if (vi.uniformPriority) {
|
|
481
|
-
findings.push(`VIEWPOINT-PRIORITY-UNIFORM: all ${vi.uniformPriority.rows} rows of the Priority Viewpoints table are "${vi.uniformPriority.levels[0]}". That is a formality, not a priority: nothing can be selected for a smoke run and the release conversation has no input. Rank by business impact and risk — the basic flow and the data-integrity guards are not the same bet as an exit path a screen suite already covers.`);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
465
|
// #595 — a viewpoint item naming a browser-level gesture, answered with an in-app control.
|
|
485
466
|
for (const g of browserGestureSubstitutions(viewpointPath, scenarios, platform).slice(0, 4)) {
|
|
486
|
-
|
|
467
|
+
// The remedy is not the same on both platforms, and getting it wrong is the difference between
|
|
468
|
+
// useful advice and a lie: web still has no reload/back step (#593), so `@manual` is the honest
|
|
469
|
+
// reply — but every mobile gesture in this set now compiles, so telling a mobile author to defer
|
|
470
|
+
// would send them to a manual procedure for work the compiler does. Read from the ledger entry
|
|
471
|
+
// (`substitutionRemedy`), never re-derived here, so a step landing for web needs no edit here.
|
|
472
|
+
const remedy = substitutionRemedy(g);
|
|
473
|
+
findings.push(`VIEWPOINT-GESTURE-SUBSTITUTED: the viewpoint asks for "${g.gesture}" ("${g.item.slice(0, 80)}…") but the suite exercises an in-app control instead. They are different mechanisms — an app button runs the screen's own re-hydrate logic and the gesture does not, so a defect that only shows on the gesture's own path lives in exactly that gap. ${remedy}`);
|
|
487
474
|
}
|
|
488
475
|
// #595 — a flow whose requirement list is a hand restatement of the screen specs it
|
|
489
476
|
// traverses. `specFR` read 100% over two restated FRs while the guard clause the flow most
|
|
@@ -523,6 +510,41 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
|
|
|
523
510
|
findings.push(`FLOW-HANDOFF-SHALLOW: only ${flowQ.handoffs.asserted}/${flowQ.handoffs.total} cross-screen transitions are followed by an assertion in the new screen — carried state (the thing a flow exists to verify) is unproven at the handoff. businessDepth is capped until asserted.`);
|
|
524
511
|
}
|
|
525
512
|
}
|
|
513
|
+
// #694 — two DIFFERENT scenarios wearing the same VP id. BLOCKING (it joins the gate
|
|
514
|
+
// conjunction below) where the declaration-integrity findings that follow are advisory: a
|
|
515
|
+
// reused id does not stop here, it reaches the customer. `generateTcId` builds the delivered
|
|
516
|
+
// testcase id straight out of the vpId, so the collision ships as two rows carrying ONE id in
|
|
517
|
+
// the deliverable — and the result-merge fallback has already attached one sibling's run
|
|
518
|
+
// result to another, delivering 7 never-executed testcases as "Passed" (see
|
|
519
|
+
// `exporters/scenario-merger.ts`). `matrix/gates.ts` already grades this `severity: 'error'`,
|
|
520
|
+
// but only at delivery; blocking at audit is what makes it cheap to fix (renumber, regenerate).
|
|
521
|
+
const reusedIds = scenarioIdReuse(scenarios);
|
|
522
|
+
for (const r of reusedIds.slice(0, 6)) {
|
|
523
|
+
findings.push(`SCENARIO-ID-REUSED: ${r.count} different scenarios in ${r.file || 'this feature'} carry the id "${r.id}" (${r.titles.map((t) => `"${t.slice(0, 52)}…"`).join(' · ')}). Every axis stays green — the duplicate sensor clusters identical STEPS, so scenarios that merely share an id sail past it — while the deliverable gets ${r.count} rows under one testcase id and the run-result merge can attach the wrong scenario's result. Give each scenario its own sequence number within its category; the ledger item that now reads UNCOVERED is the sibling that lost its number.`);
|
|
524
|
+
}
|
|
525
|
+
// #599 — integrity of the DECLARATION itself: three ways it can be internally wrong while
|
|
526
|
+
// every coverage number still reads well. Advisory. This used to sit inside the
|
|
527
|
+
// `flowQ.hasContract` branch above, so a SCREEN unit never reached it at all — the checks ran
|
|
528
|
+
// on flows only, silently, for every release since they landed (#694).
|
|
529
|
+
{
|
|
530
|
+
const testDataDir = path.join(screenDir, 'test-data');
|
|
531
|
+
const extra: Array<{ label: string; text: string }> = [];
|
|
532
|
+
try {
|
|
533
|
+
for (const f of fs.readdirSync(testDataDir).filter((x) => x.endsWith('.yaml'))) {
|
|
534
|
+
extra.push({ label: `test-data/${f}`, text: readTextFile(path.join(testDataDir, f)) ?? '' });
|
|
535
|
+
}
|
|
536
|
+
} catch { /* api units and fresh scaffolds carry none */ }
|
|
537
|
+
const vi = viewpointIntegrity(viewpointPath, scenarios.map((sc) => sc.vpId ?? '').filter(Boolean), extra);
|
|
538
|
+
for (const d of vi.duplicateIds.slice(0, 4)) {
|
|
539
|
+
findings.push(`VIEWPOINT-ID-REUSED: "${d.id}" labels ${d.count} different claims (${d.texts.map((t) => `"${t.slice(0, 44)}…"`).join(' · ')}). The ledger then counts ${d.count} items while traceability sees ONE id, so both the coverage arithmetic and "which test proves this?" go wrong — and neither number looks suspicious. Give each atomic claim its own id; several ids may share a flow.`);
|
|
540
|
+
}
|
|
541
|
+
for (const d of vi.danglingRefs.slice(0, 5)) {
|
|
542
|
+
findings.push(`TRACE-REF-DANGLING: ${d.where} cites "${d.ref}", which no scenario carries. Nothing breaks at runtime, so a wrong pointer survives every refactor and quietly misleads the next maintainer. Fix the reference, or the scenario id it was meant to name.`);
|
|
543
|
+
}
|
|
544
|
+
if (vi.uniformPriority) {
|
|
545
|
+
findings.push(`VIEWPOINT-PRIORITY-UNIFORM: all ${vi.uniformPriority.rows} rows of the Priority Viewpoints table are "${vi.uniformPriority.levels[0]}". That is a formality, not a priority: nothing can be selected for a smoke run and the release conversation has no input. Rank by business impact and risk — the basic flow and the data-integrity guards are not the same bet as an exit path a screen suite already covers.`);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
526
548
|
// #592 W5 — a continuity mechanism proved on one side only.
|
|
527
549
|
if (isUiFlow) {
|
|
528
550
|
const scenarioTexts = scenarios.map((s) => `${s.name} ${s.stepsText}`);
|
|
@@ -536,7 +558,7 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
|
|
|
536
558
|
// manual, most of them M5-inbox — invisible while tagged bare).
|
|
537
559
|
const bareManual = (featureText.match(/@manual(?![:\w])/g) || []).length;
|
|
538
560
|
if (bareManual > 0) {
|
|
539
|
-
findings.push(`MANUAL-CODE-MISSING: ${bareManual} @manual tag(s) carry no reason code — tag @manual
|
|
561
|
+
findings.push(`MANUAL-CODE-MISSING: ${bareManual} @manual tag(s) carry no reason code — tag @manual:${MANUAL_REASON_RANGE} (M5 = external dependency e.g. inbox, M3 = mock/network, M7 = environment, M10 = device/OS capability, M11 = real-device only) so the capability planner can route what a driver would automate.`);
|
|
540
562
|
}
|
|
541
563
|
}
|
|
542
564
|
for (const c of flowCredits) {
|
|
@@ -671,7 +693,7 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
|
|
|
671
693
|
const plan = buildPlan(screenDir, screenName, catalogScreenName, platform);
|
|
672
694
|
if (plan.recommendations.length) {
|
|
673
695
|
const recs = plan.recommendations.map((r) => `\`sungen capability add ${r.driver}\` (automates ${r.count})`).join(' · ');
|
|
674
|
-
findings.push(`CAPABILITY-SUGGESTION: ${plan.capabilityManual} @manual scenario(s) are capability-manual (a driver could automate them) — ${recs}. Recommend-only: nothing is installed automatically; the ${plan.judgmentManual} judgment-manual (
|
|
696
|
+
findings.push(`CAPABILITY-SUGGESTION: ${plan.capabilityManual} @manual scenario(s) are capability-manual (a driver could automate them) — ${recs}. Recommend-only: nothing is installed automatically; the ${plan.judgmentManual} judgment-manual (${KEEP_REASON_CODES.join('/')}) correctly stay manual.`);
|
|
675
697
|
}
|
|
676
698
|
// Named, not dropped: without this the scenarios read as "nothing could help", and the
|
|
677
699
|
// operator's only clue was an install that dead-ends (#597).
|
|
@@ -835,15 +857,18 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
|
|
|
835
857
|
const calibration = { axes, weakest, inflated, notApplicable, cappedAt: capped ? cap : undefined };
|
|
836
858
|
|
|
837
859
|
// Gate spans coverage (viewpoint themes), depth, claim-proof, spec-clause coverage,
|
|
838
|
-
//
|
|
860
|
+
// taxonomy-match (scenarios must use the project's viewpoint IDs when defined),
|
|
861
|
+
// AND scenario-id uniqueness — a reused id reaches the customer's deliverable as two rows
|
|
862
|
+
// under one testcase id, and has already shipped a never-executed testcase as "Passed" (#694).
|
|
839
863
|
const gateStatus: 'PASS' | 'FAIL' =
|
|
840
|
-
gate.gaps.length === 0 && depth.verdict !== 'fail' && claim.verdict !== 'fail' && spec.verdict !== 'fail' && !taxonomyMismatch && !gateSensorError
|
|
864
|
+
gate.gaps.length === 0 && depth.verdict !== 'fail' && claim.verdict !== 'fail' && spec.verdict !== 'fail' && !taxonomyMismatch && !gateSensorError
|
|
865
|
+
&& reusedIds.length === 0 ? 'PASS' : 'FAIL';
|
|
841
866
|
|
|
842
867
|
return {
|
|
843
868
|
screen: screenName,
|
|
844
869
|
scenarioCount: scenarios.length,
|
|
845
870
|
gate, depth, claim, taxonomy, balance, duplicates, trace, spec,
|
|
846
|
-
taxonomyMismatch, downstream, manualOracle: manualOracleResult, automatableManual: autoManual, flowDepth, oracle, ledger, viewpointBaseline, calibration,
|
|
871
|
+
taxonomyMismatch, reusedScenarioIds: reusedIds, downstream, manualOracle: manualOracleResult, automatableManual: autoManual, flowDepth, oracle, ledger, viewpointBaseline, calibration,
|
|
847
872
|
...(isUiFlow ? { flowQuality: flowQ, flowInventory: inventory ?? undefined } : {}),
|
|
848
873
|
score: {
|
|
849
874
|
overall: Math.round(overall * 10) / 10,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Capability Planner (Phase 2b) — deterministic, recommend-only.
|
|
3
3
|
*
|
|
4
4
|
* Classifies each scenario's execution mode + each @manual case by reason code
|
|
5
|
-
* (M1–
|
|
5
|
+
* (M1–M11), maps capability-reasons to drivers, and emits the manual-reason KPI.
|
|
6
6
|
* Never installs anything (that's `sungen capability add`). See
|
|
7
7
|
* docs/spec/sungen_phase2b_spec.md.
|
|
8
8
|
*/
|
|
@@ -22,13 +22,37 @@ export const MANUAL_REASONS: Record<string, ReasonDef> = {
|
|
|
22
22
|
M4: { code: 'M4', label: 'Missing stable selector/test-id', cls: 'capability', drivers: [] }, // locator contract, no driver
|
|
23
23
|
M5: { code: 'M5', label: 'External dependency', cls: 'capability', drivers: ['mail-file', 'contract'] },
|
|
24
24
|
M6: { code: 'M6', label: 'Visual / UX judgment', cls: 'keep', drivers: ['specialized'] },
|
|
25
|
+
// `capability` with no driver is deliberate and matches M4: the case IS automatable once the
|
|
26
|
+
// environment exists, it just is not an `sungen capability add` away. Reclassifying it as `keep`
|
|
27
|
+
// would claim the opposite — that no environment could ever run it — and would silently move
|
|
28
|
+
// every existing M7 scenario from the capability-manual count to judgment-manual.
|
|
25
29
|
M7: { code: 'M7', label: 'Environment limitation', cls: 'capability', drivers: [] }, // testability, no driver
|
|
26
30
|
M8: { code: 'M8', label: 'Not worth automating', cls: 'keep', drivers: [] },
|
|
27
31
|
M9: { code: 'M9', label: 'True human judgment', cls: 'keep', drivers: [] },
|
|
32
|
+
// Mobile-specific (M10/M11). Both are `keep` with no driver, and that is the honest answer:
|
|
33
|
+
// nothing installable automates them, so the planner must not imply otherwise. Before these
|
|
34
|
+
// existed every mobile-specific reason collapsed into M7, which made "needs a real device" and
|
|
35
|
+
// "waiting on staging infra" indistinguishable in the report.
|
|
36
|
+
M10: { code: 'M10', label: 'Device/OS capability', cls: 'keep', drivers: [] },
|
|
37
|
+
M11: { code: 'M11', label: 'Real-device only', cls: 'keep', drivers: [] },
|
|
28
38
|
// Not a single-screen driver gap: automatable cross-screen via a flow (/sungen:add-flow).
|
|
29
39
|
XS: { code: 'XS', label: 'Cross-screen (automate via flow)', cls: 'flow', drivers: [] },
|
|
30
40
|
};
|
|
31
41
|
|
|
42
|
+
/** Codes that stay manual whatever is installed — derived, so a new `keep` code joins by itself. */
|
|
43
|
+
export const KEEP_REASON_CODES: string[] = Object.values(MANUAL_REASONS)
|
|
44
|
+
.filter((r) => r.cls === 'keep')
|
|
45
|
+
.map((r) => r.code);
|
|
46
|
+
|
|
47
|
+
/** The documented reason-code range, e.g. "M1..M11". Derived so guidance can never go stale. */
|
|
48
|
+
export const MANUAL_REASON_RANGE: string = (() => {
|
|
49
|
+
const ns = Object.keys(MANUAL_REASONS)
|
|
50
|
+
.filter((c) => /^M\d+$/.test(c))
|
|
51
|
+
.map((c) => Number(c.slice(1)))
|
|
52
|
+
.sort((a, b) => a - b);
|
|
53
|
+
return ns.length ? `M${ns[0]}..M${ns[ns.length - 1]}` : '';
|
|
54
|
+
})();
|
|
55
|
+
|
|
32
56
|
// Keyword inference (best-effort retrofit). Order matters — first match wins.
|
|
33
57
|
// Cross-screen "deferred to a flow" is checked FIRST: it is not a driver gap on
|
|
34
58
|
// this screen, it is handled by a flow — so it must not recommend a driver.
|
|
@@ -41,6 +65,14 @@ const INFER: { code: string; re: RegExp }[] = [
|
|
|
41
65
|
// "email" alone is too greedy (every subscription test mentions it) → require a real external-mail
|
|
42
66
|
// signal (verification mail / OTP / inbox), so an API/DB-oracle test isn't misread as M5.
|
|
43
67
|
{ code: 'M5', re: /\b(external|third[-\s]?party|sandbox|payment gateway|invoice|download|verification (e?mail|link)|otp|mailbox|inbox|e?mail link)\b/i },
|
|
68
|
+
// Mobile-specific, and they MUST sit ahead of M6/M7 or they never fire: M6 matches
|
|
69
|
+
// /keyboard|accessibilit|responsive/ and M7 matches /environment/, either of which would take a
|
|
70
|
+
// mobile reason first. They stay BEHIND M1–M5 on purpose, so a mobile phrasing of an ordinary
|
|
71
|
+
// driver gap ("assert via API", "needs a stable test-id") still routes to the driver that solves
|
|
72
|
+
// it. One known consequence of that order: "IAP sandbox" hits M5's `sandbox` before M10 — the
|
|
73
|
+
// external-payment reading is the more useful one, and the order test pins it either way.
|
|
74
|
+
{ code: 'M11', re: /\b(real device|máy thật|physical device|nfc|biometric|fingerprint|face id|touch id|camera thật|real camera|push token)\b/i },
|
|
75
|
+
{ code: 'M10', re: /\b(notification shade|app switcher|recents|in-app purchase|iap|interruption|incoming call|permission variance|os version)\b/i },
|
|
44
76
|
{ code: 'M6', re: /\b(visual|responsive|layout|accessibilit|a11y|keyboard|screen reader|ux|breakpoint)\b/i },
|
|
45
77
|
{ code: 'M7', re: /\b(environment|staging[-\s]?only|infra|env limitation)\b/i },
|
|
46
78
|
{ code: 'M8', re: /\b(not worth|exploratory|one[-\s]?off)\b/i },
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# status: shipped → published as an npm package (R5); planned → not built yet.
|
|
11
11
|
# bundled: true → installed automatically (a dependency of @sun-asterisk/sungen),
|
|
12
12
|
# so `capability add` is unnecessary.
|
|
13
|
-
# unblocks: manual-reason codes (M1–
|
|
13
|
+
# unblocks: manual-reason codes (M1–M11) this driver resolves (Phase 2b taxonomy).
|
|
14
14
|
#
|
|
15
15
|
# R5 status: the three real capabilities ship as packages — @sungen/driver-ui (web UI,
|
|
16
16
|
# bundled as the default), @sungen/driver-db, @sungen/driver-api. The web *platform*
|
|
@@ -106,6 +106,125 @@ page_types:
|
|
|
106
106
|
- theme: navigation-correctness
|
|
107
107
|
keywords: [tap, navigate, "leaves home", "is hidden", opens, navigation]
|
|
108
108
|
|
|
109
|
+
# ---- mobile page-types -------------------------------------------------------------------
|
|
110
|
+
# All `mobile-*`, so `sensors.ts` never offers them to a web target. Two rules shaped the
|
|
111
|
+
# keywords below:
|
|
112
|
+
# 1. Detection needs 2 distinct hits AND a 1-hit lead (MIN_HITS/MIN_MARGIN), so keywords must
|
|
113
|
+
# DISCRIMINATE, not merely occur. Generic mobile words ("tap", "screen") are absent.
|
|
114
|
+
# 2. A mobile target still considers the web types, and that is correct: a mobile commerce
|
|
115
|
+
# screen SHOULD select ecommerce-list, and a mobile form leaning on generic form
|
|
116
|
+
# vocabulary (field/submit/validation) SHOULD select `form`. These types are for what a
|
|
117
|
+
# web type has no concept of, so each keyword set is built from natively-distinctive nouns.
|
|
118
|
+
# Themes carry `depth:` wherever the honest oracle is a value rather than a sighting — that is
|
|
119
|
+
# what separates a suite that scrolls and asserts a value from one that only asserts presence.
|
|
120
|
+
# Every theme is expressible in the SHIPPED mobile vocabulary (scroll/swipe/pull-to-refresh/
|
|
121
|
+
# rotate/background/restart/grant-permission/set-connectivity/deep-link), so none of them forces
|
|
122
|
+
# an @manual. OS-back themes remain absent, but the REASON has changed: the `go back` step now
|
|
123
|
+
# exists (per-OS KEYCODE_BACK / WDA navigation-back), so the blocker is no longer vocabulary. What
|
|
124
|
+
# stops it now is blast radius — a new `must_cover` theme is a new gap for every existing mobile
|
|
125
|
+
# suite, which is a scoring decision for an owner, not a drive-by. `viewpoint-ledger` already
|
|
126
|
+
# covers the dangerous half by refusing `tap [Back]` as an answer to an OS-back viewpoint item.
|
|
127
|
+
mobile-list:
|
|
128
|
+
detect_keywords: [feed, "pull to refresh", "infinite scroll", "load more", "list item", "list row"]
|
|
129
|
+
must_cover:
|
|
130
|
+
- theme: list-data
|
|
131
|
+
keywords: [list, feed, row, "list item", displayed]
|
|
132
|
+
depth:
|
|
133
|
+
requires: data-assertion
|
|
134
|
+
cross_screen: false
|
|
135
|
+
keywords: ["row contains", "item contains", "every row", "all items", "each row", "list shows"]
|
|
136
|
+
template: "User see all [List Item] text contains {{expected_label}}"
|
|
137
|
+
- theme: refresh-correctness
|
|
138
|
+
keywords: ["pull to refresh", refresh, reload, refreshed]
|
|
139
|
+
depth:
|
|
140
|
+
requires: data-assertion
|
|
141
|
+
cross_screen: false
|
|
142
|
+
keywords: ["after refresh", "refreshed list", "new item", "updated list", "after pull to refresh"]
|
|
143
|
+
template: "User pull to refresh [List] … User see all [List Item] text contains {{expected_label}}"
|
|
144
|
+
- theme: scroll-reachability
|
|
145
|
+
keywords: [scroll, swipe, "load more", "infinite scroll", "below the fold"]
|
|
146
|
+
depth:
|
|
147
|
+
requires: data-assertion
|
|
148
|
+
cross_screen: false
|
|
149
|
+
keywords: ["after scrolling", "scrolled to", "last item", "load more", "next page"]
|
|
150
|
+
template: "User scroll to [Last List Item] … User see [Last List Item] text contains {{expected_last}}"
|
|
151
|
+
|
|
152
|
+
mobile-detail:
|
|
153
|
+
detect_keywords: ["detail screen", "detail view", "detail header", "item detail", "detail pane"]
|
|
154
|
+
must_cover:
|
|
155
|
+
- theme: detail-data
|
|
156
|
+
keywords: [detail, header, displayed, field]
|
|
157
|
+
depth:
|
|
158
|
+
requires: data-assertion
|
|
159
|
+
cross_screen: false
|
|
160
|
+
keywords: ["detail shows", "detail contains", "detail header", "detail value", "detail field"]
|
|
161
|
+
template: "User see [Detail Title] text contains {{expected_title}}"
|
|
162
|
+
- theme: list-detail-consistency
|
|
163
|
+
keywords: [consistent, consistency, match, "same item", "correct item"]
|
|
164
|
+
depth:
|
|
165
|
+
requires: data-assertion
|
|
166
|
+
cross_screen: true
|
|
167
|
+
keywords: ["same item name", "matching name", "same value", "consistency", "same title"]
|
|
168
|
+
template: "User remember [List Item] text as {{v}} … User see [Detail Title] text contains {{v}}"
|
|
169
|
+
|
|
170
|
+
mobile-form:
|
|
171
|
+
detect_keywords: ["soft keyboard", "keyboard overlap", "hide keyboard", "on-screen keyboard", "keyboard covers"]
|
|
172
|
+
must_cover:
|
|
173
|
+
- theme: field-validation
|
|
174
|
+
keywords: [validation, invalid, required, error]
|
|
175
|
+
depth:
|
|
176
|
+
requires: data-assertion
|
|
177
|
+
cross_screen: false
|
|
178
|
+
keywords: ["error message", "validation message", "invalid input", "required message"]
|
|
179
|
+
template: "User see [Field Error] message contains {{error_text}}"
|
|
180
|
+
# No `depth:` on purpose: the claim IS a sighting — after the keyboard is hidden the field
|
|
181
|
+
# and its action are visible again. Forcing a value assertion here would invent an oracle.
|
|
182
|
+
- theme: keyboard-overlap
|
|
183
|
+
keywords: ["soft keyboard", "keyboard overlap", "hide keyboard", "keyboard covers", "keyboard hides"]
|
|
184
|
+
- theme: submit-correctness
|
|
185
|
+
keywords: [submit, save, submitted, saved]
|
|
186
|
+
depth:
|
|
187
|
+
requires: data-assertion
|
|
188
|
+
cross_screen: false
|
|
189
|
+
keywords: ["after submit", "saved value", "success message", "after saving"]
|
|
190
|
+
template: "User see [Success Message] text contains {{success_text}}"
|
|
191
|
+
|
|
192
|
+
mobile-auth:
|
|
193
|
+
detect_keywords: [biometric, fingerprint, "face id", "touch id", "app lock"]
|
|
194
|
+
must_cover:
|
|
195
|
+
- theme: credential-validation
|
|
196
|
+
keywords: [invalid, "wrong password", error, incorrect]
|
|
197
|
+
depth:
|
|
198
|
+
requires: data-assertion
|
|
199
|
+
cross_screen: false
|
|
200
|
+
keywords: ["error message", "invalid credential", "wrong password", "incorrect password"]
|
|
201
|
+
template: "User see [Login Error] message contains {{error_text}}"
|
|
202
|
+
- theme: session-persistence
|
|
203
|
+
keywords: [session, restart, persist, "stays signed in"]
|
|
204
|
+
depth:
|
|
205
|
+
requires: data-assertion
|
|
206
|
+
cross_screen: false
|
|
207
|
+
keywords: ["after restart", "still signed in", "session persists", "remains signed in"]
|
|
208
|
+
template: "User restart the app … User see [Account Name] text contains {{user_name}}"
|
|
209
|
+
|
|
210
|
+
mobile-settings:
|
|
211
|
+
detect_keywords: ["settings screen", toggle, preference, "settings list", "settings item"]
|
|
212
|
+
must_cover:
|
|
213
|
+
- theme: toggle-state-correctness
|
|
214
|
+
keywords: [toggle, switch, enabled, disabled]
|
|
215
|
+
depth:
|
|
216
|
+
requires: data-assertion
|
|
217
|
+
cross_screen: false
|
|
218
|
+
keywords: ["toggle state", "switch is on", "enabled state", "reflects the", "shows enabled"]
|
|
219
|
+
template: "User see [Notifications Toggle] text contains {{expected_state}}"
|
|
220
|
+
- theme: setting-persistence
|
|
221
|
+
keywords: [persist, restart, saved, "after reopening"]
|
|
222
|
+
depth:
|
|
223
|
+
requires: data-assertion
|
|
224
|
+
cross_screen: false
|
|
225
|
+
keywords: ["after restart", "setting persists", "still enabled", "saved setting", "after reopening"]
|
|
226
|
+
template: "User restart the app … User see [Notifications Toggle] text contains {{expected_state}}"
|
|
227
|
+
|
|
109
228
|
auth:
|
|
110
229
|
detect_keywords: [login, logout, password, signin, "sign in", credential]
|
|
111
230
|
must_cover:
|
|
@@ -127,3 +246,29 @@ universal:
|
|
|
127
246
|
keywords: ["empty", "no data", "no result", "failed", "error state"]
|
|
128
247
|
- theme: accessibility
|
|
129
248
|
keywords: ["keyboard", "tab order", "accessible", "aria", "focus"]
|
|
249
|
+
|
|
250
|
+
# Same role as `universal`, but only offered to MOBILE targets — `universal` applies to web too,
|
|
251
|
+
# where "rotate to landscape" or "airplane mode" is meaningless.
|
|
252
|
+
#
|
|
253
|
+
# READ THIS BEFORE ADDING TEETH HERE: like `universal`, these themes are REMINDERS. They surface
|
|
254
|
+
# through `universalGaps`, which reaches the audit narrative and the capability sensors but is NOT
|
|
255
|
+
# an input to the score. A theme placed here can never move a number.
|
|
256
|
+
#
|
|
257
|
+
# That is deliberate, not an oversight. These concerns are real on every mobile screen, but not
|
|
258
|
+
# every mobile screen owes every one of them — a settings screen has no deep link, a read-only list
|
|
259
|
+
# has no permission prompt. Scoring them uniformly would penalise honest suites for gaps that are
|
|
260
|
+
# not gaps. The themes that DO carry weight sit in each page-type's `must_cover` above, where they
|
|
261
|
+
# apply to a screen that genuinely owes them.
|
|
262
|
+
mobile_universal:
|
|
263
|
+
- theme: orientation-stability
|
|
264
|
+
keywords: [rotate, landscape, portrait, orientation]
|
|
265
|
+
- theme: connectivity-degraded
|
|
266
|
+
keywords: ["airplane mode", offline, "wifi", "mobile data", "no connection"]
|
|
267
|
+
- theme: app-lifecycle-resume
|
|
268
|
+
keywords: [background, resume, foreground, "returns to the app", restart]
|
|
269
|
+
- theme: permission-prompt
|
|
270
|
+
keywords: [permission, grant, denied, allow]
|
|
271
|
+
- theme: gesture-reachability
|
|
272
|
+
keywords: [scroll, swipe, "off screen", "below the fold"]
|
|
273
|
+
- theme: deep-link-entry
|
|
274
|
+
keywords: ["deep link", deeplink, "universal link"]
|