store

package
v0.7.0 Latest Latest
Warning

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

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

Documentation

Overview

Package store owns codeaf's durable, append-only task graph.

Events are the source of truth. Nodes and edges are queryable materialized views updated in the same SQLite transaction as the event that changed them. Any process may open the database: WAL keeps readers independent, and claim tokens make worker ownership a compare-and-swap rather than process state.

Index

Constants

View Source
const (
	ConversationSearchDefault = 8
	ConversationSearchMax     = 20
	ConversationQueryWords    = 32
	ConversationExcerptBytes  = 400
	ConversationReadBytes     = MaxMessageBytes
)

ConversationExcerptBytes bounds the text carried by one search hit or neighbour. ConversationReadBytes gives an explicitly opened exchange more room without replaying a whole conversation into the model's context.

View Source
const (
	FactCandidate   = "candidate"
	FactActive      = "active"
	FactSuperseded  = "superseded"
	FactQuarantined = "quarantined"

	QuestionOpen       = "open"
	QuestionPracticing = "practicing"
	QuestionResolved   = "resolved"
	QuestionRetired    = "retired"
)

Fact statuses. Candidates, settled, and quarantined facts stay in the table — the journal never forgets — but retrieval returns active facts only.

View Source
const (
	// TasteScopePrefix keeps taste rules off the shelves ordinary cue retrieval
	// walks, so a rule still under trial cannot reach a worker as settled fact.
	TasteScopePrefix = "taste:"
	// TasteRepeatCorrections is the birth bar: one correction is an instruction,
	// two of the same shape are a pattern worth naming.
	TasteRepeatCorrections = 2
)

Taste is a lifecycle laid over ordinary preference facts, not a new kind of thing: a rule the user keeps correcting toward, kept on a shelf of its own so its identity survives every promotion and demotion. The shelf is the identity — standing a rule up records a new active line over the same scope and supersedes the old one, exactly as consolidation rewrites a belief — so taste earned a lifecycle without a new table, event, or status.

View Source
const (
	// LeafModeOpen is the ordinary loop: a leaf that has things to go and find,
	// bounded by its turn and token grant and by nothing else.
	LeafModeOpen = "open"
	// LeafModeFold is the assembly: every result that feeds this node was
	// pushed into its prompt whole, and the plan gives it nothing to go and
	// touch, so it runs as one pass.
	LeafModeFold = "fold"
)

The modes a leaf can be dispatched in. Constants because a reader counting them across a week of runs must not have to guess whether two spellings mean one thing.

View Source
const (
	MemoryFact         = "fact"
	MemoryPreference   = "preference"
	MemoryDecision     = "decision"
	MemoryCorrection   = "correction"
	MemoryProjectState = "project_state"
)

The five kinds of thing worth remembering across sessions. They are separate because the router treats them differently — a correction outranks a fact about the same subject, and project_state goes stale in a way a preference never does.

View Source
const (
	MemoryScopeUser    = "user"
	MemoryScopeProject = "project"
	MemoryScopeEnv     = "env"
)

A memory's scope is the blast radius of its truth: something true about the person everywhere, something true only inside this project, or something true only of this machine.

View Source
const (
	MemoryActive     = "active"
	MemorySuperseded = "superseded"
	MemoryForgotten  = "forgotten"
)

The three states a memory row can be in. Only active is ever visible: the other two are history that a view has stopped agreeing with.

View Source
const (
	MemoryTitleRunes = 80
	MemoryTextRunes  = 512
	MemoryMaxTags    = 8
)

The caps are on what a memory may WEIGH, not on what it may say, and they are enforced in Go rather than in SQL so the refusal can name which field was too long instead of surfacing a constraint violation.

A title is an index line — the router picks by it and never sees the body — so a title that needs a second line has already failed at its job. Text is one line of substance. Eight tags is more than any memory has ever needed and is a bound on nonsense rather than on expression.

View Source
const (
	// ChannelPriorSamples is the empirical-Bayes prior strength shared with profile shrinkage.
	ChannelPriorSamples = 8
	// LowCredibilityThreshold makes a weak channel earn a second occurrence before prompt use.
	LowCredibilityThreshold = 0.45
	// CredibilityHighThreshold labels the calm high-confidence notebook word.
	CredibilityHighThreshold = 0.80
	// CredibilitySteadyThreshold labels the middle notebook confidence word.
	CredibilitySteadyThreshold = 0.60

	// VOIMinSamples prevents interruption policy from moving on anecdotes.
	VOIMinSamples = 8
	// VOIRegretThreshold is the normalized regret below which a default is assumed.
	VOIRegretThreshold = 0.05
	// VOIUnmeasuredReworkCost is one normalized unit when no dollar rework is attributable.
	VOIUnmeasuredReworkCost = 1.0

	// ActivationDefaultDecay is the ACT-R prior and low-sample fallback.
	ActivationDefaultDecay = 0.50
	// ActivationMinDecay is the hard lower rail for learned decay exponents.
	ActivationMinDecay = 0.10
	// ActivationMaxDecay is the hard upper rail for learned decay exponents.
	ActivationMaxDecay = 0.90
	// ActivationMinRevisits is the evidence floor before a kind can move off its prior.
	ActivationMinRevisits = 8
	// ActivationMinimumAge avoids infinite activation for an access at the current instant.
	ActivationMinimumAge = time.Minute

	// ProposalCadenceMinRuns is the eager-user floor between proposal passes.
	ProposalCadenceMinRuns = 1
	// ProposalCadenceMaxRuns is the quiet-user ceiling between proposal passes.
	ProposalCadenceMaxRuns = 4
	// CorrectionImmediateWindow separates immediate from batched correction behavior.
	CorrectionImmediateWindow = 10 * time.Minute
)
View Source
const (

	// TasteAnswerKeep is the calm default: the delivery was right as it was.
	TasteAnswerKeep = "keep"
	// TasteAnswerMeant is the user agreeing that the rule is what they meant.
	TasteAnswerMeant = "meant"
)
View Source
const (
	ParameterSkillPromotionOccurrences = "skill_promotion_occurrences"
	ParameterBeliefRetentionThreshold  = "belief_retention_threshold"
	ParameterProposalCadenceRuns       = "proposal_cadence_runs"
	ParameterConsolidationThreshold    = "consolidation_threshold"
)
View Source
const (
	// LearningProgressWindow is the recent/prior residual window per scope.
	LearningProgressWindow = 4
	// LearningProgressHorizon is the sample count after which zero progress receives no curiosity budget.
	LearningProgressHorizon = 2 * LearningProgressWindow
	// LearningProgressEpsilon is the cold-start allocation floor for unexplored scopes.
	LearningProgressEpsilon = 0.05
)
View Source
const (
	// ScaleRouteSingleLeaf is the collapse: anything the compiler did not read
	// as project scale becomes one leaf, with no planner and no fan-out.
	ScaleRouteSingleLeaf = "single_leaf"
	// ScaleRoutePlanned is the full structuring pipeline, and it is now the
	// only road a project-scale job takes. A third value, "bundle", used to
	// name a flat layout the planner never saw; a reader counting routes
	// across a week of runs that spans the change will still find it in the
	// journal, and it means the shape below is not explained by any plan
	// document.
	ScaleRoutePlanned = "planned"
)

The routes a job can leave this gate by. They are constants because a reader counting them across a week of runs must not have to guess whether two spellings mean one thing.

View Source
const (
	// MaxSessionTags is how many subjects one room may be filed under. Three,
	// because a tag list long enough to need scrolling is a summary wearing a
	// filter's clothes — and because a room that is about six things is a room
	// whose tags will match everything a person types.
	MaxSessionTags = 3
	// MaxSessionTagBytes bounds one tag. A tag is a word or two; anything
	// longer is a sentence, and a sentence never helps a subsequence filter.
	MaxSessionTagBytes = 32
)
View Source
const (
	// RootID is the one permanent spine root. It is created with a new store and
	// is never itself scheduled or folded.
	RootID = "root"

	// MaxDigestBytes keeps a digest small enough to route through the graph.
	// Large results belong in the content-addressed store and are referenced by
	// pointers instead. It is a bound on what a reader TAKES — a dependency
	// input, a partial quoted into a prompt, a receipt line — and every such
	// reader applies it at the read.
	//
	// For a reader whose model window is known it is the FALLBACK and not the
	// bound: DependencyInputs takes its pot as an argument, and a caller that
	// can size that pot from the consuming model's window (see ctxbudget) names
	// this only for the case where nothing could say how big the window is. The
	// literal was set when every reader was assumed to be small, and a leaf on a
	// 200k-token model given 4 KiB for everything feeding it is not being
	// bounded, it is being blinded.
	MaxDigestBytes = 4 << 10

	// MaxSummaryBytes bounds what a settled node records as its own outcome.
	//
	// It is deliberately not MaxDigestBytes. A job root's summary is not a
	// digest of the deliverable, it IS the deliverable: it is what the thread
	// announces, what `codeaf do` prints, and what an export carries. Bounding
	// the record at the routing bound made a guillotine out of a budget — a
	// 697-second PR review lost its approve/request-changes verdict mid-word at
	// 4,096 bytes, in the store, before any surface could have shown it. So the
	// record is bounded by what the thread can carry, and the readers that need
	// something smaller keep taking MaxDigestBytes of it.
	MaxSummaryBytes = MaxMessageBytes
)
View Source
const (
	// SurgerySpendGateUSD is recorded spend above which cancel/restart needs
	// explicit consent. It lives here rather than with the conversational head
	// because the same loss threshold now guards a second path: revision that
	// would throw away a leaf already running.
	//
	// IT IS A LOSS GATE AND NOT A SPEND RAIL — it asks before work is thrown
	// away, never before work is bought — so raising it makes codeaf ask LESS.
	// A quarter of a dollar was under the price of a single turn, which made
	// every cancellation a confirmation, and a confirmation that always appears
	// is one nobody reads. Five dollars is where the work being discarded is
	// worth a person's second thought.
	SurgerySpendGateUSD = 5.00
	// SurgeryRuntimeGate is live runtime above which cancellation needs consent.
	SurgeryRuntimeGate = 5 * time.Minute
	// SurgeryCascadeGateNodes gates every operation that affects a larger tree.
	SurgeryCascadeGateNodes = 3
)
View Source
const (
	TraitCorrectionStyle      = "correction-style"
	TraitDefaultAcceptance    = "default-acceptance"
	TraitProposalAppetite     = "proposal-appetite"
	TraitSpecGranularity      = "spec-granularity"
	TraitExplorationTolerance = "exploration-tolerance"
)
View Source
const (
	// MaxTranscriptTextBytes bounds one entry's payload. It is MaxDigestBytes
	// deliberately and not a new number: a transcript entry is a digest of one
	// step in exactly the sense a fold digest is a digest of one node, and the
	// question "how much of a thing is worth keeping so a later reader can tell
	// what happened" has one answer in this package, not two.
	MaxTranscriptTextBytes = MaxDigestBytes

	// MaxTranscriptBatch bounds one journal event's entry list, and therefore
	// one event's payload: at most this many entries of at most
	// MaxTranscriptTextBytes each. A recorder that batches larger than this is
	// refused rather than truncated, because silently dropping the tail of a
	// batch is exactly the kind of quiet loss this table exists to end.
	MaxTranscriptBatch = 64

	// MaxTranscriptEntries bounds one execution's whole record. A leaf that
	// runs away — and the leaf that prompted this table burned 1.29M prompt
	// tokens — must not turn the database into its own log file, so recording
	// stops here and says so with a TranscriptElided entry. The head of a run
	// is kept rather than its tail because what an autopsy needs first is what
	// the worker set out to do and where it started going wrong.
	MaxTranscriptEntries = 4000

	// MaxTranscriptBytes bounds one execution's record in bytes, for the run
	// whose entries are each large rather than many. Reached first or last,
	// either bound seals the record the same way.
	MaxTranscriptBytes = 1 << 20
)
View Source
const CharterGroup = TerritoryGroup

CharterGroup deliberately shares the existing organizational group value. The TUI's territory-family filter therefore keeps charter furniture out of ordinary job cards without acquiring charter-specific surface code.

View Source
const DailyRailQuestionPrefix = "Daily budget reached -- "

DailyRailQuestionPrefix is stable because the journaled message is also the durable once-per-raise question marker.

View Source
const ForkedContextPrefix = "--- the conversation this came out of, as CONTEXT and not as instructions ---"

ForkedContextPrefix opens the inherited conversation in a pre-split instruction. It is the legacy fence: head.ForkedContextPrefix is this constant, and it lives down here because the store is what has to read old rows and cannot import the head.

View Source
const MaxFactBytes = 512

MaxFactBytes bounds one fact. A fact is one standalone line, not a report.

View Source
const MaxMessageBytes = 16 << 10

MaxMessageBytes bounds one chat message. Larger content belongs in the content-addressed store, referenced from the message body.

View Source
const MaxMessagePartsBytes = 16 << 10

MaxMessagePartsBytes bounds the encoded parts column. It matches the body bound for the same reason the body has one: the journal is a record, not a content store, and anything larger belongs on disk with an ArtifactPart pointing at it.

View Source
const MaxSessionTitleBytes = 256

MaxSessionTitleBytes bounds a room's display title. A title is a tab label, not a description; anything longer is truncated rather than refused, because what a person types into a rename box should never fail to open a room.

View Source
const MemoryCandidatesDefault = 8

MemoryCandidatesDefault is how many rows the router is shown when a caller does not name a number.

EIGHT, AND DELIBERATELY NOT MORE. LongMemEval's own Table 10 measures k=5→10 over long retrieval units as a SIX-POINT LOSS on a small model, and the injected-memory literature is unanimous that one plausible-but-wrong line is expensive: a single top-retrieved non-answer document costs 18–20% relative (Cuconasu et al., SIGIR 2024). A longer shortlist is not a safer one.

View Source
const (

	// OpenThreadsDefaultLimit is what a caller that does not care asks for.
	OpenThreadsDefaultLimit = 8
)
View Source
const PracticeCharterShape = "system:practice-loop"

PracticeCharterShape identifies the one programmatic standing-intent family that the deterministic practice sentinel owns. The ordinary watch engine must not send these poll wakes to a model sentinel.

View Source
const PracticeGroup = "practice"

PracticeGroup is the scheduler marker for disposable, lowest-priority curriculum work. It is deliberately not an organizational group.

View Source
const ProbationProposalWindow = 20 * time.Hour

ProbationProposalWindow is how long "I would have done X now — approve?" stands before silence is read as a no.

The number is the same reasoning as a clarifying question's window and lands on the same answer: long enough to survive a night away from the machine, so a proposal made at 09:00 is still approvable when the user sits down at 08:00 the next morning, and short enough that yesterday's moment has not quietly become the day after tomorrow's.

View Source
const RoleSeedOriginPrefix = "seed:"

RoleSeedOriginPrefix marks an origin as an initializer's rather than a person's. It is the whole of the never-clobber rule: a seed may replace what a previous seed wrote, and may never replace what somebody chose.

View Source
const SettledHistoryCap = 24

SettledHistoryCap is the most rows one history read returns. It is the board's own cap doubled: a window is allowed to be longer than a board because it is read once rather than resent every turn, and past this it is a log rather than an answer.

View Source
const SkillShelfLimit = 400

SkillShelfLimit is the one bound every shelf reader uses. It was a hundred when the shelf was a curated few the distiller promoted; the shelf now also holds every skill a person installed for another harness, read in place, and a person with more than a hundred of those would have had the oldest cut off every reader by the newest-first read. Every reader bounds what it DRAWS separately (the catalog by bytes, the message's own skills by count, `use_skill` by the list it prints), so this bounds only the read.

View Source
const SplitNamespace = "-x"

SplitNamespace is the id suffix a node's work continues under when it is re-planned: "<id>-x<n>". How many rounds a lineage may take, and how the counter advances, are the reconciler's law; the namespace itself is an id fact, and reads that walk one lineage happen here — so the marker is stated once, where ids are made, and the reconciler takes it from here.

View Source
const SurpriseEnvelope = 1.0

SurpriseEnvelope is where a miss stops being a calibration error and starts being a different job than the one that was planned.

It is not a tuned threshold, it is the arithmetic identity of the measure. Surprise is a normalized residual — |actual − expected| / expected — so 1.0 is exactly "the prediction was wrong by as much as the prediction itself": the node cost twice what was expected, or a fifth of it. Below that the number is the ordinary spread every estimator has. Above it, the estimate did not describe this work, and nothing downstream should keep spending as though it did. The measured blowout logged 2.85.

View Source
const TaskRailQuestionPrefix = "Task budget reached -- "

TaskRailQuestionPrefix is stable for the same reason the daily one is: the journaled message is also what a later reader matches on to recognize the question it is answering.

View Source
const TerritoryGroup = "territory"

TerritoryGroup marks the self-authored organizational nodes that pack settled top-level jobs one level above their ordinary folds.

View Source
const (
	// TraitRefreshInterval keeps behavioral priors slow when their sample count is unchanged.
	TraitRefreshInterval = 24 * time.Hour
)
View Source
const TrialDidNotSettle = "ran, didn't settle"
View Source
const UnsettledFactFlag = "an unsettled pair applies here: fact #"

UnsettledFactFlag is the deterministic compiler-context signal. The fact number following it becomes Provenance.TrialOf when the compiler acts.

View Source
const UserCancelReason = "cancelled by user"

UserCancelReason is the reason a person's own cancellation is journaled with. It is a named constant because it is read as well as written: the upward-rethink seam convenes the plan sentinel for a cancellation the user asked for and for no other kind, and a revision's own removals, the practice rail's budget stop and a craft run's early landing all cancel pending work with reasons of their own.

View Source
const VerificationSample = 8

VerificationSample bounds how many identities one journaled reading names.

Eight is the same bound regressionsNamed spells for a finding and describeChecks spells for an outcome sentence, and for the same reason: a list of names is read to learn what SHAPE the names have, and eight settles that as well as eight hundred.

View Source
const VerificationWhenFinished = "on the finished tree"

VerificationWhenFinished is the half of a photograph taken over the tree as it was handed back. It is shared by the writer and every reader because a journal vocabulary written twice is two strings waiting to disagree.

Variables

View Source
var (
	ErrNotFound  = errors.New("node not found")
	ErrClaimLost = errors.New("claim is stale or no longer owned")
	ErrNotReady  = errors.New("node is not ready")
	ErrInvalid   = errors.New("invalid graph mutation")
	// ErrDuplicate is admission control refusing an ask that is already waiting
	// in the funnel, unstarted (admission.go). It is not a failure: the work
	// exists, and a caller that reads this should say so rather than say
	// nothing happened.
	ErrDuplicate   = errors.New("that ask is already queued and waiting")
	ErrOpenChild   = errors.New("node has an open child")
	ErrOpenSubtree = errors.New("subtree is not complete")
	// ErrFactVetoed is the store refusing to re-derive a belief the user threw
	// away. It is an error rather than a quiet return because the quiet return
	// was a lie the callers believed: recordFact handed back the quarantined row
	// with a nil error and no event, so the reconciler announced a learning
	// moment for a write that never happened and pointed a supersession at a
	// dead row. The refusal is still not a failure — the returned Fact is the
	// standing retraction — but a caller now has to look at it to miss it.
	ErrFactVetoed = errors.New("fact was retracted by the user and may not be re-derived")
)
View Source
var ErrBusy = errors.New("the graph is busy being written by something else")

ErrBusy is a write giving up on the lock. It is not corruption and not a refusal: something else is writing the graph, and this write did not happen. A caller that can drop the write (the chat's transcript copy) drops it; a caller that cannot should say so to whoever asked.

Functions

func AgeLabel

func AgeLabel(at, now time.Time) string

FactKind classifies what a notebook entry teaches. AgeLabel renders how old a fact is, for retrieval surfaces: every reader of a memory sees when it was written, because a claim's age is part of its evidence — "the dev server has been up for days" means something different noted yesterday versus noted last quarter.

func BaseLevelActivation

func BaseLevelActivation(accesses []time.Time, now time.Time, decay float64) float64

BaseLevelActivation computes log(sum(t_i^-d)) using ages in days.

func CadenceInterval

func CadenceInterval(cadence string) time.Duration

CadenceInterval is the polling-cadence reading of the same words, used by file, graph, and poll watches whose wake-up is an interval, not a schedule.

func CharterHygieneKeepValue

func CharterHygieneKeepValue(charterID string) string

CharterHygieneKeepValue is the durable option value that marks a watch as already questioned. The stop half deliberately reuses the ordinary retire code, so the answer travels the route that already exists.

func DecodeRedirectOption

func DecodeRedirectOption(value string) (action, target, message string, ok bool)

DecodeRedirectOption reverses RedirectOptionValue. A value from any other family decodes as not-ok rather than as an error.

func DecodeTasteOption

func DecodeTasteOption(value string) (answer, scope string, ok bool)

DecodeTasteOption reverses TasteOptionValue. A value from any other family decodes as not-ok rather than as an error.

func FormatRecall

func FormatRecall(hits []RecallHit, maxBytes int) string

FormatRecall renders hits for a model-facing context. The wording states the memory contract once: the digest is enough to orient, while pointers are the route to source material when the work needs depth.

func FormatUnsettledPair

func FormatUnsettledPair(pair UnsettledPair) string

FormatUnsettledPair is the readable projection indexed by FTS and handed to models. The Unsettled field remains the authoritative representation.

func HumaneQuestionBody

func HumaneQuestionBody(prompt string, options []QuestionOption) string

HumaneQuestionBody renders an ask as prose a person can read without any machinery at all: the prompt, then one numbered line per option.

This is what replaces the fenced JSON on every ask whose whole meaning survives the trip. What does NOT survive is a preselected default and a refusal of free text, because a numbered list cannot say either — which is exactly why QuestionMessageBody is still used for those, and why this function is chosen by QuestionBodyFor rather than by a caller guessing.

func InlineProduct

func InlineProduct(files []string, limit int, seen map[string]bool) (string, bool)

InlineProduct is readProduct with its second answer kept: whether the block it returns is ALL of what those files hold.

The bool exists because the sentence rendered under the block is an instruction either way and the two instructions are opposites — "read them if you need the full detail" is an invitation to go and fetch what the consumer is already holding, and following it is what nineteen turns of filesystem archaeology looked like. Only the caller that inlined the files can answer it, and until this it was answered by proxy: the resident surface asked whether the digest had been clipped, and the headless scheduler never asked at all.

Whole means every named file is in the consumer's hands: inlined here entire, or already inlined for this same consumer by an earlier dependency that named the same file. Anything short of that — a file past the budget, a file that reads as binary, a path that is not a regular file — is false, because the consumer would have to go and open something.

func IsOrganizationalGroup

func IsOrganizationalGroup(group string) bool

IsOrganizationalGroup identifies durable spine furniture rather than work a runner may claim. New organizational node kinds join this one family.

func IsPracticeCharter

func IsPracticeCharter(charter Charter) bool

IsPracticeCharter keeps the ordinary model sentinel from handling the deterministic practice poll.

func MemoryShelfTypes

func MemoryShelfTypes(shelf MemoryShelf) []string

MemoryShelfTypes is a shelf's kinds in a settled order — the section line's own reading, so that two draws of one shelf do not name its kinds in two orders. Kinds this build knows come first in the order the store declares them; anything else follows, sorted.

func MemoryShelfWord

func MemoryShelfWord(scope string) string

MemoryShelfWord is a shelf's heading in words a person uses.

It is the SHORT form of the same three meanings internal/session's consolidateScopeWord spells out at length ("true only inside one project") — that one is prose written for a model reading a listing, this one is a column heading. Two audiences, two lengths, one meaning; a scope this build does not know reads as nothing rather than as itself.

func NewMemoryID

func NewMemoryID() string

NewMemoryID mints a memory's name: sortable by the millisecond it was made, unique by eight random bytes after it.

The time prefix is fixed width on purpose. A base-36 stamp that grows a digit would sort every id minted before the rollover after every id minted after it, and an id that is only sometimes ordered is worse than one that never claimed to be. Nine digits carry the clock past the year 3000.

func NewSessionID

func NewSessionID() string

NewSessionID mints a fresh room id. It is random rather than sequential because a room id is a name, not an order: two windows opened in the same second must not collide, and nothing downstream reads it as a number.

It lives in the store because a room is a store concept and both the surface that opens one by key press and the head that opens one by splitting a conversation need the same generator. Two spellings of "a new room's name" is how two builds come to disagree about what a room id looks like.

func NextCronDue

func NextCronDue(schedule CronSchedule, after time.Time) (time.Time, error)

NextCronDue returns the first occurrence strictly after the supplied instant. Daily schedules search real instants in the local day, so nonexistent spring times move to the first valid minute and repeated fall times fire once.

func NextWatchDue

func NextWatchDue(watch WatchSpec, due time.Time) (time.Time, error)

NextWatchDue advances one completed wake from its scheduled occurrence.

func QuestionBodyFor

func QuestionBodyFor(prompt string, options []QuestionOption, config QuestionConfig) string

QuestionBodyFor is the body one ask should be journaled with, and the rule it applies is about the READER that cannot see parts rather than about taste.

A numbered list carries a prompt and some choices completely. It cannot carry which choice stands if the person says nothing, and it cannot carry that an answer outside the list is refused. Both of those are consent semantics on the questions that have them, and 11.1 says the existing chat keeps working — so a question that depends on either keeps the payload it has always carried, and every other question stops carrying one.

func QuestionMessageBody

func QuestionMessageBody(prompt string, options []QuestionOption, configs ...QuestionConfig) string

func QuestionPrompt

func QuestionPrompt(body string) string

QuestionPrompt recovers the prose from a body this package wrote. It is a decoder, not a scanner: QuestionMessageBody, HumaneQuestionBody and the inline numbered spelling are the spellings that exist, all of them are written in this package, and this reverses exactly those and nothing else.

It exists because the durable question row stores its RENDERED body as its text, so the prompt a text part should carry has to be read back out of it — and reading it back in one owned place is the difference between a codec and the brace scanner this whole file exists to retire.

13.5 bug 6 is why the inline spelling is decoded here too. A producer that wrote its choices into the SENTENCE — "…not here? ▸ 1 yes, always · ▸ 2 only while I'm around" — put them somewhere a per-line rule could not reach, so the text part carried the options as prose and the honest question block drew them again underneath. Every producer of that shape is fixed at its own source, and the decoder covers the shape as well, because a prompt that lists its own options is a class of mistake rather than one caller's habit.

func RecognizedCadence

func RecognizedCadence(cadence string) bool

RecognizedCadence is whether these words say anything about time that this engine can act on. It is how a caller tells a cadence apart from a default: words that fall through to the two-minute fallback are not a rhythm anyone chose, and a surface that presents them as one is lying quietly.

func RecurringWatch

func RecurringWatch(watch WatchSpec) bool

RecurringWatch is true for every watch that comes back around. Only a cron at-schedule — one named instant — happens exactly once. Expiry is decided from this and never from the words: "remind me every Sunday" and "remind me tomorrow at 9" are the same sentence shape and opposite lifetimes.

func RedirectOptionValue

func RedirectOptionValue(action, target, message string) string

RedirectOptionValue encodes one answer to a redirection askback. Both ends of the option are somewhere else — the head asks which job the user meant, the reconciler asks whether a running leaf may be thrown away — so the shape belongs with the durable option rather than with either speaker.

func RoomSwitchTarget

func RoomSwitchTarget(part MessagePart) (string, bool)

RoomSwitchTarget reads the room a part points at, and reports false for every other kind. It exists so no reader has to know that this part spells its payload in Text — the one place that knowledge lives is here.

func ServiceHygieneKeepValue

func ServiceHygieneKeepValue(serviceID string) string

ServiceHygieneKeepValue is the durable option value that marks a service as already nudged. It is shared by the asker and the answer router.

func ServiceHygieneStopValue

func ServiceHygieneStopValue(serviceID string) string

ServiceHygieneStopValue is the answering half of the same nudge.

func ShrunkRate

func ShrunkRate(local, global float64, n int) float64

ShrunkRate applies n/(n+8) shrinkage toward a global empirical rate.

func SkillBodyFile

func SkillBodyFile(artifact string) (string, bool)

SkillBodyFile reports the readable body of one skill's artifact: its top-level SKILL.md, present when the skill arrived from Claude Code, Codex or any other agentskills.io harness rather than the forge. There is nothing to run in such a folder — the content is the markdown — so the doors that hand a worker a path hand out this FILE where the forge's own skills hand out the directory holding the executable.

The convention keys on the folder and never on the fact's trust tier, so it cannot drift from how the skill was recorded. ok is false for every other artifact: the forge's executable skill directories, a path that does not resolve, an artifact that is itself a plain file, an empty one. A false answer leaves the caller rendering the artifact exactly as it always has, which is the compatibility law this sits under. SKILL.md must be a REGULAR file — a directory of that name is not a body, and neither is a dangling symlink.

func SkillsBinDir

func SkillsBinDir() (string, error)

func SkillsRoot

func SkillsRoot() (string, error)

SkillsRoot is the user-owned shelf where promoted artifacts live. Keeping this path independent of any one database lets every resident thread offer the same learned commands without changing the headless no-store path.

func TasteOptionValue

func TasteOptionValue(answer, scope string) string

TasteOptionValue encodes one answer to a taste annotation. The shelf rather than the fact sequence is named, because standing a rule up records a new line and an answer must outlive that.

func TasteScope

func TasteScope(subject, body string) string

TasteScope names the shelf one rule owns: what it is about, then a slug of the rule's own words, so the same rule always lands on the same shelf. An unusable rule returns the empty string rather than a shelf nothing can find.

func TasteSubject

func TasteSubject(scope string) (string, bool)

TasteSubject reverses TasteScope's subject half. The slug carries no colon, so the last one separates a subject that may itself be scoped — repo:/p.

func TruncateTranscriptText

func TruncateTranscriptText(text string) string

TruncateTranscriptText bounds one entry's payload, keeping the head AND the tail with the gap named between them.

Head-only would be the easy bound and it is the wrong one here. A tool result says what it did at the top and whether it worked at the bottom — a build log ends in the error, a test run ends in the count, a bash tool ends in its exit footer — so a record that keeps only the first four kilobytes of a fifty kilobyte output preserves the part a reader already guessed and throws away the part they opened it for.

func WeekdayNamed

func WeekdayNamed(text string) bool

WeekdayNamed is whether these words name a day of the week. Callers deciding which watch family a sentence implies need it: a named day is a clock rule however the rest of the sentence reads.

Types

type Acceptance

type Acceptance struct {
	Points []AcceptancePoint `json:"points"`
}

Acceptance is the whole checklist for one piece of work.

type AcceptancePoint

type AcceptancePoint struct {
	Behaviour string `json:"behaviour"`
	Quote     string `json:"quote"`
	// Kind is "behaviour" or "action" — whether this point is something the
	// finished work must be, or something the RUN does on the way. It is the
	// classification the settlement acts on, and it is journaled so an autopsy
	// of a run whose coverage finding fired on nothing checkable can see which
	// way each point was read. Empty on a row written before the reading
	// existed, which every reader takes as behaviour.
	Kind string `json:"kind,omitempty"`
}

AcceptancePoint is one thing the request states, the words of the request it is a reading of, and which of the two kinds it is.

The store learns no more about a point than that, and deliberately: Quote is what the grounding rule weighs and Behaviour is what a person reads, and the rules that weigh them live where the gate lives. This is the journal's copy.

type AgentQuestion

type AgentQuestion struct {
	Seq              int64
	SessionID        string
	Text             string
	OriginNodeID     string
	OriginCharterID  string
	OriginCommandSeq int64
	Urgency          QuestionUrgency
	Class            QuestionClass
	Status           AgentQuestionStatus
	Options          []QuestionOption
	Category         QuestionCategory
	DefaultAnswer    string
	CreatedAt        time.Time
	AskedAt          time.Time
	ResolvedAt       time.Time
	ExpiresAt        time.Time
	Resolution       string
	AskedMessageSeq  int64
	AnswerMessageSeq int64
	UpdatedSeq       int64
}

AgentQuestion is one materialized agent-to-user question. Seq is the question's queue event. OriginCommandSeq is retained for compiler askbacks; ordinary resident questions should name either their node or charter.

type AgentQuestionStatus

type AgentQuestionStatus string

AgentQuestionStatus is the durable lifecycle of an agent-to-user question. Pending is quiet, Asked has entered a thread, and Answered/Expired are terminal resolutions.

const (
	QuestionPending  AgentQuestionStatus = "pending"
	QuestionAsked    AgentQuestionStatus = "asked"
	QuestionAnswered AgentQuestionStatus = "answered"
	QuestionExpired  AgentQuestionStatus = "expired"
)

type ArtifactPart

type ArtifactPart struct {
	Path string `json:"path"`
	MIME string `json:"mime,omitempty"`
	// Bytes is the length of the file at the moment it was referenced.
	Bytes int64 `json:"bytes,omitempty"`
	// NodeID is the work this artifact came out of, empty when the head made it
	// directly in conversation.
	NodeID string `json:"node_id,omitempty"`
}

ArtifactPart is the artifact law made storable: a reference to something on disk, never the thing itself. Bytes is the length as written, which is what lets a surface say "1.6 KB" without opening the file and what lets a later reader notice the file has changed underneath the message.

type AsidePart

type AsidePart struct {
	Question string `json:"question"`
	Answer   string `json:"answer"`
	// Model is what served the answer, recorded for the same reason a reply
	// records it: an aside is a real provider call that really cost money, and
	// "which model said that" is unanswerable afterwards without this.
	Model string `json:"model,omitempty"`
}

AsidePart is one side-channel exchange, kept in full under a collapsed line.

Both halves are stored because both are the record: the question is what was asked, and dropping it would leave an answer to nothing. They are stored HERE rather than as two text parts because a reader has to be able to tell which is which, and a pair of anonymous blocks cannot say.

type BindingScope

type BindingScope string

BindingScope names how far one binding reaches. The three shapes are the doc's: the machine, one task's subtree, one node.

const ScopeGlobal BindingScope = "global"

ScopeGlobal is the whole brain file — the binding a chip at home sets.

func NodeScope

func NodeScope(id string) BindingScope

NodeScope reaches exactly one node. It is the finest binding and still not the finest word about a node's model — a pin outranks it, because a pin is what the node was promised and a binding is only what it inherits.

func ParseBindingScope

func ParseBindingScope(text string) (BindingScope, error)

ParseBindingScope reads a scope word from a palette or a payload. Malformed input is ErrInvalid, including the two shapes that look almost right — "task:" and "node:" with nothing after them name no target at all.

func TaskScope

func TaskScope(root string) BindingScope

TaskScope reaches root and everything beneath it, the way a task ceiling does: the nearest governing root wins and an outer one takes over the moment the nearer one is cleared.

func (BindingScope) Kind

func (scope BindingScope) Kind() string

Kind is "global", "task", "node", or "" for a scope nobody can interpret.

func (BindingScope) Target

func (scope BindingScope) Target() string

Target is the node id a task or node scope names, and empty for global. A scope that names nothing is not a scope; Kind reports it invalid and every writer refuses it.

func (BindingScope) Valid

func (scope BindingScope) Valid() bool

Valid is Kind's closed list, said as a question.

type Brief

type Brief struct {
	SinceSeq      int64 `json:"since_seq"`
	ThroughSeq    int64 `json:"through_seq"`
	Done          int   `json:"done,omitempty"`
	Failed        int   `json:"failed,omitempty"`
	Cancelled     int   `json:"cancelled,omitempty"`
	Questions     int   `json:"questions,omitempty"`
	CharterFired  int   `json:"charter_fired,omitempty"`
	FactsLearned  int   `json:"facts_learned,omitempty"`
	SkillsLearned int   `json:"skills_learned,omitempty"`
	// Waiting counts the standing rows — what is stopped on the user now, not
	// what happened in the window. Every other total is a fact about the past.
	Waiting int         `json:"waiting,omitempty"`
	CostUSD float64     `json:"cost_usd,omitempty"`
	Items   []BriefItem `json:"items"`
}

Brief marks one agent message as an arrival fold. Counts and cost are deterministic journal facts; Items and the containing message Body are the resident's composed voice. SinceSeq and ThroughSeq make the interval auditable.

type BriefItem

type BriefItem struct {
	Kind BriefItemKind `json:"kind"`
	Body string        `json:"body"`
	Ref  string        `json:"ref,omitempty"`
}

BriefItem is one composed row in a morning-brief fold. Ref is optional durable provenance (a node id, charter id, or fact sequence).

type BriefItemKind

type BriefItemKind string

BriefItemKind says what one slim row in an arrival brief represents. The body remains resident-written prose; the kind gives every lens a stable glyph and lets it summarize the fold without parsing that prose.

const (
	BriefDone      BriefItemKind = "done"
	BriefFailure   BriefItemKind = "failure"
	BriefCancelled BriefItemKind = "cancelled"
	BriefQuestion  BriefItemKind = "question"
	BriefCharter   BriefItemKind = "charter"
	BriefFact      BriefItemKind = "fact"
	BriefSkill     BriefItemKind = "skill"
	// BriefCraft is a learned way of working — a whole workflow the resident
	// distilled and can run again — as against BriefSkill, which is one small
	// executable it forged. Crafts rode as skills until this kind existed, which
	// made the arrival brief say "learned a tool" about a four-step workflow and
	// left every lens unable to tell the two apart or send a reader to the right
	// page for either.
	BriefCraft BriefItemKind = "craft"
	BriefSpend BriefItemKind = "spend"
	// BriefWaiting is the only kind that is not an event in the window. Every
	// other row answers "what happened while you were away"; this one answers
	// "what is still true now" — work stopped on an unanswered question, work
	// that has not moved. A returning employer's first question is what is
	// waiting on them, and until this kind existed the brief structurally could
	// not say it.
	BriefWaiting BriefItemKind = "waiting"
)

type CardPart

type CardPart struct {
	NodeID string `json:"node_id"`
}

CardPart names the graph node this block is about. Only the reference is stored: a title, a status and a spend are the node's to answer, and copying them here would be a second truth that ages.

type CategoryStats

type CategoryStats struct {
	Category       QuestionCategory
	N              int
	Accepted       int
	Different      int
	AcceptanceRate float64
	MeanReworkCost float64
	ExpectedRegret float64
}

CategoryStats is the journal-derived acceptance and regret projection.

type ChangedDefinition

type ChangedDefinition struct {
	Name string `json:"name"`
	File string `json:"file,omitempty"`
	// Sites is how many usage sites were found outside the lines this run
	// changed, and Shapes is those sites grouped by what they DO with the name.
	Sites  int             `json:"sites"`
	Shapes []ConsumerShape `json:"shapes,omitempty"`
}

ChangedDefinition is one definition the run's diff overlapped, and what still uses it.

type ChannelSurvival

type ChannelSurvival struct {
	Kind        FactKind
	Channel     FactChannel
	N           int
	Survived    int
	Reversed    int
	Raw         float64
	Global      float64
	Credibility float64
}

ChannelSurvival is the rebuildable survival projection for one kind/channel sensor.

type Charter

type Charter struct {
	ID            string
	Invariant     string
	Watch         WatchSpec
	SentinelHint  string
	Action        CharterAction
	Status        CharterStatus
	Autonomy      CharterAutonomy
	GreenFirings  int
	Demotions     int
	Ratification  Ratification
	ProposalShape string

	// Spec and the adjacent fields are the head's lossless ratification card.
	// The structured engine fields above remain the executable source of truth.
	SessionID        string
	Spec             CharterSpec
	SourceCommandSeq int64
	CreatedAt        time.Time

	LastWake time.Time
	// LastChecked and LastCheckLine are the quiet half of a standing watch: the
	// moment a sentinel last looked, and the sentence it wrote when it did.
	// Both were journaled and neither was ever materialized or read, so a watch
	// that had checked faithfully for thirty mornings and correctly found
	// nothing rendered byte-identically to a watch that had never run once —
	// "last fired never · 0 today". Diligence and death are not the same state
	// and the user must be able to tell them apart without being told anything
	// on the days there is nothing to tell.
	LastChecked     time.Time
	LastCheckLine   string
	NextDue         time.Time
	WakeSeq         int64
	WakePending     bool
	SentinelYes     bool
	WakeEvidence    string
	FileFingerprint string
	GraphCursor     int64
	GraphDay        string
	GraphTriggered  bool
	CreatedSeq      int64
	UpdatedSeq      int64
	// contains filtered or unexported fields
}

Charter is one first-class standing responsibility. Rails are private so a caller cannot construct a usable charter while omitting them; NewCharter is the only admission constructor.

func NewCharter

func NewCharter(id, invariant string, watch WatchSpec, sentinelHint string,
	action CharterAction, rails CharterRails, status CharterStatus,
	ratification Ratification) (Charter, error)

NewCharter validates every field that can make standing work unbounded.

func (Charter) Rails

func (c Charter) Rails() CharterRails

Rails returns the immutable bounds carried by a charter.

func (Charter) WithProposalShape

func (c Charter) WithProposalShape(shape string) Charter

WithProposalShape attaches the deterministic recurrence key used to suppress a proposal after the user declines it.

type CharterAction

type CharterAction struct {
	Template string `json:"template"`
	SayOnly  bool   `json:"say_only,omitempty"`
}

CharterAction is re-grounded into ordinary work when a sentinel answers yes. SayOnly is the reminder path: it posts attention instead of a job.

type CharterAutonomy

type CharterAutonomy string

CharterAutonomy is the earned right to turn a checked wake into work without asking again. It is deliberately independent of CharterStatus: status says whether a charter is armed; autonomy says how it may fire.

const (
	CharterProbation CharterAutonomy = "probation"
	CharterTenured   CharterAutonomy = "tenured"
)

type CharterFiringAssessment

type CharterFiringAssessment struct {
	CharterID string
	WakeSeq   int64
	JobID     string
	Decided   bool
	Success   bool
	Reason    string
	CostUSD   float64
}

CharterFiringAssessment is the independent, mechanical verdict used by the resident after a firing's graph or usage changes.

type CharterRails

type CharterRails struct {
	PerFiringBudgetUSD float64    `json:"per_firing_budget_usd"`
	MaxFiringsPerDay   int        `json:"max_firings_per_day"`
	ExpiresAt          *time.Time `json:"expires_at,omitempty"`

	// Compiler-facing standing drafts predate the M3 execution rails. These
	// fields preserve that public contract; NewCharter uses the fields above.
	EstimatedCostUSD       float64 `json:"estimated_cost_usd,omitempty"`
	MaxPerDay              int     `json:"max_per_day,omitempty"`
	MaxPerDayJustification string  `json:"max_per_day_justification,omitempty"`
	Expiry                 string  `json:"expiry,omitempty"`
}

CharterRails bound every firing. ExpiresAt nil means never.

type CharterSpec

type CharterSpec struct {
	Invariant string           `json:"invariant"`
	Watch     CharterWatch     `json:"watch"`
	Sentinel  string           `json:"sentinel"`
	Action    string           `json:"action"`
	SayOnly   bool             `json:"say_only,omitempty"`
	Rails     CharterSpecRails `json:"rails"`
}

CharterSpec is the compiled, still-inert form of standing intent.

type CharterSpecRails

type CharterSpecRails struct {
	EstimatedCostUSD       float64 `json:"estimated_cost_usd"`
	MaxPerDay              int     `json:"max_per_day"`
	MaxPerDayJustification string  `json:"max_per_day_justification"`
	Expiry                 string  `json:"expiry"`
}

CharterSpecRails bound every firing before a charter can be ratified. Expiry is the compiler's word: "never", or "once" for reminders that must fire a single time and then retire.

type CharterStatus

type CharterStatus string

CharterStatus is the ratification lifecycle of standing intent.

const (
	// CharterDraft is the older compiler-facing inert standing draft. It shares
	// the public lifecycle type with the M3 engine while remaining in its own
	// materialized view.
	CharterDraft    CharterStatus = "draft"
	CharterProposed CharterStatus = "proposed"
	CharterActive   CharterStatus = "active"
	CharterPaused   CharterStatus = "paused"
	CharterRetired  CharterStatus = "retired"
)

type CharterWatch

type CharterWatch struct {
	Kind     WatchKind `json:"kind"`
	Cadence  string    `json:"cadence"`
	Schedule string    `json:"schedule,omitempty"`
	Spec     WatchSpec `json:"spec,omitempty"`
}

CharterWatch preserves the user's cadence words beside their executable schedule. Surfaces speak Cadence; the standing engine consumes Spec. Schedule is the compiler's optional structured hint (a glob, predicate, or schedule sketch) and is never executed directly.

type CharterWatchState

type CharterWatchState struct {
	NextDue         time.Time `json:"next_due"`
	FileFingerprint string    `json:"file_fingerprint,omitempty"`
	GraphCursor     int64     `json:"graph_cursor,omitempty"`
	GraphDay        string    `json:"graph_day,omitempty"`
	GraphTriggered  bool      `json:"graph_triggered,omitempty"`
}

CharterWatchState is the restart-safe observation cursor carried by both a quiet watch advance and a wake reservation.

type Claim

type Claim struct {
	ID    string
	Owner string
	Token uint64
}

Claim is the complete authority a worker needs to mutate one claimed node. Both owner and token must continue to match; release and reassignment make an older Claim permanently unusable.

type Command

type Command struct {
	Seq       int64
	Time      time.Time
	SessionID string
	Kind      CommandKind
	// Issuer names who asked — see issuer.go. Empty is the legacy value and
	// reads as IssuerUser, which is what every command written before the axis
	// existed actually was.
	Issuer CommandIssuer
	// Reflex asks the reconciler to admit exactly one verbatim micro-leaf
	// without compiling or planning it. It remains a splice command so a
	// promotion can enqueue the ordinary path with the same instruction.
	Reflex bool
	// Fresh is the person asking for this one to be worked out from scratch
	// rather than the way it has been done before. It is a reading of what they
	// meant — "don't use the template this time", "plan this one properly" —
	// made where every other reading of a message is made, and carried here
	// because the engine that would reach for learned know-how runs long after
	// the sentence is gone.
	Fresh bool
	// Deliberate is the person saying, in so many words, that this ask runs
	// BESIDE work already under way — the one override on the duplicate guard
	// in admission.go. It is transient: no column, no replay, no meaning past
	// the moment of admission, because what it records is a fact about the
	// sentence rather than a property of the work.
	Deliberate bool
	Target     string
	// Instruction is the ASK: the person's words for this piece of work and
	// nothing else. Everything that treats a command as "what they said" reads
	// this field, which is why the conversation a fork inherits is no longer
	// allowed anywhere near it (ask.go).
	Instruction string
	// Context is the conversation this ask came out of, carried so PLANNING is
	// well-informed. It is evidence about what the ask meant, never more ask:
	// see [Command.Brief], which is the only composition of the two, and the
	// only reader of it is the compiler.
	Context     string
	Attachments []string
	Status      CommandStatus
	Result      string
	UpdatedSeq  int64
}

Command is one materialized mutation request.

func (Command) Authority

func (command Command) Authority() CommandIssuer

Authority resolves what the journal holds into who is actually being trusted, which is the only form any check should ever read.

func (Command) Brief

func (c Command) Brief() string

Brief is the ask with its context underneath, fenced — what the compiler and the planner read, and the one place the two halves are legitimately one string. The fence is still written here because a model reading a brief needs to be told which half is the order and which half is only evidence about what the order meant.

A command with no context comes back as its ask, byte for byte, so the overwhelming majority of work is briefed with exactly the string it always was.

type CommandIssuer

type CommandIssuer string

CommandIssuer names the authority behind one command.

The empty string is the legacy value and reads as IssuerUser: every command ever written before this axis existed came from a person, through a path nothing checked, and the whole point of a default is that it must describe what was actually true. Storing "" rather than rewriting it to "user" keeps old events replaying byte-identical — the resolution happens in Authority, once, where it can be read.

const (
	// IssuerUser is the person themselves, and the top of the ladder. It is
	// what the head writes when it is carrying a sentence somebody typed.
	IssuerUser CommandIssuer = "user"
	// IssuerMain is the main head acting on its own initiative rather than
	// relaying a sentence. Nothing distinguishes it from user today; it exists
	// so that the day the two are told apart, the journal already knows which
	// commands were which.
	IssuerMain CommandIssuer = "main"
	// IssuerReconciler is the resident writing a command to itself — a repair,
	// a continuation, a follow-up it decided on while settling something else.
	IssuerReconciler CommandIssuer = "reconciler"
	// IssuerTaskPrefix builds the one bounded issuer: a task orchestrator
	// speaks as task:<root> and may only reach what hangs beneath that root.
	IssuerTaskPrefix = "task:"
)

func TaskIssuer

func TaskIssuer(root string) CommandIssuer

TaskIssuer is the issuer a task orchestrator rooted at root writes. It is a constructor rather than a formatting convention at the call sites, because the parsing half below has to agree with it exactly.

func (CommandIssuer) TaskRoot

func (issuer CommandIssuer) TaskRoot() (string, bool)

TaskRoot reports the root a task issuer speaks for. The second return is false for every other issuer and for a malformed one — "task:" with nothing after it names no root, and a caller that cannot say what it governs is refused rather than trusted.

type CommandKind

type CommandKind string

CommandKind names an asynchronous graph mutation requested from the thread.

const (
	// CommandSplice asks for new work: Instruction carries the verbatim user
	// intent; the reconciler compiles and splices it.
	CommandSplice CommandKind = "splice"
	// CommandAmend redirects existing work: Target names the node whose
	// subtree the instruction amends.
	CommandAmend CommandKind = "amend"
	// CommandCancel withdraws work: Target names the subtree root to cancel.
	CommandCancel CommandKind = "cancel"
	// CommandRedirect carries the user's own words into a job already in
	// flight: Target names its root, Instruction is what they said, verbatim.
	// The remaining plan is revised against it and the running leaves are told.
	CommandRedirect CommandKind = "redirect"
	// CommandExpedite is redirection's impatient sibling: Target names a live
	// job's root and the user wants it sooner, not different. It is a separate
	// kind rather than a flag on redirect so replay stays a switch on the verb
	// and no command row grows a column.
	CommandExpedite CommandKind = "expedite"
	// CommandPause/Resume operate on a journal-derived scheduler hold rather
	// than inventing a presentation-only node status.
	CommandPause        CommandKind = "pause"
	CommandResume       CommandKind = "resume"
	CommandReprioritize CommandKind = "reprioritize"
	CommandRestart      CommandKind = "restart"
	// CommandSetModel re-points what a job's remaining work runs on without
	// touching the work itself: Target names the subtree, Instruction names the
	// model. It is a surgery verb rather than a setting because the pin is
	// provenance — it lives on the nodes, it is journaled, and it survives a
	// restart — and because the change has to be as revisable and as visible as
	// every other mid-run correction. It never interrupts anything: a leaf
	// already handed to a model finishes there, and the new pin is read by the
	// next one to be claimed.
	CommandSetModel CommandKind = "set_model"

	// Charter commands are requested through the same durable reconciler queue
	// as graph mutations. Their target names a charter rather than a node.
	CommandCharterRatify  CommandKind = "charter_ratify"
	CommandCharterPause   CommandKind = "charter_pause"
	CommandCharterRetire  CommandKind = "charter_retire"
	CommandCharterCadence CommandKind = "charter_cadence"
	// CommandCharterWording changes what a standing rule says or does without
	// touching when it runs. It is the other half of editing a rule by talking
	// about it: "change it to Tuesday" retimes, "make it say take the bins out
	// too" rewords, and before this the second sentence had nowhere to land.
	CommandCharterWording   CommandKind = "charter_wording"
	CommandCharterOnce      CommandKind = "charter_once"
	CommandCharterFire      CommandKind = "charter_fire"
	CommandCharterDecline   CommandKind = "charter_decline"
	CommandCharterAlways    CommandKind = "charter_always"
	CommandCharterNever     CommandKind = "charter_never"
	CommandCharterProbation CommandKind = "charter_probation"

	CommandServiceStop        CommandKind = "service_stop"
	CommandServiceRestart     CommandKind = "service_restart"
	CommandServiceAutoRestart CommandKind = "service_auto_restart"

	// Craft commands act on a learned way of working. Their target is the
	// workflow's NAME rather than a row in this database, because a craft is a
	// file in a git repository and that repository — not the store — is the
	// authority on which names exist. The store therefore checks only that a
	// name was given; a name nobody has forged is refused in words by whoever
	// applies the command, which is the same shape a missing service gets.
	//
	// CommandCraftRun asks for the named workflow to be compiled and run.
	// Instruction carries the user's own words, because that is where the
	// workflow's parameters are read from — the same seam recognition already
	// fills them through.
	CommandCraftRun CommandKind = "craft_run"
	// CommandCraftRevert puts a workflow back to its previous version.
	// Instruction is the reason, in the user's own words, and the repository
	// refuses a revert that does not carry one: a version that failed is
	// evidence, and history that cannot say why it moved cannot be read.
	CommandCraftRevert CommandKind = "craft_revert"
	// CommandCraftRetire stops a workflow being reached for. Nothing is
	// deleted: the file and its history stay exactly where they are, and the
	// recognizer simply stops offering it. Instruction is why.
	CommandCraftRetire CommandKind = "craft_retire"

	// CommandSkillRetire takes one forged tool off the shelf. Target is the
	// skill belief's own number — the number the notebook shows beside it —
	// because a skill IS a belief with an artifact hanging off it, and that
	// number is the one handle every surface already has for it.
	CommandSkillRetire CommandKind = "skill_retire"

	// Standing-watch commands carry the one global unattended-presence
	// decision. They deliberately have no graph-node or charter target.
	CommandStandingWatchEnable  CommandKind = "standing_watch_enable"
	CommandStandingWatchDecline CommandKind = "standing_watch_decline"

	// CommandHandover asks whoever currently holds the resident role to give it
	// up; Instruction says who is asking and why, in plain words. It is a
	// command rather than a new event because the journal already has exactly
	// the shape this needs: a durable request only the resident drains,
	// resolved exactly once, replayed like everything else — and because a
	// resident too old to know the verb rejects it in words instead of
	// ignoring it, which is how a requester learns it must wait for the
	// heartbeat to go stale instead.
	CommandHandover CommandKind = "handover"

	// CommandHeadInterrupt is a turn-cancel promoted from a keypress to a
	// journaled command (12.3.3, 12.8.10): a stop rides the same funnel as
	// every other authority in the product instead of a narrower in-process
	// road. It targets no node — the turn in flight belongs to the head
	// serving the session, not to a subtree — so it joins isGlobalCommand and
	// deliberately does NOT enter validateNodeCommand's status table. Its
	// value must stay byte-identical to internal/head's HeadInterruptKind,
	// which duplicates this constant because the store's kind list was closed
	// to that lane; TestHeadInterruptKindMatchesHeadPackage pins the two
	// together.
	CommandHeadInterrupt CommandKind = "head_interrupt"
)

type CommandStatus

type CommandStatus string

CommandStatus is the lifecycle of a requested command. Commands are durable the moment they are requested and are resolved exactly once.

const (
	CommandPending  CommandStatus = "pending"
	CommandApplied  CommandStatus = "applied"
	CommandRejected CommandStatus = "rejected"
)

type CompetenceClass

type CompetenceClass string

CompetenceClass is the current evidence-backed posture of one scope.

const (
	CompetenceStrong   CompetenceClass = "strong"
	CompetenceFrontier CompetenceClass = "frontier"
	CompetenceWeak     CompetenceClass = "weak"
	CompetenceStale    CompetenceClass = "stale"
)

type CompetenceMap

type CompetenceMap struct {
	Scopes []ScopeCompetence `json:"scopes"`
}

CompetenceMap is a pure derived view. It owns no cache and writes nothing.

func (CompetenceMap) Frontier

func (m CompetenceMap) Frontier() []ScopeCompetence

Frontier returns an independent, stable list of scopes in the learnable band. A future practice loop can consume it without depending on SQL, territory layout, profile files, or classification logic.

type CompetenceOptions

type CompetenceOptions struct {
	Profile    *profile.Profile
	Thresholds *CompetenceThresholds
	Now        time.Time
}

CompetenceOptions supplies the model profile that owns the generic execution buckets, an optional policy override, and a clock for deterministic callers. With no options, CompetenceMap still returns the journal-derived territory view.

type CompetenceThresholds

type CompetenceThresholds struct {
	EstablishedSamples int
	StrongFailureBelow float64
	FrontierFailureMin float64
	FrontierFailureMax float64
	WeakFailureAbove   float64
	LowSurpriseMax     float64
	TrendWindow        int
	TrendMinSamples    int
	TrendDelta         float64
	StaleAfter         time.Duration
}

CompetenceThresholds keeps every policy boundary out of the arithmetic. Copy DefaultCompetenceThresholds(), adjust the fields a consumer owns, and pass it through CompetenceOptions.

func DefaultCompetenceThresholds

func DefaultCompetenceThresholds() CompetenceThresholds

DefaultCompetenceThresholds returns the resident's current classification policy. The eight-sample evidence floor matches profile.MinSamples.

type ConsumerShape

type ConsumerShape struct {
	Shape  string   `json:"shape"`
	Count  int      `json:"count"`
	Sample []string `json:"sample,omitempty"`
}

ConsumerShape is one syntactic shape of use, how many sites have it, and a bounded sample of where they are.

type ConsumersReading

type ConsumersReading struct {
	// Weighed is how many changed definitions were read. Zero with no rows is a
	// real answer — the run touched no declaration this program can read — and
	// it is not the same answer as no row at all.
	Weighed int                 `json:"weighed"`
	Changed []ChangedDefinition `json:"changed,omitempty"`
}

ConsumersReading is that reading as the journal keeps it: one row per changed definition, with its consumers counted by shape.

COUNTS PLUS A BOUNDED SAMPLE, the same shape SurfaceReading keeps and for the same reason: what a reader wants from a hundred usage sites is how many there are and what kind they are.

type ConversationHit

type ConversationHit struct {
	MessageHit
	// Title is the conversation's name (internal/session's title.go, kept in the
	// sessions table). Empty for a thread nobody has named yet, or one that
	// posted messages without ever opening a session row — which is unknown and
	// not "untitled": a page draws the project or the first line instead, and
	// never a word this store made up.
	Title string
}

ConversationHit is one remembered line with the NAME of the thread it was said in — the one fact MessageHit does not carry and the one a result on a search page cannot be drawn without.

Everything else a row needs is already on the hit underneath: the session id to open, the bounded body to quote, the instant to sort on and the age to print.

type CorrectionStyleValue

type CorrectionStyleValue struct {
	Style              string  `json:"style"`
	MeanLatencySeconds float64 `json:"mean_latency_seconds"`
}

CorrectionStyleValue is measured only from non-default question resolutions.

type CostCardT

type CostCardT struct {
	RunTokens      int64 `json:"run,omitempty"`
	ReadTokens     int64 `json:"read,omitempty"`
	DelegateTokens int64 `json:"delegate,omitempty"`
}

CostCardT is the token budget a skill carries: zero until measured. ReadTokens cover reading the skill's body; RunTokens cover executing the check and run; DelegateTokens cover handing a sub-task to the skill.

type CraftForged

type CraftForged struct {
	Name    string `json:"name"`
	Commit  string `json:"commit,omitempty"`
	Refined bool   `json:"refined,omitempty"`
	// Because is the evidence line the commit carries, kept short. It is what
	// lets a digest say what the new version answers without a git call.
	Because string `json:"because,omitempty"`
}

CraftForged is one forging on the wire. Commit is the version it landed as, so a reader can line the announcement up against the repository's own history; Refined says whether this replaced a way of working that already existed, which is the difference between "learned how to" and "got better at" in every sentence written about it.

type CronKind

type CronKind string

CronKind is one supported structured schedule. Raw cron expressions are deliberately not represented by this type.

Every wall-clock kind here is read in the PROCESS'S LOCAL ZONE — the zone the machine running codeaf is set to. "Sunday at 9" means nine in the morning where the user is sitting, and a schedule that survives a restart is recomputed in that same zone (NextWatchDue restores time.Local before doing wall-clock math, because SQLite hands timestamps back in UTC).

const (
	CronEveryMinutes CronKind = "every_minutes"
	CronEveryHours   CronKind = "every_hours"
	CronDaily        CronKind = "daily"
	CronWeekdays     CronKind = "weekdays"
	// CronWeekly is one named weekday at one wall time — "every Sunday",
	// "Tuesdays at 8pm". It exists because it is the commonest standing rule a
	// person states and the only one the engine could not hold: before it,
	// "every Sunday" degraded to an interval measured from the ratification
	// instant, which drifts off the named day immediately.
	CronWeekly CronKind = "weekly"
	// CronAt is a single wall-clock instant: the reminder schedule. After it
	// fires once, its expiry rail retires the charter.
	CronAt CronKind = "at"
)

type CronSchedule

type CronSchedule struct {
	Kind     CronKind `json:"kind"`
	Interval int      `json:"interval,omitempty"`
	Hour     int      `json:"hour,omitempty"`
	Minute   int      `json:"minute,omitempty"`
	// Weekday is read only by CronWeekly. Sunday is the zero value, so a
	// weekly schedule on a Sunday round-trips through JSON without the field.
	Weekday time.Weekday `json:"weekday,omitempty"`
	At      time.Time    `json:"at,omitempty"`
}

CronSchedule is a local-time schedule with no raw-cron escape hatch.

func CadenceSchedule

func CadenceSchedule(cadence string, now time.Time) CronSchedule

CadenceSchedule maps cadence words onto one structured CronSchedule. Unknown words remain a short every-minutes interval instead of being treated as cron syntax.

Every wall time it produces is local: "Sundays at 9" is nine in the morning in the zone this process runs in, and NextCronDue searches real instants in that zone. A named weekday wins over every other reading, because a person who said a day meant the day — "every sunday morning" is a weekly rule at nine, not a daily one.

type DailyRail

type DailyRail struct {
	Base      float64
	Raised    float64
	Spend     float64
	Pending   float64
	Ceiling   float64
	Unlimited bool
	Reached   bool
}

DailyRail is today's policy state. Base zero is unlimited; Raised remains visible as journal history but cannot make an unlimited rail more unlimited.

Spend is everything the rail is deciding against, which is not always what the journal has seen: Pending is the part of it that has not been recorded — in-process cost a headless run will journal at exit, or the catalog price of a generation that has not happened yet. The split exists so a question can say which is which, because the two are consented to by different arithmetic.

func (DailyRail) Question

func (rail DailyRail) Question() string

Question renders the one user-visible policy stop. Resource units stay backstage; only today's spend, ceiling, and exact effect of consent appear.

This is the wording for a caller that consents on the very rail it was shown — the headless prompt, which raises RaiseAmount() of this same figure the moment the operator says yes. There the pending part is money already spent in this process and merely not yet journaled, so folding it into the total is the honest thing to say.

func (DailyRail) RaiseAmount

func (rail DailyRail) RaiseAmount() float64

RaiseAmount restores one configured budget unit of headroom. Concurrent leaves may overshoot the old rail while landing, so the raise also covers that overshoot instead of immediately asking the same question again.

func (DailyRail) WithAdditionalSpend

func (rail DailyRail) WithAdditionalSpend(amount float64) DailyRail

WithAdditionalSpend includes not-yet-journaled in-process cost in a rail check. Headless scheduling uses it between landed leaves, then journals the aggregate before exit.

type DefaultAcceptanceValue

type DefaultAcceptanceValue map[QuestionCategory]struct {
	Rate float64 `json:"rate"`
	N    int     `json:"n"`
}

DefaultAcceptanceValue keeps a rate and sample count per durable question category.

type DeferredOverrun

type DeferredOverrun struct {
	Seq       int64    `json:"-"`
	NodeID    string   `json:"-"`
	Partial   string   `json:"partial,omitempty"`
	Gap       string   `json:"gap,omitempty"`
	Artifacts []string `json:"artifacts,omitempty"`
	Prefix    string   `json:"prefix"`
	// State is the dead leaf's structured findings, carried across the rail
	// for the same reason everything else here is: the continuation needs it
	// to resume rather than restart, and a repair that resumed without it
	// would re-read everything the dead leaf already diagnosed.
	State string `json:"state,omitempty"`
}

DeferredOverrun is a repair plan held at the dollar rail. Seq and NodeID identify its journal record; the remaining fields are the durable planner input needed to resume without rerunning or discarding the landed partial.

type DeliveryGate

type DeliveryGate struct {
	Pass         bool     `json:"pass"`
	Gap          string   `json:"gap,omitempty"`
	PolishClosed bool     `json:"polish_closed"`
	Quote        string   `json:"quote,omitempty"`
	Quotes       []string `json:"quotes,omitempty"`
	Round        int      `json:"round,omitempty"`
	Extended     bool     `json:"extended,omitempty"`
	Refused      string   `json:"refused,omitempty"`
	Mechanical   bool     `json:"mechanical,omitempty"`

	// Finding names WHICH MEASUREMENT raised this gap — `regression`,
	// `own-checks-failing`, `removed-public-name`, `removed-checks` — and
	// Quotes above holds the names it cited. Empty where a model judge read the
	// request rather than the world.
	//
	// The pair is what makes a finding comparable ACROSS ROUNDS, and until it
	// existed the only identity a finding had was its sentence — with a bounded
	// list of names glued into the middle, so one finding raised over two
	// different tails read as two. happy-dom's v4-flash s13 raised the identical
	// removed-checks finding on four consecutive rounds, each round bought a
	// repair, no repair could close it, and no reader of this event could say
	// the four were one thing (2026-08-29, bench/deepswe).
	Finding string `json:"finding,omitempty"`

	// Unclosed says the gap STANDS: the repair that would have closed it was
	// never bought, so nothing ran and nothing about the shortfall changed.
	//
	// It is the distinction the exit code turns on, and it is recorded rather
	// than read out of the refusal sentence because those are two categorically
	// different refusals wearing the same field. A gap refused as ungrounded, or
	// as one somebody already paid to close, is the GATE being wrong and caught
	// at it — the deliverable stands whole. A gap whose repair a governor would
	// not fund, or that nothing could plan, is the gate being RIGHT and
	// unaffordable: the thing it named is still missing, and a run that hands
	// that over is handing over less than it promised. One measured run shipped
	// "Deliverable is empty - contains no implementation" over exit 0 because
	// the two were one field (2026-08-28, meta/muse-spark-1.1).
	Unclosed bool `json:"unclosed,omitempty"`

	// Unjudged says NOBODY EVER READ THIS DELIVERY. The gate was asked and could
	// not be reached — a dead route, a refused account, a service that was down —
	// so the work shipped with no verdict behind it at all.
	//
	// It is a field of its own beside Refused because the two refusals it
	// separates are what a battery comparing runs has to tell apart. `{Refused,
	// Unclosed}` on its own is the gate that was NEVER ASKED: the harness stopped
	// spending once nothing was changing, and declined to buy a judgement. This
	// one was asked, twice where the wall allowed it, and the answer never came
	// back. A run that declined to check and a run whose checker was unreachable
	// are different facts about the same missing verdict, and a rig that reads
	// one row for both learns nothing from either.
	//
	// It was measured costing two graded runs their whole meaning. reef-145's
	// repair leaf finished its work, both of the gate's calls were refused 404,
	// the door ended `ok` at exit 0, and the store held no gate row for the
	// delivered leaf at all — so the rig compared an unchecked delivery against
	// runs that had been judged and read it as a clean pass (2026-09-02,
	// codeaf-14 anchor 1; #514). Whole below spends it, so the exit code
	// cannot report a delivery nobody read as one that stands.
	Unjudged bool `json:"unjudged,omitempty"`

	// Overturned says the refusal was CHECKED AGAINST THE WORLD and the finding
	// lost: the file the review says is missing is on disk under the name the
	// request used, or the things it says are absent are in the delivered text.
	//
	// It is the other half of the distinction Unclosed opened, and it is the one
	// the exit code should have been reading all along. Refused holds refusals
	// of two categorically different kinds. One looks at the filesystem or at
	// the deliverable and finds the review wrong — that acquits, and charging it
	// a non-zero code would teach a harness to distrust the gate's own
	// corrections. The other looks only at where the review's words came from
	// and declines to BUY a round; it settles nothing about whether the work
	// landed, because no ruling on a citation makes missing work appear.
	//
	// Recorded rather than inferred from the sentence, for the reason every
	// other field here is: the exit code turns on it, and a sentence is not a
	// field. Seven of eight measured runs exited 0 over a provenance refusal
	// while the review that named the missing work was right every time
	// (2026-08-28, bench/deepswe; see docs/design/gate/SETTLEMENT.md §2).
	//
	// THE WORLD IS THE DISK, A READING, OR THE RECORD — NEVER THE DELIVERABLE'S
	// OWN PROSE. The deliverable is the component the gate is checking, and a
	// refusal that reads it is FAILSAFE clause 2 broken in the strict sense the
	// clause states it. One measured run set this field because the words of the
	// request appeared in a summary the worker had written about work it had not
	// done, and shipped 1 of 20 hidden checks over exit 0 (2026-08-29,
	// bench/deepswe textual s5; SETTLEMENT.md §6). The delivered text may settle
	// a finding only where it IS the whole of what the run left behind — a
	// question answered in prose, whose message is its own artifact.
	Overturned bool `json:"overturned,omitempty"`

	// Unmoved says the repair round that was judged here LEFT THE TREE EXACTLY AS
	// THE FINDING FOUND IT: same files, same sizes, same modification times, stamped
	// on either side of the round.
	//
	// It is recorded because it is the fact that explains a PolishClosed which is
	// absent — and, on the runs that made this necessary, one which is present and
	// should not have been. A composed repair (revision.Compose) rewrites the
	// account of work that already landed and runs nothing, so it cannot change what
	// the world says; ink s5 and ofetch s5 both composed a better summary over a
	// finding about the substance of the work, were re-judged on the summary, and
	// settled whole at 7 of 25 and 44 of 47 hidden checks (2026-08-29,
	// bench/deepswe; docs/design/gate/SETTLEMENT.md §8).
	//
	// A round that moved nothing may still close a finding whose only ground was the
	// delivered text — that is what writing can honestly fix — so this is a fact
	// about the round and never a verdict on its own. The verdict is PolishClosed,
	// which the wiring sets only where the two agree.
	Unmoved bool `json:"unmoved,omitempty"`

	// Exercised is the acceptance mapping as the gate settled it: one row per
	// behaviour the request stated, naming the check that exercises it, or
	// naming nothing when no check does.
	//
	// It is recorded rather than reduced to the finding it produced, because the
	// mapping is the evidence and the finding is only its conclusion. A run that
	// passed with every point exercised and a run that passed because the
	// checklist was empty are the same event without it, and telling those two
	// apart is the whole of what an autopsy of this mechanism has to do.
	Exercises []ExercisedPoint `json:"exercises,omitempty"`

	// Unexercised is the behaviours the request stated that no check exercises,
	// one entry per line of the request they were read from.
	//
	// It is the FINDING; Exercised above is the evidence it is a conclusion of.
	// They are two fields because a mapping with three empty rows and a finding
	// naming three behaviours are the same fact only to a reader who already
	// knows this mechanism exists, and the person watching the run is not that
	// reader. igel s6 journaled the mapping and never the finding: the gate event
	// carried "exercises: 17 rows, 3 unmapped" and the coverage gap survived only
	// as a paragraph inside `gap`, where the stream's own line — firstLine(gap) —
	// could not reach it and no repair round was ever aimed at it.
	Unexercised []string `json:"unexercised,omitempty"`

	// Unasserted is the behaviours the request stated that a check NAMES and no
	// assertion WEIGHS, one entry per line of the request they were read from,
	// each naming the observables nothing asserted.
	//
	// It is a finding of its own beside Unexercised because the two are answered
	// by different evidence and a repair round is aimed at them differently.
	// Unexercised says write a check; this says the check you wrote runs the
	// behaviour and asserts nothing about it, and names which identifier to
	// assert on. textual s13's gate had said `no check exercises:
	// RichLog.write(expand=True) …` in round one; round two wrote a check that
	// called `write("short", expand=True)` and asserted `len(lines) > 0`, the
	// mapping paired the two, and the run passed at exit 0 with the hidden check
	// for that behaviour red.
	//
	// It stands exactly as Unexercised does — it leaves the delivery short in
	// Whole below, and it empties the one way a measurement empties: a later
	// reading finds an assertion that names the observable.
	Unasserted []string `json:"unasserted,omitempty"`

	// OwnFailing is the checks THIS WORK WROTE that are red: names the baseline
	// roster never held, so nothing that was working stopped.
	//
	// It is a field beside Unexercised rather than prose inside Gap because the
	// distinction it carries is the one happy-dom's nemotron n1 run lost. That
	// gate read `This work broke checks that were passing before it:
	// IntersectionObserver initial observation queuing …` over eighteen checks
	// the run had written that hour, on a tree the grader scored 9 of 9. A run
	// that broke the repository and a run that has not finished its own tests
	// are two different states, and an autopsy with one list could not tell them
	// apart.
	OwnFailing []string `json:"own_failing,omitempty"`

	// Unmeasured says the gate held a checklist and could settle none of it:
	// the project declares no verification this run could read and the change
	// produced no readable diff, so nothing could be matched to what the
	// request asked for.
	//
	// It is a field rather than a silence because NOBODY LOOKED IS NOT NOTHING
	// WRONG, and the two are the same event without it. A delivery that
	// satisfied every point and one that was measured against nothing both
	// journal a passing gate; only this tells them apart, and an autopsy of
	// this mechanism has nothing else to read.
	Unmeasured string `json:"unmeasured,omitempty"`

	// Unreadable says the project DECLARED a way of checking itself and this run
	// could not read it. It is the half of Unmeasured that leaves the delivery
	// short, and it is what Whole below spends.
	Unreadable bool `json:"unreadable,omitempty"`

	// Consumers is the finding the changed-definition reading produced: one line
	// per definition this run reshaped that the rest of the project still uses,
	// naming the shape its callers expect and how many of them there are.
	//
	// It is the FINDING; EventConsumers is the evidence it is a conclusion of,
	// and they are two records for the reason Unexercised and Exercises are two:
	// a finding that lives only as a paragraph inside `gap` is journaled by
	// nothing and reachable by nothing. igel s12 changed `configs` from a dict
	// to an instance of a class it wrote and the whole store held not one word
	// about it (2026-08-29, bench/deepswe).
	Consumers []string `json:"consumers,omitempty"`

	// Unbound is the finding the unbound-reference reading produced: one line
	// per name the run's own sources READ that nothing in the tree binds, each
	// naming the file and line it is read at.
	//
	// It is a field beside Consumers because it is the same kind of fact one
	// question further back. Consumers is a name that exists and no longer
	// answers to how it is used; this is a name that does not exist at all —
	// igel s14 imported `temp_post_req_data_path` from a module that had stopped
	// binding it, and the run's whole record of that was that its own checks
	// were red, never WHICH name was missing (2026-08-29, bench/deepswe).
	Unbound []string `json:"unbound,omitempty"`

	// Subject is WHAT THIS GATE JUDGED, in the words the gate keeps them:
	// "tree (6 files)" where the run changed the repository and the change was
	// the deliverable, "claim" where the run left nothing behind and the
	// worker's message was the whole of what it produced.
	//
	// It is a field because an autopsy has nothing else to read. Three gates on
	// one run refused a delivery for what the worker's final MESSAGE was — "the
	// fenced text contains only {"contract": …}" — while forty-two kilobytes of
	// changed Python sat in the worktree and the artifact record named every
	// file of it (2026-08-29, bench/deepswe textual-richlog-follow-state
	// nemotron n1). Afterwards those three events were indistinguishable from
	// three refusals over a real reading of the world, and the only way to tell
	// was to reconstruct the prompt from the transcript.
	//
	// Empty on every gate journaled before this existed, which reads as
	// unrecorded rather than as either answer.
	Subject string `json:"subject,omitempty"`

	// HeldPoint is WHICH BEHAVIOUR OF THE REQUEST this gate was held to: the
	// span a refusal was built on, the size of the list a pass was weighed
	// against, or "checklist: empty" where the request states none and the
	// requirement was off.
	//
	// Subject says what the gate read; this says what it was allowed to
	// convict on. textual v4-flash s13 journaled two gates with the subject
	// right and the quote a verbatim behaviour of the request, and nothing in
	// the event could tell whether the quote had passed the checklist or there
	// had been no checklist to pass — the mechanism working and the mechanism
	// switched off, wearing one event.
	//
	// Empty on a claim-subject gate, where there is no such list, and on every
	// gate journaled before this existed.
	HeldPoint string `json:"held_point,omitempty"`

	// Constraint is the rules the person SET that this work broke, one entry
	// per rule: their own words, then the files the run changed in spite of
	// them. It is the finding of a gate law rather than of a review — the words
	// are the person's by construction, so there is no citation to weigh — and
	// it is a list of its own for the reason Unexercised is one: a finding that
	// travels as prose inside somebody else's gap is journaled by nothing and
	// reachable by nothing.
	//
	// A delivery carrying one is not whole, and no round is bought to close it:
	// the work did the thing it was told not to do, and more work is not the
	// answer to that. See revision.HoldConstraints and revision.ExtendForGap.
	Constraint []string `json:"constraint,omitempty"`

	// Receipt is the positive sentence this delivery earned, in the words the
	// person reads: that the request was met as stated, or that the work's own
	// checks were green and coverage could not be measured.
	//
	// IT IS THE OPPOSITE OF EVERY OTHER FIELD ON THIS ROW, which is why it is
	// one. Everything else here says what a gate found wanting; a run that ends
	// because the thing that was asked for is in hand has a fact of its own to
	// record, and without it a delivery that stopped for the right reason and
	// one that stopped because the rounds ran out are the same event. It is
	// deliberately NOT read by Whole below: a receipt is a statement about why
	// the run ended, and whether the delivery is whole is still settled by the
	// pass, the repair and the world-doors exactly as it was.
	Receipt string `json:"receipt,omitempty"`

	// Missing is what the request asked for that the request-met question found
	// absent, in the request's own words, on a run where that question was put
	// and answered no.
	//
	// It rides beside the gap rather than inside it. The gap is the judge's
	// finding and a repair round is briefed with it verbatim; folding a second
	// reader's sentence into that string would hand the round a requirement
	// nobody weighed against the person's words, which is the laundering the
	// admission rules exist to prevent.
	Missing string `json:"missing,omitempty"`
}

DeliveryGate is the final judge's evidence about one job. Pass is the first delivery's result; Gap names what it missed; PolishClosed says whether the single permitted repair was subsequently judged complete.

The last fields are the gap ledger, and they are fields on this event rather than a second event kind because every reader of a job's judgement already reads this one. Quotes are the spans of the user's verbatim request the gap was said to be a failure of, and Quote is those spans as the one line a person reads; Round is which round of repair it was weighed for; Extended says the job actually grew work to close it; Refused names, in the words the user would be told, why it did not. A citation that was extended on is spent — the same words may not buy a second round — so the ledger that bounds the loop is exactly what replays out of the journal.

Quotes is a list because a gap may be a failure of several things at once: the mechanical half of the gate names one citation per file the plan promised and the disk does not hold. Quote stays, holding the same citations joined, because it is what every existing reader and every already-written journal row has — see Cited, which is how the ledger reads either.

Mechanical distinguishes those two halves, and it is recorded rather than inferred because the exit code depends on it. A refused gap from a model judge is the gate being wrong; a refused gap from the mechanical half is a file that is still not on disk, and no refusal of a citation makes it appear.

func (DeliveryGate) Cited

func (g DeliveryGate) Cited() []string

Cited is the gate's citations however they were written down. A row recorded before the list existed carries only the joined line, and reading it as one citation is the honest reading of it: that is exactly what it was when it was written, and a ledger that treated it as nothing would hand an old job a fresh allowance on replay.

func (DeliveryGate) Done added in v0.3.0

func (g DeliveryGate) Done() bool

Done is whether this gate's own row reports the requested work as done: the judgement passed, or its only shortfall was behaviours the request states that no check exercises or asserts — the work is there, the checks for it are not.

It is the positive fact a delivery gate had no way to state before, and two readers turn on it rather than on their own reading of the fields. The envelope's `core_done_seconds` is the moment it first became true for a run, and the share-of-spend rail measures growth from the same moment — one definition, because a rail and a receipt that disagreed about when the work was done would be two answers to one question.

func (DeliveryGate) Whole

func (g DeliveryGate) Whole() bool

Whole is THE reading of what this gate settled, and it is a method because it had been two readings.

Three fields say the delivery stands: the first judgement passed; the one permitted repair was re-judged and passed (PolishClosed); or the finding was weighed against the world and lost (Overturned). Everything else leaves the finding STANDING — a fail nothing repaired, a refusal about where a review got its words, a gap nothing could fund, a promised file the disk does not hold.

It lives here, on the event, because two readers spent this differently and disagreed out loud. deliveredWhole in cmd/codeaf/do.go combined all three fields to decide the exit code; gateWords, in the same file, built the line a person watching reads from Pass and Refused alone — so ink s5 and ofetch s5 printed "gate: fail — The deliverable is a listing of files, not the answer itself" as the last thing anybody saw and left with exit 0 (2026-08-29, bench/deepswe; docs/design/gate/SETTLEMENT.md §7). A verdict a person reads and a verdict an exit code carries are one fact, and one fact is one reading.

type DependencyFanIn

type DependencyFanIn struct {
	Count int
	Bytes int
}

DependencyFanIn is what actually landed into one node: how many settled hard dependencies it has, and how many bytes of result text they wrote between them. All of it — not the share DependencyInputs carries into the prompt.

It is a measurement and not an estimate, and it exists because a gathering node's budget has to be one. A join sized from the flat leaf defaults is sized for a leaf that gathers nothing, which is how an assembler ran out of room mid-assembly and had to be bought a continuation to finish typing what it had already read.

type DependencyInput

type DependencyInput struct {
	NodeID    string
	Digest    string
	Artifacts []string
	// Handle is the absolute path of a file holding this dependency's complete
	// text, and it is set exactly when the digest above is short of it.
	//
	// It was written on the belief that pushing was what cost 37× — that a
	// window-sized pot had been handing every join every upstream result in
	// full. That belief was wrong, and the measurement says so: the join that
	// billed 163k tokens was handed 2.3 KB, and this field was never once set in
	// either benchmark run, because a fan-in of one-sentence summaries is never
	// large enough to overrun anything. What actually cost was the opposite, the
	// pulling: a consumer handed paths instead of results went and read them.
	//
	// So the digest carries the product now, and this is what remains true of
	// the handle: a fan-in genuinely too large for its reader is clipped, and
	// every withheld byte is one ordinary path away instead of gone. It is the
	// exception it was always meant to be rather than the rule it silently was.
	//
	// The path is content-addressed, so the same settled result yields the same
	// handle on every read: a prompt prefix built from these does not move
	// underneath a cache that is counting on it not moving.
	Handle string
}

DependencyInput is one settled hard dependency as its consumer receives it: who produced it, the bounded digest of what it said, the files it left behind, and — when the digest is not the whole of it — a handle that opens the whole of it.

Artifacts are a separate field rather than the tail of the digest because they are the one part that must survive the byte bound. A producer writes its file list at the end of its summary, which is exactly where the bound bites first, and a consumer that loses the paths loses its only route to the full detail — it is then holding a 200-word pointer to work it cannot open.

type Edge

type Edge struct {
	From         string
	To           string
	Kind         EdgeKind
	CreatedSeq   int64
	CreatedOrder int
}

Edge points from an input to the node that consumes or is constrained by it.

type EdgeKind

type EdgeKind string

EdgeKind says how one node bears on another. FeedsInto and Blocks are hard scheduling dependencies; Suggests routes a soft hint and never delays work.

const (
	FeedsInto EdgeKind = "feeds_into"
	Blocks    EdgeKind = "blocks"
	Suggests  EdgeKind = "suggests"
)

type EndKind

type EndKind string

EndKind says how a turn ended. Exactly one of these is true of every turn, and only the three abnormal ones are ever written: a turn that finished because it was finished needs no mark, and marking it would put a row on every message in the journal to say nothing happened.

const (
	// EndCompleted is the turn ending on its own terms. Defined so the
	// vocabulary is total; not written by the engine.
	EndCompleted EndKind = "completed"
	// EndLength is the output cap. This is the shape of the failure in session
	// bd3c78ed: 1,611 characters of an SVG, cut at exactly 600 completion
	// tokens, journaled as if whole.
	EndLength EndKind = "length"
	// EndStreamDrop is a stream that stopped without ever saying why — no
	// terminal frame, or a provider-side error in place of one.
	EndStreamDrop EndKind = "stream-drop"
	// EndInterrupted is the person stopping the turn. What they saw is kept;
	// this says they are the reason it goes no further.
	EndInterrupted EndKind = "interrupted"
)

func ClassifyEnd

func ClassifyEnd(finishReason string, streamed bool) EndKind

ClassifyEnd reads the provider's finish_reason into our vocabulary. streamed says whether the call was made with a stream observer attached, and it is not decoration: an empty finish reason means two different things on the two paths. On a stream it means no terminal frame ever arrived — the connection ended mid-answer. On a single response it means the endpoint simply did not say, which is not evidence of anything.

type EndedPart

type EndedPart struct {
	How          EndKind `json:"how"`
	FinishReason string  `json:"finish_reason,omitempty"`
}

EndedPart is the truncation law's carrier. FinishReason is the provider's own word, kept verbatim beside our reading of it: the vocabulary of finish reasons is not ours and grows without asking, so the raw string is the only thing that stays true when it does.

func EndedFor

func EndedFor(finishReason string, streamed bool) *EndedPart

EndedFor is the mark a turn earns, or nil when it earned none. Returning nil for the ordinary case is the point: the truncation law puts a mark on a turn that did not finish, and puts nothing at all on the turns that did.

func InterruptedEnd

func InterruptedEnd() *EndedPart

InterruptedEnd is the mark for a turn the person stopped. It has no finish reason because no provider was ever asked to give one.

type ErrandSpend

type ErrandSpend struct {
	Work   SpendSlice
	Spine  SpendSlice
	Shared bool
}

ErrandSpend is one errand's whole bill, read off the journal rather than counted in a process.

It exists because the figure a one-shot run printed was a subtraction — today's spend after minus today's spend before — and that arithmetic is wrong in three separate ways at once. It is read while the run is still landing, so a leaf that journals its row a second later is money the receipt never saw (P1 of the perf wave reported $0.5255 against a table that summed to $0.8221: the difference was one leaf, exactly). It is scoped to a day, so a run that crosses local midnight subtracts the wrong baseline. And it is scoped to the whole store, so a durable journal another session is also billing hands this run somebody else's money.

The two slices are kept apart because they are known differently well, in the same way RoomSpend keeps them apart. Work is exact: every node this errand owns carries its session on its provenance, and the leaf rows and the per-node structuring rows both land there. Spine is the root-billed half — planning passes and head structuring bill RootID, which belongs to no session — and inside a store only this errand is using it is exactly this errand's overhead. Shared says another session billed its own nodes inside the same window, which makes Spine a ceiling rather than a bill.

func (ErrandSpend) Cost

func (spend ErrandSpend) Cost() float64

Cost is the whole bill: what this errand's nodes cost plus what it cost to decide what they should be. It is the number a receipt prints, and on a private store it is the sum of the usage table.

func (ErrandSpend) Runs

func (spend ErrandSpend) Runs() int

Runs is every usage row the bill counted.

type Event

type Event struct {
	Seq     int64
	Time    time.Time
	NodeID  string
	Kind    EventKind
	Payload json.RawMessage
}

Event is one immutable journal entry.

type EventKind

type EventKind string

EventKind names state transitions in the append-only journal.

const (
	// EventLeafExhausted is one attempt ending because it ran out of the room
	// it was granted, rather than because it finished or failed.
	//
	// IT IS NOT A FAILURE AND IT IS NOT A RESTART. The growth governor already
	// weighs exhaustion when it decides whether more room is worth buying; what
	// it could not do was tell a person, or a later reader, that this is what
	// happened. A leaf that was still working when the clock ran out looks
	// exactly like a leaf that hung, and the two want opposite responses.
	EventLeafExhausted EventKind = "leaf_exhausted"
	// EventLeafResumed is a claim taking over work that is already recorded,
	// with the size of the record it was handed. It is the receipt for the
	// promise in resident.Bank — that a restarted leaf does not start over —
	// and until it existed nothing anywhere said whether the promise was kept.
	EventLeafResumed EventKind = "leaf_resumed"
	// EventLeafStopped is the worker behind a claim reporting that it is gone,
	// naming the token it held.
	//
	// IT IS THE ORDERING PROOF AND THAT IS ITS WHOLE JOB. A claim taken back
	// while its worker is still running does not free the node, it doubles it:
	// two leaves on one node, writing one workspace, each undoing the other's
	// edits. So a reaped claim is released by the worker's OWN landing, after
	// its context has been cancelled and it has actually returned, and this row
	// is journaled immediately before that release. In any store's journal,
	// `leaf_stopped` for a token strictly precedes the `node_released` that
	// frees it — and where it does not, a worker was overtaken.
	EventLeafStopped EventKind = "leaf_stopped"
)
const (
	// EventMemoryAdd carries a whole new memory row.
	EventMemoryAdd EventKind = "memory_add"
	// EventMemoryUpdate carries an id and the new title, text and tags. It is a
	// correction in place: the memory is still the same memory, and its id,
	// type, scope and use count survive.
	EventMemoryUpdate EventKind = "memory_update"
	// EventMemorySupersede retires one memory in favour of another in a single
	// event, because the two halves are one decision. Two events — forget the
	// old, add the new — would let a replay stop between them and leave the
	// brain believing nothing at all about the subject.
	EventMemorySupersede EventKind = "memory_supersede"
	// EventMemoryForget is a tombstone and never a deletion. The row stays for
	// audit; every view and every search excludes it from the moment this
	// lands.
	EventMemoryForget EventKind = "memory_forget"
	// EventMemoryRestore returns one forgotten memory to the active views.
	EventMemoryRestore EventKind = "memory_restore"
	// EventMemoryRanking carries a periodic SNAPSHOT of the two ranking
	// counters — how often each memory helped, and how often it was put in
	// front of a model and did not.
	//
	// It exists because those counters are now load-bearing: [Store.MemoryCandidates]
	// ranks on them, so a Rebuild that reset them to zero would not merely lose
	// telemetry, it would change which eight rows the router is shown. One event
	// per retrieval is still the wrong answer for the reason [Memory.UseCount]
	// gives — it would bury the five events that carry meaning under thousands
	// that carry none — so the journal takes a snapshot on an interval instead
	// and a replay lands on that floor rather than on nothing.
	EventMemoryRanking EventKind = "memory_ranking"
)

Memories are what one session knows and the next one would otherwise have to be told again.

The notebook (facts.go) distils beliefs out of finished WORK: a fact is something the graph learned by running. A memory is something a person said, decided, corrected or is in the middle of — it arrives in conversation, it is addressed by a short title rather than found by a retrieval sweep, and it is carried across sessions by a router that is shown a SHORTLIST of titles — eight of them, ranked here in SQL (Store.MemoryCandidates) — and asks for the two or three that bear on the moment.

It is event-sourced like everything else here, and for the same reason: the events table is truth, the memories table and memories_fts are materialized views refreshed inside the same write transaction as the event that changed them, and Rebuild reproduces both by replaying the journal. Nothing is ever deleted — a forgotten memory is a tombstone with its row intact, because "the user told me to forget this" is itself a thing worth being able to prove later.

const (
	EventQuestionStatusChanged     EventKind = "question_status_changed"
	EventQuestionPracticeStarted   EventKind = "question_practice_started"
	EventQuestionPracticeCompleted EventKind = "question_practice_completed"
)
const (
	EventSpineCreated   EventKind = "spine_created"
	EventSpineRepaired  EventKind = "spine_repaired"
	EventSubtreeSpliced EventKind = "subtree_spliced"
	EventNodeClaimed    EventKind = "node_claimed"
	EventNodeStarted    EventKind = "node_started"
	EventNodeCompleted  EventKind = "node_completed"
	EventNodeFailed     EventKind = "node_failed"
	EventNodeReleased   EventKind = "node_released"
	EventSubtreeFolded  EventKind = "subtree_folded"
	EventEdgeAdded      EventKind = "edge_added"
	EventEdgeRemoved    EventKind = "edge_removed"
	EventNodeAmended    EventKind = "node_amended"
	EventNodeReparented EventKind = "node_reparented"
	EventNodeCancelled  EventKind = "node_cancelled"
	// Surgery controls are separate from the public status enum. Holds keep a
	// pending node visibly pending while making it unschedulable; cancel
	// requests let the live claim owner release cooperatively at a turn
	// boundary before the ordinary cancelled transition lands.
	EventNodeCancelRequested EventKind = "node_cancel_requested"
	EventNodeHeld            EventKind = "node_held"
	EventNodeResumed         EventKind = "node_resumed"
	EventNodePriorityChanged EventKind = "node_priority_changed"
	// A node's worker changing hands, journaled by a build that had more than
	// one worker. NOTHING WRITES ONE. It is replayed and never appended, so a
	// graph that holds them opens, rebuilds and reads back what it recorded.
	EventNodeWorkerChanged EventKind = "node_worker_changed"
	// A node's RUNNING worker is a different fact from the one above, and it is
	// the fact an autopsy actually needs: which worker the dispatch path built
	// and handed the work to. A node's assignment column says nothing at all —
	// nothing routes a node — so without this row nobody can tell an unrouted
	// node from a node nobody ran. The s9 sweep cost a day to exactly that:
	// every node in its stores said nothing, and no other row said who had done
	// the work.
	EventNodeRan EventKind = "node_ran"
	// A node's model may change whenever somebody says so, for as long as the
	// node still has work left. It is one event per node rather than one sweep
	// over a subtree, so a replay re-points exactly the nodes the sweep found
	// rather than whatever happens to be live when the replay runs.
	EventNodeModelChanged EventKind = "node_model_changed"

	// Thread events: the conversation and its asynchronous mutation requests
	// live in the same journal as the graph they act on.
	EventMessagePosted    EventKind = "message_posted"
	EventCommandRequested EventKind = "command_requested"
	EventCommandResolved  EventKind = "command_resolved"
	// EventSessionOpened is a room's birth certificate. Until it existed the
	// sessions table was a projection of the messages naming a session and
	// nothing else, so a room could not be created before somebody spoke in it
	// — which is exactly what a thread switcher does when it opens a new,
	// empty conversation. It is a separate event rather than a flag on the
	// first message because the two facts are separate: a room being opened,
	// and something being said in it.
	EventSessionOpened EventKind = "session_opened"
	// EventSessionRenamed is a room keeping its birthday and taking a new name.
	// It is a separate event from EventSessionOpened for the same reason opening
	// is separate from speaking: a room's title changing is not the room being
	// born again, and folding the two into one mint-or-rename event would let a
	// rename raise last_active — a retitle is not activity, and the projection
	// write below is what keeps that true.
	EventSessionRenamed EventKind = "session_renamed"
	// EventSessionDiscarded is a room being taken back: opened, never spoken in,
	// never named. It is journaled rather than deleted quietly because the
	// sessions table is a projection — a bare DELETE would be undone by the next
	// rebuild, and the empty rooms it removes would all come back.
	EventSessionDiscarded      EventKind = "session_discarded"
	EventSeenTouched           EventKind = "seen_touched"
	EventAgentQuestionQueued   EventKind = "agent_question_queued"
	EventAgentQuestionSurfaced EventKind = "agent_question_surfaced"
	EventAgentQuestionResolved EventKind = "agent_question_resolved"

	// Standing-watch policy is global to this brain file. Offered is the
	// durable never-ask-twice gate; enabled and declined are the user's final
	// decision; pass is one completed headless wake observation.
	EventStandingWatchOffered  EventKind = "standing_watch_offered"
	EventStandingWatchEnabled  EventKind = "standing_watch_enabled"
	EventStandingWatchDeclined EventKind = "standing_watch_declined"
	// EventStandingWatchStoodDown is the reverse gear. Enabled and declined
	// used to be terminal by construction, which made an unattended-presence
	// consent one the product accepted and structurally refused to give back —
	// while the timer repaired itself against the user's own hands every five
	// minutes. Standing down is a fifth state rather than a rewrite of the
	// fourth because the journal is append-only and the fact that the user once
	// said yes is part of the history.
	EventStandingWatchStoodDown EventKind = "standing_watch_stood_down"
	EventStandingWatchPass      EventKind = "standing_watch_pass"

	// Usage and surprise are journaled separately because a planned leaf's
	// prediction becomes known when the complete plan lands, after its spend.
	EventUsageRecorded    EventKind = "usage_recorded"
	EventSurpriseRecorded EventKind = "surprise_recorded"
	// EventTurnUsageRecorded carries one execution's per-turn shape beside the
	// summed row EventUsageRecorded already writes. It is a separate kind and a
	// separate table because every existing reader counts usage rows to mean
	// executions; see usage_turns.go.
	EventTurnUsageRecorded EventKind = "turn_usage_recorded"
	// EventTranscriptRecorded carries one flush of one leaf's turn-by-turn
	// record: what the model said, which tools it called with what arguments,
	// what came back, and how the loop ended. It is a separate kind and a
	// separate table for the same reason turn usage is — every reader of a
	// node's messages means "what was said about this work" by them, and a
	// worker's internal loop is not that. See transcript.go.
	EventTranscriptRecorded EventKind = "transcript_recorded"
	// EventSelfReceipt is the cost-and-learning receipt produced when one
	// self-originated splice settles.
	EventSelfReceipt EventKind = "self_receipt"
	// EventSelfInquiryRetired records the deterministic two-strike policy
	// decision that stops an inquiry line which is not earning learning rent.
	EventSelfInquiryRetired EventKind = "self_inquiry_retired"

	// EventRailRaised records the user's decision to extend today's dollar
	// ceiling. The journal is the policy record; no process-local flag resumes
	// work.
	EventRailRaised EventKind = "rail_raised"

	// EventTaskCeilingSet records a dollar ceiling placed over one task's
	// subtree, or — carrying Cleared — its removal. The daily rail governs a
	// shared day; this one governs a single root and stops nothing outside it.
	EventTaskCeilingSet EventKind = "task_ceiling_set"
	// EventTaskRailAsked is the per-root marker that the ceiling question has
	// already been asked. It is journaled against the root because the question
	// itself is an ordinary message and messages carry no task key.
	EventTaskRailAsked EventKind = "task_rail_asked"

	// Overrun deferrals preserve a landed partial whose repair could not be
	// admitted at the rail. Resumption is a separate event so a rebuild can
	// recover exactly the continuations that still need to be spliced.
	EventOverrunDeferred EventKind = "overrun_deferred"
	EventOverrunResumed  EventKind = "overrun_resumed"

	// EventOverrunEvidence is a leaf caught running far past what work of its
	// kind had ever cost on this machine, journaled at the moment the comparison
	// was made rather than reconstructed afterwards from a bill.
	//
	// The comparison is no longer made, so nothing writes this kind any more.
	// The constant and its replay stay because journals that carry it are on
	// disk, and a rebuild that could not name one of its own events would
	// refuse a graph it wrote itself.
	EventOverrunEvidence EventKind = "overrun_evidence"

	// EventDeliveryGate is the final judge's evidence about one delivered job.
	EventDeliveryGate EventKind = "delivery_gate"

	// EventFactLearned is one durable fact distilled from finished work.
	EventFactLearned EventKind = "fact_learned"
	// EventFactActivated records execution promoting a skill candidate.
	EventFactActivated EventKind = "fact_activated"
	// EventFactSuperseded retires one fact in favour of a newer one.
	EventFactSuperseded EventKind = "fact_superseded"
	// EventFactInjected attributes a batch of notebook facts to one node's
	// context.
	EventFactInjected EventKind = "fact_injected"
	// EventFactQuarantined removes a suspect fact from retrieval without
	// deleting it.
	EventFactQuarantined EventKind = "fact_quarantined"
	// EventFactRestored returns a quarantined fact to active retrieval.
	EventFactRestored EventKind = "fact_restored"
	// EventScopeAliased shelves one emergent scope under another while keeping
	// the old name valid as a retrieval cue.
	EventScopeAliased EventKind = "scope_aliased"

	// EventRetrospectiveCheckpointed records how much settled top-level work
	// the periodic retrospective has already considered.
	EventRetrospectiveCheckpointed EventKind = "retrospective_checkpointed"
	// EventResidentWatermarked records how far one resident lane has already
	// got. The settle lane's cursor used to live only in the reconciler's
	// memory, which made every restart step over whatever landed while nothing
	// was ticking; a lane watermark is the same durable answer the
	// retrospective already had.
	EventResidentWatermarked EventKind = "resident_watermarked"
	// EventAssumedWithDefault records a VOI-gated skipped ask for later correction matching.
	EventAssumedWithDefault EventKind = "assumed_with_default"
	// EventParameterChanged is the sole bounded self-tuning mutation surface.
	EventParameterChanged EventKind = "parameter_changed"

	// Charter events keep standing intent and every watch decision in the same
	// append-only policy record as the work a firing creates.
	EventCharterCreated          EventKind = "charter_created"
	EventCharterRevised          EventKind = "charter_revised"
	EventCharterStatusChanged    EventKind = "charter_status_changed"
	EventCharterWatchAdvanced    EventKind = "charter_watch_advanced"
	EventCharterWoken            EventKind = "charter_woken"
	EventSentinelChecked         EventKind = "sentinel_checked"
	EventCharterFired            EventKind = "charter_fired"
	EventCharterFiringBlocked    EventKind = "charter_firing_blocked"
	EventCharterFiringDeferred   EventKind = "charter_firing_deferred"
	EventCharterProposalDeclined EventKind = "charter_proposal_declined"
	EventCharterFiringProposed   EventKind = "charter_firing_proposed"
	EventCharterFiringDeclined   EventKind = "charter_firing_declined"
	EventCharterFiringReviewed   EventKind = "charter_firing_reviewed"
	EventCharterPromoted         EventKind = "charter_promoted"
	EventCharterDemoted          EventKind = "charter_demoted"

	// Service events are the durable ownership record for processes promoted
	// out of a leaf's background-job registry.
	EventServicePromoted  EventKind = "service_promoted"
	EventServiceAdopted   EventKind = "service_adopted"
	EventServiceStopped   EventKind = "service_stopped"
	EventServiceFailed    EventKind = "service_failed"
	EventServiceRestarted EventKind = "service_restarted"
	EventServiceRested    EventKind = "service_rested"
)
const EventAcceptance EventKind = "acceptance"

EventAcceptance is the acceptance checklist journaled against the piece of work it will be used to judge: the behaviours the person's own request states, read from the request before any work began.

It is a first-class event beside the plan blob for the reason EventNodeBrief is: the checklist lives on plan.Spec, inside a document held in memory for the life of a run, and "what was this work actually asked for" is exactly the question an autopsy of a finished run needs answered from the run's own journal. It is also what the headless stream reads to say the checklist exists at all — a fail-safe that does not reach the person watching is decoration (docs/design/failsafe/FAILSAFE.md clause 3).

const EventConsumers EventKind = "consumers"

EventConsumers is the third reading of the same tree, journaled beside the other two: the definitions this run's own diff touched, and what the rest of the project still does with them.

It is its own kind for the reason EventSurface is. The check-level reading answers what a suite says, the surface reading answers whether a name is still there, and neither can see a definition that kept its name and changed its SHAPE — igel s12 rebound `configs` from a dict to an instance of a class it wrote, the surface row read `compared: 8, lost: 0`, and twenty-four hidden tests failed on `'Configs' object does not support item assignment`.

const EventCraftForged EventKind = "craft_forged"

EventCraftForged records that the resident distilled a way of working into the craft repository.

const EventJobGrowth EventKind = "job_growth"

A job that grows while it runs used to leave no single trace of having grown. An overrun replan spliced a subtree, a revision sentinel spliced a node, and afterwards the two were indistinguishable without reading intents node by node — so "why did this job end up with 41 nodes, and who asked for the last eleven?" had no answer, and neither did "what did a governor refuse".

So every execution-time growth decision — admitted or refused — is journaled against the job root it grew, the same key the job's own nodes are minted under. It is diagnosis for the refusals and accounting for the admissions: the round counter that bounds growth is derived from these events, so the journal is the counter rather than a description of one.

EventJobGrowth is declared here rather than in store.go's block for the same reason EventScaleGate is declared beside its writer: a kind whose payload one file understands is easier to keep honest next to that file.

const EventLeafMode EventKind = "leaf_mode"

The shape a leaf was dispatched in, journaled where every other durable fact about a node lives.

It is diagnosis, not control — nothing reads it back to decide anything — and it exists for the same reason the scale gate's reading does: a decision taken at claim time against numbers that no longer exist afterwards is a decision nobody can check. A node that ran as a fold and a node that happened to finish in two turns look identical in the record, and only one of them is evidence that the predicate fired. The counts ride with it so the predicate can be argued with rather than merely observed: how many results fed it, how many bytes of them were pushed whole, how many had to be left on a handle.

const EventLeafSelfClose EventKind = "leaf_self_close"

EventLeafSelfClose is one leaf reading its own finished work, finding a fault it caused, and being held back to fix it before it lands.

IT IS NOT A ROUND AND IT IS NOT A RETRY. The finding the leaf's own closing photograph raises — a public name it deleted, a name it reads that nothing binds, its own checks red, a check it turned red — used to reach nobody until the leaf had landed, a gate had weighed it, and the growth governor had bought a repair round: a COLD leaf with a fresh brief and none of the context that made the mistake. igel s14 bought three of them and every one deleted what the last had relied on. This row is the other answer: the leaf that caused it is still standing, still holds its own transcript, and is asked once.

Nothing reads it to decide anything. It is a record, so that a run where the leaf fixed its own work and a run where nobody looked stop being the same silence (FAILSAFE.md clause 4).

const EventNodeBrief EventKind = "node_briefed"

EventNodeBrief is one node's rendered brief journaled as a first-class, queryable event. A run's sufficiency sentence used to live only as an opaque field inside the single plan_graph blob, so a finished leaf's criterion was unfalsifiable from the run's own artifacts: the question "what was this node told to be done by?" could be answered only by reading the whole plan back and finding the node inside it. This event carries the rendered instruction, the criterion and the subharness, one row per briefed node, written beside the blob rather than in place of it — RecordPlanGraph still writes the whole graph, additively.

const EventNodeFaulted EventKind = "node_faulted"

EventNodeFaulted is a recovered panic inside one node's work. It is not a node failure: a fault is frequently followed by a retry or an escalation that succeeds, and a node that recovered is not a node that failed.

const EventPlanGraph EventKind = "plan_graph"

A job's plan used to live only in the memory of the process that produced it. That was defended as telemetry — lose it and you lose a recalibration record — right up until result-driven revision began reading the same map: editing a running job's unstarted remainder is work, and a redirect that found no plan answered the user with a receipt saying the plan had been read and needed no changes.

So the plan is journaled where every other durable fact about a job lives: as an event on the job's own root node. The store deliberately learns nothing about what a plan is — the bytes arrive already encoded and go back out the same way — because the planner is a consumer of the store and inverting that would make the graph package a dependency of the journal.

EventPlanGraph is declared here rather than in the block in store.go for the same reason the question-practice kinds are declared beside their writer: a kind whose payload only one file understands is easier to keep honest next to that file.

const EventRoleBindingSet EventKind = "role_binding_set"

EventRoleBindingSet records one role binding decision, or — carrying Cleared — its removal. It is journaled against the node the scope names so an indexed reader can find a scope's history without scanning; a global binding names no node, exactly as a message names none.

const EventScaleGate EventKind = "scale_gate"

A job's shape is decided in one branch, before any node exists, and until now that branch left no trace of itself. A run that came out as a single leaf and a run that fanned into eleven look identical afterwards except for the nodes themselves, so the only way to answer "why did this have no parallelism?" was to run it again and watch — which is not an answer, because the reading that decided it is a model's and does not repeat.

So the reading is journaled where every other durable fact about a job lives: as an event on the id namespace the job's nodes are minted under. It is diagnosis, not control — nothing reads it back to decide anything — and it is written in the same breath as the decision it explains rather than inferred from the shape that resulted, because the shape is the thing being explained.

EventScaleGate is declared here rather than in the block in store.go for the same reason EventPlanGraph is declared beside its writer: a kind whose payload only one file understands is easier to keep honest next to that file.

const EventStructuredRepair EventKind = "structured_repair"

A run that repaired its own model calls twice used to look exactly like a run that never had to.

FAILSAFE.md clause 4: a fail-safe that fires without leaving a record is a fail-safe nobody can autopsy, and clause 3: a fact that changes what somebody watching should expect is a line in the stream. Both are about the same events — a structured answer cut off at the output ceiling and continued, one asked again because it came back as prose, one given up on. Every one of them costs money, changes how long the run takes, and is the first thing anyone reading a $0.50 run's autopsy wants to know about.

EventStructuredRepair is declared here rather than in store.go's block for the reason EventJobGrowth is: a kind whose payload one file understands is easier to keep honest next to that file.

const EventSurface EventKind = "surface"

EventSurface is the symbol-level half of the photograph, journaled beside the check-level one.

It is its own kind rather than a field on the reading because the two answer different questions from different evidence, and a run can have either without the other: a project that declares no verification still has a public surface, and a suite that ran fine still says nothing about a name it never touched. igel s11's check-level row said the tree got BETTER on the run that deleted eight public attributes.

const EventUnbound EventKind = "unbound"

EventUnbound is the fourth reading of the same tree, journaled beside the other three: the names the run's own sources READ that nothing in the tree binds.

It is its own kind for the reason EventSurface and EventConsumers are. Those three all answer a question about a name that used to exist — is it still there, does a check exercise it, did its shape move under its callers — and none of them can see a name that was NEVER there. igel s14 imported `temp_post_req_data_path` from a module that had just stopped binding it, all twenty-four hidden tests failed on `ImportError`, and the run's own record held only that its checks were red.

const EventVerification EventKind = "verification"

EventVerification is one reading of a project's own checks, journaled against the node whose work it is a reading of.

type ExercisedPoint

type ExercisedPoint struct {
	Point string `json:"point"`
	Check string `json:"check,omitempty"`

	// Observables is what the behaviour was weighed against: the identifiers the
	// request spelled, bound, or named in words against the tree's own public
	// surface. It is journaled beside the finding because the RESOLUTION is the
	// half an autopsy cannot reconstruct — "vertical scrollbar position" became
	// `ScrollBar.position` by a reading of a tree that has since moved on, and
	// without the row there is no way to ask whether the door was asking about
	// the right thing at all.
	Observables []string `json:"observables,omitempty"`

	// Unasserted is the behaviour's own observables — the identifiers the
	// request spelled — that the mapped check's ASSERTIONS never name. A row
	// with a check and an unasserted list is a pairing the world admits and the
	// check does not earn: the check runs the behaviour and weighs nothing about
	// it.
	//
	// It is journaled beside the pairing rather than reduced to the finding it
	// produces, for the reason Exercises itself is. textual s13 shipped at exit
	// 0 with three such rows, and afterwards there was no way to ask which
	// observable had been skipped — `expand` and `min_width` were named in the
	// request, called in the check, and asserted nowhere, and the mapping said
	// only that a check existed. See revision.WeighAssertions.
	Unasserted []string `json:"unasserted,omitempty"`
}

ExercisedPoint is one row of that mapping: a behaviour the request stated and the check that exercises it. An empty Check is the finding — nothing in the project's own verification touches this.

type ExplorationToleranceValue

type ExplorationToleranceValue struct {
	TrialCorrectionRate float64 `json:"trial_correction_rate"`
	PlainCorrectionRate float64 `json:"plain_correction_rate"`
	Tolerance           float64 `json:"tolerance"`
}

ExplorationToleranceValue compares correction rates on trial and plain work.

type Fact

type Fact struct {
	Seq          int64
	Time         time.Time
	NodeID       string // the node whose work taught this
	Scope        string // what it is about: user, env, tool:x, repo:/p, file:/p/f, domain:x
	Kind         FactKind
	Channel      FactChannel
	Body         string
	Status       string
	StatusSeq    int64
	EvidenceSeq  int64
	StatusOrigin FactChangeOrigin

	// Unsettled is present only when Kind is FactUnsettled. Body is its
	// readable projection; this payload is what code branches on.
	Unsettled *UnsettledPair

	// Artifact points at a skill candidate's teaching directory, then at its
	// installed directory after execution promotion. StatusNote records why a
	// candidate or active skill was retired.
	Artifact   string
	StatusNote string

	// Uses and LastUsed are retrieval telemetry for consolidation, not
	// journaled truth: Rebuild resets them, deliberately, and so does the facts
	// migration. Nothing ranks on them — a value the journal cannot rebuild may
	// inform a human reading the table, never a retrieval deciding what a model
	// sees. FactOutcomes answers "has this been useful" from the journal.
	Uses     int
	LastUsed time.Time
	// Confidence is the current shrunk survival rate for Kind x Channel.
	Confidence float64

	// Trust is the provenance tier for skill facts: "authored" (default),
	// "imported-provisional", or "forged". Empty is stored and read back as
	// "authored" by SkillFactAccessors.
	Trust string
	// CostCard is the measured token budget for read/run/delegate operations.
	CostCard CostCardT
	// Digest is the content-addressable digest of the payload directory,
	// computed at install time from all files' contents.
	Digest string
}

Fact is one materialized notebook entry.

func (Fact) SkillName

func (f Fact) SkillName() string

SkillName is the shelf name of a skill fact — the one spelling every reader of the shelf matches on. It is the directory the artifact points at, or the scope when the fact predates installation. use_skill answers names spelled this way (tools_skill.go's get), so a reader matching anything else answers a name the worker was never shown.

type FactChangeOrigin

type FactChangeOrigin string

FactChangeOrigin names who changed a fact's retrieval status.

const (
	FactOriginUser         FactChangeOrigin = "user"
	FactOriginCLI          FactChangeOrigin = "cli"
	FactOriginConsolidator FactChangeOrigin = "consolidator"
	FactOriginSupersession FactChangeOrigin = "supersession"
)

type FactChannel

type FactChannel string

FactChannel records how a belief entered the notebook.

const (
	FactChannelStated    FactChannel = "stated"
	FactChannelInferred  FactChannel = "inferred"
	FactChannelDistilled FactChannel = "distilled"
	FactChannelTrial     FactChannel = "trial"
)

func ChannelForWriter

func ChannelForWriter(writer FactWriter) FactChannel

ChannelForWriter derives a fact's channel at its write boundary.

type FactKind

type FactKind string
const (
	// FactPreference is how the user wants things done.
	FactPreference FactKind = "preference"
	// FactQuirk is a scoped oddity of one file, repo, tool, or product.
	FactQuirk FactKind = "quirk"
	// FactLesson is a transferable mistake-turned-rule.
	FactLesson FactKind = "lesson"
	// FactPlain is an entity and its stable attributes.
	FactPlain FactKind = "fact"
	// FactUnsettled is a machine-readable pair of approaches whose evidence
	// does not yet establish one standing rule.
	FactUnsettled FactKind = "unsettled"
	// FactSkill is an execution-verified procedure offered to future work.
	FactSkill FactKind = "skill"
	// FactPlaybook is one scoped strategy bullet earned from earlier work.
	FactPlaybook FactKind = "playbook"
	// FactQuestion is a durable knowledge gap. Unlike ordinary notebook facts,
	// questions have their own open/practicing/resolved/retired lifecycle and
	// never enter retrieval as standing knowledge.
	FactQuestion FactKind = "question"
	// FactTrait is a measured second-order user fact. Its scope is trait:<name>
	// and its body is a structured TraitMeasurement payload.
	FactTrait FactKind = "trait"
)

type FactOutcome

type FactOutcome struct {
	FactSeq      int64
	Rides        int
	Bad          int
	LatestBadSeq int64
}

FactOutcome is the outcome co-occurrence attached to one notebook fact. Bad counts distinct injected nodes that failed, hit a failed delivery gate, or grew an overrun continuation. LatestBadSeq is evidence for quarantine.

type FactQuery

type FactQuery struct {
	// Cues are scope keys to match exactly, in priority order — the caller
	// walks hierarchies (file → folder → repo) into this list.
	Cues []string
	// Terms feed FTS5/BM25 and may be empty.
	Terms string
	// Kind restricts retrieval to one fact kind. Empty includes every kind.
	Kind FactKind
	// PreferUseful orders proven matches first and newest matches next: a fact
	// that has ridden into real work and come back without a failed gate
	// outranks one that has not. Scope cue order remains the primary match
	// signal when this is false.
	PreferUseful bool
	// MaxBytes bounds the returned scope-and-body bullet lines. Zero is
	// unbounded; the small per-line allowance covers "- [scope] body\n".
	MaxBytes int
	Limit    int
}

FactQuery is one retrieval: ordered scope cues (most specific first) plus optional free-text terms for the BM25 layer.

type FactWriter

type FactWriter string

FactWriter names the bounded write seams from which channels are derived.

const (
	FactWriterOther     FactWriter = "other"
	FactWriterHead      FactWriter = "head"
	FactWriterDistiller FactWriter = "distiller"
	FactWriterTrial     FactWriter = "trial"
)

type FileWatch

type FileWatch struct {
	Glob    string        `json:"glob"`
	Cadence time.Duration `json:"cadence"`
}

FileWatch is an mtime-polled glob. Cadence bounds filesystem work even when the resident reconciler ticks several times per second.

type FireDisposition

type FireDisposition string

FireDisposition is the deterministic result of trying to admit a checked yes wake under all three charter rails.

const (
	FireAdmitted FireDisposition = "admitted"
	FireQuota    FireDisposition = "quota"
	FireExpired  FireDisposition = "expired"
	FireRailWait FireDisposition = "daily_rail_wait"
)

type GraphPredicate

type GraphPredicate string

GraphPredicate is one durable graph transition a charter can observe.

const (
	GraphNodeSettled    GraphPredicate = "node_settled"
	GraphNodeFailed     GraphPredicate = "node_failed"
	GraphSpendThreshold GraphPredicate = "spend_threshold"
)

type GraphWatch

type GraphWatch struct {
	Predicate    GraphPredicate `json:"predicate"`
	Title        string         `json:"title,omitempty"`
	Scope        string         `json:"scope,omitempty"`
	ThresholdUSD float64        `json:"threshold_usd,omitempty"`
	Cadence      time.Duration  `json:"cadence"`
}

GraphWatch matches node transitions by title and/or notebook scope, or one daily spend threshold. Cadence controls how often the journal is scanned.

type GrowthFinding

type GrowthFinding struct {
	Kind  string `json:"kind,omitempty"`
	Names string `json:"names,omitempty"`
}

GrowthFinding is one review finding as the two things that decide whether a later round is being bought for the SAME finding: what kind of finding it is, and which names it cites.

IT IS THE STRUCTURED FINDING AND NEVER THE PROSE. A gate records its conclusions as lists — the behaviours no check exercises, the checks the run wrote and left red, the definitions it reshaped, the spans it convicted on — and those lists are stable across a rewording of the paragraph that carries them. Comparing paragraphs answers "did the reviewer type the same sentence twice", which is a question about a model's phrasing; comparing these answers "is the same thing still missing", which is a question about the work.

Names is a digest rather than the list because it is only ever compared for equality and a list of names is unbounded. The names themselves are on the row, in BoughtFor, because THE ROUND IS BOUGHT NAME BY NAME: the digest says two gates raised the same set, and the set is exactly what a rotating citation never repeats.

func (GrowthFinding) Empty

func (f GrowthFinding) Empty() bool

Empty reports that this round was not bought for any finding the record can name — which is not the same as a finding that cites nothing.

func (GrowthFinding) Same

func (f GrowthFinding) Same(other GrowthFinding) bool

Same reports that two rounds were bought for the same finding: same kind, same names. An empty finding is never the same as anything, INCLUDING ANOTHER EMPTY ONE — "nobody recorded what this round was for" is not evidence that two rounds were for one thing, and reading it as such would refuse a path that never named a finding at all.

type JobGrowth

type JobGrowth struct {
	Reason  string `json:"reason"`
	Lineage string `json:"lineage,omitempty"`
	Adding  int    `json:"adding,omitempty"`
	Round   int    `json:"round"`
	Allowed bool   `json:"allowed"`
	Refused string `json:"refused,omitempty"`
	// Cause is the machine-readable half of Refused: which governor spoke.
	Cause string `json:"cause,omitempty"`

	// Produced is how many files the work this round grows FROM left behind
	// THAT THIS JOB IS ABOUT — the workspace's own before-and-after reading,
	// narrowed to the change's own focus, and never the worker's account of
	// itself. It is journaled because it is the only evidence the next round
	// can be weighed against: a lineage whose last two bodies of work both
	// changed nothing relevant is not making slow progress, it is at a
	// standstill, and no round after that buys anything.
	//
	// IT COUNTS WHAT MATTERS AND NOT WHAT MOVED. It used to be every path the
	// tree gained, which is a count a stuck model raises for free: ink s10
	// spent its whole 5400-second wall over eight exhaustions of one lineage
	// while the only thing any round wrote was `debug-grid.ts`,
	// `debug-grid10.ts`, `debug-yoga.ts` and eleven more of the same beside a
	// change that never moved. Every one of those is a file, so every round
	// looked productive to a detector asking "did anything change" — and the
	// standstill rule, which was right, never got a chance to speak.
	Produced int `json:"produced,omitempty"`

	// Scratch is the rest of what the round wrote: files outside the focus,
	// which are not progress and are not nothing either.
	//
	// It is a separate count rather than a subtraction because the two facts
	// answer different questions. Produced answers "did this round move the
	// work"; this answers "then what WAS it doing", and a person reading a
	// refusal is owed the second — a round that wrote fourteen files and moved
	// none of them is a specific, recognisable failure and the count is what
	// makes it recognisable.
	Scratch int `json:"scratch,omitempty"`

	// Moved names the files inside the focus that the round did change, bounded
	// the same way. It is what the run's closing line points at when it says
	// what the last real change was — a person told "nothing has moved for
	// three rounds" is owed the name of the last thing that did.
	Moved []string `json:"moved,omitempty"`

	// Wrote names those files, bounded. The count says a round wrote nothing
	// that mattered; this says WHAT it wrote instead, which is the whole of
	// what an autopsy of a fruitless round has to work with — and it was, in
	// s10, only recoverable by reading resume payloads out of the transcript.
	Wrote []string `json:"wrote,omitempty"`

	// Unexercised, Red and Standing are the job's own shortfall as its record
	// stood when this round was weighed: how many stated behaviours no check
	// exercises, how many checks the newest reading found red, and a digest of
	// the review finding that still stands.
	//
	// They are journaled because MOVING A FILE IS NOT THE ONLY WAY TO MOVE THE
	// WORK. A round that closed a regression, answered a standing finding, or
	// brought a behaviour under a check has made progress even where the focus
	// gained nothing, and a rule that could not see it would refuse the round
	// after the one that finally started working. Each is compared against the
	// row before it and only ever for a FALL — a shortfall reworded is not a
	// shortfall closed, which is the same distinction Remainder draws below.
	Unexercised int `json:"unexercised,omitempty"`
	Red         int `json:"red,omitempty"`
	// Lost is the symbol-level half of the same shortfall: public names the
	// finished tree no longer spells. See SurfaceReading.
	Lost     int    `json:"lost,omitempty"`
	Standing string `json:"standing,omitempty"`

	// Measured says somebody actually looked, so a Produced of zero reads as
	// "nothing was written" rather than as "nobody counted". A row written
	// before this field existed decodes false, which is the honest reading of
	// it: nothing counted anything.
	Measured bool `json:"measured,omitempty"`

	// CoveredDespite names the standing evidence that stopped the coverage
	// question from refusing this round: the kinds the WORLD still says are
	// wrong with the job, when the plan-level reading said everything it is
	// judged on was already covered.
	//
	// It is journaled because the two readings DISAGREED and the disagreement is
	// the measurement. Coverage is a claim about the plan — acceptance points
	// mapped onto work that has landed — and it can be perfectly true of a job
	// whose checks are red and whose stated behaviours nothing exercises,
	// because none of those is a point on the plan. A row carrying this is a row
	// where a model said "nothing left" over a tree that was demonstrably not
	// finished, and an autopsy asking how often that happens has nothing else to
	// read. Empty is every round where the two agreed or the question was never
	// put.
	CoveredDespite []string `json:"covered_despite,omitempty"`

	// Finding is the REVIEW FINDING this round was bought for: what kind of
	// finding it is and which names it cites, as the structured record holds
	// them rather than as the review's paragraph spells them.
	//
	// It is journaled because A FINDING HAS ITS OWN FIXED POINT and nothing
	// else in this row can see it. Remainder below is a digest of the review's
	// PROSE, so a finding restated in fresh words reads as new work; Produced
	// is a fact about the tree, so a round that rewrote half a repository and
	// left the finding exactly where it found it reads as progress. happy-dom
	// v4-flash s13 is the measured case: four gate events carrying one
	// identical finding — the same four check names, word for word — bought
	// four rounds, every one of them journaled as productive, and the finding
	// they were bought FOR never moved at all (2026-08-29, bench/deepswe).
	//
	// Empty is every round nobody bought for a finding: an overrun, a
	// cooperative split, a resumption. Those keep exactly the governors they
	// had.
	Finding GrowthFinding `json:"finding,omitempty"`

	// BoughtFor is every NAME that finding stood on when this round was bought:
	// the behaviours no check exercises, the checks the run left red, the public
	// names the change deleted. A round bought for a set is a round bought for
	// every name in it.
	//
	// It is journaled as names and not as a count because THE FINDING IS EACH
	// NAME AND NOT THE SET. A gate cites whichever subset of the request it
	// happened to weigh, and the subset rotates: ofetch v4-flash s15 raised four
	// unexercised findings whose sets digested to four different values while
	// `Count a circuit failure for body-read/stream-consumption errors` sat in
	// every one of them, unclosed, for four rounds and the whole run. Nothing
	// that compares sets can see that; the names can.
	BoughtFor []string `json:"bought_for,omitempty"`

	// Spent is the names that had already had their two rounds when this
	// decision was taken — the ones that may not buy another. A refused round
	// carries the whole set here, which is what makes the refusal legible: the
	// person is told which things were worked on twice and still stand.
	Spent []string `json:"spent,omitempty"`

	// Remainder is a digest of the work this round was planned to finish. Two
	// consecutive rounds handed the same remainder are a fixed point: the round
	// that just ran was aimed at exactly this and did not move it. The digest
	// rather than the text because the text is unbounded and this is only ever
	// compared for equality.
	Remainder string `json:"remainder,omitempty"`
}

JobGrowth is one decision by the growth governor.

Reason names the path that asked — an overrun replan, a delivery gap, a revision sentinel — because the whole point of the journal is that those were indistinguishable afterwards. Lineage is the namespace the rounds are counted under: a leaf's own split lineage for a replan, the job root for growth that belongs to the job as a whole. Two siblings that each split once are two lineages with one round each, not one lineage with two.

Refused carries the governor's own words when it said no, so a reader of the journal sees the same sentence the work's record got.

type JobGrowthRound

type JobGrowthRound struct {
	JobGrowth
	At time.Time
}

JobGrowthRound is one journaled decision and when it was journaled.

The time is the journal's own and not a field anybody wrote, and it is exposed because A JOB'S PACE IS READ FROM ITS OWN ROUNDS. How long a round of this job takes is the gap between two of these, measured on the job that is running rather than assumed from a constant, and it is what answers "can the wall still hold another one".

type JobLife

type JobLife struct {
	NodeID string
	Status Status
	// Admitted is the journal stamp of the event that created this node — the
	// moment the work was spliced in. Zero only for a node whose creating event
	// predates the journal it was rebuilt from, which is absence and not "now".
	Admitted time.Time
	// Attempt is the node's claim counter: 1 is the first go at it, 2 the first
	// restart. Zero means never claimed.
	Attempt uint64
	// AttemptStarted is the CURRENT attempt's start stamp, the column a restart
	// resets. It is carried so a caller can say when the restart happened, never
	// so it can pass for the job's age.
	AttemptStarted time.Time
	FinishedAt     time.Time
}

JobLife is one node's whole run history: when the work was admitted, how many attempts it has taken, and when the attempt now in flight started.

ADMITTED IS THE JOB'S CLOCK; ATTEMPTSTARTED IS THE ATTEMPT'S. Both are returned because both are true, and a caller that needs to say "restarted a minute ago" is asking a different question from one that needs to say "at it for thirty-two minutes". What no caller may do is spend the second where the first was asked for, which is the whole of the incident behind this type.

func (JobLife) AttemptWords

func (life JobLife) AttemptWords() string

AttemptWords is the attempt count as a phrase, empty on a first attempt. Ordinals rather than "attempt 2" because the reader is a person or a model composing for one, and neither says "attempt 2" out loud.

func (JobLife) Elapsed

func (life JobLife) Elapsed(now time.Time) (time.Duration, bool)

Elapsed is how long this work has been going, measured from admission and NOT from the current attempt. A job still running is measured against now; a job that settled is measured to its finish. The second return is presence: a node with no admission stamp has no clock, which is a different sentence from a clock reading zero.

func (JobLife) Live

func (life JobLife) Live() bool

Live reports work that has been admitted and has not stopped.

func (JobLife) Restarted

func (life JobLife) Restarted() bool

Restarted reports work that has been picked up more than once. It is the presence bit for the attempt clause: a job on its first attempt says nothing about attempts at all, because "first attempt" is noise on every job that has never gone wrong.

func (JobLife) SinceRestart

func (life JobLife) SinceRestart(now time.Time) (time.Duration, bool)

SinceRestart is how long the current attempt has been going. It is absent on work that has only ever had one attempt, because there is no restart to date.

type JobSpend

type JobSpend struct {
	JobID  string
	Title  string
	Runs   int
	Cost   float64
	Last   time.Time
	Models []string
}

JobSpend is one job root's share of a window, named well enough to read aloud: what it was for, what it cost, and when it last spent anything.

type JobUsage

type JobUsage struct {
	NodeCount        int
	Runs             int
	PromptTokens     int
	CompletionTokens int
	Cost             float64
	SurpriseSamples  int
	SurpriseTokens   int
	ExpectedTokens   int
	Surprise         *float64
}

JobUsage is one top-level job's full subtree size and measured spend. NodeCount is graph structure; Runs is the number of recorded executions, which may exceed NodeCount when a node is attempted more than once.

type LastCall

type LastCall struct {
	Model string
	At    time.Time
}

LastCall is one model call as the journal remembers it: which model served it and when its usage row landed. It is what a watcher with nothing else to go on can say about a silence.

type LeafExhausted

type LeafExhausted struct {
	// Attempt is which try this was within the claim, counted from one.
	Attempt int `json:"attempt"`
	// Bound names what ran out in the executor's own vocabulary — the
	// exec.StopReason, so "deadline", "turn-cap", "budget", "overrun" or
	// "tool-timeouts". It is carried verbatim rather than reworded because the
	// words a person reads are composed at the surface and the record keeps the
	// fact.
	Bound string `json:"bound"`
	// Allowed is the room it was given, spelled as the surface granted it
	// ("15m0s", "200 turns"). Empty when the surface did not say.
	Allowed string `json:"allowed,omitempty"`
	// Turns is how many turns it had taken when it stopped.
	Turns int `json:"turns,omitempty"`
	// Meter, Reached, Allowance and Unit are the bound that actually fired,
	// named, with its own two numbers.
	//
	// Bound above is the executor's StopReason, and three different ceilings
	// used to share one of those: a leaf could be landed by its cost grant, by
	// an undiscounted ceiling three times that grant, or by a cumulative bound
	// on prompt sent, and every one of them journaled "budget". So the record
	// said "it ran out of its tokens" and Allowed printed the grant — which in
	// the ink run of 2026-08-29 was 150,000 against three leaves landed at
	// 240,000 by a different meter, and no reading of the store could tell.
	//
	// Empty on an attempt whose executor does not name its bounds, which reads
	// as "not said" rather than as a bound called "".
	Meter     string `json:"meter,omitempty"`
	Reached   int    `json:"reached,omitempty"`
	Allowance int    `json:"allowance,omitempty"`
	Unit      string `json:"unit,omitempty"`
	// Reason is the one sentence a person is shown.
	Reason string `json:"reason"`
}

LeafExhausted is one attempt that ran out of room, as a reader needs it.

type LeafMode

type LeafMode struct {
	Mode string `json:"mode"`
	// Deps is how many settled results fed this node.
	Deps int `json:"deps,omitempty"`
	// Pushed is how many bytes of them went into the prompt, and Handles how
	// many of them were too large for it and travelled as a path instead. A
	// single handle is enough to disqualify a fold: a node told to assemble
	// material it holds only a pointer to has to go and get it.
	Pushed  int `json:"pushed,omitempty"`
	Handles int `json:"handles,omitempty"`
	// Turns and Tokens are the grant this decision bought.
	Turns  int `json:"turns,omitempty"`
	Tokens int `json:"tokens,omitempty"`
}

LeafMode is one dispatch decision and the measurements behind it.

type LeafResumed

type LeafResumed struct {
	// Turns is how many recorded turns the seed carries. Zero never reaches the
	// journal: a claim that resumed from nothing did not resume.
	Turns int `json:"turns"`
	// Files are the paths the earlier attempts were SEEN to change — the
	// workspace's own before-and-after reading, not the worker's claim about it
	// (FAILSAFE.md rule 2). Bounded by the caller.
	Files []string `json:"files,omitempty"`
}

LeafResumed is what a fresh claim was handed from the record of the attempts before it.

type LeafSelfClose

type LeafSelfClose struct {
	// Kinds names the findings the leaf raised against itself, in this
	// program's own vocabulary: "lost public names", "unbound names",
	// "its own checks", "checks it turned red".
	Kinds []string `json:"kinds"`
	// Names is a bounded sample of what the findings are ABOUT. A kind alone
	// sends a reader to run a suite; the name is the whole diagnosis, and it
	// was readable off the tree for nothing.
	Names []string `json:"names,omitempty"`
	// Turns is how many turns the leaf had taken when it read its own work. It
	// is the turns USED and not the turns a close was granted: the room a close
	// may spend is whatever the leaf has left of its own meter, so subtracting
	// this row from the leaf's final turn count is what says how much one cost.
	Turns int `json:"turns,omitempty"`
	// Closed says the leaf was actually held back and asked. False is the floor
	// arm and is journaled just as loudly: the finding stands, the leaf lands
	// with it, and the gate weighs it exactly as it did before — because the
	// leaf had already closed this kind once, or because its meter was spent.
	Closed bool `json:"closed"`
	// Why is the one sentence saying which of those it was, for a person and
	// for an autopsy. Empty on the arm that closed.
	Why string `json:"why,omitempty"`
}

LeafSelfClose is one leaf's own closing reading, and what was done about it.

type LeafStopped

type LeafStopped struct {
	// Token is the claim this worker held. It is the identity that matters: a
	// node id alone cannot say WHICH of a node's workers stopped, and telling
	// them apart is the entire reason this row exists.
	Token uint64 `json:"token"`
	// Reason is why it was asked to stop, carried from the sweep that asked.
	Reason string `json:"reason,omitempty"`
}

LeafStopped is one worker reporting that it has stopped, and why it was asked to.

type Memory

type Memory struct {
	ID     string
	Type   string
	Scope  string
	Title  string
	Text   string
	Tags   []string
	Status string
	// UseCount is how often this memory HELPED, and MissCount is how often it
	// was put in front of a model and bore on nothing.
	//
	// THE COUNTER MEASURES HELP, NOT INJECTION. It used to be incremented for
	// every id the router named, which credited a memory for being retrieved
	// rather than for being worth retrieving — RoMeRL (arXiv 2608.02508) names
	// that the "memory-reward trap": when several memories are co-retrieved,
	// all of them receive credit. So the two counters are written together,
	// from one confirmation after the turn, and they are the same bargain
	// internal/session's fixstore.go already keeps for a suggested fix: a
	// patch that was offered and then failed is counted AGAINST itself, or the
	// store would rank a line that has never once mattered at the top of its
	// own ranking forever.
	//
	// Neither is journaled per write, for the reason [EventMemoryRanking]
	// states; a snapshot on an interval is what carries them through a Rebuild.
	UseCount  int
	MissCount int
	// UpdatedAt is when the event that last touched this memory was journaled —
	// transaction time, resolved from updated_seq inside the same statement
	// that reads the row rather than by a second read per row.
	//
	// It is what lets a reader SHOW a memory's age. A model cannot judge
	// staleness it cannot see, and LongMemEval (ICLR 2025) measures time-aware
	// expansion as the single largest category lever it ablated (+11.3%
	// recall). Zero is unknown provenance — an old row whose event predates the
	// column — and renders as nothing.
	UpdatedAt     time.Time
	CreatedSeq    int64
	UpdatedSeq    int64
	SourceSession string
	SourceSeq     int64
}

Memory is one durable thing known across sessions.

type MemoryShelf

type MemoryShelf struct {
	// Scope is `user`, `project` or `env` — the raw word, for a caller that
	// filters on it. [MemoryShelfWord] is what a person reads.
	Scope string
	// Label is the shelf's heading in words a person uses.
	Label string
	// Memories are this shelf's rows, NEWEST TOUCHED FIRST, and they are a
	// SAMPLE where the snapshot's limit bit: the counts below are over the whole
	// shelf and this list may be shorter than any of them.
	Memories []Memory
	// Held, LetGo and Superseded are this shelf's whole population by status —
	// `active`, `forgotten` and `superseded` in the words screen 2d uses. Every
	// memory on the shelf is in exactly one of the three.
	Held       int
	LetGo      int
	Superseded int
	// ByType counts every memory on the shelf by its kind — `fact`,
	// `preference`, `decision`, `correction`, `project_state` — whatever its
	// status, so a section line can say what a shelf is MADE of. A kind nobody
	// has used is absent rather than zero.
	ByType map[string]int
}

MemoryShelf is one scope's worth of what is remembered.

THE SHELVES ARE A CLOSED THREE AND CANNOT BE MORE. `scope` on a memory is an enum of exactly `user`, `project` and `env`, enforced on the way in — so a page drawing "86 shelves" would be drawing the OTHER product's fact table, where scopes are free-form strings. Three is the number, and it is worth a page saying so plainly rather than implying an open list.

THERE IS NO PROJECT DIRECTORY ON A PROJECT MEMORY, and a shelf headed `project:/some/path` cannot be built from this table. The row carries the word `project` and nothing else: no workspace column, and its source session's row carries no workspace either. Which project a project-scoped memory belongs to is a fact this store has never kept — see MemoryShelf.Scope.

type MemoryShelves

type MemoryShelves struct {
	// Shelves are in the order `user`, `project`, `env`, and a shelf with
	// nothing on it is NOT here — an empty shelf is not a shelf. The three
	// scopes are a closed enum, so a page that wants to name a missing one can.
	Shelves []MemoryShelf
	// The machine's totals, by the same three statuses.
	Held       int
	LetGo      int
	Superseded int
	// Shown is how many rows the shelves actually carry, and Total is how many
	// exist. Shown < Total is the snapshot's limit biting, and a page quoting a
	// figure off the rows rather than off the counts has to know.
	Shown int
	Total int
}

MemoryShelves is the whole snapshot: the shelves in a fixed order, and the machine's own totals beside them.

type MemoryStub

type MemoryStub struct{ ID, Title, Type, Scope string }

MemoryStub is one line of the router's shortlist: enough to decide whether a memory bears on the moment, and nothing more. The full text is a second call away on purpose — the shortlist is read every turn and the bodies are not.

type Message

type Message struct {
	Seq         int64
	Time        time.Time
	SessionID   string
	Role        Role
	Body        string
	Attachments []string
	// Model is chat-lane metadata. On a user message it requests the model for
	// that one conversational turn; on an agent message it records the model
	// that actually produced the reply. Empty preserves the ordinary talk lane.
	Model string
	// NodeID optionally anchors the message to a graph node (a fold
	// announcement, an ask, a completion report).
	NodeID string
	// CommandSeq optionally links the message to the command it acknowledges
	// or reports on.
	CommandSeq int64
	// QuestionSeq links an agent ask or the user's answer to the durable
	// agent-question lifecycle it belongs to. It is separate from Options:
	// free-text questions need the same unambiguous answer routing.
	QuestionSeq int64
	// Answers is the newest user turn this line answers, and it exists because
	// one reply is no longer one message. A run of messages typed in one breath
	// is folded into a single turn and answered once, so a surface counting what
	// it is still owed cannot read that count off the replies alone: it would
	// wait forever for answers that were never going to come separately. Zero
	// everywhere except the head's own replies, where it is the seq of the last
	// user row the turn covered.
	Answers int64
	// Options is the ordered set of selectable answers for an askback.
	// Nil means the question accepts free text only.
	Options []QuestionOption
	// Brief is non-nil only for the resident's folded arrival summary.
	Brief *Brief
	// Progress is non-nil only for a replaceable compile-progress post. The
	// body remains a readable journal line; these fields let surfaces present
	// the current phase and real generated titles without parsing prose.
	Progress *MessageProgress
	// Parts is the ordered list of typed blocks this message carries — see
	// message_parts.go. Nil is a legacy prose message and is what almost every
	// message in a real database is; Body remains the whole rendered line
	// either way, so a surface that has never heard of parts renders exactly
	// what it rendered before.
	Parts []MessagePart
}

Message is one materialized thread entry. Seq is the journal sequence, so message order is total and shared with every other event in the store.

type MessageHit

type MessageHit struct {
	// Complete is true only when the reader returned the entire indexed body.
	// Older excerpt-only readers leave it false.
	Complete  bool
	Seq       int64
	SessionID string
	Role      Role
	Body      string
	Time      time.Time
	Age       string
}

MessageHit is one remembered line of conversation with enough around it to be quoted honestly: who said it, when, and in which thread.

type MessagePart

type MessagePart struct {
	Kind     PartKind
	Text     string
	Question *QuestionPart
	Card     *CardPart
	Progress *ProgressPart
	Artifact *ArtifactPart
	Ended    *EndedPart
	Aside    *AsidePart
	// contains filtered or unexported fields
}

MessagePart is one typed block. Exactly one payload field is meaningful, and which one is decided by Kind; a part of an unrecognized kind keeps its original bytes and re-emits them unchanged.

func ArtifactRef

func ArtifactRef(artifact ArtifactPart) MessagePart

ArtifactRef points one part at a deliverable on disk.

func AsideRef

func AsideRef(aside AsidePart) MessagePart

AsideRef carries one side-channel exchange under its collapsed line.

func CardRef

func CardRef(nodeID string) MessagePart

CardRef points one part at a graph node.

func EndedMark

func EndedMark(ended EndedPart) MessagePart

EndedMark carries how the turn ended.

func PartsForQuestion

func PartsForQuestion(question AgentQuestion) []MessagePart

PartsForQuestion is the durable question row rendered as blocks. It is what the surfacing path attaches to the message it posts, so that EVERY producer of a durable question — this package's callers, the resident, the compiler, a worker — emits the same contract without any of them knowing it exists.

Everything it says comes off the row or off the body the row already holds. Nothing is invented, and nothing is copied that the message already carries: the options ride the message's own typed column, exactly as they always have.

func ProgressRef

func ProgressRef(progress ProgressPart) MessagePart

ProgressRef carries one structured progress block.

func QuestionBlock

func QuestionBlock(question QuestionPart) MessagePart

QuestionBlock is the full render contract for one ask. It exists beside QuestionRef rather than replacing it because the two say different things: a ref names a lifecycle row and leaves the drawing to whoever finds it, and a block is the ask as it should appear, whether or not a lifecycle row exists.

func QuestionParts

func QuestionParts(prompt string, question QuestionPart) []MessagePart

QuestionParts is the render contract for one ask: the prompt as prose, and the ask as types. It is the ONLY constructor callers should use, so that "which blocks does a question message carry" has one answer rather than one per producer.

A prompt that is empty produces no text part rather than an empty one — the part list stays a description of what is actually there.

func QuestionRef

func QuestionRef(seq int64) MessagePart

QuestionRef points one part at a durable question by sequence. It carries the conservative class explicitly rather than by omission, so the value a reader gets from the constructor is the value the normalizer would have given it.

func RoomSwitchRef

func RoomSwitchRef(sessionID string) MessagePart

RoomSwitchRef points the conversation at another room by id.

func TextPart

func TextPart(text string) MessagePart

TextPart, QuestionRef, CardRef, ArtifactRef and EndedMark are the constructors. They exist so a caller never has to remember which payload field pairs with which kind, which is the one way to build an invalid part.

func (MessagePart) MarshalJSON

func (p MessagePart) MarshalJSON() ([]byte, error)

MarshalJSON writes the envelope for a known kind and the original bytes for an unknown one.

func (*MessagePart) UnmarshalJSON

func (p *MessagePart) UnmarshalJSON(data []byte) error

UnmarshalJSON reads a known kind into its typed payload and keeps an unknown one whole.

type MessageProgress

type MessageProgress struct {
	Phase  string `json:"phase"`
	Done   int    `json:"done"`
	Total  int    `json:"total"`
	Latest string `json:"latest"`
}

MessageProgress is the durable, user-facing shape of compile progress.

type ModelRebinding

type ModelRebinding struct {
	Root    string
	Model   string
	Nodes   []string
	Running int
}

ModelRebinding is what one subtree rebinding actually moved. Running is counted separately because it is the half the person has to be told about: those steps finish where they started, and a receipt that implies otherwise promises an immediacy the design deliberately refuses.

type ModelRole

type ModelRole string

ModelRole is one of the five named slots. It is a distinct type from the conversation's Role because they are different words for different things: one names who spoke, this one names what a call is for.

const (
	// RoleOrchestrate is the voice: head turns and task-orchestrator turns.
	RoleOrchestrate ModelRole = "orchestrate"
	// RolePlan is the architect: compiling, replanning, revising the graph.
	RolePlan ModelRole = "plan"
	// RoleWork is the hands: worker and executor turns.
	RoleWork ModelRole = "work"
	// RoleVerify is the skeptic: gates, judges, verify-then-escalate probes.
	RoleVerify ModelRole = "verify"
	// RoleScribe is the clerk: labels, titles, folds, briefs, sentinels — the
	// one-sentence-out jobs an ultra-cheap model does indistinguishably well.
	RoleScribe ModelRole = "scribe"
)

func ModelRoles

func ModelRoles() []ModelRole

ModelRoles lists the five in ladder order — the order the settings surface shows them in, and the order this doc names them. It is a fresh slice every call because a caller sorting the ladder must not resort the ladder.

func ParseModelRole

func ParseModelRole(text string) (ModelRole, error)

ParseModelRole turns a typed or journaled word into a role. It trims and lowercases because the word arrives from a palette, a flag, and a JSON payload, and refuses everything else with ErrInvalid — never a panic, and never a silent promotion to some default role.

func (ModelRole) Valid

func (role ModelRole) Valid() bool

Valid is a closed list and stays one. An unrecognized role is refused rather than stored, for the same reason an unrecognized issuer is: a typo that gets written becomes a binding nobody can find and nobody can clear.

func (ModelRole) Word

func (role ModelRole) Word() string

Word is the role's word in the product's language — what the chip says when it is not saying a model name. The words are the doc's (5.23) and not a second vocabulary invented here.

type NamedTrait

type NamedTrait struct {
	Name        string
	Measurement TraitMeasurement
}

NamedTrait is one pure journal projection ready to persist as a singleton fact.

type Need

type Need struct {
	NodeID string   `json:"node_id"`
	Kind   EdgeKind `json:"kind"`
}

Need is one incoming edge named by a node specification.

type Node

type Node struct {
	ID     string
	Parent string
	Brief  string
	Title  string
	Group  string
	// Subharness is the settled answer to "what runs this leaf": the node's own
	// choice where it made one, the splice's otherwise. It is resolved once, at
	// admission, so every dispatch path reads one field and cannot disagree
	// with another about which worker a node was promised.
	Subharness string
	// Ran is the worker that actually executed this node, written by the
	// dispatch path at the moment it builds the executor and again whenever an
	// escalation builds a different one. Subharness above is what the node was
	// ASKED to run on and is empty wherever nobody answered; this is what ran,
	// and it is never empty for a node that ran — the generalist says "linear"
	// out loud rather than leaving a blank that four other things also mean.
	Ran string
	// Spec is the planner's task object as it was admitted, journal-derived
	// like every other field on this view. Readers that do not know what a spec
	// is pass it along; the one that does decodes it.
	Spec       json.RawMessage
	Stage      int
	Status     Status
	Owner      string
	ClaimToken uint64
	Attempt    uint64
	Summary    string
	Error      string
	// Held and CancelRequested are journal-derived scheduling controls. They
	// intentionally do not add presentation-only statuses to the graph.
	Held            bool
	CancelRequested bool
	Priority        int

	Provenance   Provenance
	CreatedSeq   int64
	CreatedOrder int
	UpdatedSeq   int64
	StartedAt    time.Time
	FinishedAt   time.Time

	// Folded marks historical nodes replaced in the active view. FoldRoot is
	// the compact representative that remains visible in place of its subtree.
	Folded       bool
	FoldRoot     bool
	FoldDigest   string
	FoldPointers []string
}

Node is the durable scheduling view of one graph node.

type NodeBrief

type NodeBrief struct {
	Node      int    `json:"node"`
	Brief     string `json:"brief"`
	Criterion string `json:"criterion"`
	// Fault names why the model did not write this brief, on the nodes where it
	// did not. The brief beside it is then composed from what the plan already
	// knew about the node rather than absent, so the only way an autopsy can
	// tell a written instruction from a composed one is this field — and
	// without it a plan that quietly briefed itself reads exactly like a plan
	// every call answered. Empty is the ordinary case.
	Fault      string `json:"fault,omitempty"`
	Subharness string `json:"subharness,omitempty"`
	// Skills is the ordered list of skill names attached to this node.
	// Pinned skills (named by the person) come first, followed by retrieval
	// candidates. Order is precedence: earlier-listed skills win conflicts.
	Skills []string `json:"skills,omitempty"`
}

NodeBrief is one node's brief as it was rendered for the agent that runs it. Node is the plan node id; the event's node_id column carries the store spelling of the same node under its job's prefix (the bare prefix for the deliverable sink, "<prefix>-n<id>" otherwise). Criterion is the rendered sufficiency sentence (Spec.Done), the one statement a reader holding only the result can test.

type NodeControl

type NodeControl struct {
	CancelRequested bool
	Held            bool
}

NodeControl is the scheduler-visible part of conversational surgery. Cancel wins over Hold when both are present: a worker must relinquish its claim permanently rather than merely parking work the user withdrew.

type NodeReceipt

type NodeReceipt struct {
	NodeID string
	// Parent is the node's own parent, which may point outside the subtree when
	// the receipt is the root's. It is carried because a tree is drawn from it
	// and re-reading the node to learn it would defeat the single query.
	Parent string
	Status Status
	// Folded says this node is history in the active view. It is reported rather
	// than filtered: see the second law above.
	Folded bool

	// Runs is how many usage rows name this node. It is the presence bit —
	// see Billed — and not decoration.
	Runs             int
	Cost             float64
	PromptTokens     int
	CompletionTokens int
	CachedTokens     int
	// LastBilled is the newest usage row against this node, or the zero time
	// when there is none. It is the journal's own stamp, so two surfaces asking
	// the same question agree about when the money moved.
	LastBilled time.Time

	StartedAt  time.Time
	FinishedAt time.Time
}

NodeReceipt is one node's own line: what it cost, when it ran, and what became of it.

COST-SO-FAR IS PARTIAL, AND THIS IS WHERE THAT IS WRITTEN DOWN. A leaf's own tool loop is journaled ONCE, on the way out of the run — resident's recordSpend bills settled, refused and failed from one place, deliberately, because the three endings differ in what happens to the node and not at all in what was paid. So a leaf that is still running usually carries no usage row of its own and reports Billed false: not zero, not an estimate, absent. What a live node CAN carry is money spent against it by somebody else — a judge, a sentinel, a revision pass, all of which bill the node they are about through pool.WithSpendNode — and the runs of an earlier attempt, which stay on the node across a retry. Those are real and they are shown. A running node's figure is therefore a floor and never a forecast, and the way to make it a live total is to make the executor journal as it goes, not to make this read guess.

func (NodeReceipt) Billed

func (receipt NodeReceipt) Billed() bool

Billed reports whether the journal has a single run to show for this node. False means nothing was measured here — drawn as — — while true with a zero Cost means a run that genuinely cost nothing, which is $0.00 and a different sentence. It is RoomSpend.Recorded for one node.

func (NodeReceipt) Elapsed

func (receipt NodeReceipt) Elapsed(now time.Time) (time.Duration, bool)

Elapsed is how long this node has been at it, and whether that can be said at all. Work that never started has no clock — absence, not a zero duration — and work still running is measured against now, which is why the caller hands its own clock in rather than this package reading one.

func (NodeReceipt) Open

func (receipt NodeReceipt) Open() bool

Open reports work that started and has not stopped: the node holds a start stamp, no finish stamp, and no terminal status. A node that ended without a finish stamp — old history, a store written before the column meant anything — is NOT open, because a clock that would run forever is worse than no clock.

type NodeSpec

type NodeSpec struct {
	ID     string `json:"id"`
	Parent string `json:"parent,omitempty"`
	Brief  string `json:"brief"`
	Stage  int    `json:"stage"`
	Needs  []Need `json:"needs,omitempty"`

	// Title is a few-word display name for surfaces that cannot afford the
	// brief; empty is valid and means "derive from the brief".
	Title string `json:"title,omitempty"`

	// Group names the planning container this node expanded out of. It is
	// provenance for display — execution reads only Parent and Needs.
	Group string `json:"group,omitempty"`

	// Subharness names the worker this one node was sized for. There is one
	// worker, so a node written by this build carries "linear" or nothing;
	// only an empty name — nobody wrote the column — inherits the splice's own
	// choice. Both facts are kept because a graph written by a build that had
	// more than one worker still has to read back what it recorded, and
	// "nobody wrote this" is not the same fact as "this says linear".
	Subharness string `json:"subharness,omitempty"`

	// Spec is the planner's task object for this node, carried as opaque bytes.
	//
	// The store learns nothing about what a spec is, for the same reason it
	// learns nothing about what a plan is: the planner is a consumer of the
	// store, and decoding its object here would make the plan package a
	// dependency of the journal. What the store guarantees is that the bytes
	// arrive, land on the node, and come back out unchanged — which is all a
	// retry needs to inherit a criterion instead of inventing one.
	//
	// Empty is legal and is what every node admitted before this field existed
	// carries. Brief remains the read; this is the object beside it.
	Spec json.RawMessage `json:"spec,omitempty"`
}

NodeSpec is one node to admit. Exactly one node in a Subtree has an empty Parent; Splice attaches that node to the parent argument. Every other Parent names another node in the same subtree.

type NodeSurprise

type NodeSurprise struct {
	NodeID         string  `json:"node_id"`
	ActualTokens   int     `json:"actual_tokens"`
	ExpectedTokens int     `json:"expected_tokens"`
	Surprise       float64 `json:"surprise"`
}

NodeSurprise is the prediction attached to one leaf when its profile record lands. ActualTokens is repeated here so job prediction comparisons exclude leaves whose expectation was undefined.

func (NodeSurprise) OutOfEnvelope

func (n NodeSurprise) OutOfEnvelope() bool

OutOfEnvelope reports whether this residual is large enough to be evidence rather than noise. An undefined expectation is never out of envelope: a node with nothing to be surprised against has not surprised anyone.

type NodeUsage

type NodeUsage struct {
	NodeID           string  `json:"node_id"`
	PromptTokens     int     `json:"prompt_tokens"`
	CompletionTokens int     `json:"completion_tokens"`
	CachedTokens     int     `json:"cached_tokens,omitempty"`
	Cost             float64 `json:"cost"`
	Model            string  `json:"model,omitempty"`
}

NodeUsage is what one node's execution spent.

Model is the model that actually served the call, which is not the model anybody asked for: an escalation moves a leaf to a stronger rung, a cascade picks by class, and the only durable record of who did the work used to be Provenance.WorkModel — the pin the user requested, empty on almost every job. So "which model wrote this?" was unanswerable from every surface. It is recorded here rather than on the node because a node can run more than once and each run has its own answer, and because the row that carries the money is the row that should carry the name.

CachedTokens is the part of PromptTokens the provider billed at the cached rate. It was computed in three places and persisted in none, which is not a missing nicety: it is the reason a whole class of defect went unnoticed. The harness spends real effort on cache shape — a byte-stable prefix, decay that fires in batches so most turns leave the transcript untouched, a tool block that never moves — and a run key that was never set produces exactly the same journal as a run whose prefix was perfect. The number that separates them is this one, and until it was written down nobody could tell the two apart.

type Origin

type Origin string

Origin says who introduced a subtree onto the spine.

const (
	OriginUser    Origin = "user"
	OriginTrigger Origin = "trigger"
	OriginSelf    Origin = "self"
)

type OverrunEvidence

type OverrunEvidence struct {
	Seq int64 `json:"-"`
	// NodeID is the leaf this is about.
	NodeID string `json:"-"`
	// Spent is what the leaf had cost when the comparison was made, and Turns is
	// how many rounds it took to spend it.
	Spent int `json:"spent"`
	Turns int `json:"turns,omitempty"`
	// Anchor is the measured median, Threshold the point that was crossed,
	// Multiple how many anchors that is, and Samples how many measured leaves
	// the pair was derived from.
	Anchor    int     `json:"anchor"`
	Threshold int     `json:"threshold"`
	Multiple  float64 `json:"multiple,omitempty"`
	Samples   int     `json:"samples,omitempty"`
	// Verdict is what was decided, in whatever words the deciding party used.
	Verdict string `json:"verdict,omitempty"`
}

OverrunEvidence is one straggler, recorded as the comparison that found it rather than as a conclusion drawn from it.

Nothing writes this any more — the mechanism that compared a running leaf against what leaves of its kind cost was retired — but the records it left are on disk, and this is the shape they decode into. Both sides of the comparison are here on purpose. "This leaf spent 150,000 tokens" is not evidence of anything; it is evidence once it sits beside the 4,000 its siblings spent and the number of runs that median came from.

type ParameterChange

type ParameterChange struct {
	Name      string            `json:"name"`
	Old       float64           `json:"old"`
	New       float64           `json:"new"`
	Evidence  ParameterEvidence `json:"evidence"`
	Direction string            `json:"direction"`
	Phrase    string            `json:"phrase"`
	Seq       int64             `json:"-"`
}

ParameterChange is one bounded, journaled dial movement.

type ParameterEvidence

type ParameterEvidence struct {
	Reversals int     `json:"reversals"`
	Total     int     `json:"total"`
	Rate      float64 `json:"rate"`
}

ParameterEvidence is attached to every parameter_changed journal event.

type PartKind

type PartKind string

PartKind names one typed block in a message's ordered parts list. The set is open on purpose: a part whose kind this build does not recognize is carried through reads, writes and rebuilds byte for byte rather than dropped, so an older reader cannot silently erase a newer writer's record.

const (
	// PartText is readable prose. The message body remains the whole rendered
	// line for every surface that has not learned parts; a text part is that
	// same prose addressable as a block.
	PartText PartKind = "text"
	// PartQuestion refers to the durable agent-question lifecycle by sequence,
	// which is the same number Message.QuestionSeq carries. The options live on
	// the question, not in the body.
	PartQuestion PartKind = "question"
	// PartCard refers to a graph node the message is about — the work surface's
	// unit, named rather than described.
	PartCard PartKind = "card"
	// PartProgress is replaceable structured progress: the same shape the
	// progress column already carries, addressable per block.
	PartProgress PartKind = "progress"
	// PartArtifact refers to a deliverable on disk. It never carries the bytes.
	PartArtifact PartKind = "artifact"
	// PartEnded says how the turn that produced this message ended.
	PartEnded PartKind = "ended"
	// PartRoomSwitch says the conversation continues in another room, and names
	// it. It is the one cross-seam contract of the chats layer (the August 2026
	// chat-simplification audit, no longer in the tree, 5.4): when a thread splits,
	// the engine journals this part on a row in the
	// OLD room and the surface applies it on its ordinary poll — composer and
	// view re-point, and the head simply serves the new room. The coupling is
	// journal-only on purpose. An in-process channel between the answer gate and
	// the window would be a second seam, unreadable after the fact and absent
	// entirely on a rebuild; a typed part is a fact both halves can read, and a
	// surface that has never heard of it renders the row's prose and is merely
	// out of date rather than wrong.
	//
	// Text is the new room's session id and nothing else. No title rides here:
	// the scribe names the new room on its ordinary post-turn lane, moments
	// later, and a name copied onto this part would be a second truth that is
	// stale before it is read.
	PartRoomSwitch PartKind = "room-switch"
	// PartAside is a side-channel exchange, kept whole and shown collapsed.
	//
	// 8.2.9's law is that statements are durable and questions may be ephemeral:
	// a curiosity question about running work is asked and answered without
	// taking a turn's worth of the orchestrator's context. "Ephemeral" there
	// means ephemeral to the MODEL's context, never to the record — journal-is-
	// truth and 5.20's no-dead-air rule both still hold — so the exchange lands
	// as one collapsed row that can be opened, referred back to, and searched.
	// The body is the collapsed line; this part is what opening it shows.
	PartAside PartKind = "aside"
)

type PlanGraph

type PlanGraph struct {
	Root  string          `json:"root"`
	Model string          `json:"model,omitempty"`
	Graph json.RawMessage `json:"graph"`
}

PlanGraph is one job's structure as the planner wrote it, plus the two facts execution needs to use it again: which node's landing means the job is over, and which model its leaves were sized for.

type PollWatch

type PollWatch struct {
	Condition string        `json:"condition"`
	Cadence   time.Duration `json:"cadence"`
}

PollWatch asks the sentinel to inspect a broad external condition on a fixed cadence. Condition is kept verbatim for the sentinel prompt.

type ProgressPart

type ProgressPart struct {
	NodeID string `json:"node_id,omitempty"`
	Phase  string `json:"phase"`
	Done   int    `json:"done,omitempty"`
	Total  int    `json:"total,omitempty"`
	Latest string `json:"latest,omitempty"`
}

ProgressPart is one replaceable progress block. NodeID is optional: compile progress belongs to a pending splice that has no node yet.

type ProposalAppetiteValue

type ProposalAppetiteValue struct {
	Acceptance float64 `json:"acceptance"`
}

ProposalAppetiteValue is the accepted share of journaled standing proposals.

type Provenance

type Provenance struct {
	Origin    Origin `json:"origin"`
	SessionID string `json:"session_id,omitempty"`
	Intent    string `json:"intent"`
	// CharterID points work back to the standing responsibility whose firing or
	// self-maintenance inquiry admitted it. It is empty for ordinary user work.
	CharterID string `json:"charter_id,omitempty"`
	// Attachments are user-supplied image paths kept separate from visible
	// intent text so every leaf can receive them as multimodal content.
	Attachments []string `json:"attachments,omitempty"`
	// TrialOf is the fact sequence of the unsettled pair this subtree tests.
	// Zero means the splice is ordinary work.
	TrialOf int64 `json:"trial_of,omitempty"`
	// RetryOf links a freshly spliced retry to the failed/cancelled node it
	// supersedes. The predecessor stays immutable and fully inspectable.
	RetryOf string `json:"retry_of,omitempty"`
	// ServiceIntent records the compiler's deterministic recognition that the
	// user asked for a running thing. It is consent provenance, not a display
	// hint, and therefore travels through the splice event and Rebuild.
	ServiceIntent bool `json:"service_intent,omitempty"`
	// WorkModel is the model the user named for this job in their own words
	// ("with the better model", "use gemini"). Empty means the surface's
	// current work model serves, as always. It is provenance rather than
	// configuration: the leaf that ran is inseparable from the model asked for.
	WorkModel string `json:"work_model,omitempty"`
	// PlanModel is the model that actually structured this job, recorded only
	// when it was not the model the job's work runs on. Empty — which is nearly
	// every job — means the plan slot followed the work slot, the default the
	// whole product is built around, and a surface that shows it says nothing.
	// It is provenance for the same reason WorkModel is: a graph's shape is
	// inseparable from the model that drew it, and a slot moved an hour later
	// must not be able to rewrite the answer to "who planned this".
	PlanModel string `json:"plan_model,omitempty"`
	// RunModel is the model this job's leaves were handed to work on, recorded
	// only in the same breath as PlanModel — when the plan slot split from the
	// work slot. It is what makes "planned by <model>" legible instead of
	// alarming: a reader who is told who structured the job and never told who
	// worked it concludes the wrong thing about both. It is deliberately not
	// WorkModel: "the model you named" and "the model the work ran on" are two
	// different claims, and only one of them is ever the user's.
	RunModel string `json:"run_model,omitempty"`
	// Craft names the learned workflow this subtree compiled from, as
	// "name@commit". Empty is ordinary planned work. Every node of a craft run
	// carries it: survival is measured per workflow version, so the version a
	// leaf actually ran under must be as durable as the leaf itself.
	Craft string `json:"craft,omitempty"`
	// Subharness names the worker chosen for this whole subtree by a build that
	// had more than one to choose from. NOTHING WRITES IT: it is kept so that a
	// graph written by such a build still replays and still reads back what it
	// recorded, which is the same reason the hand-over event above is kept.
	Subharness string `json:"subharness,omitempty"`
}

Provenance is stamped onto every node admitted by one splice. Intent is deliberately stored verbatim: later planning and folding may interpret it, but the store never rewrites what was asked.

type QuestionCategory

type QuestionCategory string

QuestionCategory is the stable class used by the empirical ask gate.

const (
	QuestionCategoryCharterRatification QuestionCategory = "charter-ratification"
	QuestionCategorySurgeryConfirm      QuestionCategory = "surgery-confirm"
	QuestionCategoryCompileAssumption   QuestionCategory = "compile-assumption"
	QuestionCategoryRailRaise           QuestionCategory = "rail-raise"
	QuestionCategoryCharterCadence      QuestionCategory = "charter-cadence"
	// QuestionCategoryServiceConsent is the promotion boundary: keeping a
	// process alive past its task is consent-bearing, so it is measured like
	// every other ask but never gated away.
	QuestionCategoryServiceConsent QuestionCategory = "service-consent"
	// QuestionCategoryServiceHygiene is the long-running nudge, which is an
	// ordinary VOI-gated ask: if the user always keeps them, stop nagging.
	QuestionCategoryServiceHygiene QuestionCategory = "service-hygiene"
	// QuestionCategoryStandingHygiene is the same nudge pointed at a watch
	// rather than a process. It is its own category because the two are
	// answered differently — a service is nearly always still wanted, a watch
	// that has found nothing for a fortnight often is not — and one shared
	// category would let each teach the gate the wrong thing about the other.
	QuestionCategoryStandingHygiene QuestionCategory = "standing-hygiene"
	// QuestionCategoryRedirectTarget is "did you mean the running job, or is
	// this new work?" — reversible either way, so the meta loop is free to
	// learn that the top-ranked job is simply always what was meant.
	QuestionCategoryRedirectTarget QuestionCategory = "redirect-target"
	// QuestionCategoryTaste is "or keep it the way I just did it?" — the one
	// question a delivery is allowed to carry. It is reversible and never holds
	// anything up, so the meta loop is free to learn that this user simply keeps
	// what they are given, and stop asking.
	QuestionCategoryTaste QuestionCategory = "taste"
	// QuestionCategoryScope is "the quick look now, or the proper job?" — the one
	// boundary the head genuinely cannot always read off the words. Nothing about
	// it is consent-bearing: both answers are things the person asked for, and
	// the wrong one costs a redo rather than a loss, so it is an ordinary
	// VOI-gated ask. A person who always wants the proper job stops being asked
	// for it, which is the whole point of asking in the first place.
	QuestionCategoryScope QuestionCategory = "scope"
	// QuestionCategoryThreadSplit is "shall I take that as its own thread?" —
	// the offer the head makes when a conversation pivots to something genuinely
	// new. Like scope it is a boundary the words alone do not always settle, and
	// like scope nothing about it is consent-bearing: both answers are places to
	// keep talking, and the wrong one costs a switch rather than a loss. So it is
	// an ordinary VOI-gated ask, and a person who always says yes stops being
	// asked and simply gets the new thread with one clause said.
	QuestionCategoryThreadSplit QuestionCategory = "split"
	QuestionCategoryGeneric     QuestionCategory = "generic"
)

type QuestionClass

type QuestionClass string

QuestionClass separates a question that needs a human's consent from one that merely informs — the axis that will later gate which questions an orchestrator may answer on its own. The conservative default is law: nothing constructs a question this package will read back as QuestionInformational unless a producer explicitly says so. An unlabeled question is a consent question, everywhere — the zero value, the schema default, and every read path agree on that, so silence never widens autonomy.

const (
	QuestionConsent       QuestionClass = "consent"
	QuestionInformational QuestionClass = "informational"
)

type QuestionConfig

type QuestionConfig struct {
	Kind      QuestionKind
	Default   string
	Category  QuestionCategory
	AllowFree *bool
}

QuestionConfig selects the structured component spelling. The zero value is the existing choose question with free text enabled.

type QuestionKind

type QuestionKind string

QuestionMessageBody renders a selectable askback the way every surface can read it: the prompt in plain text for transcripts, followed by the structured JSON payload the TUI's question components parse. Options carry numeric keys, so a selection replies "N" and selects options[N-1] in every surface; the durable option rows on the message remain the continuation and validation source.

const (
	QuestionChoose  QuestionKind = "choose"
	QuestionConfirm QuestionKind = "confirm"
	QuestionText    QuestionKind = "text"
)

type QuestionOption

type QuestionOption struct {
	Label string `json:"label"`
	Value string `json:"value,omitempty"`
	Hint  string `json:"hint,omitempty"`
}

QuestionOption is one ordered, selectable answer carried beside an askback. Value is machine-facing continuation data; Label is the user's wording.

type QuestionPart

type QuestionPart struct {
	Seq int64 `json:"seq"`
	// Kind is how the question is drawn: a numbered list, an inline yes/no
	// strip, or a plain prompt. It was previously recoverable only by parsing
	// the body, which is why a confirm question and a choose question were
	// indistinguishable to anything that did not brace-scan.
	Kind QuestionKind `json:"kind,omitempty"`
	// Class is the consent axis (9.4). It rides on the part because the surface
	// that draws the question is the surface that must not offer to answer a
	// consent question on the person's behalf, and it should not have to open a
	// second table to find out which kind it is holding.
	Class QuestionClass `json:"class,omitempty"`
	// Category is the gate this question is asked under, which is what a
	// "don't ask me this again" affordance acts on.
	Category QuestionCategory `json:"category,omitempty"`
	// Default is the option key that stands if the person says nothing. It is a
	// key rather than a label because the label is the option's to change.
	Default string `json:"default,omitempty"`
	// AllowFree says whether an answer outside the options is accepted. It is
	// spelled positively and defaults to false, so a part written by a producer
	// that forgot the field offers the narrower affordance rather than the wider
	// one — the same direction Class defaults in, and for the same reason.
	AllowFree bool `json:"allow_free,omitempty"`
	// NodeID and CharterID are what the question is about, when it is about
	// something. Both are references; neither carries a title, a status or a
	// spend, because those are the referent's to answer.
	NodeID    string `json:"node_id,omitempty"`
	CharterID string `json:"charter_id,omitempty"`
}

QuestionPart is the ask, said in types instead of smuggled through prose.

Part 2.11's indictment lands here more sharply than anywhere else: a question existed in five places at once — a durable question row, a message row, a JSON blob inside that message's body, an options column beside it, and an FTS copy of the lot — and the surface that had to draw it recovered its components with a hand-rolled brace scanner over the body while the typed columns went unread. 13.3's first bug is that scanner's bill coming due: the moment a renderer drew the journal honestly, the smuggled JSON appeared on screen as an agent's own words.

So this part is the whole render contract, and the rule that keeps it from becoming a sixth place the same fact lives is CardPart's rule: it carries what nothing else carries, and REFERS to everything else.

  • The options are NOT here. They are Message.Options on the same row — already typed, already normalized by this package, already durable, and already the thing a reply of "3" is validated against. Copying them here would be a second truth that ages.
  • The prompt is NOT here. It is the message's text part, and the body.
  • What IS here is everything the body used to smuggle and nothing else records: how the question is drawn, whether it may be answered in free text, which option stands if the person says nothing, and what the question is about.

Seq refers to the durable agent-question lifecycle, and it is the same number Message.QuestionSeq carries. Zero is legal and means exactly one thing: this ask lives on the message alone, with no lifecycle row behind it — the shape every conversational askback has always had.

type QuestionPractice

type QuestionPractice struct {
	StartSeq         int64
	QuestionSeq      int64
	JobID            string
	BaselineSurprise float64
	ExpectedTokens   int
	ResultSurprise   *float64
	Reduced          *bool
	CompletionSeq    int64
	Reason           string
}

QuestionPractice is one round, including unfinished rounds recovered after restart. CompletionSeq zero means the job still needs an outcome landing.

type QuestionPracticeStarted

type QuestionPracticeStarted struct {
	QuestionSeq      int64   `json:"question_seq"`
	JobID            string  `json:"job_id"`
	BaselineSurprise float64 `json:"baseline_surprise"`
	ExpectedTokens   int     `json:"expected_tokens"`
}

QuestionPracticeStarted is the durable link between one question and the self-origin subtree admitted to exercise it.

type QuestionUrgency

type QuestionUrgency string

QuestionUrgency controls when the resident may move a queued question into the conversation. Whenever questions remain ambient until a user chooses one from a lens such as the TUI dock.

const (
	QuestionBlocking          QuestionUrgency = "blocking"
	QuestionNextNaturalMoment QuestionUrgency = "next-natural-moment"
	QuestionWhenever          QuestionUrgency = "whenever"
)

type RailAdjustment

type RailAdjustment struct {
	Amount    float64 `json:"amount"`
	Origin    string  `json:"origin"`
	Unlimited bool    `json:"unlimited,omitempty"`
}

RailAdjustment is one journaled increase to today's dollar ceiling.

type Ratification

type Ratification struct {
	Origin    Origin `json:"origin"`
	SessionID string `json:"session_id,omitempty"`
	Evidence  string `json:"evidence"`
}

Ratification records who accepted the standing-spend consequence.

type RecallHit

type RecallHit struct {
	NodeID   string   `json:"node_id"`
	Intent   string   `json:"intent"`
	Digest   string   `json:"digest"`
	Pointers []string `json:"pointers"`
	Age      string   `json:"age"`
	Score    float64  `json:"score"`
}

RecallHit is one compact route back into prior work. Digest is the bounded map carried in the prompt; Pointers name the territory an executor can read when the digest says that memory matters.

type ResidentLane

type ResidentLane string

ResidentLane names one durable resident cursor.

const (
	// LaneSettlement is the announce/distill/fold cursor. Its cursor is the
	// last journal sequence the settle pass has already reacted to, so a
	// process that starts after another one stopped resumes at the gap rather
	// than stepping over it.
	LaneSettlement ResidentLane = "settlement"
	// LaneConsolidation paces the notebook's belief-rewriting sleep pass. It
	// carries no cursor: the event's own time is the whole watermark.
	LaneConsolidation ResidentLane = "consolidation"
)

type ResidentWatermark

type ResidentWatermark struct {
	Lane   ResidentLane
	Seq    int64
	At     time.Time
	Cursor int64
}

ResidentWatermark is one lane's durable position.

type ResolvedRole

type ResolvedRole struct {
	Role   ModelRole
	Model  string
	Source RoleSource
	// Scope is the scope that answered, empty for a pin, a default, and an
	// unbound role.
	Scope BindingScope
}

ResolvedRole is one answer and the reason for it.

func (ResolvedRole) Bound

func (resolved ResolvedRole) Bound() bool

Bound reports whether anything at all answered. False is the untouched machine, and a caller that gets it must do exactly what it did before this table existed.

type RetrospectiveWatermark

type RetrospectiveWatermark struct {
	Seq         int64
	At          time.Time
	SettledJobs int
}

RetrospectiveWatermark is the last durable retrospective checkpoint. At is the journal event time; SettledJobs is the uncapped count considered then.

type ReversalRate

type ReversalRate struct {
	Class     string
	Reversals int
	Total     int
	Rate      float64
}

ReversalRate is the evidence for one retrospective action class.

type Role

type Role string

Role says who authored a thread message. System messages are emitted by the graph itself (folds landing, commands applying, budgets tripping).

const (
	RoleUser   Role = "user"
	RoleAgent  Role = "agent"
	RoleSystem Role = "system"
)

type RoleBinding

type RoleBinding struct {
	Role    ModelRole    `json:"role"`
	Scope   BindingScope `json:"scope"`
	Value   string       `json:"value,omitempty"`
	Origin  string       `json:"origin,omitempty"`
	Cleared bool         `json:"cleared,omitempty"`
	Seq     int64        `json:"-"`
}

RoleBinding is one journaled decision about what a role runs on inside one scope.

Value is one model slug and carries its own effort, because effort has no axis of its own today (12.3.5). The store keeps a name and no opinion about which names exist — whether a slug reaches a reachable model is the client pool's question, one layer up, at dispatch, exactly as it is for a node's pinned model and for a worker's name.

Cleared says the scope binds nothing again, which is not the same as binding the empty string: an unbound scope inherits from its parent scope, so the two must be different rows in the journal rather than the same one.

type RoleDefaults

type RoleDefaults map[ModelRole]string

RoleDefaults is the compiled-in floor of the ladder: what a role resolves to when nothing is bound anywhere. It is process configuration rather than journaled policy — it comes from flags, the environment, and the catalog, none of which belong in a brain file — so it is installed on the open store and never written to the journal.

func NewRoleDefaults

func NewRoleDefaults(orchestrate, plan, work, cheap string) RoleDefaults

NewRoleDefaults seeds the five from the models a surface already resolved. Verify and scribe take the cheap model when the configuration names one and the work model when it does not, which is the honest fallback: the ladder is how spend is steered, and steering nowhere must never cost more than not steering. Empty arguments bind nothing rather than binding "".

type RoleSource

type RoleSource string

RoleSource names which rung of the ladder answered a resolution. It exists so a receipt can say why a model was chosen — the predictability law forbids a switch without one — and so a chip can render "inherited" honestly.

const (
	// RoleFromPin is the node's own promised model, journaled at splice or by
	// CommandSetModel's subtree sweep. It outranks every binding.
	RoleFromPin RoleSource = "pin"
	// RoleFromNode is a binding on exactly this node.
	RoleFromNode RoleSource = "node"
	// RoleFromTask is a binding on the nearest ancestor task root, itself
	// included.
	RoleFromTask RoleSource = "task"
	// RoleFromGlobal is the machine-wide binding.
	RoleFromGlobal RoleSource = "global"
	// RoleFromDefault is the compiled-in fallback the surface installed.
	RoleFromDefault RoleSource = "default"
	// RoleUnbound is the answer on a machine that has bound nothing and
	// installed no defaults: the caller's own resolution stands, unchanged.
	RoleUnbound RoleSource = "unbound"
)

type RoomSpend

type RoomSpend struct {
	SessionID string
	// SinceSeq and Since are the journal row the window opens at: the room's
	// first message for a whole-room read, the room's newest user message for
	// a turn. Zero means there was nothing to open at.
	SinceSeq int64
	Since    time.Time
	// Last is the newest usage row inside the window, or the zero time when
	// there is none. It is the journal's own timestamp rather than a clock
	// read here, so two lenses asking the same question agree.
	Last time.Time

	Work  SpendSlice
	Spine SpendSlice

	// Shared says another room was live inside this window — it spent against
	// its own nodes, or it was spoken in. Spine is then a ceiling on this
	// room's conversational cost and not its bill.
	Shared bool

	// SpinePromptHighWater is the largest prompt_tokens on any single spine row
	// inside the window. It is named for what it measures rather than for what
	// it is wanted for, because those are not quite the same thing and the gap
	// is the whole of what 5.9 still owes.
	//
	// What it is wanted for: the head's context occupancy, the numerator of
	// ctx%. Most spine rows are written one per provider call by
	// pool.recordStructuringSpend, so such a row's prompt_tokens IS that call's
	// whole context — and the answering call's prompt dominates the routing and
	// compiling calls beside it, which see one instruction rather than the
	// thread. For a turn that was pure conversation, this is the head's window,
	// exactly.
	//
	// Where it stops being exact: three call sites journal ONE spine row for
	// MANY calls, summing their prompts — the planner's passes
	// (journalPlanSpend) and headless preparation and run totals. A summed
	// prompt is not a context occupancy, so a window containing one of those
	// makes this an upper bound. That is the safe direction for a health signal
	// — a context gauge that errs toward alarm sends a person to look, while
	// one that errs toward calm is why nobody could answer "why did it get
	// dumber" — but it is an error and it is written down here rather than
	// dressed up at the seam.
	//
	// It is deliberately measured over Spine alone. A leaf's row is a whole
	// tool loop summed by construction, so the same maximum over Work rows
	// would be a number with no referent at all.
	//
	// It is NOT 5.9's durable context figure and must never be labelled as one.
	// That one needs executors to journal window-size high-water marks — the
	// window a call actually occupied, per call, as its own fact — which no
	// executor does yet. Until they do, this is what the journal can say, it
	// can only say it about the conversation, and it says nothing at all when
	// Shared is true.
	SpinePromptHighWater int
}

RoomSpend is what one room of conversation has cost, split by how well the journal can say so.

"A usage row carries a node and a time, never a session" was true when it was written and is now true of exactly half the bill:

  • Work commissioned FROM a room carries the room on its node. The splice stamps Provenance.SessionID on every node it admits, and every repair, revision and retry underneath copies it forward, so summing usage rows whose node names this room is exact — no window, no guess, no double counting.
  • The head's OWN calls — routing a message, compiling an instruction, writing the reply — bill the spine, which belongs to no room at all (pool.SpendNode defaults to RootID for precisely that reason). Nothing in the row says which room was being answered. Only the window says it, and only while one room is talking.

So this carries two figures and a warning rather than one number. Work is this room's, exactly. Spine is what conversation cost inside the window, which is this room's alone only when this room was the only one live — Shared says it was not, and a renderer that quotes Spine anyway is quoting an upper bound.

func (RoomSpend) Cost

func (spend RoomSpend) Cost() float64

Cost is the whole window's measured money. It folds the ambiguous half in, so a caller that shows it while Shared is true is showing a ceiling; a caller that wants only what it can defend shows Work.Cost.

func (RoomSpend) Recorded

func (spend RoomSpend) Recorded() bool

Recorded reports whether the journal has a single run to show for the window. It is the distinction a bare float64 cannot make and the one the renderer's missing-data law (8.2.20) turns on: false means nothing has been billed here — absence, drawn as — — while true with a zero Cost means runs that genuinely cost nothing, which is $0.00 and a different sentence.

func (RoomSpend) Runs

func (spend RoomSpend) Runs() int

Runs is every run the window counted, room work and conversation together.

type ScaleGate

type ScaleGate struct {
	Goal      string `json:"goal,omitempty"`
	Structure string `json:"structure,omitempty"`
	Scale     string `json:"scale,omitempty"`
	Route     string `json:"route"`
	Leaves    int    `json:"leaves"`
	// Parts is how many separable requests the compiler read in the ask. Zero
	// is the ordinary ask; two or more once meant a second route out of this
	// gate — a flat layout with no planner in it — and now means only that the
	// planner was handed the person's own division as evidence. It is kept
	// because it is the one number that says whether a wide plan followed a
	// wide ask or was found by the planner in a single one.
	Parts int `json:"parts,omitempty"`
}

ScaleGate is one job's shape and the reading behind it.

Structure is the compiler's structural reading of the ask — whether it enumerates, stratifies, is one judgement, or is a single act — and Scale is the size that reading was reconciled to. They are two fields rather than one because the reconciliation is exactly where a surprise lives: a goal read as "enumerates" that still arrived as a lookup is a different story from one read as "single_act", and only the pair tells them apart.

Route names the branch actually taken, and Leaves is how many nodes the splice carried. Together they are the answer to the question the audit asked of this gate: whether a run had any parallelism at all, and on whose reading.

type ScopeAlias

type ScopeAlias struct {
	From string
	To   string
	Seq  int64
}

ScopeAlias is one old scope name and the canonical scope it now resolves to. Seq is the journal event that introduced the direct alias.

type ScopeCompetence

type ScopeCompetence struct {
	Scope           string          `json:"scope"`
	Kind            ScopeKind       `json:"kind"`
	Class           CompetenceClass `json:"class"`
	Samples         int             `json:"samples"`
	Successes       int             `json:"successes"`
	Failures        int             `json:"failures"`
	SuccessRate     float64         `json:"success_rate"`
	FailureRate     float64         `json:"failure_rate"`
	SurpriseSamples int             `json:"surprise_samples"`
	Surprise        float64         `json:"surprise"`
	SurpriseTrend   SurpriseTrend   `json:"surprise_trend"`
	InstalledSkills []string        `json:"installed_skills,omitempty"`
	LastTouched     time.Time       `json:"last_touched,omitempty"`
}

ScopeCompetence is the narrow, serializable unit future practice loops may consume. Rates are fractions in [0,1]. InstalledSkills contains active skill docs whose canonical scope touches this scope.

type ScopeKind

type ScopeKind string

ScopeKind names the two vocabularies admitted to the map. Territory scopes are canonical notebook scopes earned by folded jobs. Profile scopes are prefixed with "profile:" so a domain named "atomic" cannot collide with the planner's atomic bucket.

const (
	CompetenceTerritory ScopeKind = "territory"
	CompetenceProfile   ScopeKind = "profile"
)

type ScopeSurprise

type ScopeSurprise struct {
	Scope            string
	Samples          int
	SettledJobs      int
	Territories      int
	AverageSurprise  float64
	ExpectedTokens   int
	Evidence         string
	RecentSurprise   float64
	PriorSurprise    float64
	LearningProgress float64
	ColdStart        bool
	Allocation       float64
}

ScopeSurprise is the journal-derived learning signal for one notebook scope. Surprise is averaged over the newest requested sample window while relevance counts all settled user jobs and territories carrying the scope.

func AllocateLearningProgress

func AllocateLearningProgress(metrics []ScopeSurprise) []ScopeSurprise

AllocateLearningProgress normalizes only positive improvement plus a cold-start floor.

type Seen

type Seen struct {
	Seq       int64
	Time      time.Time
	Surface   string
	SessionID string
	State     SeenState
}

Seen is one journaled observation that a user-facing lens was present.

type SeenState

type SeenState string

SeenState is one edge of a human-facing session. Both edges are journaled: a clean detach is the precise watermark, while a lone attach still gives a useful conservative watermark after a crash.

const (
	SeenAttached SeenState = "attached"
	SeenDetached SeenState = "detached"
)

type SelfInquiryRetirement

type SelfInquiryRetirement struct {
	Scope      string `json:"scope"`
	Origin     string `json:"origin"`
	TargetKind string `json:"target_kind,omitempty"`
	TargetID   string `json:"target_id,omitempty"`
	Action     string `json:"action"`
	Reason     string `json:"reason"`
}

SelfInquiryRetirement is the journaled explanation for automatically stopping a line of inquiry. Action says which existing retirement mechanism was used.

type SelfReceipt

type SelfReceipt struct {
	Seq           int64     `json:"-"`
	Time          time.Time `json:"-"`
	NodeID        string    `json:"node_id"`
	Origin        string    `json:"origin"`
	Scope         string    `json:"scope"`
	Cost          float64   `json:"cost"`
	FactIDs       []int64   `json:"fact_ids"`
	SkillIDs      []int64   `json:"skill_ids"`
	Surprise      *float64  `json:"surprise,omitempty"`
	SurpriseDelta *float64  `json:"surprise_delta,omitempty"`
	Nothing       bool      `json:"nothing"`

	TargetKind string `json:"target_kind,omitempty"`
	TargetID   string `json:"target_id,omitempty"`
}

SelfReceipt is the durable cost-and-learning account for one settled OriginSelf splice. Cost is derived from ordinary usage rows; receipts never accept or land spend independently.

type SentinelCheck

type SentinelCheck struct {
	WakeSeq int64  `json:"wake_seq"`
	Yes     bool   `json:"yes"`
	Line    string `json:"line,omitempty"`
	Error   string `json:"error,omitempty"`
}

SentinelCheck is the journaled outcome of exactly one wake-time judgment.

type SentinelJudgment

type SentinelJudgment struct {
	Yes  bool
	Line string
	// Outcome is what happened after the judgment — the firing it caused, or
	// the user's refusal of that firing. Empty means nothing followed, which is
	// itself worth reading: a yes that led nowhere.
	Outcome string
	Error   string
}

SentinelJudgment is one past wake judgment together with what became of it. Line and Error had no reader anywhere: the sentinel wrote down its reasoning every wake and never saw a word of it again.

type Service

type Service struct {
	ID           string            `json:"id"`
	Name         string            `json:"name"`
	Command      string            `json:"command"`
	Dir          string            `json:"dir"`
	Health       ServiceHealth     `json:"health"`
	LogPath      string            `json:"log_path"`
	Provenance   ServiceProvenance `json:"provenance"`
	PID          int               `json:"pid"`
	StartedAt    time.Time         `json:"started_at"`
	Status       ServiceStatus     `json:"status"`
	AutoRestart  bool              `json:"auto_restart"`
	RestartCount int               `json:"restart_count"`
	CreatedSeq   int64             `json:"created_seq"`
	UpdatedSeq   int64             `json:"updated_seq"`
}

Service is the materialized view of a process the user meant to keep.

type ServiceHealth

type ServiceHealth struct {
	Kind  ServiceHealthKind `json:"kind"`
	Value string            `json:"value"`
}

ServiceHealth is deliberately small: one cheap probe with one bounded value.

func ParseServiceHealth

func ParseServiceHealth(raw string) (ServiceHealth, error)

func (ServiceHealth) String

func (h ServiceHealth) String() string

func (ServiceHealth) Suffix

func (h ServiceHealth) Suffix() string

Suffix is the compact rail/receipt spelling.

type ServiceHealthKind

type ServiceHealthKind string
const (
	ServiceHealthPort ServiceHealthKind = "port"
	ServiceHealthURL  ServiceHealthKind = "url"
	ServiceHealthCmd  ServiceHealthKind = "cmd"
)

type ServiceProvenance

type ServiceProvenance struct {
	OriginJobID int    `json:"origin_job_id"`
	LeafNodeID  string `json:"leaf_node_id"`
}

type ServiceStatus

type ServiceStatus string

ServiceStatus is the journal-derived state of one promoted process.

const (
	ServiceRunning ServiceStatus = "running"
	ServiceStopped ServiceStatus = "stopped"
	ServiceFailed  ServiceStatus = "failed"
	ServiceResting ServiceStatus = "resting"
)

type Session

type Session struct {
	ID    string
	Title string
	// Tags are the subject words the naming pass filed this room under. They
	// are a FINDING aid and not a second title: nothing draws them as chips,
	// and the one place they earn their keep is a switcher's filter, where a
	// person who remembers what a conversation was ABOUT but not what it ended
	// up called can still type their way back into it.
	//
	// They are written by the same pass that names the room and by nothing
	// else. A person renaming a tab states a new NAME; they are not restating
	// what the conversation is about, so [Store.RenameSession] leaves whatever
	// is here exactly as it stands.
	Tags    []string
	Surface string
	// Created is the first message that named this session; LastActive is the
	// newest one. Both are message times rather than wall-clock times taken
	// here, so a rebuild reproduces them exactly.
	Created    time.Time
	LastActive time.Time
}

Session is one conversation thread's own row.

type SilentClaim

type SilentClaim struct {
	// ID is the node the claim is on.
	ID string
	// Owner and Token are the claim itself, so a caller that decides to take it
	// back can do so through the ordinary CAS without reading the node again.
	Owner string
	Token uint64
	// CancelRequested carries the surgery flag through, because a claim the user
	// had already asked to stop is finished as a cancellation once it is back.
	CancelRequested bool
	// Quiet is how long it had been since the node last showed a sign of life.
	Quiet time.Duration
	// LastSign is when that sign was. It is the claim's own start when the
	// worker never wrote anything at all, which is the honest reading: the
	// claim was granted and nothing has happened since.
	LastSign time.Time
	// Reason is the release sentence, journaled on the release event.
	Reason string
}

SilentClaim is one claim this sweep found showing no sign of life: which node and which claim, how long it had been silent, and the sentence that says so. The sentence is carried out rather than composed at the caller because the numbers behind it are known here and nowhere else.

func (SilentClaim) Claim

func (c SilentClaim) Claim() Claim

Claim is the claim this silence was found on, ready for Release.

type Snapshot

type Snapshot struct {
	Nodes []Node
	Edges []Edge
}

Snapshot is a deterministic copy of the full materialized views, including folded historical nodes. It is useful for inspection and rebuild checks.

type SpecGranularityValue

type SpecGranularityValue struct {
	MedianBriefBytes  int     `json:"median_brief_bytes"`
	CorrectionDensity float64 `json:"correction_density"`
}

SpecGranularityValue projects ask size and subsequent redirect density.

type SpendSlice

type SpendSlice struct {
	Runs             int
	Cost             float64
	PromptTokens     int
	CompletionTokens int
	CachedTokens     int
}

SpendSlice is one class of runs inside a window: how many there were, what they cost, and the tokens they moved. It is a slice of a bill rather than a bill, because a room's bill has two parts the journal knows differently well and reporting them as one number would be reporting the weaker half's certainty as the stronger half's.

type SpendWindow

type SpendWindow struct {
	Since            time.Time
	Until            time.Time
	Runs             int
	PromptTokens     int
	CompletionTokens int
	Cost             float64
}

SpendWindow is what one arbitrary stretch of time cost. It is the shape every "what did I spend this week" question wants and the shape no query in this package could answer: localDayBounds was the only bucketing helper anywhere, so every user-facing number was either today or all time.

SelfReceipts(since) had already proved the signature — for the resident's own practice, and unreachable from any user surface. The user's jobs get the same courtesy here.

type StandingWatchDecision

type StandingWatchDecision string

StandingWatchDecision is the journal-derived global policy state.

const (
	StandingWatchUndecided StandingWatchDecision = ""
	StandingWatchOffered   StandingWatchDecision = "offered"
	StandingWatchEnabled   StandingWatchDecision = "enabled"
	StandingWatchDeclined  StandingWatchDecision = "declined"
	// StandingWatchStoodDown is a yes the user has taken back. It is distinct
	// from declined because the host timer exists in this state and has to be
	// removed, and because it can be turned back on — declined never installed
	// anything and its offer was the once-ever gate.
	StandingWatchStoodDown StandingWatchDecision = "stood-down"
)

type StandingWatchPass

type StandingWatchPass struct {
	Examined  int `json:"examined"`
	Woken     int `json:"woken"`
	Checked   int `json:"checked"`
	Fired     int `json:"fired"`
	Proposed  int `json:"proposed"`
	No        int `json:"no"`
	Errors    int `json:"errors"`
	Quota     int `json:"quota"`
	Expired   int `json:"expired"`
	RailWaits int `json:"rail_waits"`
}

StandingWatchPass is the bounded receipt written by `codeaf wake`. It is journal-native because status needs only the event time.

type StateCounts

type StateCounts struct {
	Queued    int
	Running   int
	Done      int
	Failed    int
	Cancelled int
}

StateCounts is a subtree's census, the figure a collapsed parent draws in place of the rows it is hiding.

Queued folds Claimed in with Pending on purpose. A claim is a worker picking the work up, and 13.11's second decision already settled that the state axis may only brighten on work that MOVES: a claimed node has not moved, so a reader counting what is running must not be told it has.

func (StateCounts) Settled

func (counts StateCounts) Settled() int

Settled is the work that has stopped, however it stopped. It is the numerator of the `3/7` a card draws.

func (StateCounts) Total

func (counts StateCounts) Total() int

Total is every node the census covers.

type Status

type Status string

Status is the scheduling state of a node.

const (
	Pending   Status = "pending"
	Claimed   Status = "claimed"
	Running   Status = "running"
	Done      Status = "done"
	Failed    Status = "failed"
	Cancelled Status = "cancelled"
)

type Store

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

Store is one handle onto the shared SQLite graph.

func Open

func Open(path string) (*Store, error)

Open opens or creates the store at path. WAL is persistent database state; busy_timeout and foreign keys are connection-local and therefore live in the DSN so every pooled connection receives them.

func (*Store) AcceptanceFor

func (s *Store) AcceptanceFor(nodeID string) (Acceptance, bool, error)

AcceptanceFor returns the newest checklist journaled for a node. It reads the event directly, exactly as DeliveryGateFor does and for the same reason: the payload is sparse, looked up by id, and has no query anyone would run across it.

func (*Store) ActivateSkill

func (s *Store) ActivateSkill(factSeq int64, artifact, digest string) error

ActivateSkill journals the only transition that makes a candidate retrievable. The caller has already copied and executed the artifact check. Digest is the content digest of the payload directory, computed at install time by installSkillTrial.

func (*Store) ActiveCharters

func (s *Store) ActiveCharters() ([]Charter, error)

ActiveCharters is the plain standing list used by conversation and /standing: ratified work only, newest first.

func (*Store) ActiveEdges

func (s *Store) ActiveEdges() ([]Edge, error)

ActiveEdges returns only edges whose endpoints remain in ActiveNodes.

func (*Store) ActiveFacts

func (s *Store) ActiveFacts(scope string, limit int) ([]Fact, error)

ActiveFacts lists a scope's live entries, newest first — consolidation's working set. An empty scope lists every active fact.

func (*Store) ActiveNodes

func (s *Store) ActiveNodes() ([]Node, error)

ActiveNodes returns the live graph plus the outermost compact representative for each fold. Nested fold roots remain addressable history, but their folded parent already represents them in the active view.

func (*Store) ActiveServices

func (s *Store) ActiveServices() ([]Service, error)

func (*Store) ActiveSnapshot

func (s *Store) ActiveSnapshot() (Snapshot, error)

ActiveSnapshot copies the compact, schedulable view.

func (*Store) AddEdge

func (s *Store) AddEdge(from, to string, kind EdgeKind) error

AddEdge appends one dependency between existing nodes: to now also waits for from. It is restricted to pending consumers on purpose — rewiring a node that already started would change what its transcript was built from. Adding an edge that already exists is a no-op, so callers can wire idempotently.

func (*Store) AddMemory

func (s *Store) AddMemory(m Memory) (Memory, error)

AddMemory journals one new memory and materializes it in the same transaction. The returned Memory is the stored row — id minted if the caller left it empty, status active, both sequences set to the event that created it.

func (*Store) AddressableNodes

func (s *Store) AddressableNodes() ([]Node, error)

AddressableNodes is ActiveNodes plus the jobs a territory has packed away.

The packer is what made a month-old job invisible to every snapshot-derived read at once. FormTerritory re-parents a settled fold under a territory node that is itself a fold root, so ActiveNodes' "outermost representative" clause — correct for a fold's own members, which the root speaks for — starts excluding the job root too. The territory then speaks for it, and a territory says "eleven jobs about pricing", which is not an answer to a question about one of them.

So reads that are asking "what do I have about this?" use this corpus and verbs keep the compact one. Membership in a territory is a filing decision made hours after a job landed; it was never meant to be the thing that decides whether the job can be spoken about.

func (*Store) AdoptService

func (s *Store) AdoptService(id string) error

func (*Store) AdvanceCharterWatch

func (s *Store) AdvanceCharterWatch(id string, state CharterWatchState) error

AdvanceCharterWatch journals a due observation that did not warrant a sentinel call: an initial file baseline or a graph scan with no match.

func (*Store) AgeFacts

func (s *Store) AgeFacts(now time.Time) (int, error)

AgeFacts applies ACT-R retention and reuses quarantine as the visible reversible outcome.

func (*Store) AgeFactsBounded

func (s *Store) AgeFactsBounded(now time.Time) (int, error)

AgeFactsBounded is AgeFacts with the journal read bounded to the two event kinds that can record a fact access, in one pass for the whole notebook instead of one whole-journal read per belief. The retention verdict for every fact is the one AgeFacts reaches; only the reading is different.

The unbounded original grows with tenure forever — the resident calls this on a timer, and its cost must follow the notebook, not the journal.

func (*Store) AgentQuestionBySeq

func (s *Store) AgentQuestionBySeq(seq int64) (AgentQuestion, bool, error)

AgentQuestionBySeq returns one materialized question.

func (*Store) AliasScope

func (s *Store) AliasScope(from, to string) error

AliasScope journals one taxonomy merge and re-shelves only active facts. Retired and quarantined rows retain the scope they had as historical evidence; retrieval and display resolve that name through the alias table.

func (*Store) AmendPending

func (s *Store) AmendPending(id, brief, title string) error

AmendPending rewrites a pending node's brief and/or display title. Empty arguments leave that field as it is.

func (*Store) AskQuestion

func (s *Store) AskQuestion(question AgentQuestion) (AgentQuestion, error)

AskQuestion queues a question without surfacing it. The resident decides when policy permits a separate SurfaceQuestion transition.

func (*Store) AssessCharterFiring

func (s *Store) AssessCharterFiring(nodeID string) (CharterFiringAssessment, bool, error)

AssessCharterFiring derives a verdict from current graph state. Failures, cancellation, a rejected final gate, or a rail breach decide immediately; success waits for the entire firing subtree to settle green.

func (*Store) AttachAmendment

func (s *Store) AttachAmendment(id, sessionID, instruction string) (bool, error)

AttachAmendment appends rather than rewrites the user's contract. For an active claim it also journals an anchored user message; the chat executor's existing steering mailbox delivers that exact text before its next turn.

func (*Store) BeginCharterWake

func (s *Store) BeginCharterWake(id string, at time.Time, evidence string, state CharterWatchState) (int64, error)

BeginCharterWake durably reserves one due occurrence. A pending reservation is returned unchanged after restart instead of creating another wake.

func (*Store) BriefFor

func (s *Store) BriefFor(nodeID string) (NodeBrief, bool, error)

BriefFor returns the newest brief journaled for a node. It reads the event directly, exactly as PlanGraphFor does and for the same reason: the payload is sparse, looked up by id, and has no query anyone would run across it — so a materialized table would be a second copy of the truth with nothing to gain by existing.

func (*Store) CancelPending

func (s *Store) CancelPending(id, reason string) error

CancelPending retires a pending node whose purpose no longer exists. Unlike the claim-based cancel path, it does not require the node to be ready — revision most often removes nodes still waiting on their inputs.

func (*Store) CancelPendingWithPartial

func (s *Store) CancelPendingWithPartial(id, reason, partial string) error

CancelPendingWithPartial is the same retirement carrying what the worker had already written before it was stopped.

The partial used to be computed and then dropped on the floor: the cancel path built it, handed it to the runner as a result summary, and the store wrote only the reason — so a cancelled node's whole contribution to whatever came next was "(not run): cancelled by user". The restart wires a fresh subtree to the dead attempt's digest precisely so the retry can read what its predecessor got done, and there was never anything there to read. It goes in the summary column because that is where every other settled node's words already live, and the digest reads it from there.

func (*Store) ChannelSurvivalStats

func (s *Store) ChannelSurvivalStats() ([]ChannelSurvival, error)

ChannelSurvivalStats derives every rate from fact lifecycle events.

func (*Store) Charter

func (s *Store) Charter(id string) (Charter, bool, error)

Charter returns one materialized charter.

func (*Store) CharterCheckCount

func (s *Store) CharterCheckCount(id string, since time.Time) (int, error)

CharterCheckCount is how many times a sentinel has looked since a moment. It is the denominator of usefulness: without it "this watch has found nothing" cannot be told apart from "this watch has never run".

func (*Store) CharterClockDeadline

func (s *Store) CharterClockDeadline(now time.Time) (time.Time, bool, error)

CharterClockDeadline reports the earliest instant at which the passage of time alone could change charter state: a reserved wake still pending, a scheduled next_due arriving, or an expiry rail falling due. The second result is false when no charter is waiting on the clock at all, which is the normal answer for a store with no standing work.

func (*Store) CharterFiredNodes

func (s *Store) CharterFiredNodes(afterSeq int64) ([]Node, error)

CharterFiredNodes returns the nodes a charter firing admitted and whose outcome may still be undecided, in the same stable admission order as Nodes. The reconciler asks this question twice a second and the answer is almost always empty, so the filter belongs in SQL rather than in a full-table decode the caller throws away.

Two clauses do that narrowing, and both are statements about what cannot still be pending. A folded node's job settled at least a fold grace ago, and the resident reviews charter outcomes before it folds anything on every one of the thousands of ticks in between — so a folded firing has been reviewed, and asking again costs a node read, a parent walk and two unindexed json_extract queries to be told so. afterSeq is the caller's own watermark over the same fact: everything at or below it is settled business, and the verdict it reached is journaled, so nothing is lost by not deriving it twice.

func (*Store) CharterFiringApproved

func (s *Store) CharterFiringApproved(id string, wakeSeq int64) (bool, error)

CharterFiringApproved reports the durable one-wake authorization used to resume a daily-rail-deferred probation firing without asking twice.

func (*Store) CharterFiringRefusals

func (s *Store) CharterFiringRefusals(id string) (int, error)

CharterFiringRefusals counts every firing this charter proposed and did not get: explicit declines, and proposals that stood past their window with no answer. Both are the user saying no; one of them just costs less to say.

The ladder measured whether work completed and never whether it mattered, so a watch the user waved away four times could still be promoted to unsupervised firing on its next three approvals — the refusals reset the consecutive run and left no other trace. This is that trace.

func (*Store) CharterHygieneAsked

func (s *Store) CharterHygieneAsked(charterID string) (bool, error)

CharterHygieneAsked mirrors ServiceHygieneAsked exactly: the durable question is the memory, and asking twice about the same watch is what it prevents.

func (*Store) CharterLastFired

func (s *Store) CharterLastFired(id string) (time.Time, error)

CharterLastFired is when this watch last did anything at all. A zero time means it never has, which is the sharpest form of the same answer.

func (*Store) CharterProposalDeclined

func (s *Store) CharterProposalDeclined(shape string) (bool, error)

CharterProposalDeclined reports whether a recurrence shape has already been explicitly refused.

func (*Store) CharterWakeFired

func (s *Store) CharterWakeFired(id string, wakeSeq int64) (bool, error)

CharterWakeFired is the crash-retry guard for an approval command whose FireCharter transaction committed before ResolveCommand did.

func (*Store) Charters

func (s *Store) Charters(statuses ...CharterStatus) ([]Charter, error)

Charters lists first-class standing objects in creation order.

func (*Store) CheckpointRetrospective

func (s *Store) CheckpointRetrospective(settledJobs int) (RetrospectiveWatermark, error)

CheckpointRetrospective appends a watermark event and advances its singleton materialized view in the same transaction.

func (*Store) Claim

func (s *Store) Claim(id, owner string) (Claim, bool, error)

Claim atomically moves a ready pending node to claimed. The UPDATE includes both the observed token and pending state: workers racing from separate processes may observe the same candidate, but only one can change it.

func (*Store) ClearRoleBinding

func (s *Store) ClearRoleBinding(role ModelRole, scope BindingScope, origin string) (bool, error)

ClearRoleBinding unbinds one role inside one scope and reports whether anything was there to unbind. A scope with nothing bound is not an error: the caller asked for a state the store is already in, and the parent scope — or the compiled-in default — resumes answering with no second pass.

func (*Store) ClearTaskCeiling

func (s *Store) ClearTaskCeiling(root, origin string) error

ClearTaskCeiling returns one task to ungoverned. A root with no ceiling to clear is reported rather than journaled: the journal records decisions that changed something, and an outer ceiling — if any — resumes governing the subtree the moment this one is gone.

func (*Store) Close

func (s *Store) Close() error

Close releases this process's connections. The database remains immediately resumable by any other handle.

func (*Store) CommandBySeq

func (s *Store) CommandBySeq(seq int64) (Command, bool, error)

CommandBySeq returns one command by its journal sequence.

func (*Store) CompetenceMap

func (s *Store) CompetenceMap(options ...CompetenceOptions) (CompetenceMap, error)

CompetenceMap derives what the resident is currently good and bad at from terminal work, delivery gates, journaled surprise, active skills, territory scopes, and the supplied model profile. It makes no model calls and performs no writes.

func (*Store) CompilerAssumptionGuidance

func (s *Store) CompilerAssumptionGuidance() string

CompilerAssumptionGuidance exposes the measured compiler seam without narrating a personality.

func (*Store) Complete

func (s *Store) Complete(claim Claim, summary string) error

Complete settles a claimed or running node successfully. Composite nodes cannot complete while any child remains open.

func (*Store) CompleteAndRequestFollowup

func (s *Store) CompleteAndRequestFollowup(claim Claim, summary string, command Command) (Command, error)

CompleteAndRequestFollowup atomically settles one node and journals the ordinary splice that will continue it. Reflex promotion uses this instead of two writes so a process exit can leave neither a lost promotion nor a command whose partial is still absent from the graph.

func (*Store) CompleteQuestionPractice

func (s *Store) CompleteQuestionPractice(jobID string, resultSurprise float64) (string, error)

CompleteQuestionPractice lands one measured round and deterministically chooses the next question state. A ten-percent improvement clears the gap; two measured non-improvements retire it as noisy television.

func (*Store) ConsumersFor

func (s *Store) ConsumersFor(nodeID string) ([]ConsumersReading, error)

ConsumersFor returns every changed-definition reading journaled for a node, oldest first.

func (*Store) Control

func (s *Store) Control(id string) (NodeControl, error)

Control returns the direct durable control flags for one node.

func (*Store) ConversationExchange

func (s *Store) ConversationExchange(ctx context.Context, sessionID string, seq int64, radius, byteLimit int) ([]MessageHit, error)

ConversationExchange reads an anchor and its actual neighbours in one thread. Sequence numbers belong to the whole journal, so arithmetic on seq would mix conversations or miss neighbours whenever another writer posted in between.

func (*Store) CorrectionFacts

func (s *Store) CorrectionFacts(limit int) ([]Fact, error)

CorrectionFacts lists the ordinary preference lines taste aggregates over — what the distiller wrote down when the user corrected something — newest first, with the taste shelves left out.

func (*Store) CreateCharter

func (s *Store) CreateCharter(charter Charter) error

CreateCharter journals and materializes a charter plus its inert spine node.

func (*Store) DailyRailToday

func (s *Store) DailyRailToday(base float64) (DailyRail, error)

DailyRailToday combines the configured base with today's journaled raises.

func (*Store) DeclineCharterFiring

func (s *Store) DeclineCharterFiring(id string, wakeSeq int64, reason string, pause bool) error

DeclineCharterFiring closes a probation wake and resets consecutive green evidence. Never uses pause=true; an ordinary decline leaves the charter armed.

func (*Store) DeclineCharterProposal

func (s *Store) DeclineCharterProposal(id, reason string) error

DeclineCharterProposal retires the proposal and writes a searchable notebook fact. The decline event itself is the durable no-reproposal key.

func (*Store) DeferOverrun

func (s *Store) DeferOverrun(deferred DeferredOverrun) error

DeferOverrun journals a repair that must wait for the user's word. Repeated checks of the same exhausted node leave the original pending record intact.

func (*Store) DeliveryGateAnchor added in v0.3.0

func (s *Store) DeliveryGateAnchor(baseID string) (seq int64, at time.Time, ok bool, err error)

DeliveryGateAnchor returns where in the journal — and when — a job's requested work was FIRST found done: the oldest gate recorded for the node and everything spliced beneath its id whose verdict passed or left only a coverage finding. ok is false while no such gate has been recorded, which is a job whose core work has not been found done.

The SEQUENCE is the point and not the payload. A spend rail measured from the moment the work was done reads the journal by sequence (SpendSinceSeq), and a caller given the payload alone would have to walk the whole event log to get back to the row it came from.

func (*Store) DeliveryGateFor

func (s *Store) DeliveryGateFor(nodeID string) (DeliveryGate, bool, error)

DeliveryGateFor returns the latest gate event for a node. More than one is legal because corrections in an append-only journal are later events.

func (*Store) DeliveryGateLineage

func (s *Store) DeliveryGateLineage(baseID string) ([]DeliveryGate, error)

DeliveryGateLineage returns every gate recorded for a node and everything spliced beneath its id, oldest first — one job's whole run of judgements, including the repair rounds that continue it under "<id>-x<n>".

It is an id-range read rather than a graph walk for the same reason the round counter is: the lineage IS an id namespace, and a reader that rebuilt it from parents and edges would own a second copy of the "-x" law.

func (*Store) DemoteTasteRule

func (s *Store) DemoteTasteRule(seq int64) (Fact, error)

DemoteTasteRule returns one active rule to candidacy after the user has said twice that the delivery was right as it was.

func (*Store) DependencyAccounts

func (s *Store) DependencyAccounts(id string, maxBytes int) ([]DependencyInput, error)

DependencyAccounts is DependencyInputs for a reader that needs to know what exists rather than to hold it: a sub-planner deciding how to divide a claimed node, an audit, anything whose next act is a judgment about shape.

It carries the producers' own accounts of their work — which is what this edge carried for everyone until the consumers that have to work from it were told apart from the consumers that do not. The files still travel, so a reader that turns out to need a byte of the material has the path; it simply is not handed eight reports to decide that three parts are really four.

func (*Store) DependencyDigests

func (s *Store) DependencyDigests(id string, maxBytes int) ([]string, error)

DependencyDigests is the bounded context handed from settled hard dependencies to a downstream node. Failures are named instead of omitted.

func (*Store) DependencyFanIn

func (s *Store) DependencyFanIn(id string) (DependencyFanIn, error)

DependencyFanIn measures the settled hard dependencies of one node. It is read once, at claim time, by a caller that then holds the two numbers fixed for the life of the worker: a budget that moved between turns would move the prompt prefix with it.

The measurement counts the product and not the announcement of it. A summary reading "The evaluation is complete. The file is at /w/job/07-vendors.md" is 61 bytes and stands for 7 KB, so a fan-in of four such nodes measured 244 bytes and sized its consumer's completion reserve, turn grant and token grant for 244 bytes of assembly. Every one of those numbers is arithmetic over this one, which is why this one has to be about the work.

func (*Store) DependencyInputs

func (s *Store) DependencyInputs(id string, maxBytes int) ([]DependencyInput, error)

DependencyInputs is DependencyDigests with the producer and its files kept separate instead of flattened into one line.

The budget is shared out per dependency rather than first-come. One shared pot in edge order meant the first verbose finding could take all 4 KB and every sibling after it was dropped by a bare `continue` — no marker, no warning, nothing the consumer could notice. A fan-out of fifty leaves therefore synthesised whatever happened to be first. Each dependency now gets an equal share of the pot, unused share is handed back to the ones that need it, and a clipped digest says out loud that it was clipped.

The pot itself is the caller's to name, and it must be sized from the window of the model that will read these inputs — see ctxbudget. MaxDigestBytes is what a caller passes when nothing can say how big that window is; it is a fallback, not a ceiling, and a caller that knows better must not use it.

What every input carries is as much of the producer's product as its share buys, and a handle whenever that was not all of it — a path to a file holding the whole. The consumer decides what to open. That is the whole policy: the pot is the push, the handle is the pull, and a fan-in costs what its consumer reads rather than what its producers wrote.

This is the shape for the node that has to WORK from what fed it, and the files a producer left are read back into its digest. For the reader that is deciding a shape rather than doing the work, see DependencyAccounts.

func (*Store) DraftCharter

func (s *Store) DraftCharter(id, sessionID string, sourceCommandSeq int64, spec CharterSpec) (Charter, error)

DraftCharter compiles a head spec into one canonical proposed charter. The id is assigned by the caller from its source command, so retries converge on the same identity instead of drafting twice.

func (*Store) DueCharters

func (s *Store) DueCharters(now time.Time, limit int) ([]Charter, error)

DueCharters returns active work that is due or has an interrupted wake to resume. Expiry is handled by the engine before any sentinel call.

func (*Store) Edges

func (s *Store) Edges() ([]Edge, error)

Edges returns every materialized edge, including folded history.

func (*Store) EmptySessions

func (s *Store) EmptySessions() ([]Session, error)

EmptySessions lists every room that was opened and never became a conversation — no message of any kind, and no name of its own — newest first.

A title is part of the test and not an afterthought: a room somebody deliberately named is a place they made on purpose, and emptying it is not the same as never having used it. The scribe never names a room with nothing in it, so the only titles this excludes are the ones a person typed.

func (*Store) EnsureSession

func (s *Store) EnsureSession(id, surface string) (Session, error)

EnsureSession mints the row for a session the first time it is seen and raises its activity mark, and is safe to call on every message. An empty id is not a session: messages the machine posts to no room in particular carry one, and minting a nameless row for them would put a phantom thread in every thread list.

Surface is first-writer-wins. The message path knows the session but not the lens it is being typed into, so it ensures with an empty surface and a lens that names itself later fills it in without overwriting an earlier answer.

func (*Store) Events

func (s *Store) Events(afterSeq int64, limit int) ([]Event, error)

Events returns journal entries after afterSeq. A non-positive limit means no limit.

IT DOES NOT RETURN LEAF TRANSCRIPTS, and that exclusion is deliberate. Every caller of this function derives a DECISION from the journal — trial verdicts, reversal rates, measured capacity, what the resident learned, what happened while the machine slept — and four of them read the whole journal from sequence one to do it. A leaf's transcript is bulk evidence rather than a decision: it is journaled here so a rebuild can put it back (see Store.Rebuild, which reads the events table directly and therefore still sees every one of them), it is bounded per execution, and it is still far larger than every decision event in the database put together. Handing it to a full-journal scan would make each of those readers page a megabyte of tool output per leaf to answer a question about none of it. Its own reader is Store.TranscriptFor.

func (*Store) EventsThrough

func (s *Store) EventsThrough(afterSeq, throughSeq int64) ([]Event, error)

EventsThrough returns journal entries in the window (afterSeq, throughSeq], oldest first. It is the bounded form of Events, for a reader that already knows the watermark its work ends at: carrying the rest of the journal into memory only to discard it is a cost that grows with tenure forever.

A throughSeq at or below afterSeq is an empty window, not an error.

It leaves out leaf transcripts for the same reason Store.Events does, and it matters more here rather than less: both of this function's callers are summarising what happened to a person, and a worker's tool output is not what happened, it is how.

func (*Store) Fact

func (s *Store) Fact(seq int64) (Fact, bool, error)

Fact returns one notebook entry by its durable event sequence, including a superseded entry needed to explain an already-fired trial.

func (*Store) FactActivation

func (s *Store) FactActivation(factSeq int64, now time.Time) (float64, float64, int, error)

FactActivation projects one belief's journaled access history at now.

func (*Store) FactBySeq

func (s *Store) FactBySeq(seq int64) (Fact, bool, error)

FactBySeq returns one notebook entry regardless of retrieval status.

func (*Store) FactLineage

func (s *Store) FactLineage(scope string, limit int) ([]Fact, error)

FactLineage returns the beliefs recorded in one scope, newest first, INCLUDING the ones a later wording superseded. It is the read a writer makes before deciding whether it has anything new to say; nothing that retrieves facts for use may read it, for the reason the active view exists.

func (*Store) FactOutcomes

func (s *Store) FactOutcomes() (map[int64]FactOutcome, error)

FactOutcomes joins journal-native injections to graph and gate outcomes. The query deliberately assigns correlation, not causation; policy about how much repeated evidence warrants quarantine belongs to consolidation.

func (*Store) Facts

func (s *Store) Facts(limit int) ([]Fact, error)

Facts lists notebook entries in journal order, including settled and quarantined beliefs. A non-positive limit returns the complete notebook.

func (*Store) Fail

func (s *Store) Fail(claim Claim, message string) error

Fail settles a claimed or running node unsuccessfully. Failed is terminal, so dependents become ready and receive the failure digest instead of being stranded.

func (*Store) FailService

func (s *Store) FailService(id, reason string, restartCount int) error

func (*Store) FindConversationMessages

func (s *Store) FindConversationMessages(ctx context.Context, terms, sessionID, excludeSessionID string, limit int) ([]MessageHit, error)

FindConversationMessages keeps ranking in the existing index but extracts the matching passage rather than the beginning of a possibly unrelated paragraph. Quoted Unicode tokens are data, never FTS operators. No query means browsing one explicitly named conversation; it never silently lists the whole store.

func (*Store) FireApprovedCharter

func (s *Store) FireApprovedCharter(id string, wakeSeq int64, subtree Subtree, provenance Provenance,
	dailyBudgetUSD float64, now time.Time) (FireDisposition, error)

FireApprovedCharter follows the same journaled admission path after a user approves one probation proposal. It is the only probation bypass.

func (*Store) FireCharter

func (s *Store) FireCharter(id string, wakeSeq int64, subtree Subtree, provenance Provenance,
	dailyBudgetUSD float64, now time.Time) (FireDisposition, error)

FireCharter atomically admits either an ordinary trigger job or one attention message. Daily-rail waits leave sentinel_yes pending for retry.

func (*Store) FirePracticeCharter

func (s *Store) FirePracticeCharter(id string, wakeSeq int64, subtree Subtree,
	questionSeq int64, baselineSurprise float64, expectedTokens int,
	dailyBudgetUSD float64, now time.Time) (FireDisposition, error)

FirePracticeCharter is the self-origin variant of FireCharter. It preserves the same wake, expiry, firing-cap, and global-rail admission, adds the practice charter's own daily dollar carve-out, and atomically marks the selected question practicing after the subtree splice lands.

func (*Store) FiringsToday

func (s *Store) FiringsToday(id string, now time.Time) (int, error)

FiringsToday counts admitted actions, not sentinel checks or blocked wakes.

func (*Store) Fold

func (s *Store) Fold(subtreeRoot, digest string, pointers []string) error

Fold replaces a completed subtree in the active view with one bounded digest at subtreeRoot. The original nodes and edges remain materialized as folded history, and the journal retains every transition that produced them.

func (*Store) ForgedCraftNames

func (s *Store) ForgedCraftNames() ([]string, error)

ForgedCraftNames is every way of working this brain has learned, newest first. The repository is still the authority on what a craft IS — its steps, its versions, its ceilings — but the journal is the only place a process without the repository open can find out which names EXIST, and that turns out to be the question a conversation asks.

It exists because the verb triad resolves one id against everything the person owns (internal/head/change.go): a job, a rule, a service, a way of working. Three of those the store can confirm. Without this the fourth had to be the fall-through — which made every mistyped job id a command against a workflow nobody has forged.

func (*Store) ForgetMemory

func (s *Store) ForgetMemory(id string) error

ForgetMemory tombstones a memory. It refuses a memory that is already forgotten rather than returning quietly: "forget that" is an instruction a person expects to have had an effect, and a silent success on a row that was already gone is the store agreeing with something that did not happen.

func (*Store) ForgetMemoryFromSession

func (s *Store) ForgetMemoryFromSession(id, sourceSession string) error

ForgetMemoryFromSession records the conversation that issued the tombstone.

func (*Store) FormTerritory

func (s *Store) FormTerritory(id, title, digest string, pointers, members []string) error

FormTerritory atomically journals an organizational splice, its lifecycle, every member re-parent, and the enclosing fold. The digest is prepared before the transaction so a CAS spill cannot leave a partial event batch.

func (*Store) GetMemories

func (s *Store) GetMemories(ids []string) ([]Memory, error)

GetMemories reads full memories by id, in the order asked for.

Input order is the contract because the caller is a router that has already decided what matters most; re-sorting its choice by anything the store knows would discard the one ranking in the system that saw the actual question. Ids that name nothing, or name something no longer active, are simply absent — a memory the user forgot between the index read and this call must not reappear because a pointer to it survived.

func (*Store) GrowTerritory

func (s *Store) GrowTerritory(territoryID, memberID, digest string, pointers []string) error

GrowTerritory adds one later job fold and refreshes the enclosing digest in the same event transaction. Existing member fold roots remain searchable.

func (*Store) HasActiveFactKind

func (s *Store) HasActiveFactKind(kind FactKind) (bool, error)

HasActiveFactKind reports whether one kind can change a retrieval surface.

func (*Store) HasCommandTarget

func (s *Store) HasCommandTarget(target string, kind CommandKind) (bool, error)

HasCommandTarget reports whether the journaled command view contains a command of kind aimed at target. A targeted splice is the durable marker for a reflex promotion.

func (*Store) HasFolds

func (s *Store) HasFolds() (bool, error)

HasFolds reports whether recall can change a headless run. Callers use it as the additive boundary: a database containing only the permanent spine must not add prompt bytes or tool definitions to the benchmarked path.

func (*Store) Impact

func (s *Store) Impact(id string, now time.Time) (SurgeryImpact, error)

Impact totals the target subtree's durable spend and live runtime.

func (*Store) IncompleteQuestionPractices

func (s *Store) IncompleteQuestionPractices() ([]QuestionPractice, error)

IncompleteQuestionPractices returns every admitted round still waiting for a terminal job and a surprise measurement.

func (*Store) InstallRoleDefaults

func (s *Store) InstallRoleDefaults(defaults RoleDefaults)

InstallRoleDefaults sets the compiled-in floor for this process. It journals nothing: two machines sharing a brain file may be built and configured differently, and a default is a statement about this build, not about this history.

func (*Store) JobGrowthRounds

func (s *Store) JobGrowthRounds(jobRoot string) ([]JobGrowthRound, error)

JobGrowthRounds is the same journal with each decision's timestamp kept, oldest first. It reads the events directly, as ScaleGateFor does: the payload is sparse, looked up by one id, and has no query anyone would run across it.

func (*Store) JobGrowths

func (s *Store) JobGrowths(jobRoot string) ([]JobGrowth, error)

JobGrowths returns every growth decision journaled for a job root, oldest first.

func (*Store) LapsedCharterFiringProposal

func (s *Store) LapsedCharterFiringProposal(id string, wakeSeq int64, now time.Time) (bool, error)

LapsedCharterFiringProposal reports whether the proposal standing on this wake has run past its window unanswered. It is the read the watch pass makes before re-offering a firing nobody responded to.

func (*Store) LastNamedCallSinceSeq

func (s *Store) LastNamedCallSinceSeq(sessionID string, sinceSeq int64) (LastCall, bool, error)

LastNamedCallSinceSeq is the newest model call this errand has caused since the journal stood at sinceSeq — the same window SpendSinceSeq bills over, and the same membership: the session's own nodes plus the root-billed spine, because a run wedged in a planning pass owns no nodes yet and the planner's row is the only evidence it left.

Rows with no model name are skipped rather than returned nameless. A call whose server was never recorded cannot answer the question this read exists for — WHICH model is this waiting on — and half an answer here reads as a fact. Nothing found is reported as nothing found, so a caller says nothing at all rather than inventing a zero.

func (*Store) LastNonUserMessageSeq deprecated

func (s *Store) LastNonUserMessageSeq() (int64, error)

LastNonUserMessageSeq returns the sequence of the newest message the user did not write, or zero when the thread has only ever heard from them.

It answers the head's resume question — where does the trailing run of unanswered user messages begin — without reading the thread. Tailing pages the whole history to keep one number, and that history only grows.

Deprecated: one number cannot answer that question for two rooms — a reply in either carries it past the other's unanswered rows. Use SessionLastNonUserMessageSeq, or SessionMessageCursors for every room at once.

func (*Store) LastSeen

func (s *Store) LastSeen() (Seen, bool, error)

LastSeen returns the newest attach or detach watermark across user-facing lenses. A resident database represents one person's attention stream, so a TUI close followed by a web open is one continuous seen history.

func (*Store) LastStandingWake

func (s *Store) LastStandingWake() (time.Time, bool, error)

LastStandingWake returns the newest headless pass or charter wake/check/fire event, whichever is most recent.

func (*Store) LatestEventSeq

func (s *Store) LatestEventSeq() (int64, error)

LatestEventSeq returns the current journal watermark without walking the journal. It is useful for projections that report only transitions written by one bounded operation.

func (*Store) LatestFinishedVerification

func (s *Store) LatestFinishedVerification(nodeID string) (VerificationReading, int64, error)

LatestFinishedVerification returns a node's last finished-tree observation with its journal sequence. Node status can change after a reading, so only this sequence can order observations made by different workers.

func (*Store) LatestSession

func (s *Store) LatestSession() (Session, bool, error)

LatestSession names the room a launch comes back to.

The honest answer is "the room the PERSON was last in", and the journal has two candidates for it that disagree in exactly one case. The newest session row by activity is the wrong one: a job delivering at 03:00 into the room that commissioned it raises that room's activity mark, and coming back to that room the next morning would be the machine deciding where the conversation continues. The newest USER message is the right one — a room a person spoke in last is the conversation they were having, whether they left it by switching rooms in the window or by closing the lid.

The fallback below it is for a store with rooms and no words in any of them: the newest row by activity, so a launch that follows an opened-but-unspoken room still comes back to it rather than opening a second one beside it.

False means there is no room to come back to at all, which is only true of a journal nobody has ever spoken into. A caller mints then, and only then.

func (*Store) LeafExhaustedFor

func (s *Store) LeafExhaustedFor(nodeID string) (LeafExhausted, bool, error)

LeafExhaustedFor is the newest record of this node running out of room, or that there is none.

It exists because the fact has to be READ and not only written. The record was journaled and then nothing ever opened it: the judgement that decided whether an exhausted leaf had left work behind was shown the brief and the worker's last paragraph, and was not told that the worker had been cut off at all. See revision.JudgeRemainder.

func (*Store) LeafModeFor

func (s *Store) LeafModeFor(nodeID string) (LeafMode, bool, error)

LeafModeFor returns the newest dispatch journaled against one node. A node dispatched more than once — a retry, an escalation — reports its latest.

func (*Store) LearnedDecay

func (s *Store) LearnedDecay(kind FactKind) (float64, int, error)

LearnedDecay estimates one kind's exponent from revisit intervals and shrinks to its prior.

func (*Store) LineageNodes

func (s *Store) LineageNodes(baseID string) ([]Node, error)

LineageNodes returns every node of one job's lineage, oldest first: the node itself and everything spliced beneath its id, including the repair rounds that continue it under "<id>-x<n>" and their children.

It is an id-range read rather than a graph walk for exactly the reason DeliveryGateLineage is: THE LINEAGE IS AN ID NAMESPACE, and a reader that rebuilt it from parents and edges would own a second copy of the "-x" law and would get a different answer the first time the two drifted. A repair round is not a child of the node it repairs — it is spliced beside it, under the root, so that its result is announced like any other deliverable — so a parent walk finds none of them.

The namespace test is the node itself plus SplitNamespace and nothing else: a bare prefix range would also swallow "jobless" for "job", which would let one job's record bound another's.

func (*Store) ListMemories

func (s *Store) ListMemories(scope string, limit int) ([]Memory, error)

ListMemories returns active memories newest-touched first. An empty scope means every scope, which is what a person means by "what do you remember".

func (*Store) MarkResidentWatermark

func (s *Store) MarkResidentWatermark(lane ResidentLane, cursor int64) (ResidentWatermark, error)

MarkResidentWatermark appends a lane watermark event and advances its row in the same transaction — the retrospective checkpoint's shape, keyed by lane.

func (*Store) MeasureTraits

func (s *Store) MeasureTraits(now time.Time) ([]NamedTrait, error)

MeasureTraits computes all five v1 traits without creating telemetry.

func (*Store) MeasuredCostPerRun

func (s *Store) MeasuredCostPerRun() (float64, error)

MeasuredCostPerRun is what one executed node has actually cost on this machine, taken as the median of every priced run so one runaway job cannot set the price of the next one. Zero means nothing has been measured yet, and a caller with no measurement must say nothing rather than guess.

func (*Store) MeasuredTraitBlock

func (s *Store) MeasuredTraitBlock(maxBytes int) string

MeasuredTraitBlock renders the measured traits as plain sentences, bounded by maxBytes. It exists because promptEligible excludes FactTrait outright and always will: a trait is a number about the user, and letting it into ordinary cue retrieval would put behavioural statistics in front of a worker who asked about a parser. This is the explicit carve-out — a caller that wants self-knowledge asks for it by name, and gets a byte-capped block rather than a retrieval.

Without it, five second-order traits were re-measured on every retrospective and reached no model at all except as the one derived policy line CompilerAssumptionGuidance already emits.

func (*Store) MemoryCandidates

func (s *Store) MemoryCandidates(terms string, limit int) ([]MemoryStub, error)

MemoryCandidates is the router's shortlist: the few remembered lines most likely to bear on what was just typed, ranked here in SQL and handed to a model to REJECT rather than to search.

The ranking is Reciprocal Rank Fusion over the three orderings this table already has, and they are chosen because they fail in different directions — which is the only condition under which fusion is worth anything:

  • RELEVANCE, bm25(memories_fts) over the words of the message. ftsQueryFrom ORs its terms rather than ANDing them, and tags are indexed alongside title and text, so a partial match still ranks.
  • IMPORTANCE, over the lines that have ACTUALLY HELPED at least once, ranked by help less miss. It is what keeps a HIGH-VALUE HEAD in the pool whose words appear nowhere in the message, which is the one failure mode a lexical index has and cannot fix. Counting the miss inside the ordering is what makes an injection that bore on nothing cost something: a line that helped twice and missed ten times sinks to where its contribution is smallest, the way fixstore.go sinks a patch it offered that then failed.
  • RECENCY, updated_seq descending — the transaction-time ordering, so something corrected this morning is in the pool on the strength of that alone.

A LIST ONLY CONTAINS ROWS IT HAS SOMETHING TO SAY ABOUT, and that is what makes the fusion honest rather than a weighting in disguise. RRF combines RANKINGS OF CANDIDATES, not total orders over a corpus: an importance list that ran on past its evidence — ordering the rows that have never once helped by how recently they changed — would be a second copy of the recency list, and two thirds of the score would be one signal wearing two hats. So a row with no retrieval history is simply absent from the importance ranking, and a message with no matchable words produces no lexical ranking at all.

THE LIMIT BOUNDS THE POOL, NEVER THE STORE. The read it replaces was capped at two hundred titles, which quietly made memory two hundred and one unreachable forever; every active row is ranked here and the limit only says how many of the ranked rows are carried out.

A query with nothing in it to match — punctuation, or nothing but words shorter than the index keeps — is not an error and not an empty answer: the two arithmetic orderings still rank, so a person who types "ok, do it" is still shown what has mattered most and what changed last.

func (*Store) MemoryChangedSince

func (s *Store) MemoryChangedSince(t time.Time) (learned, letGo int, err error)

MemoryChangedSince is the "since you left" line's two figures: how many memories were learned after t, and how many were let go of after it.

THE TIMESTAMP IS NOT ON THE MEMORY, and that is worth a caller knowing. The memories table carries `created_seq` and `updated_seq` — positions in the journal, not instants — so both figures come from joining each memory to the EVENT that wrote it. Two consequences follow and neither is a defect:

  • A memory whose event predates the columns joins to nothing and is counted as neither, which is right: nobody knows when it was learned, and unknown provenance must not become "learned just now".
  • "let go" is read off the memory's CURRENT status and its LAST event. A memory forgotten and then restored is not counted, because it is not let go of any more — the line is about what stands now, not about what happened.

A zero t answers zeros: with no origin there is no "since", and a first look that declared every memory ever learned to be news would be the delta with no delta in it (internal/session's look.go makes the same refusal).

It is ONE statement, and it does not carry a single body across the wire.

func (*Store) MemoryIndex

func (s *Store) MemoryIndex(limit int) ([]MemoryStub, error)

MemoryIndex is the whole of what is remembered as title-sized lines: one per active memory, most-used first and newest-touched within a tie.

IT IS NO LONGER WHAT THE ROUTER READS. Handing every title to a model on every message costs ~3,200 tokens at a two-hundred-memory store and grows linearly with what a person has remembered, so the per-turn read is Store.MemoryCandidates — a shortlist ranked here rather than a dump. This stays because a pass that wants to look at ALL the titles at once, off the person's path, wants exactly this shape and nothing bigger.

It is a separate read from ListMemories rather than a projection of it because carrying five hundred bodies to render five hundred titles is how a memory store becomes the most expensive thing in the loop.

func (*Store) MemoryProvenance

func (s *Store) MemoryProvenance(id string) (sessionID, sessionTitle string, writtenAt time.Time, err error)

MemoryProvenance names the conversation and journal instant that last wrote a memory. Old events carry no source, which is unknown provenance rather than an error.

func (*Store) MemoryRecord

func (s *Store) MemoryRecord(id string) (Memory, bool, error)

MemoryRecord reads one memory by id whatever its status, which is the read that makes the tombstone an audit trail instead of a claim.

Every other read here is active-only by design; without this one, "the row stays for audit" would be true of the table and false of the package, and nothing outside the store could ever answer "what did that memory say before it was replaced".

func (*Store) MemorySnapshot

func (s *Store) MemorySnapshot(limit int) (MemoryShelves, error)

MemorySnapshot is everything remembered, shelved, counted and bounded.

limit caps how many ROWS come back in total, newest touched first across the whole store and then dealt onto their shelves; zero or less means [memorySnapshotRows]. The COUNTS never depend on it.

It reads every status, which is the point: a page cannot say what was let go of by asking a reader that filters let-go rows out.

func (*Store) MessageTail

func (s *Store) MessageTail(sessionID string, limit int) ([]Message, error)

MessageTail is the end of one room's conversation, oldest first.

Messages is the TAILING primitive: a lens remembers the last seq it rendered and asks for what came after, so its window opens at the front and its limit bounds how far forward it reads. That is exactly the wrong shape for the one question this answers — "what were we saying in there" — where the front of a day-old room is the part nobody wants and the limit would cut off the part they do. Paging forward to find the end would mean one query per two hundred messages to throw all but the last handful away.

So this reads backward and hands the result back in reading order. The decoding is the same decoding, because a message that came out of this query has to be indistinguishable from a message that came out of that one.

func (*Store) MessageWindowFloor

func (s *Store) MessageWindowFloor(sessionID string, keep int) (int64, error)

MessageWindowFloor is the seq of the keep-th newest message in a session: everything below it is conversation the front desk can no longer see.

It exists so a caller can ask the one question that separates "they are talking about what we just said" from "they are asking me to remember". Zero means the session is still short enough that nothing has fallen out of sight, which is the same as saying there is nothing to remember yet.

func (*Store) Messages

func (s *Store) Messages(sessionID string, afterSeq int64, limit int) ([]Message, error)

Messages returns thread messages after a journal sequence, oldest first. An empty sessionID returns every session's messages; afterSeq zero starts from the beginning. This is the tailing primitive: a lens remembers the last Seq it rendered and asks for what came after.

func (*Store) MetaReversalRates

func (s *Store) MetaReversalRates() (map[string]ReversalRate, error)

MetaReversalRates derives auditable action-class reversals from existing events.

func (*Store) NeighbouringCorrections

func (s *Store) NeighbouringCorrections(body string, excludeSeq, limit int64) ([]Fact, error)

NeighbouringCorrections ranks the corrections already in the notebook against one of their own, best first, on the same FTS5/BM25 index every other retrieval uses. It narrows, it does not decide: on a young notebook every taste word is in most of the lines, BM25's idf collapses, and the ranking carries no signal at all — so the caller still has to judge each neighbour. Taste shelves are excluded, because a rule may not be evidence for itself.

func (*Store) NextSiblingPriority

func (s *Store) NextSiblingPriority(id string) (int, error)

NextSiblingPriority returns a value that moves id ahead of every pending sibling while retaining deterministic order among all other nodes.

func (*Store) Node

func (s *Store) Node(id string) (Node, bool, error)

Node returns one node from the complete materialized view.

func (*Store) NodeIDExistsWithPrefix

func (s *Store) NodeIDExistsWithPrefix(prefix string) (bool, error)

NodeIDExistsWithPrefix reports whether the graph holds prefix itself or any node inside its dash-delimited namespace.

func (*Store) NodeIDsWithPrefix

func (s *Store) NodeIDsWithPrefix(prefix string) ([]string, error)

NodeIDsWithPrefix returns every node id beginning with prefix, in id order.

func (*Store) NodeLife

func (s *Store) NodeLife(id string) (JobLife, bool, error)

NodeLife reads one node's run history in a single query.

The admission stamp comes off the journal row the node's created_seq already points at — the same join surgery.go has been doing inline to age a search result — so this read invents no new bookkeeping and cannot disagree with the event log. The second return is presence.

func (*Store) NodeMessages

func (s *Store) NodeMessages(nodeID string, afterSeq int64, limit int) ([]Message, error)

NodeMessages returns the messages anchored to one node after a journal sequence, oldest first — a running worker's steering mailbox, and a node view's conversation trail.

func (*Store) NodeModels

func (s *Store) NodeModels(id string) ([]string, error)

NodeModels names every model that served one node's subtree, most expensive first. This is the read behind "which model produced this?" — a question that had no answer on any surface until the usage row started carrying the name.

func (*Store) NodeRedispatches added in v0.3.0

func (s *Store) NodeRedispatches(nodeID string) (int, error)

NodeRedispatches is how many times this node has been re-dispatched in place after running out of the room it was granted: the count of its releases that handed recorded turns on. It is read from the journal rather than counted anywhere in a process for the same reason every run figure is — a durable store outlives the binary that wrote it, and a re-dispatch a resident made is as much a re-dispatch as one this process made.

func (*Store) NodeSpend

func (s *Store) NodeSpend(id string) (SpendSlice, error)

NodeSpend is what one job and everything under it has actually cost: the usage rows themselves, summed, with the number of priced model calls behind the figure.

Impact already summed the cost, and a caller that only has the cost cannot tell "nothing was ever billed here" from "what was billed rounds to nothing" — the two facts a question about money most needs kept apart. The run count separates them, so a read can say a figure is small without anybody having to explain why it might be zero.

func (*Store) Nodes

func (s *Store) Nodes() ([]Node, error)

Nodes returns every node, including folded history, in stable admission order.

func (*Store) OfferStandingWatch

func (s *Store) OfferStandingWatch(sessionID, charterID string) (bool, error)

OfferStandingWatch atomically records the never-ask-twice gate and surfaces exactly one selectable agent question. A restart can therefore land before or after the transaction, never between the flag and the question.

func (*Store) OfferStandingWatchStandDown

func (s *Store) OfferStandingWatchStandDown(sessionID string) (bool, error)

OfferStandingWatchStandDown asks, once per enablement, whether the quiet background checks should stop. It mirrors OfferStandingWatch exactly — atomic gate plus one selectable question — and reuses the enable/decline option codes, so the answer travels the route that already exists.

The gate is "since the last enable" rather than "ever": a user who stands the watch down and later turns it back on has a new consent, and a new consent can be withdrawn again.

func (*Store) OpenNodes

func (s *Store) OpenNodes() ([]Node, error)

OpenNodes is every node the graph has not finished with, FOLDED OR NOT.

Folding is a presentation decision about SETTLED work: a job is filed away once it is over, and the fold root then speaks for its members so the active view stays the size of what is happening. Nothing about that reasoning applies to a node that is still running, claimed or pending, and the day the two states met the reasoning failed outright — a running continuation whose lineage had been filed away was invisible to every read the head owns, so a person watching it tick on the rail asked to cancel it and was told, three board reads and five searches later, that no such work existed. The rail could see it; nothing the head could ask could.

So this is the corpus that answers "what is still going on", and its one law is that FOLDING HIDES NOTHING THAT IS STILL ALIVE. It is deliberately not a replacement for Store.ActiveNodes — the compact view is right for the question it answers — but any reader whose sentence turns on liveness must union this in, because a live node missing from that reader's world is not a tidier answer, it is a false one.

The permanent spine is excluded: it is Running forever by construction and is nobody's live work.

func (*Store) OpenOrReuseSession

func (s *Store) OpenOrReuseSession(id, surface string) (Session, bool, error)

OpenOrReuseSession is the `+ new room` door, and the whole of the difference between it and OpenSession is the question it asks first: is there already an empty unnamed room to walk into?

An empty room is not a document — it has no content to lose and no name to confuse with another — so two of them are indistinguishable to a reader and the second one is pure accumulation. Reusing is therefore not a compromise on "new": the room it hands back is exactly as new as the one it would have minted, and it journals nothing, which is the honest record of a request that changed nothing.

The boolean says which happened, for a caller that wants to word it.

func (*Store) OpenQuestions

func (s *Store) OpenQuestions(sessionID string, limit int) ([]AgentQuestion, error)

OpenQuestions returns every question in one session the user still owes an answer to, quiet and already-surfaced alike, oldest first.

PendingQuestions answers "what has nobody been shown yet", which is a surfacing decision. This answers "what is still waiting on you", which is the only honest basis for a lens that lists open questions: a blocking question crosses into the thread the instant it is asked, so anything built on the unsurfaced set is structurally blind to exactly the questions a running job is stuck behind.

func (*Store) OpenSession

func (s *Store) OpenSession(id, title, surface string) (Session, error)

OpenSession mints an empty room — one that exists before anything has been said in it — and is the single door for doing so. It is the capability a thread switcher needs: a new conversation is a place first and a transcript second, and until this event existed the store could only learn of a room by being spoken to in it.

Opening is a mint, not a touch. A room that already exists has already been opened, so a second call journals nothing and returns the row as it stands: appending a second birthday would put a fact in the journal that is not true, and replay would faithfully reproduce it. Callers that want to know which happened compare the returned Created against their own clock, or read the room first.

The empty id is not a room, for the reason EnsureSession states: messages posted to no room in particular carry one, and a nameless row would put a phantom thread in every thread list.

func (*Store) OpenThreads

func (s *Store) OpenThreads(limit int) ([]ThreadArc, error)

OpenThreads returns the conversations with an unresolved arc, newest active first. It is the one reader behind the head's alive glance and the surface's board home, so the two can never disagree about which threads are alive.

A thread is alive when one of three things is true of its end: the head asked and nothing came back, the person spoke and nothing answered, or work landed and nobody has been in the room since. Everything else has sunk.

func (*Store) OverrunDeferred

func (s *Store) OverrunDeferred(nodeID string) (bool, error)

OverrunDeferred reports whether a node ever handed its unfinished remainder to the durable rail queue. Completion narration uses it to keep the partial as internal evidence even after the continuation has resumed.

func (*Store) OverrunEvidenceFor

func (s *Store) OverrunEvidenceFor(nodeID string) ([]OverrunEvidence, error)

OverrunEvidenceFor reads back what was recorded against one node, oldest first. It is the read side of a retired mechanism: no run writes these any more, and this is how an audit still reads the ones an older run left.

func (*Store) Parameter

func (s *Store) Parameter(name string) float64

Parameter returns the replayed value or the coded registry default.

func (*Store) ParkedThreads

func (s *Store) ParkedThreads(now time.Time, idle time.Duration, limit int) ([]ThreadArc, error)

ParkedThreads is OpenThreads narrowed to the ones that have been sitting on their open thing longer than idle. It is the nudge's query: a thread parked since this morning is an ordinary working conversation, and one parked since last week is something the person has genuinely lost track of.

func (*Store) PauseDailyRail

func (s *Store) PauseDailyRail(base float64, sessionID string) (DailyRail, bool, error)

PauseDailyRail checks policy immediately before a claim or replan. At the rail it atomically posts at most one agent question since the latest raise; callers simply stop claiming and try again on their next tick.

func (*Store) PauseDailyRailWithAdditionalSpend

func (s *Store) PauseDailyRailWithAdditionalSpend(base float64, sessionID string, additional float64) (DailyRail, bool, error)

PauseDailyRailWithAdditionalSpend applies the same durable gate while also considering a known cost that has not happened yet. Generation tools use it for catalog-priced jobs; zero retains the ordinary pre-call gate path.

func (*Store) PauseTaskRail

func (s *Store) PauseTaskRail(nodeID, sessionID string, additional float64) (TaskRail, bool, error)

PauseTaskRail is the gate: it checks one node against the ceiling governing it immediately before the work starts, and at the ceiling it atomically posts at most one agent question per root per ceiling change. Callers do exactly what they do at the daily rail — stop, and try again on their next tick — except that the stop is scoped to this subtree.

The first thing it does is ask whether any ceiling exists at all, because the answer is no on every machine that has not set one and the whole check must cost nothing there.

func (*Store) PendingCommands

func (s *Store) PendingCommands(limit int) ([]Command, error)

PendingCommands returns unapplied commands oldest first — the reconciler's work queue.

func (*Store) PendingDailyRailApproval

func (s *Store) PendingDailyRailApproval(base float64, sessionID string) (DailyRail, bool, error)

PendingDailyRailApproval reports whether this session's most recent rail question still awaits a raise. The head uses it to intercept a plain "yes" without spending a model call or inventing a graph command.

It stays session-scoped on purpose. Falling back to another session's question would let a bare "yes" meant for something else entirely raise the day's ceiling; the pause is what guarantees this session was asked in the first place, and a raise by any session clears the rail for everyone, which turns an unanswered question into a moot one rather than a stuck one.

func (*Store) PendingOverruns

func (s *Store) PendingOverruns(limit int) ([]DeferredOverrun, error)

PendingOverruns returns repair plans that have not yet recorded a resumed event, oldest first. No process-local queue participates in correctness.

func (*Store) PendingQuestion

func (s *Store) PendingQuestion(sessionID string, beforeSeq int64) (Message, bool, error)

PendingQuestion returns the latest selectable askback this user message can answer. An intervening user turn consumes a question even when it was free text, preventing old choices from capturing unrelated conversation.

func (*Store) PendingQuestions

func (s *Store) PendingQuestions(sessionID string, limit int) ([]AgentQuestion, error)

PendingQuestions returns quiet, unsurfaced questions oldest first. An empty sessionID returns all sessions for resident policy work.

func (*Store) PendingSiblingCount

func (s *Store) PendingSiblingCount(id, parent string) (int, error)

PendingSiblingCount counts the work queued beside one node under the same parent, excluding the node itself. An empty parent is the spine root's missing parent, exactly as the node view reports it.

func (*Store) PlanGraphFor

func (s *Store) PlanGraphFor(prefix string) (PlanGraph, bool, error)

PlanGraphFor returns the newest plan journaled for a namespace. It reads the event directly, exactly as DeliveryGateFor does and for the same reason: the payload is sparse, looked up by id, and has no query anyone would run across it — so a materialized table would be a second copy of the truth with nothing to gain by existing.

func (*Store) PostMessage

func (s *Store) PostMessage(message Message) (Message, error)

PostMessage appends one thread message. Seq and Time on the argument are ignored; the returned Message carries the assigned values.

func (*Store) PracticedToday

func (s *Store) PracticedToday(now time.Time) (time.Duration, error)

PracticedToday is the wall clock spent on self-directed practice since local midnight — the day receipt's "42m practiced".

It is a read rather than a derivation because the derivation is a WHOLE GRAPH SCAN: the old self page answered this by walking Snapshot() for roots whose group is PracticeGroup, which is every node in the store to find a handful. The query below is those roots and nothing else.

WALL CLOCK, NOT SUM. Two practice roots that ran at the same time cost one stretch of clock, not two, and a day receipt that added them would tell the reader the machine practised for longer than the day was: the intervals are merged before they are totalled, the same rule store.SubtreeReceipts follows for a job's elapsed. A root still running is counted up to now, because it is still practising; a root with no start is not counted at all, because a node that never started spent no time (10.2.8 — absent is not zero, and here the absence genuinely means nothing was spent).

func (*Store) ProjectTraits

func (s *Store) ProjectTraits(now time.Time) ([]Fact, error)

ProjectTraits re-measures supported traits and supersedes only measurements with evidence.

func (*Store) PromoteCharter

func (s *Store) PromoteCharter(id, reason string, override bool) error

PromoteCharter records a user override of the earned ladder. Automatic promotion uses the same payload with Override=false from the review path.

func (*Store) PromoteService

func (s *Store) PromoteService(service Service) (Service, error)

PromoteService transfers a live job into the durable service view. The partial unique index is the race-safe enforcement of live name ownership.

func (*Store) PromoteTasteRule

func (s *Store) PromoteTasteRule(seq int64) (Fact, error)

PromoteTasteRule stands one candidate up as a rule the gate is held to.

func (*Store) PromptEligible

func (s *Store) PromptEligible(fact Fact) (bool, error)

PromptEligible applies the two-occurrence bar only to empirically weak channels.

func (*Store) ProposalCadenceRuns

func (s *Store) ProposalCadenceRuns() int

ProposalCadenceRuns scales the tuned cadence within hard rails by observed appetite.

func (*Store) ProposeCharterFiring

func (s *Store) ProposeCharterFiring(id string, wakeSeq int64, intent string) (bool, error)

ProposeCharterFiring posts exactly one selectable probation question for a checked-yes wake. The question and its proposal marker land atomically.

func (*Store) QuarantineFact

func (s *Store) QuarantineFact(factSeq, evidenceSeq int64, origin FactChangeOrigin) error

QuarantineFact removes one active fact from every retrieval path. The event itself is the evidence when evidenceSeq is zero, as for a direct CLI veto.

func (*Store) QuestionCategoryStats

func (s *Store) QuestionCategoryStats(category QuestionCategory) (CategoryStats, error)

QuestionCategoryStats measures answered durable questions by offered default.

func (*Store) QuestionForAnswer

func (s *Store) QuestionForAnswer(sessionID string, beforeSeq, referenceSeq int64) (AgentQuestion, bool, error)

QuestionForAnswer matches an explicit reference first, otherwise the most recent surfaced question with no intervening user turn.

func (*Store) QuestionPractices

func (s *Store) QuestionPractices(questionSeq int64) ([]QuestionPractice, error)

QuestionPractices lists every round for one question.

func (*Store) Questions

func (s *Store) Questions(status string, limit int) ([]Fact, error)

Questions lists knowledge gaps in newest-first order. Empty status includes the complete question history.

func (*Store) QuestionsForAnswer

func (s *Store) QuestionsForAnswer(sessionID string, beforeSeq int64) ([]AgentQuestion, error)

QuestionsForAnswer returns every surfaced question this reply could plausibly be answering, newest first. QuestionForAnswer takes the first of these and that is right whenever there is only one; when there are several, "newest wins" is a coin toss dressed as a rule, and the caller needs to see the whole set before it silently spends one of them.

func (*Store) QuestionsForNode

func (s *Store) QuestionsForNode(nodeID string, limit int) ([]AgentQuestion, error)

QuestionsForNode returns every question one node has asked, newest first, whatever became of each. UnresolvedQuestions answers "what is outstanding", which is a live queue; this answers "what has this node already asked and what was said back", which is a durable record. A stop that must be put to the user exactly once — and that means something different once they have answered it — can only be built on the second: a question drops out of the unresolved set the moment it is answered, and a marker that disappears when the answer arrives is a question that gets asked forever.

func (*Store) RaiseDailyRail

func (s *Store) RaiseDailyRail(amount float64, origin string) error

RaiseDailyRail journals consent to extend today's ceiling.

func (*Store) RaiseDailyRailUnlimited

func (s *Store) RaiseDailyRailUnlimited(origin string) error

RaiseDailyRailUnlimited journals consent to remove today's ceiling. The configured default remains unchanged and returns at local midnight.

func (*Store) RaiseTaskCeiling

func (s *Store) RaiseTaskCeiling(root string, amount float64, origin string) error

RaiseTaskCeiling lifts an existing ceiling by amount. It is the verb the question promises, so it exists beside the setter rather than leaving consent to reconstruct the new total from a figure that may have moved underneath it.

func (*Store) Ready

func (s *Store) Ready(limit int) ([]Node, error)

Ready returns pending active nodes whose hard dependencies have all settled. Failed and cancelled dependencies are terminal by design; their digest is available through DependencyDigests.

func (*Store) ReapEmptySessions

func (s *Store) ReapEmptySessions(keep string) ([]string, error)

ReapEmptySessions takes back the empty unnamed rooms that accumulated before the two doors above existed, and returns the ids it discarded.

It keeps two rooms out of the reap on purpose. The newest empty one stays because an empty room is what `+ new room` just made and the next launch must not delete the place somebody is standing in; keep stays because it is the room this launch resolved, and a window may not open onto a row it is about to remove. Everything older than both is a room that was opened, never spoken in, and left behind.

The delete is journaled rather than performed quietly, because the sessions table is a projection: a bare DELETE would be undone by the next `codeaf rebuild`, and a projection that disagrees with the journal is the one thing this store does not have. A discarded room replays as discarded.

func (*Store) Rebuild

func (s *Store) Rebuild() error

Rebuild discards and reconstructs both materialized views solely by replaying the immutable event journal. The replacement happens in one transaction, so readers never observe a half-rebuilt graph.

func (*Store) Recall

func (s *Store) Recall(terms string, scopeCues []string, limit int) ([]RecallHit, error)

Recall searches folded graph memory using lexical relevance, optional workspace/file cues, and recency. FTS is deliberately first: embeddings add cost and opacity before there is evidence that local lexical recall fails. Hostile FTS input is treated as a miss so memory can specialize a run but can never prevent it from starting.

func (*Store) RecentFacts

func (s *Store) RecentFacts(limit int) ([]Fact, error)

RecentFacts returns the newest active facts across all scopes.

func (*Store) RecentQuestionPractices

func (s *Store) RecentQuestionPractices(limit int) ([]QuestionPractice, error)

RecentQuestionPractices is every practice round of the newest rounds, in ONE query, so a page listing thirty questions costs one read instead of thirty.

Store.QuestionPractices answers per question and stays the right read for the resident, which is always working on one gap at a time. A surface is not: it draws the whole band on every journal move, and thirty indexed queries per move is thirty round trips to answer a question the table can answer once. The caller buckets by QuestionPractice.QuestionSeq.

Newest first, because a window that has to drop rounds should drop the oldest.

func (*Store) RecentSentinelJudgments

func (s *Store) RecentSentinelJudgments(id string, limit int) ([]SentinelJudgment, error)

RecentSentinelJudgments returns a charter's last judgments, newest first.

A poll charter's evidence is the constant condition string, so the sentinel's input is byte-identical every wake — which means a firing the user has already declined will be judged the same way, forever, by a call that has no way of knowing it ever happened before. This is that memory: one bounded read of the charter's own journal, shaped like DeliveryGateFor, with no new table and no new event behind it.

The outcome is paired in the same pass rather than queried per judgment. The journal is ordered, so walking backwards means every firing or refusal is seen before the check that produced it.

func (*Store) RecordAcceptance

func (s *Store) RecordAcceptance(nodeID string, acceptance Acceptance) error

RecordAcceptance journals the checklist against the node whose delivery it governs. An empty checklist writes nothing: a request that states no checkable behaviour has no checklist, and an event saying so would be a row every reader has to learn to ignore.

func (*Store) RecordAssumedWithDefault

func (s *Store) RecordAssumedWithDefault(category QuestionCategory, defaultAnswer, sessionID, question string) error

RecordAssumedWithDefault journals every skipped ask for later correction matching.

func (*Store) RecordCharterFiringOutcome

func (s *Store) RecordCharterFiringOutcome(assessment CharterFiringAssessment, tenureAfter int) (bool, error)

RecordCharterFiringOutcome admits one independent verification result. A job can affect the ladder once even when several terminal/usage events mention it.

func (*Store) RecordConsumers

func (s *Store) RecordConsumers(nodeID string, reading ConsumersReading) error

RecordConsumers journals one reading of the changed definitions against a node.

EVERY READING IS WRITTEN, including one that found nothing, for the reason RecordSurface's is: "the diff overlapped no declaration" and "nobody looked" are two facts and the absence of the row is the only spelling either has.

func (*Store) RecordCraftForged

func (s *Store) RecordCraftForged(forged CraftForged) (int64, error)

RecordCraftForged journals one forging. There is no view to materialize — the repository is the view — so this writes the event and stops, which is why replay decodes it and does nothing else.

func (*Store) RecordDeliveryGate

func (s *Store) RecordDeliveryGate(nodeID string, gate DeliveryGate) error

RecordDeliveryGate appends one gate result. It has no materialized view: the event is sparse, read by node id, and remains the source of truth on rebuild.

func (*Store) RecordFact

func (s *Store) RecordFact(nodeID, scope string, kind FactKind, body string) (Fact, error)

RecordFact appends one learned fact. An identical active or quarantined fact in the same scope is superseded rather than duplicated — write-time hygiene is what keeps the notebook worth reading.

func (*Store) RecordFactFrom

func (s *Store) RecordFactFrom(writer FactWriter, nodeID, scope string, kind FactKind, body string) (Fact, error)

RecordFactFrom derives and persists the observation channel from writer.

func (*Store) RecordFactInjection

func (s *Store) RecordFactInjection(nodeID string, factSeqs []int64) error

RecordFactInjection attributes one bounded notebook batch to the node whose context received it. Repeated calls are legal; outcome accounting counts a fact's ride on a node once.

func (*Store) RecordJobGrowth

func (s *Store) RecordJobGrowth(jobRoot string, growth JobGrowth) error

RecordJobGrowth journals one growth decision against a job root. Losing it costs the round counter its memory and diagnosis its record, so callers treat a failure as a note — but they do treat it: an unrecorded admission is a round nobody spent.

func (*Store) RecordLeafExhausted

func (s *Store) RecordLeafExhausted(nodeID string, record LeafExhausted) error

RecordLeafExhausted appends one attempt's exhaustion against a node.

func (*Store) RecordLeafMode

func (s *Store) RecordLeafMode(nodeID string, mode LeafMode) error

RecordLeafMode journals one dispatch. Losing it costs diagnosis and nothing else, so every caller treats a failure as a note rather than an error.

func (*Store) RecordLeafResumed

func (s *Store) RecordLeafResumed(nodeID string, record LeafResumed) error

RecordLeafResumed appends what a fresh claim picked up. A resumption of zero turns is refused rather than journaled: the whole value of this row is that it distinguishes a leaf that carried its predecessor's work from one that did not, and a row saying "resumed from nothing" would blur exactly that line.

func (*Store) RecordLeafSelfClose

func (s *Store) RecordLeafSelfClose(nodeID string, record LeafSelfClose) error

RecordLeafSelfClose appends one leaf's reading of its own work. A row naming no finding is refused: this record exists to say what the leaf found against itself, and "it found nothing" is what the surface, unbound and verification rows beside it already say.

func (*Store) RecordLeafStopped

func (s *Store) RecordLeafStopped(nodeID string, record LeafStopped) error

RecordLeafStopped appends one worker's report that it is gone.

func (*Store) RecordMemoryOutcome

func (s *Store) RecordMemoryOutcome(helped, unused []string) error

RecordMemoryOutcome settles what a turn's injected memories actually did: helped names the ones that bore on the answer, unused names the ones that were put in front of the model and did not.

BOTH HALVES OR NEITHER, in one transaction, for the reason the retrieval count was always written in one: a turn's accounting is one fact about that turn, and half of it landing is a ranking signal nobody can interpret.

It writes no event, for the reason stated on Memory.UseCount — the journalled floor is Store.SnapshotMemoryRanking's job. Ids that name nothing, or name an inactive memory, are skipped in silence: telemetry is not a place to raise an alarm about a stale pointer.

func (*Store) RecordNodeBrief

func (s *Store) RecordNodeBrief(nodeID string, brief NodeBrief) error

RecordNodeBrief journals one node's rendered brief against the store id the node was minted under. It is best-effort in the same sense RecordPlanGraph is: a write that fails costs an audit and never the plan. The blob in RecordPlanGraph stays the source of the whole graph; this is the per-node index that makes one leaf's criterion answerable without re-reading it.

func (*Store) RecordNodeFault

func (s *Store) RecordNodeFault(nodeID, scope, fault string) error

RecordNodeFault appends one recovered fault against a node.

It is lenient about the node in one direction only: an empty id is refused, because a fault filed against nothing is a row no reader can find. Everything else about it is deliberately cheap — one append, no view, no lock beyond the write transaction — because it is called from a deferred recover, and a failsafe that can itself be slow or fussy on the unwinding path is a failsafe that will one day swallow the very fault it exists to report.

func (*Store) RecordNodeRan

func (s *Store) RecordNodeRan(id, subharness, reason string) (bool, error)

RecordNodeRan journals the worker that is running this node, and returns whether anything changed.

It is the answer to a question the `subharness` column cannot answer. That column records an ASSIGNMENT — what the node was to be run on — and it is legitimately empty for the great majority of nodes, because nothing routes a node and the generalist is what a node with no assignment gets. This records a FACT ABOUT THE RUN: the dispatch path resolved that empty assignment to an executor, and the executor has a name. An autopsy that can only read the assignment cannot tell an unrouted node from a node nobody ran.

It refuses nothing but a blank. A node may be recorded before it settles and once more per hand-over, and a name this build does not have is stored as faithfully as one it does — the store carries names and holds no opinion about which ones exist.

func (*Store) RecordPlanGraph

func (s *Store) RecordPlanGraph(prefix string, plan PlanGraph) error

RecordPlanGraph journals a job's plan against the id namespace its nodes were minted under. It is written on every revision as well as at plan time, and later events simply win: an append-only journal corrects by appending, and the reader below asks only for the newest.

func (*Store) RecordQuestion

func (s *Store) RecordQuestion(nodeID, scope, body string) (Fact, error)

RecordQuestion journals one open knowledge gap. A scope has at most one question over its lifetime: resolved and retired gaps are hysteresis, not an invitation for a periodic scan to manufacture the same curriculum again.

func (*Store) RecordScaleGate

func (s *Store) RecordScaleGate(prefix string, gate ScaleGate) error

RecordScaleGate journals one job's shape against the id namespace its nodes were minted under, which is the same key RecordPlanGraph uses so the two read together. It is written before the splice — there is no node to charge yet, exactly as with planning spend — and losing it costs diagnosis and nothing else, so every caller treats a failure as a note rather than an error.

func (*Store) RecordSentinelCheck

func (s *Store) RecordSentinelCheck(id string, check SentinelCheck) error

RecordSentinelCheck records yes, no, and provider error outcomes. A no or error closes the wake; yes leaves a durable firing pending.

func (*Store) RecordSkillCandidate

func (s *Store) RecordSkillCandidate(nodeID, scope, body, artifact string, trust ...string) (Fact, error)

RecordSkillCandidate journals a procedure the distiller found in one job. It is intentionally absent from retrieval until a later execution event activates it. Trust defaults to "authored" when empty.

func (*Store) RecordSkillCandidateFrom

func (s *Store) RecordSkillCandidateFrom(writer FactWriter, nodeID, scope, body, artifact string, trust ...string) (Fact, error)

RecordSkillCandidateFrom records a candidate on writer's channel.

func (*Store) RecordStandingWatchDecision

func (s *Store) RecordStandingWatchDecision(decision StandingWatchDecision, reason string) error

RecordStandingWatchDecision appends one final decision. Replaying a command after a crash is idempotent when it agrees with the journal and rejected if it conflicts with the decision already made.

func (*Store) RecordStandingWatchPass

func (s *Store) RecordStandingWatchPass(pass StandingWatchPass) error

RecordStandingWatchPass records one completed `codeaf wake` pass.

func (*Store) RecordStructuredRepair

func (s *Store) RecordStructuredRepair(nodeID string, repair StructuredRepair) error

RecordStructuredRepair journals one repair against the node it was made for — or against the job root, when it happened before any node existed, which is where the planner's repairs happen and where the s4 sweep lost a whole run.

Losing the row costs the autopsy its evidence and nothing else, so callers treat a failure as a note: a repair that could not be written down is not a reason to stop a run that is otherwise recovering.

func (*Store) RecordSurface

func (s *Store) RecordSurface(nodeID string, reading SurfaceReading) error

RecordSurface journals one symbol-level comparison against a node.

EVERY COMPARISON IS WRITTEN, including one that found nothing. "Sixteen files were compared and no public name was lost" and "nobody compared anything" are two facts, and the absence of the row was the only spelling either of them had.

func (*Store) RecordSurprise

func (s *Store) RecordSurprise(surprise NodeSurprise) error

RecordSurprise attaches a defined profile prediction residual to one node. Undefined expectations produce no event, preserving absent versus zero.

func (*Store) RecordTasteCandidate

func (s *Store) RecordTasteCandidate(nodeID, subject, body string) (Fact, error)

RecordTasteCandidate opens one shelf with the correction that named it. A shelf may be opened once; every later standing is a re-record over the same scope, which is what makes the shelf the rule's durable identity.

func (*Store) RecordTasteCorrectionOnce

func (s *Store) RecordTasteCorrectionOnce(nodeID, subject, body string) (Fact, bool, error)

RecordTasteCorrectionOnce files a free-text taste answer where corrections already live: on the shelf's subject, as an ordinary preference line, which is exactly what the aggregation pass reads. It is idempotent because the answer is durable and the pass that reads it runs every tick — recording the same sentence again would supersede its own copy forever, and a notebook that churns is a notebook nobody can trust.

recorded is false when the line is already on that shelf.

func (*Store) RecordTrait

func (s *Store) RecordTrait(name string, measurement TraitMeasurement) (Fact, error)

RecordTrait supersedes the active singleton for name with one re-measurement.

func (*Store) RecordTranscript

func (s *Store) RecordTranscript(nodeID, model string, entries []TranscriptEntry) error

RecordTranscript appends one flush of one leaf's record to the journal.

It is called repeatedly during a run rather than once at the end, and that is the point: a leaf can die mid-loop — a panic in a tool, a deadline, the process going away — and what it had already done must survive the way it happened. An empty batch is not an event.

Bounds are applied HERE rather than trusted from the caller, because this is the durable edge and a writer that forgot to truncate would otherwise put an unbounded blob in the journal forever.

func (*Store) RecordTurnUsage

func (s *Store) RecordTurnUsage(nodeID, model string, turns []TurnUsage) error

RecordTurnUsage appends one execution's per-turn shape to the journal.

It is a companion to RecordUsage rather than a replacement for it, and callers write both: the node row is what every existing reader sums, this is what a reader asking about shape needs. An empty ledger is not an event — an executor that does not meter turns has recorded no shape, which is a different fact from a leaf that ran none.

func (*Store) RecordUnbound

func (s *Store) RecordUnbound(nodeID string, reading UnboundReading) error

RecordUnbound journals one reading of the run's own references against a node.

EVERY READING IS WRITTEN, including one that found nothing, for the reason RecordSurface's is: "the changed sources reference nothing this tree fails to bind" and "nobody looked" are two facts and the absence of the row is the only spelling either has.

func (*Store) RecordUnsettledFact

func (s *Store) RecordUnsettledFact(nodeID, scope string, pair UnsettledPair) (Fact, error)

RecordUnsettledFact appends one structured competing pair. Its Body is derived from the pair so the searchable prose cannot disagree with code.

func (*Store) RecordUnsettledFactFrom

func (s *Store) RecordUnsettledFactFrom(writer FactWriter, nodeID, scope string, pair UnsettledPair) (Fact, error)

RecordUnsettledFactFrom records a structured pair on writer's channel.

func (*Store) RecordUsage

func (s *Store) RecordUsage(usage NodeUsage) error

RecordUsage appends one node's spend to the journal. Zero-valued usage is recorded too: "this ran and cost nothing measurable" is information.

func (*Store) RecordVerification

func (s *Store) RecordVerification(nodeID string, reading VerificationReading) error

RecordVerification journals one reading, or one reading that could not be taken, against a node.

A ROW THAT SAYS NOTHING IS THE ONLY ONE NOT WRITTEN. A reading naming neither a command nor a reason is the zero value — nobody called this — and a row for it would be one every reader has to learn to ignore. Everything else is written, including every refusal: the absence of the event used to be the only spelling of four different facts.

func (*Store) Release

func (s *Store) Release(claim Claim) error

Release returns claimed or running work to pending and increments the token again. The extra increment is what makes the released Claim stale before a replacement worker even arrives.

func (*Store) ReleaseOrphans

func (s *Store) ReleaseOrphans() ([]string, error)

ReleaseOrphans returns every claimed or running node to pending. It exists for surface startup: the chat store has exactly one resident writer, so any claim found at open belongs to a process that died or was closed mid-run — the user watched a leaf sit "running" for 49 minutes with no worker behind it. Each release goes through the ordinary CAS path with the recorded owner and token, so the journal tells the truth and a genuinely live worker (a race at the margin) keeps its claim by failing our stale CAS.

func (*Store) ReleaseWithReason

func (s *Store) ReleaseWithReason(claim Claim, reason string) error

ReleaseWithReason is Release with the sentence that explains it, journaled on the release itself. Everything that takes a claim back from a worker that did not offer it uses this one, so the record always says who decided and why.

func (*Store) ReleaseWithRecord

func (s *Store) ReleaseWithRecord(claim Claim, reason string, recorded int) error

ReleaseWithRecord is ReleaseWithReason for the one release that hands work on rather than takes it away: a leaf that ran out of its room, whose recorded turns the next claim will carry on from. The count is journaled beside the reason so a reader can tell this release from the reaper's without reading the sentence — see [releasePayload.Recorded].

func (*Store) ReleasedTurnsFor added in v0.3.0

func (s *Store) ReleasedTurnsFor(nodeID string) (int, bool, error)

ReleasedTurnsFor is how many recorded turns the newest hand-on release left waiting for the next claim, or that no release of this node ever handed work on. It exists because the release is where the count the attempt before banked is written down — the settle that re-dispatched the node journaled it in the same breath as the reason — and the settle that has to COMPARE against it (a re-dispatch deciding whether it moved) cannot compose that comparison from its own memory across processes.

Releases that took a claim back without handing work on are not it: they say nothing about how much the attempt before banked, and the newest count that does say is the one a re-dispatch is compared against.

func (*Store) RemoveEdge

func (s *Store) RemoveEdge(from, to string, kind EdgeKind) error

RemoveEdge withdraws a dependency a pending consumer no longer needs — the other half of rewiring, with AddEdge as the first.

func (*Store) RenameSession

func (s *Store) RenameSession(id, title string) (Session, error)

RenameSession retitles an existing room. It is the door OpenSession deliberately is not: OpenSession refuses to re-title a room that already exists, because a second birthday would be a false fact, but a person renaming a tab is not claiming the room was just born — they are stating a new name for something that already has one. Renaming a room that does not exist is refused rather than minting it: a rename names an intent about an existing place, and a caller with no room to rename has a bug, not a new room to open.

Renaming to the title the room already has journals nothing, the same idempotence OpenSession gives a second open: two switchers racing to set the identical name must not put two facts in the journal for one true state, and a rebuild replaying the single event they agree on must land on the same row either way.

The projection write touches only the title. A rename is not activity — nobody spoke, nothing happened in the room — so created_at and last_active_at are exactly what they were before this call.

func (*Store) RenameSessionTagged

func (s *Store) RenameSessionTagged(id, title string, tags []string) (Session, error)

RenameSessionTagged is RenameSession plus the subjects the room is filed under. It is the naming pass's door and deliberately not a second verb: a title and the tags beside it come out of ONE reading of what the room is about, so they are one event and land or fail together.

An empty tag list states nothing about the subject and therefore changes nothing about it — see [sessionRenamedPayload].

func (*Store) ReplaceFact

func (s *Store) ReplaceFact(factSeq int64, nodeID, scope string, kind FactKind, body string) (Fact, error)

ReplaceFact records a new ordinary fact and supersedes factSeq in the same transaction. A failed replacement leaves neither event behind.

func (*Store) ReplaceFactFrom

func (s *Store) ReplaceFactFrom(writer FactWriter, factSeq int64, nodeID, scope string, kind FactKind, body string) (Fact, error)

ReplaceFactFrom records a replacement on writer's derived channel.

func (*Store) ReplaceUnsettledFactFrom

func (s *Store) ReplaceUnsettledFactFrom(writer FactWriter, factSeq int64, nodeID, scope string, pair UnsettledPair) (Fact, error)

ReplaceUnsettledFactFrom carries a pair forward on writer's channel.

func (*Store) RequestCommand

func (s *Store) RequestCommand(command Command) (Command, error)

RequestCommand records one asynchronous mutation request and returns immediately. The reconciler picks it up via PendingCommands and settles it with ResolveCommand; the requester never blocks on the mutation itself.

func (*Store) RequestNodeCancel

func (s *Store) RequestNodeCancel(id, reason string) error

RequestNodeCancel records cooperative cancellation for a claim owner to observe between model turns. Pending nodes use CancelPending directly.

func (*Store) ResidentWatermarkFor

func (s *Store) ResidentWatermarkFor(lane ResidentLane) (ResidentWatermark, bool, error)

ResidentWatermarkFor returns one lane's latest watermark, if it has ever run.

func (*Store) ResolveCommand

func (s *Store) ResolveCommand(seq int64, status CommandStatus, result string) error

ResolveCommand settles a pending command exactly once. Status must be CommandApplied or CommandRejected; result says what actually happened and belongs in the system message reported back to the thread.

func (*Store) ResolveOverrun

func (s *Store) ResolveOverrun(deferred DeferredOverrun) error

ResolveOverrun journals that one deferred repair is now represented in the graph. The event follows the splice, so a crash can never discard the plan.

func (*Store) ResolveQuestion

func (s *Store) ResolveQuestion(seq int64, status AgentQuestionStatus, resolution string, messageSeq ...int64) error

ResolveQuestion terminally settles a question exactly once. Answered questions must have been surfaced or already linked to an agent message; expiry may retire either a pending or asked question. messageSeq optionally points at the user reply.

func (*Store) ResolveQuestionWithCommand

func (s *Store) ResolveQuestionWithCommand(seq int64, resolution string, answerSeq int64, command Command) (Command, bool, error)

ResolveQuestionWithCommand atomically settles one selectable question and enqueues its continuation command. The conditional no-op update takes the SQLite write lock before reading the question, so racing message and dock answers serialize: exactly one transaction journals both events and later answers observe an already-settled question without creating another command.

func (*Store) ResolveRole

func (s *Store) ResolveRole(role ModelRole, nodeID string) (ResolvedRole, error)

ResolveRole answers what one role runs on at one node, and says which rung answered.

The precedence is one sentence in five parts, and the order is the whole contract:

  1. the node's PIN — nodes.work_model for the work role, nodes.plan_model for the plan role. A pin is what the node was promised, by its splice or by CommandSetModel's subtree sweep, and a promise outranks an inheritance.
  2. a binding at node:<id> — this node and no other.
  3. a binding at task:<root> — the nearest governing ancestor, itself included, exactly as a task ceiling resolves.
  4. a binding at global.
  5. the compiled-in default this process installed.

With nothing bound and no defaults installed the answer is RoleUnbound with an empty model, and a caller must then do precisely what it did before this table existed. That is the guarantee the empty table buys, and it is why the first thing this does after reading a pin is ask whether the table holds a single row for this role — on an untouched machine the walk never runs.

An empty node id is the global question, which is what a chip at home asks: pins and scopes are skipped and resolution starts at global.

func (*Store) ResolveRoleForNode

func (s *Store) ResolveRoleForNode(role ModelRole, node Node) (ResolvedRole, error)

ResolveRoleForNode is the dispatch-path shape: the caller already holds the row, so the pin costs no query at all and an unbound machine answers out of one covering probe of an empty table.

func (*Store) ResolveScope

func (s *Store) ResolveScope(scope string) (string, error)

ResolveScope follows aliases to the current shelf. A corrupt cycle is an error rather than a partial answer; the visited-set guard also makes old or manually edited databases safe to query.

func (*Store) RestService

func (s *Store) RestService(id, reason string, restartCount int) error

func (*Store) RestartService

func (s *Store) RestartService(id string, pid int, startedAt time.Time, restartCount int) error

func (*Store) RestoreFact

func (s *Store) RestoreFact(factSeq int64, origin FactChangeOrigin) error

RestoreFact returns one quarantined fact to retrieval. Restoration is a new journal event; the quarantine evidence remains intact in the earlier event.

func (*Store) RestoreMemory

func (s *Store) RestoreMemory(id string) error

RestoreMemory returns a forgotten memory to the active views. Superseded memories remain retired because their replacement is still the store's truth.

func (*Store) ResurfaceQuestion

func (s *Store) ResurfaceQuestion(seq int64, sessionID string) (Message, error)

ResurfaceQuestion carries an unanswered question into a live session and re-posts it there. It is the recovery path for a blocking question whose original session is gone: the request behind it was never dropped by anyone's decision, it simply stopped being visible, and a question nobody can see is a request that was silently abandoned.

Unlike SurfaceQuestion this moves the question's own session, because QuestionForAnswer is session-filtered — showing the words without moving the question would render a prompt the user's reply could not reach.

func (*Store) RetireExpiredCharter

func (s *Store) RetireExpiredCharter(id string, now time.Time) (bool, error)

RetireExpiredCharter journals expiry before any wake-time model call.

func (*Store) RetireExpiredCharters

func (s *Store) RetireExpiredCharters(now time.Time) (int, error)

RetireExpiredCharters applies expiry even while a charter is paused or still proposed; expiry is a standing-spend boundary, not a scheduling state.

func (*Store) RetractedFacts

func (s *Store) RetractedFacts(limit int) ([]Fact, error)

RetractedFacts lists what the user has explicitly thrown away, newest first.

The derivation path's whole visible world is FactActive — searchFacts filters on it in both arms and the quarantine also deletes the row from the FTS index — so the one thing the distiller could never see was what the user had refused, which is exactly the thing it needs in order not to write it down again. The store now refuses to promote a human veto on its own (see recordFact), and this is the other half: the lines a derivation prompt can be shown as already-rejected, so the model has the evidence rather than the system having a rule.

func (*Store) RetrospectiveRuns

func (s *Store) RetrospectiveRuns() (int, error)

RetrospectiveRuns counts existing checkpoints; it is rebuild-stable by construction.

func (*Store) RetrospectiveWatermark

func (s *Store) RetrospectiveWatermark() (RetrospectiveWatermark, bool, error)

RetrospectiveWatermark returns the latest checkpoint, if reflection has run.

func (*Store) ReturnCharterToProbation

func (s *Store) ReturnCharterToProbation(id, reason string) error

ReturnCharterToProbation is the conversational "back to asking" path. It is not a failure demotion and therefore does not consume the two-strike pause.

func (*Store) ReviseCharter

func (s *Store) ReviseCharter(id, invariant string, watch WatchSpec, sentinelHint string,
	action CharterAction, rails CharterRails) error

ReviseCharter replaces the editable definition while preserving identity, status, and ratification history. A changed watch starts from a fresh due calculation so old cadence state cannot leak into the revision.

func (*Store) RewriteActiveSkillFrom

func (s *Store) RewriteActiveSkillFrom(writer FactWriter, nodeID, scope, body string, sourceSeq int64) (Fact, error)

RewriteActiveSkillFrom rewrites an active skill on writer's channel.

func (*Store) RoleBindingAt

func (s *Store) RoleBindingAt(role ModelRole, scope BindingScope) (RoleBinding, bool, error)

RoleBindingAt reads exactly what is bound at one scope, which is not the same question as what governs a node there. ResolveRole answers that one.

func (*Store) RoleBindings

func (s *Store) RoleBindings() ([]RoleBinding, error)

RoleBindings lists every binding in force, in ladder order and then by scope, which is the order the settings view shows five rows in.

func (*Store) RoleDefaults

func (s *Store) RoleDefaults() RoleDefaults

RoleDefaults reports the installed floor, as a copy.

func (*Store) ScaleGateFor

func (s *Store) ScaleGateFor(prefix string) (ScaleGate, bool, error)

ScaleGateFor returns the newest reading journaled for a namespace. It reads the event directly, exactly as PlanGraphFor does and for the same reason: the payload is sparse, looked up by id, and has no query anyone would run across it.

func (*Store) ScopeAliases

func (s *Store) ScopeAliases() ([]ScopeAlias, error)

ScopeAliases lists old names with their transitive canonical destination.

func (*Store) ScopeSurprises

func (s *Store) ScopeSurprises(minSamples int) ([]ScopeSurprise, error)

ScopeSurprises joins journaled residuals back to the scopes distilled from their settled user jobs. Only the newest minSamples residuals determine the current error level; older jobs still contribute to relevance.

func (*Store) SearchActiveCharters

func (s *Store) SearchActiveCharters(reference string) ([]Charter, error)

SearchActiveCharters uses SQLite's BM25 rank over invariant text. An empty reference deliberately returns every active charter so pronouns can resolve when there is exactly one and ask back when there is more than one.

func (*Store) SearchConversations

func (s *Store) SearchConversations(terms string, limit int) ([]ConversationHit, error)

SearchConversations finds conversation by its words ACROSS EVERY THREAD, with each hit carrying the name of the thread it came from.

IT IS ONE FTS QUERY AND IT STAYS ONE. The title comes from a LEFT JOIN in the same statement rather than a lookup per hit, which is the difference between a search page and a search page that opens fifty connections to draw fifty rows (see internal/store's memory snapshot for the same defect written down). The ranking, the bound on one quoted body, and the tolerance of hostile FTS syntax are all Store.SearchMessages's and deliberately not restated here.

There is no session filter: a search PLACE is the question "we talked about this once", and the answer to it is the whole machine. A caller that wants one thread already has Store.SearchMessages.

func (*Store) SearchFacts

func (s *Store) SearchFacts(query FactQuery) ([]Fact, error)

SearchFacts blends the two retrieval layers under reserved slots: the scope cues get their share, relevance gets a share that nothing can eat, and the leftovers go to whichever arm still has candidates. Returned facts have their use telemetry bumped.

func (*Store) SearchFactsUncounted

func (s *Store) SearchFactsUncounted(query FactQuery) ([]Fact, error)

SearchFactsUncounted performs the same retrieval without changing use telemetry. Notebook maintenance calls use it so the notebook cannot make its own lines look useful merely by inspecting them.

func (*Store) SearchMemories

func (s *Store) SearchMemories(query string, limit int) ([]Memory, error)

SearchMemories finds active memories by their words, best match first.

Ranking is bm25 with the more recently touched memory as the tiebreak. The tiebreak is not a term: a search that quietly preferred recent memories would answer "what did we decide about pricing" with whatever was said this morning, which is the failure the store exists to prevent.

A query nothing can be made of — punctuation, or nothing but words shorter than the index keeps — is a miss and not an error. ftsQueryFrom is what makes that safe to say: it reduces the caller's words to quoted alphanumeric terms joined by OR, so hostile FTS syntax never reaches MATCH and a failure here is a real failure worth returning.

func (*Store) SearchMessages

func (s *Store) SearchMessages(terms, sessionID string, limit int) ([]MessageHit, error)

SearchMessages finds conversation by its words, newest first among equals.

Ranking is bm25 with recency as the tiebreak rather than as a term: the whole failure this read exists for is a question about something old, and a search that quietly prefers recent lines answers it with the same window the caller already had. A session filter narrows to one thread; empty searches every thread, which is what a person means by "we talked about this once".

func (*Store) SearchRestartableServices

func (s *Store) SearchRestartableServices(reference string) ([]Service, error)

SearchRestartableServices includes stopped history so the startup receipt's “start it again” instruction has a real conversational target. The newest incarnation of each name wins when a stopped name was later reused.

func (*Store) SearchServices

func (s *Store) SearchServices(reference string) ([]Service, error)

func (*Store) SearchSurgeryTargets

func (s *Store) SearchSurgeryTargets(reference string, includeLeaves bool, allowed ...Status) ([]SurgeryTarget, error)

SearchSurgeryTargets mirrors charter reference resolution with a small in-memory BM25 index over the current snapshot. Title and brief dominate; verbatim intent and landed summary still make ordinary user wording work.

A statusless search — the read, as opposed to the verb — also reaches fold roots, and that is a correction. Every folded node was excluded here, which is right for a fold's members and wrong for its root: folding is what happens to a job once it is thoroughly over, and a job that is over is exactly the one a person asks about the next day. The transcript was a settled, distilled and folded architecture review, asked about in a fresh session, answered with "nothing in the current graph or notebook matches" — honestly, because the search could not see it. A fold root durably carries the digest and the pointers to what it wrote; its members are represented by it and stay hidden, because the root speaks for them.

The eligibility is deliberately tied to the absence of a status filter rather than tested at each call site. Every caller that intends to act supplies the statuses its verb may legally touch, and no verb may touch settled work; every caller that intends to read supplies none. So the same argument that already separates reading from acting decides this, and no folded node can be reached by a verb through a route that did not exist before. The same argument decides the corpus. A statusless read searches the addressable graph — which includes the jobs a territory packed away — and a verb searches the compact one it always did. Filing a settled job under a territory was never meant to decide whether it can be spoken about, and it was deciding exactly that: the read that opens the head's toolbelt starts here, so a January job being tidied in February made every later question about it fall through to a router with no January in its context at all.

func (*Store) SeedRoleBinding

func (s *Store) SeedRoleBinding(role ModelRole, scope BindingScope, value, origin string) (bool, error)

SeedRoleBinding is the initializer's door: CODEAF_PLAN_MODEL and --plan-model set the global plan binding through it at startup.

It writes in exactly two cases — nothing is bound yet, or what is bound was written by an initializer and the initializer now says something else. It never overwrites a binding a person made, because an environment variable that outranks the palette would make the palette a liar the next time the process restarted, and it never rewrites its own unchanged value, because every boot would then journal an event nobody caused.

func (*Store) SelfReceipts

func (s *Store) SelfReceipts(since time.Time) ([]SelfReceipt, error)

SelfReceipts returns receipts at or after since in journal order. A zero time returns the full history.

func (*Store) SelfSpendToday

func (s *Store) SelfSpendToday() (float64, error)

SelfSpendToday sums today's settled self-work receipts. The receipt is the attribution boundary, while its Cost came from the same usage table read by SpendToday.

func (*Store) Service

func (s *Store) Service(id string) (Service, bool, error)

func (*Store) ServiceByName

func (s *Store) ServiceByName(name string) (Service, bool, error)

func (*Store) ServiceHygieneAsked

func (s *Store) ServiceHygieneAsked(serviceID string) (bool, error)

ServiceHygieneAsked reports whether the once-per-service hygiene nudge has already been journaled. The durable question is the memory; asking twice about the same service is the thing this prevents.

func (*Store) Session

func (s *Store) Session(id string) (Session, bool, error)

Session reads one thread's row. The boolean is false when nothing has ever been said in that session, which is not an error: a caller holding a session id from an older build, or from a lens that has not spoken yet, asks this.

func (*Store) SessionLastNonUserMessageSeq

func (s *Store) SessionLastNonUserMessageSeq(sessionID string) (int64, error)

SessionLastNonUserMessageSeq is LastNonUserMessageSeq scoped to one room.

func (*Store) SessionMemberNodes

func (s *Store) SessionMemberNodes(sessionID string) ([]Node, error)

SessionMemberNodes returns every node one session admitted — steps and all, not the job roots Store.SessionNodes answers with — in the same stable admission order as Nodes. The splice stamps its session on every node it admits and an extension inherits it, so equality on the stored id is the whole membership test, and the spine root, which belongs to no session, is excluded the way every session-scoped read excludes it.

A headless run asks this several times a second for as long as it lasts. It used to ask by decoding every node in the graph and throwing away the ones that were somebody else's, which on a store with any history at all is a thirty-nine-column decode of a month's work to be told about four nodes.

func (*Store) SessionMessageCursors

func (s *Store) SessionMessageCursors() (map[string]int64, error)

SessionMessageCursors returns, for every session that has ever been spoken in, the sequence of its newest non-user message — the same resume rule LastNonUserMessageSeq states for the whole journal, asked one room at a time. A session that has only ever heard from the user reports zero.

It is one query rather than a read per session because the head asks it once at startup and must not pay a round trip per room to do it. Sessions are keyed by their raw id, the empty one included: messages posted to no room in particular still have a resume point, and leaving them out of the map would silently give them everyone else's.

func (*Store) SessionNodes

func (s *Store) SessionNodes(sessionID string, limit int) ([]Node, error)

SessionNodes returns the job roots one conversation commissioned, newest first. Roots only: a splice stamps every node it admits with the room, so the unfiltered answer would be one row per step and a conversation that commissioned three jobs would read as forty.

Folded history is included on purpose. This read answers "what did we set going in here, and what came of it", and what came of it is only knowable once the job has settled — which is also when the fold packs it away.

func (*Store) SessionQuietSince

func (s *Store) SessionQuietSince(sessionID string, since time.Time) (bool, error)

SessionQuietSince reports whether a session has carried no user message since the given moment — "no activity near this service" in one query.

func (*Store) SessionSeenSeq

func (s *Store) SessionSeenSeq(sessionID string) (int64, error)

SessionSeenSeq is one room's attention watermark: the newest moment a lens was in it. Zero means nobody ever has been, which is the honest answer and the one that makes everything in the room unread.

func (*Store) SessionSpend

func (s *Store) SessionSpend(sessionID string) (RoomSpend, bool, error)

SessionSpend is one room's whole bill, from its first message to now.

The second return is presence, not emptiness: false means this room has never been spoken in, so there is no window and nothing to say. A room that exists and has billed nothing returns true with Recorded false, which is a different fact and renders as a different glyph.

func (*Store) Sessions

func (s *Store) Sessions() ([]Session, error)

Sessions lists every known thread, most recently active first.

func (*Store) SetCharterStatus

func (s *Store) SetCharterStatus(id string, status CharterStatus, ratification Ratification) error

SetCharterStatus journals pause, activation, and retirement. Activation is the one transition that requires fresh explicit ratification provenance.

func (*Store) SetCharterStatusWithReason

func (s *Store) SetCharterStatusWithReason(id string, status CharterStatus, ratification Ratification, reason string) error

SetCharterStatusWithReason is the policy-bearing form used by conversational management and automatic pauses. The reason is part of the journal event.

func (*Store) SetNodeHold

func (s *Store) SetNodeHold(id string, held bool, reason string) error

SetNodeHold journals a scheduler hold or its release. Running claim owners observe the flag at their next executor boundary and Release back to pending.

func (*Store) SetNodePriority

func (s *Store) SetNodePriority(id string, priority int, reason string) error

SetNodePriority changes claim order without altering dependencies.

func (*Store) SetRoleBinding

func (s *Store) SetRoleBinding(role ModelRole, scope BindingScope, value, origin string) (bool, error)

SetRoleBinding binds one role inside one scope, and reports whether the journal grew.

Asking twice writes once: a binding already carrying this value is left alone, because a journal records decisions that changed something and a re-set changed nothing. Origin is recorded and deliberately not compared — the same choice arriving from a chip and from a flag is the same choice, and a machine that re-declared it on every boot would fill the journal with events nobody made.

func (*Store) SetServiceAutoRestart

func (s *Store) SetServiceAutoRestart(id string, enabled bool) error

func (*Store) SetSubtreeWorkModel

func (s *Store) SetSubtreeWorkModel(root, model, reason string) (ModelRebinding, error)

SetSubtreeWorkModel re-points every live node at or beneath root onto model.

Live means exactly what the funnel means by it — unfolded and not settled. Work that is already finished keeps the model it was done on, because what ran is a fact and not a preference; work that has not started yet is a preference and nothing else. A node already pinned to this model is left alone rather than journaled again, so asking twice writes once.

The store carries a name and no opinion about which names exist, exactly as it does for workers: whether a slug reaches a reachable model is the client pool's question, one layer up, at dispatch.

func (*Store) SetTaskCeiling

func (s *Store) SetTaskCeiling(root string, ceiling float64, origin string) error

SetTaskCeiling journals a dollar ceiling over one task's subtree. Setting it again replaces the figure, and the replacement re-arms the question: a task that was stopped and then given more room is a task that may ask once more.

func (*Store) SettledHistory

func (s *Store) SettledHistory(since, until time.Time, limit int) ([]Node, error)

SettledHistory returns the job roots that finished inside [since, until], newest first.

A job root is what a person means by "a job": something spliced under the permanent root, or a job that a territory has since packed away — the second clause is what keeps packed history reachable. Territory furniture, the permanent root and the resident's own practice are not jobs and never appear.

A zero since or until is unbounded on that side, so one call spells "since yesterday", "until Friday", and "everything" without a second entry point. limit <= 0 takes SettledHistoryCap; anything larger is clamped to it.

func (*Store) ShouldAsk

func (s *Store) ShouldAsk(category QuestionCategory) (bool, CategoryStats, error)

ShouldAsk applies empirical VOI while preserving consent-bearing exceptions.

func (*Store) SilenceConsentWait

func (s *Store) SilenceConsentWait(base time.Duration) time.Duration

SilenceConsentWait expands the existing wait seam to the observed correction latency.

func (*Store) SilentClaims

func (s *Store) SilentClaims(quietFor time.Duration) ([]SilentClaim, error)

SilentClaims is every claimed or running node that has shown no sign of life for the given window, with the sentence that says so.

IT READS AND DOES NOT ACT, and the split is the point. Taking a claim back is only half of what has to happen: if a worker in this process is still holding it, that worker must be STOPPED first, or the release simply hands one workspace to a second worker while the first goes on writing to it — which is what the ink run of 2026-08-29 did four times over. Only the scheduler knows which claims it is itself behind, so only the scheduler can decide between stopping a worker and taking a claim from a process that is gone. See resident.Runner.reapSilentClaims.

It exists for the live-run case ReleaseOrphans does not reach: a worker that dies mid-run — a process killed, a goroutine wedged past every deadline it was given — leaves its node running forever, and every downstream node gated on it waits behind a claim nobody holds any longer. The resident heartbeats the whole time and finds nothing to do, because the ready set never opens: that is the live-lock a long-horizon run dies of.

A window of zero or less disarms the sweep entirely, which is what a caller that has not decided a window should get.

func (*Store) SkillFactAccessors

func (s *Store) SkillFactAccessors(seq int64) (artifact, doc, digest, trust string, err error)

SkillFactAccessors returns the three accessor projections for one skill: shelf path, the skill doc, and the content digest. It records one use through the existing Uses/LastUsed telemetry. Trust defaults to "authored" when the stored value is empty.

func (*Store) SkillFacts

func (s *Store) SkillFacts(status string, limit int) ([]Fact, error)

SkillFacts lists skills in one status, newest first. Empty status includes candidates, active skills, and retired entries for reconciliation.

func (*Store) Snapshot

func (s *Store) Snapshot() (Snapshot, error)

Snapshot copies both complete materialized views.

func (*Store) SnapshotMemoryRanking

func (s *Store) SnapshotMemoryRanking(minInterval time.Duration) (bool, error)

SnapshotMemoryRanking journals what the two ranking counters currently say, at most once per minInterval, and reports whether it wrote one.

THIS IS THE SIMPLEST SCHEME THAT IS CORRECT, and the simplicity is the argument for it. The counters cannot be journaled per write — that is the most frequent write in the feature and would bury the five events that carry meaning. They cannot be left unjournaled either, now that Store.MemoryCandidates ranks on them: a Rebuild would silently change which rows the router is shown. So the journal carries a periodic photograph instead. A replay lands on the last photograph rather than on zero, which is a floor a week deep at worst and nothing anybody has to reason about.

IT DOES NOT HALVE, AND THAT IS DELIBERATE. Halving old counts is plausible ranking hygiene and it is also exactly the mechanism no paper has ever ablated: MemoryBank (AAAI 2024) proposed the Ebbinghaus curve and never tested it, and FadeMem (arXiv 2601.18642) — the most decay-committed paper in the literature — attributes its own gains to fusion and conflict resolution and ships no "without decay" row. Surviving a rebuild is a correctness problem and is solved here; decay is a guess and is not.

Nothing is written when every counter is still zero: a store nobody has used yet has no ranking to preserve, and a weekly event saying so forever is the journal noise this whole arrangement exists to avoid.

func (*Store) SpendBetween

func (s *Store) SpendBetween(since, until time.Time) (SpendWindow, error)

SpendBetween sums recorded cost over an arbitrary window. A zero Until means now; a zero Since means the beginning of the journal. Both bounds are half-open the way every other range read here is: [since, until).

func (*Store) SpendByJob

func (s *Store) SpendByJob(since, until time.Time, limit int) ([]JobSpend, error)

SpendByJob groups a window's cost under the job root each run belongs to, heaviest first. Grouping needs no new taxonomy: the graph already knows which root a node descends from, and that root's title is what the user called the work. A limit of zero returns every job that spent anything.

A run under no job root at all — planning charged to the spine, a voice transcription — is deliberately absent rather than bucketed into a fake job. The window total from SpendBetween is the authority on the whole bill, and the difference between it and the sum of these rows is exactly the overhead that belongs to no single errand.

func (*Store) SpendSinceSeq

func (s *Store) SpendSinceSeq(sessionID string, sinceSeq int64) (ErrandSpend, error)

SpendSinceSeq is the errand read: what session sessionID has cost since the journal stood at sinceSeq.

The window is a primary-key range over usage (seq IS the rowid), so this is the tail of the journal from where the errand opened and never the whole table, and nodes is entered by primary key through the LEFT JOIN once per row in that tail. Pass the watermark taken before the command was requested; a zero sinceSeq reads the journal from the beginning, which is what a caller that owns the whole store means.

func (*Store) SpendToday

func (s *Store) SpendToday() (float64, error)

SpendToday sums recorded execution cost since local midnight. Event times are UTC on disk; the boundary is local policy time converted to UTC, so DST and non-UTC operators get the day they actually mean.

func (*Store) Splice

func (s *Store) Splice(parent string, subtree Subtree, provenance Provenance) error

Splice atomically admits a complete subtree below parent. Validation and the event/view writes share one immediate transaction, so another process sees either the complete admission or none of it.

func (*Store) StandingWatchDecisionState

func (s *Store) StandingWatchDecisionState() (StandingWatchDecision, error)

StandingWatchDecisionState returns the newest journal-derived choice.

func (*Store) Start

func (s *Store) Start(claim Claim) error

Start moves a claimed node to running.

func (*Store) StopService

func (s *Store) StopService(id, reason string) error

func (*Store) StructuredRepairs

func (s *Store) StructuredRepairs(nodeID string) ([]StructuredRepair, error)

StructuredRepairs returns every repair journaled against one node, oldest first. It reads the events directly, as JobGrowths does: the payload is sparse, looked up by one id, and has no query anyone would run across it.

func (*Store) SubtreeNodes

func (s *Store) SubtreeNodes(root string) ([]Node, error)

SubtreeNodes returns root and every descendant in the same stable admission order as Nodes, without loading the rest of the graph.

func (*Store) SubtreeReceipts

func (s *Store) SubtreeReceipts(root string) (SubtreeLedger, error)

SubtreeReceipts reads one receipt per node in root's subtree — money, clock and state, per node, folded or not — in a single query.

This is the read 13.11 filed as missing. Its shape is Store.SubtreeNodes' shape on purpose: same recursion, same order, same indifference to folding, so a surface can lay the two side by side and know the rows line up.

func (*Store) SubtreeRollup

func (s *Store) SubtreeRollup(root string) (SubtreeRollup, bool, error)

SubtreeRollup is the one-figure form: what a whole subtree cost, how long it took, and what state its members are in, without the caller holding the members. It is the read behind a COLLAPSED card, and it is the ledger's own rollup of its own root rather than a second query with a second opinion.

The second return is presence. A root the graph has never heard of has no rollup — absent — which a caller must not draw as an empty job.

func (*Store) SubtreeSpend

func (s *Store) SubtreeSpend(root string) (float64, error)

SubtreeSpend sums every usage row recorded against root or any node beneath it. A run is one row against one node, so a subtree total is a sum of distinct rows: what a child spent is never counted a second time for its parent, and a node that ran twice contributes both of its runs.

func (*Store) SupersedeFact

func (s *Store) SupersedeFact(factSeq, bySeq int64) error

SupersedeFact retires one active or quarantined fact in favour of another, journaled. Consolidation uses it to rewrite a scope into fewer, better lines.

func (*Store) SupersedeFactWithReason

func (s *Store) SupersedeFactWithReason(factSeq, bySeq int64, reason string) error

SupersedeFactWithReason records why a belief retired. Skill trial failures use the reason as durable execution evidence even when there is no replacing fact and bySeq is zero.

func (*Store) SupersedeMemory

func (s *Store) SupersedeMemory(oldID string, m Memory) (Memory, error)

SupersedeMemory retires one memory and admits its replacement as one event, so no replay and no reader can ever observe the gap between them.

func (*Store) SurfaceQuestion

func (s *Store) SurfaceQuestion(seq int64) (Message, error)

SurfaceQuestion moves one pending question into its thread. The message and status transition are separate journal events committed atomically.

func (*Store) SurfaceQuestionForSession

func (s *Store) SurfaceQuestionForSession(seq int64, sessionID string) (Message, error)

SurfaceQuestionForSession surfaces a neutral queued question into the live session that chose it. Session-bound questions keep their original session.

func (*Store) SurfacesFor

func (s *Store) SurfacesFor(nodeID string) ([]SurfaceReading, error)

SurfacesFor returns every symbol-level comparison journaled for a node, oldest first.

func (*Store) SurpriseFor

func (s *Store) SurpriseFor(nodeID string) (NodeSurprise, bool, error)

SurpriseFor returns the prediction residual recorded against one node, if one was ever recorded. It is the read that did not exist: surprise was written to the journal and to an analytics table, then only ever summed, averaged and rendered as a percentage on a receipt somebody might read afterwards.

A number nothing consults at a decision point is decoration. This is the route by which the machinery that decides whether to retry, escalate or continue a node can be told that the node already cost 2.85× what its own profile predicted — which is a fact about the work, and belongs in front of the judge that is about to buy more of it.

func (*Store) TargetedCommands

func (s *Store) TargetedCommands(target string, kind CommandKind, limit int) ([]Command, error)

TargetedCommands returns what was aimed at one node, oldest first. HasCommandTarget answers whether it happened; this answers what was said, which is what a redirect's own words are — the strongest correction signal in the system, and one that survived downstream only as a boolean.

func (*Store) TaskCeilingOf

func (s *Store) TaskCeilingOf(root string) (float64, bool, error)

TaskCeilingOf reports the ceiling set on exactly this root, which is not the same question as what governs it: an ancestor's ceiling still applies to a node that carries none of its own. TaskRailFor answers that one.

func (*Store) TaskRailFor

func (s *Store) TaskRailFor(nodeID string) (TaskRail, error)

TaskRailFor resolves the ceiling governing one node — the nearest ancestor carrying one, itself included — and measures that root's subtree against it. An ungoverned node returns the zero rail, which is Set false and therefore never Reached.

func (*Store) TasteAnswers

func (s *Store) TasteAnswers() ([]TasteAnswer, error)

TasteAnswers reads every settled verdict, oldest first, from the one rare category taste writes — the same read shape the skipped-ask projection uses, decoded in Go. The stored resolution is the label the user chose, so the option that label names is what carries the shelf.

func (*Store) TasteRules

func (s *Store) TasteRules(status string) ([]Fact, error)

TasteRules returns the current line on every taste shelf, newest first. An empty status returns each shelf whatever its standing; a shelf's superseded history stays in the journal and out of this answer.

func (*Store) TerritoryJobs

func (s *Store) TerritoryJobs() ([]TerritoryJob, error)

TerritoryJobs returns ordinary job fold roots, including roots already nested directly under a territory. Scope and continuity are derived from journal-built views; workspace is derived from the fold's durable pointers.

func (*Store) ThreadIndex

func (s *Store) ThreadIndex(limit int) ([]ThreadArc, error)

ThreadIndex returns EVERY conversation, newest active first, with its open arc filled in when it has one.

IT IS OpenThreads WITHOUT THE FILTER, AND THE DIFFERENCE IS A PRODUCT BUG THAT SHIPPED. Store.OpenThreads answers "what is still alive", which is the right question for the head's alive glance and for the nudge — and the WRONG one for a switcher. A switcher is an index: it exists so a person can walk back into a conversation, and the conversations a person most wants to walk back into are usually the ones that were finished properly. Driving the switcher from the open-loops query meant a store holding three real sessions drew a list of none — every answered conversation was invisible, the only row was the `new thread` door, and enter on it abandoned the thread the reader was standing in. That is the whole of "I cannot reach the chats feature".

So OPEN IS A DECORATION HERE, NEVER A FILTER. A row's ThreadArc.Open and ThreadArc.UnseenDelivery still say what is unresolved in it; nothing is dropped for being settled. Callers that genuinely want the live set keep asking OpenThreads, which is unchanged.

Cost is OpenThreads': one tail read per room, bounded by the same scan cap, paid when a door opens rather than on a cadence.

func (*Store) TopLevelJobUsage

func (s *Store) TopLevelJobUsage() (map[string]JobUsage, error)

TopLevelJobUsage joins every node and usage event to its job root. A job remains a job root when a territory moves it one level below the spine. Folded history therefore keeps its original node count and measured cost.

func (*Store) TouchSeen

func (s *Store) TouchSeen(surface, sessionID string, state SeenState) (Seen, error)

TouchSeen appends one attach/detach edge and returns its journal watermark.

func (*Store) TouchSession

func (s *Store) TouchSession(id string, at time.Time) error

TouchSession raises one session's activity mark, minting the row if this is the first the store has heard of it. A zero time means now.

func (*Store) Trait

func (s *Store) Trait(name string) (TraitMeasurement, Fact, bool, error)

Trait returns the current singleton measurement for name.

func (*Store) TranscriptFor

func (s *Store) TranscriptFor(nodeID string, limit int) ([]TranscriptEntry, error)

TranscriptFor is one node's record, oldest entry first: every flush of every attempt, in the order the entries happened. A limit of zero or less reads the whole thing; a node whose worker never recorded a transcript answers with nothing, which reads as "this executor keeps no record" rather than as "this leaf did nothing".

func (*Store) TrialStats

func (s *Store) TrialStats() (TrialStats, error)

TrialStats returns all trial-marked splices in admission order and resolves their verdicts through fact supersession events written by the trial root.

func (*Store) TuneParameter

func (s *Store) TuneParameter(name string, direction int, evidence ParameterEvidence, phrase string) (ParameterChange, bool, error)

TuneParameter moves one registry dial by at most one step inside its rails.

func (*Store) TurnSpend

func (s *Store) TurnSpend(sessionID string) (RoomSpend, bool, error)

TurnSpend is what the room's newest turn has cost so far: the window that opens at the room's newest user message and runs to the end of the journal.

A turn is bounded by the message that asked for it because that is the only boundary the journal draws for one. There is no turn row and no turn id — the head answers a message, spends against the spine while it does, and the work it commissions bills its own nodes. The user's last word is where all three start.

The second return is false when the room holds no user message: nothing has been asked, so no turn exists to cost. That is absence and not zero.

func (*Store) TurnUsageFor

func (s *Store) TurnUsageFor(nodeID string) ([]TurnUsage, error)

TurnUsageFor is one node's journaled shape, oldest execution first and each execution's turns in order. A node whose executor never metered turns answers with nothing at all, which reads as "no shape recorded".

func (*Store) UnboundFor

func (s *Store) UnboundFor(nodeID string) ([]UnboundReading, error)

UnboundFor returns every unbound-reference reading journaled for a node, oldest first.

func (*Store) UnnamedSessionsWithExchange

func (s *Store) UnnamedSessionsWithExchange(limit int) ([]Session, error)

UnnamedSessionsWithExchange lists the rooms a naming pass would still have something to say about: no title, at least one thing the person said, and at least one answer. Most recently active first, so a backfill that can only afford a few names the rooms a reader is most likely looking at; the older ones keep their turn for the next launch.

limit bounds the answer because the caller is spending a model call per row and an unbounded list would be an unbounded bill.

func (*Store) UnresolvedQuestions

func (s *Store) UnresolvedQuestions(limit int) ([]AgentQuestion, error)

UnresolvedQuestions includes both quiet and already-surfaced questions. It lets the resident expire stale work without conflating expiry with display.

func (*Store) UpdateMemory

func (s *Store) UpdateMemory(id, title, text string, tags []string) error

UpdateMemory corrects a memory in place. Type and scope are not arguments because a memory that changed either of those is a different memory and wants SupersedeMemory: the whole point of an update is that the router's existing pointers to this id stay valid.

func (*Store) UpdateMemoryFromSession

func (s *Store) UpdateMemoryFromSession(id, title, text string, tags []string, sourceSession string) error

UpdateMemoryFromSession records which conversation supplied the correction.

func (*Store) Usage

func (s *Store) Usage() (TotalUsage, error)

Usage returns the graph-wide total.

func (*Store) UserIdle

func (s *Store) UserIdle(now time.Time, quietFor time.Duration) (bool, error)

UserIdle is the cheap reconciler gate: one indexed materialized-view check for live user work and one journal timestamp lookup for the quiet period.

func (*Store) VerificationsFor

func (s *Store) VerificationsFor(nodeID string) ([]VerificationReading, error)

VerificationsFor returns every reading journaled for a node, oldest first. It reads the events directly, exactly as AcceptanceFor does and for the same reason: the payload is sparse, looked up by id, and has no query anyone would run across it.

type StructuredRepair

type StructuredRepair struct {
	Lane    string `json:"lane"`
	Model   string `json:"model,omitempty"`
	Kind    string `json:"kind"`
	Round   int    `json:"round,omitempty"`
	Spent   int    `json:"spent,omitempty"`
	Ceiling int    `json:"ceiling,omitempty"`
	Line    string `json:"line"`

	// Note is why the answer could not be read, in the reader's own words —
	// shaped.Repair.Note. Line says what was done about it and reads the same
	// for every cause; this says which cause, and it is the difference between
	// a model reasoning out loud (the seam working) and a caller's own contract
	// refusing a well-formed answer (a question asked badly).
	Note string `json:"note,omitempty"`
}

StructuredRepair is one repair internal/shaped performed to get an answer.

Lane is the pass that asked, in a person's words — "plan", "gate", "compile". Kind is what was done about it. Line is the whole sentence as a person reads it, written by the seam and kept verbatim, so a reader of the journal and a person watching the stream are looking at the same words rather than at two renderings of one fact that will eventually disagree.

type Subtree

type Subtree struct {
	Nodes []NodeSpec `json:"nodes"`
}

Subtree is the atomic unit of admission.

type SubtreeLedger

type SubtreeLedger struct {
	// Root is the node the ledger was read from, and Receipts are it and every
	// descendant in the same stable admission order as [Store.SubtreeNodes].
	Root     string
	Receipts []NodeReceipt
	// contains filtered or unexported fields
}

SubtreeLedger is one subtree's receipts, read once and asked many times.

It exists because a tree is not a list. The read is bounded by the subtree a reader ENTERED — the same gesture and the same bound as Store.SubtreeNodes, for the reason 257800f gives — and every level inside it then rolls up from what is already in hand. Expanding and collapsing a parent is therefore a walk over a slice the window already holds, not a query per disclosure triangle.

func (SubtreeLedger) Receipt

func (ledger SubtreeLedger) Receipt(id string) (NodeReceipt, bool)

Receipt is one member's own line. The second return is presence: a node that is not in this subtree has no receipt here, which is not the same as a node that has spent nothing.

func (SubtreeLedger) Rollup

func (ledger SubtreeLedger) Rollup(id string) (SubtreeRollup, bool)

Rollup aggregates any member and everything beneath it, using only what the single read already returned. Asked for the ledger's own root it is the whole job; asked for a step it is that step's branch; asked for a leaf it is the leaf, which is the same figures its own receipt carries and is deliberately not a special case — a row and the collapsed version of that row must agree.

The second return is presence, for the same reason [Receipt]'s is.

type SubtreeRollup

type SubtreeRollup struct {
	// Root is the node rolled up. It is a member of its own rollup: a parent's
	// own judge calls bill the parent, and a total that dropped them would be
	// smaller than the sum of the rows a reader can expand to see.
	Root  string
	Nodes int

	Runs             int
	Cost             float64
	PromptTokens     int
	CompletionTokens int
	CachedTokens     int
	LastBilled       time.Time

	// Started is the earliest start anywhere under Root and Settled the latest
	// finish. They are the ENDS OF ONE WALL and not two sums: four workers that
	// each took ten minutes side by side took ten minutes, not forty, and a
	// rollup that added them would tell a reader a parallel job was four times
	// as slow as they watched it be.
	Started time.Time
	Settled time.Time
	// Live says something under Root started and has not stopped, which is what
	// makes the wall open-ended rather than measured.
	Live bool

	States StateCounts
}

SubtreeRollup is what one collapsed level says on one line: the money under it, the wall it has occupied, and the census of its members.

func (SubtreeRollup) Billed

func (roll SubtreeRollup) Billed() bool

Billed reports whether anything under this root has been measured at all.

func (SubtreeRollup) Elapsed

func (roll SubtreeRollup) Elapsed(now time.Time) (time.Duration, bool)

Elapsed is the wall this subtree has occupied: earliest start to latest settle while it is done, earliest start to now while anything under it still runs, and absent when nothing has started or when what started never recorded how it ended.

type SurfaceReading

type SurfaceReading struct {
	// Compared is how many changed source files the two readings were compared
	// across. Zero with Lost zero is a real answer — the run changed no source
	// this program can read — and it is not the same answer as no row at all.
	Compared int `json:"compared"`
	// Lost is how many public names the finished tree no longer spells.
	Lost  int      `json:"lost"`
	Names []string `json:"names,omitempty"`
}

SurfaceReading is that comparison as the journal keeps it.

A COUNT PLUS A BOUNDED SAMPLE, exactly as the check roster is kept, and for the identical reason: a repository's public surface is tens of thousands of short strings, what a reader wants is the difference, and a handful of names settles what SHAPE the loss has as well as four hundred would.

type SurgeryImpact

type SurgeryImpact struct {
	Nodes      int
	OpenNodes  int
	Running    int
	Cost       float64
	RunningFor time.Duration
}

SurgeryImpact is the loss/cascade estimate used by conversational gates.

type SurgeryTarget

type SurgeryTarget struct {
	Node  Node
	Age   string
	Score float64
}

SurgeryTarget is one BM25-ranked graph referent with a user-facing age.

type SurpriseTrend

type SurpriseTrend string

SurpriseTrend describes whether recent prediction error is moving enough to matter. Unknown means there is not yet a complete comparison window.

const (
	SurpriseUnknown   SurpriseTrend = "unknown"
	SurpriseImproving SurpriseTrend = "improving"
	SurpriseFlat      SurpriseTrend = "flat"
	SurpriseWorsening SurpriseTrend = "worsening"
)

type TaskCeiling

type TaskCeiling struct {
	Root    string  `json:"root"`
	Ceiling float64 `json:"ceiling"`
	Origin  string  `json:"origin"`
	Cleared bool    `json:"cleared,omitempty"`
}

TaskCeiling is one journaled decision about what a task may spend.

Cleared says the root is no longer governed at all, which is not a ceiling of zero: a zero ceiling would stop the task on its first recorded cent, so the two must be different rows in the journal rather than the same number.

type TaskRail

type TaskRail struct {
	Root    string
	Ceiling float64
	Spend   float64
	Pending float64
	Set     bool
	Reached bool
}

TaskRail is one subtree's policy state, in the shape DailyRail already uses: Spend is everything the rail decides against and Pending is the part of it the journal has not recorded yet. Set separates "no ceiling governs this node" from "a ceiling that happens to be small", and only a set rail can be Reached — an ungoverned node is never stopped by this rail.

func (TaskRail) Question

func (rail TaskRail) Question() string

Question is the one user-visible stop a task rail produces. It names the task because, unlike the day, there can be several of them; it quotes what the journal knows and names any pending item separately rather than folding it into the total.

func (TaskRail) RaiseAmount

func (rail TaskRail) RaiseAmount() float64

RaiseAmount restores one ceiling's worth of headroom plus whatever landed past the ceiling while concurrent leaves were finishing, so consent does not immediately face the same question again.

It is computed from journaled spend on purpose. Consent arrives later and from somewhere else, and it can only raise against the figure the journal holds — quoting a total that includes unrecorded cost promises a number consent cannot deliver, which is the lesson DailyRail.postedQuestion records.

func (TaskRail) WithAdditionalSpend

func (rail TaskRail) WithAdditionalSpend(amount float64) TaskRail

WithAdditionalSpend includes a known cost that has not happened yet, the way the daily rail does for catalog-priced work. An ungoverned rail absorbs nothing: there is no ceiling for the addition to be measured against.

type TaskRailAsk

type TaskRailAsk struct {
	Root      string  `json:"root"`
	SessionID string  `json:"session_id,omitempty"`
	Spend     float64 `json:"spend"`
	Ceiling   float64 `json:"ceiling"`
}

TaskRailAsk is the durable "this task has already been asked" marker.

The daily rail finds its own question by matching the message prefix, which works because its marker is the whole day. A per-root marker needs a key, and node ids are not safe LIKE patterns, so the ask is journaled against the root node instead — one indexed lookup on (node_id, seq) rather than a scan of every message ever posted.

type TasteAnswer

type TasteAnswer struct {
	Seq   int64
	Scope string
	// Answer is one of the offered verdicts, or empty when the user typed
	// something instead of choosing. Both go on the same shelf.
	Answer string
	// Free is the user's own words when they answered a taste question with a
	// sentence rather than an option. The ask deliberately allows free text —
	// "keep it this way, or 'shorter, no headings'?" invites exactly this — and
	// discarding it meant a user who answered in their own words was ignored
	// and asked the same question again after the next delivery. A sentence is
	// not a verdict on the rule; it is a fresh correction, so it counts neither
	// for nor against and is filed where corrections are aggregated.
	Free string
}

TasteAnswer is one settled verdict on a taste shelf. Seq is the question's own sequence, which is how a refusal is told from a refusal that predates the standing it would undo.

type TerritoryJob

type TerritoryJob struct {
	Node          Node
	Workspace     string
	DominantScope string
	Continuity    []string
}

TerritoryJob is one folded job plus the local signals the retrospective uses to decide whether several jobs belong to the same territory.

type ThreadArc

type ThreadArc struct {
	SessionID string
	Title     string
	// Tags are the subjects the naming pass filed this room under
	// ([Session.Tags]). They are carried here for one reason: a switcher's
	// filter is the only place they are read, and a switcher is driven from
	// this projection. Nothing draws them as ornaments.
	Tags []string
	// LastActive is the room's own activity mark, which is what the list is
	// ordered by; Since is when the OPEN thing started, which is what "parked
	// for two days" measures.
	LastActive time.Time
	Since      time.Time
	Open       ThreadOpenKind
	Left       string
	// UnseenDelivery is the one ornament the product allows: work landed here
	// and no lens has been in the room since. It is separate from Open because
	// a thread can be waiting on an answer AND holding an unread delivery, and
	// the dot is drawn for the second regardless of the first.
	UnseenDelivery bool
}

ThreadArc is one conversation with something still open in it.

Left is the one line the thread was left at — the words of whichever message is the open thing — because a switcher row that says only a name and a time cannot tell a reader which conversation they want.

func ThreadArcOf

func ThreadArcOf(session Session, tail []Message, seenSeq int64) (ThreadArc, bool)

ThreadArcOf is the arc reader with the room's rows passed in. OpenThreads is this function over every room; a caller that already holds a BOUNDED window of one room — the head building a re-entry brief, which must read the thread as it stood before the message it is grounding — asks it directly, so both answers come from one piece of judgment about what "still open" means.

tail is oldest-first, which is what MessageTail returns.

type ThreadOpenKind

type ThreadOpenKind string

ThreadOpenKind names the one unresolved shape that keeps a thread alive. There are exactly three, and each is a different party owing the other something.

const (
	// ThreadOpenQuestion is the head waiting on the person: a question was put
	// and nothing came back.
	ThreadOpenQuestion ThreadOpenKind = "question"
	// ThreadOpenDelivery is work that landed in a room the person has not
	// opened since. Nobody is blocked; something is simply unread.
	ThreadOpenDelivery ThreadOpenKind = "delivery"
	// ThreadOpenUnanswered is the person waiting on the head: they spoke last
	// and no reply followed.
	ThreadOpenUnanswered ThreadOpenKind = "unanswered"
)

type TotalUsage

type TotalUsage struct {
	Nodes            int
	PromptTokens     int
	CompletionTokens int
	Cost             float64
}

TotalUsage is the graph-wide running total.

type TraitMeasurement

type TraitMeasurement struct {
	Value   any       `json:"value"`
	N       int       `json:"n"`
	Updated time.Time `json:"updated"`
}

TraitMeasurement is the structured body stored by every trait fact.

type TranscriptEntry

type TranscriptEntry struct {
	// Turn is the model request this entry belongs to, numbered from one. Every
	// entry of a turn shares it, which is what lets a reader collapse a turn.
	Turn int            `json:"turn"`
	Kind TranscriptKind `json:"kind"`
	// Tool is the tool's name on tool_call and tool_result, empty elsewhere.
	Tool string `json:"tool,omitempty"`
	// CallID is the provider's own id for one call, carried on both halves so a
	// result can be matched to its call when a turn issued several in parallel
	// and they landed out of order.
	CallID string `json:"call_id,omitempty"`
	Text   string `json:"text,omitempty"`
	// Millis is wall time for a tool result. Zero everywhere else, and zero is
	// also the honest value for a tool that returned instantly.
	Millis int64 `json:"ms,omitempty"`
	// Failed says the tool reported an error. It is a separate fact from the
	// text because a tool that failed usefully and a tool that succeeded both
	// return prose, and only this tells them apart.
	Failed bool `json:"failed,omitempty"`
}

TranscriptEntry is one line of one leaf's record.

Text is the payload for every kind and its meaning follows the kind: the assistant's prose, the tool call's arguments, the tool result's output, the fault's error. It is bounded — see MaxTranscriptTextBytes — because this is a record and not a content store; a tool that printed a megabyte is journaled as its head and its tail with the gap named.

type TranscriptKind

type TranscriptKind string

TranscriptKind names one entry in a leaf's record. The four that carry the loop are assistant / tool_call / tool_result / fault; the two that carry the harness's own voice are note and elided.

const (
	// TranscriptAssistant is one model turn's text, as the model wrote it.
	TranscriptAssistant TranscriptKind = "assistant"
	// TranscriptToolCall is one tool the model asked for, with its arguments.
	// Tool and CallID are set; CallID ties it to its result.
	TranscriptToolCall TranscriptKind = "tool_call"
	// TranscriptToolResult is what that tool returned. Millis is how long it
	// took and Failed says the tool reported an error, which is the pair of
	// facts an autopsy asks for first.
	TranscriptToolResult TranscriptKind = "tool_result"
	// TranscriptFault is the loop ending on something other than its own
	// completion: a provider error the retries could not absorb, a deadline, a
	// panic caught by the guard. The text is the error as it was seen.
	TranscriptFault TranscriptKind = "fault"
	// TranscriptNote is the harness speaking about its own machinery — a
	// compaction pass, a retry budget spent. It is not the model's words and is
	// marked so nobody reads it as such.
	TranscriptNote TranscriptKind = "note"
	// TranscriptElided is the bound admitting itself. A run past the cap stops
	// being recorded, and this says so where the record stops rather than
	// leaving a reader to believe the loop ended there.
	TranscriptElided TranscriptKind = "elided"
)

type TrialOutcome

type TrialOutcome struct {
	NodeID         string
	TrialOf        int64
	Status         TrialStatus
	ReplacementSeq int64
	Kind           FactKind
	Body           string
}

TrialOutcome connects one trial-marked splice to the fact that consumed its unsettled pair. Body is the winning rule or the carried-forward pair.

type TrialStats

type TrialStats struct {
	Fired        int
	Settled      int
	Inconclusive int
	Pending      int
	Outcomes     []TrialOutcome
}

TrialStats answers whether the experiment loop has fired and what each run settled. Counts are derived from journal events rather than process state.

type TrialStatus

type TrialStatus string

TrialStatus says whether a fired experiment has produced a notebook verdict. Pending means its trial-marked subtree has not consumed the pair.

const (
	TrialPending      TrialStatus = "pending"
	TrialSettled      TrialStatus = "settled"
	TrialInconclusive TrialStatus = "inconclusive"
)

type Tunable

type Tunable struct {
	Name    string
	Default float64
	Floor   float64
	Ceiling float64
	Step    float64
	Label   string
}

Tunable names the registry entry that is the only meta-learning mutation surface.

type TurnUsage

type TurnUsage struct {
	Turn             int     `json:"turn"`
	PromptTokens     int     `json:"prompt_tokens"`
	CompletionTokens int     `json:"completion_tokens"`
	CachedTokens     int     `json:"cached_tokens,omitempty"`
	SentTokens       int     `json:"sent_tokens,omitempty"`
	Cost             float64 `json:"cost"`
}

TurnUsage is one turn of one node's execution.

Sent is the quantity that could not be reconstructed from anything already journaled: what this turn put on the wire, cache-served prefix included. Summed over turns it is the leaf's cumulative context pressure, which is the meter the runaway nodes were invisible to — see internal/exec/meter.go.

type UnboundReading

type UnboundReading struct {
	// Found is how many unbound references the reading came back with. Zero is a
	// real answer — the run's own files reference nothing this tree fails to
	// bind — and the ROW's existence is what says the reading happened at all,
	// which is not the same fact and had no other spelling.
	Found int           `json:"found"`
	Names []UnboundSite `json:"names,omitempty"`
}

UnboundReading is that reading as the journal keeps it: how many sources were read, and the references that came back with their sites.

NAMES PLUS THE SITE THEY WERE READ AT, which is the shape SurfaceReading keeps one field wider — the whole value of this finding to a repair round is the name AND the line, and a list of names with no line sends a worker looking.

type UnboundSite

type UnboundSite struct {
	Name string `json:"name"`
	// Where is the file and line, as `file:line`, and Ground is where this
	// reading looked for a binding and did not find one.
	Where  string `json:"where,omitempty"`
	Ground string `json:"ground,omitempty"`
}

UnboundSite is one reference and where it stands.

type UnsettledApproach

type UnsettledApproach struct {
	Approach string  `json:"approach"`
	Scope    string  `json:"scope"`
	Evidence []int64 `json:"evidence"`
}

UnsettledApproach is one side of a competing pair. Scope describes where the approach worked; Evidence names the durable fact sequences behind it.

type UnsettledPair

type UnsettledPair struct {
	Approaches []UnsettledApproach `json:"approaches"`
	Trials     []UnsettledTrial    `json:"trials,omitempty"`
}

UnsettledPair is the structured payload of an unsettled fact. Approaches must contain exactly two entries; Trials is append-only evidence carried forward when an experiment cannot choose a winner.

func (UnsettledPair) Validate

func (pair UnsettledPair) Validate() error

Validate rejects prose-only or ambiguous pairs before they enter the journal. Evidence sequences are positive and deduplicated per approach.

func (UnsettledPair) WithInconclusiveTrial

func (pair UnsettledPair) WithInconclusiveTrial(nodeID string) UnsettledPair

WithInconclusiveTrial carries the pair forward with one new piece of evidence. The returned value owns its slices and does not mutate pair.

type UnsettledTrial

type UnsettledTrial struct {
	NodeID  string `json:"node_id"`
	Outcome string `json:"outcome"`
}

UnsettledTrial records that one trial ran without resolving the pair. A conclusive trial replaces the pair with an ordinary fact instead.

type VerificationReading

type VerificationReading struct {
	// When says which half of the photograph this is: the tree before the
	// job's first change, or the tree as it was handed over.
	When string `json:"when"`
	// Command is what actually ran, which is not always what the project
	// declared — a lifecycle script that lints before it tests is read through
	// the runner underneath it. Declared keeps the project's own spelling.
	Command  string `json:"command"`
	Declared string `json:"declared,omitempty"`
	// Read says a reading EXISTS. False is the row this type was extended for:
	// a reading that was not taken is still an event, because "nobody looked"
	// and "this project declares no verification" and "the command was killed
	// at its ceiling" are three different facts that cost three different
	// amounts, and a run that journals none of them is a run whose autopsy
	// cannot tell them apart. Why says which, in one sentence.
	Read bool   `json:"read"`
	Why  string `json:"why,omitempty"`
	// Runner and Format are the strategy: which program was asked, and how its
	// answer was read. ReadAsPlain says the strategy's own reader found nothing
	// and the shared vocabulary read the same bytes instead.
	Runner      string `json:"runner,omitempty"`
	Format      string `json:"format,omitempty"`
	Source      string `json:"source,omitempty"`
	ReadAsPlain bool   `json:"read_as_plain,omitempty"`
	// Scope is HOW MUCH of the project this reading covered — "whole", or the
	// count of files a reading scoped to the change selected — and Package is
	// WHERE it was taken, which for a monorepo is the package it read rather
	// than the workspace root.
	//
	// They are journaled because a roster of forty checks means two different
	// things and the row could not say which: a small project read whole, or a
	// large one read next to the change. The regression comparison turns on the
	// same distinction (verify.Reading.comparable), so an autopsy that cannot
	// see the scope cannot check the comparison either.
	Scope   string `json:"scope,omitempty"`
	Package string `json:"package,omitempty"`
	// Exit is the command's own status, and -1 is a command that never got far
	// enough to have one. TimedOut says the ceiling fired, which is an
	// INCOMPLETE OBSERVATION and not a red one.
	Exit     int  `json:"exit"`
	TimedOut bool `json:"timed_out,omitempty"`
	// Named is the size of the roster and Red the size of its failing half.
	Named int `json:"named"`
	Red   int `json:"red"`
	// Sample is a bounded handful of the identities, so an autopsy can see what
	// shape the names came out in — a file path means the reader read a
	// file-level summary, a test name means it read the checks.
	Sample []string `json:"sample,omitempty"`
	// Partial says the reading was CUT: the command was killed at its ceiling
	// having already named some of its checks, and Elapsed is how long it ran
	// before that happened.
	//
	// They are journaled because the pair is what an autopsy needs to tell a
	// small suite from a big one that was interrupted, and because Elapsed is
	// the only thing this run ever learns about the PACE of the machine it is
	// on. The budget's arithmetic assumes a native host; these readings are
	// taken in amd64 containers under qemu, where everything is five to ten
	// times slower, and a ceiling derived from a wall knows nothing about that
	// until a reading is cut and says so.
	Partial bool          `json:"partial,omitempty"`
	Elapsed time.Duration `json:"elapsed,omitempty"`
	// Uncollected says the runner produced no test record of its own — a suite
	// that failed to COLLECT rather than one that ran and went red — and Trouble
	// is what it said instead, in its own words.
	//
	// They are journaled because the two were the same row: ofetch's nemotron n1
	// run wrote `named: 1, red: 1` four times over a suite that never ran a
	// check, and an autopsy reading that row had no way to tell it from a suite
	// with one failing test in it.
	Uncollected bool   `json:"uncollected,omitempty"`
	Trouble     string `json:"trouble,omitempty"`
	// Replaced is how many of the checks this roster stopped naming were
	// REWRITTEN rather than removed: a check the after reading no longer holds
	// by name, whose subject a check it does hold still covers.
	//
	// It is journaled because the removal finding it suppresses is invisible
	// otherwise. happy-dom's v4-flash s13 raised `This work removed checks that
	// existed before it: IntersectionObserver observe() Does nothing, …` on
	// four consecutive rounds over four stubs the run had replaced with real
	// checks under the same describe path, and the store held nothing that
	// could tell that from a deletion. A mechanism that declines to convict
	// says so, or an autopsy cannot tell it from one that never ran
	// (FAILSAFE.md clause 4).
	Replaced int `json:"replaced,omitempty"`
	// Inherited says this reading was not taken here: it is the baseline this
	// job took before its first change, carried forward into a later round.
	Inherited bool `json:"inherited,omitempty"`
}

VerificationReading is that reading as the journal keeps it.

The roster is kept as a COUNT plus a bounded sample rather than whole. The count is what every question an autopsy asks is actually about — did this reader name anything — and a suite with two thousand checks would otherwise write a megabyte into the journal on every round of every job.

type WatchKind

type WatchKind string

WatchKind names the deterministic mechanism that wakes a sentinel.

const (
	WatchCron  WatchKind = "cron"
	WatchFile  WatchKind = "file"
	WatchGraph WatchKind = "graph"
	WatchPoll  WatchKind = "poll"
)

type WatchSpec

type WatchSpec struct {
	Kind    WatchKind     `json:"kind"`
	Cadence string        `json:"cadence,omitempty"`
	Cron    *CronSchedule `json:"cron,omitempty"`
	File    *FileWatch    `json:"file,omitempty"`
	Graph   *GraphWatch   `json:"graph,omitempty"`
	Poll    *PollWatch    `json:"poll,omitempty"`

	// CadenceGuessed marks a rhythm nobody said. Cadence used to hold the
	// user's words OR a default backfilled when nothing was recognised, and the
	// two were indistinguishable downstream — so a card told a user her weekly
	// reminder fired "about every 2 minutes" in the same flat voice it would
	// have used for words she actually said. A guess is a question, and this
	// flag is what lets the ratification card ask it.
	CadenceGuessed bool `json:"cadence_guessed,omitempty"`
}

WatchSpec is exactly one of cron, file, graph, or poll. Cadence preserves the user's own cadence words for surfaces; the typed fields are what the engine executes.

func CadenceWatchSpec

func CadenceWatchSpec(kind WatchKind, cadence, hint, condition string, now time.Time) WatchSpec

CadenceWatchSpec turns conversational cadence words into the engine's typed WatchSpec. This is the head's human-language mapping table with a structured output: cron cadences become CronSchedules, and file or graph watches whose structured parts cannot be derived deterministically degrade to a poll of the invariant itself rather than guessing at globs or predicates.

func RetimeWatch

func RetimeWatch(watch WatchSpec, cadence string, now time.Time) WatchSpec

RetimeWatch applies new cadence words to an existing typed watch: cron watches get a freshly mapped schedule while file, graph, and poll watches keep their structure and change only how often they are examined.

A clock on its own — "push the reminder to 8pm" — moves the hour and keeps the rhythm. Read as a fresh cadence it would say "once, at eight tonight", which turns a standing rule into a one-off in answer to a sentence that only asked for a later hour. The same words mean a single instant when nothing exists yet, and that reading still lives in CadenceSchedule.

func (WatchSpec) Spoken

func (watch WatchSpec) Spoken() string

Spoken renders the same schedule the way a person says it: "Sundays at 9am", "every day at 8pm", "about every 2 minutes". It is the only spelling any surface a user reads should use — String is the log's spelling and carries a watch-family prefix and a colon, which is machinery wearing a schedule's clothes ("fires: about every 2 minutes (cron:every 2 minutes)" was a real card). Times are in the process's local zone, the same zone the schedule runs in.

func (WatchSpec) String

func (watch WatchSpec) String() string

String renders the internal structured schedule with the interface's stable watch-family prefix.

Jump to

Keyboard shortcuts

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