v0.2.3 — pre-write lint gate, push/PR CI, pi-internals anchors
Hardening release (post-0.2.2 review follow-up, P0–P4)
sf-hooks: pre-write python lint gate (TDD, 9/9 seam selftest)
A red python edit/write is now denied at tool_call time — before the file is modified (would-be content linted on a temp copy with the file's own ruff config + mode). Timeout/hung-ruff/ruff-absent degrade to allow (hard 5s bound, resolves immediately). The post-write fast_gate message now discloses the edit already applied — the bare BLOCK that read as write-prevented caused a nearly-shipped contaminated commit on 2026-09-03.
ci.yml — the full gate set runs on every push/PR
Previously every gate depended on the author's local in-session hooks. Now: ruff (tools + all skill infra), per-skill lint_self/disconnect_check/plugin_layout, pi real-loader smoke (7 checks), sf-hooks seam selftest, markdownlint (maintained surfaces), npm-pack leak check, and a headless loader-e2e that imports + initializes all 5 extensions through pi's own jiti loader.
Docs & invariants
docs/pi-internals-anchors.md: the pi 0.84.x internal behaviors this package deliberately relies on (manifest-only discovery, barrel-hijack immunity, namespace composition, post-write block semantics) with a re-verify trigger on pi bumps- README Development section: local gate commands + contributor checklist (extension registration, bare agent names, PI_REF discipline)
"type": "module"; markdownlint adopted; plugin_layout gate bidirectional (a stray 23rd agent can no longer ride silently)
Process (dogfooded)
Outer-ring code review (fresh context) returned REQUEST CHANGES: 1 blocker (workflow YAML dead on arrival), 1 major (timeout→deny contract violation, empirically reproduced), plus minors — all fixed with hardened tests (AC6 now exercises the genuine timeout path). CI then caught a one-character SHA typo the local gates could not see. Green end-to-end before release.
Deferred: gallery preview image (no assets in repo; needs design input).