desk

package
v0.89.0 Latest Latest
Warning

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

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package desk is the ONE assembly of an investigation, shared by every door that serves it.

It exists because this codebase has now learned the same lesson three times: a question with two call sites grows two answers. Attribute() was reached only from the dashboard, so the emailed brief said "cause not yet attributed" about a finding the desk had already explained. Movements were wired into WithContext only, so the CLI rendered none. The fix each time was to collapse the callers into one, and this package is that collapse done in advance rather than after a customer notices.

So: /v1/investigate, the MCP investigate tool, the dashboard desk, the share page and the daily brief all build their Opts here and read the tracking plan here. Nobody assembles their own. The byte-agreement test between the route and the MCP tool is only meaningful because there is nothing left for the two of them to disagree about.

It is also where the environment is read. internal/investigate stays pure — no os.Getenv, no clock — so its gates are table tests; the switch that turns the newest gate off entirely is a deployment concern and lives out here with the other serving-layer decisions.

Index

Constants

View Source
const (
	// RevertWarmup is how long an experiment must have run before a breach may pull it, and
	// RevertMinGap is the minimum distance between the two failing checks that confirm a breach.
	//
	// Exported and quoted by GuardrailTrigger so the sentence the page prints is built from the
	// same constants confirmedBreach enforces. The tracking detector already learned this lesson
	// the expensive way: a promise restated from memory is a promise that drifts the first time
	// somebody edits the number.
	RevertWarmup = 15 * time.Minute
	RevertMinGap = 5 * time.Minute
	// SafetyPassEvery is how often the unprompted pass runs — alerts, then guardrails. The slab
	// says "rechecked every 5 minutes" and reads it from here, so the claim cannot outlive the
	// ticker in cmd/smolanalytics.
	SafetyPassEvery = 5 * time.Minute
)
View Source
const ReadMeFirst = "Findings are ranked by cost — money when the metric carries revenue, people otherwise. " +
	"needs_you=true is worth interrupting a human for; recovered=true is closed work kept for the record. " +
	"cause is computed correlation and says so; never present it as proof. " +
	"A quiet=true result with a populated scanned list is a real answer: nothing moved enough to matter. " +
	"kind=tracking_broke is the one class that is NOT a product problem: an event in the declared tracking plan " +
	"went silent while a witness metric held, which means a track() call was deleted — its cost is deliberately " +
	"unsized because we stopped counting, and its fix is to put the call back. Every other regression carries " +
	"tracking_ruled_out saying why it is not that."

ReadMeFirst is the contract text every agent reads before the findings themselves. Served identically by the HTTP route and the MCP tool, because an agent that learns the rules one way over MCP and another way over HTTP is an agent that will eventually quote the wrong ones.

View Source
const RevertEnv = "SMOLANALYTICS_AUTO_REVERT"

RevertEnv is the kill switch for ACTING on a guardrail breach. Detection and action are separate levers on purpose: "stop turning my flags off" and "stop telling me a guardrail failed" are different requests, and a safety feature with one switch gets switched off whole.

It lives here, beside TrackingBrokeEnv, because this package's own doc comment says the environment is read at the seam — internal/api used to read it, which meant the only place that knew whether the product was armed was the package that could not tell the page.

View Source
const RevertEvent = "$experiment_reverted"

RevertEvent is the receipt written onto the operator's OWN event log when a flag is pulled. Moved here from internal/api for the same reason: the ledger has to find these receipts, and the ledger is composed here.

View Source
const TrackingBrokeEnv = "SMOLANALYTICS_TRACKING_BROKE"

TrackingBrokeEnv is the kill switch for DETECTION. Set it to "off" and a regression is never promoted to tracking_broke anywhere — dashboard, brief, MCP and API alike — which means the cloud's actuator has nothing to act on. Detection-off and action-off are separate levers on purpose: "stop opening pull requests" and "stop telling me my tracking is broken" are different requests, and a safety feature with one switch gets the whole product switched off.

Variables

This section is empty.

Functions

func Build

Build is BuildDesk's investigation half, kept because the CLI brief and the share page want exactly that and nothing more.

func DetectionEnabled

func DetectionEnabled() bool

DetectionEnabled reports whether tracking-break promotion may run. Default on; only the exact word "off" disables it, so a typo fails loudly toward the documented behaviour.

func Doc

func Doc(d Desk) map[string]any

Doc is the serialized shape of a desk, identical on both public doors. The ledger travels with it so an agent reading over MCP and a browser reading the page are looking at one answer.

func GuardrailTrigger added in v0.88.0

func GuardrailTrigger(e flag.Experiment) string

GuardrailTrigger states a running experiment's breach condition in the same arithmetic confirmedBreach enforces, built from the exported constants rather than restated from memory.

func Planned

Planned turns the tracking-plan store into the lookup the investigator's G1 gate needs.

Returns nil — which the gate reads as "refuse" — in all three of the cases that mean the same thing: no store, an empty plan, or the switch off. Nil is never a permissive default here.

func RevertEnabled added in v0.88.0

func RevertEnabled() bool

RevertEnabled reports whether auto-revert may act. Default on; only the exact word "off" disables it, so a typo fails loudly toward the documented behaviour.

Types

type Act added in v0.88.0

type Act struct {
	Kind string    `json:"kind"` // guardrail_revert | tracking_pr
	Chip string    `json:"chip"`
	Head string    `json:"head"`
	Sub  string    `json:"sub"`
	At   time.Time `json:"at"`
	When string    `json:"when"`
	// Evidence is where the reader lands to check the claim. Exactly one per row, always.
	EvText string `json:"evidence_text"`
	EvHref string `json:"evidence"`
	// EvExternal marks an off-instance destination (the pull request itself), which the page
	// renders target=_blank rel=noopener.
	EvExternal bool `json:"evidence_external,omitempty"`
}

Act is one thing the system did without being asked, backed by a receipt on the user's own timeline. There are exactly two kinds, and both are built from a persisted event — never from configuration, an intention, or a capability. If it did not happen, there is no Act.

type Desk added in v0.88.0

type Desk struct {
	Investigation investigate.Investigation `json:"investigation"`
	Ledger        Ledger                    `json:"ledger"`
}

Desk is one pass: the investigation, plus the ledger of what the system is standing over and what it has already done. Every door builds this, so the page cannot show a ledger the API disagrees with — the same collapse this package was created to perform for the investigation.

func BuildDesk added in v0.88.0

func BuildDesk(evs []event.Event, src Sources, o investigate.Opts) Desk

BuildDesk runs the full pass: change findings, cause attribution, tracking-break promotion, the kill list, the quarter movements, the outcome-ledger overlay — and then the ledger over the top.

type Ledger added in v0.88.0

type Ledger struct {
	ArmedCount int `json:"armed_count"`
	ActedCount int `json:"acted_count"`
	// RevertMode and TrackingMode are "armed" or "off", read from the two environment switches.
	// The page prints both verbatim: an operator who switched something off must be able to see
	// that from the screen, and a reader must never be told a flag will be pulled on an instance
	// where it will not.
	RevertMode   string `json:"revert_mode"`
	TrackingMode string `json:"tracking_mode"`
	// CheckedAt is the sweep's clock reading. Deliberately NOT serialized: it is the same value
	// as investigation.generated_at, and shipping the one clock reading twice is how the
	// two-doors agreement test would start failing on a minute boundary for no real reason.
	CheckedAt time.Time `json:"-"`

	Acted    []Act                 `json:"acted,omitempty"`
	Closed   []investigate.Finding `json:"closed,omitempty"`
	Open     []investigate.Finding `json:"open,omitempty"`
	Standing []Watch               `json:"standing,omitempty"`
}

Ledger is the page's subject.

func (Ledger) Armed added in v0.88.0

func (l Ledger) Armed() []Watch

Armed and Cold split Standing for rendering. Kept as methods rather than two stored slices so the JSON carries one list and the two halves can never disagree about which row is in which.

func (Ledger) Claim added in v0.88.0

func (l Ledger) Claim() string

Claim is the slab's one sentence. Three states, and the unit never changes between them.

func (Ledger) Cold added in v0.88.0

func (l Ledger) Cold() []Watch

func (Ledger) HasTracking added in v0.88.0

func (l Ledger) HasTracking() bool

HasTracking reports whether any tracking watch is armed, which is the only condition under which the page may say anything at all about where the restore half runs.

func (Ledger) Subject added in v0.88.0

func (l Ledger) Subject() string

Subject is the slab's permanent unit. Acts are the body, never the figure, so the readout cannot swap units under the reader between one visit and the next.

func (Ledger) Support added in v0.88.0

func (l Ledger) Support() string

Support prints the two real modes, read from the environment rather than from a hope.

type Sources

type Sources struct {
	Flags   []flag.Flag
	Deploys []deploys.Deploy
	Acted   func(string) (time.Time, bool)
	Planned investigate.PlanLookup
	// Plan is the DECLARED events themselves. Planned above is a lookup — it answers "is this
	// one declared" and cannot be enumerated — and the ledger has to name every event it is
	// standing over, which is a list. Both come from the same store; neither replaces the other.
	Plan []trackplan.PlannedEvent
	// Alerts and Webhooks are the other two standing orders on an instance: what a human asked
	// to be told about, and whether there is anywhere to tell them.
	Alerts   []alert.Alert
	Webhooks int
}

Sources is the instance state an investigation reads beyond the events themselves. Every field is optional and nil-safe: a bare instance with no flags, no deploys, no ledger and no plan still gets a full investigation, it just gets fewer kinds of answer.

type Watch added in v0.88.0

type Watch struct {
	Kind        string `json:"kind"` // step_change | guardrail | tracking | alert | floor
	Armed       bool   `json:"armed"`
	Subject     string `json:"subject"`
	CheckedText string `json:"checked"`
	Trigger     string `json:"trigger"`
	Action      string `json:"action,omitempty"`
	Blocked     string `json:"blocked,omitempty"`
	EvText      string `json:"evidence_text"`
	EvHref      string `json:"evidence"`
}

Watch is one condition being checked on this instance: what trips it, and what happens then.

Armed means the condition is live. Not-armed is NOT disabled chrome — it is the product saying what it would take, with one concrete next step, which is the half of an empty state that is worth anything.

func (Watch) Sub added in v0.88.0

func (w Watch) Sub() string

Sub is the row's one full-width sentence. Armed rows read "{trigger} → {action}"; not-armed rows read the refusal followed by the single step that would clear it.

Jump to

Keyboard shortcuts

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