feedback

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Index

Constants

View Source
const (

	// EventServed marks one answered call, and its shape.
	EventServed = "served"
	// EventHook marks something a hook observed.
	EventHook = "hook"
)

The adoption log is telemetry, kept apart from the feedback log on purpose.

feedback.jsonl is training data: a retrieval reaches it only once a label judges it, which is why counting "calls" from it would silently mean "calls that were followed by a search". Adoption needs the opposite — every call, with none of the payload. Putting both in one file cost two invariants on the first attempt, and the tests that guard the training log caught it.

Nothing here stores a query, a candidate or a feature vector. A served line is about ninety bytes against the 5.6KB of a retrieval event, so the growth that forced a size cap on the other log does not apply.

View Source
const (
	// OutcomeNudgeShown is written when the post-grep hook handed the agent a
	// concrete position to pass back. Note carries that position.
	OutcomeNudgeShown = "nudge_shown"
	// OutcomeGateBlocked is written when the discovery gate turned a search away.
	OutcomeGateBlocked = "gate_blocked"
)

Outcomes recorded by the hooks rather than by the agent. Asking the agent does not work: record_feedback was called 57 times across 95958 served responses.

View Source
const OutcomeSearchedAfterContext = "searched_after_context"

OutcomeSearchedAfterContext marks a retrieval the agent followed with a text search of its own.

DECISION(2026-08): the name describes what was OBSERVED, not what it means. It is tempting to call this a rejection — the agent had the answer and went looking anyway — but the same behaviour covers verifying a result, chasing a literal string, and a question the tool was never meant to answer (its own description tells agents to prefer grep on small or familiar repositories). Whoever trains on this decides what it is worth; the recorder's job is to stop losing the observation, not to grade it.

Variables

View Source
var LooksPositional = func(string) bool { return false }

LooksPositional classifies a query as a position rather than a sentence. It is installed by the composition root from the retrieval package's own rule, so the report counts by exactly what the pipeline routes on; the default keeps the field honest (rather than wrong) if nothing installed it.

Functions

func AdoptionPath

func AdoptionPath(logPath string) string

AdoptionPath is where telemetry for a given feedback log lives.

func NewRequestID

func NewRequestID() string

func PendingPath

func PendingPath(logPath string) string

PendingPath is the single-entry breadcrumb holding the most recent unlabelled retrieval. The in-memory ring cannot serve the discovery hook, which runs as its own short-lived process and shares nothing with the server; without a file on disk a behavioural signal would arrive with a request id and no candidates, which is a label with nothing to label.

It is one file, overwritten on every call and removed the moment the retrieval is labelled — a snapshot of the last query, not a history of every query.

func RecordHookEvent

func RecordHookEvent(logPath, outcome, note string) error

RecordHookEvent appends one observation from a hook: the gate turning a search away, or the post-grep nudge being shown.

Best-effort by construction, like everything a hook does: it runs on the agent's critical path, so the error is returned for tests and ignored by callers.

func RecordObservedOutcome

func RecordObservedOutcome(logPath, outcome string, maxAge time.Duration) (bool, error)

RecordObservedOutcome labels the last unlabelled retrieval from the outside, for callers that cannot see the server's memory — the discovery hook is a separate process, so the breadcrumb on disk is the only thing it can read.

maxAge keeps an old breadcrumb from being blamed for something that happened much later. Returns false when there was nothing recent to label, which is the ordinary case and not an error.

func RotatedPath

func RotatedPath(path string) string

RotatedPath is where the previous generation lives. Readers that want the whole retained history must read it before the current file.

Types

type Candidate

type Candidate struct {
	Rank          int                `json:"rank"`
	File          string             `json:"file"`
	QualifiedName string             `json:"qualified_name"`
	Kind          string             `json:"kind"`
	Score         float32            `json:"score"`
	Why           string             `json:"why"`
	Features      map[string]float32 `json:"features,omitempty"`
}

type FeedbackEvent

type FeedbackEvent struct {
	Event           string    `json:"event"`
	RequestID       string    `json:"request_id"`
	Time            time.Time `json:"time"`
	Query           string    `json:"query,omitempty"`
	SelectedSymbols []string  `json:"selected_symbols,omitempty"`
	RejectedSymbols []string  `json:"rejected_symbols,omitempty"`
	Outcome         string    `json:"outcome,omitempty"`
	Note            string    `json:"note,omitempty"`
	Source          string    `json:"source,omitempty"`
}

type Recorder

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

func NewRecorder

func NewRecorder(path string) *Recorder

func (*Recorder) RecordFeedback

func (r *Recorder) RecordFeedback(event FeedbackEvent) error

func (*Recorder) RecordRetrieval

func (r *Recorder) RecordRetrieval(event RetrievalEvent) error

type RetrievalEvent

type RetrievalEvent struct {
	Event       string      `json:"event"`
	RequestID   string      `json:"request_id"`
	Time        time.Time   `json:"time"`
	Query       string      `json:"query"`
	Candidates  []Candidate `json:"candidates"`
	TotalTokens int         `json:"total_tokens,omitempty"`
	Source      string      `json:"source,omitempty"`
}

Jump to

Keyboard shortcuts

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