serverstore

package
v0.1.59 Latest Latest
Warning

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

Go to latest
Published: Aug 27, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Overview

Package serverstore is the csx-server persistence layer: a Store interface over PostgreSQL (plan contract C4) plus the pure ingest logic — batch validation and delta-merge dedup semantics — which unit-tests without a database. This file must stay free of pgx imports; the pgx implementation lives in pg.go.

Index

Constants

View Source
const (
	// AuthoringMaxSessionHandouts is how many times ONE writer may be handed
	// the same coordinate before it is moved on to different work. This is
	// the bound the 22-attempt incident needed: the lease was 24 hours, the
	// session stayed alive, and nothing else would ever have released it.
	//
	// Three, because a writer that has looked at a coordinate three times
	// across three separate stretches of work has told us what it knows, and
	// because three is small enough that the loss when we are wrong is one
	// worker-hour rather than four.
	AuthoringMaxSessionHandouts = 3

	// AuthoringNoOutputQuarantine is how many attempts may produce nothing
	// before the coordinate stops being offered at all.
	//
	// Six, which is exactly two writers' worth: with the per-writer bound
	// above, six unexcused attempts cannot be reached by one machine. That is
	// the point — one writer failing is one writer's opinion, and the network
	// only withholds work on the evidence of two independent ones.
	AuthoringNoOutputQuarantine = 6

	// AuthoringNoSymbolQuarantine is how many DISTINCT writers must measure
	// that nothing callable exists before the coordinate is withheld.
	//
	// Two, for the same reason and at a far lower count: this outcome is a
	// measurement of the artifact rather than a report about the attempt, so
	// it does not need six tries to be believed — but one writer's report is
	// still one writer's opinion.
	AuthoringNoSymbolQuarantine = 2

	// AuthoringExcusedAttempts is how many attempts on one coordinate may be
	// refunded as somebody else's fault before refunding stops.
	//
	// Excusing has to be bounded or a writer stuck in a loop reporting the
	// same excuse holds the network's attention forever. Four is more than
	// any real outage needs on a single coordinate and far fewer than a loop
	// produces.
	AuthoringExcusedAttempts = 4

	// AuthoringHistoryDepth bounds the stored evidence per coordinate. The
	// ticket asked for a BOUNDED history: an operator needs the last few
	// attempts to judge a withholding, and nobody needs the two hundredth.
	AuthoringHistoryDepth = 10
)

The thresholds. Every one of them is a proposal measured against the incidents above rather than a preference, and every one of them is safe to be wrong about in the withholding direction because withholding is visible and reversible.

View Source
const (
	AuthoringReasonNoCallableSymbol = "no callable symbol: independent writers measured that nothing here can be called"
	AuthoringReasonNoOutput         = "repeated no output: handed out and produced nothing publishable"
)

The withholding reasons. They are counted as keys in the operations panel, so they are fixed strings rather than assembled prose.

View Source
const (
	// AdminInsightDays is the number of UTC calendar days shown by the
	// private operator dashboard. The stats read includes one additional
	// baseline day so the first visible day's delta can be calculated.
	AdminInsightDays = 30
)
View Source
const AnomalyCooldown = 6 * time.Hour

AnomalyCooldown is how long the same fingerprint waits before a repeat submission is worth anything to anybody.

It does not refuse the repeat — a duplicate is always answered with the report it duplicates, which is the useful answer — it is what the response tells the caller to wait before saying it again. The dedupe key already prevents a second verification job; this exists so an agent in a retry loop is told to stop rather than left to discover it.

View Source
const AuthoringAttemptDebounce = 5 * time.Minute

AuthoringAttemptDebounce is how much time must pass before the same coordinate in the same writer's hands counts as a second attempt.

Polling is not attempting. `csx sample-worker next` is a one-shot command an agent runs, and an agent that runs it twice in a minute has not tried twice; counting it as two would withhold a coordinate nobody ever worked on. Five minutes is shorter than any real authoring attempt and longer than any poll loop.

View Source
const AuthoringQuarantineCooldown = 30 * 24 * time.Hour

AuthoringQuarantineCooldown is how long a withholding INFERRED from repeated no output lasts before it lapses on its own.

A withholding that never lapses is a deletion with better manners. Repeated no output is an inference about attempts, not a measurement of the artifact, and the thing it most plausibly reflects — a registry, a toolchain or an image that was broken for a while — heals. Thirty days is long enough that the coordinate is not immediately back in the queue and short enough that nobody has to remember it.

View Source
const CurrentFailureClusterPredicateSQL = `` /* 135-byte string literal not displayed */

A failure cluster is derived data, and migration 0024 deliberately does not clear it: emptying a production table is a destructive operation that does not belong in an unattended additive migration. So the rows written before structured failure evidence existed are still there, each keyed by its own pre-contract fingerprint.

The current builder never writes those keys again. A hash produced before exit code, signal, timeout and normalized error were recorded is provenance, not a failure identity, so missing and legacy evidence collapse into one explicit evidence-gap row with an empty fingerprint. The preserved rows are therefore historical material sitting beside the live ones — and counting them is what took production from 17,737 to 35,488 cluster observations on a deployment where the FAIL total never moved.

They are hidden here rather than deleted. Removing them is a separately authorized cleanup with its own rollback and evidence.

CurrentFailureClusterPredicateSQL and IsCurrentFailureCluster are two spellings of one rule. The deploy transaction computes the ledger in shell against the same predicate, so a change here is a change to what the gate measures.

View Source
const JobLease = 30 * time.Minute

JobLease is how long a claim holds a job before it returns to the queue.

A claim used to be permanent, and nothing ever called CompleteJob — there was no route to it — so every claimed job was stranded for good. Claiming needs no authentication, and deliberately so: publishing on this network is anonymous and accounts are not the answer (goal.md §8.6). But that makes an unbounded claim a way for one stranger to empty the verification queue permanently, at no cost. A lease is the version of this that cannot be abused: an abandoned claim expires and someone else picks the job up.

View Source
const JobStatusUnsupported = "unsupported"

JobStatusUnsupported is work no verifier lane in this build can run.

It is not "open", because nothing can claim it, and it is not "done", because nothing measured the sample. Production spent three days with an open cross queue every worker skipped in silence; a job that no image can serve now says so in the one field an operator already reads.

View Source
const MaxAdminTokens = 64

MaxAdminTokens bounds how many live credentials may exist at once, so an authenticated browser cannot mint an unbounded set of permanent keys.

View Source
const MaxAuthoringSessions = 64

Variables

View Source
var (
	ErrAuthoringSessionLimit   = errors.New("too many active authoring sessions")
	ErrAuthoringSessionMissing = errors.New("authoring session unavailable")
	ErrAuthoringSessionExpired = errors.New("authoring session expired")
)
View Source
var ErrPoolBusy = errors.New("serverstore: no database connection available within the wait budget")

ErrPoolBusy is returned when a caller's class had no connection to give within its wait budget. It is deliberately its own error and not a context deadline: "the database is saturated" and "this request ran out of time" want different HTTP statuses and very different operator responses, and telling them apart afterwards from a wrapped context.DeadlineExceeded is guesswork.

Functions

func ContractWasJudged added in v0.1.36

func ContractWasJudged(contractResult string) bool

ContractWasJudged reports whether a receipt reached a verdict on the sample, as opposed to never getting far enough to run the contract.

A cross job is hidden from any peer that already filed a receipt for that sample, and rightly so: a peer that judged a sample must not judge it again and manufacture its own independence. But the queue treated every receipt alike, and the two are not alike.

One farm node mounted an empty workspace into its container — systemd PrivateTmp — so every run died at the first stage with {"resolve":"FAIL","contract":"SKIPPED"}. 167 receipts were written that way. The samples were fine; pulled by hand into the same image under the same constraints they exit 0. The infrastructure was fixed and that peer still could not touch any of them: sixteen of seventeen open cross jobs were invisible to it, the oldest unclaimed for over two hours. Deleting the receipts by hand cleared it in minutes, which is first aid.

A receipt that never ran the contract says nothing about the sample. It says something about the verifier that night. It is kept — it is signed evidence and the audit trail is the point — and it stops locking anyone out.

func IsCurrentFailureCluster added in v0.1.45

func IsCurrentFailureCluster(c ClusterRow) bool

IsCurrentFailureCluster reports whether a stored cluster row is one the current builder still writes. It deliberately matches the SQL predicate: an empty (but non-NULL) EvidenceQuality is not a legacy value and remains current even when it carries a fingerprint.

func IsPoolBusy added in v0.1.45

func IsPoolBusy(err error) bool

IsPoolBusy reports whether err is the pool refusing to make a caller wait any longer.

func IsQueryCanceled added in v0.1.45

func IsQueryCanceled(err error) bool

IsQueryCanceled reports the wider condition: the statement did not finish because something cancelled it, whether a timeout or a cancel request.

func IsQueryTimeout added in v0.1.45

func IsQueryTimeout(err error) bool

IsQueryTimeout reports whether PostgreSQL cancelled the statement because it outlived its statement_timeout (SQLSTATE 57014, "canceling statement due to statement timeout"). A cancel requested by a client carries the same SQLSTATE with a different message, so the message is part of the test: an operator reading "query timeout" must be reading about a ceiling this code set, not about a client that hung up.

func Migrate

func Migrate(ctx context.Context, conn *pgx.Conn) error

Migrate applies every embedded migration not yet recorded in schema_migrations, each inside its own transaction. It is idempotent and safe to run on every server start.

func ValidAuthoringOutcome added in v0.1.44

func ValidAuthoringOutcome(outcome AuthoringOutcome) bool

ValidAuthoringOutcome reports whether a worker may report this outcome. HANDED_OUT and AUTHORED are the server's own bookkeeping and are not accepted from a client.

func ValidateBatch

func ValidateBatch(b domain.ObservationBatch) error

ValidateBatch checks one ObservationBatch against the wire contract before it may touch storage. It is pure and shared with the HTTP ingest handler.

Enforced here (binding):

  • PURL parses and its ecosystem is on the public allowlist (§8.1).
  • Stage is an observation stage. SYMBOL_EXECUTED / SYMBOL_CALL are A3-only runtime-instrumentation stages and no Public v1 adapter claims A3, so they are rejected (docs/execution-context.md §3).
  • symbolConfidence is EXACT, PROBABLE or UNKNOWN (empty allowed).
  • errorFingerprint must be a sha256 content id — raw error text can never ride in on that field.

func ValidateFailureLineage added in v0.1.46

func ValidateFailureLineage(f domain.FailureEvidence) error

ValidateFailureLineage applies the shared privacy-bounded public-coordinate contract to both anonymous observation batches and signed receipts. A signature authenticates a string; it does not make arbitrary text safe to retain or publish.

func WithAuthoringPoll added in v0.1.50

func WithAuthoringPoll(ctx context.Context) context.Context

WithAuthoringPoll marks the read half of /v1/authoring/work/next. It lets TopWanted use the fleet poll's database-owned statement ceiling without changing unrelated background/admin callers or the pool-guard-off contract.

func WithQueryBudget added in v0.1.45

func WithQueryBudget(ctx context.Context, b *QueryBudget) context.Context

WithQueryBudget attaches a budget to ctx. Every store call made under that context acquires connections in its class and reports into it.

func WithQueryClass added in v0.1.45

func WithQueryClass(ctx context.Context, class QueryClass) context.Context

WithQueryClass is WithQueryBudget for a caller that wants the class but has nowhere to read the counters back -- a background loop, a test.

Types

type AdminDailyStat added in v0.1.6

type AdminDailyStat struct {
	Day             time.Time
	Evidence        AdminMetricValue
	VerifiedSamples AdminMetricValue
	Packages        AdminMetricValue
}

AdminDailyStat is one stored UTC snapshot. Missing days are not synthesized.

type AdminEcosystemCount added in v0.1.6

type AdminEcosystemCount struct {
	Ecosystem     string
	Verifications int64
}

AdminEcosystemCount counts 30-day PASS receipts by the environment recorded on the receipt itself. It never substitutes the sample author's manifest environment for where a matrix verification actually ran. The PG reader returns only nine fixed supported labels plus "other", never raw input.

type AdminFlow added in v0.1.45

type AdminFlow struct {
	Hour AdminFlowWindow
	Day  AdminFlowWindow
	Week AdminFlowWindow

	// PreviousHour is the hour before Hour, so the current hour can be read
	// as rising or falling rather than as a bare count.
	PreviousHour AdminFlowWindow

	LastVerification    time.Time
	HasLastVerification bool

	LastSample    time.Time
	HasLastSample bool

	LastSearchOutcome    time.Time
	HasLastSearchOutcome bool
}

AdminFlow is the bounded aggregate behind the three operator questions this dashboard could not previously answer: is search still finding things, are verifiers still finishing work, and are samples still becoming usable.

The Last* timestamps are what separate a normal zero from a broken one. An hour with no verifications and a last receipt twelve minutes old is a lull; the same zero with a last receipt three days old is a stopped lane, and without the timestamp the panel cannot tell the operator which one it is. They are absent, never substituted with the current time, when nothing was ever recorded.

type AdminFlowWindow added in v0.1.45

type AdminFlowWindow struct {
	// Since is the start of the window in UTC; Length is its width.
	Since  time.Time
	Length time.Duration

	// NoMatches and Hits are deduplicated search outcomes, counted in the
	// same unit on both sides: one reporter's one question, once per UTC day.
	// Retries collapse; a report naming ten packages is still one question.
	NoMatches int64
	Hits      int64

	// Verifications is every completed verification receipt in the window,
	// not only the passing ones. A FAIL is a verifier that did its job, and
	// counting passes alone reports a stalled farm and a failing farm as the
	// same zero. The mix is what the drill-down is for.
	Verifications AdminVerificationCounts

	// AcceptedSamples is the samples uploaded in this window that the server
	// currently serves. HeldSamples is the ones uploaded in the same window
	// that are still quarantined — a draft awaiting its cross verification,
	// or one that was withdrawn. Producing and being usable are different
	// events, and merging them hides the case worth seeing: a producer that
	// is busy while nothing it makes reaches anyone.
	AcceptedSamples int64
	HeldSamples     int64
}

AdminFlowWindow is production measured over one bounded, recent window.

The rest of the dashboard reports stock — what has accumulated. Stock cannot answer whether the line is running: a corpus of ten thousand verified samples looks identical whether the last verification finished a minute ago or in March. Every count here is scoped to a window and every window is named on screen, because a rate without its window is not a number an operator can act on.

func (AdminFlowWindow) SearchTotal added in v0.1.45

func (w AdminFlowWindow) SearchTotal() int64

SearchTotal is the denominator of the No-match rate: every search in the window whose outcome the server got to see.

type AdminInsights added in v0.1.6

type AdminInsights struct {
	WindowStart  time.Time
	WindowEnd    time.Time
	Daily        []AdminDailyStat
	Verification AdminVerificationCounts
	Ecosystems   []AdminEcosystemCount
	PackageDepth []AdminPackageDepth
	Search       AdminSearchOutcomeCounts
	Jobs         AdminJobQueue
	// Flow is production measured over recent bounded windows rather than
	// accumulated. Every other field here is stock, and stock cannot say
	// whether the line is running right now.
	Flow AdminFlow
}

AdminInsights is a bounded, read-only view for operator decisions.

type AdminInsightsReader added in v0.1.6

type AdminInsightsReader interface {
	AdminInsights(ctx context.Context, now time.Time) (AdminInsights, error)
}

AdminInsightsReader is intentionally separate from Store. The private dashboard discovers this optional read capability dynamically, so adding operational reporting does not widen the public server persistence contract or force every test fake to implement it.

type AdminJobQueue added in v0.1.15

type AdminJobQueue struct {
	Cross           AdminJobReasonCounts
	Matrix          AdminJobReasonCounts
	Other           AdminJobReasonCounts
	LiveClaimants   int64
	OldestClaimable time.Time
	HasOldest       bool
}

AdminJobQueue is an aggregate of verification_jobs. It deliberately never returns claimed_by: the dashboard needs workload and lease health, not a list of contributor identities. LiveClaimants is the number of distinct anonymous IDs holding a non-expired lease, not the number of online workers.

func (AdminJobQueue) Claimable added in v0.1.15

func (q AdminJobQueue) Claimable() int64

func (AdminJobQueue) Live added in v0.1.15

func (q AdminJobQueue) Live() int64

func (AdminJobQueue) Stale added in v0.1.15

func (q AdminJobQueue) Stale() int64

type AdminJobReasonCounts added in v0.1.15

type AdminJobReasonCounts struct {
	Claimable int64
	Live      int64
	Stale     int64
}

AdminJobReasonCounts separates work a verifier may claim now from live leases and abandoned leases. Stale jobs are also claimable; they remain a separate count because a growing stale share is an operational fault signal.

type AdminMetricValue added in v0.1.6

type AdminMetricValue struct {
	Value int64
	Valid bool
}

AdminMetricValue preserves the difference between a measured zero and a missing/malformed field in an old stats_daily document.

type AdminPackageDepth added in v0.1.6

type AdminPackageDepth struct {
	Ecosystem       string
	Name            string
	VerifiedSamples int64
}

AdminPackageDepth is one of the most deeply covered package names among v2 PASS receipts with resolvedPackages in the last 30 UTC calendar days. Versions are collapsed and one sample counts once per package. V1 receipts establish no resolved version and are intentionally absent.

type AdminSearchOutcomeCounts added in v0.1.10

type AdminSearchOutcomeCounts struct {
	Available  bool
	SampleHits int64
	NoMatches  int64
	Days       int64
	FirstDay   string
	LastDay    string
}

AdminSearchOutcomeCounts counts calls to the HTTP search endpoint. It is NOT a measure of how often the network is searched, and reading it as one inverts the truth.

Every shipped client answers search from its own synced shard cache and never posts to /v1/search: the MCP tool, the daemon and the CLI all call the local engine. The only HTTP search client in the repo had no callers at all and has been deleted. So this counter can only move when something outside the product calls the wire API directly, and it has recorded six events in its lifetime.

Real search volume is visible in the asymmetry instead. A MISS uploads a Wanted ask, so misses reach the server — 648 asks in the first week. A HIT writes a local hits row that is never uploaded, so hits reach nothing; what proves they happened is that 130 distinct samples were adopted, and a sample can only be adopted after a hit surfaced it.

Available distinguishes no collected rows from a measured zero. Dates are UTC calendar dates.

func (AdminSearchOutcomeCounts) Total added in v0.1.10

func (c AdminSearchOutcomeCounts) Total() int64

type AdminTokenRow added in v0.1.21

type AdminTokenRow struct {
	TokenHash  string
	TokenID    string
	Label      string
	IssuedAt   time.Time
	ExpiresAt  time.Time // zero = never expires
	LastUsedAt time.Time
	LastUsedIP string
	RevokedAt  time.Time
}

AdminTokenRow is one long-lived operator API credential.

Only the SHA-256 digest is ever stored, the same rule every other bearer in this server follows: a row is useful to nobody who does not already hold the token.

A zero ExpiresAt means the token never expires on its own. That is a deliberate option rather than an oversight — an operator running a farm needs a credential that outlives any session — and it is exactly why LastUsedAt and LastUsedIP exist. A credential that cannot expire needs some other way for its owner to notice somebody else is using it.

func (AdminTokenRow) Live added in v0.1.21

func (r AdminTokenRow) Live(now time.Time) bool

Live reports whether the row may still authorize a request.

type AdminTokenStore added in v0.1.21

type AdminTokenStore interface {
	IssueAdminTokens(ctx context.Context, rows []AdminTokenRow) error
	// ResolveAdminToken validates a presented digest and, on success, records
	// that it was used. Recording is part of resolving because a token that
	// never expires is only observable through its use.
	ResolveAdminToken(ctx context.Context, tokenHash, ip string, now time.Time) (AdminTokenRow, bool, error)
	ListAdminTokens(ctx context.Context, limit int) ([]AdminTokenRow, error)
	RevokeAdminToken(ctx context.Context, tokenID string, now time.Time) (bool, error)
}

AdminTokenStore keeps operator API credentials across restarts.

type AdminVerificationCounts added in v0.1.6

type AdminVerificationCounts struct {
	Pass         int64
	Fail         int64
	Skipped      int64
	Unclassified int64
}

AdminVerificationCounts is all verification receipt activity in the displayed network window. It deliberately does not claim to isolate the private sample factory from other contributors.

func (AdminVerificationCounts) Total added in v0.1.6

func (c AdminVerificationCounts) Total() int64

Total returns every receipt counted in the window.

type AdoptionCounts added in v0.1.4

type AdoptionCounts struct {
	Reports   int64
	Applied   int64
	BuildPass int64
	BuildFail int64
}

AdoptionCounts summarises adoption reports for the stats rollup.

The three numbers are kept apart on purpose. Applied says the answer was used; BuildPass and BuildFail say whether it then worked. Folding an unknown build into either bucket would turn "we did not measure" into a claim, which is the failure mode this project cares most about.

type AdoptionRow added in v0.1.4

type AdoptionRow struct {
	SampleID  string
	Applied   bool
	BuildPass *bool // nil = the reporter ran no build
	Epoch     string
	AnonID    string
}

type AnomalyInsights added in v0.1.46

type AnomalyInsights struct {
	WindowStart time.Time
	WindowEnd   time.Time
	// Reports counts submissions, Unique counts distinct fingerprints.
	// Duplicates is the difference, and their ratio is the honest measure
	// of whether the channel is being used or hammered.
	Reports    int64
	Unique     int64
	Duplicates int64

	Queued      int64
	Verifying   int64
	Verified    int64
	Unsupported int64

	Verdicts     []AnomalyVerdictCounts
	Confirmed    int64
	CSXDefects   int64
	Insufficient int64

	// VerdictLatencyTotal / VerdictLatencyCount give the mean; Max is the
	// tail an operator actually notices. A mean with no count behind it is
	// not reported as zero, it is reported as absent.
	VerdictLatencyTotal time.Duration
	VerdictLatencyCount int64
	VerdictLatencyMax   time.Duration

	// BusiestReporter is the highest submission count from a single
	// anonymous bucket in the window. It is a number, never a name.
	BusiestReporter int64
}

AnomalyInsights is the bounded operator view of the feedback channel: how much is coming in, how much of it is the same thing said twice, how much of it turned out to be real, and how long the answer took.

func (AnomalyInsights) MeanVerdictLatency added in v0.1.46

func (i AnomalyInsights) MeanVerdictLatency() (time.Duration, bool)

MeanVerdictLatency reports the average report→verdict time and whether anything was measured at all.

type AnomalyReportRow added in v0.1.46

type AnomalyReportRow struct {
	ID          int64
	Fingerprint string
	// ReportJSON is the canonical domain.AnomalyReport as submitted, after
	// normalization and redaction.
	ReportJSON  string
	AnomalyType string
	PURL        string
	Symbol      string
	// SampleID is the sample this report contests, when it contests one.
	// Empty means there is nothing this network can hand a verifier.
	SampleID string
	Status   string
	Verdict  string
	// UnsupportedReason says, in a sentence an operator and an agent can
	// both read, why no lane can reproduce this. A report that cannot be
	// verified must SAY so rather than sit in the queue looking busy.
	UnsupportedReason string
	// JobID is the verification job created for this report, 0 when none.
	JobID int64
	// Reports counts submissions of this fingerprint, first included.
	Reports int64
	// ReporterBucket is the rotating anonymous id of the FIRST reporter.
	// It exists to detect one client flooding, never to identify anyone.
	ReporterBucket string
	FirstSeen      time.Time
	LastSeen       time.Time
	VerdictAt      time.Time
}

AnomalyReportRow is one stored verification request.

Note what is NOT here: no reporter identity beyond the rotating anonymous bucket every other anonymous write on this server already uses, and no place for the report to become public. A row here is a question, and it stays a question until a signed receipt answers it.

type AnomalyStore added in v0.1.46

type AnomalyStore interface {
	// RecordAnomalyReport stores a report, or recognizes it as one already
	// held. duplicate=true returns the EXISTING row untouched except for its
	// submission count and last-seen time — deliberately, because that row
	// already owns whatever verification job exists, and a duplicate must
	// not be able to queue a second one.
	RecordAnomalyReport(ctx context.Context, row AnomalyReportRow, now time.Time) (stored AnomalyReportRow, duplicate bool, err error)
	// AnomalyReportByID reads one report.
	AnomalyReportByID(ctx context.Context, id int64) (AnomalyReportRow, bool, error)
	// AttachAnomalyVerificationJob binds a report to the job that will
	// answer it and moves it to that status.
	AttachAnomalyVerificationJob(ctx context.Context, id, jobID int64, status, unsupportedReason string) error
	// SetAnomalyVerdict closes a report. It is a no-op on a report that
	// already has a verdict: a second receipt for the same sample answers a
	// different question and must not rewrite an answer already given.
	SetAnomalyVerdict(ctx context.Context, id int64, verdict string, at time.Time) (bool, error)
	// OpenAnomalyReportsForSample lists the reports still waiting on a
	// verdict for one sample, oldest first.
	OpenAnomalyReportsForSample(ctx context.Context, sampleID string) ([]AnomalyReportRow, error)
	// ListAnomalyReports returns the newest reports for the operator view.
	ListAnomalyReports(ctx context.Context, limit int) ([]AnomalyReportRow, error)
	// AnomalyInsights aggregates the last `days` days.
	AnomalyInsights(ctx context.Context, now time.Time, days int) (AnomalyInsights, error)
}

AnomalyStore is the ingest and verdict half of the feedback channel.

It is part of Store rather than a side table with its own life, because the verdict path has to read verification jobs and receipts in the same transaction-shaped world those already live in.

type AnomalyVerdictCounts added in v0.1.46

type AnomalyVerdictCounts struct {
	Verdict string
	Count   int64
}

AnomalyVerdictCounts is one verdict bucket in the operator view.

type AuthoringAttempt added in v0.1.44

type AuthoringAttempt struct {
	At        time.Time        `json:"at"`
	Kind      string           `json:"kind"`
	SessionID string           `json:"sessionId"`
	Outcome   AuthoringOutcome `json:"outcome"`
	Detail    string           `json:"detail,omitempty"`
}

AuthoringAttempt is one entry of the bounded per-coordinate history. SessionID is the internal writer session, which is operator-private state and never leaves the admin surface.

type AuthoringAttemptState added in v0.1.44

type AuthoringAttemptState struct {
	Ecosystem string `json:"ecosystem"`
	Name      string `json:"name"`
	Version   string `json:"version"`
	Symbol    string `json:"symbol"`
	// Kind is the work kind of the most recent handout. Withholding is keyed
	// on the coordinate rather than on the kind because a package with no
	// callable symbol has none whichever queue picked it, and splitting the
	// key would let the same hopeless coordinate restart its count under
	// another kind. The kind stays on every history entry, so the record
	// still distinguishes them.
	Kind     string `json:"kind"`
	Attempts int    `json:"attempts"`
	// NoOutput counts attempts that produced nothing publishable and were not
	// excused, since the last attempt that did produce something.
	NoOutput int `json:"noOutput"`
	Authored int `json:"authored"`
	Excused  int `json:"excused"`
	// SessionsMeasuringImpossible is how many DISTINCT writers reported that
	// nothing callable can exist here.
	SessionsMeasuringImpossible int       `json:"sessionsMeasuringImpossible"`
	FirstAttemptAt              time.Time `json:"firstAttemptAt"`
	LastAttemptAt               time.Time `json:"lastAttemptAt"`
	QuarantinedAt               time.Time `json:"quarantinedAt,omitempty"`
	QuarantineReason            string    `json:"quarantineReason,omitempty"`
	// ReopensAt is when the withholding lapses by itself. Zero means it does
	// not: a measured impossibility does not heal, so only an operator lifts
	// that one.
	ReopensAt time.Time          `json:"reopensAt,omitempty"`
	History   []AuthoringAttempt `json:"history,omitempty"`
}

AuthoringAttemptState is everything remembered about one coordinate: why work was withheld, what the evidence was, and how old it is.

func (AuthoringAttemptState) Withheld added in v0.1.44

func (s AuthoringAttemptState) Withheld(now time.Time) bool

Withheld reports whether this coordinate is being kept off the board right now. It is deliberately pure: the picker and the operations panel both ask exactly this question of exactly this state, which is the only way the two can be made to agree.

type AuthoringDraftRow added in v0.1.16

type AuthoringDraftRow struct {
	SampleID           string
	SessionID          string
	WorkerLabel        string
	ManifestJSON       string
	LocalStatus        string
	VerificationStatus string
	CreatedAt          time.Time
	UpdatedAt          time.Time
}

AuthoringDraftRow is an internal, non-public sample uploaded by a sample worker. Its artifact is content-addressed in the server blob store, but it is not inserted into samples and therefore cannot appear in public search.

type AuthoringOutcome added in v0.1.44

type AuthoringOutcome string

AuthoringOutcome classifies one authoring attempt. The three failure classes are not interchangeable, and treating them as one is how a bad afternoon at a registry turns into a permanent exclusion.

const (
	// AuthoringHandedOut opens an attempt. It is recorded the moment a
	// coordinate is given to a writer, because the only thing the server can
	// observe unaided is that it gave the work out and got nothing back.
	AuthoringHandedOut AuthoringOutcome = "HANDED_OUT"
	// AuthoringAuthored is a sample actually written against the coordinate.
	// It answers the question and clears every counter that withholds work.
	AuthoringAuthored AuthoringOutcome = "AUTHORED"
	// AuthoringInfrastructure is the worker's own machine failing — no Docker
	// daemon, no disk, no route to this server. It measured nothing about the
	// coordinate and must not count against it.
	AuthoringInfrastructure AuthoringOutcome = "INFRASTRUCTURE"
	// AuthoringTransient is a registry or toolchain that would not answer. A
	// registry that will not answer has not said no.
	AuthoringTransient AuthoringOutcome = "TRANSIENT"
	// AuthoringNoCallableSymbol is the strong one: the writer looked and
	// measured that no symbol or project a contract could call exists here —
	// a pom with no jar, a marker artifact, a lone .node binary the parent
	// package selects internally.
	AuthoringNoCallableSymbol AuthoringOutcome = "NO_CALLABLE_SYMBOL"
	// AuthoringNoOutput is a writer that gave up without saying why. It is
	// already implied by the handout it closes and is accepted so a worker
	// can hand its slot back immediately instead of sitting on the lease.
	AuthoringNoOutput AuthoringOutcome = "NO_OUTPUT"
)

type AuthoringSessionRow added in v0.1.15

type AuthoringSessionRow struct {
	TokenHash     string
	SessionID     string
	Label         string
	Model         string
	Reasoning     string
	IssuedAt      time.Time
	LastRefreshAt time.Time
	IdleExpiresAt time.Time
	LastRefreshIP string
	ComputerName  string
	RevokedAt     time.Time
}

type AuthoringSessionStore added in v0.1.15

type AuthoringSessionStore interface {
	IssueAuthoringSessions(ctx context.Context, rows []AuthoringSessionRow, now time.Time) error
	RotateAuthoringSession(ctx context.Context, sessionID, tokenHash string, now, idleExpiresAt time.Time) (AuthoringSessionRow, error)
	RefreshAuthoringSession(ctx context.Context, tokenHash, ip, computerName string, now, idleExpiresAt time.Time) (AuthoringSessionRow, error)
	RevokeAuthoringSession(ctx context.Context, sessionID string, now time.Time) (bool, error)
	ListAuthoringSessions(ctx context.Context, now time.Time, limit int) ([]AuthoringSessionRow, error)
	SaveAuthoringDraft(ctx context.Context, row AuthoringDraftRow) error
	ListAuthoringDrafts(ctx context.Context, limit int) ([]AuthoringDraftRow, error)
	// ListAuthoringExpansionCandidates supplies ranked, exact public package
	// coordinates when every unresolved Wanted row is already being authored.
	// Failure-cluster symbols rank first, then observed package-version-symbol
	// coordinates that still have no independently verified sample.
	ListAuthoringExpansionCandidates(ctx context.Context, limit int) ([]WantedRow, error)
	ClaimAuthoringWork(ctx context.Context, sessionID string, candidates []WantedRow, now, leaseExpiresAt time.Time) (AuthoringWorkRow, bool, error)
	AuthoringWorkForSubmission(ctx context.Context, sessionID, sampleID string, now time.Time) (AuthoringWorkRow, bool, error)
	AttachAuthoringWorkSample(ctx context.Context, sessionID string, work AuthoringWorkRow, sampleID string, now time.Time) (bool, error)
	// ReportAuthoringOutcome records how the work this session holds turned
	// out and hands the claim back. It returns the released work and false
	// when the session holds nothing: a report can only speak for work the
	// writer actually has.
	ReportAuthoringOutcome(ctx context.Context, sessionID string, outcome AuthoringOutcome, detail string, now time.Time) (AuthoringWorkRow, bool, error)
	// ListAuthoringQuarantine returns the coordinates currently withheld from
	// authoring, newest withholding first, with the reason and the evidence.
	ListAuthoringQuarantine(ctx context.Context, now time.Time, limit int) ([]AuthoringAttemptState, error)
	// AuthoringAttemptState reads one coordinate's ledger, withheld or not.
	AuthoringAttemptState(ctx context.Context, ecosystem, name, version, symbol string) (AuthoringAttemptState, bool, error)
	// ReopenAuthoringQuarantine puts a withheld coordinate back on the board
	// and resets the counters that took it off. It returns false when nothing
	// was withheld, which is not an error.
	ReopenAuthoringQuarantine(ctx context.Context, ecosystem, name, version, symbol string, now time.Time) (bool, error)
}

AuthoringSessionStore keeps internal authoring sessions alive across server restarts while preserving their one-hour idle expiry and individual revoke boundary.

type AuthoringWorkRow added in v0.1.16

type AuthoringWorkRow struct {
	Ecosystem      string
	Name           string
	Version        string
	Symbol         string
	Asks           int64
	Kind           string
	Score          int64
	SessionID      string
	ClaimedAt      time.Time
	LeaseExpiresAt time.Time
	SampleID       string
}

type CSXIssueInsights added in v0.1.46

type CSXIssueInsights struct {
	WindowStart time.Time
	WindowEnd   time.Time

	Occurrences int64
	Unique      int64
	Duplicates  int64

	Triage       int64
	ReplayQueued int64
	NoReplayLane int64
	Resolved     int64

	Confirmed int64
	Linked    int64
}

CSXIssueInsights is the bounded operator view.

type CSXIssueReportRow added in v0.1.46

type CSXIssueReportRow struct {
	ID          int64
	Fingerprint string
	ReportJSON  string
	Surface     string
	IssueKind   string
	Component   string
	Status      string
	Verdict     string
	// ReplayReason says why nothing here can re-run it, when nothing can.
	ReplayReason string
	// CanonicalRef is the existing bug this defect belongs to, e.g.
	// "R2C-51". Set by an operator, never by a reporter: a reporter that
	// could name the ticket could also aim reports at it.
	CanonicalRef   string
	Occurrences    int64
	ReporterBucket string
	FirstSeen      time.Time
	LastSeen       time.Time
	VerdictAt      time.Time
}

CSXIssueReportRow is one stored product-defect candidate.

Occurrences is the field that makes the policy work. A defect many agents meet is ONE row whose count goes up — never a growing pile of tickets — and once an operator has linked that row to a canonical bug, every later occurrence answers with that link instead of creating anything.

type CSXIssueStore added in v0.1.46

type CSXIssueStore interface {
	// RecordCSXIssueReport stores a report or recognizes it as another
	// occurrence of one already held. duplicate=true returns the existing
	// row with its occurrence count incremented — including its canonical
	// ref, which is the answer a repeat reporter actually wants.
	RecordCSXIssueReport(ctx context.Context, row CSXIssueReportRow, now time.Time) (stored CSXIssueReportRow, duplicate bool, err error)
	CSXIssueReportByID(ctx context.Context, id int64) (CSXIssueReportRow, bool, error)
	// SetCSXIssueTriage records the replay decision for a report.
	SetCSXIssueTriage(ctx context.Context, id int64, status, replayReason string) error
	// SetCSXIssueVerdict closes a report. Like an anomaly verdict it never
	// overwrites one already given.
	SetCSXIssueVerdict(ctx context.Context, id int64, verdict string, at time.Time) (bool, error)
	// LinkCSXIssueCanonical attaches an existing bug reference. Only a
	// confirmed defect may be linked, which is enforced here rather than in
	// a handler so no second caller can forget it.
	LinkCSXIssueCanonical(ctx context.Context, id int64, ref string) (bool, error)
	ListCSXIssueReports(ctx context.Context, limit int) ([]CSXIssueReportRow, error)
	CSXIssueInsights(ctx context.Context, now time.Time, days int) (CSXIssueInsights, error)
}

CSXIssueStore is the product-defect half of the feedback channel.

It shares nothing with AnomalyStore after ingest, on purpose. An anomaly can become compatibility evidence; a product defect never can, and giving them one table would be the way that boundary eventually leaks.

type Changes added in v0.1.1

type Changes struct {
	Targets     []SnapshotTarget
	SamplePURLs []string
}

NetworkCounts are the honest headline numbers behind /v1/stats (goal.md §14.5). Estimated values are computed elsewhere and always labeled; these are raw counts only. Changes is everything that could have altered a materialized view since a given time: evidence targets whose rows were touched, author-declared packages of samples that changed, and exact package versions established by receipts.

Receipts are the complete signal for sample state: SetSampleStatus is only ever called from the receipt handler, so a status transition always has a receipt behind it and never needs its own timestamp column.

func (Changes) Empty added in v0.1.1

func (c Changes) Empty() bool

Empty reports that nothing moved, so a pass has no work beyond stats.

type ClassPoolStats added in v0.1.45

type ClassPoolStats struct {
	Class     string
	Limit     int    // connections this class may hold at once
	InUse     int    // held right now
	Acquired  uint64 // successful acquisitions
	Waited    uint64 // acquisitions that could not be served immediately
	WaitTotal time.Duration
	WaitMax   time.Duration
	Busy      uint64 // refused: ErrPoolBusy
	Timeouts  uint64 // statements PostgreSQL cancelled on this class's ceiling
}

ClassPoolStats is one class's share of the pool and what it has cost.

type ClusterRow

type ClusterRow struct {
	ID                    int64
	Ecosystem             string
	PackageName           string
	Symbol                string
	Stage                 string
	ErrorFingerprint      string
	ErrorCode             string
	TerminationKind       string
	ExitCode              *int
	Signal                string
	TimeoutMillis         int64
	ErrorSummary          string
	EvidenceQuality       string
	OuterCommands         []string
	ActualToolchain       string
	StageEvidence         string
	FailureEvidenceGap    string
	ObservationCount      int64
	EnvSummaryJSON        string
	EnvVariantsJSON       string
	EvidenceBreakdownJSON string
	HypothesesJSON        string // [{domain,confidence}] — never a definitive cause
	RegressionCandidate   bool
	DiagnosticCandidate   bool
	VersionsJSON          string
	FirstSeen             time.Time
	LastSeen              time.Time
}

ClusterRow is one failure_clusters-table row.

type DependencyEdge added in v0.1.32

type DependencyEdge struct {
	ParentName    string
	ParentVersion string
	ChildName     string
	ChildVersion  string
	Projects      int
}

DependencyEdge is one "this package pulled that version of that library" relationship, as the machine holding the lockfile saw it.

VersionCoresidence says two versions of a library were installed together. That is the half of the answer nobody can act on; this is the other half — which dependency wanted which version, which is the thing a person moves to fix the build.

Projects counts distinct project-days, not rebuilds.

type EvidenceRow

type EvidenceRow struct {
	PURL                 string
	Symbol               string
	SymbolConfidence     string
	EnvHash              string
	EnvJSON              string
	Stage                string
	Result               string
	ErrorFingerprint     string
	ErrorCode            string
	TerminationKind      string
	ExitCode             *int
	Signal               string
	TimeoutMillis        int64
	ErrorSummary         string
	EvidenceQuality      string
	OuterCommand         string
	OuterCommands        []string
	OuterStage           string
	ActualToolchain      string
	StageEvidence        string
	FailureEvidenceGap   string
	ObservationCount     int64
	UniquePeerBuckets    int
	UniqueProjectBuckets int
	// Direct: at least one reporter listed this package in their own
	// manifest rather than receiving it through somebody else's.
	Direct    bool
	FirstSeen time.Time
	LastSeen  time.Time
}

EvidenceRow is one aggregated evidence_agg row.

type Fake

type Fake struct {

	// NowFn is the test seam for time-dependent behavior; nil means time.Now.
	NowFn func() time.Time
	// ChangedSinceFn overrides change detection. The fake keeps no per-row
	// timestamps, so incremental-rebuild tests script it directly.
	ChangedSinceFn func(context.Context, time.Time) (Changes, error)
	// contains filtered or unexported fields
}

Fake is a complete in-memory Store implementation. Handler and builder tests (and e2e harnesses that want a server without PostgreSQL) use it; its ingest semantics are the mergeState reference implementation that pg.go is held to, so both stores behave identically.

func NewFake

func NewFake() *Fake

NewFake returns an empty in-memory Store.

func (*Fake) AdoptionSummary added in v0.1.4

func (f *Fake) AdoptionSummary(_ context.Context) (AdoptionCounts, error)

func (*Fake) AnnouncePeer

func (f *Fake) AnnouncePeer(_ context.Context, p PeerRow) error

func (*Fake) AnomalyInsights added in v0.1.46

func (f *Fake) AnomalyInsights(_ context.Context, now time.Time, days int) (AnomalyInsights, error)

func (*Fake) AnomalyReportByID added in v0.1.46

func (f *Fake) AnomalyReportByID(_ context.Context, id int64) (AnomalyReportRow, bool, error)

func (*Fake) AttachAnomalyVerificationJob added in v0.1.46

func (f *Fake) AttachAnomalyVerificationJob(_ context.Context, id, jobID int64, status, unsupportedReason string) error

func (*Fake) AttachAuthoringWorkSample added in v0.1.16

func (f *Fake) AttachAuthoringWorkSample(_ context.Context, sessionID string, work AuthoringWorkRow, sampleID string, now time.Time) (bool, error)

func (*Fake) AuthoringAttemptState added in v0.1.44

func (f *Fake) AuthoringAttemptState(_ context.Context, ecosystem, name, version, symbol string) (AuthoringAttemptState, bool, error)

func (*Fake) AuthoringWorkForSubmission added in v0.1.16

func (f *Fake) AuthoringWorkForSubmission(_ context.Context, sessionID, sampleID string, now time.Time) (AuthoringWorkRow, bool, error)

func (*Fake) CSXIssueInsights added in v0.1.46

func (f *Fake) CSXIssueInsights(_ context.Context, now time.Time, days int) (CSXIssueInsights, error)

func (*Fake) CSXIssueReportByID added in v0.1.46

func (f *Fake) CSXIssueReportByID(_ context.Context, id int64) (CSXIssueReportRow, bool, error)

func (*Fake) ChangedSince added in v0.1.1

func (f *Fake) ChangedSince(ctx context.Context, since time.Time) (Changes, error)

ChangedSince reports everything as changed. The fake keeps no per-row timestamps, and over-reporting is the safe direction: a builder test then exercises the full path, and no test can pass because a change was silently missed.

func (*Fake) ClaimAuthoringWork added in v0.1.16

func (f *Fake) ClaimAuthoringWork(_ context.Context, sessionID string, candidates []WantedRow, now, leaseExpiresAt time.Time) (AuthoringWorkRow, bool, error)

func (*Fake) ClaimJob

func (f *Fake) ClaimJob(_ context.Context, id int64, peerID string) (bool, error)

func (*Fake) Close

func (f *Fake) Close()

Close implements Store; the fake has nothing to release.

func (*Fake) CompleteJob

func (f *Fake) CompleteJob(_ context.Context, id int64) error

func (*Fake) CompleteJobsForSample added in v0.1.4

func (f *Fake) CompleteJobsForSample(_ context.Context, sampleID, peerID string) error

func (*Fake) CreateJob

func (f *Fake) CreateJob(_ context.Context, j JobRow) (int64, error)

func (*Fake) CrossJobsForLaneReview added in v0.1.45

func (f *Fake) CrossJobsForLaneReview(_ context.Context, limit int) ([]JobRow, error)

func (*Fake) DeleteSnapshots added in v0.1.5

func (f *Fake) DeleteSnapshots(_ context.Context, targets []SnapshotTarget) error

func (*Fake) Dependants added in v0.1.32

func (f *Fake) Dependants(_ context.Context, ecosystem, name string) ([]DependencyEdge, error)

Dependants lists what pulled each version of one library.

func (*Fake) Dependencies added in v0.1.33

func (f *Fake) Dependencies(_ context.Context, ecosystem, name string) ([]DependencyEdge, error)

Dependencies lists what shipped ALONGSIDE each version of one package.

Upgrade a library and its dependencies move under you; the one that moved is usually the one that broke the build. Same table as Dependants, read from the parent end.

func (*Fake) EnsureCrossJob added in v0.1.46

func (f *Fake) EnsureCrossJob(_ context.Context, j JobRow) (int64, error)

func (*Fake) EvidenceForTarget

func (f *Fake) EvidenceForTarget(_ context.Context, purl, symbol string) ([]EvidenceRow, error)

func (*Fake) ExpirePeers

func (f *Fake) ExpirePeers(_ context.Context, now time.Time) (int64, error)

func (*Fake) FarmBacklogNow added in v0.1.44

func (f *Fake) FarmBacklogNow(_ context.Context, since, now time.Time) (FarmBacklog, error)

func (*Fake) FarmCompletenessNow added in v0.1.46

func (f *Fake) FarmCompletenessNow(_ context.Context) (FarmCompleteness, error)

FarmCompletenessNow counts every PUBLIC release by which of Sample, Evidence and Dependency it holds. The PG half is the same six predicates in one query; TestIntegrationFarmCompletenessMatchesPostgres holds them together.

func (*Fake) FarmCoverage added in v0.1.25

func (f *Fake) FarmCoverage(_ context.Context) ([]FarmAxisCoverage, error)

func (*Fake) FarmHealthNow added in v0.1.21

func (f *Fake) FarmHealthNow(_ context.Context, now time.Time) (FarmHealth, error)

func (*Fake) FarmWorkers added in v0.1.21

func (f *Fake) FarmWorkers(_ context.Context, since, now time.Time) ([]FarmWorker, error)

func (*Fake) GetLatestStats

func (f *Fake) GetLatestStats(_ context.Context) (string, bool, error)

func (*Fake) GetPackage

func (f *Fake) GetPackage(_ context.Context, purl string) (PackageRow, bool, error)

func (*Fake) GetSample

func (f *Fake) GetSample(_ context.Context, sampleID string) (SampleRow, bool, error)

func (*Fake) GetShard

func (f *Fake) GetShard(_ context.Context, key string) (string, string, bool, error)

func (*Fake) GetShardEtag added in v0.1.35

func (f *Fake) GetShardEtag(_ context.Context, key string) (string, bool, error)

func (*Fake) GetSnapshot

func (f *Fake) GetSnapshot(_ context.Context, purl, symbol string) (string, bool, error)

func (*Fake) HotShardKeys

func (f *Fake) HotShardKeys(_ context.Context, limit int) ([]string, error)

HotShardKeys returns the stored keys in sorted order — the fake has no traffic model, only determinism.

func (*Fake) IdentityByAPIToken

func (f *Fake) IdentityByAPIToken(_ context.Context, apiTokenHash string) (IdentityRow, bool, error)

func (*Fake) IngestBatches

func (f *Fake) IngestBatches(_ context.Context, batches []domain.ObservationBatch) (int, []RejectedBatch, error)

IngestBatches mirrors PG.IngestBatches: validate, then delta-merge.

func (*Fake) IssueAdminTokens added in v0.1.21

func (f *Fake) IssueAdminTokens(_ context.Context, rows []AdminTokenRow) error

func (*Fake) IssueAuthoringSessions added in v0.1.15

func (f *Fake) IssueAuthoringSessions(_ context.Context, rows []AuthoringSessionRow, now time.Time) error

func (*Fake) Job added in v0.1.12

func (f *Fake) Job(_ context.Context, id int64) (JobRow, bool, error)

func (*Fake) JobsForSample

func (f *Fake) JobsForSample(_ context.Context, sampleID string) ([]JobRow, error)

func (*Fake) LinkCSXIssueCanonical added in v0.1.46

func (f *Fake) LinkCSXIssueCanonical(_ context.Context, id int64, ref string) (bool, error)

func (*Fake) ListAdminTokens added in v0.1.21

func (f *Fake) ListAdminTokens(_ context.Context, limit int) ([]AdminTokenRow, error)

func (*Fake) ListAnomalyReports added in v0.1.46

func (f *Fake) ListAnomalyReports(_ context.Context, limit int) ([]AnomalyReportRow, error)

func (*Fake) ListAuthoringDrafts added in v0.1.16

func (f *Fake) ListAuthoringDrafts(_ context.Context, limit int) ([]AuthoringDraftRow, error)

func (*Fake) ListAuthoringExpansionCandidates added in v0.1.19

func (f *Fake) ListAuthoringExpansionCandidates(_ context.Context, limit int) ([]WantedRow, error)

func (*Fake) ListAuthoringQuarantine added in v0.1.44

func (f *Fake) ListAuthoringQuarantine(_ context.Context, now time.Time, limit int) ([]AuthoringAttemptState, error)

func (*Fake) ListAuthoringSessions added in v0.1.15

func (f *Fake) ListAuthoringSessions(_ context.Context, now time.Time, limit int) ([]AuthoringSessionRow, error)

func (*Fake) ListCSXIssueReports added in v0.1.46

func (f *Fake) ListCSXIssueReports(_ context.Context, limit int) ([]CSXIssueReportRow, error)

func (*Fake) ListFailureClusters

func (f *Fake) ListFailureClusters(_ context.Context, packageName string) ([]ClusterRow, error)

func (*Fake) ListFailureClustersIncludingPreserved added in v0.1.45

func (f *Fake) ListFailureClustersIncludingPreserved(_ context.Context, packageName string) ([]ClusterRow, error)

ListFailureClustersIncludingPreserved mirrors the PostgreSQL read of the same name: exact failure matching still needs the pre-0024 fingerprints.

func (*Fake) ListPackageVersions

func (f *Fake) ListPackageVersions(_ context.Context, ecosystem, name string) ([]PackageRow, error)

func (*Fake) ListSamples

func (f *Fake) ListSamples(_ context.Context, limit int) ([]SampleRow, error)

func (*Fake) ListSamplesPage added in v0.1.4

func (f *Fake) ListSamplesPage(ctx context.Context, limit, offset int) ([]SampleRow, error)

ListSamplesPage is ListSamples with an offset.

func (*Fake) ListSnapshotTargets

func (f *Fake) ListSnapshotTargets(_ context.Context) ([]SnapshotTarget, error)

func (*Fake) ListSnapshots added in v0.1.5

func (f *Fake) ListSnapshots(_ context.Context) ([]SnapshotRow, error)

func (*Fake) ListVerifiedBeliefSamples added in v0.1.45

func (f *Fake) ListVerifiedBeliefSamples(ctx context.Context, after SampleCursor, limit int) ([]SampleRow, error)

ListVerifiedBeliefSamples mirrors the PG query, keyset and all, so a test written against the Fake proves something about the server.

The ordering is the SQL's: newest first, with sample_id DESC as the tiebreak, because that pair is what the cursor compares. A missing created_at sorts as the epoch here for the same reason it does there.

func (*Fake) ListVerifiedSamples added in v0.1.5

func (f *Fake) ListVerifiedSamples(ctx context.Context, limit int) ([]SampleRow, error)

func (*Fake) ListWanted added in v0.1.6

func (f *Fake) ListWanted(_ context.Context, query string, offset, limit int) ([]WantedRow, int, error)

func (*Fake) NetworkCounts

func (f *Fake) NetworkCounts(_ context.Context, now time.Time) (NetworkCounts, error)

func (*Fake) OpenAnomalyReportsForSample added in v0.1.46

func (f *Fake) OpenAnomalyReportsForSample(_ context.Context, sampleID string) ([]AnomalyReportRow, error)

func (*Fake) OpenJobs

func (f *Fake) OpenJobs(ctx context.Context, capability, peerID, reason string, limit int) ([]JobRow, error)

func (*Fake) OpenJobsPage added in v0.1.12

func (f *Fake) OpenJobsPage(_ context.Context, capability, peerID, reason, verifierOS string, limit, offset int) ([]JobRow, error)

func (*Fake) PeersForSample

func (f *Fake) PeersForSample(_ context.Context, sampleID string) ([]PeerRow, error)

func (*Fake) PurgeDedupOlderThan

func (f *Fake) PurgeDedupOlderThan(_ context.Context, days int) (int64, error)

PurgeDedupOlderThan drops rotating dedup ledger entries older than the retention window; accumulated counts and unique-bucket sets stay frozen, matching pg.go.

func (*Fake) PutShard

func (f *Fake) PutShard(_ context.Context, key, etag, shardJSON string) error

func (*Fake) PutSnapshot

func (f *Fake) PutSnapshot(_ context.Context, purl, symbol, snapshotJSON string) error

func (*Fake) ReceiptsForSample

func (f *Fake) ReceiptsForSample(_ context.Context, sampleID string) ([]ReceiptRow, error)

func (*Fake) RecordAdoption added in v0.1.4

func (f *Fake) RecordAdoption(_ context.Context, r AdoptionRow) error

func (*Fake) RecordAnomalyReport added in v0.1.46

func (f *Fake) RecordAnomalyReport(_ context.Context, row AnomalyReportRow, now time.Time) (AnomalyReportRow, bool, error)

func (*Fake) RecordCSXIssueReport added in v0.1.46

func (f *Fake) RecordCSXIssueReport(_ context.Context, row CSXIssueReportRow, now time.Time) (CSXIssueReportRow, bool, error)

func (*Fake) RecordSearchHit added in v0.1.37

func (f *Fake) RecordSearchHit(_ context.Context, r SearchHitRow) error

RecordSearchHit counts one search that found something, deduplicated the way postgres does: once per reporter per offer per day.

func (*Fake) RecordWanted added in v0.1.4

func (f *Fake) RecordWanted(ctx context.Context, epoch, anonID string, rows []WantedRow) error

func (*Fake) RecordWantedBatch added in v0.1.5

func (f *Fake) RecordWantedBatch(_ context.Context, reports []WantedSubmission) error

func (*Fake) RefreshAuthoringSession added in v0.1.15

func (f *Fake) RefreshAuthoringSession(_ context.Context, tokenHash, ip, computerName string, now, idleExpiresAt time.Time) (AuthoringSessionRow, error)

func (*Fake) ReopenAuthoringQuarantine added in v0.1.44

func (f *Fake) ReopenAuthoringQuarantine(_ context.Context, ecosystem, name, version, symbol string, now time.Time) (bool, error)

func (*Fake) ReportAuthoringOutcome added in v0.1.44

func (f *Fake) ReportAuthoringOutcome(_ context.Context, sessionID string, outcome AuthoringOutcome, detail string, now time.Time) (AuthoringWorkRow, bool, error)

func (*Fake) ResolveAdminToken added in v0.1.21

func (f *Fake) ResolveAdminToken(_ context.Context, tokenHash, ip string, now time.Time) (AdminTokenRow, bool, error)

func (*Fake) RevokeAdminToken added in v0.1.21

func (f *Fake) RevokeAdminToken(_ context.Context, tokenID string, now time.Time) (bool, error)

func (*Fake) RevokeAuthoringSession added in v0.1.15

func (f *Fake) RevokeAuthoringSession(_ context.Context, sessionID string, now time.Time) (bool, error)

func (*Fake) RotateAuthoringSession added in v0.1.16

func (f *Fake) RotateAuthoringSession(_ context.Context, sessionID, tokenHash string, now, idleExpiresAt time.Time) (AuthoringSessionRow, error)

func (*Fake) SamplesBySeeder added in v0.1.4

func (f *Fake) SamplesBySeeder(ctx context.Context, login string, limit int) ([]SampleRow, error)

SamplesBySeeder lists one seeder's live samples, newest first.

func (*Fake) SamplesForPackages added in v0.1.2

func (f *Fake) SamplesForPackages(ctx context.Context, patterns []string, limit int) ([]SampleRow, error)

SamplesForPackages filters the fake's samples by package prefix, mirroring the SQL LIKE ANY match.

func (*Fake) SaveAuthoringDraft added in v0.1.16

func (f *Fake) SaveAuthoringDraft(_ context.Context, row AuthoringDraftRow) error

func (*Fake) SaveCase

func (f *Fake) SaveCase(_ context.Context, c domain.Case) error

func (*Fake) SaveIdentity

func (f *Fake) SaveIdentity(_ context.Context, login string, githubID int64, tokenHash, apiTokenHash string) error

func (*Fake) SaveReceipt

func (f *Fake) SaveReceipt(_ context.Context, r ReceiptRow) error

func (*Fake) SaveReceiptForJob added in v0.1.12

func (f *Fake) SaveReceiptForJob(_ context.Context, r ReceiptRow, jobID int64) (bool, error)

func (*Fake) SaveSample

func (f *Fake) SaveSample(_ context.Context, s SampleRow) error

func (*Fake) SetAnomalyVerdict added in v0.1.46

func (f *Fake) SetAnomalyVerdict(_ context.Context, id int64, verdict string, at time.Time) (bool, error)

func (*Fake) SetCSXIssueTriage added in v0.1.46

func (f *Fake) SetCSXIssueTriage(_ context.Context, id int64, status, replayReason string) error

func (*Fake) SetCSXIssueVerdict added in v0.1.46

func (f *Fake) SetCSXIssueVerdict(_ context.Context, id int64, verdict string, at time.Time) (bool, error)

func (*Fake) SetJobRequirements added in v0.1.45

func (f *Fake) SetJobRequirements(_ context.Context, id int64, wantEnvJSON, status string) error

func (*Fake) SetSampleQuarantine added in v0.1.2

func (f *Fake) SetSampleQuarantine(_ context.Context, sampleID string, on bool, reason string) error

func (*Fake) SetSampleStatus

func (f *Fake) SetSampleStatus(_ context.Context, sampleID, status string) error

func (*Fake) SetStatsDaily

func (f *Fake) SetStatsDaily(_ context.Context, day string, statsJSON string) error

func (*Fake) ShardKeys added in v0.1.4

func (f *Fake) ShardKeys(_ context.Context) ([]string, error)

ShardKeys lists the stored keys in sorted order.

func (*Fake) ShardWrites added in v0.1.1

func (f *Fake) ShardWrites() int

ShardWrites counts PutShard calls so tests can assert that an idle aggregation pass does no work — the whole point of incremental rebuilds.

func (*Fake) SnapshotKeys added in v0.1.5

func (f *Fake) SnapshotKeys(_ context.Context) ([]SnapshotTarget, error)

func (*Fake) SnapshotUpdatedAt added in v0.1.21

func (f *Fake) SnapshotUpdatedAt(_ context.Context) (map[string]time.Time, error)

func (*Fake) StrandedDrafts added in v0.1.29

func (f *Fake) StrandedDrafts(_ context.Context, maxAttempts, limit int) ([]string, error)

StrandedDrafts lists quarantined authoring drafts that have no verification left to wait for: no passing receipt, no open or claimed job, and fewer than maxAttempts cross jobs already spent.

func (*Fake) TopWanted added in v0.1.4

func (f *Fake) TopWanted(_ context.Context, limit int) ([]WantedRow, error)

func (*Fake) UpsertFailureCluster

func (f *Fake) UpsertFailureCluster(_ context.Context, c ClusterRow) error

func (*Fake) UpsertPackage

func (f *Fake) UpsertPackage(_ context.Context, p PackageRow) error

func (*Fake) VerifiedSampleCodeCounts added in v0.1.46

func (f *Fake) VerifiedSampleCodeCounts(_ context.Context, packagePrefix string) ([]VerifiedSampleCodeCount, error)

func (*Fake) VerifiedSamplesForPackages added in v0.1.5

func (f *Fake) VerifiedSamplesForPackages(ctx context.Context, patterns []string, limit int) ([]SampleRow, error)

func (*Fake) VersionCoresidence added in v0.1.31

func (f *Fake) VersionCoresidence(_ context.Context, ecosystem, name string) ([]VersionCoresidence, error)

VersionCoresidence lists the version pairs of one library that a scanner saw in a single resolution.

func (*Fake) WantedForPackage added in v0.1.5

func (f *Fake) WantedForPackage(_ context.Context, ecosystem, name string) ([]WantedRow, error)

type FarmAxisCoverage added in v0.1.25

type FarmAxisCoverage struct {
	OS        string
	Ecosystem string
	// Observed is distinct public purls that developer machines reported
	// using on this OS. Relayed, never graded.
	Observed int
	// Measured is distinct public purls the fleet actually RAN on this OS,
	// pass or fail. A failed run is a measurement of this platform, and
	// counting only passes made "we ran it here and it broke" read the same
	// as "we never came here" -- the exact collapse this panel exists to
	// prevent.
	Measured int
	// Proven is the subset of Measured whose run reached a contract PASS.
	Proven int
	// ObservedProven is |Observed AND Proven|: of what we see used here, how
	// much have we actually proven here. It is a separate field rather than
	// a re-reading of Proven because that ambiguity is precisely what made
	// the Fake and the PG store disagree -- the Fake intersected, the SQL
	// did not, and the doc comment claimed the intersection.
	ObservedProven int
}

FarmAxisCoverage is one (os, ecosystem) cell of the compatibility map: how many public packages the network has seen used there, against how many it has actually proven there.

The gap is the point. Observations come from developer machines and verifications come from containers, so an ecosystem can be heavily used on one platform and proven only on another — which is precisely what this network exists to notice about itself.

type FarmBacklog added in v0.1.44

type FarmBacklog struct {
	// CoverageHoles is how many PUBLIC coordinates carry evidence and no
	// passing sample: the `-` cells, counted.
	CoverageHoles int
	// Dependencies is how many coordinates are reachable only through a
	// resolved dependency edge and still carry no evidence and no proof.
	//
	// It is the WHOLE backlog, not the bounded slice one scheduling pass
	// offers. A backlog reported at its own cap reads as finished work.
	Dependencies int
	// ClaimedByKind is work handed out inside the window, by queue source.
	// This is the generation rate: what the scheduler actually produced,
	// rather than what it could have.
	ClaimedByKind map[string]int
	// FirstProven is how many coordinates earned their first passing receipt
	// inside the window -- the resolution rate.
	//
	// First, not any: re-proving a coordinate on another platform is real
	// work and real evidence, but it does not take anything off the backlog
	// above, and a rate that counted it would never square with a stock that
	// does not.
	FirstProven int
	// Matrix is the same absence counted at the grain a reader sees it.
	//
	// CoverageHoles above is per RELEASE: a purl either has a passing sample
	// or it does not. A package page is not drawn at that grain -- it spreads
	// symbol against version -- so a release counted as proven can render a
	// page that is almost entirely dashes, and in production it does. The two
	// numbers are both true and they are not the same number, so they are
	// reported side by side rather than one standing in for the other.
	Matrix MatrixCells
}

FarmBacklog is the coverage gap the queue is working through, and how fast it is moving through it.

The farm panel could say how much had been proven and nothing at all about how much was left, so "the fleet is busy" and "the fleet is nearly done" looked identical -- and a queue that generates its own work can be busy forever. These are the two stocks and the two flows.

A `-` cell and an unopened dependency are counted apart on purpose. They are different absences: one is a package the network watches people use and has never proven, the other is a release nobody has reported at all and that only a resolved lockfile even names. Pooling them would hide which of the two the fleet is actually failing to drain.

type FarmCompleteness added in v0.1.46

type FarmCompleteness struct {
	// States is the eight-cell matrix, keyed by completenessStates. Always
	// eight entries.
	States map[string]int
	// The dependency axis split three ways. These sum to the same total as
	// States, because every coordinate is in exactly one of each.
	//
	// ProvenNone is reported separately from Unknown even while nothing can
	// produce it. A field that is absent until it has a value is a field
	// nobody notices arriving, and this is the one number that says whether
	// the network can tell "no dependencies" from "we never looked".
	DependencyGraph      int
	DependencyProvenNone int
	DependencyUnknown    int
}

FarmCompleteness is every verifiable coordinate counted by which of the three assets it holds.

type FarmCompletenessStore added in v0.1.46

type FarmCompletenessStore interface {
	FarmCompletenessNow(ctx context.Context) (FarmCompleteness, error)
}

FarmCompletenessStore counts the corpus by three-axis completeness. It is the stock the scheduler is judged against: NO_WORK is only honest when every cell but SED is empty of coordinates the current policy can run.

type FarmHealth added in v0.1.21

type FarmHealth struct {
	PublicSamples   int
	DuplicateCoords int // coordinates carrying more than one public sample
	StaleClaims     int // open claims whose session is no longer live
	// QuarantinedByReason is why things were withdrawn, counted by reason.
	//
	// Every withdrawal already recorded one; none of it reached the operator,
	// so seeing why anything was pulled meant opening a database. A bare
	// count cannot be acted on -- "983 quarantined" is alarming and "983
	// duplicate coordinates, superseded" is a finished piece of work. The
	// empty key is deliberate: a withdrawal nobody explained is the row most
	// worth surfacing.
	QuarantinedByReason map[string]int
	ReceiptsByOS        map[string]int // PASS receipts per operating system
	// WithheldCoordinates is how many public coordinates the authoring queue
	// is currently refusing to offer, and WithheldByReason is why.
	//
	// They are read from exactly the state the picker consults, because an
	// operator reading "0 withheld" while the fleet is being refused work is
	// the failure the attempt ledger exists to make visible.
	WithheldCoordinates int
	WithheldByReason    map[string]int
	// UnsupportedJobs is verification work no verifier image in this build
	// can run, and it exists because the absence of this number cost three
	// days. The open cross queue held rows every worker skipped before
	// claiming; the panel showed work, the workers reported none, and both
	// were telling the truth. An operator reading a queue depth needs to
	// know which part of it no machine can take.
	UnsupportedJobs int
}

FarmHealth is what the network looks like as a whole.

DuplicateCoords is the one that matters most: it sat at 37% for a day without appearing anywhere an operator could see it.

type FarmStatsStore added in v0.1.21

type FarmStatsStore interface {
	FarmCoverage(ctx context.Context) ([]FarmAxisCoverage, error)
	FarmWorkers(ctx context.Context, since, now time.Time) ([]FarmWorker, error)
	FarmHealthNow(ctx context.Context, now time.Time) (FarmHealth, error)
	// FarmBacklogNow reports the coverage gap now and the flow through it
	// since. The window is the caller's so the panel can keep one window for
	// every rate it shows.
	FarmBacklogNow(ctx context.Context, since, now time.Time) (FarmBacklog, error)
	// FarmCompletenessNow reports the three-axis stock: every verifiable
	// coordinate by which of Sample, Evidence and Dependency it holds. No
	// window -- it is a stock, and the flows beside it carry their own.
	FarmCompletenessStore
}

FarmStatsStore reports the farm's state for the operations dashboard.

type FarmWorker added in v0.1.21

type FarmWorker struct {
	Label         string
	ComputerName  string // reported by the worker itself; "" until it refreshes
	IssuedAt      time.Time
	LastRefreshAt time.Time // zero = never came alive
	IdleExpiresAt time.Time
	Drafts        int    // submitted inside the window
	Published     int    // of those, now public
	Holding       string // the coordinate it currently claims; "" if none
}

FarmWorker is one live authoring session and what it has actually produced.

The fields are the ones that would have caught the failures this dashboard exists for: a session issued but never refreshed (a worker that failed to start), and a worker whose draft count stops moving.

type IdentityRow

type IdentityRow struct {
	Login        string
	GithubID     int64
	Display      string
	TokenHash    string
	APITokenHash string
	CreatedAt    time.Time
}

IdentityRow is one identities-table row (persistent seeder/verifier identity; automatic evidence never uses these).

type JobRow

type JobRow struct {
	ID          int64
	SampleID    string
	Reason      string // "cross" | "matrix"
	WantEnvJSON string // "" ⇒ NULL (any environment)
	Status      string // open | claimed | done | unsupported
	ClaimedBy   string
	ClaimedAt   time.Time
	CreatedAt   time.Time
}

JobRow is one verification_jobs-table row.

type MatrixCells added in v0.1.46

type MatrixCells struct {
	// Cells is the denominator: symbol x version cells across every PUBLIC
	// package with a symbol grid. Non-public coordinates are left out for the
	// same reason CoverageHoles leaves them out -- the queue may not offer
	// them, so they are not a backlog anybody can work off.
	Cells int
	// Observed is cells with at least one observation. This is the number
	// R2C-89's completion criterion is written against.
	Observed int
	// VerifiedNoObservation is a coordinate where a sample of ours passed
	// and no project build has been attributed to it. It is reported apart
	// from Observed and never added to it -- an observation and a
	// verification are different classes of evidence and this repository does
	// not sum them (goal.md §3.5, and the snapshot builder says so in as many
	// words).
	VerifiedNoObservation int
	// Unmeasured is an inferred corpus cell: the symbol exists at some other
	// release, with nothing recorded at this one.
	Unmeasured int
	// PackagesShowingBothDashes is the legacy JSON name for how many packages
	// contain both a passed-verification-only coordinate and an unmeasured
	// coordinate in the corpus. It does not claim both coordinates survive
	// the UI's bounded browse window at the same time.
	PackagesShowingBothDashes int
}

MatrixCells is the PUBLIC compatibility corpus counted at symbol x version grain.

R2C-89 asks a question the farm panel could not answer: how many canonical symbol x version coordinates carry an observation. Every stock the panel held before this was counted per RELEASE -- a purl either had a passing sample or it did not. The grain is the whole disagreement: one release with forty known symbols is forty corpus cells, and thirty-nine of them can be empty while the release counts as proven.

This deliberately counts the unbounded corpus cross product -- every symbol the network knows for a package against every release of it that has a snapshot. It is not the bounded browse window: the package UI currently reads at most six releases and ten symbols per release, then caps its axes again. Those display limits must not make older canonical coordinates disappear from the completeness denominator.

Each corpus cell falls in one of three states:

  • Observed. A real project build reached this coordinate. This is the only state R2C-89 counts as covered.
  • VerifiedNoObservation. We wrote a sample, it passed here, and no project build has been attributed to the coordinate. The page renders "≡ —": a mark, and a dash where the rate would go. It is a LINK, because the cell holds a document.
  • Unmeasured. Nothing at all: no evidence row, no sample. The page renders a plain, unlinked "—".

The two dashes read the same to a reader and come from opposite causes, and the issue's own reproduction is a page that shows both at once -- which is why PackagesShowingBothDashes is counted rather than inferred.

This is an instrument, not a queue. Nothing here hands work out: the scheduler's sources are unchanged, and what to DO about each state is the open product question recorded on R2C-89. A number that tells an operator which of the three is growing is worth having before that is answered, and the same census is what will judge the answer afterwards.

type Migration

type Migration struct {
	Version    string
	Statements []string
}

Migration is one embedded .sql file, split into executable statements. Version is the file name; lexicographic order is execution order (0001_..., 0002_...).

func LoadMigrations

func LoadMigrations() ([]Migration, error)

LoadMigrations reads the embedded migrations directory in order.

type NetworkCounts

type NetworkCounts struct {
	// Peers is the distinct anonymous peer buckets that contributed
	// evidence in the current epoch: who is actually using the network
	// today. Buckets rotate daily (goal.md §8.6), so a longer window
	// would count one person many times.
	Peers int64
	// ProjectsMonth is the distinct project buckets seen this calendar
	// month. Those buckets rotate MONTHLY rather than daily, so counting
	// them over the month is the longest honest participation window the
	// identity scheme allows — a peer id summed across days would count
	// one person once per day and report thirty where there is one.
	ProjectsMonth   int64
	Packages        int64 // distinct (ecosystem, name) pairs
	Symbols         int64 // distinct non-empty symbol families with evidence
	Observations    int64 // total aggregated observation count
	VerifiedSamples int64 // contract-verified or independently reproduced
	// ServingPeers is the P2P blob tracker population — nodes that opted
	// into peerListen. Most peers contribute evidence without ever
	// serving blobs, so this is much smaller and is not the headline.
	ServingPeers int64
}

type PG

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

PG implements Store on PostgreSQL via pgx/v5.

It manages its own small *pgx.Conn pool (pool.go) instead of pgxpool: the repo pins its dependency set and pgxpool's puddle dependency is not part of it. The pool is deliberately tiny — the production target is a 2GB VM with max_connections 40 — which is exactly why what a caller is allowed to do with a connection is bounded per class; see PoolPolicy.

func Open

func Open(ctx context.Context, dsn string) (*PG, error)

Open connects to PostgreSQL and returns a ready Store under the shipped pool policy. It validates the DSN and dials one connection eagerly so misconfiguration fails fast.

func OpenWithPolicy added in v0.1.45

func OpenWithPolicy(ctx context.Context, dsn string, pol PoolPolicy) (*PG, error)

OpenWithPolicy is Open with the timeout and admission policy named explicitly. csx-server passes what the environment configured; everything else wants Open.

func (*PG) ActivityCounts added in v0.1.6

func (p *PG) ActivityCounts(ctx context.Context, dayEpoch, monthEpoch string) (activity.Counts, error)

func (*PG) ActivityDaily added in v0.1.6

func (p *PG) ActivityDaily(ctx context.Context, fromEpoch, toEpoch string) (activity.DailyRaw, error)

ActivityDaily backs the daily chart. A bounded daily health marker makes a healthy zero distinguishable from both a collection gap and a day before collection. Bucket rows remain separate so traffic proves collection even for an epoch created before health markers were introduced.

func (*PG) AdminInsights added in v0.1.6

func (p *PG) AdminInsights(ctx context.Context, now time.Time) (AdminInsights, error)

AdminInsights performs bounded aggregate reads on indexed 30-day windows and the currently claimable/live verification-job set. stats_daily returns at most 31 rows (30 visible days plus one baseline); result and ecosystem groups are fixed buckets, and package depth is length-bounded and limited to ten rows.

func (*PG) AdoptionSummary added in v0.1.4

func (p *PG) AdoptionSummary(ctx context.Context) (AdoptionCounts, error)

AdoptionSummary counts adoption reports across the whole network.

func (*PG) AnnouncePeer

func (p *PG) AnnouncePeer(ctx context.Context, peer PeerRow) error

func (*PG) AnomalyInsights added in v0.1.46

func (p *PG) AnomalyInsights(ctx context.Context, now time.Time, days int) (AnomalyInsights, error)

AnomalyInsights is bounded by the last-seen index and returns fixed buckets, so the operator page costs one indexed scan rather than a table walk that grows with the channel.

func (*PG) AnomalyReportByID added in v0.1.46

func (p *PG) AnomalyReportByID(ctx context.Context, id int64) (AnomalyReportRow, bool, error)

func (*PG) AttachAnomalyVerificationJob added in v0.1.46

func (p *PG) AttachAnomalyVerificationJob(ctx context.Context, id, jobID int64, status, unsupportedReason string) error

func (*PG) AttachAuthoringWorkSample added in v0.1.16

func (p *PG) AttachAuthoringWorkSample(ctx context.Context, sessionID string, work AuthoringWorkRow, sampleID string, now time.Time) (bool, error)

func (*PG) AuthoringAttemptState added in v0.1.44

func (p *PG) AuthoringAttemptState(ctx context.Context, ecosystem, name, version, symbol string) (AuthoringAttemptState, bool, error)

func (*PG) AuthoringWorkForSubmission added in v0.1.16

func (p *PG) AuthoringWorkForSubmission(ctx context.Context, sessionID, sampleID string, now time.Time) (AuthoringWorkRow, bool, error)

func (*PG) CSXIssueInsights added in v0.1.46

func (p *PG) CSXIssueInsights(ctx context.Context, now time.Time, days int) (CSXIssueInsights, error)

func (*PG) CSXIssueReportByID added in v0.1.46

func (p *PG) CSXIssueReportByID(ctx context.Context, id int64) (CSXIssueReportRow, bool, error)

func (*PG) ChangedSince added in v0.1.1

func (p *PG) ChangedSince(ctx context.Context, since time.Time) (Changes, error)

ChangedSince implements the incremental-rebuild query. It includes both author-declared purls and exact purls established by v2 receipts; on an idle network the timestamp predicates return nothing and aggregation does no materialized-view work.

func (*PG) ClaimAuthoringWork added in v0.1.16

func (p *PG) ClaimAuthoringWork(ctx context.Context, sessionID string, candidates []WantedRow, now, leaseExpiresAt time.Time) (AuthoringWorkRow, bool, error)

func (*PG) ClaimJob

func (p *PG) ClaimJob(ctx context.Context, id int64, peerID string) (bool, error)

func (*PG) Close

func (p *PG) Close()

Close releases every pooled connection.

func (*PG) CompleteJob

func (p *PG) CompleteJob(ctx context.Context, id int64) error

func (*PG) CompleteJobsForSample added in v0.1.4

func (p *PG) CompleteJobsForSample(ctx context.Context, sampleID, peerID string) error

CompleteJobsForSample closes every open or claimed job for a sample.

A receipt arriving IS the completion — that is what the job asked for — and wiring it here means a finished job cannot be left behind by a peer that never calls anything else.

func (*PG) CreateJob

func (p *PG) CreateJob(ctx context.Context, j JobRow) (int64, error)

func (*PG) CrossJobsForLaneReview added in v0.1.45

func (p *PG) CrossJobsForLaneReview(ctx context.Context, limit int) ([]JobRow, error)

func (*PG) DeleteSnapshots added in v0.1.5

func (p *PG) DeleteSnapshots(ctx context.Context, targets []SnapshotTarget) error

func (*PG) Dependants added in v0.1.32

func (p *PG) Dependants(ctx context.Context, ecosystem, name string) ([]DependencyEdge, error)

Dependants lists what pulled each version of one library.

func (*PG) Dependencies added in v0.1.33

func (p *PG) Dependencies(ctx context.Context, ecosystem, name string) ([]DependencyEdge, error)

Dependencies lists what shipped ALONGSIDE each version of one package.

Upgrade a library and its dependencies move under you; the one that moved is usually the one that broke the build. Same table as Dependants, read from the parent end.

func (*PG) EnsureCrossJob added in v0.1.46

func (p *PG) EnsureCrossJob(ctx context.Context, j JobRow) (int64, error)

func (*PG) EvidenceForTarget

func (p *PG) EvidenceForTarget(ctx context.Context, purl, symbol string) ([]EvidenceRow, error)

func (*PG) ExpirePeers

func (p *PG) ExpirePeers(ctx context.Context, now time.Time) (int64, error)

func (*PG) FarmBacklogNow added in v0.1.44

func (p *PG) FarmBacklogNow(ctx context.Context, since, now time.Time) (FarmBacklog, error)

FarmBacklogNow reads the two stocks and the two flows the coverage scheduler is judged by.

The dependency count comes from the same dependency_open CTE the scheduler hands work out of (authoringCoverageCTE), not from a second definition written to look like it. That is the whole point of the shared constant: a backlog counted from a different predicate than the queue would report a figure that never moves however hard the fleet runs.

func (*PG) FarmCompletenessNow added in v0.1.46

func (p *PG) FarmCompletenessNow(ctx context.Context) (FarmCompleteness, error)

FarmCompletenessNow counts every PUBLIC release by which of Sample, Evidence and Dependency it holds.

"Proven" is read through authoringCoverageCTE rather than through a second definition written to look like it, for the reason that constant exists: a panel counting a different set from the queue it describes reports a figure that never moves however hard the fleet runs.

func (*PG) FarmCoverage added in v0.1.25

func (p *PG) FarmCoverage(ctx context.Context) ([]FarmAxisCoverage, error)

FarmCoverage measures the compatibility map against itself: for every (os, ecosystem) the network has seen used, how much of it has actually been proven there.

Observations arrive from developer machines and proofs from containers, so the two axes can disagree entirely -- and did: every observation recorded was windows while every receipt was linux. Counting them together hid that for months behind a single healthy-looking coverage number.

func (*PG) FarmHealthNow added in v0.1.21

func (p *PG) FarmHealthNow(ctx context.Context, now time.Time) (FarmHealth, error)

func (*PG) FarmWorkers added in v0.1.21

func (p *PG) FarmWorkers(ctx context.Context, since, now time.Time) ([]FarmWorker, error)

func (*PG) GetLatestStats

func (p *PG) GetLatestStats(ctx context.Context) (string, bool, error)

func (*PG) GetPackage

func (p *PG) GetPackage(ctx context.Context, purl string) (PackageRow, bool, error)

func (*PG) GetSample

func (p *PG) GetSample(ctx context.Context, sampleID string) (SampleRow, bool, error)

func (*PG) GetShard

func (p *PG) GetShard(ctx context.Context, key string) (string, string, bool, error)

func (*PG) GetShardEtag added in v0.1.35

func (p *PG) GetShardEtag(ctx context.Context, key string) (string, bool, error)

GetShardEtag reads the ETag alone: no json::text detoast, so the revalidation path costs a primary-key row read rather than the document.

func (*PG) GetSnapshot

func (p *PG) GetSnapshot(ctx context.Context, purl, symbol string) (string, bool, error)

func (*PG) HotShardKeys

func (p *PG) HotShardKeys(ctx context.Context, limit int) ([]string, error)

HotShardKeys ranks built shards by the samples they carry first, then by the observation volume of the packages they cover. Keys with no shard row are dropped: handing a client a key that 404s wastes the one warm-up it gets.

func (*PG) IdentityByAPIToken

func (p *PG) IdentityByAPIToken(ctx context.Context, apiTokenHash string) (IdentityRow, bool, error)

func (*PG) IngestBatches

func (p *PG) IngestBatches(ctx context.Context, batches []domain.ObservationBatch) (int, []RejectedBatch, error)

IngestBatches validates each batch and delta-merges the valid ones with the semantics documented in merge.go: per (bucket, agg row, epoch) only count growth is added, so a re-sent identical batch adds exactly 0. IngestBatches applies a whole request in ONE transaction. Per-batch transactions meant a 500-batch upload paid 500 commits: on a small instance that took longer than the client's timeout, so a first sync after scanning a machine could never finish. One commit is also the honest unit — a request lands completely or not at all, and the delta-merge makes a retried request add nothing twice.

func (*PG) IssueAdminTokens added in v0.1.21

func (p *PG) IssueAdminTokens(ctx context.Context, rows []AdminTokenRow) error

func (*PG) IssueAuthoringSessions added in v0.1.15

func (p *PG) IssueAuthoringSessions(ctx context.Context, rows []AuthoringSessionRow, now time.Time) error

func (*PG) Job added in v0.1.12

func (p *PG) Job(ctx context.Context, id int64) (JobRow, bool, error)

func (*PG) JobsForSample

func (p *PG) JobsForSample(ctx context.Context, sampleID string) ([]JobRow, error)

func (*PG) LinkCSXIssueCanonical added in v0.1.46

func (p *PG) LinkCSXIssueCanonical(ctx context.Context, id int64, ref string) (bool, error)

LinkCSXIssueCanonical refuses to link anything that is not a confirmed defect. The check is in the statement rather than in a handler so a second caller cannot forget it: linking an unconfirmed report to a bug is how a candidate quietly becomes a claim.

func (*PG) ListAdminTokens added in v0.1.21

func (p *PG) ListAdminTokens(ctx context.Context, limit int) ([]AdminTokenRow, error)

func (*PG) ListAnomalyReports added in v0.1.46

func (p *PG) ListAnomalyReports(ctx context.Context, limit int) ([]AnomalyReportRow, error)

func (*PG) ListAuthoringDrafts added in v0.1.16

func (p *PG) ListAuthoringDrafts(ctx context.Context, limit int) ([]AuthoringDraftRow, error)

func (*PG) ListAuthoringExpansionCandidates added in v0.1.19

func (p *PG) ListAuthoringExpansionCandidates(ctx context.Context, limit int) ([]WantedRow, error)

func (*PG) ListAuthoringQuarantine added in v0.1.44

func (p *PG) ListAuthoringQuarantine(ctx context.Context, now time.Time, limit int) ([]AuthoringAttemptState, error)

func (*PG) ListAuthoringSessions added in v0.1.15

func (p *PG) ListAuthoringSessions(ctx context.Context, now time.Time, limit int) ([]AuthoringSessionRow, error)

func (*PG) ListCSXIssueReports added in v0.1.46

func (p *PG) ListCSXIssueReports(ctx context.Context, limit int) ([]CSXIssueReportRow, error)

func (*PG) ListFailureClusters

func (p *PG) ListFailureClusters(ctx context.Context, packageName string) ([]ClusterRow, error)

func (*PG) ListFailureClustersIncludingPreserved added in v0.1.45

func (p *PG) ListFailureClustersIncludingPreserved(ctx context.Context, packageName string) ([]ClusterRow, error)

ListFailureClustersIncludingPreserved adds the pre-0024 rows back.

Exact failure matching is the one question those rows still answer. Every released client fingerprints a failure as `v1|stage|code|template`, and every one of the fingerprints this network has on file was written by such a client. Serving only current clusters would hand exact-match search a surface where nothing can ever match: the rebuilt evidence-gap rows carry no fingerprint at all, and v2 fingerprints only start arriving once a client that computes them is released. A fingerprint that was recorded is a fingerprint a caller can still hit.

func (*PG) ListPackageVersions

func (p *PG) ListPackageVersions(ctx context.Context, ecosystem, name string) ([]PackageRow, error)

func (*PG) ListSamples

func (p *PG) ListSamples(ctx context.Context, limit int) ([]SampleRow, error)

func (*PG) ListSamplesPage added in v0.1.4

func (p *PG) ListSamplesPage(ctx context.Context, limit, offset int) ([]SampleRow, error)

ListSamplesPage is ListSamples with an offset, so a caller that must visit EVERY sample can walk past the limit.

recompute-status promised to "re-derive every sample status" and read one capped page, so on a network past the cap it silently skipped the rest. Warning about it was not enough either: the list is ordered newest-first, so the "re-run until the count drops" advice returned the identical page every time and could never converge.

func (*PG) ListSnapshotTargets

func (p *PG) ListSnapshotTargets(ctx context.Context) ([]SnapshotTarget, error)

func (*PG) ListSnapshots added in v0.1.5

func (p *PG) ListSnapshots(ctx context.Context) ([]SnapshotRow, error)

func (*PG) ListVerifiedBeliefSamples added in v0.1.45

func (p *PG) ListVerifiedBeliefSamples(ctx context.Context, after SampleCursor, limit int) ([]SampleRow, error)

ListVerifiedBeliefSamples pages the finding candidates.

The predicate is the same verified-sample predicate as above plus the one thing that makes a sample a finding: its case says what was believed. That belief lives inside the manifest JSON — no column mirrors it, and adding one would put a second answer beside the artifact's own copy — so the filter reads the JSONB directly.

Doing it here rather than in Go is the whole point. The caller used to read the newest 2,000 verified samples and look for beliefs inside them, which quietly turned "every finding" into "every finding published recently": production crossed 2,000 verified samples and 308 findings fell out of the window with nothing taken down. Only a minority of samples state a belief (567 of 2,787 in production), so filtering first makes the eligible set small enough to page through completely.

The store's belief test is presence, not prose: a non-empty string in the manifest. Whether it reads as a sentence, and whether a contract line answers it, is judged in Go over a set this has already made small — so no trimming rule has to be spelled twice, in two languages, and stay identical forever.

func (*PG) ListVerifiedSamples added in v0.1.5

func (p *PG) ListVerifiedSamples(ctx context.Context, limit int) ([]SampleRow, error)

func (*PG) ListWanted added in v0.1.6

func (p *PG) ListWanted(ctx context.Context, query string, offset, limit int) ([]WantedRow, int, error)

func (*PG) MarkActivityHealthy added in v0.1.6

func (p *PG) MarkActivityHealthy(ctx context.Context, now time.Time) error

MarkActivityHealthy records only the current UTC day's explicit collection health marker. The tracker calls it at startup and at each UTC rollover, independently of collector-key readiness; one call never backfills history.

func (*PG) Migrate

func (p *PG) Migrate(ctx context.Context) error

Migrate applies the embedded migrations (see migrate.go).

Migrations are background work by definition: some of them rewrite whole tables, and a read ceiling applied to them would fail a deployment rather than protect one.

func (*PG) NetworkCounts

func (p *PG) NetworkCounts(ctx context.Context, now time.Time) (NetworkCounts, error)

NetworkCounts computes the raw /v1/stats numbers in one round trip.

Peers counts the distinct anonymous peer buckets that contributed evidence in the current epoch — the people actually using the network today. It deliberately does NOT count rows in the peers table: that is the P2P blob tracker, which a node only joins by opting into peerListen, so it read 0 while evidence was arriving every minute. Peer identities rotate daily by design (goal.md §8.6), so one day is the longest window that can be counted without inflating one user into many.

func (*PG) OpenAnomalyReportsForSample added in v0.1.46

func (p *PG) OpenAnomalyReportsForSample(ctx context.Context, sampleID string) ([]AnomalyReportRow, error)

func (*PG) OpenJobs

func (p *PG) OpenJobs(ctx context.Context, capability, peerID, reason string, limit int) ([]JobRow, error)

OpenJobs lists claimable jobs. A job that pins want_env.sandboxCapability only matches peers reporting that capability; capability "" matches all.

"Claimable" includes a job whose claim has outlived JobLease. ClaimJob has always known how to take one of those back, but this query only ever offered status='open', so nothing could reach that path: a peer that claimed a job and then died — crashed, upgraded, powered off — held it for good. 265 jobs sat claimed with zero open behind a queue that reported itself empty, and cross-verification stopped entirely without anything reporting an error.

func (*PG) OpenJobsPage added in v0.1.12

func (p *PG) OpenJobsPage(ctx context.Context, capability, peerID, reason, verifierOS string, limit, offset int) ([]JobRow, error)

func (*PG) PeersForSample

func (p *PG) PeersForSample(ctx context.Context, sampleID string) ([]PeerRow, error)

func (*PG) PoolStats added in v0.1.45

func (p *PG) PoolStats() PoolStats

PoolStats reports the connection pool as an operator needs to see it: what is in use, who is using it, how long they waited, and what the per-class ceilings have refused or cancelled.

func (*PG) PruneActivity added in v0.1.6

func (p *PG) PruneActivity(ctx context.Context, now time.Time) error

PruneActivity bounds linkable state to exactly 35 daily and 13 monthly epochs including the current UTC day/month. It remains on the independent six-hour maintenance cadence. Both tails are deleted, including health markers, so a skewed future row cannot evade a lower-bound-only pass.

func (*PG) PurgeDedupOlderThan

func (p *PG) PurgeDedupOlderThan(ctx context.Context, days int) (int64, error)

PurgeDedupOlderThan deletes dedup buckets whose epoch day is older than the retention window. Aggregate counts are kept — only the rotating bucket linkage is erased (goal.md §14.4), so unique_*_buckets freeze at their accumulated values rather than shrinking retroactively.

func (*PG) PutShard

func (p *PG) PutShard(ctx context.Context, key, etag, shardJSON string) error

func (*PG) PutSnapshot

func (p *PG) PutSnapshot(ctx context.Context, purl, symbol, snapshotJSON string) error

func (*PG) ReceiptsForSample

func (p *PG) ReceiptsForSample(ctx context.Context, sampleID string) ([]ReceiptRow, error)

func (*PG) RecordActivity added in v0.1.6

func (p *PG) RecordActivity(ctx context.Context, buckets []activity.Bucket) error

RecordActivity persists only epoch-scoped 128-bit buckets. owner is monotonic so an authenticated admin visit retroactively excludes a bucket even when an older non-owner observation arrives later from the queue.

func (*PG) RecordAdoption added in v0.1.4

func (p *PG) RecordAdoption(ctx context.Context, r AdoptionRow) error

func (*PG) RecordAnomalyReport added in v0.1.46

func (p *PG) RecordAnomalyReport(ctx context.Context, row AnomalyReportRow, now time.Time) (AnomalyReportRow, bool, error)

RecordAnomalyReport is one statement on purpose.

Two agents hitting the same wrong answer at the same moment is the normal case, not the race to worry about later: the whole point of the channel is that many consumers meet the same defect. A read-then-insert would let both pass the read and both queue a container. The unique fingerprint plus ON CONFLICT makes "already known" the database's answer rather than the application's guess, and the RETURNING tells the caller which of the two happened without a second round trip.

func (*PG) RecordCSXIssueReport added in v0.1.46

func (p *PG) RecordCSXIssueReport(ctx context.Context, row CSXIssueReportRow, now time.Time) (CSXIssueReportRow, bool, error)

RecordCSXIssueReport is one statement, for the same reason the anomaly ingest is: many consumers meeting one defect at once is the normal case, and a read-then-insert would let both pass the read and file two tickets for one bug.

func (*PG) RecordSearchHit added in v0.1.37

func (p *PG) RecordSearchHit(ctx context.Context, r SearchHitRow) error

RecordAdoption stores one adoption report, counting a reporter once per sample per epoch. A repeat within the same epoch updates the outcome — an agent that reports "applied" and later reports the build result is telling us more about the same event, not a second event. RecordSearchHit counts one search that found something.

One reporter counts once per offer per day. Re-delivery of the same queued hit carries the same offer and updates the row; a new search gets a new offer and counts separately, even when its query and result are identical.

func (*PG) RecordSearchOutcome added in v0.1.10

func (p *PG) RecordSearchOutcome(ctx context.Context, at time.Time, outcome SearchOutcome) error

RecordSearchOutcome atomically adds one result to its UTC daily aggregate. A storage failure is returned to the caller, which deliberately treats this analytics write as best-effort rather than failing an otherwise valid search.

func (*PG) RecordWanted added in v0.1.4

func (p *PG) RecordWanted(ctx context.Context, epoch, anonID string, rows []WantedRow) error

RecordWanted counts one anonymous report that the network had no answer for this package (and symbol, when the caller named one).

Counted per (reporter, epoch), not per request: one machine asking the same thing all afternoon is one data point. Counting keystrokes would let a single caller manufacture the ranking, which is the whole value of it.

func (*PG) RecordWantedBatch added in v0.1.5

func (p *PG) RecordWantedBatch(ctx context.Context, reports []WantedSubmission) error

RecordWantedBatch applies a wire batch in one database transaction. A transport retry is safe because every row first passes through the rotating dedup key, and a storage failure cannot leave half the envelope committed.

func (*PG) RefreshAuthoringSession added in v0.1.15

func (p *PG) RefreshAuthoringSession(ctx context.Context, tokenHash, ip, computerName string, now, idleExpiresAt time.Time) (AuthoringSessionRow, error)

func (*PG) ReopenAuthoringQuarantine added in v0.1.44

func (p *PG) ReopenAuthoringQuarantine(ctx context.Context, ecosystem, name, version, symbol string, now time.Time) (bool, error)

func (*PG) ReportAuthoringOutcome added in v0.1.44

func (p *PG) ReportAuthoringOutcome(ctx context.Context, sessionID string, outcome AuthoringOutcome, detail string, now time.Time) (AuthoringWorkRow, bool, error)

func (*PG) ResolveAdminToken added in v0.1.21

func (p *PG) ResolveAdminToken(ctx context.Context, tokenHash, ip string, now time.Time) (AdminTokenRow, bool, error)

ResolveAdminToken validates and stamps in one statement. The stamp is not bookkeeping: an unlimited token has no expiry to watch, so its use is the only signal its owner has that somebody else holds it.

func (*PG) RevokeAdminToken added in v0.1.21

func (p *PG) RevokeAdminToken(ctx context.Context, tokenID string, now time.Time) (bool, error)

func (*PG) RevokeAuthoringSession added in v0.1.15

func (p *PG) RevokeAuthoringSession(ctx context.Context, sessionID string, now time.Time) (bool, error)

func (*PG) RotateAuthoringSession added in v0.1.16

func (p *PG) RotateAuthoringSession(ctx context.Context, sessionID, tokenHash string, now, idleExpiresAt time.Time) (AuthoringSessionRow, error)

func (*PG) SamplesBySeeder added in v0.1.4

func (p *PG) SamplesBySeeder(ctx context.Context, login string, limit int) ([]SampleRow, error)

SamplesBySeeder lists a seeder's own published samples, newest first.

The seeder page used to read the newest 500 samples network-wide and filter them by login, so a seeder's older work disappeared from their own page the moment the network published 500 samples after it — silently, and first for the people who contributed earliest.

func (*PG) SamplesForPackages added in v0.1.2

func (p *PG) SamplesForPackages(ctx context.Context, names []string, limit int) ([]SampleRow, error)

SamplesForPackages returns non-quarantined samples whose manifest names any of the given package (ecosystem, name) pairs.

Search used to take the newest 500 samples globally and score those, which made relevance a function of publication order: at 501 samples the oldest silently stop being findable no matter how good they are, and anyone able to publish 500 rows owns every result. Filtering in SQL makes the limit per-query instead of global.

func (*PG) SaveAuthoringDraft added in v0.1.16

func (p *PG) SaveAuthoringDraft(ctx context.Context, row AuthoringDraftRow) error

func (*PG) SaveCase

func (p *PG) SaveCase(ctx context.Context, cse domain.Case) error

func (*PG) SaveIdentity

func (p *PG) SaveIdentity(ctx context.Context, login string, githubID int64, tokenHash, apiTokenHash string) error

func (*PG) SaveReceipt

func (p *PG) SaveReceipt(ctx context.Context, r ReceiptRow) error

func (*PG) SaveReceiptForJob added in v0.1.12

func (p *PG) SaveReceiptForJob(ctx context.Context, r ReceiptRow, jobID int64) (bool, error)

func (*PG) SaveSample

func (p *PG) SaveSample(ctx context.Context, s SampleRow) error

func (*PG) SetAnomalyVerdict added in v0.1.46

func (p *PG) SetAnomalyVerdict(ctx context.Context, id int64, verdict string, at time.Time) (bool, error)

SetAnomalyVerdict refuses to overwrite an answer already given.

A sample accumulates receipts for its own reasons, and each new one would otherwise re-decide every report ever filed against it — including reports a different receipt already closed. The verdict a report carries is the answer to the question it asked, at the time it was asked.

func (*PG) SetCSXIssueTriage added in v0.1.46

func (p *PG) SetCSXIssueTriage(ctx context.Context, id int64, status, replayReason string) error

func (*PG) SetCSXIssueVerdict added in v0.1.46

func (p *PG) SetCSXIssueVerdict(ctx context.Context, id int64, verdict string, at time.Time) (bool, error)

func (*PG) SetJobRequirements added in v0.1.45

func (p *PG) SetJobRequirements(ctx context.Context, id int64, wantEnvJSON, status string) error

func (*PG) SetSampleQuarantine added in v0.1.2

func (p *PG) SetSampleQuarantine(ctx context.Context, sampleID string, on bool, reason string) error

SetSampleQuarantine hides or restores a sample. Evidence, receipts and the case row are left untouched: a quarantine must be reversible and auditable, not a delete.

func (*PG) SetSampleStatus

func (p *PG) SetSampleStatus(ctx context.Context, sampleID, status string) error

func (*PG) SetStatsDaily

func (p *PG) SetStatsDaily(ctx context.Context, day string, statsJSON string) error

func (*PG) ShardKeys added in v0.1.4

func (p *PG) ShardKeys(ctx context.Context) ([]string, error)

ShardKeys lists every stored shard key, ordered so a pass is repeatable.

func (*PG) SnapshotKeys added in v0.1.5

func (p *PG) SnapshotKeys(ctx context.Context) ([]SnapshotTarget, error)

func (*PG) SnapshotUpdatedAt added in v0.1.21

func (p *PG) SnapshotUpdatedAt(ctx context.Context) (map[string]time.Time, error)

func (*PG) StrandedDrafts added in v0.1.29

func (p *PG) StrandedDrafts(ctx context.Context, maxAttempts, limit int) ([]string, error)

StrandedDrafts lists quarantined authoring drafts that have no verification left to wait for.

A verifier that cannot resolve dependencies files a SKIPPED receipt, which closes the sample's only cross job without measuring anything. Before the retry existed nothing queued another, and production accumulated 159 drafts in exactly that state — verified by nobody, waiting on nothing, invisible. This is how the reconcile finds them.

func (*PG) TopWanted added in v0.1.4

func (p *PG) TopWanted(ctx context.Context, limit int) ([]WantedRow, error)

TopWanted lists the most-asked unanswered package versions and symbols, most wanted first. A row closes only when a live sample carries the exact canonical PURL and, when requested, the exact symbol. A different release or a different API is still an unanswered request.

func (*PG) UpsertFailureCluster

func (p *PG) UpsertFailureCluster(ctx context.Context, cl ClusterRow) error

func (*PG) UpsertPackage

func (p *PG) UpsertPackage(ctx context.Context, pkg PackageRow) error

func (*PG) VerifiedSampleCodeCounts added in v0.1.46

func (p *PG) VerifiedSampleCodeCounts(ctx context.Context, packagePrefix string) ([]VerifiedSampleCodeCount, error)

func (*PG) VerifiedSamplesForPackages added in v0.1.5

func (p *PG) VerifiedSamplesForPackages(ctx context.Context, names []string, limit int) ([]SampleRow, error)

VerifiedSamplesForPackages is SamplesForPackages with a receipt-backed contract proof. Publication alone is not verification.

func (*PG) VersionCoresidence added in v0.1.31

func (p *PG) VersionCoresidence(ctx context.Context, ecosystem, name string) ([]VersionCoresidence, error)

JobsForSample lists every job for a sample regardless of status. VersionCoresidence lists the version pairs of one library that a scanner saw in a single resolution, counted by distinct project-days.

func (*PG) WantedForPackage added in v0.1.5

func (p *PG) WantedForPackage(ctx context.Context, ecosystem, name string) ([]WantedRow, error)

type PackageRow

type PackageRow struct {
	PURL       string
	Ecosystem  string
	Name       string
	Version    string
	Major      string
	Publicness string    // PUBLIC | PRIVATE | UNKNOWN
	CheckedAt  time.Time // zero = publicness never checked
	FirstSeen  time.Time
	LastSeen   time.Time
}

PackageRow is one packages-table row.

type PeerRow

type PeerRow struct {
	PeerID           string
	Addr             string
	Port             int
	CapabilitiesJSON string // JSON array, e.g. ["CONTAINER_RUN"]
	SampleIDsJSON    string // JSON array of sample ids the peer seeds
	AnnouncedAt      time.Time
	ExpiresAt        time.Time
}

PeerRow is one peers-table row (tracker state, TTL-expired).

type PoolPolicy added in v0.1.45

type PoolPolicy struct {
	// Enabled is the rollback switch (CSX_DB_POOL_GUARD=off). Disabled, the
	// pool behaves exactly as it did before R2C-58: one shared cap, no
	// statement ceiling, no wait budget.
	Enabled bool
	// MaxConns is the total number of PostgreSQL connections this process
	// may hold.
	MaxConns int
	// ProbeReserve is how many connections no class but ClassProbe may
	// occupy.
	ProbeReserve int
	// InteractiveConns and BackgroundConns cap their classes.
	InteractiveConns int
	BackgroundConns  int
	// ReadTimeout is statement_timeout for ClassInteractive; 0 means none.
	ReadTimeout time.Duration
	// ReadWait is how long ClassInteractive waits for a connection before
	// ErrPoolBusy; 0 means "as long as the context allows".
	ReadWait time.Duration
	// ProbeTimeout and ProbeWait are the same two numbers for ClassProbe.
	ProbeTimeout time.Duration
	ProbeWait    time.Duration
}

PoolPolicy is the whole defense line, as numbers an operator can change without a deploy.

The shares are not a partition: they overlap on purpose, so spare capacity stays usable by whoever needs it and only the floor is reserved. What each class is guaranteed is (pool - probe reserve) minus the sum of the OTHER classes' caps, which is why the caps deliberately add up to more than the pool.

func DefaultPoolPolicy added in v0.1.45

func DefaultPoolPolicy() PoolPolicy

DefaultPoolPolicy is the shipped, deliberately conservative setting.

ReadTimeout is 8s and not 1s on purpose. The point is a ceiling, not a tight SLA: the slowest page this site is known to have served under load took 9.3s, ordinary pages take 30-170ms, and a ceiling set near the ordinary case would turn a slow morning into an outage of its own. 8s is far below the 60s WriteTimeout that produced the 502s and far above anything healthy.

func PoolPolicyFromEnv added in v0.1.45

func PoolPolicyFromEnv(get func(string) string) PoolPolicy

PoolPolicyFromEnv reads the database pool settings, starting from the shipped policy and changing only what is named:

CSX_DB_POOL_GUARD    "off" restores the pre-R2C-58 pool entirely
CSX_DB_MAX_CONNS     total connections (default 8)
CSX_DB_PROBE_RESERVE connections only /healthz may take (default 1)
CSX_DB_READ_CONNS    ceiling on user-facing reads (default 6)
CSX_DB_WRITE_CONNS   ceiling on ingest and background work (default 5)
CSX_DB_READ_TIMEOUT  statement_timeout for reads, 0 = none (default 8s)
CSX_DB_READ_WAIT     how long a read queues before 503, 0 = forever (3s)
CSX_DB_PROBE_TIMEOUT statement_timeout for /healthz (default 2s)

An unparsable value leaves the shipped default in place. This is the one place in this file where that is the right failure: a typo in a timeout must not take the server down at boot, and the default it falls back to is the value the deployment was already tested with.

type PoolStats added in v0.1.45

type PoolStats struct {
	Enabled  bool
	MaxConns int
	Open     int // connections this process currently holds
	InUse    int
	Idle     int
	Classes  []ClassPoolStats
}

PoolStats is the pool as an operator needs to see it: how much of it is in use, who is using it, how long they waited and what was refused.

type QueryBudget added in v0.1.45

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

QueryBudget is one caller's record of what the pool cost it: the class it asked as, how long it waited, and whether it was refused or cancelled.

It exists so that this package stays silent. serverstore has never written a log line and should not start: it does not know the request path, and a store that logs is a store that logs in tests. The HTTP layer creates one budget per request, reads it afterwards and writes the one line an operator needs.

func BudgetOf added in v0.1.45

func BudgetOf(ctx context.Context) *QueryBudget

BudgetOf returns the budget attached to ctx, or nil.

func NewQueryBudget added in v0.1.45

func NewQueryBudget(class QueryClass) *QueryBudget

NewQueryBudget returns a budget for one unit of work in one class. A class this package does not know is background: the counters are a fixed array indexed by class, and an out-of-range value would take the server down from the observability code rather than from the work.

func (*QueryBudget) Class added in v0.1.45

func (b *QueryBudget) Class() QueryClass

Class reports the class this budget was opened as.

func (*QueryBudget) Pressure added in v0.1.45

func (b *QueryBudget) Pressure() (busy, timeouts int64, waited time.Duration)

Pressure reports what this unit of work ran into: how many acquisitions were refused, how many statements PostgreSQL cancelled on a ceiling, and the total time spent waiting for a connection.

type QueryClass added in v0.1.45

type QueryClass uint8

QueryClass says what a database connection is being used FOR. It travels in the context because the store's methods are shared: the same ListWanted serves a visitor's page view and an operator's dashboard, and only the caller knows which one is waiting.

const (
	// ClassBackground is the zero value: work nobody is watching a spinner
	// for. Ingest, migrations, the aggregation builder, the CLI, tests. No
	// statement ceiling -- some of this legitimately takes minutes.
	ClassBackground QueryClass = iota
	// ClassInteractive is a query a person or an agent is blocked on: a
	// website page, a public API read, a search. These get a ceiling, and
	// they are the class that must never be able to take the pool.
	ClassInteractive
	// ClassProbe is the liveness check and nothing else. It runs one
	// trivial statement and is the last class that may be starved, because
	// starving it takes the container down on top of the incident.
	ClassProbe
)

func QueryClassOf added in v0.1.45

func QueryClassOf(ctx context.Context) QueryClass

QueryClassOf reports the class ctx asks as; unclassified is background.

func (QueryClass) String added in v0.1.45

func (c QueryClass) String() string

type ReceiptRow

type ReceiptRow struct {
	ReceiptID      string
	SampleID       string
	PeerID         string
	EnvHash        string
	ReceiptJSON    string
	ContractResult string // PASS | FAIL | SKIPPED | ""
	CreatedAt      time.Time
}

ReceiptRow is one receipts-table row. ReceiptJSON is the full signed VerificationReceipt document.

type RejectedBatch

type RejectedBatch struct {
	Index  int    `json:"index"`
	Reason string `json:"reason"`
}

RejectedBatch reports one refused batch of an ingest call, mirroring the C5 wire shape {index, reason}.

type SampleCursor added in v0.1.45

type SampleCursor struct {
	CreatedAt time.Time
	SampleID  string
}

SampleCursor is a position in a newest-first sample listing, used to page through one without offsets. Offsets shift under concurrent publishing and hand the next page a row the previous one already returned; a keyset on (created_at, sample_id) cannot, because sample_id is the primary key and the pair is therefore unique and totally ordered.

The zero value means "from the newest".

func CursorFor added in v0.1.45

func CursorFor(r SampleRow) SampleCursor

CursorFor returns the keyset position of a row, so a caller can ask for the page after it.

func (SampleCursor) IsZero added in v0.1.45

func (c SampleCursor) IsZero() bool

IsZero reports whether the cursor is the start of a listing.

type SampleRow

type SampleRow struct {
	SampleID     string
	CaseID       string // "" ⇒ NULL (case unknown)
	ManifestJSON string
	Status       string // PUBLISHED | CROSS_PASS | MATRIX_PASS | STABLE
	OriginSeeder string
	License      string
	SizeBytes    int64
	HotScore     float64
	CreatedAt    time.Time
	// Quarantined hides a sample from every serving read while leaving its
	// receipts and case intact, so the action is reversible and auditable.
	Quarantined      bool
	QuarantineReason string
}

SampleRow is one samples-table row. ManifestJSON is the csx.json document.

type SearchHitRow added in v0.1.37

type SearchHitRow struct {
	Grade        string
	ResultsShown int
	SampleID     string
	OfferID      string
	Epoch        string
	AnonID       string
}

AdoptionRow is one report that an agent applied a sample. SearchHitRow is one recorded search that found something.

Counts only, by construction: the query, the packages, the symbols and the environment stay on the caller's machine. What crosses is that a search happened, how many results it was handed, and an opaque id that lets the adoption which may follow find the search it came from.

type SearchOutcome added in v0.1.10

type SearchOutcome string

SearchOutcome is the complete persisted classification of one successful public search response. It intentionally cannot carry the request, package, symbol, path, client, or an identity.

const (
	SearchOutcomeSampleHit SearchOutcome = "sample_hit"
	SearchOutcomeNoMatch   SearchOutcome = "no_match"
)

type SearchOutcomeRecorder added in v0.1.10

type SearchOutcomeRecorder interface {
	RecordSearchOutcome(ctx context.Context, at time.Time, outcome SearchOutcome) error
}

SearchOutcomeRecorder is optional at the HTTP boundary. Search remains available with alternate stores that do not implement operational metrics.

type ServerConfig

type ServerConfig struct {
	DSN         string // CSX_DSN — PostgreSQL connection string, required to run
	Listen      string // CSX_LISTEN — default ":8080"
	BlobDir     string // CSX_BLOB_DIR — sample artifact blob directory
	PublicURL   string // CSX_PUBLIC_URL — canonical external base URL
	PublicCheck string // CSX_PUBLIC_CHECK — "strict" (default) | "trust" (dev/e2e only)
	// Publishing is who may upload a sample: "seeded" (default) requires a
	// token that resolves to a seeder identity, "open" allows anonymous
	// upload and exists for local development and e2e runs only.
	//
	// The shipped policy is seeded. A sample is worth what its provenance is
	// worth, and code from an origin the network cannot establish cannot be
	// given that guarantee -- see internal/httpapi/publishgate.go. Evidence,
	// receipts and every read stay anonymous.
	Publishing         string        // CSX_PUBLISHING — "seeded" (default) | "open" (dev/e2e only)
	SnapshotInterval   time.Duration // CSX_SNAPSHOT_INTERVAL — default 5m
	GithubClientID     string        // CSX_GITHUB_CLIENT_ID — empty ⇒ device flow returns 501
	GithubClientSecret string        // CSX_GITHUB_CLIENT_SECRET
	// AdminTokenSHA256 enables the private /admin operator route only when
	// it is a valid hexadecimal SHA-256 digest. It is intentionally separate
	// from seeder credentials and never accepts a raw token.
	AdminTokenSHA256 string // CSX_ADMIN_TOKEN_SHA256
	// ActivityHashKey is a dedicated 256-bit hex key for period-scoped
	// external network estimates. It must never reuse an admin credential.
	ActivityHashKey string // CSX_ACTIVITY_HASH_KEY
	// BlobBudgetBytes caps total artifact storage (CSX_BLOB_BUDGET_MB, 0 =
	// unlimited). Sample upload is anonymous, so this is the only ceiling
	// on how much disk an unauthenticated caller can take — and the volume
	// is shared with PostgreSQL, which stops working when it fills.
	BlobBudgetBytes int64
	// DBPool is the connection-pool timeout and admission policy
	// (CSX_DB_*). It is configuration and not a constant because the only
	// honest rollback for a defense like this is one an operator can apply
	// without a build — see docs/operations.md.
	DBPool PoolPolicy
}

ServerConfig collects every csx-server environment setting (plan contract C9). It lives here so cmd/csx-server and the Wave C HTTP layer share one definition.

func ConfigFromEnv

func ConfigFromEnv() ServerConfig

ConfigFromEnv reads the CSX_* server environment with safe defaults. DSN deliberately has no default: pointing at a database must be explicit.

type SnapshotRow added in v0.1.5

type SnapshotRow struct {
	PURL         string
	Symbol       string
	SnapshotJSON string
}

SnapshotRow is one materialized compatibility document. Collection pages use this batched shape so filtering by recorded environment does not issue one database query per target.

type SnapshotTarget

type SnapshotTarget struct {
	PURL   string
	Symbol string
}

SnapshotTarget is one (purl, symbol) pair that has either aggregated observation evidence or exact version evidence from a signed v2 receipt, and therefore needs a compatibility snapshot. Symbol "" is the package-level row.

type Store

type Store interface {
	// IngestBatches validates and delta-merges observation batches
	// (semantics in merge.go). Invalid batches are reported in rejected and
	// skipped; a storage failure aborts with err.
	IngestBatches(ctx context.Context, batches []domain.ObservationBatch) (accepted int, rejected []RejectedBatch, err error)

	UpsertPackage(ctx context.Context, p PackageRow) error
	GetPackage(ctx context.Context, purl string) (PackageRow, bool, error)
	ListPackageVersions(ctx context.Context, ecosystem, name string) ([]PackageRow, error)

	GetSnapshot(ctx context.Context, purl, symbol string) (snapshotJSON string, ok bool, err error)
	ListSnapshots(ctx context.Context) ([]SnapshotRow, error)
	PutSnapshot(ctx context.Context, purl, symbol, snapshotJSON string) error
	// SnapshotKeys lists materialized rows already stored. It is distinct
	// from ListSnapshotTargets, which lists the live source rows that should
	// exist, and lets aggregation retire snapshots whose last source vanished.
	SnapshotKeys(ctx context.Context) ([]SnapshotTarget, error)
	DeleteSnapshots(ctx context.Context, targets []SnapshotTarget) error
	// ChangedSince reports what moved since a point in time, so the
	// aggregation pass can rebuild only what is stale instead of the whole
	// network on every tick.
	ChangedSince(ctx context.Context, since time.Time) (Changes, error)

	// ListSnapshotTargets returns distinct (purl, symbol) pairs established
	// by aggregated evidence or signed v2 receipt resolver output.
	ListSnapshotTargets(ctx context.Context) ([]SnapshotTarget, error)
	// SnapshotUpdatedAt reports, per PURL, when the evidence behind its
	// compatibility snapshot was last seen. It returns one row per package,
	// but it reaches that row by expanding every snapshot document: the cost
	// is a full pass over compatibility_snapshots, not an index scan. Read it
	// through a cache, never once per request.
	SnapshotUpdatedAt(ctx context.Context) (map[string]time.Time, error)
	EvidenceForTarget(ctx context.Context, purl, symbol string) ([]EvidenceRow, error)

	SaveCase(ctx context.Context, c domain.Case) error
	SaveSample(ctx context.Context, s SampleRow) error
	GetSample(ctx context.Context, sampleID string) (SampleRow, bool, error)
	ListSamples(ctx context.Context, limit int) ([]SampleRow, error)
	// ListSamplesPage is ListSamples with an offset, so a caller that means
	// EVERY sample can page instead of quietly reading the newest N.
	ListSamplesPage(ctx context.Context, limit, offset int) ([]SampleRow, error)
	// SamplesForPackages returns live samples naming any of these package
	// patterns ("pkg:npm/axios@%"), so search does not depend on a global
	// newest-N window.
	SamplesForPackages(ctx context.Context, patterns []string, limit int) ([]SampleRow, error)
	// VerifiedSamplesForPackages is the serving-only form used by package
	// pages: every returned sample has at least one contract-PASS receipt.
	// Search keeps using SamplesForPackages so source-only candidates can be
	// graded honestly rather than disappearing from the local resolver.
	VerifiedSamplesForPackages(ctx context.Context, patterns []string, limit int) ([]SampleRow, error)
	// VerifiedSampleCodeCounts returns exhaustive counts for the exact package
	// prefix (for example "pkg:npm/axios@"). Unlike
	// VerifiedSamplesForPackages, this is an aggregate rather than a newest-N
	// listing and is therefore safe for authoritative availability claims.
	VerifiedSampleCodeCounts(ctx context.Context, packagePrefix string) ([]VerifiedSampleCodeCount, error)
	// ListVerifiedSamples returns newest non-quarantined samples with an
	// actual contract-PASS receipt. Public measured findings must never be
	// derived from author prose on a source-only upload.
	//
	// This is a NEWEST-N window. Never answer a question about the whole
	// corpus with it: a serving read that filters inside a fixed window
	// shrinks as the corpus grows, which is how the findings page fell from
	// 543 entries to 250 while nothing was taken down. For findings, use
	// ListVerifiedBeliefSamples, which pages the eligible set instead.
	ListVerifiedSamples(ctx context.Context, limit int) ([]SampleRow, error)
	// ListVerifiedBeliefSamples pages the samples that could be findings:
	// non-quarantined, holding an actual contract-PASS receipt, and stating
	// in their own manifest what was believed.
	//
	// The belief is what narrows the read, and it is applied in the store so
	// the caller never has to choose between reading everything and reading
	// a recent slice of everything. Rows come back newest first, starting
	// strictly after `after`; the zero cursor starts at the newest. `limit`
	// bounds ONE read, not the answer — a caller wanting every finding pages
	// until a short page comes back.
	ListVerifiedBeliefSamples(ctx context.Context, after SampleCursor, limit int) ([]SampleRow, error)
	// SamplesBySeeder lists one seeder's published samples, so their page
	// does not depend on a global newest-N window.
	SamplesBySeeder(ctx context.Context, login string, limit int) ([]SampleRow, error)
	// SetSampleQuarantine hides or restores a sample without deleting the
	// evidence trail behind it.
	SetSampleQuarantine(ctx context.Context, sampleID string, on bool, reason string) error
	SetSampleStatus(ctx context.Context, sampleID, status string) error

	SaveReceipt(ctx context.Context, r ReceiptRow) error
	// SaveReceiptForJob atomically consumes an exact live claim and stores its
	// receipt. false means the claim no longer belongs to that peer/sample;
	// callers must reject rather than attaching evidence to a recycled lease.
	SaveReceiptForJob(ctx context.Context, r ReceiptRow, jobID int64) (bool, error)
	ReceiptsForSample(ctx context.Context, sampleID string) ([]ReceiptRow, error)

	// OpenJobs lists open verification jobs a peer with the given sandbox
	// capability may claim ("" ⇒ any). A non-empty reason restricts the
	// result to that declarative job class ("cross" or "matrix"). Jobs whose
	// want_env pins a sandboxCapability only match that capability. A job for
	// a sample peerID has already filed a receipt on is not offered as CROSS:
	// a peer cannot independently cross-verify its own work. Matrix jobs stay
	// visible sequentially because one pinned worker can measure several exact
	// runtime lines; ClaimJob prevents simultaneous same-peer/sample claims.
	OpenJobs(ctx context.Context, capability, peerID, reason string, limit int) ([]JobRow, error)
	// OpenJobsPage is the same ordered claimable view with an offset. The HTTP
	// layer uses it to skip missing CAS artifacts without letting stale head
	// rows permanently hide valid work.
	OpenJobsPage(ctx context.Context, capability, peerID, reason, verifierOS string, limit, offset int) ([]JobRow, error)
	// JobsForSample lists every verification job (any status) for a sample,
	// oldest first — the aggregation builder uses it to avoid creating
	// duplicate matrix jobs.
	JobsForSample(ctx context.Context, sampleID string) ([]JobRow, error)
	// EnsureCrossJob atomically reuses live cross work for a sample or creates
	// it. Unsupported work is reused when the requested row is also
	// unsupported. Callers must not implement this as a separate
	// JobsForSample/CreateJob pair: concurrent requests would both observe
	// absence and create duplicate verification work.
	EnsureCrossJob(ctx context.Context, j JobRow) (int64, error)
	// Job reads one job for receipt-to-claim binding.
	Job(ctx context.Context, id int64) (JobRow, bool, error)
	// CrossJobsForLaneReview lists cross jobs whose requirements can still be
	// re-checked against the verifier images this build actually pins: the
	// open ones, the unsupported ones, and claims that outlived their lease.
	// A live claim is left alone — its receipt is bound to the requirements
	// the worker was handed.
	CrossJobsForLaneReview(ctx context.Context, limit int) ([]JobRow, error)
	// SetJobRequirements rewrites one job's requirements and status, and
	// releases any claim on it. Jobs created before the fleet's lanes were
	// known are otherwise unreachable: nothing in the request path ever looks
	// at a job again once it is open.
	SetJobRequirements(ctx context.Context, id int64, wantEnvJSON, status string) error
	CreateJob(ctx context.Context, j JobRow) (int64, error)
	// ClaimJob atomically moves an open job to claimed; false means someone
	// else got there first (or the job is gone).
	ClaimJob(ctx context.Context, id int64, peerID string) (bool, error)
	CompleteJob(ctx context.Context, id int64) error
	// VersionCoresidence lists the version pairs of one library that a
	// scanner saw in a SINGLE resolution — the fact the server cannot infer,
	// because a batch carries one package and a lockfile arrives shredded.
	VersionCoresidence(ctx context.Context, ecosystem, name string) ([]VersionCoresidence, error)
	// Dependants lists what pulled each version of one library — the other
	// half of a co-residence, and the half a person can act on.
	Dependants(ctx context.Context, ecosystem, name string) ([]DependencyEdge, error)
	// Dependencies lists what shipped ALONGSIDE each version of one package:
	// upgrade a library and its dependencies move under you, and the one that
	// moved is usually the one that broke the build.
	Dependencies(ctx context.Context, ecosystem, name string) ([]DependencyEdge, error)
	// StrandedDrafts lists quarantined authoring drafts with no verification
	// left to wait for: no passing receipt, no open or claimed job, and fewer
	// than maxAttempts cross jobs already spent. They are what a verifier
	// that cannot resolve leaves behind, and without this they are invisible
	// — verified by nobody and waiting on nothing.
	StrandedDrafts(ctx context.Context, maxAttempts, limit int) ([]string, error)
	// CompleteJobsForSample closes only cross jobs a receipt has answered.
	// Matrix jobs are target-specific and are completed by exact id after
	// their claim and requested environment have been checked. The
	// receipt IS the completion, so nothing depends on a peer remembering
	// to call anything else. A cross job is NOT answered by a receipt from
	// the peer that originated the sample — that receipt proves only that
	// the sample still works where it was built.
	CompleteJobsForSample(ctx context.Context, sampleID, peerID string) error

	// RecordAdoption stores one report that an agent applied a sample and
	// what happened to the build afterwards. This is the far end of the
	// loop the product describes, and it had no route to the server at all.
	RecordAdoption(ctx context.Context, r AdoptionRow) error
	// RecordSearchHit counts one search that found something. It is the
	// denominator adoptions never had: the network could see the demand
	// it could not satisfy — a miss uploads a Wanted ask — and nothing
	// of the demand it could.
	RecordSearchHit(ctx context.Context, r SearchHitRow) error
	// AdoptionSummary counts adoption reports for the stats rollup.
	AdoptionSummary(ctx context.Context) (AdoptionCounts, error)

	// RecordWanted counts anonymous reports that the network had no answer
	// for a package. The QUESTION IS NEVER SENT — only the part of the
	// request that was already public — and one reporter counts once per
	// epoch per row, so nobody can manufacture a ranking by asking twice.
	RecordWanted(ctx context.Context, epoch, anonID string, rows []WantedRow) error
	RecordWantedBatch(ctx context.Context, reports []WantedSubmission) error
	// TopWanted lists the most-asked packages that still have no sample.
	TopWanted(ctx context.Context, limit int) ([]WantedRow, error)
	// ListWanted returns one searchable, ranked page of unanswered package
	// coordinates plus the full filtered count. TopWanted remains the small
	// public-API view; this is the collection contract used by the website.
	ListWanted(ctx context.Context, query string, offset, limit int) (rows []WantedRow, total int, err error)
	// WantedForPackage is the stable targeted lookup behind a wanted-only
	// package page; its result must not depend on the row's global rank.
	WantedForPackage(ctx context.Context, ecosystem, name string) ([]WantedRow, error)

	AnnouncePeer(ctx context.Context, p PeerRow) error
	PeersForSample(ctx context.Context, sampleID string) ([]PeerRow, error)
	ExpirePeers(ctx context.Context, now time.Time) (removed int64, err error)

	PutShard(ctx context.Context, key, etag, shardJSON string) error
	// ShardKeys lists every shard key currently stored, so a full
	// aggregation pass can tell which shards no longer have any live data
	// behind them. Without it a shard whose last sample was quarantined
	// simply stopped being rebuilt, and kept serving the withdrawn sample.
	ShardKeys(ctx context.Context) ([]string, error)
	GetShard(ctx context.Context, key string) (etag, shardJSON string, ok bool, err error)
	// GetShardEtag reads the ETag without loading the document, so a
	// revalidation costs what the limiter's 304 refund assumes it costs.
	GetShardEtag(ctx context.Context, key string) (etag string, ok bool, err error)
	// HotShardKeys lists the shard keys worth warming first, most active
	// first. A fresh install has no local package history, so this is the
	// only thing that fills its cache before the first search.
	HotShardKeys(ctx context.Context, limit int) ([]string, error)

	SaveIdentity(ctx context.Context, login string, githubID int64, tokenHash, apiTokenHash string) error
	IdentityByAPIToken(ctx context.Context, apiTokenHash string) (IdentityRow, bool, error)

	UpsertFailureCluster(ctx context.Context, c ClusterRow) error
	// ListFailureClusters returns the clusters the current builder writes.
	// Rows preserved by migration 0024 are stored but not served here.
	ListFailureClusters(ctx context.Context, packageName string) ([]ClusterRow, error)
	// ListFailureClustersIncludingPreserved adds those preserved rows back,
	// for the one question they still answer: has this exact fingerprint
	// been recorded?
	ListFailureClustersIncludingPreserved(ctx context.Context, packageName string) ([]ClusterRow, error)

	SetStatsDaily(ctx context.Context, day string, statsJSON string) error
	GetLatestStats(ctx context.Context) (statsJSON string, ok bool, err error)
	// NetworkCounts computes the raw stats-rollup numbers as of now.
	NetworkCounts(ctx context.Context, now time.Time) (NetworkCounts, error)

	// PurgeDedupOlderThan deletes rotating dedup buckets older than the
	// given number of days (goal.md §14.4: 30). Aggregates keep their
	// accumulated counts; only the bucket↔evidence linkage is erased.
	PurgeDedupOlderThan(ctx context.Context, days int) (removed int64, err error)

	Close()
}

Store is everything csx-server needs from PostgreSQL. Handlers depend on this interface, never on pgx, so tests can substitute fakes.

type VerifiedSampleCodeCount added in v0.1.46

type VerifiedSampleCodeCount struct {
	PURL    string
	Symbol  string
	Samples int64
}

VerifiedSampleCodeCount is one exhaustive serving count for a package release. Symbol "" is the release-wide count; non-empty symbols count the verified samples that name that API. Keeping this aggregate in the store avoids treating a newest-N display page as the complete code inventory.

type VersionCoresidence added in v0.1.31

type VersionCoresidence struct {
	Lower    string
	Higher   string
	Projects int
	Failing  int
}

VersionCoresidence is one pair of versions of the same library that a scanner saw in a SINGLE resolution.

The server cannot work this out for itself: an observation batch carries a single package, so a lockfile arrives already shredded into independent records and the finest grouping left is a project and a day. A project that builds twice in an afternoon against different lockfiles produces exactly the input that would be read as a collision, so pairing here would be inference. The scanner holds the lockfile at once and reports the pair.

Projects counts distinct project-days, not rebuilds. Failing is the subset where a build failed with a cause someone could name — an unattributed failure says a build containing this package broke and nothing about which package broke it.

type WantedRow added in v0.1.4

type WantedRow struct {
	Ecosystem string
	Name      string
	Version   string
	Symbol    string
	Asks      int64
	// Kind and Score are private authoring-queue metadata. Public Wanted
	// responses keep using Asks and never serialize these fields directly.
	Kind  string
	Score int64
	// TargetOS is the OS recorded by the evidence that produced a private
	// authoring candidate. Public Wanted rows leave it empty because their
	// reports do not currently carry an execution environment.
	TargetOS  string
	FirstSeen time.Time
	LastSeen  time.Time
	// HasPage is retained on the internal row for wire compatibility. Every
	// supported Wanted coordinate now has an honest request-only page, so it
	// is always true and must not trigger expensive snapshot/sample scans.
	HasPage bool
}

WantedRow is one "asked for, not answered" row.

type WantedSubmission added in v0.1.5

type WantedSubmission struct {
	Epoch  string
	AnonID string
	Rows   []WantedRow
}

WantedSubmission keeps one rotating reporter bucket attached to the rows it asked for. Batch ingest stores several submissions atomically while the dedup key remains per reporter, epoch, package version and symbol.

Jump to

Keyboard shortcuts

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