@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.
Files changed (72) hide show
  1. package/CHANGELOG.md +38 -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 +74 -51
  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/store-ready/gate-3-policy.md +6 -2
  29. package/pipeline/multi-agent-refs/test-gen/stages.md +227 -0
  30. package/pipeline/preferences-template.json +3 -0
  31. package/pipeline/rules/app-store-guidelines.md +29 -41
  32. package/pipeline/schemas/prefs.schema.json +14 -0
  33. package/pipeline/schemas/test-gen-discovery.schema.json +73 -0
  34. package/pipeline/schemas/test-gen-gaps.schema.json +122 -0
  35. package/pipeline/schemas/test-gen-inventory.schema.json +59 -0
  36. package/pipeline/schemas/test-gen-results.schema.json +44 -0
  37. package/pipeline/scripts/_handle-patterns.mjs +166 -0
  38. package/pipeline/scripts/_http-post.mjs +141 -0
  39. package/pipeline/scripts/_stack-routing.mjs +4 -0
  40. package/pipeline/scripts/_test-gaming.mjs +227 -0
  41. package/pipeline/scripts/_unified-diff.mjs +104 -0
  42. package/pipeline/scripts/_worktree-snapshot.mjs +113 -0
  43. package/pipeline/scripts/doctor.mjs +51 -0
  44. package/pipeline/scripts/evidence-gate.mjs +74 -3
  45. package/pipeline/scripts/handle-diff-audit.mjs +188 -0
  46. package/pipeline/scripts/routine-registry.mjs +5 -1
  47. package/pipeline/scripts/run-ui-tests.sh +27 -3
  48. package/pipeline/scripts/test-classify.mjs +296 -0
  49. package/pipeline/scripts/test-gen-gate.mjs +409 -0
  50. package/pipeline/scripts/test-gen-state.mjs +313 -0
  51. package/pipeline/scripts/test-integrity-gate.mjs +76 -11
  52. package/pipeline/scripts/uninstall.mjs +1 -0
  53. package/pipeline/scripts/usage-register-beacon.mjs +239 -0
  54. package/pipeline/scripts/usage-register.mjs +128 -33
  55. package/pipeline/scripts/usage-report.mjs +43 -33
  56. package/pipeline/skills/.skill-manifest.json +25 -5
  57. package/pipeline/skills/.skills-index.json +57 -2
  58. package/pipeline/skills/shared/README.md +11 -6
  59. package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +5 -4
  60. package/pipeline/skills/shared/core/apple-archive-compliance/references/rules.yml +8 -8
  61. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +3 -3
  62. package/pipeline/skills/shared/core/multi-agent-test-gen/SKILL.md +120 -0
  63. package/pipeline/skills/shared/external/app-store-review/SKILL.md +69 -8
  64. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +12 -0
  65. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +10 -1
  66. package/pipeline/skills/shared/external/fix-review-verdicts/SKILL.md +133 -0
  67. package/pipeline/skills/shared/external/handle-request/SKILL.md +97 -0
  68. package/pipeline/skills/shared/external/scenario-gap-analysis/SKILL.md +129 -0
  69. package/pipeline/skills/shared/external/scenario-gap-analysis/references/scenario-schema.md +60 -0
  70. package/pipeline/skills/shared/external/test-result-triage/SKILL.md +160 -0
  71. package/pipeline/skills/skills-index.md +7 -2
  72. package/install/_telemetry.mjs +0 -61
@@ -0,0 +1,97 @@
1
+ ---
2
+ name: handle-request
3
+ description: "Add the test handles a scenario needs and answer each request with ADDED, ALREADY or COULD NOT ADD plus file:line or reason. Identity values only, attribute-only diffs; iOS accessibilityIdentifier, Compose testTag, web data-testid. Use when a test needs an element handle the UI lacks."
4
+ metadata:
5
+ source: multi-agent-pipeline
6
+ version: 1.0.0
7
+ ---
8
+
9
+ # Handle request
10
+
11
+ A handle is the identifier a test finds an element by: it does not change with
12
+ copy, locale or layout. This step adds the handles a scenario list asks for,
13
+ and nothing else.
14
+
15
+ ## 1. Input
16
+
17
+ A list of requests, usually the "handles needed" section of
18
+ `scenario-gap-analysis`. Each request names the element, the screen, a
19
+ proposed identifier and the scenario it unblocks.
20
+
21
+ ## 2. One answer per request
22
+
23
+ | Answer | When |
24
+ |---|---|
25
+ | `ADDED file:line` | The handle was added at that line. |
26
+ | `ALREADY file:line` | A usable handle already exists there; give its value. |
27
+ | `COULD NOT ADD reason` | It was not added. The reason is specific: element rendered by a third-party view, identifier must come from a shared schema that lacks the key, repository is read-only, the element is not exposed to the accessibility tree and exposing it would change what assistive technology hears. |
28
+
29
+ No other answer exists. A request that is half done is split into the part
30
+ added and the part that could not be.
31
+
32
+ ## 3. Rules
33
+
34
+ - **Identity, never position.** A row carries the item's id
35
+ (`order_row_{orderId}`), never the loop index, which shifts when the list is
36
+ reordered or filtered. Do not rewrite a list-rendering expression to obtain
37
+ an index or an id; if the id is not in scope, answer COULD NOT ADD.
38
+ - **Attribute-only diffs.** Add identifier attributes or modifiers. No logic,
39
+ state, flow, data, styling, renames or deletions. Anything a line loses must
40
+ reappear in the added line.
41
+ - **Stable names.** Screen-scoped, descriptive, independent of visible text
42
+ and locale (`cart_checkout_button`). Follow the project's existing naming
43
+ scheme and, where it generates identifiers from a shared schema, use the
44
+ generated constant; a key missing from the schema is added upstream, so the
45
+ answer is COULD NOT ADD with that reason.
46
+ - **One pass.** Write every requested handle before building. On mobile each
47
+ build costs minutes; one handle per build turns a step into hours.
48
+ - **Out of bounds.** Build files, manifests and permissions, signing,
49
+ dependencies. No commit: leave the diff for a human.
50
+
51
+ ## 4. The handle has to be visible where the test runs
52
+
53
+ A handle in source that the test driver cannot see is worse than none: it
54
+ looks done. For each handle, confirm it reaches the tree the test reads:
55
+
56
+ | Platform | Handle | Seen by the driver only when |
57
+ |---|---|---|
58
+ | iOS (SwiftUI, UIKit) | `accessibilityIdentifier` | the element is in the accessibility tree: not hidden, not merged into a parent element |
59
+ | Android (Compose) | `Modifier.testTag` | inside the app's Compose tests always; for UI Automator based drivers only under `testTagsAsResourceId` on an ancestor |
60
+ | Android (Views) | `android:id` | the view is laid out and not excluded from accessibility |
61
+ | Web | `data-testid` (or the project's configured test id attribute) | the component forwards it to the DOM and the build under test does not strip it |
62
+ | Flutter | `Semantics(identifier: ...)` for external drivers; `Key` for in-process tests | a `Key` works with `find.byKey` inside `flutter test` and integration tests, but never reaches the accessibility tree, so an external driver (XCUITest, UI Automator, Maestro, Appium) needs the `Semantics` identifier |
63
+
64
+ Verify against the running app when a build loop exists: a UI tree dump
65
+ (`ios_get_ui_tree`, `android_get_ui_tree`), a DOM query or `web_find`. When no
66
+ build loop is available in this step, the report says "not verified on device"
67
+ and gives the build and install commands for a human. Never claim a check that
68
+ did not run.
69
+
70
+ The stack plugins carry the platform detail: `ai-ios-toolkit:handle-request`,
71
+ `ai-android-toolkit:handle-request`, `ai-frontend-toolkit:handle-request`.
72
+
73
+ ## 5. Check the diff before finishing
74
+
75
+ - `git diff -U0` shows added handle lines; their count is greater than zero
76
+ unless every answer is ALREADY or COULD NOT ADD.
77
+ - Every removed line comes back in an added line with only the identifier
78
+ added.
79
+ - No file outside the UI sources the requests point to.
80
+
81
+ ## 6. Report
82
+
83
+ ```
84
+ cart_checkout_button ADDED src/cart/CartFooter.tsx:31
85
+ order_row_{orderId} ALREADY src/orders/OrderRow.tsx:12 (data-testid="order-row-{id}")
86
+ map_pin COULD NOT ADD rendered by a third-party map view with no identifier API
87
+ ```
88
+
89
+ Then: a diff summary (files, lines changed), the scenarios these handles
90
+ unblock, and what was not verified on device, with the reason.
91
+
92
+ ## Related
93
+
94
+ - `scenario-gap-analysis` produces the requests.
95
+ - `test-result-triage` sends a locator-not-found result here before calling a
96
+ test stale.
97
+ - `e2e-testing` for the locator order a test uses once the handle exists.
@@ -0,0 +1,129 @@
1
+ ---
2
+ name: scenario-gap-analysis
3
+ description: "Set an inventory against existing tests, sort each behaviour into COVERED, WRONGLY COVERED or MISSING, and write gaps as measurable, prioritised scenarios with cross-screen flows. Use when planning tests or auditing coverage. Not for writing tests or judging a run."
4
+ metadata:
5
+ source: multi-agent-pipeline
6
+ version: 1.0.0
7
+ ---
8
+
9
+ # Scenario gap analysis
10
+
11
+ Decide **what** has to be tested, and why. How to test it belongs to the
12
+ writing step. The output is a ranked list of measurable scenarios that a test
13
+ writer can turn into code without asking what was meant.
14
+
15
+ ## 1. Read before you call anything missing
16
+
17
+ Gather the inputs first, and read all of them:
18
+
19
+ - **Inventory**: screens, modules, flows or endpoints in scope, from a design
20
+ scenario inventory, a site map, a UI tree, or exploration reports.
21
+ - **Existing tests**: the test tree and any test catalogue. Search it for every
22
+ behaviour before listing that behaviour as a gap.
23
+ - **Regression history** where the project keeps one: past bugs, regression
24
+ maps, incident notes. A case that broke before is the first candidate.
25
+ - **Exploration notes**: what someone saw the product actually do.
26
+
27
+ Match tests to inventory items by **identifier** (accessibility identifier,
28
+ test id, route, endpoint path), never by a name that merely sounds similar.
29
+ When a match is inferred rather than read, say so on that line.
30
+
31
+ ## 2. Three buckets
32
+
33
+ | Bucket | Meaning |
34
+ |---|---|
35
+ | **COVERED** | A test exercises the behaviour and its assertion would fail if the behaviour broke. |
36
+ | **WRONGLY COVERED** | A test exists and stays green while the defect is present. |
37
+ | **MISSING** | No test exercises the behaviour. |
38
+
39
+ WRONGLY COVERED is the most valuable bucket, because the suite reports safety
40
+ it does not provide. Typical shapes:
41
+
42
+ - A text scan over rendered text that never sees content injected as markup.
43
+ - A visibility filter that passes a broken image because its width is zero.
44
+ - An assertion on the HTTP status that passes while the body carries an error.
45
+ - A test that seeds the store or mocks the handoff it claims to verify.
46
+ - An existence check where the value is what matters (a total, a date, a count).
47
+
48
+ For every WRONGLY COVERED line, name the test (`file:line`) and the defect it
49
+ cannot see.
50
+
51
+ ## 3. Scenario schema
52
+
53
+ Each MISSING or WRONGLY COVERED behaviour becomes one scenario:
54
+
55
+ | Field | Content |
56
+ |---|---|
57
+ | Title | Usable as the test name. |
58
+ | Priority | `bug-catching` (broke before or likely to, hurts the user directly: data, money, dates, a dead end in the funnel, leaked copy keys) / `edge` (empty, error, boundary, slow network, back navigation, session expiry, flag combinations) / `baseline` (happy path, element present). |
59
+ | Business reason | Who loses what, or which revenue or compliance risk it carries. "Nice to have" is not a reason. |
60
+ | Preconditions | Account, data and state the scenario needs, and where each comes from. |
61
+ | Steps | What the user does. |
62
+ | Measurable expectation | A claim a test can check exactly: a value, a label, a route, an element present or absent. A scenario with no measurable expectation is not written. |
63
+ | Automation | `yes` / `no` (stays a manual check, still listed) / `needs-code` (name the missing handle or hook). |
64
+ | Handles needed | Identity-carrying handles the test will locate by, for the handle step. |
65
+ | Data needs | What test data the scenario requires. The agent states the need; a human supplies the value. Never invent a credential. |
66
+ | Flakiness risk | Third-party scripts, live content, timing. Say it up front. |
67
+
68
+ The machine-readable shape and a worked example are in
69
+ [references/scenario-schema.md](references/scenario-schema.md).
70
+
71
+ ## 4. Cross-screen flows (at least two)
72
+
73
+ Write at least two scenarios that walk a user path across screens. Only an
74
+ analysis that has seen the whole module can write them, and they catch the
75
+ class of defect screen tests cannot: screen A does not write the state screen
76
+ B reads. Both screens are green on their own and the flow is broken.
77
+
78
+ Rules for a flow scenario:
79
+
80
+ - Every step uses the state the previous step left. No seeding a store, no
81
+ injecting state, no deep link or direct route to an intermediate screen.
82
+ - Enter from the first screen and move forward the way a user does.
83
+ - Mock only noise outside the flow (a cookie banner, an analytics beacon),
84
+ never the data the flow carries: whether it is carried is the measurement.
85
+ - A long flow may be split into segments, each starting where the previous one
86
+ ended, with no seeding inside a segment.
87
+
88
+ Screen scenarios may seed state and deep link; they measure the screen's own
89
+ resilience. Flow scenarios may not.
90
+
91
+ When the scope cannot hold two flows (a single screen, a module with one
92
+ entry and no onward path), write the ones it holds and record the shortfall
93
+ under could-not-measure with the reason. Never pad the count with a flow that
94
+ seeds its own state.
95
+
96
+ ## 5. Judgement rules
97
+
98
+ - Do not propose what is already covered. A covered case listed as missing is
99
+ noise, not analysis.
100
+ - Platforms differ. Device permissions and backgrounding have no web
101
+ equivalent; browser back, reload, deep links, horizontal overflow and
102
+ keyboard navigation are web-specific.
103
+ - Ask for handles that carry identity (`data-order-id`, a row keyed by the
104
+ item id), never a list index, which moves when the order changes.
105
+ - Open with "do these three first". An unranked list of twenty is not usable.
106
+
107
+ ## 6. Could not measure
108
+
109
+ A separate section, always present. Each line names what could not be
110
+ measured, why (no account, environment down, screen unreachable, data
111
+ missing), and what would make it measurable. The absence of a measurement is
112
+ not a positive result and never folds into COVERED.
113
+
114
+ ## 7. Output order
115
+
116
+ 1. The top three, with one line each on why.
117
+ 2. Bucket table: behaviour, bucket, test `file:line` where one exists.
118
+ 3. Scenarios in priority order, flows included and marked as flows.
119
+ 4. Handles needed, grouped by screen.
120
+ 5. Data needs.
121
+ 6. Could not measure.
122
+
123
+ ## Related
124
+
125
+ - API and service gaps: `ai-backend-toolkit:scenario-gap-analysis` adds the
126
+ envelope, contract and service-chain rules.
127
+ - Adding the handles the scenarios ask for: `handle-request`.
128
+ - Judging a run of the written tests: `test-result-triage`.
129
+ - Driving a running app to observe behaviour first: `e2e-testing`.
@@ -0,0 +1,60 @@
1
+ # Scenario schema
2
+
3
+ One JSON object per scenario. Field names are the contract a test writer or a
4
+ pipeline step reads; values follow the rules in `SKILL.md`.
5
+
6
+ ```json
7
+ {
8
+ "id": "cart-total-after-coupon",
9
+ "title": "Cart total reflects a percentage coupon after quantity change",
10
+ "bucket": "WRONGLY_COVERED",
11
+ "coveredBy": "tests/cart/coupon.spec.ts:42",
12
+ "defectNotSeen": "asserts the coupon badge exists, never the total",
13
+ "priority": "bug-catching",
14
+ "businessReason": "A wrong total charges the customer a different amount than shown",
15
+ "kind": "screen",
16
+ "preconditions": ["signed-in account with an empty cart", "coupon code valid for 10 percent"],
17
+ "steps": ["add item A", "apply coupon", "change quantity to 3"],
18
+ "expectation": "total label equals 3 x unit price x 0.9, rounded to 2 decimals",
19
+ "automation": "yes",
20
+ "handles": ["cart_total_label", "cart_item_quantity_{itemId}"],
21
+ "dataNeeds": [{ "name": "coupon-10-percent", "supplied": "human" }],
22
+ "flakinessRisk": "none known"
23
+ }
24
+ ```
25
+
26
+ | Field | Values |
27
+ |---|---|
28
+ | `bucket` | `COVERED`, `WRONGLY_COVERED`, `MISSING` |
29
+ | `coveredBy` | `file:line` of the existing test, or null for MISSING |
30
+ | `priority` | `bug-catching`, `edge`, `baseline` |
31
+ | `kind` | `screen` or `flow` |
32
+ | `automation` | `yes`, `no`, `needs-code` (with the reason in `automationNote`) |
33
+ | `dataNeeds[].supplied` | always `human` for credentials and personal data |
34
+
35
+ ## A flow scenario
36
+
37
+ ```json
38
+ {
39
+ "id": "flow-browse-to-confirmation",
40
+ "title": "Item chosen on the list arrives unchanged on the confirmation screen",
41
+ "bucket": "MISSING",
42
+ "priority": "bug-catching",
43
+ "kind": "flow",
44
+ "steps": [
45
+ "open the catalogue from the home screen",
46
+ "open item A and pick size M",
47
+ "add to cart and go to checkout",
48
+ "confirm"
49
+ ],
50
+ "expectation": "confirmation shows item A, size M, the price shown on the item screen",
51
+ "rules": "no store seeding, no direct route to checkout, no mock of the cart request",
52
+ "automation": "yes"
53
+ }
54
+ ```
55
+
56
+ ## Could-not-measure entry
57
+
58
+ ```json
59
+ { "what": "refund screen", "why": "no account with a completed order", "needs": "a seeded order supplied by a human" }
60
+ ```
@@ -0,0 +1,160 @@
1
+ ---
2
+ name: test-result-triage
3
+ description: "Judge each test result on changed code as product-bug, stale-test, valid or ambiguous (the default), and list behaviour no test covers. stale-test needs a diff file:line, product-bug needs evidence. Use when tests ran on a new commit, PR or fix. Not for writing or editing tests."
4
+ metadata:
5
+ source: multi-agent-pipeline
6
+ version: 1.0.0
7
+ ---
8
+
9
+ # Test result triage
10
+
11
+ The product moved to a new commit and the tests ran against it. For every test
12
+ that ran, decide what happens next. The decision is a plan for a human (or a
13
+ setting) to approve; this skill does not edit tests or product code.
14
+
15
+ Requires `@mmerterden/multi-agent-toolkit-mcp` >= v3.25.0 for
16
+ `test_results_classify`. On an older server, or with no server, derive the
17
+ input statuses by hand as section 2 describes and say in the report that the
18
+ run used the fallback.
19
+
20
+ ## 1. The verdicts
21
+
22
+ Each test that ran gets one of four verdicts:
23
+
24
+ | Verdict | Meaning | What follows |
25
+ |---|---|---|
26
+ | `product-bug` | The test is right: behaviour broke without intent. | A finding is filed. The test is not changed. |
27
+ | `stale-test` | Behaviour changed on purpose, or a handle moved; the test expects the old state. | The test is revised. |
28
+ | `valid` | The test still measures the right thing on the new code. | Nothing. |
29
+ | `ambiguous` | The evidence does not decide it. | A human decides. |
30
+
31
+ The fifth outcome, `new-scenario`, belongs to the change rather than to a test:
32
+ behaviour the change adds that no test exercises. It goes in `newScenarios`
33
+ (section 5) and on to `scenario-gap-analysis`, never as a verdict on a test
34
+ that ran.
35
+
36
+ **The default is `ambiguous`.** Marking a product bug as `stale-test` loosens
37
+ the test and buries the bug, which is the most expensive mistake this step can
38
+ make. Calling a red test `product-bug` without evidence sends a team chasing a
39
+ bug that is not there. Every verdict other than `ambiguous` needs positive
40
+ evidence from section 4; a red test that the change merely fails to explain
41
+ stays `ambiguous`.
42
+
43
+ ## 2. Inputs
44
+
45
+ - **Classified results.** When the multi-agent-toolkit MCP server provides
46
+ `test_results_classify`, use its output as the input. It compares the head
47
+ run with a base run (the unchanged commit) and a confirmation run, and gives
48
+ each test a status with a reason:
49
+
50
+ | Status | How triage treats it |
51
+ |---|---|
52
+ | `passed` | Rule 4. Without a change analysis, read the diff for the area the test covers before calling it `valid`. |
53
+ | `regression` | Green on base, red twice on head. Rules 1 to 3, in order. |
54
+ | `preexisting` | Red on base too, so this change did not cause it. Never `stale-test` on this diff's evidence. `ambiguous` with the reason "red before the change", listed in its own section; `product-bug` (preexisting) only with the product `file:line` that causes it. |
55
+ | `unstable` | Flipped on confirmation or has a recent flake history. `ambiguous`; never green, never a product bug. |
56
+ | `not_measured` | Base, setup or environment did not measure it. `ambiguous` with the tool's reason. |
57
+
58
+ Without the tool, derive the same distinctions by hand: a setup failure, a
59
+ missing device or a server that did not start is not measured, not red.
60
+ - **The change**: the diff from base to head, commit and PR titles, release
61
+ notes.
62
+ - **The change analysis**, if one ran: which areas it expected to change and
63
+ how (behaviour change, new feature, refactor with no behaviour change).
64
+ - **Run evidence**: failure message, failing step, trace, screenshot or DOM.
65
+
66
+ ## 3. Decision rules
67
+
68
+ Apply them in this order; the first that matches decides.
69
+
70
+ 1. **Red because an element or locator was not found** -> check the handle
71
+ before anything else. Search the new tree for the element (`git grep` the
72
+ identifier, the text, the component).
73
+ - The element exists but carries no handle: `ambiguous` with the reason
74
+ "handle missing", and a request for `handle-request`. Not a stale test.
75
+ - The diff renames or moves the handle on purpose: `stale-test`, with the
76
+ diff `file:line`.
77
+ - The element is gone and the removal is intentional (diff `file:line`
78
+ plus a title or note saying so): `stale-test`.
79
+ - The element is gone and nothing says it was intended: `ambiguous`,
80
+ unless rule 3 finds positive evidence of a bug.
81
+ 2. **Red, and the diff changes that behaviour on purpose** (a commit title, a
82
+ new flow, new copy) -> `stale-test`. Cite the diff `file:line` and the
83
+ intent signal.
84
+ 3. **Red, with positive evidence of a bug** -> `product-bug`. Positive
85
+ evidence is one of:
86
+ - the test checks a contract (data loss, an error code, an empty body,
87
+ request and response parity) and the diff does not change that contract
88
+ on purpose;
89
+ - a product `file:line` that produces the wrong result;
90
+ - the change analysis states that behaviour in this area did not change,
91
+ yet the test that passed on base now fails.
92
+ Name the behaviour that broke. A red test with none of these stays
93
+ `ambiguous`.
94
+ 4. **Green** -> do not pass it only because it is green. When the change
95
+ analysis or the diff shows the behaviour this test covers changed, check
96
+ whether the test asserts the old behaviour or the new one: old, passing by
97
+ accident, `stale-test`; new, `valid`. When neither touches the area,
98
+ `valid`.
99
+ 5. **Failed for an environmental reason** (timeout, server down, network,
100
+ device) -> `ambiguous` with the reason. Never a product bug.
101
+ 6. **Anything else** -> `ambiguous`, naming the missing evidence.
102
+
103
+ A test written in this same chain that stays red after revision has often
104
+ caught a real bug. Calling it `product-bug` still needs the product code
105
+ `file:line` that causes it.
106
+
107
+ Separately from the per-test verdicts, list behaviour the change adds that no
108
+ test exercised as `newScenarios`.
109
+
110
+ ## 4. Evidence per verdict
111
+
112
+ | Verdict | Required |
113
+ |---|---|
114
+ | `stale-test` | Diff `file:line` that changes the behaviour or the handle, and the intent signal (title, note, spec). |
115
+ | `product-bug` | Expected versus observed from the run, the behaviour that broke, and one piece of positive evidence from rule 3. |
116
+ | `valid` | The green run, plus for rule 4 the reason the test asserts the new behaviour or why the area is untouched. |
117
+ | `ambiguous` | Which piece of evidence is missing. |
118
+ | `newScenarios[]` entry | The new behaviour and the diff `file:line` that adds it. |
119
+
120
+ Many tests failing on the same handle or the same fixture form a cluster: prove
121
+ one representative, decide the cluster together, and say in the reason that it
122
+ was decided as a cluster.
123
+
124
+ ## 5. Output
125
+
126
+ Every test that ran gets a verdict; a red test left without one reaches a human
127
+ as "ambiguous: no verdict given", so leaving one out only delays it.
128
+
129
+ ```json
130
+ {
131
+ "verdicts": [
132
+ {
133
+ "testId": "checkout.spec.ts > applies coupon",
134
+ "verdict": "stale-test",
135
+ "reason": "coupon field moved into a sheet on purpose",
136
+ "evidence": "src/checkout/CouponSheet.tsx:18, PR title 'move coupon entry to a sheet'",
137
+ "inputStatus": "regression"
138
+ }
139
+ ],
140
+ "newScenarios": [{ "behaviour": "...", "diff": "file:line" }]
141
+ }
142
+ ```
143
+
144
+ Write a report next to it: verdict and reason per test, a summary table by
145
+ verdict, the `preexisting` section, and what could not be measured. On a long
146
+ run, work screen by screen and save after each one, so a timeout loses nothing
147
+ already decided.
148
+
149
+ ## Boundaries
150
+
151
+ - No test edits, no product code edits.
152
+ - No red test becomes `stale-test` while there is doubt.
153
+ - A `product-bug` verdict is a report, never an automatic change to the test.
154
+
155
+ ## Related
156
+
157
+ - `scenario-gap-analysis` for `newScenarios` entries.
158
+ - `handle-request` for elements that exist but carry no handle.
159
+ - `e2e-testing` for the passed / failed / blocked verdicts of a single run.
160
+ - `fix-review-verdicts` when the red test led to a fix that now needs review.
@@ -3,7 +3,7 @@
3
3
  > Auto-generated by `pipeline/scripts/build-skills-index.mjs` - do not hand-edit.
4
4
  > Regenerate with `node pipeline/scripts/build-skills-index.mjs`.
5
5
 
6
- **229 skills** across 2 groups.
6
+ **234 skills** across 2 groups.
7
7
 
8
8
  | Group | Name | Platform | Description |
9
9
  |-------|------|----------|-------------|
@@ -24,7 +24,7 @@
24
24
  | external | `app-intents` | - | App Intents for Siri, Shortcuts, Spotlight, widgets, Control Center and Apple Intelligence: AppIntent actions, AppEntity and EntityQuery, Ap |
25
25
  | external | `app-store-changelog` | - | Generate user-facing App Store release notes from git history since the last tag. Use when release notes have to be written from the commits |
26
26
  | external | `app-store-optimization` | - | App Store Optimization (ASO) for ranking and conversion: keyword research; app name, subtitle and 100-byte keyword field; description and pr |
27
- | external | `app-store-review` | - | App Store submission readiness and rejection prevention: Review Guidelines 2.1, 2.3, 2.5.1, 3.1.1, 4.2 and 5.1.2, PrivacyInfo.xcprivacy mani |
27
+ | external | `app-store-review` | - | App Store submission readiness and rejection prevention: Review Guidelines 1.2, 2.1, 2.3, 2.3.14, 2.5.1, 2.5.19, 3.1.1, 4.2 and 5.1.2, uploa |
28
28
  | core | `apple-archive-compliance` | - | Apple App Store Review compliance - wraps the multi-agent-toolkit-mcp `ios_app_store_audit` tool (18-rule deep scan) with ITMS error code |
29
29
  | external | `apple-on-device-ai` | - | On-device AI on Apple hardware: Foundation Models (SystemLanguageModel, LanguageModelSession, @Generable and @Guide structured output, tool |
30
30
  | external | `architecture` | - | Stack-neutral architecture decisions: quality drivers, options with a trade-off matrix, reversibility, ADRs, fitness checks. Use when making |
@@ -61,9 +61,11 @@
61
61
  | external | `evidence-registry` | - | Check a package's real version, deprecation status and release notes on npm, PyPI, Maven Central or Swift Package Index. Use when a spec or |
62
62
  | external | `fastapi-pro` | - | FastAPI with Pydantic v2: lifespan, settings, Annotated dependencies, async SQLAlchemy 2.0 sessions, error handlers, background work, httpx |
63
63
  | external | `firebase` | - | You're a developer who has shipped dozens of Firebase projects. You've seen the easy path lead to security breaches, runaway costs, and impo |
64
+ | external | `fix-review-verdicts` | - | Independent fix review with three verdicts, test-gaming, scope and root-cause, each backed by file:line findings; the result is computed fro |
64
65
  | external | `github-actions-templates` | - | Authoring GitHub Actions workflows: triggers, matrices, caching, concurrency, least-privilege permissions, SHA pinning, OIDC, reusable workf |
65
66
  | core | `google-play-compliance` | - | Google Play Store publication compliance - bundletool + aapt2 + apksigner orchestration + 21-rule policy catalog with Play Console error c |
66
67
  | external | `gradle-kotlin-dsl` | - | Configure Android builds with Gradle Kotlin DSL, version catalogs (libs.versions.toml), convention plugins (build-logic module), common conf |
68
+ | external | `handle-request` | - | Add the test handles a scenario needs and answer each request with ADDED, ALREADY or COULD NOT ADD plus file:line or reason. Identity values |
67
69
  | external | `healthkit` | - | HealthKit on iOS, iPadOS, watchOS and visionOS: HKHealthStore authorization, sample, statistics and chart-ready collection queries, saving H |
68
70
  | external | `hig-app-icons` | - | iOS app icons: Icon Composer layered icons, default, dark, clear and tinted appearances, asset catalogs, alternate icons and the archive che |
69
71
  | external | `hig-components-content` | - | Apple HIG for content views mapped to SwiftUI: lists, tables, grids, charts, images, text, web views, empty states. Use when choosing or rev |
@@ -160,6 +162,7 @@
160
162
  | core | `multi-agent-test-accessibility` | - | Accessibility audit on a booted simulator / emulator: VoiceOver labels, sub-44pt tap targets, contrast, traits. Alias pinning the accessibil |
161
163
  | core | `multi-agent-test-dark-mode` | - | Dark mode UI test on a booted simulator / emulator: walk every screen light then dark, report contrast + colour bugs. Alias pinning the dark |
162
164
  | core | `multi-agent-test-dynamic-type` | - | Dynamic Type layout test on a booted simulator / emulator: re-walk every screen at XL through accessibility-extra-large, report truncation a |
165
+ | core | `multi-agent-test-gen` | - | Write the tests an app lacks, stage by stage, each gated on its artefact: inventory, read-only gap analysis, handles, tests, runs, per-test |
163
166
  | core | `multi-agent-test-screenshots` | - | App Store screenshot set from a booted simulator / emulator in a given locale, taken as an argument and defaulting to tr. Alias pinning the |
164
167
  | core | `multi-agent-testflight-validation` | - | iOS-pinned alias of store-ready: same three gates on an iOS build, one implementation. Validates a TestFlight / App Store package, never upl |
165
168
  | core | `multi-agent-uninstall` | - | Uninstall the pipeline from Claude Code + Copilot CLI. Keychain access tokens are always left untouched; --all-data also clears pipeline set |
@@ -182,6 +185,7 @@
182
185
  | external | `rest-api-design` | - | REST API design: HTTP methods, status codes, pagination, versioning, rate limiting, caching headers, OpenAPI documentation. Use when a REST |
183
186
  | external | `retrofit-networking` | - | Build networking layers on Android with Retrofit, OkHttp, and Kotlin Coroutines. Covers suspend functions in API interfaces, OkHttp intercep |
184
187
  | external | `room-database` | - | Implement Room database persistence on Android with @Entity, @Dao, @Database, Flow-based reactive queries, TypeConverters for complex types, |
188
+ | external | `scenario-gap-analysis` | - | Set an inventory against existing tests, sort each behaviour into COVERED, WRONGLY COVERED or MISSING, and write gaps as measurable, priorit |
185
189
  | external | `search-first` | - | Research-before-coding workflow. Before writing a custom implementation, check what already exists (repo utilities, installed libraries, pac |
186
190
  | external | `security-review` | - | Run a defensive, static security review of a diff or a repo: build a run-scoped threat model, find vulnerabilities joined to OWASP + CWE wit |
187
191
  | external | `shareplay-activities` | - | GroupActivities and SharePlay on iOS, macOS, tvOS and visionOS: GroupActivity, GroupSession lifecycle, messengers, playback sync, file trans |
@@ -220,6 +224,7 @@
220
224
  | external | `swiftui-view-refactor` | - | Refactor SwiftUI views into smaller components with stable, explicit data flow. Use when a SwiftUI view has grown too large and needs splitt |
221
225
  | external | `swiftui-webkit` | - | Web content in SwiftUI with WebKit for SwiftUI: WebView, WebPage, observable page state, navigation policies, link interception, JavaScript |
222
226
  | external | `tailwind-css` | - | Tailwind CSS v4: utility-first styling, responsive design, dark mode, custom themes, component patterns, and cn() utility. Use when styling |
227
+ | external | `test-result-triage` | - | Judge each test result on changed code as product-bug, stale-test, valid or ambiguous (the default), and list behaviour no test covers. stal |
223
228
  | external | `testing-backend` | - | Backend testing: pytest patterns (Python), Jest patterns (Node.js), integration testing, database fixtures/factories, API contract testing. |
224
229
  | external | `tipkit` | - | TipKit in-app tips (iOS 17+): Tip protocol, TipView, popoverTip, rules, events, TipGroup, styles, CloudKit sync. Use when building or review |
225
230
  | external | `typescript-patterns` | - | Modern TypeScript patterns: strict mode, utility types, generics, conditional types, type guards, discriminated unions, Zod validation. Use |
@@ -1,61 +0,0 @@
1
- /**
2
- * Anonymous install telemetry (opt-in only).
3
- *
4
- * Set `MULTI_AGENT_TELEMETRY=1` to enable. Nothing is sent otherwise.
5
- * Fire-and-forget; never throws and never delays the install.
6
- *
7
- * The payload is genuinely anonymous: package name, version, install
8
- * method, flags, platform/arch, and Node version. No usernames, emails,
9
- * hostnames, or other machine/user identifiers are collected.
10
- *
11
- * @module install/_telemetry
12
- */
13
-
14
- import { readFileSync } from "fs";
15
- import { platform, arch } from "os";
16
- import { join } from "path";
17
-
18
- /**
19
- * @param {{ packageRoot: string, flags: string[] }} ctx
20
- * @returns {Promise<void>}
21
- */
22
- export async function sendInstallTelemetry(ctx) {
23
- if (process.env.MULTI_AGENT_TELEMETRY !== "1") return;
24
-
25
- let method = "source";
26
- const npmExecPath = process.env.npm_execpath ?? "";
27
- if (npmExecPath.includes("npx-cli")) method = "npx";
28
- else if (process.env.npm_config_global === "true") method = "global";
29
- else if (process.env.npm_lifecycle_event === "install") method = "npm-install";
30
-
31
- let version = "unknown";
32
- try {
33
- const pkg = JSON.parse(readFileSync(join(ctx.packageRoot, "package.json"), "utf-8"));
34
- version = pkg.version ?? version;
35
- } catch {
36
- /* ignore */
37
- }
38
-
39
- const payload = {
40
- package: "@mmerterden/multi-agent-pipeline",
41
- version,
42
- method,
43
- flags: ctx.flags.filter((f) => f.startsWith("--")),
44
- platform: `${platform()} ${arch()}`,
45
- nodeVersion: process.version,
46
- };
47
-
48
- try {
49
- const ctrl = new AbortController();
50
- const timer = setTimeout(() => ctrl.abort(), 2000);
51
- await fetch("https://mmerterden.vercel.app/api/install-notify", {
52
- method: "POST",
53
- headers: { "Content-Type": "application/json" },
54
- body: JSON.stringify(payload),
55
- signal: ctrl.signal,
56
- });
57
- clearTimeout(timer);
58
- } catch {
59
- // Silent fail - never break the install if telemetry is unreachable
60
- }
61
- }