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
9 changes: 7 additions & 2 deletions src/signals/registration-readiness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ export function buildRegistrationReadiness(input: RegistrationReadinessInput): R
const blockers = [
...(!isRegistered ? ["Repository is not registered in the latest LoopOver registry snapshot."] : []),
...(configFragile ? ["Repository config quality is fragile."] : []),
...(configNeedsAttention ? ["Repository config quality needs attention before registration promotion."] : []),
...(intakeBlocked ? ["Contributor intake health is blocked."] : []),
];

Expand All @@ -200,7 +201,9 @@ export function buildRegistrationReadiness(input: RegistrationReadinessInput): R
};

const warnings = [
...(configNeedsAttention ? ["Repository config quality needs attention before registration promotion."] : []),
// configNeedsAttention is a blocker (not a warning), mirroring how configFragile is treated — the two
// needs-attention tiers of the same configQuality.level stay consistent, and blockers fully explains
// ready === false without double-flagging the same fact as a warning (#5946).
...(contributorIntakeHealth.level === "strained" ? ["Contributor intake is strained; expect more maintainer triage."] : []),
...(settings.publicSurface === "off" ? ["GitHub App public surface is disabled; maintainers will not get comment/label assistance."] : []),
...testCoverageHealth.warnings,
Expand All @@ -209,7 +212,9 @@ export function buildRegistrationReadiness(input: RegistrationReadinessInput): R
...upstreamRegistryDriftWarnings,
];

const ready = blockers.length === 0 && !configFragile && !configNeedsAttention;
// configFragile and configNeedsAttention are now both blockers, so blockers.length === 0 alone fully
// determines readiness — blockers is the single source of truth for every ready === false reason (#5946).
const ready = blockers.length === 0;

return {
repoFullName,
Expand Down
4 changes: 3 additions & 1 deletion test/unit/policy-sanitizer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,9 @@ describe("readiness warnings sanitizer", () => {
contributorIntakeHealth: { ...base.contributorIntakeHealth, level: "strained" },
});

expect(report.warnings).toEqual(expect.arrayContaining(["Repository config quality needs attention before registration promotion.", "Contributor intake is strained; expect more maintainer triage."]));
// config-attention is a blocker (not a warning) since #5946; strained-intake stays a warning.
expect(report.blockers).toEqual(expect.arrayContaining(["Repository config quality needs attention before registration promotion."]));
expect(report.warnings).toEqual(expect.arrayContaining(["Contributor intake is strained; expect more maintainer triage."]));
expect(report.warnings.join(" ")).not.toMatch(PRIVATE_TERMS_PATTERN);
expect(report.blockers.join(" ")).not.toMatch(PRIVATE_TERMS_PATTERN);
});
Expand Down
27 changes: 24 additions & 3 deletions test/unit/registration-readiness.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,30 @@ describe("buildRegistrationReadiness", () => {
});

expect(report.ready).toBe(false);
expect(report.warnings).toEqual(
expect.arrayContaining(["Repository config quality needs attention before registration promotion.", "Contributor intake is strained; expect more maintainer triage."]),
);
// "needs attention" is a blocker (mirroring "fragile"), not a warning; the strained-intake note stays a warning.
expect(report.blockers).toContain("Repository config quality needs attention before registration promotion.");
expect(report.warnings).toEqual(expect.arrayContaining(["Contributor intake is strained; expect more maintainer triage."]));
expect(report.warnings).not.toContain("Repository config quality needs attention before registration promotion.");
});

// #5946: with config "needs attention" as the ONLY gating condition (everything else healthy), the report was
// ready === false while blockers was []. blockers must now fully explain ready === false on its own.
it("lists config-needs-attention in blockers when it is the only gating condition (regression for #5946)", () => {
const repo = repoFor("octo/attention", configFor({ repo: "octo/attention" }));
const base = signalsFor(repo, [], [], [label("bug")]);
const report = buildRegistrationReadiness({
repoFullName: repo.fullName,
repo,
settings: settingsFor(repo.fullName),
installation: healthyInstall,
...base,
configQuality: { ...base.configQuality, level: "needs_attention" },
});

expect(report.ready).toBe(false);
expect(report.blockers).toContain("Repository config quality needs attention before registration promotion.");
expect(report.blockers.length).toBeGreaterThan(0);
expect(report.warnings).not.toContain("Repository config quality needs attention before registration promotion.");
});

it("keeps the report free of forbidden public language", () => {
Expand Down