# Smartico public-api — docs & RAG pipeline (developer guide)

How the `@smartico/public-api` documentation is produced, how the IDE coding
agent retrieves it, and **how to keep it all up to date**. Read this before
touching TSDoc, the capability pages, the capture scripts, or the bo_server
ingestion.

---

## 1. The big picture

```
 SOURCE OF TRUTH (you edit)                 GENERATED (never edit)            CONSUMED BY
 ─────────────────────────                  ──────────────────────           ───────────
 src/WSAPI/WSAPI<Domain>.ts  ─┐
   method TSDoc (usage)        │
 src/WSAPI/WSAPITypes.ts +     │   npm run gen-capabilities
   domain types (field docs)   ├──────────────────────────►  docs/capabilities/<method>.md ─┐
 docs/ui/<domain>/UIGuide_*.md │   (scripts/gen-capabilities.js)   (one self-contained       │
   (behavioral contract)       │                                    "API capability page")   │
 docs/capabilities/_responses/ │                                                              │
   <method>.json (REAL shapes)─┘                                                              │
                                                                                              │   JobLLM2 (env2 cron)
 src/**.ts (TSDoc)  ──────────────►  docs/api/**  (TypeDoc reference) ───┐                    ├──► llm.docs2 (Postgres, GAMES db)
   npm run doc                        (scripts/postdoc-cleanup.js)        │  ingested as        │     + embeddings (llm.chunks2)
                                                                          │  PUBLIC_API_DOCS    │
                                                                          │  ("api-raw" lane)   ▼
                                                                          └──────────────►  IDE coding agent
 docs/capabilities/** ────────────────────────────────────────────────────► ingested as PUBLIC_API_CAPABILITY
                                                                             (the PRIMARY "api" retrieval lane)
```

**The IDE agent retrieves capability pages, not raw source.** Each page is one
task-completable unit: signature + full inline return shape + behavioral
contract + a **real example response** + errors + related links. Design rules
live in `../bo_server/server/src/ide/SMARTICO_DOC_STRUCTURE_GUIDE.md`.

---

## 2. Source of truth — what to edit where

| Edit | For | Owned by |
|---|---|---|
| `src/WSAPI/WSAPI<Domain>.ts` method TSDoc | narrative usage: preconditions, error tables, refresh/cache, idempotency, `@example`, `{@link}` | `api-tsdoc` skill |
| `src/WSAPI/WSAPITypes.ts` + `src/<Domain>/*.ts` field comments | terse one-line field definitions (what + type/units + null semantics) | `api-tsdoc` skill |
| `docs/ui/<domain>/UIGuide_<method>.md` | UI/behavioral contract prose | `api-tsdoc` skill |
| `docs/capabilities/_responses/<method>.json` | the **captured real response** (anonymized) | capture scripts (§4) |
| `tsconfig.json` `typedocOptions.entryPoints` | add new public types/classes so they appear in `docs/api` | manual |

**NEVER hand-edit** (regenerated, overwritten):
- `docs/api/**` — TypeDoc output (`cleanOutputDir: true`).
- `docs/capabilities/*.md` — generated by `gen-capabilities.js`.

---

## 3. Keeping docs updated — the per-release workflow

Run after any change to a method's signature, behavior, or types.

1. **Enrich the source** — TSDoc + field comments + UI guide. Use `/api-tsdoc <method>` (one method) or `/api-tsdoc-final` (whole release batch). These never commit and never run the build steps below.
2. **Capture / refresh the real response** for the method → `docs/capabilities/_responses/<method>.json` (§4).
3. **Generate capability pages**: `npm run gen-capabilities`. Rewrites all `docs/capabilities/*.md` from TSDoc + types + the captured responses.
4. **(Reference site)** `npm run doc` — TypeDoc → `docs/api/**` (+ `postdoc-cleanup.js`). Human-triggered; confirm zero new warnings.
5. **Ship**: commit; publish (`npm version patch && npm publish`) so the npm package + `run_public_api` see new methods; `npm run bump-tracker` to flow into the live `_smartico.api`.
6. **RAG ingest is automatic**: `JobLLM2` (bo_server, env2 cron, every 60s) clones `public-api`, re-indexes changed `docs/capabilities/**` under `PUBLIC_API_CAPABILITY`. No manual step. It emails `MAIL_TO_AI_PRODUCT` when done.

**Coverage check:** `ls docs/capabilities/_responses/*.json | wc -l` vs `ls docs/capabilities/*.md | wc -l`. Methods without a `_responses` file still get a complete Returns shape from the type registry (fallback), just no real example payload.

---

## 4. Capturing real response shapes

Two mechanisms. **Prefer `run_public_api`** for everything it can reach; use the browser script only for the auth-only gaps.

### 4a. Server-side — `mcp__hive__run_public_api` (visitor mode, no browser)

Runs the real published WSAPI bound to label+brand+user, returns `JSON.stringify(result)`. No user-hash, no CORS, no SDK loader.

- **Captures:** almost all `getX()` fetch methods.
- **Cannot capture** (runs in *visitor / no-tracker* mode): `getUserProfile`, `getInboxMessageBody` (read tracker state), all `gamePick*` ("not available in visitor mode").
- **Caveat:** runs the **published npm** SDK → lags local `main`. Newly-added methods aren't there until `npm publish`.

### 4b. Headless real-user — `scripts/capture-responses-browser.mjs`

Loads the real `smartico.js` tracker bundle, `init` + `identify` as a real player, then sweeps every `_smartico.api.*` and writes anonymized `_responses/<method>.json`. Covers the auth-only gaps.

```sh
npm i -D playwright && npx playwright install chromium    # one-time
node scripts/capture-responses-browser.mjs                # read-only sweep
SM_MUTATIONS=1 node scripts/capture-responses-browser.mjs # + execute mutations (test acct only)
SM_DEBUG=1     node scripts/capture-responses-browser.mjs # full console + per-WS-frame trace
npm run gen-capabilities                                  # rebuild pages after capture
```

Progress/diagnostics stream to **`/tmp/sm-capture.log`** (stdout is buffered in background).

**Env overrides** (defaults = the env4 ICE **test** label):

| Var | Default | Meaning |
|---|---|---|
| `SM_LABEL` | `a6e7ac26-…-4` | label key (last char = env) |
| `SM_BRAND` | `f86271e6` | brand key |
| `SM_USER` | `4579cace-…c45b` | player ext id |
| `SM_SALT` | `null` | label hash salt (env4 ICE = literal `'null'`) |
| `SM_ORIGIN` | `https://app.smartico.ai/` | self-served CSP-free page origin |
| `SM_SCRIPT_URL` | `https://libs.smartico.ai/smartico.js` | tracker bundle |
| `SM_UA` | desktop Chrome | user-agent |
| `SM_MUTATIONS` | off | run the mutation pass |
| `SM_DEBUG` | off | verbose console + WS frames |

**How identify works (hard-won):**
- `smartico.js` builds `_smartico`; identify is the **method form** `_smartico.identify(user, hash, {})` — the queue form `_smartico('identify', …)` silently no-ops after load.
- hash = `md5( lower(`${user}:${salt}:${ts}`) ) + ':' + ts`, `ts = floor(now/1000)*1000 + 24h`. Server accepts it when the label salt matches (`'null'` for env4 ICE).
- realtime WS = `wss://api{ENV}.smartico.ai/websocket/services`.
- **Why a self-served origin:** `libs.smartico.ai` 403s headless clients and its error page's CSP blocks injected scripts; the script routes a blank CSP-free page on `app.smartico.ai` and fetches `smartico.js` cross-origin with a realistic UA.

**Dynamic ids + richest sampling:** the sweep fetches list methods first and harvests every param id (tournament instance, clan, jp_template, raffle/draw/run, inbox guid, gamepick matchx/quiz template) — **no hardcoded ids**. For list methods it stores the *most-populated* item so the captured shape isn't a degenerate first element.

**Anonymization (automatic):** CDN hosts (`cloudfront.net`/`smartico.ai`/`smr.vc`) → `cdn.example`; any UUID → zeros; `clean_ext_user_id` → `0`. Keep product config (names, prize tables) — only the field *shape* matters.

### 4c. Mutations (`SM_MUTATIONS=1`)

Executes write methods on the **test account** to capture result shapes; reversibles are restored. Captured: jackpot opt in/out, inbox mark-read/favorite/mark-all, setAvatar (restored), mission opt-in, claimBonus, registerInTournament, buyStoreItem, playMiniGame + acknowledge + batch. Skipped by guards when no suitable entity exists (claim-reward, raffle-optin, joinClan). **Never runs `deleteAllInboxMessages` / single delete** (destructive) or the gamepick submit (charges buy-in). Real error codes are valuable too (e.g. `buyStoreItem → 11002`).

---

## 5. The generator — `scripts/gen-capabilities.js`

Pure, deterministic Node + the `typescript` compiler API (no extra deps). Per public WSAPI method it emits `docs/capabilities/<method>.md`:

- **facts header** (title, one-line summary, import, Search-terms) — high retrieval weight.
- **Signature / Parameters** — from the method node + `@param`.
- **Returns** — annotates the **captured response** fields with the **return type's own** comments (per-type resolved, inheritance-aware, nested via the property's element type). No captured response → falls back to the resolved **type** shape (still complete).
- **Behavioral contract** — the method's `@remarks` (with an Error-codes block split out into `## Errors`).
- **Example** + **Example response (REAL shape)** — the `@example` + the captured JSON.
- **Related** — from `{@link}` targets.

Run: `npm run gen-capabilities`. Reads `_responses/<method>.json` if present. Never commits.

---

## 6. RAG ingestion (bo_server)

| Piece | File | What |
|---|---|---|
| Source-type enum | `server/src/Managers/LLMManager.ts` | `LLMSourceTypeId.PUBLIC_API_CAPABILITY = 8` |
| Ingest job | `server/src/Jobs/JobLLM2.ts` → `processPublicAPI()` | indexes `docs/capabilities/**` under the new type; the raw walk skips `capabilities`/`_responses` (`LLM_SKIP_DIRS`). env2 only, 60s refresh. |
| IDE routing | `server/src/ide/ideSmarticoTools.ts` | `SOURCE_TYPE_MAP.api → [PUBLIC_API_CAPABILITY]` (primary); `api-raw → [PUBLIC_API_DOCS]` (raw source fallback) |
| IDE tools | `ideSmarticoTools.ts` | `search_smartico_reference` (semantic + Cohere rerank → top distinct docs), `read_smartico_reference` (one doc by id), `list_smartico_reference` |
| Design rules | `server/src/ide/SMARTICO_DOC_STRUCTURE_GUIDE.md` | the capability-page spec |

The IDE `api` lane reads **only** capability pages. A method with no capability page is invisible to the agent — always run `gen-capabilities` after enriching.

---

## 7. Skills

- **`/api-tsdoc <method>`** — enrich one method end-to-end (TSDoc + UI guide + capture a response + regenerate the page). Never commits / never runs `npm run doc`.
- **`/api-tsdoc-final`** — the whole release doc batch (callbacks, `_smartico` object, native protocol, all method TSDocs, capability capture + generation), stops at a prepared commit message.

Skill files: `~/.claude/skills/api-tsdoc/SKILL.md`, `~/.claude/skills/api-tsdoc-final/SKILL.md`.

---

## 8. Adding a NEW method — checklist

1. Implement the method in `src/WSAPI/WSAPI<Domain>.ts`; add return/types to `WSAPITypes.ts` (or a domain types file).
2. Add new public types to `tsconfig.json` `typedocOptions.entryPoints`.
3. `/api-tsdoc <method>` → TSDoc + field comments + UI guide.
4. Capture a real response (§4) → `_responses/<method>.json`.
5. `npm run gen-capabilities` → new `docs/capabilities/<method>.md`. Spot-check Returns has the right per-domain field comments + a real example.
6. Commit; `npm publish`; `npm run bump-tracker`. RAG re-indexes automatically.

---

## 9. Field-type facts (server-determined; verified via `run_public_api`)

- `*_ts` / `*_date_ts` → **epoch-ms number**. Round/event/store/raffle timestamps → number ms.
- Plain Java date strings (`complete_date`, `unlock_date`, `sent_date`, bonus `create_date`/`redeem_date`) → **`"dd/MM/yyyy HH:mm:ss"` string, NOT ISO-8601** (`new Date()` won't parse them).
- GamePick (Node `r-games-server`) date strings → real ISO-8601; `match_date` / `event_resolution_date` / `last_wallet_sync_time` are **strings**, not numbers.
- `TActivityLog.create_date` → epoch **seconds** (the lone outlier).
- Avatar `dt_created` → epoch-ms number.
- GamePick request params `ext_user_id` / `smartico_ext_user_id` are SDK-injected (optional for consumers).

---

## 10. Troubleshooting

| Symptom | Cause / fix |
|---|---|
| `run_public_api`: "Tracker is not initialized" | tracker-state method (`getUserProfile`). Use the browser script. |
| `run_public_api`: "not available in visitor mode" | auth-only (`gamePick*`). Use the browser script. |
| `run_public_api`: method "is not a function" | published SDK lags local `main`. `npm publish` first. |
| Browser: `smartico.js → error` / never loads | origin blocked/CSP. Set `SM_ORIGIN` to an allowlisted origin; ensure realistic `SM_UA`. |
| Browser: `NOT identified (timeout)` | wrong hash/salt, or identify called the queue form. Confirm `SM_SALT`; identify must be method form (already is). Inspect with `SM_DEBUG=1` (`/tmp/sm-capture.log`). |
| Capture hangs | per-call 8s + stage caps already bound it; check `/tmp/sm-capture.log`. |
| `undefined.filter`/`.map` from a getter | SDK robustness bug on empty data (`getBonuses`, `getJackpotEligibleGames`) — capture once a relevant entity exists, or fix the SDK guard. |
| Capability page shows another domain's field comment | the return type is missing that field → add it to the type (don't edit the page). |
| Internal leak in a page (DB table, ClassId) | a source **field comment** leaked it → fix the comment (public-contract rule). |

---

## 11. Reference

**npm scripts:** `gen-capabilities`, `doc` (TypeDoc), `build`, `bump-tracker`.
**Scripts:** `scripts/gen-capabilities.js`, `scripts/capture-responses-browser.mjs`, `scripts/postdoc-cleanup.js`.
**Test creds (env4 ICE — dev/test label only):** label `a6e7ac26-c368-4892-9380-96e7ff82cf3e-4`, brand `f86271e6`, user `4579cace-9069-4d65-93ff-9b8b6c83c45b`, salt `null`.
**Current coverage:** 52 / 70 methods have a real captured response; the rest use the type-fallback Returns.
