Χ‘Χ‘Χ΄Χ“

MIS ↔ ops-api endpoint contracts (πŸ“ˆ MIS β†’ 🧠 Brain to build)

docs/MIS_OPSAPI_CONTRACTS.md Β· last changed (pre-VM history) Β· rendered from GitHub master

MIS ↔ ops-api endpoint contracts (πŸ“ˆ MIS β†’ 🧠 Brain to build)

Owner of these specs: πŸ“ˆ MIS. Builds + deploys them: 🧠 Brain (into ops-api, the one deploy after deploy-safety). Last updated: Thu Jun 25, 2026.
Hard rules for all endpoints: every value carries asof (ISO) + source; broker email = truth, API = freshness; if asof older than the staleness threshold (below), set stale:true (so nothing silently rots β€” this is the watchdog). Read-only. No secret VALUES in git/chat β€” Brain sets them from the secret store.

Staleness threshold (stale:true rule) β€” market-hours-aware (answer to Brain's tightening):
- Market hours (Mon–Fri 9:30 AM–4:00 PM ET): stale if asof > 30 min old (covers GF's ~15-min lag + one refresh cycle; flags a stuck feed).
- Off-hours / overnight / weekend / NYSE holiday: stale if asof predates the last NYSE session close (the brief must reflect at least the most recent completed session).
- Absolute backstop (always): asof > 26h β†’ stale:true + loud. This is the blackout-catcher β€” the 3-week dark period would've tripped this on day 1.
- If full NYSE-holiday-calendar awareness is too much for v1: default to 30 min in-hours / 18h off-hours / 26h hard cap, and I'll tune. (Better than the 24h default β€” 24h hides hours-old prices as "live" during a session.)


1. mis-bridge (the live data bridge β€” build first)

Why: lets ops-api serve MIS data without running GOOGLEFINANCE per request. Source: the MIS v2 Apps Script web app (misV2VerdictFor_, fn=book/brief/portmetrics).
Contract: ops-api calls the v2 web app /exec with RUN_TOKEN (secret name: MIS_RUN_TOKEN), caches the JSON in KV (TTL ~120s, ?fresh=1 bypass), and exposes the endpoints below. If the v2 app is unreachable or its data asof is old β†’ return stale:true + last-good, never a silent blank.

2. GET /mis/brief (feeds the morning-spine + cockpit headline β€” concise JSON, NOT HTML)

Source of truth = the v2 web app fn=briefjson (keyed with MIS_SETUP_KEY). Brain proxies it 1:1 (KV-cache + asof/stale wrap). Verified-live shape (deploy @110, Jun 30 2026, HTTP 200):

{
  "asof": "2026-06-30T16:31:42",
  "source": "mis-v2",
  "stale": false,
  "regime": { "label": "NORMAL", "vix": 16.4, "factor": 1.0 },
  "equity": { "net": 21725, "total": 21725, "equity": 21725, "cash": 528,
              "cashPct": 0.024, "topSector": "Communication Services", "topSectorPct": 0.264,
              "bookRiskPct": 0.0199, "stopPct": -20, "drawdownPct": null },
  "topHolding": { "sym": "META", "pct": 25 },
  "mtd": { "targetPct": 2.5, "actualPct": 0, "earned": 0, "targetDollar": 362,
           "gapDollar": 362, "daysLeft": 0, "status": "live", "text": "2.5% CLOCK (…) …" },
  "schwabTokenAgeD": 0.2, "peakEquity": null,
  "actionLine": "2.5% clock: $362 to go this month, 0 trading days left.",
  "flags": []
}

3. GET /mis/tile (the dynamic home MIS tile β€” tiny payload; Bee wires the tile UI to it)

{ "asof": "...", "stale": false, "topHolding": {"sym":"META","pct":49}, "equity": 22285, "drawdownPct": 0.0, "regime": "NORMAL" }

Replaces the hardcoded ?sym=NVDA. Tile shows the real top holding/risk, not a fixed bellwether.

4. Schwab-API-in-Worker (off-sheets β€” the 200–250 scale fix; co-build, sequenced AFTER deploy-safety + an engine-freeze window)

Why: replaces GOOGLEFINANCE (the 6-min wall) AND kills the weekly Schwab re-auth. Secret NAMES (values via secret store): SCHWAB_CLIENT_ID, SCHWAB_SECRET, SCHWAB_REFRESH_TOKEN.
Contract:
- OAuth refresh-token handler (auto-refresh β†’ no more weekly manual re-auth).
- GET /mis/quotes?syms=... β†’ batched real-time quotes for the universe; cache KV 5-min.
- GET /mis/holdings?acct=898|0600 β†’ positions; cache; reconcile against broker-email truth.
- History β†’ D1 (one long Price_History table, not per-ticker tabs).
- Generalizes the existing single-ticker /mis/peek real-time path to the whole universe.
Two gates, timed together: Brain's deploy-safety (adds persistent Schwab creds) + my engine-freeze window (scores/scale stay frozen until Sam opens B.75→C→STOP).


5. Entry/bracket pad β€” "Size & Protect this trade" (added Jun 29, from a live gap)

Why: the peek gives a verdict but no actionable levels β€” useless mid-trade (Sam bought 6 META @ $565.55 and had to compute the bracket by hand). The engine already has fn=entry + Quick Trade Calc; surface it in the cockpit, one tap from any ticker.
Contract β€” GET /mis/entry?sym=&shares=|amt=&risk= β†’ returns, per ticker:

{ "asof":"...", "sym":"META", "price":558.44, "atr14":15.26, "atrPct":2.46,
  "stops": { "tight_1_3x":546, "swing_2x":535, "wide_3x":520 },
  "byRiskBudget": { "risk":300, "shares":6, "stop":515, "stopAtrMult":3.3 },
  "targets": { "plus10pct":622, "plus20pct":679 }, "rr_at_plus10":1.1 }

Universe (the scale-target) β€” docs/MIS_UNIVERSE.md

The recovered 183-tradeable / 186-symbol original universe is canonical (docs/MIS_UNIVERSE.md). /mis/quotes + the cockpit watchlist + scoring scale to THIS list (20β†’183β†’250). The 4 index pseudo-tickers feed the macro strip only.

Build order β€” UPDATED per Brain (Jun 25)

Brain's single deploy: mis-bridge + GET /mis/brief + GET /mis/tile + deploy guard + the portal items (5609 / regulars-remove / bee-send key). Secrets for #1–2 already exist in the good version (MIS_RUN_TOKEN, MIS_EXEC_URL/MIS_V2_URL) β†’ no new secrets needed. Unblocks: morning-spine fresh MIS, dynamic tile, cockpit live data.
- Cameras are OFF Brain's bundle β€” Sam reassigned the camera fix fully to the camera session's lane. CAM_CF_* only rides Brain's deploy if the camera session asks Brain to set one value. (See outputs/2026-06-25_ticket_cameras-brain-infra.md β€” re-pointed to the camera lane.)
- Schwab-API-in-Worker β€” separate, gated pass (Brain deploy-safety + my engine-freeze window). Secret names: SCHWAB_CLIENT_ID/SECRET/REFRESH_TOKEN.

MIS provides specs + the v2 data source; Brain builds/deploys; Bee wires the tile UI. No parallel pusher. Daily MIS push resumes through Brain's rail once mis-bridge + the data refresh are live.

Source trail Β· docs/MIS_OPSAPI_CONTRACTS.md @ master Β· rendered 2026-07-02 7:23 PM EDT by scripts/build-docs.py Β· the .md in the repo is the truth; this page is the phone-readable view