@erclx/aitk 0.22.1 → 0.24.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/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/claude-roadmap/references/roadmap.md +12 -2
- package/claude/skills/claude-standards-audit/SKILL.md +3 -3
- package/claude/skills/create-standard/references/snippets.md +9 -0
- package/claude/skills/git-branch/references/branch.md +12 -1
- package/claude/skills/git-commit/references/commit.md +11 -1
- package/claude/skills/git-issue/references/issue.md +10 -0
- package/claude/skills/git-pr/references/branch.md +12 -1
- package/claude/skills/git-pr/references/pr.md +12 -1
- package/claude/skills/git-split/references/branch.md +12 -1
- package/claude/skills/git-split/references/pr.md +12 -1
- package/claude/skills/git-stage/references/commit.md +11 -1
- package/docs/agents.md +10 -5
- package/package.json +1 -1
- package/src/commands/sandbox.ts +99 -5
- package/src/sandbox/census.ts +228 -0
- package/standards/architecture.md +10 -2
- package/standards/bundled/branch.md +12 -1
- package/standards/bundled/commit.md +11 -1
- package/standards/bundled/issue.md +10 -0
- package/standards/bundled/pr.md +12 -1
- package/standards/bundled/roadmap.md +12 -2
- package/standards/bundled/snippets.md +9 -0
- package/standards/context.md +11 -0
- package/standards/design.md +9 -1
- package/standards/diagrams.md +13 -2
- package/standards/prose.md +11 -0
- package/standards/readme.md +9 -0
- package/standards/requirements.md +10 -1
- package/standards/rule.md +10 -0
- package/standards/skill.md +11 -0
- package/standards/standard.md +24 -4
- package/standards/tasks.md +11 -0
- package/standards/versioning.md +11 -0
- package/standards/wireframes.md +11 -1
- package/claude/skills/claude-standards-audit/references/branch.md +0 -49
- package/claude/skills/claude-standards-audit/references/pr.md +0 -124
|
@@ -10,6 +10,17 @@ Applies to `.claude/ROADMAP.md`. Sequences the scope from `.claude/REQUIREMENTS.
|
|
|
10
10
|
|
|
11
11
|
The roadmap is one scannable table. That is what keeps it distinct from `.claude/tasks/`: the roadmap is an overview read at a glance, while tasks are worked one file at a time.
|
|
12
12
|
|
|
13
|
+
## Scope
|
|
14
|
+
|
|
15
|
+
Governs the sequencing document at `.claude/ROADMAP.md`: the version table, its columns, and its lifecycle.
|
|
16
|
+
|
|
17
|
+
Does not govern:
|
|
18
|
+
|
|
19
|
+
- What the scope is, which the roadmap sequences rather than defines: `requirements.md`
|
|
20
|
+
- Task files, outcomes, and board state: `tasks.md`
|
|
21
|
+
- Phase-label format and semver discipline: `versioning.md`
|
|
22
|
+
- Rationale for a technical choice: `architecture.md`
|
|
23
|
+
|
|
13
24
|
## What goes in
|
|
14
25
|
|
|
15
26
|
- One row per version, ordered top to bottom by sequence
|
|
@@ -20,9 +31,8 @@ The roadmap is one scannable table. That is what keeps it distinct from `.claude
|
|
|
20
31
|
|
|
21
32
|
## What does not go in
|
|
22
33
|
|
|
23
|
-
- Task breakdown, checkboxes, or per-feature file lists
|
|
34
|
+
- Task breakdown, checkboxes, or per-feature file lists
|
|
24
35
|
- Implementation detail, API names, or component references
|
|
25
|
-
- Rationale for tech choices. That belongs in `.claude/ARCHITECTURE.md`.
|
|
26
36
|
- Sentence-long cells. Keep each cell terse so the table stays scannable.
|
|
27
37
|
|
|
28
38
|
## Format
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: claude-standards-audit
|
|
3
|
-
description: Audits changed markdown files against applicable authoring standards (prose, skill, readme
|
|
3
|
+
description: Audits changed markdown files against applicable authoring standards (prose, skill, readme) and reports violations without fixing. Maps each file to its standards, greps for banned tokens, and groups findings by file. Use when asked to "audit prose", "audit standards", "check standards", "standards audit", or after editing markdown where standards compliance matters. Do NOT fix violations. Reporting only.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Claude standards audit
|
|
@@ -44,11 +44,11 @@ For each changed markdown file, pick the applicable standards:
|
|
|
44
44
|
- Any markdown with prose: `.claude/standards/prose.md`
|
|
45
45
|
- `SKILL.md` under `.claude/skills/` or `claude/skills/`: also `.claude/standards/skill.md`
|
|
46
46
|
- `README.md` at any level: also `.claude/standards/readme.md`
|
|
47
|
-
- Branch names proposed in the session: `${CLAUDE_SKILL_DIR}/references/branch.md`
|
|
48
|
-
- PR titles or bodies drafted in the session: `${CLAUDE_SKILL_DIR}/references/pr.md`
|
|
49
47
|
|
|
50
48
|
Read a standard from `${CLAUDE_SKILL_DIR}/../../standards/` instead when the project does not have it.
|
|
51
49
|
|
|
50
|
+
Every mapping names a changed markdown file, which is the only thing Step 1 produces. Text that never lands in the tree, such as a branch name or a pull request body, is checked by the skill that publishes it rather than here.
|
|
51
|
+
|
|
52
52
|
## Step 3: read standards and audit
|
|
53
53
|
|
|
54
54
|
Read each applicable standard once. For each changed file, audit against every rule:
|
|
@@ -6,6 +6,15 @@ consumers: create-standard
|
|
|
6
6
|
|
|
7
7
|
# Snippet reference
|
|
8
8
|
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
Governs a snippet file: what one is for, how it is invoked, and the structure of its body.
|
|
12
|
+
|
|
13
|
+
Does not govern:
|
|
14
|
+
|
|
15
|
+
- Skill folders, which carry frontmatter, references, and scripts a snippet has none of: `skill.md`
|
|
16
|
+
- Voice, punctuation, and formatting in snippet prose: `prose.md`
|
|
17
|
+
|
|
9
18
|
## What a snippet is
|
|
10
19
|
|
|
11
20
|
A snippet is a short, focused prompt stored as a plain markdown file. Invoke one to insert a prepared instruction into any AI chat without retyping it. Each snippet covers one purpose. If a prompt needs headers or multiple goals, use a system prompt instead.
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Branch reference
|
|
3
3
|
description: Branch naming format and type conventions
|
|
4
|
-
consumers: git-branch, git-split, git-pr
|
|
4
|
+
consumers: git-branch, git-split, git-pr
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Branch reference
|
|
8
8
|
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
Governs a git branch name: its structure, its length, and the type vocabulary it draws from.
|
|
12
|
+
|
|
13
|
+
Does not govern:
|
|
14
|
+
|
|
15
|
+
- Commit subject format, which shares the type vocabulary: `commit.md`
|
|
16
|
+
- Pull request title and body: `pr.md`
|
|
17
|
+
- Whether a phase label may appear in a branch name: `versioning.md`
|
|
18
|
+
- Deriving an output filename from a branch name, which is a transform the skill running it owns
|
|
19
|
+
|
|
9
20
|
## Format
|
|
10
21
|
|
|
11
22
|
- Structure: `<type>/<description>` or `<type>/<ticket>-<description>`
|
|
@@ -6,6 +6,16 @@ consumers: git-commit, git-stage
|
|
|
6
6
|
|
|
7
7
|
# Commit message reference
|
|
8
8
|
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
Governs a git commit message: subject structure, the type and scope vocabulary, and the body.
|
|
12
|
+
|
|
13
|
+
Does not govern:
|
|
14
|
+
|
|
15
|
+
- Branch naming, which shares the type vocabulary: `branch.md`
|
|
16
|
+
- Pull request title and body, which share the subject form: `pr.md`
|
|
17
|
+
- Whether a phase label or a semver tag may appear in a subject: `versioning.md`
|
|
18
|
+
|
|
9
19
|
## Format
|
|
10
20
|
|
|
11
21
|
- Structure: `<type>(<scope>): <subject>`
|
|
@@ -26,7 +36,7 @@ consumers: git-commit, git-stage
|
|
|
26
36
|
- `ci`: CI/CD pipeline changes (GitHub Actions)
|
|
27
37
|
- `revert`: revert a previous commit
|
|
28
38
|
|
|
29
|
-
## Scope
|
|
39
|
+
## Scope vocabulary
|
|
30
40
|
|
|
31
41
|
- Single lowercase word representing a system component
|
|
32
42
|
- Prefer single word
|
|
@@ -6,6 +6,16 @@ consumers: git-issue
|
|
|
6
6
|
|
|
7
7
|
# Issue reference
|
|
8
8
|
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
Governs a tracker issue: its title, its labels, and the sections its body carries.
|
|
12
|
+
|
|
13
|
+
Does not govern:
|
|
14
|
+
|
|
15
|
+
- Pull request title and body: `pr.md`
|
|
16
|
+
- Whether a phase label may appear in issue text: `versioning.md`
|
|
17
|
+
- Voice, punctuation, and banned words in issue prose: `prose.md`
|
|
18
|
+
|
|
9
19
|
## Title
|
|
10
20
|
|
|
11
21
|
- Format: `<type>: <subject>`
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Branch reference
|
|
3
3
|
description: Branch naming format and type conventions
|
|
4
|
-
consumers: git-branch, git-split, git-pr
|
|
4
|
+
consumers: git-branch, git-split, git-pr
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Branch reference
|
|
8
8
|
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
Governs a git branch name: its structure, its length, and the type vocabulary it draws from.
|
|
12
|
+
|
|
13
|
+
Does not govern:
|
|
14
|
+
|
|
15
|
+
- Commit subject format, which shares the type vocabulary: `commit.md`
|
|
16
|
+
- Pull request title and body: `pr.md`
|
|
17
|
+
- Whether a phase label may appear in a branch name: `versioning.md`
|
|
18
|
+
- Deriving an output filename from a branch name, which is a transform the skill running it owns
|
|
19
|
+
|
|
9
20
|
## Format
|
|
10
21
|
|
|
11
22
|
- Structure: `<type>/<description>` or `<type>/<ticket>-<description>`
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Pull request reference
|
|
3
3
|
description: Pull request title and body conventions
|
|
4
|
-
consumers: git-split, git-pr
|
|
4
|
+
consumers: git-split, git-pr
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Pull request reference
|
|
8
8
|
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
Governs a pull request title and body: their format and the sections the body carries.
|
|
12
|
+
|
|
13
|
+
Does not govern:
|
|
14
|
+
|
|
15
|
+
- Commit subject format, which shares the title form: `commit.md`
|
|
16
|
+
- Branch naming: `branch.md`
|
|
17
|
+
- Whether a phase label or a semver tag may appear in a title or body: `versioning.md`
|
|
18
|
+
- Voice, punctuation, and banned words in pull request prose: `prose.md`
|
|
19
|
+
|
|
9
20
|
## Title
|
|
10
21
|
|
|
11
22
|
- Format: `<type>(<scope>): <subject>`
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Branch reference
|
|
3
3
|
description: Branch naming format and type conventions
|
|
4
|
-
consumers: git-branch, git-split, git-pr
|
|
4
|
+
consumers: git-branch, git-split, git-pr
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Branch reference
|
|
8
8
|
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
Governs a git branch name: its structure, its length, and the type vocabulary it draws from.
|
|
12
|
+
|
|
13
|
+
Does not govern:
|
|
14
|
+
|
|
15
|
+
- Commit subject format, which shares the type vocabulary: `commit.md`
|
|
16
|
+
- Pull request title and body: `pr.md`
|
|
17
|
+
- Whether a phase label may appear in a branch name: `versioning.md`
|
|
18
|
+
- Deriving an output filename from a branch name, which is a transform the skill running it owns
|
|
19
|
+
|
|
9
20
|
## Format
|
|
10
21
|
|
|
11
22
|
- Structure: `<type>/<description>` or `<type>/<ticket>-<description>`
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Pull request reference
|
|
3
3
|
description: Pull request title and body conventions
|
|
4
|
-
consumers: git-split, git-pr
|
|
4
|
+
consumers: git-split, git-pr
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Pull request reference
|
|
8
8
|
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
Governs a pull request title and body: their format and the sections the body carries.
|
|
12
|
+
|
|
13
|
+
Does not govern:
|
|
14
|
+
|
|
15
|
+
- Commit subject format, which shares the title form: `commit.md`
|
|
16
|
+
- Branch naming: `branch.md`
|
|
17
|
+
- Whether a phase label or a semver tag may appear in a title or body: `versioning.md`
|
|
18
|
+
- Voice, punctuation, and banned words in pull request prose: `prose.md`
|
|
19
|
+
|
|
9
20
|
## Title
|
|
10
21
|
|
|
11
22
|
- Format: `<type>(<scope>): <subject>`
|
|
@@ -6,6 +6,16 @@ consumers: git-commit, git-stage
|
|
|
6
6
|
|
|
7
7
|
# Commit message reference
|
|
8
8
|
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
Governs a git commit message: subject structure, the type and scope vocabulary, and the body.
|
|
12
|
+
|
|
13
|
+
Does not govern:
|
|
14
|
+
|
|
15
|
+
- Branch naming, which shares the type vocabulary: `branch.md`
|
|
16
|
+
- Pull request title and body, which share the subject form: `pr.md`
|
|
17
|
+
- Whether a phase label or a semver tag may appear in a subject: `versioning.md`
|
|
18
|
+
|
|
9
19
|
## Format
|
|
10
20
|
|
|
11
21
|
- Structure: `<type>(<scope>): <subject>`
|
|
@@ -26,7 +36,7 @@ consumers: git-commit, git-stage
|
|
|
26
36
|
- `ci`: CI/CD pipeline changes (GitHub Actions)
|
|
27
37
|
- `revert`: revert a previous commit
|
|
28
38
|
|
|
29
|
-
## Scope
|
|
39
|
+
## Scope vocabulary
|
|
30
40
|
|
|
31
41
|
- Single lowercase word representing a system component
|
|
32
42
|
- Prefer single word
|
package/docs/agents.md
CHANGED
|
@@ -70,7 +70,7 @@ Full help: `aitk <command> --help`.
|
|
|
70
70
|
| `aitk sandbox reset` | Reset sandbox to baseline |
|
|
71
71
|
| `aitk sandbox clean` | Wipe the sandbox |
|
|
72
72
|
| `aitk sandbox check` | Score a provisioned sandbox against a scenario expectation (`--json` for the verdict) |
|
|
73
|
-
| `aitk sandbox coverage` | Report which scenarios declare expectations (`--json`, `--strict`)
|
|
73
|
+
| `aitk sandbox coverage` | Report which scenarios declare expectations (`--json`, `--strict`, `--skills`) |
|
|
74
74
|
| `aitk indexes regen` | Regenerate `index.md` files from sibling frontmatter |
|
|
75
75
|
| `aitk docs [topic]` | Emit toolkit reference docs (`list`, or a topic by name) |
|
|
76
76
|
| `aitk design render` | Render `.claude/DESIGN.md` tokens to HTML and CSS |
|
|
@@ -228,13 +228,18 @@ Exit 0 means `pass` or `unchecked`. Exit 1 means `fail`, or a caller error: a ma
|
|
|
228
228
|
aitk sandbox coverage --json
|
|
229
229
|
```
|
|
230
230
|
|
|
231
|
-
| Flag | Effect
|
|
232
|
-
| ---------- |
|
|
233
|
-
| `--json` | Emit the coverage record on stdout
|
|
234
|
-
| `--strict` | Exit 1 while any scenario declares no expectation
|
|
231
|
+
| Flag | Effect |
|
|
232
|
+
| ---------- | ----------------------------------------------------------- |
|
|
233
|
+
| `--json` | Emit the coverage record on stdout |
|
|
234
|
+
| `--strict` | Exit 1 while any scenario declares no expectation |
|
|
235
|
+
| `--skills` | Add a per-skill asserted, should-be-asserted, exempt census |
|
|
235
236
|
|
|
236
237
|
The record carries every scenario with the arms that declare, plus `totalScenarios`, `armedScenarios`, and `armedArms`. Scenarios and arms count separately, since several arms can share one scenario and dividing one by the other overstates the rollout.
|
|
237
238
|
|
|
239
|
+
`--skills` answers what the scenario count cannot, which is whether anything can fail a given skill. It adds `skills`, `totalSkills`, `asserted`, `shouldBeAsserted`, `exempt`, `staleExemptions`, and `supersededExemptions` to the record, and keeps the scenario view rather than replacing it. The two denominators disagree on purpose: an armed scenario under `infra/` or `tooling/` exercises a CLI domain and pairs with no skill at all.
|
|
240
|
+
|
|
241
|
+
A skill pairs to a scenario by filename, `<category>-<command>` first and bare `<command>` second, so `claude/setup-init.sh` reaches the `setup-init` skill. `should-be-asserted` is the default and is the work queue for writing arms. `exempt` means no arm should be written and holds only with a reason, declared in `scripts/sandbox/exempt.toml` and limited to a harness limit the checker cannot reach past or a skill that writes no artifact. An armed arm outranks an exemption. An exemption naming no shipped skill, or naming one an arm now asserts, exits 1 without `--strict`. Each armed arm reports as `<category>:<command>/<arm>`, so two same-named arms under different scenarios stay distinct.
|
|
242
|
+
|
|
238
243
|
`scripts/sandbox/run.sh` calls this after a headless run and merges the verdict into the envelope it prints. It also writes that merged record to `.claude/.tmp/sandbox-runs/<target>-<arm>-<timestamp>.json` with a `writes` array appended, and logs the path on stderr. Both fields are what a later re-score needs, since `--envelope` and `--writes` read files the run deletes on exit. Stdout carries the same bytes it did before the record existed.
|
|
239
244
|
|
|
240
245
|
## Docs
|
package/package.json
CHANGED
package/src/commands/sandbox.ts
CHANGED
|
@@ -3,6 +3,11 @@ import { homedir } from 'node:os'
|
|
|
3
3
|
import { join } from 'node:path'
|
|
4
4
|
import type { Command } from 'commander'
|
|
5
5
|
import { PROJECT_ROOT, execScript } from '@/exec'
|
|
6
|
+
import {
|
|
7
|
+
assertedPercent,
|
|
8
|
+
collectCensus,
|
|
9
|
+
type CensusReport,
|
|
10
|
+
} from '@/sandbox/census'
|
|
6
11
|
import {
|
|
7
12
|
collectCoverage,
|
|
8
13
|
coveragePercent,
|
|
@@ -100,6 +105,7 @@ interface CheckOptions {
|
|
|
100
105
|
interface CoverageOptions {
|
|
101
106
|
readonly json?: boolean
|
|
102
107
|
readonly strict?: boolean
|
|
108
|
+
readonly skills?: boolean
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
function getCategories(): string[] {
|
|
@@ -245,20 +251,105 @@ function reportCoverage(report: CoverageReport): void {
|
|
|
245
251
|
else logInfo(summary)
|
|
246
252
|
}
|
|
247
253
|
|
|
254
|
+
/**
|
|
255
|
+
* Names the skills nothing can fail, which is the work queue the arm batches
|
|
256
|
+
* consume. Exempt entries print their reason, since an exemption with no reason
|
|
257
|
+
* beside it is indistinguishable from a skill nobody has got to yet.
|
|
258
|
+
*/
|
|
259
|
+
function reportCensus(report: CensusReport): void {
|
|
260
|
+
const shouldBe = report.skills.filter(
|
|
261
|
+
(s) => s.verdict === 'should-be-asserted',
|
|
262
|
+
)
|
|
263
|
+
const exempt = report.skills.filter((s) => s.verdict === 'exempt')
|
|
264
|
+
|
|
265
|
+
if (shouldBe.length > 0) {
|
|
266
|
+
logStep('No arm can fail these')
|
|
267
|
+
for (const entry of shouldBe)
|
|
268
|
+
logWarn(
|
|
269
|
+
`${entry.skill} (${entry.scenarios.length === 0 ? 'no scenario' : entry.scenarios.join(', ')})`,
|
|
270
|
+
)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (exempt.length > 0) {
|
|
274
|
+
logStep('Exempt')
|
|
275
|
+
for (const entry of exempt) logInfo(`${entry.skill}: ${entry.reason}`)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// A wrong exemption is the one way this report can overstate itself, so both
|
|
279
|
+
// kinds print as errors even on a run that is otherwise clean. They separate
|
|
280
|
+
// because the reader checks a different thing: whether the skill left the
|
|
281
|
+
// tree, or whether an arm landed and the entry outlived its reason.
|
|
282
|
+
if (report.staleExemptions.length > 0) {
|
|
283
|
+
logStep('Exemptions naming no shipped skill')
|
|
284
|
+
for (const skill of report.staleExemptions) logError(skill)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (report.supersededExemptions.length > 0) {
|
|
288
|
+
logStep('Exemptions an arm now asserts')
|
|
289
|
+
for (const skill of report.supersededExemptions)
|
|
290
|
+
logError(`${skill}, delete the entry`)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
logStep('Skills')
|
|
294
|
+
const summary =
|
|
295
|
+
`${report.asserted}/${report.totalSkills} skills asserted ` +
|
|
296
|
+
`(${assertedPercent(report)}%), ${report.shouldBeAsserted} should be, ` +
|
|
297
|
+
`${report.exempt} exempt`
|
|
298
|
+
if (report.shouldBeAsserted > 0) logWarn(summary)
|
|
299
|
+
else logInfo(summary)
|
|
300
|
+
}
|
|
301
|
+
|
|
248
302
|
function runCoverage(options: CoverageOptions): void {
|
|
249
303
|
if (reportAbsentScenarioTree()) return
|
|
250
304
|
|
|
251
305
|
intro('aitk sandbox coverage')
|
|
252
306
|
|
|
253
307
|
const report = collectCoverage(PROJECT_ROOT)
|
|
308
|
+
|
|
309
|
+
// A broken `exempt.toml` reads as a caller error, not as a crash. The parser
|
|
310
|
+
// throws rather than returning a smaller set, since a dropped exemption is
|
|
311
|
+
// invisible in the counts, and the conversion belongs here for the reason
|
|
312
|
+
// `resolveVerdict` catches its own parse: a typo in a declaration should read
|
|
313
|
+
// the way a pattern that does not compile does rather than as a stack trace.
|
|
314
|
+
let census: CensusReport | undefined
|
|
315
|
+
if (options.skills === true) {
|
|
316
|
+
try {
|
|
317
|
+
census = collectCensus(PROJECT_ROOT, report)
|
|
318
|
+
} catch (error) {
|
|
319
|
+
const reason = error instanceof Error ? error.message : String(error)
|
|
320
|
+
reportCoverage(report)
|
|
321
|
+
logStep('Skills')
|
|
322
|
+
logError(`Cannot read the exemptions: ${reason}`)
|
|
323
|
+
outro()
|
|
324
|
+
process.exitCode = 1
|
|
325
|
+
|
|
326
|
+
return
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// The scenario view stays whichever way `--skills` is set. The two count
|
|
331
|
+
// different denominators, and replacing one with the other loses the scenario
|
|
332
|
+
// rollout the strict gate is written against.
|
|
254
333
|
reportCoverage(report)
|
|
255
|
-
if (
|
|
334
|
+
if (census !== undefined) reportCensus(census)
|
|
335
|
+
|
|
336
|
+
if (options.json === true)
|
|
337
|
+
process.stdout.write(
|
|
338
|
+
`${JSON.stringify(census === undefined ? report : { ...report, ...census })}\n`,
|
|
339
|
+
)
|
|
256
340
|
|
|
257
341
|
outro()
|
|
258
|
-
|
|
342
|
+
|
|
343
|
+
// A wrong exemption exits non-zero without `--strict`. It is a wrong claim in
|
|
344
|
+
// committed data rather than a rollout still in progress, and the whole point
|
|
345
|
+
// of the verdict is that an exemption someone can no longer check is worse
|
|
346
|
+
// than no exemption at all.
|
|
347
|
+
const wrongExemption =
|
|
348
|
+
(census?.staleExemptions.length ?? 0) > 0 ||
|
|
349
|
+
(census?.supersededExemptions.length ?? 0) > 0
|
|
350
|
+
const rolloutIncomplete =
|
|
259
351
|
options.strict === true && report.armedScenarios < report.totalScenarios
|
|
260
|
-
|
|
261
|
-
: 0
|
|
352
|
+
process.exitCode = wrongExemption || rolloutIncomplete ? 1 : 0
|
|
262
353
|
}
|
|
263
354
|
|
|
264
355
|
function runCheck(
|
|
@@ -361,6 +452,7 @@ export function register(program: Command): void {
|
|
|
361
452
|
.helpOption('-h, --help', 'Show this help message')
|
|
362
453
|
.option('--json', 'Emit the report as JSON on stdout')
|
|
363
454
|
.option('--strict', 'Exit non-zero while any scenario declares nothing')
|
|
455
|
+
.option('--skills', 'Add a per-skill asserted, should-be, or exempt census')
|
|
364
456
|
.addHelpText(
|
|
365
457
|
'after',
|
|
366
458
|
[
|
|
@@ -368,8 +460,10 @@ export function register(program: Command): void {
|
|
|
368
460
|
'Examples:',
|
|
369
461
|
' aitk sandbox coverage',
|
|
370
462
|
' aitk sandbox coverage --json',
|
|
463
|
+
' aitk sandbox coverage --skills',
|
|
371
464
|
'',
|
|
372
|
-
'Exit codes: 0, unless --strict and a scenario declares nothing
|
|
465
|
+
'Exit codes: 0, unless --strict and a scenario declares nothing, or',
|
|
466
|
+
'--skills and an exemption names no shipped skill or one an arm asserts.',
|
|
373
467
|
'Where the scenario tree does not ship, exits 1 without a report.',
|
|
374
468
|
].join('\n'),
|
|
375
469
|
)
|