## [2026-05-29T22:21:12.942Z]
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-30T02:29:44.193Z]
The per-node size guard changed from limiting the raw count of mapped source files to limiting the total number of characters in a node's reviewer context — its mapped source files plus the reference files of its effective aspects — and from a non-blocking warning to a blocking error. The motivation is that the reviewer concatenates all of a node's files into each aspect prompt, so an oversized node risks exceeding the model's context window, which deterministically rejects unchanged code near the truncation point; a file-count limit missed this because one very large file could stay under the count while still blowing the prompt. Binary files do not count toward the budget, and a node mapping a single unsplittable generated or binary artifact (a lockfile, an append-only changelog, an image) may carry a documented per-node exemption with a required justification.
## [2026-05-30T02:50:36.801Z]
Documented inline that the repository-relative paths emitted in the strict backward-coverage diagnostics are already separator-normalized upstream by the repository scanner, so they are safe to write into agent-facing output on every platform without re-normalizing. This records why those output sites intentionally omit a local path-normalization step.
## [2026-05-30T02:56:29.914Z]
Hardened the strict backward-coverage scan to re-apply the canonical path normalization to every repository-relative path before it is written into an agent-facing diagnostic, so output is provably separator-normalized on every platform rather than depending on the upstream scanner's contract. The normalization is idempotent, so file-owner lookups are unchanged.
## [2026-05-30T04:04:45.986Z]
Hardened the per-node character-budget check after review: a source file larger than the content scanner's in-memory limit is now counted by its on-disk byte size rather than scored as zero, so the very largest files cannot slip under the budget; the effective-aspect computation is guarded so an aspect-implies cycle (which is reported separately) no longer aborts the whole validation run with a raw error; and the check now reuses the caller's shared file-content cache instead of re-reading files from a cold cache.
## [2026-05-31T16:03:33.023Z]
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-05-31T16:28:48.880Z]
Two related correctness improvements to the validation layer. First, the set of structural error codes — the codes that always block the check regardless of drift — had been hard-coded in two places, once for the summary tally and once for the rendered grouping, and the two had silently diverged so the count could disagree with what was shown to the agent. They now share a single definition, so the tally and the grouping can never drift apart again. Second, a new validation rejects a node mapping that resolves outside the repository root — an absolute path, or one that climbs above the root with a parent-directory segment. The mapping-path normalizer only converts separators and strips a leading current-directory prefix and trailing slashes; it does not collapse parent-directory segments, so without this guard a mapping could claim files outside the project and bypass coverage and aspect enforcement.
## [2026-06-08T14:21:59.377Z]
The per-node character budget (oversized-node) now applies only to nodes an LLM reviewer actually reads: those carrying at least one effective non-draft LLM aspect. The budget protects the LLM reviewer single-prompt context window; deterministic checks read files programmatically and aspect-less nodes are never reviewed, so neither has a window to overflow and bounding them was a false constraint. Resolved from effective aspects plus effective statuses. Consequence: the gate is cascade-sensitive, since an LLM aspect arriving via a type default, flow, port, or implies can newly bound a node that was previously unbounded.
## [2026-06-08T15:11:09.489Z]
Mapping validation is glob-aware. Backward coverage for strict types resolves a file owner by pattern match against mapping entries. Mapping-path existence treats a glob entry as satisfied when it currently matches at least one file on disk, and reports it as missing only when it matches nothing — distinct from a plain path, which is missing when that exact file is absent. This supports scoping a node to a subset of a directory by naming pattern while still catching stale patterns that no longer match anything.
## [2026-06-08T16:40:57.446Z]
Mapping-overlap detection now also resolves globs to concrete files and flags any file owned by two non-hierarchical nodes, enforcing one-file-one-node even when a glob in one node resolves to a file claimed by another. A literal string comparison of mapping entries cannot see such an overlap. The file-level pass runs only when some node uses a glob, so glob-free graphs are unaffected and their plain overlaps stay on the existing string comparison; an ancestor-descendant pair is still allowed because the deeper node wins.
## [2026-06-12T13:31:38.603Z]
Replaced the locally-defined BINARY_EXTENSIONS set with an import from utils/binary-extensions.ts, the canonical single source of truth. Two copies of this set existed (this file and structure/runner.ts) — they happened to be byte-for-byte identical today, but divergence was possible because neither file referenced the other. A shared definition enforced at the import boundary makes future extension safe: adding a new extension in one place propagates to all three consumers (the node-size budget checker, the deterministic structure runner, and the LLM subject-file filter in pairs.ts).
