decide

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Sep 28, 2026 License: MIT Imports: 28 Imported by: 0

Documentation

Overview

An answer is checked against the question that asked it (edges 22 and 23 of the non-author's read of #1327).

A typed decision is typed at BOTH ends. The question carries a closed set of criteria, and until this file existed nothing ever compared the answer to it: an answer of "deepseek-flash" to a question offering continue, ask-all- friends and ask-glenn printed `HELP help=deepseek-flash conf=0.94 below=-` at exit 0, and `{"type":"choice","confidence":0.99}` -- an answer naming nothing at all -- printed an empty value ABOVE the floor at exit 0. Both are the provider failing to answer the question, and a decision that was never made cannot be authorized by the confidence attached to it.

So: a choice answer must name one of the options its question offered, and the refusal names the answer and the offered set, because a reader has to see the gap to act on it.

The decider chain (deprecated/docs/SPEC-DECIDE.md D1-D2, :719-756).

A decider is anything that answers a typed question over framed evidence. Four ship: `rules`, a deterministic table that sees private evidence and makes no network call; `jev`, the remote provider, which must be assumed to train on what it sees; `local`, the same wire shape at a loopback address; and `none`. Nothing in this file is specific to us, and no question's text, option or rule row names a person, a bench, a repository or a model of ours.

The walk is the part worth reading twice. `rules` is always consulted first, whether or not it is named, because a question a table can answer is a call not worth making. A STOPPING member ends the walk before the floor is looked at, at any confidence -- a first provider's stop is not undone by a second provider's permission, and that is the one deliberate exception to "below the floor is unknown". Private evidence offered to a sees=public decider is refused BEFORE the call and the question falls through to the next decider, so a private bus is triaged by the table or by a loopback model and by nothing else. When the chain is exhausted the answer is `unknown`, which is a member of no answer set: it is the absence of an answer, and every caller's behaviour for it is today's behaviour.

Package decide makes one typed decision per call through TypeSafe Jev.

The provider is POST <baseURL> with header Authorization: Bearer <key> and a JSON body {"state": <text>, "model": "jev-latest", "questions": {...}}. Each question is one of three kinds: a choice among named options, a score against ordered levels, or a noul (null) statement. The response carries one typed answer per question plus a usage count.

The key comes ONLY from the environment variable the caller names (New's keyEnv, default JEV_API_KEY with TYPESAFE_API_KEY also accepted): never a file, never argv, and it is never printed. A decision below the floor is a suggestion, never an authorization: callers keep today's behaviour as the fallback.

The decisions table (rule 8): a decision is logged beside the outcome it predicted so a floor is re-tuned from data. The row is (question_hash, kind, answer, provider_confidence, floor, outcome).

Exactly one writer appends to the table -- the decision client itself, after every call -- and every other verb only reads it. The table is a projection of the decision journal and never an authority over the machinery.

The table is a TSV file: the file is the record. There is no database behind it (the driver it once reached for was never linked, and the database is retired, #2623), so a DSN that is a URL is refused rather than taken for a path.

Proposing a confidence floor PER KIND from the escalation log (rule 8, and the finding of 2026-09-18).

One floor for every kind is one number standing in for ten different questions. Routing the day's twenty real units through live Jev put 13 of 13 provider answers below the 0.90 floor -- 0.70 to 0.78 -- and every one of them stepped up: a 100% escalation rate, against tune's own 0.7 cap, and the end of "the lowest rung the evidence supports", because the evidence never got to support anything.

The fix is a floor per kind, and the floor is MEASURED. For each kind this takes the provider answers the log holds, keeps the ones that STOOD -- no failure, no timeout, no abandonment and no refusal recorded against them -- and proposes their p25: a floor three answers in four would have cleared. Fewer than MinFloorRows answers is not a quartile, so that kind is not proposed a floor at all and keeps the built-in default, which the log line says is a floor with no rows behind it.

And a floor above the provider's observed MAX for a kind is refused, with the remedy. That floor cannot be met by anything the provider has ever said: it does not gate the decision, it deletes it.

Package decide handles mind routing decisions across the ladder.

friends.go reads friend presence keys (friend:<lineage>:down) from the fleet store so that route never sends work to a friend who is down (#3397).

The Jev boundary for the harvest reading (toolwork T22, nova-tools#1666).

Jev classifies only what the accept gate LEFT UNDECIDED. Where a verb already settled the question, asking a provider is a paid coin-flip over a known answer (docs/SPEC-TOOLWORK.md §4 rule 2), so the boundary's first job is to not make the call at all.

Its second job is the one Johnny reads first. Everything a card writes is untrusted text written by somebody else, and some of it is written to be read by a classifier (deprecated/docs/SPEC-DECIDE.md:587-594, S1). So the state this package builds is not "the card's output, cleaned up". It is three enumerated fields read mechanically from the OUTCOME line, each checked against a closed set before anything is framed. RESULT.md prose has no path through this file -- not a truncated one, not a redacted one. That is what makes SPEC-DECIDE rule 4, public or synthetic state only (:226-241), true by construction instead of by care, and it is what SPEC-TOOLWORK §4 rule 3(a) asks for in those words.

Its third job is to be unable to loosen anything. A classification ROUTES; it never accepts (§4 rule 4, and S4 at :631-649). The type below has no field a caller could read as permission: Pushes, LiftsHold and SkipsRead answer from the gate's own verdict, and the class is not an input to any of them.

The second decision (Glenn 2026-09-18): do I keep going, ask all my friends, or ask Glenn?

The evidence is what a line can count about itself: hours on the SAME problem, retries on one rung, failures in the last hour and how many of those it caused itself, whether a class of failure is recurring, whether landing moved at all, and the uncertainty it states out loud.

One rule stands over the rest: ask-glenn only AFTER ask-all-friends. A line that has not asked its friends has not earned the interrupt.

The ladder is the retry policy (Glenn 2026-09-18).

One unit of work, one decision: WHICH MIND does it. The answer is the lowest rung the evidence supports with confidence that the FIRST attempt is right. Below the floor the answer steps UP a rung, never down. A failed attempt re-enters the decision carrying its evidence -- what failed, how -- and the answer is the next rung, automatically: sideways first, where the same height holds another lineage, then up.

Two rungs are chosen by KIND and not by height, and the machinery decides them, not the provider: security -- a guard, secrets, the sandbox, sudo, deploy keys, the network -- is Johnny's always; and so is a fresh take, where the rungs below failed or a design has one author.

A designation on a RESERVED mind is a READ and not the work (2026-09-18). The security rule used to answer rung=johnny, and on the day's twenty real units that sent seven -- units the work set owns as rowan-child -- to a mind reserved for reads and for the STOP a read can call. The rule now answers rung=<the rung the evidence supports> read=johnny: the work goes where the evidence puts it, and the security read is attached beside it. Nothing else about security changes -- it is still answered HERE and never by the provider, and a security unit with no reader available is still a refusal rather than a unit that quietly goes unread.

Friends first: the DeepSeek rungs take MECHANICAL kinds and nothing else.

Jev advises and the machinery decides (SPEC-DECIDE rules 5, 6 and 7): the provider is offered the eligible rungs at the supported height and the one above it -- never a rung below what the evidence already burned -- and an answer below the floor, an answer naming a rung nobody offered, or no answer at all leaves the rules' own rung standing.

The decision log has two sinks. The JSONL file at the path --log names is the log as it has always been, on every bench, the whole row with its evidence; routelog.go writes it and the summary reads it. The fleet's record of the same decision is one `decide` event on the cards:done stream (nova-tools #2623): written by internal/events, the writer every card transition goes through, and folded into the `decisions` table of the SQLite fold, where the calibration set is answered across benches.

There was a third sink, the decide_log table. It is retired (#2623): the stream carries the row, the fold is the table, and one writer means one stream (Rowan + Johnny, 2026-09-22 17:16Z).

A question and the criteria it is answered against are ONE versioned pair, and the pair is carried through the call boundary rather than asserted on disk (Stella, 2026-09-19, repair 1 of the #1925 hold).

The first shape of this shipped a question file naming a `criteria_file`, a `criteria_version` and its `state_fields`, and a parser that admitted those three keys and then DISCARDED them. Nothing loaded the criteria, nothing embedded it, nothing validated the state against the declared fields, and the only gate was a documentation test comparing two files on disk. Text parity is not ingestion: the bytes that went to the provider were the caller's state and the compact questions, exactly as before.

LoadQuestionFile loads the pair, refusing a version that disagrees and a criteria path that leaves the question file's own directory. Payload is the gate in front of the provider: it validates the state against the declared typed fields and returns the bytes that go out -- the criteria first, the state second -- so a missing or mistyped field is a refusal BEFORE any call is made and before anything is spent.

Who reads a finished card, as machinery rather than as prose (Stella, 2026-09-19, repair 2 of the #1925 hold).

The first shape of this put the mandatory rules in a criteria file and asked the provider to honour them. Prose is something a high-confidence answer may contradict, and rule 6 already says confidence never authorizes: a settled designation is not a judgement to be bought, and an obediently wrong answer at 1.00 is exactly as wrong as one at 0.10.

So four things are derived here and the provider's answer is CONSTRAINED by them, never trusted over them:

  1. a settled security designation is taken without asking at all;
  2. an unresolved holder of the area keeps its read, and no answer lifts a hold or replaces its holder;
  3. a design read that the evidence requires survives an answer that names somebody else first -- an answer says who reads FIRST, never who may be skipped;
  4. the human is reached only after the friends, which is `help --state`'s own rule and not a preference.

The roles are ROLES and not this house's roster (repair 4): the provider is offered configured, opaque role names, and the binding from role to a mind is local. A role no registry configures is a refusal, because an answer cannot invent an owner.

The registry of minds: the ladder nova-decide routes a unit of work over (Glenn 2026-09-18).

A rung is a HEIGHT, not a name: Flash and Pro at the bottom on the DeepSeek lineage, then the child rungs -- Opus (Rowan's) and Sol (Stella's) -- at ONE height in two lineages, so a failure moves SIDEWAYS before it moves up; then the friends, each a mind with an owned lane; then Astra and Fable as the top pair, all friends at once above them, and Glenn above that.

Two rungs are chosen by KIND and not by height: a guard, secrets, the sandbox, sudo, deploy keys or the network is Johnny's always, and so is a fresh take -- the rungs below failed, or a design with one author. The `kinds` column is that designation and nothing else.

A designation on a RESERVED mind is a READ, never the work. Johnny is reserved -- for a different view, and for the STOP a security read can call -- so the security kind attaches him as the READER and the work goes to the rung the evidence supports. A designation that hands a reserved mind the work itself is the routing bug of 2026-09-18: seven units the work set owns as rowan-child were routed to a mind that does not take work.

The registry is a DATA FILE. A path names one; an empty path is the default embedded below, so the loop runs on a bench with no file of its own. Every row is validated on the way in: a bad row is a refusal, never a guess.

Beside the minds it holds two MEASURED tables, data for the same reason the ladder is data:

  • floors: the confidence floor PER KIND. One floor for every kind is one number standing in for ten different questions, and on 2026-09-18 it made 13 of 13 provider answers escalate -- a 100% escalation rate against tune's own 0.7 cap. Each row carries the measurement behind it in `from`; a kind with no row keeps DefaultFloor, which is a floor with no rows behind it, and the log line says so.
  • rates: what one model's tokens cost, per million, so a usage row carries usd instead of a dash. A model with no rate is a dash and a NOTE naming the model and the remedy -- never a guessed price.

The escalation log (Glenn 2026-09-18): every routing decision is written down with the evidence that produced it, the rung it tried, what followed, the rung that finally succeeded -- and, beside all of it, what Rowan would have picked. That last column is the point: it is how we find out whether the decision route is better than the coordinator's own hand, one row at a time.

The log is append-only JSON lines, one object per decision, at a path the caller names. Nothing here reads a working directory and nothing is rewritten in place; the rows are the record, and the summary is a projection of them.

The summary regenerates the STARTING RUNG per kind from the rows: the lowest rung that is carrying its own weight -- successes at that height, and at least as many successes as failures. A kind with no success keeps the rung the table started from, because a starting rung with no rows behind it is not regenerated (SPEC-DECIDE rule 8).

Tuning a confidence floor from a decisions log (rule 8): a decision is logged beside the outcome it predicted, and the floor is re-tuned from those rows, never from a feeling about the model.

A decisions log is JSONL, one row per decision. Each row joins the decision (the field named by TuneOptions.Choice, default "decision"), its confidence (TuneOptions.Conf, default "confidence") and the outcome (TuneOptions.Label, default "label"). A row without a label is counted in Lines and skipped as unlabeled. For each floor, a row at or above the floor was decided: Tune reports how many of those agreed with their label (agree_rate) and how many fell below it (escalation_rate, against every labeled row). The best floor is the one with the highest agree_rate whose escalation_rate is at most TuneOptions.MaxEscalation; a tie keeps the higher (more selective) floor. Fewer than MinLabeled labeled rows cannot set a floor, so the caller refuses rather than guesses.

The who-reads machinery at the CALL BOUNDARY (Stella, 2026-09-19, r2 of the #1925 hold).

readers.go derived the rules and constrained an answer against them, and nothing in production called it: MandatoryReader, RequiredReads, ConstrainRead and ReadState had no reference outside that file and its tests. The verb loaded the pair, called the provider and printed the answer verbatim, so a state carrying a settled security designation, two design defaults, moved normative text and an unresolved hold accepted `child-review` at confidence 1.00 -- one call, exit 0. A rule nothing calls is prose with a test beside it.

This file is the wiring, and it is three small things:

  • a question file DECLARES the machinery it is answered under (`"machinery": "who-reads"`), so the binding is in the versioned pair rather than in a name match inside the verb;
  • ReadStateOf turns the state's own typed fields -- the ones Payload has already validated -- into the ReadState the rules are derived from, and refuses a holder no registry configures, because no answer creates an owner;
  • ReadLine prints the whole decision: who reads first, every read the evidence obliges beside it, which of the two settled it, and lifts_hold=false as a FIELD rather than as the absence of a sentence.

The order is the point. A settled designation is taken before a client is constructed, so it costs zero calls and no key; an advisory answer is constrained before it is printed and before it is recorded.

Index

Constants

View Source
const (
	SeesPublic  = "public"
	SeesPrivate = "private"
)

What a decider may see (S7, :696-716).

View Source
const (
	EvidencePublic  = "public"
	EvidencePrivate = "private"
)

Where a piece of evidence came from.

View Source
const (
	WhyProviderError   = "provider-error"
	WhyPrivateEvidence = "private-evidence"
	WhyTamper          = "tamper"
	WhySecretShaped    = "secret-shaped"
)

Why a line reads as it does (D3's `why=`).

View Source
const (
	AcceptOK      = "ok"
	AcceptReject  = "reject"
	AcceptAbstain = "abstain"
	AcceptNone    = "none"
)

The accept gate's verdict, as the OUTCOME line carries it. These are read from the line by code and are never asked of anybody (S3, :620-630).

View Source
const (
	Line2Blocked = "blocked"
	Line2Abstain = "abstain"
	Line2None    = "-"
)

The second OUTCOME line's word, for the `accept=none` shapes §4 rule 3 names.

View Source
const (
	ClassClean            = "clean"
	ClassDefect           = "defect"
	ClassSkipPrecondition = "skip-precondition"
	ClassBlockedToolchain = "blocked-toolchain"

	// ClassRejected is a member of the class set that NO PROVIDER IS EVER ASKED
	// FOR. The gate already said reject; a typed judgment over evidence a verb
	// settled is a paid coin-flip over a known answer (§4 rule 2). It is also
	// the reason `failed` is not this set's word for a rejected card: a card the
	// gate rejected did not fail, it was refused, and the ladder must not count
	// it against the rung that ran it.
	ClassRejected = "rejected"

	// ClassUnknown is a member of NO answer set. It is the absence of an answer
	// (rule 11, :99), which is why it is declared apart from the four above.
	ClassUnknown = "unknown"

	// ClassFailed is named here only so that a test can assert it is never the
	// answer for a rejected card. Nothing in this file ever returns it.
	ClassFailed = "failed"
)

The harvest question's class set (deprecated/docs/SPEC-DECIDE.md:938-947, reading 2).

View Source
const (
	DeciderRules = "rules"
	DeciderJev   = "jev"
	DeciderNone  = "none"
)

The deciders this boundary can name (D1, :719-733).

View Source
const (
	WhyNone       = "-"
	WhyBelowFloor = "below-floor"
	WhyNoDecider  = "no-decider"
)

Why a line reads as it does (D3's `why=`, :790-799).

View Source
const (
	EventRerunClean = "rerun-clean"
	EventRerunRed   = "rerun-red"
)

The observed events a later harvest of the SAME unit on another bench appends (D6, deprecated/docs/SPEC-DECIDE.md:1186-1190, reading 2). Neither is truth: a card that is clean elsewhere may have been racing a flaky fixture, and one red elsewhere may have hit a second bench's second defect. Truth comes from the escalated reader's --truth and the audit sample (D6).

View Source
const (
	HelpContinue      = "continue"
	HelpAskAllFriends = "ask-all-friends"
	HelpAskGlenn      = "ask-glenn"
)

The three answers.

View Source
const (
	KindRebase          = "rebase"
	KindStack           = "stack"
	KindFixtureRetarget = "fixture-retarget"
	KindFleetChore      = "fleet-chore"
	KindDogfood         = "dogfood"
	KindRowTest         = "row-test"
	KindFixWithRedTest  = "fix-with-red-test"
	KindNewVerb         = "new-verb"
	KindSpec            = "spec"
	KindDesign          = "design"
	KindGuard           = "guard"
	KindCauseToFind     = "cause-to-find"
	KindTranscriptTest  = "transcript-test"
)

The kinds of unit a decision is asked about. They are the evidence's first field and the log's key: the starting rung is regenerated per kind.

View Source
const (
	OutcomeOK        = "ok"
	OutcomeFailed    = "failed"
	OutcomeTimeout   = "timeout"
	OutcomeAbandoned = "abandoned"
)

The outcome of one attempt.

View Source
const (
	SourceRules = "rules"
	SourceRule  = "rule"
	SourceJev   = "jev"
)

Where a route answer came from.

View Source
const (
	TouchGuard      = "guard"
	TouchSecrets    = "secrets"
	TouchSandbox    = "sandbox"
	TouchSudo       = "sudo"
	TouchDeployKeys = "deploy-keys"
	TouchNetwork    = "network"
)

The six things that make a unit security work. They are an enumeration and not free text: a touch the table does not hold is a refusal.

View Source
const (
	// WaitNone is the absence, rendered as a dash so every line carries the
	// field and no reader has to infer it.
	WaitNone = "-"
	// WaitAwaitingTermination is the lease rule: an attempt timed out, its
	// expiry is UNKNOWN, and nothing is dispatched until it is known dead.
	WaitAwaitingTermination = "awaiting_termination"
)

RouteResult is one routing decision: the rung, the number the floor was applied to, the floor, why, and -- for the log -- what the rules alone would have picked. The typed actions a route answers with beside the rung. A wait is NOT permission to retry: the rung named is the one an attempt may still be running on, and the caller's next move is to establish what happened to it.

View Source
const (
	SourceMachinery = "machinery"
	SourceProvider  = "provider"
)

SourceMachinery says the answer was settled here and no provider answer could have moved it. SourceProvider says the provider's pick stood, within the constraints.

View Source
const (
	// AskBus is a note on the bus: a friend, the top pair, all friends, Glenn.
	AskBus = "bus"
	// AskCard is a swarm card: the DeepSeek rungs take work as cards.
	AskCard = "card"
	// AskChild is a child of the coordinator that owns that lineage.
	AskChild = "child"
)

How a rung is asked. A mind is reached one of three ways and the row says which, because the caller has to hand the unit over after the decision.

View Source
const (
	AvailabilityAvailable = "available"
	AvailabilityAsleep    = "asleep"
	AvailabilityReserved  = "reserved"
)

A mind's availability. A reserved mind is OFF the height ladder and reached only by a kind designation -- which is exactly Johnny: reserved for a different view, and security's rung regardless.

View Source
const (
	// FloorFromFlag is a floor the caller named on the command line. An
	// explicit number beats a table: the person asking is looking at something
	// the table does not know.
	FloorFromFlag = "flag"
	// FloorFromKind is the registry's floor for this unit's kind, measured.
	FloorFromKind = "kind"
	// FloorFromBuiltIn is DefaultFloor: no row, no measurement, a floor with
	// nothing behind it.
	FloorFromBuiltIn = "built-in"
)

Where an effective floor came from. Every decision line carries it, because a floor measured from rows and a floor nobody has ever measured are two different claims and a reader cannot tell them apart from the number.

View Source
const (
	// ReceiptRecorded: the configured decisions table took the row.
	ReceiptRecorded = "recorded"
	// ReceiptNotConfigured: no table was configured, so there is no row and
	// the line says so rather than saying nothing.
	ReceiptNotConfigured = "not-configured"
)

Receipts a who-reads line may carry: where the decision's durable row went, or why there is none. A decision printed with no word about its row is a decision whose receipt a reader has to assume (Stella, 2026-09-19, expanded Go read of #1925).

View Source
const (
	WorkTypeIssueColdRead          = "issue-cold-read"
	WorkTypeTranscriptReproduction = "transcript-reproduction"
	WorkTypeSpecRuleConformance    = "spec-rule-conformance"
	WorkTypeCodeAuditRead          = "code-audit-read"
	WorkTypeSpecContractProbe      = "spec-contract-probe"
	WorkTypeIssueFixRedFirst       = "issue-fix-red-first"
	WorkTypeRecutAtTip             = "recut-at-tip"
	WorkTypeConformanceCell        = "conformance-cell"

	WorkTypeUnclassified = "unclassified"
)

The eight work types, in the report's order (cheapest per useful card first), and the answer for a card no rule and no Jev could read.

View Source
const (
	WorkTypeByRules = "rules"
	WorkTypeByJev   = "jev"
)

Who answered.

View Source
const AdjudicatedField = "adjudicated"

AdjudicatedField is the row field saying whether a label is adjudicated truth or an observation joined to the row afterwards.

View Source
const (
	DeciderLocal = "local"
)

The deciders that ship (D1).

View Source
const DecisionsEnv = "NOVA_DSN"

DecisionsEnv names the environment variable a decisions table path is read from when a verb is not given one on the command line.

View Source
const DefaultBaseURL = "https://api.typesafe.ai/v1/systemone"

DefaultBaseURL is the TypeSafe Jev endpoint New uses when baseURL is empty.

View Source
const DefaultFloor = 0.65

DefaultFloor is the confidence floor a decision is gated on when the caller names none, matching nova-decide's --floor default.

It was 0.9, and 0.9 was a number nobody had rows behind (rule 8 asks for the rows). The rows exist now: 39 real route calls over 13 units on 2026-09-18 came back between 0.61 and 0.91, and the SAME unit with the SAME evidence came back 0.78, 0.80, 0.81 and 0.82 on four calls. A floor inside that band does not separate a right answer from a wrong one -- it separates one call from the next, and the schema campaign watched three row cards miss 0.90 by 0.01 and step a whole rung off pro, which then landed all four green. So the floor sits BELOW the band: a step-up now means the provider's confidence actually collapsed, not that it returned its ordinary number. 0.65 and not 0.7, because 0.7 was still inside it -- one rebase unit came back 0.68, 0.69 and 0.71 on three calls and routed two ways.

View Source
const DefaultKeyEnv = "JEV_API_KEY"

DefaultKeyEnv is the environment variable New reads when keyEnv is empty. TYPESAFE_API_KEY is accepted as a fallback.

View Source
const DefaultMaxEscalation = 0.7

DefaultMaxEscalation is the escalation-rate cap Tune uses to pick the best floor when none is given.

View Source
const DefaultMaxSteps = 3

DefaultMaxSteps is how many decisions --step-up makes before it stops. Three is the ladder's own shape: the rung the evidence supports, one sideways, one up. A step-up that has not landed by then is not a confidence problem.

View Source
const DefaultModel = "jev-latest"

DefaultModel is the model every request names.

View Source
const DesignationFreshTake = "fresh-take"

DesignationFreshTake is the kind designation for a fresh take: the rungs below failed, or a design with one author.

View Source
const FallbackKeyEnv = "TYPESAFE_API_KEY"

FallbackKeyEnv is accepted when the named variable is unset.

View Source
const LineageDeepSeek = "deepseek"

LineageDeepSeek is the lineage of the two card rungs. It is named here because two rules turn on it: friends first, and a mechanical kind that failed on one of them is not mechanical after all.

View Source
const MachineryWhoReads = "who-reads"

MachineryWhoReads is the one machinery a question file may declare today: a question file naming it is answered under readers.go's rules.

View Source
const MinFloorRows = 2

MinFloorRows is the fewest provider answers a kind's floor may be proposed from. Two is the fewest a quartile can be read off at all, and a floor from two rows is a floor to re-propose next week -- which is why every row carries the count it was measured from.

View Source
const MinLabeled = 10

MinLabeled is the fewest labeled rows a floor can be set from.

View Source
const OutcomeSkipped = "skipped"

OutcomeSkipped is the fourth ROUTE-OUTCOME word, and it is deliberately not one of the four above: an attempt has an outcome because it RAN, and a unit skipped for an unmet precondition was never asked to run. It is an outcome row all the same -- coverage counts it -- but it is no rung's success and no rung's failure, so it moves no floor in either direction (SPEC-DECIDE H2).

View Source
const ReadQuestion = "reader"

ReadQuestion is the question name the who-reads machinery constrains. A question file declaring the machinery and not asking it is a refusal.

View Source
const RungQuestion = "rung"

RungQuestion is the name of the one choice Jev is asked.

View Source
const SourceOutcome = "outcome"

SourceOutcome marks a row that is not a decision at all: the outcome of a unit a decision routed earlier, appended later by whoever watched the work. The log is append-only -- a row written is never rewritten -- so an outcome is its own row, and the summary folds it into the rung it names without counting it as a second decision.

View Source
const SourceSkipped = "skipped"

SourceSkipped marks a row for a route a launcher was explicitly told to skip: not a decision, and carrying the reason that opened the skip. A skip is a fact in the log and not an absence (SPEC-DECIDE housekeeping H4, #1625).

View Source
const WorkTypeQuestion = "worktype"

WorkTypeQuestion is the name the work-type question is asked under.

Variables

View Source
var (
	// SizeBuckets are the buckets a file, package or lane count falls into.
	SizeBuckets = []string{"none", "1-3", "4-9", "10-19", "20+"}
	// AttemptBuckets are the buckets a prior-attempt count falls into.
	AttemptBuckets = []string{"0", "1", "2", "3+"}
	// PlatformBuckets say whether a platform need is one of the benches we run
	// all day, or one outside them -- never which.
	PlatformBuckets = []string{"ordinary", "named"}
	// DeadlineBuckets are the buckets a deadline falls into.
	DeadlineBuckets = []string{"none", "under-10m", "under-2h", "over-2h"}
)

The buckets the evidence is reduced to before any of it leaves this process. They are ENUMERATIONS: every value the provider ever sees is one of these tokens, so no title, path, branch name, error text or attempt reason can ride out on a state line (SPEC-DECIDE rule 4).

View Source
var ConfBuckets = []string{"0.0-0.5", "0.5-0.6", "0.6-0.7", "0.7-0.8", "0.8-0.9", "0.9-1.0"}

ConfBuckets are the buckets the per-kind confidence histogram counts into, in order. They are coarse on purpose: the question a reader brings to this histogram is "where do the provider's answers actually land, and is the floor above all of them", and six buckets answer it on one line.

View Source
var DefaultFloors = []float64{0.5, 0.7, 0.8, 0.9, 0.95}

DefaultFloors are the confidence floors Tune reports on when none are given.

View Source
var ErrAdjudicatedMalformed = errors.New("decide: tune: an adjudication marker is present and is not a boolean")

ErrAdjudicatedMalformed is the refusal a row earns by carrying an adjudication marker nobody can read. It is a different fault from ErrNotAdjudicated and gets a different one-word reason: a legible false is a log that says what it is, and this is a log that says something unreadable.

View Source
var ErrNotAdjudicated = errors.New("decide: tune: these labels are observations and not adjudicated truth")

ErrNotAdjudicated is the refusal a log of observations earns when a floor was asked of it. It is a sentinel so a caller names it in one word rather than matching on a sentence.

Kinds is every kind a unit may name, in the order the spec names them.

Roles is every role a question may offer and an answer may name.

Touches is every touch a unit may name.

WorkTypes is the closed set, in the report's order.

Functions

func AppendEntry

func AppendEntry(path string, e Entry) error

AppendEntry appends one row to the log at path, creating it if it is not there. The file is the tool's own (0600) and is never rewritten.

func AppendObservedRow

func AppendObservedRow(path, unit, event, bench string) error

AppendObservedRow appends one OBSERVED row (D6) to outcomes.jsonl: a later harvest of the same unit on another bench saw it rerun-clean or rerun-red, with the bench in fields. An observed row is never truth: it carries no class, no confidence and no verdict a floor could be tuned from -- only the event, the unit and where it was seen.

func AppendOutcomeRow

func AppendOutcomeRow(path, unit string, c Classification) error

AppendOutcomeRow appends one JSON line to outcomes.jsonl beside the route log (§4 rule 5). class= and conf= are written back on every row, including the unknown ones: a below-floor answer is logged as the absence it is, with its confidence, never dropped (:100), because a row that is not written is a row the floor can never be re-tuned from.

func AskedHarvestClasses

func AskedHarvestClasses() []string

AskedHarvestClasses is the set a provider may choose among. `rejected` and `unknown` are deliberately absent: the first is mechanical, the second is the absence of an answer.

func CanonicalKind

func CanonicalKind(kind string) string

CanonicalKind resolves an alias to the kind the table holds and returns anything else unchanged. It is applied ONCE, where the evidence is read, so the kind the ladder decides on and the kind the route log records are the same name -- an alias that reached the log would split every per-kind floor.

func CheckFloors

func CheckFloors(floors []KindFloor, proposals FloorProposals) error

CheckFloors refuses a floor no answer could ever meet: one above the provider's observed maximum for that kind. Such a floor does not gate the decision, it deletes it -- every answer steps up, whatever the provider says -- and that is the 2026-09-18 defect being written back into the file it came from. The message carries the remedy: the number to write instead.

func ConfiguredRole

func ConfiguredRole(r Role) bool

ConfiguredRole reports whether a role is one the registry configures. An answer naming anything else is refused: no model response creates an owner.

func DecisionEvent

func DecisionEvent(e Entry) (events.Event, error)

DecisionEvent is one log row as a `decide` event: decide_log's fields under decide_log's names (internal/events/decide.go). The stamp is the entry's at; the label is the unit, the id the whole stream joins on. A counter the provider did not report stays absent, never zero, and so does a confidence or a floor the row did not carry. Free text (the reason, the refusal) is capped at the stream's field ceiling with a mark that says so; the uncut text is in the JSON lines log. The evidence document does not travel: its measured columns do.

A stamp that is not a time is a refusal naming it: the record never takes a zero stamp for a timestamp nobody could read.

func DefaultRegistryJSON

func DefaultRegistryJSON() []byte

DefaultRegistryJSON is the embedded ladder's own bytes, for a caller that has to merge into the document rather than into the parsed ladder -- the floor proposal writing a registry on a bench that has never had a file of its own. A copy, because the embedded bytes are the package's.

func DownFriends

func DownFriends(ctx context.Context, addr, user, password string, reg *Registry) (map[string]bool, []string, error)

DownFriends connects to Redis at addr and reads friend:<lineage>:down for every friend rung in one pipeline.

func HarvestState

func HarvestState(ev HarvestEvidence) (string, error)

HarvestState builds the framed state, and it is the only function that ever produces text for a provider. S2 (:595-619) fixes the shape: one frame, a fresh sixteen-hex-digit nonce per call that is never derived from the evidence, every evidence line prefixed with a bar and a space so that no evidence line can equal a marker whatever it contains, and the tamper answer named in the instructions.

Three fields go in. A fourth never does.

func KnownKind

func KnownKind(kind string) bool

KnownKind reports whether the kind is one of the ten.

func KnownWorkType

func KnownWorkType(t string) bool

KnownWorkType reports whether t is one of the eight.

func Line

func Line(prefix string, answers map[string]Answer, floor float64) string

Line renders one status line for a decision: the prefix, one <name>=<value> conf=<0-1> pair per answer in name order, then the floor and the below list naming every answer under it. A decision below the floor is a suggestion, never an authorization.

func Mechanical

func Mechanical(kind string) bool

Mechanical reports whether a kind is mechanical -- the only kinds a DeepSeek rung is eligible for.

func MergeFloors

func MergeFloors(registryJSON []byte, floors []KindFloor) ([]byte, error)

MergeFloors writes the floors into a registry document, leaving every other field of the file exactly as it was -- the comments above all, which are where the ladder explains itself. The document is decoded as raw fields and re-encoded, so a key this package has never heard of survives the write.

func NeedsProvider

func NeedsProvider(ev HarvestEvidence) bool

NeedsProvider reports whether this is a shape Jev is for at all. §4 rule 3: only `accept=abstain`, and `accept=none` whose second line is BLOCKED or ABSTAIN. Everything else the gate decided, and a decision already made is not a question.

func P25

func P25(ascending []float64) float64

P25 is the first quartile of an ASCENDING list, by nearest rank: the lowest value at or above a quarter of the rows. It is the number a floor is proposed from -- a floor that would have accepted three answers in four -- and it is here rather than in tune because the log summary reports it too, and one quartile computed two ways is two quartiles.

func ParseQuestions

func ParseQuestions(data []byte) (map[string]Question, error)

ParseQuestions parses a questions file: either a bare map of name to question, or {"questions": {...}}. Each entry carries a type (choice/score/noul), instructions, and criteria (a map for choice, a list for score, absent for noul). Anything else is a refusal, never a guess.

func QuestionHash

func QuestionHash(state, name string, q Question) string

QuestionHash is the stable hash of one question over its state: the kind, the name, the instructions and the state text. A replay names the same hash, so an answer already journaled is reproduced without calling the provider.

func ReadDownFriends

func ReadDownFriends(ctx context.Context, client redis.Cmdable, reg *Registry) (map[string]bool, []string, error)

ReadDownFriends checks Redis for friend:<seat>:down for every friend rung in the registry in one pipeline. It returns the set of down rung names (e.g. "astra" -> true for the stella lineage) and the sorted list of seat-lineage exclusion tokens (e.g. ["stella:down"]).

func ReadLine

func ReadLine(prefix string, d ReadDecision, s ReadState, confidence float64, hasConfidence bool, floor float64, receipt string) string

ReadLine renders one constrained who-reads decision. Every field a caller would otherwise have to read out of prose is a field: the required set, the holder, whether its hold is open, that nothing lifted it, and where the row went.

hasConfidence is false for a decision the MACHINERY settled. The provider was never asked, so there is no confidence to print and the column is a dash: a display constant printed there becomes, one copy later, calibration evidence about a call nobody made.

func RedactURL

func RedactURL(u string) string

RedactURL prints a URL with any password in it replaced, so a refusal that names what it was given never prints a credential.

func ResolveFloor

func ResolveFloor(reg *Registry, kind string, flagFloor float64, flagGiven bool) (float64, string)

ResolveFloor answers the floor one decision is gated on and says where it came from: the caller's flag where they gave one, else this kind's measured floor, else the built-in default.

func StampCard

func StampCard(card string, lines []string) string

StampCard writes the lines onto the card: any earlier stamp is removed and the lines go in after the card's first line, where a reader of the header finds them. Stamping twice leaves one copy.

func StartHeight

func StartHeight(kind string) (int, bool)

StartHeight is the starting rung for a kind before any evidence adjusts it.

func ValidFloor

func ValidFloor(floor float64) error

ValidFloor refuses a floor that is not a number between 0 and 1, with the one remedy in the message. NaN compares false against every bound, so a bare `floor < 0 || floor > 1` lets it through -- which is exactly how it got in.

func ValidateAnswers

func ValidateAnswers(qs map[string]Question, answers map[string]Answer) error

ValidateAnswers checks each typed answer against the question it answers. It is the last gate before an answer becomes a decision: a choice outside the criteria, a choice naming nothing, an answer of the wrong type, and an answer to a question nobody asked are all PROVIDER ERRORS rather than decisions.

The check is deterministic: questions are walked in name order, so the same bad response always names the same first offence.

func WorkTypeCardLines

func WorkTypeCardLines(wt WorkTypeResult, res RouteResult, reg *Registry, allowed WorkTypeRoutes) []string

WorkTypeCardLines is the two lines the route writes on the card: the work type with allowed_routes[type], and the route receipt in the dispatch path's own grammar (jev=<rung> where Jev chose it, jev=fallback where the rules' answer stands) with the work type on it.

func WorkTypeProducesBranch

func WorkTypeProducesBranch(t string) bool

WorkTypeProducesBranch reports whether a card of type t writes code: the three types that end in a branch. Their route is gated by allowed_routes, so a card of one of them is not routed without the table.

func WriteJevLedger

func WriteJevLedger(ctx context.Context, emitter events.Emitter, v JevVerdict) (string, error)

WriteJevLedger writes one Jev verdict to the cards:done stream: one kind=jev entry with the pull request, the head and the score as route. The production caller is `nova-decide review --ledger redis`, once per JEV line it prints.

Types

type Answer

type Answer struct {
	Type          string
	Choice        string
	Probabilities map[string]float64
	Score         float64
	Noul          float64
	Confidence    float64
}

Answer is one typed answer. Type names which of the three it is ("choice", "score" or "noul"). Choice and Probabilities are set for choice answers, Score for score answers, Noul for noul answers; Confidence is set for choice and score answers from the response, and for a noul answer it is the noul value itself: the confidence that the question is null.

func (Answer) Value

func (a Answer) Value() string

Value renders one answer as the table's answer column: the chosen option, the score, or the noul value.

type Attempt

type Attempt struct {
	Rung       string `json:"rung"`
	Outcome    string `json:"outcome"`
	Reason     string `json:"reason,omitempty"`
	Terminated bool   `json:"terminated,omitempty"`
}

Attempt is one prior attempt on this unit: the rung, what happened, why, and -- for a timeout -- whether the attempt is known to have TERMINATED. It is what makes the ladder a retry policy: a confirmed failure re-enters the decision carrying its own evidence.

Terminated is the lease rule (Stella): a timeout is a silence, not a death. Until something proves the attempt is dead, its expiry is UNKNOWN, and a rung whose attempt may still be running is not a rung to step off.

func (Attempt) Failed

func (a Attempt) Failed() bool

Failed reports whether this attempt is a CONFIRMED failure -- one the ladder may step past. A timeout counts only once termination is proved: an attempt that may still be running has not failed, it has not finished.

func (Attempt) Open

func (a Attempt) Open() bool

Open reports whether this attempt timed out with no proof that it died. The answer for an open attempt is the same rung, not the next one.

type Chain

type Chain struct {
	Deciders []ChainDecider
	Escalate string
	// Tamper is the pattern table; the shipped one is used when it is nil.
	Tamper []string
	// Now is a var so a test can pin a row's timestamp.
	Now func() time.Time
}

Chain is the ordered walk. Escalate names the stronger reader an unknown or a tampered item goes to (D5); it is a name the caller supplies and never one this package knows.

func (Chain) Classify

func (c Chain) Classify(ctx context.Context, q questions.Question, ev Evidence, floor float64) Result

Classify walks the chain for ONE item. One item to a call, always: one item's text can never colour another item's answer (D4).

type ChainDecider

type ChainDecider interface {
	Name() string
	// Sees is SeesPublic for anything that leaves the machine.
	Sees() string
	Ask(ctx context.Context, q questions.Question, state string) (answer string, confidence float64, usage Usage, err error)
}

ChainDecider is one member of the walk.

D1 names the interface `Decide(ctx, state, questions)`, and that interface ALREADY EXISTS in this package as `Decider` (ladder.go:821), where the route asks the provider through it. This is deliberately a second, narrower seam rather than a replacement: a chain member also has to say its NAME and what it may SEE (S7), which a wire-level interface has no business carrying, and displacing the route's seam to add two methods would change a call site this task has no reason to touch. JevDecider below wraps the existing `Decider`, so there is one wire client and not two.

The state a member is handed is already framed, redacted and bounded; a chain member never sees an unframed byte.

type Classification

type Classification struct {
	Class         string
	Confidence    float64
	Floor         float64
	Decider       string
	Why           string
	AskedProvider bool
	RequeueOnce   bool
	Evidence      HarvestEvidence
}

Classification is one harvest answer. It has no field that grants anything: Pushes, LiftsHold and SkipsRead below read the gate's verdict and ignore the class entirely, which is §4 rule 4 made structural rather than remembered.

func ClassifyHarvest

func ClassifyHarvest(ev HarvestEvidence, res Result, floor float64) Classification

ClassifyHarvest applies the boundary to one unit. res is the chain's own answer, decider and why; it is ignored entirely where the gate already decided, because a decision already made is not a question (§4 rule 2).

func (Classification) ChangesBench

func (c Classification) ChangesBench() bool

ChangesBench reports whether this classification moves the unit to another bench on the bench-red ground (deprecated/docs/SPEC-DECIDE.md:1175-1184, reading 2). That is a loosening, so it rests on mechanical facts (S4) and on no answer: the class must be the rule table's OWN toolchain row -- blocked-toolchain answered by the rules, never a provider's label -- AND a fact the card did not write (the job's exit status being 126 or 127, or the supervisor's own harness-error line naming a missing executable), AND the unit must not have moved on this ground before: a unit is moved to another bench on this ground at most once. A provider's blocked-toolchain without those facts is printed, is a label for the manager, and leaves the failure counted exactly as today -- a bench with no compiler is not a rung that failed, and a red the bench did not cause is not the bench's.

func (Classification) LiftsHold

func (c Classification) LiftsHold() bool

LiftsHold is always false. Rule 6 (:66) is untouched by every reading in the amendment, and it is stated here as a method so that a caller asking the question gets the answer in the type rather than in a comment.

func (Classification) Pushes

func (c Classification) Pushes() bool

Pushes reports whether this unit is pushed. It reads the GATE, never the class: no classification, at any confidence, turns a reject or an abstain into a push (§4 rule 4; S4, :631-649).

func (Classification) SkipsRead

func (c Classification) SkipsRead() bool

SkipsRead is always false, for the same reason: a classification routes work, it does not stand in for a reader.

type Client

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

Client talks to one Jev endpoint with one key the caller named.

One client's Decide is handed around as a decideFunc and called from several goroutines at once (internal/swarm's task decider does exactly that), so the per-call bookkeeping the receipt needs -- the row source and what the decisions table did with the row -- is guarded. The fields set once before any call, and read-only during them, are not.

func New

func New(baseURL, keyEnv string) (*Client, error)

New reads the key from the environment variable keyEnv (DefaultKeyEnv when empty, with FallbackKeyEnv also accepted) and refuses with an error naming the variable when it is unset. baseURL empty means DefaultBaseURL. The key is never printed.

func (*Client) Constrain

func (c *Client) Constrain(fn func(map[string]Answer) (map[string]Answer, error))

Constrain installs the machinery that stands over a provider's answers. It runs after the answers are validated against their own questions and BEFORE anything records or prints them, so a rule the evidence settles is never something a confident answer can be read past. A nil function leaves the client forwarding the provider's answer, which is every ordinary question.

func (*Client) Decide

func (c *Client) Decide(ctx context.Context, state string, qs map[string]Question) (map[string]Answer, Usage, error)

Decide asks the provider one typed decision and parses the answers. It applies a 10 s deadline of its own. A decision below the caller's floor is a suggestion, never an authorization: the caller keeps today's behaviour as the fallback.

func (*Client) RecordErr

func (c *Client) RecordErr() error

func (*Client) Recorded

func (c *Client) Recorded() int

Recorded is how many rows this client appended, and RecordErr the first append that failed. A decision the caller was told succeeded while its configured table was never written is a decision with no receipt, so the caller reads both and reports rather than assuming (Stella, 2026-09-19, expanded Go read of #1925).

func (*Client) SetFloor

func (c *Client) SetFloor(f float64)

SetFloor sets the confidence floor the client logs beside a decision. The zero value keeps DefaultFloor.

func (*Client) SetRowSource

func (c *Client) SetRowSource(source string, hasProviderConfidence bool)

SetRowSource names which of the two decided the answers this call is about, and whether a provider confidence stands behind them. Machinery that settled a decision writes SourceMachinery with hasProviderConfidence false: the provider was not asked, so there is no calibration evidence in the row and none is invented.

func (*Client) UseDecisions

func (c *Client) UseDecisions(d DecisionDriver)

UseDecisions attaches the client's decisions table. It is the one writer rule 8 names: Decide appends a row per answer after every call. A nil driver leaves the client without a table.

type Decider

type Decider interface {
	Decide(ctx context.Context, state string, qs map[string]Question) (map[string]Answer, Usage, error)
}

Decider is the seam a route asks a typed decision through. *Client is one; a test passes a fake, so no unit test ever dials the provider.

type DecisionDriver

type DecisionDriver interface {
	Append(row DecisionRow) error
	Rows(kind string) ([]DecisionRow, error)
	Close() error
}

DecisionDriver is the storage seam for the decisions table. The tool opens one driver per process. Append is the one writer; Rows is the read every other verb uses; Close releases the handle.

func OpenDecisions

func OpenDecisions(dsn string) (DecisionDriver, error)

OpenDecisions opens the decisions table at a TSV path. An empty value is a refusal, never a guess; so is a URL, which names a database this tool no longer reaches rather than a file.

type DecisionRow

type DecisionRow struct {
	QuestionHash string
	Kind         string
	Answer       string
	// ProviderConfidence is meaningful only where HasProviderConfidence is
	// true. Where it is false the provider was never asked and the column
	// is written as a dash.
	ProviderConfidence    float64
	HasProviderConfidence bool
	Floor                 float64
	Outcome               string
	// Source is SourceMachinery where the rules settled the decision with
	// no provider asked, SourceProvider where the provider's answer stood
	// (within the constraints), and empty in a row written before the
	// column existed.
	Source string
}

DecisionRow is one row of the decisions table: the question that was asked, the kind of judgment, the answer, the provider's confidence, the floor it was gated on, the outcome that followed (empty until known), and which of the two decided it.

type Entry

type Entry struct {
	Time      string `json:"time"`
	Unit      string `json:"unit"`
	Kind      string `json:"kind"`
	Evidence  Unit   `json:"evidence"`
	RungTried string `json:"rung_tried"`
	Height    int    `json:"height"`
	// Confidence and Floor are ABSENT rather than zero where the row did not
	// carry them, by the same presence rule as the counters below: a row read
	// back from a log line that omitted either keeps it nil, and the decide
	// event it becomes leaves the field off, so the fold stores NULL, never a
	// 0 nobody measured (Stella, HOLD 7 on #2628).
	Confidence    *float64 `json:"confidence,omitempty"`
	Floor         *float64 `json:"floor,omitempty"`
	SteppedUp     bool     `json:"stepped_up"`
	Escalated     bool     `json:"escalated"`
	Designated    bool     `json:"designated,omitempty"`
	Source        string   `json:"source"`
	RowanPick     string   `json:"rowan_pick"`
	Reason        string   `json:"reason,omitempty"`
	Outcome       string   `json:"outcome,omitempty"`
	RungSucceeded string   `json:"rung_succeeded,omitempty"`

	// Wait is the typed action beside the rung: "-" for a decision the caller
	// may act on, awaiting_termination for one it may not.
	Wait string `json:"wait,omitempty"`
	// Read is the mind -- or minds, comma-joined -- a KIND designation attached
	// to this unit as a READER rather than as the rung: a security read, or a
	// fresh take whose designate is reserved. The work went to RungTried; this
	// is who reads it.
	Read string `json:"read,omitempty"`
	// FloorFrom says where Floor came from: flag, kind or built-in. Two rows
	// carrying floor 0.90 are different claims when one was measured from rows
	// and the other is the default nobody has ever tuned.
	FloorFrom string `json:"floor_from,omitempty"`
	// Refusal is why the route ended in a refusal, where it did. The row is
	// still written: a call that was already made is still a cost, and a
	// decision that could not be made is still evidence.
	Refusal string `json:"refusal,omitempty"`
	// AwaitingTermination is the same fact as a boolean, for a reader that
	// gates on it: the rung named is the one an attempt may still be running
	// on, and the lease rule keeps its expiry UNKNOWN until termination.
	AwaitingTermination bool `json:"awaiting_termination,omitempty"`

	// What the decision spent. Calls is the number of provider calls it made;
	// TokensIn and TokensOut are ABSENT rather than zero where no call was made
	// or the call failed, because a zero is a measurement and an absence is not
	// (SPEC-TOKENS rule 14). UsageFailed marks a call whose cost is unknown.
	Calls       int  `json:"calls,omitempty"`
	TokensIn    *int `json:"tokens_in,omitempty"`
	TokensOut   *int `json:"tokens_out,omitempty"`
	UsageFailed bool `json:"usage_failed,omitempty"`

	// Excluded is the set of down friend rungs excluded from routing (#3397).
	Excluded    string `json:"excluded,omitempty"`
	DownChecked bool   `json:"down_checked"`

	// Ms is the provider round trip in milliseconds, measured by the caller
	// on a monotonic clock around the call alone; WallMs is the verb's start
	// to its line. Each is ABSENT, never zero, where there was no call or no
	// measurement, by the per-counter presence rule: a zero is a measurement
	// and an absence is not (SPEC-TOKENS rule 14).
	Ms     *int `json:"ms,omitempty"`
	WallMs *int `json:"wall_ms,omitempty"`
}

Entry is one row of the escalation log.

func EntryFor

func EntryFor(res RouteResult, u Unit, now time.Time) Entry

EntryFor is the row one route decision writes. The outcome and the rung that succeeded are filled in later, by the caller that watched the work: a decision never writes them for itself.

func LastDecision

func LastDecision(entries []Entry, unit string) (Entry, bool)

LastDecision finds the most recent DECISION row for a unit -- never an outcome row -- so an outcome takes the kind and the rung from the decision it answers. A unit the log does not hold is a refusal: an outcome against a decision nobody made is a row that would regenerate a starting rung from nothing.

func OutcomeEntry

func OutcomeEntry(unit, kind, rung, outcome string, now time.Time) Entry

OutcomeEntry is the row that records what happened to a unit a decision routed: the rung that ran it and how it ended. It is a row of its own because the log is append-only, and it names the kind and the rung from the decision it answers rather than from a caller's memory of them.

func ReadEntries

func ReadEntries(path string) ([]Entry, error)

ReadEntries reads the log back. A missing file, or a line that is not one JSON object, is a refusal naming what it could not read.

func SkippedEntry

func SkippedEntry(unit, reason string, now time.Time) Entry

SkippedEntry is the row one explicitly skipped route leaves behind: the reason travels in the row, because a skip nobody can explain is the habit H4 exists to end.

type EventSink

type EventSink struct {
	Emitter events.Emitter
	// Bench is the bench the decision was made on, when the caller knows it.
	Bench string
	// Timeout bounds one write; zero is ten seconds.
	Timeout time.Duration
	// contains filtered or unexported fields
}

EventSink writes each decision as one `decide` event through an Emitter: the fleet store's RedisStore in the tool, the in-memory FakeStream in a test. It is write-only. The decisions on the stream are read by the fold (`nova-pulse fold`), never back through this sink.

func OpenEventSink

func OpenEventSink(addr, user, password, bench string) (*EventSink, error)

OpenEventSink dials the fleet store at addr and returns the sink that writes decisions to cards:done. The password comes from the caller's environment, never from argv.

func (*EventSink) Append

func (s *EventSink) Append(e Entry) error

Append writes the decision as one event on the stream.

func (*EventSink) Close

func (s *EventSink) Close() error

Close releases the store connection, if this sink dialed one.

func (*EventSink) Entries

func (s *EventSink) Entries() ([]Entry, error)

Entries refuses: the stream is read by the fold, not by the writer.

type Evidence

type Evidence struct {
	Text    string
	Class   string
	Pointer string
}

Evidence is one item's text and where it came from. The class is a fact about the SOURCE -- the forge reporting a repository public, a bus clone holding a marker -- and is never inferred from the text.

func (Evidence) Public

func (e Evidence) Public() bool

Public reports whether this evidence may be shown to a decider that leaves the machine. Anything not positively known to be public is private: the boundary fails closed.

type FakeLogSink

type FakeLogSink struct {

	// AppendErr, when set, is what Append returns: the seam for a test that
	// wants to see a sink fail.
	AppendErr error
	// contains filtered or unexported fields
}

FakeLogSink is the in-memory sink the unit tests run on: append, read back in order, and a seam for a sink that fails.

func NewFakeLogSink

func NewFakeLogSink() *FakeLogSink

NewFakeLogSink returns an empty sink.

func (*FakeLogSink) Append

func (f *FakeLogSink) Append(e Entry) error

Append stores the row.

func (*FakeLogSink) Close

func (f *FakeLogSink) Close() error

Close is a no-op; the fake holds nothing.

func (*FakeLogSink) Entries

func (f *FakeLogSink) Entries() ([]Entry, error)

Entries returns the rows in the order they were appended.

type FileSink

type FileSink struct{ Path string }

FileSink is the log as it has always been: append-only JSON lines at a path the caller names, written by AppendEntry and read by ReadEntries.

func (*FileSink) Append

func (f *FileSink) Append(e Entry) error

Append writes one row.

func (*FileSink) Close

func (f *FileSink) Close() error

Close is a no-op: the file sink holds nothing open between rows.

func (*FileSink) Entries

func (f *FileSink) Entries() ([]Entry, error)

Entries reads the rows back, in the order they were written.

type FloorProposal

type FloorProposal struct {
	Kind string
	// Rows is every provider answer for this kind; Stood is those with no
	// failure recorded against them, and Failed the rest.
	Rows   int
	Stood  int
	Failed int
	// Max and P25 describe the answers that stood.
	Max float64
	P25 float64
	// Current is the floor in force now and CurrentFrom where it came from.
	Current     float64
	CurrentFrom string
	// Floor is the proposal, set only when Proposed.
	Floor    float64
	Proposed bool
	// Defeated says the CURRENT floor is above every answer that stood: the
	// finding this verb exists to surface.
	Defeated bool
	// Note is why no floor was proposed, where none was.
	Note string
}

FloorProposal is one kind's read: the provider answers the log holds for it, how many stood, their shape, the floor in force now and the floor proposed from the rows.

type FloorProposals

type FloorProposals struct {
	Rows      int
	Proposals []FloorProposal
}

FloorProposals is the whole read, one row per kind, in kind order.

func ProposeFloors

func ProposeFloors(reg *Registry, entries []Entry) (FloorProposals, error)

ProposeFloors reads the log and proposes one floor per kind. A row that is not a provider answer is not evidence about the provider and is left out: the rules' own confidences are the machinery's numbers, and averaging them in would hide exactly what this is measuring.

func (FloorProposals) Proposed

func (p FloorProposals) Proposed(from string) []KindFloor

Proposed is the proposals that name a floor, as registry rows ready to be written. The From field is the measurement, so a floor in the registry can always be traced back to the rows behind it.

func (FloorProposals) Render

func (p FloorProposals) Render() string

Render is the proposal, one line per kind then the finish. Every field is on every line and a number nobody measured is a dash.

type FloorStat

type FloorStat struct {
	Floor     float64
	Decided   int
	Agree     int
	Escalated int
	// Defaulted is the escalated rows a named default answered, and
	// DefaultAgree how many of those the default got right. Both are zero
	// when no default is named: an escalation with no single answer behind
	// it is a count and not a score.
	Defaulted    int
	DefaultAgree int
}

FloorStat is one floor's line: how many rows the floor decided, how many of those agreed with their label, and how many it escalated.

func (FloorStat) AgreeRate

func (s FloorStat) AgreeRate() float64

AgreeRate is the share of decided rows that agreed with their label.

func (FloorStat) EscalationRate

func (s FloorStat) EscalationRate(labeled int) float64

EscalationRate is the share of labeled rows the floor left below it.

func (FloorStat) Missed

func (s FloorStat) Missed() int

Missed is the below-floor rows a named default answered WRONG: the rows the floor handed to the cheap answer where the log says the cheap answer was not the one the work needed. It is zero where no default is named.

type HarvestEvidence

type HarvestEvidence struct {
	Accept string // the gate's verdict, mechanical
	Line2  string // the second OUTCOME line's word
	Reason string // the reason TOKEN, from the closed set above

	// Requeued is the forge's own fact about this unit: it has been through
	// rule 14's requeue path already. An answer cannot set it.
	Requeued bool

	// ExitStatus is the supervisor's own record of the job's exit status: a
	// fact the card did not write. A negative value is its absence, never a
	// guess. It is read by the bench-red rule below and is never framed for a
	// provider.
	ExitStatus int

	// HarnessError is the supervisor's own harness-error line where it wrote
	// one, "" where it did not. Nothing a card wrote is this field, and it is
	// never framed for a provider.
	HarnessError string

	// BenchMoved is the forge's own fact about this unit: it has already been
	// moved to another bench on the bench-red ground. An answer cannot set
	// it, and the ground moves a unit at most once.
	BenchMoved bool

	// Prose is whatever the card wrote. NOTHING IN THIS PACKAGE READS IT. It is
	// carried so that a caller cannot accidentally build state from it by
	// reaching past this type for the file instead.
	Prose string
}

HarvestEvidence is everything the boundary will let out, and the Prose field is the joke it does not laugh at: a caller may set it, and nothing reads it. It is here so that the type a caller already holds can be passed whole without anyone having to remember to strip the prose first -- the stripping is this package's, not the caller's, because a rule the caller has to remember is the rule that failed.

type HelpResult

type HelpResult struct {
	Answer string
	Reason string
}

HelpResult is the answer and why.

func Help

func Help(s HelpState) (HelpResult, error)

Help answers the second decision. Nothing here is a judgment call at run time: the same evidence gives the same answer, on any bench, with no network.

func (HelpResult) Line

func (r HelpResult) Line() string

Line is the one line the help decision prints.

type HelpState

type HelpState struct {
	Hours            float64 `json:"hours"`
	RetriesOnRung    int     `json:"retries_on_rung"`
	FailuresLastHour int     `json:"failures_last_hour"`
	SelfInflicted    int     `json:"self_inflicted"`
	ClassRecurring   bool    `json:"class_recurring"`
	LandingMoved     bool    `json:"landing_moved"`
	Uncertainty      float64 `json:"uncertainty"`
	AskedAllFriends  bool    `json:"asked_all_friends"`
}

HelpState is the evidence for the help decision.

func ParseHelpState

func ParseHelpState(data []byte) (HelpState, error)

ParseHelpState reads the help evidence from JSON, refusing a field it does not hold.

func (HelpState) Validate

func (s HelpState) Validate() error

Validate refuses a state that cannot be, rather than answering over it.

type JevDecider

type JevDecider struct {
	Client Decider
	Local  bool
}

JevDecider adapts the existing wire client -- D1's `Decider`, the one the route already asks through -- to a chain member. It is `sees=public`: assume a remote provider trains on what it sees (S7). LocalDecider is the same wire shape at a loopback address, and is `sees=private` for the same reason a loopback model is: nothing leaves the machine.

func (JevDecider) Ask

Ask asks the one question, one item to a call (D4), and returns the choice and its confidence. An answer of a type the question did not ask for is no answer: the chain's caller sees an empty string and walks on.

func (JevDecider) Name

func (j JevDecider) Name() string

Name is `jev` for the remote provider and `local` for a loopback one.

func (JevDecider) Sees

func (j JevDecider) Sees() string

Sees is the whole point of the type: a remote provider is public, a loopback one is private, and the chain refuses private evidence to the first before any call is made.

type JevVerdict

type JevVerdict struct {
	Repo    string // owner/name
	PR      int
	Head    string // the head sha the line was written at
	Verdict string // PASS, BOUNCE or UNSURE; the stream has no field for it, it is here for the caller's record
	Score   int    // 1-10 when Scored
	Scored  bool   // false when the line printed score=-
	Model   string // the model the score was asked of; "jev" when empty
}

JevVerdict is one Jev line as the ledger stream carries it: the pull request, the exact head, the verdict word and the 1-10 score, or no score at all.

func (JevVerdict) Check

func (v JevVerdict) Check() error

Check refuses what is not a Jev verdict before it can reach the stream.

func (JevVerdict) Label

func (v JevVerdict) Label() string

Label is the id the fold joins and groups on: repo#pr, one row per pull request. The repo alone made every Jev verdict across a repository one pseudo-card in by_label and totals (Emma's read of PR #2788).

func (JevVerdict) Route

func (v JevVerdict) Route() string

Route is score/N, or score/- when no score was given: an absent score is not a zero (no evidence is not negative evidence).

type KindFloor

type KindFloor struct {
	Kind  string  `json:"kind"`
	Floor float64 `json:"floor"`
	From  string  `json:"from,omitempty"`
}

KindFloor is one kind's confidence floor and the measurement behind it. From is not decoration: a floor nobody can trace is a feeling with a number on it, and rule 8 says a floor is tuned from rows or it is not tuned at all.

type KindSummary

type KindSummary struct {
	Kind        string
	Decisions   int
	Escalations int
	Successes   int
	Failures    int
	StartHeight int
	StartRung   string
	DefaultRung string
	Regenerated bool

	// ProviderRows is how many rows carried a provider answer for this kind.
	ProviderRows int
	// ConfMin, ConfMax and ConfP25 describe those answers; they mean nothing
	// when ProviderRows is 0 and the line prints a dash there.
	ConfMin float64
	ConfMax float64
	ConfP25 float64
	// Hist counts the provider answers into ConfBuckets.
	Hist []int
	// Floor is the floor this kind is gated on now, and FloorFrom where it came
	// from. BelowFloor is how many provider answers fall under it -- the
	// escalation rate for this kind, counted rather than felt.
	Floor      float64
	FloorFrom  string
	BelowFloor int
	// Defeated is the finding of 2026-09-18 as a flag: the floor is ABOVE every
	// answer the provider has given for this kind, so nothing it says can ever
	// clear it and the step-up is universal.
	Defeated bool
}

KindSummary is one kind's read of the log: how many decisions, how many were escalations, the starting rung regenerated from the rows beside the default it replaces -- and the shape of the confidences the PROVIDER gave for this kind, against the floor those confidences were gated on.

The histogram counts provider rows only. The rules' own confidences are the machinery's numbers (1.00 for a designation, 0.90 for a sized unit) and mixing them in hides the thing the histogram exists to show: whether the floor sits above every answer the provider has ever given for this kind, in which case the step-up is not a policy, it is the only outcome.

func (KindSummary) HistField

func (k KindSummary) HistField() string

HistField renders the histogram as one field: every bucket, in order, named and counted. Fixed tables write every field, so a bucket with nothing in it is a zero and not an omission.

type LatencySummary

type LatencySummary struct {
	// Kind names the group for per-kind rows; Decider for per-decider rows.
	// Exactly one of the two is set.
	Kind    string
	Decider string
	N       int
	Median  int
	P95     int
	Has     bool
}

LatencySummary is the ms distribution over the measured rows of one group. N counts measured rows only; Median and P95 are the nearest-rank 50th and 95th percentiles, and Has reports whether anything was measured at all: a latency never measured is unknown, never zero, so a group with no measured row prints dashes.

type LogSink

type LogSink interface {
	Append(e Entry) error
	Entries() ([]Entry, error)
	Close() error
}

LogSink is where a decision row lands. Append is the one writer; Entries is the read the summary is a projection of; Close releases whatever the sink holds. A file sink holds nothing and an event sink holds a connection.

func OpenLogSink

func OpenLogSink(path string) (LogSink, error)

OpenLogSink opens the JSON lines log at a path. An empty path is a refusal, never a guess at one -- the same refusal AppendEntry has always made.

func Tee

func Tee(sinks ...LogSink) LogSink

Tee is one sink over several: Append writes every one of them and reports every one that failed, Entries reads the first, Close closes them all. A nil sink is skipped, so a caller passes what it opened and nothing else.

type Mind

type Mind struct {
	Name         string   `json:"name"`
	Lineage      string   `json:"lineage"`
	Height       int      `json:"height"`
	Kinds        []string `json:"kinds"`
	Lanes        []string `json:"lanes"`
	Availability string   `json:"availability"`
	Ask          string   `json:"ask"`

	// Model is the model id a unit dispatched to this mind RUNS with, where
	// this mind is a model at all. It is registry data and never a constant
	// here: the ladder comes from the file, and so do the ids on it. A mind
	// asked on the bus or as a child is a person or a coordinator and carries
	// none, so a caller that can only dispatch a model keeps today's model and
	// says so.
	Model string `json:"model,omitempty"`
}

Mind is one rung of the ladder: its name, the lineage it thinks in, its height, the kinds it is designated for, the lanes it owns, its availability and how it is asked.

func (Mind) DesignatedFor

func (m Mind) DesignatedFor(kind string) bool

DesignatedFor reports whether this mind is the rung for that kind by designation -- by KIND, never by height.

func (Mind) Dispatchable

func (m Mind) Dispatchable() bool

Dispatchable reports whether this mind can be handed a unit as a MODEL: it is asked as a card and the registry gives the model id to run it with.

func (Mind) Owns

func (m Mind) Owns(lane string) bool

Owns reports whether this mind owns the named lane. An empty lane is owned by nobody, so a unit that names none has no owner to prefer.

func (Mind) Usable

func (m Mind) Usable() bool

Usable reports whether the height ladder may pick this mind at all. A reserved or asleep mind is not on the ladder; a reserved one is still reachable by a designation.

type Question

type Question struct {
	Instructions string
	Choice       map[string]string
	Score        []string
	Noul         bool
}

Question is one typed question. Exactly one of Choice, Score or Noul must be set: a non-nil Choice is a choice question with per-option descriptions, a non-nil Score is a score question with ordered level texts, and Noul true is a noul question carrying only its statement in Instructions.

func (Question) Kind

func (q Question) Kind() string

Kind names which of the three question types q is, or "" for a malformed question.

type QuestionFile

type QuestionFile struct {
	Path            string
	CriteriaVersion string
	CriteriaPath    string
	Criteria        string
	StateFields     []StateField
	Questions       map[string]Question
	// Machinery is the rules this question is answered UNDER, declared in the
	// versioned pair rather than matched on a question's name inside a verb.
	// Empty is the ordinary question: the provider's answer stands as it is.
	// MachineryWhoReads binds the file to readers.go's rules, which the call
	// boundary applies -- a settled designation before any client is built, and
	// a constraint over any advisory answer before it is printed or recorded.
	Machinery string
}

QuestionFile is a loaded question file: its questions, the criteria they are answered against, and the typed state fields the asker owes.

func LoadQuestionFile

func LoadQuestionFile(path string) (QuestionFile, error)

LoadQuestionFile reads a question file and the criteria file it names. A bare question file -- no criteria, no declared fields -- loads as it always did, so every caller that predates the pair keeps working.

func (QuestionFile) Payload

func (f QuestionFile) Payload(state string) (string, error)

Payload validates the state against the declared typed fields and returns the bytes that go to the provider: the criteria first, the state second. A required field the state does not carry, or carries with the wrong type, is a refusal HERE -- before the call, before the spend, before a confidence is attached to an answer given over evidence that was not there.

type Rate

type Rate struct {
	Model     string  `json:"model"`
	Provider  string  `json:"provider,omitempty"`
	InputUSD  float64 `json:"input_usd_per_mtok"`
	OutputUSD float64 `json:"output_usd_per_mtok"`
	From      string  `json:"from,omitempty"`
}

Rate is what one model's tokens cost, in US dollars per MILLION tokens, and where the number was published. Per million rather than per token because that is how a provider quotes it, and a rate copied from a page should read like the page it was copied from.

func (Rate) USD

func (r Rate) USD(inputTokens, outputTokens int) float64

USD is what a call of this many tokens cost at this rate. The counters are per million, so the arithmetic is done once, here, and never at a call site.

type ReadDecision

type ReadDecision struct {
	First    Role
	Required []Role
	Source   string
	Reason   string
	// LiftsHold is always false. It is a field so a caller gates on it rather
	// than on the absence of a sentence.
	LiftsHold bool
}

ReadDecision is who reads first, who reads regardless, and which of the two settled it.

func ConstrainRead

func ConstrainRead(answer Role, confidence float64, s ReadState) (ReadDecision, error)

ConstrainRead applies the machinery over a provider's answer and returns the decision that stands. The confidence is carried for the record and is not a lever: it appears in no rule here.

type ReadState

type ReadState struct {
	SecurityShapedPackage bool
	DesignDefaultsTaken   int
	NormativeSpecMoved    bool
	// HolderOfTheArea is the role that already has an open read or hold on
	// these files, or empty.
	HolderOfTheArea Role
	// HoldIsOpen says that holder's hold is unresolved.
	HoldIsOpen bool
	// HelpAnswer is `nova-decide help --state`'s own answer, verbatim.
	HelpAnswer string
}

ReadState is the typed evidence the who-reads decision is made over. Every field is one the asker computes BEFORE the question, and every rule below turns on a field rather than on prose.

func ReadStateOf

func ReadStateOf(state string) (ReadState, error)

ReadStateOf builds the typed ReadState from a state text's own fields. The state has already been validated against the question's declared types by Payload; what is added here is the one check a type cannot make -- a holder is a CONFIGURED ROLE or it is a refusal, before any call is made.

type Registry

type Registry struct {
	Minds  []Mind      `json:"minds"`
	Rules  []Rule      `json:"rules,omitempty"`
	Floors []KindFloor `json:"floors,omitempty"`
	Rates  []Rate      `json:"rates,omitempty"`
}

Registry is the ladder: every mind, in height then name order, the committed rules that answer a kind without a call, and the two measured tables beside them -- the floor per kind, and the rate per model.

func DefaultRegistry

func DefaultRegistry() (*Registry, error)

DefaultRegistry is the embedded ladder, the one a bench with no registry file runs on.

func LoadRegistry

func LoadRegistry(path string) (*Registry, error)

LoadRegistry reads the registry a path names. An empty path is the embedded default; an unreadable or invalid file is a refusal naming the path.

func ParseRegistry

func ParseRegistry(data []byte) (*Registry, error)

ParseRegistry parses and validates a registry. Every row must name a mind, a lineage, a height at or above zero, an availability of the three, and an ask of the three (a row naming none is asked on the bus). A duplicate name, an empty table or anything else is a refusal.

func (*Registry) AtHeight

func (r *Registry) AtHeight(h int) []Mind

AtHeight is every mind on one rung, in name order.

func (*Registry) ByName

func (r *Registry) ByName(name string) (Mind, bool)

ByName finds one mind.

func (*Registry) DesignatedFor

func (r *Registry) DesignatedFor(kind string) []Mind

DesignatedFor is every mind designated for a kind, in height then name order.

func (*Registry) FloorFor

func (r *Registry) FloorFor(kind string) (KindFloor, bool)

FloorFor is the registry's floor for one kind, and whether it holds one at all. A kind with no row is not a kind with a floor of zero.

func (*Registry) FriendRungs

func (r *Registry) FriendRungs() []Mind

FriendRungs returns the minds in the registry that are friend rungs: minds asked by bus, excluding the all-friends broadcast and Glenn.

func (*Registry) Heights

func (r *Registry) Heights() []int

Heights is every rung height the registry holds, ascending.

func (*Registry) ModelFor

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

ModelFor is the model id a rung runs a unit with, and whether the registry gives it one at all. A rung with no model is not a refusal: it is a mind a card cannot be dispatched to, and the caller keeps today's model.

func (*Registry) RateFor

func (r *Registry) RateFor(model string) (Rate, bool)

RateFor is the rate table's row for one model. A model with no row is a dash on the usage line and a NOTE, never a price somebody made up.

func (*Registry) RuleFor

func (r *Registry) RuleFor(kind string) (Rule, bool)

RuleFor is the committed rule for a kind, if the registry holds one. A kind is ruled at most once, so the first match is the only match.

func (*Registry) RungName

func (r *Registry) RungName(h int) string

RungName names a height: one mind, or every mind on that rung joined by "/" -- the two lineages of one rung are one rung.

func (*Registry) TopHeight

func (r *Registry) TopHeight() int

TopHeight is the highest rung: above it there is nothing to escalate to.

type Result

type Result struct {
	Question   string
	Version    int
	Answer     string
	Confidence float64
	Floor      float64
	Decider    string
	Stop       bool
	Below      string
	Tamper     bool
	Why        string
	Escalate   string
	Bytes      int
	Hash       string
	Usage      Usage

	// Skipped names the deciders that were not asked and why, so a line that
	// fell through to a weaker decider says so rather than looking like a
	// choice somebody made.
	Skipped string
	// contains filtered or unexported fields
}

Result is one classification, and the fields of D3's CLASSIFY line.

func (Result) AttemptsSkipped

func (r Result) AttemptsSkipped() string

AttemptsSkipped is the bounded typed record of every decider the walk could not get an answer out of: `<decider>=<why token>` pairs, comma separated, or `-` where nothing was skipped. It goes on BOTH receipts, and the reason is that without it two different walks print the same words. A chain with no provider configured and a chain whose provider was configured and failed both end `decider=none why=no-decider`; an answer from `local` after `jev` failed ahead of it reads as a clean first-try walk. The outage is invisible in exactly the records anybody would go to to find it.

What is NOT here is the provider's own sentence. The token says a call was made and did not return an answer, which is the fact; the error text is the provider's prose, it is unbounded, and it has no business in a durable row.

func (Result) Exit

func (r Result) Exit() int

Exit is D3's exit code: 0 for an answer at or above the floor (and for a stop, which the caller acts on), 3 for unknown, 2 for a refusal.

func (Result) Line

func (r Result) Line(pointer string) string

Line is D3's one CLASSIFY line.

func (Result) Row

func (r Result) Row(pointer string) string

Row is the classify log's decision row. THE EVIDENCE TEXT IS NEVER IN IT: what joins a row to an item is a hash and a size, because a log that held the text would be a second copy of everything anybody ever classified, kept forever, on a disk nobody audited.

type Role

type Role string

Role is a configured routing role. It is what the provider is offered and what it answers with; the binding from a role to a mind is local and is never sent.

const (
	// RoleSecurity is the designated security read: anything that execs,
	// pushes, reads the environment or a secret, or lands in the reaper, the
	// launcher or the merge machinery.
	RoleSecurity Role = "security-designate"
	// RoleDesignAuthority rules on a design default no ruling covers, on
	// normative text, on scope and on kernel semantics.
	RoleDesignAuthority Role = "design-authority"
	// RoleLaneOwner is the owner of the lane the change lands in.
	RoleLaneOwner Role = "lane-owner"
	// RoleChildReview is a child model's cold read: the ordinary read for a
	// self-contained mechanical change.
	RoleChildReview Role = "child-review"
	// RoleSecondChildReview is a second, independent child read on the other
	// lineage.
	RoleSecondChildReview Role = "second-child-review"
	// RoleCoordinator holds the shift's context: landing order and sequencing.
	RoleCoordinator Role = "coordinator"
	// RoleAllFriends is every friend at once.
	RoleAllFriends Role = "all-friends"
	// RoleHuman is the person, reached only after the friends.
	RoleHuman Role = "human"
)

The configured roles. They describe an obligation, not a person.

func MandatoryReader

func MandatoryReader(s ReadState) (Role, string, bool)

MandatoryReader is the designation that needs no provider. It is the security read and nothing else: every other rule constrains an answer rather than replacing it.

func RequiredReads

func RequiredReads(s ReadState) []Role

RequiredReads is every read the evidence obliges, whoever reads first.

type RouteResult

type RouteResult struct {
	Unit       string
	Kind       string
	Rung       Mind
	Confidence float64
	Floor      float64
	Reason     string
	Wait       string
	Refusal    string
	SteppedUp  bool
	Escalated  bool
	Designated bool
	Source     string
	RulesRung  string
	Offered    []string
	Usage      RouteUsage
	// Next is the rung ABOVE the one answered, named whenever the answer is
	// below the floor. The step-up signal used to name only the question that
	// fell short, which left a reader to work out where the work goes next from
	// a ladder they cannot see (edge 24). It is empty at or above the floor,
	// and empty where there is no rung above.
	Next string
	// Steps is how many decisions this answer took: 1 for an ordinary route,
	// and one more for each re-ask --step-up made.
	Steps int
	// WallMs is the verb's start to its line in milliseconds, stamped by the
	// verb that printed it. HasWallMs reports whether the verb measured it:
	// where no verb stamped one there is no measurement, and no measurement
	// is an absence, never a zero.
	WallMs    int
	HasWallMs bool
	// Reads are the minds a KIND designation attached to this unit as READERS
	// rather than as the rung: a reserved mind takes no work, so security --
	// and a fresh take where the designate is reserved -- reaches the unit as a
	// read beside the rung the evidence supports. The work is dispatched to the
	// rung; the read goes out with it.
	Reads []string
	// FloorFrom says where the floor came from: the caller's flag, this kind's
	// measured row, or the built-in default with no rows behind it. A floor
	// nobody can trace is a feeling with a number on it.
	FloorFrom string
	// Excluded is the set of down friend rungs excluded from routing (#3397).
	Excluded []string
	// DownChecked records whether this route consulted the fleet presence keys.
	DownChecked bool
}

RouteResult is one routing decision: the rung, the number the floor was applied to, the floor, why, the typed wait, what it spent, and -- for the log -- what the rules alone would have picked.

A REFUSED decision is still a RouteResult. Where the route ends in an error, the result comes back populated with everything that was already true -- above all what a completed provider call spent -- and Refusal says why it ended. A refusal cannot unspend tokens, so the caller persists the row and then exits on the refusal (Stella, #1327).

func RouteJev

func RouteJev(ctx context.Context, d Decider, reg *Registry, u Unit, floor float64) (RouteResult, error)

RouteJev asks the provider which rung, among the eligible ones the rules offer, and keeps the machinery's word everywhere it matters: security and a designation are never asked, a rung that may still be running is never asked (there is no choice to make while an attempt is alive), a choice below the floor steps up, and a provider error or a rung nobody offered leaves the rules' answer standing.

func RouteJevExcluded

func RouteJevExcluded(ctx context.Context, d Decider, reg *Registry, u Unit, floor float64, excluded map[string]bool, downExclusions []string) (RouteResult, error)

RouteJevExcluded is RouteJev with down friends excluded (#3397).

func RouteRules

func RouteRules(reg *Registry, u Unit, floor float64) (RouteResult, error)

RouteRules answers by the rules alone: no provider, no key, no network, the same answer every time. It is what --no-jev runs, and it is the answer the provider's is measured against in the log.

func RouteRulesExcluded

func RouteRulesExcluded(reg *Registry, u Unit, floor float64, excluded map[string]bool, downExclusions []string) (RouteResult, error)

RouteRulesExcluded is RouteRules with down friends excluded (#3397).

func RouteStepUp

func RouteStepUp(ctx context.Context, d Decider, reg *Registry, u Unit, floor float64, maxSteps int) ([]RouteResult, error)

RouteStepUp turns the step-up SIGNAL into the rung above it (edge 24).

Exit 3 said "below the floor" and named the question that fell short, and there it stopped: nothing re-asked, and the caller was left to read a ladder it cannot see. This asks, and where the answer is below the floor it EXCLUDES that rung from the criteria and asks the same question again, up to maxSteps times.

Every step is a decision in its own right: the slice returned holds them all, in order, each carrying its own reason and its own step number, and the caller logs every one of them. The last is the answer, and its exit code is the ordinary one -- a step-up that never got above the floor is still a suggestion, never an authorization.

func RouteStepUpExcluded

func RouteStepUpExcluded(ctx context.Context, d Decider, reg *Registry, u Unit, floor float64, maxSteps int, initialExcluded map[string]bool, downExclusions []string) ([]RouteResult, error)

RouteStepUpExcluded is RouteStepUp with down friends excluded (#3397).

func (RouteResult) AwaitingTermination

func (r RouteResult) AwaitingTermination() bool

AwaitingTermination reports whether this decision is a wait on an attempt that is not known to have terminated.

func (RouteResult) Dispatchable

func (r RouteResult) Dispatchable() bool

Dispatchable reports whether the caller may hand the unit to the rung named. A wait is an answer about WHO owns the work, not permission to start it.

func (RouteResult) Line

func (r RouteResult) Line() string

Line is the one line a route decision prints: the unit (the evidence pointer), the rung, the confidence, the floor it was gated on, where that floor came from, the reader a kind designation attached, the rung ABOVE it where the answer fell below that floor, how many steps the answer took, the reason and how that rung is asked. Every field is on every line: next and read are the dash where there is nothing above and nobody reading, so no reader has to infer an absence.

func (RouteResult) ReadField

func (r RouteResult) ReadField() string

ReadField renders the readers as one field: the names in order, or the dash, so every line carries it and no reader has to tell an absent field from an absent read.

type RouteUsage

type RouteUsage struct {
	Calls        int
	InputTokens  int
	OutputTokens int
	HasInput     bool
	HasOutput    bool
	Failed       bool
	// Ms is the provider round trip in milliseconds, measured by the caller
	// on a monotonic clock around the call alone. HasMs reports whether a
	// call was made at all: with no call there is no measurement, and no
	// measurement is an absence, never a zero (SPEC-TOKENS rule 14).
	Ms    int
	HasMs bool
}

RouteUsage is what one routing decision spent with the provider: how many calls it made, the counters the provider reported, and -- PER COUNTER -- whether it reported them at all. A call that failed, and a call that answered without saying what it cost, both spent something we cannot measure, and UNKNOWN is not zero (SPEC-TOKENS rule 14).

func (RouteUsage) Known

func (u RouteUsage) Known() bool

Known reports whether any counter was measured.

type Rule

type Rule struct {
	Kind string `json:"kind"`
	Rung string `json:"rung"`
	By   string `json:"by"`
	From string `json:"from,omitempty"`
}

Rule is one committed constant answer: for a KIND, the rung a person has found is always right, who committed it, and the log summary date it came from. Promotion is a person's commit and never the tool's, so a rule with no `by` is refused at load (SPEC-DECIDE housekeeping H1).

type RulesDecider

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

RulesDecider is the deterministic table. Confidence is 1.00 where a row matches and there is no answer where none does; it sees private evidence because it never leaves the machine, and it makes no call.

func NewRulesDecider

func NewRulesDecider(rows map[string]string) *RulesDecider

NewRulesDecider builds the table from substring -> member rows. The rows are the caller's data; where a default ships it is a file of plain words a caller replaces whole (D1).

func (*RulesDecider) Ask

Ask matches the rows in a stable order, so two runs over one evidence give one answer even where two rows could match.

func (*RulesDecider) Name

func (r *RulesDecider) Name() string

func (*RulesDecider) Sees

func (r *RulesDecider) Sees() string

type StateField

type StateField struct {
	Name     string `json:"name"`
	Type     string `json:"type"`
	Optional bool   `json:"optional,omitempty"`
}

StateField is one typed fact the asker must compute BEFORE the question is asked. Type is one of "string", "int" or "bool"; a field is required unless it says otherwise, because a criterion that turns on a fact the state may or may not carry is a criterion the provider must infer from prose.

type Summary

type Summary struct {
	Entries int
	Kinds   []KindSummary

	// Decisions and Outcomes are the two halves of rule 8's row, counted as
	// ROWS across every kind, which is the arithmetic the hurt was measured
	// with: 141 outcomes for 412 decisions on 2026-09-19. Their ratio is
	// printed as coverage, because a floor tuned on a third of the rows is
	// tuned on the rows somebody remembered (SPEC-DECIDE, housekeeping H2).
	Decisions int
	Outcomes  int

	// LatencyByKind and LatencyByDecider are the ms distribution over the
	// MEASURED rows of each group: the median and the 95th percentile
	// (SPEC-DECIDE, housekeeping H3). A kind is the route log's question and
	// a source its decider; outcome rows are not decisions and carry no
	// measurement, so neither group counts them.
	LatencyByKind    []LatencySummary
	LatencyByDecider []LatencySummary
}

Summary is the whole read of the log.

func Summarize

func Summarize(reg *Registry, entries []Entry) (Summary, error)

Summarize counts the escalations per kind and regenerates the starting rung from the rows. An entry naming a kind the table does not hold is a refusal: a summary over evidence nobody can read is not a summary.

func (Summary) Render

func (s Summary) Render() string

Render is the summary, one line per kind then the finish. Every kind carries the shape of the provider's answers beside the floor they were gated on: how many landed under it, and whether the floor is above every answer the provider has ever given for that kind, which is the step-up being the only outcome rather than a policy. The latency tokens are appended last on the lines they belong to, so every field before them keeps its name, position and spelling: per-kind median and p95 on the kind's own line, per-decider median and p95 on the finish.

type TuneOptions

type TuneOptions struct {
	Label         string
	Choice        string
	Conf          string
	Floors        []float64
	MaxEscalation float64
	// Default is the answer a below-floor row actually gets. Where the
	// escalation is a step UP a rung it is empty, because the row gets a
	// different, more careful answer and no single name covers it. Where
	// the escalation is a fallback to one cheap answer -- the who-reads
	// question falls back to opus-child -- naming it here lets each floor
	// report what that fallback got right and what it MISSED, and the best
	// floor becomes the one that misses fewest rather than the one that
	// agrees most on the rows it kept.
	Default string
	// Observations admits a log whose labeled rows say
	// `"adjudicated": false`. It is the EXPLICITLY NON-RECOMMENDING mode:
	// the arithmetic runs and is printed in full, and no floor comes out of
	// it. Without it, a log carrying even one such row is a refusal -- a
	// floor set from observations is a floor set from labels nobody
	// adjudicated, which is what the renamed fixture's own README says it
	// is not for.
	//
	// A row that does not carry the field AT ALL is a log written before
	// the field existed, and is read exactly as it always was: a historical
	// format is never silently reinterpreted (Stella, 2026-09-19, r2 of the
	// #1925 hold).
	Observations bool
}

TuneOptions names the fields a decisions log carries and the floors to try. An empty field name or floor list takes the default; an empty label is a row to skip, never a field to guess.

type TuneResult

type TuneResult struct {
	Lines     int
	Labeled   int
	Floors    []FloorStat
	BestFloor float64
	// Observations is the labeled rows that said `"adjudicated": false`.
	Observations int
	// Recommends is whether this read may set a floor at all. It is false
	// exactly when the log carried an observation row, and Render then
	// prints best_floor=none: the arithmetic is a statement about the log,
	// and a floor is a statement about the future.
	Recommends bool
}

TuneResult is the whole read of a decisions log: the line and labeled counts, one stat per floor, and the best floor under the escalation cap.

func Tune

func Tune(data []byte, opts TuneOptions) (TuneResult, error)

Tune parses a decisions log and reports, per floor, the decisions it made and the rows it escalated, then the best floor under the escalation cap. A line that is not a JSON object, or a labeled line with no confidence, is a refusal, never a guess.

func (TuneResult) Render

func (r TuneResult) Render() string

Render is the tune read, one line per floor then the finish. Every rate is printed to two places and every floor verbatim.

type Unit

type Unit struct {
	ID        string    `json:"id"`
	Kind      string    `json:"kind"`
	Files     int       `json:"files,omitempty"`
	Packages  int       `json:"packages,omitempty"`
	Lanes     int       `json:"lanes,omitempty"`
	LaneOwner string    `json:"lane_owner,omitempty"`
	Attempts  []Attempt `json:"attempts,omitempty"`
	Platform  string    `json:"platform,omitempty"`
	Guard     bool      `json:"guard,omitempty"`
	Secrets   bool      `json:"secrets,omitempty"`
	Touches   []string  `json:"touches,omitempty"`
	FreshTake bool      `json:"fresh_take,omitempty"`
	Deadline  string    `json:"deadline,omitempty"`
}

Unit is the evidence for one unit of work: its kind, its size (files, packages, lanes), the lane's owner, the prior attempts, any platform need, whether a guard or secrets are touched, whether it wants a fresh take, and the deadline. The ID is the evidence pointer every decision line carries (SPEC-DECIDE rule 10), so a person can retrieve the original.

func ParseUnit

func ParseUnit(data []byte) (Unit, error)

ParseUnit reads one unit of evidence from JSON. Anything that is not an object, or an object whose evidence cannot be, is a refusal.

func (Unit) Public

func (u Unit) Public(reg *Registry) (map[string]string, error)

Public is the unit's public projection: the typed, enumerated evidence the provider is given, and the whole of what it is given about the unit. The unit's id, its lane's spelling, its platform's name, its deadline and every attempt reason stay here. A value that is not on the allowlist is a refusal rather than a payload.

func (Unit) Security

func (u Unit) Security() bool

Security reports whether this unit is security work: a guard, secrets, the sandbox, sudo, deploy keys or the network. It is a KIND and not a height, and it is answered here rather than by any provider.

func (Unit) Validate

func (u Unit) Validate() error

Validate checks the evidence itself, before any registry is consulted.

type Usage

type Usage struct {
	InputTokens  int
	OutputTokens int
	HasInput     bool
	HasOutput    bool
}

Usage counts the tokens one call spent, and says PER COUNTER whether the provider reported it at all. A 200 carrying a valid answer is not evidence of reported usage: a response with no usage object, or one naming only some of the counters, has said nothing about the rest -- and nothing is not zero. An explicitly reported 0 is a measurement and is kept as one (SPEC-TOKENS rule 14).

func (Usage) Known

func (u Usage) Known() bool

Known reports whether the provider measured anything at all.

type WorkTypeResult

type WorkTypeResult struct {
	Type       string
	By         string // rules | jev
	Rule       string // the rule that fired, or why none did
	Confidence float64
	Usage      RouteUsage
}

WorkTypeResult is one card's work type and how it was reached.

func ClassifyWorkType

func ClassifyWorkType(ctx context.Context, d Decider, card string) (WorkTypeResult, error)

ClassifyWorkType reads one card. The rules answer first, with no call; only where none fires and d is not nil is Jev asked, once.

func (WorkTypeResult) Known

func (r WorkTypeResult) Known() bool

Known reports whether the card has one of the eight types.

type WorkTypeRoutes

type WorkTypeRoutes map[string][]string

WorkTypeRoutes is allowed_routes keyed by work type: the routes the per-type ranking lets a card of that type run on.

func LoadWorkTypeRoutes

func LoadWorkTypeRoutes(path string) (WorkTypeRoutes, error)

LoadWorkTypeRoutes reads allowed_routes from a JSON object of work type to route list. A key that is not one of the eight is refused: a misspelt type would otherwise be a row no card ever matches.

func (WorkTypeRoutes) Admit

func (w WorkTypeRoutes) Admit(t string, res RouteResult, reg *Registry) error

Admit is the gate on the SELECTED route: the rung the router chose, by its name or the model id the registry gives it, must be one of allowed_routes[t]. With a table given, a type with no row admits nothing (an unclassified card has no row: the table refuses a key outside the eight). With no table, only a type that produces no branch passes (RequireTable). A route that is a wait dispatches nothing and is not gated.

func (WorkTypeRoutes) For

func (w WorkTypeRoutes) For(t string) []string

For is allowed_routes[t], or nil where the table has no row for t.

func (WorkTypeRoutes) RequireTable

func (w WorkTypeRoutes) RequireTable(t string) error

RequireTable refuses a card whose type produces a branch when no allowed_routes table was given: for a coding card the table IS the route gate, and a gate that is absent is not a pass. It runs after the card is classified and before any route is chosen.

Directories

Path Synopsis
Package questions is the one place a typed question lives: its closed answer set, its stopping members, its tamper answer, its evidence bound and truncation rule, its instructions and its criteria, keyed by name and version (deprecated/docs/SPEC-DECIDE.md D3, :757-789).
Package questions is the one place a typed question lives: its closed answer set, its stopping members, its tamper answer, its evidence bound and truncation rule, its instructions and its criteria, keyed by name and version (deprecated/docs/SPEC-DECIDE.md D3, :757-789).

Jump to

Keyboard shortcuts

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