## [2026-05-15T09:57:38.730Z]
resolveFileArg call updated: cwd arg removed, file arg now repo-root-relative
## [2026-05-15T14:17:01.037Z]
Drop deprecated .message field: build-context.ts now renders ValidationIssue via buildIssueMessage(err.messageData). R0.1 Phase 5.
## [2026-05-15T14:23:01.259Z]
Fix ENOENT handler to use buildIssueMessage: 'Run yg init first' is a remediation command requiring structured what/why/next format per what-why-next aspect.
## [2026-05-15T14:25:36.164Z]
Fix node normalization: remove extra .replace(/^\.\//,'') not in cli-command-contract; restore ENOENT message to required verbatim string per cli-command-contract (what-why-next aspect updated to exempt this standardized string).
## [2026-05-15T17:52:31.033Z]
Fix diagnostic-logging violations: add debugWrite() to catch block that exits without re-throwing.
## [2026-05-16T05:57:54.796Z]
Phase 4.7 (no-direct-fs): inject appendToDebugLog as third argument to initDebugLog; debug-log DI refactor decouples utils/debug-log from node:fs
## [2026-05-16T08:39:07.376Z]
Normalize result.file at output boundary (displayFile) before use in buildIssueMessage and stderr write — satisfies posix-paths-output aspect added via build-context flow
## [2026-05-16T17:37:13.431Z]
Replaced inline 'No .yggdrasil/ directory found' error block with the shared loadGraphOrAbort helper from formatters/cli-preamble.ts. Reason: the same string and exit-1 logic was duplicated across 12 CLI command handlers; centralization eliminates a copy-paste class and routes the missing-graph message through buildIssueMessage uniformly. Other errors continue to flow through the surrounding catch and will be migrated to buildIssueMessage in the next task.
## [2026-05-16T18:22:20.160Z]
Migrated remaining ad-hoc stderr errors to buildIssueMessage (constant-text errors wrapped inline) and routed generic catch-blocks through the new abortOnUnexpectedError helper from formatters/cli-preamble.ts. Reason: even after the loadGraphOrAbort centralization, command-specific errors and option-validation messages bypassed the what/why/next structure; this commit aligns them so the AST aspect added in the next commit can enforce the rule mechanically.
## [2026-05-28T07:49:26.246Z]
Normalize resolvedFilePath via the canonical .replace(/\/g, '/').replace(/\/+$/, '') pair before passing it to buildFileContextData. The unnormalized result.file flowed into formatFileContext output via FileContextData.filePath, exposing stdout to backslash separators on Windows-native paths. Surfaced during cascade re-approve after the cli/io/parsers node split; the issue pre-existed but the reviewer caught it on this pass.
## [2026-05-28T11:11:18.488Z]
Cascade follow-through: dependency cli/formatters added a new shared message-builder module file to its mapping. No call-site or contract changed for build-context — the new builder is consumed only by the aspect parser. Re-approve sweep keeps the build-context node aligned with the refreshed upstream metadata.
## [2026-05-29T10:05:51.028Z]
Test suite for this command was updated to reflect the redesigned yg check output format. The old format had section headers (Structural:, Cascade summary:), per-node cascade repetition, and a Result: footer. The new format uses a single-line verdict header, grouped cascade blocks, and Why:/Fix: labelled output. Tests that asserted the old format strings were updated to the equivalent new format assertions.
## [2026-05-31T14:14:22.666Z]
Asking for the context of a node that does not exist is an ordinary user mistake — usually a mistyped path or a path that still includes the model prefix — yet it was surfaced through the catch-all handler reserved for genuine internal failures, which tells the user the CLI hit an unclassified error and that this is a bug to be reported. That is both wrong and unhelpful. The node-not-found case is now recognized explicitly before reaching the catch-all and rendered with the same what/why/next structure as every other diagnostic: it states which node is missing, explains that the node path must name an existing node directory under the model tree written without that prefix, and points to the tree and find commands for locating a valid one.
## [2026-05-31T14:21:42.285Z]
Requesting the context of a node that does not exist is a routine user mistake and must read as one. The not-found case is recognized before the catch-all crash handler and rendered with a structured what/why/next that names the missing node, explains the node path must identify an existing node directory under the model tree written without that prefix, and points to the browse and search commands — rather than telling the user the CLI hit an unclassified internal error to be reported as a bug. The helper that builds that structured message is shared from the formatters layer and is imported once at the top of this file.
## [2026-05-31T16:03:31.210Z]
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-31T17:27:16.128Z]
Moved the shared command-layer support helpers — the graph-load-or-abort wrapper and the unexpected-error funnel — out of the formatters layer and into the command layer. These helpers must reach both the engine (to load the graph) and the formatters (to build the uniform what/why/next message), and only the command layer may legally depend on both; keeping them in the formatters layer was an upward dependency on the engine that the layering rules forbid. The helpers register no command of their own, so they live under a dedicated command-support classification rather than as a command handler. Command handlers now import them from their new command-layer location.
## [2026-06-13T05:34:12.731Z]
The node view now surfaces read-only lock-observability fields: a per-aspect subject-file count (or unit count when an aspect reviews per file) so a reader sees at a glance which aspects are vacuous or fan out across files, and a log state indicating whether a fresh log entry is required before a fill can record a verdict (the node's type opts into requiring a log entry and the node's current source fingerprint differs from the one stored in the lock) and whether such an entry is already present. This is a pure read with no model calls and no writes; a structurally garbled lock surfaces as a fail-closed error rather than being treated as empty.
## [2026-06-13T07:02:11.104Z]
Displaying a component's status must not crash when one of its listed files cannot be read. Computing the source fingerprint for an unreadable file now raises a typed error; this read-only status view catches it and reports the log-requirement state as not-applicable rather than aborting, because the unreadable file is already surfaced as a blocking error by the verification command, which is where the author acts on it. A listed file that cannot be read is a fixable hard error, not a reason to break an unrelated status view.
## [2026-06-13T10:52:15.349Z]
Passing a file path that lies outside the project root used to be reported as an unclassified internal bug telling the agent to file an issue. That is a normal user-input mistake, not a bug, so it is now caught explicitly and surfaced as a clear what/why/next error directing the agent to pass a path inside the project. Behavior for in-root paths is unchanged.
