Skip to content
Closed
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
7 changes: 6 additions & 1 deletion src/review/content-lane/registry-logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,12 @@ export function checkContentLaneDeliverable(
issueTitle?: string,
): ContentLaneDeliverableCheck {
const matchesSpec = (candidate: string): boolean => spec.entryFilePattern.test(candidate) || (spec.providerFilePattern?.test(candidate) ?? false);
const mentionedPath = extractPathTokens(issueText).find(matchesSpec);
// Mirror classifyRegistryPrScope's matchesPattern: the spec patterns are compiled by globToRegExp against a
// CANONICALIZED path (lowercased + `./`-stripped + `\`→`/`, no `i` flag), so an issue body writing the path with
// any capitalization must be matched on canonicalize(token) — otherwise it produces no mentionedPath and the gate
// silently reports not-applicable. Keep the ORIGINAL token for mentionedPath: it is quoted verbatim into the
// public PR comment and must match what the contributor and maintainer see in the issue.
const mentionedPath = extractPathTokens(issueText).find((token) => matchesSpec(canonicalize(token)));
const titleImplies = !mentionedPath && Boolean(issueTitle && spec.issueTitleImpliesEntryPattern?.test(issueTitle));
if (!mentionedPath && !titleImplies) return { verdict: "not-applicable" };
const delivered = changedFiles.some((file) => matchesSpec(canonicalize(file)));
Expand Down
32 changes: 32 additions & 0 deletions test/unit/content-lane-registry-logic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,38 @@ describe("checkContentLaneDeliverable (generic, spec-driven — #content-lane-de
expect(checkContentLaneDeliverable(entryOnlySpec, issueText, ["tests/foo.test.mjs"]).verdict).toBe("missing");
});

// #9667: the issue-body scan must canonicalize each token before testing it against the spec (globToRegExp
// compiles the patterns against a canonicalized/lowercased path with no `i` flag), exactly as the changedFiles
// side already does — while quoting the ORIGINAL, non-canonicalized token in the public-comment mentionedPath.
describe("canonicalizes the issue-body path token before matching (#9667)", () => {
it("is 'missing' for a mixed-case issue path the PR doesn't deliver, quoting the ORIGINAL token verbatim", () => {
const issueText = "Add the missing surfaces to Registry/Subnets/Foo.json please.";
expect(checkContentLaneDeliverable(spec, issueText, ["tests/foo-verify.test.mjs"])).toEqual({
verdict: "missing",
mentionedPath: "Registry/Subnets/Foo.json",
});
});

it("is 'delivered' for that mixed-case issue path when the PR changes the canonical file", () => {
const issueText = "Add the missing surfaces to Registry/Subnets/Foo.json please.";
expect(checkContentLaneDeliverable(spec, issueText, ["registry/subnets/foo.json"])).toEqual({ verdict: "delivered" });
});

it("keeps the all-lowercase path behaviour byte-identical (both delivered and missing)", () => {
const issueText = "Add the missing surfaces to registry/subnets/foo.json.";
expect(checkContentLaneDeliverable(spec, issueText, ["registry/subnets/foo.json"])).toEqual({ verdict: "delivered" });
expect(checkContentLaneDeliverable(spec, issueText, ["tests/foo-verify.test.mjs"])).toEqual({
verdict: "missing",
mentionedPath: "registry/subnets/foo.json",
});
});

it("stays not-applicable for a mixed-case path token that matches NO spec pattern (not over-broadened)", () => {
const issueText = "See the config in Docs/Guide/Setup.md for details.";
expect(checkContentLaneDeliverable(spec, issueText, ["registry/subnets/foo.json"])).toEqual({ verdict: "not-applicable" });
});
});

// #content-lane-deliverable follow-up (metagraphed #7060-class gap): the literal-path scan alone is BLIND
// to metagraphed's own ~120 "MCP execute: verify + wire SN*" issues, whose bodies write the registry path
// with a generic `<slug>` documentation placeholder rather than the real resolved filename — confirmed
Expand Down
Loading