@erclx/aitk 0.83.0 → 0.84.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/git-pr/references/labels.md +7 -1
- package/docs/agents/markdown-audit.md +3 -1
- package/governance/rules/core/070-planning.md +1 -0
- package/governance/rules/core/075-dependencies.md +25 -0
- package/governance/rules/lib/300-testing-ts.md +1 -1
- package/governance/rules/lib/360-security-server.md +39 -0
- package/governance/rules/lib/370-database.md +35 -0
- package/governance/stacks/python.toml +1 -1
- package/package.json +1 -1
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +19 -2
|
@@ -40,7 +40,13 @@ The map is authored by hand and nothing detects a directory it fails to cover, s
|
|
|
40
40
|
|
|
41
41
|
Apply labels after the pull request resolves, never as a flag on the create. `gh pr create --label` fails whole on a label the remote does not carry, so a name the map got wrong opens no pull request at all and the run stops with the branch pushed and nothing to review. A `gh pr edit --add-label` against a pull request that already exists costs a warning instead, and it is one command across both the create and the edit path rather than two flags that have to stay in step.
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
Labelling runs whenever this skill runs and at no other time. Nothing else computes the set, so a push made any other way leaves the labels exactly as the last run left them. Any caller invoking this skill again reaches the step again, and it recomputes over the whole branch diff rather than over the new commits.
|
|
44
|
+
|
|
45
|
+
An ordinary branch therefore labels once, when the pull request opens. The return leg that answers a review hands its push to `git-followup`, which refreshes the body without invoking this skill, so the commits that answer a review reach no labelling step.
|
|
46
|
+
|
|
47
|
+
A follow-up push reaching a surface the earlier ones did not merges under-labelled, with nothing to report the miss. Keeping the step in one skill is worth that cost, since a review fix lands in the files the review named and rarely opens a surface the branch had not already touched.
|
|
48
|
+
|
|
49
|
+
`--add-label` adds and never removes. A label a person applied by hand is not this skill's to strip, and a re-run over a branch that has since dropped a surface keeps the label that surface earned.
|
|
44
50
|
|
|
45
51
|
## A label the remote does not carry
|
|
46
52
|
|
|
@@ -116,7 +116,9 @@ Four surfaces read the ban sets and two of them go through this verb. `.claude/h
|
|
|
116
116
|
|
|
117
117
|
The other two read the standards directly and neither is 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. The seed copy of the hook keeps its awk, because a scaffolded project may carry no `aitk` and `scripts/core/check-seed-independence.sh` exists to catch seed content depending on the toolkit CLI. Both are the likelier place for the next drift, since nothing compares either against the verb.
|
|
118
118
|
|
|
119
|
-
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.
|
|
119
|
+
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.missingStandards` out of the same record, so a standard the verb found under neither root reaches the author as a check narrowed to what it could read.
|
|
120
|
+
|
|
121
|
+
A machine with neither runner still blocks no edit, and it says so rather than exiting clean. The push stage holds either way. An edit nobody checked and an edit carrying no violation are one silence to a reader, so the enforcement a machine lacks is reported rather than inferred.
|
|
120
122
|
|
|
121
123
|
The stage measures the whole corpus rather than the changed files. A `Do not use` bullet added to a standard bans a token retroactively, and no file in the push that adds the bullet was edited.
|
|
122
124
|
|
|
@@ -12,4 +12,5 @@ description: Enforce planning standards before implementation
|
|
|
12
12
|
- State where the search ran and why each candidate was rejected. Do not assert a search without naming its results.
|
|
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
|
+
- Write the test for a behavior before the code that implements it. Confirm visual output after implementing it, not before.
|
|
15
16
|
- Do not modify code without a confirmed plan.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Require a dependency to be declared in the manifest before it is imported
|
|
3
|
+
paths:
|
|
4
|
+
- '**/*.ts'
|
|
5
|
+
- '**/*.tsx'
|
|
6
|
+
- '**/*.js'
|
|
7
|
+
- '**/*.jsx'
|
|
8
|
+
- '**/*.py'
|
|
9
|
+
- '**/package.json'
|
|
10
|
+
- '**/pyproject.toml'
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Dependency standards
|
|
14
|
+
|
|
15
|
+
## Declaration
|
|
16
|
+
|
|
17
|
+
- Declare a package in the project manifest before importing it anywhere in the source.
|
|
18
|
+
- Add a package with the package manager command that writes the manifest and the lockfile together, such as `bun add` or `uv add`. Never hand-edit the manifest and never install without recording the result.
|
|
19
|
+
- Commit the lockfile with the manifest change in the same commit.
|
|
20
|
+
- Declare a package used only by tests, builds, or tooling as a development dependency.
|
|
21
|
+
- Never import a package that arrives only as a transitive dependency of another package.
|
|
22
|
+
|
|
23
|
+
## Removal
|
|
24
|
+
|
|
25
|
+
- Remove a package from the manifest in the change that removes its last import.
|
|
@@ -32,7 +32,7 @@ paths:
|
|
|
32
32
|
## Conventions
|
|
33
33
|
|
|
34
34
|
- Use `.test.ts` / `.test.tsx` for unit tests.
|
|
35
|
-
- Use `.spec.ts` / `.spec.tsx` for integration tests
|
|
35
|
+
- Use `.spec.ts` / `.spec.tsx` for integration tests and for Playwright tests under `e2e/`.
|
|
36
36
|
- Do not make real network calls in unit tests.
|
|
37
37
|
- `describe()` labels use the exact identifier of the subject under test in its natural casing.
|
|
38
38
|
- `it()` descriptions use "should" + sentence case.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Enforce server-side authorization, secret handling, and abuse limits on request handlers
|
|
3
|
+
paths:
|
|
4
|
+
- '**/*.py'
|
|
5
|
+
- '**/*.ts'
|
|
6
|
+
- '**/*.js'
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Server security standards
|
|
10
|
+
|
|
11
|
+
## Authorization
|
|
12
|
+
|
|
13
|
+
- Authorize every request on the server, whatever the client already checked.
|
|
14
|
+
- Derive the caller identity from the verified session or token. Never read it from a request body, query string, or header the client sets.
|
|
15
|
+
- Check that the caller owns or may reach the specific record a request names, not only that the caller is signed in.
|
|
16
|
+
- Deny by default. Grant a route access through an explicit allow.
|
|
17
|
+
|
|
18
|
+
## Credentials
|
|
19
|
+
|
|
20
|
+
- Hash passwords with a memory-hard algorithm and a per-record salt. Never store a reversible password.
|
|
21
|
+
- Compare tokens, signatures, and password hashes with a constant-time function.
|
|
22
|
+
- Expire and revoke sessions and refresh tokens on the server. Do not rely on client-side deletion.
|
|
23
|
+
|
|
24
|
+
## Secrets
|
|
25
|
+
|
|
26
|
+
- Read every secret from the environment or a secret manager at runtime.
|
|
27
|
+
- Never commit a secret, connection string, or private key to the repository.
|
|
28
|
+
- Never return a secret, connection string, or internal hostname in a response body.
|
|
29
|
+
|
|
30
|
+
## Abuse limits
|
|
31
|
+
|
|
32
|
+
- Rate-limit authentication, password reset, and any endpoint that sends mail or costs money per call.
|
|
33
|
+
- Set an explicit maximum body size and request timeout on every endpoint.
|
|
34
|
+
- Bound pagination parameters with a server-side maximum.
|
|
35
|
+
|
|
36
|
+
## Transport
|
|
37
|
+
|
|
38
|
+
- Serve every route over TLS and reject plaintext requests.
|
|
39
|
+
- Restrict CORS to an explicit origin list. Never reflect the request origin or pair a wildcard with credentials.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Enforce persistence boundaries for migrations, query construction, transactions, and rollback
|
|
3
|
+
paths:
|
|
4
|
+
- '**/*.py'
|
|
5
|
+
- '**/*.ts'
|
|
6
|
+
- '**/*.js'
|
|
7
|
+
- '**/*.sql'
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Persistence standards
|
|
11
|
+
|
|
12
|
+
## Schema changes
|
|
13
|
+
|
|
14
|
+
- Express every schema change as a migration file committed to version control.
|
|
15
|
+
- Ship a tested rollback path with every migration that changes a schema.
|
|
16
|
+
- Never alter a deployed schema outside a migration.
|
|
17
|
+
- Never edit a migration that has run in a shared environment. Add a new one.
|
|
18
|
+
- Separate a destructive migration from the deploy that stops reading the dropped column.
|
|
19
|
+
|
|
20
|
+
## Query construction
|
|
21
|
+
|
|
22
|
+
- Pass every runtime value as a bound parameter.
|
|
23
|
+
- Never interpolate, concatenate, or format a value into a statement string.
|
|
24
|
+
- Name the columns a read needs. Do not select every column by wildcard.
|
|
25
|
+
|
|
26
|
+
## Transactions
|
|
27
|
+
|
|
28
|
+
- Give each transaction one owner that opens it, commits it, and rolls it back.
|
|
29
|
+
- Never open a transaction inside a function that was handed one.
|
|
30
|
+
- Keep network calls, queue publishes, and filesystem writes outside an open transaction.
|
|
31
|
+
|
|
32
|
+
## Access patterns
|
|
33
|
+
|
|
34
|
+
- Load related rows in the query that fetches their parents. Do not resolve a relation lazily inside an iteration.
|
|
35
|
+
- Scope a connection or session to the request that opened it and release it on exit.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
extends = "base"
|
|
2
|
-
rules = ["110-python", "340-pydantic", "330-testing-py"]
|
|
2
|
+
rules = ["110-python", "340-pydantic", "330-testing-py", "360-security-server", "370-database"]
|
package/package.json
CHANGED
|
@@ -33,6 +33,7 @@ esac
|
|
|
33
33
|
# bullet added to markdown.md is parsed by nothing and enforces silently.
|
|
34
34
|
standard="${CLAUDE_PROJECT_DIR:-.}/.claude/standards/prose.md"
|
|
35
35
|
words=""
|
|
36
|
+
unread=""
|
|
36
37
|
if [ -f "$standard" ]; then
|
|
37
38
|
words=$(grep '^- Do not use ' "$standard" |
|
|
38
39
|
grep -o '`[^`]*`' |
|
|
@@ -40,6 +41,12 @@ if [ -f "$standard" ]; then
|
|
|
40
41
|
grep -x '[a-z][a-z]*' |
|
|
41
42
|
sort -u |
|
|
42
43
|
paste -sd '|' -)
|
|
44
|
+
else
|
|
45
|
+
# An absent standard empties the word list, and the awk below reads an empty
|
|
46
|
+
# list as nothing to look for rather than as nothing found. The path is kept
|
|
47
|
+
# so the report names what could not be read, since a file carrying no banned
|
|
48
|
+
# word and a file nobody checked produce the same silence otherwise.
|
|
49
|
+
unread="$standard"
|
|
43
50
|
fi
|
|
44
51
|
|
|
45
52
|
hits=$(awk -v words="$words" '
|
|
@@ -66,8 +73,18 @@ hits=$(awk -v words="$words" '
|
|
|
66
73
|
}
|
|
67
74
|
' "$file")
|
|
68
75
|
|
|
69
|
-
[ -z "$hits" ] && exit 0
|
|
76
|
+
[ -z "$hits" ] && [ -z "$unread" ] && exit 0
|
|
70
77
|
|
|
71
|
-
|
|
78
|
+
nl=$'\n'
|
|
79
|
+
msg=""
|
|
80
|
+
|
|
81
|
+
if [ -n "$unread" ]; then
|
|
82
|
+
msg=$(printf 'Standards-audit: no word ban checked in %s. Found no standard at %s, so only the character bans ran. Restore it with `aitk standards install`.' "$file" "$unread")
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
if [ -n "$hits" ]; then
|
|
86
|
+
found=$(printf 'Standards-audit: prose.md and markdown.md violations in %s. Rewrite or restructure (do not lazy-swap).\n%s' "$file" "$hits")
|
|
87
|
+
msg="${msg:+$msg$nl}$found"
|
|
88
|
+
fi
|
|
72
89
|
|
|
73
90
|
jq -nc --arg msg "$msg" '{hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:$msg}}'
|