Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions tools/bg/backlog-ready-notifier.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
Expand Down
16 changes: 14 additions & 2 deletions tools/bg/backlog-ready-notifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,31 @@ export const AGENT_MAP: Record<string, string[]> = {
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 [];
Expand Down
Loading