From 7b89ddaa5088c2a99518ec82e6ea7b539d812e03 Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Sun, 14 Jun 2026 05:05:56 -0700 Subject: [PATCH] feat(funnel): surface the earn-on-Gittensor path for oss-anti-slop adopters (#694) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completes Pillar 6's funnel: a non-Gittensor adopter running the `oss-anti-slop` pack now sees an opt-in path from "I use the anti-slop gate" → "I'm a Gittensor contributor." - The predicted-gate verdict gains a `funnel` field, populated ONLY under the `oss-anti-slop` pack (null under `gittensor` — those contributors are already on Gittensor): a public-safe "Gittensor lets GitHub contributors earn for work like this — register to start earning" CTA + the register URL (reuses GITTENSOR_HOME_URL, same "earn"-only wording as the PR-comment footer). - Surfaced through the `gittensory_predict_gate` MCP tool (the agent-native self-check) so an agent on a non-Gittensor repo sees the conversion path inline. Opt-in + non-spammy (one CTA, oss-anti-slop only, never reward/payout/score wording). Tests: funnel present under oss-anti-slop with the register URL + "earn" copy, null under gittensor, and public-safe. 97% coverage gate green; workers pass. --- src/mcp/server.ts | 1 + src/rules/predicted-gate.ts | 12 ++++++++++++ test/unit/predicted-gate.test.ts | 9 +++++++++ 3 files changed, 22 insertions(+) diff --git a/src/mcp/server.ts b/src/mcp/server.ts index 92748bf228..005ffefca7 100644 --- a/src/mcp/server.ts +++ b/src/mcp/server.ts @@ -381,6 +381,7 @@ const predictGateOutputSchema = { readinessScore: z.number().nullable().optional(), blockers: z.unknown().optional(), warnings: z.unknown().optional(), + funnel: z.unknown().optional(), note: z.string().optional(), }; diff --git a/src/rules/predicted-gate.ts b/src/rules/predicted-gate.ts index f21e7ebe36..51e307ed30 100644 --- a/src/rules/predicted-gate.ts +++ b/src/rules/predicted-gate.ts @@ -8,7 +8,15 @@ import { } from "../signals/engine"; import type { FocusManifest } from "../signals/focus-manifest"; import { sanitizePublicComment } from "../github/commands"; +import { GITTENSOR_HOME_URL } from "../github/footer"; import type { BountyRecord, GatePolicyPack, IssueRecord, PullRequestRecord, RepositoryRecord } from "../types"; + +// Opt-in funnel (#694): a non-Gittensor adopter running the `oss-anti-slop` pack learns that Gittensor pays +// contributors for OSS work like this. Public-safe "earn" wording only (never reward/payout/score). +const OSS_ANTI_SLOP_FUNNEL = { + message: "This repo runs the Gittensor anti-slop gate. Gittensor lets GitHub contributors earn for open-source work like this — register to start earning.", + registerUrl: GITTENSOR_HOME_URL, +} as const; import { buildPullRequestAdvisory, evaluateGateCheck, type GateCheckConclusion } from "./advisory"; /** @@ -38,6 +46,9 @@ export type PredictedGateVerdict = { confirmedContributor: boolean | undefined; blockers: Array<{ code: string; title: string; detail: string; action?: string | undefined }>; warnings: Array<{ code: string; title: string; detail: string; action?: string | undefined }>; + /** Opt-in conversion funnel (#694): present only under the `oss-anti-slop` pack — a non-Gittensor + * adopter's path to "earn on Gittensor". `null` under `gittensor` (the contributor is already there). */ + funnel: { message: string; registerUrl: string } | null; note: string; }; @@ -149,6 +160,7 @@ export function buildPredictedGateVerdict(args: { confirmedContributor: effectiveConfirmedContributor, blockers: evaluation.blockers.map(publicSafeFinding), warnings: evaluation.warnings.map(publicSafeFinding), + funnel: pack === "oss-anti-slop" ? { ...OSS_ANTI_SLOP_FUNNEL } : null, note: PREDICTED_GATE_NOTE, }; } diff --git a/test/unit/predicted-gate.test.ts b/test/unit/predicted-gate.test.ts index da4d0149b8..85c25d7631 100644 --- a/test/unit/predicted-gate.test.ts +++ b/test/unit/predicted-gate.test.ts @@ -85,6 +85,15 @@ describe("pack-aware prediction (#693)", () => { expect(verdict({ gate: { duplicates: "block" } }).pack).toBe("gittensor"); }); + it("surfaces the earn funnel only under oss-anti-slop (#694), public-safe", () => { + expect(verdict({ gate: { duplicates: "block" } }).funnel).toBeNull(); + const oss = verdict({ gate: { pack: "oss-anti-slop", duplicates: "block" } }); + expect(oss.funnel).not.toBeNull(); + expect(oss.funnel?.registerUrl).toBe("https://gittensor.io"); + expect(oss.funnel?.message.toLowerCase()).toContain("earn"); + expect(JSON.stringify(oss.funnel)).not.toMatch(/reward|payout|trust score|wallet/i); + }); + it("under oss-anti-slop, blocks ANY author — even a self-declared non-confirmed contributor", () => { const result = buildPredictedGateVerdict({ input: { ...BASE_INPUT, body: "no issue", linkedIssues: [] },