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
190 changes: 190 additions & 0 deletions src/services/contributor-intake-breakdown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import { sanitizePublicComment } from "../github/commands";
import type { ContributorIntakeHealth } from "../signals/engine";

// ─── Contributor intake breakdown (explanation family) ───────────────────────────────────────────
// A pure projection over a computed {@link ContributorIntakeHealth} that decomposes its otherwise-opaque
// intake `score` into the weighted deductions that lowered it from a perfect 100, and names the single
// highest-leverage lever a maintainer can pull to make the repo more attractive to contributors. Sibling of
// `queue-burden-breakdown.ts` and `score-breakdown.ts`: deterministic, no I/O, no GitHub fetch. Public-safe by
// construction — it reports the same observable drivers the intake summary already prints (queue burden out of
// 100, duplicate-cluster count, config band) and routes every rendered string through `sanitizePublicComment`.

export type IntakeDeductionBand = "none" | "low" | "moderate" | "high";

export type IntakeDeduction = {
/** The intake factor this deduction comes from. */
component: "queueBurden" | "duplicateClusters" | "configQuality";
/** Observable driver behind the deduction (a queue-burden reading, a cluster count, or a config band). */
driver: string;
/** Points removed from the base 100 by this factor (always >= 0). */
deduction: number;
/** Share of the total deduction (0–100). */
sharePercent: number;
band: IntakeDeductionBand;
summary: string;
lever: string;
/** 0–100 ranking weight used to pick the single highest-leverage improvement lever. */
leverageScore: number;
};

export type ContributorIntakeBreakdown = {
repoFullName: string;
generatedAt: string;
/** The authoritative (already clamped) intake score carried on the ContributorIntakeHealth. */
score: number;
level: ContributorIntakeHealth["level"];
/** The perfect score every repo starts from before deductions. */
baseScore: number;
/** Sum of every factor's deduction (may exceed 100 before the engine floors the score at 0). */
totalDeduction: number;
/** True when the deductions exceeded the base 100 and the engine floored the score at 0. */
clamped: boolean;
components: IntakeDeduction[];
highestLeverageLever: { component: string; lever: string; reason: string };
summary: string;
};

const BASE_SCORE = 100;

// These weights MIRROR buildContributorIntakeHealth() in src/signals/engine.ts:
// score = clamp(100 - burdenScore*0.55 - duplicateClusters*8 - configPenalty, 0, 100)
// A drift-guard test rebuilds a ContributorIntakeHealth through that function and asserts this module recomposes
// the same score, so an engine weight change fails the suite instead of silently producing a wrong breakdown.
const QUEUE_BURDEN_WEIGHT = 0.55;
const DUPLICATE_CLUSTER_WEIGHT = 8;

// The config-quality band maps to a fixed penalty (an excellent/unknown band costs nothing).
function configPenaltyFor(level: ContributorIntakeHealth["configLevel"]): number {
if (level === "fragile") return 30;
if (level === "needs_attention") return 18;
if (level === "good") return 6;
return 0;
}

function bandFor(deduction: number, sharePercent: number): IntakeDeductionBand {
if (deduction <= 0) return "none";
if (sharePercent >= 40) return "high";
if (sharePercent >= 15) return "moderate";
return "low";
}

function shareOf(deduction: number, totalDeduction: number): number {
if (totalDeduction <= 0) return 0;
return Math.round((deduction / totalDeduction) * 100);
}

function pickHighestLeverage(components: IntakeDeduction[]): ContributorIntakeBreakdown["highestLeverageLever"] {
// Rank by share of the total deduction; break ties toward the larger raw deduction, then by name for
// determinism. When nothing is deducted (a perfect intake), return an explicit no-op lever rather than an
// arbitrary component, so the breakdown stays honest for a healthy repo.
const ranked = [...components].sort(
(left, right) =>
right.leverageScore - left.leverageScore ||
right.deduction - left.deduction ||
left.component.localeCompare(right.component),
);
const top = ranked[0]!;
if (top.leverageScore <= 0) {
return {
component: "none",
lever: sanitizePublicComment("No intake lever needs attention; nothing is currently lowering the intake score."),
reason: sanitizePublicComment("Contributor intake is at full strength, so there is no pressing lever to pull."),
};
}
const reason =
top.band === "high"
? `${top.component} is the dominant drag on contributor intake right now.`
: `${top.component} is the largest remaining drag on contributor intake.`;
return {
component: top.component,
lever: top.lever,
reason: sanitizePublicComment(reason),
};
}

/**
* Pure projection over a {@link ContributorIntakeHealth} that explains how the intake `score` breaks down into
* the weighted deductions that lowered it and names the single highest-leverage lever to improve intake.
*/
export function explainContributorIntake(health: ContributorIntakeHealth): ContributorIntakeBreakdown {
const burdenDeduction = health.queueHealth.burdenScore * QUEUE_BURDEN_WEIGHT;
const clusterDeduction = health.duplicateClusters * DUPLICATE_CLUSTER_WEIGHT;
const configDeduction = configPenaltyFor(health.configLevel);
const totalDeduction = burdenDeduction + clusterDeduction + configDeduction;

const raw: Array<Pick<IntakeDeduction, "component" | "driver" | "deduction" | "summary" | "lever">> = [
{
component: "queueBurden",
driver: `queue burden ${health.queueHealth.burdenScore}/100`,
deduction: burdenDeduction,
summary:
burdenDeduction > 0
? `Queue burden of ${health.queueHealth.burdenScore}/100 is the review-load drag on intake.`
: "Queue burden is zero, so it is not dragging on intake.",
lever:
burdenDeduction > 0
? "Bring the queue burden down (land or link open PRs, clear stale and aged work) to lift intake."
: "Keep the queue clear so review load never drags on intake.",
},
{
component: "duplicateClusters",
driver: `${health.duplicateClusters} duplicate cluster(s)`,
deduction: clusterDeduction,
summary:
clusterDeduction > 0
? `${health.duplicateClusters} duplicate or overlapping work cluster(s) are discouraging clean contributions.`
: "No duplicate or overlapping work clusters are dragging on intake.",
lever:
clusterDeduction > 0
? "Resolve overlapping submissions so contributors are not competing on the same work."
: "Keep deduplicating incoming work so collisions never drag on intake.",
},
{
component: "configQuality",
driver: `config ${health.configLevel}`,
deduction: configDeduction,
summary:
configDeduction > 0
? `Repository config quality is ${health.configLevel}, which lowers how confidently contributors can engage.`
: `Repository config quality is ${health.configLevel}, so it is not dragging on intake.`,
lever:
configDeduction > 0
? "Fix the flagged registry and label config issues to raise config quality and intake."
: "Keep the registry and label config healthy so config quality never drags on intake.",
},
];

const components: IntakeDeduction[] = raw.map((entry) => {
const sharePercent = shareOf(entry.deduction, totalDeduction);
return {
component: entry.component,
driver: entry.driver,
deduction: entry.deduction,
sharePercent,
band: bandFor(entry.deduction, sharePercent),
summary: sanitizePublicComment(entry.summary),
lever: sanitizePublicComment(entry.lever),
leverageScore: sharePercent,
};
});

const clamped = totalDeduction > BASE_SCORE;
const highestLeverageLever = pickHighestLeverage(components);
const summary =
highestLeverageLever.component === "none"
? `Contributor intake is ${health.level} with nothing lowering the score.`
: `Contributor intake is ${health.level}; ${highestLeverageLever.component} is the leading drag to address.`;

return {
repoFullName: health.repoFullName,
generatedAt: health.generatedAt,
score: health.score,
level: health.level,
baseScore: BASE_SCORE,
totalDeduction,
clamped,
components,
highestLeverageLever,
summary: sanitizePublicComment(summary),
};
}
143 changes: 143 additions & 0 deletions test/unit/contributor-intake-breakdown.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { describe, expect, it } from "vitest";
import { explainContributorIntake } from "../../src/services/contributor-intake-breakdown";
import { buildContributorIntakeHealth, type CollisionReport, type ContributorIntakeHealth } from "../../src/signals/engine";
import type { IssueRecord, PullRequestRecord, RepositoryRecord } from "../../src/types";

const FORBIDDEN = /\b(wallet|hotkey|coldkey|mnemonic|payout|reward|raw[-_\s]?trust|credibility|farming)\b/i;

const clamp = (value: number): number => Math.max(0, Math.min(100, value));

function makeIntake(input: {
burdenScore?: number;
duplicateClusters?: number;
configLevel?: ContributorIntakeHealth["configLevel"];
score?: number;
level?: ContributorIntakeHealth["level"];
repoFullName?: string;
generatedAt?: string;
}): ContributorIntakeHealth {
return {
repoFullName: input.repoFullName ?? "owner/repo",
generatedAt: input.generatedAt ?? "2026-07-01T00:00:00.000Z",
level: input.level ?? "healthy",
score: input.score ?? 100,
queueHealth: {
burdenScore: input.burdenScore ?? 0,
level: "low",
signals: {
openIssues: 0,
openPullRequests: 0,
unlinkedPullRequests: 0,
stalePullRequests: 0,
draftPullRequests: 0,
maintainerAuthoredPullRequests: 0,
collisionClusters: 0,
ageBuckets: { under7Days: 0, days7To30: 0, over30Days: 0 },
likelyReviewablePullRequests: 0,
},
},
configLevel: input.configLevel ?? "excellent",
duplicateClusters: input.duplicateClusters ?? 0,
reviewablePullRequests: 0,
summary: "fixture",
findings: [],
};
}

const componentByName = (breakdown: ReturnType<typeof explainContributorIntake>, name: string) =>
breakdown.components.find((entry) => entry.component === name)!;

describe("contributor intake breakdown", () => {
it("reports a perfect intake with no deductions and an honest no-op lever", () => {
const breakdown = explainContributorIntake(makeIntake({ score: 100, level: "healthy" }));
expect(breakdown.totalDeduction).toBe(0);
expect(breakdown.clamped).toBe(false);
expect(breakdown.components).toHaveLength(3);
for (const entry of breakdown.components) {
expect(entry.band).toBe("none");
expect(entry.sharePercent).toBe(0);
expect(entry.leverageScore).toBe(0);
}
expect(breakdown.highestLeverageLever.component).toBe("none");
expect(breakdown.highestLeverageLever.reason).toMatch(/full strength/i);
expect(breakdown.summary).toMatch(/nothing lowering/i);
});

it("flags a dominant queue-burden drag as high band and the top lever, with a small low-band factor", () => {
// burden 100×0.55 = 55, config good = 6, clusters 0 → total 61. burden ≈90% (high), config ≈10% (low).
const breakdown = explainContributorIntake(makeIntake({ burdenScore: 100, configLevel: "good", score: 39, level: "strained" }));
const burden = componentByName(breakdown, "queueBurden");
expect(burden.deduction).toBeCloseTo(55);
expect(burden.sharePercent).toBe(90);
expect(burden.band).toBe("high");
expect(componentByName(breakdown, "duplicateClusters").band).toBe("none");
expect(componentByName(breakdown, "configQuality").band).toBe("low");
expect(breakdown.clamped).toBe(false);
expect(breakdown.highestLeverageLever.component).toBe("queueBurden");
expect(breakdown.highestLeverageLever.reason).toMatch(/dominant/i);
});

it("classifies a moderate top drag and names the largest-remaining lever", () => {
// burden 15×0.55 = 8.25, clusters 1×8 = 8, config good = 6 → total 22.25; all shares in the moderate band.
const breakdown = explainContributorIntake(makeIntake({ burdenScore: 15, duplicateClusters: 1, configLevel: "good", score: 78, level: "healthy" }));
const burden = componentByName(breakdown, "queueBurden");
expect(burden.band).toBe("moderate");
expect(breakdown.highestLeverageLever.component).toBe("queueBurden");
expect(breakdown.highestLeverageLever.reason).toMatch(/largest remaining/i);
});

it("decomposes each config band into its fixed penalty", () => {
expect(componentByName(explainContributorIntake(makeIntake({ configLevel: "needs_attention" })), "configQuality").deduction).toBe(18);
expect(componentByName(explainContributorIntake(makeIntake({ configLevel: "good" })), "configQuality").deduction).toBe(6);
expect(componentByName(explainContributorIntake(makeIntake({ configLevel: "excellent" })), "configQuality").deduction).toBe(0);
});

it("marks the breakdown clamped when deductions exceed the base 100", () => {
// burden 100×0.55 = 55, clusters 3×8 = 24, config fragile = 30 → 109 > 100, engine floors the score at 0.
const breakdown = explainContributorIntake(makeIntake({ burdenScore: 100, duplicateClusters: 3, configLevel: "fragile", score: 0, level: "blocked" }));
expect(breakdown.totalDeduction).toBeCloseTo(109);
expect(breakdown.clamped).toBe(true);
expect(componentByName(breakdown, "configQuality").deduction).toBe(30);
expect(breakdown.score).toBe(0);
});

it("passes through repo identity, level, and generatedAt", () => {
const breakdown = explainContributorIntake(
makeIntake({ repoFullName: "acme/widgets", generatedAt: "2026-02-03T04:05:06.000Z", level: "watch", score: 60, burdenScore: 40 }),
);
expect(breakdown.repoFullName).toBe("acme/widgets");
expect(breakdown.generatedAt).toBe("2026-02-03T04:05:06.000Z");
expect(breakdown.level).toBe("watch");
expect(breakdown.baseScore).toBe(100);
expect(breakdown.summary).toMatch(/contributor intake is watch/i);
});

it("never leaks private or reward terminology in any rendered string", () => {
const breakdown = explainContributorIntake(makeIntake({ burdenScore: 80, duplicateClusters: 2, configLevel: "needs_attention" }));
for (const entry of breakdown.components) {
expect(entry.summary).not.toMatch(FORBIDDEN);
expect(entry.lever).not.toMatch(FORBIDDEN);
expect(entry.driver).not.toMatch(FORBIDDEN);
}
expect(breakdown.highestLeverageLever.reason).not.toMatch(FORBIDDEN);
expect(breakdown.summary).not.toMatch(FORBIDDEN);
});

it("recomposes the exact intake score the engine computes (weight drift guard)", () => {
const repo = { fullName: "owner/repo", isRegistered: true } as unknown as RepositoryRecord;
const pullRequests: PullRequestRecord[] = [
{ repoFullName: "owner/repo", number: 1, title: "aged unlinked", state: "open", labels: [], linkedIssues: [], updatedAt: "2020-01-01T00:00:00.000Z" },
{ repoFullName: "owner/repo", number: 2, title: "aged unlinked two", state: "open", labels: [], linkedIssues: [], updatedAt: "2020-01-01T00:00:00.000Z" },
];
const issues = [{ repoFullName: "owner/repo", number: 10, title: "open issue", state: "open", labels: [], linkedPrs: [], body: null }];
const collisions = { repoFullName: "owner/repo", summary: { clusterCount: 2, highRiskCount: 0 } } as unknown as CollisionReport;

const built = buildContributorIntakeHealth(repo, issues, pullRequests, "owner/repo", collisions);
const breakdown = explainContributorIntake(built);

// Reconstructing 100 minus the decomposed deductions (using this module's weights) must equal the engine score.
expect(clamp(breakdown.baseScore - breakdown.totalDeduction)).toBeCloseTo(built.score, 6);
expect(componentByName(breakdown, "duplicateClusters").deduction).toBe(16);
expect(componentByName(breakdown, "queueBurden").deduction).toBeCloseTo(built.queueHealth.burdenScore * 0.55, 6);
});
});
Loading