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
4 changes: 3 additions & 1 deletion packages/loopover-engine/src/focus-manifest/guidance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {
FocusManifestFinding,
FocusManifestGuidance,
} from "../types/predicted-gate-types.js";
import { isCodeFile } from "../signals/path-matchers.js";

const FOCUS_MANIFEST_TERMS = /\b(reward\w*|score\w*|wallets?|hotkeys?|coldkeys?|seed[-\s]?phrases?|mnemonics?|private[-\s]?keys?|farming|payouts?|rankings?|raw[-\s]?trust(?:[-\s]?scores?)?|trust[-\s]?scores?|private[-\s]?reviewability|reviewability(?:[-\s]?internals?)?|private[-\s]?scoreability|scoreability|public[-\s]?score[-\s]?(?:estimate|prediction|claim)s?|estimated[-\s]?scores?|score[-\s]?(?:estimate|prediction|preview)s?)\b/i;
const FOCUS_MANIFEST_LOCAL_PATH_PATTERN = new RegExp(String.raw`/Users/|/home/|/root/|/var/|/opt/|/tmp/|/private/|[A-Za-z]:[\\/]Users[\\/]|[A-Za-z]:[\\/]Program Files[\\/]`, "i");
Expand Down Expand Up @@ -124,6 +125,7 @@ export function buildFocusManifestGuidance(args: {
const linkedIssueCount = Math.max(0, args.linkedIssueCount ?? 0);
const testFileCount = Math.max(0, args.testFileCount ?? 0);
const passedValidationCount = Math.max(0, args.passedValidationCount ?? 0);
const codeFileCount = changedPaths.filter(isCodeFile).length;

const matchedWantedPaths = matchedPatterns(changedPaths, manifest.wantedPaths);
const preferredLabelHits = manifest.preferredLabels.filter((label) => labels.includes(label.toLowerCase()));
Expand Down Expand Up @@ -201,7 +203,7 @@ export function buildFocusManifestGuidance(args: {
publicNextSteps.push("Link a tracked issue if one exists; the maintainer prefers linked issues.");
}

if (manifest.testExpectations.length > 0 && testFileCount === 0 && passedValidationCount === 0) {
if (manifest.testExpectations.length > 0 && codeFileCount > 0 && testFileCount === 0 && passedValidationCount === 0) {
const safeExpectations = manifest.testExpectations.filter(isFocusManifestPublicSafe).slice(0, 3);
const expectationDetail = safeExpectations.length > 0 ? ` Expected evidence: ${safeExpectations.join("; ")}.` : "";
findings.push({
Expand Down
5 changes: 3 additions & 2 deletions src/signals/focus-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ import { DEFAULT_LINKED_ISSUE_HARD_RULES } from "../review/linked-issue-hard-rul
import { DEFAULT_UNLINKED_ISSUE_GUARDRAIL } from "../review/unlinked-issue-guardrail-config";
import { DEFAULT_ADVISORY_AI_ROUTING } from "../review/advisory-ai-routing-config";
import { DEFAULT_SCREENSHOT_TABLE_GATE } from "../review/screenshot-table-gate";
import { classifyChangedFile } from "./path-matchers";
import { classifyChangedFile, isCodeFile } from "./path-matchers";
import {
EMPTY_AUTO_REVIEW_CONFIG,
EMPTY_MAX_FINDINGS_CONFIG,
Expand Down Expand Up @@ -658,6 +658,7 @@ export function buildFocusManifestGuidance(args: {
const hasNoIssueRationale = args.hasNoIssueRationale ?? false;
const testFileCount = Math.max(0, args.testFileCount ?? 0);
const passedValidationCount = Math.max(0, args.passedValidationCount ?? 0);
const codeFileCount = changedPaths.filter(isCodeFile).length;

const matchedWantedPaths = matchedPatterns(changedPaths, manifest.wantedPaths);
const preferredLabelHits = manifest.preferredLabels.filter((label) => labels.includes(label.toLowerCase()));
Expand Down Expand Up @@ -735,7 +736,7 @@ export function buildFocusManifestGuidance(args: {
publicNextSteps.push("Link a tracked issue if one exists; the maintainer prefers linked issues.");
}

if (manifest.testExpectations.length > 0 && testFileCount === 0 && passedValidationCount === 0) {
if (manifest.testExpectations.length > 0 && codeFileCount > 0 && testFileCount === 0 && passedValidationCount === 0) {
const safeExpectations = manifest.testExpectations.filter(isFocusManifestPublicSafe).slice(0, 3);
const expectationDetail = safeExpectations.length > 0 ? ` Expected evidence: ${safeExpectations.join("; ")}.` : "";
findings.push({
Expand Down
19 changes: 19 additions & 0 deletions test/unit/focus-manifest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,25 @@ describe("buildFocusManifestGuidance", () => {
expect(guidance.findings.some((finding) => finding.code === "manifest_missing_tests")).toBe(false);
});

it("REGRESSION (#manifest-missing-tests-docs-only-false-positive): does not require tests when the change touches no code files", () => {
// A content/docs-only PR (e.g. a catalog registry .mdx entry) has nothing a test could meaningfully cover,
// so it must not trip manifest_missing_tests just because no test file or validation evidence exists --
// mirrors the codeFileCount > 0 guard local_diff_missing_tests already applies (predicted-gate-engine.ts).
const guidance = buildFocusManifestGuidance({ manifest: wanted, changedPaths: ["docs/readme.md"], linkedIssueCount: 1, testFileCount: 0, passedValidationCount: 0 });
expect(guidance.findings.some((finding) => finding.code === "manifest_missing_tests")).toBe(false);
});

it("still requires tests when the change mixes code with docs and neither tests nor validation evidence exist", () => {
const guidance = buildFocusManifestGuidance({
manifest: wanted,
changedPaths: ["docs/readme.md", "src/x.ts"],
linkedIssueCount: 1,
testFileCount: 0,
passedValidationCount: 0,
});
expect(guidance.findings.some((finding) => finding.code === "manifest_missing_tests")).toBe(true);
});

it("notes when issue-discovery is discouraged", () => {
const guidance = buildFocusManifestGuidance({ manifest: wanted, changedPaths: ["src/x.ts"], labels: ["bug"], linkedIssueCount: 1, testFileCount: 1 });
expect(guidance.findings.some((finding) => finding.code === "manifest_issue_discovery_discouraged")).toBe(true);
Expand Down
26 changes: 26 additions & 0 deletions test/unit/predicted-gate-engine-coverage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,32 @@ describe("predicted-gate engine module coverage (#2283)", () => {
});
expect(missingTests.findings.some((f) => f.code === "manifest_missing_tests")).toBe(true);
expect(missingTests.findings.find((f) => f.code === "manifest_missing_tests")?.detail).not.toContain("wallet");

// REGRESSION (#manifest-missing-tests-docs-only-false-positive): a docs/content-only change has nothing a
// test could cover, so it must not trip manifest_missing_tests just because no test file or validation
// evidence exists.
const docsOnlyNoFalsePositive = buildFocusManifestGuidance({
manifest: {
present: true,
source: "repo_file",
wantedPaths: [],
preferredLabels: [],
linkedIssuePolicy: "optional",
testExpectations: ["paste your wallet hotkey here"],
issueDiscoveryPolicy: "neutral",
maintainerNotes: [],
publicNotes: [],
gate: { present: true } as FocusManifest["gate"],
settings: {},
review: { present: true, preMergeChecks: [] },
warnings: [],
},
changedPaths: ["content/registry/new-entry.mdx"],
linkedIssueCount: 1,
testFileCount: 0,
passedValidationCount: 0,
});
expect(docsOnlyNoFalsePositive.findings.some((f) => f.code === "manifest_missing_tests")).toBe(false);
});

it("covers remaining codecov patch branch arms in ported engine modules", () => {
Expand Down
6 changes: 5 additions & 1 deletion test/unit/queue-2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4028,7 +4028,11 @@ describe("queue processors", () => {
await upsertPullRequestFile(env, {
repoFullName: "JSONbored/gittensory",
pullNumber: 47,
path: "README.md",
// A code file, deliberately -- this test's subject is whether an ignored-bot author still trips the
// deterministic manifestPolicyGateMode gate, not manifest_missing_tests' own code-vs-docs trigger
// (see the codeFileCount > 0 guard in buildFocusManifestGuidance). A docs-only path would no longer
// trip the finding at all and silently stop testing this test's actual subject.
path: "src/example.ts",
status: "modified",
additions: 1,
deletions: 1,
Expand Down