prioritize

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package prioritize scores the frontier, just in time: only the next-K claimable backlog items of a repo — the scoring frontier (O3 2026-10-05) — are worth scorer spend, so ONE batch-scorer task (executor type "prioritize") covers that window; when the task completes, its verdicts are cached (priority_scores) and applied to the matching PENDING tasks as task.reprioritized facts. The agent only contributes scores; everything downstream (batching, dedup, precedence, protection) is mechanical.

The frontier ROLLS: a claim drains the head, so the claim fact itself mints the refill batch; a requeue SUPERSEDES the item's cached verdict (a durable Source stamp) because the claim attempt may have moved the repo under the score; an edited item re-keys (harvest.ItemKey hashes the text) and re-enters unscored. Time-based verdict aging is RETIRED — spend scales with work claimed, not with backlog size or score age.

Triggers are journal-driven (cursor "prioritize-sweeper", head-bootstrapped like every sweeper): a harvest enqueue means new unscored work; a scorer completion means verdicts to apply — and, right after applying, a re-check for items that entered the frontier while the batch was in flight. The first sweep (BootMint) also mints for pre-cursor pending items, so enabling the sweeper on a pool with a standing backlog scores its frontier without waiting for a fresh enqueue.

Loop safety is structural: batch tasks are type "prioritize", never "agent", so they never trigger mints themselves; a batch's dedup key is the hash of its exact key set, so an unchanged working set never re-mints (a dead batch is retried only when the set changes — the DLQ is the human surface until then); and every mint pass runs under the pool's budget guard like every other enqueue.

Index

Constants

View Source
const (
	// ConsumerKey is the sweeper's identity in the watermarks table: the
	// persisted cursor shared by every sweeper instance over the same
	// database, rewindable with `tq watermarks set prioritize-sweeper SEQ`
	// (replay is idempotent: cache upserts and same-value priority updates
	// write nothing new).
	ConsumerKey = "prioritize-sweeper"

	// SourceScorer stamps cached verdicts (queue.PriorityScore.Source):
	// the batch scorer's identity. When SweeperConfig.Model is set the
	// source gains a ":<model>" suffix (see scorerSource), so a verdict
	// scored by a different model is treated as stale and re-scored — a
	// provider retraining behind a fixed name, or a model swap, must not
	// rank fresh work against a stale model's verdict (turnstone lesson 14).
	SourceScorer = "ai:batch-scorer"

	// SourceSuperseded is the durable invalidation stamp a REQUEUE writes
	// over a cached verdict (O3 2026-10-05): the item was claimed and put
	// back, so the repo may have moved under the score and it must be
	// re-issued before ranking again. The stamp trips the same
	// Source-mismatch gate as a model change, so the item re-joins the
	// next frontier batch even though an old batch covered it; the
	// re-score's upsert overwrites the stamp with the real scorer source.
	SourceSuperseded = SourceScorer + ":superseded"

	// PrioritySourceAI is the task.reprioritized source label for applied
	// verdicts (ADR-0015 §3 ladder: ai).
	PrioritySourceAI = "ai"

	// DefaultFrontierK is the default scoring-frontier size
	// (SweeperConfig.FrontierK): how many next-claimable backlog items per
	// repo form the JIT scoring surface. Small by design — scorer spend
	// scales with the claims the window serves, not with backlog size.
	DefaultFrontierK = 8
)

Variables

This section is empty.

Functions

func DedupKey

func DedupKey(repo string, keys []string, generation int64) string

DedupKey is the dedup identity of one repo's batch over one exact key set: "prioritize:<repo>:<hash>". A set that changes (new item, item reworded and re-keyed) mints a fresh batch; an unchanged set never mints twice — even after the first batch died, whose recovery then rides the next set change (the DLQ is the human surface until then).

generation is the newest ScoredAt among the batch's stale-verdict re-joins (0 when the batch has none): a superseded verdict's refresh must mint a NEW batch instead of colliding with the old key, so nonzero generations stamp a ":g<generation>" suffix. Zero keeps the legacy key shape byte-identical, so stored dedup keys keep resolving.

Types

type SweepStats

type SweepStats struct {
	// Facts is the number of new facts consumed.
	Facts int
	// BatchesEnqueued counts fresh scorer tasks this sweep created.
	BatchesEnqueued int
	// BatchesKnown counts mints whose batch task already existed (dedup
	// hit — the batch ran, or is in flight, elsewhere).
	BatchesKnown int
	// VerdictsCached counts verdicts written to the score cache.
	VerdictsCached int
	// TasksReprioritized counts PENDING tasks whose priority changed by an
	// applied verdict.
	TasksReprioritized int
	// Skipped counts facts that could not yield work (vanished records,
	// foreign payload shapes, unparsable results). A refused store
	// operation is not counted here: it aborts the sweep before the
	// checkpoint so the fact redelivers.
	Skipped int
	// CachePruned counts stale cache entries the prune pass evicted:
	// verdicts whose item key no longer belongs to any PENDING backlog
	// task (the item was reworded and re-keyed, checked off, or its task
	// reached a terminal state).
	CachePruned int
}

SweepStats summarizes one sweep pass.

type Sweeper

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

Sweeper turns the journal's enqueue and scorer-completion facts into batch-scorer mints and score applications. It is safe for concurrent use (the mutex serializes the first-sweep boot mint; the cursor serializes the page pump).

func NewSweeper

func NewSweeper(ctx context.Context, store queue.Store, cfg SweeperConfig) (*Sweeper, error)

NewSweeper returns a sweeper over store. The cursor resumes from the persisted checkpoint; a first run bootstraps at the journal head (same semantics as the review and dlqfix sweepers).

func (*Sweeper) Sweep

func (s *Sweeper) Sweep(ctx context.Context) (SweepStats, error)

Sweep consumes new facts since the last pass: harvest enqueues trigger a mint check for their repo, scorer completions apply their verdicts. Idempotent by dedup keys, cache upserts and same-value transition guards — a replayed page (crash between consumption and checkpoint) re-hits dedup instead of duplicating work.

A store refusal — a transient failure while reading a trigger record, caching/applying verdicts, or minting a batch — aborts the sweep BEFORE the checkpoint: the fact redelivers on the next pass instead of silently dropping the work forever (dlqfix 13-15 §e pattern). Deterministic skips (vanished records, foreign shapes, done-guard dedup hits) stay checkpointed past: retrying them can never succeed.

type SweeperConfig

type SweeperConfig struct {
	// Model, when set, overrides the scorer model in every batch payload.
	// Empty (the recommended default) leaves model+effort to each repo's
	// crush config.
	Model string
	// Yolo marks the scorer autonomous (same contract as agent payloads).
	Yolo bool
	// AllowDirty lets the scorer start on a dirty tree. Default false: the
	// scorer reads the repo for context and should see committed state.
	AllowDirty bool
	// BootMint makes the FIRST sweep also mint for the pre-cursor working
	// set (items already pending when the sweeper was enabled), instead of
	// waiting for the next enqueue to trigger.
	BootMint bool
	// Log receives one summary line per mint/apply. nil logs nothing.
	Log *slog.Logger
	// PageSize bounds one fact-stream page; 0 selects the default.
	PageSize int
	// FrontierK is the JIT scoring-frontier size (O3 2026-10-05): minting
	// considers only the next-K claimable backlog items of a repo, in
	// claim order (ADR-0015 §4 effective priority). The cache rolls with
	// the window: verdicts enter as items enter the frontier, leave as it
	// drains (claims) or as facts invalidate them (requeue supersedes,
	// item edits re-key). Zero selects DefaultFrontierK.
	FrontierK int
}

SweeperConfig controls one Sweeper.

Jump to

Keyboard shortcuts

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