capinspector

package
v0.0.16 Latest Latest
Warning

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

Go to latest
Published: Jul 23, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package capinspector renders the capability detail / schematic that the carousel's status-bar segments open on click. One App per window; the carousel pushes a selectedCap onto an internal queue before opening so the next-allocated App captures the right initial selection.

Phase 1 (this package): static descriptions per cap + a layered (Sugiyama) schematic of App → capability → backend, laid out by Graphviz dot in-process and painted through the layeredgraph widget (ADR-0069, see archgraph.go). The layout is cached (the cap registry is closed); only the per-frame colours — selected cap, effective backend, degraded cap — vary. Live audit activity renders as a companion sparkline strip beneath the schematic.

Index

Constants

View Source
const ManifestId app.AppIdT = "github.com/stergiotis/boxer/apps/capinspector"

ManifestId is exported so the carousel can call host.Open with a stable identifier when a status-bar segment is clicked.

Variables

View Source
var Registry = map[CapId]CapSpec{
	CapRun: {
		Id:            CapRun,
		Display:       "Run identity",
		SubjectFamily: "(process identity)",
		Description: "Per-process identifier minted by runinfo.Init() at boot " +
			"and exported as PEBBLE2_RUN_ID for child processes (incl. the Rust " +
			"client). Every audit row carries this id so a session's activity " +
			"groups under one runtime-start fact. ADR-0026 §SD12 / 2026-05-12 " +
			"runtime-run amendment.",
		Backend: "runtime/runinfo + runtime/heartbeat",
		Backends: []BackendImpl{

			{Id: "runinfo", Display: "runinfo + heartbeat"},
		},
	},
	CapFacts: {
		Id:            CapFacts,
		Display:       "Audit + state backend",
		SubjectFamily: "(audit backend — not a subject)",
		Description: "Where grants, audit records, app-lifecycle rows, " +
			"heartbeats, and persist state land. chstore.NewWithFallback " +
			"returns a live ClickHouse-backed Store when reachable; otherwise " +
			"InMemoryFactsStore. Read paths: LookupRunStart, LifecyclesByRun, " +
			"LastHeartbeatForRun, RecentLogs.",
		Backend: "runtime/factsstore + runtime/factsstore/chstore",

		Backends: []BackendImpl{
			{Id: "inmem", Display: "InMem"},
			{Id: "chstore", Display: "chstore"},
		},
	},
	CapBus: {
		Id:            CapBus,
		Display:       "In-proc subject router",
		SubjectFamily: "(all subjects)",
		Description: "inprocbus.Inst routes Publish/Subscribe/Request between " +
			"per-app inprocbus.Client instances minted from Manifest.Caps. M4 " +
			"swaps the in-proc transport for NATS; the BusI surface is stable " +
			"across the swap. Every allowed call lands an audit row via the " +
			"factsstore.AsAuditSink sink the carousel attaches.",
		Backend: "runtime/inprocbus",

		AppFilter: func(_ app.SubjectFilter) bool { return true },

		Backends: []BackendImpl{
			{Id: "inprocbus", Display: "inprocbus"},
		},
	},
	CapFs: {
		Id:            CapFs,
		Display:       "fs.* Powerbox",
		SubjectFamily: "fs.dialog.{read|write|bundle|watch}, fs.handle.{uuid}.{read|close|watch|unwatch|event}",
		Description: "User-mediated filesystem access. Apps publish " +
			"fs.dialog.read to request a file pick; fsbroker.Service queues " +
			"the request; the picker overlay resolves with a user-selected " +
			"path; the broker mints an opaque handle uuid and augments the " +
			"app's caps with fs.handle.{uuid}.>. The path is never exposed " +
			"to the app — only the handle subject is. fs.dialog.watch adds " +
			"streaming directory-change notifications on the conventional " +
			"fs.handle.{uuid}.event subject; the broker grants Pub+Sub on " +
			"the per-uuid handle pattern so the app can subscribe. Watch " +
			"requests carry an optional WatchRequest.Recursive flag — when " +
			"set, events fire for the entire subtree and Name carries the " +
			"forward-slash relpath under the watch root.",
		Backend: "runtime/fsbroker (inotify primary, poller fallback for inotify-blind FS) + runtime/fsbroker/pickerbridge",
		AppFilter: func(f app.SubjectFilter) bool {
			return strings.HasPrefix(f.Pattern, "fs.")
		},

		Backends: []BackendImpl{
			{Id: "fsbroker", Display: "fsbroker"},
		},
	},
	CapPersist: {
		Id:            CapPersist,
		Display:       "runtime.persist.* state",
		SubjectFamily: "runtime.persist.{appAlias}.{key}.{get|set|delete}",
		Description: "Per-app key-value cold-state surface. " +
			"persist.NewClient(busC, appId) is the StorageI MountCtx hands to " +
			"every app; the wire subject is runtime.persist.{ownAlias}.{key}.{op}. " +
			"Keys must be a single NATS token (no dots). The windowhost auto- " +
			"injects the runtime.persist.{ownAlias}.> cap when Manifest.PersistedKeys " +
			"is non-empty — apps declare keys, not caps.",
		Backend: "runtime/persist (Service + Client + MemoryBackend)",
		AppFilter: func(f app.SubjectFilter) bool {
			return strings.HasPrefix(f.Pattern, "runtime.persist.")
		},
		HostInjected: func(m app.Manifest) string {
			if len(m.PersistedKeys) == 0 {
				return ""
			}
			return "runtime.persist." + m.Id.SubjectAlias() + ".>"
		},

		Backends: []BackendImpl{
			{Id: "mem", Display: "MemBackend"},
		},
	},
	CapTask: {
		Id:            CapTask,
		Display:       "task.* background primitive",
		SubjectFamily: "task.<id>.{created|progress|cancel|done|error}, task.list.inflight",
		Description: "Cancellable, observable background work over the bus " +
			"(ADR-0038). Apps spawn handles through task.ForApp(MountCtx); the " +
			"API auto-injects OwnerAppId / OwnerTileKey / OwnerRunId so audit " +
			"rows join back to AppLifecycleRow + RuntimeStartRow. " +
			"task.PatternAll (\"task.>\") is the universal observer subscription; " +
			"task.SubjectListInflight (\"task.list.inflight\") is a request/reply " +
			"the M3 supervisor serves with a buscodec-encoded snapshot. The " +
			"runtime/task package owns the protocol; runtime/task/supervisor is " +
			"the opt-in audit + heartbeat layer that lands rows in factsstore.",
		Backend: "runtime/task + runtime/task/supervisor",
		AppFilter: func(f app.SubjectFilter) bool {
			return strings.HasPrefix(f.Pattern, "task.")
		},

		Backends: []BackendImpl{
			{Id: "task", Display: "task"},
			{Id: "supervisor", Display: "+supervisor"},
		},
	},
}

Registry is the lookup table the inspector reads to render any cap detail page. The set is intentionally small (one entry per shipped M2 cap); adding a new cap means appending here.

View Source
var Tally = &Counters{}

Tally is the package-singleton Counters the carousel wires via MultiSink. Inspector windows read from it directly; no DI needed because the inspector is itself a carousel-owned package.

Functions

func ActiveBackend

func ActiveBackend(capId CapId) (backendId string)

ActiveBackend returns the recorded effective backend for capId, or "" when the carousel didn't set one (a degraded mode — the cap's service likely failed NewService and is unbound).

func PushSelection

func PushSelection(capId CapId)

PushSelection enqueues a capId for the next newApp() to consume. The carousel calls this immediately before host.Open(ManifestId) so the inspector window opens already pointing at the right cap. The queue is FIFO so two rapid clicks open two windows in the click order.

func SetActiveBackend

func SetActiveBackend(capId CapId, backendId string)

SetActiveBackend records the implementation the runtime selected for one capability. Called by the carousel after each service is constructed (chstore.NewWithFallback resolves facts; fsbroker.NewService resolves fs; etc.). backendId must match one of the CapSpec.Backends[].Id values for the cap — the inspector renders an unknown id by leaving every backend dim, which is the right signal that the carousel and the registry drifted.

Re-calling SetActiveBackend overwrites the previous value; useful only in tests since the carousel sets each cap exactly once per boot.

Types

type App

type App struct {
	// contains filtered or unexported fields
}

App is the per-window inspector instance. selectedCap stays mutable so the in-window picker can switch caps without opening another window.

func (*App) Frame

func (inst *App) Frame(ctx app.FrameContextI) (err error)

Frame renders the inspector body. The host has already pre-pushed a window-unique salt onto inst.ids via c.IdScope (windowhost. renderWindowBody, ADR-0026 §SD9), so widget ids derived from inst.ids are unique across all concurrently open instances — the app must not Reset() the stack or wrap the body in its own instance salt (doing so discards the host salt and collides with sibling apps that share a label string).

func (*App) Manifest

func (inst *App) Manifest() (m app.Manifest)

func (*App) Mount

func (inst *App) Mount(ctx app.MountContextI) (err error)

func (*App) Unmount

func (inst *App) Unmount(ctx app.MountContextI) (err error)

type BackendImpl

type BackendImpl struct {
	// Id is the stable identifier the carousel uses with
	// SetActiveBackend. Short and lower-case (e.g. "chstore", "inmem").
	Id string
	// Display is the short label rendered inside the backend box.
	// Must fit in ~70px at 10pt when the cap has 2 impls; 152px at
	// 11pt when the cap has 1 impl.
	Display string
}

BackendImpl is one realisation of a capability's contract. A cap can have several (e.g. Facts: InMemoryFactsStore vs chstore.Store); the carousel reports which one is effective via SetActiveBackend. The inspector renders every available impl side-by-side in the backend row, with the effective one highlighted.

type CapId

type CapId = string

CapId is the short identifier the carousel's status bar uses when asking the inspector to open with a pre-selected capability. The set is closed — exactly the entries in Registry.

const (
	CapRun     CapId = "run"
	CapFacts   CapId = "facts"
	CapBus     CapId = "bus"
	CapFs      CapId = "fs"
	CapPersist CapId = "persist"
	CapTask    CapId = "task"
)

type CapSpec

type CapSpec struct {
	// Id is the short capId the inspector key by; matches one of the
	// Cap* constants above.
	Id CapId
	// Display is the human label for the cap.
	Display string
	// SubjectFamily is the NATS-style subject pattern this capability
	// serves, or "(process identity)" / "(audit backend)" for the
	// non-subject ones.
	SubjectFamily string
	// Description is a single multi-line paragraph rendered above the
	// schematic. Keep concise; the schematic carries the live data.
	Description string
	// Backend names the package + key types that implement the cap.
	Backend string
	// AppFilter returns true when an app's SubjectFilter pattern
	// relates to this capability. Nil for non-subject caps (run,
	// facts) — those have no app-level wiring.
	AppFilter func(filter app.SubjectFilter) bool
	// HostInjected is the auto-grant pattern the windowhost minted
	// for an app declaring a related Manifest field (e.g. PersistedKeys
	// → runtime.persist.{ownAlias}.>). Empty when no host injection.
	HostInjected func(m app.Manifest) string
	// Backends is the set of available implementations of this cap.
	// One per shipping concrete impl. At runtime, the carousel calls
	// SetActiveBackend(capId, backendId) so the inspector knows which
	// one is in use; non-active impls render dimmed. Must be non-empty
	// (a cap with no impls would be a runtime bug, not a documentation
	// concern).
	Backends []BackendImpl
}

CapSpec describes one capability for the inspector body. The schematic is live-generated from the registry by reading every Manifest's Caps and filtering with Matches; the prose fields are static and live here.

type Counters

type Counters struct {
	// contains filtered or unexported fields
}

Counters is the audit-sink-shaped per-capability counter the inspector reads to render live activity on cap nodes. Bus Request calls land here via the carousel's MultiSink fan-out; classify() maps the subject to a CapId; Record increments the matching counter atomically (no lock).

Counts are monotonic since process start — Phase 2 design keeps the data flat; a future sliding-window variant can wrap this with a periodic tick that resets stale buckets.

func (*Counters) Count

func (inst *Counters) Count(capId CapId) (n uint64)

Count returns the live row count for one cap. CapBus is special: it's the router's universal substrate so the count is everything that crossed it (total). The other caps return their classifier bucket. Unknown capIds return 0.

func (*Counters) Record

func (inst *Counters) Record(rec audit.AuditRecord)

func (*Counters) Reset

func (inst *Counters) Reset()

Reset clears every counter and sliding-window histogram. Test-only helper; the production path never resets — the inspector renders monotonic counts and a rolling sparkline.

func (*Counters) Snapshot

func (inst *Counters) Snapshot(capId CapId) (out SparkSnapshot)

Snapshot returns the sliding-window sparkline buckets for capId, oldest-to-newest. Unknown capIds return a zero array. The renderer uses this for the per-cap activity bar inside each cap node.

type SparkSnapshot

type SparkSnapshot = [sparkBuckets]uint64

SparkSnapshot is the oldest-to-newest sequence of per-bucket counts the renderer consumes. Fixed length so the caller can iterate without bounds checks; zero entries render as gaps in the strip.

Jump to

Keyboard shortcuts

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