Third refactor-induced defect caught from yesterday's v7+v8 → substrate rename (`bae5caf` for the package, `209d670` for the Makefile). Same pattern: a callsite that text-search misses because the import path doesn't connect through Python. CI surface (the `v8-score:` GitLab CI job) had two issues: 1. Job name `v8-score:` was a UX surface — operators see it in the GitLab MR pipeline UI. Renamed to `substrate-score:` for consistency with the package name + the CLI subcommand. 2. Script line called ``.venv/bin/arborist v8 score …``. Would have failed on the next manual MR pipeline run with an argparse "invalid choice: 'v8'" error. Comment block (lines 80-90 + 115-125) refreshed to call out the distinction: ``v8 paper`` (the substrate-paper version, name preserved per published convention) vs the module location (``arborist/substrate/fork_score.py`` post-2026-05-10 rename). Sweep verified: ``grep -rnE "arborist v[0-9]\\b|arborist\\.v[78]\\b"`` across the entire tree returns only intentional historical-note comments + the placeholder-seed bytestring derivation (which cannot change without invalidating KAT vectors). Three loose ends from one refactor: -85be5eb: fork_score.py import (Python imports caught by tests) -209d670: Makefile bench-fork-score target (would surface on run) - this: .gitlab-ci.yml job (would surface on next MR pipeline) Lesson written across the three commits: text-search-replace on a CLI rename misses callsites that argparse processes at runtime. Pre-rename checklist for next time: ``grep -rn "<cli-old-name>" Makefile .gitlab-ci.yml .github/workflows scripts bench``.
200 lines
7.3 KiB
YAML
200 lines
7.3 KiB
YAML
# GitLab CI for arborist.
|
|
#
|
|
# Runs the unit test suite on every push. Lives at the same shape as
|
|
# the sibling repos (`unsandbox.com`, `unfirehose-nextjs-logger`):
|
|
# `tags: build` selects the in-house runner; `before_script` warms up
|
|
# the venv; `script` runs the actual gate.
|
|
#
|
|
# What's NOT in CI:
|
|
# - `make test-live` — needs the live Hermes endpoint + populated
|
|
# shards under ~/.arborist/shards. Run by hand via `make test-live`
|
|
# when iterating on QA quality.
|
|
# - `make test-crawler` — needs `[crawler]` extras + network access
|
|
# to real HTML sites. Opt-in via `make test-crawler` locally.
|
|
# - `make bench-qa` — runs the live LLM bench, ~30-70 min wall-clock.
|
|
# Run on demand via `make bench-qa-{quick,smoke}` (10s / 30s) or
|
|
# full `make bench-qa` (full sweep).
|
|
|
|
# Pipeline RE-ENABLED 2026-05-09 with `test-ci` (skips wikipedia
|
|
# ingest tests; full suite still available locally via `make test`).
|
|
# Originally disabled 2026-05-02 because bench infrastructure
|
|
# overlapped with the runner pool; mitigation today is the
|
|
# `test-ci` scope cap + per-job parallelism cap
|
|
# (PYTEST_XDIST_AUTO_NUM_WORKERS=4) so CI doesn't crowd live bench
|
|
# work.
|
|
|
|
stages:
|
|
- test
|
|
|
|
variables:
|
|
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.pip-cache"
|
|
# Pin the parallelism factor so we don't oversubscribe on shared
|
|
# runners. pytest-xdist's `-n auto` reads `os.cpu_count()` which on
|
|
# cgroup-limited containers can over-report the host's cores. Setting
|
|
# this var caps the worker count regardless. Local `make test` keeps
|
|
# using -n auto (untouched by this var).
|
|
PYTEST_XDIST_AUTO_NUM_WORKERS: "4"
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Default test job — runs the CI-scoped suite via `make test-ci`,
|
|
# which is `make test` minus tests/crawler (network) and the
|
|
# wikipedia ingest tests (`test_wikipedia_old.py`,
|
|
# `test_wikipedia_xml.py`; their runtime path is exercised end-to-end
|
|
# by real ingest under `make ingest-*` so the synthetic fixtures
|
|
# duplicate coverage). pytest-xdist `-n auto` parallelism is capped
|
|
# by PYTEST_XDIST_AUTO_NUM_WORKERS so cgroup-limited containers
|
|
# don't oversubscribe the host. Local `make test` stays
|
|
# comprehensive for the dev loop.
|
|
# ----------------------------------------------------------------------
|
|
test:
|
|
stage: test
|
|
tags:
|
|
- build
|
|
cache:
|
|
# Key on pyproject.toml so dependency churn invalidates the cache;
|
|
# otherwise reuse the venv across CI runs to avoid re-installing
|
|
# editable + dev extras on every push.
|
|
key:
|
|
files:
|
|
- pyproject.toml
|
|
paths:
|
|
- .venv/
|
|
- .pip-cache/
|
|
before_script:
|
|
- python3 --version
|
|
- test -d .venv || python3 -m venv .venv
|
|
- .venv/bin/pip install --upgrade pip wheel
|
|
- .venv/bin/pip install -e '.[dev]'
|
|
script:
|
|
# `make test-ci` invokes pytest with --ignore=tests/crawler
|
|
# plus --ignore on the two wikipedia ingest test files.
|
|
# PYTEST_XDIST_AUTO_NUM_WORKERS env var caps the worker count on
|
|
# the runner; locally `-n auto` uses the full machine.
|
|
- make test-ci
|
|
artifacts:
|
|
when: on_failure
|
|
paths:
|
|
- .pytest_cache/
|
|
expire_in: 1 week
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Bench gate — runs the complete Dav1DPrometheus suite (5S + 5T + 5F
|
|
# + 5R = 21 sub-batteries, 462+ deterministic fixtures) on every push.
|
|
# Job fails if any fixture fails. Bench result JSON is stored as a
|
|
# pipeline artifact so the substrate-score job (below) can compare branches.
|
|
# Wall-clock ~3-5s on the in-house runner; cheaper than `make test`.
|
|
#
|
|
# Closes the loop from "we have a fitness substrate" (#000021,
|
|
# #000023-25) to "every push is gated by it." Phase 1 of #000012 +
|
|
# the 2026-05-08 fox roadmap note.
|
|
# ----------------------------------------------------------------------
|
|
bench-suite:
|
|
stage: test
|
|
tags:
|
|
- build
|
|
cache:
|
|
key:
|
|
files:
|
|
- pyproject.toml
|
|
paths:
|
|
- .venv/
|
|
- .pip-cache/
|
|
before_script:
|
|
- python3 --version
|
|
- test -d .venv || python3 -m venv .venv
|
|
- .venv/bin/pip install --upgrade pip wheel
|
|
- .venv/bin/pip install -e '.[dev]'
|
|
script:
|
|
- mkdir -p bench/results
|
|
- .venv/bin/python -m bench.batteries.runner --all --out bench/results/bench-${CI_COMMIT_SHORT_SHA}.json
|
|
artifacts:
|
|
paths:
|
|
- bench/results/
|
|
expire_in: 30 days
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Substrate ForkScore gate — for merge requests, score the bench
|
|
# delta between this branch and main. ACCEPT or MARGINAL pass;
|
|
# REJECT fails the job. Phase 1 of #000012's selection protocol; the
|
|
# consensus layer (validators, slashing, fork-choice) lives in the
|
|
# Merkle-AGI v8 paper itself (paper version, not module location —
|
|
# the module is at arborist/substrate/fork_score.py per the
|
|
# 2026-05-10 v7+v8 → substrate refactor).
|
|
#
|
|
# This job is `manual` for now — auto-gating waits until the v8
|
|
# paper pins weight-set defaults for arborist's deployment shape.
|
|
# Operators trigger it on demand from the MR UI.
|
|
# ----------------------------------------------------------------------
|
|
substrate-score:
|
|
stage: test
|
|
tags:
|
|
- build
|
|
rules:
|
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
when: manual
|
|
allow_failure: true
|
|
- when: manual
|
|
allow_failure: true
|
|
needs:
|
|
- job: bench-suite
|
|
artifacts: true
|
|
cache:
|
|
key:
|
|
files:
|
|
- pyproject.toml
|
|
paths:
|
|
- .venv/
|
|
- .pip-cache/
|
|
before_script:
|
|
- test -d .venv || python3 -m venv .venv
|
|
- .venv/bin/pip install --upgrade pip wheel
|
|
- .venv/bin/pip install -e '.[dev]'
|
|
script:
|
|
# Find this branch's bench result.
|
|
- CHILD=$(ls -t bench/results/bench-*.json | head -1)
|
|
# Pull main's most recent bench result via the latest pipeline
|
|
# artifact. The runner exposes CI_API_V4_URL + CI_PROJECT_ID;
|
|
# we curl the artifacts endpoint for the latest main pipeline's
|
|
# bench-suite job.
|
|
- |
|
|
curl -sf -H "PRIVATE-TOKEN: ${CI_JOB_TOKEN}" \
|
|
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/jobs/artifacts/main/raw/bench/results/?job=bench-suite" \
|
|
-o /tmp/parent-bench.zip 2>/dev/null && \
|
|
unzip -p /tmp/parent-bench.zip 'bench/results/bench-*.json' \
|
|
> /tmp/parent.json || \
|
|
echo '{"schema_version":"bench-result-v1","results":[]}' > /tmp/parent.json
|
|
# Score child vs parent. Exit 1 on REJECT (gates the merge).
|
|
- .venv/bin/arborist substrate score --parent /tmp/parent.json --child "$CHILD"
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Optional: crawler extras + crawler-tagged tests. Opt-in via the
|
|
# `crawler` keyword so it doesn't gate every push (network access +
|
|
# heavier deps).
|
|
# ----------------------------------------------------------------------
|
|
test-crawler:
|
|
stage: test
|
|
tags:
|
|
- build
|
|
rules:
|
|
# Only run when explicitly invoked or commit message asks for it.
|
|
- if: '$CI_COMMIT_MESSAGE =~ /\[ci-crawler\]/'
|
|
- when: manual
|
|
allow_failure: true
|
|
cache:
|
|
key:
|
|
files:
|
|
- pyproject.toml
|
|
paths:
|
|
- .venv/
|
|
- .pip-cache/
|
|
before_script:
|
|
- test -d .venv || python3 -m venv .venv
|
|
- .venv/bin/pip install --upgrade pip wheel
|
|
- .venv/bin/pip install -e '.[dev,crawler]'
|
|
script:
|
|
- make test-crawler
|
|
artifacts:
|
|
when: on_failure
|
|
paths:
|
|
- .pytest_cache/
|
|
expire_in: 1 week
|