engine

package
v0.17.0-alpha.4 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package engine implements the v1 workflow engine core: procedure specs parsed from kind: procedure graph entries, a typed variable store per running instance, guards as boolean combinations of named Go predicates, a closed function registry (predicates, queries, commands), gate-transition cascade with chooser stops, and append-only JSONL session persistence.

Everything semantic lives in named Go functions composed by name in the procedure spec — the spec language has no expressions, no literals, no assignment. See the v1 surface spec (plan 20260702-220449-d-tac-ry0) and the engine directive (20260702-174833-d-cpt-3yw).

Index

Constants

View Source
const (
	EndCompleted = "end(completed)"
	EndAbandoned = "end(abandoned)"
)

Terminal transition targets. A procedure ends by transitioning to one of these instead of a step ID.

View Source
const ExampleSpecFrontmatter = `` /* 1759-byte string literal not displayed */

ExampleSpecFrontmatter is the worked example the procedure spec reference fact serves: a small review move written for width — optional param and optional collect, two injects with differently shaped args, multi-clause infix guards, a user chooser looping back for correction, a dispatch seed on the confirming option, and a closing gate on the field the dispatched recording hands back. Authored beside the engine so its own tests load it — the served example cannot drift from what the engine accepts.

View Source
const LogVersion = 1

LogVersion stamps every event line. A session generally does not survive an sdd upgrade mid-flight — replay rejects unknown versions rather than guessing (accepted per the surface spec). Exported for shells that append terminal events to a parked log without replaying it (teardown by handle).

Variables

This section is empty.

Functions

func ComposeInstructions

func ComposeInstructions(unitText string, diagnostics []string) string

ComposeInstructions joins a rendered unit (or a shell-substituted reminder) with stall diagnostics — the one composition rule for the Instructions field, shared by the engine's serve and shells recomposing around served-instruction memory.

func IsEndTarget

func IsEndTarget(to string) bool

IsEndTarget reports whether a transition target is a terminal rather than a step ID.

Types

type BaseType

type BaseType string

BaseType is one of the closed set of domain types a procedure variable can declare. Adding a domain type means adding it here, once, with its validation — no other types exist.

const (
	TypeText              BaseType = "text"
	TypeBool              BaseType = "bool"
	TypeEntryID           BaseType = "entry-id"
	TypeRef               BaseType = "ref"
	TypeLabel             BaseType = "label"
	TypeParticipant       BaseType = "participant"
	TypeEntryKind         BaseType = "entry-kind"
	TypeLayer             BaseType = "layer"
	TypeConfidence        BaseType = "confidence"
	TypeIntent            BaseType = "intent"
	TypeAttachmentHandle  BaseType = "attachment-handle"
	TypeProcedureSpec     BaseType = "procedure-spec"
	TypeFactIndex         BaseType = "fact-index"
	TypePreflightFindings BaseType = "preflight-findings"
	TypeGuideFindings     BaseType = "guide-findings"
	TypeInvolvement       BaseType = "involvement"
	TypeInvolvementWhen   BaseType = "involvement-when"
	TypeSearchReplace     BaseType = "search-replace"
	// TypeProse validates exactly like text; the distinct declaration tells
	// serve-side rendering to treat changes as content diffs rather than
	// whole-value re-serves (20260826-120330-d-tac-8f8).
	TypeProse BaseType = "prose"
)

func BaseTypeValues added in v0.17.0

func BaseTypeValues() []BaseType

BaseTypeValues lists the domain types in canonical order, for surfaces that render or generate from the enumeration instead of restating it.

func (BaseType) Description added in v0.17.0

func (t BaseType) Description() string

Description returns the type's served meaning; empty for an unknown type.

type ChooserKind

type ChooserKind string

ChooserKind classifies who advances a step: the engine (gate, auto-advance on guards), the agent (advisory pick, logged with evidence), or the user (dialogue-presence made structural).

const (
	ChooserGate  ChooserKind = "gate"
	ChooserAgent ChooserKind = "agent"
	ChooserUser  ChooserKind = "user"
)

type ChooserOption

type ChooserOption struct {
	Choice  string
	Collect []CollectField
}

ChooserOption is one selectable choice in a served chooser.

type ChooserServe

type ChooserServe struct {
	Chooser string
	Kind    ChooserKind
	Options []ChooserOption
}

ChooserServe is the pending-chooser part of a serve: which step's chooser is pending, who answers, and what the options are. Chooser is the step ID the caller must name in a chooser answer — carried here so the value the answer requires appears in the payload it answers.

type CollectField

type CollectField struct {
	Name     string
	Optional bool
}

CollectField names a state field a report may write at a step; Optional fields don't gate the cascade.

type Command

type Command struct {
	Doc FuncDoc
	Fn  CommandFunc
	// MutatesGraph declares that running this command changes the on-disk graph
	// (a new entry, a rewritten summary). The engine invalidates the graph
	// provider after such a command so later reads in the same advance reload
	// and see the write — post-write freshness driven by the command's own
	// declaration, replacing the shell's hand-maintained refresh calls.
	MutatesGraph bool
}

Command is a registered command.

type CommandFunc

type CommandFunc func(ctx *Context) error

CommandFunc executes a side effect (gate ops and chooser calls only). Its store writes go through Store.WriteEngine per the declared contract.

type Context

type Context struct {
	Store *Store
	Graph *model.Graph
	// Step is the step the function runs at — commands like confirmPlayback
	// record it (the reopen target when a confirmation goes stale).
	Step string
	// Reads is the session's folded read set — the deepest depth each entry
	// was served at (refsInspected evaluates it). Nil means nothing was
	// served; reading a nil map is safe.
	Reads map[string]ReadDepth
}

Context is what registry functions see: the running instance's store and the graph, read-only by convention for predicates and queries. Commands additionally reach their side-effect dependencies through the closures they were registered with — the registry itself stays dependency-free.

type ContextualGraphs added in v0.17.0

type ContextualGraphs interface {
	CurrentFor(*Store) (*model.Graph, error)
}

ContextualGraphs optionally resolves the graph for one procedure store. The engine does not interpret store fields: application shells use this hook when a move carries an explicit graph authority that differs from the session's ordinary read graph. Procedure loading still uses Graphs.Current.

type Dispatch

type Dispatch struct {
	// Procedure optionally names the child canonical this option dispatches.
	// When set, it guards the handoff — the seed applies only to a child of
	// that procedure. Omit it for a generic junction whose child is chosen at
	// runtime (e.g. engage's move), where the seed applies to whatever is
	// dispatched next.
	Procedure string
	// Seed maps child field ← parent field: the key is the field the child
	// declares as state, the value is this parent's own declared field carrying
	// the evidence. Required — a Dispatch with no seed has nothing to carry.
	Seed map[string]string
}

Dispatch is a junction option's declaration of the grounding it seeds into a child dispatched after this option is answered. The seeding contract (d-tac-tlo) keeps the declaration entirely in the parent's spec: answering an option carrying a Dispatch stashes its Seed on the parent instance, and the next child started under that parent inherits exactly that mapping. There is no engine-wide default — a handoff happens only where a junction declares one, so every inheritance is readable at the junction that grants it.

type Engine

type Engine struct {
	Registry *Registry
	Graphs   Graphs
	// contains filtered or unexported fields
}

Engine executes procedure instances against a graph provider and a registry. It is pure Go over data — shells (MCP, webapp) sit on top; side-effectful commands come in through the registry with their own dependencies. The graph is not held as a mutable field: the engine reads it through Graphs, so ownership of "what the current graph is" stays on the read side.

func New

func New(registry *Registry, graphs Graphs, opts ...EngineOption) *Engine

New creates an engine reading the current graph through graphs.

func (*Engine) NewSession

func (e *Engine) NewSession(id, participant string, sink EventSink, opts ...SessionOption) *Session

NewSession creates an empty session appending to sink.

func (*Engine) ReplaySession

func (e *Engine) ReplaySession(id, participant string, events []Event, resolve SpecResolver, sink EventSink, opts ...SessionOption) (*Session, error)

ReplaySession reconstructs a session by folding its event log: state is applied directly from the logged values — reports, op results, and transitions — never by re-running commands, so replay is free of side effects. The returned session continues appending to sink.

type EngineOption added in v0.17.0

type EngineOption func(*Engine)

EngineOption configures an engine.

func WithTemplateValues added in v0.17.0

func WithTemplateValues(values map[string]any) EngineOption

WithTemplateValues adds read-only values available to procedure templates and inject-argument templates.

type Event

type Event struct {
	V        int            `json:"v"`
	TS       time.Time      `json:"ts"`
	Session  string         `json:"session"`
	Seq      int            `json:"seq"`
	Instance string         `json:"instance,omitempty"`
	Event    EventType      `json:"event"`
	Data     map[string]any `json:"data,omitempty"`
}

Event is one line of the append-only session log. Memory is the runtime source of truth; the log is the persistence, the session protocol, and the forensic record — transition reports are the trajectory evidence.

func ReadEvents

func ReadEvents(r io.Reader) ([]Event, error)

ReadEvents parses a JSONL session log.

type EventSink

type EventSink interface {
	Append(Event) error
}

EventSink receives events as they happen. The shell wires it to an append-only JSONL file; tests use an in-memory sink.

type EventType

type EventType string

EventType is one of the closed set of session-log events.

const (
	// EventSessionMeta is the session-level header line (no instance):
	// participant identity, so a log is self-describing for list_sessions
	// descriptors without resolving any procedure spec.
	EventSessionMeta EventType = "session_meta"
	// EventLabeled carries a human-meaningful session label (no instance):
	// the dialogue's subject, agent-supplied and updatable as it sharpens.
	// Last one wins on fold and replay.
	EventLabeled       EventType = "labeled"
	EventStarted       EventType = "started"
	EventReport        EventType = "report"
	EventChooserAnswer EventType = "chooser_answer"
	EventOpResult      EventType = "op_result"
	EventServed        EventType = "served"
	EventTransition    EventType = "transition"
	EventCompleted     EventType = "completed"
	EventAbandoned     EventType = "abandoned"
	// EventRead records what a read surface served to the session: the tool,
	// the entry IDs, and the depth — metadata only, never payloads. Reads stay
	// free and ungated; tracking is logging, not gating (d-tac-dbk). No
	// instance — the read set is session-level, so evidence inspected by a
	// dispatching parent counts for its seeded children.
	EventRead EventType = "read"
	// EventParked records that a running move was deliberately parked back to
	// the session junction — state kept, resumable through next. Forensic
	// only: a resuming agent can tell a shelved move from one that drifted.
	EventParked EventType = "parked"
)

type ExportedValue

type ExportedValue struct {
	Value      any        `json:"value"`
	Provenance Provenance `json:"provenance"`
}

ExportedValue is the persisted form of one store value.

type FactIndex added in v0.17.0

type FactIndex struct {
	Title string `json:"title"`
	Topic string `json:"topic"`
}

type FailedPredicate

type FailedPredicate struct {
	Name    string
	Message string
}

FailedPredicate names a predicate that held a gate, with its registered failure message — the message becomes the served instruction.

type FuncClass

type FuncClass string

FuncClass is one of the registry's three function classes.

const (
	ClassPredicate FuncClass = "predicate"
	ClassQuery     FuncClass = "query"
	ClassCommand   FuncClass = "command"
)

type FuncDoc

type FuncDoc struct {
	Name   string
	Class  FuncClass
	Doc    string
	Reads  []string
	Writes []string
}

FuncDoc is a registry function's documented contract: what it reads from and writes into the store. YAML never maps fields — it only names functions; these contracts are what spec authors consult (registryList, the MCP registry tool) and what load-time collision checks enforce.

type Graphs added in v0.14.1

type Graphs interface {
	Current() (*model.Graph, error)
	Invalidate()
}

Graphs is the engine's read-through to the current graph. The read side owns loading and freshness (a finders.GraphSource); the engine only reads through this value — Current returns the current graph (memoized by the source), Invalidate drops that memo after a graph write so the next read reloads. Declared here as an interface so the engine takes no finders import.

type GuardExpr

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

GuardExpr is a parsed guard expression.

func ParseGuard

func ParseGuard(src string) (*GuardExpr, error)

ParseGuard parses a guard expression. Whitespace (including newlines from folded YAML scalars) separates tokens.

func (*GuardExpr) Eval

func (g *GuardExpr) Eval(eval func(name string) (bool, error)) (bool, error)

Eval evaluates the expression against a predicate evaluator. Predicates are pure, so full evaluation (no short-circuit) is safe and keeps stall diagnostics complete.

func (*GuardExpr) Predicates

func (g *GuardExpr) Predicates() []string

Predicates returns the distinct predicate names the expression references, in first-appearance order. Used by spec validation (every name must exist in the registry) and by stall diagnostics.

func (*GuardExpr) String

func (g *GuardExpr) String() string

String returns the original expression source.

type InjectCall

type InjectCall struct {
	// Id is the stable identifier the unit template references the result
	// under. Optional — it falls back to Fn — but required to distinguish two
	// injects of the same fn on one step (d-tac-87o).
	Id   string
	Fn   string
	Args map[string]any
	// Cap is the author's size override for this inject's result; the zero
	// value defers to the query's registration default (d-tac-qwc).
	Cap serveview.Cap
}

InjectCall is a query op the engine runs before serving a step's unit. Args are literals or Go templates rendered against the store.

func (InjectCall) EffectiveID added in v0.17.0

func (c InjectCall) EffectiveID() string

EffectiveID is the template-context key an inject's result lands under.

type Instance

type Instance struct {
	ID     string
	Spec   *Spec
	Store  *Store
	Step   string
	Status InstanceStatus
	// Outcome is the end(...) label the instance finished with.
	Outcome string
	// Parent is the spawning instance's ID for sub-procedures, empty at the
	// top level.
	Parent string
	// contains filtered or unexported fields
}

Instance is one running procedure — a spec, its typed store, and a step position. Instances belong to a session; sub-procedures carry a parent link.

type InstanceStatus

type InstanceStatus string

InstanceStatus is a procedure instance's lifecycle state.

const (
	StatusRunning   InstanceStatus = "running"
	StatusCompleted InstanceStatus = "completed"
	StatusAbandoned InstanceStatus = "abandoned"
)

type Involvement added in v0.17.0

type Involvement struct {
	Target    string
	Actors    []string
	ActorsSet bool
	When      *When
}

Involvement is the engine-side value of an involvement-typed variable: one target a focus advances, with optional per-target actors and when, before it becomes a model.Involvement at the write gate. ActorsSet keeps the model's unset (inherit focus default) versus explicit-empty (pull-available) distinction across the JSON round-trip through the session log.

func (Involvement) MarshalJSON added in v0.17.0

func (i Involvement) MarshalJSON() ([]byte, error)

MarshalJSON emits actors only when set, so the replay round-trip through map[string]any reconstructs ActorsSet from the key's presence — omitempty cannot tell an explicit empty list from an unset one.

func (Involvement) String added in v0.17.0

func (i Involvement) String() string

type Option

type Option struct {
	Choice  string
	Call    string // command run on selection, per its Go contract
	Collect []CollectField
	To      string
	// Dispatch declares the grounding this junction option seeds into a child
	// dispatched after it is answered (child field ← parent field, named in the
	// parent's own spec). Nil means this option hands nothing down.
	Dispatch *Dispatch
}

Option is one choice on an agent or user chooser step.

type PartSize added in v0.17.0

type PartSize struct {
	Part  string
	Bytes int
}

PartSize names one serve part and its byte size — the per-part accounting behind the serve-budget measurement (d-tac-qwc). Injects and lanes are the scaling parts; schema, diagnostics, and produced complete a serve's weight.

type Predicate

type Predicate struct {
	Doc         FuncDoc
	Fn          PredicateFunc
	FailMessage string
	// FailDetail, when set, renders the failure message against the live
	// context — for gates whose rejection must name the offending values
	// (refsInspected naming the un-inspected IDs). Empty results fall back
	// to FailMessage.
	FailDetail func(ctx *Context) string
}

Predicate is a registered predicate with its contract and failure text — the message served as instruction when the predicate stalls a gate.

type PredicateFunc

type PredicateFunc func(ctx *Context) (bool, error)

PredicateFunc is a pure check over the store (and graph): no side effects, deterministic for a given state.

type PresencePair added in v0.17.0

type PresencePair struct {
	Field     string
	Predicate string
}

PresencePair is one gateable field with the presence predicate that reads it — the pairing surfaces render instead of restating.

func PresencePairs added in v0.17.0

func PresencePairs() []PresencePair

PresencePairs lists the presence predicates and the store field each reads, sorted by field — the closed gateable vocabulary.

type Provenance

type Provenance string

Provenance classifies who wrote a store value. The split carries the trust property from the surface spec: reports can only write declared state fields; params are fixed at start; everything trust-bearing (created IDs, findings, confirmation records) is engine-written via ops and chooser calls, structurally out of a report's reach.

const (
	ProvenanceParam  Provenance = "param"
	ProvenanceState  Provenance = "state"
	ProvenanceEngine Provenance = "engine"
)

type Query

type Query struct {
	Doc FuncDoc
	Fn  QueryFunc
	// ServeSafe marks the query as a pure read with no side effects — it writes
	// nothing to the session log or graph. Only serve-safe queries may be
	// declared as shell framing lanes: framing renders on every serve, and a
	// serve must not write (I7). A query that logs its reads (LogRead) or
	// mutates is not serve-safe and is rejected as a framing lane at spec load.
	ServeSafe bool
	// Bound declares the query's serving knowledge at its one authoritative
	// site: what part kind the result is, its default cap (a spec-declared
	// cap overrides it), and how to compose a pull expression for a cut's
	// remainder (d-tac-qwc).
	Bound QueryBound
}

Query is a registered query.

type QueryBound added in v0.17.0

type QueryBound struct {
	Part serveview.PartKind
	Cap  serveview.Cap
	// Pull composes a ready-to-run expression for what a cut dropped, from
	// the rendered inject args and the cut's accounting. Nil when no pull is
	// expressible.
	Pull func(args map[string]any, cut truncate.Cut) string
}

QueryBound is a query's declared serving knowledge; see Query.Bound.

type QueryFunc

type QueryFunc func(ctx *Context, args map[string]any) (any, error)

QueryFunc serves data for dynamic injection: pure read, result enters the template context (not the store).

type QueryResolver added in v0.17.0

type QueryResolver interface {
	Query(name string) (*Query, bool)
}

QueryResolver resolves a query's registration by name — what the arithmetic sizes inject caps against. *Registry implements it. A resolver miss means the spec names an unknown query, which Validate rejects before the arithmetic runs; the arithmetic skips such injects.

type ReadDepth

type ReadDepth string

ReadDepth classifies how deeply an entry was served: full means the body was served (a show primary, an injected chain's primary, or a same-session write); summary covers chain bullets, search headers, and snippets.

const (
	ReadSummary ReadDepth = "summary"
	ReadFull    ReadDepth = "full"
)

type Ref

type Ref struct {
	ID   string `json:"id"`
	Kind string `json:"kind"`
	Desc string `json:"desc,omitempty"`
}

Ref is the engine-side value of a ref-typed variable: the same closed-kind reference shape entries carry, before it becomes a model.Ref at the write gate.

type Registry

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

Registry is the closed set of Go functions a procedure spec may name. All semantics live here, composed by name in YAML — the spec language itself carries no logic. Enumerable so spec authors and lint can check every referenced name.

func NewRegistry

func NewRegistry() *Registry

NewRegistry returns a registry pre-populated with the built-in predicates (largely the mechanical pre-flight checks re-exposed — single path, no duplicated validation). Queries and commands with side-effect dependencies are registered by the shell that owns those dependencies.

func (*Registry) Command

func (r *Registry) Command(name string) (*Command, bool)

Command looks up a command by name.

func (*Registry) Docs

func (r *Registry) Docs(class FuncClass) []FuncDoc

Docs enumerates registered function contracts, optionally filtered by class, sorted by name — the registryList query's data.

func (*Registry) Predicate

func (r *Registry) Predicate(name string) (*Predicate, bool)

Predicate looks up a predicate by name.

func (*Registry) Query

func (r *Registry) Query(name string) (*Query, bool)

Query looks up a query by name.

func (*Registry) RegisterCommand

func (r *Registry) RegisterCommand(c Command) error

RegisterCommand adds a command. Names are unique across all classes.

func (*Registry) RegisterPredicate

func (r *Registry) RegisterPredicate(p Predicate) error

RegisterPredicate adds a predicate. Names are unique across all classes.

func (*Registry) RegisterQuery

func (r *Registry) RegisterQuery(q Query) error

RegisterQuery adds a query. Names are unique across all classes.

type Serve

type Serve struct {
	Instance  string
	Procedure string
	Status    InstanceStatus
	Outcome   string
	Step      string
	// Goal is a one-line statement of what advances the instance from here.
	Goal string
	// Instructions is the step's instruction unit rendered against the
	// store, with stall diagnostics appended when a gate is held.
	Instructions string
	// Unit names the instruction unit rendered into Instructions (empty when
	// the step has none). Shells key their served-instruction memory on it.
	Unit string
	// UnitText is the rendered unit alone, without diagnostics — what a
	// shell replaces with a one-line reminder once the unit was served.
	UnitText string
	// Lanes are the unit's rendered lanes in declaration order (empty
	// rendered lanes dropped), the blocks a host dedups independently
	// (d-tac-87o). UnitText is their join.
	Lanes []ServeLane
	// Diagnostics are the stall messages appended to Instructions ("Gate
	// held" lines), kept separate so shells can recompose around UnitText.
	Diagnostics []string
	// Missing names the current step's required collect fields not yet in
	// the store.
	Missing []string
	// Failing lists predicates currently holding the gate.
	Failing []FailedPredicate
	// ReportSchema is the JSON Schema for the current step's report.
	ReportSchema map[string]any
	// Chooser is set when the step awaits an agent or user choice.
	Chooser *ChooserServe
	// Produced carries the engine-written results on completion (e.g. the
	// created entry ID), excluding internal trust machinery.
	Produced map[string]any
	// Sizes is the per-part byte accounting of this serve — inject results,
	// rendered lanes, schema, diagnostics, produced (d-tac-qwc).
	Sizes []PartSize
	// Cuts records every bound that fired on this serve; the engine-owned
	// cuts lane renders them and the measurement harness reads them.
	Cuts []truncate.Cut
}

Serve is what the engine returns after every advance — the current step's rendered instructions, the report schema, chooser material when one is pending, and stall diagnostics naming exactly what's missing.

type ServeLane added in v0.17.0

type ServeLane struct {
	Name string
	Text string
}

ServeLane is one rendered lane of a serve's instruction unit — the unit a host's served-once memory dedups at (d-tac-87o).

type Session

type Session struct {
	ID          string
	Participant string
	// Label is the session's human-meaningful subject line — what a user
	// picks a parked dialogue by. Agent-supplied via SetLabel, updatable;
	// empty until supplied.
	Label string
	// contains filtered or unexported fields
}

Session is one dialogue session: N procedure instances interleaved serially, one append-only event log. Per-participant; the shell owns file placement and lifecycle.

func (*Session) Abandon

func (s *Session) Abandon(instanceID, reason string) error

Abandon explicitly discards a running instance, logged as an abandonment transition. It never cleans up implicitly — anything the instance holds (a WIP marker, staged attachments) is left standing for resume or groom.

func (*Session) Answer

func (s *Session) Answer(instanceID, chooser, choice string, fields map[string]any, userWords string) (*Serve, error)

Answer resolves the pending chooser at the instance's current step: the named chooser must be the current step (no early, late, or double answers), the choice must be one of its options, and any carried fields are limited to the option's collect list. User answers carry the user's words verbatim for the auditable-relay record.

func (*Session) Inject added in v0.17.0

func (s *Session) Inject(instanceID string, call InjectCall) (any, *truncate.Cut, error)

Inject runs one registered query against an instance's live context — the same path renderUnit uses for a step's inject, exposed so a shell can render declared framing lanes (which live outside any step unit) through the one query mechanism. Args templates render against the instance store. The result arrives bounded by the call's effective cap; a non-nil cut says what the bound dropped, for the caller's surface to render in its own register.

func (*Session) Instance

func (s *Session) Instance(id string) (*Instance, bool)

Instance returns a session instance by ID.

func (*Session) Instances

func (s *Session) Instances() []*Instance

Instances returns the session's instances in start order.

func (*Session) LogRead

func (s *Session) LogRead(tool string, full, summary []string)

LogRead records what a read surface served to the session: entry IDs at full depth (body served) and summary depth (headers, chain bullets, snippets), attributed to the serving tool. Every call appends a read event — re-reads are part of the forensic record — and folds into the session's read set, where full depth never downgrades. Empty calls append nothing.

func (*Session) Park

func (s *Session) Park(instanceID, note string) error

Park records that a running move was deliberately parked back to the session junction: state kept, position kept, resumable through the normal advance path. The event is forensic — nothing about the instance changes — but it makes the shelving auditable and legible to a resuming agent.

func (*Session) ReadDepthOf

func (s *Session) ReadDepthOf(id string) ReadDepth

ReadDepthOf returns the deepest depth the entry was served to this session at (empty when never served).

func (*Session) Report

func (s *Session) Report(instanceID string, fields map[string]any) (*Serve, error)

Report applies state fields from a transition report, re-evaluates, and cascades. Reports can only write declared state fields; batched fields for later steps are accepted. A report does not answer a pending chooser.

func (*Session) Serve

func (s *Session) Serve(instanceID string) (*Serve, error)

Serve re-serves the instance's current position without advancing it — shells use it to rehydrate an agent after resume_session. Draft (serveDelta) fields serve whole here: a rehydrating agent holds no earlier base, and the full serve resets the delta base for the rounds that follow.

func (*Session) SetLabel

func (s *Session) SetLabel(label string)

SetLabel records the session's subject label. Idempotent per value — a resent identical label appends nothing, so agents may safely carry the label on every call.

func (*Session) SinkErr added in v0.17.0

func (s *Session) SinkErr() error

checkSink surfaces a deferred log-append failure before advancing. SinkErr returns a stashed durable-append failure without clearing it, so the operation that caused it can surface the typed error synchronously while subsequent operations still refuse through checkSink.

func (*Session) Start

func (s *Session) Start(spec *Spec, params map[string]any, parent string) (*Serve, error)

Start begins a procedure instance from a loaded spec with typed params, then cascades and serves. Parent links a sub-procedure to its spawning instance.

type SessionOption

type SessionOption func(*Session)

SessionOption configures a session.

func WithClock

func WithClock(now func() time.Time) SessionOption

WithClock injects the timestamp source (tests use a fixed clock).

type Spec

type Spec struct {
	// EntryID is the graph entry the spec was loaded from.
	EntryID string
	// Canonical is the procedure's stable identity (capture, engage, …).
	Canonical string
	// Class is the procedure's execution role: a move is started through the
	// loop, a shell is a session base auto-started by the session door.
	Class model.ProcedureClass
	// Params are the typed inputs accepted at start_procedure.
	Params map[string]VarDecl
	// State is the report-writable variable store declaration. Engine-
	// written values are deliberately not declared — they enter the store
	// per the Go contracts of the functions the spec names, and collisions
	// with these declarations are rejected at load.
	State map[string]VarDecl
	// Steps is the state graph, in declaration order. The first step is the
	// entry step.
	Steps []*Step
	// ServeBudget is the spec's declared worst-case serve total in bytes;
	// zero defers to the engine's default budget. Read only by the advisory
	// authoring arithmetic (WorstCaseServeBytes) — never at load or runtime.
	ServeBudget int
	// StepByID indexes Steps.
	StepByID map[string]*Step
	// Units are the body's instruction units by name (`## unit: <name>`
	// sections), rendered as Go templates against the store at serve time.
	Units map[string]Unit
	// Framing declares a shell's session-framing lanes: inject query calls the
	// shell renders into its serve alongside the engine-supplied info block,
	// through the same query mechanism a step's inject uses. Empty on moves and
	// on shells that declare none (which then serve info-only framing).
	Framing []InjectCall
}

Spec is the typed, validated form of a procedure entry's state machine — what the engine executes. Parsed from the raw YAML the model retains on kind: procedure entries (structural validation happens here, at engine load time, per the type-system revision contract) plus the body's per-step instruction units.

func LoadSpec

func LoadSpec(entry *model.Entry, reg *Registry) (*Spec, error)

LoadSpec parses and fully validates a procedure entry against the registry — the one-call path the engine and lint use.

func ParseSpec

func ParseSpec(entry *model.Entry) (*Spec, error)

ParseSpec parses a procedure entry into a typed Spec: variable declarations, the step graph with parsed guards, and the body's instruction units. Registry-independent validation happens here (types, step wiring, guard syntax, collect declarations); function existence and write-collision checks need the registry and run in Validate.

func (*Spec) AnswerSchemaForStep

func (s *Spec) AnswerSchemaForStep(step *Step) map[string]any

AnswerSchemaForStep generates the JSON Schema for a chooser step's answer: the chooser to name (its step id), the choice to pick, the user's verbatim words for a user chooser, and the option-collected fields nested under `fields`. A flat report schema at a chooser step misled callers into placing collected fields at the top level (rejected); this envelope makes the required nesting explicit. `fields` unions every option's collect fields — each option enforces its own required set at answer time, so the envelope marks none of them required.

func (*Spec) EffectiveTotal added in v0.17.0

func (s *Spec) EffectiveTotal(budget serveview.Budget) int

EffectiveTotal is the total the arithmetic checks against: the spec's declared serveBudget when set — the author's recorded trade — else the budget's default Total.

func (*Spec) OverBudget added in v0.17.0

func (s *Spec) OverBudget(budget serveview.Budget, resolver QueryResolver) []StepSize

OverBudget returns the steps whose worst case exceeds the effective total.

func (*Spec) ReportSchemaForStep

func (s *Spec) ReportSchemaForStep(step *Step) map[string]any

ReportSchemaForStep generates the JSON Schema for a step's report from the spec's variable declarations: the step's collect fields are the named, described properties (required unless marked optional), and every other declared state field is accepted too — reports may batch fields for later steps, and the cascade rule makes the one-shot full draft as fast as today. The same desc that feeds instruction text feeds the schema.

func (*Spec) Validate

func (s *Spec) Validate(reg *Registry) []string

Validate runs the registry-dependent load checks: every function a spec names exists in the right class, and no named command writes into a declared param or state field (engine-written values must stay structurally out of the report-writable surface). Returns all problems.

func (*Spec) WorstCaseServeBytes added in v0.17.0

func (s *Spec) WorstCaseServeBytes(budget serveview.Budget, resolver QueryResolver) []StepSize

WorstCaseServeBytes sizes every step's automatic serve at its declared worst: the unit's lane skeleton (authored template text as written), each inject at its effective cap, each referenced declared field at its typed slot allowance, and the draft lane's cap when the step serves a delta. Individually capped parts can still sum past a host budget — this is the check that moved from runtime to authoring surfaces.

type SpecResolver

type SpecResolver func(canonical string) (*Spec, error)

SpecResolver resolves a procedure canonical to its loaded spec — replay uses it to rebind logged instances to their procedure definitions.

type StaticGraphs added in v0.14.1

type StaticGraphs struct{ Graph *model.Graph }

StaticGraphs is a Graphs backed by a fixed in-memory graph — for tests and callers with no reload need. Invalidate is a no-op: there is nothing behind the value to re-read.

func (StaticGraphs) Current added in v0.14.1

func (s StaticGraphs) Current() (*model.Graph, error)

Current returns the fixed graph.

func (StaticGraphs) Invalidate added in v0.14.1

func (s StaticGraphs) Invalidate()

Invalidate is a no-op for a static graph.

type Step

type Step struct {
	ID          string
	Collect     []CollectField
	Inject      []InjectCall
	Render      string
	Chooser     ChooserKind
	Options     []Option
	Guard       *GuardExpr
	Op          string
	Transitions []Transition
	// Goal overrides the serve's generic per-chooser goal line for this
	// step. Built for resident steps whose standing posture the generic
	// wording would misstate (a session shell's junction is "dialogue
	// freely", not "put the choice to the user").
	Goal string
	// ServeDelta names the state fields the engine renders as a draft block
	// on this step's serves: whole on the first serve (and on resume), only
	// what changed after — prose fields as content diffs, lists item-level,
	// scalars whole (20260826-120330-d-tac-8f8).
	ServeDelta []string
}

Step is one node of the state graph.

type StepSize added in v0.17.0

type StepSize struct {
	Step  string
	Bytes int
}

StepSize is one step's worst-case automatic serve weight in bytes.

type Store

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

Store is the typed variable store of one procedure instance. Declared params and state come from the spec; engine-written values enter through command contracts (their Writes set) and are validated against declaration collisions at spec load time, not here.

func NewStore

func NewStore(spec *Spec) *Store

NewStore creates an empty store bound to the spec that declares its params and state fields.

func (*Store) Clone added in v0.17.0

func (s *Store) Clone() *Store

Clone creates an isolated store for candidate mutation. Every stored value is a normalized JSON document, so a container-recursion copy fully isolates the candidate — a rejected batch leaves the source untouched.

func (*Store) Collected added in v0.17.0

func (s *Store) Collected() map[string]any

Collected returns the param- and state-provenance values that are present and non-empty, excluding internal trust machinery. It is a resuming agent's view of what this instance has already gathered — the anchor, chosen scope, and reported judgments that persist across a handover and must not be re-derived. Engine-produced trust records are structurally excluded by the provenance filter; the explicit trust-machinery skip keeps that guarantee even if such a field were ever param- or state-declared.

func (*Store) Export

func (s *Store) Export() map[string]ExportedValue

Export returns all values with provenance for session-log persistence.

func (*Store) Get

func (s *Store) Get(name string) (any, bool)

Get returns the value and whether it is present.

func (*Store) Has

func (s *Store) Has(name string) bool

Has reports whether the field is present and non-empty. Empty strings, empty lists, and nil don't count as present — a presence predicate asking hasBody wants substance, not a key.

func (*Store) SetParams

func (s *Store) SetParams(params map[string]any) error

SetParams validates and writes the start-time params. Required params must be present; unknown params are rejected.

func (*Store) SetStart

func (s *Store) SetStart(inputs map[string]any) error

SetStart applies the start-time input map, the shared seeding primitive (d-tac-tlo): a key naming a declared param sets that param (fixed at start), a key naming a declared state field seeds it — a start-time state write, equivalent to an immediate report, so an entry gate reading it is satisfied on entry. Move dispatch and direct start share this: a caller passing an anchor a procedure declares as state seeds the resolver, and the parent handoff seeds the same fields from the parent's store. Unknown keys are rejected.

func (*Store) StateSnapshot

func (s *Store) StateSnapshot() string

StateSnapshot returns a deterministic fingerprint over the report-writable state values. confirmPlayback binds a confirmation to this fingerprint; playbackConfirmed compares it — any state edit after confirmation changes the snapshot and reopens playback.

func (*Store) TemplateContext

func (s *Store) TemplateContext() map[string]any

TemplateContext exposes every store value by name for instruction-unit and inject-arg template rendering.

func (*Store) WriteEngine

func (s *Store) WriteEngine(name string, v any) error

WriteEngine writes an engine-produced value (an op result or chooser-call effect) per the producing function's Go contract. Never reachable from a report. The value is normalized to its JSON document form so pre-restart reads match the replayed form; a value that cannot marshal is a loud write-time error, leaving the store unchanged.

func (*Store) WriteState

func (s *Store) WriteState(fields map[string]any) ([]string, error)

WriteState validates and writes report-supplied state fields. Only fields declared in the spec's state block are writable — this is the report trust boundary. Returns the names actually written, sorted.

type Transition

type Transition struct {
	When      *GuardExpr
	Otherwise bool
	To        string
}

Transition is one ordered {when, to} entry; the final entry may be an otherwise fallback (When nil).

type Unit added in v0.17.0

type Unit struct {
	Lanes []UnitLane
}

Unit is one named instruction unit, as ordered lanes rendered independently so a host can dedup each on its own (d-tac-87o). A unit body without lane markers is one implicit lane named after the unit.

type UnitLane added in v0.17.0

type UnitLane struct {
	Name string
	Text string
}

UnitLane is one declared slice of a unit's instruction text (`### lane: <name>` sections inside a unit).

type VarDecl

type VarDecl struct {
	Type     VarType
	Optional bool
	Desc     string
	// Default is an optional start-time value applied to a state field the
	// caller leaves unset — the one place the spec carries a literal, and only
	// a declaration attribute, not an expression in the step language. It lets
	// a procedure carry a constant it seeds into every child it dispatches
	// (bootstrap's recognitionMode flag). Validated against Type at load; nil
	// means no default. Applied at store start on state only.
	Default any
	// PatchOf names a text state field this field edits in place: a reported
	// value is an ordered list of search-replace pairs applied atomically to
	// the target, and the target's new value is what lands and logs — the
	// patch field itself is never stored (20260826-120330-d-tac-8f8). Requires
	// an optional list<search-replace> declaration; validated at load.
	PatchOf string
}

VarDecl declares one typed variable. The desc seeds both the generated report schema and the "provide the following" instruction text — one declaration, both surfaces.

type VarType

type VarType struct {
	Base BaseType
	List bool
}

VarType is a declared variable type: a base domain type, optionally wrapped as list<T>.

func ParseVarType

func ParseVarType(s string) (VarType, error)

ParseVarType parses a type string from a variable declaration: a base domain type name or list<T> around one.

func (VarType) String

func (t VarType) String() string

func (VarType) ValidateValue

func (t VarType) ValidateValue(v any) (any, error)

ValidateValue checks a raw value (as decoded from a JSON report or supplied by Go code) against the type, returning a normalized value. Lists validate per element.

type When added in v0.17.0

type When struct {
	From string `json:"from,omitempty"`
	To   string `json:"to,omitempty"`
}

When is the engine-side value of an involvement-when: a temporal range that becomes a model.FocusWhen at the write gate. At least one end is set.

func (When) String added in v0.17.0

func (w When) String() string

type WriterSink

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

WriterSink appends events as JSON lines to an io.Writer.

func NewWriterSink

func NewWriterSink(w io.Writer) *WriterSink

NewWriterSink wraps a writer as an EventSink emitting one JSON line per event.

func (*WriterSink) Append

func (s *WriterSink) Append(e Event) error

Append writes the event as one JSON line.

Jump to

Keyboard shortcuts

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