@erclx/aitk 0.65.0 → 0.66.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/docs/agents/markdown-audit.md +27 -4
- package/package.json +1 -1
- package/scripts/core/check-seed-independence.sh +59 -0
- package/scripts/core/verify.sh +10 -10
- package/scripts/lib/tooling.sh +11 -0
- package/src/commands/markdown.ts +1 -1
- package/src/markdown/structure.ts +1 -1
- package/standards/markdown.md +1 -1
- package/tooling/claude/seeds/CLAUDE.md +2 -2
|
@@ -55,9 +55,28 @@ Every weight and depth measure counts the text a reader is shown. A link reduces
|
|
|
55
55
|
|
|
56
56
|
A code span is walked around rather than through, so a path quoting link or angle-bracket syntax keeps the width the page gives it. Masking inside one takes back the decision to count it, and the placeholders this toolkit writes are where that shows.
|
|
57
57
|
|
|
58
|
-
The paragraph check
|
|
58
|
+
The paragraph check measures both halves of one rule. `markdown.md` caps a paragraph at four sentences, and a sentence cap on its own is satisfied by writing fewer and longer ones: 88 paragraphs in this corpus sit inside four sentences and past the weight checkpoint, and the heaviest of those runs 1121 characters. The standard therefore states a weight beside the sentence cap, and the verb reads it as its own checkpoint.
|
|
59
59
|
|
|
60
|
-
The paragraph weight and the bullet weight
|
|
60
|
+
The paragraph weight sits at 600 and the bullet weight at 400. The two shapes measure one population, sharing a median near 170 characters with no gap behind either candidate, so the paragraph number was borrowed from the bullet rule when both checks shipped. They are separate checkpoints in the standard and separate patterns in the parser, and the sample below moved one and left the other untouched.
|
|
61
|
+
|
|
62
|
+
#### The sample behind the paragraph number
|
|
63
|
+
|
|
64
|
+
The checkpoint shipped at 400 as a borrowed number and was decided against a read of the prose it reports. Thirty-six findings were sampled, six from each of six weight bands, drawn at even spacing through each band ordered by path and line, and each was classed as prose a reader wants split or prose the checkpoint should not have reported.
|
|
65
|
+
|
|
66
|
+
| Band | Wants the split | Reads as written |
|
|
67
|
+
| --------- | --------------- | ---------------- |
|
|
68
|
+
| 400 - 425 | 1 | 5 |
|
|
69
|
+
| 425 - 450 | 2 | 4 |
|
|
70
|
+
| 450 - 500 | 2 | 4 |
|
|
71
|
+
| 500 - 600 | 2 | 4 |
|
|
72
|
+
| 600 - 750 | 6 | 0 |
|
|
73
|
+
| Past 750 | 6 | 0 |
|
|
74
|
+
|
|
75
|
+
Precision is what moved the number rather than the finding count. Below 600 the checkpoint was right about seven of twenty-four sampled paragraphs, and past 600 it was right about all twelve. A checkpoint is a prompt to look, and a prompt wrong three times in four teaches a reader to stop looking. The distribution offers no seam to place the number against, with a median of 487 and a seventy-fifth percentile of 563, so the read is the whole of the evidence.
|
|
76
|
+
|
|
77
|
+
Nothing inside the 500 to 600 band separated the two classes by length, which is the reason the number did not land there. The two paragraphs wanting a split ran 543 and 590 characters against four reading well at 515, 532, 555, and 569.
|
|
78
|
+
|
|
79
|
+
The sample is thirty-six paragraphs against a reported population in the hundreds, and one reader classed all of them. Treat a band's rate as the order of magnitude it is rather than as a measured precision, and re-sample before moving the number again.
|
|
61
80
|
|
|
62
81
|
A bullet, a heading, a table row, a blockquote, a blank line, and a fence each end a paragraph, so a heavy bullet is reported by the bullet check alone and never counted twice.
|
|
63
82
|
|
|
@@ -67,9 +86,13 @@ Exit codes are `0` for a completed run and `1` for a refusal. Every finding repo
|
|
|
67
86
|
|
|
68
87
|
A banned character is a fact rather than a judgment, which is the test that would ordinarily make it gate. What holds it back is that gating on day one against a corpus never checked mechanically fails loudly on work nobody has had a chance to fix. The order is to land the verb reporting, measure the corpus once, fix what it finds, and turn the gate on as its own change. Bullet, paragraph, and depth weight are judgments and stay advisory under any later gate.
|
|
69
88
|
|
|
70
|
-
Measured across 444 files
|
|
89
|
+
Measured across 444 files with the paragraph checkpoint at 600: 8 word hits, no character or spelling hits, 119 heavy bullets, 221 heavy paragraphs across 86 files, and 41 files carrying a run past the depth checkpoint. Of the paragraphs, 88 fire on weight alone. This is the baseline the corpus sweep tracks its work against. The ban count is what a gate would have to hold at zero, and it is the only one of the five a gate should ever read.
|
|
90
|
+
|
|
91
|
+
A count written into prose goes stale against the corpus it describes, and nothing compares the two. The paragraph figure recorded when the masking fix shipped was already wrong by twelve one release later, which is why the standard states the rule and this page carries the numbers.
|
|
92
|
+
|
|
93
|
+
A standard sits inside the corpus this verb measures, so rewriting a rule can breach the rule beside it. A rewrite of the paragraph weight bullet landed at 539 characters against the bullet checkpoint stated two lines below it, in the authoring copy and the consumed one alike. Neither the drift stage nor the test suite reads that, so run the verb over a standard after editing one.
|
|
71
94
|
|
|
72
|
-
Masking took 7 of the
|
|
95
|
+
Masking took 7 of the weight-only paragraphs the checkpoint reported at 400 and 4 of the 44 files under their checkpoints, and no bullet at all. The first corpus triage put those at 31 paragraphs and 2 bullets, and neither reproduces: a code span is walked around, so a backticked path holding an angle-bracket placeholder keeps the width the page gives it, and both bullets the triage counted were that shape.
|
|
73
96
|
|
|
74
97
|
## What it does not cover
|
|
75
98
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -e
|
|
3
|
+
set -o pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
PROJECT_ROOT="${PROJECT_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}"
|
|
7
|
+
|
|
8
|
+
source "$PROJECT_ROOT/scripts/lib/tooling.sh"
|
|
9
|
+
|
|
10
|
+
TOOLKIT_TOKEN="aitk"
|
|
11
|
+
TOOLING_ROOT="$PROJECT_ROOT/tooling"
|
|
12
|
+
|
|
13
|
+
# `find` writes to stderr and returns non-zero for a missing root, inside a
|
|
14
|
+
# process substitution whose status nothing reads. Without this the walk covers
|
|
15
|
+
# nothing and the check reports the seeds independent having never read one.
|
|
16
|
+
if [ ! -d "$TOOLING_ROOT" ]; then
|
|
17
|
+
echo "No tooling root at ${TOOLING_ROOT#"$PROJECT_ROOT/"}, seed independence unverifiable." >&2
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# An empty discovery is a real state rather than a broken walk, and the Seed
|
|
22
|
+
# standards stage already reports it as a skip. Failing here would have the two
|
|
23
|
+
# stages disagree about what the same condition means.
|
|
24
|
+
seed_roots=$(collect_seed_roots)
|
|
25
|
+
if [ -z "$seed_roots" ]; then
|
|
26
|
+
echo "No seed root carries .claude/, nothing to check." >&2
|
|
27
|
+
exit 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Markdown alone. The seed tree also ships hooks that call the toolkit CLI on
|
|
31
|
+
# purpose, each reporting a named stale-index warning when the binary is absent,
|
|
32
|
+
# and scoping by extension leaves them outside this walk without an exemption
|
|
33
|
+
# list that would have to be maintained against them.
|
|
34
|
+
cited=""
|
|
35
|
+
measured=0
|
|
36
|
+
while IFS= read -r seed_root; do
|
|
37
|
+
while IFS= read -r file; do
|
|
38
|
+
measured=$((measured + 1))
|
|
39
|
+
while IFS= read -r hit; do
|
|
40
|
+
cited="$cited ${file#"$PROJECT_ROOT/"}:$hit"$'\n'
|
|
41
|
+
done < <(grep -n "$TOOLKIT_TOKEN" "$file" || true)
|
|
42
|
+
done < <(find "$PROJECT_ROOT/$seed_root" -type f -name '*.md')
|
|
43
|
+
done <<<"$seed_roots"
|
|
44
|
+
|
|
45
|
+
# Roots resolved and no markdown under any of them is a walk that covered
|
|
46
|
+
# nothing, which is the verdict-without-a-measurement the guards above refuse for
|
|
47
|
+
# a missing tree. Reporting a pass here would say the seeds cite no CLI on the
|
|
48
|
+
# strength of having read no prose.
|
|
49
|
+
if [ "$measured" -eq 0 ]; then
|
|
50
|
+
echo "Seed roots resolved but carry no markdown, seed independence unverifiable." >&2
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
if [ -n "$cited" ]; then
|
|
55
|
+
echo "Seed prose cites the toolkit CLI:" >&2
|
|
56
|
+
printf '%s' "$cited" >&2
|
|
57
|
+
echo "A scaffolded project may not have $TOOLKIT_TOKEN installed. State the capability the line needs rather than the binary that supplies it." >&2
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
package/scripts/core/verify.sh
CHANGED
|
@@ -7,6 +7,7 @@ PROJECT_ROOT="${PROJECT_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}"
|
|
|
7
7
|
|
|
8
8
|
source "$PROJECT_ROOT/scripts/lib/ui.sh"
|
|
9
9
|
source "$PROJECT_ROOT/scripts/lib/worktree.sh"
|
|
10
|
+
source "$PROJECT_ROOT/scripts/lib/tooling.sh"
|
|
10
11
|
|
|
11
12
|
NESTED="${VERIFY_NESTED:-false}"
|
|
12
13
|
WRITE="${VERIFY_WRITE:-true}"
|
|
@@ -127,16 +128,6 @@ assert_hero_pair() {
|
|
|
127
128
|
[ "$html_commit" = "$png_commit" ]
|
|
128
129
|
}
|
|
129
130
|
|
|
130
|
-
# Whatever stacks the repo currently carries, so a new one is covered without an
|
|
131
|
-
# edit here. A seed root holding no `.claude/` seeds nothing a standard governs.
|
|
132
|
-
collect_seed_roots() {
|
|
133
|
-
local dir
|
|
134
|
-
for dir in "$PROJECT_ROOT"/tooling/*/seeds; do
|
|
135
|
-
[ -d "$dir/.claude" ] || continue
|
|
136
|
-
printf '%s\n' "${dir#"$PROJECT_ROOT"/}"
|
|
137
|
-
done
|
|
138
|
-
}
|
|
139
|
-
|
|
140
131
|
# Entries the audit actually measured, summed across the folders it resolved.
|
|
141
132
|
# `--json` carries one `"entries":<n>` per folder object, and the top-level key
|
|
142
133
|
# of that name holds an array, so the numeric match reaches folders alone.
|
|
@@ -214,6 +205,15 @@ main() {
|
|
|
214
205
|
run_check "bash $PROJECT_ROOT/scripts/core/check-plugin-boundary.sh" "Plugin ships toolkit-internal content."
|
|
215
206
|
log_info "Plugin boundary clean"
|
|
216
207
|
|
|
208
|
+
# Seed prose is installed into every scaffolded project and read there as
|
|
209
|
+
# instruction about that project, so a line naming this repository's CLI hands
|
|
210
|
+
# a target a verb it may not be able to run. This gates for the reason the
|
|
211
|
+
# Seed standards stage below gates: a defect authored once propagates into
|
|
212
|
+
# every project scaffolded after it.
|
|
213
|
+
log_step "Seed independence"
|
|
214
|
+
run_check "bash $PROJECT_ROOT/scripts/core/check-seed-independence.sh" "Seed prose cites the toolkit CLI."
|
|
215
|
+
log_info "Seed prose cites no toolkit CLI"
|
|
216
|
+
|
|
217
217
|
# A stack entry naming a rule folder takes every rule in it, which is what
|
|
218
218
|
# stops a new rule from needing a second edit to reach a target. The failure
|
|
219
219
|
# it leaves open is a rule authored into a folder no stack names, which
|
package/scripts/lib/tooling.sh
CHANGED
|
@@ -22,3 +22,14 @@ list_tooling_stacks() {
|
|
|
22
22
|
echo "$name"
|
|
23
23
|
done < <(find "$tooling_dir" -mindepth 1 -maxdepth 1 -type d | sort)
|
|
24
24
|
}
|
|
25
|
+
|
|
26
|
+
# Seed roots that carry a `.claude/`, emitted relative to `PROJECT_ROOT`. Every
|
|
27
|
+
# stage measuring seed content discovers through this rather than naming a stack,
|
|
28
|
+
# so a stack seeding `.claude/` later arrives covered with no edit to any caller.
|
|
29
|
+
collect_seed_roots() {
|
|
30
|
+
local dir
|
|
31
|
+
for dir in "$PROJECT_ROOT"/tooling/*/seeds; do
|
|
32
|
+
[ -d "$dir/.claude" ] || continue
|
|
33
|
+
printf '%s\n' "${dir#"$PROJECT_ROOT"/}"
|
|
34
|
+
done
|
|
35
|
+
}
|
package/src/commands/markdown.ts
CHANGED
|
@@ -292,7 +292,7 @@ function reportParagraphs(
|
|
|
292
292
|
`Prose paragraphs report past ${checkpoints.sentences} sentences or past ${checkpoints.paragraph} characters.`,
|
|
293
293
|
)
|
|
294
294
|
logInfo(
|
|
295
|
-
'The standard states both
|
|
295
|
+
'The standard states both, and weight moves independently of the bullet checkpoint.',
|
|
296
296
|
)
|
|
297
297
|
logInfo(
|
|
298
298
|
'Bullets, headings, tables, quotes, and fenced blocks each end a paragraph, so a bullet is measured once.',
|
package/standards/markdown.md
CHANGED
|
@@ -34,7 +34,7 @@ Does not govern:
|
|
|
34
34
|
|
|
35
35
|
- Use prose by default. Reserve bullets for discrete, unrelated items.
|
|
36
36
|
- Keep paragraphs to four sentences or fewer. Split longer blocks at the next logical boundary.
|
|
37
|
-
- Past roughly
|
|
37
|
+
- Past roughly 600 characters in one paragraph, folding in the lines that wrap it, split at the next logical boundary as well. A paragraph written as two long sentences satisfies the sentence cap above and still asks the reader to hold too much at once. This number sits above the bullet checkpoint because a paragraph is read straight through and a bullet is scanned.
|
|
38
38
|
- Keep bullets tight. Past roughly 400 characters in one top-level bullet, counting the lines that continue it and excluding any bullet nested under it, the overflow belongs in prose. The number is a checkpoint rather than a cap, and a bullet reading well past it means the number is wrong rather than the rule.
|
|
39
39
|
- Collapse a stack of bullets narrating one subsystem into a single `###` subsection carrying one narrative. Splitting a heavy bullet into three light ones satisfies the checkpoint above and leaves the reader no better off, and subdividing a block does not lighten the bullets inside it, so the two rules answer different defects.
|
|
40
40
|
- Use dashes (`-`) not asterisks (`*`) for bulleted lists
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
- Write all memory files to `.claude/memory/`, not `~/.claude/projects/`
|
|
75
75
|
- A fact about a domain goes to that domain's `.claude/context/` entry, not to memory. `claude-memory-capture` routes it there and `claude-docs` folds it in. Memory keeps only what no context entry owns.
|
|
76
76
|
- Never delete a memory entry. Retire one by moving it to `.claude/.tmp/memory-archive/`. A bulk retire runs through the shell, where no file edit fires a path-scoped rule, and the folder is gitignored with nothing to recover from.
|
|
77
|
-
- Follow `.claude/standards/memory.md` for the filename and type prefix, the frontmatter, the body shape each type carries, and the lifecycle.
|
|
77
|
+
- Follow `.claude/standards/memory.md` for the filename and type prefix, the frontmatter, the body shape each type carries, and the lifecycle. Check every entry in the pen against that standard and fix what breaks it, since nothing keeps the folder conforming on its own.
|
|
78
78
|
|
|
79
79
|
## Scratch
|
|
80
80
|
|
|
@@ -87,4 +87,4 @@
|
|
|
87
87
|
- From a linked worktree, every `Edit` or `Write` to a tracked file (source, docs) must use a path starting with `pwd`.
|
|
88
88
|
- From a linked worktree, `Edit` and `Write` are refused for every main-root path, session scratch included. The refusal names session isolation and points at the worktree copy, which is a second gitignored file no later session reads, so never take that redirect.
|
|
89
89
|
- `Read` resolves against the main root normally from a linked worktree. A main-root write reaches it only through `Bash`, as one plain command rather than a compound one, which is refused for complexity.
|
|
90
|
-
- Route a main-root write by what it does to the file. Creating a whole file goes out as one plain `Bash` command carrying a heredoc. Changing a line inside a file that already exists goes through
|
|
90
|
+
- Route a main-root write by what it does to the file. Creating a whole file goes out as one plain `Bash` command carrying a heredoc. Changing a line inside a file that already exists goes through a command that resolves the main root in-process, because the shell route for that case is the stream editor this file bans.
|