@erclx/aitk 3.0.0 → 3.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/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/claude-design-extract/SKILL.md +1 -1
- package/claude/skills/claude-intake-answer/REQUIREMENT.md +1 -1
- package/claude/skills/decision-escalate/REQUIREMENT.md +2 -2
- package/claude/skills/git-pr/SKILL.md +16 -2
- package/claude/skills/git-pr/references/labels.md +26 -2
- package/claude/skills/setup-indexes/SKILL.md +5 -3
- package/claude/skills/youtube-transcripts/SKILL.md +1 -1
- package/docs/agents/audits.md +2 -2
- package/docs/agents/commands.md +22 -19
- package/docs/agents/index.md +2 -0
- package/docs/agents/install-and-sync.md +73 -5
- package/docs/agents/label-coverage.md +73 -0
- package/docs/agents/skills-reach.md +57 -0
- package/docs/target-projects.md +14 -2
- package/package.json +1 -1
- package/src/audits/catalog.ts +85 -0
- package/src/claude/skills-reach.ts +193 -0
- package/src/cli.ts +4 -0
- package/src/commands/claude.ts +123 -4
- package/src/commands/labels.ts +166 -0
- package/src/commands/sync.ts +13 -0
- package/src/git-files.ts +74 -0
- package/src/labels/audit.ts +82 -0
- package/src/labels/coverage.ts +79 -0
- package/src/labels/map.ts +101 -0
- package/src/sync/check.ts +167 -4
|
@@ -35,7 +35,7 @@ Read these on both paths, skipping any that do not exist:
|
|
|
35
35
|
- `${CLAUDE_SKILL_DIR}/../../standards/markdown.md`: word, punctuation, and formatting constraints
|
|
36
36
|
- The `write-human` skill: tone and sentence construction constraints
|
|
37
37
|
|
|
38
|
-
On the source path, also read the UI surfaces matched in Step 1 plus `docs/agents/output-shape.md` and `docs/index.md` for output shape or framing rules already documented.
|
|
38
|
+
On the source path, also read the UI surfaces matched in Step 1 plus any `docs/agents/output-shape.md` and `docs/index.md` the project itself carries, for output shape or framing rules already documented. Those two are the toolkit's own spelling, so a project keeping its framing rules elsewhere is read there instead.
|
|
39
39
|
|
|
40
40
|
On the greenfield path, also read `.claude/ARCHITECTURE.md` for platform, tech stack, and surface type. Do not scan `src/`, stylesheets, or UI modules. Step 1 already established they hold nothing.
|
|
41
41
|
|
|
@@ -43,6 +43,6 @@ The batching fails a fifth way. A folder holding thirty unread items put as thir
|
|
|
43
43
|
|
|
44
44
|
- Filing a dump and writing the items, which is `claude-intake` and owns every other write into the folder
|
|
45
45
|
- Promoting an answered item onto the board, which is `claude-tasks` and runs after the answers land
|
|
46
|
-
- The item format, the answer contract, and retrieval, which `standards/intake.md` owns and this skill cites
|
|
46
|
+
- The item format, the answer contract, and retrieval, which the toolkit's `standards/intake.md` owns and this skill cites
|
|
47
47
|
- The comparable answer slots in groundwork and feature plans, which carry their own contracts and are a separate measurement
|
|
48
48
|
- Deciding when to fire. The skill is user-invoked through `disable-model-invocation`, so answering is the operator's call rather than a description match.
|
|
@@ -15,7 +15,7 @@ A body written around a named tool fails a third way. A session on a surface car
|
|
|
15
15
|
|
|
16
16
|
The opposite failure is the one that ships silently. A session that takes a preference decision itself produces work the operator did not ask for and never learns a choice was made, because nothing in the output says a fork was passed.
|
|
17
17
|
|
|
18
|
-
`CLAUDE.md` states both branches of the rule, sending an ordinary judgment call to a pick with the tradeoff in one sentence and a preference-deciding call to the operator. The first branch has `snippets/decision-help.md` behind it and the second had no surface at all.
|
|
18
|
+
`CLAUDE.md` states both branches of the rule, sending an ordinary judgment call to a pick with the tradeoff in one sentence and a preference-deciding call to the operator. The first branch has the toolkit's `snippets/decision-help.md` behind it, which installs into a project as `.claude/snippets/decision-help.md`, and the second had no surface at all.
|
|
19
19
|
|
|
20
20
|
## Must
|
|
21
21
|
|
|
@@ -40,6 +40,6 @@ The opposite failure is the one that ships silently. A session that takes a pref
|
|
|
40
40
|
## Out of scope
|
|
41
41
|
|
|
42
42
|
- Making the ordinary judgment call, which is a pick plus a one-sentence tradeoff and needs no surface
|
|
43
|
-
- The chat-side pick with no repository behind it, which `snippets/decision-help.md` covers and reaches a different reader
|
|
43
|
+
- The chat-side pick with no repository behind it, which the toolkit's `snippets/decision-help.md` covers and reaches a different reader
|
|
44
44
|
- Writing the decision into a plan, task, or architecture record, which each owning standard governs and this skill only routes to
|
|
45
45
|
- Deciding when to fire. The skill is user-invoked through `disable-model-invocation`, so escalating is the operator's call rather than a description match.
|
|
@@ -84,9 +84,23 @@ A detached HEAD gives `git branch --show-current` an empty result, which would r
|
|
|
84
84
|
|
|
85
85
|
### Labels
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
Ask the CLI first:
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
```bash
|
|
90
|
+
aitk labels audit --base <base> --json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The record carries `labels`, the set this branch earns, and `uncovered`, the changed paths no row of the map reaches. Join `labels` with commas into `pr_labels` below. Report each `uncovered` path beside the result line, naming the map so the reader knows where a row would go, since a surface nobody covered merges bare and nothing else says so.
|
|
94
|
+
|
|
95
|
+
Branch on the record rather than on the exit. An operator's shell profile may wrap `aitk` in a function whose status comes from a trailing command, and the binary exits 1 for an unknown subcommand and 1 for an ordinary refusal alike.
|
|
96
|
+
|
|
97
|
+
A `reason` of `no-map` is the answer that the project declared no map, which earns no labels and no warning: a label set this skill supplied would be a guess about that project's surfaces. Stop there and label nothing.
|
|
98
|
+
|
|
99
|
+
Every other `reason` is a map or a range the verb could not read, which is `unreadable-map`, `no-domains`, `no-base`, and `unreadable-changes`, plus `bad-base` for a ref this skill resolved wrongly. Take the fallback below and warn beside the result line, naming the reason. A map with a typo in it still has rows a prefix match can reach, and reading the refusal as an absence would open the pull request with no labels and nothing said, which is the surface merging bare that the verb exists to name.
|
|
100
|
+
|
|
101
|
+
The fallback is reading `.claude/aitk/pr-labels.toml` and matching it against the name-only diff per `${CLAUDE_SKILL_DIR}/references/labels.md`. It also covers no record coming back at all, which is an installed `aitk` predating the verb, since a skill reaches a target the moment it merges while the CLI reaches one only when a release publishes. The fallback labels correctly and reports no uncovered path, which is the half only the verb carries.
|
|
102
|
+
|
|
103
|
+
Leave `pr_labels` empty when no map resolves or no prefix matches, which skips the labelling command rather than running it against nothing.
|
|
90
104
|
|
|
91
105
|
### Final command
|
|
92
106
|
|
|
@@ -29,11 +29,35 @@ A label takes more than one prefix when two folders read as one surface. Two lab
|
|
|
29
29
|
|
|
30
30
|
Matching is prefix-anchored, so a row written for an authoring root reaches nothing under the copy a project consumes. A surface living only under a dotted folder carries its own prefix on the row that owns its subject, and a folder holding several subjects rather than one splits across the rows that own them.
|
|
31
31
|
|
|
32
|
-
The map is authored by hand
|
|
32
|
+
The map is authored by hand, so a surface added after it was written labels nothing until someone adds a row. `aitk labels audit` is what names that surface before the branch merges.
|
|
33
33
|
|
|
34
34
|
## Paths a map declines to label
|
|
35
35
|
|
|
36
|
-
A path that moves only when a release or a generator rewrites it earns no row. Release automation applies its own label, and a domain label on a generated file gives a mechanical edit a subject it does not have.
|
|
36
|
+
A path that moves only when a release or a generator rewrites it earns no row. Release automation applies its own label, and a domain label on a generated file gives a mechanical edit a subject it does not have.
|
|
37
|
+
|
|
38
|
+
Both go under a `[declined]` table keyed by the reason, in the same file and matched by the same prefix rule:
|
|
39
|
+
|
|
40
|
+
```toml
|
|
41
|
+
[declined]
|
|
42
|
+
release-managed = ["CHANGELOG.md", "package.json"]
|
|
43
|
+
generated = ["build/manifest.json"]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
A table rather than a comment because the check reads it. A path here is a decision already taken and a path under neither table is a gap nobody has gotten to, and a report that could not tell those apart would be useful about neither.
|
|
47
|
+
|
|
48
|
+
A path claimed by a `[domains]` row and a `[declined]` row takes the label. It already has a subject, so reporting it as deliberately unlabelled would contradict the label the same run applies.
|
|
49
|
+
|
|
50
|
+
## Reporting a surface no row reaches
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
aitk labels audit --base <base> --json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The record carries `labels`, `declined`, and `uncovered`. It exits 2 when `uncovered` has anything in it and 1 when it refuses, with `reason` naming the cause: `no-map` for a project that declared none, and a parse or range failure otherwise.
|
|
57
|
+
|
|
58
|
+
It reports and never gates. Whether an uncovered surface deserves a label is a judgment only the person who owns that surface can make, and a push failing on one teaches a contributor to route around the check while nothing about the surface has changed.
|
|
59
|
+
|
|
60
|
+
What it leaves unmeasured is a prefix reaching no path, so a row left behind by a deleted folder stays in the map. That is the map going stale from the other side and a second measure rather than this one.
|
|
37
61
|
|
|
38
62
|
## Matching
|
|
39
63
|
|
|
@@ -111,7 +111,7 @@ grep -l '^## Indexes' CLAUDE.md 2>/dev/null
|
|
|
111
111
|
|
|
112
112
|
If the section is present, skip the seed silently.
|
|
113
113
|
|
|
114
|
-
If `CLAUDE.md` exists but has no `## Indexes` section, offer to install the canonical convention block. The text below is the source of truth and is mirrored in `tooling/claude/seeds/CLAUDE.md`. Paste it verbatim. Do not rewrite, paraphrase, condense, or add punctuation.
|
|
114
|
+
If `CLAUDE.md` exists but has no `## Indexes` section, offer to install the canonical convention block. The text below is the source of truth and is mirrored in the toolkit's `tooling/claude/seeds/CLAUDE.md`. Paste it verbatim. Do not rewrite, paraphrase, condense, or add punctuation.
|
|
115
115
|
|
|
116
116
|
```markdown
|
|
117
117
|
- When a folder has an `index.md`, check it before reading individual files in that folder.
|
|
@@ -147,5 +147,7 @@ Replace bracketed values with the values from this run. Drop the "Folders bootst
|
|
|
147
147
|
|
|
148
148
|
## Reference
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
Both pages sit in the toolkit and install nowhere, so a target reads them there rather than in its own tree.
|
|
151
|
+
|
|
152
|
+
- The toolkit's `.claude/context/indexes.md`: system rationale, frontmatter contract, when to adopt
|
|
153
|
+
- The toolkit's `docs/agents/indexes.md`: `aitk indexes regen` flags, exit codes, JSON shape
|
|
@@ -5,7 +5,7 @@ description: Fetches a YouTube video transcript with metadata frontmatter into t
|
|
|
5
5
|
|
|
6
6
|
# YouTube transcripts
|
|
7
7
|
|
|
8
|
-
Turn a pasted YouTube URL into a markdown file with YAML frontmatter and a cleaned prose body. The `aitk transcripts` command owns the fetch, VTT cleanup, and frontmatter. Do not reimplement that logic.
|
|
8
|
+
Turn a pasted YouTube URL into a markdown file with YAML frontmatter and a cleaned prose body. The `aitk transcripts` command owns the fetch, VTT cleanup, and frontmatter. Do not reimplement that logic. The output format and field list live in the toolkit's `.claude/context/transcripts.md`, which a target does not receive.
|
|
9
9
|
|
|
10
10
|
## Guards
|
|
11
11
|
|
package/docs/agents/audits.md
CHANGED
|
@@ -22,11 +22,11 @@ aitk audits list --json
|
|
|
22
22
|
|
|
23
23
|
## What it runs
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
Sixteen verbs, listed by `aitk audits list`. Each runs once in its fullest form, and the aggregate reads that verb's own record rather than imposing a shared envelope on it. Every one of those records already has consumers naming its keys, so a common shape would be a breaking change bought for tidiness.
|
|
26
26
|
|
|
27
27
|
The verbs walk separate trees and share no state, so they run together. Measured on the authoring machine at twelve verbs, a run finished in 0.8 seconds of wall clock against 4.4 seconds of processor, which is under every other stage in `bun run check`. `aitk deps audit` is the one that changes that reading, since it reaches a network rather than a tree and its latency is the index's rather than this machine's.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
Thirteen of the sixteen read a tree on this disk. The two added by `state-scoped-risk.md` read committed state rather than an arriving change, which is the gap every review surface here leaves by construction, and the one added by `label-coverage.md` reads a branch range against a map the project declares.
|
|
30
30
|
|
|
31
31
|
Each is invoked as the CLI the caller is running rather than as a global `aitk`. A globally installed binary resolves to the main checkout no matter which worktree is executing, so the aggregate would measure a tree the branch never touched and report a pass over it.
|
|
32
32
|
|
package/docs/agents/commands.md
CHANGED
|
@@ -46,9 +46,11 @@ Full help: `aitk <command> --help`. Behavior notes for the install and sync verb
|
|
|
46
46
|
| `aitk markdown audit` | Fail any markdown path on a banned character, word, or spelling, and report the structural checkpoints |
|
|
47
47
|
| `aitk claude skills audit` | Report both skill corpora against the mechanical rules in `standards/skill.md` |
|
|
48
48
|
| `aitk claude skills drift` | Name the shipped skill bodies rewritten between a given ref and `HEAD`, and the installed version against the newest published (`--json`) |
|
|
49
|
+
| `aitk claude skills reach` | Report the shipped bodies citing a toolkit path no target project receives, exiting 2 on an unqualified one |
|
|
49
50
|
| `aitk gov test-order` | Report where an implementation reached history ahead of the test covering it (`--json`) |
|
|
50
51
|
| `aitk secrets scan` | Report credential-shaped values in the tree the package ships, keyed on issued values rather than on words (`--json`) |
|
|
51
52
|
| `aitk deps audit` | Report published advisories against the resolved dependency set, refusing rather than reporting clean when the index is unreachable (`--json`) |
|
|
53
|
+
| `aitk labels audit` | Report the labels a changed set earns from the pull request label map and the paths no row reaches (`--json`) |
|
|
52
54
|
| `aitk audits run` | Run every audit as one set, report per check under one verdict, and compare each count to the recorded baseline (`--json`, `--record`) |
|
|
53
55
|
| `aitk audits list` | List every audit the set runs, with the corpus each reads and whether it gates (`--json`) |
|
|
54
56
|
| `aitk capture [source]` | Render HTML capture sources to PNG, toolkit-only and absent from an installed package |
|
|
@@ -58,25 +60,26 @@ Full help: `aitk <command> --help`. Behavior notes for the install and sync verb
|
|
|
58
60
|
|
|
59
61
|
Each domain exposes a consistent shape where applicable: `list`, `install`, `sync`, `create`.
|
|
60
62
|
|
|
61
|
-
| Domain | Subcommands
|
|
62
|
-
| ----------- |
|
|
63
|
-
| `tooling` | `list`, `sync`, `ref`, `create`, `verify`, `inject`, `prune-gitignore`
|
|
64
|
-
| `snippets` | `list`, `install`, `sync`, `create`
|
|
65
|
-
| `standards` | `list`, `<name>`
|
|
66
|
-
| `gov` | `list`, `install`, `sync`, `build`, `regen`, `test-order`
|
|
67
|
-
| `claude` | `init`, `sync`, `seeds list`, `skills list`, `skills audit`, `skills drift`, `setup [dest]` |
|
|
68
|
-
| `wiki` | `init`
|
|
69
|
-
| `design` | `render`
|
|
70
|
-
| `slides` | `render`, `list`
|
|
71
|
-
| `tasks` | `archive`, `validate`
|
|
72
|
-
| `intake` | `list`, `answer`
|
|
73
|
-
| `teach` | `list`, `open`, `resource`, `glossary`
|
|
74
|
-
| `comments` | `scan`
|
|
75
|
-
| `context` | `audit`
|
|
76
|
-
| `markdown` | `audit`
|
|
77
|
-
| `secrets` | `scan`
|
|
78
|
-
| `deps` | `audit`
|
|
79
|
-
| `
|
|
63
|
+
| Domain | Subcommands |
|
|
64
|
+
| ----------- | ----------------------------------------------------------------------------------------------------------- |
|
|
65
|
+
| `tooling` | `list`, `sync`, `ref`, `create`, `verify`, `inject`, `prune-gitignore` |
|
|
66
|
+
| `snippets` | `list`, `install`, `sync`, `create` |
|
|
67
|
+
| `standards` | `list`, `<name>` |
|
|
68
|
+
| `gov` | `list`, `install`, `sync`, `build`, `regen`, `test-order` |
|
|
69
|
+
| `claude` | `init`, `sync`, `seeds list`, `skills list`, `skills audit`, `skills drift`, `skills reach`, `setup [dest]` |
|
|
70
|
+
| `wiki` | `init` |
|
|
71
|
+
| `design` | `render` |
|
|
72
|
+
| `slides` | `render`, `list` |
|
|
73
|
+
| `tasks` | `archive`, `validate` |
|
|
74
|
+
| `intake` | `list`, `answer` |
|
|
75
|
+
| `teach` | `list`, `open`, `resource`, `glossary` |
|
|
76
|
+
| `comments` | `scan` |
|
|
77
|
+
| `context` | `audit` |
|
|
78
|
+
| `markdown` | `audit` |
|
|
79
|
+
| `secrets` | `scan` |
|
|
80
|
+
| `deps` | `audit` |
|
|
81
|
+
| `labels` | `audit` |
|
|
82
|
+
| `audits` | `run`, `list` |
|
|
80
83
|
|
|
81
84
|
Common patterns:
|
|
82
85
|
|
package/docs/agents/index.md
CHANGED
|
@@ -18,6 +18,7 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
18
18
|
- [Indexes](indexes.md): Flags, exit codes, and JSON shape for aitk indexes regen, plus when it auto-stages what it rewrote
|
|
19
19
|
- [Install and sync](install-and-sync.md): What each install and sync verb writes, refuses, or leaves alone, and how drift is attributed in a target project
|
|
20
20
|
- [Intake](intake.md): Reading intake folder counts and items, the three read states an item can be in, landing a batch of selections in one cluster, the refusal reasons, and why a call is scoped to one file
|
|
21
|
+
- [Label coverage](label-coverage.md): Reading a changed set against the pull request label map, the two tables it matches, how a gap is separated from a decision, and why an absent map is an answer
|
|
21
22
|
- [Markdown audit](markdown-audit.md): Running the audit over any markdown path, where its bans and checkpoints are read from, what each check reports, and why the ban half gates while the structural half reports
|
|
22
23
|
- [Output shape](output-shape.md): Two framed shapes every command renders into, how JSON and --names modes keep stdout clean, and the exit discipline that lets piped output drain
|
|
23
24
|
- [Overview](overview.md): What this folder covers, the invocation rules every command inherits, and where domain behavior is documented instead
|
|
@@ -26,6 +27,7 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
26
27
|
- [Scripting](scripting.md): The runtime catalogs that replace hardcoded names, what each carries, and a headless invocation per domain
|
|
27
28
|
- [Sessions](sessions.md): Resolving live peer sessions to the worktree and branch each holds, the liveness confidence field, the unresolved reasons, and what the read depends on
|
|
28
29
|
- [Skill audit](skills-audit.md): Measuring both skill corpora against standards/skill.md, the checks it reads, the requirement gate that is the only failing one, and the drift verb that names bodies rewritten since a ref
|
|
30
|
+
- [Citation reach](skills-reach.md): Reporting the shipped skill bodies that cite a path no target project receives, the ownership key that decides what counts, the one-word qualifier that marks a citation as decided, and why the verb reports instead of gating
|
|
29
31
|
- [State-scoped risk](state-scoped-risk.md): Reading committed state rather than an arriving change, the shipped-tree corpus the secret scan reads, what it keys on and how a deliberate value is exempted, the advisory check and its network failure mode, and why one gates while the other reports
|
|
30
32
|
- [Tasks](tasks.md): Selecting a shipped task by stem or pull request, recording a number and closing an outcome, the refusal reasons, the board and backlog checks validate runs, and why the board root defaults to the main worktree
|
|
31
33
|
- [Teach](teach.md): Listing learning workspaces and the ordinal a new one takes, opening one with its required files, recording sources and glossary terms, resolving what the next lesson needs before it is written, the refusal reasons, and why every write here runs through a verb
|
|
@@ -138,11 +138,14 @@ edit and a job counting those stays red with no remedy.
|
|
|
138
138
|
|
|
139
139
|
### Surfaces reported beside the domains
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
that walk cannot see
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
141
|
+
Six sections sit outside the per-domain scan, because each names something
|
|
142
|
+
that walk cannot see: `seeds`, `superseded`, `unmigrated`, `newSkills`,
|
|
143
|
+
`newRules`, and `reverse`. None of them produces a change, and no sync command
|
|
144
|
+
applies any of them. The headings below group the first three together and give
|
|
145
|
+
`newSkills` its description under `newRules`, which answers the same question
|
|
146
|
+
about a different corpus.
|
|
147
|
+
|
|
148
|
+
All six report only against a toolkit-managed target, which is one carrying a
|
|
146
149
|
`.claude/` directory, a `CLAUDE.md`, or a domain still at the root layout. The
|
|
147
150
|
report says so through `managed` in the JSON and routes an unmanaged directory to
|
|
148
151
|
`aitk init`. Seeds are why the gate exists, since they enumerate from the toolkit
|
|
@@ -198,6 +201,66 @@ the toolkit ships, so a root folder holding the project's own documents beside
|
|
|
198
201
|
the installed ones reports the installed subset, where a listing reports every
|
|
199
202
|
file and proposes relocating the lot.
|
|
200
203
|
|
|
204
|
+
#### Rules the target never received
|
|
205
|
+
|
|
206
|
+
`newRules` names a rule the toolkit authored after this target last synced
|
|
207
|
+
governance. A sync refreshes the files a target already holds and adds none, so
|
|
208
|
+
without this section a project's rule set freezes at its install date while every
|
|
209
|
+
file it does hold reports as current. That is the report's most confident wrong
|
|
210
|
+
answer, since a clean result reads as a target holding everything the toolkit
|
|
211
|
+
publishes.
|
|
212
|
+
|
|
213
|
+
The list rides beside `newSkills`, which asks the same question about the plugin
|
|
214
|
+
catalog. Both are names rather than paths, and neither queues a change, because
|
|
215
|
+
the two remedies differ: a skill loads live from the plugin directory and needs
|
|
216
|
+
nothing run, while a rule reaches a target only when someone runs
|
|
217
|
+
`aitk gov install`.
|
|
218
|
+
|
|
219
|
+
Read a clean section as reporting rather than as delivering. Nothing here
|
|
220
|
+
installs, nothing counts toward `--exit-code`, and a target can read the list and
|
|
221
|
+
act on none of it. The value stops at an operator reading it, which is the same
|
|
222
|
+
contract the skills list already sets.
|
|
223
|
+
|
|
224
|
+
The measurement anchors on governance's own stamp rather than on the oldest
|
|
225
|
+
anchor across domains, since rules are domain-scoped and a shared anchor would
|
|
226
|
+
let a snippets sync move the revision rules are measured from. A target carrying
|
|
227
|
+
no governance anchor reports nothing at all: it has no date to measure against,
|
|
228
|
+
and diffing from the start of history would read the whole catalog as new.
|
|
229
|
+
|
|
230
|
+
An anchor this toolkit cannot resolve reports nothing by the same route, and that
|
|
231
|
+
one is not visible. A stamp naming a revision the running clone has never seen,
|
|
232
|
+
which is what a registry install without history or a shallow clone produces,
|
|
233
|
+
fails the read and yields an empty list rather than a stated absence. It looks
|
|
234
|
+
identical to a target holding every rule the toolkit publishes. `newSkills`
|
|
235
|
+
behaves the same way, and neither carries the `historyUnavailable` flag the
|
|
236
|
+
per-domain scan uses to separate the two. Treat an empty section on a toolkit
|
|
237
|
+
that is not a full clone as unmeasured rather than clean.
|
|
238
|
+
|
|
239
|
+
Entitlement is filtered, because a stack does not receive every rule. The base
|
|
240
|
+
stack takes the `core` and `claude` folders whole and every other stack extends
|
|
241
|
+
it with individually named rules, so an unfiltered list would tell a base
|
|
242
|
+
consumer about rules it can never receive and train the reader to skip the
|
|
243
|
+
section.
|
|
244
|
+
|
|
245
|
+
The filter accepts a band on either of two grounds. A folder the base stack takes
|
|
246
|
+
whole is entitled to every target, read from the stack file so a folder added to
|
|
247
|
+
base later needs no code change. Every other band is read off the folders the
|
|
248
|
+
target already carries, since `aitk gov install` records file hashes and never
|
|
249
|
+
the stack it resolved, which leaves the installed tree as the only evidence of
|
|
250
|
+
what a chain reached. One band can be reached by more than one stack, so the test
|
|
251
|
+
over-reports inside a folder the target holds, which costs a line where
|
|
252
|
+
under-reporting would cost the section its point.
|
|
253
|
+
|
|
254
|
+
A rule the target already holds is dropped by name. That is what keeps a rule the
|
|
255
|
+
toolkit moved between band folders out of the list, since a rename reaches this
|
|
256
|
+
read as an addition and only the name tells the two apart.
|
|
257
|
+
|
|
258
|
+
This closes the dangling-citation case as a side effect rather than checking for
|
|
259
|
+
one. The live instance is a rule citing a sibling authored after the target's
|
|
260
|
+
install, and the section names the sibling as new rather than naming the citation
|
|
261
|
+
as broken. That is enough for an operator to act on, and it is not a citation
|
|
262
|
+
check.
|
|
263
|
+
|
|
201
264
|
#### The reverse walk
|
|
202
265
|
|
|
203
266
|
`reverse` is the one section built by walking the target rather than the
|
|
@@ -249,6 +312,11 @@ documented and unreachable from any report.
|
|
|
249
312
|
is: only the user can move content they wrote, so failing a job on it leaves the
|
|
250
313
|
job red with no mechanical remedy.
|
|
251
314
|
|
|
315
|
+
`newRules` is excluded on a different ground, since a command does close it. What
|
|
316
|
+
excludes it is that installing a rule changes what a project is governed by, so
|
|
317
|
+
gating on the count would pressure a target into adopting rules nobody chose.
|
|
318
|
+
`newSkills` is excluded because it needs no command at all.
|
|
319
|
+
|
|
252
320
|
The whole `reverse` section is excluded on the same grounds, and more strongly.
|
|
253
321
|
Every entry in it is a judgment about a file the project may own, and one of its
|
|
254
322
|
three verdicts is a labelled unknown by design. The unmigrated detection shipped
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Label coverage
|
|
3
|
+
description: Reading a changed set against the pull request label map, the two tables it matches, how a gap is separated from a decision, and why an absent map is an answer
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Label coverage
|
|
7
|
+
|
|
8
|
+
`aitk labels audit` resolves the paths a branch changed against the label map a project declares, reports the labels the set earns, and names every path no row reaches. It closes a gap the map's own comment had predicted since the map shipped: nothing detected a surface added after the rows were written, so such a branch merged carrying no label and nobody heard about it.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
aitk labels audit
|
|
12
|
+
aitk labels audit --json
|
|
13
|
+
aitk labels audit --base origin/main
|
|
14
|
+
aitk labels audit src/cli.ts docs/index.md --json
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
| Option | Behavior |
|
|
18
|
+
| --------------- | ----------------------------------------------------------------- |
|
|
19
|
+
| `--base <ref>` | Far side of the range, defaulting to the merge base against trunk |
|
|
20
|
+
| `--root <path>` | Repository to read, defaulting to the current directory |
|
|
21
|
+
| `--json` | Add a machine-readable record on stdout, keeping the frame |
|
|
22
|
+
|
|
23
|
+
Positional paths replace the range entirely. A caller holding a changed set already passes it rather than paying for a second git read, and the record then omits `base` to say the range was never resolved.
|
|
24
|
+
|
|
25
|
+
Under `--json` the record holds stdout alone and the frame still renders on stderr, refusals included, which is the split `output-shape.md` fixes for every mode.
|
|
26
|
+
|
|
27
|
+
## The map it reads
|
|
28
|
+
|
|
29
|
+
The map sits at `.claude/aitk/pr-labels.toml` and carries two tables. `[domains]` keys a label name to the path prefixes that earn it, and `[declined]` keys a reason to the prefixes that earn no label on purpose.
|
|
30
|
+
|
|
31
|
+
```toml
|
|
32
|
+
[domains]
|
|
33
|
+
api = ["services/api/"]
|
|
34
|
+
web = ["apps/web/", "packages/ui/"]
|
|
35
|
+
|
|
36
|
+
[declined]
|
|
37
|
+
release-managed = ["CHANGELOG.md", "package.json"]
|
|
38
|
+
generated = ["build/manifest.json"]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Matching is prefix-anchored, so a row written for an authoring root reaches nothing under the copy a project consumes. A path claimed by rows in both tables takes the label, since it already has a subject and reporting it as deliberately unlabelled would contradict the label the same run applies.
|
|
42
|
+
|
|
43
|
+
## A gap and a decision are different findings
|
|
44
|
+
|
|
45
|
+
The verb sorts every changed path into three buckets and keeps two of them apart:
|
|
46
|
+
|
|
47
|
+
- **Labelled.** At least one `[domains]` row reaches the path. It contributes its label and nothing else.
|
|
48
|
+
- **Declined.** A `[declined]` row reaches it. Somebody already decided the path earns no label, so the run names it and moves no exit code.
|
|
49
|
+
- **Uncovered.** Neither table reaches it. This is the finding, and it wants either a prefix on the row that owns its subject or a `[declined]` row carrying the reason.
|
|
50
|
+
|
|
51
|
+
Folding the last two together was the shape this replaced. A report that cannot tell a surface nobody has gotten to from one somebody refused is useful about neither, which is why the declined half moved out of the map's trailing comment and became data the command reads.
|
|
52
|
+
|
|
53
|
+
## The range it reads
|
|
54
|
+
|
|
55
|
+
The default range is the branch against the trunk, resolved as the merge base against `origin/main` and then local `main`. The changed set is that base diffed against the working tree, plus untracked files git does not ignore, rather than against `HEAD`.
|
|
56
|
+
|
|
57
|
+
Reading the working tree is what lets the check run before the branch commits, which is the moment a session adds the surface nobody covered. The set is a superset of `base..HEAD`, so a caller running after the commits still sees the whole branch.
|
|
58
|
+
|
|
59
|
+
## Exit codes and refusals
|
|
60
|
+
|
|
61
|
+
| Code | Meaning |
|
|
62
|
+
| ---- | ---------------------------------------------- |
|
|
63
|
+
| `0` | every changed path is labelled or declined |
|
|
64
|
+
| `1` | refused, with `reason` naming the cause |
|
|
65
|
+
| `2` | at least one changed path is reached by no row |
|
|
66
|
+
|
|
67
|
+
It reports and never gates. Whether an uncovered surface deserves a label is a judgment only whoever owns that surface can make, and a push failing on one teaches a contributor to route around the check while nothing about the surface has changed.
|
|
68
|
+
|
|
69
|
+
A project declaring no map refuses with `no-map`, which is an answer rather than a fault. Such a project is labelled silently by design, and treating the absence as a break would make the map mandatory for every target. `aitk audits run` reads that one reason as an expected absence and every other refusal as a measure that did not run.
|
|
70
|
+
|
|
71
|
+
## What it does not measure
|
|
72
|
+
|
|
73
|
+
A prefix reaching no path is invisible here. A row left behind by a deleted folder stays in the map forever, and this verb has nothing to say about it. That is the map going stale from the other side and a second measure rather than this one.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Citation reach
|
|
3
|
+
description: Reporting the shipped skill bodies that cite a path no target project receives, the ownership key that decides what counts, the one-word qualifier that marks a citation as decided, and why the verb reports instead of gating
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Citation reach
|
|
7
|
+
|
|
8
|
+
`aitk claude skills reach [path]` reports every shipped skill body citing a path that exists in the toolkit and reaches no target project. It reads and reports. Repairing what it finds is separate work.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
aitk claude skills reach
|
|
12
|
+
aitk claude skills reach --json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
| Option | Behavior |
|
|
16
|
+
| -------- | ---------------------------------------------------------- |
|
|
17
|
+
| `--json` | Add a machine-readable record on stdout, keeping the frame |
|
|
18
|
+
|
|
19
|
+
## The defect it reads for
|
|
20
|
+
|
|
21
|
+
A plugin skill installs into a project and the toolkit's own tree is not there. A body naming `.claude/context/transcripts.md` resolves for a session running in this repository and sends every other reader to nothing, and no stage asked the question until this one. The shape is wider than one folder: a seed naming a standard with no route and a machine-readable field naming a toolkit-only path are the same claim, true here and false in a target.
|
|
22
|
+
|
|
23
|
+
## What counts as a citation
|
|
24
|
+
|
|
25
|
+
A backticked token carrying a separator and an extension, which is how every body spells a path it means a reader to open. Three forms are skipped by construction.
|
|
26
|
+
|
|
27
|
+
- A placeholder such as `.claude/context/<domain>.md`, which names a shape rather than a file
|
|
28
|
+
- A path resolved through `${CLAUDE_SKILL_DIR}`, which is self-contained wherever the plugin loads
|
|
29
|
+
- A sibling named relatively, such as `references/labels.md`, which matches no authoring root and travels with the body
|
|
30
|
+
|
|
31
|
+
The same sibling named from the repository root as `claude/skills/<name>/references/<file>.md` is reported rather than skipped. The plugin loads from a cache rather than from the project tree, so that spelling resolves for nobody and the report is correct.
|
|
32
|
+
|
|
33
|
+
A path the toolkit does not hold is dropped rather than reported. The measure asks whether a claim true here is false in a target, and a path true in neither is a different defect that `aitk context audit` already reports against its own corpus.
|
|
34
|
+
|
|
35
|
+
## The ownership key
|
|
36
|
+
|
|
37
|
+
A cited path counts when it sits under an authoring root no install channel delivers. Standards install nowhere and are read through the plugin corpus, snippets land under `.claude/snippets/`, governance rules under `.claude/rules/`, and the rest is this repository's own source, catalogs, and contract pages.
|
|
38
|
+
|
|
39
|
+
`src/`, `scripts/`, and bare `docs/` are deliberately outside the list. A body naming one of those is describing the reader's own tree, so listing them reports a correct citation on every run and buries the finding under the pass.
|
|
40
|
+
|
|
41
|
+
A path a seed installs is disowned twice, under its own name and under the folder spelling it takes once a project splits the entry. A domain that outgrows one file becomes `<domain>/`, which is still the entry the seed delivered, so reporting the split form would fail a project for growing.
|
|
42
|
+
|
|
43
|
+
## The qualifier
|
|
44
|
+
|
|
45
|
+
A correct citation and a defective one are the same string, and the sentence around it is the difference. A citation counts as decided when its line names the toolkit as the owner, matching the bodies that already spell it that way. The repair for a finding is to say whose copy the path is, never to delete the citation, since the paths name real documents a reader wants.
|
|
46
|
+
|
|
47
|
+
```markdown
|
|
48
|
+
Read `.claude/context/indexes.md` from the toolkit if context on the system is needed.
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
A line mentioning the toolkit for an unrelated reason exempts a citation on it. That is the accepted cost of a word over a notation every future body would have to learn.
|
|
52
|
+
|
|
53
|
+
## Exit codes
|
|
54
|
+
|
|
55
|
+
Exit codes are `0` when every citation names its owner, `1` for a refusal, and `2` when at least one is unqualified. The refusal is a tree carrying no `claude/skills/`, which ships no plugin body to measure, and it reports the reason rather than a clean count over nothing.
|
|
56
|
+
|
|
57
|
+
The verb reports rather than gates. A toolkit-scoped instruction is sometimes meant for a session in this repository, so failing a push on one would make the check something to route around. `aitk audits run` registers it with no gating exit for the same reason, and carries `unqualifiedCitations` as its retained count.
|
package/docs/target-projects.md
CHANGED
|
@@ -130,13 +130,25 @@ Each domain holds its own toolkit commit, so syncing governance today does not m
|
|
|
130
130
|
|
|
131
131
|
A project that has never synced under a toolkit new enough to write a stamp falls back to the toolkit's own git history. Installed content matching any version that history published proves the file untouched, so it reports `stale` naming the commit it came from, and content matching no published version stays `drifted`. That fallback needs the toolkit as a git checkout. Installed from the registry it ships source without history, and the report says attribution was unavailable rather than reading every file as a local edit.
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
Further causes sit outside the per-domain scan, each naming something that walk cannot see. A seed the project edited is reported under `seeds` and reconciled with `aitk:claude-seed-sync`, since no sync command touches a seed. A file a newer seed folder replaced is reported under `superseded`, such as `.claude/TASKS.md` against the `.claude/tasks/` that now ships, and nothing moves it because the content is the project's own. A domain sitting at the root layout with nothing under `.claude/` is reported under `unmigrated` and handed to `aitk:migration-standards`.
|
|
134
134
|
|
|
135
135
|
That third one matters most on an older project. Before it existed, a target holding `snippets/` at its root reported zero entries for that domain, so a project that had never migrated was indistinguishable from one that was fully current. It covers snippets alone, since a root `standards/` folder in a target is the project's own authoring surface and nothing proposes moving it.
|
|
136
136
|
|
|
137
|
+
#### Rules you never received
|
|
138
|
+
|
|
139
|
+
A sync refreshes the files you already hold and adds none, so your rule set is frozen at the date you installed governance while every file in it reports as current. `newRules` names the rules the toolkit has authored since then, which is the one section that reads your absence rather than your contents.
|
|
140
|
+
|
|
141
|
+
Take a clean section as reporting rather than as delivering. Nothing here installs, and it counts toward nothing, so pick the rules up with `aitk gov install <stack>` or take one with `--add <rule>`. That separation is deliberate: adopting a rule changes what your project is governed by, which is a choice a sync has no business making for you.
|
|
142
|
+
|
|
143
|
+
The list is filtered to what your stack can receive, read off the rule folders you already carry plus the folders the base stack takes whole. A rule under `lang/` or `ui/` belongs to some stacks and not others, so an unfiltered list would name rules you can never install. A target that has never stamped governance reports nothing at all, since there is no date to measure against.
|
|
144
|
+
|
|
145
|
+
An empty section is not proof either way when the toolkit running the check is not a full git clone. The read needs history to reach your anchor, and an install from the registry ships none, so the section goes quiet rather than saying it could not measure. Run the check from a clone before reading a clean result as a complete one.
|
|
146
|
+
|
|
147
|
+
This also closes the case where a rule arrives citing a sibling you do not have. A sync refreshing a rule can land a version pointing at a file it never installs, and the section names the missing sibling rather than the broken citation, which is enough to act on.
|
|
148
|
+
|
|
137
149
|
#### What the toolkit stopped shipping
|
|
138
150
|
|
|
139
|
-
The
|
|
151
|
+
The last cause runs backwards. Every one above starts from what the toolkit ships and asks whether the target matches, so a folder the toolkit dropped appears in none of them. `reverse` walks the target instead and reports a folder sitting at a top-level path the toolkit once shipped and has since deleted.
|
|
140
152
|
|
|
141
153
|
Each entry carries a verdict, since a dropped folder and one the project wrote are the same bytes at the same path.
|
|
142
154
|
|