6.1 KiB
6.1 KiB
standards and conventions
Status: direction (Option B decided) — as of 2026-07-17 Connects to: deterministic-gates, agent-design-principles, never-ask-twice, self-improvement-loops, overview
Purpose
Defines once, and reuses everywhere, the coding standards and conventions the factory applies across many languages and frameworks (e.g. Sandi Metz 99-Bottles OOP for all OOP languages) — so a standard is authored a single time, not redefined per project. Load this before designing project onboarding, the green command, or any standard-carrying context packet for a pipeline agent.
Design
- Three layers, separated on purpose:
- The opinion — language-agnostic prose (the Metz rules themselves). Written once.
- Per-language bindings — executable configs (
.rubocop.yml, eslint fragment,ruff.toml) each tagged with the standard + version it implements. One opinion, N bindings: this is where cross-language overlap resolves. - Per-project adoption — a project copies the right bindings, wires the green command,
and records a repo ADR ("adopts
sandi-metz-oopv2 for Ruby") linking the vault opinion.
- Layout — Option B (DECIDED). Opinion lives in the vault as a
convention/note (the cross-project source of truth, per never-ask-twice); executable bindings ship in the plugin because they are deployable, git-versioned/diffable artifacts and the vault is a knowledge graph, not an artifact store. Precedent:plugins/cc-architect/references/conventions/cc-os-naming.md(canonical repo copy; vault note defers to it).~/Documents/SecondBrain/convention/sandi-metz-oop.md # opinion; links to bindings plugins/os-sdlc/standards/sandi-metz-oop/ standard.md # canonical prose (vault note defers here) ruby/rubocop.yml javascript/eslintrc.json python/ruff.toml - The residue rule: anything lint-enforceable is in nobody's prompt. An agent is never told the arity/length/naming limit — the green command's linter tells it, only on violation, injected into its own next turn (mechanism: deterministic-gates). Standing context cost of enforceable rules is therefore zero. Only the judgment residue a linter cannot check (abstraction choice, "composition over inheritance", pattern selection) is ever routed into a prompt — and only into the reviewer's (pipeline-stages).
- Routing key: standard × language × audience × facet. Each standard's prose is sectioned
by facet (interface / implementation / test) and audience-tagged, so the context packet is
a mechanical section-filter, not a per-session judgment call:
- programmer — gets nothing standing; learns quality rules only as gate feedback.
- test-writer — is the interface designer in a red-first pipeline, so it gets test conventions plus the interface facet (naming, public message shape, arity-as-interface) — but not implementation-facing rules (method length, private structure, duplication).
- reviewer — gets the judgment-facet residue; it is the designated judgment actor.
- How far linting reaches (Ruby, the deep case):
rubocop(metrics/style/naming, custom cops for house rules),reek(semantic smells — feature envy, data clumps, control coupling; much of "Metz taste" is reek findings),flay/flog(structural duplication / complexity),mutant(mutation testing — deterministically proves the tests constrain behavior, keeping the test-writer honest and mechanically answering the "gaming the green-assert gate" concern in pipeline-stages). JS (eslint+plugins) / Python (ruff) are shallower but workable. Ceiling: tools detect symptoms, not choices — they police the boundaries of good code; the reviewer polices the choices within them. - Pre-seeding, not just mining. The Mobbin move from never-ask-twice
generalizes: our own standards are self-sourced pre-seeds — writing
convention/sandi-metz-oopup front lets the "OOP approach" decision category start atafk-readyinstead of being re-asked per project. This is the concrete cure for "defined Metz a dozen times." - Sequencing (hard constraint): all of this is post-tracer-bullet. v1 nails the flow with disposable code and trivial prompts; standards/gate-tuning land afterward, alongside self-improvement-loops. Do not add quality gates before the happy path is trusted.
Open questions
- Adoption/update ownership. First-time adoption (copy bindings, wire green command) is naturally an os-sdlc onboarding skill. Drift-checking (a project on an outdated standard version) might extend os-status — but os-status:fix is scoped to "the cc-os approach," whereas this layer targets arbitrary client projects in many languages. Ownership unsettled.
- Gate strictness is a tuning parameter, not an ideology. A maximal cop wall can thrash a cheap model (fix one violation → trigger another) and burn the iteration budget. Tune strictness against iteration counts via autoresearch, same as prompt text — baseline at zero standards first (audit defaults before customizing) and admit each rule only if it beats that baseline.
- Auditing existing projects is deferred. One cheap harvest now: seed the canonical Metz standard + first Ruby binding from the best of the dozen existing definitions. The other projects reconcile later via the version-check path, one at a time (like ADR rollout).
- Bindings for non-OOP standards (functional, framework-conformance) — schema unproven.
Sources
- SecondBrain vault:
convention/facet,matt-pocock-skills-v1-1-changes.md plugins/cc-architect/references/conventions/cc-os-naming.md(Option B precedent)- Ruby toolchain: rubocop, reek, flay, flog, mutant
- ADR-0037; never-ask-twice (vault-as-source-of-truth split)
- 2026-07-17 design session (this doc's origin)