No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
The original design let a team add its own rules beside the built-in validators, each with an id, a severity and the whole graph query API, run in the same pass and reported in the same output (docs/lineage/v0-design/06-extraction-and-validation.md §6.5). The Protocol has two check families, conformance and honesty, and every validator belongs to one of them. The architectural annotation decision sends a corpus's own rules to the corpus's own gate.
The first adopter's gate runs sdp validate and parses its summary line, then checks its own context isolation, entry addresses, dependency cycles, question keys, prose mentions, cited laws and Pack pages. It also parses carrier frontmatter to read kind, readiness and relations, a second read model that a graph-based corpus-rule runner would remove.
A rules file holds the body sdp q evaluates, so a rule tried through sdp q runs unchanged under sdp validate, and a catalog recipe whose answer carries findings, such as the architecture walk, is a rules file as shipped. A rules file that needs a shipped recipe's answer calls it through recipes and keeps no copy of its code. The runner reads only the answer's findings, so the recipe keeps the rest of its answer for a reader. Corpus findings print after the Protocol's and are tallied on a line of their own, so a gate that reads the Protocol's summary line reads it unchanged; any error, the Protocol's or the corpus's, exits 1, and the two lines say which. Each rules file receives its own copy of what it reads, so a careless rule cannot change another rule's input and the order of the files changes only the order of the output. Its parameters are its own too: a catalog recipe answers a parameter name it does not take with that name and no findings, so parameters shared by every file would fail the walk on the names another file reads.
Intent
problem
A corpus with rules of its own checks them off the one validation path, reading the carriers a second way and reporting in a form no Protocol surface reads.
outcome
Let a corpus author its own graph rules and have their findings join the one validation report, so no corpus re-parses its carriers to check itself.
A corpus rule is a graph body the corpus authors, given g, graph, report, params and recipes as a recipe body is, and returning findings that each carry a rule id, a subject, a message and a severity.
A corpus rule reads the one derived graph, the Protocol's report and the params the operator supplies for its file, directly or through the shipped recipes it calls, and no carrier, source file or network; that is the rule author's obligation, because the runner evaluates the body with the trust sdp q asks and claims no sandbox.
Validation runs corpus rules only from a file the operator names with sdp validate --rules PATH, which may repeat, and never from a file it finds in the corpus or in a configuration; it asks the trust sdp q already asks, to run code the operator chose.
Rules files run one at a time in the order named, each to completion, after the Protocol's validators; every file receives the same Protocol report and none sees another file's findings, so the order changes only the order of the output.
Each rules file receives its own copy of the graph and the report, made after the graph is written, and its own params, so a body that changes what it receives changes no node, edge, delivery fact or Protocol finding, and nothing another rules file receives.
Each rules file receives as params only the parameters the operator names after its --rules and before the next --rules, or {} when none follow it, so no file receives a parameter meant for another.
Each corpus finding names its rule and its rules file as its source. The Protocol states none of these rules: a shipped recipe that a corpus names as a rules file checks the rule data the corpus passes it.
Corpus findings stand outside the conformance and honesty families, in a section of the output labelled as the corpus's own and tallied on a summary line of their own, so the two families keep their meaning, the guardrail that checks never judge content quality or workflow keeps binding the Protocol's own validators, and no corpus finding adds to, suppresses or changes a Protocol finding or the exit reason it sets.
A corpus finding carries severity error or warning. When the operator names --rules, an error corpus finding makes sdp validate exit nonzero and a warning stays informative; without --rules no corpus rule runs and only the Protocol's validators set the exit code.
A corpus finding moves no readiness floor and reaches no other surface: not the report sdp q hands a body, not the reader, not the written graph, and not the Design Review or another projection.
A rules file that cannot be read or does not parse, a body that throws, or an answer that is not an object with a findings array of well-formed findings is a rule execution failure; sdp validate reports it in the corpus section and exits nonzero, so a broken rule never passes as a clean run. A failed file reports none of its findings, and the other files still run.
sdp validate --watch with --rules reads and runs every named rules file afresh in each cycle, after the Protocol's validators, and a create, change, delete or rename of a named rules file starts a cycle as a carrier edit does, wherever the file lives, under a directory discovery skips such as node_modules included.
Under --watch, each cycle after the first reads again every file a --params @PATH or KEY=@PATH after a --rules names, and an edit to such a file starts a cycle, wherever the file lives; a file that cannot be read or parsed then fails only the rules file it belongs to, for that cycle, while the first cycle's read refuses the command as paramsFlag states.
Address resolution (recipe 25) and dependency cycles (recipe 26) answer with findings beside the rest of their answers, as the architecture walk (recipe 42), external registers (recipe 50) and entry citations (recipe 51) do, so a corpus names any of those shipped files as a rules file, or calls it through recipes from a rules file of its own.
Given a probe corpus in which {corpus: "two Specs depend on each other through dependsOn"}
Given the caller passes the addresses {addresses: "none"}
When the shipped {recipe: "dependency cycles"} file runs {invocation: "as a rules file named by sdp validate --rules"}
Then the command exits {exitCode: 1}
Then the answer carries {findings: 1} findings with the rule ids {ruleIds: "dependency-cycle"}
Given
a probe corpus in which {corpus: "two Specs depend on each other through dependsOn"}
the caller passes the addresses {addresses: "none"}
When
the shipped {recipe: "dependency cycles"} file runs {invocation: "as a rules file named by sdp validate --rules"}
Then
the command exits {exitCode: 1}
the answer carries {findings: 1} findings with the rule ids {ruleIds: "dependency-cycle"}
Given a probe corpus in which {corpus: "one Spec depends on another"}
Given the caller passes the addresses {addresses: "spec:probe.one#design.absent"}
When the shipped {recipe: "address resolution"} file runs {invocation: "as a rules file named by sdp validate --rules"}
Then the command exits {exitCode: 1}
Then the answer carries {findings: 1} findings with the rule ids {ruleIds: "unresolved-address"}
Given
a probe corpus in which {corpus: "one Spec depends on another"}
the caller passes the addresses {addresses: "spec:probe.one#design.absent"}
When
the shipped {recipe: "address resolution"} file runs {invocation: "as a rules file named by sdp validate --rules"}
Then
the command exits {exitCode: 1}
the answer carries {findings: 1} findings with the rule ids {ruleIds: "unresolved-address"}
Given a probe corpus the Protocol's validators find clean
Given a first rules file that {first: "empties the graph it receives"}
Given a second rules file that returns one warning when the graph it receives holds no node
When the probe corpus is validated with the rules files named by --rules in that order
Then the command exits {exitCode: 0}
Then the Protocol summary line reads {protocolSummary: "validate: 0 errors · 0 warnings (conformance + honesty over the one graph)"}
Then the corpus summary line reads {corpusSummary: "corpus rules: 0 errors · 0 warnings · 0 of 2 files failed (the corpus's own rules)"}
Given
a probe corpus the Protocol's validators find clean
a first rules file that {first: "empties the graph it receives"}
a second rules file that returns one warning when the graph it receives holds no node
When
the probe corpus is validated with the rules files named by --rules in that order
Then
the command exits {exitCode: 0}
the Protocol summary line reads {protocolSummary: "validate: 0 errors · 0 warnings (conformance + honesty over the one graph)"}
the corpus summary line reads {corpusSummary: "corpus rules: 0 errors · 0 warnings · 0 of 2 files failed (the corpus's own rules)"}
Given a probe corpus the Protocol's validators find clean
Given a first rules file that {first: "returns one error finding"}
When the probe corpus is validated with the rules files named by --rules in that order
Then the command exits {exitCode: 1}
Then the Protocol summary line reads {protocolSummary: "validate: 0 errors · 0 warnings (conformance + honesty over the one graph)"}
Then the corpus summary line reads {corpusSummary: "corpus rules: 1 errors · 0 warnings · 0 of 1 files failed (the corpus's own rules)"}
Given
a probe corpus the Protocol's validators find clean
a first rules file that {first: "returns one error finding"}
When
the probe corpus is validated with the rules files named by --rules in that order
Then
the command exits {exitCode: 1}
the Protocol summary line reads {protocolSummary: "validate: 0 errors · 0 warnings (conformance + honesty over the one graph)"}
the corpus summary line reads {corpusSummary: "corpus rules: 1 errors · 0 warnings · 0 of 1 files failed (the corpus's own rules)"}
Given a probe corpus the Protocol's validators find clean
Given a first rules file that {first: "returns a finding with no subject"}
When the probe corpus is validated with the rules files named by --rules in that order
Then the command exits {exitCode: 1}
Then the Protocol summary line reads {protocolSummary: "validate: 0 errors · 0 warnings (conformance + honesty over the one graph)"}
Then the corpus summary line reads {corpusSummary: "corpus rules: 0 errors · 0 warnings · 1 of 1 files failed (the corpus's own rules)"}
Given
a probe corpus the Protocol's validators find clean
a first rules file that {first: "returns a finding with no subject"}
When
the probe corpus is validated with the rules files named by --rules in that order
Then
the command exits {exitCode: 1}
the Protocol summary line reads {protocolSummary: "validate: 0 errors · 0 warnings (conformance + honesty over the one graph)"}
the corpus summary line reads {corpusSummary: "corpus rules: 0 errors · 0 warnings · 1 of 1 files failed (the corpus's own rules)"}
Given a probe corpus the Protocol's validators find clean
Given a first rules file that {first: "reads a parameter file that gains a key after the first cycle under --watch"}
Given a second rules file that returns one warning when the graph it receives holds no node
When the probe corpus is validated with the rules files named by --rules in that order
Then the second cycle's corpus summary line reads {corpusSummary: "corpus rules: 0 errors · 2 warnings · 0 of 2 files failed (the corpus's own rules)"}
Given
a probe corpus the Protocol's validators find clean
a first rules file that {first: "reads a parameter file that gains a key after the first cycle under --watch"}
a second rules file that returns one warning when the graph it receives holds no node
When
the probe corpus is validated with the rules files named by --rules in that order
Then
the second cycle's corpus summary line reads {corpusSummary: "corpus rules: 0 errors · 2 warnings · 0 of 2 files failed (the corpus's own rules)"}
Given a probe corpus the Protocol's validators find clean
Given a first rules file that {first: "is rewritten to return one error finding after the first cycle under --watch"}
Given a second rules file that returns one warning when the graph it receives holds no node
When the probe corpus is validated with the rules files named by --rules in that order
Then the second cycle's corpus summary line reads {corpusSummary: "corpus rules: 1 errors · 0 warnings · 0 of 2 files failed (the corpus's own rules)"}
Given
a probe corpus the Protocol's validators find clean
a first rules file that {first: "is rewritten to return one error finding after the first cycle under --watch"}
a second rules file that returns one warning when the graph it receives holds no node
When
the probe corpus is validated with the rules files named by --rules in that order
Then
the second cycle's corpus summary line reads {corpusSummary: "corpus rules: 1 errors · 0 warnings · 0 of 2 files failed (the corpus's own rules)"}
Given a probe corpus the Protocol's validators find clean
Given a first rules file that {first: "reads a parameter file that stops being JSON after the first cycle under --watch"}
Given a second rules file that returns one warning when the graph it receives holds no node
When the probe corpus is validated with the rules files named by --rules in that order
Then the second cycle's corpus summary line reads {corpusSummary: "corpus rules: 0 errors · 0 warnings · 1 of 2 files failed (the corpus's own rules)"}
Then the watcher is still running after the second cycle: {running: true}
Given
a probe corpus the Protocol's validators find clean
a first rules file that {first: "reads a parameter file that stops being JSON after the first cycle under --watch"}
a second rules file that returns one warning when the graph it receives holds no node
When
the probe corpus is validated with the rules files named by --rules in that order
Then
the second cycle's corpus summary line reads {corpusSummary: "corpus rules: 0 errors · 0 warnings · 1 of 2 files failed (the corpus's own rules)"}
the watcher is still running after the second cycle: {running: true}
Given a probe corpus the Protocol's validators find clean
Given a first rules file that {first: "returns one warning finding"}
When the probe corpus is validated with the rules files named by --rules in that order
Then the command exits {exitCode: 0}
Then the Protocol summary line reads {protocolSummary: "validate: 0 errors · 0 warnings (conformance + honesty over the one graph)"}
Then the corpus summary line reads {corpusSummary: "corpus rules: 0 errors · 1 warnings · 0 of 1 files failed (the corpus's own rules)"}
Given
a probe corpus the Protocol's validators find clean
a first rules file that {first: "returns one warning finding"}
When
the probe corpus is validated with the rules files named by --rules in that order
Then
the command exits {exitCode: 0}
the Protocol summary line reads {protocolSummary: "validate: 0 errors · 0 warnings (conformance + honesty over the one graph)"}
the corpus summary line reads {corpusSummary: "corpus rules: 0 errors · 1 warnings · 0 of 1 files failed (the corpus's own rules)"}
Given a probe corpus the Protocol's validators find clean
Given a first rules file that {first:"returns one error finding"|"returns one warning finding"|"returns a finding with no subject"|"empties the graph it receives"|"is rewritten to return one error finding after the first cycle under --watch"|"reads a parameter file that gains a key after the first cycle under --watch"|"reads a parameter file that stops being JSON after the first cycle under --watch"}
Given a second rules file that returns one warning when the graph it receives holds no node
When the probe corpus is validated with the rules files named by --rules in that order
Then the command exits {exitCode:number}
Then the Protocol summary line reads {protocolSummary:string}
Then the corpus summary line reads {corpusSummary:string}
Then the second cycle's corpus summary line reads {corpusSummary:string}
Then the watcher is still running after the second cycle: {running:boolean}
sdp validate [root] [--exclude PATH]... [--check-clean | --watch] [--rules PATH [--params JSON | --params @PATH | --params KEY=@PATH]...]...; --rules and --params are options of validate alone, a --params before the first --rules is refused, one file named twice is refused, including through a symlink, and each PATH resolves from the working directory, as a --params @PATH file does. Diagnostics retain the path the operator named.
--params on validate takes the three forms of sdp q --params with the same refusals, before the graph derives; each --params belongs to the nearest --rules before it in the argument list, whatever other options stand between them; one file's parameters merge as sdp q merges them, a key given twice for one file is refused, two files may each take the same key, and a file with no --params after it receives {}.
a rules file is UTF-8 text holding one plain JavaScript async function body, the form sdp q evaluates, with the bindings g, graph, report, params and recipes; the runner reads the text and never imports it as a module, so no file extension is required and a catalog recipe file under dist/recipes/ is a lawful rules file.
{ findings: [] }: the body returns an object whose findings is an array, possibly empty; the runner reads findings and nothing else, so the answer's other keys stay the body's own data and are never printed.
{ validatorId, subjectId, severity, message, relatedId?, path?, file?, line? }, where validatorId is the rule id, one token matching ^[a-z][a-z0-9-]*$, so it never reads as a Protocol validator id; subjectId and message are non-empty strings; severity is "error" or "warning"; relatedId and path are strings; file is a non-empty root-relative POSIX path, with absolute paths, backslashes and traversal above the root refused, and line a positive integer that requires file; the runner ignores a finding's other keys.
{ rulesFile, validatorId, subjectId, severity, message, relatedId?, path?, file?, line? } is the corpus branch of the finding currency, where rulesFile is the path as the operator named it; it carries no family, and the Protocol's findings keep their shape.
the report a run with --rules builds keeps the Protocol's findings unchanged in findings and adds corpusFindings, the corpus findings of each file that did not fail, in the order the files are named and then in the order returned, and corpusFailures, one { rulesFile, reason } for each failed file in the order named, never a finding; the report a rules file receives, like the one sdp q hands a body, carries neither.
on standard error, after every Protocol finding, each rules file in the order named prints the line corpus rules <path> and then its findings in the order returned, each in the one composition of location, severity in brackets, rule id and message; a failed file prints corpus rules <path> failed: <reason> in place of its findings.
corpus rules: <errors> errors · <warnings> warnings · <failed> of <files> files failed (the corpus's own rules), written to standard output directly after the Protocol's summary line, which stays as spec:validation.diagnostic-rendering#design.summaryLine pins it; without --rules no such line prints; when the graph does not derive, no rules file runs and no Protocol summary line prints, and the corpus line, the last line on standard output, reads corpus rules: not run, the graph did not derive.
with --rules, sdp validate exits 1 when a Protocol finding is an error, a corpus finding is an error, a rules file fails or the graph does not derive, and 0 otherwise; the two summary lines say which.
<reason> is cannot be read (<cause>), does not parse at line <L>, column <C>: <cause>, threw: <message on one line>, returned no findings array, followed by ; diagnostics: <the answer's diagnostics as JSON> when the answer carries diagnostics or by ; unknownParams: <as JSON>; accepts: <as JSON> when it carries unknownParams, finding <N> has no lawful <field>, with N counted from 1, or, under --watch after the first cycle, its parameters cannot be read (<cause>) when a parameter file named after its --rules cannot be read or parsed.
leaves non-watch corpus-rule points and incomplete points unspecified
not recorded
passed
0.36 ms
leaves address points outside the oracle's bound probes unspecified
not recorded
passed
0.17 ms
executes the bound example against a fresh world
A body calls a shipped recipe and returns its answer unchanged (spec:consumers.agent-surface.evaluation-sink.recipe-call)
passed
21.85 ms
executes the bound example against a fresh world
A call to a recipe the catalog does not hold fails the body (spec:consumers.agent-surface.evaluation-sink.unknown-recipe)
passed
3.48 ms
executes the bound example against a fresh world
A script holding a graph runs a shipped recipe through the exported evaluator (spec:consumers.agent-surface.evaluation-sink.exported-evaluator)
passed
3.89 ms
executes the bound example against a fresh world
A dependency chain with no cycle yields no finding (spec:consumers.agent-surface.address-and-cycle-recipes.chain-reports-nothing)
passed
3.1 ms
executes the bound example against a fresh world
The shipped dependency-cycles file fails a rules run on a cycle (spec:consumers.agent-surface.address-and-cycle-recipes.cycle-fails-a-rules-run)
passed
5.52 ms
executes the bound example against a fresh world
The shipped address-resolution file fails a rules run on an address that names no entry (spec:consumers.agent-surface.address-and-cycle-recipes.unresolved-address-fails-a-rules-run)
passed
3.86 ms
executes the bound example against a fresh world
Rewriting a rules file under node_modules starts a cycle that runs the new body (spec:validation.corpus-rules.rules-edit-starts-a-cycle)
passed
16.19 ms
executes the bound example against a fresh world
Editing a parameter file starts a cycle that reads the new parameters (spec:validation.corpus-rules.params-edit-starts-a-cycle)
passed
46.21 ms
executes the bound example against a fresh world
A parameter file that stops being JSON fails only its own rules file, and the watcher runs on (spec:validation.corpus-rules.unreadable-params-fail-one-file)
spec:validation.corpus-rules.copies-contain-changes · A rules file that empties its graph leaves the next file's graph whole · declared · example enabled · specs/validation/corpus-rules.copies-contain-changes.sdp.md
External run evidence from test/self-hosting-corpus-checks.test.ts
A rules file that empties its graph leaves the next file's graph whole (spec:validation.corpus-rules.copies-contain-changes)
passed
21.24 ms
executes the bound example against a fresh world
An error from a corpus rule fails validation and leaves the Protocol's line alone (spec:validation.corpus-rules.error-finding-fails)
passed
4.29 ms
executes the bound example against a fresh world
A finding with no subject fails its rules file (spec:validation.corpus-rules.malformed-finding-fails)
passed
3.72 ms
executes the bound example against a fresh world
A warning from a corpus rule informs and passes (spec:validation.corpus-rules.warning-finding-informs)
passed
3.36 ms
executes the bound example against a fresh world
A domain member that uses an infrastructure member breaks a forbidden pair (spec:validation.architecture-constraints.forbidden-layer-pair)
passed
16.29 ms
executes the bound example against a fresh world
The walk named as a rules file fails validation on an isolation breach (spec:validation.architecture-constraints.isolated-context-as-rule)
passed
3.85 ms
executes the bound example against a fresh world
A component with no layer leaves its edge unclassified (spec:validation.architecture-constraints.unstated-layer-unclassified)
passed
3.28 ms
executes the bound example against a fresh world
A realized component that differs from its design gives one row per field (spec:model.planned-architecture.differing-layer-and-uses)
passed
10.85 ms
executes the bound example against a fresh world
A realized component that matches its design gives no row (spec:model.planned-architecture.matching-design)
passed
5.28 ms
executes the bound example against a fresh world
A component design no anchor satisfies is listed as unrealized (spec:model.planned-architecture.unrealized-design)
passed
4.57 ms
spec:validation.corpus-rules.error-finding-fails · An error from a corpus rule fails validation and leaves the Protocol's line alone · declared · example enabled · specs/validation/corpus-rules.error-finding-fails.sdp.md
spec:validation.corpus-rules.params-edit-starts-a-cycle · Editing a parameter file starts a cycle that reads the new parameters · declared · example enabled · specs/validation/corpus-rules.params-edit-starts-a-cycle.sdp.md
spec:validation.corpus-rules.rules-edit-starts-a-cycle · Rewriting a rules file under node_modules starts a cycle that runs the new body · declared · example enabled · specs/validation/corpus-rules.rules-edit-starts-a-cycle.sdp.md
spec:validation.corpus-rules.unreadable-params-fail-one-file · A parameter file that stops being JSON fails only its own rules file, and the watcher runs on · declared · example enabled · specs/validation/corpus-rules.unreadable-params-fail-one-file.sdp.md
first · "returns one error finding" | "returns one warning finding" | "returns a finding with no subject" | "empties the graph it receives" | "is rewritten to return one error finding after the first cycle under --watch" | "reads a parameter file that gains a key after the first cycle under --watch" | "reads a parameter file that stops being JSON after the first cycle under --watch" · declared by a first rules file that {first}
a probe corpus the Protocol's validators find clean
a first rules file that {first:"returns one error finding"|"returns one warning finding"|"returns a finding with no subject"|"empties the graph it receives"|"is rewritten to return one error finding after the first cycle under --watch"|"reads a parameter file that gains a key after the first cycle under --watch"|"reads a parameter file that stops being JSON after the first cycle under --watch"}
a second rules file that returns one warning when the graph it receives holds no node
When
the probe corpus is validated with the rules files named by --rules in that order
Then
the command exits {exitCode:number}
the Protocol summary line reads {protocolSummary:string}
the corpus summary line reads {corpusSummary:string}
the second cycle's corpus summary line reads {corpusSummary:string}
the watcher is still running after the second cycle: {running:boolean}
Composing needs the script.
Design view
Requirement drawing
Requirement drawing for spec:validation.corpus-rules
E6: refines (7), verifies (9) · declared
The diagram as text
spec:validation.corpus-rules: Corpus-authored rules run on the one validation path · declared Spec
spec:validation.architecture-constraints: Declared architecture rules are checked against anchored structure · declared Spec
spec:validation.corpus-rules.copies-contain-changes: A rules file that empties its graph leaves the next file's graph whole · declared Spec
spec:validation.corpus-rules.error-finding-fails: An error from a corpus rule fails validation and leaves the Protocol's line alone · declared Spec
spec:validation.corpus-rules.malformed-finding-fails: A finding with no subject fails its rules file · declared Spec
spec:validation.corpus-rules.params-edit-starts-a-cycle: Editing a parameter file starts a cycle that reads the new parameters · declared Spec
spec:validation.corpus-rules.rules-edit-starts-a-cycle: Rewriting a rules file under node_modules starts a cycle that runs the new body · declared Spec
spec:validation.corpus-rules.unreadable-params-fail-one-file: A parameter file that stops being JSON fails only its own rules file, and the watcher runs on · declared Spec
spec:validation.corpus-rules.warning-finding-informs: A warning from a corpus rule informs and passes · declared Spec
spec:validation.external-registers: A corpus checks the register tokens its prose cites · declared Spec
spec:consumers.agent-surface.address-and-cycle-recipes.cycle-fails-a-rules-run: The shipped dependency-cycles file fails a rules run on a cycle · declared Spec
spec:consumers.agent-surface.address-and-cycle-recipes.unresolved-address-fails-a-rules-run: The shipped address-resolution file fails a rules run on an address that names no entry · declared Spec
spec:validation.architecture-constraints.forbidden-layer-pair: A domain member that uses an infrastructure member breaks a forbidden pair · declared Spec
spec:validation.architecture-constraints.isolated-context-as-rule: The walk named as a rules file fails validation on an isolation breach · declared Spec
spec:validation.architecture-constraints.unstated-layer-unclassified: A component with no layer leaves its edge unclassified · declared Spec
spec:validation.external-registers.uncited-on-request: A held token no Spec cites fails a rules run only when the caller asks · declared Spec
spec:validation.external-registers.unknown-and-retired: A cited token the register lacks or retires fails a rules run · declared Spec
spec:consumers.agent-surface: Agents script a visible typed graph · declared Spec
impl:protocol.architecture-walk-recipe: asserts realization of the shipped architecture walk recipe · anchored code · test/architecture-recipes.test.ts:10
impl:protocol.corpus-rule-runner: runs selected corpus rules and separates their failures · anchored code · src/cli/corpus-rules.ts:65
impl:protocol.corpus-rules: runs copied rule bodies after Protocol validation and composes the separate corpus report, output and exit · anchored code · src/cli/validate-view-command.ts:79
impl:protocol.external-registers-recipe: asserts realization of the shipped external-registers recipe · anchored code · test/external-registers.test.ts:9
impl:protocol.validate-watch: watches carrier directories and coalesces events into a pending validation rerun · anchored code · src/cli/validate-watch.ts:591
spec:validation.architecture-constraints refines spec:validation.corpus-rules · declared — the architecture walk is a corpus-selected rule over anchored structure
spec:validation.corpus-rules refines spec:consumers.agent-surface · declared — a corpus scripts the graph through the evaluation sink to report its own findings
Architectural significance is annotated on the anchor of the unit that realizes it. A code anchor may carry role, the architectural pattern the unit plays; a component: anchor may additionally carry layer, one of edge, application, domain, adapter, or infrastructure, and context, its bounded context. The component: anchor is anchored architecture: it is the declared component, and there is no separate architecture file, because the anchor sits where the component is realized. It is not the original design's declared Component that could exist before code; an unrealized component lives in Specs and never as an invented CodeNode. A role is a free, corpus-owned vocabulary whose taxonomy the census renders with counts from the graph; service, decider, projection, read-model, codec, contract, barrel, and utility are the lineage set, not a closed list. layer is a closed set, and a value outside it is an envelope error; layer or context on a non-component anchor is an envelope error. All three attributes are optional, and omission is lawful.
impl:protocol.corpus-rules · runs copied rule bodies after Protocol validation and composes the separate corpus report, output and exit · src/cli/validate-view-command.ts:79
Shown as text: this drawing exceeds the height budget of 2000 pixels after folding.
The diagram as text
spec:consumers.agent-surface: Agents script a visible typed graph
spec:consumers.agent-surface.address-and-cycle-recipes.cycle-fails-a-rules-run: The shipped dependency-cycles file fails a rules run on a cycle
spec:consumers.agent-surface.address-and-cycle-recipes.unresolved-address-fails-a-rules-run: The shipped address-resolution file fails a rules run on an address that names no entry
spec:consumers.agent-surface.evaluation-sink: The evaluation sink runs one body and prints its return
spec:consumers.agent-surface.recipe-parameters: Recipes take parameters as data and ship as runnable files
spec:consumers.validate-watch: Validation re-runs while an author edits carriers
spec:decisions.architectural-annotation: Architectural significance is annotated where it is realized
spec:validation.architecture-constraints: Declared architecture rules are checked against anchored structure
spec:validation.corpus-rules: Corpus-authored rules run on the one validation path
spec:validation.corpus-rules.copies-contain-changes: A rules file that empties its graph leaves the next file's graph whole
spec:validation.corpus-rules.error-finding-fails: An error from a corpus rule fails validation and leaves the Protocol's line alone
spec:validation.corpus-rules.malformed-finding-fails: A finding with no subject fails its rules file
spec:validation.corpus-rules.params-edit-starts-a-cycle: Editing a parameter file starts a cycle that reads the new parameters
spec:validation.corpus-rules.rules-edit-starts-a-cycle: Rewriting a rules file under node_modules starts a cycle that runs the new body
spec:validation.corpus-rules.unreadable-params-fail-one-file: A parameter file that stops being JSON fails only its own rules file, and the watcher runs on
spec:validation.corpus-rules.warning-finding-informs: A warning from a corpus rule informs and passes
spec:validation.diagnostic-rendering: One diagnostic currency, its location composed from structured fields
spec:validation.external-registers: A corpus checks the register tokens its prose cites
spec:validation.two-check-families: Validation separates well-formedness from non-pretending
spec:validation.corpus-rules dependsOn spec:consumers.agent-surface.evaluation-sink · declared — a rules file holds the body the sink evaluates, with the sink's bindings and trust
spec:validation.corpus-rules dependsOn spec:consumers.agent-surface.recipe-parameters · declared — validate takes `--params` in the sink's grammar
spec:validation.corpus-rules dependsOn spec:consumers.validate-watch · declared — the watch loop reruns the named rules in each cycle
spec:validation.corpus-rules dependsOn spec:validation.diagnostic-rendering · declared — corpus findings use the shared diagnostic currency
spec:validation.corpus-rules refines spec:consumers.agent-surface · declared — a corpus scripts the graph through the evaluation sink to report its own findings
spec:validation.external-registers dependsOn spec:validation.corpus-rules · declared — the recipe answers with findings and runs as a rules file
spec:validation.architecture-constraints refines spec:validation.corpus-rules · declared — the architecture walk is a corpus-selected rule over anchored structure
impl:protocol.corpus-rule-runner · runs selected corpus rules and separates their failures · src/cli/corpus-rules.ts:65 · role service · component component:protocol.cli · layer edge · context protocol
impl:protocol.corpus-rules · runs copied rule bodies after Protocol validation and composes the separate corpus report, output and exit · src/cli/validate-view-command.ts:79 · role service · component component:protocol.cli · layer edge · context protocol
impl:protocol.validate-watch · watches carrier directories and coalesces events into a pending validation rerun · src/cli/validate-watch.ts:591 · role service · component component:protocol.cli · layer edge · context protocol
spec:validation.corpus-rules.copies-contain-changes · A rules file that empties its graph leaves the next file's graph whole · declared · specs/validation/corpus-rules.copies-contain-changes.sdp.md · example enabled
spec:validation.corpus-rules.error-finding-fails · An error from a corpus rule fails validation and leaves the Protocol's line alone · declared · specs/validation/corpus-rules.error-finding-fails.sdp.md · example enabled
spec:validation.corpus-rules.params-edit-starts-a-cycle · Editing a parameter file starts a cycle that reads the new parameters · declared · specs/validation/corpus-rules.params-edit-starts-a-cycle.sdp.md · example enabled
spec:validation.corpus-rules.rules-edit-starts-a-cycle · Rewriting a rules file under node_modules starts a cycle that runs the new body · declared · specs/validation/corpus-rules.rules-edit-starts-a-cycle.sdp.md · example enabled
spec:validation.corpus-rules.unreadable-params-fail-one-file · A parameter file that stops being JSON fails only its own rules file, and the watcher runs on · declared · specs/validation/corpus-rules.unreadable-params-fail-one-file.sdp.md · example enabled