qa-engineer 0.9.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/COMPATIBILITY.md +71 -0
- package/LICENSE +21 -0
- package/README.md +508 -0
- package/package.json +90 -0
- package/packages/installer/README.md +46 -0
- package/packages/installer/bin/qa.mjs +136 -0
- package/packages/installer/lib/agents/registry.mjs +209 -0
- package/packages/installer/lib/cli/commands.mjs +29 -0
- package/packages/installer/lib/cli/flags.mjs +64 -0
- package/packages/installer/lib/commands/doctor.mjs +190 -0
- package/packages/installer/lib/commands/install.mjs +291 -0
- package/packages/installer/lib/commands/onboard.mjs +163 -0
- package/packages/installer/lib/commands/repair.mjs +68 -0
- package/packages/installer/lib/commands/self-test.mjs +45 -0
- package/packages/installer/lib/commands/uninstall.mjs +167 -0
- package/packages/installer/lib/commands/update.mjs +69 -0
- package/packages/installer/lib/commands/verify.mjs +62 -0
- package/packages/installer/lib/constants.mjs +34 -0
- package/packages/installer/lib/core/bundle.mjs +124 -0
- package/packages/installer/lib/core/config.mjs +73 -0
- package/packages/installer/lib/core/conflict.mjs +29 -0
- package/packages/installer/lib/core/errors.mjs +29 -0
- package/packages/installer/lib/core/fs-safe.mjs +236 -0
- package/packages/installer/lib/core/hash.mjs +19 -0
- package/packages/installer/lib/core/lockfile.mjs +75 -0
- package/packages/installer/lib/core/logger.mjs +46 -0
- package/packages/installer/lib/core/manifest.mjs +89 -0
- package/packages/installer/lib/core/paths.mjs +74 -0
- package/packages/installer/lib/core/schema-validate.mjs +142 -0
- package/packages/installer/lib/core/skill-meta.mjs +75 -0
- package/packages/installer/lib/core/validate-install.mjs +152 -0
- package/packages/installer/lib/core/wrappers.mjs +91 -0
- package/packages/installer/lib/detect/environment.mjs +54 -0
- package/packages/installer/lib/detect/frameworks.mjs +94 -0
- package/packages/installer/lib/detect/project.mjs +126 -0
- package/packages/installer/lib/detect/recommend.mjs +85 -0
- package/packages/installer/lib/detect/scan.mjs +48 -0
- package/packages/installer/lib/ui/progress.mjs +32 -0
- package/packages/installer/lib/ui/theme.mjs +81 -0
- package/packages/installer/lib/version.mjs +47 -0
- package/packages/installer/package.json +28 -0
- package/packages/installer/schemas/qa-lock.schema.json +89 -0
- package/packages/installer/schemas/qa.config.schema.json +91 -0
- package/shared/analysis/lib/qa_analysis/__init__.py +11 -0
- package/shared/analysis/lib/qa_analysis/branding.json +9 -0
- package/shared/analysis/lib/qa_analysis/branding.py +175 -0
- package/shared/analysis/lib/qa_analysis/cli.py +129 -0
- package/shared/analysis/lib/qa_analysis/context.py +233 -0
- package/shared/analysis/lib/qa_analysis/contracts.py +158 -0
- package/shared/analysis/lib/qa_analysis/diff_guard.py +327 -0
- package/shared/analysis/lib/qa_analysis/discovery.py +113 -0
- package/shared/analysis/lib/qa_analysis/evidence.py +128 -0
- package/shared/analysis/lib/qa_analysis/har.py +58 -0
- package/shared/analysis/lib/qa_analysis/junit.py +80 -0
- package/shared/analysis/lib/qa_analysis/redaction.py +99 -0
- package/shared/analysis/lib/qa_analysis/taxonomy.py +98 -0
- package/shared/analysis/schemas/context.schema.json +82 -0
- package/shared/diagnostics/lib/qa_diagnostics/__init__.py +13 -0
- package/shared/diagnostics/lib/qa_diagnostics/cli.py +124 -0
- package/shared/diagnostics/lib/qa_diagnostics/engine.py +143 -0
- package/shared/diagnostics/lib/qa_diagnostics/internal_contracts.py +75 -0
- package/shared/diagnostics/lib/qa_diagnostics/prioritization.py +101 -0
- package/shared/diagnostics/lib/qa_diagnostics/repair.py +72 -0
- package/shared/diagnostics/lib/qa_diagnostics/root_cause.py +89 -0
- package/shared/diagnostics/lib/qa_diagnostics/timeline.py +71 -0
- package/shared/diagnostics/schemas/internal/analysis-result.schema.json +28 -0
- package/shared/diagnostics/schemas/internal/diagnosis.schema.json +55 -0
- package/shared/diagnostics/schemas/internal/execution-result-min.schema.json +34 -0
- package/shared/frameworks/cypress/lib/cypress_analysis.py +27 -0
- package/shared/frameworks/playwright/lib/playwright_analysis.py +167 -0
- package/shared/frameworks/registry.json +150 -0
- package/shared/frameworks/registry.mjs +37 -0
- package/shared/frameworks/registry.schema.json +74 -0
- package/shared/frameworks/selenium/lib/selenium_analysis.py +28 -0
- package/shared/frameworks/webdriverio/lib/webdriverio_analysis.py +24 -0
- package/shared/tooling/qa_tool.py +127 -0
- package/skills/README.md +31 -0
- package/skills/qa/README.md +19 -0
- package/skills/qa/SKILL.md +52 -0
- package/skills/qa/examples/routing.md +86 -0
- package/skills/qa/references/routing-map.md +33 -0
- package/skills/qa-api/README.md +19 -0
- package/skills/qa-api/SKILL.md +68 -0
- package/skills/qa-api/contracts/api-result.schema.json +51 -0
- package/skills/qa-api/examples/graphql-review.md +43 -0
- package/skills/qa-api/references/authentication.md +45 -0
- package/skills/qa-api/references/deterministic-tooling.md +128 -0
- package/skills/qa-api/references/evidence-and-reporting.md +66 -0
- package/skills/qa-api/references/graphql.md +44 -0
- package/skills/qa-api/references/rest.md +45 -0
- package/skills/qa-api/references/websocket.md +44 -0
- package/skills/qa-audit/README.md +19 -0
- package/skills/qa-audit/SKILL.md +70 -0
- package/skills/qa-audit/contracts/audit-result.schema.json +63 -0
- package/skills/qa-audit/examples/accessibility-audit.md +46 -0
- package/skills/qa-audit/references/accessibility.md +44 -0
- package/skills/qa-audit/references/deterministic-tooling.md +128 -0
- package/skills/qa-audit/references/evidence-and-reporting.md +66 -0
- package/skills/qa-audit/references/performance.md +44 -0
- package/skills/qa-audit/references/security.md +43 -0
- package/skills/qa-audit/references/visual-testing.md +44 -0
- package/skills/qa-debug/README.md +19 -0
- package/skills/qa-debug/SKILL.md +76 -0
- package/skills/qa-debug/contracts/debug-result.schema.json +121 -0
- package/skills/qa-debug/examples/failed-login.md +61 -0
- package/skills/qa-debug/examples/locator-break.md +59 -0
- package/skills/qa-debug/examples/network-timeout.md +61 -0
- package/skills/qa-debug/examples/successful-debug.md +62 -0
- package/skills/qa-debug/references/confidence-model.md +26 -0
- package/skills/qa-debug/references/deterministic-tooling.md +128 -0
- package/skills/qa-debug/references/diagnostic-engine.md +36 -0
- package/skills/qa-debug/references/evidence-and-reporting.md +66 -0
- package/skills/qa-debug/references/evidence-model.md +41 -0
- package/skills/qa-debug/references/failure-taxonomy.md +44 -0
- package/skills/qa-debug/references/finding-prioritization.md +43 -0
- package/skills/qa-debug/references/investigation-workflow.md +48 -0
- package/skills/qa-debug/references/recommendation-ranking.md +34 -0
- package/skills/qa-debug/references/root-cause-analysis.md +49 -0
- package/skills/qa-debug/references/timeline-builder.md +37 -0
- package/skills/qa-example/README.md +19 -0
- package/skills/qa-example/SKILL.md +60 -0
- package/skills/qa-example/contracts/self-check-report.schema.json +65 -0
- package/skills/qa-example/examples/self-check.md +53 -0
- package/skills/qa-example/references/example-domain.md +28 -0
- package/skills/qa-example/references/skill-format-notes.md +26 -0
- package/skills/qa-explore/README.md +22 -0
- package/skills/qa-explore/SKILL.md +87 -0
- package/skills/qa-explore/contracts/explore-result.schema.json +249 -0
- package/skills/qa-explore/examples/attached-test-cases.md +70 -0
- package/skills/qa-explore/examples/screenshot-proof-finding.md +50 -0
- package/skills/qa-explore/examples/url-smoke-explore.md +80 -0
- package/skills/qa-explore/references/accessibility.md +44 -0
- package/skills/qa-explore/references/api-replay.md +48 -0
- package/skills/qa-explore/references/browser-adapters.md +51 -0
- package/skills/qa-explore/references/evidence-and-reporting.md +66 -0
- package/skills/qa-explore/references/evidence-capture.md +54 -0
- package/skills/qa-explore/references/exploratory-qa.md +52 -0
- package/skills/qa-explore/references/finding-taxonomy.md +47 -0
- package/skills/qa-explore/references/performance.md +44 -0
- package/skills/qa-explore/references/pipeline.md +74 -0
- package/skills/qa-explore/references/report-pipeline.md +69 -0
- package/skills/qa-explore/references/security.md +43 -0
- package/skills/qa-explore/references/test-case-intake.md +44 -0
- package/skills/qa-fix/README.md +19 -0
- package/skills/qa-fix/SKILL.md +70 -0
- package/skills/qa-fix/contracts/fix-result.schema.json +132 -0
- package/skills/qa-fix/examples/repair-plan.md +56 -0
- package/skills/qa-fix/references/deterministic-tooling.md +128 -0
- package/skills/qa-fix/references/diagnostic-engine.md +36 -0
- package/skills/qa-fix/references/evidence-and-reporting.md +66 -0
- package/skills/qa-fix/references/repair-strategy.md +48 -0
- package/skills/qa-fix/references/root-cause-analysis.md +49 -0
- package/skills/qa-fix/references/suite-extension.md +73 -0
- package/skills/qa-flaky/README.md +19 -0
- package/skills/qa-flaky/SKILL.md +67 -0
- package/skills/qa-flaky/contracts/flaky-result.schema.json +62 -0
- package/skills/qa-flaky/examples/flaky-locator.md +46 -0
- package/skills/qa-flaky/references/deterministic-tooling.md +128 -0
- package/skills/qa-flaky/references/evidence-and-reporting.md +66 -0
- package/skills/qa-flaky/references/flakiness.md +48 -0
- package/skills/qa-flaky/references/retry.md +44 -0
- package/skills/qa-flaky/references/waiting-strategies.md +44 -0
- package/skills/qa-generate/README.md +42 -0
- package/skills/qa-generate/SKILL.md +83 -0
- package/skills/qa-generate/contracts/generation-result.schema.json +124 -0
- package/skills/qa-generate/examples/bootstrap-new-framework.md +24 -0
- package/skills/qa-generate/examples/extend-existing-suite.md +26 -0
- package/skills/qa-generate/references/code-style.md +29 -0
- package/skills/qa-generate/references/evidence-and-reporting.md +66 -0
- package/skills/qa-generate/references/framework-selection.md +88 -0
- package/skills/qa-generate/references/generation-strategy.md +48 -0
- package/skills/qa-generate/references/naming-conventions.md +27 -0
- package/skills/qa-generate/references/playwright-conventions.md +23 -0
- package/skills/qa-generate/references/playwright-generation.md +41 -0
- package/skills/qa-generate/references/playwright-project-discovery.md +42 -0
- package/skills/qa-generate/references/project-bootstrap.md +54 -0
- package/skills/qa-generate/references/repository-analysis.md +43 -0
- package/skills/qa-generate/references/suite-extension.md +73 -0
- package/skills/qa-generate/references/template-selection.md +48 -0
- package/skills/qa-generate/templates/playwright/api.ts +36 -0
- package/skills/qa-generate/templates/playwright/base-page.ts +14 -0
- package/skills/qa-generate/templates/playwright/data.ts +25 -0
- package/skills/qa-generate/templates/playwright/env.example +16 -0
- package/skills/qa-generate/templates/playwright/example.spec.ts +14 -0
- package/skills/qa-generate/templates/playwright/fixtures.ts +28 -0
- package/skills/qa-generate/templates/playwright/framework-readme.md +39 -0
- package/skills/qa-generate/templates/playwright/login.page.ts +26 -0
- package/skills/qa-generate/templates/playwright/playwright.config.ts +28 -0
- package/skills/qa-generate/templates/playwright/utils.ts +18 -0
- package/skills/qa-init/README.md +20 -0
- package/skills/qa-init/SKILL.md +72 -0
- package/skills/qa-init/examples/initialize-a-repo.md +91 -0
- package/skills/qa-init/references/detection-guide.md +76 -0
- package/skills/qa-init/references/deterministic-tooling.md +128 -0
- package/skills/qa-init/references/evidence-and-reporting.md +66 -0
- package/skills/qa-init/templates/context.md +68 -0
- package/skills/qa-report/README.md +19 -0
- package/skills/qa-report/SKILL.md +72 -0
- package/skills/qa-report/contracts/report-result.schema.json +186 -0
- package/skills/qa-report/examples/release-report.md +68 -0
- package/skills/qa-report/references/deterministic-tooling.md +128 -0
- package/skills/qa-report/references/diagnostic-engine.md +36 -0
- package/skills/qa-report/references/evidence-and-reporting.md +66 -0
- package/skills/qa-report/references/finding-prioritization.md +43 -0
- package/skills/qa-report/references/recommendation-ranking.md +34 -0
- package/skills/qa-report/references/report-aggregation.md +44 -0
- package/skills/qa-review/README.md +19 -0
- package/skills/qa-review/SKILL.md +58 -0
- package/skills/qa-review/contracts/review-result.schema.json +59 -0
- package/skills/qa-review/examples/suite-review.md +51 -0
- package/skills/qa-review/references/anti-patterns.md +49 -0
- package/skills/qa-review/references/assertion-patterns.md +45 -0
- package/skills/qa-review/references/evidence-and-reporting.md +66 -0
- package/skills/qa-review/references/fixtures.md +45 -0
- package/skills/qa-review/references/page-objects.md +45 -0
- package/skills/qa-run/README.md +22 -0
- package/skills/qa-run/SKILL.md +92 -0
- package/skills/qa-run/contracts/execution-plan.schema.json +132 -0
- package/skills/qa-run/contracts/execution-result.schema.json +204 -0
- package/skills/qa-run/examples/execute-playwright.md +89 -0
- package/skills/qa-run/examples/plan-a-run.md +83 -0
- package/skills/qa-run/references/artifact-collector.md +40 -0
- package/skills/qa-run/references/browser-launch.md +39 -0
- package/skills/qa-run/references/command-builder.md +39 -0
- package/skills/qa-run/references/deterministic-tooling.md +128 -0
- package/skills/qa-run/references/environment-detection.md +37 -0
- package/skills/qa-run/references/evidence-and-reporting.md +66 -0
- package/skills/qa-run/references/execution-strategy.md +54 -0
- package/skills/qa-run/references/playwright-artifacts.md +29 -0
- package/skills/qa-run/references/playwright-execution.md +48 -0
- package/skills/qa-run/references/playwright-project-discovery.md +42 -0
- package/skills/qa-run/references/report-normalization.md +49 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:qa-pack:contract:qa-run:execution-result:1",
|
|
4
|
+
"title": "qa-run normalized execution result",
|
|
5
|
+
"description": "The framework-independent record of a completed (or attempted) test run: status, counts, per-test outcomes, collected artifacts, and environment. This is the interface the analysis layer of later milestones consumes; nothing downstream branches on the producing framework. classification is the run status.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["contract", "skill", "generatedAt", "summary", "classification", "evidence", "execution", "framework", "tests", "environment", "artifacts"],
|
|
9
|
+
"allOf": [
|
|
10
|
+
{
|
|
11
|
+
"title": "A green claim must be backed by the runner's own numbers",
|
|
12
|
+
"description": "classification 'passed' requires exit code 0 and zero failing tests. This is the contract-level answer to hallucinated green: an agent cannot emit a valid result that claims success over a non-zero exit code or a failed test.",
|
|
13
|
+
"if": {
|
|
14
|
+
"required": ["classification"],
|
|
15
|
+
"properties": { "classification": { "const": "passed" } }
|
|
16
|
+
},
|
|
17
|
+
"then": {
|
|
18
|
+
"properties": {
|
|
19
|
+
"execution": { "properties": { "exitCode": { "const": 0 } } },
|
|
20
|
+
"tests": { "properties": { "failed": { "const": 0 } } }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"title": "A failure claim must point at a failing test",
|
|
26
|
+
"description": "classification 'failed' requires at least one failing test. A run with no failures is 'passed', 'no-tests-run', or 'errored' — never 'failed'.",
|
|
27
|
+
"if": {
|
|
28
|
+
"required": ["classification"],
|
|
29
|
+
"properties": { "classification": { "const": "failed" } }
|
|
30
|
+
},
|
|
31
|
+
"then": {
|
|
32
|
+
"properties": { "tests": { "properties": { "failed": { "minimum": 1 } } } }
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"title": "no-tests-run means nothing executed",
|
|
37
|
+
"description": "classification 'no-tests-run' requires a zero total. If tests executed, the status is decided by their outcomes.",
|
|
38
|
+
"if": {
|
|
39
|
+
"required": ["classification"],
|
|
40
|
+
"properties": { "classification": { "const": "no-tests-run" } }
|
|
41
|
+
},
|
|
42
|
+
"then": {
|
|
43
|
+
"properties": { "tests": { "properties": { "total": { "const": 0 } } } }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"properties": {
|
|
48
|
+
"contract": {
|
|
49
|
+
"type": "object",
|
|
50
|
+
"additionalProperties": false,
|
|
51
|
+
"required": ["name", "version"],
|
|
52
|
+
"properties": {
|
|
53
|
+
"name": { "const": "qa-run/execution-result" },
|
|
54
|
+
"version": { "type": "string", "pattern": "^1\\.[0-9]+\\.[0-9]+$" }
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"skill": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"additionalProperties": false,
|
|
60
|
+
"required": ["name", "version"],
|
|
61
|
+
"properties": {
|
|
62
|
+
"name": { "const": "qa-run" },
|
|
63
|
+
"version": { "type": "string" }
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"generatedAt": { "type": "string", "format": "date-time" },
|
|
67
|
+
"summary": { "type": "string", "minLength": 1 },
|
|
68
|
+
"classification": {
|
|
69
|
+
"description": "The run status, computed from the reporter and exit code — never chosen by feel.",
|
|
70
|
+
"enum": ["passed", "failed", "errored", "no-tests-run", "blocked"]
|
|
71
|
+
},
|
|
72
|
+
"confidence": { "type": "number", "minimum": 0, "maximum": 1 },
|
|
73
|
+
"evidence": {
|
|
74
|
+
"description": "The observations that justify the status: the reporter file, the exit code, launch errors.",
|
|
75
|
+
"type": "array",
|
|
76
|
+
"minItems": 1,
|
|
77
|
+
"items": {
|
|
78
|
+
"type": "object",
|
|
79
|
+
"additionalProperties": false,
|
|
80
|
+
"required": ["type", "description", "source"],
|
|
81
|
+
"properties": {
|
|
82
|
+
"type": { "enum": ["report", "command", "log", "file", "artifact"] },
|
|
83
|
+
"description": { "type": "string", "minLength": 1 },
|
|
84
|
+
"source": { "type": "string", "minLength": 1 },
|
|
85
|
+
"excerpt": { "type": "string" }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"execution": {
|
|
90
|
+
"type": "object",
|
|
91
|
+
"additionalProperties": false,
|
|
92
|
+
"required": ["strategy", "command", "exitCode"],
|
|
93
|
+
"properties": {
|
|
94
|
+
"strategy": {
|
|
95
|
+
"enum": ["smoke", "regression", "full-suite", "changed", "single-spec", "targeted", "tag-based", "directory-based", "failed-only", "retry", "dry-run"]
|
|
96
|
+
},
|
|
97
|
+
"command": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"description": "The exact command executed, verbatim and secret-free."
|
|
100
|
+
},
|
|
101
|
+
"startedAt": { "type": "string", "format": "date-time" },
|
|
102
|
+
"finishedAt": { "type": "string", "format": "date-time" },
|
|
103
|
+
"durationMs": { "type": "integer", "minimum": 0 },
|
|
104
|
+
"exitCode": {
|
|
105
|
+
"type": ["integer", "null"],
|
|
106
|
+
"description": "Runner process exit code; null when the run was not attempted (blocked)."
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"framework": {
|
|
111
|
+
"type": "object",
|
|
112
|
+
"additionalProperties": false,
|
|
113
|
+
"required": ["name"],
|
|
114
|
+
"properties": {
|
|
115
|
+
"name": { "enum": ["playwright", "selenium", "cypress", "webdriverio"] },
|
|
116
|
+
"version": { "type": ["string", "null"] }
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
"tests": {
|
|
120
|
+
"type": "object",
|
|
121
|
+
"additionalProperties": false,
|
|
122
|
+
"required": ["total", "passed", "failed", "skipped"],
|
|
123
|
+
"properties": {
|
|
124
|
+
"total": { "type": "integer", "minimum": 0 },
|
|
125
|
+
"passed": { "type": "integer", "minimum": 0 },
|
|
126
|
+
"failed": { "type": "integer", "minimum": 0 },
|
|
127
|
+
"skipped": { "type": "integer", "minimum": 0 },
|
|
128
|
+
"flaky": { "type": "integer", "minimum": 0 }
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
"executed": {
|
|
132
|
+
"description": "Per-test outcomes, normalized across frameworks.",
|
|
133
|
+
"type": "array",
|
|
134
|
+
"items": {
|
|
135
|
+
"type": "object",
|
|
136
|
+
"additionalProperties": false,
|
|
137
|
+
"required": ["title", "status"],
|
|
138
|
+
"properties": {
|
|
139
|
+
"title": { "type": "string", "minLength": 1 },
|
|
140
|
+
"file": { "type": "string" },
|
|
141
|
+
"status": { "enum": ["passed", "failed", "skipped", "flaky"] },
|
|
142
|
+
"durationMs": { "type": "integer", "minimum": 0 },
|
|
143
|
+
"retries": { "type": "integer", "minimum": 0 }
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"artifacts": {
|
|
148
|
+
"description": "Everything the run produced, in the common artifact model, for the analysis layer to consume.",
|
|
149
|
+
"type": "array",
|
|
150
|
+
"items": {
|
|
151
|
+
"type": "object",
|
|
152
|
+
"additionalProperties": false,
|
|
153
|
+
"required": ["type", "location", "framework", "timestamp", "ownership"],
|
|
154
|
+
"properties": {
|
|
155
|
+
"type": {
|
|
156
|
+
"enum": ["stdout", "stderr", "console-log", "network-log", "screenshot", "video", "trace", "har", "junit", "html-report", "attachment"]
|
|
157
|
+
},
|
|
158
|
+
"location": { "type": "string", "minLength": 1 },
|
|
159
|
+
"framework": { "type": "string" },
|
|
160
|
+
"timestamp": { "type": "string", "format": "date-time" },
|
|
161
|
+
"mediaType": { "type": "string" },
|
|
162
|
+
"ownership": { "type": "string" },
|
|
163
|
+
"testRef": { "type": "string" },
|
|
164
|
+
"present": {
|
|
165
|
+
"type": "boolean",
|
|
166
|
+
"description": "False when the artifact was planned but expected-and-absent."
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"environment": {
|
|
172
|
+
"type": "object",
|
|
173
|
+
"additionalProperties": false,
|
|
174
|
+
"required": ["location", "headless"],
|
|
175
|
+
"properties": {
|
|
176
|
+
"location": { "enum": ["local", "ci", "remote"] },
|
|
177
|
+
"headless": { "type": "boolean" },
|
|
178
|
+
"browser": { "type": ["string", "null"] },
|
|
179
|
+
"baseUrl": { "type": ["string", "null"] },
|
|
180
|
+
"os": { "type": "string" },
|
|
181
|
+
"ciProvider": { "type": ["string", "null"] },
|
|
182
|
+
"envVarNames": {
|
|
183
|
+
"type": "array",
|
|
184
|
+
"description": "Names only of the environment variables the run depended on — never values.",
|
|
185
|
+
"items": { "type": "string" }
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
"recommendations": {
|
|
190
|
+
"type": "array",
|
|
191
|
+
"items": {
|
|
192
|
+
"type": "object",
|
|
193
|
+
"additionalProperties": false,
|
|
194
|
+
"required": ["action", "priority"],
|
|
195
|
+
"properties": {
|
|
196
|
+
"action": { "type": "string", "minLength": 1 },
|
|
197
|
+
"priority": { "enum": ["high", "medium", "low"] },
|
|
198
|
+
"command": { "type": "string" }
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"metadata": { "type": "object" }
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Example: execute a Playwright smoke run
|
|
2
|
+
|
|
3
|
+
Shows the full execution path — plan, run, collect, normalize — for the one framework this milestone executes. Contrast with [plan-a-run.md](plan-a-run.md), which stops at the plan; here `qa-run` actually runs the suite and reports what happened.
|
|
4
|
+
|
|
5
|
+
## Request
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
/qa-run smoke
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Context
|
|
12
|
+
|
|
13
|
+
The Playwright + TypeScript repository from the qa-init example: `.qa/context.md` records `testFramework.e2e: playwright`, `packageManager: pnpm`, `conventions.specGlob: e2e/**/*.spec.ts`, and a `chromium` project. Smoke tests are tagged `@smoke`. `BASE_URL` is set in the environment; a local dev server is running.
|
|
14
|
+
|
|
15
|
+
## Expected behavior
|
|
16
|
+
|
|
17
|
+
1. **Discover / adapter.** `.qa/context.md` exists and records Playwright — a supported framework, so execution proceeds.
|
|
18
|
+
2. **Intent / strategy.** "smoke" selects the `smoke` strategy, scope `@smoke`.
|
|
19
|
+
3. **Environment.** Local, headless, `chromium`, base URL from `BASE_URL`; the variable name is recorded, its value is not.
|
|
20
|
+
4. **Command.** Playwright config discovered; one command built with a JSON reporter and `--trace=on-first-retry`, recorded verbatim.
|
|
21
|
+
5. **Execute.** The command runs under the smoke timeout; one test fails and is retried once, still failing; the browser is cleaned up.
|
|
22
|
+
6. **Collect / normalize.** Artifacts located into the common model; the JSON reporter is normalized — 11 passed, 1 failed → status `failed`, backed by the reporter and the exit code.
|
|
23
|
+
7. **Report.** The result is self-validated and presented; a recommendation points at the collected trace for future failure analysis.
|
|
24
|
+
|
|
25
|
+
## Expected output
|
|
26
|
+
|
|
27
|
+
The normalized result `qa-artifacts/qa-run-result-9c2e.json` (the plan artifact is emitted first, as in the planning example):
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"contract": { "name": "qa-run/execution-result", "version": "1.0.0" },
|
|
32
|
+
"skill": { "name": "qa-run", "version": "0.2.0" },
|
|
33
|
+
"generatedAt": "2026-07-18T11:05:03Z",
|
|
34
|
+
"summary": "Smoke run executed on Playwright/Chromium (headless): 11 passed, 1 failed. The checkout purchase test failed after one retry; its trace was collected. No tests were skipped.",
|
|
35
|
+
"classification": "failed",
|
|
36
|
+
"confidence": 0.98,
|
|
37
|
+
"evidence": [
|
|
38
|
+
{
|
|
39
|
+
"type": "report",
|
|
40
|
+
"description": "Playwright JSON reporter: 11 passed, 1 failed, 0 skipped",
|
|
41
|
+
"source": "test-results/results.json",
|
|
42
|
+
"excerpt": "\"stats\": { \"expected\": 11, \"unexpected\": 1, \"skipped\": 0 }"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"type": "command",
|
|
46
|
+
"description": "Runner exited non-zero, consistent with a reported failure",
|
|
47
|
+
"source": "exit code 1"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"execution": {
|
|
51
|
+
"strategy": "smoke",
|
|
52
|
+
"command": "pnpm exec playwright test --grep @smoke --project=chromium --reporter=json,line --trace=on-first-retry",
|
|
53
|
+
"startedAt": "2026-07-18T11:04:33Z",
|
|
54
|
+
"finishedAt": "2026-07-18T11:05:03Z",
|
|
55
|
+
"durationMs": 30120,
|
|
56
|
+
"exitCode": 1
|
|
57
|
+
},
|
|
58
|
+
"framework": { "name": "playwright", "version": "1.58.0" },
|
|
59
|
+
"tests": { "total": 12, "passed": 11, "failed": 1, "skipped": 0, "flaky": 0 },
|
|
60
|
+
"executed": [
|
|
61
|
+
{ "title": "checkout > completes a purchase", "file": "e2e/checkout.spec.ts", "status": "failed", "durationMs": 8300, "retries": 1 },
|
|
62
|
+
{ "title": "login > accepts valid credentials", "file": "e2e/login.spec.ts", "status": "passed", "durationMs": 2100, "retries": 0 }
|
|
63
|
+
],
|
|
64
|
+
"artifacts": [
|
|
65
|
+
{ "type": "attachment", "location": "test-results/results.json", "framework": "playwright", "timestamp": "2026-07-18T11:05:03Z", "mediaType": "application/json", "ownership": "qa-run", "present": true },
|
|
66
|
+
{ "type": "trace", "location": "test-results/checkout-completes-a-purchase/trace.zip", "framework": "playwright", "timestamp": "2026-07-18T11:05:01Z", "ownership": "qa-run", "testRef": "checkout > completes a purchase", "present": true },
|
|
67
|
+
{ "type": "html-report", "location": "playwright-report/index.html", "framework": "playwright", "timestamp": "2026-07-18T11:05:03Z", "ownership": "qa-run", "present": true }
|
|
68
|
+
],
|
|
69
|
+
"environment": {
|
|
70
|
+
"location": "local",
|
|
71
|
+
"headless": true,
|
|
72
|
+
"browser": "chromium",
|
|
73
|
+
"baseUrl": "http://localhost:3000",
|
|
74
|
+
"os": "linux",
|
|
75
|
+
"ciProvider": null,
|
|
76
|
+
"envVarNames": ["BASE_URL"]
|
|
77
|
+
},
|
|
78
|
+
"recommendations": [
|
|
79
|
+
{
|
|
80
|
+
"action": "Analyze the checkout failure from its collected trace once failure analysis ships",
|
|
81
|
+
"priority": "high",
|
|
82
|
+
"command": "/qa-debug"
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
"metadata": { "planRef": "qa-run-plan-9c2e" }
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The prose reply states the counts, that the run genuinely executed, and where the failure's evidence was collected — without diagnosing the failure, which is a later skill's job.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Example: plan a smoke run
|
|
2
|
+
|
|
3
|
+
## Request
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
/qa-run smoke
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
The repository from the qa-init example: `.qa/context.md` exists with `testFramework.e2e: playwright`, `packageManager: pnpm`, and `conventions.specGlob: e2e/**/*.spec.ts`. Smoke tests are tagged `@smoke`.
|
|
12
|
+
|
|
13
|
+
## Expected behavior
|
|
14
|
+
|
|
15
|
+
1. **Discover.** Read `.qa/context.md`; it exists, so proceed.
|
|
16
|
+
2. **Understand repository / framework.** Runner is Playwright via pnpm, from the context.
|
|
17
|
+
3. **Understand intent.** "smoke" selects the smoke strategy; no ambiguity, so no question.
|
|
18
|
+
4. **Determine strategy.** `smoke`, justified by the intent word "smoke" and the Playwright context fact.
|
|
19
|
+
5. **Plan.** Scope is the `@smoke`-tagged tests; the evidence plan captures a trace on failure and a report always; the collect, execute, and validate phases are marked `deferred`.
|
|
20
|
+
6. **Report.** Emit and self-validate the execution plan; execute nothing.
|
|
21
|
+
|
|
22
|
+
## Expected output
|
|
23
|
+
|
|
24
|
+
`qa-artifacts/qa-run-7f3a.json`:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"contract": { "name": "qa-run/execution-plan", "version": "1.0.0" },
|
|
29
|
+
"skill": { "name": "qa-run", "version": "0.1.0" },
|
|
30
|
+
"generatedAt": "2026-07-18T10:20:00Z",
|
|
31
|
+
"summary": "Smoke run planned: the @smoke-tagged Playwright suite, run with pnpm, capturing a trace on failure. Planning only — no tests were executed.",
|
|
32
|
+
"classification": "smoke",
|
|
33
|
+
"confidence": 0.9,
|
|
34
|
+
"evidence": [
|
|
35
|
+
{
|
|
36
|
+
"type": "context",
|
|
37
|
+
"description": "E2E framework and runner",
|
|
38
|
+
"source": ".qa/context.md",
|
|
39
|
+
"excerpt": "testFramework.e2e: playwright; packageManager: pnpm"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"type": "intent",
|
|
43
|
+
"description": "User selected the smoke strategy",
|
|
44
|
+
"source": "user request",
|
|
45
|
+
"excerpt": "/qa-run smoke"
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"plan": {
|
|
49
|
+
"framework": "playwright",
|
|
50
|
+
"runner": "pnpm exec playwright test",
|
|
51
|
+
"command": "pnpm exec playwright test --grep @smoke --trace on-first-retry",
|
|
52
|
+
"scope": { "include": ["@smoke"], "exclude": [] },
|
|
53
|
+
"environment": {},
|
|
54
|
+
"phases": [
|
|
55
|
+
{ "name": "discover", "status": "performed", "detail": "read .qa/context.md" },
|
|
56
|
+
{ "name": "understand-repository", "status": "performed" },
|
|
57
|
+
{ "name": "understand-intent", "status": "performed" },
|
|
58
|
+
{ "name": "determine-framework", "status": "performed", "detail": "playwright from context" },
|
|
59
|
+
{ "name": "determine-strategy", "status": "performed", "detail": "smoke" },
|
|
60
|
+
{ "name": "collect-evidence", "status": "deferred", "detail": "execution engine, later milestone" },
|
|
61
|
+
{ "name": "execute", "status": "deferred", "detail": "execution engine, later milestone" },
|
|
62
|
+
{ "name": "validate", "status": "deferred", "detail": "execution engine, later milestone" },
|
|
63
|
+
{ "name": "report", "status": "performed" },
|
|
64
|
+
{ "name": "recommendations", "status": "performed" }
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
"evidencePlan": {
|
|
68
|
+
"artifacts": [
|
|
69
|
+
{ "type": "trace", "when": "on-failure", "purpose": "timeline for /qa-debug if the run fails" },
|
|
70
|
+
{ "type": "report", "when": "always", "purpose": "machine-readable pass/fail for the result" }
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"recommendations": [
|
|
74
|
+
{
|
|
75
|
+
"action": "Deterministic execution of this plan arrives in a later milestone; until then the illustrative command can be run manually",
|
|
76
|
+
"priority": "medium"
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
"metadata": {}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The prose reply presents the strategy and scope, states plainly that nothing was executed, and points to the plan artifact.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!-- synced-from: shared/execution/artifact-collector.md — do not edit; edit the source and run: node scripts/sync-shared.mjs --write -->
|
|
2
|
+
# Artifact Collector
|
|
3
|
+
|
|
4
|
+
The common, framework-independent model for everything a run produces, and the rules for collecting it. This model is the interface between execution and the analysis layer of later milestones: a future analyzer consumes artifacts by their normalized type and never needs to know which framework produced them.
|
|
5
|
+
|
|
6
|
+
## The artifact model
|
|
7
|
+
|
|
8
|
+
Every collected artifact is described by the same fields, whatever produced it:
|
|
9
|
+
|
|
10
|
+
| Field | Meaning |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| `type` | Normalized kind, from the closed set below — the field analyzers key on |
|
|
13
|
+
| `location` | Path to the artifact, relative to the repository root |
|
|
14
|
+
| `framework` | The framework that produced it, for provenance (analyzers do not branch on this) |
|
|
15
|
+
| `timestamp` | ISO 8601 UTC time the artifact was produced |
|
|
16
|
+
| `mediaType` | The artifact's media type where meaningful (for example, the type for a video or an XML report) |
|
|
17
|
+
| `ownership` | The skill and run that produced it, for example `qa-run` |
|
|
18
|
+
| `testRef` | The test the artifact belongs to, when it is test-scoped rather than run-scoped |
|
|
19
|
+
|
|
20
|
+
## Normalized types
|
|
21
|
+
|
|
22
|
+
The `type` set is fixed so analyzers can rely on it across frameworks:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
stdout · stderr · console-log · network-log · screenshot · video · trace · har · junit · html-report · attachment
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
A framework that emits something outside this set maps it to the closest type or to `attachment` with a descriptive note; it never invents a new top-level type, because a new type is a change every future analyzer would have to learn.
|
|
29
|
+
|
|
30
|
+
## Collection rules
|
|
31
|
+
|
|
32
|
+
- **Locate, describe, never move.** Collection records where the framework wrote each artifact; it does not relocate or rewrite them. The result points at real files in place.
|
|
33
|
+
- **Run-scoped and test-scoped.** Some artifacts belong to the whole run (stdout, the JUnit report); others belong to one test (a trace, a failure screenshot). Test-scoped artifacts carry `testRef`.
|
|
34
|
+
- **Collect what the strategy planned.** The evidence plan chose what to capture and when (for example, a trace only on failure). Collection gathers exactly that set, so cost matches the strategy.
|
|
35
|
+
- **Redact at the boundary.** Text artifacts (stdout, logs) may contain credentials from the environment; any credential or token is redacted as the artifact is described, before it appears in a result or is shown. This applies to the description and any excerpt, not to the file on disk, which the user controls.
|
|
36
|
+
- **Absence is data.** A planned artifact that is missing (no trace though a test failed) is recorded as an expected-but-absent note, not silently dropped — its absence may matter to an analyzer.
|
|
37
|
+
|
|
38
|
+
## Why normalize now
|
|
39
|
+
|
|
40
|
+
Normalizing artifacts at collection time, rather than leaving each framework's raw layout for analyzers to decode, is what lets the analysis layer be written once against one model. It is the concrete form of the pack's promise that `qa-debug` and `qa-report` will work across frameworks: they will read this model, not Playwright's or Selenium's native output. The decision is recorded in the pack's architecture decision on the normalized result.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!-- synced-from: shared/execution/browser-launch.md — do not edit; edit the source and run: node scripts/sync-shared.mjs --write -->
|
|
2
|
+
# Browser Execution Lifecycle
|
|
3
|
+
|
|
4
|
+
How a run's browser and mode are chosen and controlled: startup, timeouts, retries, cleanup, and cancellation. The engine expresses these as intents; the framework adapter realizes them with the framework's own mechanisms.
|
|
5
|
+
|
|
6
|
+
## Browsers and modes
|
|
7
|
+
|
|
8
|
+
| Dimension | Options | Default |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| Engine | Chromium, Firefox, WebKit | The framework's configured default, else Chromium |
|
|
11
|
+
| Display | Headed, headless | Headless (headed only on explicit request, and never in CI) |
|
|
12
|
+
| Location | Local, remote/grid, CI runner | Local this milestone; remote and CI-runner execution are adapter extensions |
|
|
13
|
+
|
|
14
|
+
The chosen browser and mode come from the environment decision (see the environment-detection module) and are recorded in the result's environment block, so a reader knows exactly what ran where.
|
|
15
|
+
|
|
16
|
+
## Lifecycle
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
resolve browser+mode → start → run under timeout → on failure: bounded retry → collect → clean up
|
|
20
|
+
│
|
|
21
|
+
cancellation can interrupt at any point → clean up
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- **Startup.** The adapter launches the browser as part of the run command; the engine does not manage browser processes directly. Startup failure (missing browser binary, unavailable display) is an `errored` result with the cause as evidence — never a silent fallback.
|
|
25
|
+
- **Timeout.** Every run has an overall wall-clock timeout appropriate to the strategy (a smoke run is short; a regression run is long). A run that exceeds it is stopped, cleaned up, and reported as `errored` with the timeout as the cause — a hang is never reported as a failure of the tests.
|
|
26
|
+
- **Retry.** Retries are the framework's own test-level retry (configured through the command), used to observe flakiness, not to manufacture a pass. The number of retries is recorded; a test that passes only on retry is reported as flaky, not as passed.
|
|
27
|
+
- **Cleanup.** After every run — success, failure, timeout, or cancellation — browser processes are ended and temporary state is removed, so no run leaves orphaned processes or locked resources.
|
|
28
|
+
- **Cancellation.** If the user interrupts, the run is stopped, the browser is cleaned up, and a partial result is reported honestly as cancelled with whatever completed — never as passed.
|
|
29
|
+
|
|
30
|
+
## Rules
|
|
31
|
+
|
|
32
|
+
- Headless by default; headed is explicit and never assumed in CI.
|
|
33
|
+
- A hang, a crash, and a test failure are three different outcomes and are reported as three different things.
|
|
34
|
+
- Cleanup always runs, on every exit path.
|
|
35
|
+
- The browser, mode, and location that actually ran are recorded as evidence; the result never describes an environment that was requested but not achieved.
|
|
36
|
+
|
|
37
|
+
## Extension
|
|
38
|
+
|
|
39
|
+
Remote and grid execution, additional engines, and containerized browsers are adapter-level additions: they change how the adapter starts and points the browser, not the lifecycle above. The startup-timeout-retry-cleanup-cancellation shape holds for every framework and location.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!-- synced-from: shared/execution/command-builder.md — do not edit; edit the source and run: node scripts/sync-shared.mjs --write -->
|
|
2
|
+
# Command Builder
|
|
3
|
+
|
|
4
|
+
How a chosen strategy, a resolved scope, a browser, and an environment become the one concrete command the run executes. The builder is framework-agnostic: it assembles the *intent* of the command, and the framework adapter supplies the framework's actual flags and syntax.
|
|
5
|
+
|
|
6
|
+
Every built command is recorded verbatim in the execution result, so a run is always reproducible and auditable.
|
|
7
|
+
|
|
8
|
+
## Inputs
|
|
9
|
+
|
|
10
|
+
The builder consumes decisions already made by other modules — it invents nothing:
|
|
11
|
+
|
|
12
|
+
| Input | Source |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| Strategy | The chosen strategy (see the execution-strategy module) |
|
|
15
|
+
| Scope | The include and exclude sets the strategy resolved |
|
|
16
|
+
| Browser and mode | The environment decision (see the environment-detection module) |
|
|
17
|
+
| Runner | The framework adapter, from the recorded framework |
|
|
18
|
+
| Reporter | Always includes a machine-readable reporter, so the result can be normalized |
|
|
19
|
+
|
|
20
|
+
## The build
|
|
21
|
+
|
|
22
|
+
1. Start from the adapter's base run command.
|
|
23
|
+
2. Apply the scope as the adapter's selection mechanism — a tag filter, a path filter, a project selection, or named files. The adapter owns the syntax; the builder owns which selection to apply.
|
|
24
|
+
3. Apply the browser and mode as the adapter's flags.
|
|
25
|
+
4. Always add a machine-readable reporter alongside any human reporter. Normalization depends on it; a run without it cannot produce a trustworthy result.
|
|
26
|
+
5. Add the evidence flags the artifact plan requires (tracing, video, screenshots) at the levels the strategy chose.
|
|
27
|
+
6. Record the full command string in the result.
|
|
28
|
+
|
|
29
|
+
## Rules
|
|
30
|
+
|
|
31
|
+
- **One command, fully specified.** The builder produces a single command with every relevant flag explicit. It does not rely on ambient defaults that a reader of the result could not see.
|
|
32
|
+
- **Reporter is non-negotiable.** A machine-readable reporter is always present; the result's counts and per-test outcomes come from it, not from scraping human output.
|
|
33
|
+
- **Secrets never enter the command line.** Credentials are passed by environment-variable reference, never interpolated into the recorded command (the command is stored and shown).
|
|
34
|
+
- **No destructive flags.** The builder never adds flags that update snapshots, rewrite baselines, or delete artifacts; execution observes, it does not mutate the project.
|
|
35
|
+
- **Illustrative until launched.** The built command is presented in the plan before the run; the guardrails against claiming a run happened apply until the command has actually executed and returned.
|
|
36
|
+
|
|
37
|
+
## Extension
|
|
38
|
+
|
|
39
|
+
A new framework changes only the adapter's answers — base command, selection syntax, reporter and evidence flags. The builder's logic (which selection, which reporter, record verbatim) is unchanged. This is why adding a framework never touches the command-building step of any skill.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<!-- synced-from: shared/execution/deterministic-tooling.md — do not edit; edit the source and run: node scripts/sync-shared.mjs --write -->
|
|
2
|
+
# Deterministic tooling invocation
|
|
3
|
+
|
|
4
|
+
How a skill runs the pack's deterministic tooling. One recipe, identical in every
|
|
5
|
+
skill that bundles an engine, so an agent never has to invent the glue.
|
|
6
|
+
|
|
7
|
+
**The rule this module exists to enforce:** deterministic code owns facts. If a
|
|
8
|
+
value could have been computed by a tool, the skill runs the tool and cites its
|
|
9
|
+
output. Hand-normalizing a reporter, hand-counting failures, or hand-classifying
|
|
10
|
+
an error message is a boundary violation, not a shortcut — see the pack's
|
|
11
|
+
*Deterministic Execution Boundary* architecture document.
|
|
12
|
+
|
|
13
|
+
## 1. One command shape, every platform
|
|
14
|
+
|
|
15
|
+
The engine is bundled inside the installed skill, and a launcher beside it
|
|
16
|
+
resolves its own location. There is nothing to set up and no shell features are
|
|
17
|
+
involved:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
python3 <skill-dir>/scripts/qa_tool.py <tool> <subcommand> [args]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`<skill-dir>` is wherever the host installed this skill — usually
|
|
24
|
+
`.agents/skills/<skill>` or, for Claude Code, `.claude/skills/<skill>`. Use
|
|
25
|
+
whichever exists.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python3 .agents/skills/qa-run/scripts/qa_tool.py analysis junit test-results/results.xml
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
That line is identical in bash, zsh, PowerShell, and cmd.exe. **On Windows, use
|
|
32
|
+
`python` if `python3` is not on PATH** — that is the only platform difference.
|
|
33
|
+
|
|
34
|
+
An earlier version of this contract used a shell recipe
|
|
35
|
+
(`QA_LIB="$(ls -d … | head -1)"` with a `PYTHONPATH=` prefix). It was POSIX-only,
|
|
36
|
+
so on Windows every deterministic call failed, each skill fell back to its manual
|
|
37
|
+
path, and the user silently got guesswork while believing the tooling had run.
|
|
38
|
+
Never reintroduce a shell-dependent invocation.
|
|
39
|
+
|
|
40
|
+
If `qa_tool.py` is missing, the engine is not installed: say so, recommend
|
|
41
|
+
`qa repair`, use the skill's documented fallback, and mark the result degraded.
|
|
42
|
+
|
|
43
|
+
Every tool writes JSON to stdout. Exit `0` means success; exit `1` means an
|
|
44
|
+
invalid contract; exit `2` means unreadable input, a malformed artifact, or a
|
|
45
|
+
payload that failed its seam contract, and the JSON body carries `error` and
|
|
46
|
+
`detail`. Treat a non-zero exit as missing evidence, never as a value to guess.
|
|
47
|
+
|
|
48
|
+
Standard-library Python 3.8+ only — nothing to install.
|
|
49
|
+
|
|
50
|
+
## 2. Analysis core — `qa_tool.py analysis`
|
|
51
|
+
|
|
52
|
+
Framework-agnostic parsing, redaction, and validation.
|
|
53
|
+
|
|
54
|
+
| Subcommand | Invocation | Returns |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| `junit` | `python3 <skill-dir>/scripts/qa_tool.py analysis junit <report.xml>` | `{tests: {...}, executed: [...]}` normalized counts and per-test outcomes |
|
|
57
|
+
| `har` | `python3 <skill-dir>/scripts/qa_tool.py analysis har <file.har> [--slow-ms N]` | Redacted request/response summary, failures, slow calls |
|
|
58
|
+
| `discover` | `python3 <skill-dir>/scripts/qa_tool.py analysis discover [--root DIR] [--path P]` | Artifacts found, by type, with presence flags |
|
|
59
|
+
| `diff-guard` | `python3 <skill-dir>/scripts/qa_tool.py analysis diff-guard <diff-file>` | `{issues: [...], safe: bool}` — `safe:false` blocks the change |
|
|
60
|
+
| `redact` | `python3 <skill-dir>/scripts/qa_tool.py analysis redact <file>` | The file's text with credentials masked |
|
|
61
|
+
| `validate` | `python3 <skill-dir>/scripts/qa_tool.py analysis validate <instance.json> <schema.json>` | `{valid: bool, errors: [...]}`; exit 1 when invalid |
|
|
62
|
+
| `classify` | `python3 <skill-dir>/scripts/qa_tool.py analysis classify "<error message>" [--http-status N]` | `{classification, confidence, reason}` from the shared taxonomy |
|
|
63
|
+
| `context` | `python3 <skill-dir>/scripts/qa_tool.py analysis context [--root DIR] [--path .qa/context.md]` | The parsed, schema-validated project context as JSON |
|
|
64
|
+
|
|
65
|
+
## 3. Diagnostic engine — `qa_tool.py diagnostics`
|
|
66
|
+
|
|
67
|
+
One engine, consumed by the diagnostic skills. Reasoning lives here once.
|
|
68
|
+
|
|
69
|
+
| Subcommand | Invocation | Returns |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| `diagnose` | `python3 <skill-dir>/scripts/qa_tool.py diagnostics diagnose --execution-result <path> [--analysis-result <path>]` | `{entries: [...], timeline: [...], recommendations: [...]}` |
|
|
72
|
+
| `plan-repairs` | `python3 <skill-dir>/scripts/qa_tool.py diagnostics plan-repairs --diagnosis <path>` | `{plans: [...]}` — one plan per entry, escalations included |
|
|
73
|
+
| `summarize` | `python3 <skill-dir>/scripts/qa_tool.py diagnostics summarize --execution-result <path> --diagnosis <path>` | `{totals, byClassification, topPriority, releaseReadiness}` |
|
|
74
|
+
| `report` | `python3 <skill-dir>/scripts/qa_tool.py diagnostics report --execution-result <path> [--analysis-result <path>]` | `{diagnosis, plans, summary}` — all three in one call |
|
|
75
|
+
|
|
76
|
+
**Inputs.** `--execution-result` takes a `qa-run` execution result, or the minimal
|
|
77
|
+
subset (`tests` counts plus `executed[]` entries carrying `status`).
|
|
78
|
+
`--analysis-result` takes `{findings: [...]}` and is preferred over `executed[]`
|
|
79
|
+
when available. Both are validated against the internal seam contracts before
|
|
80
|
+
the engine runs, so a malformed payload fails loudly with `exit 2` instead of
|
|
81
|
+
producing a confident-looking diagnosis from nothing.
|
|
82
|
+
|
|
83
|
+
**Output.** Every diagnosis is validated against the internal diagnosis contract
|
|
84
|
+
before it is returned. The skill adds explanation, never new facts.
|
|
85
|
+
|
|
86
|
+
**The engine's shape is internal; the public contract is a projection of it.** Do
|
|
87
|
+
not copy an engine object wholesale into a contract field — the internal shape
|
|
88
|
+
carries more than the public contract accepts, and every public contract sets
|
|
89
|
+
`additionalProperties: false`, so a wholesale copy is rejected. Map the fields the
|
|
90
|
+
contract names:
|
|
91
|
+
|
|
92
|
+
| Contract field | Take from | Note |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| `rootCause` | `entries[i].rootCause` | Exactly five keys: `classification`, `confidence`, `reason`, `ownership`, `recommendation`. The engine also returns per-cause `evidence` — that belongs in the envelope's `evidence[]`, not nested here. |
|
|
95
|
+
| `priority` | `entries[i].priority` | Copied as-is |
|
|
96
|
+
| `timeline` | `diagnosis.timeline` | Add `order` if absent |
|
|
97
|
+
| `evidence[]` | the artifacts and commands you actually ran | Include a `command` entry citing the invocation |
|
|
98
|
+
| `classification` | `entries[0].rootCause.classification` | The envelope mirrors the top cause |
|
|
99
|
+
|
|
100
|
+
This mapping is not busywork: the strictness is what stops a skill from shipping a
|
|
101
|
+
result whose shape nobody checked. Validate before completion —
|
|
102
|
+
`python3 <skill-dir>/scripts/qa_tool.py analysis validate <result.json> <schema.json>` — and fix the
|
|
103
|
+
result, never the claim.
|
|
104
|
+
|
|
105
|
+
## 4. Framework adapters
|
|
106
|
+
|
|
107
|
+
Framework-specific artifact shapes stay in the adapter. The core CLI never takes
|
|
108
|
+
a `--framework` flag.
|
|
109
|
+
|
|
110
|
+
| Adapter | Invocation | Returns |
|
|
111
|
+
| --- | --- | --- |
|
|
112
|
+
| Playwright report | `python3 <skill-dir>/scripts/qa_tool.py playwright report <results.json>` | The same `{tests, executed}` shape as `junit` |
|
|
113
|
+
| Playwright trace | `python3 <skill-dir>/scripts/qa_tool.py playwright trace <trace.zip>` | Actions, console/network counts, errors, classification |
|
|
114
|
+
|
|
115
|
+
For Selenium, Cypress, and WebdriverIO, normalize through
|
|
116
|
+
`qa_tool.py analysis junit` — those adapters have no richer artifact than JUnit, and
|
|
117
|
+
the skill says so rather than implying trace-grade depth.
|
|
118
|
+
|
|
119
|
+
## 5. Reporting what ran
|
|
120
|
+
|
|
121
|
+
Cite the invocation in `evidence[]`: the command, the file it read, and the field
|
|
122
|
+
that carried the fact. A skill that reports a fact no tool produced has violated
|
|
123
|
+
its own contract, and the adversarial evaluation cases exist to catch it.
|
|
124
|
+
|
|
125
|
+
When a tool is unavailable, the skill's documented fallback applies — and the
|
|
126
|
+
result must state that it is degraded, name what was missing, and lower
|
|
127
|
+
confidence accordingly. Silence about a missing tool is the failure mode; an
|
|
128
|
+
honest "I could not run the trace analyzer" is not.
|