Show egress/ingress levels in the registry; freeze checks at the verdict
Registry: the "last result" column now also shows, per level (egress,
ingress), how many of the recorded checks of the latest cycle succeeded, split
by check family (tcp-22 and tcp-443 are both "tcp"). One grouped query per
chunk of addresses; new fields last_cycle_id, egress, ingress in
GET /admin/registry; the dashboard renders them under the verdict.
Verdict integrity (migration 0010):
- the prober is handed an address once per site and attempt, not on every
poll, so results are no longer overwritten by later probe rounds;
- UpsertCheckIfOpen refuses writes once the address is aggregating or has its
verdict, or for an older attempt; senders get {"ok":true,"ignored":N} and a
result_dropped event is recorded;
- the checking window counts from checking_started_at, not from assigned_at;
- checks.recorded_at (server clock) and checks.after_verdict (flag for rows
written after the verdict in existing data);
- the verdict rule is a pure function (computeVerdict) and the aggregated
event carries the egress/ingress check counts.
Rebuilt bin/control-api and bin/admin-dashboard to match. Plans and summaries
are in docs/changes; README, API, USAGE, DASHBOARD and DIAGRAMS are updated.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
db73409e8f
commit
864208238f
34 files changed
+1570
-72
No files matched your search
@@ -264,8 +264,47 @@ type registryItem struct {
|
||||
LastCheckedAt *time.Time `json:"last_checked_at"`
|
||||
InQueue bool `json:"in_queue"`
|
||||
CurrentState string `json:"current_state"`
|
||||
// LastCycleID is the cycle counted by Egress and Ingress (0 = no checks).
|
||||
LastCycleID int `json:"last_cycle_id"`
|
||||
Egress levelResult `json:"egress"`
|
||||
Ingress levelResult `json:"ingress"`
|
||||
}
|
||||
|
||||
// levelResult is "ok of total" recorded checks of one level (egress or
|
||||
// ingress) in the last cycle, split by check family — see httpapi's
|
||||
// levelResultDTO.
|
||||
type levelResult struct {
|
||||
Total int `json:"total"`
|
||||
OK int `json:"ok"`
|
||||
ByType []typeStat `json:"by_type"`
|
||||
}
|
||||
|
||||
type typeStat struct {
|
||||
Type string `json:"type"`
|
||||
Total int `json:"total"`
|
||||
OK int `json:"ok"`
|
||||
}
|
||||
|
||||
// statClass picks the colour of an "ok of total" figure: all checks passed,
|
||||
// none passed, some passed, or nothing recorded.
|
||||
func statClass(ok, total int) string {
|
||||
switch {
|
||||
case total == 0:
|
||||
return "none"
|
||||
case ok == total:
|
||||
return "ok"
|
||||
case ok == 0:
|
||||
return "fail"
|
||||
}
|
||||
return "part"
|
||||
}
|
||||
|
||||
// Class is the CSS modifier for the level's total.
|
||||
func (l levelResult) Class() string { return statClass(l.OK, l.Total) }
|
||||
|
||||
// Class is the CSS modifier for one check family.
|
||||
func (t typeStat) Class() string { return statClass(t.OK, t.Total) }
|
||||
|
||||
type registryHistoryResponse struct {
|
||||
Registry registryItem `json:"registry"`
|
||||
Checks []check `json:"checks"`
|
||||
|
||||
Reference in new issue
Block a user