sentinel

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 26, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package sentinel detects test coverage disappearing, whatever route it took.

Blocking commands is whack-a-mole. Probing kirobuff's own preToolUse rules found six working bypasses for two rules: a test can be removed with rm, git rm, mv, unlink or find -delete, and only the first two were caught. Every rule added invites the next variation.

This measures the outcome instead. It counts test files and assertions across the repository, remembers the highest figures it has seen, and reports when the current count is lower. That catches deletion by any method, including ones nobody has thought of, because it never looks at the command.

The tradeoff is timing. Kiro CLI's stop hook cannot block a tool call, only warn after the turn, so this finds the loss a minute later rather than preventing it. A minute is still the difference between noticing and shipping.

Index

Constants

View Source
const StateFile = ".kiro/kirobuff/sentinel.json"

StateFile is where the high-water mark lives, relative to the workspace.

It sits outside .kiro/loop so a repository can use the sentinel without a loop, and enforce protects it from being written by the agent: whoever can lower the baseline can defeat the check.

Variables

This section is empty.

Functions

func Save

func Save(workspace string, s State) error

Save writes the state.

Types

type Measurement

type Measurement struct {
	Files      int `json:"files"`
	Assertions int `json:"assertions"`
}

Measurement is one scan of the repository.

func Accept

func Accept(workspace string) (Measurement, error)

Accept lowers the peak to the current measurement.

Deleting a genuinely obsolete test is legitimate, so there has to be a way to say so. It is deliberately a separate, explicit command rather than a flag on the check: an agent cannot run it as part of the same turn that removed the test, because the state file is in enforce's protected paths.

func Scan

func Scan(workspace string) (Measurement, error)

Scan measures the test surface of a workspace.

Assertion counting reuses enforce.CountAssertions, so the sentinel and the preToolUse rule can never disagree about what an assertion is.

type State

type State struct {
	// Peak is the best measurement seen, which is what current results are
	// compared against. A transient drop therefore stays visible rather than
	// quietly becoming the new normal.
	Peak      Measurement `json:"peak"`
	Last      Measurement `json:"last"`
	UpdatedAt string      `json:"updated_at"`
}

State is the persisted high-water mark.

func Load

func Load(workspace string) (State, bool, error)

Load reads the state, returning a zero State when none exists yet.

type Verdict

type Verdict struct {
	Current    Measurement
	Peak       Measurement
	Regressed  bool
	FirstRun   bool
	FilesLost  int
	AssertLost int
}

Verdict is the result of a check.

func Check

func Check(workspace string) (Verdict, error)

Check scans the workspace and compares against the stored peak.

The peak only ever rises. Recording a drop as the new baseline would let coverage ratchet down one turn at a time without a single warning, which is exactly the failure this package exists to catch.

func (Verdict) Detail

func (v Verdict) Detail() string

Detail renders a human-readable explanation.

Jump to

Keyboard shortcuts

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