@mmerterden/multi-agent-pipeline 20.27.2 → 20.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +6 -5
- package/README.tr.md +6 -5
- package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +0 -1
- package/docs/architecture.md +4 -4
- package/docs/ecosystem.md +5 -5
- package/docs/facts.json +14 -12
- package/docs/features.md +2 -0
- package/install/_dev-only-files.mjs +1 -0
- package/install/catalog-history.json +1 -1
- package/install/index.mjs +0 -2
- package/manifest.json +67 -44
- package/package.json +4 -1
- package/pipeline/agents/code-reviewer.md +1 -0
- package/pipeline/agents/test-gen-analyst.md +98 -0
- package/pipeline/commands/multi-agent/sync/SKILL.md +3 -3
- package/pipeline/commands/multi-agent/test-gen/SKILL.md +124 -0
- package/pipeline/multi-agent-refs/cross-cli-contract.md +11 -5
- package/pipeline/multi-agent-refs/features/doctor.md +13 -0
- package/pipeline/multi-agent-refs/features/test-classification.md +76 -0
- package/pipeline/multi-agent-refs/features/usage-reporting.md +17 -0
- package/pipeline/multi-agent-refs/help/en.md +1 -0
- package/pipeline/multi-agent-refs/help/tr.md +1 -0
- package/pipeline/multi-agent-refs/phases/operations.md +2 -2
- package/pipeline/multi-agent-refs/phases/phase-2-dev.md +6 -7
- package/pipeline/multi-agent-refs/phases/phase-3-review.md +3 -3
- package/pipeline/multi-agent-refs/phases/phase-5-report.md +6 -5
- package/pipeline/multi-agent-refs/test-gen/stages.md +227 -0
- package/pipeline/preferences-template.json +3 -0
- package/pipeline/schemas/prefs.schema.json +14 -0
- package/pipeline/schemas/test-gen-discovery.schema.json +73 -0
- package/pipeline/schemas/test-gen-gaps.schema.json +122 -0
- package/pipeline/schemas/test-gen-inventory.schema.json +59 -0
- package/pipeline/schemas/test-gen-results.schema.json +44 -0
- package/pipeline/scripts/_handle-patterns.mjs +166 -0
- package/pipeline/scripts/_http-post.mjs +141 -0
- package/pipeline/scripts/_stack-routing.mjs +4 -0
- package/pipeline/scripts/_test-gaming.mjs +227 -0
- package/pipeline/scripts/_unified-diff.mjs +104 -0
- package/pipeline/scripts/_worktree-snapshot.mjs +113 -0
- package/pipeline/scripts/doctor.mjs +51 -0
- package/pipeline/scripts/evidence-gate.mjs +74 -3
- package/pipeline/scripts/handle-diff-audit.mjs +188 -0
- package/pipeline/scripts/routine-registry.mjs +5 -1
- package/pipeline/scripts/run-ui-tests.sh +27 -3
- package/pipeline/scripts/test-classify.mjs +296 -0
- package/pipeline/scripts/test-gen-gate.mjs +409 -0
- package/pipeline/scripts/test-gen-state.mjs +313 -0
- package/pipeline/scripts/test-integrity-gate.mjs +76 -11
- package/pipeline/scripts/uninstall.mjs +1 -0
- package/pipeline/scripts/usage-register-beacon.mjs +239 -0
- package/pipeline/scripts/usage-register.mjs +128 -33
- package/pipeline/scripts/usage-report.mjs +43 -33
- package/pipeline/skills/.skill-manifest.json +23 -3
- package/pipeline/skills/.skills-index.json +57 -2
- package/pipeline/skills/shared/README.md +10 -5
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +3 -3
- package/pipeline/skills/shared/core/multi-agent-test-gen/SKILL.md +120 -0
- package/pipeline/skills/shared/external/fix-review-verdicts/SKILL.md +133 -0
- package/pipeline/skills/shared/external/handle-request/SKILL.md +97 -0
- package/pipeline/skills/shared/external/scenario-gap-analysis/SKILL.md +129 -0
- package/pipeline/skills/shared/external/scenario-gap-analysis/references/scenario-schema.md +60 -0
- package/pipeline/skills/shared/external/test-result-triage/SKILL.md +160 -0
- package/pipeline/skills/skills-index.md +7 -2
- package/install/_telemetry.mjs +0 -61
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# test-gen stages
|
|
2
|
+
|
|
3
|
+
<!-- toc -->
|
|
4
|
+
- [Artefacts and gates](#artefacts-and-gates)
|
|
5
|
+
- [Read-only stages](#read-only-stages)
|
|
6
|
+
- [1. Inventory](#1-inventory)
|
|
7
|
+
- [Priority](#priority)
|
|
8
|
+
- [2. Discovery](#2-discovery)
|
|
9
|
+
- [3. Gaps](#3-gaps)
|
|
10
|
+
- [4. Handles](#4-handles)
|
|
11
|
+
- [5. Write](#5-write)
|
|
12
|
+
- [6. Run](#6-run)
|
|
13
|
+
- [7. Classify](#7-classify)
|
|
14
|
+
- [8. Triage](#8-triage)
|
|
15
|
+
- [End: the change base](#end-the-change-base)
|
|
16
|
+
<!-- /toc -->
|
|
17
|
+
|
|
18
|
+
The contract behind `/multi-agent:test-gen`. Each stage is a subagent with one
|
|
19
|
+
artefact under `$RUN` (`$HOME/.claude/logs/test-gen/<repo>/<timestamp>/`), and
|
|
20
|
+
no stage starts until the previous artefact has passed its gate. A stage that
|
|
21
|
+
says it is done without its artefact on disk is not done.
|
|
22
|
+
|
|
23
|
+
## Artefacts and gates
|
|
24
|
+
|
|
25
|
+
| # | Stage | Runs as | Artefact | Gate |
|
|
26
|
+
|---|---|---|---|---|
|
|
27
|
+
| 1 | inventory | orchestrator, with the toolkit inventory tools | `inventory.json` | `test-gen-gate.mjs check --stage inventory`, `evidence-gate.mjs --claim artefact` |
|
|
28
|
+
| - | priority | AskUserQuestion; autopilot takes the top three | `inventory.json` `priority` | `check --stage inventory` again |
|
|
29
|
+
| 2 | discovery | `test-gen-analyst` (read-only) | `discovery.json` | `check --stage discovery`, `evidence-gate.mjs --claim artefact` |
|
|
30
|
+
| 3 | gaps | `coverage_gap`, then `test-gen-analyst` (read-only) | `gaps.json` | `check --stage gaps`, `evidence-gate.mjs --claim artefact` |
|
|
31
|
+
| 4 | handles | general-purpose subagent, product code, handles only | `handles.md` and the stage's delta | `test-gen-gate.mjs handles`, `handle-diff-audit.mjs --baseline` exit 0 |
|
|
32
|
+
| 5 | write | general-purpose subagent, test files only | the test files and `written.json` | `test-gen-gate.mjs written --baseline` |
|
|
33
|
+
| 6 | run | orchestrator | `run-<k>.log` and per-test reports | `evidence-gate.mjs --claim test` |
|
|
34
|
+
| 7 | classify | orchestrator | `results.json` | `check --stage results` |
|
|
35
|
+
| 8 | triage | orchestrator, result by result | `results.json` `triage` | `test-gen-state.mjs revise` |
|
|
36
|
+
|
|
37
|
+
Before each stage take `STAGE_START=$(date -u +%Y-%m-%dT%H:%M:%SZ)`. The
|
|
38
|
+
artefact gate (`--claim artefact --stage-start "$STAGE_START" --evidence <its own
|
|
39
|
+
file>`) rejects a file written before the stage began and a file that is not
|
|
40
|
+
whole (JSON that does not parse). It is applied to the JSON a model writes
|
|
41
|
+
(inventory, discovery, gaps); the scripts write `results.json` and the
|
|
42
|
+
baselines whole.
|
|
43
|
+
|
|
44
|
+
The two stages that may edit the repository (handles, write) start with a
|
|
45
|
+
snapshot: `test-gen-gate.mjs baseline` records the working tree, untracked files
|
|
46
|
+
included, as a git tree without touching it or the index. Their gates read only
|
|
47
|
+
what changed after it, so uncommitted work the person had before the stage is
|
|
48
|
+
never taken for the stage's change, and never reverted to satisfy a gate.
|
|
49
|
+
|
|
50
|
+
## Read-only stages
|
|
51
|
+
|
|
52
|
+
Discovery and gaps are dispatched with `subagent_type: "test-gen-analyst"`
|
|
53
|
+
(`agents/test-gen-analyst.md`). The persona's grant is an allowlist: Read, Grep,
|
|
54
|
+
Glob and the read-only toolkit tools (`coverage_gap`, the `repo_*` readers, the
|
|
55
|
+
`code_*` language-server queries). No Write, Edit, Bash, Agent or other MCP tool
|
|
56
|
+
is granted, so an analysis stage cannot change the repository however it is
|
|
57
|
+
prompted. It returns JSON; the orchestrator writes it with the Write tool.
|
|
58
|
+
Copilot CLI installs the same persona with the same grant. Codex CLI has no
|
|
59
|
+
per-agent tool grant: there, run the two stages in the main session and change
|
|
60
|
+
nothing during them.
|
|
61
|
+
|
|
62
|
+
## 1. Inventory
|
|
63
|
+
|
|
64
|
+
Prefer a tool over reading: `design_scenario_inventory` (a screen's states from
|
|
65
|
+
the design), `web_map` (a web app's routes), the UI tree (`ios_get_ui_tree`,
|
|
66
|
+
`android_get_ui_tree`) of each reachable screen, or the OpenAPI spec. Without a
|
|
67
|
+
tool, read the navigation and routes and set `source: "agent"`. Every item has a
|
|
68
|
+
stable `id`: route, screen id, design node id, endpoint path.
|
|
69
|
+
|
|
70
|
+
When a change base exists (`test-gen-state.mjs base-scan` measured), keep the
|
|
71
|
+
items whose `path` is among the scan's `files` or `graph.affectedFiles`, and say
|
|
72
|
+
how many fell away. A scan with `measured: false` narrows nothing: the inventory
|
|
73
|
+
stays whole and the reason is reported.
|
|
74
|
+
|
|
75
|
+
## Priority
|
|
76
|
+
|
|
77
|
+
Show the items in one table (id, kind, title, existing tests from a quick grep)
|
|
78
|
+
and ask which to cover (AskUserQuestion, multi-select, following
|
|
79
|
+
`multi-agent-refs/picker-contract.md`). Autopilot asks nothing:
|
|
80
|
+
it takes the three items most likely to hide a failure, in this order: no test
|
|
81
|
+
reaches them, they changed since the base, they are flows rather than single
|
|
82
|
+
screens. Record `priority: {mode, selected}`.
|
|
83
|
+
|
|
84
|
+
## 2. Discovery
|
|
85
|
+
|
|
86
|
+
`test-gen-analyst`, stage `discovery`, with the selected items. It returns test
|
|
87
|
+
roots and runners, the tests that reach each item (joined by identifier), the
|
|
88
|
+
handles already present, and the conventions for new tests. Save as
|
|
89
|
+
`discovery.json` and gate it with `check --stage discovery`.
|
|
90
|
+
|
|
91
|
+
## 3. Gaps
|
|
92
|
+
|
|
93
|
+
With `coverage_gap` (toolkit >= v3.25.0): call it with the inventory and the
|
|
94
|
+
test root from discovery; its `covered`, `uncovered` and `unmatched` buckets go
|
|
95
|
+
into the analyst's prompt, and `coverage.method` is `coverage_gap`. Without it:
|
|
96
|
+
`coverage.method` is `agent` and every match the analyst makes is
|
|
97
|
+
`method: "inferred"`. Then `test-gen-analyst`, stage `gaps`. Save its answer as
|
|
98
|
+
`gaps.json`. The scenario-gap-analysis skill (ai-common-toolkit) defines the
|
|
99
|
+
buckets and the scenario fields when it is enabled.
|
|
100
|
+
|
|
101
|
+
Before writing any test, show the gaps and the `dataNeeds[]`. Each need is
|
|
102
|
+
named, never filled: the person supplies the value, or names the credential the
|
|
103
|
+
test resolves by `secretRef`. Autopilot writes only the scenarios whose needs
|
|
104
|
+
are already met and lists the rest as blocked by data.
|
|
105
|
+
|
|
106
|
+
## 4. Handles
|
|
107
|
+
|
|
108
|
+
Only gaps with `handlesNeeded`. Before dispatch:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
node "$HOME/.claude/scripts/test-gen-gate.mjs" baseline --repo "$REPO" --out "$RUN/handles-baseline.json"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The subagent adds the missing handles and nothing else: iOS
|
|
115
|
+
`accessibilityIdentifier`, Compose `testTag` (or `testTagsAsResourceId` in a
|
|
116
|
+
semantics block), web `data-testid`. Never a list index, never a renamed or
|
|
117
|
+
moved element, never a handle the accessibility tree cannot see. It writes
|
|
118
|
+
`handles.md`, one line per request: `ADDED file:line`, `ALREADY file:line`,
|
|
119
|
+
`COULD NOT ADD <reason>` (the handle-request skill, when enabled). When nothing
|
|
120
|
+
was missing, the first line is `HANDLES: none-needed` followed by the
|
|
121
|
+
`ALREADY file:line` lines that prove it. Then:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
node "$HOME/.claude/scripts/test-gen-gate.mjs" handles --repo "$REPO" \
|
|
125
|
+
--baseline "$RUN/handles-baseline.json" --handles "$RUN/handles.md"
|
|
126
|
+
node "$HOME/.claude/scripts/handle-diff-audit.mjs" --repo "$REPO" \
|
|
127
|
+
--baseline "$RUN/handles-baseline.json" > "$RUN/handle-audit.json"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`handles` passes when the stage added a handle line, or on
|
|
131
|
+
`HANDLES: none-needed` with at least one cited line, inside the repository, that
|
|
132
|
+
carries a handle. `handle-diff-audit.mjs` must exit 0: 2 means the stage changed
|
|
133
|
+
more than handles (`violations[]` name the file and the lost, extra or
|
|
134
|
+
reordered tokens), so revert those hunks of the stage's own change and rerun; 3
|
|
135
|
+
means it could not read the diff, which is not a pass.
|
|
136
|
+
|
|
137
|
+
## 5. Write
|
|
138
|
+
|
|
139
|
+
Take a new snapshot first (`test-gen-gate.mjs baseline --out
|
|
140
|
+
"$RUN/write-baseline.json"`), then one subagent per platform, with the gaps,
|
|
141
|
+
discovery's conventions and the handles. With `ui_locator_codegen` (toolkit >= v3.25.0), locators come from the
|
|
142
|
+
UI tree node: `{platform, node}` returns the XCUITest or Compose code, or
|
|
143
|
+
`NO_HANDLE` with the handle to add, which goes back to stage 4. Without it,
|
|
144
|
+
write locators from the handles by hand. A locator is a handle, never a list
|
|
145
|
+
index or a visible string that is translated.
|
|
146
|
+
|
|
147
|
+
Each test asserts the gap's `expectation`. Test data comes from `secretRef` or
|
|
148
|
+
the fixtures the person supplied, never a literal secret. The subagent writes
|
|
149
|
+
`written.json`: `{files: [...], command: "<runs exactly these tests>",
|
|
150
|
+
tests: [{id, file}]}`. Then run the command once with a per-test report and:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
node "$HOME/.claude/scripts/test-gen-gate.mjs" written --repo "$REPO" \
|
|
154
|
+
--baseline "$RUN/write-baseline.json" --written "$RUN/written.json" \
|
|
155
|
+
--discovery "$RUN/discovery.json" --junit "$RUN/run-1.junit.xml"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
(`--xcresult-json` or `--log` where the runner writes no JUnit.) The gate fails
|
|
159
|
+
when the stage changed anything but test files, when a listed file is outside
|
|
160
|
+
the repository, missing, empty or not changed by the stage, when the stage's
|
|
161
|
+
diff carries test gaming (an environment branch, a swallowed error, an inflated
|
|
162
|
+
wait), when the command is none of the runners discovery found, or when the run
|
|
163
|
+
executed zero tests.
|
|
164
|
+
|
|
165
|
+
## 6. Run
|
|
166
|
+
|
|
167
|
+
Run `written.json`'s command `testStability.repeatCount` times (default 3),
|
|
168
|
+
each run's log and per-test report kept as `run-<k>.log` and
|
|
169
|
+
`run-<k>.junit.xml` (or `.xcresult`). A UI suite goes through
|
|
170
|
+
`run-ui-tests.sh run`, whose `UI_TEST_RESULT` names the report. Each log must
|
|
171
|
+
clear `evidence-gate.mjs --claim test --status passed` before a pass is
|
|
172
|
+
recorded; a failing run is evidence too and is kept.
|
|
173
|
+
|
|
174
|
+
## 7. Classify
|
|
175
|
+
|
|
176
|
+
`features/test-classification.md`: `test_results_classify` with run 1 as
|
|
177
|
+
`head`, the others as `confirm`, and the project's flake ledger, then
|
|
178
|
+
`test-classify.mjs merge`; without the tool, `test-classify.mjs fallback` over
|
|
179
|
+
the runs. Then:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
node "$HOME/.claude/scripts/test-gen-gate.mjs" results --classification "$RUN/test-classification.json" \
|
|
183
|
+
--written "$RUN/written.json" --out "$RUN/results.json"
|
|
184
|
+
node "$HOME/.claude/scripts/test-gen-gate.mjs" check --stage results --file "$RUN/results.json"
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
`results.json` is three-state: `pass`, `fail` (a regression, an unstable test, a
|
|
188
|
+
preexisting failure), `not_measured` (no base, a setup failure); every non-pass
|
|
189
|
+
carries its reason. `preexisting` is a fail here although Gate 3 inherits it: the
|
|
190
|
+
test is new, so red on the base too means the behaviour it asserts is missing,
|
|
191
|
+
which is a finding for triage, not someone else's failure.
|
|
192
|
+
|
|
193
|
+
## 8. Triage
|
|
194
|
+
|
|
195
|
+
Each `fail` and `not_measured` gets one verdict (the test-result-triage skill,
|
|
196
|
+
when enabled): `product-bug`, `stale-test`, `new-scenario`, `valid` or
|
|
197
|
+
`ambiguous`, and `ambiguous` is the default. `stale-test` needs the `file:line`
|
|
198
|
+
in the diff that changed the behaviour on purpose; a locator that found nothing
|
|
199
|
+
goes back to stage 4 before it may be called stale. A green test whose subject
|
|
200
|
+
changed behaviour is questioned too. Record each verdict, then:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
node "$HOME/.claude/scripts/test-gen-state.mjs" revise --state "$TG_STATE" --run "$RUN_ID" \
|
|
204
|
+
--test "<id>" --verdict "<verdict>" ${AUTOPILOT:+--autopilot}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
| Action | Then |
|
|
208
|
+
|---|---|
|
|
209
|
+
| `apply` | revise the test, rerun from stage 6 for that test |
|
|
210
|
+
| `park` | autopilot stops, because the verdict is `product-bug` (never applied without a person) or the stale-test cap (`prefs.global.testGen.revisionCap`, per run and per day) is reached. Report and end |
|
|
211
|
+
| `ask` | attended `product-bug`: show the evidence and ask whether to open it through `/multi-agent` |
|
|
212
|
+
| `none` | keep the verdict in `results.json` |
|
|
213
|
+
|
|
214
|
+
The count is read and written under a lock, so parallel triage cannot pass the
|
|
215
|
+
cap. A state or prefs file that does not parse is never counted as empty:
|
|
216
|
+
autopilot parks (exit 3), an attended run stops with exit 4 and records nothing.
|
|
217
|
+
|
|
218
|
+
## End: the change base
|
|
219
|
+
|
|
220
|
+
After the report, record where this run ended so the next one diffs from here:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
node "$HOME/.claude/scripts/test-gen-state.mjs" base-record --state "$TG_STATE" --repo "$REPO" --run "$RUN_ID"
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The reason names the run (`test-gen run <id> finished`). It records which code
|
|
227
|
+
the tests were written against, not that the app is understood.
|
|
@@ -1123,6 +1123,20 @@
|
|
|
1123
1123
|
}
|
|
1124
1124
|
}
|
|
1125
1125
|
},
|
|
1126
|
+
"testGen": {
|
|
1127
|
+
"type": "object",
|
|
1128
|
+
"additionalProperties": false,
|
|
1129
|
+
"description": "/multi-agent:test-gen knobs. Read by test-gen-state.mjs revise.",
|
|
1130
|
+
"properties": {
|
|
1131
|
+
"revisionCap": {
|
|
1132
|
+
"type": "integer",
|
|
1133
|
+
"minimum": 0,
|
|
1134
|
+
"maximum": 500,
|
|
1135
|
+
"default": 20,
|
|
1136
|
+
"description": "Stale-test revisions autopilot may apply, counted per run and per calendar day (UTC), whichever is reached first. At the cap the run parks instead of editing more tests. 0 parks on the first one."
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
},
|
|
1126
1140
|
"testStability": {
|
|
1127
1141
|
"type": "object",
|
|
1128
1142
|
"additionalProperties": false,
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/mmerterden/multi-agent-pipeline/pipeline/schemas/test-gen-discovery.schema.json",
|
|
4
|
+
"title": "Multi-Agent Pipeline - test-gen discovery",
|
|
5
|
+
"description": "What the repository already has for testing the selected inventory items, $RUN/discovery.json of /multi-agent:test-gen (multi-agent-refs/test-gen/stages.md). Returned by the read-only test-gen-analyst persona and written by the orchestrator. testRoots[].command is what the write stage's run command is checked against (test-gen-gate.mjs written --discovery). Existing tests are joined to items by the identifier the test uses, never by a name. test-gen-gate.mjs check --stage discovery checks this shape without a dependency.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["stage", "testRoots", "existing", "handles"],
|
|
9
|
+
"$defs": {
|
|
10
|
+
"fileLine": { "type": "string", "pattern": "^[^\\s:]+:[1-9][0-9]*$" }
|
|
11
|
+
},
|
|
12
|
+
"properties": {
|
|
13
|
+
"stage": { "const": "discovery" },
|
|
14
|
+
"testRoots": {
|
|
15
|
+
"type": "array",
|
|
16
|
+
"items": {
|
|
17
|
+
"type": "object",
|
|
18
|
+
"additionalProperties": false,
|
|
19
|
+
"required": ["path", "runner", "command"],
|
|
20
|
+
"properties": {
|
|
21
|
+
"path": { "type": "string", "minLength": 1 },
|
|
22
|
+
"runner": {
|
|
23
|
+
"enum": [
|
|
24
|
+
"xcuitest",
|
|
25
|
+
"xctest",
|
|
26
|
+
"swift-testing",
|
|
27
|
+
"espresso",
|
|
28
|
+
"compose",
|
|
29
|
+
"junit",
|
|
30
|
+
"playwright",
|
|
31
|
+
"cypress",
|
|
32
|
+
"jest",
|
|
33
|
+
"vitest",
|
|
34
|
+
"pytest",
|
|
35
|
+
"other"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"command": { "type": "string", "minLength": 1 },
|
|
39
|
+
"report": { "enum": ["junit", "xcresult", "none"] }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"existing": {
|
|
44
|
+
"type": "array",
|
|
45
|
+
"items": {
|
|
46
|
+
"type": "object",
|
|
47
|
+
"additionalProperties": false,
|
|
48
|
+
"required": ["inventoryId", "tests"],
|
|
49
|
+
"properties": {
|
|
50
|
+
"inventoryId": { "type": "string", "minLength": 1 },
|
|
51
|
+
"tests": { "type": "array", "items": { "$ref": "#/$defs/fileLine" } },
|
|
52
|
+
"joinedBy": { "type": "string", "minLength": 1 }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"handles": {
|
|
57
|
+
"type": "array",
|
|
58
|
+
"items": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"additionalProperties": false,
|
|
61
|
+
"required": ["inventoryId", "file", "line", "handle"],
|
|
62
|
+
"properties": {
|
|
63
|
+
"inventoryId": { "type": "string", "minLength": 1 },
|
|
64
|
+
"file": { "type": "string", "minLength": 1 },
|
|
65
|
+
"line": { "type": "integer", "minimum": 1 },
|
|
66
|
+
"handle": { "type": "string", "minLength": 1 }
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"conventions": { "type": "array", "items": { "type": "string", "minLength": 1 } },
|
|
71
|
+
"notes": { "type": "array", "items": { "type": "string" } }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/mmerterden/multi-agent-pipeline/pipeline/schemas/test-gen-gaps.schema.json",
|
|
4
|
+
"title": "Multi-Agent Pipeline - test-gen gaps",
|
|
5
|
+
"description": "The gap analysis of /multi-agent:test-gen, $RUN/gaps.json (multi-agent-refs/test-gen/stages.md). Written from the read-only analyst's answer: the selected inventory items set against the existing tests, each gap a scenario to write. `wrongly-covered` (a test exists but cannot see the failure) is kept apart from `missing`. dataNeeds[] says what test data a scenario needs and who provides it; it never holds a value, because values are entered by a person or resolved by secret reference at run time. unmeasured[] lists what the analysis could not measure, which is not the same as covered. test-gen-gate.mjs check --stage gaps checks this shape without a dependency.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["schemaVersion", "coverage", "gaps", "dataNeeds", "unmeasured"],
|
|
9
|
+
"$defs": {
|
|
10
|
+
"fileLine": { "type": "string", "pattern": "^[^\\s:]+:[1-9][0-9]*$" }
|
|
11
|
+
},
|
|
12
|
+
"properties": {
|
|
13
|
+
"schemaVersion": { "const": "1.0.0" },
|
|
14
|
+
"coverage": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"additionalProperties": false,
|
|
17
|
+
"required": ["method", "measured"],
|
|
18
|
+
"properties": {
|
|
19
|
+
"method": {
|
|
20
|
+
"enum": ["coverage_gap", "agent"],
|
|
21
|
+
"description": "coverage_gap: the toolkit tool joined inventory and tests by identifier; agent: the analyst's own reading, on a toolkit without the tool."
|
|
22
|
+
},
|
|
23
|
+
"measured": { "type": "boolean" },
|
|
24
|
+
"reason": { "type": "string", "minLength": 1 },
|
|
25
|
+
"covered": { "type": "integer", "minimum": 0 },
|
|
26
|
+
"uncovered": { "type": "integer", "minimum": 0 },
|
|
27
|
+
"unmatched": { "type": "integer", "minimum": 0 }
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"gaps": {
|
|
31
|
+
"type": "array",
|
|
32
|
+
"items": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"additionalProperties": false,
|
|
35
|
+
"required": [
|
|
36
|
+
"id",
|
|
37
|
+
"inventoryId",
|
|
38
|
+
"bucket",
|
|
39
|
+
"title",
|
|
40
|
+
"priority",
|
|
41
|
+
"rationale",
|
|
42
|
+
"expectation",
|
|
43
|
+
"automation",
|
|
44
|
+
"method"
|
|
45
|
+
],
|
|
46
|
+
"properties": {
|
|
47
|
+
"id": { "type": "string", "minLength": 1 },
|
|
48
|
+
"inventoryId": { "type": "string", "minLength": 1 },
|
|
49
|
+
"bucket": { "enum": ["missing", "wrongly-covered"] },
|
|
50
|
+
"title": { "type": "string", "minLength": 1 },
|
|
51
|
+
"priority": {
|
|
52
|
+
"enum": ["bug-catching", "edge", "basic"],
|
|
53
|
+
"description": "bug-catching: would catch a failure users hit; edge: a boundary or error path; basic: the happy path."
|
|
54
|
+
},
|
|
55
|
+
"rationale": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"minLength": 1,
|
|
58
|
+
"description": "Why the business cares."
|
|
59
|
+
},
|
|
60
|
+
"expectation": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"minLength": 1,
|
|
63
|
+
"description": "What the test asserts, measurable."
|
|
64
|
+
},
|
|
65
|
+
"automation": { "enum": ["yes", "no", "needs-code"] },
|
|
66
|
+
"method": {
|
|
67
|
+
"enum": ["exact", "inferred"],
|
|
68
|
+
"description": "exact: matched by identifier; inferred: the analyst's judgement, kept apart."
|
|
69
|
+
},
|
|
70
|
+
"evidence": { "type": "array", "items": { "$ref": "#/$defs/fileLine" } },
|
|
71
|
+
"handlesNeeded": {
|
|
72
|
+
"type": "array",
|
|
73
|
+
"items": {
|
|
74
|
+
"type": "object",
|
|
75
|
+
"additionalProperties": false,
|
|
76
|
+
"required": ["target", "suggestion"],
|
|
77
|
+
"properties": {
|
|
78
|
+
"target": { "type": "string", "minLength": 1 },
|
|
79
|
+
"suggestion": { "type": "string", "minLength": 1 }
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"dataNeeds": {
|
|
87
|
+
"type": "array",
|
|
88
|
+
"items": {
|
|
89
|
+
"type": "object",
|
|
90
|
+
"additionalProperties": false,
|
|
91
|
+
"required": ["id", "gapIds", "what", "kind"],
|
|
92
|
+
"properties": {
|
|
93
|
+
"id": { "type": "string", "minLength": 1 },
|
|
94
|
+
"gapIds": {
|
|
95
|
+
"type": "array",
|
|
96
|
+
"minItems": 1,
|
|
97
|
+
"items": { "type": "string", "minLength": 1 }
|
|
98
|
+
},
|
|
99
|
+
"what": { "type": "string", "minLength": 1 },
|
|
100
|
+
"kind": { "enum": ["account", "seed", "fixture", "secret", "other"] },
|
|
101
|
+
"secretRef": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"minLength": 1,
|
|
104
|
+
"description": "Credential name a test resolves at run time; never the value."
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"unmeasured": {
|
|
110
|
+
"type": "array",
|
|
111
|
+
"items": {
|
|
112
|
+
"type": "object",
|
|
113
|
+
"additionalProperties": false,
|
|
114
|
+
"required": ["reason"],
|
|
115
|
+
"properties": {
|
|
116
|
+
"inventoryId": { "type": "string", "minLength": 1 },
|
|
117
|
+
"reason": { "type": "string", "minLength": 1 }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/mmerterden/multi-agent-pipeline/pipeline/schemas/test-gen-inventory.schema.json",
|
|
4
|
+
"title": "Multi-Agent Pipeline - test-gen inventory",
|
|
5
|
+
"description": "What the app has that a test could cover, written by the inventory stage of /multi-agent:test-gen as $RUN/inventory.json (multi-agent-refs/test-gen/stages.md). Items are joined to tests by their stable id (route, screen id, Figma node id, endpoint path), never by title. `priority` is added after the inventory, from the user's pick or, in autopilot, the top three. test-gen-gate.mjs check --stage inventory checks this shape without a dependency.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["schemaVersion", "platform", "source", "items"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"schemaVersion": { "const": "1.0.0" },
|
|
11
|
+
"platform": { "enum": ["ios", "android", "web", "api"] },
|
|
12
|
+
"repo": { "type": "string", "minLength": 1 },
|
|
13
|
+
"source": {
|
|
14
|
+
"enum": ["design_scenario_inventory", "web_map", "ui_tree", "openapi", "agent"],
|
|
15
|
+
"description": "Where the items came from. `agent` is the stage's own reading of the code, used when no tool answered."
|
|
16
|
+
},
|
|
17
|
+
"generatedAt": { "type": "string", "format": "date-time" },
|
|
18
|
+
"items": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"minItems": 1,
|
|
21
|
+
"items": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"additionalProperties": false,
|
|
24
|
+
"required": ["id", "kind", "title"],
|
|
25
|
+
"properties": {
|
|
26
|
+
"id": { "type": "string", "minLength": 1, "description": "Stable identifier." },
|
|
27
|
+
"kind": { "enum": ["screen", "flow", "endpoint", "component"] },
|
|
28
|
+
"title": { "type": "string", "minLength": 1 },
|
|
29
|
+
"path": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"minLength": 1,
|
|
32
|
+
"description": "Code path that implements it, file or directory."
|
|
33
|
+
},
|
|
34
|
+
"handles": {
|
|
35
|
+
"type": "array",
|
|
36
|
+
"items": { "type": "string", "minLength": 1 },
|
|
37
|
+
"description": "Automation handles already on it (accessibilityIdentifier, testTag, data-testid)."
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"priority": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"additionalProperties": false,
|
|
45
|
+
"required": ["mode", "selected"],
|
|
46
|
+
"properties": {
|
|
47
|
+
"mode": {
|
|
48
|
+
"enum": ["user", "autopilot-top3"],
|
|
49
|
+
"description": "user: picked by the person; autopilot-top3: the three the run proceeded with unattended."
|
|
50
|
+
},
|
|
51
|
+
"selected": {
|
|
52
|
+
"type": "array",
|
|
53
|
+
"minItems": 1,
|
|
54
|
+
"items": { "type": "string", "minLength": 1 }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/mmerterden/multi-agent-pipeline/pipeline/schemas/test-gen-results.schema.json",
|
|
4
|
+
"title": "Multi-Agent Pipeline - test-gen results",
|
|
5
|
+
"description": "The outcome of the tests /multi-agent:test-gen wrote, $RUN/results.json, built by test-gen-gate.mjs results from the classify stage (multi-agent-refs/features/test-classification.md). Three states: pass, fail, not_measured; anything but pass carries its reason. `classification` keeps the measured class behind the state (an unstable test is a fail, a test with no base is not_measured), and `triage` the result-triage verdict once one is made. test-gen-gate.mjs check --stage results checks this shape without a dependency.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["schemaVersion", "source", "green", "tests", "summary"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"schemaVersion": { "const": "1.0.0" },
|
|
11
|
+
"source": { "enum": ["toolkit", "fallback"] },
|
|
12
|
+
"green": { "type": "boolean" },
|
|
13
|
+
"tests": {
|
|
14
|
+
"type": "array",
|
|
15
|
+
"items": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"additionalProperties": false,
|
|
18
|
+
"required": ["id", "status"],
|
|
19
|
+
"properties": {
|
|
20
|
+
"id": { "type": "string", "minLength": 1 },
|
|
21
|
+
"file": { "type": "string", "minLength": 1 },
|
|
22
|
+
"status": { "enum": ["pass", "fail", "not_measured"] },
|
|
23
|
+
"classification": {
|
|
24
|
+
"enum": ["passed", "regression", "preexisting", "unstable", "not_measured"]
|
|
25
|
+
},
|
|
26
|
+
"reason": { "type": "string", "minLength": 1 },
|
|
27
|
+
"triage": { "enum": ["product-bug", "stale-test", "new-scenario", "valid", "ambiguous"] }
|
|
28
|
+
},
|
|
29
|
+
"if": { "properties": { "status": { "enum": ["fail", "not_measured"] } } },
|
|
30
|
+
"then": { "required": ["reason"] }
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"summary": {
|
|
34
|
+
"type": "object",
|
|
35
|
+
"additionalProperties": false,
|
|
36
|
+
"required": ["pass", "fail", "not_measured"],
|
|
37
|
+
"properties": {
|
|
38
|
+
"pass": { "type": "integer", "minimum": 0 },
|
|
39
|
+
"fail": { "type": "integer", "minimum": 0 },
|
|
40
|
+
"not_measured": { "type": "integer", "minimum": 0 }
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|