## [2026-05-29T22:21:12.791Z]
The graph validation checks were extracted from a single oversized validator module into domain-grouped modules (architecture, aspects, mapping and coverage, relations and flows) plus a small shared helper, leaving the orchestrator that runs every check and assembles the result in place to compose them. The move was verbatim: no change to which rules run, their order, their diagnostic messages, or their verdicts. The motivation is that one very large source file degrades reviewer accuracy and risks context-window truncation that can spuriously reject unchanged code; keeping each unit small enough to be reviewed in full removes that failure mode.
## [2026-05-30T18:08:09.451Z]
The vocabulary for how a rule is verified was reduced from three kinds to two. Previously a rule was checked by one of: a human-language reviewer, a single-file programmatic check, or a graph-aware programmatic check. The two programmatic kinds are now a single "deterministic" kind, leaving just deterministic-or-reviewer.

The motivation: the three-way split was drawn on the wrong axis. It described HOW a programmatic check reached its context (one file at a time, versus the whole graph), but the distinction that actually matters to a rule author and to cost is whether verification is local-and-free or requires the paid, non-deterministic reviewer. The single-file kind was already a strict subset of the graph-aware kind — every input the former could see, the latter also provides — so maintaining two of them forced rule authors to make a false choice up front and forced the engine to carry two parallel handling paths for one concept. Collapsing them removes that false choice and the duplicated handling, and routes every programmatic check through the one graph-aware path.

The language a programmatic check infers for a source file is determined solely from that file's extension, so a check no longer declares which languages it targets. A rule's verification kind being deterministic is also no longer carried as a separate synthetic identity signal — a deterministic rule's identity is fully covered by the files it already tracks — which keeps re-verification of such rules free.
## [2026-05-30T18:40:33.542Z]
A reference path embedded in a validation message was written without normalizing its separators, which on some platforms would emit a non-POSIX path at an output boundary that must always use forward slashes. The path is now normalized before it is placed in any message; the filesystem path used to stat the file is left platform-native, since only the message is an output boundary.
## [2026-05-31T16:03:32.849Z]
Replaced the hand-inlined path-separator normalization with calls to a single shared helper. The same small idiom — convert backslash separators to forward slashes, and in most places also strip a trailing slash — had been copied across many modules, so the normalization rule lived in dozens of places at once and any change to it risked drifting them out of step. Consolidating it behind one well-named helper means the rule lives in exactly one spot and each call site reads by intent instead of by a repeated regex. Behavior is unchanged: the helper bodies are byte-for-byte equivalent to the expressions they replace, and the full test suite passes identically.
## [2026-06-03T07:05:08.637Z]
Aspect-contract validation now recognises three reviewer kinds inferred from which rule source is present: content.md means LLM, check.mjs means deterministic, and neither-file-but-implies means an aggregating aspect that is a named bundle with no own reviewer. The kind is inferred from file presence so authors do not have to declare it; an explicit reviewer.type, if given, must agree with what the files imply, and a mismatch is a validation error.
## [2026-06-08T19:22:36.423Z]
An aspect's effective enforcement level is the strongest level contributed by any source that reaches a node, and that set of sources must include the aspect's own declared default — not only the levels named at individual attach sites. The downgrade guard previously compared an attach site's level against the other attach sites alone, omitting the aspect default, so a lone attach site that named a weaker level than the aspect's default escaped detection and silently weakened enforcement. The guard now folds the aspect default into the baseline it compares against, so any attempt to attach an aspect at a level below what it already guarantees is rejected.

Separately, a conditional applicability predicate may key off a consumed port, and such a predicate must reference a port that genuinely exists somewhere in the graph; a predicate naming a phantom port is a graph error. That check previously only fired for the paired relation-and-port shape and missed the bare port-name shape. Both shapes are now validated against the full set of declared ports so an unknown port is reported regardless of how the predicate spells it.
## [2026-06-13T10:52:16.035Z]
A reviewer-configuration error called a project with only mechanical checks an 'AST-only' project. The system's vocabulary for mechanical check.mjs aspects is 'deterministic', never 'AST', so the wording was aligned to avoid an undefined term an agent has to guess at.
