shadowconsumer

package
v0.26.0 Latest Latest
Warning

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

Go to latest
Published: Sep 1, 2026 License: AGPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package shadowconsumer is the Epic 69 S1 shadow consumer (US-69.5): the API subscribes on-demand to a pod's ABI stream with the reference client, folds it, and diffs the fold against its own API-side dialect derivation (ReferenceFold — the proxy-tracker semantics). Zero unexplained divergence across the scenario suite is the S1 exit.

Shadow only: nothing here feeds a production traffic path. The package is deliberately disposable after S1 (design 0055: "only the comparator is disposable").

Index

Constants

View Source
const (
	ClassBusyMismatch      = "busy_mismatch"
	ClassPartMismatch      = "part_mismatch"
	ClassSessionSet        = "session_set_mismatch"
	ClassSeqNonMonotonic   = "seq_non_monotonic"
	ClassSnapshotInconsist = "snapshot_inconsistency"
)

Divergence classes (issue #1139): busy mismatch, part mismatch/loss, session-set mismatch, seq anomalies, snapshot inconsistency.

Variables

This section is empty.

Functions

This section is empty.

Types

type ABISource

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

ABISource streams one pod's ABI surface via the reference client.

func NewABISource

func NewABISource(hc *http.Client, baseURL string) *ABISource

func (*ABISource) Stream

func (s *ABISource) Stream(ctx context.Context, onUpdate func(*Fold)) error

Stream folds the pod stream, invoking onUpdate per applied frame, until ctx is canceled. Reconnects on transport errors with backoff — a shadow consumer must survive pod restarts.

type Comparator

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

Comparator diffs the ABI fold against the reference derivation and tracks seq-stall observability (the 0050 D1 progress signal).

func NewComparator

func NewComparator(rec *Recorder) *Comparator

func (*Comparator) CompareNow

func (c *Comparator) CompareNow() int

CompareNow diffs the two folds at a checkpoint (scenario boundaries, quiescent polls) and records divergences. Returns the unexplained count. A checkpoint against a still-converging pair records NOTHING: the ABI seq counts a superset of the reference's projectable events, so a seq-based lag guard cannot prove per-session quiescence — only agreement can.

func (*Comparator) Converged

func (c *Comparator) Converged() bool

Converged reports whether both sides have been observed and currently agree (used by the scenario harness's eventual assertions).

func (*Comparator) Counts

func (c *Comparator) Counts() map[string]int64

Counts returns divergence counts per class (the shadow_divergence_total backing data).

func (*Comparator) Debug

func (c *Comparator) Debug() string

Debug renders the current both-sides state (harness failure dumps).

func (*Comparator) NoteGenerationReseed

func (c *Comparator) NoteGenerationReseed(sessionBusy map[string]bool)

NoteGenerationReseed mirrors the API tracker's generation-change reconcile: the reference adopts store truth (busy per session, in-flight cleared); the ABI side reaches the same state via its own reseed.

func (*Comparator) NoteHarnessDeath

func (c *Comparator) NoteHarnessDeath()

NoteHarnessDeath mirrors the API tracker's agent-death semantics: busy clears reference-side; the ABI side reaches the same state via reseed → store truth, so a transient busy mismatch inside the reseed window is EXPLAINED (not a divergence).

func (*Comparator) ObserveABI

func (c *Comparator) ObserveABI(f *Fold)

ObserveABI records an ABI-side fold. Seq monotonicity is checked on every observation (cheap, ordering-valid); state diffs run only at checkpoints (CompareNow) — per-observation diffing across an async pipeline manufactures phantom divergences from propagation lag.

func (*Comparator) ObserveReference

func (c *Comparator) ObserveReference(ref ReferenceState)

ObserveReference records an API-side derivation snapshot.

func (*Comparator) Report

func (c *Comparator) Report() string

Report renders all divergences for failure messages and exit reports.

func (*Comparator) SeqStallSeconds

func (c *Comparator) SeqStallSeconds() float64

SeqStallSeconds returns the current (or last) stall duration.

func (*Comparator) SeqStalled

func (c *Comparator) SeqStalled() bool

SeqStalled reports whether no seq advance has been observed within the stall threshold while the consumer is running (M3.3: starvation must be observable, not guessed).

func (*Comparator) SetReferenceSource

func (c *Comparator) SetReferenceSource(r *ReferenceFold)

SetReferenceSource lets the comparator read the current reference fold (used for harness-driven convergence checks).

func (*Comparator) SetStallThreshold

func (c *Comparator) SetStallThreshold(d time.Duration)

SetStallThreshold tunes the seq-stall detector (soak scenarios).

func (*Comparator) Unexplained

func (c *Comparator) Unexplained() int

Unexplained counts divergences not marked explained.

func (*Comparator) WithDivergenceHook

func (c *Comparator) WithDivergenceHook(fn func(class string)) *Comparator

WithDivergenceHook installs a per-divergence callback (the API wiring uses it to increment shadow_divergence_total{class} on the process registry).

type Divergence

type Divergence struct {
	Time      time.Time `json:"time"`
	Class     string    `json:"class"`
	Detail    string    `json:"detail"`
	ABI       string    `json:"abi,omitempty"`
	Ref       string    `json:"ref,omitempty"`
	Explained bool      `json:"explained"`
	Note      string    `json:"note,omitempty"`
}

Divergence is one observed difference, recorded as an artifact.

type Fold

type Fold = abiclient.SessionState

Fold is the ABI-side view handed to the comparator (an immutable abiclient snapshot).

type Recorder

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

Recorder writes the scenario artifacts (issue #1139: "recorded streams + tracker state"): the raw dialect stream the harness fed, and every divergence observed. One directory per run.

func NewRecorder

func NewRecorder(dir string) (*Recorder, error)

func (*Recorder) Close

func (r *Recorder) Close() error

func (*Recorder) RecordDialect

func (r *Recorder) RecordDialect(raw []byte)

func (*Recorder) RecordDivergence

func (r *Recorder) RecordDivergence(d Divergence)

type ReferenceFold

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

ReferenceFold is the API-side dialect fold — the same semantics the proxy tracker derives from raw opencode events (busy from session.status, in-flight parts from message.part.updated upserts), kept independent from the pod-side translation by construction (it consumes the DIALECT, not the contract).

func NewReferenceFold

func NewReferenceFold(workspaceID string) *ReferenceFold

func (*ReferenceFold) ObserveDialect

func (r *ReferenceFold) ObserveDialect(raw []byte)

ObserveDialect folds one raw opencode SSE payload.

func (*ReferenceFold) ObserveHarnessDeath

func (r *ReferenceFold) ObserveHarnessDeath()

ObserveHarnessDeath drops every session record — the API tracker's onAgentDied semantics: after agent death the derived session set is not authoritative and is rebuilt from the store on the next reconcile (the same rule the ABI side enforces via reseed-from-store).

func (*ReferenceFold) ObserveReconcile

func (r *ReferenceFold) ObserveReconcile(sessionBusy map[string]bool)

ObserveReconcile folds the API tracker's reconcile-on-generation-change: in-flight parts clear (live-turn state is not store truth) and busy follows the store. Mirrors proxy_events.go reconcileSessionState.

func (*ReferenceFold) Snapshot

func (r *ReferenceFold) Snapshot() ReferenceState

type ReferenceSession

type ReferenceSession struct {
	Busy    bool
	PartIDs map[string]bool
}

ReferenceSession is one session's API-side derivation. PartIDs is the in-flight part set (distinct part IDs upserted, cleared on idle/death — comparable to the ABI fold's in-flight parts).

func (ReferenceSession) PartCount

func (r ReferenceSession) PartCount() int

type ReferenceState

type ReferenceState struct {
	Sessions map[string]ReferenceSession
	Observed int
}

ReferenceState is the API-side derivation snapshot (the tracker facts the comparator diffs against). Observed is the count of projectable events folded so far — the comparator's lag guard (the ABI fold arrives via the async stream; diffing against a stale fold would manufacture phantom divergences).

Jump to

Keyboard shortcuts

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