@erclx/aitk 3.38.0 → 3.38.1

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aitk",
3
3
  "description": "Automated governance, versioning, and discovery tools for Claude Code.",
4
- "version": "3.38.0",
4
+ "version": "3.38.1",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -35,12 +35,18 @@ The set is closed rather than derived, so widening it is a deliberate change to
35
35
 
36
36
  ## How a match is decided
37
37
 
38
- A sentence has to carry an assertion verb (`loads`, `ships`, `carries`, `holds`, `counts`, `totals`, `documents`, `declares`, `installs`, `lists`, `contains`, `comprises`) or an article (`the`, `a`, `an`) immediately ahead of the number, which is immediately ahead of the catalog noun, with one optional qualifying word between the number and the noun (`sixty-one shipped skills`). The number reads either as digits or as a spelled-out cardinal through ninety-nine, since this corpus states a catalog size in words as often as in digits.
38
+ A sentence has to carry an assertion verb (`loads`, `ships`, `carries`, `holds`, `counts`, `totals`, `documents`, `declares`, `installs`, `lists`, `contains`, `comprises`, `authors`), the quantifier `all`, or an article (`the`, `a`, `an`) immediately ahead of the number, which is immediately ahead of the catalog noun, with one optional qualifying word between the number and the noun (`sixty-one shipped skills`). The number reads either as digits or as a spelled-out cardinal through ninety-nine, since this corpus states a catalog size in words as often as in digits.
39
+
40
+ Nothing stands between the trigger and the number, which is the rule an author writing a new count has to know. It separates `the toolkit authors 69 rules` and `took all 69 rules`, both read, from `a domain of 55 skills` and `denominator of sixty-one shipped skills`, neither of them read. A figure meant as a past state takes a date in the same sentence instead, which reads the sentence past whatever its shape.
41
+
42
+ ## How the trigger set grew
39
43
 
40
44
  The verb gate is not the first design tried. A bare number next to a catalog noun anywhere in the tracked corpus returned 290 findings against a repository whose actionable instance count was one. Reading that run showed why: `18 rules citing a standard`, `21 skill bodies`, and `eight internal skills` all pair a number with a catalog noun while naming a subset, an example, or a different catalog than the one matched, and that shape dominates ordinary prose. Every instance this sweep was written against reads the number as the direct object of a verb asserting the catalog's own total, and gating on that verb is what took the false-positive count from 290 to five on the same tree.
41
45
 
42
46
  The article half was added after a first review of the shipped design found a live miss: `.claude/context/development/gates.md` stated a stale audit total while the tree held 20, and the verb gate never reached it, since that sentence puts its verb after the noun rather than ahead of the number. Widening the trigger set to admit an article ahead of the number closed that gap.
43
47
 
48
+ The quantifier `all` and the verb `authors` joined on the same evidence, two more live misses failing only the trigger test. Allowing words to stand between the trigger and the number was the other candidate, measured and declined: at widths of one, two, and three it reached 77, 104, and 132 sentences against a baseline of 65, missed `took all 69 rules` at every width, and reached `the toolkit authors 69 rules` only at a width admitting the indirect-noun shape below. The two words reach both at 75 sentences and no false positive.
49
+
44
50
  ## The plausibility filter
45
51
 
46
52
  The verb gate alone still left four false positives standing: `carries two rules about a standard's own lifecycle`, `holds one rule or one fact` (twice, once per mirrored copy), and `documents two similar commands`. Each pairs an assertion verb with a catalog noun used for something the `rules` or `commands` catalog does not mean, and what tells those apart from the one live finding is magnitude: a catalog this sweep tracks drifts by a few members between the day a sentence was written and the day it is read, so a genuine staleness claim sits near the true count. `2` beside a true count of `59` is not a catalog that shrank, it is a different `rules` entirely.
@@ -51,7 +57,9 @@ The article gate is looser than the verb list and carries a real cost. Re-runnin
51
57
 
52
58
  ## What it does not measure
53
59
 
54
- A delta phrased as a transition (`from fourteen to fifteen`), a fraction (`thirteen of sixteen`), and a total reached through an indirect noun (`denominator of sixty-one shipped skills`) are all catalog-size claims this corpus carries, and none matches the assertion-verb shape this reads. Each is a known gap rather than an oversight, left for a wider pass once this design's own false-positive rate is measured over more than one run.
60
+ A delta phrased as a transition (`from fourteen to fifteen`), a fraction (`thirteen of sixteen`), and a total reached through an indirect noun (`denominator of sixty-one shipped skills`) are all catalog-size claims this corpus carries, and none matches the trigger shape this reads. Each stays a known gap. The false-positive rate that gated closing them has a measurement behind it now, and what it showed is that the widening these three need is the one that costs a false positive rather than the one that does not.
61
+
62
+ A second figure in a sentence whose first figure already matched is a fourth gap and a structural one, since one match is taken per catalog per sentence. `authors 69 rules under governance/rules/ and consumes 54 into .claude/rules/` is read for its 69 alone, which is correct here because the two figures name different populations, and a sentence stating one catalog twice would go unread the same way.
55
63
 
56
64
  A calendar date (`2026-08-21`) or a backticked commit reference in the same sentence reads the whole sentence past, since that is how this corpus already marks a figure as a historical record rather than a live claim. `.claude/ARCHITECTURE.md` and the context entries carry a figure this way deliberately, and every one of them stays correct forever.
57
65
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/aitk",
3
3
  "type": "module",
4
- "version": "3.38.0",
4
+ "version": "3.38.1",
5
5
  "description": "Infrastructure and quality tooling for developer workflows",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -78,6 +78,16 @@ function sentencesOf(line: string): string[] {
78
78
  * asserting the catalog's own total, `the full entry loads 59 skills` being
79
79
  * the live one, and gating the match on that verb is what a full re-read of
80
80
  * the 290 showed removing all of them while keeping that one.
81
+ *
82
+ * `authors` joined the list on a corpus measurement rather than on the shape
83
+ * argument above. `.claude/context/development/regeneration.md` states `the
84
+ * toolkit authors 69 rules under governance/rules/`, which is the assertion
85
+ * shape this list was built for with a verb the list did not carry, and the
86
+ * word costs one further sentence across the whole corpus and no finding.
87
+ * Extending the vocabulary is the narrow half of this fix and it is taken
88
+ * knowingly: a list of thirteen verbs still grows by whatever the next author
89
+ * writes, and the measurement below is what ruled out the general axis that
90
+ * would have replaced it.
81
91
  */
82
92
  const ASSERTION_VERBS = [
83
93
  'loads',
@@ -92,8 +102,26 @@ const ASSERTION_VERBS = [
92
102
  'lists',
93
103
  'contains',
94
104
  'comprises',
105
+ 'authors',
95
106
  ]
96
107
 
108
+ /**
109
+ * A quantifier asserting the whole of a catalog immediately ahead of the
110
+ * number, which is the one trigger class that states a total outright rather
111
+ * than by implication.
112
+ *
113
+ * `all 69 rules` names the catalog entire, where `the 69 rules` leaves a
114
+ * reader to decide whether a qualifier narrows it. That makes this class
115
+ * tighter than the articles below rather than looser, and the corpus agrees:
116
+ * adding it reached 9 further sentences and produced 2 further findings, both
117
+ * of them real staleness this repository then repaired.
118
+ *
119
+ * `every` and `both` were measured beside `all` and reached nothing, so
120
+ * neither ships. A quantifier earns a place here by naming a sentence in the
121
+ * corpus, not by belonging to the same part of speech.
122
+ */
123
+ const QUANTIFIERS = ['all']
124
+
97
125
  /**
98
126
  * An article immediately ahead of the number, admitting the shape a bare verb
99
127
  * gate cannot reach: `the twelve audits read gitignored folders` asserts the
@@ -120,8 +148,9 @@ const ASSERTION_VERBS = [
120
148
  const ARTICLES = ['the', 'a', 'an']
121
149
 
122
150
  /**
123
- * Matches a catalog's stated size: an assertion verb or an article, the
124
- * number, an optional single qualifying word, then the noun in either number.
151
+ * Matches a catalog's stated size: an assertion verb, a quantifier, or an
152
+ * article, the number, an optional single qualifying word, then the noun in
153
+ * either number.
125
154
  *
126
155
  * The optional word between the number and the noun is what reaches a form
127
156
  * like `installs 11 shipped snippets` without also reaching past an
@@ -130,16 +159,34 @@ const ARTICLES = ['the', 'a', 'an']
130
159
  * double as its match narrows the corpus this reads without hand-listing
131
160
  * every irregular plural, since none of these six is irregular.
132
161
  *
133
- * What this drops along with the false positives: `denominator of sixty-one
134
- * shipped skills` and `exposed all 59` both state a real catalog total and
135
- * neither puts a verb or an article directly ahead of the number, so both
136
- * read past. The gap between the trigger and the number is a second axis
137
- * this could widen once this design's own false-positive rate is measured
138
- * over more than the two runs behind it so far.
162
+ * The gap between the trigger and the number was the second axis this comment
163
+ * used to name as open to widening once the false-positive rate had been
164
+ * measured over more than two runs. It was measured over the whole corpus at
165
+ * 518 files and 31,836 sentences and it is not the axis to take. Widths of
166
+ * one, two, and three optional words reached 77, 104, and 132 sentences
167
+ * against a baseline of 65, and the two live misses that motivated the
168
+ * measurement came back missed at every width but one: no width reaches `took
169
+ * all 69 rules`, whose nearest verb or article is the `The` opening the
170
+ * sentence, with five words standing between it and the number, and the width
171
+ * that does reach `the toolkit authors 69 rules` is the same
172
+ * width that admits `a domain of 55 skills`, which is the indirect-noun shape
173
+ * this module already records as out of scope. Widening the gap buys one of
174
+ * two misses at 60 percent more reach and a false positive of a class already
175
+ * named.
176
+ *
177
+ * The trigger vocabulary carries both misses instead, at 75 sentences reached
178
+ * against 65 and no false positive: `all` reaches the first and `authors` the
179
+ * second. Two of the four findings that shape reports were new, and both were
180
+ * real. Measured at `ffe7e7c6` on 2026-08-28.
181
+ *
182
+ * What this still drops: `denominator of sixty-one shipped skills` states a
183
+ * real catalog total through an indirect noun and reads past, which the gap
184
+ * measurement above is the argument for leaving alone rather than an
185
+ * oversight.
139
186
  */
140
187
  function buildMatcher(catalog: Catalog): RegExp {
141
188
  const [singular, plural] = catalog.nouns
142
- const triggers = [...ASSERTION_VERBS, ...ARTICLES].join('|')
189
+ const triggers = [...ASSERTION_VERBS, ...QUANTIFIERS, ...ARTICLES].join('|')
143
190
  return new RegExp(
144
191
  `\\b(?:${triggers})\\s+(${NUMBER_PATTERN})(?:\\s+[a-z]+)?\\s+(?:${singular}|${plural})\\b`,
145
192
  'gi',
@@ -187,10 +234,19 @@ function isPlausibleClaim(stated: number, actual: number): boolean {
187
234
  * What it does not measure: a delta phrased as a transition (`from fourteen
188
235
  * to fifteen`), a fraction (`thirteen of sixteen`), and a total reached
189
236
  * through an indirect noun (`denominator of sixty-one shipped skills`) are
190
- * all catalog-size claims this corpus carries, and none matches the
191
- * assertion-verb shape this reads. Each is a known gap rather than an
192
- * oversight, left for a wider pass once this one's false-positive rate is
193
- * measured.
237
+ * all catalog-size claims this corpus carries, and none matches the trigger
238
+ * shape this reads. Each stays a known gap. The rate that used to gate
239
+ * closing them is measured now, and what it showed is that the widening they
240
+ * would need is the one that costs a false positive rather than the one that
241
+ * does not, which `buildMatcher` records with its numbers.
242
+ *
243
+ * A second figure in a sentence whose first figure already matched is a
244
+ * fourth gap and a structural one: `regex.exec` takes one match per catalog
245
+ * per sentence, so `authors 69 rules under governance/rules/ and consumes 54
246
+ * into .claude/rules/` is read for its 69 alone. Reaching the 54 would be
247
+ * wrong here rather than better, since it counts the consumed mirror rather
248
+ * than the source catalog this sweep tracks, but a sentence stating one
249
+ * catalog twice would go unread the same way.
194
250
  */
195
251
  export async function scanCounts(root: string): Promise<CountsReport> {
196
252
  const scope = await resolveMarkdown(root, [])