From 9c8311415990e38482f31449b645316e4a82daf9 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 13 May 2026 18:33:28 -0400 Subject: [PATCH] fix(bg/notifier): strip YAML inline comments from depends_on values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `parseDependsOn` in `tools/bg/backlog-ready-notifier.ts` extracted the raw line content after the `-` marker without stripping YAML inline comments. Block-style entries like depends_on: - B-0395 # operational-resonance-conversation-interface (Clifford engine) were parsed as the literal string `B-0395 # operational-resonance-...` rather than `B-0395`, producing a false-positive dangling-dep warning (the row exists; the comment was conflated with the ID). Fix: - New `stripInlineComment(value)` helper finds the first whitespace+`#` and slices everything after it off. Backlog IDs never contain `#`, so the simple split is safe and matches YAML's actual comment semantics (`#` preceded by whitespace, outside quoted contexts). - Apply to both inline-array (`[B-0440, B-0441]`) and block-style (`- B-0440\n - B-0441`) parsing paths. Tests: - New `strips YAML inline comments from block-style depends_on` uses the real B-0422 → B-0395 example that surfaced the bug. - New `strips YAML inline comments from inline-array depends_on` exercises the array path. - Existing 33 tests unchanged; 35/35 pass. Empirical effect on origin/main: dangling dep ref(s): 9 → 8 (The remaining 8 are real lost-files cases — B-0257..B-0261, B-0289 addressed by PR #3044; B-0055.1, B-0054.1 are genuine missing sub-row decompositions for a future tick.) Co-Authored-By: Claude --- tools/bg/backlog-ready-notifier.test.ts | 33 +++++++++++++++++++++++++ tools/bg/backlog-ready-notifier.ts | 16 ++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/tools/bg/backlog-ready-notifier.test.ts b/tools/bg/backlog-ready-notifier.test.ts index 26f034dea3..fb506a9023 100644 --- a/tools/bg/backlog-ready-notifier.test.ts +++ b/tools/bg/backlog-ready-notifier.test.ts @@ -150,6 +150,39 @@ depends_on: expect(row?.dependsOn).toEqual(["B-9000", "B-9001", "B-9002"]); }); + test("strips YAML inline comments from block-style depends_on", () => { + // Real-world example from B-0422: `- B-0395 # operational-resonance-...` + // was previously parsed as the full string (including the comment), + // producing a false-positive dangling-dep warning. + const content = `--- +id: B-9011 +priority: P1 +status: open +depends_on: + - B-0395 # operational-resonance-conversation-interface (Clifford engine) + - B-9001 + - B-9002 # short trailing note +---`; + const row = parseRow(content, "B-9011.md"); + expect(row?.dependsOn).toEqual(["B-0395", "B-9001", "B-9002"]); + }); + + test("strips YAML inline comments from inline-array depends_on", () => { + const content = `--- +id: B-9012 +priority: P1 +status: open +depends_on: [B-0440, B-0441 # ready-to-grind notifier, B-0442] +---`; + const row = parseRow(content, "B-9012.md"); + // Note: a `#` in an inline-array element terminates the list visually + // but YAML doesn't treat `]` as commentable so this is best-effort. + // The first two entries are clean; the third gets absorbed by the + // comment which the parser strips. Verify the clean entries survive. + expect(row?.dependsOn).toContain("B-0440"); + expect(row?.dependsOn).toContain("B-0441"); + }); + test("returns null when frontmatter missing", () => { expect(parseRow("no frontmatter here", "x.md")).toBeNull(); }); diff --git a/tools/bg/backlog-ready-notifier.ts b/tools/bg/backlog-ready-notifier.ts index ee27087e64..d7b9042893 100644 --- a/tools/bg/backlog-ready-notifier.ts +++ b/tools/bg/backlog-ready-notifier.ts @@ -91,19 +91,31 @@ export const AGENT_MAP: Record = { riven: ["riven", "grok"], }; +// Strip a YAML inline comment from a parsed depends_on value. +// Lines like `- B-0395 # operational-resonance-conversation-interface` +// previously produced the full string (including the comment) as a +// "dependency ID" which then surfaced as a false-positive dangling-dep +// warning. YAML's spec treats `#` (preceded by whitespace) as the start +// of a comment outside quoted contexts; backlog IDs never contain `#`, +// so the simple "split on whitespace-#" handling is sufficient and safe. +function stripInlineComment(value: string): string { + const idx = value.search(/\s+#/); + return (idx === -1 ? value : value.slice(0, idx)).trim(); +} + function parseDependsOn(frontmatter: string): string[] { const inlineMatch = frontmatter.match(/^depends_on:\s*\[(.*?)\]/m); if (inlineMatch && inlineMatch[1] !== undefined) { return inlineMatch[1] .split(",") - .map(s => s.trim()) + .map(s => stripInlineComment(s.trim())) .filter(s => s.length > 0); } const blockMatch = frontmatter.match(/^depends_on:\s*\n((?:[ \t]+-[ \t]*[^\r\n]+\r?\n?)+)/m); if (blockMatch && blockMatch[1] !== undefined) { return blockMatch[1] .split(/\r?\n/) - .map(line => line.match(/^[ \t]+-[ \t]*(.+?)\s*$/)?.[1] ?? "") + .map(line => stripInlineComment(line.match(/^[ \t]+-[ \t]*(.+?)\s*$/)?.[1] ?? "")) .filter(s => s.length > 0); } return [];