# Backend battery as one command. `make battery` IS the manual battery every session used to retype;
# it is the entry point CI will call, so what runs locally and what runs there cannot drift.
#
# Run from backend/. Toolchain and linter are PINNED here (never "latest"): the linter's findings are a
# gate, and a gate that changes under you on someone else's machine is not a gate.

GO ?= go
GO_MIN_VERSION := 1.26.4
GOLANGCI_LINT ?= golangci-lint
GOLANGCI_VERSION := 2.12.2
# backend/bin/ is already gitignored, so the vet tool leaves no untracked file behind.
TMVET := bin/tmvet

.PHONY: build vet fmt lint test battery battery-stand tools-check

build: tools-check
	$(GO) build ./...

# `-vettool` REPLACES the standard vet suite rather than adding to it (measured: a copylocks finding
# that plain `go vet` reports disappears under -vettool), so both passes have to run. Both tag sets too:
# the paid `live` tests compile only under -tags live and would otherwise rot unseen.
vet:
	$(GO) vet ./...
	$(GO) vet -tags live ./...
	$(GO) build -o $(TMVET) ./cmd/tmvet
	$(GO) vet -vettool=$(TMVET) ./...
	$(GO) vet -tags live -vettool=$(TMVET) ./...

# `gofmt -l` exits 0 even when it names files, so the emptiness of its output is the assertion.
fmt:
	@test -z "$$(gofmt -l .)" || { echo "gofmt: not formatted:"; gofmt -l .; exit 1; }

tools-check:
	@$(GO) version | grep -qE 'go1\.(2[6-9]|[3-9][0-9])' || { \
		echo "Go $(GO_MIN_VERSION)+ required (go.mod floor); got: $$($(GO) version)"; exit 1; }
	@$(GOLANGCI_LINT) --version 2>/dev/null | grep -q " $(GOLANGCI_VERSION) " || { \
		echo "golangci-lint $(GOLANGCI_VERSION) required (findings are version-dependent)."; \
		echo "install: https://github.com/golangci/golangci-lint/releases/tag/v$(GOLANGCI_VERSION)"; exit 1; }

lint: tools-check
	$(GOLANGCI_LINT) run --timeout=15m ./...

# -race needs cgo (a C toolchain). If it is missing this fails loudly — dropping -race would turn a
# missing toolchain into a green run that proved less than it claims.
#
# The PER-PACKAGE timeout is stated rather than left at Go's 10-minute default, because under the load
# this project treats as normal the default is not far enough away to be one. `internal/pipeline` under
# -race has been measured from ~95 s on a quiet host to ~560 s with three parallel agent sessions
# sharing it — a 6x spread on load alone — and past the default the whole battery ends in a per-package
# timeout that looks like a failure and is not one (it has done so twice). Raising the ceiling weakens
# no assertion: the same tests run, to completion. A package that genuinely hangs still fails, twenty
# minutes later.
test:
	$(GO) test ./... -race -count=1 -timeout=20m

# The hermetic battery: everything that is green on a bare clone. It ends by NAMING the tests that did
# not run, because a skip is invisible in `ok` lines and a silent skip reads as coverage.
battery: build vet fmt lint test
	@echo "--- did NOT run (no stand data; see battery-stand) ---"
	@$(GO) test ./... -count=1 -v > .skips.log 2>&1 || { echo "the skip-harvest pass FAILED:"; \
		grep -E '^(---|\s+---) FAIL|^FAIL' .skips.log; rm -f .skips.log; exit 1; }
	@grep -- '--- SKIP' .skips.log || echo "(none)"
	@rm -f .skips.log

# The stand battery: adds the corpus-gated tests. With the flags set, MISSING data fails instead of
# skipping, so "the corpus is here" is asserted rather than assumed.
battery-stand: build vet fmt lint
	TM_MINER_PARITY=1 TM_CHECKER_LABELS=1 $(GO) test ./... -race -count=1 -timeout=20m
