@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.
Files changed (65) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +6 -5
  3. package/README.tr.md +6 -5
  4. package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +0 -1
  5. package/docs/architecture.md +4 -4
  6. package/docs/ecosystem.md +5 -5
  7. package/docs/facts.json +14 -12
  8. package/docs/features.md +2 -0
  9. package/install/_dev-only-files.mjs +1 -0
  10. package/install/catalog-history.json +1 -1
  11. package/install/index.mjs +0 -2
  12. package/manifest.json +67 -44
  13. package/package.json +4 -1
  14. package/pipeline/agents/code-reviewer.md +1 -0
  15. package/pipeline/agents/test-gen-analyst.md +98 -0
  16. package/pipeline/commands/multi-agent/sync/SKILL.md +3 -3
  17. package/pipeline/commands/multi-agent/test-gen/SKILL.md +124 -0
  18. package/pipeline/multi-agent-refs/cross-cli-contract.md +11 -5
  19. package/pipeline/multi-agent-refs/features/doctor.md +13 -0
  20. package/pipeline/multi-agent-refs/features/test-classification.md +76 -0
  21. package/pipeline/multi-agent-refs/features/usage-reporting.md +17 -0
  22. package/pipeline/multi-agent-refs/help/en.md +1 -0
  23. package/pipeline/multi-agent-refs/help/tr.md +1 -0
  24. package/pipeline/multi-agent-refs/phases/operations.md +2 -2
  25. package/pipeline/multi-agent-refs/phases/phase-2-dev.md +6 -7
  26. package/pipeline/multi-agent-refs/phases/phase-3-review.md +3 -3
  27. package/pipeline/multi-agent-refs/phases/phase-5-report.md +6 -5
  28. package/pipeline/multi-agent-refs/test-gen/stages.md +227 -0
  29. package/pipeline/preferences-template.json +3 -0
  30. package/pipeline/schemas/prefs.schema.json +14 -0
  31. package/pipeline/schemas/test-gen-discovery.schema.json +73 -0
  32. package/pipeline/schemas/test-gen-gaps.schema.json +122 -0
  33. package/pipeline/schemas/test-gen-inventory.schema.json +59 -0
  34. package/pipeline/schemas/test-gen-results.schema.json +44 -0
  35. package/pipeline/scripts/_handle-patterns.mjs +166 -0
  36. package/pipeline/scripts/_http-post.mjs +141 -0
  37. package/pipeline/scripts/_stack-routing.mjs +4 -0
  38. package/pipeline/scripts/_test-gaming.mjs +227 -0
  39. package/pipeline/scripts/_unified-diff.mjs +104 -0
  40. package/pipeline/scripts/_worktree-snapshot.mjs +113 -0
  41. package/pipeline/scripts/doctor.mjs +51 -0
  42. package/pipeline/scripts/evidence-gate.mjs +74 -3
  43. package/pipeline/scripts/handle-diff-audit.mjs +188 -0
  44. package/pipeline/scripts/routine-registry.mjs +5 -1
  45. package/pipeline/scripts/run-ui-tests.sh +27 -3
  46. package/pipeline/scripts/test-classify.mjs +296 -0
  47. package/pipeline/scripts/test-gen-gate.mjs +409 -0
  48. package/pipeline/scripts/test-gen-state.mjs +313 -0
  49. package/pipeline/scripts/test-integrity-gate.mjs +76 -11
  50. package/pipeline/scripts/uninstall.mjs +1 -0
  51. package/pipeline/scripts/usage-register-beacon.mjs +239 -0
  52. package/pipeline/scripts/usage-register.mjs +128 -33
  53. package/pipeline/scripts/usage-report.mjs +43 -33
  54. package/pipeline/skills/.skill-manifest.json +23 -3
  55. package/pipeline/skills/.skills-index.json +57 -2
  56. package/pipeline/skills/shared/README.md +10 -5
  57. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +3 -3
  58. package/pipeline/skills/shared/core/multi-agent-test-gen/SKILL.md +120 -0
  59. package/pipeline/skills/shared/external/fix-review-verdicts/SKILL.md +133 -0
  60. package/pipeline/skills/shared/external/handle-request/SKILL.md +97 -0
  61. package/pipeline/skills/shared/external/scenario-gap-analysis/SKILL.md +129 -0
  62. package/pipeline/skills/shared/external/scenario-gap-analysis/references/scenario-schema.md +60 -0
  63. package/pipeline/skills/shared/external/test-result-triage/SKILL.md +160 -0
  64. package/pipeline/skills/skills-index.md +7 -2
  65. 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 (65 commands)](#1-command-inventory-65-commands)
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 (65 commands)
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 --state "$STATE_FILE" --event halted >/dev/null 2>&1 || true
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 --state "$STATE_FILE" --event parked >/dev/null 2>&1 || true
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. A pass only on retry is a flake signal, not a pass. Same rule on the Phase 3 rework re-entry.
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. A failure here does not
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`; interactive runs skip this paragraph) 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.
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).** Phase 0 Step 7.6 recorded whether the suite was already red, so Gate 3 blocks on what this work broke, not what it walked into:
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 from today |
435
+ | `unknown` / absent | unchanged |
437
436
 
438
- The subtraction never widens: match on identifier only, and when identifiers cannot be compared fall to the `not attributable` row.
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 is too weak for a suite made green by deleting tests, so this makes it blocking findings triage must adjudicate. Pure function of the full report. `--out` always writes the file, the empty result included.
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 (unreadable input: zero). Feed it the FULL report: `--top` hides a shrinking test file 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.
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`). Mark the run finished in the state, then emit the completed event; both never block the run:
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 --state "$STATE_FILE" --event completed >/dev/null 2>&1 || true
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. Aggregator handles missing files gracefully.
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, so quality across real runs is measured, not asserted.
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 (mandatory):** as part of agent-log compose, append the per-task cost block produced by `render-agent-log-cost.sh`:
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