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
17 changes: 14 additions & 3 deletions src/signals/local-branch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ export type LocalBranchValidation = {
exitCode?: number | undefined;
};

/**
* A local validation command counts as passing test evidence when it ran green — either a full run
* (`"passed"`) or a focused subset (`"focused"`, e.g. `vitest run path/to/file.test.ts`). Single-sourced
* so every evidence surface (the PR-packet validation summary, the freshness evidence list, the
* `validation_as_test_evidence` finding, and the v2 workspace-intelligence count) agrees on what passing
* means instead of drifting apart.
*/
export function isPassingValidation(entry: LocalBranchValidation): boolean {
return entry.status === "passed" || entry.status === "focused";
}

export type LocalBranchScorer = {
mode: "metadata_only" | "external_command" | "gittensor_root";
activeModel?: string | undefined;
Expand Down Expand Up @@ -841,7 +852,7 @@ function buildLocalFindings(
},
]
: []),
...((input.validation ?? []).some((entry) => entry.status === "passed") && !changedFiles.some((file) => isTestFile(file.path))
...((input.validation ?? []).some(isPassingValidation) && !changedFiles.some((file) => isTestFile(file.path))
? [
{
code: "validation_as_test_evidence",
Expand Down Expand Up @@ -1209,7 +1220,7 @@ function renderPrPacketMarkdown(title: string, sections: Array<{ heading: string

function summarizeValidation(validation: LocalBranchValidation[]): LocalBranchAnalysis["prPacket"]["validationSummary"] {
return {
passed: validation.filter((entry) => entry.status === "passed" || entry.status === "focused").length,
passed: validation.filter(isPassingValidation).length,
failed: validation.filter((entry) => entry.status === "failed").length,
notRun: validation.filter((entry) => entry.status === "not_run" || entry.status === "skipped" || entry.status === "unknown").length,
commands: validation,
Expand All @@ -1218,7 +1229,7 @@ function summarizeValidation(validation: LocalBranchValidation[]): LocalBranchAn

function validationEvidence(validation: LocalBranchValidation[] | undefined): string[] {
return (validation ?? [])
.filter((entry) => entry.status === "passed" || entry.status === "focused")
.filter(isPassingValidation)
.map((entry) => entry.command);
}

Expand Down
3 changes: 2 additions & 1 deletion src/signals/local-workspace-intelligence.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isPassingValidation } from "./local-branch";
import type { LocalBranchAnalysis, LocalBranchAnalysisInput, LocalBranchChangedFile, LocalBranchValidation } from "./local-branch";
import { isTestPath } from "./test-evidence";
import { sanitizeLocalScorerWarnings } from "./local-scorer-diagnostics";
Expand Down Expand Up @@ -55,7 +56,7 @@ export function buildLocalWorkspaceIntelligence(args: {
}): LocalWorkspaceIntelligence {
const validation = args.input.validation ?? [];
const testFileCount = args.changedFiles.filter((file) => isTestPath(file.path)).length;
const passedValidationCount = validation.filter((entry) => entry.status === "passed").length;
const passedValidationCount = validation.filter(isPassingValidation).length;
const hasTestFiles = testFileCount > 0;
const hasValidation = passedValidationCount > 0;
const testEvidenceLevel = hasTestFiles && hasValidation ? "both" : hasTestFiles ? "test_files" : hasValidation ? "validation_commands" : "none";
Expand Down
42 changes: 41 additions & 1 deletion test/unit/local-branch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { join } from "node:path";
import { pathToFileURL } from "node:url";
import { afterEach, describe, expect, it } from "vitest";
import { SCENARIO_MAX_BRANCH_REF_CHARS, SCENARIO_MAX_LINKED_ISSUE_NUMBERS } from "../../src/scenarios/input-model";
import { buildLocalBranchAnalysis, findCurrentBranchPullRequest } from "../../src/signals/local-branch";
import { buildLocalBranchAnalysis, findCurrentBranchPullRequest, isPassingValidation } from "../../src/signals/local-branch";
import { MAX_LOCAL_SCORER_WARNING_CHARS, MAX_LOCAL_SCORER_WARNING_COUNT } from "../../src/signals/local-scorer-diagnostics";
import type { ContributorOutcomeHistory, ContributorProfile, ContributorScoringProfile, IssueQualityReport } from "../../src/signals/engine";
import type { RepositoryRecord, ScoringModelSnapshotRecord } from "../../src/types";
Expand Down Expand Up @@ -1117,6 +1117,46 @@ describe("local branch analysis", () => {
expect(analysis.recommendedRerunCondition).toMatch(/git fetch origin/i);
});

it("treats a focused validation run as passing test evidence across every surface (regression)", () => {
const analysis = buildLocalBranchAnalysis({
input: {
login: "oktofeesh1",
repoFullName: repo.fullName,
baseRef: "origin/main",
baseSha: "base",
headSha: "head",
remoteTrackingSha: "base",
body: "Fixes #7",
changedFiles: [{ path: "internal/entity/model.go", additions: 10, deletions: 2, status: "modified" }],
// A focused subset run (`vitest run path`) is green evidence; summarizeValidation/validationEvidence
// already count it, so the finding and the v2 workspace count must agree instead of dropping it.
validation: [{ command: "vitest run internal/entity/model.test.ts", status: "focused", summary: "focused subset passed" }],
},
repo,
issues: [{ repoFullName: repo.fullName, number: 7, title: "Entity model edge case", state: "open", labels: ["bug"], linkedPrs: [] }],
pullRequests: [],
profile,
outcomeHistory,
scoringSnapshot,
scoringProfile,
});

expect(analysis.prPacket.validationSummary.passed).toBe(1);
expect(analysis.baseFreshness.passedValidationCount).toBe(1);
expect(analysis.localFindings).toEqual(expect.arrayContaining([expect.objectContaining({ code: "validation_as_test_evidence" })]));
expect(analysis.workspaceIntelligence.testEvidence.passedValidationCount).toBe(1);
expect(analysis.workspaceIntelligence.testEvidence.level).toBe("validation_commands");
expect(analysis.preflight.findings.map((finding) => finding.code)).not.toContain("local_diff_missing_tests");
});

it("counts only green validation statuses (passed or focused) as passing evidence", () => {
expect(isPassingValidation({ command: "npm test", status: "passed" })).toBe(true);
expect(isPassingValidation({ command: "vitest run x", status: "focused" })).toBe(true);
for (const status of ["failed", "not_run", "skipped", "unknown"] as const) {
expect(isPassingValidation({ command: "npm test", status })).toBe(false);
}
});

it("treats focused validation as evidence and failed validation as actionable", () => {
const analysis = buildLocalBranchAnalysis({
input: {
Expand Down
34 changes: 34 additions & 0 deletions test/unit/local-workspace-intelligence.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,40 @@ describe("local workspace intelligence v2", () => {
expect(preflight.findings.map((finding) => finding.code)).not.toContain("local_diff_missing_tests");
});

it("treats a focused validation run as test evidence, matching the PR-packet summary", () => {
const intelligence = buildLocalWorkspaceIntelligence({
input: {
login: "oktofeesh1",
repoFullName: repo.fullName,
changedFiles: [{ path: "internal/entity/model.go", status: "modified" }],
validation: [{ command: "vitest run internal/entity/model.test.ts", status: "focused", summary: "focused subset passed" }],
},
analysis: {
baseFreshness: { status: "fresh", changedFileCount: 1, testFileCount: 0, passedValidationCount: 1, warnings: [] },
branchQualityBlockers: [],
accountStateBlockers: [],
recommendedRerunCondition: "Rerun after any branch, base, or PR state changes before opening/submitting.",
prPacket: {
titleSuggestion: "Entity model fix",
markdown: "# Entity model fix\n",
bodySections: [],
reviewerNotes: [],
validationSummary: {
passed: 1,
failed: 0,
notRun: 0,
commands: [{ command: "vitest run internal/entity/model.test.ts", status: "focused", summary: "focused subset passed" }],
},
publicSafeWarnings: [],
},
},
changedFiles: [{ path: "internal/entity/model.go", status: "modified" }],
});

expect(intelligence.testEvidence.passedValidationCount).toBe(1);
expect(intelligence.testEvidence.level).toBe("validation_commands");
});

it("records metadata-only scorer diagnostics when no external scorer is configured", () => {
const intelligence = buildLocalWorkspaceIntelligence({
input: {
Expand Down
Loading