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
19 changes: 14 additions & 5 deletions src/signals/engine.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {

Check warning on line 1 in src/signals/engine.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Possible duplicate overlap

Items reference the same linked issue #627.

Check notice on line 1 in src/signals/engine.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Possible duplicate overlap

Open PR work references issue #627.

Check notice on line 1 in src/signals/engine.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Issue discovery is disabled for this repo

This repo is configured for direct contribution review rather than issue-discovery flow.
AdvisoryFinding,
BountyRecord,
CheckSummaryRecord,
Expand Down Expand Up @@ -3839,6 +3839,14 @@

export const PR_PANEL_RETRIGGER_MARKER = "<!-- gittensory-rerun-review:v1 -->";

/** Earn-CTA target for a public-comment footer. The repo-scoped miner page is only meaningful for
* repos registered on Gittensor (per `gittensorRepoEarnUrl`'s documented contract); for an
* unregistered repo the page has no miner data, so fall back to the general Gittensor home URL
* (the `gittensoryFooter` default) instead of implying THIS repo's contributions already earn. */
function footerEarnUrl(repo: RepositoryRecord | null, repoFullName: string): string | undefined {
return repo?.isRegistered ? gittensorRepoEarnUrl(repoFullName) : undefined;
}

export function buildPublicPrIntelligenceComment(args: {
repo: RepositoryRecord | null;
pr: PullRequestRecord;
Expand Down Expand Up @@ -3948,9 +3956,10 @@
publicFindings.length > 0
? publicFindings.map((finding) => `- ${sanitizePanelText(finding.title)}: ${sanitizePanelText(finding.publicText ?? finding.detail)}`)
: ["- No public-safe advisory findings were generated from cached metadata."];
// Always-on earn CTA — a permanent, free marketing surface on every reviewed PR. The CTA points at
// this repo's public Gittensor miner page (social proof for THIS repo + a path to register).
const footer = gittensoryFooter({ earnUrl: gittensorRepoEarnUrl(args.pr.repoFullName) });
// Always-on earn CTA — a permanent, free marketing surface on every reviewed PR. For a registered
// repo the CTA points at this repo's public Gittensor miner page (social proof for THIS repo + a
// path to register); for an unregistered repo it falls back to the general Gittensor home URL.
const footer = gittensoryFooter({ earnUrl: footerEarnUrl(args.repo, args.pr.repoFullName) });
return [
"<!-- gittensory-pr-panel:v1 -->",
"",
Expand Down Expand Up @@ -4014,7 +4023,7 @@
* analysis is for registered Gittensor contributors, so we skip the panel and post a brief welcome
Comment thread
JSONbored marked this conversation as resolved.
* + earn invite; the always-on footer CTA does the conversion. Carries the same panel marker so it
* updates in place if the author later registers (the full panel then replaces it). */
function buildMinimalInviteComment(args: { pr: PullRequestRecord }): string {
function buildMinimalInviteComment(args: { repo: RepositoryRecord | null; pr: PullRequestRecord }): string {
return [
"<!-- gittensory-pr-panel:v1 -->",
"",
Expand All @@ -4025,7 +4034,7 @@
]),
"",
"---",
gittensoryFooter({ earnUrl: gittensorRepoEarnUrl(args.pr.repoFullName) }),
gittensoryFooter({ earnUrl: footerEarnUrl(args.repo, args.pr.repoFullName) }),
].join("\n");
}

Expand Down
58 changes: 58 additions & 0 deletions test/unit/signals.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, expect, it } from "vitest";

Check warning on line 1 in test/unit/signals.test.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Possible duplicate overlap

Items reference the same linked issue #627.

Check notice on line 1 in test/unit/signals.test.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Possible duplicate overlap

Open PR work references issue #627.

Check notice on line 1 in test/unit/signals.test.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Issue discovery is disabled for this repo

This repo is configured for direct contribution review rather than issue-discovery flow.
import {
buildBountyAdvisory,
buildBurdenForecast,
Expand Down Expand Up @@ -30,6 +30,7 @@
detectGittensorContributor,
shouldPublishPrIntelligenceComment,
} from "../../src/signals/engine";
import { GITTENSOR_HOME_URL } from "../../src/github/footer";
import type {
BountyRecord,
CheckSummaryRecord,
Expand Down Expand Up @@ -357,6 +358,63 @@
expect(comment).not.toMatch(/wallet|raw trust score|ranking|farming|reward/i);
});

it("scopes the earn-footer CTA to the repo miner page only when the repo is registered", () => {
const currentPr = pullRequests[0]!;
const settings = {
repoFullName: repo.fullName,
commentMode: "detected_contributors_only" as const,
publicAudienceMode: "gittensor_only" as const,
publicSignalLevel: "standard" as const,
checkRunMode: "off" as const,
checkRunDetailLevel: "minimal" as const,
gateCheckMode: "off" as const,
linkedIssueGateMode: "advisory" as const,
duplicatePrGateMode: "advisory" as const,
qualityGateMode: "advisory" as const,
qualityGateMinScore: null,
autoLabelEnabled: true,
gittensorLabel: "gittensor",
createMissingLabel: true,
publicSurface: "comment_and_label" as const,
includeMaintainerAuthors: false,
requireLinkedIssue: false,
backfillEnabled: true,
privateTrustEnabled: true,
};
const collisions = buildCollisionReport(repo.fullName, issues, pullRequests);
const queueHealth = buildQueueHealth(repo, issues, pullRequests, collisions);
const preflight = buildPreflightResult({ repoFullName: repo.fullName, title: currentPr.title, body: "Fixes #7", linkedIssues: [7] }, repo, issues, pullRequests);
const repoEarnPage = `${GITTENSOR_HOME_URL}/miners/repository?name=${encodeURIComponent(repo.fullName)}&tab=miners`;
const homeCta = `(${GITTENSOR_HOME_URL})`;

// Detected contributor → full panel. Registered repo links the repo miner page; unregistered repo
// must NOT (the page has no miner data for an unregistered repo) and falls back to the home URL.
const priorPr: PullRequestRecord = { ...currentPr, number: 3, state: "closed", mergedAt: "2026-05-01T00:00:00.000Z" };
const detected = { ...detectGittensorContributor("oktofeesh1", currentPr, [currentPr, priorPr], []), source: "official_gittensor_api" as const };
const detectedProfile = buildContributorProfile("oktofeesh1", { login: "oktofeesh1", topLanguages: ["TypeScript"], source: "github" }, [currentPr, priorPr], []);
expect(detected.detected).toBe(true);

const registeredComment = buildPublicPrIntelligenceComment({ repo, pr: currentPr, profile: detectedProfile, detection: detected, queueHealth, collisions, preflight, settings });
expect(registeredComment).toContain(repoEarnPage);

const unregisteredRepo = { ...repo, isRegistered: false, registryConfig: null };
const unregisteredComment = buildPublicPrIntelligenceComment({ repo: unregisteredRepo, pr: currentPr, profile: detectedProfile, detection: detected, queueHealth, collisions, preflight, settings });
expect(unregisteredComment).not.toContain("/miners/repository");
expect(unregisteredComment).toContain(homeCta);

// Non-detected contributor → minimal invite. Same registration gating must hold there.
const undetected = detectGittensorContributor("brand-new-outsider", currentPr, [], []);
const undetectedProfile = buildContributorProfile("brand-new-outsider", { login: "brand-new-outsider", topLanguages: [], source: "github" }, [], []);
expect(undetected.detected).toBe(false);

const minimalRegistered = buildPublicPrIntelligenceComment({ repo, pr: currentPr, profile: undetectedProfile, detection: undetected, queueHealth, collisions, preflight, settings });
expect(minimalRegistered).toContain(repoEarnPage);

const minimalUnregistered = buildPublicPrIntelligenceComment({ repo: unregisteredRepo, pr: currentPr, profile: undetectedProfile, detection: undetected, queueHealth, collisions, preflight, settings });
expect(minimalUnregistered).not.toContain("/miners/repository");
expect(minimalUnregistered).toContain(homeCta);
});

it("builds a compact, source-free public AI signal bundle", () => {
const sourceMarker = "SECRET_SOURCE_LINE_should_never_reach_ai_provider";
const currentPr: PullRequestRecord = {
Expand Down