## [2026-05-15T17:44:12.755Z]
Phase 2: split from cli/ast — loader hook, parser, check runner, suppress. Type: ast-adapter.
## [2026-05-15T19:28:49.972Z]
Move IssueMessage type from formatters/message-builder to model/validation — engine→formatter import violation fix for boundaries enforcement
## [2026-05-26T09:43:17.807Z]
Add find-comments.ts reading comment node types from language registry per ctx.language. Two discriminated forms: file ({ ast, language }) or subtree ({ rootNode, language }). Both present throws AST_FINDCOMMENTS_AMBIGUOUS_TARGET; unknown language throws AST_FINDCOMMENTS_UNKNOWN_LANGUAGE. Errors propagate through runner's AST_CHECK_THROWN path. Task 28 reassigns to cli/ast/report alongside walk/file-path/index.
## [2026-05-26T09:50:11.164Z]
Add AST_CHECK_FILE_NOT_IN_CONTEXT runtime guard. check.mjs cannot synthesize violations for files outside ctx.files (protects suppress mechanism — markers cannot reach unknown files). Throws via existing AstRunnerError; cli/approve.ts catch (added in Task 3) flows it through errorSource: 'astRuntime'.
## [2026-05-26T10:52:26.554Z]
Remove find-comments.ts from mapping — this file was reassigned to cli/ast/report as part of the public API consolidation. The runtime node now only contains: loader hook, parser, check runner, and suppress marker extractor.
## [2026-05-28T10:07:11.726Z]
Added optional ParseCache parameter to RunAstAspectParams and runAstAspect. When provided, the cache is checked before reading and parsing each file — if the file is already in the cache, the cached content and AST are reused directly. After parsing, the result is stored in the cache. This avoids redundant file reads and re-parses when the same source files are visited by multiple AST aspects in a single dry-run or approve invocation. The ParseCache type is exported for use by CLI-layer callers.
## [2026-05-29T06:40:35.395Z]
Extract the ParseCache type alias from the AST runner into a small neutral module so the upcoming structure runner can share the same per-invocation cache shape. Runner re-exports the type for callers that import it from the AST entry.
## [2026-05-30T07:12:18.331Z]
The four check.mjs export-shape guards — named export present, not a default-only export, is a function, takes exactly one argument — now come from one shared validator so the AST and structure runtimes cannot drift apart in what they accept or in the wording of the error they raise. Error codes are unchanged; the only text change is a trailing aspect-id suffix on the default-export message.
## [2026-05-30T14:09:01.061Z]
The per-aspect language declaration was removed from the system. An aspect that ships a parsed-tree check used to carry a `language:` list naming the languages it targeted, and the system validated that list with four dedicated checks. Nothing in the runtime ever read it: the engine already determines each source file's language from its file extension through one shared registry, then loads the matching grammar. The declaration was therefore inert metadata that could silently disagree with what the engine actually parsed — an authoritative-looking field that governed nothing.

This change deletes the field, the validators that policed its shape, and the documentation and tests that described it, and promotes the extension-to-grammar registry to the single authority for matching a file to its parser. The motivation is to remove a confusing mismatch between what an aspect claimed about languages and what the engine did, and to collapse the duplicated extension-knowledge that had drifted into more than one place.

The language a parsed-tree check sees for a given file is now derived solely from that file's extension; an unrecognized extension yields no parsed tree rather than a per-aspect error. The drift identity of a graph-aware structural check is deliberately held stable across this change so existing approvals are not invalidated by metadata that never affected behavior.
## [2026-05-31T10:45:42.357Z]
Made the parser locate its grammar binaries correctly in a published install. The grammars are bundled with the package, but two layout assumptions were wrong: the binaries were copied under a short name the parser never looks up, and the directory the parser searched was computed one level too high for the flattened published layout — so a real install found no grammar and fell back to a build-only dependency that ships only to developers, failing with an opaque module-not-found. The parser now searches the directory beside the bundled entry first, keeps the previous location as a fallback, and degrades to a clear could-not-find-grammar message when no grammar package is present, instead of leaking a raw require error. This is what makes the local-language checks usable by an adopter rather than only in this repo's own test runs.
## [2026-06-03T07:05:07.509Z]
Suppression-marker scanning now resolves comment nodes per source language instead of assuming one comment syntax. Different grammars label comments differently, so a single hard-coded node type silently missed markers in some languages, letting suppressed violations slip past or unsuppressed ones get hidden. Resolving the comment node kind from the active language makes yg-suppress detection correct across every supported grammar.
## [2026-06-08T19:22:20.137Z]
Inline suppression markers must be recognized wherever an author can legitimately place them, including inside a block comment that spans several physical lines. The marker-matching expressions previously anchored the end-of-text without multi-line semantics, so a marker sitting on any line other than the very last of a multi-line comment was silently ignored — the documented multi-line and bracket-disable placement forms did not actually take effect. Matching is now line-aware so a marker is found on whichever line it appears, keeping the parser behaviour consistent with what the suppression documentation promises authors.
## [2026-06-08T19:56:24.041Z]
A deterministic check that only inspects file text must be able to see every file in a node's mapping, including files whose extension has no parser (documentation, shell scripts, JSON, and the like). The single-file deterministic runner previously parsed every file up front and aborted the entire run on the first file it could not parse, with a message that told the author to delete exactly the file the check was meant to read. That contradicted the promise made to check authors that content-only rules may iterate non-parseable files, and it disagreed with the graph-aware runner used elsewhere, which already hands such files to the check with no parse tree attached. The runner now treats a file with no registered grammar as non-parseable: it is still delivered to the check with its text and an absent parse tree, so text and pattern rules run over it, while a genuine failure to load a grammar that should exist still fails closed. Suppression markers, which are discovered through the parse tree, simply contribute nothing for a file that has none.
## [2026-06-08T20:29:14.366Z]
Inline suppression waivers must be honored in every source language, not only those with a parser. Markers were previously discovered solely by walking a file's parse tree for comment nodes, so a file whose extension has no registered grammar yielded no waivers at all. Once content-only deterministic checks began running over such files, an author flagged in, say, a SQL or shell file had no way to record an approved exception there — the escape hatch was missing for exactly the files that needed it. Suppression collection now falls back to a language-agnostic scan of the raw file text when there is no parse tree, keying on the distinctive suppression token rather than on any particular comment delimiter, so a waiver works regardless of language. Files that do have a parser keep using their comments, which keeps the token from being mistaken for a marker when it merely appears inside a string. The collector accordingly receives the file text alongside the optional tree.
## [2026-06-08T22:08:23.047Z]
Loading a parser grammar must be safe when many checks run at once. The one-time initialization of the parsing runtime and the loading of each language grammar were previously gated by a flag and a cache that were only set AFTER the awaited work completed. When several deterministic checks ran concurrently — as they do when approval verifies multiple targets in parallel — they could all observe the "not ready yet" state in the same window, all kick off their own initialization or grammar load, and one of them could pick up a grammar object that was still only half-loaded, which the parsing library reports as an incompatible language version. The symptom was a deterministic check spuriously failing in a batch while the very same check passed when the target was processed on its own. The fix records the in-flight work as a shared promise the moment it starts, so every concurrent caller awaits the same single initialization and the same single grammar load; a load that fails is removed so a later attempt can retry rather than inheriting a cached failure. Determinism is the whole point of these checks, so a concurrency-dependent failure had to be eliminated rather than worked around by serializing approvals.
## [2026-06-13T10:37:55.841Z]
A diagnostic message shown when a deterministic check crashes told the agent to re-run a standalone approve command that no longer exists. The only verdict-writer now is the unified check-with-approve step, so the suggested next action was corrected to point there. Text-only fix to the agent-facing next-step guidance.
## [2026-06-13T11:23:06.992Z]
The inventory scan that lists active suppression markers matched marker syntax anywhere in a file's raw text, including inside string literals — so source that merely quotes or talks about the marker syntax (tests, templates) was falsely counted. A new comment-only scan walks the parsed comment nodes (the same comment extraction the marker-honoring path already uses) so the inventory counts a marker only where it would actually take effect. The marker-honoring path was already comment-aware and is unchanged; this only corrects the inventory's accuracy.
