Evidence Bindings
The recurring objection to an architecture model is the fair one: how do I know it’s still true? A diagram drifts from the code silently, and by the time anyone notices, nobody trusts it enough to fix it.
ArchLang’s answer is not to generate the model from code — Chapter 30 explains why derived architecture is a picture of your imports, not of your design. The answer is a citation. A module names the file ranges that attest it, and a host that has the repository can check whether that citation still holds.
The model asserts. The repository attests. Nothing is derived from code.
sources: is an ordinary field
Section titled “sources: is an ordinary field”module Checkout { sources: "src/checkout/index.ts:12-88", "src/checkout/tax.ts:5-40"}There is no new construct here, and that is deliberate. sources is a well-known field (Chapter 9) like latency — ordinary structured data that a named tool interprets. So everything you already know about fields applies unchanged:
- refinement and
overrideat the type or instance level (Chapter 19), cascade/appendpropagation (Chapter 18),- merging across
in <Module> { … }extension blocks, - and it crosses the wire — JSON export, the viewer, the diff — with no serializer change.
An entry is one of three shapes, repo-root-relative:
| Form | Means |
|---|---|
"src/tax.ts" | the whole file |
"src/tax.ts:40" | a single line |
"src/tax.ts:12-88" | a line range, 1-based and inclusive |
The pin is package-scoped
Section titled “The pin is package-scoped”A path on its own attests that a file existed once. To attest that the model is true of a revision, the repository and the commit are pinned in package.archspace — peers of version: and widgets: (Chapter 12):
package: acme.shopversion: "1.4.0"
repo: "https://github.com/acme/shop"commit: "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"commit: is required whenever repo: is set. Scoping the pin to the package — rather than writing a repository beside every binding — is what keeps a bare path unambiguous however many dependencies the package has.
A commit: naming a branch or tag is still checked, but warns: a branch moves, so verified would be a claim about whatever it points at today rather than about a fixed revision.
Verdicts are tri-state
Section titled “Verdicts are tri-state”| Verdict | Means |
|---|---|
verified | the path is a blob at the pinned commit, and the range fits inside it |
broken | the citation no longer holds — the file is gone, the range runs past the end of it, or the entry doesn’t parse |
unverified | nothing could check it — no repository, no pin, or the wrong repository |
unverified is never a pass. An unchecked citation is never displayed as a checked one, and the board draws no badge at all for it — a node the viewer could not check must look exactly like one that cites nothing. The inspector still lists the citations either way, so a reader can tell “no evidence” from “evidence, unchecked”.
A citation that cannot parse is broken, not merely unchecked. An unreadable range would otherwise pass every bounds test vacuously, which is the one way a citation could claim more than it proves.
What a host checks is mechanical: the path is a blob at the pinned commit, the range fits inside that blob, and the checkout’s origin remote is the declared repository. Whether the code at those lines really is the module is a judgement for a reviewer — and the verdict is the input to that judgement, not a replacement for it.
Checking it — archlang evidence
Section titled “Checking it — archlang evidence”archlang evidence ./architecture --repo=../shophttps://github.com/acme/shop @ a1b2c3d ✓ Checkout src/checkout/index.ts:12-88 ✗ Checkout src/checkout/tax.ts:5-40 · Ledger src/ledger.ts
warning: 'Checkout' cites 'src/checkout/tax.ts' up to line 40, but that file is 22 lines long at the pinned commit.
1 verified, 1 broken, 1 unverifiedIt exits non-zero only on broken. A binding nobody could check is reported and does not fail the build — the asymmetry is the point: a broken binding is a defect the author can fix, an unverifiable one usually means the machine running the check has no repository.
Evidence is also a phase of the combined gate, so CI needs no extra step:
archlang check ./architecture # validate + policy-check + format --check + evidenceThe seven diagnostics are all warning severity, and the three repository-level ones suppress the per-entry noise they would otherwise cause:
| Code | Fires when |
|---|---|
EVIDENCE_MALFORMED | an entry isn’t path / path:line / path:start-end |
EVIDENCE_PIN_MISSING | bindings exist but repo: or commit: is absent |
EVIDENCE_PIN_NOT_A_COMMIT | commit: names a branch or tag |
EVIDENCE_UNVERIFIED | the pinned commit could not be read |
EVIDENCE_ORIGIN_MISMATCH | the checkout’s origin isn’t the declared repository |
EVIDENCE_PATH_MISSING | a cited path isn’t in the repository at that commit |
EVIDENCE_RANGE_OUT_OF_FILE | the range runs past the end of the file |
A verdict needs a host that can read the repository
Section titled “A verdict needs a host that can read the repository”The engine is git-free. It verifies a snapshot the host hands it, and derives nothing from the contents of that snapshot:
archlang evidenceandarchlang checksupply the snapshot for a local checkout (Chapter 21).- Studio supplies it for a repository the reader never cloned, because it already owns the repository.
- The plain viewer supplies nothing, so nothing is verified — and, per the rule above, nothing is badged.
Where verdicts are supplied, a corner badge marks the module. It is drawn from the one composed scene tree, so the live board and an exported SVG or PNG carry it identically, and the inspector’s citations link to the pinned commit.
Writing citations that stay true
Section titled “Writing citations that stay true”- Cite the load-bearing range, not the directory.
"src/checkout/"is not a claim anyone can check meaningfully;"src/checkout/index.ts:12-88"is. - Prefer a whole file to a stale range. A range that drifts by four lines is
brokenevery week. If the module is the file, cite the file. - Bump the pin with the model.
commit:is what makes the citation an assertion about a revision; a stale pin verifies against history and quietly stops telling you anything. - A citation is readable without any repository. One ⌘F row per citation, so “which module claims this file?” is answerable from the model alone — including by someone who has only the
.archfiles.