@mmerterden/multi-agent-pipeline 20.16.0 → 20.17.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 +30 -0
- package/README.md +6 -5
- package/README.tr.md +6 -5
- package/docs/architecture.md +3 -3
- package/docs/ecosystem.md +5 -5
- package/docs/facts.json +14 -12
- package/docs/features.md +9 -1
- package/install/catalog-history.json +1 -1
- package/install/claude.mjs +41 -6
- package/install/codex.mjs +3 -3
- package/manifest.json +62 -49
- package/package.json +1 -1
- package/pipeline/commands/multi-agent/bug-bash/SKILL.md +154 -0
- package/pipeline/commands/multi-agent/review/SKILL.md +13 -9
- package/pipeline/commands/multi-agent/setup/SKILL.md +8 -6
- package/pipeline/commands/multi-agent/sync/SKILL.md +4 -3
- package/pipeline/commands/multi-agent/update/SKILL.md +5 -1
- package/pipeline/commands/sim-test.md +71 -6
- package/pipeline/lib/plugin-skill-roots.mjs +80 -0
- package/pipeline/lib/usage-lifecycle.mjs +83 -0
- package/pipeline/multi-agent-refs/cross-cli-contract.md +20 -4
- package/pipeline/multi-agent-refs/features/assertion-judge.md +76 -0
- package/pipeline/multi-agent-refs/features/exploratory-testing.md +140 -0
- package/pipeline/multi-agent-refs/features/skill-conformance.md +1 -1
- package/pipeline/multi-agent-refs/features/usage-reporting.md +59 -5
- package/pipeline/multi-agent-refs/features/valven.md +30 -3
- package/pipeline/multi-agent-refs/help/en.md +2 -0
- package/pipeline/multi-agent-refs/help/tr.md +2 -0
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-4-commit.md +2 -2
- package/pipeline/schemas/bug-bash-verification.schema.json +41 -0
- package/pipeline/schemas/explore-run.schema.json +108 -0
- package/pipeline/schemas/prefs.schema.json +1 -1
- package/pipeline/scripts/_stack-routing.mjs +2 -0
- package/pipeline/scripts/bug-bash.mjs +379 -0
- package/pipeline/scripts/explore-findings.mjs +410 -0
- package/pipeline/scripts/gen-skills-index.mjs +1 -2
- package/pipeline/scripts/pr-timeline.mjs +135 -0
- package/pipeline/scripts/pre-commit-check.sh +4 -2
- package/pipeline/scripts/skill-conformance.mjs +17 -71
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +1 -1
- package/pipeline/scripts/uninstall.mjs +29 -8
- package/pipeline/scripts/usage-identity.mjs +36 -10
- package/pipeline/scripts/usage-register.mjs +95 -8
- package/pipeline/scripts/usage-report.mjs +52 -2
- package/pipeline/scripts/valven-gate.mjs +292 -11
- package/pipeline/skills/.skill-manifest.json +18 -10
- package/pipeline/skills/.skills-index.json +28 -6
- package/pipeline/skills/shared/README.md +6 -4
- package/pipeline/skills/shared/core/multi-agent-bug-bash/SKILL.md +150 -0
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +5 -1
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +4 -3
- package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +4 -1
- package/pipeline/skills/shared/external/e2e-testing/SKILL.md +124 -0
- package/pipeline/skills/shared/external/e2e-testing/references/document-fixtures.md +65 -0
- package/pipeline/skills/shared/external/valven-rules/SKILL.md +93 -0
- package/pipeline/skills/shared/{core → external}/valven-rules/references/rules.yml +52 -6
- package/pipeline/skills/skills-index.md +4 -2
- package/pipeline/skills/shared/core/valven-rules/SKILL.md +0 -62
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Exploratory testing - findings, budgets, stop rules
|
|
2
|
+
|
|
3
|
+
<!-- toc -->
|
|
4
|
+
- [1. The run file](#1-the-run-file)
|
|
5
|
+
- [2. A finding](#2-a-finding)
|
|
6
|
+
- [3. Budget and stop rules](#3-budget-and-stop-rules)
|
|
7
|
+
- [4. Product failure or blocked](#4-product-failure-or-blocked)
|
|
8
|
+
- [5. Driving the app: locators and expect steps](#5-driving-the-app-locators-and-expect-steps)
|
|
9
|
+
- [6. Report](#6-report)
|
|
10
|
+
<!-- /toc -->
|
|
11
|
+
|
|
12
|
+
An exploratory run drives a live app toward a goal and reports what looks
|
|
13
|
+
wrong. What it produces is a set of claims, and this contract keeps them
|
|
14
|
+
checkable: every finding carries what was expected, what was seen and how to
|
|
15
|
+
get there again; every run has a budget and stops on its own; a step that could
|
|
16
|
+
not run is reported apart from a product that ran and was wrong.
|
|
17
|
+
|
|
18
|
+
Consumers: `/multi-agent:test` (the UI Bug Hunter, `commands/sim-test.md`),
|
|
19
|
+
`/multi-agent:bug-bash` (one run per charter). Script:
|
|
20
|
+
`$HOME/.claude/scripts/explore-findings.mjs`. Run file:
|
|
21
|
+
`$HOME/.claude/schemas/explore-run.schema.json`. Assertions that need judgement go
|
|
22
|
+
to a fresh judge: `features/assertion-judge.md`.
|
|
23
|
+
|
|
24
|
+
## 1. The run file
|
|
25
|
+
|
|
26
|
+
Write the run as it goes to `<log dir>/run.json`: `goal`, `platform`, `budget`,
|
|
27
|
+
`usage`, `steps[]`, `findings[]`. One step is one charter-sized move ("change
|
|
28
|
+
the quantity on the first cart row and read the total"), not one tap.
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{"index": 3, "title": "Change quantity", "status": "failed", "code": "ASSERTION_FAILED",
|
|
32
|
+
"detail": "total stayed 12.00", "trace": "<path of the toolkit's trace.md, if any>"}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`status` is `passed | failed | blocked | exhausted`. `code` is the toolkit's
|
|
36
|
+
code when the step did not pass; it decides how the step counts (section 4).
|
|
37
|
+
|
|
38
|
+
## 2. A finding
|
|
39
|
+
|
|
40
|
+
| Field | Rule |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `kind` | `issue` (functional defect, fails the run) or `warning` (cosmetic, does not) |
|
|
43
|
+
| `severity` | integer 1-5: 1 trivial, 2 low, 3 medium, 4 high, 5 critical |
|
|
44
|
+
| `title`, `screen` | short, and where it was seen |
|
|
45
|
+
| `expected` | what should have happened, from the spec when there is one (`spec` quotes it) |
|
|
46
|
+
| `observed` | what happened instead |
|
|
47
|
+
| `repro` | the steps that reach it from launch, at least one |
|
|
48
|
+
| `evidence` | at least one `{kind, path}`: `screenshot`, `ui-tree`, `video`, `trace`, `log`, `text` |
|
|
49
|
+
| `step` | the step that reported it |
|
|
50
|
+
|
|
51
|
+
Report a finding the moment its evidence is on disk, not at the end. A finding
|
|
52
|
+
that misses a field is listed under "failed the contract" and cannot fail the
|
|
53
|
+
run: `explore-findings.mjs report` holds it out of the verdict.
|
|
54
|
+
|
|
55
|
+
Secrets never appear in a finding. A credential is named, not written:
|
|
56
|
+
`secret_ref:<name>`. The script refuses `password: <value>`, `token=<value>`
|
|
57
|
+
and the like in any finding text.
|
|
58
|
+
|
|
59
|
+
## 3. Budget and stop rules
|
|
60
|
+
|
|
61
|
+
| Budget | Default | Range |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| steps | 8 | 1-12 |
|
|
64
|
+
| minutes (wall clock) | 10 | 3-15 |
|
|
65
|
+
| tokens | 150000 | 20000-400000 |
|
|
66
|
+
|
|
67
|
+
Values outside the range are clamped and named in `clamped`. Before each new
|
|
68
|
+
step run:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
node "$HOME/.claude/scripts/explore-findings.mjs" check --run "<run.json>"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`{"stop": true}` ends the run with that `reason`:
|
|
75
|
+
|
|
76
|
+
- `step-limit`, `time`, `tokens`: the budget is spent.
|
|
77
|
+
- `stuck`: the last three steps were blocked and none of them reported a
|
|
78
|
+
finding. Three blocked steps in a row means the environment, not the app, is
|
|
79
|
+
in the way, and more steps would spend the budget learning nothing.
|
|
80
|
+
|
|
81
|
+
A failed step does not stop the run; only the rules above do.
|
|
82
|
+
|
|
83
|
+
## 4. Product failure or blocked
|
|
84
|
+
|
|
85
|
+
| Step | Counts as |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `failed` + `ASSERTION_FAILED` / `ASSERTION_INCONCLUSIVE` | product failure |
|
|
88
|
+
| `CREDENTIAL_MISSING` | blocked: credentials |
|
|
89
|
+
| `ENVIRONMENT_UNAVAILABLE` | blocked: environment |
|
|
90
|
+
| `SEED_DATA_MISSING` | blocked: seed data |
|
|
91
|
+
| `LOCATOR_NOT_FOUND`, `LOCATOR_AMBIGUOUS`, `REPLAY_DIVERGED` | blocked: automation |
|
|
92
|
+
| `BUDGET_EXCEEDED` | exhausted (neither) |
|
|
93
|
+
| `failed` with no code | blocked: unknown (never silently a product failure) |
|
|
94
|
+
|
|
95
|
+
A blocked step is a fact about the test setup. It goes in its own report
|
|
96
|
+
section, grouped by cause, so "the login screen is broken" and "the run had no
|
|
97
|
+
test account" are never the same line.
|
|
98
|
+
|
|
99
|
+
Verdict, from `explore-findings.mjs report`:
|
|
100
|
+
|
|
101
|
+
- **failed**: at least one valid `issue`.
|
|
102
|
+
- **blocked**: no step ran, or every step was blocked, and no `issue`.
|
|
103
|
+
- **passed**: steps ran, no `issue`, not every step blocked. Warnings allowed.
|
|
104
|
+
|
|
105
|
+
## 5. Driving the app: locators and expect steps
|
|
106
|
+
|
|
107
|
+
With `@mmerterden/multi-agent-toolkit-mcp` ≥ v3.19.0, prefer these over
|
|
108
|
+
coordinates; on an older toolkit, fall back to the UI tree plus frame-centre
|
|
109
|
+
taps as before and say so in the report:
|
|
110
|
+
|
|
111
|
+
- **Locate, then act.** `ui_locate` resolves an element by accessibility
|
|
112
|
+
identifier, by role plus label, or by visible text; `ios_tap_element` /
|
|
113
|
+
`android_tap_element` tap what it resolves. Identifier first, role plus label
|
|
114
|
+
second, text last (text changes with locale). `LOCATOR_NOT_FOUND` and
|
|
115
|
+
`LOCATOR_AMBIGUOUS` are automation blocks, not product findings: narrow the
|
|
116
|
+
locator and retry once before recording the step as blocked.
|
|
117
|
+
- **Assert with expect steps.** In `agent_run_steps`, `expect_text`,
|
|
118
|
+
`expect_element` and `expect_url` decide a deterministic check and return
|
|
119
|
+
`verdict: passed | failed | blocked` with a code. Use them for anything
|
|
120
|
+
exact: a total, a label, a route. Only a visual or semantic claim ("the
|
|
121
|
+
layout is not clipped", "the error explains what to do") goes to the judge.
|
|
122
|
+
- **Secrets by reference.** The type tools take `secret_ref` instead of the
|
|
123
|
+
value; the value never enters the transcript, the run file or a finding.
|
|
124
|
+
- **Traces.** A failed `agent_run_steps` writes a `trace.md`; put its path in
|
|
125
|
+
the step's `trace` and in the finding's `evidence` as `kind: "trace"`.
|
|
126
|
+
- **Replay.** `save_as` stores a step sequence that reached a finding, and
|
|
127
|
+
`replay` runs it again. `REPLAY_DIVERGED` means the app no longer follows the
|
|
128
|
+
recorded path: an automation block, and a hint that the screen changed.
|
|
129
|
+
- **Web sessions.** Pass `session` to keep parallel browser sessions apart
|
|
130
|
+
(one per bug-bash charter).
|
|
131
|
+
|
|
132
|
+
Tool inputs are the tool's own schema; the names above are the contract, the
|
|
133
|
+
argument shapes are read from the server.
|
|
134
|
+
|
|
135
|
+
## 6. Report
|
|
136
|
+
|
|
137
|
+
`explore-findings.mjs report --run <run.json>` prints the verdict, why the run
|
|
138
|
+
ended, the budget used, issues before warnings with the most severe first,
|
|
139
|
+
blocked steps by cause, and the findings that failed the contract. The UI Bug
|
|
140
|
+
Hunter keeps its own screen table and summary around this block.
|
|
@@ -44,7 +44,7 @@ The key sits under `metadata:` because the host skill frontmatter schema has no
|
|
|
44
44
|
|
|
45
45
|
`skill-conformance.mjs` reads frontmatter across the installed skills trees and loads what declared itself. Nothing in the pipeline names `ios-coding-standard`, `apple-archive-compliance` or any other skill, so a future UIKit, Objective-C, Kotlin or backend registry drops in with zero pipeline change - and a registry that is absent produces a declared coverage gap rather than a silent pass.
|
|
46
46
|
|
|
47
|
-
**The skills root differs per host**, so discovery is a bounded walk over candidate roots
|
|
47
|
+
**The skills root differs per host**, so discovery is a bounded walk over candidate roots and the first registry found under a name wins. On Claude Code the order is each marketplace stack plugin's `skills/` (the checkout, then every cached version, from `lib/plugin-skill-roots.mjs`), `~/.claude/multi-agent-refs/registries` (registries the installer lays down for the pipeline's gates, `valven-rules` among them), `~/.claude/skills`, then `<repo>/pipeline/skills`: a registry that ships in a plugin (`ios-coding-standard`, `valven-rules`) is what Claude Code loads, and a same-named copy an older install left behind must not shadow it. Copilot CLI and Codex load no plugin, so their installed skills dir (`<install>/skills`, `<install>/multi-agent-refs/skills`) comes first and the plugin roots follow. `install/copilot.mjs` copies `scripts/` byte-for-byte with no path rewrite, so a hardcoded `~/.claude/skills` is inert on two of the three hosts. `skillsRootsSearched` is recorded in the manifest so an empty result is attributable to a root rather than to an absence of registries.
|
|
48
48
|
|
|
49
49
|
## Scope is required, and it is what makes this stack-generic
|
|
50
50
|
|
|
@@ -57,6 +57,21 @@ progress.
|
|
|
57
57
|
| `completed` | Phase 5, after it writes `status: complete` and `finishedAt` to the state; the analysis render step |
|
|
58
58
|
| `halted` | the halt-visibility step in `phases/operations.md` |
|
|
59
59
|
| `parked` | the park-visibility step in `phases/operations.md`, after a run writes `awaiting_input` or `waitingFor` |
|
|
60
|
+
| `install`, `update` | registration, setup and update, and every accepted run event, when the installed version was not reported yet (see below) |
|
|
61
|
+
|
|
62
|
+
**Install and update records.** Derived, never written by the installer (see
|
|
63
|
+
section 8): the version stamp `install.js` writes (`.pipeline-version`, Claude
|
|
64
|
+
Code's first) says which version is installed and, by its modification time,
|
|
65
|
+
since when; prefs keep the last version reported (`usageLog.reportedVersion`).
|
|
66
|
+
When they differ, `usage-report.mjs --lifecycle` sends one record: `ev`
|
|
67
|
+
(`update` from the reported version; without one, `install` on a machine that
|
|
68
|
+
registered after the stamp and `update` from an unknown version on one that
|
|
69
|
+
registered before it), `v`, `vf`, `hs` (the host trees at that version) and `t`
|
|
70
|
+
(the stamp time), and moves `reportedVersion` forward once the server accepted
|
|
71
|
+
it. The id is derived from the version and the stamp time, so a resend replaces
|
|
72
|
+
the record. It runs after a successful registration, after setup or update finds
|
|
73
|
+
a token already onboarded, and after every accepted run event. The panel lists
|
|
74
|
+
the records under "Kurulumlar" and keeps them out of the run counts.
|
|
60
75
|
|
|
61
76
|
The panel derives a run's status from the last event it received. A run still
|
|
62
77
|
`in_progress` with no event for **6 hours** is shown as abandoned; a parked run
|
|
@@ -79,16 +94,55 @@ corporate title, and never simply the active `gh` account, which on a machine
|
|
|
79
94
|
with a work account and a personal account is often the one without access.
|
|
80
95
|
|
|
81
96
|
The answer is cached in prefs (`usageLog.login`, `loginRepo`, `loginCheckedAt`)
|
|
82
|
-
for 7 days, or 1 day when no account
|
|
83
|
-
network call. Refresh it after changing accounts or being granted access:
|
|
97
|
+
for 7 days, or 1 day for a fallback or when no account was found, so a phase
|
|
98
|
+
boundary costs no network call. Refresh it after changing accounts or being granted access:
|
|
84
99
|
|
|
85
100
|
```bash
|
|
86
101
|
node "$HOME/.claude/scripts/usage-identity.mjs" --refresh
|
|
87
102
|
```
|
|
88
103
|
|
|
89
|
-
**No account with access
|
|
90
|
-
|
|
91
|
-
|
|
104
|
+
**No account with access: the active account, and the server decides.** A work
|
|
105
|
+
machine often has only an enterprise-managed account logged in to gh, and such an
|
|
106
|
+
account can never be a collaborator of a personal repository. Then the active
|
|
107
|
+
account (else the first) is used as a fallback, marked `usageLog.loginFallback`
|
|
108
|
+
and cached for 1 day so an account with access added later takes over. The
|
|
109
|
+
server accepts it when its suffix is one the operator listed
|
|
110
|
+
(`USAGE_ENTERPRISE_SUFFIXES`) and refuses it with a 403 otherwise.
|
|
111
|
+
|
|
112
|
+
**No gh account at all, no report.** The emitter sends nothing and writes one
|
|
113
|
+
line to stderr (`usage-report: not sent - no GitHub account is logged in ...`);
|
|
114
|
+
registration is skipped with the same reason.
|
|
115
|
+
|
|
116
|
+
**`--quiet` still speaks once.** The Phase 0 backstop discards stdout, so a
|
|
117
|
+
registration that leaves reporting off for a reason the user can fix (a refused
|
|
118
|
+
login, no gh account, an unreachable endpoint) prints one stderr line,
|
|
119
|
+
`multi-agent: usage reporting is off - <reason>`, on every run until it is fixed.
|
|
120
|
+
|
|
121
|
+
### Personal account
|
|
122
|
+
|
|
123
|
+
A registration is pinned: the server binds the token to the login it verified,
|
|
124
|
+
and the machine keeps that login in `usageLog.registeredAs`. Every later record
|
|
125
|
+
is named after it, with no gh call, and a fallback account never replaces it
|
|
126
|
+
(`decideRegistration`). So the personal account has to be logged in to gh only
|
|
127
|
+
once, at the moment of registration; it can be logged out afterwards.
|
|
128
|
+
|
|
129
|
+
`usage-register.mjs --json` reports `needsPersonalAccount: true` while the
|
|
130
|
+
machine is not pinned to an account that can read the pipeline repository: no
|
|
131
|
+
registration yet, or one made with a fallback account. Setup and update then ask
|
|
132
|
+
once (AskUserQuestion per `$HOME/.claude/multi-agent-refs/picker-contract.md`; label
|
|
133
|
+
`Add personal account (Recommended)` / `Skip`):
|
|
134
|
+
|
|
135
|
+
1. Note the active account: `gh api user --jq .login`.
|
|
136
|
+
2. The person runs the browser login for the account that holds access, in their
|
|
137
|
+
own terminal (in Claude Code: `! gh auth login --hostname github.com --web`).
|
|
138
|
+
gh keeps both accounts.
|
|
139
|
+
3. Switch the work account back, so pull requests keep their author:
|
|
140
|
+
`gh auth switch --hostname github.com --user <the noted account>`.
|
|
141
|
+
4. `node "$HOME/.claude/scripts/usage-register.mjs" --refresh --json`. It finds
|
|
142
|
+
the account with access, replaces the fallback registration and pins the new
|
|
143
|
+
one.
|
|
144
|
+
|
|
145
|
+
Skip leaves the fallback in place; the next update asks again.
|
|
92
146
|
|
|
93
147
|
## 4. The server side
|
|
94
148
|
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
# Valven delivery rules across the phases
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<!-- toc -->
|
|
4
|
+
- [Phase 1](#phase-1)
|
|
5
|
+
- [Phase 2](#phase-2)
|
|
6
|
+
- [Phase 3](#phase-3)
|
|
7
|
+
- [Phase 4](#phase-4)
|
|
8
|
+
- [Development Behaviors](#development-behaviors)
|
|
9
|
+
- [Old work](#old-work)
|
|
10
|
+
<!-- /toc -->
|
|
11
|
+
|
|
12
|
+
The `valven-rules` skill holds the rules in `references/rules.yml`; `valven-gate.mjs` measures them and `valven-split.mjs` turns an oversized branch into stacked pull requests. This file is the per-phase contract the phase docs point at.
|
|
13
|
+
|
|
14
|
+
The skill ships in `ai-common-toolkit`, the always-on plugin, so the rules reach everyone who installs the marketplace, with or without the pipeline. Claude Code loads it from the plugin (`ai-common-toolkit:valven-rules`); the installer copies it into the skills tree on Copilot CLI and Codex. The gate reads the registry installed with it, so its evaluators and its rules come from one release: `multi-agent-refs/registries/valven-rules/` on Claude Code (laid down by the installer outside the skills dir, so the host does not load the skill twice), the skills tree on Copilot CLI and Codex, the source in a checkout, and the plugin copies only when none of those exists. `skill-conformance.mjs` finds the judgement rules in the plugin on Claude Code and falls back to the same registries dir. The gate prints the path it used as `rulesPath`; when none is found it exits 2, which every step below treats as "could not measure", never as a pass.
|
|
4
15
|
|
|
5
16
|
## Phase 1
|
|
6
17
|
|
|
@@ -15,11 +26,11 @@ node $HOME/.claude/scripts/valven-gate.mjs --mode dev --repo "$WORKTREE" --base
|
|
|
15
26
|
--out "$WORKTREE/.pipeline/valven-dev.json" >/dev/null
|
|
16
27
|
```
|
|
17
28
|
|
|
18
|
-
**Gate 6** (valven-rules, dev mode). Exit 2 blocks the phase: the rules could not be read or git failed. Exit 1: `VLV-TEST-01` (source changed, no test changed) and `VLV-TRACE-01` (no issue key in the branch) are fixed here before Review. `VLV-SIZE-01`, `VLV-SIZE-02` and `VLV-SCOPE-01` are not fixed by editing: keep building on this branch, set `state.valven.splitRequired = true`, and Phase 4 Step 2.95 splits it into stacked PRs. `VLV-REWORK-01` is reported to the user with the ratio and continues. Contract:
|
|
29
|
+
**Gate 6** (valven-rules, dev mode). Exit 2 blocks the phase: the rules could not be read or git failed. Exit 1: `VLV-TEST-01` (source changed, no test changed) and `VLV-TRACE-01` (no issue key in the branch) are fixed here before Review. `VLV-SIZE-01`, `VLV-SIZE-02` and `VLV-SCOPE-01` are not fixed by editing: keep building on this branch, set `state.valven.splitRequired = true`, and Phase 4 Step 2.95 splits it into stacked PRs. `VLV-REWORK-01` is reported to the user with the ratio and continues. Contract: the `valven-rules` skill.
|
|
19
30
|
|
|
20
31
|
## Phase 3
|
|
21
32
|
|
|
22
|
-
Step 1.762, after the owned-path gate. The PR body
|
|
33
|
+
Step 1.762, after the owned-path gate. The PR body and the pull request do not exist yet, so `VLV-PRDESC-01`, `VLV-CYCLE-01`, `VLV-CYCLE-02`, `VLV-CYCLE-03` and `VLV-PICKUP-01` report `not-measured`; Phase 4 and `/multi-agent:review` measure them.
|
|
23
34
|
|
|
24
35
|
```bash
|
|
25
36
|
VG_FILE="$WORKTREE/.pipeline/valven-gate.json"
|
|
@@ -55,6 +66,12 @@ VG_RC=$?
|
|
|
55
66
|
|
|
56
67
|
Log: `Phase 4 Step 2.95: valven {pass|fixed|split N|shipped-whole}`
|
|
57
68
|
|
|
69
|
+
The commit-mode report also scores `VLV-CYCLE-01`, from the oldest author date among the commits about to be pushed to now. Phase 4 commits right before the push, so this is what Valven will read from the pushed history, and it is a `suggestion` that never blocks the push. The rule carries information on a pull request whose commits were pushed as they were made, which `/multi-agent:review` measures.
|
|
70
|
+
|
|
71
|
+
### Opening the pull request
|
|
72
|
+
|
|
73
|
+
Every gate has passed before the push, so the pull request opens ready for review with the default reviewers attached, and the draft/ready prompt recommends READY. A draft delays the reviewers' notification, and `VLV-PICKUP-01` flags a draft older than 3 hours on the next review.
|
|
74
|
+
|
|
58
75
|
### PR body
|
|
59
76
|
|
|
60
77
|
**Valven body check (required, every PR).** After the body is written to `/tmp/pr-body-$TASK_ID.md` and before the PR is created or updated:
|
|
@@ -67,6 +84,16 @@ jq -r '.findings[] | select(.ruleId == "VLV-PRDESC-01") | .issue' "$WORKTREE/.pi
|
|
|
67
84
|
|
|
68
85
|
Any `VLV-PRDESC-01` line blocks creation: add the missing why / how-to-verify text and re-run. Other findings here were already handled at Step 2.95.
|
|
69
86
|
|
|
87
|
+
## Development Behaviors
|
|
88
|
+
|
|
89
|
+
`VLV-CYCLE-01` (coding: first commit to the pull request opening), `VLV-CYCLE-02` (pickup: ready for review to the first review) and `VLV-CYCLE-03` (review: first review to approval or merge) are scored into Valven's bands, reported as `results[].score` and collected in `scores`; `VLV-REWORK-01` adds the churn score, `100 - churn %`. A duration in the 50 or 0 band is a `suggestion`, because the time has passed and the pull request cannot change it. `VLV-PICKUP-01` is `important` when the pull request has no reviewer, which the author fixes now; a draft older than 3 hours is a `suggestion` (`draft_severity`), because an unattended run opens a draft on purpose and a person decides when it is ready.
|
|
90
|
+
|
|
91
|
+
The durations need the pull request's timeline, passed with `--pr-meta-file`. On GitHub, `pr-timeline.mjs --repo <owner/repo> --pr <N> --out <file>` writes it: `gh pr view --json` (head and base branch, body, commits, author, open, close and merge times, draft state, review requests, reviews) plus two things only GitHub's GraphQL timeline carries, the time a draft was marked ready (`readyAt`) and each review author's type, so a bot such as Copilot's reviewer is not counted as a person. When that query fails the script keeps the `gh pr view` output and says on stderr that pickup then counts from the opening and bots are not recognised; the summary repeats it.
|
|
92
|
+
|
|
93
|
+
A Bitbucket caller writes `{createdAt, readyAt, isDraft, reviewerCount, firstReviewAt, approvedAt, mergedAt, closedAt}` in ISO 8601: `createdDate`, `draft` and the close time of a declined pull request from the pull request, `reviewerCount` the length of `reviewers[]`, `firstReviewAt` the earliest `COMMENTED`, `REVIEWED` or `APPROVED` activity by someone other than the author, `approvedAt` the earliest `APPROVED`; a field it cannot read is null. Bitbucket records no ready-for-review time, so its `readyAt` is null.
|
|
94
|
+
|
|
95
|
+
The gate leaves out reviews by the author, by bots and pending reviews, and a review left before the pull request was ready: pickup and review time start at ready. An unknown reviewer count stays unknown (`VLV-PICKUP-01` reports it `not-measured`, never "no reviewer"), a draft is not asked for a reviewer, and on a merged or closed pull request the clocks stop there and `VLV-PICKUP-01` does not apply. A file that does not parse, or has no valid `createdAt`, is reported on stderr and the timeline rules report `not-measured`; every other rule is still measured.
|
|
96
|
+
|
|
70
97
|
## Old work
|
|
71
98
|
|
|
72
99
|
`VLV-AGE-01` (a commit older than 14 days, by author date so a rebase does not hide it), `VLV-BEHIND-01` (more than 50 commits behind the base, or a merge-base older than 14 days) and `VLV-TRACE-03` (commits carrying another issue's key) mean the branch carries old or foreign work. The answer is never a rebase of the old history: the change moves.
|
|
@@ -186,6 +186,8 @@ UI Testing (standalone - not part of pipeline phases):
|
|
|
186
186
|
through three gates per platform, and lives at /multi-agent:store-ready. The old
|
|
187
187
|
/multi-agent:test "store-ready" [path] tag still works and hands off there.
|
|
188
188
|
|
|
189
|
+
/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
|
|
190
|
+
|
|
189
191
|
Uses xcrun simctl / adb (native, no external app needed).
|
|
190
192
|
Booted simulator/emulator required. Auto-detects bundle ID from project.
|
|
191
193
|
|
|
@@ -185,6 +185,8 @@ UI Testing (standalone - pipeline fazlarından bağımsız):
|
|
|
185
185
|
geçirerek doğrular, iOS + Android, ve /multi-agent:store-ready altında. Eski
|
|
186
186
|
/multi-agent:test "store-ready" [path] etiketi çalışır ve oraya devreder.
|
|
187
187
|
|
|
188
|
+
/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
|
|
189
|
+
|
|
188
190
|
xcrun simctl / adb kullanır (harici app gerekmez).
|
|
189
191
|
Booted simulator/emulator şart. Bundle ID proje'den otomatik algılanır.
|
|
190
192
|
|
|
@@ -681,7 +681,7 @@ Phase 0 owns `agent-state.json`. Do not call
|
|
|
681
681
|
|
|
682
682
|
```bash
|
|
683
683
|
node "$HOME/.claude/scripts/phase0-exit-gate.mjs" "$TASK_ID" --input "$ORIGINAL_INPUT"
|
|
684
|
-
node "$HOME/.claude/scripts/usage-register.mjs" --quiet >/dev/null
|
|
684
|
+
node "$HOME/.claude/scripts/usage-register.mjs" --quiet >/dev/null || true
|
|
685
685
|
node "$HOME/.claude/scripts/usage-report.mjs" --task-id "$TASK_ID" --phase 0 --event phase >/dev/null 2>&1 || true
|
|
686
686
|
```
|
|
687
687
|
|
|
@@ -20,7 +20,7 @@ Progress emission per `$HOME/.claude/multi-agent-refs/progress-contract.md` -
|
|
|
20
20
|
> │
|
|
21
21
|
> ┌──────────────── PR payload ─────────────────────────┘
|
|
22
22
|
> │ title + description (rawfile) + reviewers + fromRef + toRef + draft
|
|
23
|
-
> └──► POST (Bitbucket) or gh pr create
|
|
23
|
+
> └──► POST (Bitbucket) or gh pr create (GitHub) ──► PR open
|
|
24
24
|
> ```
|
|
25
25
|
|
|
26
26
|
#### Input contract
|
|
@@ -239,7 +239,7 @@ PR author cannot appear in `--reviewer` - strip from list.
|
|
|
239
239
|
|
|
240
240
|
##### Draft vs ready-for-review
|
|
241
241
|
|
|
242
|
-
Before creating PR, ask: "
|
|
242
|
+
Before creating PR, ask: "READY or DRAFT? [1/2], default `defaultPrMode` or 1" - READY notifies reviewers + CI, DRAFT blocks merge and notifies later. Skip in `autopilot` → READY.
|
|
243
243
|
|
|
244
244
|
- **Bitbucket**: `"draft": true` in payload (DC 8.x+). Promote: `draft: false` PUT. Older: prefix title `[DRAFT]`.
|
|
245
245
|
- **GitHub**: `--draft`. Promote: `gh pr ready {N}`.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/mmerterden/multi-agent-pipeline/pipeline/schemas/bug-bash-verification.schema.json",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"title": "Multi-Agent Pipeline - bug bash verifications",
|
|
6
|
+
"description": "One entry per merged candidate, written by the verifying subagents of /multi-agent:bug-bash. bug-bash.mjs report confirms a candidate only when its repro test failed with ASSERTION_FAILED on the assertion that encodes it (failedAt equals assertion); any other outcome is listed as rejected with the reason.",
|
|
7
|
+
"type": "array",
|
|
8
|
+
"items": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"required": ["id", "status"],
|
|
11
|
+
"properties": {
|
|
12
|
+
"id": { "type": "string", "pattern": "^BB-[0-9]+$" },
|
|
13
|
+
"status": { "enum": ["confirmed", "rejected"] },
|
|
14
|
+
"reason": {
|
|
15
|
+
"enum": ["artifact", "environment", "design", "fixture", "did-not-reproduce", "duplicate"],
|
|
16
|
+
"description": "Required when rejected. artifact: the explorer misread the screen; environment: a key, service or limit only the local stack lacks; design: the code, tests or copy say it is intended; fixture: the seed data lacks what real records have."
|
|
17
|
+
},
|
|
18
|
+
"note": { "type": "string" },
|
|
19
|
+
"productionRisk": {
|
|
20
|
+
"type": "boolean",
|
|
21
|
+
"description": "An environment rejection whose failure handling production users would also see."
|
|
22
|
+
},
|
|
23
|
+
"rootCause": { "type": "string", "description": "file:line, when the source was read." },
|
|
24
|
+
"repro": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"required": ["path", "command", "code", "assertion"],
|
|
27
|
+
"properties": {
|
|
28
|
+
"path": { "type": "string", "minLength": 1 },
|
|
29
|
+
"command": { "type": "string", "minLength": 1 },
|
|
30
|
+
"code": {
|
|
31
|
+
"type": ["string", "null"],
|
|
32
|
+
"description": "ASSERTION_FAILED, PASSED, or the failure code the run produced."
|
|
33
|
+
},
|
|
34
|
+
"assertion": { "type": "string", "minLength": 1 },
|
|
35
|
+
"failedAt": { "type": ["string", "null"] },
|
|
36
|
+
"trace": { "type": "string" }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/mmerterden/multi-agent-pipeline/pipeline/schemas/explore-run.schema.json",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"title": "Multi-Agent Pipeline - exploratory test run",
|
|
6
|
+
"description": "One exploratory session of /multi-agent:test or one /multi-agent:bug-bash charter, written as the run goes so explore-findings.mjs can decide when it must stop (check) and what its verdict is (report). Findings are claims with evidence; a bug bash proves them with a reproducing test before reporting them.",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"required": ["goal", "budget", "steps", "findings"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"goal": { "type": "string", "minLength": 1 },
|
|
11
|
+
"platform": { "enum": ["ios", "android", "web"] },
|
|
12
|
+
"persona": { "type": "string" },
|
|
13
|
+
"budget": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"description": "Per-run budget; explore-findings.mjs fills defaults (8 steps, 10 minutes, 150000 tokens) and clamps to steps 1-12, minutes 3-15, tokens 20000-400000.",
|
|
16
|
+
"properties": {
|
|
17
|
+
"steps": { "type": "integer", "minimum": 1 },
|
|
18
|
+
"minutes": { "type": "number", "minimum": 0 },
|
|
19
|
+
"tokens": { "type": "integer", "minimum": 0 }
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"usage": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"properties": {
|
|
25
|
+
"steps": { "type": "integer", "minimum": 0 },
|
|
26
|
+
"minutes": { "type": "number", "minimum": 0 },
|
|
27
|
+
"tokens": { "type": "integer", "minimum": 0 }
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"ended": { "enum": ["finished", "step-limit", "time", "tokens", "stuck", "aborted"] },
|
|
31
|
+
"steps": {
|
|
32
|
+
"type": "array",
|
|
33
|
+
"items": {
|
|
34
|
+
"type": "object",
|
|
35
|
+
"required": ["index", "status"],
|
|
36
|
+
"properties": {
|
|
37
|
+
"index": { "type": "integer", "minimum": 1 },
|
|
38
|
+
"title": { "type": "string" },
|
|
39
|
+
"status": { "enum": ["passed", "failed", "blocked", "exhausted"] },
|
|
40
|
+
"code": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "The toolkit's verdict or locator code when the step did not pass: ASSERTION_FAILED and ASSERTION_INCONCLUSIVE are product failures; CREDENTIAL_MISSING, ENVIRONMENT_UNAVAILABLE and SEED_DATA_MISSING block by cause; LOCATOR_NOT_FOUND, LOCATOR_AMBIGUOUS and REPLAY_DIVERGED block as automation; BUDGET_EXCEEDED is exhausted."
|
|
43
|
+
},
|
|
44
|
+
"detail": { "type": "string" },
|
|
45
|
+
"trace": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"description": "Path of the toolkit's failure trace.md, when it wrote one."
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"findings": {
|
|
53
|
+
"type": "array",
|
|
54
|
+
"items": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"required": ["kind", "severity", "title", "expected", "observed", "repro", "evidence"],
|
|
57
|
+
"properties": {
|
|
58
|
+
"id": { "type": "string" },
|
|
59
|
+
"step": { "type": "integer", "minimum": 1 },
|
|
60
|
+
"kind": {
|
|
61
|
+
"enum": ["issue", "warning"],
|
|
62
|
+
"description": "issue: a functional defect, fails the run. warning: cosmetic, does not."
|
|
63
|
+
},
|
|
64
|
+
"severity": {
|
|
65
|
+
"type": "integer",
|
|
66
|
+
"minimum": 1,
|
|
67
|
+
"maximum": 5,
|
|
68
|
+
"description": "1 trivial, 2 low, 3 medium, 4 high, 5 critical."
|
|
69
|
+
},
|
|
70
|
+
"title": { "type": "string", "minLength": 1 },
|
|
71
|
+
"screen": { "type": "string" },
|
|
72
|
+
"expected": { "type": "string", "minLength": 1 },
|
|
73
|
+
"observed": { "type": "string", "minLength": 1 },
|
|
74
|
+
"repro": {
|
|
75
|
+
"type": "array",
|
|
76
|
+
"minItems": 1,
|
|
77
|
+
"items": { "type": "string", "minLength": 1 }
|
|
78
|
+
},
|
|
79
|
+
"evidence": {
|
|
80
|
+
"type": "array",
|
|
81
|
+
"minItems": 1,
|
|
82
|
+
"items": {
|
|
83
|
+
"type": "object",
|
|
84
|
+
"required": ["kind", "path"],
|
|
85
|
+
"properties": {
|
|
86
|
+
"kind": { "enum": ["screenshot", "ui-tree", "video", "trace", "log", "text"] },
|
|
87
|
+
"path": { "type": "string", "minLength": 1 }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"spec": {
|
|
92
|
+
"type": "string",
|
|
93
|
+
"description": "The acceptance criterion the expectation comes from, quoted, or 'no spec, model expectation'."
|
|
94
|
+
},
|
|
95
|
+
"judge": {
|
|
96
|
+
"type": "object",
|
|
97
|
+
"description": "Present when a visual or semantic assertion decided the finding: the fresh judge's checked verdict.",
|
|
98
|
+
"properties": {
|
|
99
|
+
"verdict": { "enum": ["passed", "failed"] },
|
|
100
|
+
"code": { "type": ["string", "null"] },
|
|
101
|
+
"reason": { "type": "string" }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -1503,7 +1503,7 @@
|
|
|
1503
1503
|
"valven": {
|
|
1504
1504
|
"type": "object",
|
|
1505
1505
|
"additionalProperties": false,
|
|
1506
|
-
"description": "valven-rules delivery gate (
|
|
1506
|
+
"description": "valven-rules delivery gate (the valven-rules skill, shipped in ai-common-toolkit). Runs at Phase 2 exit (Gate 6), Phase 4 Step 2.95 before push, Phase 3 Step 1.762 and every /multi-agent:review. Findings carry tag `valven`; an accepted important or blocking one sets NEEDS WORK, and an oversized branch is split into stacked PRs by valven-split.mjs.",
|
|
1507
1507
|
"properties": {
|
|
1508
1508
|
"enabled": {
|
|
1509
1509
|
"type": "boolean",
|