Part of #5016.
Problem
Every other sub-issue in this epic assumes repositories.isInstalled is a trustworthy "this repo is active for gittensory" signal. It plausibly is on cloud and on a non-brokered self-host (an operator's own GitHub App). It is NOT reliably populated on a brokered self-host — the officially documented onboarding path (src/selfhost/setup-wizard.ts:89: "install the Gittensory Orb App … complete enrollment").
Root cause
- The central Orb relay deliberately does NOT forward
installation/installation_repositories webhook events to brokered containers (src/orb/relay.ts:13-27, RELAY_FORWARD_EVENTS) — by design, so a brokered container never mistakes the CENTRAL app's installation state for its own.
- There is no other eager sync: no "list installation repositories" GitHub API call anywhere in the codebase for the brokered path.
- The only two places that ever INSERT into
repositories are src/registry/sync.ts:118 (subnet registry) and upsertRepositoryFromGitHub in src/db/repositories.ts:294-323 (called from processGitHubWebhook, src/queue/processors.ts:4977-5943).
- Net effect: a brokered self-host repo only gets a
repositories row + isInstalled=true the FIRST time a forwarded event (pull_request, pull_request_review, pull_request_review_comment, check_suite, issue_comment, issues) arrives for it. A freshly-enrolled, quiet repo with no activity yet has NO row at all. Repo removal from the installation is never learned either (no installation_repositories removed forwarding), so isInstalled can go stale-true forever once set.
Requirements
Pick and implement one of:
- (a) Add a minimal repo-list sync at enrollment/relay-registration time — the central Orb already knows the installation's repos (
orb_github_installations / the App API); expose a repo list at enroll time and have the self-host pull it once.
- (b) Forward a safe repo-list delta alongside
installation_repositories events (no permissions/secrets, just full_names added/removed).
- (c) Have the self-host periodically pull its own installed-repo list through the broker (polling fallback).
Whichever is chosen must also handle repo REMOVAL (uninstall/repo detached from the installation), not just addition — today there is no path for that at all on brokered self-host.
Deliverables
- A self-host instance's
repositories.isInstalled reflects reality within a bounded time window after (a) enrollment, (b) a repo being added to or removed from the installation — even for a repo with zero PR/issue activity.
- Tests: enrollment with N repos populates N rows with
isInstalled=true and no PR/issue activity required; a repo removed from the installation eventually flips to isInstalled=false.
- No change to non-brokered self-host or cloud behavior (both already work correctly).
Why this blocks everything else
Sub-issues #1/#2/#4/#5/#6 in this epic move core sweeps (signal snapshots, fidelity repair, burden forecasts, ops-alerts, selftune, maintainer-recap, RAG indexing) from isRegistered to isInstalled. If this lands before #0, a brokered self-host with quiet, newly-enrolled repos silently loses coverage from all of those sweeps — the same class of silent feature loss this whole epic exists to prevent. Land this first.
Part of #5016.
Problem
Every other sub-issue in this epic assumes
repositories.isInstalledis a trustworthy "this repo is active for gittensory" signal. It plausibly is on cloud and on a non-brokered self-host (an operator's own GitHub App). It is NOT reliably populated on a brokered self-host — the officially documented onboarding path (src/selfhost/setup-wizard.ts:89: "install the Gittensory Orb App … complete enrollment").Root cause
installation/installation_repositorieswebhook events to brokered containers (src/orb/relay.ts:13-27,RELAY_FORWARD_EVENTS) — by design, so a brokered container never mistakes the CENTRAL app's installation state for its own.repositoriesaresrc/registry/sync.ts:118(subnet registry) andupsertRepositoryFromGitHubinsrc/db/repositories.ts:294-323(called fromprocessGitHubWebhook,src/queue/processors.ts:4977-5943).repositoriesrow +isInstalled=truethe FIRST time a forwarded event (pull_request,pull_request_review,pull_request_review_comment,check_suite,issue_comment,issues) arrives for it. A freshly-enrolled, quiet repo with no activity yet has NO row at all. Repo removal from the installation is never learned either (noinstallation_repositories removedforwarding), soisInstalledcan go stale-true forever once set.Requirements
Pick and implement one of:
orb_github_installations/ the App API); expose a repo list at enroll time and have the self-host pull it once.installation_repositoriesevents (no permissions/secrets, just full_names added/removed).Whichever is chosen must also handle repo REMOVAL (uninstall/repo detached from the installation), not just addition — today there is no path for that at all on brokered self-host.
Deliverables
repositories.isInstalledreflects reality within a bounded time window after (a) enrollment, (b) a repo being added to or removed from the installation — even for a repo with zero PR/issue activity.isInstalled=trueand no PR/issue activity required; a repo removed from the installation eventually flips toisInstalled=false.Why this blocks everything else
Sub-issues #1/#2/#4/#5/#6 in this epic move core sweeps (signal snapshots, fidelity repair, burden forecasts, ops-alerts, selftune, maintainer-recap, RAG indexing) from
isRegisteredtoisInstalled. If this lands before #0, a brokered self-host with quiet, newly-enrolled repos silently loses coverage from all of those sweeps — the same class of silent feature loss this whole epic exists to prevent. Land this first.