@mmerterden/multi-agent-pipeline 20.27.1 → 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 +38 -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 +74 -51
- 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/store-ready/gate-3-policy.md +6 -2
- package/pipeline/multi-agent-refs/test-gen/stages.md +227 -0
- package/pipeline/preferences-template.json +3 -0
- package/pipeline/rules/app-store-guidelines.md +29 -41
- 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 +25 -5
- package/pipeline/skills/.skills-index.json +57 -2
- package/pipeline/skills/shared/README.md +11 -6
- package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +5 -4
- package/pipeline/skills/shared/core/apple-archive-compliance/references/rules.yml +8 -8
- 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/app-store-review/SKILL.md +69 -8
- package/pipeline/skills/shared/external/app-store-review/evals/evals.json +12 -0
- package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +10 -1
- 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,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Write the tests an app lacks, stage by stage, each gated on its artefact: inventory, read-only gap analysis, handles, tests, runs, per-test classification. Use when screens, flows or a change need tests."
|
|
3
|
+
description-tr: "Uygulamada eksik olan testleri üretir: envanter, salt-okunur keşif ve eksik analizi, otomasyon tutamakları, test yazımı, tekrarlı koşum ve test başına sınıflama; her aşama kendi artefaktıyla kapılanan bir subagent'tır. Ekranlar, akışlar ya da son değişiklik için test yazılması gerektiğinde kullan."
|
|
4
|
+
allowed-tools: Agent, Bash, Read, Write, Edit, Grep, Glob, AskUserQuestion, TaskCreate, TaskUpdate, TaskList
|
|
5
|
+
argument-hint: "[scope] [--platform ios|android|web] [--repo <path>] - scope: a screen, route or flow, or empty for what changed since the last test-gen run"
|
|
6
|
+
parameters: [{"name":"scope","kind":"text"},{"name":"--platform","kind":"enum","enum":["ios","android","web"]},{"name":"--repo","kind":"path"}]
|
|
7
|
+
gui: form
|
|
8
|
+
destructive: false
|
|
9
|
+
confirm: none
|
|
10
|
+
not-for: test, bug-bash, scenario-audit, manual-test
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# multi-agent test-gen
|
|
14
|
+
|
|
15
|
+
**Input**: $ARGUMENTS
|
|
16
|
+
|
|
17
|
+
Writes the tests an app is missing, in the repo's own frameworks, and reports
|
|
18
|
+
what they found. Seven stages run as subagents, each leaving one artefact that a
|
|
19
|
+
script gates before the next stage starts: inventory, discovery, gaps, handles,
|
|
20
|
+
write, run, classify. The two analysis stages run as a read-only agent type, so
|
|
21
|
+
nothing they do can change the repository.
|
|
22
|
+
|
|
23
|
+
Stage contract, read before Step 1:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
$HOME/.claude/multi-agent-refs/test-gen/stages.md
|
|
27
|
+
$HOME/.claude/multi-agent-refs/features/test-classification.md
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Scripts: `test-gen-gate.mjs` (artefact, handle and write gates),
|
|
31
|
+
`handle-diff-audit.mjs` (handles only), `test-classify.mjs`,
|
|
32
|
+
`test-gen-state.mjs` (change base, revision cap), `evidence-gate.mjs`, all under
|
|
33
|
+
`$HOME/.claude/scripts/`. Schemas: `test-gen-inventory`, `test-gen-gaps`,
|
|
34
|
+
`test-gen-results` under `$HOME/.claude/schemas/`.
|
|
35
|
+
|
|
36
|
+
> **Pickers follow** `$HOME/.claude/multi-agent-refs/picker-contract.md`: never a one-option call, and branch on the option selected, not on its text.
|
|
37
|
+
|
|
38
|
+
## Gotchas
|
|
39
|
+
|
|
40
|
+
- An analysis stage that wants to "just fix" something is out of its lane. Discovery and gaps go to `test-gen-analyst`, whose grant is an allowlist of read-only tools.
|
|
41
|
+
- The handle stage adds handles and nothing else. A wrapped view, a renamed element or a changed condition fails `handle-diff-audit.mjs`; revert the hunk, do not argue with the audit.
|
|
42
|
+
- `HANDLES: none-needed` is a claim that the handles exist. It needs the `file:line` of each.
|
|
43
|
+
- A test that passed once is not green. Unstable is a fail, and a red test with no base to compare is `not_measured`, not a regression.
|
|
44
|
+
- Test data is named in `dataNeeds[]`, never filled in by the run. A credential is a `secretRef`.
|
|
45
|
+
- A product bug is reported, never fixed here. In autopilot it parks the run.
|
|
46
|
+
|
|
47
|
+
## Step 1 - Prepare
|
|
48
|
+
|
|
49
|
+
1. Repo: `--repo`, else the current directory; confirm it in one line.
|
|
50
|
+
Platform: `--platform`, else detect as `/multi-agent:test` does. Run id
|
|
51
|
+
`tg-<timestamp>`; `RUN="$HOME/.claude/logs/test-gen/<repo>/<timestamp>"`,
|
|
52
|
+
created with `mkdir -p "$RUN"`.
|
|
53
|
+
2. Toolkit: `test_results_classify`, `coverage_gap` and `ui_locator_codegen`
|
|
54
|
+
need `@mmerterden/multi-agent-toolkit-mcp` >= v3.25.0. Check the tool list
|
|
55
|
+
once. Each missing tool has a fallback in `stages.md` (classify from the
|
|
56
|
+
repeats, the analyst matches coverage itself with every match `inferred`,
|
|
57
|
+
locators written by hand from the handles); say which fallbacks are in use,
|
|
58
|
+
once.
|
|
59
|
+
3. Change base. `TG_STATE="$HOME/.claude/knowledge/<project>/test-gen-state.json"`:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
node "$HOME/.claude/scripts/test-gen-state.mjs" base-scan --state "$TG_STATE" --repo "$REPO" \
|
|
63
|
+
--graph "$HOME/.claude/knowledge/<project>/code-graph.json" > "$RUN/base-scan.json"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Exit 0: the changed files and their dependents narrow an empty scope. Exit 1
|
|
67
|
+
(`measured: false`, first run or base gone): nothing is narrowed, and the
|
|
68
|
+
reason goes in the report.
|
|
69
|
+
|
|
70
|
+
## Step 2 - Inventory and priority
|
|
71
|
+
|
|
72
|
+
Stage 1 of `stages.md`, then the priority pick: ask which items to cover
|
|
73
|
+
(autopilot: the top three, recorded as `autopilot-top3`). Gate:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
node "$HOME/.claude/scripts/test-gen-gate.mjs" check --stage inventory --file "$RUN/inventory.json"
|
|
77
|
+
node "$HOME/.claude/scripts/evidence-gate.mjs" --claim artefact --status passed \
|
|
78
|
+
--evidence "$RUN/inventory.json" --stage-start "$STAGE_START"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Step 3 - Discovery and gaps (read-only)
|
|
82
|
+
|
|
83
|
+
Stages 2 and 3, both with `subagent_type: "test-gen-analyst"`. Write each answer
|
|
84
|
+
with the Write tool, then gate each file with `evidence-gate.mjs --claim
|
|
85
|
+
artefact` against its own stage start, and each with `test-gen-gate.mjs check`
|
|
86
|
+
(`--stage discovery`, `--stage gaps`). Show the gaps (bucket, priority,
|
|
87
|
+
expectation) and the `dataNeeds[]`; ask for the data or the credential names
|
|
88
|
+
(autopilot: write only the scenarios whose needs are met).
|
|
89
|
+
|
|
90
|
+
## Step 4 - Handles
|
|
91
|
+
|
|
92
|
+
Stage 4. Snapshot first (`test-gen-gate.mjs baseline`), then the subagent, then
|
|
93
|
+
both gates against that snapshot: `test-gen-gate.mjs handles` and
|
|
94
|
+
`handle-diff-audit.mjs --baseline` exit 0. The gates read only the stage's own
|
|
95
|
+
change; the person's uncommitted work is never the stage's to revert. Skip the
|
|
96
|
+
stage when no gap has `handlesNeeded`, and say so.
|
|
97
|
+
|
|
98
|
+
## Step 5 - Write, run, classify
|
|
99
|
+
|
|
100
|
+
Stages 5 to 7: a new snapshot, the tests and `written.json`, the
|
|
101
|
+
`test-gen-gate.mjs written --baseline` gate (test files only, inside the repo
|
|
102
|
+
and changed by the stage, no test gaming, a discovered runner, more than zero
|
|
103
|
+
tests run), the repeated runs, then
|
|
104
|
+
`results.json` through `test-classify.mjs` and `test-gen-gate.mjs results`.
|
|
105
|
+
|
|
106
|
+
## Step 6 - Triage
|
|
107
|
+
|
|
108
|
+
Stage 8, one verdict per non-pass result, each through `test-gen-state.mjs
|
|
109
|
+
revise`. Exit 3 parks the run: stop, keep every artefact, report why, and record
|
|
110
|
+
no change base, because the run did not finish.
|
|
111
|
+
|
|
112
|
+
## Step 7 - Report and base
|
|
113
|
+
|
|
114
|
+
Print, in this order: the tests written (file, scenario, expectation), the
|
|
115
|
+
results table from `results.json` with every `fail` and `not_measured` reason,
|
|
116
|
+
the triage verdicts, the handles added (`handles.md`), the scenarios blocked by
|
|
117
|
+
data, and `gaps.json`'s `unmeasured[]`. State which parts are mechanical (the
|
|
118
|
+
gates, the classification, the handle audit) and which are judgement (the
|
|
119
|
+
inventory, the gaps, the triage). Then record the change base
|
|
120
|
+
(`test-gen-state.mjs base-record`).
|
|
121
|
+
|
|
122
|
+
Offer, one question: open the product bugs through `/multi-agent` with each
|
|
123
|
+
failing test as the acceptance check, or stop. **No commit, no push, no issue
|
|
124
|
+
from this command.**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Cross-CLI Contract (Claude Code · Copilot CLI · Codex CLI)
|
|
2
2
|
|
|
3
3
|
<!-- toc -->
|
|
4
|
-
- [1. Command Inventory (
|
|
4
|
+
- [1. Command Inventory (66 commands)](#1-command-inventory-66-commands)
|
|
5
5
|
- [2. Canonical Placeholder Vocabulary](#2-canonical-placeholder-vocabulary)
|
|
6
6
|
- [2.6 Intentional structural divergence - thin dispatcher vs inlined orchestrator](#26-intentional-structural-divergence---thin-dispatcher-vs-inlined-orchestrator)
|
|
7
7
|
- [2.7 One command, three different meanings: `/multi-agent:model`](#27-one-command-three-different-meanings-multi-agentmodel)
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
## 1. Command Inventory (
|
|
23
|
+
## 1. Command Inventory (66 commands)
|
|
24
24
|
|
|
25
25
|
```
|
|
26
26
|
analysis, analysis-jira, analysis-resolve, autopilot, autopilot-off,
|
|
@@ -32,7 +32,7 @@ prune-prompts, purge, refactor, research, resume, review,
|
|
|
32
32
|
review-analysis, review-issue, review-jira, route-off, route-on,
|
|
33
33
|
route-status, routines, save, scaffold, scan, scenario-audit, search,
|
|
34
34
|
security-review, serve, setup, stack, status, steer, store-ready, sync, test, test-accessibility,
|
|
35
|
-
test-dark-mode, test-dynamic-type, test-screenshots, testflight-validation,
|
|
35
|
+
test-dark-mode, test-dynamic-type, test-gen, test-screenshots, testflight-validation,
|
|
36
36
|
uninstall, update
|
|
37
37
|
```
|
|
38
38
|
|
|
@@ -42,7 +42,7 @@ Categories:
|
|
|
42
42
|
- **Issue generator** (one-shot, no worktree, asks type Task/Bug/Story, hard approval gate before create): `create-jira`
|
|
43
43
|
- **Pipeline entries**: `autopilot` (plus the bare `/multi-agent` in the dispatcher). The phase set is a property of the command, and every mode runs its whole set.
|
|
44
44
|
- **Tail path** (the pipeline tail over work already on a branch, no run behind it): `resume`
|
|
45
|
-
- **Ops commands** (one-shot, no worktree): `status`, `log`, `kill`, `steer`, `purge`, `uninstall`, `resume`, `review`, `review-jira`, `review-issue`, `analysis`, `analysis-resolve`, `research`, `scaffold`, `complaint-analysis`, `bug-bash`, `build-optimize`, `channels`, `scan`, `search`, `diff-explain`, `garbage-collect`, `graph`, `postmortem`, `prune-logs`, `prune-prompts`, `serve`
|
|
45
|
+
- **Ops commands** (one-shot, no worktree): `status`, `log`, `kill`, `steer`, `purge`, `uninstall`, `resume`, `review`, `review-jira`, `review-issue`, `analysis`, `analysis-resolve`, `research`, `scaffold`, `complaint-analysis`, `bug-bash`, `test-gen`, `build-optimize`, `channels`, `scan`, `search`, `diff-explain`, `garbage-collect`, `graph`, `postmortem`, `prune-logs`, `prune-prompts`, `serve`
|
|
46
46
|
- **Local audits** (worktree only to build; no commit, push, PR or channels): `design-check`, `testflight-validation`, `ios-coding-standard`. `testflight-validation` additionally never invokes `altool --upload-app` - a validation run must not be able to ship a build by accident.
|
|
47
47
|
- **Meta-ops**: `setup`, `sync`, `update`, `help`, `refactor`, `test`, `stack`, `manual-test`, `language`
|
|
48
48
|
- **Routines** (user-defined routine registry; the routines they create are local-only and never synced): `save`, `routines`, `forget`
|
|
@@ -102,7 +102,10 @@ Superseded by section 1.1: Claude Code resolves component dispatch to the market
|
|
|
102
102
|
`e2e-testing` knowledge skill (ai-common-toolkit) call these toolkit tools when
|
|
103
103
|
the server has them, and fall back to UI-tree reads and frame-centre taps when
|
|
104
104
|
it does not. Contracts: `features/exploratory-testing.md`,
|
|
105
|
-
`features/assertion-judge.md`.
|
|
105
|
+
`features/assertion-judge.md`. `/multi-agent:test-gen` and the Phase 2 exit
|
|
106
|
+
gate use the three v3.25.0 tools below; each consumer checks the server's tool
|
|
107
|
+
list once and names the fallback it takes (`test-gen/stages.md`,
|
|
108
|
+
`features/test-classification.md`).
|
|
106
109
|
|
|
107
110
|
| Capability | Tools / fields | Minimum |
|
|
108
111
|
|---|---|---|
|
|
@@ -118,6 +121,9 @@ it does not. Contracts: `features/exploratory-testing.md`,
|
|
|
118
121
|
| Free-model delegation | `llm_delegate`, `llm_providers`; `ESCALATE_TO_CLAUDE`; the `multi-agent-toolkit-llm` CLI (`delegate`, `providers`, `probe`, `usage`) | ≥ v3.21.0 |
|
|
119
122
|
| Related repositories | `repo_resolve`, `repo_grep`, `repo_read`, `repo_ls`, `repo_log`, `repo_find_keys`; `stale`, `not_found_at_sha` (`features/product-context.md`) | ≥ v3.22.1 |
|
|
120
123
|
| Language-server answers over MCP | `code_references`, `code_definition`, `code_document_symbols`, `code_index_status` as JSON with structured content; `graph-confirm.mjs` reads them (`features/code-graph.md`) | ≥ v3.22.2 |
|
|
124
|
+
| Per-test classification | `test_results_classify` `{head, base?, confirm?, flake_ledger?, format?, now?}` -> `tests[]` of `passed / regression / preexisting / unstable / not_measured` with `reason`, `summary`, `breaker?`; `test-classify.mjs merge` reads it (Phase 2 Gate 3, `/multi-agent:test-gen`; `features/test-classification.md`). Without it: `test-classify.mjs fallback` over the repeat runs | ≥ v3.25.0 |
|
|
125
|
+
| Coverage by identifier | `coverage_gap` `{inventory, test_root}` -> `covered / uncovered / unmatched`, each entry `method: exact / inferred` (`/multi-agent:test-gen` gap stage). Without it: the analyst matches, every match `inferred` | ≥ v3.25.0 |
|
|
126
|
+
| Mobile locator code | `ui_locator_codegen` `{platform: ios / android, node}` -> `{code}` or `{code: null, error: "NO_HANDLE", suggestion}` (`/multi-agent:test-gen` write stage). Without it: locators written from the handles by hand | ≥ v3.25.0 |
|
|
121
127
|
|
|
122
128
|
---
|
|
123
129
|
|
|
@@ -303,6 +303,19 @@ other outcome (`redirected`, `rejected`, `not-accepted`, `failed`, `skipped`),
|
|
|
303
303
|
with the status code or reason and the step that fixes it. The emitter runs
|
|
304
304
|
detached from phase-tracker with its output discarded, so this record is the
|
|
305
305
|
only surface on which a reporting path that stopped working shows up.
|
|
306
|
+
|
|
307
|
+
### usage-register
|
|
308
|
+
|
|
309
|
+
The outcome `usage-register.mjs` recorded for its last attempt, read from
|
|
310
|
+
`logs/multi-agent/usage-last-register.json`, and whether the failure report
|
|
311
|
+
that attempt may have sent reached the site (`usage-register-beacon.json`).
|
|
312
|
+
SKIP when `usageLog.optOut` is set or nothing was attempted yet; OK after a
|
|
313
|
+
registration or when a token is already onboarded; WARN for every other
|
|
314
|
+
outcome, naming the status, its detail and either "the failure report
|
|
315
|
+
(<reason>) reached the site", "could not be delivered" or "no failure report
|
|
316
|
+
was sent" (no login, a dry run, or a refusal the person chose). Registration
|
|
317
|
+
runs quietly from setup, update and Phase 0, so this is where a machine that
|
|
318
|
+
never registers shows why.
|
|
306
319
|
### free-models
|
|
307
320
|
|
|
308
321
|
Can `route-on --free` actually leave Claude. SKIP while routing or its free
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Test result classification
|
|
2
|
+
|
|
3
|
+
A red test says something about the change only when the base was green and
|
|
4
|
+
the test stayed red when run again. This step measures that per test instead of
|
|
5
|
+
reading one run's exit code, and the gates act on the measured class.
|
|
6
|
+
|
|
7
|
+
Used at the Phase 2 exit gate (Gate 3), on the Phase 3 rework re-entry, and by
|
|
8
|
+
the classify stage of `/multi-agent:test-gen`.
|
|
9
|
+
|
|
10
|
+
## Classes
|
|
11
|
+
|
|
12
|
+
| Class | Means | Gate |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `passed` | green | pass |
|
|
15
|
+
| `regression` | green on the base, red in two runs of the head | blocks: fix it |
|
|
16
|
+
| `preexisting` | red on the base too, or listed failing in the Phase 0 baseline | inherited: does not block, is reported |
|
|
17
|
+
| `unstable` | runs disagree, or the test was unstable in two or more separate runs over the last 7 days | blocks: never green. Log `test.flake_signal` and fix the test or the code |
|
|
18
|
+
| `not_measured` | no base to compare, or a setup failure before the test ran; carries a `reason` | blocks: stays red, the reason is reported |
|
|
19
|
+
|
|
20
|
+
## Inputs
|
|
21
|
+
|
|
22
|
+
| Input | Source |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `head` | the Gate 3 run's report: JUnit XML, the xcresult bundle, or Playwright JSON. UI tests: `UI_TEST_RESULT` from `run-ui-tests.sh run` (`UI_TEST_RESULT_FORMAT` names the format) |
|
|
25
|
+
| `confirm` | a second run of the red tests: one of the `testStability.repeatCount` repeats Phase 2 already ran |
|
|
26
|
+
| `base` | the Phase 0 baseline's report when it captured one (`state.baseline.tests.logPath`) |
|
|
27
|
+
| `flake_ledger` | `$HOME/.claude/knowledge/<project>/flake-ledger.jsonl`, the project's history of measured unstable results. The toolkit counts only runs that turned green on confirm, never its own earlier `unstable` verdicts, so one flaky result cannot exempt a test for good |
|
|
28
|
+
|
|
29
|
+
## With the toolkit (`test_results_classify`)
|
|
30
|
+
|
|
31
|
+
Needs `@mmerterden/multi-agent-toolkit-mcp` >= v3.25.0. When the tool is
|
|
32
|
+
listed, call `mcp__multi-agent-toolkit__test_results_classify` with
|
|
33
|
+
`{head, base, confirm, flake_ledger, format}`, save its answer with the Write
|
|
34
|
+
tool as `$WORKTREE/.pipeline/test-classified.json`, then:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
node $HOME/.claude/scripts/test-classify.mjs merge \
|
|
38
|
+
--classified "$WORKTREE/.pipeline/test-classified.json" \
|
|
39
|
+
--state "$STATE_FILE" --out "$WORKTREE/.pipeline/test-classification.json"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`merge` applies the pipeline's rules on top of the toolkit's answer: `unstable`
|
|
43
|
+
is never green; the Phase 0 baseline joins the preexisting set (a listed test the
|
|
44
|
+
toolkit could not measure becomes `preexisting`; a listed test the toolkit calls
|
|
45
|
+
a `regression` becomes `unstable`, because the base disagreed with itself); a
|
|
46
|
+
tripped breaker is not green; nothing classified is not green.
|
|
47
|
+
|
|
48
|
+
## Without it (older toolkit, or no server)
|
|
49
|
+
|
|
50
|
+
Say so once in the run log. When the repeats wrote JUnit XML, classify from them
|
|
51
|
+
alone:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
node $HOME/.claude/scripts/test-classify.mjs fallback \
|
|
55
|
+
--run "$WORKTREE/.pipeline/repeat-1.junit.xml" --run "$WORKTREE/.pipeline/repeat-2.junit.xml" \
|
|
56
|
+
--state "$STATE_FILE" --out "$WORKTREE/.pipeline/test-classification.json"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Runs that disagree, and a run that saw one test both fail and pass (a retry,
|
|
60
|
+
reports from several devices), are `unstable`; red in every run is `not_measured` (there is
|
|
61
|
+
no base run), green in every run is `passed`. With no per-test report at all
|
|
62
|
+
(an xcodebuild log only), Gate 3 keeps its log-and-baseline rule and logs
|
|
63
|
+
`test.classify_skipped reason=<why>`.
|
|
64
|
+
|
|
65
|
+
## Verdict
|
|
66
|
+
|
|
67
|
+
| Exit | Gate 3 |
|
|
68
|
+
|---|---|
|
|
69
|
+
| 0 | pass. `inherited[]` is what the "red + `failing[]`" row subtracts; log `test:pass (inherited {N})` when it is not empty |
|
|
70
|
+
| 1 | fail. `blocking[]` names the tests and `tests[].reason` says why. A tripped `breaker` is one environment failure seen across most runs: report its signature; autopilot parks the run as `verification-failed` rather than reworking code that is not at fault |
|
|
71
|
+
| 2 | call error, never a pass |
|
|
72
|
+
| 3 | the classification could not be read: Gate 3 keeps its log-and-baseline rule, and the reason is logged |
|
|
73
|
+
| 4 | the script crashed: a defect to report, never a red verdict; Gate 3 keeps its log-and-baseline rule |
|
|
74
|
+
|
|
75
|
+
Script: `scripts/test-classify.mjs`. The toolkit tool and its minimum version
|
|
76
|
+
are listed with the other end-to-end testing tools in the cross-CLI contract.
|
|
@@ -268,6 +268,23 @@ WARN with one step. `migrate-prefs.mjs` rewrites an endpoint on the platform
|
|
|
268
268
|
host to the site's domain, so a stored redirecting endpoint does not outlive an
|
|
269
269
|
update.
|
|
270
270
|
|
|
271
|
+
A registration that ends `unavailable` also sends one failure report, detached
|
|
272
|
+
so it never delays or fails the caller (`usage-register-beacon.mjs`): `POST
|
|
273
|
+
<register URL>/failure` with `{ u, v, reason, os }` and nothing else, no token
|
|
274
|
+
and no header beyond Content-Type. `u` is the login this run had (proven or
|
|
275
|
+
declared; with no login nothing is sent), `v` the installed version, `reason`
|
|
276
|
+
one word from a fixed list (`endpoint-unreachable`, `tls-untrusted`,
|
|
277
|
+
`proxy-refused`, `timeout`, `redirected`, `not-collaborator`,
|
|
278
|
+
`gh-account-mismatch`, `proof-rejected`, `proof-required`, `no-proof`,
|
|
279
|
+
`rate-limited`, `server-error`, `credential-store`, `prefs-write`, `other`) and
|
|
280
|
+
`os` darwin. It is never sent for an opted-out machine (feedback runs
|
|
281
|
+
included), on a dry run, for a decline, or to a register URL the login proof
|
|
282
|
+
may not go to. Each (reason, version) goes at most once a day; one that was not
|
|
283
|
+
delivered is tried again on the next failed registration. The state is
|
|
284
|
+
`~/.claude/logs/multi-agent/usage-register-beacon.json`, and doctor's
|
|
285
|
+
`usage-register` check reads it next to `usage-last-register.json`. The server
|
|
286
|
+
keeps the report only for the owner or a collaborator of the access repository.
|
|
287
|
+
|
|
271
288
|
`prefs.global.usageLog.endpoint` overrides where both calls go - the register URL
|
|
272
289
|
is derived from it, so a self-hosted ingest gets its own registration rather than
|
|
273
290
|
this one's. Absent means the shipped default, and every shipped default names the
|
|
@@ -188,6 +188,7 @@ UI Testing (standalone - not part of pipeline phases):
|
|
|
188
188
|
/multi-agent:test "store-ready" [path] tag still works and hands off there.
|
|
189
189
|
|
|
190
190
|
/multi-agent:bug-bash [scope] Parallel exploratory sessions by charter and persona, each with a budget; a finding is reported only when a repro test fails for its reason
|
|
191
|
+
/multi-agent:test-gen [scope] Writes the tests an app lacks: inventory, read-only discovery and gap analysis, handles, tests, repeated runs, per-test classification; each stage gated on its artefact
|
|
191
192
|
|
|
192
193
|
Uses xcrun simctl / adb (native, no external app needed).
|
|
193
194
|
Booted simulator/emulator required. Auto-detects bundle ID from project.
|
|
@@ -187,6 +187,7 @@ UI Testing (standalone - pipeline fazlarından bağımsız):
|
|
|
187
187
|
/multi-agent:test "store-ready" [path] etiketi çalışır ve oraya devreder.
|
|
188
188
|
|
|
189
189
|
/multi-agent:bug-bash [kapsam] Charter ve persona başına bütçeli paralel keşif oturumları; bulgu, sebebiyle fail olan bir repro testi varsa raporlanır
|
|
190
|
+
/multi-agent:test-gen [kapsam] Eksik testleri yazar: envanter, salt-okunur keşif ve eksik analizi, tutamaklar, testler, tekrarlı koşum, test başına sınıflama; her aşama artefaktıyla kapılanır
|
|
190
191
|
|
|
191
192
|
xcrun simctl / adb kullanır (harici app gerekmez).
|
|
192
193
|
Booted simulator/emulator şart. Bundle ID proje'den otomatik algılanır.
|
|
@@ -143,13 +143,13 @@ that) is the last-resort ceiling for a PID that has been recycled.
|
|
|
143
143
|
**Halt visibility (required, autopilot included).** A halt is never silent. Whenever a phase halts on a hard error (validator failed twice, no subagent returned, dispatch error past fallback, lock irrecoverable), in addition to the `agent-log.md` line: (a) write `state.status = "paused"` and `state.haltReason = "<phase>:<cause>"`; (b) record the cause on the tracker via `phase-tracker.sh meta <phase> halt "<cause>"` and `phase-tracker.sh update <phase> failed`; (c) emit one `>&2` alert line `HALT phase <N>: <cause> - resume with /multi-agent:resume #<id>`; (d) if `prefs.global.usageLog.enabled` is true, emit the end-of-run report so a run that never reaches Phase 5 is still recorded with the phase it stopped at (`state.currentPhase` + `haltReason`) - the emitter no-ops when it is off or unconfigured:
|
|
144
144
|
|
|
145
145
|
```bash
|
|
146
|
-
node $HOME/.claude/scripts/usage-report.mjs --
|
|
146
|
+
node $HOME/.claude/scripts/usage-report.mjs --task-id "$TASK_ID" --event halted >/dev/null 2>&1 || true
|
|
147
147
|
```
|
|
148
148
|
|
|
149
149
|
**Park visibility.** A run that stops to wait for a person (`state.status = "awaiting_input"`, or `state.waitingFor` set: a maturity decision, an open question, the channels choice) emits the same report with `--event parked` right after the state write, so the panel shows it as waiting rather than abandoned:
|
|
150
150
|
|
|
151
151
|
```bash
|
|
152
|
-
node $HOME/.claude/scripts/usage-report.mjs --
|
|
152
|
+
node $HOME/.claude/scripts/usage-report.mjs --task-id "$TASK_ID" --event parked >/dev/null 2>&1 || true
|
|
153
153
|
```
|
|
154
154
|
|
|
155
155
|
Autopilot suppresses *confirmations*, not *halts* - the user must always be able to see why an unattended run stopped without reading the log. The endpoint upserts by run id, so this halt record and a later Phase 5 record (after resume) collapse into one.
|
|
@@ -156,7 +156,7 @@ For each task (respecting dependency order), on start and on end: `bash $HOME/.c
|
|
|
156
156
|
**REFACTOR (if needed):**
|
|
157
157
|
- Only if duplication or naming is poor
|
|
158
158
|
- Re-run tests after refactor → still GREEN
|
|
159
|
-
- **Stability (required):** run every test added or changed in this diff `prefs.global.testStability.repeatCount` times (default 3; 1 disables) with the single-test invocation above. Disagreeing outcomes are not GREEN: log `test.flake_signal file=<f> passed=<k> of=<N>` and fix the test or the code first.
|
|
159
|
+
- **Stability (required):** run every test added or changed in this diff `prefs.global.testStability.repeatCount` times (default 3; 1 disables) with the single-test invocation above. Disagreeing outcomes are not GREEN: log `test.flake_signal file=<f> passed=<k> of=<N>` and fix the test or the code first. Same rule on the Phase 3 rework re-entry. Keep each repeat's `.pipeline/repeat-<k>.junit.xml`.
|
|
160
160
|
|
|
161
161
|
**Target resolution** (auto-detect once per project, cache in `agent-state.json`; ios resolves scheme + simulator, android resolves module + variant, backend/web need none):
|
|
162
162
|
ios (prefer the scheme matching the project name, then the first non-test scheme):
|
|
@@ -393,8 +393,7 @@ Shared localization keys: reuse before minting (`features/localization-reuse.md`
|
|
|
393
393
|
## Exit gate: Verify (BLOCKING)
|
|
394
394
|
|
|
395
395
|
These deterministic gates run once, at this phase's exit, so the build runs once:
|
|
396
|
-
Review inherits the logs instead of regenerating them.
|
|
397
|
-
reach Review at all.
|
|
396
|
+
Review inherits the logs instead of regenerating them.
|
|
398
397
|
|
|
399
398
|
#### Step 1 - Deterministic Gates (run BEFORE AI review)
|
|
400
399
|
|
|
@@ -422,20 +421,20 @@ node $HOME/.claude/scripts/evidence-gate.mjs --claim test --status passed --evi
|
|
|
422
421
|
|
|
423
422
|
This prevents a false "it built" claim with no log behind it. On exit 1, treat the gate as failed (do NOT proceed to AI review) and surface the gate's `reason`.
|
|
424
423
|
|
|
425
|
-
**Autopilot runs** (`state.autopilot` or `MULTI_AGENT_UNATTENDED=1
|
|
424
|
+
**Autopilot runs** (`state.autopilot` or `MULTI_AGENT_UNATTENDED=1`) also run the stack-aware checks, each recording its verdict in `state.gates[]`: `evidence-gate.mjs --stack`, `test-summary.mjs` (zero tests executed parks the run as `verification-failed` instead of reworking), `test-strength.mjs --head worktree` and `symbol-existence-gate.mjs`. With the variable set, the Phase 4 commit hook refuses a commit whose ledger lacks them. Commands and verdicts: `$HOME/.claude/multi-agent-refs/features/unattended-gates.md` section 4.
|
|
426
425
|
|
|
427
426
|
**Scaffolded repo** (`.scaffold.json` at the worktree root): at this phase's entry and exit, `scaffold-gate.mjs --dir "$WORKTREE" --phase story --story <id>`; exit 1 or 3 halts and the next story does not start; 2 is a call error, never a pass (`$HOME/.claude/multi-agent-refs/features/scaffold.md`).
|
|
428
427
|
|
|
429
|
-
**Inherited failures (when `state.baseline.tests` exists).**
|
|
428
|
+
**Inherited failures (when `state.baseline.tests` exists).** Gate 3 blocks on what this work broke, not on what Phase 0 Step 7.6 found red:
|
|
430
429
|
|
|
431
430
|
| baseline status | Gate 3 |
|
|
432
431
|
|---|---|
|
|
433
432
|
| `green` | unchanged; every failure is this run's |
|
|
434
433
|
| `red` + `failing[]` | subtract those ids. Nothing left -> pass, logged `test:pass (inherited {N})`. A NEW failure still blocks. |
|
|
435
434
|
| `red`, empty `failing[]` | do NOT pass and do NOT silently block: report `test:inherited-red (not attributable, <logPath>)` and ask. Inventing a set here masks regressions. |
|
|
436
|
-
| `unknown` / absent | unchanged
|
|
435
|
+
| `unknown` / absent | unchanged |
|
|
437
436
|
|
|
438
|
-
The subtraction never widens:
|
|
437
|
+
The subtraction never widens: identifier matches only. Classify a per-test report first (`$HOME/.claude/multi-agent-refs/features/test-classification.md`); `unstable` is never green.
|
|
439
438
|
|
|
440
439
|
**Gate results:**
|
|
441
440
|
|
|
@@ -123,18 +123,18 @@ $HOME/.claude/scripts/log-metric.sh "$TASK_ID" 3 review.diff_risk \
|
|
|
123
123
|
|
|
124
124
|
#### Step 1.76 - Test-integrity gate (produces BLOCKING findings)
|
|
125
125
|
|
|
126
|
-
Step 1.75's `test_lines_removed` hint
|
|
126
|
+
Turns Step 1.75's `test_lines_removed` hint into blocking findings triage must adjudicate, and greps the diff for test gaming (`gaming.scanned: false` is not clean). `--out` always writes the file, even empty.
|
|
127
127
|
|
|
128
128
|
```bash
|
|
129
129
|
TI_FILE="$WORKTREE/.pipeline/test-integrity.json"
|
|
130
|
-
printf '%s' "$RISK_FULL" | node $HOME/.claude/scripts/test-integrity-gate.mjs --out "$TI_FILE" 2>/dev/null
|
|
130
|
+
printf '%s' "$RISK_FULL" | node $HOME/.claude/scripts/test-integrity-gate.mjs --diff-base "$BASE_BRANCH" --repo "$WORKTREE" --out "$TI_FILE" 2>/dev/null
|
|
131
131
|
TI_COUNT=$(jq -r '.count // 0' "$TI_FILE" 2>/dev/null || echo 0)
|
|
132
132
|
[ "$TI_COUNT" -gt 0 ] && $HOME/.claude/scripts/log-metric.sh "$TASK_ID" 3 review.test_integrity findings="$TI_COUNT"
|
|
133
133
|
```
|
|
134
134
|
|
|
135
135
|
`findings[]` are reviewer-shaped (`test_integrity`, `blocking`), so they merge into the reviewer findings at Step 3.0 and need no triage-prompt or `validate-triage.mjs` change. Triage keeps each blocking unless the removal is justified per the immutable-test rule (spec changed AND commit body names the test) → `deferred[]`.
|
|
136
136
|
|
|
137
|
-
The gate never blocks the phase; it *emits* blocking findings
|
|
137
|
+
The gate never blocks the phase; it *emits* blocking findings. Feed it the FULL report: `--top` hides files below the cut. **No opt-out**: a run that can switch off its own anti-reward-hacking control cannot be trusted to report a pass.
|
|
138
138
|
|
|
139
139
|
**TDD evidence**: `node $HOME/.claude/lib/tdd-evidence.mjs unverified --state "$STATE_FILE"` lists todos closed without RED/GREEN or by `--no-tests`, as reviewer notes, not findings.
|
|
140
140
|
|
|
@@ -211,21 +211,22 @@ $HOME/.claude/scripts/log-metric.sh "$TASK_ID" 5 task.completed \
|
|
|
211
211
|
duration_ms=$TOTAL_DURATION
|
|
212
212
|
```
|
|
213
213
|
|
|
214
|
-
**Operational reporting** (`features/usage-reporting.md`)
|
|
214
|
+
**Operational reporting** (`features/usage-reporting.md`): mark the run finished, then report it. Neither blocks:
|
|
215
215
|
|
|
216
216
|
```bash
|
|
217
|
+
STATE_FILE="${STATE_FILE:-$(node $HOME/.claude/scripts/usage-report.mjs --task-id "$TASK_ID" --print-state)}"
|
|
217
218
|
printf '{"status":"complete","currentPhase":5,"finishedAt":"%s"}' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
218
219
|
| node $HOME/.claude/scripts/write-state.mjs "$STATE_FILE" >/dev/null 2>&1 || true
|
|
219
|
-
node $HOME/.claude/scripts/usage-report.mjs --
|
|
220
|
+
node $HOME/.claude/scripts/usage-report.mjs --task-id "$TASK_ID" --event completed >/dev/null 2>&1 || true
|
|
220
221
|
```
|
|
221
222
|
|
|
222
223
|
Parked on the channels choice instead: emit `--event parked` and leave `status` alone.
|
|
223
224
|
|
|
224
|
-
**Aggregate before reporting**: run `aggregate-metrics.mjs --since=$(date -u -v-30d +%Y-%m-%d)` and embed output in agent-log.md. Use `--json` for Jira
|
|
225
|
+
**Aggregate before reporting**: run `aggregate-metrics.mjs --since=$(date -u -v-30d +%Y-%m-%d)` and embed output in agent-log.md. Use `--json` for Jira; missing files are skipped.
|
|
225
226
|
|
|
226
|
-
**Per-run outcome metrics (evidence corpus):** also emit `run-metrics.mjs --state <agent-state.json>` and append/persist its JSON. It records review iterations, first-pass-clean, reviewer signal-to-noise, consensus verdict and build outcome
|
|
227
|
+
**Per-run outcome metrics (evidence corpus):** also emit `run-metrics.mjs --state <agent-state.json>` and append/persist its JSON. It records review iterations, first-pass-clean, reviewer signal-to-noise, consensus verdict and build outcome.
|
|
227
228
|
|
|
228
|
-
**Cost Breakdown emission (
|
|
229
|
+
**Cost Breakdown emission (required):** as part of agent-log compose, append the per-task cost block produced by `render-agent-log-cost.sh`:
|
|
229
230
|
|
|
230
231
|
```bash
|
|
231
232
|
bash $HOME/.claude/scripts/render-agent-log-cost.sh "$TASK_ID" --append "$AGENT_LOG" 2>/dev/null
|
|
@@ -12,8 +12,12 @@ and gather the evidence below from repo source, not the binary.
|
|
|
12
12
|
| Tracking | if any tracking API or SDK is present, an ATT prompt exists and runs before collection |
|
|
13
13
|
| Account deletion | if the app creates accounts, an in-app deletion path exists (guideline 5.1.1(v)) |
|
|
14
14
|
| Privacy policy | reachable in-app and in the metadata |
|
|
15
|
-
| IAP | anything unlocking features goes through StoreKit
|
|
16
|
-
|
|
|
15
|
+
| IAP | anything unlocking features goes through StoreKit; an external purchase link needs a StoreKit External Purchase Link entitlement or, where permitted, a Music Streaming Services entitlement for that storefront, except on the US storefront (guideline 3.1.1(a)) |
|
|
16
|
+
| Login services | when a third-party or social login is offered, an equivalent privacy-focused option such as Sign in with Apple is offered too (guideline 4.8) |
|
|
17
|
+
| User-generated and AI content | if users post content, message each other, or generate content with AI: filtering, reporting, blocking, published contact, and a way to report and remove nonconsensual intimate imagery; an app used primarily for random or anonymous chat is a blocker however it moderates (guideline 1.2) |
|
|
18
|
+
| Hidden features | no feature switched on after review by remote config or a dormant code path that the review notes do not describe (guideline 2.5.19) |
|
|
19
|
+
| Upload floor | `IPHONEOS_DEPLOYMENT_TARGET` is 13.0 or later; the toolchain is Xcode 26+ (iOS 27 SDK from April 2027) |
|
|
20
|
+
| App Store Connect declarations | age rating questionnaire answered, including the social media capability questions; Health & Fitness or Medical apps carry the regulated medical device declaration. Not visible in the repo: report as a manual check |
|
|
17
21
|
| Crash symbolication | a dSYM upload step exists: an Xcode run-script calling `upload-symbols`, or a Crashlytics / Sentry / Datadog upload in CI |
|
|
18
22
|
|
|
19
23
|
## Android - `ai-android-toolkit:play-store-review`
|