Firing the repository health scan
Hosting/RepoHealth can measure the fleet and cannot notice anything. This page is the design for
the half that is missing, written down because it was designed and deliberately NOT built: a partly
wired scheduler is worse than none, since it is an alarm that looks armed.
Status: NOT IMPLEMENTED. The classifier half of Plugins#2245 shipped (see /Hosting/ActionsBudgetAttribution); this half did not.
What was measured
| Link in the chain | State | Evidence |
|---|---|---|
| Instrument | ✅ exists | RepoHealthProbe.Scan — reactive, credential-reusing, six checks |
| A surface to run it | ✅ exists, human-only | RepoHealthLayoutAreas declares Content (one recorded scan), Fleet (recorded scans merged) and Scan ("runs the probe NOW"). All three need a person to open a page |
| Schedule | ❌ does not exist | zero matches for schedul\|cron\|recurr\|Timer\|IHostedService\|BackgroundService\|Digest in RepoHealthContent.cs or RepoHealthLayoutAreas.cs |
| Anything that records a scan | ❌ does not exist | the Scan area renders what it finds and writes nothing |
| A scan ever recorded | ❌ never, on either portal | search nodeType:Hosting/RepoHealth partitions:all → count: 0 on memex.systemorph.com AND memex.meshweaver.cloud |
| Destination | ✅ exists | core's NotificationService platform bell, as /Hosting/FleetWatch already uses it |
| A sweep that could carry it | ⚠️ exists for the wrong subject | Hosting/FleetWatch sweeps Hosting/Deployment records and the workloads of their namespaces. It never mentions RepoHealth, and repositories are not deployments |
So every link but the schedule and the record exists. That is the same shape FleetWatch closed for deployments, and the same conclusion: the destination costs nothing extra, and the missing piece is a join.
The shape to copy
FleetWatch's, exactly:
- a sweep on a cadence, writing an observation node per subject, with the cadence and the instant the
reading stops being current written ON the node — a frozen reading must render as history, which
RepoHealthLayoutAreas.Freshnessalready does; - a heartbeat beside the sweep that notices when the sweep itself stops, published on
/healthwith the census tag and no probe tag — a monitoring outage must never take a pod out of rotation; - a notification raised per Critical condition, and a healthy fleet raising nothing.
The finding category to route to the bell is actions-budget
(MainBranchRules.BudgetCategory). It is the one condition that is (a) org-wide, (b) not about any
one repository's code, and (c) actionable within minutes by a person with billing access. main-health
is a candidate for a daily digest, never for a bell: a red trunk is usually already known to whoever
made it red.
🚨 The registration hazard — the reason this is a design and not a diff
Where the hosted service is registered decides how many meshes run it. A hosted service
registered in AddAI runs in EVERY test mesh in the fleet, and on the Orleans test cluster once per
silo — a shape that has already cost one suite a 900 s kill with no verdict. An operational service
that sweeps the world and writes a status node belongs to the MODULE, behind a feature switch, so that
portals get it and a test mesh opts in.
The precedent to follow is in this repo, and it carries three separate lessons in eleven lines
(SelfUpdateAksModuleAttribute):
- Register the singleton AND the hosted service, from the same instance.
🚨 Registering the singleton without theservices.AddSingleton<RepoHealthSweep>(); services.AddHostedService(sp => sp.GetRequiredService<RepoHealthSweep>());AddHostedServiceline means it is never STARTED, and every case then waits out its bound on state nobody created — a hang with no error. And resolving the same instance (rather thanAddHostedService<T>()) is what keeps the health check from watching a different deadline from the one the sweep arms. - Do not host the guard inside the thing that can fail. FleetWatch's sweep is armed inside a
NodeType's
configurationlambda, and on 2026-09-16 that whole chain silently failed to load while the assembly's hosted services kept running. A guard hosted inside the thing that fails is unreachable exactly when it matters, so the heartbeat lives in the module's own registration. - A monitoring outage must not restart a pod. The health check gets the census tag and no probe tag, so it prints its reading whether or not the sweep is beating — "I measured and it is fine" and "nothing here measures that" have to be different sentences.
A Features:* switch gates the registration; the module wrapper (IsolatedModuleHostedService) then
makes a failure cost this feature and never the host.
The two decisions that are NOT measurements
Neither can be settled by reading anything, so neither was decided here:
What a scan record is. A node per run, a node per day, or ONE rolling record per portal. Each is a different retention story and a different
Fleetboard:- per run — full history, and an unbounded node count in a partition nobody prunes;
- per day — a bounded series, and a merge that has to decide what "today's scan" means across
time zones (
DisplayStampalready renders in the viewer's zone, so the KEY would have to be UTC while the display is not); - one rolling record — trivially bounded, no history at all, and
Merge— which exists to keep the newest scan per repository — becomes nearly pointless.
RepoHealthLayoutAreas.MergeandFleetQueryare written for a MULTI-record world (newest-wins per repository, anchored to one partition), which argues for per-day; but that is an argument from the existing code, not a decision about retention cost.Who is notified, and how loudly. The bell is read-scoped to
hub.IsGlobalAdmin(), and the Notifications module escalates per recipient to email/Teams. An org budget refusal at 07:00 on a Saturday is either exactly what someone wants paged or exactly what makes them mute the bell.
What must NOT be done in the meantime
- Do not half-wire it. A singleton with no
AddHostedService, a sweep with no heartbeat, or a notification with no recipient all produce a board that looks armed. The current state — obviously human-driven — is honest; a half-wired one is not. - Do not put the sweep in
AddAI(above). - Do not make the
Scanarea record on render. A page render is not a schedule, and a recorded scan per page view would make theFleetboard's freshness a function of who happened to look.
Related
/Hosting/ActionsBudgetAttribution · /Hosting/FleetWatch · /Hosting/RequiredStatusChecks