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
185 changes: 185 additions & 0 deletions apps/gittensory-ui/public/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -3408,6 +3408,190 @@
"warnings"
]
},
"policyReadiness": {
"type": "object",
"nullable": true,
"properties": {
"repoFullName": {
"type": "string"
},
"source": {
"type": "string",
"enum": [
"focus_manifest_policy"
]
},
"previewOnly": {
"type": "boolean"
},
"present": {
"type": "boolean"
},
"publicWarnings": {
"type": "array",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"category": {
"type": "string",
"enum": [
"contribution_flow",
"direct_pr_policy",
"issue_discovery",
"validation",
"maintainer_burden"
]
},
"severity": {
"type": "string",
"enum": [
"info",
"warning",
"critical"
]
},
"title": {
"type": "string"
},
"detail": {
"type": "string"
},
"action": {
"type": "string"
}
},
"required": [
"code",
"category",
"severity",
"title",
"detail",
"action"
]
}
},
"ownerContext": {
"type": "object",
"properties": {
"manifestPresent": {
"type": "boolean"
},
"manifestSource": {
"type": "string",
"enum": [
"repo_file",
"api_record",
"none"
]
},
"privateNoteCount": {
"type": "number"
},
"manifestWarningCount": {
"type": "number"
},
"wantedPathCount": {
"type": "number"
},
"blockedPathCount": {
"type": "number"
},
"validationExpectationCount": {
"type": "number"
},
"queueLevel": {
"type": "string",
"enum": [
"low",
"medium",
"high",
"critical"
]
},
"contributorIntakeLevel": {
"type": "string",
"enum": [
"healthy",
"watch",
"strained",
"blocked"
]
},
"configLevel": {
"type": "string",
"enum": [
"excellent",
"good",
"needs_attention",
"fragile"
]
},
"issuePolicy": {
"type": "string"
},
"issueDiscoveryPolicy": {
"type": "string",
"enum": [
"encouraged",
"neutral",
"discouraged"
]
}
},
"required": [
"manifestPresent",
"manifestSource",
"privateNoteCount",
"manifestWarningCount",
"wantedPathCount",
"blockedPathCount",
"validationExpectationCount",
"queueLevel",
"contributorIntakeLevel",
"configLevel",
"issuePolicy",
"issueDiscoveryPolicy"
]
},
"droppedPublicWarnings": {
"type": "array",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"reason": {
"type": "string",
"enum": [
"unsafe_public_text"
]
}
},
"required": [
"code",
"reason"
]
}
},
"summary": {
"type": "string"
}
},
"required": [
"repoFullName",
"source",
"previewOnly",
"present",
"publicWarnings",
"ownerContext",
"droppedPublicWarnings",
"summary"
]
},
"blockers": {
"type": "array",
"items": {
Expand Down Expand Up @@ -3442,6 +3626,7 @@
"contributorIntakeHealth",
"docsCompleteness",
"githubApp",
"policyReadiness",
"blockers",
"warnings",
"dataQuality"
Expand Down
4 changes: 3 additions & 1 deletion src/api/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2829,10 +2829,11 @@ async function buildRepoOutcomePatternsResponse(env: Env, fullName: string) {

async function buildRegistrationReadinessResponse(env: Env, fullName: string) {
/* v8 ignore start -- Registration readiness route-level shaping over covered signal helpers. */
const [intelligence, settings, upstreamReports] = await Promise.all([
const [intelligence, settings, upstreamReports, focusManifest] = await Promise.all([
buildRepoIntelligenceResponse(env, fullName),
getRepositorySettings(env, fullName),
listUpstreamDriftReports(env, 20),
loadRepoFocusManifest(env, fullName, { fetcher: async () => null }),
]);
const repo = intelligence.repo;
const installation = await loadInstallationHealthSummary(env, repo);
Expand All @@ -2848,6 +2849,7 @@ async function buildRegistrationReadinessResponse(env: Env, fullName: string) {
contributorIntakeHealth: intelligence.contributorIntakeHealth as ReturnType<typeof buildContributorIntakeHealth>,
installation,
upstreamRegistryDriftWarnings: registryHyperparameterDriftWarningsForRepo(upstreamReports, fullName),
focusManifest,
});
return { ...report, dataQuality: intelligence.dataQuality };
/* v8 ignore stop */
Expand Down
39 changes: 39 additions & 0 deletions src/openapi/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,45 @@ export const RegistrationReadinessSchema = z
behavior: z.string(),
warnings: z.array(z.string()),
}),
policyReadiness: z
.object({
repoFullName: z.string(),
source: z.enum(["focus_manifest_policy"]),
previewOnly: z.boolean(),
present: z.boolean(),
publicWarnings: z.array(
z.object({
code: z.string(),
category: z.enum(["contribution_flow", "direct_pr_policy", "issue_discovery", "validation", "maintainer_burden"]),
severity: z.enum(["info", "warning", "critical"]),
title: z.string(),
detail: z.string(),
action: z.string(),
}),
),
ownerContext: z.object({
manifestPresent: z.boolean(),
manifestSource: z.enum(["repo_file", "api_record", "none"]),
privateNoteCount: z.number(),
manifestWarningCount: z.number(),
wantedPathCount: z.number(),
blockedPathCount: z.number(),
validationExpectationCount: z.number(),
queueLevel: z.enum(["low", "medium", "high", "critical"]),
contributorIntakeLevel: z.enum(["healthy", "watch", "strained", "blocked"]),
configLevel: z.enum(["excellent", "good", "needs_attention", "fragile"]),
issuePolicy: z.string(),
issueDiscoveryPolicy: z.enum(["encouraged", "neutral", "discouraged"]),
}),
droppedPublicWarnings: z.array(
z.object({
code: z.string(),
reason: z.enum(["unsafe_public_text"]),
}),
),
summary: z.string(),
})
.nullable(),
blockers: z.array(z.string()),
warnings: z.array(z.string()),
dataQuality: z.record(z.string(), z.unknown()),
Expand Down
19 changes: 19 additions & 0 deletions src/signals/registration-readiness.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { RegistryRepoConfig, RepositoryRecord, RepositorySettings } from "../types";
import { nowIso } from "../utils/json";
import type { ConfigQuality, ContributorIntakeHealth, LabelAudit, LaneAdvice, MaintainerCutReadiness, QueueHealth } from "./engine";
import type { FocusManifest } from "./focus-manifest";
import { buildRepoPolicyReadiness, policyReadinessWarningText, type RepoPolicyReadinessReport } from "./repo-policy-readiness";

export type RegistrationMode = "direct_pr" | "issue_discovery" | "split";
export type IssuePolicy = "issue_discovery_enabled" | "split_pr_and_issue_discovery_enabled" | "direct_pr_requires_linked_issue" | "direct_pr_no_issue_required";
Expand Down Expand Up @@ -58,6 +60,7 @@ export type RegistrationReadinessReport = {
contributorIntakeHealth: ContributorIntakeHealth;
docsCompleteness: { status: string; requiredDocs: string[]; note: string };
githubApp: GithubAppBehavior;
policyReadiness: RepoPolicyReadinessReport | null;
blockers: string[];
warnings: string[];
};
Expand All @@ -74,6 +77,7 @@ export type RegistrationReadinessInput = {
contributorIntakeHealth: ContributorIntakeHealth;
installation: InstallationHealthSummary | null;
upstreamRegistryDriftWarnings?: string[] | undefined;
focusManifest?: FocusManifest | undefined;
};

const REQUIRED_DOCS = ["README", "CONTRIBUTING", "SECURITY", "SUPPORT"];
Expand Down Expand Up @@ -142,6 +146,19 @@ export function buildRegistrationReadiness(input: RegistrationReadinessInput): R

const testCoverageHealth = buildTestCoverageHealth(labelAudit, settings);
const githubApp = buildGithubAppBehavior(repo, settings, installation);
const policyReadiness =
input.focusManifest === undefined
? null
: buildRepoPolicyReadiness({
repoFullName,
focusManifest: input.focusManifest,
settings,
lane,
configQuality,
labelAudit,
queueHealth,
contributorIntakeHealth,
});

const blockers = [
...(!isRegistered ? ["Repository is not registered in the latest Gittensory registry snapshot."] : []),
Expand Down Expand Up @@ -174,6 +191,7 @@ export function buildRegistrationReadiness(input: RegistrationReadinessInput): R
...(settings.publicSurface === "off" ? ["GitHub App public surface is disabled; maintainers will not get comment/label assistance."] : []),
...testCoverageHealth.warnings,
...labelAudit.missingConfiguredLabels.map((label) => `Configured registry label "${label}" is missing from live GitHub labels.`),
...(policyReadiness?.publicWarnings.map(policyReadinessWarningText) ?? []),
...upstreamRegistryDriftWarnings,
];

Expand Down Expand Up @@ -210,6 +228,7 @@ export function buildRegistrationReadiness(input: RegistrationReadinessInput): R
note: "Gittensory validates public repo docs from the local project during CI; remote repo-doc crawling is not enabled in this signal yet.",
},
githubApp,
policyReadiness,
blockers,
warnings,
};
Expand Down
Loading