{
  "schema": "sgraph-coding-conventions/v1",
  "surveyed": "2026-08-24",
  "method": "Derived by counting from the code, not from documentation. Every number measured this session.",
  "python": {
    "files": 3999,
    "loc": 217266,
    "filenames_with_double_underscore": 3871,
    "prefix_families": {
      "Schema__": 614,
      "Safe_Str__": 290,
      "Enum__": 185,
      "Cli__": 82,
      "Routes__": 59,
      "Safe_Int__": 18,
      "Section__": 15,
      "Fast_API__": 12,
      "Safe_UInt__": 7
    },
    "suffix_families": {
      "__Builder": 97,
      "__Helper": 86,
      "__Client": 77,
      "__Service": 46,
      "__Mapper": 39,
      "__Detector": 23,
      "__Loader": 17,
      "__Registry": 14,
      "__Writer": 14,
      "__Parser": 10,
      "__Runner": 9,
      "__Manager": 7,
      "__Factory": 4,
      "__Watchdog": 2,
      "__Middleware": 1,
      "__Poller": 1
    },
    "class_bases_new_tree": {
      "total": 1034,
      "Type_Safe": 506,
      "TestCase": 169,
      "Safe_Str": 78,
      "str_Enum": 69,
      "Fast_API__Routes": 46,
      "Type_Safe__List": 44,
      "Schema__Step__Base": 25,
      "Safe_Int": 13,
      "Enum": 8,
      "Safe_UInt": 6
    },
    "one_class_per_file": {
      "sampled": 208,
      "exactly_one": 187,
      "pct": 90
    },
    "banners": {
      "repo_files_with_banner": 3120,
      "class_files_in_new_tree": 992,
      "starting_with_banner": 992,
      "pct": 100
    },
    "compliance": {
      "rule_1_type_safe": "essentially all, excluding 169 TestCase and 77 enums",
      "rule_7_banner": "992/992 = 100%",
      "rule_8_no_docstrings": "989/992 = 99.7%",
      "rule_9_no_underscore_private": "895/992 = 91% (97 violations)",
      "rule_22_empty_init": "299/302 = 99%"
    },
    "alignment": {
      "schema_attribute_colons": {
        "files": 46,
        "aligned": 46,
        "pct": 100
      },
      "from_import_keyword": {
        "files": 817,
        "aligned": 321,
        "pct": 39
      }
    },
    "primitives_dir": [
      "Safe_Int__Disk__GB",
      "Safe_Int__Exit__Code",
      "Safe_Int__Hours",
      "Safe_Int__Log__Lines",
      "Safe_Int__Max__Hours",
      "Safe_Int__Pids",
      "Safe_Int__Port",
      "Safe_Int__Uptime__Seconds",
      "Safe_Str__AWS__Region",
      "Safe_Str__Api__Key",
      "Safe_Str__Docker__Image",
      "Safe_Str__IP__Address",
      "Safe_Str__Image__Registry",
      "Safe_Str__Image__Tag",
      "Safe_Str__Instance__Type",
      "Safe_Str__Log__Content",
      "Safe_Str__Message",
      "Safe_Str__Node__Id",
      "Safe_Str__Node__Name",
      "Safe_Str__Ollama__Model",
      "Safe_Str__Platform__Name",
      "Safe_Str__Pod__Name",
      "Safe_Str__SG__Id",
      "Safe_Str__SSM__Path",
      "Safe_Str__Spec__Id",
      "Safe_Str__Stack__Id",
      "Safe_Str__Stack__Name"
    ]
  },
  "javascript": {
    "files": 50,
    "custom_elements_define": 41,
    "attach_shadow": 6,
    "type_module_script_tags": 48,
    "quotes": {
      "single": 4006,
      "double": 400,
      "pct_single": 91
    },
    "semicolons": {
      "lines_with": 401,
      "statement_lines_without": 531,
      "note": "components/ is semicolon-free; shared/ is not"
    },
    "indent": {
      "multiple_of_4": 3791,
      "other": 148
    },
    "banner_files": 15,
    "component_triplet": [
      ".js",
      ".html",
      ".css"
    ],
    "cdn": {
      "host": "dev.tools.sgraph.ai",
      "path_scheme": "/components/<name>/v<major>/v<major>.<minor>/v<major>.<minor>.<patch>/<file>",
      "served": [
        "sg-component.js (SgComponent base)",
        "sg-tokens.css",
        "sg-vault-client.js",
        "sg-vault-write.js"
      ]
    },
    "base_class_contract": {
      "static jsUrl": "import.meta.url \u2014 required, enables self-location",
      "get resourceName()": "basename of sibling .html/.css",
      "get sharedCssPaths()": "tokens and shared sheets",
      "onReady()": "lifecycle hook \u2014 NOT connectedCallback directly"
    },
    "event_namespace": {
      "prefix": "sp-cli:",
      "files": 23,
      "note": "LEGACY NAMING \u2014 a rename surface"
    }
  },
  "css": {
    "files": 38,
    "alignment": "property values aligned per block, column set by the block's longest property",
    "token_prefixes": {
      "unprefixed": [
        "--bg-panel",
        "--border-1",
        "--text-1..4",
        "--text-link",
        "--shadow-1..2",
        "--warn",
        "--warn-soft",
        "--soon"
      ],
      "sg": [
        "--sg-text",
        "--sg-text-muted",
        "--sg-surface",
        "--sg-sp-1..4",
        "--sg-transition-fast"
      ],
      "sgl": [
        "--sgl-tab-h",
        "--sgl-panel-h"
      ]
    },
    "note": "THREE PREFIX FAMILIES FOR ONE TOKEN SYSTEM \u2014 resolve before publishing",
    "naming": "plain semantic class names. NOT BEM, NOT utility classes \u2014 shadow DOM makes both unnecessary"
  },
  "html": {
    "files": 37,
    "indent": 2,
    "note": "deliberately different from the 4 used in JS and CSS",
    "rules": [
      "component markup is a fragment, no html/head/template wrapper",
      "semantic elements, never div onclick",
      "ARIA on every interactive element",
      "data-* is the behaviour hook; classes are for styling; the two never mix",
      "unicode glyphs instead of icon fonts or SVG sprites"
    ]
  },
  "bash": {
    "sh_files": 5,
    "set_e_files": 2,
    "set_e_forms": [
      "set -euo pipefail",
      "set -eu",
      "set -u"
    ],
    "generated_shell": {
      "pattern": "Section__*(Type_Safe) with a single render() -> str and a module-level TEMPLATE",
      "count": 15,
      "sections": [
        "Base",
        "Docker",
        "Sidecar",
        "Nginx",
        "Env__File",
        "GPU_Verify",
        "NVIDIA_Container_Toolkit",
        "Ollama",
        "VLLM",
        "SGit_Venv",
        "Claude_Code__Firstboot",
        "Claude_Launch",
        "Agent_Tools",
        "Node",
        "Shutdown"
      ],
      "conventions": [
        "banner names the coupling, not just the purpose",
        "generated shell gets a # -- banner (box-drawing, not the Python ===)",
        "computation in Python, literals in the emitted shell",
        "bracketed echo breadcrumbs so boot logs are greppable",
        "composition is a list of sections, never a template with conditionals"
      ]
    }
  },
  "enforcement": {
    "linters": 0,
    "formatters": 0,
    "type_checkers": 0,
    "ci_guards": {
      "total": 4,
      "working": 3,
      "broken": 1,
      "list": [
        {
          "name": "test_no_object_none_annotations",
          "enforces": "bans ': object = None'",
          "state": "works"
        },
        {
          "name": "test_sg_compute_ami_picker__snapshot",
          "enforces": "web component live-fetch contract",
          "state": "works"
        },
        {
          "name": "test_sg_compute_spec_detail__snapshot",
          "enforces": "web component structure",
          "state": "works"
        },
        {
          "name": "test_wheel_contains_ui",
          "enforces": "wheel contains per-spec UI assets",
          "state": "works"
        },
        {
          "name": "test_sg_compute_does_not_import_legacy",
          "enforces": "no legacy imports in the new tree",
          "state": "BROKEN \u2014 regex sgraph_ai_service_playwright[^_] cannot match sgraph_ai_service_playwright__cli",
          "measured": "guard matches 0 files; 228 real imports in 69 files; deleting [^_] makes it fail as intended"
        }
      ]
    },
    "documented_rules": {
      "source": ".claude/CLAUDE.md",
      "count": 31,
      "plus": "4 non-negotiable testing rules",
      "groups": [
        "Code Patterns 1-9",
        "Security 10-13",
        "AWS Naming 14-15",
        "Responsibility Boundaries 16-19",
        "Class/File Naming 20-22",
        "Process 23-31"
      ],
      "coverage": "ALL are Python or process. Zero rules for JS, CSS, HTML or Bash."
    }
  },
  "cross_cutting": [
    "one idea per file, and the filename says which",
    "a banner names every file (three characters: === Python, -- shell and JS shared, JSDoc JS components)",
    "alignment as a first-class convention, per block",
    "single source of truth enforced by structure, not by asking",
    "conventions chosen because an LLM is a primary reader and writer"
  ]
}