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

screening

package
v0.14.0 Latest Latest
Warning

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

Go to latest
Published: Oct 23, 2026 License: AGPL-3.0 Imports: 8 Imported by: 0

Documentation

Overview

Package screening turns an AI adapter's proposed amendments into changes to a draft spec, or refuses them.

It is the enforcement point for R-332 and R-333, and it lives in core for the same reason authorization does (R-027): an adapter cannot amend a spec, it can only propose an amendment to one, and Apply is the only thing in the tree that turns the second into the first.

The amendment types live in internal/adapter/api because an adapter returns them. Deciding which of them land is not the adapter's, and the split is deliberate — a screener that could apply its own amendments would be a screener that could write anything the spec can hold.

Nothing here fails a detection. R-335: a screening that cannot run, or whose every amendment is refused, leaves the proposal exactly as the deterministic pipeline produced it. Design 10 is the argument; §4.1 is this rule.

Index

Constants

View Source
const (
	DefaultMaxFiles = 40
	DefaultMaxBytes = 256 << 10
	DefaultTimeout  = 2 * time.Minute
)

Default budget (R-339). Overridden downward by an adapter's own capabilities and by the install's configuration; never raised by either.

View Source
const MaxAmendments = 32

MaxAmendments bounds one screening.

Not a safety property — every amendment is validated individually — but a review a person cannot read is a review that does not happen (R-098), and a screener returning ninety changes to a spec with four workloads has misunderstood the question rather than found ninety things.

Variables

This section is empty.

Functions

func Apply

func Apply(s *spec.AppSpec, env Env, amendments []api.Amendment) (applied []Applied, refused []Refused)

Apply folds amendments into s, returning what landed and what did not.

It never returns an error. Every way an amendment can be wrong produces a Refused with a reason, because a screening that fails a detection is the thing R-335 forbids — and one bad amendment must not discard the good ones beside it.

Types

type Applied

type Applied struct {
	Amendment api.Amendment `json:"amendment"`

	// Summary is what changed, in one line, for the review.
	Summary string `json:"summary"`
}

Applied is an amendment that landed.

type Env

type Env struct {
	// Source is the repository, read-only. Used to check that the paths an
	// amendment rests on exist (R-334) — the cheapest available check on
	// whether the screener read this repository or recalled a framework.
	//
	// A nil Source refuses every amendment: evidence that cannot be checked is
	// evidence that was not checked, and the honest failure is the one that
	// keeps the deterministic proposal.
	Source api.SourceView

	// Trial is what was observed (R-333), and whether the app crashed, which
	// is what decides whether a screener-added slot may be Required (O-4).
	Trial api.TrialSummary
}

Env is what Apply needs beyond the spec to decide.

type Outcome

type Outcome struct {
	// Ran is false when nothing screened. Skipped says why.
	Ran bool `json:"ran"`

	// Skipped is the reason no screening happened: no adapter configured, one
	// that does not screen, host policy, an unreachable provider, a timeout.
	// Every one of them is an ordinary outcome (R-335).
	Skipped string `json:"skipped,omitempty"`

	// SkipCode is Skipped as a stable machine value, so a client can branch
	// without matching on a sentence that may be reworded.
	SkipCode SkipCode `json:"skip_code,omitempty"`

	// Function is what the adapter was asked to do: repair_plan when detection
	// failed, answer_questions when it asked something (R-336). Empty when
	// nothing was needed.
	Function api.AIFunction `json:"function,omitempty"`

	// Why is what made the call necessary — the trial run crashed, no detector
	// could read the repository, detection asked a question — in one sentence.
	// On the repair path the original failure is still on the proposal, as its
	// trial log, whatever the repair did (R-107).
	Why string `json:"why,omitempty"`

	AdapterRef string `json:"adapter_ref,omitempty"`
	Model      string `json:"model,omitempty"`

	// FilesRead is what left the host (R-337).
	FilesRead []string `json:"files_read,omitempty"`

	Applied []Applied `json:"applied,omitempty"`

	// Refused is never dropped. An amendment that vanishes because core did not
	// like it teaches nobody anything, and these are how the next version of
	// the prompt gets written.
	Refused []Refused `json:"refused,omitempty"`

	// Answers are the detection questions the screener answered (R-338),
	// applied through the same machinery a person's answers go through.
	Answers map[string]string `json:"answers,omitempty"`

	Notes []string `json:"notes,omitempty"`

	DurationMS int64 `json:"duration_ms,omitempty"`
}

Outcome is what a screening did, recorded on the proposal.

On the proposal and not only in the audit log, because the console renders it as a section of the review: which adapter, which model, what it read, what it changed and why, and what it asked for that Pando would not do. R-334 calls for attribution, and attribution nobody can see is a record, not attribution.

func Run

Run calls fn on the screener under the budget and returns what it said.

It never returns an error. Every failure becomes a skipped Outcome carrying its reason, because R-335 is that a screening which cannot run leaves the deterministic proposal exactly as it was — and a caller that has to remember to ignore an error is a caller that will one day not.

func SkippedOutcome

func SkippedOutcome(code SkipCode, reason string) Outcome

SkippedOutcome returns an outcome for a screening that never ran.

func (Outcome) Changed

func (o Outcome) Changed() bool

Changed reports whether the screening altered the proposal at all.

func (Outcome) Elapsed

func (o Outcome) Elapsed(d time.Duration) Outcome

Elapsed records how long a screening took.

func (Outcome) For

func (o Outcome) For(fn api.AIFunction) Outcome

For records which function the outcome was for.

type Refused

type Refused struct {
	Amendment api.Amendment `json:"amendment"`
	Reason    string        `json:"reason"`
}

Refused is an amendment that did not, and why.

func Split

func Split(env Env, amendments []api.Amendment, outstanding map[string]bool) (
	answers map[string]string, rest []api.Amendment, refused []Refused,
)

Split separates answers to detection's questions from spec amendments.

R-338 makes an answer an amendment like any other — evidenced, attributed, refused when it does not match an outstanding question — but it is applied through detection's own answer machinery rather than here, because that machinery already knows that answering "which service is primary" changes what every other answer means. Two ways to apply an answer is how the two would drift.

type Screener

type Screener interface {
	Capabilities(ctx context.Context) (api.AICapabilities, error)
	RepairPlan(ctx context.Context, req api.ScreenRequest) (api.ScreenResult, error)
	AnswerQuestions(ctx context.Context, req api.ScreenRequest) (api.ScreenResult, error)
	RevisePlan(ctx context.Context, req api.ScreenRequest) (api.ScreenResult, error)
}

Screener is the half of api.AIAdapter this package needs.

Narrowed so a test can supply one in a few lines, and so the dependency reads as what it is: something that repairs a plan or answers questions, not an adapter registry.

type SkipCode

type SkipCode string

SkipCode says why a screening did not run.

const (
	// SkipNotConfigured is the ordinary case: no AI adapter. The console shows
	// nothing for it, because an install without one is not degraded (R-335).
	SkipNotConfigured SkipCode = "not_configured"

	// SkipNotNeeded is the other ordinary case, and the common one on an install
	// that has an adapter: detection produced a plan, the plan did not fail, and
	// nothing was asked. No call is made, nothing leaves the host, and the
	// console shows nothing for it (R-336).
	SkipNotNeeded SkipCode = "not_needed"

	SkipPolicy      SkipCode = "policy"      // host policy forbids it (R-336)
	SkipUnsupported SkipCode = "unsupported" // the adapter does not do what was needed
	SkipUnavailable SkipCode = "unavailable" // the provider failed or timed out
	SkipBlocked     SkipCode = "blocked"     // nothing to screen (R-099)
)

Jump to

Keyboard shortcuts

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