Documentation
¶
Overview ¶
Package reporting is the single source of the four PLAN-17 report shapes — event, log, metrics, transcript-upload — published over NATS. Both entry points use it: the standalone `ape event`/`log`/`metrics`/ `transcript` commands and the PTY runners at finalize, so a supervised run and a self-reporting agent emit byte-compatible payloads on the same taxonomy (docs/reference/events.md).
Unlike the fire-and-forget eventing publisher, reporting publishes SYNCHRONOUSLY and surfaces failures: a publish rejected by the server (an identity the credential is not scoped for) is detected via nc.LastError() after a Flush round-trip and returned as an error, so the standalone commands can exit non-zero (PLAN-17 D5). The runner reuses the same builders but ignores the error (its taps stay fire-and-forget).
Every subject carries the <user> token decoded from the .creds identity (natsconn.Identity) — server-enforceable when the operator scopes publish permissions to `ape.*.<token>.>` — and every payload carries the resolved session id.
Index ¶
- Constants
- Variables
- func LevelValid(level string) bool
- type MetricsPayload
- type Options
- type Reporter
- func (r *Reporter) Close()
- func (r *Reporter) Conn() *nats.Conn
- func (r *Reporter) Event(sessionID, event string, payload json.RawMessage) error
- func (r *Reporter) Log(sessionID, level, msg string, fields map[string]string) error
- func (r *Reporter) Metrics(sessionID string, p MetricsPayload) error
- func (r *Reporter) PublishTranscriptUploaded(sessionID string, result TranscriptResult) error
- func (r *Reporter) UploadTranscripts(ctx context.Context, store blobstore.Store, sessionID string, ...) (TranscriptResult, error)
- type TranscriptFile
- type TranscriptResult
Constants ¶
const ( // LevelDebug…LevelError are the valid `ape log` levels. LevelDebug = "debug" LevelInfo = "info" LevelWarn = "warn" LevelError = "error" // EventTranscriptUploaded is the companion event `ape transcript upload` // publishes with the uploaded blobs' digest map. EventTranscriptUploaded = "transcript-uploaded" )
Subject roots. ape.evt is overridable (--events-subject-prefix); ape.log and ape.metrics are fixed, versioned, additive-only roots.
Variables ¶
var ErrDisabled = errors.New("reporting: no NATS URL configured")
ErrDisabled is returned by Connect when no NATS URL is configured — the standalone commands map it to a usage/config exit code (exit 2).
Functions ¶
func LevelValid ¶
LevelValid reports whether level is one of the four accepted log levels.
Types ¶
type MetricsPayload ¶
type MetricsPayload struct {
DurationSeconds float64
NumTurns int
PerModel map[string]eventing.ModelMetrics
FirstTurnAt string // RFC3339Nano, "" when unknown
LastTurnAt string
ClaudeCodeVersion string
RunID string // set only in --run-id (manifest-totals) mode
}
MetricsPayload is the ape.metrics.<user>.<project>.<sid> payload's metric-specific fields (PLAN-17 D3). It carries per-model token counts + timestamps so a consumer can reprice against Claude Code API rates at any later moment (the "convert to API prices any moment" requirement): the per_model tokens times the date-aware price table equal cost_usd.
func BuildMetrics ¶
func BuildMetrics(scan cost.ScanResult, runID string) MetricsPayload
BuildMetrics maps a scanned session set onto the metrics payload. Pure and deterministic given the scan — the runner and the CLI both call it, which is what makes a supervised run and a standalone `ape metrics` byte-identical (PLAN-17 exit gate).
type Options ¶
type Options struct {
// Identity is the decoded credential identity; its SubjectToken is the
// <user> subject segment and Name/PublicKey fill the payload user block.
Identity natsconn.Identity
// Project is the project root; slugged into the <project> segment.
Project string
// EvtPrefix overrides the ape.evt root (default eventing.DefaultPrefix).
EvtPrefix string
// SubjectUser overrides the <user> token (test-only seam behind
// --debug-subject-user, to prove server-enforced identity rejects a
// forged token). Empty uses Identity.SubjectToken.
SubjectUser string
}
Options configures a Reporter.
type Reporter ¶
type Reporter struct {
// contains filtered or unexported fields
}
Reporter publishes the four report shapes on one connection.
func Connect ¶
func Connect(ctx context.Context, cfg natsconn.Config, name string, opts Options) (*Reporter, error)
Connect opens a reporting connection for the standalone commands. It swaps the default stderr async-error handler for a silent one; publish rejections are detected synchronously via nc.LastError() and returned by the publish methods (PLAN-17 D5). Returns ErrDisabled when cfg carries no URL. The caller must Close the returned Reporter.
func New ¶
New wraps an existing connection (the runner's shared conn). The returned Reporter does not own nc and Close is a no-op on it.
func (*Reporter) Close ¶
func (r *Reporter) Close()
Close drains and closes the connection when the Reporter owns it.
func (*Reporter) Conn ¶
Conn exposes the underlying connection so a caller can build a blobstore backend against the same connection (the standalone `ape transcript` command selects nats-object vs uri-offload and passes the store to UploadTranscripts).
func (*Reporter) Event ¶
func (r *Reporter) Event(sessionID, event string, payload json.RawMessage) error
Event publishes a caller-named session event on ape.evt.<user>.<project>.session.<sid>.<event>. payload is the caller's arbitrary JSON (nil when none).
func (*Reporter) Log ¶
Log publishes a structured log record on ape.log.<user>.<project>.<sid>.<level>.
func (*Reporter) Metrics ¶
func (r *Reporter) Metrics(sessionID string, p MetricsPayload) error
Metrics publishes a metrics snapshot on ape.metrics.<user>.<project>.<sid>.
func (*Reporter) PublishTranscriptUploaded ¶
func (r *Reporter) PublishTranscriptUploaded(sessionID string, result TranscriptResult) error
PublishTranscriptUploaded emits the companion ape.evt.<user>.<project>.session.<sid>.transcript-uploaded event carrying the uploaded blobs' digest map (keyed by file base name) so consumers learn about the blobs without polling the store.
func (*Reporter) UploadTranscripts ¶
func (r *Reporter) UploadTranscripts(ctx context.Context, store blobstore.Store, sessionID string, files []cost.SessionFile) (TranscriptResult, error)
UploadTranscripts uploads a session's file set (main + sub-agents, content-addressed, zstd, idempotent) through store. Re-uploading a blob already present is a cheap no-op (Existed=true, same digest). It does not publish — call PublishTranscriptUploaded with the result to emit the companion event.
type TranscriptFile ¶
type TranscriptFile struct {
Path string `json:"path"`
SessionID string `json:"session_id"`
Digest string `json:"digest"`
URI string `json:"uri,omitempty"`
Bytes int64 `json:"bytes"`
Existed bool `json:"existed"` // true when the blob was already present (dedup no-op)
}
TranscriptFile is one uploaded transcript in the result object.
type TranscriptResult ¶
type TranscriptResult struct {
SessionID string `json:"session_id"`
Files []TranscriptFile `json:"files"`
}
TranscriptResult is `ape transcript upload`'s result object (stdout).