openvibers/openvibe.compare Commits

AGENTS.md: the context an agent starts from (#10)

OP OpenVibers committed 1 days ago · e6e11a516e · 2 files, +127 −0

Changes

ddiff --git a/AGENTS.md b/AGENTS.md
nnew file mode 100644
iindex 0000000..d12749e
---- /dev/null
++++ b/AGENTS.md
@@@ -0,0 +1,126 @@
++# AGENTS.md — OpenVibe.Compare
++
++## Project overview
++
++Public, source-linked comparisons for the OpenVibe network: AI models (price and measured Bench
++quality/speed), AI coding agents (Codes harnesses plus verified Bench runs) and OpenVibe plans
++(Billing's public plan list). Node.js/Express, fed entirely by other services' public APIs, **no
++database, no accounts, no write API**. Server-rendered pages; `openvibe-shared` for the shell.
++
++- Origin `https://openvibe.compare`, port `5280`, unit `openvibe-compare.service`.
++- One rule above all: **missing evidence is not zero**. A thing without a measurement is unranked,
++ never scored 0; a failed feed shows an explicit unavailable state and fills nothing in.
++
++## What it owns
++
++- `GET /` — the comparison index and search.
++- `GET /comparisons/:slug` — one comparison; weight overrides via `?w.<criterion>=`.
++- `GET /things/:id` — one thing across every comparison that contains it; `/models/:org/:model`
++ 301s here.
++- `GET /api/v1/comparisons[/:slug]` — the same data as JSON, CORS-allowed for the origins in
++ [server/origins.json](server/origins.json).
++- `robots.txt`, `sitemap.xml`, `llms.txt`, Dataset JSON-LD, and `Accept: text/markdown` negotiation —
++ all generated from the same data, never hand-written separately.
++
++It owns no private data, no paid execution, no builder or version-history write (reserved in the
++schema with no API in v1).
++
++## Who it reads
++
++Five public endpoints, all in [server/data.js](server/data.js) `ENDPOINTS`:
++
++| Feed | What |
++|---|---|
++| `api.openvibe.exchange/api/v1/exchange/market` | dated offers and checked prices (AI Exchange) |
++| `bench.openvibe.services/api/v1/boards/chat.arena` | Arena Elo and median response time (OpenVibe.Bench) |
++| `bench.openvibe.services/api/v1/runs?kind=codes.patch` / `codes.ticket` | verified Bench runs (OpenVibe.Bench) |
++| `openvibe.codes/api/v1/harnesses` | coding harness catalog (OpenVibe.Codes) |
++| `billing.openvibe.network/api/v1/plans` | published plans (OpenVibe.Billing) |
++
++It does not call AI, Live, Network or any authenticated API. Nothing here writes anywhere.
++
++## Repository map
++
++- **Entry:** [server/index.js](server/index.js) — listens on `PORT || 5280`, graceful SIGTERM.
++- **App/routes:** [server/app.js](server/app.js) — security headers, static `public/`, `/shared`,
++ health/ready, `/release.json`, `/api/v1`, pages, 404 and 503.
++- **Data:** [server/data.js](server/data.js) — fetches the five feeds (8 s timeout), builds the three
++ comparisons, coalesces concurrent reads and caches for ten minutes; a failed feed becomes `null`.
++- **Views:** [server/views.js](server/views.js) — HTML, markdown, escaping, JSON-LD, the method text.
++- **Ranking:** [public/rank.js](public/rank.js) — the one ranking implementation, required by both the
++ server views and the browser.
++- **Browser:** [public/comparison.js](public/comparison.js), [public/compare-account.js](public/compare-account.js),
++ [public/compare.css](public/compare.css).
++- **Deploy:** [deploy/systemd/openvibe-compare.service](deploy/systemd/openvibe-compare.service),
++ [deploy/nginx/openvibe.compare.conf](deploy/nginx/openvibe.compare.conf).
++
++## Commands
++
++```bash
++npm ci
++npm start # node server/index.js, http://127.0.0.1:5280
++npm test # node --test test/*.test.js
++ov test # the harness's sharded run of what the change reaches
++node --check <file.js>
++```
++
++There is no `dev` script and no build step: edit `server/` or `public/` and restart.
++
++## Testing
++
++`test/compare.test.js` uses Node's built-in test runner with fixture feeds. It pins the rules that
++matter: every measurement is finite, dated, sourced, and references a known thing and criterion;
++missing evidence stays missing; exact model identity only; ranking handles direction, equal values,
++zero/invalid weights and all-zero weights (unranked); pages and JSON agree. `ov test` runs the same
++file plus the repository checks the harness adds.
++
++## Conventions
++
++- **Compact, single-line JS** is the house style here (`server/app.js`, `server/data.js`); match the
++ file you edit rather than reformatting it.
++- CommonJS, `'use strict'`, 4 spaces in the newer data helpers, no linter.
++- All user-visible data is escaped with `views.esc`; JSON is embedded with `json()` (escapes `<`).
++- Reuse `openvibe-shared/kit`, `openvibe-shared/shell` and `openvibe-shared/serve` instead of new
++ layout or asset code.
++
++## Data and provenance rules
++
++- A result needs a finite number, a parseable date, and an `https:` source URL; otherwise it is not
++ added ([server/data.js](server/data.js) `result`).
++- Prices: the cheapest dated offer by input + output, both from the same provider. Provider feedback
++ and observation dates are labelled; no price is estimated.
++- Arena quality: at least ten judged games and **exact** model identity (`r.model === id`); no fuzzy
++ joins, because a fuzzy join silently compares a different model revision.
++- Coding agents: only `provenance === 'verified'` runs; benchmark version and model form separate
++ criteria; newest verified run per harness/cohort.
++- Plans: packages and memberships have separate units and are never ranked together.
++- Ranking: min–max within the comparison then a weighted mean on 0–100; equal values get 50;
++ criteria with no measurements are excluded; all-zero weights leave everything unranked.
++
++## Deploy
++
++No database and no service credentials. The unit runs `/opt/openvibe.compare/server/index.js` on
++`127.0.0.1:5280`, env `/etc/openvibe/compare.env`. The README's launch path predates ovhost:
++`register-compare.py` registers port 5280 with a lifecycle override until a Contracts manifest is
++released, then `merge-deploy.sh` and `ov-vhost-install deploy/nginx/openvibe.compare.conf`. Keep the
++vhost and unit in sync with [deploy/](deploy/); a docs-only change needs no deploy.
++
++## Pitfalls
++
++- **Do not invent a write path.** Builder and version history are deliberately absent from v1.
++- **Do not cache a failed feed into an old value.** It is `null` for that read; the next request
++ retries, and the comparison lists it as unavailable.
++- **Do not hand-write `sitemap.xml`, `llms.txt` or JSON-LD.** They are generated from `getData()` so
++ they cannot drift from the pages.
++- **Keep `public/rank.js` framework-free and dual-use** (server `require` and browser global); the
++ test loads it both ways.
++- **CORS is an exact allow-list** ([server/origins.json](server/origins.json)); no `*` and no
++ credentials.
++- **`Accept: text/markdown`** on `/`, `/comparisons/:slug` and `/things/:id` is part of the product;
++ keep it when touching the views.
++- **Do not remove the 503 handler**: an unexpected feed failure must answer explicitly, not 500.
++
++## Documentation
++
++The [README.md](README.md) is the whole product brief (there is no `docs/`). Contracts, if a manifest
++is added later, live in OpenVibe.Contracts.
ddiff --git a/CLAUDE.md b/CLAUDE.md
nnew file mode 100644
iindex 0000000..43c994c
---- /dev/null
++++ b/CLAUDE.md
@@@ -0,0 +1 @@