Help us shape the future of Go! Take the 2026 Go Developer Survey

runview

package
v0.16.0 Latest Latest
Warning

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

Go to latest
Published: Oct 14, 2026 License: Apache-2.0 Imports: 33 Imported by: 0

Documentation

Overview

Package runview is a read-only, local web viewer for a journal's runs: a run list (RunList) with each run's kind and state, and one run's page: a plan flow's declared topology with the run's path drawn over it, or an agent run's timeline of model turns, tool calls, attempts, approvals and halts, with the audit verdict when a signed head or evidence package is given. The page of a run in progress, read from a store, follows the run as records land (see Follower). It never writes to the store it reads, and it serves on a loopback address only (see Listen). The bide view command (cmd/bide, its own module) is its front end.

Index

Constants

View Source
const KindSteps = "steps"

KindSteps is the kind of a run journaled by Journal.Step calls alone: it has no run:start, so the journal does not say what kind of run it is.

Variables

This section is empty.

Functions

func Check added in v0.14.0

func Check(w io.Writer, c Config) bool

Check writes c's problems as "file:node: message" lines (the node, "from->to" for an edge or arm, or nothing for the config as a whole), warnings marked as such, then, when the config has assertions, a line counting their verdicts, and reports whether any problem is an error (or, with c.Strict, any problem at all). A violated, undecided or invalid assertion is an error.

func CheckDiff added in v0.15.0

func CheckDiff(w io.Writer, d Diff) (weakened bool, err error)

CheckDiff writes the diff as text, for CI and a pull request comment: one line per change, a line per weakened approval gate, and a summary line with the counts and the digest, each prefixed with the new config's name. It reports whether an approval policy was weakened.

func CheckDiffStyled added in v0.16.0

func CheckDiffStyled(w io.Writer, d Diff, st term.Style) (weakened bool, err error)

CheckDiffStyled is CheckDiff in st's colors (bide check -diff -check on a terminal): added green, removed red, changed amber, and each weakened approval gate in bold red, called out before the changes rather than after them. With color off it writes what CheckDiff writes.

func CheckStyled added in v0.16.0

func CheckStyled(w io.Writer, c Config, st term.Style) bool

CheckStyled is Check in st's colors (bide check on a terminal): a red cross on each error, a violated assertion's counterexample path in red with the node it reaches in bold, risk classes colored as the risk map colors them, and the verdict counts in green, red and amber. With color off it writes what Check writes.

func Handler

func Handler(o Options) http.Handler

Handler serves the run list at / (as JSON at /runs.json; see RunList) and a run at /run?id=<run> (its View as JSON at /run.json?id=<run>, and, for a run in progress in a store, its live updates at /run/live?id=<run>&after=<cursor>). It answers only GET and HEAD, and only requests addressed to a loopback host, so a page on another site cannot read it through a rebound DNS name.

func Listen

func Listen(addr string) (net.Listener, error)

Listen listens on addr, which must name a loopback IP (127.0.0.1 or ::1) or "localhost" (listened on as 127.0.0.1). Any other host, an empty one included, is refused: the viewer shows a journal's contents and must not be reachable from another machine.

func Main

func Main(args []string, stdout, stderr io.Writer, stores Stores) int

Main is the bide view command: it parses args, opens the input, and serves until interrupted. It returns the exit status: 0 after a clean shutdown, 2 for a usage error, 1 otherwise.

Types

type ApprovalCheck

type ApprovalCheck struct {
	OK   bool   `json:"ok"`
	Text string `json:"text"`

	// What the approver cards show; not in the JSON view. Counted and Denied are the approvers
	// whose decision counted in the recount, Ignored the reason each other decision did not, Keys
	// each approver's key fingerprint (from the approver keys given), and Times the two times of
	// each counted approver's decision, with their sanity flags (audit.ApprovalVerdict.Times).
	Counted, Denied []string                      `json:"-"`
	Ignored         map[string]string             `json:"-"`
	Keys            map[string]string             `json:"-"`
	Times           map[string]audit.DecisionTime `json:"-"`
}

ApprovalCheck is audit.VerifyApprovals' verdict on one gate, in words.

type Approvals

type Approvals struct {
	Keys     agent.ApproverVerifierFor
	Expected *agent.ApprovalPolicy
}

Approvals configures the approval-signature check a Prover runs: Keys resolves each approver's public key (nil: no check), and Expected, when set, is the policy the auditor expects, which the check runs against instead of the policy the gate's tally records.

type ApproverCard added in v0.16.0

type ApproverCard struct {
	Name     string
	Initials string
	// State is approved, denied or pending.
	State string
	// Verify says what is known of the signature, in words: "signature verified", "signature NOT
	// verified", "in the signed log, signature not checked" or "signature not checked". VerifyOK
	// reports the first. Empty for a pending approver.
	Verify   string
	VerifyOK bool
	Why      string // why the decision did not count, when it did not
	// Fingerprint is the approver's key as "ed25519:3b6a27bc" (the first 8 hex digits of the
	// SHA-256 of its public key), when -approver-keys gave it.
	Fingerprint string
	// DecidedAt is when the approver says they decided, by their clock, inside the signature;
	// RecordedAt is when the decision was journaled, by the submitter's clock (not signed). Both are display text
	// in UTC ("2026-10-13 12:14:03.123"), empty when the record holds none. Gap is the difference
	// between them in words, shown without judgment, and Flags the sanity notes on them
	// (audit.FlagDecisionTimes, under audit.DefaultDecisionTimeTolerance), which never change
	// the gate's outcome. Empty for a pending approver.
	DecidedAt, RecordedAt string
	Gap                   string
	Flags                 []string
	// TimesNote says why no times are shown when the approver has several signed decisions with
	// the card's outcome and their signatures were not checked: which one counted, and so which
	// decided_at is signed, is not known.
	TimesNote string
}

ApproverCard is one approver of an approval gate, as the page shows them: who, what they decided, whether their signature verified, the fingerprint of their key, and when they decided and when bide recorded it.

type Change added in v0.15.0

type Change struct {
	Change string `json:"change"` // added, removed or changed
	What   string `json:"what"`   // node, edge, entry or flow
	Node   string `json:"node,omitempty"`
	From   string `json:"from,omitempty"`
	To     string `json:"to,omitempty"`
	// Details say what changed, one item each ("block charge -> refund", "approval 1 of 3 -> 2 of
	// 3"); for an added or removed node, what it was.
	Details []string `json:"details,omitempty"`
	// Gate is how the node's approval gate changed: weakened (a set of decisions the new gate
	// accepts would not have passed the old one: the gate was removed, its need lowered, or an
	// approver added without raising the need to match), strengthened (the reverse, and not
	// weakened), or reordered (the same approvers and need in another policy order). Empty when the
	// gate did not change. A removed node's gate counts as removed.
	Gate string `json:"gate,omitempty"`
}

Change is one difference between two flow definitions: a node, an edge or Switch arm, the entry, or the flow's name, added, removed or changed.

func (Change) String added in v0.15.0

func (c Change) String() string

String is the change as one line: "changed node charge: approval 1 of 3 -> 2 of 3 (strengthened)".

type Config added in v0.14.0

type Config struct {
	Name     string
	Data     []byte
	Registry *plan.Registry
	// Strict makes Check fail on a warning as well as on an error (bide view -check -strict).
	Strict bool
}

Config is a flow definition to show instead of a run: its file name (for messages), its JSON bytes (a YAML file converted to JSON), and, when the program embeds the viewer, the plan.Registry its blocks, predicates and merges are registered in. With no Registry the check is structural (see plan.InspectConfig).

type ConfigView added in v0.14.0

type ConfigView struct {
	Name       string               `json:"name"`
	Flow       string               `json:"flow"`
	Typed      bool                 `json:"typed"`
	Digest     string               `json:"digest,omitempty"`
	Errors     int                  `json:"errors"`
	Warnings   int                  `json:"warnings"`
	Problems   []plan.ConfigProblem `json:"problems,omitempty"`
	Graph      *Graph               `json:"graph,omitempty"`
	Approvals  []string             `json:"approvals,omitempty"`
	CheckLabel string               `json:"check"`
	// Risk counts the nodes by crash behavior and gate, for the summary card.
	Risk RiskSummary `json:"risk"`
	// Assertions are the verdicts on the config's assert lines, in order.
	Assertions []plan.AssertionResult `json:"assertions,omitempty"`
	// Verdict is the answer the page opens with (see configVerdict); it is not in the JSON view.
	Verdict Verdict `json:"-"`
}

ConfigView is what the config page shows.

func BuildConfig added in v0.14.0

func BuildConfig(c Config) *ConfigView

BuildConfig checks c with plan.InspectConfig and lays out its declared graph, each problem marked on the node, edge or arm it belongs to.

type Conformance

type Conformance struct {
	OK     bool     `json:"ok"`
	Method string   `json:"method"` // "plan.Conform", or "structural" (see structural)
	Source string   `json:"source"` // where the topology came from
	Diffs  []string `json:"diffs,omitempty"`
	Digest string   `json:"digest"` // "match", "mismatch", or "not compared"
}

Conformance is the verdict on whether the run followed the declared topology.

type Counts added in v0.15.0

type Counts struct {
	NodesAdded   int `json:"nodes_added"`
	NodesRemoved int `json:"nodes_removed"`
	NodesChanged int `json:"nodes_changed"`
	EdgesAdded   int `json:"edges_added"`
	EdgesRemoved int `json:"edges_removed"`
	EdgesChanged int `json:"edges_changed"`
}

Counts are a diff's changes by kind.

type Decision

type Decision struct {
	Approver   string `json:"approver,omitempty"` // empty for a one-decision gate's Approve
	Approved   bool   `json:"approved"`
	Signed     bool   `json:"signed"`
	DecidedAt  string `json:"decided_at,omitempty"`
	RecordedAt string `json:"recorded_at,omitempty"`
}

Decision is one recorded approval decision. A signed decision carries two times: DecidedAt, the approver's clock inside the signature, and RecordedAt, the submitter's clock when it was journaled (not signed).

type Diff added in v0.15.0

type Diff struct {
	Old, New Config
}

Diff is a flow definition compared with an earlier version of it: bide check -diff. Each side is read as BuildConfig reads a config (plan.InspectConfig), so with a Registry on both sides the page also shows the digest each side's runs journal.

type DiffView added in v0.15.0

type DiffView struct {
	Name    string `json:"name"`
	OldName string `json:"old_name"`
	Flow    string `json:"flow"`
	// Typed reports both sides were checked against a plan.Registry, so their digests are known
	// (unless a side has errors).
	Typed     bool     `json:"typed"`
	OldDigest string   `json:"old_digest,omitempty"`
	NewDigest string   `json:"new_digest,omitempty"`
	Changes   []Change `json:"changes"`
	// Weakened and Strengthened name each node whose approval gate changed that way, with how:
	// "charge: approval 2 of 3 -> 1 of 3".
	Weakened     []string `json:"weakened,omitempty"`
	Strengthened []string `json:"strengthened,omitempty"`
	Counts       Counts   `json:"counts"`
	// OldErrors and NewErrors count each side's config errors (bide check lists them): a side
	// with errors is compared as far as it reads.
	OldErrors int    `json:"old_errors"`
	NewErrors int    `json:"new_errors"`
	Graph     *Graph `json:"graph,omitempty"`
	// Verdict is the answer the page opens with (see diffVerdict); it is not in the JSON view.
	Verdict Verdict `json:"-"`
}

DiffView is what the diff page shows.

func BuildDiff added in v0.15.0

func BuildDiff(d Diff) (*DiffView, error)

BuildDiff compares d.New with d.Old and draws the new flow with the old one's removed nodes and edges as ghosts. It fails only when a side cannot be read as a flow config at all.

func (*DiffView) DigestLine added in v0.15.0

func (v *DiffView) DigestLine() string

DigestLine says how the digest changed, in words, for the text summary and the page.

type Event

type Event struct {
	Seq    int      `json:"seq"`   // 1-based position in the journal
	Name   string   `json:"name"`  // the record's journal name
	Kind   string   `json:"kind"`  // agent.StepKind
	Class  string   `json:"class"` // the row's style: model, tool, attempt, approval, halt, end, value
	Title  string   `json:"title"`
	Detail string   `json:"detail,omitempty"`
	Badges []string `json:"badges,omitempty"`

	// What the page adds to the row; none of it is in the JSON view.
	At      time.Time `json:"-"` // when the journal says the record happened (a start or an attempt marker), else zero
	Payload string    `json:"-"` // the record as indented JSON, cut to a readable size (see prettyJSON)
	Rel     string    `json:"-"` // At as an offset from the run's start ("+3.2s")
	Abs     string    `json:"-"` // At in UTC, for the hover
	Bar     *TimeBar  `json:"-"` // the span from At to the next timestamped record
}

Event is one journal record, as a timeline row.

func (Event) IconName added in v0.16.0

func (e Event) IconName() string

IconName is the row's glyph.

type Exports

type Exports map[string][]agent.Record

Exports is a Source over exported journals (audit.JournalExport), by run ID.

func (Exports) History

func (x Exports) History(_ context.Context, runID string) ([]agent.Record, error)

History returns the exported run's records.

func (Exports) Runs

func (x Exports) Runs(context.Context) ([]string, error)

Runs lists the exported runs.

type Flow

type Flow struct {
	Topology plan.Topology
	// Digest is flow.Digest(), compared with the digest the run journaled. Empty: not compared.
	Digest string
	// Conform is flow.Conform. Nil: the viewer runs only its structural check (see Conformance).
	// Source says where the topology came from, as the page shows it.
	Conform func(ctx context.Context, j *agent.Journal, runID string) (bool, []string, error)
	Source  string
}

Flow is a declared flow the viewer draws a run against. The journal records a flow run's name and topology digest, not its topology, so the topology comes from the caller: a program that holds the *plan.Flow passes its Topology, Digest and Conform; the bide view command reads a Topology exported as JSON (json.Marshal(flow.Topology())) and, optionally, the digest.

type Follower added in v0.15.0

type Follower interface {
	// Grew reports whether runID has a record after the store sequence after (agent.Entry.Seq).
	// It is the read live mode polls, so it is cheap: one Load from after, stopped at its first entry.
	Grew(ctx context.Context, runID string, after int64) (bool, error)
	// HistorySeq is History with each record's store sequence, both read in one pass.
	HistorySeq(ctx context.Context, runID string) ([]agent.Record, []int64, error)
}

Follower is a Source whose runs can grow while the viewer reads them: a store, not an export. JournalSource is one.

type Gate

type Gate struct {
	ToolUseID  string     `json:"tool_use_id"`
	ToolName   string     `json:"tool_name,omitempty"`
	Single     bool       `json:"single,omitempty"` // a one-decision gate (agent.Approve)
	Need       int        `json:"need,omitempty"`
	Approvers  []string   `json:"approvers,omitempty"`
	ApprovedBy []string   `json:"approved_by,omitempty"`
	DeniedBy   []string   `json:"denied_by,omitempty"`
	Pending    []string   `json:"pending,omitempty"`
	Decisions  []Decision `json:"decisions,omitempty"`
	Tallied    bool       `json:"tallied"` // the gate journaled its terminal tally
	// AskedAt is when the run asked for approval, by the run's clock: a flow node's request time
	// (agent.ApprovalRequest.RecordedAt), else the pause's (agent.ApprovalWait.RecordedAt); empty
	// when the journal does not say.
	AskedAt string `json:"asked_at,omitempty"`
	// Waiting: the run paused at this gate (its approval-pending record, agent.ApprovalWait) and
	// the call has no result, no terminal tally, and (for a one-decision gate) no decision yet.
	Waiting bool `json:"waiting"`
	// Signatures is whether the gate's approver signatures were verified (audit.VerifyApprovals,
	// with -approver-keys), or why they were not checked; SignaturesOK reports a verified gate.
	Signatures   string `json:"signatures"`
	SignaturesOK bool   `json:"signatures_ok"`
	Status       string `json:"status"`
	// Reapproval: the gate's recorded tally passed on decisions that predate the signed decision
	// format (agent.DecisionFormat) and the call has not run, so the gate asks again when the run
	// resumes (agent.PendingReapproval); only decisions with a signed time count.
	Reapproval bool `json:"reapproval,omitempty"`
	// Cards is each approver as the page shows them (see ApproverCard); not in the JSON view.
	Cards []ApproverCard `json:"-"`
}

Gate is a tool call's or a plan flow node's approval gate, from the decisions and tally the journal holds. A flow node's ToolUseID is its key ("node:<name>", "node:iter:<n>:<name>").

func (Gate) Class added in v0.14.0

func (gt Gate) Class() string

Class is the gate's style: good, wait or bad.

func (Gate) HasTimes added in v0.16.0

func (g Gate) HasTimes() bool

HasTimes reports whether any of the gate's approver cards shows a decision time.

func (Gate) Headline added in v0.14.0

func (gt Gate) Headline() string

Headline is the gate's state in a few words, as the page's gate card and the node's box show it.

func (Gate) SigLine added in v0.14.0

func (gt Gate) SigLine() string

SigLine is the gate's signature verdict in a few words.

type Graph

type Graph struct {
	Nodes   []GraphNode `json:"nodes"`
	Edges   []GraphEdge `json:"edges"`
	SVG     string      `json:"-"`
	Mermaid string      `json:"mermaid"`
	Width   int         `json:"-"`
	Height  int         `json:"-"`
	// contains filtered or unexported fields
}

Graph is the declared topology with the run's path overlaid.

type GraphEdge

type GraphEdge struct {
	From    string `json:"from"`
	To      string `json:"to"`
	Label   string `json:"label,omitempty"`
	Taken   bool   `json:"taken"`
	Back    bool   `json:"back,omitempty"`
	Problem string `json:"problem,omitempty"` // a config problem at this edge or arm
	Cex     bool   `json:"cex,omitempty"`     // on a violated assertion's counterexample path
	// Change is how a flow diff changed this edge or arm (added, removed or changed), which
	// styles it; empty outside a diff.
	Change string `json:"change,omitempty"`
	// contains filtered or unexported fields
}

GraphEdge is one declared edge or Switch arm, and whether the run took it.

type GraphNode

type GraphNode struct {
	Name   string `json:"name"`
	Kind   string `json:"kind"`
	Status string `json:"status"` // done, halted, attempted, waiting (at its approval gate), not-reached
	// Gate is the node's declared approval gate ("2 of 3", "one decision"), empty for none, and
	// GateStatus where its latest evaluation stands (see Gate.Status).
	Gate       string `json:"gate,omitempty"`
	GateStatus string `json:"gate_status,omitempty"`
	// GateLine and SigLine are what the node's box says about its gate, short enough to read in
	// a screenshot: "approved 2 of 3" or "waiting, 1 of 2 approvals", and "signatures verified" (or
	// not, and why in short). GateClass styles them: good, wait or bad.
	GateLine  string `json:"gate_line,omitempty"`
	SigLine   string `json:"sig_line,omitempty"`
	GateClass string `json:"gate_class,omitempty"`
	Iters     int    `json:"iters,omitempty"`
	Last      bool   `json:"last,omitempty"`
	Note      string `json:"note,omitempty"`  // a line under the box
	Title     string `json:"title,omitempty"` // the tooltip, when not "name: status"
	// Risk is a config node's safety class ("side effect", "read-only", "idempotent", "safety
	// unknown") and Crash its crash behavior in a few words; empty on a run's graph. Cex marks a
	// node on a violated assertion's counterexample path.
	Risk  string `json:"risk,omitempty"`
	Crash string `json:"crash,omitempty"`
	Cex   bool   `json:"cex,omitempty"`
	// contains filtered or unexported fields
}

GraphNode is one declared node and what the run did with it.

type Halt

type Halt struct {
	Op          string    `json:"op"` // "tool" or "step"
	ID          string    `json:"id"` // the tool-use ID, or the step name ("node:<name>" for a plan node)
	ToolName    string    `json:"tool_name,omitempty"`
	Marker      string    `json:"marker"`
	AttemptedAt time.Time `json:"attempted_at,omitzero"`
	Ref         string    `json:"ref"` // the agent.HaltRef to resolve it with, as Go
}

Halt is an operation whose attempt marker is live with no result: a resume of the run returns *agent.OutcomeUnknown for it until agent.ResolveHalt records its outcome.

type Head struct {
	Title string
	Icon  template.URL
}

Head is what a page's <head> carries that differs between pages: its title and its icon.

type JournalSource

type JournalSource struct{ J *agent.Journal }

JournalSource reads a store through a Journal. Runs lists through the store's agent.Lister, when it has one.

func (JournalSource) Grew added in v0.15.0

func (s JournalSource) Grew(ctx context.Context, runID string, after int64) (bool, error)

Grew implements Follower.

func (JournalSource) History

func (s JournalSource) History(ctx context.Context, runID string) ([]agent.Record, error)

History reads the run's records.

func (JournalSource) HistorySeq added in v0.15.0

func (s JournalSource) HistorySeq(ctx context.Context, runID string) ([]agent.Record, []int64, error)

HistorySeq implements Follower. It reads the run through a Journal over the same store, so each record is decoded and checked as History does, and keeps the Seq of each entry the store yields.

func (JournalSource) Runs

func (s JournalSource) Runs(ctx context.Context) ([]string, error)

Runs lists the store's runs, or none when the store cannot list them.

type KindOption added in v0.15.0

type KindOption struct {
	Value, Label string
	On           bool
}

KindOption is one of the kind filter's options.

type ListFilter added in v0.15.0

type ListFilter struct {
	State string `json:"state,omitempty"`
	Kind  string `json:"kind,omitempty"`
	Q     string `json:"q,omitempty"`
	Limit int    `json:"limit"`
}

ListFilter is what the run list shows: the runs in a state group and of a kind, whose ID contains Q (ignoring case), at most Limit of them. Empty fields admit every run.

type LiveUpdate added in v0.15.0

type LiveUpdate struct {
	Changed bool `json:"changed"`
	// Live: the run has no end marker yet, so the page polls again; false once it has one.
	Live bool `json:"live"`
	// Cursor is the store sequence of the run's last record: the after of the next poll.
	Cursor    int64   `json:"cursor"`
	State     string  `json:"state,omitempty"`
	StateText string  `json:"state_text,omitempty"`
	Events    []Event `json:"events,omitempty"` // the rows of the records after the cursor given, only
}

LiveUpdate is GET /run/live's answer: whether the run has records after the cursor the page gave, and, when it has, the timeline rows of those records and the run's state now.

type MerklePath added in v0.16.0

type MerklePath struct {
	Seq   int    // the record's 1-based position in the journal
	Name  string // its journal name
	Size  int    // the journal length the signed root commits to
	Leaf  string // the record's leaf hash, hex
	Steps []MerkleStep
	Root  string // the signed root, hex
	// Climbed reports that hashing the path from the leaf gave Root, which the page checks again
	// here for the intermediate hashes it shows; the proof itself was verified by audit.
	Climbed  bool
	Alg      string
	SignedAt time.Time
}

MerklePath is one record's climb to the signed root: its leaf hash, the sibling hash at each level of the RFC 6962 audit path and the node it combines into, ending at the root the signed tree head commits to. The page draws it as a small diagram. It is built from the proof the audit package verified (audit.ProofBundle), so the diagram shows a path that holds.

func (*MerklePath) Caption added in v0.16.0

func (m *MerklePath) Caption() string

Caption says what the diagram shows.

func (*MerklePath) Diagram added in v0.16.0

func (m *MerklePath) Diagram() template.HTML

Diagram is the path drawn as an SVG, or empty when it did not climb to the root (the page then shows no diagram rather than one that does not hold).

type MerkleStep added in v0.16.0

type MerkleStep struct {
	Sibling string
	Left    bool // the sibling is the left child
	Node    string
}

MerkleStep is one level: the sibling hash, which side it is on, and the node they make.

type Options

type Options struct {
	Source Source
	// Flows are the declared flows runs are drawn against, by flow name.
	Flows map[string]*Flow
	// Provers check runs against audit artifacts; the first to return a verdict for a run wins.
	Provers []Prover
	// Config, when set, makes the handler show this flow definition instead of runs: the page at /
	// and its view as JSON at /config.json. Source is then not read.
	Config *Config
	// Diff, when set, makes the handler show a flow definition compared with an earlier one
	// instead of runs: the page at / and its view as JSON at /diff.json (see BuildDiff).
	Diff *Diff
}

Options configure Handler.

type Proof

type Proof struct {
	Source   string   `json:"source"` // "signed tree head" or "evidence package"
	OK       bool     `json:"ok"`
	Summary  string   `json:"summary"`
	Covers   int      `json:"covers"` // journal records the signed head commits to
	Problems []string `json:"problems,omitempty"`
	Items    []string `json:"items,omitempty"`
	// Approvals is the signature verdict on each m-of-n gate that journaled its tally, by
	// tool-use ID: audit.VerifyApprovals over the gate's evidence, with the approver keys given.
	// Nil without approver keys.
	Approvals map[string]ApprovalCheck `json:"approvals,omitempty"`

	// What the page draws from the proof; none of it is in the JSON view.
	Merkle   *MerklePath `json:"-"` // the proven record's path to the signed root
	SignedAt time.Time   `json:"-"` // when the signed head was signed
}

Proof is the audit verdict on the run's journal, from the audit package's own verifiers (the code bide audit verify and verify-evidence run), never a reimplementation.

type Prover

type Prover func(ctx context.Context, runID string, recs []agent.Record) *Proof

Prover checks a run's records against an audit artifact. It returns nil for a run the artifact is not about.

func EvidenceProver

func EvidenceProver(pkg audit.EvidencePackage, v audit.Verifier, ap Approvals, opts ...audit.EvidenceVerifyOption) Prover

EvidenceProver checks an evidence package (audit.EvidencePackage.Verify, as bide audit verify-evidence does) and that its signed head commits to the journal shown.

With approver keys (ap.Keys non-nil), it also checks each m-of-n gate's signatures with audit.VerifyApprovals over the package's actions, as bide audit verify-approvals does.

func HeadProver

func HeadProver(sth audit.SignedTreeHead, v audit.Verifier, ap Approvals) Prover

HeadProver checks a signed tree head: its signature under v and the timestamp rule (audit.CheckTimestamp), and that its root commits to the first sth.Size records of the journal shown, by building and verifying an inclusion proof of the last of them (audit.ProveRecord, ProofBundle.Verify), as bide audit prove and verify do.

With approver keys (ap.Keys non-nil), it also checks each m-of-n gate's signatures: it builds the gate's evidence from the journal under sth (audit.ApprovalEvidence) and verifies it with audit.VerifyApprovals, as bide audit verify-approvals does.

type RiskSummary added in v0.15.0

type RiskSummary struct {
	SideEffects int `json:"side_effects"`
	Gated       int `json:"gated"`
	Ungated     int `json:"ungated"`
	ReadOnly    int `json:"read_only"`
	Idempotent  int `json:"idempotent"`
	Unknown     int `json:"unknown"`
	// Line is the headline, as "3 side-effect steps, 2 gated, 1 ungated" ("steps known" when a
	// class is unknown).
	Line string `json:"line"`
	// UnknownLine says why some classes are unknown, empty when none is.
	UnknownLine string `json:"unknown_line,omitempty"`
}

RiskSummary counts a config's nodes by safety class: side effects (gated, when every path to one passes an approval gate, and ungated), read-only, idempotent, and unknown (the structural check cannot see a block's registered Safety).

type RunList added in v0.15.0

type RunList struct {
	Filter ListFilter `json:"filter"`
	Rows   []RunRow   `json:"runs"`
	// Matched is how many runs the filter admits; Rows holds the first Filter.Limit of them.
	Matched int `json:"matched"`
	// Summarized is how many runs were read; Listed how many the source lists. They differ when
	// more than maxSummarized runs match the ID filter.
	Summarized int      `json:"summarized"`
	Listed     int      `json:"listed"`
	Kinds      []string `json:"kinds"` // the kinds of the runs read, for the kind filter
	// Counts are the runs of each state group the ID and kind filters admit, and All their sum:
	// the state filter's counts.
	Counts map[string]int `json:"counts"`
	All    int            `json:"all"`
	More   string         `json:"more,omitempty"` // the page with listPage more rows, when there are more
	Notes  []string       `json:"notes,omitempty"`
	Err    string         `json:"error,omitempty"`
}

RunList is the run list page: the runs the filter admits, newest first by start time, then the runs that record none by run ID.

func (RunList) KindOptions added in v0.15.0

func (l RunList) KindOptions() []KindOption

KindOptions are the kind filter's options: the kinds of the runs read, and the chosen one.

func (RunList) States added in v0.15.0

func (l RunList) States() []StateOption

States are the state filter's options: every run, then each state group that has a run or is chosen.

func (RunList) Verdict added in v0.16.0

func (l RunList) Verdict() Verdict

Verdict is the run list's headline: what needs a person first.

type RunRow added in v0.15.0

type RunRow struct {
	ID        string `json:"run_id"`
	Kind      string `json:"kind"`  // agent.RunKind, or "" when the run has no run:start
	State     string `json:"state"` // the View state (see Build)
	StateText string `json:"state_text"`
	Group     string `json:"group"` // the state filter group
	Flow      string `json:"flow,omitempty"`
	Records   int    `json:"records"`
	// Started is when the run's first drive started, as its run:start records it
	// (agent.RunStart.Started). Zero for a run journaled by a version that recorded none.
	Started time.Time `json:"started,omitzero"`
}

RunRow is one run as the run list shows it.

func (RunRow) KindText added in v0.15.0

func (r RunRow) KindText() string

KindText is the run's kind as the list shows it.

func (r RunRow) Link() string

Link is the run's page.

func (RunRow) StartedText added in v0.15.0

func (r RunRow) StartedText() string

StartedText is Started as the list shows it, or "" when the run records no start time.

type Source

type Source interface {
	Runs(ctx context.Context) ([]string, error)
	History(ctx context.Context, runID string) ([]agent.Record, error)
}

Source is what the viewer reads: the runs it lists and each run's records. Both are reads.

type Stat added in v0.16.0

type Stat struct {
	Value, Label string
	Sub          string // one line under the label
	Class        string // good, bad, warn or empty
}

Stat is one key number under the verdict.

type StateOption added in v0.15.0

type StateOption struct {
	Value, Label string
	Count        int
	Link         string // the list with this option chosen, the other filters kept
	On           bool   // the option is the filter's
}

StateOption is one of the state filter's options.

type Stores

type Stores struct {
	SQLite   func(path string) (agent.Store, io.Closer, error)
	Postgres func(dsn string) (agent.Store, io.Closer, error)
	// YAML converts a YAML flow config to the JSON plan reads; nil means this build reads JSON
	// configs only.
	YAML func(data []byte) ([]byte, error)
}

Stores opens the stores bide view reads, read-only. It is how the command plugs in store backends (store/sqlite's and store/postgres's OpenReadOnly) without the core module importing one. A nil opener means this build cannot read that kind of store.

type TimeBar added in v0.16.0

type TimeBar struct {
	X, W  float64
	Label string
}

TimeBar is a timeline row's span on the run's clock, in percent of the whole: from the row's own time to the next timestamped record's. The journal timestamps only the run's start and its attempt markers, so this is how long the attempt had been open when the next one was written, an upper bound on the operation, not its duration.

type Verdict added in v0.16.0

type Verdict struct {
	// Class styles the banner: good, bad, warn, wait or info.
	Class string
	// Word is the state in capitals ("VERIFIED"), Icon its glyph (a name of icons) and Line one
	// sentence of why.
	Word, Icon, Line string
	// Details are further lines the state calls out (a weakened gate's policy).
	Details []string
	Stats   []Stat
}

Verdict is the answer a page opens with: one state in large type, a line under it, and a few key numbers. A state is never carried by color alone: Word and Icon say it too.

type View

type View struct {
	RunID  string `json:"run_id"`
	Kind   string `json:"kind"` // agent.RunKind, or "" when the run has no run:start
	Input  string `json:"input,omitempty"`
	Flow   string `json:"flow,omitempty"`   // the flow name run:start records
	Digest string `json:"digest,omitempty"` // the topology digest flow:digest records
	// State is the agent.RunState, except "halted" for a started run with a live attempt marker
	// and no result (see Halts): a resume returns *agent.OutcomeUnknown, so it is not in progress.
	State     string `json:"state"`
	StateText string `json:"state_text"` // State as the page shows it ("halted: outcome unknown")
	Terminal  string `json:"terminal,omitempty"`
	Records   int    `json:"records"`

	Events    []Event      `json:"events"`
	Halts     []Halt       `json:"halts,omitempty"`
	Gates     []Gate       `json:"gates,omitempty"`
	Graph     *Graph       `json:"graph,omitempty"`
	Conform   *Conformance `json:"conformance,omitempty"`
	Proof     *Proof       `json:"proof,omitempty"`
	Notes     []string     `json:"notes,omitempty"` // what the page cannot show for this run, and why
	LastNode  string       `json:"last_node,omitempty"`
	FinalText string       `json:"final_text,omitempty"`

	// Live: the page follows the run (live mode): it was read from a store, not an export, and has
	// no end marker. Cursor is the store sequence (agent.Entry.Seq) of its last record.
	Live   bool  `json:"live,omitempty"`
	Cursor int64 `json:"cursor,omitempty"`

	// Verdict is the answer the page opens with (see runVerdict); it is not in the JSON view.
	Verdict Verdict `json:"-"`
}

View is everything the run page shows, built from the run's records alone (see Build).

func Build

func Build(ctx context.Context, runID string, recs []agent.Record, flow *Flow) *View

Build reads the run's records into a View. recs is the run's journal in order (header included); flow, when non-nil, is the declared flow the run is drawn against.

func (*View) KindText added in v0.16.0

func (v *View) KindText() string

KindText is the run's kind as the page shows it.

Jump to

Keyboard shortcuts

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