Files
shockbot/test/providers.ts
T
Colin McDonnell 1f4c3031be ci: filter test matrices by per-test coverage globs (#730)
* ci: filter test matrices by per-test coverage globs to cut LLM spend

every test in `crossagent/`, `agnostic/`, and every provider entry now
declares a `coverage: string[]` of repo-relative globs. the new `changes`
job runs `paths-filter` for a docs-only short-circuit, then pipes the
changed-file list into `action/test/matrix.ts`, which intersects each
entry's coverage against the diff and emits filtered `agents`,
`agnostic`, `flagships`, and `aliases` matrices. main pushes and
`workflow_dispatch` set `FULL=1` to run everything as a stale-glob safety
net.

retires `changed-agents.sh` and the `MODE=flagships` branch in
`list-aliases.ts` in favor of one consistent model.

* ci(matrix): switch test discovery to dep-free static parsing

the GHA `changes` job has no `node_modules` installed. the previous
dynamic-import path pulled the test files transitively through
`utils.ts` -> `agents/index.ts` -> `@actions/core`, which exploded with
ERR_MODULE_NOT_FOUND. parse the test files via regex instead so
matrix.ts stays zero-dep — the chain (matrix -> coverage / providers /
list-aliases / models) imports only node builtins and relative TS files.

* ci(matrix): address PR #730 review feedback

- drop dangling `action/mcp/toolFiltering.ts` glob from `nobash`,
  `restricted`, `tokenExfil` (file doesn't exist; `.test.ts` does, but
  the runtime tooling lives in `mcp/shell.ts` and `agents/{claude,opencode}.ts`,
  both already covered).
- drop unused `coverageForProvider` export and its `byName` map from
  `providers.ts` (matrix.ts builds its own lookup inline).
- derive the active agent list from `agents/index.ts` via the same
  dep-free regex tactic as `parseTestFile` instead of hardcoding
  `["claude", "opencode"]` — adding a new harness file now wires it
  into the dynamic matrix automatically.
- treat `coverage: []` as `coverage: undefined` in `shouldRun` so an
  accidentally-empty array doesn't silently skip CI on every PR.
- add `action/utils/activity.ts` and `action/mcp/selectMode.ts` to the
  `timeout` test's coverage — the activity-timeout enforcement path
  was the original reason the test exists.
- ungate the `root` job (lint/format/typecheck/vitest). it's a required
  status check on `main`, so gating it on `code == 'true'` would make
  docs-only PRs unmergeable (skipped jobs don't satisfy required-check
  rules). the real LLM savings come from skipping the four matrices,
  not from skipping `root`.
- harden the four matrix-job `if:` guards from `outputs.matrix && ...`
  to `outputs.matrix != '' && ...` — explicit > implicit short-circuit.
- document `expandBraces`'s flat-only support so a future author isn't
  surprised by `{a,{b,c}}` not expanding.
- fix awkward sentence in `wiki/action-tests.md` "CI Cost Filtering".
2026-05-14 03:55:33 +00:00

89 lines
2.6 KiB
TypeScript

/**
* provider catalog — the source of truth for `providers-live` (full harness
* smoke per provider) and the per-provider coverage globs that scope `models-live`
* (per-alias CLI smoke).
*
* each entry pins one standard-tier flagship slug per provider — not the
* pro/opus tier (too expensive for per-push) and not the free/experimental
* tier (too flaky). these flagships catch provider-class regressions like
* Gemini schema sanitization or OpenAI tool-call format drift that the cheap
* per-alias CLI smoke can't see.
*
* `coverage` lists the source files that, when changed, should rerun this
* provider's flagship + every alias of this provider. `action/models.ts` is
* included on every entry — touching the resolution table reruns all model
* tests (simple model; matches the per-PR-precision answer from planning).
*
* adding a new provider:
* 1. add an entry here with the flagship slug, agent harness, coverage globs
* 2. add a row to wiki/models-catalog.md "To add a provider"
* 3. CI picks it up automatically — no workflow change
*/
export type ProviderEntry = {
name: string;
/** flagship slug for `providers-live` full-harness smoke. */
flagship: string;
/** harness used by the runtime for this provider's models. */
agent: "claude" | "opencode";
/** repo-relative globs that invalidate this provider's matrix entries. */
coverage: string[];
};
const SHARED_OPENCODE_COVERAGE = [
"action/models.ts",
"action/agents/opencode.ts",
"action/agents/opencodePlugin.ts",
];
export const providers: ProviderEntry[] = [
{
name: "anthropic",
flagship: "anthropic/claude-sonnet",
agent: "claude",
coverage: ["action/models.ts", "action/agents/claude.ts"],
},
{
name: "openai",
flagship: "openai/gpt",
agent: "opencode",
coverage: SHARED_OPENCODE_COVERAGE,
},
{
name: "google",
flagship: "google/gemini-pro",
agent: "opencode",
coverage: [...SHARED_OPENCODE_COVERAGE, "action/mcp/geminiSanitizer.ts"],
},
{
name: "xai",
flagship: "xai/grok",
agent: "opencode",
coverage: SHARED_OPENCODE_COVERAGE,
},
{
name: "deepseek",
flagship: "deepseek/deepseek-pro",
agent: "opencode",
coverage: SHARED_OPENCODE_COVERAGE,
},
{
name: "moonshotai",
flagship: "moonshotai/kimi-k2",
agent: "opencode",
coverage: SHARED_OPENCODE_COVERAGE,
},
{
name: "opencode",
flagship: "opencode/big-pickle",
agent: "opencode",
coverage: SHARED_OPENCODE_COVERAGE,
},
{
name: "openrouter",
flagship: "openrouter/claude-sonnet",
agent: "opencode",
coverage: SHARED_OPENCODE_COVERAGE,
},
];