propose an edit → · view source →

You are reading the v1 practitioner version of this property. The formal, normative v2 specification — frozen core, profile mechanism, deterministic verifier, and §5 cross-repo measurement chain — lives at /sama/v2. This page is preserved as background reading.

S — Sorted

Rule: alphabetical sort = dependency direction. UI sits at the edge — foundation, data and logic layers (c1*, c3*) never depend on UI (c5*+). Handlers (c21) are the orchestration layer and may import anything.

The first property of SAMA. Run ls src/ and you have the architecture diagram. There is no separate "where does the data flow?" document because the file system answers it.

#Why

Two reasons:

  1. An agent can navigate by ls. No need to read a README to know that c14_github.ts is lower than c21_app.ts. The prefix is the layer; the layer is the import contract.
  2. The rule is mechanically verifiable. A grep proves it or refutes it in one second. There is no judgement call about "is this dependency OK?" — the only question is whether the prefix on the left is lower than the prefix on the right.

#The verification command

Run this from the repo root:

grep -rE 'from "\./c[5-9]' src/c1*.ts src/c3*.ts

If the output is empty, the rule holds. If anything appears, you have a UI dependency leaking into a foundation, data or logic layer — fix the import or move the file. (Note: c2* files are intentionally excluded — handlers compose UI calls, so c21c51 is the normal pattern.)

This is the single load-bearing test for the Sorted property. Wire it into CI and forget about it.

#Examples

Allowed — lower importing higher? Never. Higher importing lower? Always:

// src/c21_app.ts (handler layer — c21)
import { fetchUser } from "./c14_github.ts";        // c14 < c21 ✓
import { parseCommit } from "./c31_commits.ts";     // c31 > c21 — wrong direction!

Wait — c31 is higher than c21, so this would be backwards. Let me restate the example correctly:

// src/c21_app.ts
import { fetchUser } from "./c14_github.ts";        // c14 < c21 ✓ (handler uses I/O)
import { parseCommit } from "./c31_commits.ts";     // c31 > c21 — this is fine,
                                                    //   c21 (handler) consumes c31 (model)

The rule is lower numbers never import higher numbers. So c14 (I/O) cannot import c21 (handler) — that would be a leaf importing the trunk. c21 importing c31 is fine because c21 (handler) is meant to compose models from c31.

Forbidden:

// src/c14_github.ts (I/O layer — c14)
import { renderPage } from "./c51_render_layout.ts";  // c51 < c14? NO — c51 > c14, but
                                                      //   wait, the rule is
                                                      //   "lower never imports higher",
                                                      //   and c14 < c51, so importing
                                                      //   c51 from c14 is forbidden.

Plain reading of the rule: a file at level n may only import from levels < n. The grep above checks the most common violation (1- and 2- and 3-prefixed files reaching into 5+).

#Common mistakes

  • Putting "shared utilities" in a top-level file with no prefix. The prefix isn't optional. If a helper is used across layers, it belongs in the lowest layer that all callers can reach — usually c31_* (pure models) or a layer-appropriate _layout / _helpers file (e.g. c51_render_layout.ts).
  • Re-exporting from a "barrel" file. Defeats the grep. Every module imports directly from the source file.
  • Treating tests as "outside the rule". Tests are part of the layer they test. c32_session.test.ts is itself c32 and follows the same import constraints.

#What this gives you

A file tree where:

  • ls src/ is the dependency graph, sorted top-to-bottom.
  • The agent can answer "where does X live?" in one prefix-letter.
  • Layer violations are caught by grep, not by reviewers' memory.

← /sama · next: A — Architecture →