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
5 changes: 4 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,10 @@ 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);
// globToRegExp compiles the spec patterns against a CANONICALIZED (lowercased) path, so test canonicalize(token)
// — exactly as the changedFiles side below and classifyRegistryPrScope's matchesPattern already do — while
// keeping the ORIGINAL token for mentionedPath, which is quoted verbatim into the public PR comment (#9667).
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
29 changes: 29 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,35 @@ describe("checkContentLaneDeliverable (generic, spec-driven — #content-lane-de
expect(checkContentLaneDeliverable(entryOnlySpec, issueText, ["tests/foo.test.mjs"]).verdict).toBe("missing");
});

describe("canonicalizes the issue-body path token so mixed-case paths still fire the gate (#9667)", () => {
it("is 'missing' for a mixed-case issue path against a non-delivering PR, quoting the ORIGINAL token", () => {
const issueText = "Add the surfaces to Registry/Subnets/Foo.json.";
const result = checkContentLaneDeliverable(spec, issueText, ["tests/foo-verify.test.mjs"]);
// The gate fires (was silently not-applicable before #9667), and mentionedPath stays verbatim for the
// public comment — NOT lowercased.
expect(result).toEqual({ verdict: "missing", mentionedPath: "Registry/Subnets/Foo.json" });
});

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

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

it("still returns not-applicable for an issue path that matches no spec pattern (not over-broadened)", () => {
const issueText = "Update the docs at Docs/Readme.md — nothing registry-shaped here.";
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