verify

package
v0.6.0 Latest Latest
Warning

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

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

Documentation

Overview

Package verify maps a set of changed repository paths to focused verification checks, and pairs them with the repository's always-required full gates, per ADR-0032 ("Agent-First Development Experience"), P0: "Add focused agent verification with explicit skipped statuses" (Jira MOD-63), step 5 of the ADR's "Standard agent workflow":

`modulex agent verify` runs focused checks followed by required
repository gates and reports skipped checks separately from
successful checks.

verify is a standalone leaf package (github.com/mediusfy/modulex/verify), like provenance and discovery: it does not import the core modulex package. It depends on provenance for the Status/VerificationCategory/ VerificationResult types (so a future `modulex agent handoff` can consume this package's output directly without translation) and on discovery for discovery.ToolStatus (so tool-availability gating uses the same data discovery.Discover already produces, rather than re-probing PATH itself).

changedFiles is untrusted input

changedFiles typically comes from a diff (e.g. `git diff --name-only`) and may include paths from an external contribution this agent did not author. PlanFor never uses a changed path to build a CheckSpec.Command unless the path passes isPathSafeForCommand (letters, digits, '_', '-', '.', '/' only, no ".." traversal segment) — a path containing shell metacharacters is routed to fallbackToFullGates instead, so it can never inject shell syntax into a Command that Run later executes via "sh -c". See TestPlanFor_RejectsShellMetacharactersInPath for the regression test.

Focused vs. full: two mandatory outputs, not alternatives

PlanFor produces a Plan with two fields:

  • FocusedChecks: checks recommended because of what actually changed — a spot-check, cheap to run, scoped to the affected package(s).
  • FullGates: the fixed, complete list of this repository's required gates (make build, test, test-arch, lint, and the boundary/ compatibility/changelog scripts), unconditionally, every time.

FullGates is never a function of changedFiles. This is deliberate: per ADR-0032's acceptance criterion "Full gates remain required before push or release," a caller must never be able to skip the full gate set just because the focused checks looked sufficient. Nothing in this package's API lets FocusedChecks stand in for FullGates.

Why PlanFor, not Plan

The ticket's sketch named the function Plan, returning a type also named Plan. Go does not allow a function and a type to share one identifier in the same package, so the function is named PlanFor instead. PlanFor takes only changedFiles, not a discovery.Repository: every mapping rule below is derived from path shape alone (path prefixes/suffixes), never from repository contents, so no repository context is needed to select focused checks. (Run, by contrast, does need discovery.ToolStatus data, because tool availability is an environment fact PlanFor cannot know from paths alone.)

The tool/network fields on CheckSpec

CheckSpec carries RequiredTool and Networked fields beyond the ticket's minimal sketch (Name, Command, Category, Reason). This keeps the "what does this check need" decision entirely inside this package (made once, here, when a CheckSpec is constructed) rather than making Run re-parse or pattern-match Command strings to guess at a dependency — Run stays a generic executor that works for any CheckSpec, from any caller, without needing to understand this repository's specific command vocabulary.

Known gaps (documented, not engineered around)

The per-file mapping in focusedChecksForFile is a reasonable rule table for this repository's actual layout, not an exhaustive or fully general solution:

  • A changed file inside a nested Go module other than the root module (examples/external-consumer/*.go, tools/modboundary/*.go) is mapped the same way as a root-module package directory (go test ./<dir>/...), which is not necessarily a valid build target from the root module's perspective. A future revision could consult discovery.Repository. Modules to find the nearest enclosing module and rewrite the command accordingly; PlanFor's signature deliberately leaves room for that (see "Why PlanFor, not Plan" above) without requiring it today.
  • The examples/ rule identifies "the specific example's own tests" by taking the first path segment after examples/; it does not verify that segment is actually one of discovery.Repository.CompositionRoots.

Index

Constants

This section is empty.

Variables

View Source
var FullGates = []CheckSpec{
	{
		Name:         "build",
		Command:      "make build",
		Category:     provenance.VerificationFull,
		Reason:       "compiles all packages and examples; required before any push or release per AGENTS.md",
		RequiredTool: "go",
	},
	{
		Name:         "test",
		Command:      "make test",
		Category:     provenance.VerificationFull,
		Reason:       "runs the full test suite; required before any push or release per AGENTS.md",
		RequiredTool: "go",
	},
	{
		Name:         "test-arch",
		Command:      "make test-arch",
		Category:     provenance.VerificationFull,
		Reason:       "runs the full test suite under the race detector; required before any push or release per AGENTS.md",
		RequiredTool: "go",
	},
	{
		Name:         "lint",
		Command:      "make lint",
		Category:     provenance.VerificationFull,
		Reason:       "runs golangci-lint across the repository; required before any push or release per AGENTS.md",
		RequiredTool: "golangci-lint",
	},
	{
		Name:         "check-consumer-boundary",
		Command:      "make check-consumer-boundary",
		Category:     provenance.VerificationFull,
		Reason:       "verifies a consumer importing only the core package does not compile in an integration adapter as a build dependency",
		RequiredTool: "go",
	},
	{
		Name:         "check-module-boundary",
		Command:      "make check-module-boundary",
		Category:     provenance.VerificationFull,
		Reason:       "runs the modboundary analyzer against examples/deployment to enforce feature-module boundaries",
		RequiredTool: "go",
	},
	{
		Name:         "check-api-compat",
		Command:      "make check-api-compat",
		Category:     provenance.VerificationFull,
		Reason:       "reports public API changes since the latest git tag",
		RequiredTool: "go",
	},
	{
		Name:         "check-changelog",
		Command:      "make check-changelog",
		Category:     provenance.VerificationFull,
		Reason:       "verifies CHANGELOG.md is updated when required (PR diff vs origin/main)",
		RequiredTool: "git",
	},
}

FullGates is the fixed, complete list of this repository's required gates before push or release, per AGENTS.md ("`make test-arch`, `make build`, `make lint`, and `make test` must all pass locally before pushing") and the boundary/compatibility/changelog scripts already wired into the Makefile. Exported so a caller (or CI) can iterate the canonical list without hardcoding it themselves.

Treat this as read-only. PlanFor and callers that want their own copy should use a defensive copy (PlanFor does this internally); mutating an element of this slice in place would affect every future PlanFor call.

Functions

func RenderText

func RenderText(results []provenance.VerificationResult) string

RenderText renders results as a human-readable, multi-line summary, grouped by provenance.VerificationCategory, suitable for pasting into a PR comment or printing to a terminal. This is the "human-readable" counterpart to results' existing machine-readable form ([]provenance.VerificationResult, already JSON-marshalable as-is).

Within each category, results are rendered in the order they appear in results (Run preserves the order of its input checks, so this is typically focused-checks-then-full-gates order); categories themselves are rendered in alphabetical order for stable output regardless of how results was assembled.

func Run

func Run(ctx context.Context, checks []CheckSpec, tools []discovery.ToolStatus, allowNetwork bool) []provenance.VerificationResult

Run executes every check in checks and returns exactly one provenance.VerificationResult per input CheckSpec, in the same order — this 1:1 correspondence is the core "does not silently treat missing tools as success" guarantee from ADR-0032/Jira MOD-63: nothing in checks can disappear from the result set, and every result's Status is one of the five explicit provenance.Status values, never inferred as success by omission.

tools is the discovery.Discover output's Tools field (or an equivalent slice), used to gate any CheckSpec with a non-empty RequiredTool: if the named tool is not Present, Run reports StatusUnavailable with a Reason naming the missing tool and does NOT attempt to run the check's Command at all — no process is spawned, so a check requiring a missing tool can never accidentally "pass" by running something else on PATH with a similar name, and can never hang or error in a way that gets confused with an actual failure.

allowNetwork gates any CheckSpec with Networked set: when false, such a check is reported as StatusSkipped with an explanatory Reason instead of being run. The ticket's sketch signature omitted this parameter ("accept an explicit allowNetwork bool parameter or a similar environment- capability flag the caller passes in"); it is added here as an explicit argument rather than folded into CheckSpec or inferred from the environment, since real network-reachability detection is out of scope and an explicit caller-supplied flag is what the ticket asked for.

Every other check is actually executed via "sh -c <Command>", with ctx honored for cancellation/timeout. Exit code 0 maps to StatusPass; any other outcome (nonzero exit, or ctx cancellation) maps to StatusFail. Combined stdout+stderr is captured into Message, truncated per maxOutputBytes.

Types

type CheckSpec

type CheckSpec struct {
	// Name is a short, stable identifier for this check (e.g. "test-httpx",
	// "lint"), suitable as a map key or a provenance.VerificationResult.Name.
	Name string
	// Command is the shell command line that performs this check (e.g. "go
	// test ./httpx/..."), executed by Run via "sh -c".
	Command  string
	Category provenance.VerificationCategory
	// Reason explains why this check was selected (for a focused check) or
	// why it is always required (for a full gate).
	Reason string
	// RequiredTool is the discovery.ToolStatus.Name this check depends on
	// (e.g. "golangci-lint", "go", "git"), or "" if the check has no such
	// dependency Run should verify before attempting it.
	RequiredTool string
	// Networked marks a check that performs network I/O. Run skips these
	// when its caller's allowNetwork argument is false.
	Networked bool
}

CheckSpec describes one verification check: a human-readable name, the shell command that performs it, the provenance category it belongs to, and why it was selected. The same type is used for both Plan. FocusedChecks and Plan.FullGates/FullGates — a full gate is just a CheckSpec whose Category is provenance.VerificationFull instead of provenance.VerificationFocused.

type Plan

type Plan struct {
	// FocusedChecks are the checks PlanFor recommends given changedFiles.
	// Always non-nil (possibly empty — see the package doc's ".github/
	// workflows" note in focusedChecksForFile) and deterministically
	// ordered (sorted by Category then Name), so two calls with the same
	// changedFiles in a different order produce identical output.
	FocusedChecks []CheckSpec
	// FullGates is always a copy of the package-level FullGates slice,
	// regardless of changedFiles.
	FullGates []CheckSpec
}

Plan is the output of mapping a set of changed files to focused checks, paired with the repository's always-required full gates. See the package doc comment's "Focused vs. full" section for why both fields are always present and neither can substitute for the other.

func PlanFor

func PlanFor(changedFiles []string) Plan

PlanFor maps changedFiles (paths relative to the repository root, e.g. "httpx/httpx.go") to a Plan: focused checks recommended by what changed, plus the repository's full gates, unconditionally.

See the package doc comment for the reasoning behind this name (not Plan), the focused/full distinction, and known gaps in the mapping rules.

Jump to

Keyboard shortcuts

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