@erclx/aitk 0.104.1 → 0.106.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-address-review/SKILL.md +4 -3
- package/claude/skills/claude-design-extract/SKILL.md +3 -3
- package/claude/skills/claude-docs/SKILL.md +1 -1
- package/claude/skills/claude-groundwork/SKILL.md +3 -2
- package/claude/skills/claude-memory-capture/SKILL.md +2 -2
- package/claude/skills/claude-pr-review/SKILL.md +1 -1
- package/claude/skills/claude-standards-audit/SKILL.md +8 -6
- package/claude/skills/claude-worktree/SKILL.md +6 -1
- package/claude/skills/create-skill/SKILL.md +2 -2
- package/claude/skills/create-snippet/SKILL.md +2 -2
- package/claude/skills/create-snippet/references/snippets.md +2 -2
- package/claude/skills/create-standard/SKILL.md +2 -2
- package/claude/skills/docs-sync/SKILL.md +2 -2
- package/claude/skills/git-issue/SKILL.md +2 -2
- package/claude/skills/git-issue/references/issue.md +2 -2
- package/claude/skills/git-pr/SKILL.md +2 -2
- package/claude/skills/git-pr/references/pr.md +2 -2
- package/claude/skills/git-split/references/pr.md +2 -2
- package/claude/skills/git-stage/SKILL.md +2 -2
- package/claude/skills/migration-standards/SKILL.md +1 -1
- package/claude/skills/setup-indexes/SKILL.md +1 -1
- package/claude/skills/write-human/REQUIREMENT.md +46 -0
- package/claude/skills/write-human/SKILL.md +68 -0
- package/claude/skills/write-human/references/density.md +38 -0
- package/claude/skills/write-human/references/machine-tells.md +107 -0
- package/claude/skills/write-human/references/source-material.md +37 -0
- package/docs/agents/commands.md +2 -1
- package/docs/agents/index.md +1 -0
- package/docs/agents/markdown-audit.md +7 -7
- package/docs/agents/test-order.md +56 -0
- package/docs/ai-workflow.md +3 -0
- package/docs/target-projects.md +1 -1
- package/governance/rules/claude/500-prose.md +7 -5
- package/governance/rules/claude/501-markdown.md +5 -4
- package/governance/rules/core/070-planning.md +1 -0
- package/package.json +1 -1
- package/scripts/core/install-check.sh +1 -1
- package/src/commands/gov.ts +135 -0
- package/src/commands/markdown.ts +2 -2
- package/src/comments/vocabulary.ts +1 -1
- package/src/gov/test-order.ts +383 -0
- package/src/markdown/bans.ts +2 -2
- package/src/standards/closure.ts +1 -1
- package/standards/bundled/issue.md +2 -2
- package/standards/bundled/pr.md +2 -2
- package/standards/bundled/snippets.md +2 -2
- package/standards/diagrams.md +5 -5
- package/standards/glossary.md +2 -2
- package/standards/groundwork.md +6 -2
- package/standards/index.md +1 -2
- package/standards/intake.md +2 -2
- package/standards/markdown.md +55 -6
- package/standards/memory.md +2 -2
- package/standards/plan.md +2 -2
- package/standards/publish.md +2 -2
- package/standards/readme.md +4 -4
- package/standards/skill.md +2 -2
- package/standards/standard.md +2 -2
- package/standards/teach.md +2 -2
- package/standards/versioning.md +2 -2
- package/standards/wireframes.md +3 -3
- package/tooling/astro/manifest.toml +5 -5
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +2 -2
- package/tooling/vite-react/manifest.toml +4 -4
- package/tooling/web/configs/scripts/worktree-port.sh +44 -6
- package/tooling/web/manifest.toml +3 -3
- package/tooling/web/reference.md +4 -1
- package/standards/prose.md +0 -89
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Source material
|
|
3
|
+
description: Which external writing patterns this skill adopted, which it declined, and the measurement behind each decision
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Source material
|
|
7
|
+
|
|
8
|
+
Two external writing skills were read on 2026-08-19 as source material for this one. The first catalogs 31 patterns of machine-sounding prose. The second layers document mode, sentence construction, information density, and ambiguity prevention.
|
|
9
|
+
|
|
10
|
+
Neither was imported wholesale, and one measurement settles why. Read this before adding a rule from outside this corpus, and extend the position below rather than deriving a second one.
|
|
11
|
+
|
|
12
|
+
## What was adopted
|
|
13
|
+
|
|
14
|
+
Roughly half the pattern catalog had no counterpart in this corpus, and six of those patterns are now in `machine-tells.md`: rule-of-three, synonym cycling, false ranges, inline-header lists, adverb propping, and passive voice with an unnamed actor. Each is a shape rather than a token, which is what kept it out of a ban list that matches words.
|
|
15
|
+
|
|
16
|
+
The density layer had no counterpart at all and is now `density.md`. Its useful half is the split between what a compression pass may cut and what it may not, since a terse register already instructs a session to cut and names nothing that has to survive.
|
|
17
|
+
|
|
18
|
+
The ambiguity rules travel with that layer for the same reason. Compression is what creates the ambiguity, so a rule about pronouns and modifiers belongs beside the rule that shortened the sentence.
|
|
19
|
+
|
|
20
|
+
## What was declined
|
|
21
|
+
|
|
22
|
+
- **The ban on abstract metaphor nouns.** The nouns it names are load-bearing terms in this corpus rather than decoration, and the count below is what decides it.
|
|
23
|
+
- **Document mode as a selector.** The source has the writer pick a mode before drafting. In this corpus a document's shape is already fixed by the standard governing its type, so a mode selector adds a second authority over one question and the two will disagree.
|
|
24
|
+
- **Any restatement of a banned word set.** The bans ship as package data that `aitk markdown audit` reads, and a copy here would be a second source for one list with a machine reading the other.
|
|
25
|
+
- **A voice register per surface.** One baseline covers every surface. A surface needing a warmer register states its own voice and claims the yield, which lifts voice alone and leaves the bans, the rhythm rules, and the tells in force.
|
|
26
|
+
|
|
27
|
+
The first of those four rests on a count. The source names `surface` among the nouns it bans, and tracked markdown in the authoring repository used `surface` 593 times, `harness` 95, `scaffolding` 17, and `primitive` 4, measured at `57ee7467` on 2026-08-19. Adopting the item either rewrites established vocabulary across the corpus or is ignored in silence, and a reader arriving later cannot tell which happened.
|
|
28
|
+
|
|
29
|
+
## Where this diverges
|
|
30
|
+
|
|
31
|
+
The source material treats repetition of a noun as a defect. This skill treats it as precision and bans the synonym cycling that avoids it, which reverses the item for reference prose where a reader has to know that two names are one thing.
|
|
32
|
+
|
|
33
|
+
The source material also prefers shorter sentences without bound. This skill measures the spread instead, since a passage of uniformly short sentences is the reported failure rather than the fix for it.
|
|
34
|
+
|
|
35
|
+
## The industry-guide record
|
|
36
|
+
|
|
37
|
+
The cadence rules and the bans they pair with trace to three industry style guides, being Google's developer documentation style guide, Microsoft's writing style guide, and Apple's style guide. The authoring toolkit keeps the per-rule attributions and the dates each guide was read, and no install carries that record, so this file is the position a target reads.
|
package/docs/agents/commands.md
CHANGED
|
@@ -45,6 +45,7 @@ Full help: `aitk <command> --help`. Behavior notes for the install and sync verb
|
|
|
45
45
|
| `aitk markdown audit` | Fail any markdown path on a banned character, word, or spelling, and report the structural checkpoints |
|
|
46
46
|
| `aitk claude skills audit` | Report both skill corpora against the mechanical rules in `standards/skill.md` |
|
|
47
47
|
| `aitk claude skills drift` | Name the shipped skill bodies rewritten between a given ref and `HEAD` (`--json`) |
|
|
48
|
+
| `aitk gov test-order` | Report where an implementation reached history ahead of the test covering it (`--json`) |
|
|
48
49
|
| `aitk capture [source]` | Render HTML capture sources to PNG, toolkit-only and absent from an installed package |
|
|
49
50
|
|
|
50
51
|
## Domain commands
|
|
@@ -56,7 +57,7 @@ Each domain exposes a consistent shape where applicable: `list`, `install`, `syn
|
|
|
56
57
|
| `tooling` | `list`, `sync`, `ref`, `create`, `verify`, `inject`, `prune-gitignore` |
|
|
57
58
|
| `snippets` | `list`, `install`, `sync`, `create` |
|
|
58
59
|
| `standards` | `list`, `install`, `sync`, `<name>` |
|
|
59
|
-
| `gov` | `list`, `install`, `sync`, `build`
|
|
60
|
+
| `gov` | `list`, `install`, `sync`, `build`, `regen`, `test-order` |
|
|
60
61
|
| `claude` | `init`, `sync`, `seeds list`, `skills list`, `skills audit`, `skills drift`, `setup [dest]` |
|
|
61
62
|
| `wiki` | `init` |
|
|
62
63
|
| `design` | `render` |
|
package/docs/agents/index.md
CHANGED
|
@@ -27,3 +27,4 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
27
27
|
- [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
|
|
28
28
|
- [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
|
|
29
29
|
- [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
|
|
30
|
+
- [Test order](test-order.md): Reading where an implementation reached history ahead of its test, how a pair is decided, the three verdicts, the coverage the pairing cannot reach, and why the check reports rather than gates
|
|
@@ -5,7 +5,7 @@ description: Running the audit over any markdown path, where its bans and checkp
|
|
|
5
5
|
|
|
6
6
|
# Markdown audit
|
|
7
7
|
|
|
8
|
-
`aitk markdown audit [path...]` reports any markdown file against the
|
|
8
|
+
`aitk markdown audit [path...]` reports any markdown file against the attribute standard `markdown.md`. An attribute standard governs a file rather than a folder, so this resolves no folder and requires no `index.md`, which is what puts `.claude/rules/`, `governance/`, and `snippets/` in reach. Folder-shaped findings stay in `aitk context audit`, described in `context-audit.md`.
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
11
|
aitk markdown audit
|
|
@@ -29,9 +29,9 @@ A bare run measures every markdown file git lists, tracked plus untracked-and-no
|
|
|
29
29
|
|
|
30
30
|
The three ban sets and all six checkpoints ship with the `aitk` package as data, in `src/markdown/bans.ts` and `src/markdown/structure.ts`. Every project is measured against the same sets whether or not it installed any standards, and no file has to resolve for a run to mean something.
|
|
31
31
|
|
|
32
|
-
Reading them out of the standards per run was the original design. It put a parser contract on
|
|
32
|
+
Reading them out of the standards per run was the original design. It put a parser contract on a document authored for people, and the standard had to carry a paragraph of its own warning an author that a one-word backticked example in a `- Do not use ` bullet would be lifted into a literal ban set and ban that word everywhere. A rule existing to protect a parser from the prose it parses is the argument for separating them.
|
|
33
33
|
|
|
34
|
-
`markdown.md`
|
|
34
|
+
`markdown.md` still states every ban and every checkpoint, and a reader follows it rather than the code. Nothing compares the two, so a number moved in one place and left in the other drifts silently. Move both in the same change.
|
|
35
35
|
|
|
36
36
|
The sets are closed rather than extensible, so a project cannot add a term by editing a file. What decides that is the measurement behind them: 21 terms across 483 markdown files report a clean exit, and every occurrence of a banned word in the corpus sits inside the ban list itself or inside an example demonstrating the ban. The set is a prior an author already knows rather than a filter that has caught anything, and enumeration cannot close the gap it aims at, since `just`, `allows`, and `very` carry honest uses no literal match separates.
|
|
37
37
|
|
|
@@ -45,7 +45,7 @@ A set shipped empty is reported rather than passed. It finds nothing and would e
|
|
|
45
45
|
|
|
46
46
|
### Bans
|
|
47
47
|
|
|
48
|
-
Three closed sets report a hit: the characters `markdown.md` bans under `## Punctuation`, the single lowercase words
|
|
48
|
+
Three closed sets report a hit: the characters `markdown.md` bans under `## Punctuation`, the single lowercase words it bans under `## Language`, and the British spellings of the American examples that section lists.
|
|
49
49
|
|
|
50
50
|
Deriving the spellings rather than pattern-matching a suffix is what keeps `exercises`, `promises`, and `revised` out of the report. A suffix pattern over the same corpus produced 46 false positives from words of that shape, and a closed set of whole words reaches none of them.
|
|
51
51
|
|
|
@@ -120,7 +120,7 @@ Rewrite the sentence rather than swapping the banned token for a near-synonym. T
|
|
|
120
120
|
|
|
121
121
|
A code span clears the report too, since the ban scan walks around one, and it is the answer only where the token is genuinely an identifier under discussion. `## Code and identifiers` in `markdown.md` reserves the span for commands, API names, file paths, and identifiers, so backticking a quoted utterance spends one rule to satisfy another and leaves the corpus no cleaner.
|
|
122
122
|
|
|
123
|
-
A hit the closed set cannot separate from correct prose is the case with no third option. `
|
|
123
|
+
A hit the closed set cannot separate from correct prose is the case with no third option. `markdown.md` bans vague qualifiers and lists the tokens those qualifiers happen to spell, so the temporal `just` reports as the vague one. The rule as written reaches neither, and rewriting the sentence is what the toolkit settled on over building an exemption path, for the reasons below.
|
|
124
124
|
|
|
125
125
|
### Where the rules are enforced
|
|
126
126
|
|
|
@@ -150,9 +150,9 @@ Masking took 7 of the weight-only paragraphs the checkpoint reported at 400 and
|
|
|
150
150
|
|
|
151
151
|
### How the ban count reached zero
|
|
152
152
|
|
|
153
|
-
Eight word hits stood between the baseline and a gate, and only three carried the sense
|
|
153
|
+
Eight word hits stood between the baseline and a gate, and only three carried the sense the standard bans. `leverage` sat in the requirements worldview, `allows` in the claude stack reference, and one `just` was the vague qualifier in a skill body. Those three lost the qualifier rather than the word.
|
|
154
154
|
|
|
155
|
-
The other five were correct prose the closed set cannot separate from a violation. Four were the temporal `just`, meaning a moment ago, in phrases like the implementation `just` completed and the field the user `just` edited. The fifth quoted an anti-pattern a skill exists to forbid. `
|
|
155
|
+
The other five were correct prose the closed set cannot separate from a violation. Four were the temporal `just`, meaning a moment ago, in phrases like the implementation `just` completed and the field the user `just` edited. The fifth quoted an anti-pattern a skill exists to forbid. `markdown.md` bans vague qualifiers and lists the tokens those qualifiers happen to spell, so the rule as written reaches none of the five while the scan reaches all of them.
|
|
156
156
|
|
|
157
157
|
### Why they were rewritten rather than exempted
|
|
158
158
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Test order
|
|
3
|
+
description: Reading where an implementation reached history ahead of its test, how a pair is decided, the three verdicts, the coverage the pairing cannot reach, and why the check reports rather than gates
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test order
|
|
7
|
+
|
|
8
|
+
`aitk gov test-order` reports where an implementation reached a commit ahead of the test covering the same behavior. It answers the rule in `.claude/rules/core/070-planning.md` that asks for the test first, which until this verb existed was prose loaded on a glob match with nothing measuring it.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
aitk gov test-order
|
|
12
|
+
aitk gov test-order --base origin/main --json
|
|
13
|
+
aitk gov test-order --root ../my-app
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
| Option | Behavior |
|
|
17
|
+
| --------------- | ----------------------------------------------------------------- |
|
|
18
|
+
| `--base <ref>` | Far side of the range, defaulting to the merge base against trunk |
|
|
19
|
+
| `--root <path>` | Repository to read, defaulting to the current directory |
|
|
20
|
+
| `--json` | Add a machine-readable record on stdout, keeping the frame |
|
|
21
|
+
|
|
22
|
+
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. A consumer reading stdout sees pure data, and an operator reading the terminal sees why a run refused rather than a command that appeared to do nothing.
|
|
23
|
+
|
|
24
|
+
## The range it reads
|
|
25
|
+
|
|
26
|
+
The default range is the branch against the trunk, resolved as the merge base against `origin/main` and then local `main`. A repository carrying neither falls back to the root commit, so a fresh checkout still answers rather than refusing.
|
|
27
|
+
|
|
28
|
+
Reading all history on every run measures work nobody is reviewing and buries the finding that matters under the ones already merged. `--base` widens or narrows it when a reader wants a different window.
|
|
29
|
+
|
|
30
|
+
Only history is read. A file sitting in the working tree and in no commit is invisible here, which is the point: the verification run sees a tree at one moment, and the ordering exists nowhere but history.
|
|
31
|
+
|
|
32
|
+
## How a pair is decided
|
|
33
|
+
|
|
34
|
+
A test is paired to an implementation by the module path with the test suffix removed, so `src/parser.test.ts` covers `src/parser.ts`. Every record is keyed on the implementation path, which is what a reader goes looking for.
|
|
35
|
+
|
|
36
|
+
Pairing is the whole difficulty. A test and its implementation are related by behavior rather than by filename, so a behavior split across two modules pairs wrongly or not at all. That is what the unclassified verdict exists to catch rather than hide.
|
|
37
|
+
|
|
38
|
+
## The three verdicts
|
|
39
|
+
|
|
40
|
+
- **Satisfied.** The implementation was added in the range and its test reached history no later. A test that predates the range counts, and so does one commit carrying both sides, since the rule asks that the test not come after and a single commit is the shape a small change takes.
|
|
41
|
+
- **Implementation-first.** The implementation was added in the range and its test was added in a later commit of the same range. This is the only verdict that moves the exit code.
|
|
42
|
+
- **Unclassified.** Everything the pairing cannot read, each carrying its own reason. A module the range modified rather than added lands here, because a refactor and a new behavior cannot be told apart from history. So does an implementation no test names, and a test whose implementation the range never introduced.
|
|
43
|
+
|
|
44
|
+
## What it reads past
|
|
45
|
+
|
|
46
|
+
Only `.ts` and `.tsx` are paired, since a test sits beside its subject under one name across that corpus and a bash script has no such partner. Declaration files carry no behavior to test. Every other changed path is counted under `Read past` rather than dropped silently.
|
|
47
|
+
|
|
48
|
+
Coverage is narrower than the rule the check answers to. The rule speaks to every behavior, and the verb speaks to the behaviors it can identify, so the report states its own scope on every run rather than implying it looked at everything.
|
|
49
|
+
|
|
50
|
+
## Exit codes
|
|
51
|
+
|
|
52
|
+
Exit codes are `0` when nothing reached history ahead of its test, `1` for a refusal, and `2` for at least one implementation-first finding. Unclassified rows move no exit code.
|
|
53
|
+
|
|
54
|
+
Nothing wires this into `bun run check` or into a hook. The unclassified class is large and known, and gating a measure carrying a known false-positive class is what teaches contributors to route around the stage. `aitk tasks validate` is the precedent: it exits `2` on findings and is called where the claim is made rather than on every push.
|
|
55
|
+
|
|
56
|
+
An exit code says nothing about a call made from a session, since a shell profile may wrap the binary in a function taking its status from a later command. Read the JSON record's `findings` array rather than the exit when a skill consumes this.
|
package/docs/ai-workflow.md
CHANGED
|
@@ -55,6 +55,8 @@ The routing test is whether the repository can answer an item today. A session g
|
|
|
55
55
|
|
|
56
56
|
A groundwork track may run experiments to settle a question, writing a fixture it reads itself under `.claude/.tmp/groundwork-fixtures/<slug>/` and spawning up to three billed headless runs before it asks. A fixture a headless run is pointed at sits outside the repository, since a session started under the project root inherits that project's `CLAUDE.md` and rules and would measure them instead of the arm.
|
|
57
57
|
|
|
58
|
+
What a spike produces goes somewhere else again. An input the run reads is re-runnable and cited by nothing, so the scratch path above is the right lifetime for it, while a recording or a render the track cites as evidence for a finding is what a later reader opens to check the claim. Evidence therefore lives in `evidence/` inside the track beside the file citing it, since the scratch tree holds only what can be deleted without loss.
|
|
59
|
+
|
|
58
60
|
#### Session 2
|
|
59
61
|
|
|
60
62
|
Start a fresh Claude Code session. The diff is sufficient context for both review and ship.
|
|
@@ -279,6 +281,7 @@ This section is the corpus the coverage claim is measured against: every name `a
|
|
|
279
281
|
| `aitk:toolkit-cli` | Before a sync or install, to learn what it overwrites, merges, or leaves alone |
|
|
280
282
|
| `aitk:youtube-transcripts` | When a video transcript is wanted in the repo as context |
|
|
281
283
|
| `aitk:claude-teach` | To learn a subject across sessions, in a workspace that holds the progress |
|
|
284
|
+
| `aitk:write-human` | Before drafting or revising prose, for voice, rhythm, and density |
|
|
282
285
|
|
|
283
286
|
Every row answers a question rather than marking a point in a project's life, so a phase above would send a reader to the wrong group.
|
|
284
287
|
|
package/docs/target-projects.md
CHANGED
|
@@ -88,7 +88,7 @@ Run `aitk tooling list --json` and `aitk gov list --json` to see the current cat
|
|
|
88
88
|
|
|
89
89
|
`governance`, `standards`, and `wiki` are skippable:
|
|
90
90
|
|
|
91
|
-
- `--skip governance`: leave `.claude/rules/` empty. Standards still install, so `.claude/standards/
|
|
91
|
+
- `--skip governance`: leave `.claude/rules/` empty. Standards still install, so `.claude/standards/markdown.md` lands with nothing pointing at it and no coding standard loads on a file match. The preview names any `--add` rules the skip drops, and the run prints the `aitk gov install <stack> <path>` command to add rules afterward, carrying those extras so one paste restores what the skip declined.
|
|
92
92
|
- `--skip standards`: leave standards out. The governance rules still reference `.claude/standards/`, so their authority lines resolve to nothing for a reader following the path. Toolkit skills are unaffected, since each falls back to the copy in its own plugin root. `aitk standards <name>` searches the corpus inside the CLI's own package behind both project roots, so it prints a standard in a project that skipped the install, and `aitk markdown audit` needs no standard at all, its ban sets and checkpoints shipping with the package as data. What the skip costs is the editable copy rather than the enforcement.
|
|
93
93
|
- `--skip wiki`: skip the `.claude/wiki/` scaffold. A target that already carries a root `wiki/` keeps it, since the verb reports that folder rather than migrating it.
|
|
94
94
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Route markdown edits to the
|
|
2
|
+
description: Route markdown edits to the write-human skill for voice, rhythm, sentence construction, and information density
|
|
3
3
|
paths:
|
|
4
4
|
- '**/*.md'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# Markdown
|
|
7
|
+
# Markdown voice standards
|
|
8
8
|
|
|
9
9
|
## Authority
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
11
|
+
- Load the `aitk:write-human` skill for voice, rhythm, sentence construction, and information density. It is the single source for all four.
|
|
12
|
+
- Load it before drafting a passage, not after revising one.
|
|
13
|
+
- Report it rather than proceeding silently when the skill does not resolve.
|
|
14
|
+
- Do not work these rules from memory.
|
|
15
|
+
- Banned words, spellings, punctuation, formatting, and file references are a separate topic. `501-markdown` routes them.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Route markdown edits to the markdown standard for headings, lists, punctuation, and
|
|
2
|
+
description: Route markdown edits to the markdown standard for headings, lists, punctuation, banned words, and frontmatter wording
|
|
3
3
|
paths:
|
|
4
4
|
- '**/*.md'
|
|
5
5
|
---
|
|
@@ -8,6 +8,7 @@ paths:
|
|
|
8
8
|
|
|
9
9
|
## Authority
|
|
10
10
|
|
|
11
|
-
- Follow `.claude/standards/markdown.md` for headings, paragraph and list structure, code spans, punctuation, emphasis,
|
|
12
|
-
- Read it before a substantial markdown edit. Do not work the banned characters from memory.
|
|
13
|
-
-
|
|
11
|
+
- Follow `.claude/standards/markdown.md` for headings, paragraph and list structure, code spans, punctuation, emphasis, file references, the banned words and spellings, and the wording of a `title` or `description`. It is the single source.
|
|
12
|
+
- Read it before a substantial markdown edit. Do not work the banned words or characters from memory.
|
|
13
|
+
- Run `aitk markdown audit <path>` after the edit, and rewrite the sentence carrying a hit rather than swapping the token for a near-synonym.
|
|
14
|
+
- Voice, rhythm, and sentence construction are a separate topic. `500-prose` routes them.
|
|
@@ -13,4 +13,5 @@ description: Enforce planning standards before implementation
|
|
|
13
13
|
- Propose the simplest solution that satisfies the requirement before implementing complex patterns.
|
|
14
14
|
- Write or update tests as part of every implementation plan.
|
|
15
15
|
- Write the test for a behavior before the code that implements it. Confirm visual output after implementing it, not before.
|
|
16
|
+
- Run `aitk gov test-order` before shipping a branch. Fix what it names as reaching history ahead of its test.
|
|
16
17
|
- Do not modify code without a confirmed plan.
|
package/package.json
CHANGED
|
@@ -79,7 +79,7 @@ log_step "Assert scaffold"
|
|
|
79
79
|
# The snippets path has to name a slug the default preset still carries, since
|
|
80
80
|
# init resolves snippets through `essentials`. Editing that preset without
|
|
81
81
|
# editing this line fails the gate on a correct install.
|
|
82
|
-
for path in "CLAUDE.md" ".claude/snippets/decision-help.md" ".claude/standards/
|
|
82
|
+
for path in "CLAUDE.md" ".claude/snippets/decision-help.md" ".claude/standards/skill.md" ".claude/standards/markdown.md" ".claude/wiki/index.md" ".claude" ".claude/context/index.md" ".claude/wireframes/index.md" ".claude/diagrams/index.md" \
|
|
83
83
|
".prettierrc" ".editorconfig" ".lintstagedrc" ".husky/pre-commit" ".github/workflows/verify.yml" "scripts/verify.sh" \
|
|
84
84
|
".claude/rules/core/000-constitution.md"; do
|
|
85
85
|
if [ ! -e "$TARGET_DIR/$path" ]; then
|
package/src/commands/gov.ts
CHANGED
|
@@ -14,6 +14,11 @@ import {
|
|
|
14
14
|
mergeExtraRules,
|
|
15
15
|
resolveRules,
|
|
16
16
|
} from '@/gov/stacks'
|
|
17
|
+
import {
|
|
18
|
+
type PairRecord,
|
|
19
|
+
readTestOrder,
|
|
20
|
+
type TestOrderReport,
|
|
21
|
+
} from '@/gov/test-order'
|
|
17
22
|
import { recordStamp, runDomainSync } from '@/sync/engine'
|
|
18
23
|
import { resolveTarget } from '@/target'
|
|
19
24
|
import {
|
|
@@ -48,6 +53,12 @@ interface ListOptions {
|
|
|
48
53
|
readonly json?: boolean
|
|
49
54
|
}
|
|
50
55
|
|
|
56
|
+
interface TestOrderOptions {
|
|
57
|
+
readonly base?: string
|
|
58
|
+
readonly root?: string
|
|
59
|
+
readonly json?: boolean
|
|
60
|
+
}
|
|
61
|
+
|
|
51
62
|
export function register(program: Command): void {
|
|
52
63
|
const gov = program
|
|
53
64
|
.command('gov')
|
|
@@ -133,6 +144,130 @@ export function register(program: Command): void {
|
|
|
133
144
|
.action((opts: ListOptions) => {
|
|
134
145
|
process.exitCode = runList(opts)
|
|
135
146
|
})
|
|
147
|
+
|
|
148
|
+
gov
|
|
149
|
+
.command('test-order')
|
|
150
|
+
.description(
|
|
151
|
+
'Report where an implementation reached history before its test',
|
|
152
|
+
)
|
|
153
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
154
|
+
.option('--base <ref>', 'Far side of the range, defaulting to the trunk')
|
|
155
|
+
.option('--root <path>', 'Repository to read, defaulting to the cwd')
|
|
156
|
+
.option('--json', 'Add a machine-readable record on stdout')
|
|
157
|
+
.addHelpText(
|
|
158
|
+
'after',
|
|
159
|
+
[
|
|
160
|
+
'',
|
|
161
|
+
'Measures the rule in .claude/rules/core/070-planning.md that asks for',
|
|
162
|
+
'the test before the code. It reports and never gates, because pairing',
|
|
163
|
+
'a test to an implementation is a judgment.',
|
|
164
|
+
'',
|
|
165
|
+
'Coverage:',
|
|
166
|
+
' a test sits beside its subject under the same name, minus .test',
|
|
167
|
+
' only .ts and .tsx are paired, and every other path is named as read past',
|
|
168
|
+
' a module the range modified rather than added is unclassified, since',
|
|
169
|
+
' a refactor and a new behavior cannot be told apart from history',
|
|
170
|
+
'',
|
|
171
|
+
'Exit codes:',
|
|
172
|
+
' 0 no implementation reached history ahead of its test',
|
|
173
|
+
' 1 refused, with the reason on stderr or in the JSON record',
|
|
174
|
+
' 2 at least one implementation reached history ahead of its test',
|
|
175
|
+
'',
|
|
176
|
+
'Examples:',
|
|
177
|
+
' aitk gov test-order',
|
|
178
|
+
' aitk gov test-order --base origin/main --json',
|
|
179
|
+
'',
|
|
180
|
+
].join('\n'),
|
|
181
|
+
)
|
|
182
|
+
.action((opts: TestOrderOptions) => {
|
|
183
|
+
process.exitCode = runTestOrder(opts)
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Reports and never gates, so the finding count moves the exit code without
|
|
189
|
+
* anything wiring it into a push. `aitk tasks validate` set that shape: a
|
|
190
|
+
* measure carrying a known false-positive class is what forces contributors to
|
|
191
|
+
* route around a stage, and the unclassified bucket here is that class.
|
|
192
|
+
*/
|
|
193
|
+
function runTestOrder(opts: TestOrderOptions): number {
|
|
194
|
+
const root = resolve(opts.root ?? process.cwd())
|
|
195
|
+
const report = readTestOrder(root, { base: opts.base })
|
|
196
|
+
const emitJson = opts.json ?? false
|
|
197
|
+
|
|
198
|
+
// The frame renders on stderr in both modes and the record goes to stdout
|
|
199
|
+
// alone, which is the split `docs/agents/output-shape.md` fixes. A consumer
|
|
200
|
+
// reading stdout sees pure data either way, and an operator reading the
|
|
201
|
+
// terminal sees the refusal rather than a command that appeared to do nothing.
|
|
202
|
+
if (report.kind === 'unreadable') {
|
|
203
|
+
intro('aitk gov test-order')
|
|
204
|
+
logStep('Refused')
|
|
205
|
+
logError(report.reason)
|
|
206
|
+
outro()
|
|
207
|
+
|
|
208
|
+
if (emitJson) {
|
|
209
|
+
process.stdout.write(
|
|
210
|
+
`${JSON.stringify({ ok: false, reason: report.reason })}\n`,
|
|
211
|
+
)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return 1
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
reportTestOrder(report, root)
|
|
218
|
+
|
|
219
|
+
if (emitJson) {
|
|
220
|
+
process.stdout.write(`${JSON.stringify({ ok: true, root, ...report })}\n`)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return report.findings.length > 0 ? 2 : 0
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function describePair(record: PairRecord): string {
|
|
227
|
+
const test = record.test === null ? 'no test' : record.test
|
|
228
|
+
return `${record.subject} → ${test}: ${record.reason}`
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function reportTestOrder(
|
|
232
|
+
report: Extract<TestOrderReport, { kind: 'measured' }>,
|
|
233
|
+
root: string,
|
|
234
|
+
): void {
|
|
235
|
+
intro('aitk gov test-order')
|
|
236
|
+
|
|
237
|
+
logStep('Range')
|
|
238
|
+
logInfo(`${report.base.slice(0, 8)}..${report.head.slice(0, 8)} in ${root}`)
|
|
239
|
+
|
|
240
|
+
logStep(report.findings.length === 0 ? 'Clean' : 'Findings')
|
|
241
|
+
if (report.findings.length === 0) {
|
|
242
|
+
logInfo('no implementation reached history ahead of the test covering it')
|
|
243
|
+
} else {
|
|
244
|
+
for (const finding of report.findings) logWarn(describePair(finding))
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
logStep('Satisfied')
|
|
248
|
+
logInfo(`${report.satisfied.length} pair(s) whose test came first`)
|
|
249
|
+
|
|
250
|
+
// The unclassified rows carry the warn glyph and move no exit code. A pass
|
|
251
|
+
// over a change the pairing could not read is the claim this check exists to
|
|
252
|
+
// avoid making, so the rows are named rather than counted into the clean line.
|
|
253
|
+
logStep('Unclassified')
|
|
254
|
+
if (report.unclassified.length === 0) {
|
|
255
|
+
logInfo('every changed module paired')
|
|
256
|
+
} else {
|
|
257
|
+
logWarn(
|
|
258
|
+
`${report.unclassified.length} change(s) the pairing could not read`,
|
|
259
|
+
)
|
|
260
|
+
for (const record of report.unclassified) logWarn(describePair(record))
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Coverage is narrower than the rule, and a report that did not say so would
|
|
264
|
+
// read as a verdict over every behavior in the range.
|
|
265
|
+
logStep('Read past')
|
|
266
|
+
logInfo(
|
|
267
|
+
`${report.ignored.length} path(s) outside ${report.scope.extensions.join(', ')}`,
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
outro()
|
|
136
271
|
}
|
|
137
272
|
|
|
138
273
|
/**
|
package/src/commands/markdown.ts
CHANGED
|
@@ -87,8 +87,8 @@ export function register(program: Command): void {
|
|
|
87
87
|
'',
|
|
88
88
|
'Bans and checkpoints ship with the aitk package rather than being read',
|
|
89
89
|
'out of a standards file, so a project that installed no standards is',
|
|
90
|
-
'measured the same as one that did. markdown.md
|
|
91
|
-
'
|
|
90
|
+
'measured the same as one that did. markdown.md still states every rule',
|
|
91
|
+
'for a reader. No folder has to resolve and no index.md has',
|
|
92
92
|
'to exist, so .claude/rules/, governance/, and snippets/ are in reach.',
|
|
93
93
|
'',
|
|
94
94
|
'Examples:',
|
|
@@ -57,7 +57,7 @@ export function parseVocabulary(markdown: string): string[] | undefined {
|
|
|
57
57
|
*
|
|
58
58
|
* Reading the list out of the rule rather than hardcoding it is what keeps one
|
|
59
59
|
* definition when the rule installs into a target, the same way
|
|
60
|
-
*
|
|
60
|
+
* `aitk markdown audit` owns one copy of the ban sets for every caller.
|
|
61
61
|
*/
|
|
62
62
|
export async function loadVocabulary(root: string): Promise<Vocabulary> {
|
|
63
63
|
for (const ruleRoot of RULE_ROOTS) {
|