openvibers/openvibe.trade AGENTS.md

AGENTS.md

main 6.3 KB · 103 lines · markdown

1# AGENTS.md — OpenVibe.Trade
2
3## Project overview
4
5OpenVibe.Trade (`https://openvibe.trade`) is an **informational** market context product: instruments
6and aliases with deterministic resolution, timestamped market observations with their sources, SEC
7filings and other source documents, private watchlists and alerts, short AI briefs from filed numbers,
8and editor-written/edited context. It is explicitly **not** custody, order execution, a marketplace or
9investment advice (ADR-025); the disclaimer is on every page.
10
11- **Entry:** `server/index.js`; app `server/app.js`; port `4860`, service id `trade`.
12- **API:** `server/http/api.js` (`/api/v1`), `api`/`editor`/`private` route groups, `discovery.js`,
13 `actor-limits.js`; pages `server/http/pages.js` and `server/render/` (`home.js`, `layout.js`,
14 `views.js`, `short.js`); `public/js/passkey-signin.js` is the only own script, CSS in `public/css`.
15- **Domain:** `server/domain/` — `instruments.js`, `observations.js`, `documents.js`, `facts.js`,
16 `mapping.js`, `context.js`, `briefs.js`/`market-briefs.js`/`ai-briefs`, `alerts.js`, `watchlists.js`,
17 `ingest.js`, `reading.js`, `source-status.js`, `account-data.js`, `indexing.js`, `urls.js`.
18- **Clients and events:** `server/clients/sec.js` (SEC ticker/XBRL data), `server/clients/ai.js`,
19 `server/events/consumer.js` (Sources items, account export/deletion), SDK outbox.
20- **Docs:** `docs/marketplace-open-question.md` (the historical marketplace branch); `SECURITY.md` has
21 the threat review.
22
23## Owns, does not own
24
25Owns its nine charter tables in `ov_trade`: `trade_instruments` (symbol, name, kind, exchange, SEC
26CIK, currency, status, published context revision), `trade_instrument_aliases` (tickers/CIKs/names
27with a normalised resolution key), `trade_watchlists` (private, one owner), the alert rules/deliveries,
28observations, documents, context revisions, briefs, reviews, shares and outbox.
29
30Does not own: money, custody, orders, escrow, listings or advice (none exist here; money is Billing's,
31ADR-012/025); source items (Sources owns ingestion, robots, terms, items and their removals — Trade
32keeps metadata keyed by item id and follows revisions/removals); identity (Network); notifications
33(Network renders/delivers them from `trade.alert.triggered`; Trade sends no email).
34
35## Who calls it, what it calls
36
37Public reads (`GET /instruments`, `/instruments/:symbol`, observations, documents, `/sources`) are
38anonymous and cacheable. People sign in with Network SSO for watchlists/alerts; editors use
39instrument and context management; services use audience `openvibe.trade` tokens with
40`trade.instrument.resolve`, `trade.instrument.manage`, `trade.observation.write` (services only) and
41`trade.context.read`. SDK `openvibe-sdk/trade` is the client surface. Trade calls Network (JWKS, SSO),
42Sources (items, revisions, removals; `svc:trade` created the `sec-company-tickers` source), SEC's own
43tickers/XBRL, AI (`trade.summarize_market_context`, labelled output) and Events (outbox:
44`trade.alert.triggered`, context/brief events).
45
46## Database and migrations
47
48PostgreSQL `ov_trade` through `openvibe-sdk/db` (PgBouncer for the app, direct owner role for
49migrations); migrations `0001..0010` cover instruments, observations, documents, alerts, AI/market
50briefs, shares, the brief batch and the outbox rejection index. Applied at boot; only add tables and
51columns — never edit one that has run, and a rollback must keep working. Tests use PGlite or, with
52`TRADE_TEST_STORE=pg`, the PostgreSQL containers.
53
54## Auth and privacy
55
56Only verified Network RS256 JWTs (offline against JWKS) and service tokens for audience
57`openvibe.trade`. A bad service token is refused, never downgraded to anonymous; identity never comes
58from a body or query, and `X-OV-*` headers are ignored for browsers. Watchlists and alerts are the
59person's own; a share is read-only. Public pages are cacheable with no personal data; a person's page
60is `private, no-store`. `/internal/events` is signed (v2) and loopback-only; account export/deletion
61covers every table with a person column, leaving contributions without the person id.
62
63## Deploy
64
65`sudo ovhost deploy trade` (git-checkout: fetch, fast-forward `/opt/openvibe.trade`, install on a
66lockfile change, restart, wait for `/api/ready`; rollback `sudo ovhost rollback trade --to <sha>`).
67Unit `openvibe-trade.service` on `127.0.0.1:4860`, env `/etc/openvibe/trade.env`, database `ov_trade`;
68the release migrates at boot.
69
70## Commands and tests
71
72```bash
73npm ci
74npm run dev # http://127.0.0.1:4860
75npm test # every test/*.test.js, PGlite + mock Network/Sources
76npm test -- schedule # only matching files
77npm run test:pg # the same on PostgreSQL
78```
79
80`test/run.js` uses `openvibe-shared/test-runner` (60 s, serial); PGlite plus in-process Network and
81Sources mocks, never the network. Coverage includes instrument/alias resolution, observations and
82freshness, alerts and their scheduling, filings/documents and citations, AI/context briefs, watchlists
83and shares, the route inventory/scope test, capabilities/contracts, CSP/analytics, account data and
84the pages.
85
86## Conventions and pitfalls
87
88- CommonJS, 4-space indent, single quotes, semicolons; problem+json errors and escaped HTML.
89- **Information only:** no route may hold or move value, execute an order, escrow, list a marketplace
90 item, or read as advice. The route-inventory test and ADR-025 enforce the scope; a new "trade"
91 feature that touches money belongs in Billing, not here.
92- **Every observation shows when it was observed, when it was retrieved and which source stated it.**
93 A missing value is null/"not known", never zero or inferred.
94- **Resolution is deterministic:** a ticker or CIK names exactly one instrument (unique), a name may be
95 ambiguous and must return candidates; never pick one silently.
96- **AI briefs are labelled and cite the filed numbers/documents**; they are not reviewed by a person.
97 Editor context is reviewed; drafts are only visible with `?all=1` to an editor and the AI workflow
98 input route is capability-guarded.
99- **Sources revisions and removals win:** when Sources retracts an item, Trade's copy follows and a
100 citation to it must not survive as if still sourced.
101- **Passkeys/sign-in never expose the token** to the page: the session is a Network cookie (or Bearer
102 for the API); `public/js/passkey-signin.js` only drives the browser ceremony.
103