@erclx/canon 4.36.1 → 4.37.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.
- package/claude/.claude-plugin/plugin.json +1 -1
- package/docs/agents/markdown-audit.md +6 -2
- package/package.json +1 -1
- package/src/migrate/plan.ts +1 -0
- package/tooling/base/configs/scripts/verify.sh +47 -0
- package/tooling/base/reference.md +2 -0
- package/tooling/base/seeds/.claude/context/development.md +1 -1
|
@@ -154,11 +154,15 @@ A hit the closed set cannot separate from correct prose is the case with no thir
|
|
|
154
154
|
|
|
155
155
|
### Where the rules are enforced
|
|
156
156
|
|
|
157
|
-
|
|
157
|
+
Five surfaces apply the ban sets and four of them go through this verb. `.claude/hooks/standards-audit.sh` runs it against a single file after each markdown edit, the seed copy a project installs does the same, the `Markdown bans` stage in `canon gate run` runs it across the whole corpus before this repository's own push, and the same-named stage in `tooling/base/configs/scripts/verify.sh` runs it across a scaffolded project's tracked markdown before its own push. Each hook parsed its own copy of the word bans in awk before that, which left a British spelling passing at edit time and failing the push with nothing in between explaining the difference.
|
|
158
158
|
|
|
159
159
|
The seed copy moved onto the verb when the sets became data, since its awk had nothing left to parse. It resolves one runner where the toolkit copy resolves two, looking for no checkout source, and a machine carrying no `canon` gets a report naming the binary to install rather than a silent pass. `scripts/core/check-seed-independence.sh` scopes its walk to markdown and leaves the seed hooks outside it, which its own comment records as deliberate.
|
|
160
160
|
|
|
161
|
-
The
|
|
161
|
+
The target push stage reads the same exit codes `canon gate run`'s own stage reads: 0 passes, 1 is a refusal logged as a skip, 2 is a finding, and 3 is a shipped-empty ban set. It skips and logs rather than failing when no `canon` binary is on the machine's PATH, since a scaffolded project is not guaranteed the toolkit is installed, and its skip line names the install command.
|
|
162
|
+
|
|
163
|
+
The target push stage excludes `CHANGELOG.md`, unlike every other surface here. A changelog a generator builds from commit subjects carries prose nobody wrote against the ban set, where this repository's own passes only because `release-please` builds it from subjects sessions already wrote to the rule. The stage passes an explicit file list rather than the bare invocation the other surfaces use, so a corpus with no file left once the changelog is set aside reads as a pass rather than falling back to the whole tree.
|
|
164
|
+
|
|
165
|
+
The fifth surface reads the standards directly and is not a consolidation left half done. `claude/skills/claude-standards-audit/SKILL.md` greps the banned tokens agent-side, which is a session reading prose rather than a process it can shell out to, and it ships to every target. It is the likeliest place for the next drift, since nothing compares it against the verb.
|
|
162
166
|
|
|
163
167
|
The hook prefers a checkout's own `src/cli.ts` over a globally installed binary, so it and the push stage read one build. A published binary lags a branch by whatever has not been released, which would put a ban kind added on the branch into the push and not into the edit. It reads its findings out of the `--json` record rather than off the exit code, so an older binary still reports where the fallback applies. It reads `bans.emptySets` out of the same record, so a set the verb shipped empty reaches the author as a check narrowed to what it could measure rather than as a clean pass.
|
|
164
168
|
|
package/package.json
CHANGED
package/src/migrate/plan.ts
CHANGED
|
@@ -23,6 +23,50 @@ check_dependencies() {
|
|
|
23
23
|
command -v bun >/dev/null 2>&1 || log_error "bun is not installed"
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
check_markdown_bans() {
|
|
27
|
+
if ! command -v canon >/dev/null 2>&1; then
|
|
28
|
+
log_info "Skipped: no canon binary on PATH. Install with \`bun install --global @erclx/canon\`."
|
|
29
|
+
return 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
local files=()
|
|
33
|
+
while IFS= read -r file; do
|
|
34
|
+
files+=("$file")
|
|
35
|
+
done < <(git ls-files --cached --others --exclude-standard -- '*.md' ':(exclude)CHANGELOG.md' ':(exclude)**/CHANGELOG.md')
|
|
36
|
+
|
|
37
|
+
if [ ${#files[@]} -eq 0 ]; then
|
|
38
|
+
log_info "No markdown file to check outside the exclusion set."
|
|
39
|
+
return 0
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
local output code
|
|
43
|
+
if output=$(canon markdown audit "${files[@]}" 2>&1); then
|
|
44
|
+
code=0
|
|
45
|
+
else
|
|
46
|
+
code=$?
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
case "$code" in
|
|
50
|
+
0)
|
|
51
|
+
log_info "No banned character, word, or spelling"
|
|
52
|
+
;;
|
|
53
|
+
1)
|
|
54
|
+
log_info "Skipped: canon markdown audit refused and measured nothing."
|
|
55
|
+
;;
|
|
56
|
+
2)
|
|
57
|
+
echo "$output" | pipe_output
|
|
58
|
+
log_error "Markdown prose carries a banned character, word, or spelling, or a relative link resolves to nothing on disk"
|
|
59
|
+
;;
|
|
60
|
+
3)
|
|
61
|
+
echo "$output" | pipe_output
|
|
62
|
+
log_error "The markdown audit shipped an empty ban set, so the corpus was walked and nothing was looked for"
|
|
63
|
+
;;
|
|
64
|
+
*)
|
|
65
|
+
log_error "canon markdown audit exited $code, which is neither a pass nor a finding"
|
|
66
|
+
;;
|
|
67
|
+
esac
|
|
68
|
+
}
|
|
69
|
+
|
|
26
70
|
run_check() {
|
|
27
71
|
local cmd=$1
|
|
28
72
|
local err_msg=$2
|
|
@@ -55,6 +99,9 @@ main() {
|
|
|
55
99
|
run_check "bun run check:shell" "Shell check failed"
|
|
56
100
|
log_info "Shell check passed"
|
|
57
101
|
|
|
102
|
+
log_step "Markdown bans"
|
|
103
|
+
check_markdown_bans
|
|
104
|
+
|
|
58
105
|
if [ "$NESTED" = false ]; then
|
|
59
106
|
echo -e "${GREY}└${NC}\n"
|
|
60
107
|
echo -e "${GREEN}✓ Verification passed${NC}"
|
|
@@ -96,3 +96,5 @@ Sticky negative knowledge. Do not relearn.
|
|
|
96
96
|
| `bun run prepare` | Initializes husky hooks, run automatically on `bun install` |
|
|
97
97
|
|
|
98
98
|
`bun run check` repairs a checkout rather than gating one. It runs `format` first to auto-fix drifted code, then asserts only what the formatters could not fix. The pull request workflow calls `check:format`, `check:spell`, and `check:shell` directly, and those three are the gate.
|
|
99
|
+
|
|
100
|
+
`scripts/verify.sh`'s `Markdown bans` stage is the exception: it gates rather than repairs. It runs `canon markdown audit` over every tracked markdown file except `CHANGELOG.md`, since a generated changelog carries commit subjects nobody wrote against the ban set, and exits `2` on a finding or `3` on a shipped-empty ban set, failing `bun run check` and the `pre-push` hook that calls it. A refusal to measure exits `1` and is logged as a skip rather than a failure, as does a corpus with no file left to check once `CHANGELOG.md` is set aside. The stage needs `canon` on PATH. `docs/target-projects.md` names the install command. Without it, the stage is skipped and logged, and coverage falls back to the three checks above.
|
|
@@ -34,4 +34,4 @@ All `.sh` files live under `scripts/`. Do not place shell scripts outside `scrip
|
|
|
34
34
|
|
|
35
35
|
- `pre-commit` runs `lint-staged` (prettier, cspell, shfmt, shellcheck on staged files).
|
|
36
36
|
- `commit-msg` runs `commitlint` against the conventional commit format.
|
|
37
|
-
- `pre-push` runs `bun run check`. After pushing, run `git status`. If files changed, commit the diff as `style(<scope>):` and push again.
|
|
37
|
+
- `pre-push` runs `bun run check`. When a markdown-bans audit tool is on PATH, it also gates on banned characters, words, and spellings across every tracked markdown file except `CHANGELOG.md`. After pushing, run `git status`. If files changed, commit the diff as `style(<scope>):` and push again.
|