loopfleet

package
v0.35.0 Latest Latest
Warning

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

Go to latest
Published: Jun 30, 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  docs/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)

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 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

This section is empty.

Types

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"`
}

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 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