Closes #120 (items 2 and the suggested gate fix).
`task build` has been broken since `cmd/supervisor` was deleted in c117634, and
CI stayed green the entire time. That combination is the finding: not that a
path went stale, but that nothing could notice.
`check` ran lint, test and vet. All three walk `./...`, which enumerates the
packages that EXIST. A build target naming a DELETED package is invisible to
every one of them — `go vet ./...` cannot complain about a directory it never
visits. The gate was complete with respect to the code present and blind to the
code referenced.
`build` is now part of `check`, with that reasoning written above it.
Flip-tested: reintroducing `go build ./cmd/supervisor` takes `task check` to
exit 201, naming the missing directory.
Removed, all pointing at binaries that no longer exist:
- `supervisor:dev` and `supervisor:build` -> ./cmd/supervisor
- `supervisor:test:smoke` -> curls a server nothing can start
- `smoke:routing` + scripts/smoke-routing.sh -> ./cmd/routing
- the `supervisor:` line in Procfile, which also still pointed
SUPERVISOR_MODELS_FILE at the file deleted in #116
`build` now aggregates `hyperguild:build` + `ingestion:build`, the two binaries
that actually exist.
A false lead worth recording so it is not re-investigated: a first sweep flagged
`./cmd/server` and `./cmd/frontmatterlint` as missing too. They are not — their
tasks set `dir: ingestion`, and both exist under `ingestion/cmd/`. Any checker
for this class has to resolve a task's working directory before judging its
paths, or it reports two false positives for every true one.
Not addressed here: #120's third item, that `internal/config` has zero non-test
callers. `RoutingConfig` is the only written record of the routing pod's
configuration contract, so deleting it is a judgement call rather than a
correction.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
192 lines
7.5 KiB
YAML
192 lines
7.5 KiB
YAML
version: '3'
|
|
|
|
vars:
|
|
PROJECT_NAME: hyperguild
|
|
VERSION:
|
|
sh: git describe --tags --always --dirty 2>/dev/null || echo "dev"
|
|
SHORT_SHA:
|
|
sh: git rev-parse --short HEAD
|
|
|
|
tasks:
|
|
context:sync:
|
|
desc: Regenerate all harness-specific context files
|
|
cmds:
|
|
- bash scripts/context-sync.sh
|
|
|
|
context:sync:claude:
|
|
cmds: [bash scripts/context-sync.sh claude]
|
|
context:sync:agents:
|
|
cmds: [bash scripts/context-sync.sh agents]
|
|
|
|
# ── Development ────────────────────────────────────────────────────────────
|
|
|
|
start:
|
|
desc: Start ingestion (requires goreman — go install github.com/mattn/goreman@latest)
|
|
cmds:
|
|
- goreman start
|
|
|
|
stop:
|
|
desc: Stop all hyperguild processes (Ctrl-C in the goreman terminal, or kill by port)
|
|
cmds:
|
|
- lsof -ti:3300 | xargs kill -9 2>/dev/null || true
|
|
- lsof -ti:3200 | xargs kill -9 2>/dev/null || true
|
|
- echo "hyperguild stopped"
|
|
|
|
hyperguild:dev:
|
|
desc: Run hyperguild CLI from source (e.g. task hyperguild:dev -- tier)
|
|
cmds:
|
|
- go run ./cmd/hyperguild {{.CLI_ARGS}}
|
|
|
|
hyperguild:build:
|
|
desc: Build the hyperguild binary into ./bin/hyperguild
|
|
cmds:
|
|
- mkdir -p bin
|
|
- go build -o bin/hyperguild ./cmd/hyperguild
|
|
|
|
hyperguild:install:
|
|
desc: Install hyperguild into $GOBIN
|
|
cmds:
|
|
- go install ./cmd/hyperguild
|
|
|
|
ingestion:dev:
|
|
desc: Run ingestion server in development mode
|
|
dir: ingestion
|
|
env:
|
|
INGEST_BRAIN_DIR: "{{.ROOT_DIR}}/brain"
|
|
INGEST_PORT: "3300"
|
|
cmds:
|
|
- go run ./cmd/server
|
|
|
|
# ── Build ──────────────────────────────────────────────────────────────────
|
|
|
|
build:
|
|
desc: Build all binaries
|
|
cmds:
|
|
- task: hyperguild:build
|
|
- task: ingestion:build
|
|
|
|
ingestion:build:
|
|
desc: Build ingestion server binary
|
|
dir: ingestion
|
|
cmds:
|
|
- go build -trimpath -ldflags="-s -w" -o ../bin/ingestion-server ./cmd/server
|
|
|
|
# ── Quality ────────────────────────────────────────────────────────────────
|
|
|
|
check:
|
|
desc: Run all checks (context freshness + lint + test + vet + build) across all modules
|
|
cmds:
|
|
# Context sync is skipped under CI, matching dma-cli, gitea-mcp, and the
|
|
# rest of the estate. It is not a preference: context-sync.sh walks UP
|
|
# the tree for the canonical .context/AGENT.md, which lives in local-dev
|
|
# and does not exist on a CI runner. Without this guard, the script
|
|
# silently falls back to "project context only" and regenerates AGENTS.md
|
|
# and .context/system-prompt.txt shorter than their committed, correct
|
|
# versions -- so the drift assertion fails every CI run for a purely
|
|
# environmental reason, not real drift. Verified, not assumed: this is
|
|
# exactly what was happening here (AGENTS.md 430 lines committed vs. an
|
|
# 82-line regeneration on the runner).
|
|
#
|
|
# The cost is real and worth stating: drift is therefore only ever caught
|
|
# on a developer machine, or by infra's estate-wide context-sync-drift
|
|
# CronJob (ADR-0019), which does have canonical access and is the actual
|
|
# enforcement mechanism now.
|
|
- cmd: |
|
|
if [ -n "${CI:-}" ]; then
|
|
echo "✓ context sync: skipped in CI (no canonical AGENT.md on the runner)"
|
|
else
|
|
bash scripts/context-sync.sh
|
|
drift=$(git status --porcelain -- AGENTS.md CLAUDE.md .context/system-prompt.txt 2>/dev/null)
|
|
if [ -n "$drift" ]; then
|
|
echo "ERROR: derived adapters drifted from canonical context." >&2
|
|
echo "$drift" >&2
|
|
echo "" >&2
|
|
echo "Run: git add AGENTS.md CLAUDE.md .context/system-prompt.txt" >&2
|
|
echo " git commit -m 'chore: re-sync context adapters'" >&2
|
|
exit 1
|
|
fi
|
|
echo "✓ context: canonical and adapters are in sync"
|
|
fi
|
|
- task: lint
|
|
- task: test
|
|
- task: vet
|
|
# `build` is in the gate deliberately (hyperguild#120). vet and test walk
|
|
# ./... , which enumerates the packages that EXIST — so a build target
|
|
# naming a DELETED package is invisible to both. `task build` pointed at
|
|
# ./cmd/supervisor for months after that directory was removed, and CI
|
|
# stayed green the whole time because nothing in check ever built.
|
|
- task: build
|
|
- task: security:gitleaks
|
|
|
|
# ── Security ─────────────────────────────────────────────
|
|
security:gitleaks:
|
|
desc: Scan the working tree for secrets (gitleaks, fail-closed; skipped if gitleaks absent)
|
|
dir: '{{.ROOT_DIR}}'
|
|
cmds:
|
|
- |
|
|
GL="$(command -v gitleaks || true)"
|
|
[ -z "$GL" ] && [ -x "$(go env GOPATH 2>/dev/null)/bin/gitleaks" ] && GL="$(go env GOPATH)/bin/gitleaks"
|
|
if [ -z "$GL" ]; then
|
|
echo "⚠ gitleaks not installed — skipping secret scan (CI enforces it)."
|
|
echo " Install: go install github.com/zricethezav/gitleaks/v8@latest"
|
|
exit 0
|
|
fi
|
|
"$GL" detect --no-git --redact --config .gitleaks.toml --source .
|
|
|
|
security:gitleaks:history:
|
|
desc: "One-time FULL-HISTORY secret audit (infra#39 rotation pass; not a per-push gate)"
|
|
dir: '{{.ROOT_DIR}}'
|
|
cmds:
|
|
- |
|
|
GL="$(command -v gitleaks || true)"
|
|
[ -z "$GL" ] && [ -x "$(go env GOPATH 2>/dev/null)/bin/gitleaks" ] && GL="$(go env GOPATH)/bin/gitleaks"
|
|
if [ -z "$GL" ]; then
|
|
echo "gitleaks not installed: go install github.com/zricethezav/gitleaks/v8@latest" >&2
|
|
exit 2
|
|
fi
|
|
echo "Scanning FULL git history (redacted). Known historical leaks are expected"
|
|
echo "until the infra#39 rotation pass completes — triage against the rotation list."
|
|
"$GL" detect --redact --config .gitleaks.toml
|
|
|
|
lint:
|
|
cmds:
|
|
- golangci-lint run ./...
|
|
- cd ingestion && golangci-lint run ./...
|
|
|
|
lint:frontmatter:
|
|
desc: Report brain notes whose YAML frontmatter does not parse (BRAIN=path, FIX=1 repairs in place)
|
|
cmds:
|
|
- cd ingestion && go run ./cmd/frontmatterlint {{if .FIX}}-fix{{end}} {{.BRAIN | default "../../brain"}}
|
|
|
|
test:
|
|
cmds:
|
|
- go test -race -count=1 ./...
|
|
- cd ingestion && go test -race -count=1 ./...
|
|
|
|
vet:
|
|
cmds:
|
|
- go vet ./...
|
|
- govulncheck ./... || true
|
|
- cd ingestion && go vet ./...
|
|
|
|
# ── Git / Release ──────────────────────────────────────────────────────────
|
|
|
|
tag:
|
|
desc: Create and push a semver tag (usage — task tag version=v1.2.3)
|
|
preconditions:
|
|
- sh: '[[ "{{.version}}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]'
|
|
msg: "version must be semver, e.g. v1.2.3 or v1.2.3-rc.1"
|
|
- sh: "git diff --quiet && git diff --cached --quiet"
|
|
msg: "working tree must be clean before tagging"
|
|
cmds:
|
|
- git tag -a {{.version}} -m "Release {{.version}}"
|
|
- git push origin {{.version}}
|
|
|
|
push:
|
|
desc: Push current branch and tags to origin
|
|
vars:
|
|
BRANCH:
|
|
sh: git rev-parse --abbrev-ref HEAD
|
|
cmds:
|
|
- git push origin {{.BRANCH}} --tags
|