upgrade

package
v0.6.1 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Overview

Package upgrade watches upstream for new versions of the pinned coding CLIs and for new models in configured provider model lists, and turns each new candidate into an eval-gated pull request: it verifies the candidate's install artifacts (sha256 / npm integrity, via release.ArtifactResolver), writes the candidate pin on a branch, runs the eval suite, and opens a PR carrying the scorecard. It never merges, never publishes a release and never retags a ring: a human reviews and merges every PR.

All network access sits behind Registry, ModelLister and Verifier, so the whole loop runs against fakes in tests.

Index

Constants

View Source
const (
	KindCLI   = "cli"
	KindModel = "model"
)

Candidate kinds.

Variables

This section is empty.

Functions

func GateVerdict

func GateVerdict(sc *eval.Scorecard) string

GateVerdict is the scorecard's gate verdict ("hold" if it has none).

func Table

func Table(cs []Candidate) string

Table renders candidates as a compact terminal table.

Types

type ArtifactVerifier

type ArtifactVerifier struct{ Resolver release.ArtifactResolver }

ArtifactVerifier verifies through the same resolver `halo release build` uses, so a pin is only proposed for bytes halod would be allowed to install.

func (ArtifactVerifier) Verify

func (a ArtifactVerifier) Verify(ctx context.Context, h, ver string) (int, error)

type Candidate

type Candidate struct {
	Kind      string `json:"kind"`
	Harness   string `json:"harness,omitempty"`
	Package   string `json:"package,omitempty"`
	Provider  string `json:"provider,omitempty"`
	Alias     string `json:"alias,omitempty"`
	From      string `json:"from"`
	To        string `json:"to"`
	Artifacts int    `json:"artifacts,omitempty"` // verified install artifacts (cli)
	Verdict   string `json:"verdict,omitempty"`   // gate verdict, or "" when not evaluated
	PR        string `json:"pr,omitempty"`
	Note      string `json:"note,omitempty"`

	// File and Edit are the candidate pin: the policy file it changes and how
	// to re-apply it to a given version of that file.
	File string                       `json:"file,omitempty"`
	Edit func([]byte) ([]byte, error) `json:"-"`
}

Candidate is one proposed upgrade and what happened to it.

func (Candidate) Key

func (c Candidate) Key() string

Key identifies a candidate in the state file.

type Config

type Config struct {
	// Profile is the profile whose harness pins are upgrade candidates
	// (typically the "-next" profile ring1 canaries).
	Profile string `yaml:"profile"`
	// Suite is the eval suite run for each candidate.
	Suite string `yaml:"suite"`
	// Harnesses limits which pinned harnesses are watched (default: all
	// pinned harnesses with a known package).
	Harnesses []string `yaml:"harnesses,omitempty"`
	// Models are provider model lists to watch.
	Models []ModelSource `yaml:"models,omitempty"`
	// Base is the PR base branch (default: repo default).
	Base string `yaml:"base,omitempty"`
	// State is the watcher's memory on disk (default .halos/upgrade-state.json).
	State string `yaml:"state,omitempty"`
}

Config is the upgrade watcher's YAML, by default <policy-dir>/.halos/upgrade.yaml (a dot-dir: the policy loader skips it). Paths are relative to the policy dir.

func LoadConfig

func LoadConfig(path string) (*Config, error)

LoadConfig reads and validates the watcher config.

type EvalFunc

type EvalFunc func(ctx context.Context, c Candidate) (*eval.Scorecard, error)

EvalFunc runs the eval suite for a candidate (control = current pin).

type HTTPModels

type HTTPModels struct {
	URL, APIKey string
	HTTP        *http.Client
}

HTTPModels lists models from an OpenAI/Anthropic-style {"data":[{"id"}]} or Gemini-style {"models":[{"name":"models/<id>"}]} endpoint.

func (HTTPModels) List

func (h HTTPModels) List(ctx context.Context) ([]string, error)

type ModelLister

type ModelLister interface {
	List(ctx context.Context) ([]string, error)
}

ModelLister lists a provider's model ids.

type ModelSource

type ModelSource struct {
	Provider  string `yaml:"provider"`
	URL       string `yaml:"url"` // e.g. https://ai.acme.example/v1/models
	APIKeyEnv string `yaml:"api_key_env,omitempty"`
	// Match filters ids worth evaluating (RE2), e.g. ^claude-(opus|sonnet)-.
	Match string `yaml:"match,omitempty"`
	// Known ids are never candidates (already evaluated or deliberately skipped).
	Known []string `yaml:"known,omitempty"`
	// Alias is the gateway model alias whose route the candidate pin edits
	// (models.<alias>.model in the Gateway document), e.g. sonnet-next.
	Alias string `yaml:"alias"`
}

ModelSource is one provider's model list, read through the gateway.

type NPM

type NPM struct {
	URL  string // default https://registry.npmjs.org
	HTTP *http.Client
}

NPM reads dist-tag latest from an npm registry (GET <registry>/<pkg>/latest). UNVERIFIED against registry.npmjs.org; tests use httptest.

func (NPM) Latest

func (n NPM) Latest(ctx context.Context, pkg string) (string, error)

type Registry

type Registry interface {
	Latest(ctx context.Context, pkg string) (string, error)
}

Registry reports the latest published version of an npm package.

type State

type State struct {
	Handled map[string]string `json:"handled"` // candidate key -> verdict / PR url
}

State is the watcher's on-disk memory: what it already handled.

type Verifier

type Verifier interface {
	Verify(ctx context.Context, harness, version string) (int, error)
}

Verifier checks that harness@version resolves to hash-pinned install artifacts and returns how many (one per platform, or one npm tarball).

type Watcher

type Watcher struct {
	PolicyDir string
	Config    *Config
	Registry  Registry
	Models    map[string]ModelLister // by provider; nil = HTTPModels from Config
	Verifier  Verifier
	Eval      EvalFunc         // required unless DryRun
	PR        promote.PROpener // required unless DryRun
	DryRun    bool
	// Warn receives non-fatal notices (e.g. a skipped malformed model id); nil = discard.
	Warn func(string)
}

Watcher runs the check.

func (*Watcher) Candidates

func (w *Watcher) Candidates(ctx context.Context) ([]Candidate, error)

Candidates discovers new CLI versions and models without side effects.

func (*Watcher) Check

func (w *Watcher) Check(ctx context.Context) ([]Candidate, error)

Check discovers candidates and, unless DryRun, evaluates each one not yet handled and opens a PR for every candidate whose gate is not block.

func (*Watcher) Watch

func (w *Watcher) Watch(ctx context.Context, every time.Duration, report func([]Candidate, error))

Watch runs Check every interval until ctx ends, reporting each round.

Jump to

Keyboard shortcuts

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