Skip to content

fix(control-panel): deduplicate the access-scope computation behind one shared helper#8453

Merged
loopover-orb[bot] merged 2 commits into
JSONbored:mainfrom
kai392:fix/critical-issue-dedupe-access-scope
Jul 24, 2026
Merged

fix(control-panel): deduplicate the access-scope computation behind one shared helper#8453
loopover-orb[bot] merged 2 commits into
JSONbored:mainfrom
kai392:fix/critical-issue-dedupe-access-scope

Conversation

@kai392

@kai392 kai392 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

buildControlPanelAccessScope and buildControlPanelRoleSummary each carried a byte-identical copy of the same access-scope computation — including the #953 suspension fix, which had to be applied twice. That's the exact structural precondition for the "fixed in one place, missed in its identical sibling" bug class, on logic canLoginAccessRepo/canWatchRepo rely on for private-repo access decisions.

Both now call one private resolveAccountRepoScope(args), and the #953 comment lives on that single computation instead of being duplicated.

Behaviour-preserving, and one subtlety made it non-mechanical: the two maintainerRepos lines were not identical — buildControlPanelAccessScope finishes with uniqueRepoNames, while buildControlPanelRoleSummary uses uniqueRepos, which additionally applies sanitizeRoleText. So the helper returns maintainerRepoNames pre-deduplication and each caller applies its own finisher; deduplicating inside the helper would have silently changed one builder's output. That reasoning is recorded in the helper's doc comment so it isn't "simplified" away later.

accountInstallationIds/suspendedAccountInstallationIds stay internal to the helper — neither caller uses them beyond deriving ownedInstalledRepos, so they're deliberately not in the returned shape.

Nothing else changed: canLoginAccessRepo, canWatchRepo, loadControlPanelAccessScope, loadControlPanelRoleSummary, buildStaticControlPanelRoleSummary, buildRoleCards, and the exported RoleSummaryInputs/ControlPanelAccessScope/ControlPanelRoleSummary types are all untouched.

Closes #8373

Test plan

  • 89/89 green across every suite that exercises this file, unmodifiedtest/unit/control-panel-roles.test.ts, test/unit/agent-orchestrator.test.ts, test/unit/policy-sanitizer.test.ts. Since this is a pure refactor, the existing suite passing untouched (including its [Bug]: suspending the App does not revoke control-panel access to your own repos #953 suspended-installation cases) is the correctness evidence; no new assertions were invented to describe unchanged behaviour
  • Local coverage on src/services/control-panel-roles.ts: every line and branch in this diff (lines 74-131) is covered — the file's remaining uncovered lines are its DB-loading functions (loadControlPanelAccessScope, canLoginAccessRepo), which this change does not touch
  • npm run typecheck clean
  • CI validate

@kai392
kai392 requested a review from JSONbored as a code owner July 24, 2026 13:45
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.62%. Comparing base (6c25eb6) to head (de7d84d).
⚠️ Report is 16 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8453      +/-   ##
==========================================
+ Coverage   79.69%   89.62%   +9.92%     
==========================================
  Files         791       98     -693     
  Lines       79319    22785   -56534     
  Branches    23954     3903   -20051     
==========================================
- Hits        63216    20420   -42796     
+ Misses      13298     2187   -11111     
+ Partials     2805      178    -2627     
Flag Coverage Δ
shard-1 87.34% <100.00%> (?)
shard-2 83.54% <100.00%> (+32.43%) ⬆️
shard-3 94.93% <100.00%> (+41.51%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/services/control-panel-roles.ts 100.00% <100.00%> (+1.17%) ⬆️

... and 693 files with indirect coverage changes

@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 24, 2026
@loopover-orb

loopover-orb Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-24 14:47:42 UTC

1 file · 1 AI reviewer · no blockers · readiness 93/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This is a clean, behavior-preserving refactor that extracts the duplicated access-scope computation (including the #953 suspension fix) into a single private `resolveAccountRepoScope` helper. The subtle divergence between the two callers' `maintainerRepos` finishers (`uniqueRepoNames` vs `uniqueRepos`+`sanitizeRoleText`) is correctly preserved by returning `maintainerRepoNames` pre-deduplication and letting each caller apply its own finisher, which is exactly right and is documented in the new doc comment. No test files were added, but the existing 89 tests exercising this file (per the description) run unmodified against the refactored code, which is the correct verification strategy for a pure refactor.

Nits — 4 non-blocking
  • No new tests were added for this change, but since it's a pure refactor with no behavior change, relying on the existing 89 passing tests (including [Bug]: suspending the App does not revoke control-panel access to your own repos #953 suspended-installation cases) is reasonable rather than a gap.
  • src/services/control-panel-roles.ts:76 references issue fix(control-panel): deduplicate identical access-scope computation in control-panel-roles.ts #8373 in a comment as plain text; consider whether the repo has a convention for linking issue numbers (e.g. a URL) for long-term traceability.
  • Consider adding a small unit test that directly exercises `resolveAccountRepoScope` (via the internals export pattern already used for `sanitizeRoleText`) to lock in the pre-deduplication contract described in the doc comment, since that's the one non-obvious invariant a future refactor could break.
  • Code changes lack test evidence — Add focused regression tests or explain why existing coverage is sufficient.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #8373
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 135 registered-repo PR(s), 68 merged, 10 issue(s).
Contributor context ✅ Confirmed Gittensor contributor kai392; Gittensor profile; 135 PR(s), 10 issue(s).
Improvement ℹ️ None detected risk: low · value: none · LLM: moderate
Linked issue satisfaction

Addressed
The diff extracts the duplicated installed/owned/maintainer/suspended computation into a single resolveAccountRepoScope helper, has both builders call it, and preserves the #953 comment and each caller's distinct maintainerRepos finisher (uniqueRepoNames vs uniqueRepos+sanitizeRoleText), matching the issue's exact requirements.

Review context
  • Author: kai392
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, JavaScript, Kotlin, Perl, TypeScript, Vue
  • Official Gittensor activity: 135 PR(s), 10 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Triage stale or unlinked PRs.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit 12f2e14 into JSONbored:main Jul 24, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(control-panel): deduplicate identical access-scope computation in control-panel-roles.ts

2 participants