loopfleet

package
v0.46.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 4, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package loopfleet is the cross-ledger loop-health fold (#1196, part of #1173 — the verified loop): one read-only pane that answers "show me EVERY loop's health — last tick, run count, keep/witness rate, and whether it has gone DARK" across the repo's fragmented loop ledgers.

The loop ladder runs on disjoint journals, each owned by a different package and written in its own schema:

loopmgr   .fak/loops.jsonl            (fak.loop-event.v1)
nightrun  .fak/nightrun/collected.jsonl (fak-nightrun-collect/1)
dojo      docs/dojo/history.jsonl       (fak-dojo-ledger/1)
cadence   docs/cadence/history.jsonl    (fak-cadence-ledger/1)
dispatch  .dispatch-runs/progress.jsonl (fleet-issue-resolve-progress/1)
steerpr   docs/nightrun/steerpr-overlay.jsonl (fak.steerpr-overlay.v1, #5023)

loopmgr.FoldHealth already unifies the two ledgers reachable WITHIN loopmgr (the loop-event ledger + the job registry) but, by design, does not import the other packages' journals. This package is the cross-ledger surface that comment names: each ledger gets a small read-only adapter, and one Fold joins them into a single per-loop health view that reuses loopmgr's HealthState vocabulary so the whole ladder speaks one word for "live"/"stale"/"dark"/"unknown".

It is PURE and READ-ONLY: every adapter only os.ReadFile's its journal, `now` is supplied (no clock read in the fold), and nothing is appended or mutated. An unreadable or missing ledger is skipped-and-surfaced (recorded in Report.Skipped), never fatal — the `fak loop rollup` discipline. Adding a ledger to the set changes only the VIEW, never any loop's behavior.

Scope (honest): this folds 5 of the 7 ledgers the issue names. The two not yet wired — rsiloop (its Row carries no timestamp, so no last-tick is derivable) and guardrsi (a config-dir directory of guard-audit.jsonl files, not a single repo-relative file) — are deliberate follow-ons; each would be one more adapter here with the same read-only contract. The acceptance bar is "≥3 of the listed ledgers", which 5 clears.

Index

Constants

View Source
const BackgroundStatusSchema = "fak.background-fleet-status.v1"
View Source
const Schema = "fak.loop-fleet-health.v1"

Schema is the versioned payload tag so a `--json` consumer can pin the shape.

Variables

This section is empty.

Functions

func ClassifyBackgroundCommand added in v0.42.0

func ClassifyBackgroundCommand(command string) (kind, name string, ok bool)

ClassifyBackgroundCommand recognizes durable background drivers by behavior, not by Slack naming. Keep this additive: unknown processes are ignored rather than guessed, while newly introduced loop families can add one explicit signature.

Types

type BackgroundLoop added in v0.42.0

type BackgroundLoop struct {
	ID              string `json:"id"`
	Kind            string `json:"kind"`
	Source          string `json:"source"`
	State           string `json:"state"`
	PID             int    `json:"pid,omitempty"`
	AgeSeconds      int64  `json:"age_seconds,omitempty"`
	LastSeenSeconds int64  `json:"last_seen_seconds,omitempty"`
	Detail          string `json:"detail,omitempty"`
}

type BackgroundStatus added in v0.42.0

type BackgroundStatus struct {
	Schema      string           `json:"schema"`
	GeneratedAt time.Time        `json:"generated_at"`
	Total       int              `json:"total"`
	Live        int              `json:"live"`
	Managed     int              `json:"managed"`
	ProcessOnly int              `json:"process_only"`
	Stale       int              `json:"stale"`
	Loops       []BackgroundLoop `json:"loops"`
}

func BuildBackgroundStatus added in v0.42.0

func BuildBackgroundStatus(status loopmgr.Status, processes []Process, now time.Time) BackgroundStatus

BuildBackgroundStatus joins the durable loop-manager ledger with live OS process evidence. The two sources are intentionally retained rather than forcing a lossy identity merge: the ledger explains managed work, while process discovery catches super-loops and legacy background drivers that predate loopmgr registration.

type LoopHealth

type LoopHealth struct {
	// Kind is the loop's stable identity. For the single-purpose ledgers it is the
	// ledger name ("nightrun", "dojo", "cadence", "dispatch"); for loopmgr — whose
	// one ledger holds many loops — it is "loopmgr:<loop_id>".
	Kind string `json:"kind"`
	// Ledger names the journal this row was folded from.
	Ledger string `json:"ledger"`
	// State is the derived verdict (live/stale/dark/unknown), loopmgr's vocabulary.
	State loopmgr.HealthState `json:"state"`
	// Dark is the surfaced boolean the issue makes first-class: true iff State==dark,
	// so a `--json` consumer (or a scheduler) gates on one field without re-deriving.
	Dark bool `json:"dark"`
	// LastTickUnixNano is the loop's most recent ledger event time, 0 if never ticked.
	LastTickUnixNano int64 `json:"last_tick_unix_nano,omitempty"`
	// AgeSeconds is now-lastTick in whole seconds; 0 when the loop has never ticked.
	AgeSeconds int64 `json:"age_seconds,omitempty"`
	// CadenceSeconds is the expected interval the verdict compared the age against.
	CadenceSeconds int64 `json:"cadence_seconds,omitempty"`
	// Runs is the count of recorded runs/ticks — the denominator of the keep rate.
	Runs int `json:"runs"`
	// Keep is the count of runs that landed a kept/positive outcome.
	Keep int `json:"keep"`
	// Witness is the count of runs that carried an independent witness (an artifact,
	// a measurement, a witnessed-done verdict) — the evidence behind the keep.
	Witness int `json:"witness"`
	// KeepRate is Keep/Runs rounded to 3 decimals; -1 when Runs==0 (no denominator),
	// so a brand-new loop is never slandered as 0% kept on an empty base.
	KeepRate          float64 `json:"keep_rate"`
	RecentRuns        int     `json:"recent_runs"`
	RecentKeep        int     `json:"recent_keep"`
	RecentWitness     int     `json:"recent_witness"`
	RecentKeepRate    float64 `json:"recent_keep_rate"`
	RecentWitnessRate float64 `json:"recent_witness_rate"`
	RecentAvailable   bool    `json:"recent_available"`
}

LoopHealth is one loop's row in the cross-ledger pane: its identity (kind + source ledger), the inputs the verdict was derived from (last tick, cadence, counts), and the derived HealthState — so a reader sees not just "dark" but the cadence and last tick that made it dark.

type Process added in v0.42.0

type Process struct {
	PID       int       `json:"pid"`
	ParentPID int       `json:"parent_pid,omitempty"`
	StartedAt time.Time `json:"started_at,omitempty"`
	Command   string    `json:"command"`
}

Process is the small, platform-neutral process view consumed by BackgroundStatus.

type Report

type Report struct {
	Schema     string       `json:"schema"`
	TSUnixNano int64        `json:"ts_unix_nano"`
	Loops      []LoopHealth `json:"loops"`
	Skipped    []Skipped    `json:"skipped"`
	Rollup     Rollup       `json:"rollup"`
}

Report is the full read-only fold: schema tag, the time it was folded, the per-loop rows (stable kind order), the surfaced skipped ledgers, and the rollup.

func Fold

func Fold(root string, now time.Time, th loopmgr.HealthThresholds) Report

Fold is the cross-ledger health fold. It runs every adapter against root, derives one LoopHealth per loop found, surfaces every skipped ledger, and tallies the rollup. It is PURE: `now` is supplied, the only I/O is reading the journals, and no input is mutated. A zero-value HealthThresholds is fine — the classifier fills the defaults.

type Rollup

type Rollup struct {
	Loops   int `json:"loops"`
	Live    int `json:"live"`
	Stale   int `json:"stale"`
	Dark    int `json:"dark"`
	Unknown int `json:"unknown"`
	Ledgers int `json:"ledgers"` // ledgers present and folded
	Skipped int `json:"skipped"` // ledgers missing/unreadable/empty
}

Rollup is the fleet-wide tally: how many loops, how many in each state, and how many ledgers were folded vs skipped. Dark>0 is the signal a scheduler gates on.

type Skipped

type Skipped struct {
	Ledger string `json:"ledger"`
	Path   string `json:"path"`
	Reason string `json:"reason"`
}

Skipped is a ledger that could not be folded — missing, unreadable, or holding no parseable rows. It is surfaced (never silent) so "absent" reads as a known gap, not as a healthy zero.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL