canary-test-cli 7.0.0 → 7.2.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/agents/skills/README.md +308 -0
- package/agents/skills/canary:generate.md +49 -0
- package/agents/skills/canary:init.md +37 -0
- package/agents/skills/canary:migrate.md +66 -0
- package/agents/skills/claude-code/canary-add-framework/SKILL.md +248 -0
- package/agents/skills/claude-code/canary-blackhawk/SKILL.md +170 -0
- package/agents/skills/claude-code/canary-blackhawk/scripts/cli.mjs +188 -0
- package/agents/skills/claude-code/canary-blackhawk/scripts/rules.mjs +120 -0
- package/agents/skills/claude-code/canary-blackhawk/scripts/scanner.mjs +244 -0
- package/agents/skills/claude-code/canary-blackhawk/scripts/string-literals.mjs +116 -0
- package/agents/skills/claude-code/canary-cassandra/SKILL.md +180 -0
- package/agents/skills/claude-code/canary-cassandra/scripts/cli.mjs +268 -0
- package/agents/skills/claude-code/canary-cassandra/scripts/engine.mjs +95 -0
- package/agents/skills/claude-code/canary-ci-ready/SKILL.md +161 -0
- package/agents/skills/claude-code/canary-ci-ready/skill.yaml +14 -0
- package/agents/skills/claude-code/canary-company-knowledge/SKILL.md +196 -0
- package/agents/skills/claude-code/canary-critical-areas/SKILL.md +142 -0
- package/agents/skills/claude-code/canary-critical-areas/skill.yaml +16 -0
- package/agents/skills/claude-code/canary-edge-case-discovery/SKILL.md +160 -0
- package/agents/skills/claude-code/canary-edge-case-discovery/skill.yaml +16 -0
- package/agents/skills/claude-code/canary-fail-fast/SKILL.md +75 -0
- package/agents/skills/claude-code/canary-fail-fast/scripts/cli.mjs +118 -0
- package/agents/skills/claude-code/canary-fail-fast/scripts/digest.mjs +69 -0
- package/agents/skills/claude-code/canary-fail-fast/scripts/failures.mjs +60 -0
- package/agents/skills/claude-code/canary-fail-fast/scripts/fastfail_check.mjs +43 -0
- package/agents/skills/claude-code/canary-fail-fast/scripts/parse.mjs +149 -0
- package/agents/skills/claude-code/canary-failure-impact/SKILL.md +153 -0
- package/agents/skills/claude-code/canary-failure-impact/skill.yaml +15 -0
- package/agents/skills/claude-code/canary-fleet-health/SKILL.md +196 -0
- package/agents/skills/claude-code/canary-generate-test/SKILL.md +185 -0
- package/agents/skills/claude-code/canary-instrument/SKILL.md +157 -0
- package/agents/skills/claude-code/canary-instrument/scripts/cli.mjs +178 -0
- package/agents/skills/claude-code/canary-instrument/scripts/otel_bootstrap/instrument.mjs +96 -0
- package/agents/skills/claude-code/canary-instrument/scripts/otel_bootstrap/playwright-fixture.ts +44 -0
- package/agents/skills/claude-code/canary-instrument/scripts/run_types.mjs +81 -0
- package/agents/skills/claude-code/canary-instrument/scripts/span_reader.mjs +187 -0
- package/agents/skills/claude-code/canary-katana/SKILL.md +243 -0
- package/agents/skills/claude-code/canary-katana/scripts/alarm.mjs +296 -0
- package/agents/skills/claude-code/canary-katana/scripts/cli.mjs +247 -0
- package/agents/skills/claude-code/canary-katana/scripts/diffscan.mjs +0 -0
- package/agents/skills/claude-code/canary-katana/scripts/ledger.mjs +183 -0
- package/agents/skills/claude-code/canary-pr-guardian/SKILL.md +129 -0
- package/agents/skills/claude-code/canary-pr-guardian/skill.yaml +17 -0
- package/agents/skills/claude-code/canary-promote-test/SKILL.md +228 -0
- package/agents/skills/claude-code/canary-savant/SKILL.md +233 -0
- package/agents/skills/claude-code/canary-savant/scripts/cli.mjs +274 -0
- package/agents/skills/claude-code/canary-savant/scripts/restoration.mjs +274 -0
- package/agents/skills/claude-code/canary-savant/scripts/rules.mjs +168 -0
- package/agents/skills/claude-code/canary-savant/scripts/runner.mjs +572 -0
- package/agents/skills/claude-code/canary-savant/scripts/scanner.mjs +374 -0
- package/agents/skills/claude-code/canary-savant/scripts/string-literals.mjs +116 -0
- package/agents/skills/claude-code/canary-setup-harness/SKILL.md +263 -0
- package/agents/skills/claude-code/canary-shadow/SKILL.md +131 -0
- package/agents/skills/claude-code/canary-shadow/scripts/cases.example.json +32 -0
- package/agents/skills/claude-code/canary-shadow/scripts/cli.mjs +195 -0
- package/agents/skills/claude-code/canary-ship/SKILL.md +177 -0
- package/agents/skills/claude-code/canary-ship/skill.yaml +16 -0
- package/agents/skills/claude-code/canary-strix/SKILL.md +130 -0
- package/agents/skills/claude-code/canary-strix/scripts/cli.mjs +255 -0
- package/agents/skills/claude-code/canary-strix/scripts/scanner.mjs +252 -0
- package/agents/skills/claude-code/canary-strix/scripts/terms.mjs +132 -0
- package/agents/skills/claude-code/canary-test-pipeline/SKILL.md +159 -0
- package/agents/skills/claude-code/canary-test-pipeline/skill.yaml +19 -0
- package/agents/skills/claude-code/canary-test-reporter/SKILL.md +138 -0
- package/agents/skills/claude-code/canary-test-reporter/scripts/cli.mjs +98 -0
- package/agents/skills/claude-code/canary-test-reporter/scripts/json_report.mjs +58 -0
- package/agents/skills/claude-code/canary-test-reporter/scripts/parse.mjs +216 -0
- package/agents/skills/claude-code/canary-test-reporter/scripts/render.mjs +114 -0
- package/agents/skills/lib/parse-args.mjs +214 -0
- package/dist/engine/analysis/cli.js +116 -54
- package/dist/engine/analysis/engine.js +34 -16
- package/dist/engine/analysis/reports.js +5 -4
- package/dist/engine/cli-commands.js +252 -106
- package/dist/engine/cli-common.js +15 -24
- package/dist/engine/cli.core.js +37 -11
- package/dist/engine/cli.js +2 -2
- package/dist/engine/company-knowledge-cli.js +2 -2
- package/dist/engine/core/adoption.js +408 -0
- package/dist/engine/core/framework-probes.js +7 -7
- package/dist/engine/core/fs-glob.js +2 -2
- package/dist/engine/core/gate-result.js +17 -0
- package/dist/engine/core/migrator.js +9 -17
- package/dist/engine/core/pattern-matcher.js +23 -5
- package/dist/engine/core/persona.js +421 -0
- package/dist/engine/core/promotion-verdict.js +261 -0
- package/dist/engine/core/quality-scorer.js +15 -2
- package/dist/engine/core/reporter.js +1 -9
- package/dist/engine/core/skill-dispatch.js +115 -0
- package/dist/engine/core/skill-examples.js +392 -0
- package/dist/engine/core/skill-registry.js +59 -4
- package/dist/engine/core/skill-surfaces.js +307 -0
- package/dist/engine/core/static-linter.js +310 -38
- package/dist/engine/core/test-files.js +77 -0
- package/dist/engine/core/ticket-updater.js +1 -7
- package/dist/engine/core/vacuity-scanner.js +726 -0
- package/dist/engine/core/workflow-discovery.js +2 -8
- package/dist/engine/core/workspace-detect.js +7 -6
- package/dist/engine/data/personas/registry.json +36 -0
- package/dist/engine/guardian/adjudication.js +5 -5
- package/dist/engine/guardian/analysis-emit.js +19 -28
- package/dist/engine/guardian/cli.js +150 -51
- package/dist/engine/guardian/coverage.js +1 -1
- package/dist/engine/guardian/diff-coverage/heuristic-tier.js +1 -1
- package/dist/engine/guardian/diff-coverage/orchestrator.js +2 -2
- package/dist/engine/guardian/pr-check.js +322 -33
- package/dist/engine/guardian/pr-comment.js +4 -3
- package/dist/engine/history/cli.js +210 -6
- package/dist/engine/history/ndjson-store.js +9 -5
- package/dist/engine/history/record.js +34 -5
- package/dist/engine/history/run-recorder.js +165 -0
- package/dist/engine/history/schema.js +25 -7
- package/dist/engine/history/store.js +9 -0
- package/dist/engine/mcp-server.js +35 -13
- package/dist/engine/skills-cli.js +249 -23
- package/dist/engine/util/ensure-ascii.js +37 -0
- package/dist/engine/workflow-cli.js +6 -6
- package/dist/gate-result.d.ts +11 -0
- package/dist/gate-result.js +18 -0
- package/dist/reporters/testtracker.d.ts +1 -1
- package/dist/reporters/testtracker.js +1 -1
- package/dist/uninstall.js +12 -5
- package/package.json +3 -2
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: canary-company-knowledge
|
|
3
|
+
description: >
|
|
4
|
+
Scaffold .canary/company.json — the org-specific pointer file (Confluence
|
|
5
|
+
spaces, Jira projects, internal docs/domains, MCP servers, dashboard, and the
|
|
6
|
+
user-catalog skill) that canary-ci-ready and canary-failure-impact silently
|
|
7
|
+
assume already exists. Use when the user says "set up company knowledge",
|
|
8
|
+
"bootstrap company.json", "no company.json", "canary company-knowledge init",
|
|
9
|
+
or when canary-ci-ready/canary-failure-impact report no user-catalog config
|
|
10
|
+
for auth/config failures. Scaffolds the file and prompts for the fields that
|
|
11
|
+
genuinely cannot be inferred — it does not claim full automation.
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Canary: Company Knowledge Init
|
|
15
|
+
|
|
16
|
+
Wraps `canary company-knowledge init` to scaffold `.canary/company.json` — the
|
|
17
|
+
_pointers-only_ file that lets Canary skills reach into your org's internal
|
|
18
|
+
tooling (Confluence, Jira, internal docs, MCP servers, a user catalog) without
|
|
19
|
+
ever committing proprietary content to this open-core repo.
|
|
20
|
+
|
|
21
|
+
This file is silently assumed to exist by
|
|
22
|
+
[`canary-ci-ready`](../canary-ci-ready/SKILL.md) (user-catalog investigation for
|
|
23
|
+
auth/config failures) and
|
|
24
|
+
[`canary-failure-impact`](../canary-failure-impact/SKILL.md) (same). If neither
|
|
25
|
+
has ever been run with a populated `company.json`, both degrade to a generic
|
|
26
|
+
"check your user catalog if you have one" message. This skill closes that gap.
|
|
27
|
+
|
|
28
|
+
## When to Use
|
|
29
|
+
|
|
30
|
+
- First-time setup for a new project or team — "we need to configure company
|
|
31
|
+
knowledge for canary"
|
|
32
|
+
- `canary-ci-ready` or `canary-failure-impact` fell back to the generic
|
|
33
|
+
user-catalog message and the user wants real investigation instead
|
|
34
|
+
- `canary company-knowledge show` reports "No company knowledge configured"
|
|
35
|
+
- Re-running setup to add a field that was skipped the first time (safe — `init`
|
|
36
|
+
merges onto existing values by default)
|
|
37
|
+
- NOT for storing secrets, API keys, or tokens — this file holds pointers only;
|
|
38
|
+
the CLI's secret heuristic (`_looks_like_secret`) rejects
|
|
39
|
+
`sk-`/`token`/`bearer`-shaped values and anything over 128 chars outside
|
|
40
|
+
`notes`
|
|
41
|
+
- NOT for company-specific proprietary content (client names, internal runbooks,
|
|
42
|
+
populated data) — per this repo's open-core boundary (`AGENTS.md`), that lives
|
|
43
|
+
only in a private overlay under `.canary/skills/` or the org's own tooling,
|
|
44
|
+
reached _via_ the pointers this file stores
|
|
45
|
+
|
|
46
|
+
## What This Skill Cannot Automate
|
|
47
|
+
|
|
48
|
+
Every field in `.canary/company.json` is org-specific and cannot be reliably
|
|
49
|
+
inferred from the codebase alone — this repo is public/open-core by design, so
|
|
50
|
+
nothing in it names a real company, Jira project, or internal host. Don't claim
|
|
51
|
+
otherwise. What this skill _can_ do:
|
|
52
|
+
|
|
53
|
+
- Scaffold the file and `.gitignore` entry so it exists and is never
|
|
54
|
+
accidentally committed
|
|
55
|
+
- Prompt for each field with the exact validation format the CLI expects, so the
|
|
56
|
+
user isn't guessing at schema
|
|
57
|
+
- Detect when a value looks like a secret and refuse it before it reaches disk
|
|
58
|
+
- Merge onto existing values, so re-running is always safe
|
|
59
|
+
|
|
60
|
+
What it cannot do: know your Confluence space key, your Jira project prefix, or
|
|
61
|
+
which MCP server your org runs. Those come from the user.
|
|
62
|
+
|
|
63
|
+
## Process
|
|
64
|
+
|
|
65
|
+
### Phase 1: CHECK — Does It Already Exist?
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
canary company-knowledge show
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- **"No company knowledge configured"** → proceed to Phase 2 (fresh scaffold).
|
|
72
|
+
- **Populated output** → note which fields are already set (shown with
|
|
73
|
+
`sources:` — `~/.canary/company.json`, `.canary/company.json`, or an env
|
|
74
|
+
layer). Proceed to Phase 2 in merge mode (no `--force`) so existing values
|
|
75
|
+
survive as defaults.
|
|
76
|
+
- **`⚠` error line** (secret-like value or malformed JSON in an existing layer)
|
|
77
|
+
→ surface the exact warning to the user before continuing; that layer is being
|
|
78
|
+
skipped entirely until fixed.
|
|
79
|
+
|
|
80
|
+
### Phase 2: SCAFFOLD — Run the Interactive Init
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
canary company-knowledge init
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Walk the user through each prompt. For each field, explain what it's for and
|
|
87
|
+
give the expected shape before they answer — the CLI accepts blank input to skip
|
|
88
|
+
or keep the current value:
|
|
89
|
+
|
|
90
|
+
| Field | Format | Purpose |
|
|
91
|
+
| -------------------- | ---------------------------------------------------------- | ---------------------------------------------- |
|
|
92
|
+
| `confluence_spaces` | comma-separated, uppercase (`QA, ENG`) | spaces the LLM should consult for org docs |
|
|
93
|
+
| `jira_projects` | comma-separated, uppercase (`PROJ, OPS`) | projects for ticket cross-referencing |
|
|
94
|
+
| `internal_doc_urls` | one URL per line, `http(s)://` only | specific reference docs to fetch via MCP |
|
|
95
|
+
| `internal_domains` | comma-separated hostnames (`corp.example.com`) | flags internal-only URLs in generated content |
|
|
96
|
+
| `mcp_servers` | comma-separated identifiers (`plugin_atlassian_atlassian`) | which configured MCP server(s) back the above |
|
|
97
|
+
| `claude_code_skills` | comma-separated slugs (`team:skill-name`) | project-overlay skills to surface as available |
|
|
98
|
+
| `notes` | free text, ≤2048 chars, no secrets | anything else the LLM should know |
|
|
99
|
+
|
|
100
|
+
Fields not prompted by `init` (`dashboard_url`, `dashboard_token_env`,
|
|
101
|
+
`otel_exporter_endpoint`) can be added by hand-editing the JSON afterward —
|
|
102
|
+
mention this if the user needs dashboard/OTel wiring; don't skip it silently.
|
|
103
|
+
|
|
104
|
+
If the user offers a value that looks like a credential (starts with `sk-`,
|
|
105
|
+
`token`, `bearer`, or is unusually long), stop and remind them: secrets go in
|
|
106
|
+
environment variables, never in `company.json`. The CLI will reject the whole
|
|
107
|
+
layer if one slips through — better to catch it before submitting.
|
|
108
|
+
|
|
109
|
+
### Phase 3: WIRE THE USER-CATALOG SKILL (Known Schema Gap)
|
|
110
|
+
|
|
111
|
+
`canary-ci-ready` and `canary-failure-impact` both read a `user_catalog_skill`
|
|
112
|
+
key directly from `.canary/company.json` to investigate auth/config failures.
|
|
113
|
+
**This key is not part of the CLI's validated schema** — it isn't in
|
|
114
|
+
`CompanyKnowledge`'s known fields, `company-knowledge init` never prompts for
|
|
115
|
+
it, and `company-knowledge show` will list it under "ignored unknown field" if
|
|
116
|
+
you inspect warnings. It still works for the two consuming skills because they
|
|
117
|
+
read the raw JSON file directly rather than going through the Python loader —
|
|
118
|
+
but be transparent with the user that this is an informal extension, not a
|
|
119
|
+
first-class field, until the schema catches up.
|
|
120
|
+
|
|
121
|
+
To wire it:
|
|
122
|
+
|
|
123
|
+
1. Ask the user which project-overlay skill (if any) looks up test users — e.g.
|
|
124
|
+
`team:user-lookup`. If they don't have one, skip this phase; the consuming
|
|
125
|
+
skills degrade gracefully to a generic prompt.
|
|
126
|
+
2. If they gave a normal skill slug, prefer adding it to `claude_code_skills` (a
|
|
127
|
+
real, validated field) _and_ separately hand-edit `.canary/company.json` to
|
|
128
|
+
add the literal key:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"claude_code_skills": ["team:user-lookup"],
|
|
133
|
+
"user_catalog_skill": "team:user-lookup"
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
3. Confirm the value matches what `canary skills run <user_catalog_skill>`
|
|
138
|
+
expects as an identifier (same slug format as `claude_code_skills`:
|
|
139
|
+
`^[a-z0-9][a-z0-9_-]*(:[a-z0-9][a-z0-9_-]*)?$`).
|
|
140
|
+
|
|
141
|
+
### Phase 4: VERIFY
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
canary company-knowledge show
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
- Confirm every field the user just set appears in the printed output.
|
|
148
|
+
- Confirm no `⚠` warnings (unknown fields other than the intentional
|
|
149
|
+
`user_catalog_skill` extension, dropped invalid entries, secret detections).
|
|
150
|
+
- Confirm `.gitignore` now contains a `.canary/` line — `init` adds it
|
|
151
|
+
automatically, but verify if the project already had a `.gitignore` with
|
|
152
|
+
unusual formatting.
|
|
153
|
+
- If JSON output is useful for the user's own tooling: `--json`.
|
|
154
|
+
|
|
155
|
+
## Error Handling
|
|
156
|
+
|
|
157
|
+
| Situation | What Happens | What To Do |
|
|
158
|
+
| --------------------------------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
159
|
+
| `.canary/company.json` already exists, no `--force` | `init` shows existing values as defaults and merges | Normal — just re-run `init` |
|
|
160
|
+
| Secret-like value entered | That whole layer is dropped; `show` prints a red `✗` | Remove the value, use an env var, re-run |
|
|
161
|
+
| Malformed JSON in an existing file | Layer skipped with a parse error | Fix the JSON by hand, then re-run `show` to confirm |
|
|
162
|
+
| Invalid entry format (e.g. lowercase Jira key) | Entry silently dropped, warning logged | Re-enter in the correct case/format |
|
|
163
|
+
| Unknown field in the file | Warned, not fatal, field ignored by the loader | Expected for `user_catalog_skill` today (Phase 3) — otherwise likely a typo |
|
|
164
|
+
| User has no Confluence/Jira/MCP setup at all | Every field is legitimately empty | Skip `init` entirely; `canary-ci-ready`/`canary-failure-impact` degrade to their generic prompts, which is correct behavior, not a bug |
|
|
165
|
+
|
|
166
|
+
## Examples
|
|
167
|
+
|
|
168
|
+
### Example: First-time team lead setup
|
|
169
|
+
|
|
170
|
+
**Prompt:** "Set up company knowledge for canary on this repo."
|
|
171
|
+
|
|
172
|
+
**Action:** Run `company-knowledge show` → "No company knowledge configured."
|
|
173
|
+
Run `company-knowledge init`. Walk through each field; the team lead has a
|
|
174
|
+
Confluence space (`QA`), a Jira project (`OPS`), and an Atlassian MCP server
|
|
175
|
+
(`plugin_atlassian_atlassian`) but no internal dashboard yet. Leave
|
|
176
|
+
`dashboard_url` unset. Ask about a user-catalog skill — they don't have one, so
|
|
177
|
+
Phase 3 is skipped. Verify with `show`.
|
|
178
|
+
|
|
179
|
+
### Example: Retrofitting `user_catalog_skill` onto an existing file
|
|
180
|
+
|
|
181
|
+
**Prompt:** "`canary-ci-ready` keeps telling me to check my user catalog
|
|
182
|
+
manually, but we have a skill for that."
|
|
183
|
+
|
|
184
|
+
**Action:** Run `show` — confirm `.canary/company.json` already has
|
|
185
|
+
`confluence_spaces`/`jira_projects` set from a prior run. Ask for the skill slug
|
|
186
|
+
(`team:test-user-lookup`). Add it to both `claude_code_skills` and the raw
|
|
187
|
+
`user_catalog_skill` key per Phase 3. Re-run `show` to confirm no new warnings,
|
|
188
|
+
then re-run `canary-ci-ready` on a known failing auth test to confirm the lookup
|
|
189
|
+
now fires.
|
|
190
|
+
|
|
191
|
+
## Related Skills
|
|
192
|
+
|
|
193
|
+
- [`canary-ci-ready`](../canary-ci-ready/SKILL.md) — consumes
|
|
194
|
+
`user_catalog_skill` for auth/config failure investigation
|
|
195
|
+
- [`canary-failure-impact`](../canary-failure-impact/SKILL.md) — same
|
|
196
|
+
investigation pattern, different trigger context
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: canary-critical-areas
|
|
3
|
+
description: >
|
|
4
|
+
Risk-based test prioritisation. Given a codebase or diff, identifies which
|
|
5
|
+
areas carry the most risk using git churn, downstream dependents,
|
|
6
|
+
business-critical signals, and existing coverage depth. Produces a ranked list
|
|
7
|
+
with recommended test types per area.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Canary: Critical Areas
|
|
11
|
+
|
|
12
|
+
Identifies the highest-risk areas of a codebase so test effort goes where it
|
|
13
|
+
matters most. Uses multiple signals, degrades gracefully when advanced tooling
|
|
14
|
+
is unavailable.
|
|
15
|
+
|
|
16
|
+
## When to Use
|
|
17
|
+
|
|
18
|
+
- Before writing new tests: "where should I focus?"
|
|
19
|
+
|
|
20
|
+
- After a large diff lands: "what did this change put at risk?"
|
|
21
|
+
|
|
22
|
+
- As Phase 1 of `/canary-test-pipeline`
|
|
23
|
+
|
|
24
|
+
- When asked to prioritise test coverage
|
|
25
|
+
|
|
26
|
+
## Signals
|
|
27
|
+
|
|
28
|
+
Collect all available signals, score each area, and rank by composite risk
|
|
29
|
+
score.
|
|
30
|
+
|
|
31
|
+
### 1. Churn / hotspot (always available)
|
|
32
|
+
|
|
33
|
+
**With harness MCP available:** call `detect_anomalies` (metric `hotspotScore`,
|
|
34
|
+
plus its co-change / single-point-of-failure signals). Harness's hotspot score
|
|
35
|
+
already blends churn with structural risk, so use it directly as this signal and
|
|
36
|
+
skip the raw `git log` pass. Normalise the returned scores to 0–1.
|
|
37
|
+
|
|
38
|
+
**Fallback (no MCP):**
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
git log --stat --since="90 days ago" -- <path> | grep -c "^"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Files changed most frequently in the last 90 days score higher. Normalise to 0–1
|
|
45
|
+
across all files in scope.
|
|
46
|
+
|
|
47
|
+
### 2. Downstream dependents
|
|
48
|
+
|
|
49
|
+
**With harness MCP available:** call `get_impact` for each candidate file
|
|
50
|
+
(`filePath`, `mode: "summary"`) and read the affected-node counts it returns
|
|
51
|
+
(tests / docs / code grouped by type). This is the purpose-built impact
|
|
52
|
+
primitive — do **not** hand-walk `get_relationships` edge-by-edge; `get_impact`
|
|
53
|
+
already computes the transitive downstream set. More affected nodes ⇒ higher
|
|
54
|
+
score.
|
|
55
|
+
|
|
56
|
+
**Fallback (no MCP):** scan for `import` statements referencing each file using
|
|
57
|
+
`grep -r`. Count unique files that import each candidate.
|
|
58
|
+
|
|
59
|
+
Files with more inbound dependents score higher — a change here breaks more.
|
|
60
|
+
|
|
61
|
+
### 3. Business-critical / critical-path flags
|
|
62
|
+
|
|
63
|
+
**With harness MCP available:** call `get_critical_paths` and add a fixed boost
|
|
64
|
+
(+0.3) to any area whose functions appear in the returned perf-critical set.
|
|
65
|
+
Also query `ask_graph` for `business_fact` nodes associated with each area; any
|
|
66
|
+
business-critical annotation adds the same +0.3 boost (apply the boost once,
|
|
67
|
+
whichever signal fires).
|
|
68
|
+
|
|
69
|
+
**Fallback:** skip this signal silently (do not penalise the score).
|
|
70
|
+
|
|
71
|
+
### 4. Coverage depth boost
|
|
72
|
+
|
|
73
|
+
If `.canary/test-inventory.json` is present: files whose endpoints are at depth
|
|
74
|
+
0 or 1 receive a boost (+0.15) — low depth in a high-churn file is especially
|
|
75
|
+
risky.
|
|
76
|
+
|
|
77
|
+
## Risk Score
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
risk_score = (churn * 0.35) + (dependents * 0.35) + (business_critical * 0.30) + depth_boost
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Capped at 1.0. Round to 2 decimal places.
|
|
84
|
+
|
|
85
|
+
## Output
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
Critical areas — <repo> (<N> files analysed)
|
|
89
|
+
|
|
90
|
+
1. src/loyalty/points.service.ts risk 0.92 ████████████
|
|
91
|
+
signals: high churn · 12 dependents · business_critical
|
|
92
|
+
recommended: api + integration tests
|
|
93
|
+
|
|
94
|
+
2. src/billing/charge.service.ts risk 0.78 ██████████
|
|
95
|
+
signals: high churn · billing domain
|
|
96
|
+
recommended: api tests · /canary-failure-impact suggested
|
|
97
|
+
|
|
98
|
+
...
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Show at most 10 areas. If more than 10 qualify, note the total and offer to show
|
|
102
|
+
all.
|
|
103
|
+
|
|
104
|
+
## Optional Artifact
|
|
105
|
+
|
|
106
|
+
When `--save` flag is passed (or when invoked by `/canary-test-pipeline`), write
|
|
107
|
+
`.canary/critical-areas.json`:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"generated": "<ISO timestamp>",
|
|
112
|
+
"areas": [
|
|
113
|
+
{
|
|
114
|
+
"path": "src/loyalty/points.service.ts",
|
|
115
|
+
"risk_score": 0.92,
|
|
116
|
+
"signals": ["high_churn", "many_dependents", "business_critical"],
|
|
117
|
+
"recommended_test_types": ["api", "integration"],
|
|
118
|
+
"summary": "High-churn service with 12 downstream dependents"
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
This file is consumed as opt-in context by `/canary-edge-cases` and
|
|
125
|
+
`/canary-failure-impact`.
|
|
126
|
+
|
|
127
|
+
## Flags
|
|
128
|
+
|
|
129
|
+
- `--diff <git ref>` — scope analysis to files changed in a diff
|
|
130
|
+
(`git diff <ref>...HEAD`)
|
|
131
|
+
|
|
132
|
+
- `--save` — write `critical-areas.json`
|
|
133
|
+
|
|
134
|
+
## Related skills
|
|
135
|
+
|
|
136
|
+
- `/canary-ci-ready` — check 4 consumes `critical-areas.json`
|
|
137
|
+
|
|
138
|
+
- `/canary-edge-cases` — focuses edge cases on critical areas when JSON present
|
|
139
|
+
|
|
140
|
+
- `/canary-failure-impact` — focuses tracing on critical paths when JSON present
|
|
141
|
+
|
|
142
|
+
- `/canary-test-pipeline` — Phase 1
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: canary-critical-areas
|
|
2
|
+
version: '1.0.0'
|
|
3
|
+
description:
|
|
4
|
+
Risk-rank a codebase or diff by git churn, downstream dependents,
|
|
5
|
+
business-critical signals, and coverage depth; outputs a ranked list with
|
|
6
|
+
recommended test types per area.
|
|
7
|
+
stability: static
|
|
8
|
+
triggers:
|
|
9
|
+
- manual
|
|
10
|
+
platforms:
|
|
11
|
+
- claude-code
|
|
12
|
+
type: rigid
|
|
13
|
+
tools: []
|
|
14
|
+
tier: 1
|
|
15
|
+
depends_on:
|
|
16
|
+
- canary-ci-ready
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: canary-edge-case-discovery
|
|
3
|
+
description: >
|
|
4
|
+
Given a feature description, function signature, or existing test suite,
|
|
5
|
+
surfaces edge cases worth testing across six categories. Explanation depth
|
|
6
|
+
scales to user skill level. Optionally focuses on critical areas when
|
|
7
|
+
critical-areas.json is present.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Canary: Edge Case Discovery
|
|
11
|
+
|
|
12
|
+
Surfaces the edge cases that tests typically miss: the inputs and conditions
|
|
13
|
+
that work in demos but break in production.
|
|
14
|
+
|
|
15
|
+
## When to Use
|
|
16
|
+
|
|
17
|
+
- After writing happy-path tests: "what else should I test?"
|
|
18
|
+
|
|
19
|
+
- When reviewing a feature for robustness
|
|
20
|
+
|
|
21
|
+
- As Phase 2 of `/canary-test-pipeline`
|
|
22
|
+
|
|
23
|
+
- When asked "what edge cases should I cover?"
|
|
24
|
+
|
|
25
|
+
## Input
|
|
26
|
+
|
|
27
|
+
Provide one of:
|
|
28
|
+
|
|
29
|
+
- A feature description: `"points accrual on tier upgrade"`
|
|
30
|
+
|
|
31
|
+
- A function signature:
|
|
32
|
+
`accruePoints(memberId: string, amount: number): Promise<Result>`
|
|
33
|
+
|
|
34
|
+
- A test file path: `tests/loyalty/points.spec.ts`
|
|
35
|
+
|
|
36
|
+
- Or nothing — Canary will infer from open files and recent context
|
|
37
|
+
|
|
38
|
+
If `.canary/critical-areas.json` is present, focus edge case discovery on the
|
|
39
|
+
highest-risk areas first (rank_score ≥ 0.6).
|
|
40
|
+
|
|
41
|
+
## The Six Categories
|
|
42
|
+
|
|
43
|
+
For each category, generate specific, actionable cases — not generic advice.
|
|
44
|
+
|
|
45
|
+
### 1. Boundary values
|
|
46
|
+
|
|
47
|
+
Zero, negative, max integer, empty string, null, undefined, one-off-by-one. For
|
|
48
|
+
amounts: 0, 1, MAX_SAFE_INTEGER, -1, 0.001 (floating point). For strings: empty
|
|
49
|
+
string, whitespace-only, max-length + 1 character.
|
|
50
|
+
|
|
51
|
+
### 2. Race conditions
|
|
52
|
+
|
|
53
|
+
Concurrent writes to the same resource. Double-submit (user clicks twice). Stale
|
|
54
|
+
reads after an update. Lock contention. Out-of-order async responses.
|
|
55
|
+
|
|
56
|
+
### 3. Locale and timezone
|
|
57
|
+
|
|
58
|
+
DST transition times. Dates at midnight UTC vs local time. Non-ASCII characters
|
|
59
|
+
in names and addresses. RTL text in string fields. Locale-specific number
|
|
60
|
+
formats (1.000,00 vs 1,000.00). Emoji in text fields.
|
|
61
|
+
|
|
62
|
+
### 4. Partial network
|
|
63
|
+
|
|
64
|
+
Request timeout mid-flight. Dropped connection after partial response. Retry
|
|
65
|
+
storms (client retries while server is still processing). Response truncation.
|
|
66
|
+
|
|
67
|
+
### 5. Unexpected input shapes
|
|
68
|
+
|
|
69
|
+
Extra fields the schema doesn't expect. Missing required fields. Wrong types
|
|
70
|
+
(string where number expected). SQL or script injection strings. Deeply nested
|
|
71
|
+
objects. Arrays where scalars expected.
|
|
72
|
+
|
|
73
|
+
### 6. Accessibility
|
|
74
|
+
|
|
75
|
+
Keyboard-only navigation paths. Missing ARIA labels. Focus trap conditions.
|
|
76
|
+
Screen reader text for dynamic content. Colour contrast for status indicators.
|
|
77
|
+
_(Only include if the input is a UI feature or test.)_
|
|
78
|
+
|
|
79
|
+
## Output Depth
|
|
80
|
+
|
|
81
|
+
**Consult the resolved persona; do not infer one here.** The engine owns that
|
|
82
|
+
decision (issue #462) so every skill adapts the same way and a downstream
|
|
83
|
+
overlay has one place to override.
|
|
84
|
+
|
|
85
|
+
Resolve it in this order:
|
|
86
|
+
|
|
87
|
+
1. `--level <id>` if the caller passed one. It is the explicit override and
|
|
88
|
+
always wins.
|
|
89
|
+
2. The `persona` block on a `canary__analyze_file` response. It carries `id`,
|
|
90
|
+
`depth`, `formats`, `reasoning`, plus `source`, `reason`, and `signals` — the
|
|
91
|
+
evidence behind the choice.
|
|
92
|
+
3. Neither available → use `junior`, the engine's fallback. Erring explanatory
|
|
93
|
+
is deliberate: over-explaining is a mild annoyance, under-explaining silently
|
|
94
|
+
fails a manual tester.
|
|
95
|
+
|
|
96
|
+
Render from the persona's `depth`, not from its `id` — an overlay may add
|
|
97
|
+
personas this table never listed:
|
|
98
|
+
|
|
99
|
+
| `depth` | Output style |
|
|
100
|
+
| -------- | ----------------------------------- |
|
|
101
|
+
| `terse` | Bullet list of cases only |
|
|
102
|
+
| `brief` | Cases + one-line _why this matters_ |
|
|
103
|
+
| `guided` | Cases + numbered reproduction steps |
|
|
104
|
+
|
|
105
|
+
When `reasoning` is true, say which persona shaped the output and why —
|
|
106
|
+
`persona.reason` is written to be quoted.
|
|
107
|
+
|
|
108
|
+
Read `source` before trusting the persona, and treat the three values
|
|
109
|
+
differently:
|
|
110
|
+
|
|
111
|
+
- `explicit` — the reader chose this. Do not second-guess it.
|
|
112
|
+
- `detected` — inferred from at least two independent signals about the project.
|
|
113
|
+
Reliable enough to act on, still a guess; mention it is overridable with
|
|
114
|
+
`CANARY_PERSONA` or `--level` if the depth seems wrong for them.
|
|
115
|
+
- `fallback` — the engine **declined** to guess, which is the common case. That
|
|
116
|
+
is not a failure and not a reason to go hunting for signals of your own: it
|
|
117
|
+
means the evidence did not clear the floor, and re-deriving an audience here
|
|
118
|
+
is exactly the hand-rolling this section replaced. Use the persona as given.
|
|
119
|
+
|
|
120
|
+
**Never infer `terse` on your own.** Stripping explanation from a reader who
|
|
121
|
+
turns out to be a manual tester is the expensive direction of this mistake;
|
|
122
|
+
`fallback` is deliberately explanatory for that reason. Note that `manual` is
|
|
123
|
+
not inferable from a file analysis at all — it is reached by an explicit choice
|
|
124
|
+
— so a `fallback` persona may well be a manual tester.
|
|
125
|
+
|
|
126
|
+
The shipped personas are `sdet` (terse), `junior` (brief), and `manual`
|
|
127
|
+
(guided); the definitions live in `ts/src/data/personas/registry.json`.
|
|
128
|
+
|
|
129
|
+
## Output Format (`sdet` example)
|
|
130
|
+
|
|
131
|
+
```text
|
|
132
|
+
Edge cases — points accrual on tier upgrade
|
|
133
|
+
|
|
134
|
+
Boundary values
|
|
135
|
+
· amount = 0
|
|
136
|
+
· amount = MAX_SAFE_INTEGER
|
|
137
|
+
· memberId empty string
|
|
138
|
+
· memberId with special characters
|
|
139
|
+
|
|
140
|
+
Race conditions
|
|
141
|
+
· concurrent accrual calls for the same memberId
|
|
142
|
+
· double-submit within 100ms
|
|
143
|
+
|
|
144
|
+
...
|
|
145
|
+
|
|
146
|
+
Suggested next: /canary-write-test "add edge case tests for accruePoints boundary values"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Flags
|
|
150
|
+
|
|
151
|
+
- `--level sdet|junior|manual` — output depth. Overrides the resolved persona;
|
|
152
|
+
the default is the persona the engine resolved (see **Output Depth**).
|
|
153
|
+
|
|
154
|
+
## Related skills
|
|
155
|
+
|
|
156
|
+
- `/canary-critical-areas` — produces `critical-areas.json` used for focus
|
|
157
|
+
|
|
158
|
+
- `/canary-write-test` — generates tests for the surfaced cases
|
|
159
|
+
|
|
160
|
+
- `/canary-test-pipeline` — Phase 2
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: canary-edge-case-discovery
|
|
2
|
+
version: '1.0.0'
|
|
3
|
+
description:
|
|
4
|
+
Surface edge cases worth testing across six categories from a feature
|
|
5
|
+
description, function signature, or existing suite; explanation depth scales
|
|
6
|
+
to user skill level.
|
|
7
|
+
stability: static
|
|
8
|
+
triggers:
|
|
9
|
+
- manual
|
|
10
|
+
platforms:
|
|
11
|
+
- claude-code
|
|
12
|
+
type: rigid
|
|
13
|
+
tools: []
|
|
14
|
+
tier: 1
|
|
15
|
+
depends_on:
|
|
16
|
+
- canary-ci-ready
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: canary-fail-fast
|
|
3
|
+
description:
|
|
4
|
+
Surface test failures fast and loud — audit a Playwright config for fail-fast
|
|
5
|
+
knobs (maxFailures/forbidOnly/retries) and print a loud, categorized failure
|
|
6
|
+
digest to the CI log + ::error annotations at run end, failing the step so the
|
|
7
|
+
signal can't be missed. Self-contained (bundles its own Playwright JSON parser
|
|
8
|
+
and failure categorizer).
|
|
9
|
+
cli: scripts/cli.mjs
|
|
10
|
+
requires: [node>=20]
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Canary Fail-Fast
|
|
14
|
+
|
|
15
|
+
Make test failures **fast** (abort a broken run early) and **loud** (surface in
|
|
16
|
+
the CI log + Checks, not a file). Two halves:
|
|
17
|
+
|
|
18
|
+
1. **Fail-fast config audit** — flags the absence of `maxFailures`,
|
|
19
|
+
`forbidOnly`, and `retries` in a `playwright.config.*`.
|
|
20
|
+
2. **Loud run-end digest** — a terse, categorized failure summary to stdout +
|
|
21
|
+
`::error` annotations, with a non-zero exit.
|
|
22
|
+
|
|
23
|
+
Self-contained: it bundles a minimal Playwright JSON parser and the failure
|
|
24
|
+
categorizer, so it has no dependency on any other skill.
|
|
25
|
+
|
|
26
|
+
## Fail-fast config (paste into `playwright.config.ts`)
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
export default defineConfig({
|
|
30
|
+
// Fail fast in CI: abort once enough has clearly broken, never on local runs.
|
|
31
|
+
forbidOnly: !!process.env.CI, // a stray test.only fails the build
|
|
32
|
+
maxFailures: process.env.CI ? 10 : 0, // stop the run after 10 failures in CI
|
|
33
|
+
retries: process.env.CI ? 2 : 0, // absorb flakes in CI; surface them locally
|
|
34
|
+
// ...your existing config
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Invocation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Loud failure digest from a Playwright JSON run (exits non-zero on failures):
|
|
42
|
+
canary skills run canary-fail-fast -- --results test-results/results.json
|
|
43
|
+
|
|
44
|
+
# Audit the fail-fast config:
|
|
45
|
+
canary skills run canary-fail-fast -- --config playwright.config.ts
|
|
46
|
+
|
|
47
|
+
# Both at once:
|
|
48
|
+
canary skills run canary-fail-fast -- \
|
|
49
|
+
--results test-results/results.json \
|
|
50
|
+
--config playwright.config.ts
|
|
51
|
+
|
|
52
|
+
# Usage and the full flag list (exits 0):
|
|
53
|
+
canary skills run canary-fail-fast -- --help
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
At least one of `--results` / `--config` is required. The digest exits `1` when
|
|
57
|
+
any test failed (so the CI step fails); the config audit alone never fails the
|
|
58
|
+
build.
|
|
59
|
+
|
|
60
|
+
## CI wiring (GitHub Actions)
|
|
61
|
+
|
|
62
|
+
Run after the Playwright step with `if: always()` so the digest surfaces even
|
|
63
|
+
when the test step already failed:
|
|
64
|
+
|
|
65
|
+
```yaml
|
|
66
|
+
- name: Run Playwright
|
|
67
|
+
run:
|
|
68
|
+
npx playwright test --reporter=json --output-file=test-results/results.json
|
|
69
|
+
|
|
70
|
+
- name: Fail-fast digest
|
|
71
|
+
if: always()
|
|
72
|
+
run: |
|
|
73
|
+
canary skills run canary-fail-fast -- \
|
|
74
|
+
--results test-results/results.json
|
|
75
|
+
```
|