Summary
The always-on "earn" footer added in #620 builds its CTA with
gittensorRepoEarnUrl(args.pr.repoFullName) unconditionally, for every
public PR comment. But that helper's own docstring scopes it to registered
repos. For a repo that has the GitHub App installed and public surface enabled
but is not registered on Gittensor (isRegistered === false), the footer
still points "register to start earning →" at that repo's Gittensor miner page —
implying contributions to this repo earn, when the repo isn't participating
yet. args.repo (which carries isRegistered) is available but unused.
Evidence
// src/github/footer.ts — the helper is documented as registered-repo-only
/** Public "who's earning on this repo" page ... Used for repos already
* registered on Gittensor (a contributor who just opened a PR here sees that
* contributions to THIS repo earn, then a path to join). */
export function gittensorRepoEarnUrl(repoFullName: string): string {
return `${GITTENSOR_HOME_URL}/miners/repository?name=${encodeURIComponent(repoFullName)}&tab=miners`;
}
// src/signals/engine.ts — buildPublicPrIntelligenceComment (args.repo: RepositoryRecord | null)
const footer = gittensoryFooter({ earnUrl: gittensorRepoEarnUrl(args.pr.repoFullName) });
// ...args.repo?.isRegistered is never consulted.
// src/signals/engine.ts — buildMinimalInviteComment (non-registered contributor path)
function buildMinimalInviteComment(args: { pr: PullRequestRecord }): string {
return [
...,
gittensoryFooter({ earnUrl: gittensorRepoEarnUrl(args.pr.repoFullName) }),
].join("\n");
}
gittensoryFooter already defines a safe fallback for the un-scoped case
(opts.earnUrl ?? GITTENSOR_HOME_URL), so the general Gittensor home URL is the
intended target when a repo-specific earn page does not apply.
Reachability
The public PR comment is posted whenever decision.willComment is true:
// src/queue/processors.ts
if (decision.willComment) {
const deterministicBody = buildPublicPrIntelligenceComment(commentArgs);
await createOrUpdatePrIntelligenceComment(env, installationId, repoFullName, pr.number, deterministicBody);
}
decidePublicSurface gates on the repo's surface settings
(publicSurface, commentMode, audience, author) — it does not check
repo.isRegistered. Registration filtering (.filter((repo) => repo.isRegistered))
appears in other processor jobs, but not on this webhook comment path. So a repo
that is App-installed with public comments enabled but absent from the Gittensor
registry reaches buildPublicPrIntelligenceComment and gets the repo-scoped earn
URL.
Why it's wrong
The product is deliberately careful about public earning claims — public
comments may only say "earn", never reward/payout/score (enforced via
sanitizePublicComment's forbidden words), precisely to avoid overstating
outcomes. Pointing an "Earn for contributions like this … register to start
earning →" CTA at an unregistered repo's miner page is the same class of
inaccurate public claim: it implies this repo's contributions are eligible to
earn when the repo is not participating, and the linked miner page has no data
for an unregistered repo. It also directly contradicts
gittensorRepoEarnUrl's documented "registered repos only" contract.
Suggested fix
Use the repo-scoped earn URL only when the repo is registered; otherwise fall
back to the general Gittensor home URL (the gittensoryFooter default).
// buildPublicPrIntelligenceComment (has args.repo)
const earnUrl = args.repo?.isRegistered ? gittensorRepoEarnUrl(args.pr.repoFullName) : undefined;
const footer = gittensoryFooter({ earnUrl });
buildMinimalInviteComment currently receives only { pr }; thread the
isRegistered flag (or repo) through so it can make the same decision, e.g.:
function buildMinimalInviteComment(args: { pr: PullRequestRecord; repo: RepositoryRecord | null }): string {
const earnUrl = args.repo?.isRegistered ? gittensorRepoEarnUrl(args.pr.repoFullName) : undefined;
return [ ..., gittensoryFooter({ earnUrl }) ].join("\n");
}
Add tests: a registered repo's comment footer links to the repo miner page; an
unregistered repo's footer links to GITTENSOR_HOME_URL (no repo-scoped page).
Test status
Not locked in. footer.test.ts covers gittensoryFooter/gittensorRepoEarnUrl
in isolation but does not assert that buildPublicPrIntelligenceComment /
buildMinimalInviteComment choose the repo-scoped vs general URL based on
isRegistered.
Confidence note
This is a moderate finding, not a slam-dunk. The severity depends on how
gittensor.io renders an unregistered repo's miner page, and one could argue
linking there is an intentional growth nudge. But it is reachable, non-duplicate,
and contradicts the helper's own documented "registered repos only" contract, and
the accurate-public-claim discipline elsewhere in the codebase supports treating
it as a defect.
Distinct from prior reports
Introduced by #620 ("earn footer + minimal invite"); no existing issue covers the
unconditional use of the registered-repo-only earn URL. Related in spirit to the
public-claim-accuracy hardening the project already invests in (the
sanitizePublicComment forbidden-word redaction), but a different surface.
Summary
The always-on "earn" footer added in #620 builds its CTA with
gittensorRepoEarnUrl(args.pr.repoFullName)unconditionally, for everypublic PR comment. But that helper's own docstring scopes it to registered
repos. For a repo that has the GitHub App installed and public surface enabled
but is not registered on Gittensor (
isRegistered === false), the footerstill points "register to start earning →" at that repo's Gittensor miner page —
implying contributions to this repo earn, when the repo isn't participating
yet.
args.repo(which carriesisRegistered) is available but unused.Evidence
gittensoryFooteralready defines a safe fallback for the un-scoped case(
opts.earnUrl ?? GITTENSOR_HOME_URL), so the general Gittensor home URL is theintended target when a repo-specific earn page does not apply.
Reachability
The public PR comment is posted whenever
decision.willCommentis true:decidePublicSurfacegates on the repo's surface settings(
publicSurface,commentMode, audience, author) — it does not checkrepo.isRegistered. Registration filtering (.filter((repo) => repo.isRegistered))appears in other processor jobs, but not on this webhook comment path. So a repo
that is App-installed with public comments enabled but absent from the Gittensor
registry reaches
buildPublicPrIntelligenceCommentand gets the repo-scoped earnURL.
Why it's wrong
The product is deliberately careful about public earning claims — public
comments may only say "earn", never reward/payout/score (enforced via
sanitizePublicComment's forbidden words), precisely to avoid overstatingoutcomes. Pointing an "Earn for contributions like this … register to start
earning →" CTA at an unregistered repo's miner page is the same class of
inaccurate public claim: it implies this repo's contributions are eligible to
earn when the repo is not participating, and the linked miner page has no data
for an unregistered repo. It also directly contradicts
gittensorRepoEarnUrl's documented "registered repos only" contract.Suggested fix
Use the repo-scoped earn URL only when the repo is registered; otherwise fall
back to the general Gittensor home URL (the
gittensoryFooterdefault).buildMinimalInviteCommentcurrently receives only{ pr }; thread theisRegisteredflag (orrepo) through so it can make the same decision, e.g.:Add tests: a registered repo's comment footer links to the repo miner page; an
unregistered repo's footer links to
GITTENSOR_HOME_URL(no repo-scoped page).Test status
Not locked in.
footer.test.tscoversgittensoryFooter/gittensorRepoEarnUrlin isolation but does not assert that
buildPublicPrIntelligenceComment/buildMinimalInviteCommentchoose the repo-scoped vs general URL based onisRegistered.Confidence note
This is a moderate finding, not a slam-dunk. The severity depends on how
gittensor.iorenders an unregistered repo's miner page, and one could arguelinking there is an intentional growth nudge. But it is reachable, non-duplicate,
and contradicts the helper's own documented "registered repos only" contract, and
the accurate-public-claim discipline elsewhere in the codebase supports treating
it as a defect.
Distinct from prior reports
Introduced by #620 ("earn footer + minimal invite"); no existing issue covers the
unconditional use of the registered-repo-only earn URL. Related in spirit to the
public-claim-accuracy hardening the project already invests in (the
sanitizePublicCommentforbidden-word redaction), but a different surface.