SHELL := /bin/sh
.DEFAULT_GOAL := harness-help

# Resolve the harness directory from this Makefile's own location so every
# target works both standalone and as `make -f .harness/Makefile <target>`
# from a consuming project's root (cwd stays the project root).
#
# Every target carries the `harness-` prefix so a consuming project's own
# Makefile targets (setup, check, test, install, ...) can never be shadowed.
HARNESS_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))

# GNU make word-splits MAKEFILE_LIST, so a checkout path containing a space
# computes a WRONG fragment above. Probing the resolved path is NOT a safe
# guard: the fragment can collide with a real sibling checkout and every
# target would silently run against that wrong harness. The only reliable
# signal is upstream of resolution: this Makefile is always loaded alone
# (via `make -f` or as the repo's own Makefile), so MAKEFILE_LIST must be
# exactly one word - any embedded space makes it more. Fail closed with the
# workaround: the .agents scripts themselves are space-safe when invoked
# directly. (This also rejects `include`-ing this Makefile, which was never
# supported - the harness- prefix isolation exists so projects call it with
# `make -f` instead.)
ifneq ($(words $(MAKEFILE_LIST)),1)
$(error harness: load this Makefile alone via `make -f`, from a checkout path without spaces - GNU make cannot address a spaced path safely. Invoke the scripts directly instead, e.g. `node <harness>/.agents/checks/env-sort.mjs --check`)
endif
# The check above sees only the -f argument. A space-free RELATIVE -f from a
# spaced project directory passes it, and the space enters when $(abspath)
# prepends CURDIR - so re-check the resolved directory's word count too.
# Together the two checks are complete: both single-word means neither the
# argument nor CURDIR carries a space, so the resolution was faithful.
ifneq ($(words $(HARNESS_DIR)),1)
$(error harness: the project path contains a space, which GNU make cannot address safely - the harness targets would run against a split fragment. Invoke the scripts directly instead, e.g. `node .harness/.agents/checks/env-sort.mjs --check`)
endif
ifeq ($(wildcard $(HARNESS_DIR)/Makefile),)
$(error harness: cannot resolve its own directory (partial copy?). Re-clone or invoke the scripts directly, e.g. `node <harness>/.agents/checks/env-sort.mjs --check`)
endif

harness-setup: ## Install dependencies, wire git hooks, build CodeGraph, and verify this owned snapshot
	npm ci --prefix $(HARNESS_DIR)
	git config core.hooksPath .githooks
	$(MAKE) -f $(HARNESS_DIR)/Makefile harness-codegraph
	$(MAKE) -f $(HARNESS_DIR)/Makefile harness-check
	@command -v codex >/dev/null 2>&1 || printf "note: codex CLI not found - Claude->Codex delegation stays disabled until it is installed and logged in\n"

harness-install: ## Project: materialize the harness into the surrounding repository (idempotent)
	@# Vendor skills are embedded snapshots; setup never clones private source repositories.
	node $(HARNESS_DIR)/.agents/scripts/install.mjs $(INSTALL_FLAGS)
	npm ci --prefix $(HARNESS_DIR)
	$(MAKE) -f $(HARNESS_DIR)/Makefile harness-codegraph

harness-update: ## Re-materialize this project's owned canonical harness
	node $(HARNESS_DIR)/.agents/scripts/install.mjs

SKILLS_VENDOR ?= mattpocock-skills

harness-skills-update: ## Update the project-owned skill snapshots, then verify them
	npx skills update
	$(MAKE) -f $(HARNESS_DIR)/Makefile harness-test

harness-migrate: ## Project: remove known old-harness files (explicit, destructive)
	node $(HARNESS_DIR)/.agents/scripts/install.mjs migrate

harness-checks: harness-env-check harness-arch-scan harness-security-scan ## Project (profile checks+): run the whole check pack

harness-env-check: ## Project (profile checks+): env-layer hygiene - canonical order, bare lines, doc coverage
	@node $(HARNESS_DIR)/.agents/checks/env-sort.mjs --check
	@node $(HARNESS_DIR)/.agents/checks/env-doc-coverage.mjs

harness-env-fix: ## Project (profile checks+): rewrite the env bases into canonical order
	@node $(HARNESS_DIR)/.agents/checks/env-sort.mjs --write

harness-arch-scan: ## Project (profile checks+): module-size ratchet + structure signals
	@bash $(HARNESS_DIR)/.agents/checks/arch-scan.sh

harness-security-scan: ## Project (profile checks+): tracked-env policy + secret patterns + optional scanners
	@bash $(HARNESS_DIR)/.agents/checks/security-scan.sh

harness-blast-radius: ## Project (profile checks+): git-derived change-impact report
	@bash $(HARNESS_DIR)/.agents/checks/blast-radius.sh

harness-new-service: ## Project (profile platform): scaffold NAME=<n> KIND=<public-http|internal-http|worker|job> SERVICE_LANG=<python|node>
	@bash $(HARNESS_DIR)/.agents/scaffold/new-service.sh

harness-check: ## Standalone: full contract tests, whitespace check, dependency audit
	$(MAKE) -f $(HARNESS_DIR)/Makefile harness-test
	git diff --check
	cd $(HARNESS_DIR) && npm audit --audit-level=high

harness-check-imported: ## Project: harness self-tests plus materialization drift check (offline)
	node --test $(HARNESS_DIR)/.agents/tests/git-guard.test.mjs $(HARNESS_DIR)/.agents/tests/adapters.test.mjs
	node $(HARNESS_DIR)/.agents/scripts/install.mjs --check

harness-test: ## Run the harness test suite (Node test runner)
	AGENT_GIT_GUARD=on AGENT_PY_GUARD=on node --test $(HARNESS_DIR)/.agents/tests/*.test.mjs

harness-codegraph: ## Initialize or incrementally sync the CodeGraph index (idempotent)
	@if [ ! -x $(HARNESS_DIR)/node_modules/.bin/codegraph ]; then printf "ERROR: run 'npm ci --prefix $(HARNESS_DIR)' first\n"; exit 1; fi
	@if [ ! -d .codegraph ]; then $(HARNESS_DIR)/node_modules/.bin/codegraph init -i; else $(HARNESS_DIR)/node_modules/.bin/codegraph sync; fi

harness-help: ## Show this help
	@grep -E '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "  %-24s %s\n", $$1, $$2}'

.PHONY: harness-setup harness-install harness-update harness-skills-update harness-migrate harness-checks harness-env-check harness-env-fix harness-arch-scan harness-security-scan harness-blast-radius harness-new-service harness-check harness-check-imported harness-test harness-codegraph harness-help
