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
344 changes: 202 additions & 142 deletions apps/gittensory-ui/public/openapi.json

Large diffs are not rendered by default.

42 changes: 41 additions & 1 deletion src/api/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ import {
MINIMUM_SUPPORTED_MCP_VERSION,
} from "../services/mcp-compatibility";
import { buildOperatorDashboardPayload } from "../services/operator-dashboard";
import { buildSelfDogfoodRegistrationPack, resolveSelfDogfoodRepoFullName } from "../services/self-dogfood-registration-pack";
import {
buildWeeklyValueReport,
formatWeeklyValueReportMarkdown,
Expand Down Expand Up @@ -184,7 +185,12 @@ import { MAX_LOCAL_SCORER_WARNING_CHARS, MAX_LOCAL_SCORER_WARNING_COUNT } from "
import { loadRepoFocusManifest } from "../signals/focus-manifest-loader";
import { buildRepoOnboardingPackPreviewForRepo } from "../services/repo-onboarding-pack";
import { buildRepoSettingsPreview, type PublicSurfaceSkipReason } from "../signals/settings-preview";
import { buildGittensorConfigRecommendation, buildRegistrationReadiness, type InstallationHealthSummary } from "../signals/registration-readiness";
import {
buildGittensorConfigRecommendation,
buildRegistrationReadiness,
type InstallationHealthSummary,
type RegistrationReadinessReport,
} from "../signals/registration-readiness";
import { fileUpstreamDriftIssues, loadUpstreamStatus, refreshUpstreamDrift, registryHyperparameterDriftWarningsForRepo } from "../upstream/ruleset";
import type {
BountyLifecycleEventRecord,
Expand Down Expand Up @@ -1491,6 +1497,22 @@ export function createApp() {
return c.json(await buildGittensorConfigRecommendationResponse(c.env, fullName));
});

app.get("/v1/app/self-dogfood/registration-pack", async (c) => {
const forbidden = await requireAppRole(c, ["maintainer", "owner", "operator"]);
if (forbidden) return forbidden;
return c.json(await buildSelfDogfoodRegistrationPackResponse(c.env));
});

app.get("/v1/repos/:owner/:repo/self-dogfood-registration-pack", async (c) => {
const forbidden = await requireAppRole(c, ["maintainer", "owner", "operator"]);
if (forbidden) return forbidden;
const fullName = `${c.req.param("owner")}/${c.req.param("repo")}`;
if (fullName.toLowerCase() !== resolveSelfDogfoodRepoFullName(c.env).toLowerCase()) {
return c.json({ error: "self_dogfood_repo_only", repoFullName: resolveSelfDogfoodRepoFullName(c.env) }, 403);
}
return c.json(await buildSelfDogfoodRegistrationPackResponse(c.env));
});

app.get("/v1/repos/:owner/:repo/onboarding-pack/preview", async (c) => {
const fullName = `${c.req.param("owner")}/${c.req.param("repo")}`;
const forbidden = await requireAppRole(c, ["maintainer", "owner", "operator"]);
Expand Down Expand Up @@ -2898,6 +2920,24 @@ function stripOwnerPolicyContext<T extends { ownerContext: unknown }>(policyRead
return publicPolicyReadiness;
}

async function buildSelfDogfoodRegistrationPackResponse(env: Env) {
const fullName = resolveSelfDogfoodRepoFullName(env);
const [readinessPayload, recommendationPayload] = await Promise.all([
buildRegistrationReadinessResponse(env, fullName),
buildGittensorConfigRecommendationResponse(env, fullName),
]);
const { dataQuality: _readinessQuality, ...registrationReadiness } = readinessPayload;
const { dataQuality: _recommendationQuality, ...gittensorConfigRecommendation } = recommendationPayload;
return {
...buildSelfDogfoodRegistrationPack({
repoFullName: fullName,
registrationReadiness: registrationReadiness as RegistrationReadinessReport,
gittensorConfigRecommendation,
}),
dataQuality: _readinessQuality,
};
}

async function buildGittensorConfigRecommendationResponse(env: Env, fullName: string) {
/* v8 ignore start -- Config recommendation route-level shaping over covered signal helpers. */
const intelligence = await buildRepoIntelligenceResponse(env, fullName);
Expand Down
16 changes: 16 additions & 0 deletions src/openapi/spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,22 @@ export function buildOpenApiSpec() {
200: { description: "Private Gittensor config recommendation for repo owners", content: { "application/json": { schema: GittensorConfigRecommendationSchema } } },
},
});
registry.registerPath({
method: "get",
path: "/v1/app/self-dogfood/registration-pack",
responses: {
200: { description: "Private self-dogfood registration pack for the Gittensory repo", content: { "application/json": { schema: z.record(z.string(), z.unknown()) } } },
403: { description: "Insufficient role for maintainer-only self-dogfood report" },
},
});
registry.registerPath({
method: "get",
path: "/v1/repos/{owner}/{repo}/self-dogfood-registration-pack",
responses: {
200: { description: "Private self-dogfood registration pack when repo matches configured Gittensory target", content: { "application/json": { schema: z.record(z.string(), z.unknown()) } } },
403: { description: "Insufficient role or repo is not the configured self-dogfood target" },
},
});
registry.registerPath({
method: "get",
path: "/v1/repos/{owner}/{repo}/onboarding-pack/preview",
Expand Down
161 changes: 161 additions & 0 deletions src/services/self-dogfood-registration-pack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import {
buildGittensorConfigRecommendation,
buildRegistrationReadiness,
type GittensorConfigRecommendation,
type GittensorConfigRecommendationInput,
type RegistrationReadinessInput,
type RegistrationReadinessReport,
} from "../signals/registration-readiness";
import { nowIso } from "../utils/json";

export const DEFAULT_SELF_DOGFOOD_REPO = "JSONbored/gittensory";

export type SelfDogfoodActionArea = {
area: string;
status: "ready" | "needs_attention" | "blocked";
actions: string[];
};

export type SelfDogfoodRegistrationPack = {
kind: "gittensory_self_dogfood_registration_pack";
repoFullName: string;
generatedAt: string;
privateOnly: true;
advisoryOnly: true;
directPrFirst: boolean;
contributorLaneStrategy: string;
maintainerEconomicsNote: string;
minerScoreabilityNote: string;
registrationReadiness: RegistrationReadinessReport;
gittensorConfigRecommendation: GittensorConfigRecommendation;
actionableAreas: SelfDogfoodActionArea[];
rerunHint: string;
};

export function resolveSelfDogfoodRepoFullName(env: { GITTENSORY_DRIFT_ISSUE_REPO?: string }): string {
const configured = env.GITTENSORY_DRIFT_ISSUE_REPO?.trim();
if (!configured || !configured.includes("/")) return DEFAULT_SELF_DOGFOOD_REPO;
return configured;
}

export function buildSelfDogfoodRegistrationPack(args: {
repoFullName: string;
registrationReadiness: RegistrationReadinessReport;
gittensorConfigRecommendation: GittensorConfigRecommendation;
}): SelfDogfoodRegistrationPack {
const { registrationReadiness: readiness, gittensorConfigRecommendation: recommendation } = args;
const issueDiscoveryReady =
readiness.issueDiscoveryReadiness.ready && readiness.issueDiscoveryReadiness.recommendation === "enabled";
const directPrFirst = !issueDiscoveryReady && readiness.recommendedRegistrationMode !== "issue_discovery";

return {
kind: "gittensory_self_dogfood_registration_pack",
repoFullName: args.repoFullName,
generatedAt: nowIso(),
privateOnly: true,
advisoryOnly: true,
directPrFirst,
contributorLaneStrategy: directPrFirst
? "Keep contributor intake direct-PR-first until issue-discovery signals, label policy, and queue health are excellent."
: "Issue-discovery intake is strong enough to keep a bounded issue-discovery lane alongside direct PRs.",
maintainerEconomicsNote:
"Maintainer cut and registry emission splits are maintainer-economics controls only; they do not change private miner scoreability or public compensation claims.",
minerScoreabilityNote:
"Miner-facing scoreability stays in private API/MCP surfaces with hashed actors; sensitive identity and ranking fields stay out of this report.",
registrationReadiness: readiness,
gittensorConfigRecommendation: recommendation,
actionableAreas: buildActionableAreas(readiness, recommendation),
rerunHint: "Rerun this pack after registry, .gittensor.yml, label policy, GitHub App, or queue changes to refresh readiness and config tradeoffs.",
};
}

export function buildSelfDogfoodRegistrationPackFromSignals(
input: RegistrationReadinessInput & GittensorConfigRecommendationInput,
): SelfDogfoodRegistrationPack {
const registrationReadiness = buildRegistrationReadiness(input);
const gittensorConfigRecommendation = buildGittensorConfigRecommendation(input);
return buildSelfDogfoodRegistrationPack({
repoFullName: input.repoFullName,
registrationReadiness,
gittensorConfigRecommendation,
});
}

function buildActionableAreas(
readiness: RegistrationReadinessReport,
recommendation: GittensorConfigRecommendation,
): SelfDogfoodActionArea[] {
const areas: SelfDogfoodActionArea[] = [
{
area: "direct_pr",
status: readiness.directPrReadiness.ready ? "ready" : readiness.blockers.length > 0 ? "blocked" : "needs_attention",
actions: readiness.directPrReadiness.ready
? ["Keep direct PRs as the default contributor lane."]
: [...readiness.directPrReadiness.reasons, ...readiness.blockers],
},
{
area: "issue_discovery",
status:
readiness.issueDiscoveryReadiness.recommendation === "not_recommended"
? "blocked"
: readiness.issueDiscoveryReadiness.ready
? "ready"
: "needs_attention",
actions:
readiness.issueDiscoveryReadiness.reasons.length > 0
? readiness.issueDiscoveryReadiness.reasons
: ["Issue discovery is intentionally deprioritized until intake is staffed and config is excellent."],
},
{
area: "label_policy",
status: readiness.labelPolicy.trustedPipelineReady ? "ready" : "needs_attention",
actions: [
...(readiness.labelPolicy.missingOrUnusedRegistryLabels.length > 0
? readiness.labelPolicy.missingOrUnusedRegistryLabels.map((label) => `Add or retire registry label "${label}".`)
: ["Label policy matches cached repo activity."]),
recommendation.recommended.labelMultipliers === "start_without_trusted_label_multipliers"
? "Start without trusted label multipliers until labels are observed in live activity."
: "Prune unused configured labels before expanding trusted multipliers.",
],
},
{
area: "maintainer_cut",
status: readiness.maintainerCutReadiness.ready ? "ready" : "needs_attention",
actions: readiness.maintainerCutReadiness.ready
? [`Consider maintainer cut near ${recommendation.recommended.maintainerCut}; keep it separate from miner scoreability.`]
: readiness.maintainerCutReadiness.reasons,
},
{
area: "tests_and_docs",
status: readiness.testCoverageHealth.status === "gate_ready" ? "ready" : "needs_attention",
actions: [
...readiness.testCoverageHealth.requiredGate.map((gate) => `Preserve CI gate: ${gate}.`),
...readiness.docsCompleteness.requiredDocs.map((doc) => `Keep ${doc} current for contributor intake.`),
],
},
{
area: "queue_and_github_app",
status:
readiness.queueHealth.level === "critical" || readiness.queueHealth.level === "high"
? "blocked"
: readiness.githubApp.installed
? "ready"
: "needs_attention",
actions: [
readiness.queueHealth.summary,
readiness.githubApp.behavior,
...readiness.githubApp.warnings,
].filter(Boolean),
},
];

if (readiness.blockers.length > 0) {
areas.unshift({
area: "registration_blockers",
status: "blocked",
actions: readiness.blockers,
});
}

return areas;
}
26 changes: 26 additions & 0 deletions test/unit/focus-manifest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ describe("parseFocusManifestContent", () => {
expect(manifest.present).toBe(false);
expect(manifest.warnings.join(" ")).toMatch(/not valid JSON/i);
});

it("warns when JSON content is not a mapping", () => {
for (const content of ['["a","b"]', '"string"']) {
const manifest = parseFocusManifestContent(content);
expect(manifest.present).toBe(false);
expect(manifest.warnings.join(" ")).toMatch(/must be a mapping/i);
}
});
});

describe("matchesManifestPath", () => {
Expand Down Expand Up @@ -366,6 +374,24 @@ describe("compileFocusManifestPolicy", () => {
expect(publicText).toContain("npm run test:ci");
});

it("skips unsafe publicNotes when entry guidance is compiled from a raw manifest", () => {
const policy = compileFocusManifestPolicy({
present: true,
source: "api_record",
wantedPaths: ["src/"],
blockedPaths: [],
preferredLabels: [],
linkedIssuePolicy: "optional",
testExpectations: [],
issueDiscoveryPolicy: "neutral",
maintainerNotes: [],
publicNotes: ["Keep PRs focused.", "Maximize your reward payout"],
warnings: [],
});
expect(policy.publicSafe.entryGuidance).toContain("Keep PRs focused.");
expect(policy.publicSafe.entryGuidance.join(" ")).not.toMatch(/reward payout/i);
});

it("publicSafe.summary never contains forbidden language", () => {
const dangerous = parseFocusManifest({ wantedPaths: ["src/"], publicNotes: ["Boost your raw trust score here"] });
const policy = compileFocusManifestPolicy(dangerous);
Expand Down
15 changes: 15 additions & 0 deletions test/unit/registration-readiness.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,21 @@ describe("buildRegistrationReadiness", () => {
expect(report.githubApp.behavior).toContain("for all PRs");
});

it("describes a quiet public surface while keeping the opt-in gate check enabled", () => {
const repo = repoFor("octo/quiet-gate", configFor({ repo: "octo/quiet-gate" }));
const settings = settingsFor(repo.fullName, { publicSurface: "off", gateCheckMode: "enabled" });
const report = buildRegistrationReadiness({
repoFullName: repo.fullName,
repo,
settings,
installation: healthyInstall,
...signalsFor(repo, [], [], [label("bug")]),
});

expect(report.githubApp.behavior).toContain("stays quiet");
expect(report.githubApp.behavior).toContain("opt-in gate check still enabled");
});

it("notes when the GitHub App is not installed", () => {
const repo = repoFor("octo/uninstalled", configFor({ repo: "octo/uninstalled" }), { isInstalled: false, installationId: null });
const report = buildRegistrationReadiness({ repoFullName: repo.fullName, repo, settings: settingsFor(repo.fullName), installation: null, ...signalsFor(repo, [], [], [label("bug")]) });
Expand Down
58 changes: 58 additions & 0 deletions test/unit/routes-self-dogfood-registration-pack.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { describe, expect, it } from "vitest";
import { createApp } from "../../src/api/routes";
import { createSessionForGitHubUser } from "../../src/auth/security";
import { createTestEnv } from "../helpers/d1";

const SELF_DOGFOOD_PATH = "/v1/repos/JSONbored/gittensory/self-dogfood-registration-pack";

function apiHeaders(env: Env): Record<string, string> {
return {
authorization: `Bearer ${env.GITTENSORY_API_TOKEN}`,
"content-type": "application/json",
};
}

describe("self-dogfood registration-pack route auth", () => {
it("rejects unauthenticated access to the repo-scoped route", async () => {
const app = createApp();
const env = createTestEnv();
const response = await app.request(SELF_DOGFOOD_PATH, {}, env);
expect(response.status).toBe(401);
await expect(response.json()).resolves.toMatchObject({ error: "unauthorized" });
});

it("rejects unauthorized session access to the repo-scoped route", async () => {
const app = createApp();
const env = createTestEnv({ ADMIN_GITHUB_LOGINS: "jsonbored" });
const { token } = await createSessionForGitHubUser(env, { login: "new-user", id: 2468 });
const response = await app.request(SELF_DOGFOOD_PATH, { headers: { cookie: `gittensory_session=${token}` } }, env);
expect(response.status).toBe(403);
await expect(response.json()).resolves.toMatchObject({ error: "insufficient_role" });
});

it("rejects wrong-repo access after role check", async () => {
const app = createApp();
const env = createTestEnv({ ADMIN_GITHUB_LOGINS: "jsonbored" });
const { token } = await createSessionForGitHubUser(env, { login: "jsonbored", id: 1 });
const response = await app.request(
"/v1/repos/other/repo/self-dogfood-registration-pack",
{ headers: { cookie: `gittensory_session=${token}` } },
env,
);
expect(response.status).toBe(403);
await expect(response.json()).resolves.toMatchObject({ error: "self_dogfood_repo_only", repoFullName: "JSONbored/gittensory" });
});

it("allows static-token access to the configured self-dogfood repo", async () => {
const app = createApp();
const env = createTestEnv();
const response = await app.request(SELF_DOGFOOD_PATH, { headers: apiHeaders(env) }, env);
expect(response.status).toBe(200);
await expect(response.json()).resolves.toMatchObject({
kind: "gittensory_self_dogfood_registration_pack",
repoFullName: "JSONbored/gittensory",
privateOnly: true,
advisoryOnly: true,
});
});
});
Loading