@erclx/aitk 3.38.0 → 3.39.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.
@@ -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.39.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -35,6 +35,8 @@ Every one of them therefore has to ship inside the skill, the four covering the
35
35
 
36
36
  The dispatch's return leg is unplaced for the same reason. A reply reaches this session as a message and settles a finding, corrects which session holds which branch, or names a gate a worker's edits pass through, and reading it is the whole of what happens to it. Both sessions then end, so the half that belonged on the pull request never reaches it and the half that belonged on the board is rediscovered by whoever needs it next.
37
37
 
38
+ Cost never enters the decision to widen a wave. The rule weighing how many tracks to open measures collision and review attention, and both describe what a worker writes rather than what the loop spends. Claude Code delivers a message from another session as a fresh turn carrying the whole accumulated context, and a recurring poll bills that same window on its own interval, so a wave's spend tracks this session's context rather than the work coming back. The one setting that bounds it reads as available to whoever finds it, and the two values that would bound it break the handback the loop runs on.
39
+
38
40
  The session also records nothing of what it learns. Both other callers of memory capture are ship-chain skills and this one never ships, so the session taking every operator correction is the session with no moment that writes one down. Hanging that moment on the merge sweep answers it and bills the operator a capture pass per batch of merges while nothing is being built, which is a cost paid on the days shipping is fastest.
39
41
 
40
42
  ## Must
@@ -43,6 +45,7 @@ The session also records nothing of what it learns. Both other callers of memory
43
45
  - Report the state of play so the human knows what to launch, what to review, and what to merge
44
46
  - Verify a plan against the tree before handing it over, counting the sites it claims and opening the files it describes
45
47
  - List a candidate's file set against every track in flight, and serialize when the sets are not disjoint
48
+ - State what a wave costs in inbound turns beside the collision rule, and name the control that bounds it together with the reason it stays unset, since a lever recorded without its conclusion reads as available to set
46
49
  - Place every finding a merged pull request produced against the surface that owns it
47
50
  - Place what the return leg carries by what it changes, sending an answer that settles a finding onto the pull request and one that corrects this session's model of the world to the task owning that surface, since neither becomes a record by being read
48
51
  - Keep one planned, non-conflicting task in reserve beyond what is running
@@ -200,6 +200,21 @@ properly and stop when you cannot. An operator can also cap this session's
200
200
  workers by saying so, and a spoken cap binds for that session rather than
201
201
  standing as a number in a file.
202
202
 
203
+ Inbound turns are the third input to that judgment. Claude Code delivers a
204
+ message from another session as a new turn whenever this one sits idle, and the
205
+ turn carries the whole accumulated context rather than the few lines the worker
206
+ sent, so one handback from a wide wave costs more than the same handback from a
207
+ narrow one. A recurring review poll bills that window again on every interval it
208
+ fires. Weigh the spend before widening, since it lands on this session's context
209
+ and never on the worker's.
210
+
211
+ `crossSessionInbound` is the control, on an `accept`, `hold`, `refuse` ladder,
212
+ and it is recorded here as deliberately not pulled. `hold` and `refuse` are the
213
+ two values that bound the cost, and both break the handback this loop runs on,
214
+ since a held message reaches nobody until a later `accept` applies and a refused
215
+ one is dropped outright. `accept` bounds nothing. Read the ladder before turning
216
+ concurrency up rather than after, and leave it unset.
217
+
203
218
  Serialize any track that touches a shared wiring seam with another in flight, and
204
219
  serialize one whose sets are disjoint when a stated reason still puts it behind
205
220
  another, since two tracks interact in ways no file-set comparison reads. One
@@ -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 70 rules` and `took all 70 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 70 rules` at every width, and reached `the toolkit authors 70 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 70 rules under governance/rules/ and consumes 55 into .claude/rules/` is read for its 70 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
 
@@ -154,6 +154,14 @@ above it, and stop adding once you can no longer review every output properly.
154
154
  Serialize a track sharing a wiring seam with another, and serialize one whose
155
155
  sets are disjoint when a stated reason still puts it behind another.
156
156
 
157
+ Inbound turns cost the controlling session as well, so weigh the spend before
158
+ widening. A message from one of your other sessions arrives as a new turn
159
+ carrying the whole accumulated context, and a recurring poll bills that window
160
+ again on its own interval, which means a wide wave spends against the
161
+ orchestrator rather than against any worker. `crossSessionInbound` is the one
162
+ control over that and stays unset here, since `hold` and `refuse` both break the
163
+ worker handback and `accept` bounds nothing.
164
+
157
165
  Unit checks run freely in many worktrees at once.
158
166
  A dev server, an end-to-end run, and a screenshot run alongside each other on a
159
167
  web stack, since every worktree derives its own port. Singleton resources (one
@@ -0,0 +1,14 @@
1
+ ---
2
+ description: State the autoContinueAtUsageLimit inversion and the autoCompactWindow cap for .claude/settings.json and its seeded copy
3
+ paths:
4
+ - '.claude/settings.json'
5
+ - 'tooling/claude/seeds/.claude/settings.json'
6
+ ---
7
+
8
+ # Settings standards
9
+
10
+ ## Session budget settings
11
+
12
+ - Never set `autoContinueAtUsageLimit` in this file. Its scope is user or managed, and a repository file setting it while no user, `--settings`, or managed value does makes Claude Code read the setting as off, so writing `true` here turns the behavior off for every operator carrying no value of their own.
13
+ - Treat `autoCompactWindow` as capped at the model's own context window. A value above that cap is inert on a session running a smaller window and bites only on one running the larger, so name the window a recorded value is meant for.
14
+ - Record why a session budget setting is left unset in the project's own development notes rather than in this file. JSON carries no pointer, so a session reading the settings file alone concludes the setting is unconfigured and sets it again.
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.39.0",
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, [])