syntaxai/tdd.md · commit d2574fd

Publish SAMA v2 draft spec at /sama/v2

The formal, normative version of SAMA — frozen core + profile
mechanism, written so a deterministic verifier in any language can
ingest it. Status per the doc itself: "Draft for v2.0".

What landed:
- content/sama/v2.md — the spec body (§0 design contract through §6
  evolution policy + Appendix A pillar mapping). Comes straight from
  the authored draft; minor markdown cleanup on the §1.1 layer table
  to render correctly.
- src/c21_handlers_sama.ts — new samaV2Handler renders the spec via
  the docs layout. Pattern follows samaSkillHandler / samaVerifyHandler:
  literal route, no ALL_SAMA registry entry (v2 is a spec doc, not one
  of the four practitioner-facing disciplines).
- src/c21_app.ts — literal route "/sama/v2" added BEFORE "/sama/:slug"
  so it wins specificity.
- The /sama landing copy gains a new section "the v2 specification
  (draft)" right after the reading-order block — discoverability for
  visitors who want the formal version.

The v1 discipline pages (/sama/sorted, /architecture, /modeled,
/atomic) stay untouched. They describe the c11/c13/c14/c21/c31/c51
prefix model in practitioner shape; v2 generalises that to the four
canonical Pure/Core/Adapter/Entry layers + profiles. Cutover from
v1→v2 framing is a separate decision; for now both coexist with v2
clearly labeled "draft".

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
author
syntaxai <[email protected]>
date
2026-05-23 06:32:51 +01:00
parent
a62513c
commit
d2574fd967f823d9df2b5ee13b5d186f41ccb642

3 files changed · +182 −0

added content/sama/v2.md +159 −0
@@ -0,0 +1,159 @@
1+# SAMA v2 — Core Specification
2+
3+> **Status:** Draft for v2.0. This document defines the *frozen core* and the *profile mechanism*. The core is normative and stable; profiles are the only extension point. Anything a CI job cannot check deterministically does not belong in this spec — it belongs in `AGENTS.md`.
4+
5+---
6+
7+## 0. Design contract
8+
9+SAMA separates **the law** (how layers may depend on each other — frozen, language-neutral, identical in every repo) from **the vocabulary** (which named sublayers a given domain uses — supplied by a profile).
10+
11+Two SAMA repositories in different languages and different profiles remain comparable at the core level. That comparability is what makes cross-repo empirical measurement possible: every repo, regardless of language or profile, emits the same core metrics.
12+
13+A conformant verifier is a **deterministic program**. No LLM judgment sits in the enforcement loop. An agent may *use* SAMA to decide where a file goes; it may never be the *referee* that decides whether a file conforms.
14+
15+---
16+
17+## 1. The frozen core
18+
19+### 1.1 The four canonical layers
20+
21+Every file in a SAMA repository belongs to exactly one of four layers. This set is **frozen**: no profile, repo, or version may add, remove, renumber, or rename a canonical layer.
22+
23+| Layer | Name | Contains | May import |
24+|---|---|---|---|
25+| 0 | Pure | Types, constants, pure functions, domain models. No I/O, no side effects. | nothing above 0 (i.e. only other Layer 0) |
26+| 1 | Core | Domain logic and decisions. No network, disk, clock, or framework. | 0 |
27+| 2 | Adapter | The boundary. External input is **parsed here and only here** (never cast). DB, network, filesystem, framework bindings. | 0, 1 |
28+| 3 | Entry | Outermost shell: `main`, CLI handler, HTTP route, UI mount, job entry. | 0, 1, 2 |
29+
30+Layer 0 depends on nothing. Layer 3 is depended on by nothing.
31+
32+### 1.2 The Law (frozen, one sentence)
33+
34+> **Imports always point to a strictly lower layer number — never upward, never sideways across a higher number, never cyclic.**
35+
36+Formally, for any import edge `A → B`: `layer(B) < layer(A)`, OR `A` and `B` are in the same layer **and** the active profile declares a sublayer ordering that permits `A → B` (see §2.2). The whole-program import graph must be acyclic.
37+
38+This single law is what makes the **Sorted** pillar enforceable: the layer number is the lexicographic sort key, so file order *is* dependency direction.
39+
40+### 1.3 Why exactly four
41+
42+Four rings is the minimal set that captures the only relation that matters for context rot: *what is allowed to depend on what.* Fewer cannot express the parse-at-the-boundary rule (it needs a distinct Adapter layer). More reintroduce ambiguity about where a file belongs — which is the drift SAMA exists to kill. This is the "as simple as possible, but not simpler" line.
43+
44+---
45+
46+## 2. Profiles
47+
48+A profile is the **only** extension mechanism. It does exactly one thing:
49+
50+> A profile MAY subdivide a canonical layer into named, ordered sublayers. A profile MUST NOT introduce, remove, reverse, or otherwise alter any dependency relation between the four canonical layers.
51+
52+If a proposed profile rule cannot be expressed as "subdivide layer N into ordered sublayers," it is not a profile rule. It is either core (and frozen) or out of scope (and belongs in `AGENTS.md`).
53+
54+### 2.1 What a profile may and may not do
55+
56+| Allowed | Forbidden |
57+|---|---|
58+| Split Layer 2 into `repository → gateway → controller` | Let Layer 1 import Layer 2 |
59+| Leave a canonical layer empty (e.g. CLI has no DB) | Add a fifth canonical layer |
60+| Define intra-layer sublayer ordering | Make Layer 0 perform I/O |
61+| Map sublayer names to filename prefixes | Reverse the import direction between core layers |
62+
63+### 2.2 Sublayer ordering
64+
65+Within a layer, sublayers are totally ordered. An import between two files in the same canonical layer is legal only if it points to an equal-or-lower sublayer in the profile's declared order. Cross-layer imports are governed solely by §1.2 and ignore sublayer order.
66+
67+### 2.3 Profile declaration format
68+
69+A profile is a single machine-readable file the verifier ingests (`sama.profile.toml`). Example — an HTTP service:
70+
71+```toml
72+sama_version = "2.0"
73+profile = "http-service"
74+
75+# Map each canonical layer to ordered sublayers and their filename prefixes.
76+# Order in the array = dependency order (later may import earlier, never reverse).
77+
78+[layers.0] # Pure — not subdivided
79+prefixes = ["p0_"]
80+
81+[layers.1] # Core
82+sublayers = [
83+ { name = "policy", prefix = "c1a_" },
84+ { name = "service", prefix = "c1b_" }, # service may import policy
85+]
86+
87+[layers.2] # Adapter
88+sublayers = [
89+ { name = "repository", prefix = "a2a_" },
90+ { name = "gateway", prefix = "a2b_" },
91+ { name = "controller", prefix = "a2c_" }, # controller → gateway → repository
92+]
93+
94+[layers.3] # Entry
95+prefixes = ["e3_"]
96+```
97+
98+A `cli` profile would leave `[layers.2]` minimal and subdivide `[layers.3]` into `arg-parser → dispatch`. A `frontend` profile would subdivide Layer 1 into `store` vs `view-logic`. Same law, different dialect.
99+
100+---
101+
102+## 3. Layer assignment & the consistency check
103+
104+The hard step is not checking the law — it is knowing each file's layer. SAMA uses **prefix as the source of truth, with a consistency check against actual imports.**
105+
106+1. **Declared layer** = the canonical layer implied by the file's prefix (per the active profile's prefix map).
107+2. **Observed layer ceiling** = the highest layer any of the file's imports resolves to.
108+3. **Consistency rule:** the verifier FAILS if a file imports from a layer that its declared layer is not permitted to import — i.e. if the prefix claims something the imports contradict.
109+
110+This gives a deterministic gate *and* protection against a misdeclared (or dishonest) prefix. A file cannot launder a forbidden dependency by lying about its layer: the import graph exposes it.
111+
112+---
113+
114+## 4. Conformance — the binary gate
115+
116+A repository **conforms to SAMA v2** if and only if all of the following pass. Each is a deterministic check; the result is binary.
117+
118+1. **Sorted** — every file carries a profile-recognized prefix; lexicographic prefix order equals layer order.
119+2. **Architecture** — every file maps to exactly one canonical layer via §2.3; no file is unprefixed or maps to two layers.
120+3. **Modeled (tests)** — every Layer 1 and Layer 2 behavior file has a sibling test file.
121+4. **Modeled (boundary)** — external input is parsed only in Layer 2. (Verifier support is profile-dependent; see §6.)
122+5. **Atomic** — no file exceeds the line cap (default ~700; profile may lower, never raise). No barrel re-export files.
123+6. **The Law** — the import graph is acyclic and every edge satisfies §1.2.
124+7. **Consistency** — no file's imports contradict its declared layer (§3).
125+
126+If any check fails, the repository does not conform. There is no partial pass, no score-to-taste. (Profiles and *measurement* are graded; **conformance** is binary.)
127+
128+---
129+
130+## 5. Core metrics (the SAMA-independent outcome)
131+
132+Every conformant repo emits these, identically, regardless of language or profile. These are the variables for A/B measurement (`SAMA on` vs `off`) — and crucially, **none of them is a compliance score.** They measure properties an agent's task performance should correlate with:
133+
134+- **Graph depth** — longest path in the import DAG.
135+- **Fan-in / fan-out distribution** per layer.
136+- **Boundary ratio** — share of external-input parsing that occurs in Layer 2.
137+- **Working-set fit** — share of files within the editor LOC sweet spot.
138+- **Violation count over time** — emitted even on conforming repos as a trailing signal (which rules agents *almost* break).
139+
140+Report the **delta** between SAMA-on and SAMA-off runs on these metrics — not the compliance rate. Compliance proves the rules were followed; the delta is what proves the rules were *worth* following.
141+
142+---
143+
144+## 6. Evolution policy (how the standard stays alive without rotting)
145+
146+- **The core (§1) is frozen.** Changing the four layers or the Law requires a major version and an extraordinarily high evidentiary bar: cross-repo data showing the current core measurably harms agent performance.
147+- **Profiles are the moving edge.** A new profile is a *falsifiable hypothesis*: "this sublayer split lowers context cost for this domain." It is admitted provisionally, measured against §5, and promoted to "official" only if the delta holds across multiple repos.
148+- **A rule agents structurally violate is a signal — to be triaged, not auto-relaxed.** Either the rule is right and the agent must improve (signal to agent-builders), or the rule is impractical and the *profile* adapts (never the core). The feedback loop tunes profiles; it does not erode the law.
149+
150+---
151+
152+## Appendix A — Mapping to the four pillars
153+
154+| Pillar | Where it lives in v2 |
155+|---|---|
156+| **S** — Sorted | §1.2 Law + §4.1; prefix = layer = sort key |
157+| **A** — Architecture | §1.1 four layers + §2 profiles (the fix for the weak A) |
158+| **M** — Modeled | §4.3 sibling tests + §4.4 boundary parsing (Layer 2) |
159+| **A** — Atomic | §4.5 line cap + no barrels |
modified src/c21_app.ts +3 −0
@@ -32,6 +32,7 @@ import {
3232 skillsSamaMdHandler,
3333 samaCliResponse,
3434 samaSkillHandler,
35+ samaV2Handler,
3536 samaVerifyHandler,
3637 samaLandingHandler,
3738 samaSlugHandler,
@@ -359,6 +360,8 @@ ${rows}
359360
360361 "/sama/skill": samaSkillHandler,
361362
363+ "/sama/v2": samaV2Handler,
364+
362365 "/sama/verify": samaVerifyHandler,
363366
364367 "/sama": samaLandingHandler,
modified src/c21_handlers_sama.ts +20 −0
@@ -61,6 +61,22 @@ export const samaSkillHandler = async (): Promise<Response> => {
6161 return htmlResponse(html);
6262 };
6363
64+// -------- /sama/v2 (the SAMA v2 Core Specification — draft) --------
65+
66+export const samaV2Handler = async (): Promise<Response> => {
67+ const md = await Bun.file("./content/sama/v2.md").text();
68+ const html = await renderDocsPage({
69+ title: "SAMA v2 — Core Specification (draft) — tdd.md",
70+ description:
71+ "Draft of the SAMA v2 Core Specification: four canonical layers (Pure / Core / Adapter / Entry), one frozen import law, profiles as the only extension mechanism. Defines the binary conformance gate and the SAMA-independent core metrics for cross-repo empirical measurement.",
72+ bodyMarkdown: md,
73+ ogPath: "https://tdd.md/sama/v2",
74+ active: "sama",
75+ pathForDocs: "/sama/v2",
76+ });
77+ return htmlResponse(html);
78+};
79+
6480 // -------- /sama/verify (form + report + dogfood short-circuit) --------
6581
6682 const VERIFY_FORM_MD = `# SAMA verify
@@ -244,6 +260,10 @@ If you're new to this:
244260
245261 Each page is short, opinionated, and ends with the common mistakes you'll see if the discipline lapses.
246262
263+## the v2 specification (draft)
264+
265+The four discipline pages above are the practitioner-facing version. The formal, normative version — frozen core + profile mechanism, written so a deterministic verifier in any language can ingest it — lives at **[/sama/v2](/sama/v2)** (draft for v2.0). That doc defines the four canonical layers (Pure / Core / Adapter / Entry), the single import law, the binary conformance gate, and the SAMA-independent core metrics for cross-repo empirical measurement.
266+
247267 ## drop into your agent
248268
249269 For agents that load skills from \`~/.claude/skills/\` (Claude Code, obra/superpowers, etc.), grab the SKILL.md version: