Help us shape the future of Go! Take the 2026 Go Developer Survey

adh

package
v0.1.0 Latest Latest
Warning

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

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

Documentation

Overview

Package adh is the foundational domain package for the agentic-dev-harness CLI: the shared language every other package speaks. It holds the core domain types, the effectful interfaces, and the Error type with its code vocabulary. It imports no sibling application package and no third-party library; every other package imports it.

Index

Constants

View Source
const (
	ECONFLICT     = "conflict"     // action cannot be performed in the current state
	EINTERNAL     = "internal"     // an unexpected internal error
	EINVALID      = "invalid"      // input or state failed validation
	ENOTFOUND     = "not_found"    // requested entity does not exist
	EUNAUTHORIZED = "unauthorized" // caller lacks the required authority
)

Error codes are machine-readable classifications set on leaf errors. They are the vocabulary the CLI's `reason` token is drawn from (SPEC §8), so a caller branches on these rather than on message text.

Variables

This section is empty.

Functions

func CanClose

func CanClose(arc *Arc, hasProof bool) error

CanClose reports whether an arc may close under NO-PROOF-NO-CLOSE (SPEC §5.4): an arc closes only with resolution-matched proof present. It returns EINVALID when the resolution is unset or unknown and ECONFLICT when proof is missing.

func ErrorCode

func ErrorCode(err error) string

ErrorCode returns the machine-readable code of the first *Error in the chain that carries one, EINTERNAL for any other non-nil error, and "" for nil. Call this instead of type-asserting *Error at a call site.

**It classifies adh's own errors and nothing else, which is narrower than it was.** The predecessor also understood errors coded by the toerr `errcode` package, because it lived in the shared library and had to read both representations. Keeping that here would put a third-party import in the domain package, which is the one thing this package does not do — so a library error classifies as EINTERNAL, and the translation happens where such errors enter adh. Today that is cmd/root, which owns the `reason` vocabulary; see reasonForCodedError there.

func ErrorMessage

func ErrorMessage(err error) string

ErrorMessage returns the human-readable message of the first *Error in the chain that carries one, a generic message for any other non-nil error, and "" for nil. It has the same narrowed scope as ErrorCode.

Types

type Arc

type Arc struct {
	ID         string     `json:"id"`
	Title      string     `json:"title"`
	Stage      Stage      `json:"stage"`
	Status     Status     `json:"status"`
	Resolution Resolution `json:"resolution,omitempty"`
	History    []string   `json:"history,omitempty"`
	Pending    *Pending   `json:"pending,omitempty"`
	// Labels and Paths are the arc's routing footprint (SPEC-ADDITIONS §10, §19.1):
	// its labels and the repository paths it touches. They ground the cold critic
	// by selecting the context units routed to the review; an arc that declares
	// them but routes nothing records a routing gap (§19.1).
	Labels []string `json:"labels,omitempty"`
	Paths  []string `json:"paths,omitempty"`
	// Context is the IDs of the context units the last stage loaded as its working
	// set (SPEC-ADDITIONS §10.3), recorded so a self-eval can tell a missed
	// requirement that was never routed (a context gap) from one routed and ignored.
	Context []string `json:"context,omitempty"`
	// Proof is the repository-relative path to the proof packet manifest the
	// builder left (SPEC §5.4). Empty until Execution records one; the critic
	// reviews against it when present (§19.1).
	Proof string `json:"proof,omitempty"`
	// Findings are the cold critic's hypotheses awaiting adjudication by the
	// Evaluation stage (§19.2). Set when the critic turn resumes; cleared once
	// Evaluation has disposed of them.
	Findings []Finding `json:"findings,omitempty"`
	// Unexamined is what the critic declared it did not look at (§19.2). It is the
	// critic's own testimony, never a derived fact — a mechanically-known gap, such
	// as a review that ran with no routed context, is reported by the harness and
	// deliberately not written here.
	//
	// Advisory always: nothing may block because an entry is present, or a critic
	// learns to declare none and the corpus loses both the gap and the finding.
	// Cleared wherever Findings is cleared; a stale gap would be declared against a
	// review that never made it.
	Unexamined []finding.Unexamined `json:"unexamined,omitempty"`
	// Bar is identity.Hash of the acceptance bar the arc was planned against,
	// recorded when Strategy completes (§19.2).
	//
	// **It is a pre-registration, not a copy.** The bar itself is derived from config
	// by resolution and is recoverable at any time; what is not recoverable is what it
	// said when the plan was made. Two things can move it between Strategy and
	// Evaluation — an edit to the config, and a change to the arc's Resolution, which
	// selects the contract — and neither leaves a trace today.
	//
	// The discipline it buys is `ruflo`'s: it rejected changes carrying large
	// favourable metrics because a *named* guard moved, under a hypothesis marked
	// "frozen before evaluation began; not modified after seeing results." A bar that
	// can move after the numbers arrive is a note, not a pre-registration.
	//
	// Empty means an arc planned before this shipped, or one that never reached
	// Strategy. It must read as **unknown**, never as changed — reporting drift on
	// every pre-existing arc would teach a reader to ignore the report.
	Bar string `json:"bar,omitempty"`
	// Reworks counts the times Evaluation confirmed a finding and returned this arc
	// to Execution (SPEC §4.1). It bounds the rework loop: once it reaches the
	// evaluation budget the arc fails terminally (StatusFailed) rather than looping.
	Reworks int `json:"reworks,omitempty"`
}

Arc is a unit of work driven through the loop.

type CriticInput

type CriticInput string

CriticInput names one input a critic's view can carry.

const (
	InputUnset CriticInput = ""

	// InputTranscript is the builder's turn history. It is the one input cold review
	// withholds (§19.1), and the only one the renderer can currently enforce.
	InputTranscript CriticInput = "transcript"

	// The grounding a critic reviews, as critic.Grounding assembles it.
	InputDiff          CriticInput = "diff"
	InputProof         CriticInput = "proof"
	InputAcceptanceBar CriticInput = "acceptance_bar"
	InputContext       CriticInput = "context"
	InputPaths         CriticInput = "paths"
	InputTools         CriticInput = "tools"
	InputCoverage      CriticInput = "coverage"
	InputNoisy         CriticInput = "noisy"
)

The inputs a critic's view can name (SPEC-ADDITIONS §19.4).

They exist so `[critic] ground_from` and `deny` are checked against a closed set rather than being free-form strings nobody validates. A mistyped input name in either list used to be a line that silently did nothing — which is the whole defect this vocabulary was added to end, and it is worse in a field a reader believes hardens the critic.

InputUnset is the zero value and names no input, so a value nobody populated cannot be mistaken for a real one.

func CriticInputs

func CriticInputs() []CriticInput

CriticInputs is every input a critic's view can name, sorted.

Requires: nothing. Ensures: sorted, so a diagnostic listing them is reproducible. Pure.

func (CriticInput) Deniable

func (c CriticInput) Deniable() bool

Deniable reports whether the renderer can enforce a denial of this input.

Requires: nothing. Ensures: true only for InputTranscript today.

**adh does not filter a critic's grounding**, and this method is where that fact is enforced rather than assumed. The critic's view omits the transcript structurally — the renderer never populates it — so a denial of it is an assertion the renderer can check. Every other input is assembled by `critic.Ground` and handed over whole; denying one would be a request to filter, which is a capability nobody has built.

Accepting such a name silently is what the config used to do. Refusing it names the gap, and the day filtering exists this method is the one place that changes.

func (CriticInput) Known

func (c CriticInput) Known() bool

Known reports whether c names an input this build understands.

Requires: nothing. Ensures: false for InputUnset, so an unpopulated value never validates.

type Direction

type Direction string

Direction names which side of a KPI threshold is degradation (§16/§18).

const (
	WorseWhenAbove Direction = "above" // higher is worse (error rate, duration)
	WorseWhenBelow Direction = "below" // lower is worse (acceptance rate)
)

Direction values name which side of a KPI's threshold is degradation (SPEC-ADDITIONS §16/§18): a higher value is worse for an error/duration metric, a lower value for an acceptance metric.

func (Direction) Valid

func (d Direction) Valid() bool

Valid reports whether d is a known degradation direction (§16/§18).

type Error

type Error struct {
	Code    string // machine-readable; set only on leaf errors
	Message string // human-readable; set only on leaf errors
	Op      string // "package.Type.Method"; set only on wrapping errors
	Err     error  // nested cause; set only on wrapping errors
}

Error is adh's one error type. A leaf error carries Code and Message; a wrapping error carries Op and Err. The two forms are never mixed on one value: leaves classify, wrappers build a single-line logical stack trace.

**It is defined here rather than borrowed.** It used to be `= skillet/errs.Error`, an alias kept in the shared library for adh's benefit alone — no other consumer of that library ever imported the package. A type with one consumer belongs to that consumer, and the layout this repository follows puts the Error type in the root domain package beside the types it classifies failures for.

A plain struct, deliberately: 203 sites compose it as a literal, and the typed CLI refusals in cmd/root reach it through Unwrap, which needs a concrete type for errors.As to find.

func (*Error) Error

func (e *Error) Error() string

Error renders the logical stack trace: each wrapper contributes its Op, and the leaf contributes its Message (or Code when Message is empty).

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap exposes the nested cause so errors.Is and errors.As traverse the chain.

type Finding

type Finding struct {
	Summary string      `json:"summary"`
	Kind    FindingKind `json:"kind"`
	// Ref names the artifact that would confirm the finding, and for a confirmed one it
	// is also the next action: re-running it is what settles the finding, so a caller
	// has the command without inferring it. That is why no remediation vocabulary
	// exists here -- a third closed set beside Class and FindingKind would classify the
	// same space twice, and "re-run the ref" covers the case anyone has named.
	Ref   string       `json:"ref,omitempty"`
	Class FindingClass `json:"class,omitempty"`
}

Finding is a critic's hypothesis about the change under review (§19.2): a summary and the repository artifact (Kind + Ref) whose run would confirm it. The Evaluation stage adjudicates it; the harness never blocks on its text.

func (*Finding) IsStructural

func (f *Finding) IsStructural() bool

IsStructural reports whether the finding needs a design change rather than a bounded edit (§19.2), so a confirmed one escalates instead of reworking.

type FindingClass

type FindingClass string

FindingClass triages how a confirmed finding is resolved (§19.2): fixable by a bounded edit or structural (a design change that escalates).

const (
	FixableFinding    FindingClass = "fixable"    // a bounded edit resolves it (rework)
	StructuralFinding FindingClass = "structural" // needs a design change (escalate)
)

FindingClass values triage a confirmed finding by how it is resolved (SPEC-ADDITIONS §19.2): a fixable finding is a bounded edit the rework loop can close; a structural finding needs a design change, so it escalates to a human instead of burning rework cycles. An empty class defaults to fixable — the common case.

func (FindingClass) Valid

func (c FindingClass) Valid() bool

Valid reports whether c is a known finding class (§19.2). An empty class is valid: it defaults to fixable, the common case, so a critic need not set it.

type FindingKind

type FindingKind string

FindingKind is the kind of repository artifact a critic finding names (§19.2).

const (
	FindingOracle    FindingKind = "oracle"    // a differential-oracle divergence
	FindingInvariant FindingKind = "invariant" // a property/invariant check
	FindingDevice    FindingKind = "device"    // an on-device (adb) check (§2.4)
	FindingNFR       FindingKind = "nfr"       // a nonfunctional-requirement check (§10)
	FindingContract  FindingKind = "contract"  // a named local contract (e.g. a proof packet)
)

FindingKind values name the repository artifact whose run would confirm a critic finding (SPEC-ADDITIONS §19.2). The Evaluation stage runs that artifact; a finding is never trusted on the critic's text alone.

func FindingKinds

func FindingKinds() []FindingKind

FindingKinds returns every known finding kind (§19.2), the single owner of the list — so callers (e.g. the critic coverage check) iterate the full set without re-declaring it.

func (FindingKind) Valid

func (k FindingKind) Valid() bool

Valid reports whether k is a known finding kind (§19.2). A validated kind lets callers switch on it without a default-panic path.

type KPI

type KPI struct {
	Metric    string    `json:"metric"`
	Threshold float64   `json:"threshold"`
	Direction Direction `json:"direction"`
}

KPI is a declared performance indicator on a tool or context unit (§16/§18): a Metric, the Threshold that bounds acceptable performance, and the Direction of degradation. A crossed threshold proposes a config change — never auto-adopted, and only after the breach replicates (§18.2). It is declared data; the kpi package evaluates observed values against it.

func (*KPI) Breached

func (k *KPI) Breached(value float64) bool

Breached reports whether an observed value has crossed into the degradation region (§16/§18): strictly past the threshold on the direction's bad side. Exactly at the threshold is acceptable — the same strict boundary as the §18.2 gate.

func (*KPI) Valid

func (k *KPI) Valid() bool

Valid reports whether the KPI is well-formed (§16/§18): a non-empty metric and a known direction. It does not check that the metric is observable — a declared KPI whose metric no source measures simply never fires.

type Pending

type Pending struct {
	Stage  Stage  `json:"stage"`
	Prompt string `json:"prompt"`
}

Pending is an outstanding model turn: a stage's prompt emitted to an operator whose reply is supplied out-of-band (the relay, SPEC §1-2), awaiting a resume. It is nil unless the arc is parked mid-turn between an emit and its response.

type Resolution

type Resolution string

Resolution is how an arc closes; a non-change arc need not run the build stages.

const (
	ResolutionChange        Resolution = "change"        // a merged/deployed code change
	ResolutionInvestigation Resolution = "investigation" // an analysis or answer, no code
	ResolutionExperiment    Resolution = "experiment"    // an instrumented painted-door surface
	ResolutionDecision      Resolution = "decision"      // a recorded decision, often "do not build"
)

Resolution values (SPEC-ADDITIONS §12); each carries its own proof contract.

func ParseResolution

func ParseResolution(s string) (Resolution, error)

ParseResolution validates a resolution string, returning the typed value or EINVALID for an unknown one.

func (Resolution) ProofKind

func (r Resolution) ProofKind() string

ProofKind is the built-in default acceptance-bar text a resolution's proof must satisfy to close (SPEC-ADDITIONS §12). It is generic — the `change` bar is code-level, not domain-specific — and a deployment overrides it per resolution via config `[proof.contract]` (§SPEC 3.1). An unknown resolution has no text.

func (Resolution) Valid

func (r Resolution) Valid() bool

Valid reports whether r is a known resolution (SPEC-ADDITIONS §12). Validity is a domain fact; the *acceptance-bar text* a resolution requires is deployment policy (config `[proof.contract]`, overriding the ProofKind default), not the domain's concern.

type Stage

type Stage string

Stage is one station of the five-stage arc loop.

const (
	StageStrategy   Stage = "strategy"
	StageExecution  Stage = "execution"
	StageCritic     Stage = "critic"
	StageEvaluation Stage = "evaluation"
	StageOps        Stage = "ops"
)

Stage values in canonical pipeline order (SPEC §1).

func NextStage

func NextStage(s Stage) (Stage, bool)

NextStage returns the stage after s in the change pipeline and whether one exists. Ops is terminal, so NextStage(StageOps) reports ("", false).

type Status

type Status string

Status is an arc's lifecycle status.

const (
	StatusOpen    Status = "open"    // moving through the loop
	StatusBlocked Status = "blocked" // waiting at a human gate
	StatusClosed  Status = "closed"  // finished with proof
	StatusFailed  Status = "failed"  // failed evaluation past its rework budget; terminal, awaiting a human
)

Status values.

type Unrunnable

type Unrunnable string

Unrunnable is why an artifact named by a finding did not run.

const (
	UnrunnableUnset Unrunnable = ""

	// UnrunnableNoRef: the finding named no artifact at all. The critic asserted
	// something and pointed at nothing, so there was never anything to run. Noise
	// rather than a refusal.
	UnrunnableNoRef Unrunnable = "no-ref"

	// UnrunnableUnknownRef: the finding named an artifact the repository does not
	// declare. Also noise — and distinct from NoRef, because it is a critic naming a
	// tool that never existed rather than one omitting the field.
	UnrunnableUnknownRef Unrunnable = "unknown-ref"

	// UnrunnableToolFailed: the finding named a **registered** tool and that tool
	// could not start — missing binary, unbuilt, wrong commit.
	//
	// This is the honest refusal, and the only one of the three that is evidence
	// about the repository rather than about the critic. §19.2's blocking decision
	// was deferred because the three were indistinguishable; they are not.
	UnrunnableToolFailed Unrunnable = "tool-failed"
)

Why a named artifact did not run (§19.2).

UnrunnableUnset is the zero value and names no reason, so an Adjudicated nobody populated does not claim one. It is also what a finding that *did* run carries, which is correct: there is no reason, because there was no failure to explain.

func (Unrunnable) Trustworthy

func (u Unrunnable) Trustworthy() bool

Trustworthy reports whether this reason is a refusal by the repository rather than a defect in the finding that named it.

Requires: nothing. Ensures: true only for UnrunnableToolFailed. The zero value is false, so a reason nobody set never reads as a trustworthy refusal.

It exists as a method rather than a comparison at each call site because it is the predicate §19.2's blocking decision would turn on if it is ever revisited, and one place should own what "trustworthy" means when that happens.

Jump to

Keyboard shortcuts

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