`test-features.mjs` shipped at v3.8.0 (per CHANGELOG of the keys.mjs
quota+cache work) and is referenced from AGENTS.md as the project's only
test artifact, but until now nothing actually ran it — no `npm test`
script, no CI step. Wiring it up so it runs on every push and PR.
### Changes
- `package.json`: add `"test": "node test-features.mjs"` to scripts.
- `.github/workflows/test.yml` (new): single-job workflow that runs
`npm test` on push to main and on every PR. Uses Node 24 because
`keys.mjs` imports `node:sqlite`, which is stable in Node 23+ (Node
24 is the current LTS; Node 22 would need `--experimental-sqlite`).
No `npm install` step — OCP has zero external runtime dependencies
per `package-lock.json`.
- `AGENTS.md`: note that `test-features.mjs` runs via `npm test` and
is enforced by `.github/workflows/test.yml`.
### Why this is a hard check, not a soft check
`test-features.mjs` is self-contained — it imports `keys.mjs` and
exercises the SQLite-backed key/quota/cache code paths against a
throwaway test DB at `~/.ocp/ocp-test.db`. It does NOT require:
- a live claude CLI binary
- a running OCP server
- any network access
So CI can run it as a real check; no `continue-on-error` needed.
### Local verification
```
$ npm test
[...]
=== Results: 24 passed, 0 failed ===
```
24 assertions cover createKey / listKeys / quota math / cache hash
determinism / cache TTL / clearCache. Exit code is 1 on any failure
(`process.exit(failed > 0 ? 1 : 0)` at the bottom of test-features.mjs).
### Future expansion
If the suite later grows to include tests that DO require a live claude
CLI or a running OCP, mark those steps `continue-on-error: true` (or
split them into a separate job). The comment in `test.yml` documents
this contract.
Refs: audit (test-features.mjs orphan / unrunnable in CI).
Co-authored-by: dtzp555 <dtzp555@gmail.com>