diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 790fe10..36407b3 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -1,6 +1,6 @@ #!/usr/bin/env bash # Pre-commit hook for dotfiles. -# - When AGENTS.md is staged, runs scripts/audit-agents-md.sh and blocks +# - When AGENTS.md is staged, runs audits/agents-md.sh and blocks # the commit if any invariant regressed. # - For all other commits, this hook is a no-op (fast path). # @@ -16,19 +16,19 @@ set -uo pipefail ROOT="$(git rev-parse --show-toplevel)" cd "$ROOT" || exit 1 -if git diff --cached --name-only | grep -qE '^(AGENTS\.md|AGENTS_INVARIANCE\.md|docs/gates/.*\.md|scripts/audit-agents-md\.sh|scripts/fixtures/.*\.diff)$'; then +if git diff --cached --name-only | grep -qE '^(AGENTS\.md|audits/agents-md\.(md|sh)|audits/data\.sh|audits/parity-dispatch\.sh|dispatch/.*\.md|audits/fixtures/.*\.diff)$'; then if [[ "${SKIP_AGENTS_AUDIT:-0}" = "1" ]]; then echo "pre-commit: SKIP_AGENTS_AUDIT=1 — bypassing AGENTS.md audit (one-off)" >&2 else - echo "pre-commit: AGENTS.md or its audit changed — running scripts/audit-agents-md.sh" >&2 - if ! bash "$ROOT/scripts/audit-agents-md.sh"; then + echo "pre-commit: AGENTS.md or its audit changed — running audits/agents-md.sh" >&2 + if ! bash "$ROOT/audits/agents-md.sh"; then cat >&2 <<'MSG' pre-commit: AGENTS.md invariance regressed. Fix the FAIL: lines above, then re-stage and re-commit. -If you also changed AGENTS.md semantics, run AGENTS_INVARIANCE.md +If you also changed AGENTS.md semantics, run audits/agents-md.md through an LLM agent before merging — the script catches mechanical regressions; the questionnaire catches reading-comprehension ones. diff --git a/.githooks/pre-push b/.githooks/pre-push index b3ac587..c6917e8 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -2,10 +2,10 @@ # Pre-push hook for dotfiles. # # Behaviour: -# - Runs scripts/audit-agents-md.sh always (script layer; deterministic). -# - When the push includes commits that touched AGENTS.md, AGENTS_INVARIANCE.md, -# or any docs/gates/*.md, ALSO requires a fresh sign-off file written by an -# LLM agent that ran the AGENTS_INVARIANCE.md questionnaire. +# - Runs audits/agents-md.sh always (script layer; deterministic). +# - When the push includes commits that touched AGENTS.md, audits/agents-md.md, +# or any dispatch/*.md, ALSO requires a fresh sign-off file written by an +# LLM agent that ran the audits/agents-md.md questionnaire. # # Sign-off file: .agents-invariance-signoff (gitignored — it's a machine-local # attestation, not a tracked artifact). Format: @@ -15,8 +15,8 @@ # A sign-off is "fresh" if its matches HEAD and the file was # written within the last 24 hours. # -# To produce the sign-off: open AGENTS_INVARIANCE.md in an LLM session and -# instruct: "Read AGENTS.md and answer every question in AGENTS_INVARIANCE.md. +# To produce the sign-off: open audits/agents-md.md in an LLM session and +# instruct: "Read AGENTS.md and answer every question in audits/agents-md.md. # When all-YES, write the sign-off line to .agents-invariance-signoff." # # One-off bypass: SKIP_INVARIANCE_PUSH=1 git push ... @@ -28,8 +28,8 @@ ROOT="$(git rev-parse --show-toplevel)" cd "$ROOT" || exit 1 # 1. Always run the script layer. -echo "pre-push: running scripts/audit-agents-md.sh" >&2 -if ! bash "$ROOT/scripts/audit-agents-md.sh"; then +echo "pre-push: running audits/agents-md.sh" >&2 +if ! bash "$ROOT/audits/agents-md.sh"; then echo "pre-push: script layer failed — fix before push" >&2 exit 1 fi @@ -46,7 +46,7 @@ while read -r local_ref local_sha remote_ref remote_sha; do range="$remote_sha..$local_sha" files=$(git diff --name-only "$range") fi - if echo "$files" | grep -qE '^(AGENTS\.md|AGENTS_INVARIANCE\.md|docs/gates/.*\.md)$'; then + if echo "$files" | grep -qE '^(AGENTS\.md|audits/agents-md\.md|dispatch/.*\.md)$'; then contract_changed=1 fi done @@ -69,11 +69,11 @@ fi if [[ ! -f "$SIGNOFF" ]]; then cat >&2 < PASS" diff --git a/AGENTS.md b/AGENTS.md index a673d3c..1987ca8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -22,7 +22,7 @@ Prose dates: `MMM DD, YYYY: HH:MM AM/PM`. Filenames: `{MMM}_{DD}_{HH_MM}`. ## Changelog voice (Mintlify-style) -Full rules in [`docs/CHANGELOG_VOICE.md`](./docs/CHANGELOG_VOICE.md). Summary: one headline per entry, no marketing words ("seamless"/"magical"/"powerful"/"robust" banned); lead paragraph states the change, not the announcement; bullets follow `**Bold lead-noun** — consequence-first clause`; internal cleanup gets aggressive trimming; never drop load-bearing facts (error codes, endpoints, env vars, schema names, money amounts); historical entries archived not rewritten; rate constants pinned to three files (`tenant_billing.zig`, `rates.ts`, `rates.mdx`). +Routed by the `write_changelog` dispatch (`dispatch/write_changelog.md`); full rules in [`docs/CHANGELOG_VOICE.md`](./docs/CHANGELOG_VOICE.md). Summary: one headline per entry, no marketing words ("seamless"/"magical"/"powerful"/"robust" banned); lead paragraph states the change, not the announcement; bullets follow `**Bold lead-noun** — consequence-first clause`; internal cleanup gets aggressive trimming; never drop load-bearing facts (error codes, endpoints, env vars, schema names, money amounts); historical entries archived not rewritten; rate constants pinned to three files (`tenant_billing.zig`, `rates.ts`, `rates.mdx`). ## Confusion Management @@ -52,7 +52,7 @@ Full rules in [`docs/CHANGELOG_VOICE.md`](./docs/CHANGELOG_VOICE.md). Summary: o - Releases: `gh release create`, `git push --tags`. `/ultrareview` (billed). CI/CD edits (`.github/workflows/**`, deploy configs). - Edits outside active spec's Files-Changed scope (no opportunistic cleanup bundling). - Cross-repo writes to `~/Projects/docs/` — own-branch flow per Operational defaults. -- **Patching a harness/gate/hook to silence its hit.** When `audit-msid-ui.sh`, `lint-zig.py`, gitleaks, ZIG/FLL gates, or pre-commit/pre-push fire, the default is to **fix the violating code** — restructure, split, or use the gate's override comment. Editing the harness evades the rule it enforces; only on explicit per-session user direction naming the harness + reason. Handoff-doc "prior approvals" don't carry forward. +- **Patching a harness/gate/hook to silence its hit.** When `msid-ui.sh`, `lint-zig.py`, gitleaks, ZIG/FLL gates, or pre-commit/pre-push fire, the default is to **fix the violating code** — restructure, split, or use the gate's override comment. Editing the harness evades the rule it enforces; only on explicit per-session user direction naming the harness + reason. Handoff-doc "prior approvals" don't carry forward. - Reverting changes the agent did not create. Branch mutation outside lifecycle transitions. Cross-worktree edits. - Unexpected changes in files you're editing → stop and ask; don't overwrite as stale. @@ -63,7 +63,7 @@ Full rules in [`docs/CHANGELOG_VOICE.md`](./docs/CHANGELOG_VOICE.md). Summary: o - **Docs-repo edits on own branch.** `~/Projects/docs/` is shared across milestones. Before: `cd ~/Projects/docs && git status`; HEAD ≠ `main` → checkout `main` or `git worktree add` off `main`; commit on `chore/m{N}-{slug}-changelog`. Recovery: `git stash` (or patch + `git checkout .`), re-apply on fresh branch. - Other dotfiles (`.zshrc`/`.gitconfig`/etc.): timestamped backup; minimal edits. - Before commit/push: `gitleaks` must pass. -- `*.zig` → read `docs/ZIG_RULES.md`; ZIG GATE fires. Auth-flow (`src/auth/**`, `ui/packages/app/lib/auth/**`, token-minting handlers, credential-typed spec dimensions): read `docs/AUTH.md` first. +- `*.zig` → read `dispatch/write_zig.md`; ZIG GATE fires. Auth-flow (`src/auth/**`, `ui/packages/app/lib/auth/**`, token-minting handlers, credential-typed spec dimensions): read `docs/AUTH.md` first. - `conn.query()` requires `.drain()` in same fn before `deinit()`. Verify `make check-pg-drain`. Use `conn.exec()` for no-rows. - Local Docker `ENOSPC`: `~/bin/mac-cleanup.sh`, verify `docker system df`, retry. - Cross-repo patterns under `$HOME/Projects/` (check before inventing): `marketplace_api` Python · `e2e-observability-platform` Rust · `cache-kit.rs` Rust · `docs` MDX · `usezombie` Zig/TS · `docs.megam.io` TS · `www.megam.io` TS · `rioos.megam.io` TS · `posthog-zig` Zig · `oss/bun` Zig · `oss/nullclaw` Zig · `oss/exonum` Rust · `oss/signoz` TS/Go · `dotfiles` Shell/MDX. @@ -94,7 +94,7 @@ One per active stream. Stay inside; no edits outside, no reads from siblings. Me Guards fire pre-hoc regardless of lifecycle stage. Override: `: SKIPPED per user override (reason: ...)` immediately preceding the edit — **user-invokable only** unless noted. Per-edit output is **one-line by default**; full block fires only on violation or new file. **HARNESS VERIFY is the determinism anchor** — pre-edit lines are early-warning ceremony. -**Rule extension protocol** — when adding a new rules file (`docs/_RULES.md`) or gate body (`docs/gates/.md`), all four steps land in the same diff: (1) row in EXECUTE doc-reads table; (2) ≥1 question in `AGENTS_INVARIANCE.md`; (3) path in `DOTFILES_RESIDENT` (audit script); (4) `make audit` ALL CHECKS PASSED. The Invariance Suite Gate fires; questionnaire all-YES + sign-off are mandatory before push. +**Rule extension protocol** — when adding a new rules file (`docs/_RULES.md`) or dispatch entry (`dispatch/.md`), all four steps land in the same diff: (1) row in EXECUTE doc-reads table; (2) ≥1 question in `audits/agents-md.md`; (3) path in `DOTFILES_RESIDENT` (audit script); (4) `make audit` ALL CHECKS PASSED. A new dispatch entry *also* lands in `REQUIRED_DISPATCH` (`audits/data.sh`) + a row in the dispatch table above, so `check_dispatch_parity` (disk == table == REQUIRED) stays green — step (4) is the backstop that bites if either is missed. The Invariance Suite Gate fires; questionnaire all-YES + sign-off are mandatory before push. **🚨 Gate-flag triage** — gate fires → **STOP, surface to Kishore.** NOT silence. NOT harness-patch. The gate exists to make the code better; silencing it forfeits the gain. The ask is structured: @@ -107,32 +107,23 @@ Guards fire pre-hoc regardless of lifecycle stage. Override: `: SKIPPED pe Kishore decides fix-or-defer. Agent does **NOT** unilaterally call a flag false-positive — even a one-line "obvious fix" goes through the ask. -**Gate index — full details in each `docs/gates/.md` body. Read the body when the gate fires.** Trigger-surface extensions: `*.zig`, `*.ts`, `*.tsx`, `*.js`, `*.jsx`, `*.py`, `*.rs`, `*.go`, `*.sh`, `*.sql`. +**Dispatch index — full rule prose in each `dispatch/.md` façade. Read the façade when its trigger fires.** Trigger-surface extensions: `*.zig`, `*.ts`, `*.tsx`, `*.js`, `*.jsx`, `*.py`, `*.rs`, `*.go`, `*.sh`, `*.sql`. Each entry is a **façade pair**: a latent `.md` (prose the agent reads) + a deterministic `.sh` (run by `audits/` + the git hooks) where the rule is mechanisable. Signal tags the `.sh` halves print: 🟢 pass · 🔴 fail · 🔵 judgment-only (no script decides — read the prose, call it) · ⚪ delegated to the product repo. The router below **is** the gate set — there is no separate `docs/gates/` directory. **Legacy-workaround family** — four rules together: **RULE NDC** (no dead code at write time, `docs/greptile-learnings/RULES.md`), **RULE NLR** (touch-it-fix-it cleanup), **RULE NLG** (no new legacy framing pre-`2.0.0`), **Legacy-Design Consult Guard** (user A/B/C consult before patching/keeping/testing legacy). Workarounds prohibited at authoring time, cleaned on touch, never silently retained. -| # | Gate | Body | Trigger surface · Override | -|---|---|---|---| -| 1 | Invariance Suite Gate (meta) | `docs/gates/invariance-suite.md` | Edit to `AGENTS.md`, `AGENTS_INVARIANCE.md`, `docs/gates/`, `scripts/audit-agents-md.sh`, `scripts/fixtures/*.diff` · **no override** (user-only push: `SKIP_INVARIANCE_PUSH=1`). Body fires the audit + questionnaire + `.agents-invariance-signoff` write. | -| 2 | RULE NLR | `docs/gates/nlr.md` | Edit to file with legacy framing / dead code (`?*T = null` no caller, `legacy_*`, `V2` twins, `if (legacy_caller)`, `// legacy` comments, `pub` no consumer) · `RULE NLR: SKIPPED per user override (reason: ...)` user-only. | -| 3 | RULE NLG | `docs/gates/nlg.md` | New `legacy_*` / `V2` / compat shim / tracking-list while `cat VERSION` < `2.0.0` · `RULE NLG: SKIPPED per user override (reason: ...)` user-only. | -| 4 | Legacy-Design Consult Guard | `docs/gates/legacy-design.md` | Patching legacy to fit new architecture; defensive `orelse` whose only reason is legacy nullability; tests for legacy path · **no override** — user A/B/C decision. | -| 5 | Schema Table Removal Guard | `docs/gates/schema-removal.md` | Create/edit/delete `schema/*.sql`, edit `schema/embed.zig` / migration array, `DROP TABLE` / `ALTER TABLE` · `SCHEMA GUARD: SKIPPED per user override (reason: ...)`. | -| 6 | File & Function Length Gate | `docs/gates/file-length.md` | Caps: file ≤ 350 · fn ≤ 50 · method ≤ 70. Net-adding lines to `.zig`/`.js`/`.ts`/`.tsx`/`.jsx`/`.py`/`.rs`/`.go`/`.sh`/`.sql`/`.yaml`/`.toml`. Exempt `vendor/`, `node_modules/`, `third_party/`, `.md` · `LENGTH GATE: SKIPPED per user override (reason: ...)`. | -| 7 | Milestone-ID Gate | `docs/gates/milestone-id.md` | Saving source / config outside `docs/`. Regex `M[0-9]+_[0-9]+`, `§X.Y`, `T7`, `dim N.M` · `MILESTONE ID ALLOWED per user override (reason: ...)` in preceding comment. | -| 8 | Architecture Consult & Update Gate | `docs/gates/architecture.md` | Naming a stream/channel/Redis namespace/queue/RPC/Postgres schema; describing a flow; mid-task architecture question — grep relevant `docs/architecture/` · **no override** — doc wins until reconciled. | -| 9 | ZIG GATE | `docs/gates/zig.md` | `*.zig` outside `vendor/`/`third_party/`/`.zig-cache/` (tests in scope) · `ZIG GATE: SKIPPED per user override (reason: ...)`. | -| 10 | Pub Surface & Struct-Shape Gate | `docs/gates/pub-surface.md` | New `*.zig` under `src/`; threshold-cross (first pub type / first method-on-pub-free-fn-dominant / last pub free fn removed); **any new `^pub` line in new-bytes** (threshold list is a floor, not a ceiling) · `PUB GATE: SKIPPED per user override (reason: ...)`. **`FILE SHAPE DECISION` skip needs user's explicit ask this turn — auto-mode does NOT cover.** Consumer-grep delegated to `zlint`'s `unused-decls: error`; body enforces **shape verdict** + **no inheritance** (own verdict per surface; do not inherit sibling justifications). **Per-edit proof-line mandatory** (full block OR one-line `PUB GATE: skipped — `); silent gate-clean edits are violations. | -| 11 | UI Component Substitution Gate | `docs/gates/ui-substitution.md` | `*.tsx`/`*.jsx` under `ui/packages/app/`. Raw HTML (`
`/`