Schema revisions per user review 2026-04-22 (all 6 open questions resolved
— see §Decision log in SUBSTRATE-SCHEMA.md):
- #3 side_effects: string tags → structured { op, domain } objects (user:
"лучше сразу с запасом")
- #4 capabilities.toml: DROPPED entirely (user: "почему не мд?"). SSoT is
atoms/*.md. Crate-level metadata moves to Cargo.toml
[package.metadata.keisei] — Cargo-native, no drift, no build.rs, no
generated files to commit. kei-sage + kei-runtime walk atoms/*.md
directly.
- #5 atom template: shipped in this PR (user: "ui же параллельно! создавай
все!") so Streams B/C/D can scaffold atoms from day 0 without waiting
for Stream A (kei-forge UI).
- #1/#2/#6 confirmed as drafted (draft-07, `::` separator, per-atom errors).
New files:
- _templates/atom/ — 5-file template set with placeholder substitution
(__CRATE__, __VERB__, __KIND__, __DESCRIPTION__ etc). Covers
atoms/<verb>.md, schemas/<verb>-{input,output}.json, src/atoms/<verb>.rs,
tests/<verb>_smoke.rs. Each file is a minimal working skeleton.
- scripts/new-atom.sh — POSIX bash generator (bash for $'\n' / readonly /
trap). Validates verb is lowercase kebab-case, kind is one of
command|query|stream|transform. Refuses to overwrite existing files.
Rolls back on any failure (trap ERR deletes all generated files so no
half-scaffolded state). Tested: produces 5 files, placeholder
substitution correct on smoke-test crate.
Stream B (atoms refactor) updated to drop the "generates capabilities.toml
via build.rs" wording — now just "writes atoms/*.md + updates Cargo.toml
[package.metadata.keisei]". Stream D reads atoms/*.md + Cargo.toml, not
capabilities.toml.
Schema status: revisions applied, decision log complete. Ready for
SCHEMA-LOCKED.md marker commit once user signs off on revised doc.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the one outstanding item from v0.21.1 wave-audit: SEC-H1 agent
left SHA256_* vars as 'SKIP' because no WebFetch available this session.
Sources verified via live curl:
https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_checksums.txt
Pinned hashes (4 platforms):
darwin_amd64: 5b44c3bc...c644
darwin_arm64: aba9ced2...953f
linux_amd64: 8aca8db9...a3d8
linux_arm64: 325e971b...f0c6
End-to-end verified locally (darwin_arm64):
HOME=/tmp/aln-test bash scripts/install-actionlint.sh
→ SHA-256 verified: aba9ced2...
→ actionlint -version: 1.7.12 installed by downloading from release page
Header comment updated: [UNVERIFIED] → [VERIFIED 2026-04-22 via curl ...].
ACTIONLINT_SHA256_OVERRIDE env var still works (for CI with different pins).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three layers of defense against the dtolnay-SHA-class bug reaching main
(today's incident: agent SHA-pinned dtolnay/rust-toolchain with a pin
that was real but semantically wrong — lost 'install current stable'
meaning, locked to rust 1.94.1 branch tip, broke CI).
Layer 1 — actionlint static lint
scripts/install-actionlint.sh (65 LOC) — installs rhysd/actionlint
v1.7.12 [VERIFIED] to ~/.local/bin or suggests brew install.
scripts/lint-workflows.sh (40 LOC) — runs actionlint on
.github/workflows/*.yml, exit 0 on clean, advisory when binary
missing.
Layer 2 — SHA existence check (today's bug class)
scripts/validate-workflow-shas.sh (98 LOC) — extracts every
'uses: <repo>@<40-hex>' from workflow files + dependabot.yml,
checks each via GitHub REST commits API (exit 200/404/422).
Supports 'validate-workflow-shas: skip=<reason>' trailing
comment for intentional exceptions. Falls back to anonymous
API (60/hr quota) if GITHUB_TOKEN probe fails.
DESIGN PIVOT from spec: spec said 'git ls-remote <repo> <sha>'
but that only resolves REFS (branch/tag tips), not arbitrary
commit SHAs — would have given false-positive 100% MISSING
report. Switched to REST API /commits/{sha} for unambiguous
200/404/422.
Layer 3 — CI gate
.github/workflows/ci.yml — new 'workflow-lint' job after
shell-lint. Installs actionlint + runs both scripts on every
push to main and PR. Blocks CI on any fabricated SHA.
Layer 4 — optional pre-commit hook
scripts/pre-commit-workflow-lint.sh (54 LOC) — detects staged
.github/workflows/*.{yml,yaml} + .github/dependabot.yml
changes, runs layers 1+2, blocks commit on failure.
Install via: ln -sf ../../scripts/pre-commit-workflow-lint.sh
.git/hooks/pre-commit
REAL EXECUTION VERIFIED (not claim-only):
- actionlint ran: zero findings on current workflows
- validate-workflow-shas.sh ran: 21 SHA pins checked, 21 OK,
0 MISSING (confirms all current v0.19.1+ pins resolve)
- bash -n on every new script: clean
- bash-3.2 parser bug workaround: case-in-subshell → grep -E
RULE 0.2 exception #6 (shell is external convention for git hooks
+ GH Actions runs — Rust rewrite would add zero value).
RULE 0.13 respected — no git invocations except read-only API calls.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>