tootsies

a discord bot for the tootsies server. ask, recap, discuss, ship features by typing.


Project maintained by mejasonmejason Hosted on GitHub Pages — Theme by mattgraham

Engineering rules register

The extensible home for engineering rules — curated from the strongest public practice (Anthropic’s agentic-coding guidance, the Karpathy CLAUDE.md line + community extensions, Sentry’s and OpenAI’s agent guides, Cloudflare’s template standards, HumanLayer) and adapted to this repo. Skim at the start of any non-trivial change. CLAUDE.md’s always-loaded judgment section stays tiny; rules land HERE.

The register’s constitution. A rule needs a provenance tag plus either a local incident or strong multi-source consensus; personality rules (“act like a senior engineer”) are banned as measured no-ops; a rule that measures as a wash gets cut (the docs/PROMPT_OPTIMIZATION.md discipline, applied to rules about ourselves); and promotion into CLAUDE.md usually trades against something coming down — the always-loaded file does not re-grow. Rules are kept to their load-bearing form: if a sentence only restates its rule, it goes.


Scope and diffs

Surgical changes — clean up only your own mess. [Karpathy] Touch only what the task needs: no drive-by reformatting, renames, or refactors of adjacent code. Cleanup is scoped the same way — remove only what YOUR change orphaned; pre-existing dead code gets mentioned (PR body / an issue), never silently deleted.

Ship big refactors in reviewable stages. [community] A multi-step migration lands as a sequence of individually green, individually revertible PRs — mechanical rename, then behavior change, then cleanup. A stage that can’t go green alone is a design smell in the split, not a reason to merge red.

Deciding and assuming

State assumptions; verify the cheap ones. [Karpathy] A load-bearing assumption gets verified (most are one query/grep away here) or stated where the reviewer will see it. “Assumed X, unverified” is fine; silence is not.

Surface conflicts — never average them. [community] When two parts of the codebase, a doc and the code, or two owner steers disagree, name the conflict and pick a side explicitly — owner for judgment, evidence for fact. Blending produces code that half-follows both and launders a decision nobody made.

Time-box the rabbit hole. [community] Past ~2× the effort you’d have estimated, stop digging: restate the problem, switch approaches or surface it. Sunk effort is not evidence the approach is right (#567: the step-back found a 10-line answer to a 300-line grind).

The second patch to the same abstraction is a redesign checkpoint. [OpenAI] Adding a second condition/branch/special case to something you already patched once means stop: re-derive the abstraction from the full case set — one redesign beats accreting compatibility branches (#824: banning crutch phrases one at a time never converged; the self-dedup redesign did).

A significant behavior change states its scope contract. [OpenAI] In the PR/issue: the required behavior, plus what is INTENTIONALLY unsupported and how it fails (skip? fallback? raise?). The unstated-unsupported case is where the next incident lives. (docs/INTEGRATIONS.md’s omitted-and-why column, applied at the behavior level.)

The deterministic / model-judged boundary

Repeatable behavior lives in code; model judgment is for taste. [OpenAI ext.; this repo’s architecture] Retries, routing, thresholds, caps, settlement math, dedup keys — same inputs, same outcome — are deterministic code with tests; the model judges language, relevance, quality. A number or branch decision living inside a prompt is a bug of this class. The mirror holds too: don’t hand-code brittle heuristics for a genuine judgment call (the classifier-vs-regex history).

Tests

Tests pin behavior, and a regression test must fail first. [community; generalizes the golden rule] A test written for a fix runs RED on the pre-fix code or it pins nothing (#1886: asserts on shapes the gate rejected anyway pass whether or not the filter works). Assert outputs, state changes, emitted events — not call counts or internal ordering. A test needing three mocks to reach its assert usually means the pure core hasn’t been extracted yet (utils/ split).

Rules, checks, and corrections

Mechanize any rule that can be a check; a repeated correction demands it. [Cloudflare / HumanLayer / claude-md-templates] A convention worth keeping becomes a test, lint, hook, or CI gate — prose rules decay under context pressure, checks don’t (the test_event_schema ratchet, output_checks, the repo-root allowlist). When the owner corrects the same CLASS of mistake twice, that session ships the durable artifact — a check, else a rule here — in the same breath; “noted” without an artifact is how the third occurrence happens.

Review findings stay scoped to the patch. [OpenAI] Complexity is a real finding only when the machinery isn’t required by the task or a verified risk — don’t accept speculative abstractions, knobs, or parallel paths a reviewer imagines wanting. Unrelated cleanup a review surfaces gets its own issue, not bolted onto the PR.

Workflow hygiene

No user content or PII beyond the surface it serves. [Sentry] Real user messages or usernames-plus-content never land in commits, PR bodies, issues, or logs — the constitution’s data-minimization rule covers our own dev artifacts too. Repro fixtures use synthetic text.

Leave a trail a cold session can follow. [HumanLayer; this repo’s doc culture] Owner steers, incident lessons, and “why it’s built this way” go in the durable homes (the surface’s docs/ARCHITECTURE.md section, the tracking issue, the PR body) — not chat. The test: could a fresh session pick this up from the repo alone?