coding.sgit.ai / the rules

The rules, and whether the code obeys them

The estate has a written style guide. It carries 31 numbered rules plus 4 non-negotiable testing rules, it lives in .claude/CLAUDE.md — an agent instruction file, not a published standard — and until the survey behind this site, nobody had ever measured compliance with it. This page is that measurement, rule by rule.

Three columns, and the third is the point. A rule with a test behind it and a rule nobody checks are different objects, and a style guide that does not distinguish them is a wish list. Of the 31 rules below, 2 are described as having a guard behind them, 27 are documented with nothing checking them, and 2 are documented, unchecked and measurably broken.

There is no linter, formatter or type-checker anywhere in the estate. The four tests/ci/ structural guards are the entire automated enforcement surface, and one of them has never worked.

Note what no rule below scores. Not one of them carries ✅ enforced by a test — because the four working guards each encode an incident (a : object = None annotation that broke something, a package-data glob that dropped the UI out of a wheel, two component contracts that regressed) rather than any of the 31 numbered rules. That is the right way to grow a guard set and it means the written rule set and the tested rule set do not currently overlap at all. The configs that would change that →

enforced by a test

a CI guard fails the build when the rule is broken

guard claimed, unlisted

the source says a CI guard enforces this, but the guard is not in the source's own table of guards

🟡
documented, unenforced

written down, high measured compliance, nothing checks it

⚠️
documented, violated

written down, unenforced, and measurably broken in the tree

undocumented convention

consistent in the code, and no rule anywhere says so

Jump to: Code patterns · Security · AWS naming · Responsibility boundaries · Class and file naming · Process · Testing — non-negotiable · the rules that do not exist

Code patterns rules 1–9

The nine that define the Python style. Every one of them is measurable, and every one of them was measured.

#RuleMeasuredEnforcement
1

All classes extend Type_Safe — no plain Python classes.

Do not publish “48% extend Type_Safe”. It is true and it is misleading: the naive percentage counts test cases and enums as failures.

paraphrased
506 direct, plus Type_Safe__List (44), Fast_API__Routes (46) and Schema__Step__Base (25), which are themselves descendants. Excluding 169 TestCase and 77 enums, essentially every class is in the lineage. 🟡 documented, unenforced
2

Zero raw primitives — no str, int, float, list or dict as attributes.

The highest-value rule in the set and the hardest to express as a lint. It would need a custom AST check.

verbatim
27 hand-written constrained primitives in sg_compute/primitives/ alone; 78 Safe_Str, 13 Safe_Int and 6 Safe_UInt subclasses in the new tree. 🟡 documented, unenforced
3

No Literals — fixed value sets use Enum__*.

Pairs with the tooling rule “Never use Pydantic. No Literals.”

paraphrased
185 Enum__* files. 🟡 documented, unenforced
4

Schemas are pure data — no methods.

paraphrased
614 Schema__* files, spot-checked. 🟡 documented, unenforced
5

Collection subclasses are pure type definitions.

paraphrased
44 Type_Safe__List subclasses. 🟡 documented, unenforced
6

Every route returns .json() on a Type_Safe schema — no raw dicts.

paraphrased
46 Fast_API__Routes subclasses, spot-checked. 🟡 documented, unenforced
7

A ═══ 80-char header on every file. Python files only — in Markdown, # is heading syntax and a header block renders as a stack of H1s.

The caveat is scar tissue: the rule was applied to Markdown once and GitHub rendered a banner as five H1 headings.

verbatim
992 of 992 class-defining files in the new tree. 100%. 3,120 of 3,999 files across the whole repo. 🟡 documented, unenforced
8

Inline comments only — no docstrings, ever.

The banner carries the purpose; trailing comments carry the reasoning. Often described as trivial to lint, and it is not: ruff's pydocstyle rules require docstrings and there is no inverse, so this needs a custom AST check — shipped here.

verbatim
989 of 992. 99.7%, three violations. 🟡 documented, unenforced
9

No underscore prefix for private methods.

The rule is either Python-only and widely ignored, or it is being ignored in two languages. The source does not say, so in practice it is neither enforced nor retired.

verbatim
895 of 992. 91%, 97 violations in the new tree alone — and the JavaScript uses _private as a matter of course. ⚠️ documented, violated

Security rules 10–13

Four rules. The source groups them as 10–13 and lists them in this order; the individual numbering below is inferred from that order, not quoted.

The numbering below is inferred. The source groups these rules and lists them in order without numbering them individually. The order is the source's; the numbers are this site's reading of it.

#RuleMeasuredEnforcement
10

Evaluate is allowlist-gated — JS__Expression__Allowlist defaults to deny-all.

The source's own table of CI guards lists five, and this is not one of them. Either the table is not the whole enforcement surface or the guard does not exist. Unresolvable from the pack alone.

paraphrased
Described in the source as having a CI guard behind it. ❓ guard claimed, unlisted
11

No arbitrary code execution — the shell-server pattern from OSBot-Playwright is explicitly not carried forward.

A banned thing with the reason named, rather than a banned thing with quiet violations.

paraphrased
A design decision, not a countable one. 🟡 documented, unenforced
12

No AWS credentials in Git. If one appears in a diff, block the commit.

This site encodes the same rule as a release gate: the leak tripwire fails the build on anything credential-shaped, including an AWS-account-id-shaped 12-digit number.

paraphrased
Not measured in the survey. 🟡 documented, unenforced
13

No vault keys in Git.

Also a tripwire pattern on this site: a long passphrase joined by a colon to a UUID-shaped id.

paraphrased
Not measured in the survey. 🟡 documented, unenforced

AWS naming rules 14–15

Both are scar tissue, both are quoted verbatim, and both name the case that motivated them. A rule that cites its own precedent is a rule people can trust.

#RuleMeasuredEnforcement
14

Security group GroupName must NOT start with sg-. AWS reserves the sg-* prefix for security group IDs and rejects CreateSecurityGroup with InvalidParameterValue.

Precedent: A rejected CreateSecurityGroup call. The rule names the helper that implements the fix.

verbatim
Not countable — a boundary rule with an API error behind it. 🟡 documented, unenforced
15

AWS Name tag — never double-prefix. When the logical name already carries the namespace (e.g. elastic-quiet-fermi), do not wrap it again into elastic-elastic-quiet-fermi.

Precedent: A double-prefixed tag that shipped. The rule names the helper that implements the fix.

verbatim
Not countable. 🟡 documented, unenforced

Responsibility boundaries rules 16–19

Four rules, each naming exactly one owner for a capability. This is the most transferable pattern in the set, and the one that matters most in a codebase whose main author is a model: it stops a generator putting a call in a reasonable-looking wrong place.

#RuleMeasuredEnforcement
16

Step__Executor is the ONLY class that calls page.* Playwright methods — with a Browser__Launcher carve-out for process lifecycle.

Same discrepancy as rule 10: the source's guard table does not list this guard. This is the model the other three should follow — a boundary rule with a test behind it — if the guard is real.

verbatim
Described in the source as enforced by a CI guard that fails the build if a raw browser.new_context( appears outside Page__Factory. ❓ guard claimed, unlisted
17

Artefact__Writer is the ONLY class that writes to sinks.

verbatim
No guard. 🟡 documented, unenforced
18

Request__Validator contains ALL cross-schema validation.

verbatim
No guard. 🟡 documented, unenforced
19

Routes have no logic — pure delegation to Playwright__Service.

verbatim
46 Fast_API__Routes subclasses. No guard. 🟡 documented, unenforced

Class and file naming rules 20–22

The three that make a symbol findable by path construction alone — no index, no grep, no re-export layer to hide behind.

#RuleMeasuredEnforcement
20

Normalise SGraph-AI to SGraph_AI. Class and module names use the underscore form; repo roots and test filenames may keep the hyphen.

paraphrased
The spec uses hyphenated names that are not legal Python identifiers, so the rule exists to settle the one hard case. 🟡 documented, unenforced
21

One class per file, filename identical to the class name. Registries (module-level constants + helper functions, e.g. STEP_SCHEMAS) are the one exception — they live in a single *_registry.py because they are logic, not a schema.

The carve-out is quoted because it is the pattern worth copying: an exception with a stated reason, rather than a rule people quietly break.

verbatim
187 of 208 sampled files define exactly one class. 90%. ⚠️ documented, violated
22

__init__.py stays empty. Never commit an empty __init__.py in a folder that shares a name with a sibling .py module: Python's import system prefers the package and every import under the module breaks.

Precedent: The warning in the rule is the incident. Somebody lost a day to it.

verbatim
299 of 302. 99%. 🟡 documented, unenforced

Process rules 23–31

Nine rules, and the source names five of them. These are agent-workflow rules rather than code style, and they belong here anyway: they are what makes a mostly-agent-written codebase safe to review.

Partly reproduced. The source summarises this group rather than enumerating it. Five of the nine are named below. The remaining four are not reproduced in the brief pack, so this site does not have them and does not guess at them.

#RuleMeasuredEnforcement
23–31

Human-only folders that agents must never write to.

paraphrased
Named, not numbered, in the source. 🟡 documented, unenforced
23–31

The good-failure / bad-failure debrief convention.

paraphrased
Named, not numbered. 🟡 documented, unenforced
23–31

Session handover.

paraphrased
Named, not numbered. 🟡 documented, unenforced
23–31

Branch naming: claude/{description}-{session-id}.

The branch this site's own content was written on follows it.

verbatim
Named, not numbered. 🟡 documented, unenforced
23–31

Agents never push to dev directly.

verbatim
Named, not numbered. 🟡 documented, unenforced

Testing — non-negotiable rules T1–T4

Four rules, quoted in full, and the strongest opinion in the whole set. No mocks. No patches. The alternative is real in-memory composition, which is only affordable because Type_Safe objects are cheap to build — the type system and the testing philosophy are the same decision.

#RuleMeasuredEnforcement
T1

No mocks. No patches. Use register_playwright_service__in_memory() and in_memory_stack-style composition.

verbatim
4,785 tests in 81 seconds. That is the evidence the position is affordable rather than aspirational. 🟡 documented, unenforced
T2

Assert on contracts — schemas, status codes, persisted artefacts — not implementation details.

verbatim
169 classes extend TestCase, so tests are class-based. 🟡 documented, unenforced
T3

Real Chromium for integration tests. Gate on SG_PLAYWRIGHT__CHROMIUM_EXECUTABLE; skip cleanly when absent.

verbatim
Not measured in the survey. 🟡 documented, unenforced
T4

Deploy-via-pytest. Deploy tests are numbered (test_1__create_lambda, test_2__invoke__health_info, …) and run top-down.

verbatim
Not measured in the survey. 🟡 documented, unenforced

The rules that do not exist

All 31 documented rules are about Python and process. JavaScript, CSS, HTML and Bash have consistent, discoverable conventions and zero written rules. These were reconstructed by counting. Every one of them is a candidate rule, and none of them is one yet.

LanguageConventionMeasuredStatus
JavaScript

Native web components. No framework, no build step.

41 customElements.define across 50 files. Zero bundler config.❌ undocumented convention
JavaScript

Every component is a three-file triplet: .js, .html, .css, same basename, same directory.

Universal in components/.❌ undocumented convention
JavaScript

static jsUrl = import.meta.url on every component, so it can locate its own siblings.

The mechanism that removes the build step.❌ undocumented convention
JavaScript

Override onReady(), never connectedCallback directly.

The base class populates the shadow root first.❌ undocumented convention
JavaScript

4-space indent, single quotes, no semicolons, trailing commas in multi-line literals.

Not yet a settled convention. The code disagrees with itself here.

3,791 indented lines a multiple of 4 vs 148 not. 4,006 single quotes vs 400 double, 91%. Semicolons split: 531 statement lines without vs 401 with.❌ undocumented convention
CSS

Property values aligned to a column, per block, set by that block's longest property name.

Consistent across 38 files. The unit of alignment is the block, not the file.❌ undocumented convention
CSS

No literal colours outside the token file. Every colour and surface is a var(--token).

The single highest-value CSS rule available, and it is not written down anywhere.❌ undocumented convention
CSS

Plain semantic class names. Not BEM, not utility classes — shadow DOM removes the problem both exist to solve.

.left-nav, .nav-item, .nav-icon.❌ undocumented convention
HTML

2-space indent — deliberately different from the 4 used in JS and CSS.

37 files.❌ undocumented convention
HTML

Classes are for styling, data-* is for behaviour, and the two never mix.

data-view="compute" read as btn.dataset.view.❌ undocumented convention
HTML

Every interactive control is a real control with an accessible name. No <div onclick>.

ARIA on every interactive element in the sampled components.❌ undocumented convention
Bash

set -euo pipefail in every .sh file.

Not yet a settled convention. The code disagrees with itself here.

2 of 5 files have set -e at all, in three different forms. This is a recommendation, not an observed convention.❌ undocumented convention
Bash

Shell is generated from a typed Section__* class, not written as a script.

15 Section__* classes; 5 .sh files in 217,266 lines.❌ undocumented convention
Bash

Every generated section opens with a # ── … ── banner and emits at least one bracketed echo breadcrumb, so boot logs stay greppable.

Consistent across the 15 sections.❌ undocumented convention
Prose

Every document is em-dash-free.

Not yet a settled convention. The code disagrees with itself here.

248 em-dashes across the 11 markdown documents that state the rule, and not one file has zero. Documented, and contradicted by its own source.❌ undocumented convention
Prose

A CC BY 4.0 footer on every markdown document, and version-prefixed filenames: v0.33.54__arch-brief__<slug>.md.

Around 1,100 files carry the footer. The filename convention is the same name-tells-you-what-it-is instinct as Schema__ and Section__.❌ undocumented convention

Where these numbers come from

Every count on this page was measured by counting the code, on 2026-08-24, and is published here from the survey document rather than typed in by hand — the page is generated from data/rules.json and CI fails the release if it has drifted. The survey is dated, not live. This repository does not contain the code it describes, so the numbers are a photograph rather than a feed, and they will drift. What that costs, and the fix.

The rule texts marked verbatim are quoted word for word. Those marked paraphrased are summarised in the survey document rather than quoted, so this site does not have their exact wording and does not invent it.