diff --git a/src/github/commands.ts b/src/github/commands.ts index ca7da7c3af..ef36b49b0f 100644 --- a/src/github/commands.ts +++ b/src/github/commands.ts @@ -23,6 +23,16 @@ export type GittensoryMentionCommand = { raw: string; }; +type PublicAnswerCard = { + title: string; + summary: string; + findings: string[]; + evidence: string[]; + nextActions: string[]; + sourceNotes: string[]; + safeDetails?: string[] | undefined; +}; + const COMMANDS = new Set(GITTENSORY_MENTION_COMMAND_CATALOG.map((command) => command.id)); const MAINTAINER_ASSOCIATIONS = new Set(["OWNER", "MEMBER", "COLLABORATOR"]); @@ -91,6 +101,13 @@ export function buildPublicAgentCommandComment(args: { }): string { const repoFullName = args.repo?.fullName ?? args.pullRequest?.repoFullName ?? "this repository"; const sections = commandSections(args.command.name, args.bundle, args.officialMiner); + const card = buildPublicAnswerCard({ + command: args.command.name, + sections, + bundle: args.bundle, + officialMiner: args.officialMiner, + actorKind: args.actorKind, + }); const body = [ AGENT_COMMAND_COMMENT_MARKER, `### ${COMMAND_TITLES[args.command.name]}`, @@ -98,13 +115,167 @@ export function buildPublicAgentCommandComment(args: { `Command: \`@gittensory ${args.command.name}\``, `Scope: ${repoFullName}#${args.issue.number}`, "", - ...sections, + ...renderPublicAnswerCard(card), "", - "_Advisory context only. Public comments exclude non-public contributor signals and reviewability internals._", + "_Advisory context only. Public comments exclude non-public contributor signals and private planning internals._", ].join("\n"); return sanitizePublicComment(body); } +function buildPublicAnswerCard(args: { + command: GittensoryMentionCommandName; + sections: string[]; + bundle: AgentRunBundle | null | undefined; + officialMiner: GittensorContributorSnapshot | null | undefined; + actorKind: "maintainer" | "author"; +}): PublicAnswerCard { + const [titleLine, ...contentLines] = args.sections; + const safeContent = contentLines.map(stripBulletPrefix).filter((line) => line.length > 0); + const findings = safeContent.length > 0 ? safeContent.slice(0, 5) : ["No public-safe findings are available from the current cached context."]; + return { + title: stripEmphasis(titleLine ?? "Answer"), + summary: commandSummary(args.command), + findings, + evidence: commandEvidence(args.command, args.bundle, args.officialMiner, args.actorKind), + nextActions: commandNextActions(args.command, args.bundle), + sourceNotes: commandSourceNotes(args.command, args.bundle, args.officialMiner), + safeDetails: safeContent.slice(5), + }; +} + +function renderPublicAnswerCard(card: PublicAnswerCard): string[] { + const lines = [ + `**${sanitizePublicComment(card.title)}**`, + "", + `- ${sanitizePublicComment(card.summary)}`, + "", + "**Findings**", + "", + ...card.findings.map((line) => `- ${sanitizePublicComment(line)}`), + "", + "**Evidence**", + "", + ...card.evidence.map((line) => `- ${sanitizePublicComment(line)}`), + "", + "**Next actions**", + "", + ...card.nextActions.map((line) => `- ${sanitizePublicComment(line)}`), + "", + "
", + "Source and freshness", + "", + ...card.sourceNotes.map((line) => `- ${sanitizePublicComment(line)}`), + "", + "
", + ]; + if (card.safeDetails && card.safeDetails.length > 0) { + lines.push("", "
", "Additional safe details", "", ...card.safeDetails.map((line) => `- ${sanitizePublicComment(line)}`), "", "
"); + } + return lines; +} + +function commandSummary(command: GittensoryMentionCommandName): string { + switch (command) { + case "help": + return "Available public commands and their safest use on a PR thread."; + case "miner-context": + return "Public miner context from official Gittensor data when available."; + case "preflight": + return "Public PR hygiene and validation readiness for this thread."; + case "blockers": + return "Public readiness blockers that are safe to show in a PR comment."; + case "duplicate-check": + return "Public duplicate, WIP, and queue-overlap caution."; + case "next-action": + return "One public-safe next step for the contributor or maintainer."; + case "reviewability": + return "Maintainer-friendly PR readiness without private review internals."; + case "repo-fit": + return "Public-safe repository fit signals from cached context."; + case "packet": + return "Public-safe PR packet guidance for the current thread."; + } +} + +function commandEvidence( + command: GittensoryMentionCommandName, + bundle: AgentRunBundle | null | undefined, + officialMiner: GittensorContributorSnapshot | null | undefined, + actorKind: "maintainer" | "author", +): string[] { + const evidence = [`Invocation authorized for ${actorKind} command use.`, "Output is sanitized before posting to GitHub."]; + if (command === "miner-context") { + evidence.push(officialMiner ? "Official Gittensor miner context was available." : "Official Gittensor miner context was unavailable."); + } + if (bundle) { + evidence.push(`Agent response status: ${publicStatus(bundle.run.status)}.`); + } + return evidence; +} + +function commandNextActions(command: GittensoryMentionCommandName, bundle: AgentRunBundle | null | undefined): string[] { + if (bundle?.run.status === "needs_snapshot_refresh") return ["Retry after the contributor decision snapshot refresh completes."]; + switch (command) { + case "help": + return ["Comment one listed command on the PR thread when more context is needed."]; + case "miner-context": + return ["Use MCP or the authenticated control panel for private contributor planning."]; + case "preflight": + return ["Run local validation and rerun before asking for maintainer review."]; + case "blockers": + return ["Resolve visible blockers before requesting detailed review."]; + case "duplicate-check": + return ["Compare linked issues, open PRs, and recent merges before expanding the branch."]; + case "next-action": + return ["Follow the recommended public-safe action, then rerun if PR state changes."]; + case "reviewability": + return ["Use this as public readiness guidance, then rerun after validation or maintainer state changes."]; + case "repo-fit": + return ["Use MCP or the authenticated control panel for deeper private repository-fit planning."]; + case "packet": + return ["Use this as public PR-thread guidance only; keep private scoring and planning details out of comments."]; + } +} + +function commandSourceNotes( + command: GittensoryMentionCommandName, + bundle: AgentRunBundle | null | undefined, + officialMiner: GittensorContributorSnapshot | null | undefined, +): string[] { + const source = + command === "help" + ? "static command catalog" + : command === "miner-context" + ? officialMiner + ? "official Gittensor miner API" + : "official miner check fallback" + : "cached Gittensory agent context"; + return [ + `Source: ${source}.`, + `Freshness: ${publicFreshness(bundle, command)}.`, + "Boundary: public GitHub comment; non-public scoring and planning context is omitted.", + ]; +} + +function publicFreshness(bundle: AgentRunBundle | null | undefined, command: GittensoryMentionCommandName): string { + if (command === "help") return "shipped command list"; + if (!bundle) return "no agent run was required or available"; + if (bundle.run.status === "needs_snapshot_refresh") return "snapshot refresh in progress"; + return `agent run status ${publicStatus(bundle.run.status)}`; +} + +function publicStatus(status: string): string { + return status.replace(/_/g, " "); +} + +function stripBulletPrefix(value: string): string { + return stripEmphasis(value).replace(/^-\s+/, "").trim(); +} + +function stripEmphasis(value: string): string { + return value.replace(/^\*\*/, "").replace(/\*\*$/, "").trim(); +} + function commandSections( command: GittensoryMentionCommandName, bundle: AgentRunBundle | null | undefined, diff --git a/test/unit/github-commands.test.ts b/test/unit/github-commands.test.ts index 4440387694..7cdb1229e7 100644 --- a/test/unit/github-commands.test.ts +++ b/test/unit/github-commands.test.ts @@ -99,9 +99,15 @@ describe("GitHub mention commands", () => { }); expect(body).toContain(""); expect(body).toContain("Scope: this repository#12"); + expect(body).toContain("**Findings**"); + expect(body).toContain("**Evidence**"); + expect(body).toContain("**Next actions**"); + expect(body).toContain("Source and freshness"); + expect(body).toContain("Source: cached Gittensory agent context."); + expect(body).toContain("Freshness: agent run status completed."); expect(body).not.toContain("Decision snapshot is stale"); expect(body).not.toContain("background rebuild"); - expect(body).not.toMatch(/wallet|hotkey|coldkey|estimated score|reward estimate|payout|farming|raw trust score|reviewability|private ranking/i); + expect(body).not.toMatch(/wallet|hotkey|coldkey|estimated score|reward estimate|payout|farming|raw trust score|reviewability|private ranking|public score estimate|scoreability/i); expect(body).not.toMatch(/private context,\s*private context/i); expect(sanitizePublicComment("wallet hotkey payout reviewability private ranking")).not.toMatch( /wallet|hotkey|payout|reviewability|private ranking/i, @@ -215,6 +221,11 @@ describe("GitHub mention commands", () => { actorKind: "maintainer", }); expect(help).toContain("@gittensory duplicate-check"); + expect(help).toContain("Source and freshness"); + expect(help).toContain("Source: static command catalog."); + expect(help).toContain("Freshness: shipped command list."); + expect(help).toContain("Additional safe details"); + expect(help).toContain("@gittensory next-action"); const minerFallback = buildPublicAgentCommandComment({ command: parseGittensoryMentionCommand("@gittensory miner-context")!, @@ -260,6 +271,32 @@ describe("GitHub mention commands", () => { }, }); expect(refresh).toContain("**Blocker snapshot refresh**"); + expect(refresh).toContain("Freshness: snapshot refresh in progress."); + expect(refresh).toContain("Retry after the contributor decision snapshot refresh completes."); + + const preflightRefresh = buildPublicAgentCommandComment({ + command: parseGittensoryMentionCommand("@gittensory preflight")!, + repo: null, + issue: { number: 31, title: "PR", state: "open", pull_request: {} }, + pullRequest: null, + actorKind: "author", + bundle: { + run: { + id: "run-preflight-refresh", + objective: "refresh", + actorLogin: "oktofeesh1", + surface: "github_comment", + mode: "copilot", + status: "needs_snapshot_refresh", + dataQualityStatus: "unknown", + payload: {}, + }, + actions: [], + contextSnapshots: [], + summary: "refresh", + }, + }); + expect(preflightRefresh).toContain("**Preflight snapshot refresh**"); const duplicateRefresh = buildPublicAgentCommandComment({ command: parseGittensoryMentionCommand("@gittensory duplicate-check")!, @@ -320,6 +357,36 @@ describe("GitHub mention commands", () => { expect(noBundle).toContain("**Preflight summary**"); expect(noBundle).toContain("No public-safe context is available"); + const emptyBlockers = buildPublicAgentCommandComment({ + command: parseGittensoryMentionCommand("@gittensory blockers")!, + repo: null, + issue: { number: 45, title: "PR", state: "open", pull_request: {} }, + pullRequest: null, + actorKind: "maintainer", + bundle: { + run: completedRun("run-empty-blockers"), + actions: [], + contextSnapshots: [], + summary: "empty blockers", + }, + }); + expect(emptyBlockers).toContain("No public readiness blockers are visible"); + + const emptyDuplicate = buildPublicAgentCommandComment({ + command: parseGittensoryMentionCommand("@gittensory duplicate-check")!, + repo: null, + issue: { number: 46, title: "PR", state: "open", pull_request: {} }, + pullRequest: null, + actorKind: "maintainer", + bundle: { + run: completedRun("run-empty-duplicate"), + actions: [], + contextSnapshots: [], + summary: "empty duplicate", + }, + }); + expect(emptyDuplicate).toContain("No duplicate or work-in-progress collision signal is visible"); + const withPrFallbackScope = buildPublicAgentCommandComment({ command: parseGittensoryMentionCommand("@gittensory next-action")!, repo: null, @@ -454,6 +521,35 @@ describe("GitHub mention commands", () => { expect(preflightWithRerun).toContain("Rerun when:"); expect(preflightWithRerun).toContain("Open pull request queue pressure"); + const duplicateBlockerLabels = buildPublicAgentCommandComment({ + command: parseGittensoryMentionCommand("@gittensory blockers")!, + repo: null, + issue: { number: 25, title: "PR", state: "open", pull_request: {} }, + pullRequest: null, + actorKind: "maintainer", + bundle: { + run: completedRun("run-dedupe-blockers"), + actions: [ + { + id: "dedupe-blockers", + runId: "run-dedupe-blockers", + actionType: "explain_score_blockers", + status: "blocked", + recommendation: "Resolve blockers", + why: [], + blockedBy: ["open_pr_pressure", "open_pr_pressure"], + publicSafeSummary: "Resolve queue pressure.", + approvalRequired: true, + safetyClass: "private", + payload: {}, + }, + ], + contextSnapshots: [], + summary: "dedupe", + }, + }); + expect(duplicateBlockerLabels.match(/Open pull request queue pressure/g)).toHaveLength(1); + const duplicateFallbackPick = buildPublicAgentCommandComment({ command: parseGittensoryMentionCommand("@gittensory duplicate-check")!, repo: null,