Skip to content
Open
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
9 changes: 8 additions & 1 deletion src/transition/preflight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,13 @@ export function validateStories(stories: Story[], parseWarnings: string[]): Pref
return issues;
}

// Matches a NO-GO verdict anywhere in the report, but NOT the "GO / NO-GO"
// label itself (e.g. the standard "## GO / NO-GO Decision" heading), where
// NO-GO is merely the second of the two listed options. Without the negative
// lookbehind, every readiness report — including GO-ready ones that carry that
// heading — would be flagged as NO-GO and block the transition.
const NO_GO_VERDICT_PATTERN = /(?<!GO\s*\/\s*)\bNO[-\s]?GO\b/i;

export function validateReadiness(content: string | null): PreflightIssue[] {
if (content === null) {
return [
Expand All @@ -165,7 +172,7 @@ export function validateReadiness(content: string | null): PreflightIssue[] {
];
}

if (/NO[-\s]?GO/i.test(content)) {
if (NO_GO_VERDICT_PATTERN.test(content)) {
return [
{
id: "E1",
Expand Down
22 changes: 22 additions & 0 deletions tests/transition/preflight.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,28 @@ Scope.

expect(issues[0]!.id).toBe("E1");
});

it("does not flag the 'GO / NO-GO' heading on a GO-ready report", () => {
const content = `# Implementation Readiness Report\n\n## GO / NO-GO Decision\n\n**Decision:** GO - all requirements met.\n`;

const issues = validateReadiness(content);

expect(issues).toHaveLength(0);
});

it("still flags a NO-GO verdict even when the 'GO / NO-GO' heading is present", () => {
const content = `# Implementation Readiness Report\n\n## GO / NO-GO Decision\n\n**Decision:** NO-GO - missing test coverage.\n`;

const issues = validateReadiness(content);

expect(issues[0]!.id).toBe("E1");
});

it("does not flag the compact 'GO/NO-GO' label without spaces", () => {
const issues = validateReadiness("## GO/NO-GO\n\nDecision: GO\n");

expect(issues).toHaveLength(0);
});
});

describe("runPreflight", () => {
Expand Down