cc-os/plugins/os-sdlc/reference/standards-and-conventions.md

89 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# standards and conventions
_Status: direction (Option B decided) — as of 2026-07-17_
_Connects to: [deterministic-gates](deterministic-gates.md), [agent-design-principles](agent-design-principles.md), [never-ask-twice](never-ask-twice.md), [self-improvement-loops](self-improvement-loops.md), [overview](../OVERVIEW.md)_
## 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:**
1. **The opinion** — language-agnostic prose (the Metz rules themselves). Written once.
2. **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.
3. **Per-project adoption** — a project copies the right bindings, wires the green command,
and records a repo ADR ("adopts `sandi-metz-oop` v2 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](never-ask-twice.md)); 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](deterministic-gates.md)).
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](pipeline-stages.md)).
- **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](pipeline-stages.md)). 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](never-ask-twice.md)
generalizes: our own standards are self-sourced pre-seeds — writing `convention/sandi-metz-oop`
up front lets the "OOP approach" decision category start at `afk-ready` instead 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](self-improvement-loops.md). 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](never-ask-twice.md) (vault-as-source-of-truth split)
- 2026-07-17 design session (this doc's origin)