Summary
assertPublicSummaryClean is the final safety guard for the public-safe scenario
summary. It serializes the entire summary object and rejects it if it matches
FORBIDDEN_PUBLIC_LANGUAGE. But summary.repoFullName is set from the input
un-sanitized (it is the repo identifier, not rendered content). So when a repo
name contains a forbidden substring — and hotkey, coldkey, and wallet are
literal Bittensor/Gittensor protocol terms — the guard matches and
renderPublicScenarioSummary throws, so no scenario summary is produced for
that repo at all.
Evidence
// src/scenarios/scenario-summary.ts:92
const FORBIDDEN_PUBLIC_LANGUAGE =
/wallet|hotkey|coldkey|mnemonic|seed phrase|payout|reward[-\s]?estimate|farming|raw trust|trust[-\s]?score|scoreability|private[-\s]?reviewability|public[-\s]?score[-\s]?(?:estimate|prediction)/i;
// :180 the guard scans the WHOLE serialized summary, including repoFullName
function assertPublicSummaryClean(summary: PublicScenarioSummary): void {
const serialized = JSON.stringify(summary);
/* v8 ignore start -- All text fields are sanitized before this guard; defensive check for future fields. */
if (FORBIDDEN_PUBLIC_LANGUAGE.test(serialized)) {
throw new Error("Public scenario summary still contains forbidden language.");
}
/* v8 ignore end */
}
// :196 repoFullName is passed through verbatim -- never sanitized
export function renderPublicScenarioSummary(input: ScenarioSummaryInput): PublicScenarioSummary {
const summary: PublicScenarioSummary = {
repoFullName: input.repoFullName, // <-- un-sanitized; flows into the JSON.stringify guard above
...
};
assertPublicSummaryClean(summary);
return summary;
}
Every rendered text field (headline, options[].*, *Notes, dataClassification)
is run through sanitizePublicComment, so the guard's /* v8 ignore */ rationale
("all text fields are sanitized … defensive check") holds for those — but
repoFullName is a structural identifier that is not sanitized and is fully
controlled by the repo name. The author's stated invariant (the throw is
unreachable) is therefore false.
Concrete trace
renderPublicScenarioSummary({
repoFullName: "octo/hotkey-manager", // a Bittensor-themed repo name
generatedAt: "2026-06-12T00:00:00.000Z",
// ...any valid scenario inputs...
});
summary.repoFullName = "octo/hotkey-manager".
JSON.stringify(summary) contains "octo/hotkey-manager".
FORBIDDEN_PUBLIC_LANGUAGE.test(serialized) matches hotkey → throws
"Public scenario summary still contains forbidden language.".
The same happens for owner/wallet, metamask/wallet-adapter,
org/coldkey-vault, team/farming-bot, etc. The public scenario summary
(MCP/API/control-panel surface) cannot be produced for these repos.
Why it's wrong
The guard's purpose is to catch forbidden language that slipped into rendered
content, not to validate the repo identifier the summary is about. A repo is
legitimately allowed to be named hotkey-manager; refusing to render its advisory
scenario summary is a denial of functionality for exactly the ecosystem
Gittensory serves (Bittensor, where hotkey/coldkey/wallet are core terms).
Reachability
renderPublicScenarioSummary is the public-safe renderer for MCP/API clients and
control-panel UIs. repoFullName is the analyzed repo, so real repo names flow in
directly. Bittensor/crypto repos frequently contain hotkey, coldkey, wallet,
or farming in their names, making this readily reachable.
Test status
Not locked in. Every case in test/unit/scenario-summary.test.ts uses
repoFullName: "octo/demo"; no test exercises a repo name containing a forbidden
term, and none asserts renderPublicScenarioSummary either throws or succeeds for
such a name.
Suggested fix
Exclude structural identifiers (repoFullName, generatedAt) from the
forbidden-language guard so it only scans rendered free-text fields:
function assertPublicSummaryClean(summary: PublicScenarioSummary): void {
const { repoFullName: _repo, generatedAt: _at, ...rest } = summary;
if (FORBIDDEN_PUBLIC_LANGUAGE.test(JSON.stringify(rest))) {
throw new Error("Public scenario summary still contains forbidden language.");
}
}
Add a regression test: renderPublicScenarioSummary({ repoFullName: "octo/hotkey-wallet", … })
returns a summary whose repoFullName is preserved and does not throw.
Distinct from prior reports
Same class as the merged #457 (miner-command sanitizer breaking legitimate
repo/login names like wallet-adapter), but a different surface and mechanism:
here a public-output guard (not a redactor) hard-throws on the un-sanitized
repoFullName. The feature PRs #416/#345/#290 introduce the renderer; no existing
issue covers the repo-name throw.
Summary
assertPublicSummaryCleanis the final safety guard for the public-safe scenariosummary. It serializes the entire summary object and rejects it if it matches
FORBIDDEN_PUBLIC_LANGUAGE. Butsummary.repoFullNameis set from the inputun-sanitized (it is the repo identifier, not rendered content). So when a repo
name contains a forbidden substring — and
hotkey,coldkey, andwalletareliteral Bittensor/Gittensor protocol terms — the guard matches and
renderPublicScenarioSummarythrows, so no scenario summary is produced forthat repo at all.
Evidence
Every rendered text field (
headline,options[].*,*Notes,dataClassification)is run through
sanitizePublicComment, so the guard's/* v8 ignore */rationale("all text fields are sanitized … defensive check") holds for those — but
repoFullNameis a structural identifier that is not sanitized and is fullycontrolled by the repo name. The author's stated invariant (the throw is
unreachable) is therefore false.
Concrete trace
summary.repoFullName = "octo/hotkey-manager".JSON.stringify(summary)contains"octo/hotkey-manager".FORBIDDEN_PUBLIC_LANGUAGE.test(serialized)matcheshotkey→ throws"Public scenario summary still contains forbidden language.".The same happens for
owner/wallet,metamask/wallet-adapter,org/coldkey-vault,team/farming-bot, etc. The public scenario summary(MCP/API/control-panel surface) cannot be produced for these repos.
Why it's wrong
The guard's purpose is to catch forbidden language that slipped into rendered
content, not to validate the repo identifier the summary is about. A repo is
legitimately allowed to be named
hotkey-manager; refusing to render its advisoryscenario summary is a denial of functionality for exactly the ecosystem
Gittensory serves (Bittensor, where
hotkey/coldkey/walletare core terms).Reachability
renderPublicScenarioSummaryis the public-safe renderer for MCP/API clients andcontrol-panel UIs.
repoFullNameis the analyzed repo, so real repo names flow indirectly. Bittensor/crypto repos frequently contain
hotkey,coldkey,wallet,or
farmingin their names, making this readily reachable.Test status
Not locked in. Every case in
test/unit/scenario-summary.test.tsusesrepoFullName: "octo/demo"; no test exercises a repo name containing a forbiddenterm, and none asserts
renderPublicScenarioSummaryeither throws or succeeds forsuch a name.
Suggested fix
Exclude structural identifiers (
repoFullName,generatedAt) from theforbidden-language guard so it only scans rendered free-text fields:
Add a regression test:
renderPublicScenarioSummary({ repoFullName: "octo/hotkey-wallet", … })returns a summary whose
repoFullNameis preserved and does not throw.Distinct from prior reports
Same class as the merged #457 (miner-command sanitizer breaking legitimate
repo/login names like
wallet-adapter), but a different surface and mechanism:here a public-output guard (not a redactor) hard-throws on the un-sanitized
repoFullName. The feature PRs #416/#345/#290 introduce the renderer; no existingissue covers the repo-name throw.