diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/RIGHTS.md b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/RIGHTS.md new file mode 100644 index 0000000..17171a6 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/RIGHTS.md @@ -0,0 +1,16 @@ +# Submission rights declaration + +Project: `BHRIGU OlaXBT Strategy Evidence Agent` +Submission slug: `bhrigu-olaxbt-strategy-evidence-agent` +Submitter: `Yulchiev A.Kh` +Date: `2026-09-12` + +The submitter confirms that they own, or have sufficient authorization for, the first-party source code, service, BHRIGU branding, tests, documentation, and other first-party materials included in this submission. + +Subject to the official program terms, the submitter authorizes X-Agent to retain, reproduce, audit, test, archive, and publish the submitted program artifact for judging, fraud prevention, dispute handling, ecosystem submission, and post-award accountability. + +Third-party components and terms: no bundled npm runtime dependencies. OlaXBT Nexus MCP is an external strategy/signal service and remains subject to OlaXBT terms. The inherited Bitcoin Temporal Evidence capability uses public Binance and mempool.space data subject to their respective terms. Third-party services, data, and branding are not claimed as first-party BHRIGU property. See `source/THIRD_PARTY.md`. + +Exceptions or restrictions: authorization covers only the bounded first-party source and materials present in this submission directory. ORION, private prompts, planners, evaluators, private corpora, unpublished methods, credentials, wallet/payment code, and trading execution are excluded. No general open-source license is granted beyond the review/archive authorization stated here and the official program terms. + +This declaration is an operational submission statement and is not a substitute for event terms reviewed by qualified counsel. diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/SUBMISSION.md b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/SUBMISSION.md new file mode 100644 index 0000000..e5ba7b7 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/SUBMISSION.md @@ -0,0 +1,81 @@ +# BHRIGU OlaXBT Strategy Evidence Agent + +## Judge-first review path + +**OLAXBT STRATEGY = CREATED + BACKTESTED + NEXUS VALIDATED.** + +**APPLICATION = DISTINCT AGENT/MCP APPLICATION.** This submission is not strategy-only, not backtest-only, and not a simple API wrapper. The application consumes four live OlaXBT Nexus evidence surfaces and exposes one bounded REST capability plus one read-only MCP tool for agent review. + +**Primary job:** Can an agent trust the evidence context behind this OlaXBT strategy signal right now? + +Verified BTC/USDT strategy evidence from the live Nexus-backed review deployment: + +- Sharpe: **1.7668** +- Win rate: **52.94%** +- Profit factor: **1.6494** +- Max drawdown: **0.31%** +- Trades: **17** +- Four Nexus sources: **signal + metrics + trades + equity** + +**Authority boundary:** **OLAXBT = strategy + signal authority. BHRIGU = evidence interpretation layer.** BHRIGU does not create a second BUY/SELL/HOLD signal, forecast price, place orders, execute trades, access wallets, or move funds. + +**Confidence epistemic boundary:** the raw OlaXBT confidence value is preserved as source evidence. BHRIGU does **not** invent a confidence threshold, calibration rule, or trading judgment from that value unless OlaXBT explicitly defines those semantics. + +## Capability + +- **One-line description:** A read-only evidence interpretation layer around the current OlaXBT BTC/USDT strategy signal, combining the observed signal with strategy metrics, recent trades, equity context, contradictions, limitations, and source status. +- **Who it helps:** AI agents and research systems that need to decide how much trust to place in the evidence context around an OlaXBT strategy signal without delegating trading authority. +- **Capability boundary:** **OLAXBT = strategy + signal authority. BHRIGU = evidence interpretation layer.** BHRIGU does not create a second BUY/SELL/HOLD signal, forecast price, place orders, execute trades, access wallets, or move funds. + +## Live API + +- **API base URL:** https://bhrigu-bitcoin-research-state-rn4vpiwc8-aibhrigus-projects.vercel.app +- **Health-check URL:** https://bhrigu-bitcoin-research-state-rn4vpiwc8-aibhrigus-projects.vercel.app/health +- **Authentication:** no caller credential. The OlaXBT Nexus credential is server-side only. +- **Rate limits / known limits:** `BTC/USDT` only in this bounded trading-track slice; upstream OlaXBT availability and limits apply; each Nexus tool call has a 15-second timeout; no SLA is claimed. +- **API contract:** REST `POST /v1/strategy-evidence` with `{"symbol":"BTC/USDT"}`; MCP `POST /mcp` tool `bhrigu_get_olaxbt_strategy_evidence` with the same symbol. Both return the same bounded Strategy Evidence object. + +## Source and reproducibility + +- **Source repository:** https://github.com/AiBhrigu/bhrigu-bitcoin-research-state-api +- **Review commit:** `d29423daf121a4318dec063d0694b5fec8eb2ed3` +- **Source submitted in this PR:** `source/` +- **Run tests:** `npm ci && npm test` +- **Run locally:** `npm ci && npm start`; live OlaXBT calls require the authorized `OLAXBT_NEXUS_API_KEY` only in the server environment. +- **Deploy:** deploy exact review commit with Node.js 22+ and bind the Nexus credential server-side. +- **Version binding:** `/health` and `/.well-known/xagent-verification.json` expose the exact deployed commit; the verification endpoint also exposes this trading-track slug. + +The deployed health response is: + +```json +{"status":"ok","commit":"d29423daf121a4318dec063d0694b5fec8eb2ed3"} +``` + +The deployment proof is: + +```json +{"schemaVersion":1,"slug":"bhrigu-olaxbt-strategy-evidence-agent","commit":"d29423daf121a4318dec063d0694b5fec8eb2ed3"} +``` + +## Verification + +Repeatable REST and MCP calls plus redacted proof are in `verification/README.md`. + +- **Health-check result:** HTTP 200, exact review commit. +- **REST capability call:** HTTP 200 with all four OlaXBT `source_status.*.ok=true`. +- **MCP capability call:** HTTP 200; `structuredContent` is the same Strategy Evidence object. +- **Expected error behavior:** unsupported symbols fail explicitly; missing or failed upstream evidence is surfaced and never fabricated. + +## Security and data handling + +- **Data collected:** only requested symbol; no user identity, wallet, payment, account, or credential data. +- **Purpose and retention:** transient evidence interpretation; no request persistence by this capability. +- **Third parties / outbound network calls:** OlaXBT Nexus MCP for strategy signal, metrics, trades, and equity. The inherited Bitcoin Temporal Evidence capability also uses public Binance and mempool.space data. +- **Secrets:** no real secret is committed or returned. Nexus credential remains server-side only. +- **Known risks / restrictions:** historical performance is context, not forecast; source availability can limit output; `assessment` is not an order instruction. + +## Support + +- **Team / builder:** BHRIGU / AiBhrigu +- **Contact:** https://x.com/bhrigu_io +- **License / rights:** no general open-source license is granted; X-Agent review/archive rights for this bounded artifact are declared in `RIGHTS.md`. diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/.github/workflows/ci.yml b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/.github/workflows/ci.yml new file mode 100644 index 0000000..c83cd6e --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/.github/workflows/ci.yml @@ -0,0 +1,49 @@ +name: CI + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + verify: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - run: npm ci + - run: npm run check + - name: Local HTTP and MCP smoke + run: | + BHRIGU_COMMIT="$GITHUB_SHA" npm start > /tmp/bhrigu.log 2>&1 & + SERVER_PID=$! + trap 'kill $SERVER_PID || true' EXIT + for n in $(seq 1 20); do + curl -fsS http://127.0.0.1:3000/health > /tmp/health.json && break + sleep 1 + done + node --input-type=module -e 'const h=JSON.parse(await (await fetch("http://127.0.0.1:3000/health")).text()); if(h.commit!==process.env.GITHUB_SHA) process.exit(1)' + curl -fsS http://127.0.0.1:3000/v1/windows > /tmp/windows.json + curl -fsS -X POST http://127.0.0.1:3000/mcp \ + -H 'content-type: application/json' \ + -H 'MCP-Protocol-Version: 2026-07-28' \ + -H 'Mcp-Method: server/discover' \ + --data '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{},"io.modelcontextprotocol/clientInfo":{"name":"ci","version":"1.0.0"}}}}' > /tmp/discover.json + curl -fsS -X POST http://127.0.0.1:3000/mcp \ + -H 'content-type: application/json' \ + -H 'MCP-Protocol-Version: 2026-07-28' \ + -H 'Mcp-Method: tools/list' \ + --data '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}' > /tmp/mcp-modern.json + curl -fsS -X POST http://127.0.0.1:3000/mcp \ + -H 'content-type: application/json' \ + -H 'MCP-Protocol-Version: 2026-07-28' \ + -H 'Mcp-Method: tools/call' \ + -H 'Mcp-Name: bhrigu_get_temporal_window' \ + --data '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"bhrigu_get_temporal_window","arguments":{"window_id":"SEP_10_2026"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}' > /tmp/mcp-call.json + node --input-type=module -e 'import fs from "node:fs"; const w=JSON.parse(fs.readFileSync("/tmp/windows.json")); const d=JSON.parse(fs.readFileSync("/tmp/discover.json")); const l=JSON.parse(fs.readFileSync("/tmp/mcp-modern.json")); const c=JSON.parse(fs.readFileSync("/tmp/mcp-call.json")); if(w.window_count!==2||w.durable_evidence_count!==1||d.result.resultType!=="complete"||!d.result.supportedVersions.includes("2026-07-28")||l.result.tools.length!==5||!l.result.tools.some((t)=>t.name==="bhrigu_get_olaxbt_strategy_evidence"&&t.annotations?.readOnlyHint===true)||l.result.ttlMs!==300000||c.result.structuredContent.window.id!=="SEP_10_2026") process.exit(1)' diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/.gitignore b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/.gitignore new file mode 100644 index 0000000..0183d71 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +.vercel/ +.env* +.DS_Store +npm-debug.log* +.vercel diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/IP_BOUNDARY.md b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/IP_BOUNDARY.md new file mode 100644 index 0000000..eef865a --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/IP_BOUNDARY.md @@ -0,0 +1,28 @@ +# IP Boundary + +## Public artifact + +This repository intentionally contains only: + +- the read-only HTTP adapter; +- deterministic state-shaping logic; +- one frozen public observation baseline; +- public-source fetchers; +- tests and deployment metadata. + +## Explicitly excluded + +The following are not part of this artifact and must not be added during hackathon packaging: + +- ORION core or private services; +- private prompts, planners, evaluators, or routing contracts; +- private or unpublished corpora; +- unpublished reconstruction or forecasting methods; +- credentials, secrets, customer/account data; +- wallet, payment, transfer, withdrawal, or trade execution logic. + +## Law + +`EXPOSE MEANING / PROTECT MECHANISM` + +Any future submission must copy only the source already present in this bounded public repository unless separately reviewed and authorized. diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/README.md b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/README.md new file mode 100644 index 0000000..b415e36 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/README.md @@ -0,0 +1,52 @@ +# BHRIGU OlaXBT Strategy Evidence Agent + +**OLAXBT = strategy + signal authority.** +**BHRIGU = evidence interpretation layer.** + +**Job:** Can an agent trust the evidence context behind this OlaXBT strategy signal right now? + +The primary trading-track capability is a bounded, read-only evidence object around the current OlaXBT `BTC/USDT` strategy signal. It consumes the live signal, strategy metrics, recent trades, and equity context from OlaXBT Nexus MCP and surfaces support, contradictions, limitations, and evidence quality without creating a second trading signal. + +## Primary interfaces + +- `POST /v1/strategy-evidence` — REST Strategy Evidence object +- MCP tool `bhrigu_get_olaxbt_strategy_evidence` — the same bounded object for agents +- `GET /health` — exact deployed commit +- `GET /.well-known/xagent-verification.json` — trading-track submission slug + exact commit + +Input is exactly `{"symbol":"BTC/USDT"}`. OlaXBT signal direction is preserved from the observed upstream `trade_intent` field; BHRIGU never infers BUY/SELL/HOLD from reasoning text. OlaXBT backtest win rate is preserved from the observed upstream `win_rate_pct` field. + +## Safety boundary + +Read-only. No order placement, exchange execution, wallet authority, payment authority, withdrawal, transfer, or second signal. Historical performance is evidence context, not a forecast. The OlaXBT Nexus credential is server-side only. + +## Evidence sources + +The Strategy Evidence object consumes exactly four OlaXBT Nexus tools: + +- `get_strategy_signal` +- `get_strategy_metrics` +- `get_strategy_trades` +- `get_strategy_equity` + +Each source is reported independently under `source_status`; missing or contradictory evidence is surfaced rather than replaced. + +## Run and test + +Requires Node.js 22+. + +```bash +npm ci +npm test +npm start +``` + +The live Strategy Evidence call requires `OLAXBT_NEXUS_API_KEY` only in the server environment. Do not put it in Git, client code, fixtures, logs, or responses. + +## Inherited capability + +This repository also preserves the earlier BHRIGU Bitcoin Temporal Evidence capability and its read-only MCP tools. That inherited Open-Innovation capability remains available, but it is not the primary object of the OlaXBT trading-track submission. + +## IP boundary + +Only the bounded public adapter is present. ORION core, private prompts, planners, evaluators, private corpora, unpublished methods, credentials, wallet/payment code, and trading execution are excluded. diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/THIRD_PARTY.md b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/THIRD_PARTY.md new file mode 100644 index 0000000..d754b08 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/THIRD_PARTY.md @@ -0,0 +1,17 @@ +# Third-party services and public data + +## OlaXBT Nexus MCP + +Primary external service for the trading-track Strategy Evidence capability. The server calls only the bound strategy's read interfaces used here: signal, metrics, trades, and equity. The authorized Nexus credential is server-side only and is not committed or returned. OlaXBT remains strategy + signal authority. + +## Binance Spot public market data + +Inherited Bitcoin Temporal Evidence capability only. Public BTCUSDT market data; no Binance account credential, trading, wallet, transfer, or private-account endpoint is used. + +## mempool.space public Bitcoin data + +Inherited Bitcoin Temporal Evidence capability only. Used for public Bitcoin tip-height context. + +## Runtime dependencies + +No npm runtime dependencies. The project uses Node.js built-ins and platform-provided `fetch`. Third-party services and data remain subject to their respective terms. diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/about.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/about.mjs new file mode 100644 index 0000000..e3e924a --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/about.mjs @@ -0,0 +1,17 @@ +import { methodGate, sendJson } from "../lib/http.mjs"; + +export default function handler(req, res) { + if (!methodGate(req, res)) return; + sendJson(res, 200, { + name: "BHRIGU Strategy Evidence Agent", + capability: "Can an agent trust the evidence context behind this OlaXBT strategy signal right now?", + endpoint: "/v1/strategy-evidence", + temporal_state: "/v1/state", + windows: "/v1/windows", + mcp: "/mcp", + openapi: "/openapi.json", + health: "/health", + verification: "/.well-known/xagent-verification.json", + boundary: "RESEARCH_STATE_NOT_TRADE" + }, "public, max-age=60"); +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/health.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/health.mjs new file mode 100644 index 0000000..1eadced --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/health.mjs @@ -0,0 +1,7 @@ +import { healthPayload } from "../lib/runtime.mjs"; +import { methodGate, sendJson } from "../lib/http.mjs"; + +export default function handler(req, res) { + if (!methodGate(req, res)) return; + sendJson(res, 200, healthPayload(), "public, max-age=30"); +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/mcp.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/mcp.mjs new file mode 100644 index 0000000..f3b5296 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/mcp.mjs @@ -0,0 +1,37 @@ +import { sendJson } from "../lib/http.mjs"; +import { handleMcpRpc } from "../lib/mcp.mjs"; + +async function readBody(req) { + if (req.body && typeof req.body === "object") return req.body; + let raw = ""; + for await (const chunk of req) raw += chunk; + return raw ? JSON.parse(raw) : null; +} + +function headerValue(req, name) { + const headers = req.headers; + if (headers?.get) return headers.get(name); + const value = headers?.[name.toLowerCase()] ?? headers?.[name]; + return Array.isArray(value) ? value[0] : value ?? null; +} + +export default async function handler(req, res) { + if (req.method !== "POST") return sendJson(res, 405, { error: "METHOD_NOT_ALLOWED", allowed: ["POST"] }); + try { + const result = await handleMcpRpc(await readBody(req), { + transportMeta: { + requireHeaders: true, + protocolVersion: headerValue(req, "MCP-Protocol-Version"), + method: headerValue(req, "Mcp-Method"), + name: headerValue(req, "Mcp-Name") + } + }); + if (result.status === 202) { + res.statusCode = 202; + return res.end(); + } + sendJson(res, result.status, result.body, "no-store"); + } catch { + sendJson(res, 400, { jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } }); + } +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/openapi.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/openapi.mjs new file mode 100644 index 0000000..8f54a91 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/openapi.mjs @@ -0,0 +1,7 @@ +import { methodGate, sendJson } from "../lib/http.mjs"; +import { openapiPayload } from "../lib/openapi.mjs"; + +export default function handler(req, res) { + if (!methodGate(req, res)) return; + sendJson(res, 200, openapiPayload(), "public, max-age=300"); +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/state.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/state.mjs new file mode 100644 index 0000000..7fb5586 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/state.mjs @@ -0,0 +1,23 @@ +import { buildState } from "../lib/state.mjs"; +import { methodGate, sendJson } from "../lib/http.mjs"; + +export default async function handler(req, res) { + if (!methodGate(req, res)) return; + const url = new URL(req.url || "/v1/state", "http://localhost"); + const symbol = String(url.searchParams.get("symbol") || "BTCUSDT").toUpperCase(); + if (symbol !== "BTCUSDT") { + sendJson(res, 400, { error: "UNSUPPORTED_SYMBOL", supported: ["BTCUSDT"] }); + return; + } + try { + const state = await buildState(); + sendJson(res, 200, state, "public, max-age=10, s-maxage=10"); + } catch (error) { + sendJson(res, 502, { + error: "PUBLIC_MARKET_SOURCE_UNAVAILABLE", + source: "Binance Spot BTCUSDT", + detail: String(error.message || error), + trading_authority: false + }); + } +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/strategy-evidence.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/strategy-evidence.mjs new file mode 100644 index 0000000..a35d193 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/strategy-evidence.mjs @@ -0,0 +1,46 @@ +import { sendJson } from "../lib/http.mjs"; +import { buildStrategyEvidence } from "../lib/strategy-evidence.mjs"; + +async function readBody(req) { + if (req.body && typeof req.body === "object") return req.body; + if (typeof req.body === "string") return req.body ? JSON.parse(req.body) : null; + let raw = ""; + for await (const chunk of req) { + raw += chunk; + if (raw.length > 65536) throw new Error("BODY_TOO_LARGE"); + } + return raw ? JSON.parse(raw) : null; +} + +function statusFor(error) { + if (error?.code === "UNSUPPORTED_SYMBOL") return 400; + if (error?.code === "OLAXBT_NEXUS_API_KEY_MISSING") return 503; + if (error?.code === "OLAXBT_UPSTREAM_AUTH_FAILED") return 502; + if (String(error?.message || "").includes("BODY_TOO_LARGE")) return 413; + if (error instanceof SyntaxError) return 400; + return 502; +} + +export default async function handler(req, res) { + if (req.method !== "POST") { + sendJson(res, 405, { error: "METHOD_NOT_ALLOWED", allowed: ["POST"] }); + return; + } + + try { + const body = await readBody(req); + if (!body || typeof body !== "object" || !body.symbol) { + sendJson(res, 400, { error: "INVALID_INPUT", required: { symbol: "BTC/USDT" } }); + return; + } + const result = await buildStrategyEvidence({ symbol: body.symbol }); + sendJson(res, 200, result); + } catch (error) { + sendJson(res, statusFor(error), { + error: error?.code || (error instanceof SyntaxError ? "INVALID_JSON" : "OLAXBT_STRATEGY_EVIDENCE_UNAVAILABLE"), + detail: String(error?.message || error), + trading_authority: false, + trade_execution: false + }); + } +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/verification.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/verification.mjs new file mode 100644 index 0000000..13e7b12 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/verification.mjs @@ -0,0 +1,7 @@ +import { verificationPayload } from "../lib/runtime.mjs"; +import { methodGate, sendJson } from "../lib/http.mjs"; + +export default function handler(req, res) { + if (!methodGate(req, res)) return; + sendJson(res, 200, verificationPayload(), "public, max-age=30"); +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/window.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/window.mjs new file mode 100644 index 0000000..8243cf0 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/window.mjs @@ -0,0 +1,11 @@ +import { methodGate, sendJson } from "../lib/http.mjs"; +import { getWindow } from "../lib/windows.mjs"; + +export default function handler(req, res) { + if (!methodGate(req, res)) return; + const url = new URL(req.url || "/", "http://localhost"); + const id = String(url.searchParams.get("id") || ""); + const record = getWindow(id, new Date()); + if (!record) return sendJson(res, 404, { error: "WINDOW_NOT_FOUND", supported: ["SEP_10_2026", "SEP_17_2026"] }); + sendJson(res, 200, record, "public, max-age=30"); +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/windows.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/windows.mjs new file mode 100644 index 0000000..490af23 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/api/windows.mjs @@ -0,0 +1,8 @@ +import { methodGate, sendJson } from "../lib/http.mjs"; +import { listWindows, temporalSummary } from "../lib/windows.mjs"; + +export default function handler(req, res) { + if (!methodGate(req, res)) return; + const now = new Date(); + sendJson(res, 200, { ...temporalSummary(now), windows: listWindows(now) }, "public, max-age=30"); +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/AGENT_WORKFLOW.md b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/AGENT_WORKFLOW.md new file mode 100644 index 0000000..341593a --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/AGENT_WORKFLOW.md @@ -0,0 +1,44 @@ +# Agent workflow — OlaXBT Strategy Evidence + +## Primary question + +Can an agent trust the evidence context behind this OlaXBT strategy signal right now? + +## Workflow + +```text +ASK BTC/USDT EVIDENCE CONTEXT +→ READ OLAXBT SIGNAL +→ READ OLAXBT METRICS +→ READ OLAXBT TRADES +→ READ OLAXBT EQUITY +→ NORMALIZE OBSERVED FIELDS +→ SURFACE SUPPORT + CONTRADICTIONS + LIMITATIONS +→ RETURN BOUNDED EVIDENCE ASSESSMENT +``` + +OLAXBT remains strategy + signal authority. BHRIGU is the interpretation layer and never emits a replacement trading signal. + +## Agent entry points + +REST: `POST /v1/strategy-evidence` with `{"symbol":"BTC/USDT"}`. + +MCP: call `bhrigu_get_olaxbt_strategy_evidence` with `{"symbol":"BTC/USDT"}`. + +Both return the same Strategy Evidence object and the same authority flags. + +## Decision discipline + +An agent may use the returned object to understand evidence quality and uncertainty. It must not treat `assessment` as an order instruction. `SUPPORTED` means the historical evidence dimensions are comparatively supportive; it does not mean BUY or SELL. + +## Failure discipline + +- Missing upstream source → explicit `source_status.*.ok=false`. +- Missing direction → no direction is invented. +- Missing source win rate → recent trade statistics are not substituted. +- Upstream authentication failure → explicit failure. +- No trade, wallet, transfer, withdrawal, or payment side effect exists. + +## Inherited temporal evidence + +The repository still exposes its prior Bitcoin Temporal Evidence tools for Open-Innovation continuity. They are secondary in the trading-track judging path and do not change the Strategy Evidence authority boundary. diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/MCP_PROTOCOL.md b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/MCP_PROTOCOL.md new file mode 100644 index 0000000..40d6063 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/MCP_PROTOCOL.md @@ -0,0 +1,29 @@ +# MCP protocol contract + +BHRIGU serves the same four read-only tools across the modern and legacy MCP lifecycle eras. + +## Modern era — 2026-07-28 + +The modern path is stateless and handshake-free. `server/discover` is available for up-front discovery, but tools can be called directly when the client already knows the contract. + +Every modern non-notification HTTP request carries: + +- `MCP-Protocol-Version: 2026-07-28` +- `Mcp-Method` matching the JSON-RPC method +- `Mcp-Name` where the method mirrors a `params.name` value, including `tools/call` +- `_meta.io.modelcontextprotocol/protocolVersion = 2026-07-28` +- `_meta.io.modelcontextprotocol/clientCapabilities` + +`_meta.io.modelcontextprotocol/clientInfo` is recommended but optional; if present it must be well formed. Notification POSTs are exempt from the standard-header presence check. + +`server/discover` advertises every protocol revision this endpoint supports so a client can negotiate the modern era or deliberately fall back to a legacy initialize-capable revision. Modern complete results carry `resultType: "complete"`; server identity is stamped in `_meta.io.modelcontextprotocol/serverInfo`, and cacheable discovery/list results carry explicit `ttlMs` and `cacheScope` hints. + +The server fails closed on malformed or missing required `_meta` fields (`-32602`), header/body mismatches (`-32020`), and unsupported protocol versions (`-32022`). `-32022` errors return both the requested revision and the supported-version set. The current BHRIGU tools require no optional client capability beyond the mandatory per-request `clientCapabilities` envelope, so they do not emit `-32021` in ordinary use. Modern `initialize` and `ping` are not served because they belong to the handshake-era lifecycle. + +## Legacy era — 2025-11-25 / 2025-03-26 + +Legacy clients can still use `initialize` and the same read-only tools. BHRIGU uses the stateless legacy HTTP form: it does not create a protocol session because these tools never require server-to-client requests or hidden transport state. + +## Safety boundary + +MCP calls never create observations, rewrite precommits, trade, sign, pay, transfer, withdraw, read credentials, or access private account data. Temporal evidence is committed separately and exposed read-only. diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/OLAXBT_STRATEGY_EVIDENCE.md b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/OLAXBT_STRATEGY_EVIDENCE.md new file mode 100644 index 0000000..2e35590 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/OLAXBT_STRATEGY_EVIDENCE.md @@ -0,0 +1,58 @@ +# OlaXBT Strategy Evidence — primary trading-track capability + +## Authority split + +- **OLAXBT:** strategy + signal authority. +- **BHRIGU:** evidence interpretation layer. +- **Job:** Can an agent trust the evidence context behind this OlaXBT strategy signal right now? + +BHRIGU does not generate a second signal. It preserves the observed OlaXBT direction and surrounds it with historical strategy evidence, recent behavior, equity context, contradictions, limitations, and source status. + +## Observed upstream normalization + +The live OlaXBT Nexus shapes observed for the bound strategy are normalized only from explicit source fields: + +- `get_strategy_signal.content.trade_intent` → `signal.direction` (`BUY`, `SELL`, or `HOLD` when supplied). +- `get_strategy_signal.content.confidence` → `signal.confidence`. +- `get_strategy_signal.content.reasoning_log` → `signal.reasoning_log`. +- `get_strategy_metrics.content.win_rate_pct` → `strategy_evidence.win_rate`. + +Reasoning text is never parsed to infer direction. Recent-trade positive share is never substituted for OlaXBT source win rate. + +## REST + +```http +POST /v1/strategy-evidence +content-type: application/json + +{"symbol":"BTC/USDT"} +``` + +## MCP + +Tool: `bhrigu_get_olaxbt_strategy_evidence` + +Input schema: exactly `symbol = BTC/USDT`. Output is the same bounded Strategy Evidence object returned by REST. + +## Four upstream sources + +1. `get_strategy_signal` +2. `get_strategy_metrics` +3. `get_strategy_trades` +4. `get_strategy_equity` + +A source failure is reported under `source_status` and in `limitations`; evidence is never fabricated. + +## Assessment enum + +`SUPPORTED | MIXED | WEAK | INSUFFICIENT` + +This evaluates evidence quality around the observed OlaXBT signal. It is not a new BUY/SELL/HOLD output and not a price forecast. + +## Secret boundary + +The authorized Nexus credential exists only as the server environment variable `OLAXBT_NEXUS_API_KEY`. The repository contains no real credential value. + +## Forbidden + +No trading execution, wallet access, exchange credentials, payment, portfolio management, autonomous order loop, signal fabrication, or reasoning-text direction inference. diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/OPERATING_PROOF.md b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/OPERATING_PROOF.md new file mode 100644 index 0000000..7ac3d78 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/OPERATING_PROOF.md @@ -0,0 +1,54 @@ +# Operating proof and failure contract + +This document defines what a reviewer or agent can verify without credentials. + +## Version binding + +A review deployment is valid only when all three surfaces agree on one exact 40-character source commit: + +1. the declared review commit in the submission package; +2. `GET /health` → `status: ok|healthy` plus that commit; +3. `GET /.well-known/xagent-verification.json` → the BHRIGU slug plus that commit. + +A mismatch is a release blocker, not a warning. + +## Deterministic source gate + +`npm run check` executes four suites: + +- original acceptance behavior; +- temporal-window behavior; +- MCP protocol/tool behavior; +- immutable-artifact and authority-boundary integrity. + +CI then boots the HTTP server and performs live local HTTP/MCP smoke checks, including modern `server/discover`, `tools/list`, and a temporal-window tool call. + +## Public runtime dependencies + +BHRIGU reads public Binance Spot BTCUSDT market data and public Bitcoin tip-height evidence from mempool.space. No API key, wallet, user account, or private credential is required. + +## Failure contract + +- Market data unavailable → fail closed; do not fabricate a live comparison. +- Protocol-height source unavailable → expose the unavailable state; do not silently substitute a private value. +- Invalid/unknown temporal window → structured `WINDOW_NOT_FOUND` tool error. +- Malformed modern MCP metadata → JSON-RPC `-32602`. +- MCP header/body mismatch → `-32020`. +- Unsupported MCP revision → `-32022` with requested/supported versions. +- No MCP call writes evidence or changes a precommit. + +## Operating boundary + +The service is intentionally narrow: public Bitcoin temporal evidence for agents. Trading, order placement, wallet access, payment, transfer, withdrawal, credentials, private account data, ORION internals, private prompts, private evaluators, and unpublished research methods remain outside this artifact. + +## Reviewer challenge + +A reviewer can challenge the service by asking it to: + +1. expose the frozen `SEP_10_2026` record and its integrity hash; +2. compare that record with live Bitcoin reality; +3. expose `SEP_17_2026` as the next precommitted window; +4. reject a malformed MCP envelope or unsupported version; +5. prove the running review deployment is bound to the exact declared commit. + +If any one of these fails, the first-place upgrade is not release-ready. diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/SCORECARD.md b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/SCORECARD.md new file mode 100644 index 0000000..d941ebf --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/SCORECARD.md @@ -0,0 +1,38 @@ +# X-Agent OlaXBT judge-first scorecard + +## Primary product truth + +**OLAXBT = strategy + signal authority.** +**BHRIGU = evidence interpretation layer.** +**Job = Can an agent trust the evidence context behind this OlaXBT strategy signal right now?** + +## Hard-gate evidence + +| Gate | Evidence | +| --- | --- | +| Callable | REST `POST /v1/strategy-evidence`; MCP `bhrigu_get_olaxbt_strategy_evidence` | +| Real | Four live OlaXBT Nexus sources: signal, metrics, trades, equity | +| Reproducible | Node 22+, lockfile, deterministic tests, exact commit binding | +| Safe | Read-only; no trading execution, wallet, payment, transfer, withdrawal, or second signal | +| Useful for agents | One machine-readable evidence object with source status, contradictions, limitations, and explicit authority | + +## Score-maximizing evidence + +### Real agent/user value +An agent does not merely receive a direction. It receives the evidence context needed to decide how much confidence to place in the *context* around an OlaXBT signal, while OlaXBT retains signal authority. + +### Demonstrated capability quality +Observed upstream fields are normalized exactly: `trade_intent` supplies direction and `win_rate_pct` supplies OlaXBT source win rate. Direction is never inferred from prose, and recent-trade positive share is not substituted for source win rate. Four upstream source statuses are independently visible. + +### Engineering / maintainability +The new MCP tool calls the same `buildStrategyEvidence()` path as REST, preventing two product implementations. No new runtime dependency or trading engine is introduced. + +### MCP productization readiness +Exactly one trading-track MCP tool is added: `bhrigu_get_olaxbt_strategy_evidence`. Input is constrained to `BTC/USDT`, output is structured and read-only, and authority flags are explicit. + +### Adoption / operating potential +The capability is small enough for another agent to call directly, requires no caller credential, and keeps the upstream Nexus key server-side. Existing Bitcoin Temporal Evidence remains inherited context rather than the first-screen product object. + +## Non-claims + +No guarantee of profitability, future return, signal correctness, or trading outcome. No autonomous execution. No second BHRIGU signal. diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/TEMPORAL_EVIDENCE.md b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/TEMPORAL_EVIDENCE.md new file mode 100644 index 0000000..23e380c --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/docs/TEMPORAL_EVIDENCE.md @@ -0,0 +1,31 @@ +# Temporal evidence contract + +BHRIGU treats time as evidence, not as a prediction claim. + +`FIELD → WINDOW → REALITY → MEMORY → NEXT WINDOW` + +## SEP_10_2026 + +The original `lib/window.mjs` was committed before the boundary and remains byte-identical. CI pins its SHA-256: + +`fd92dc8a578a2f5f393b87d3f0e65bdf2f8b9ff828ddccf21eabce66d6d39998` + +Boundary: `2026-09-10T00:00:00Z`. + +A post-boundary reality observation is now stored in `lib/evidence.mjs` and mirrored as `evidence/SEP_10_2026_POSTBOUNDARY.json`. CI pins the evidence artifact SHA-256 `80bc4e19efa6858371559815a08fbc6224a34c751658d410d6aa7d6ad3b57027`. It records the live runtime observation, exact runtime commit, direct Binance cross-check, and the limitation that an independent protocol-height probe timed out. + +## SEP_17_2026 + +`lib/window-sep17.mjs` is the second genuine future precommit. Its public proof artifact `evidence/SEP_17_2026_PRECOMMIT.json` is pinned to SHA-256 `19a27baa6c5f55efbfda84782cf4920374c82323f13f6eabce7d63ed2f0a13f2`. Its baseline was captured on 2026-09-10, seven days before the boundary. No post-boundary evidence exists yet. After the boundary, any evidence must be appended; the baseline must not be rewritten. + +## Agent value + +An agent can ask: + +1. What was fixed before the boundary? +2. What is true now? +3. What changed relative to the precommit? +4. What durable evidence exists? +5. What future precommit is next? + +The server remains read-only. It never writes observations during an MCP call and has zero trading, wallet, payment, transfer, or private-account authority. diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/evidence/SEP_10_2026_POSTBOUNDARY.json b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/evidence/SEP_10_2026_POSTBOUNDARY.json new file mode 100644 index 0000000..792ee03 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/evidence/SEP_10_2026_POSTBOUNDARY.json @@ -0,0 +1,17 @@ +{ + "schema": "bhrigu_temporal_evidence_v0_1", + "id": "SEP_10_2026__2026-09-10T04:49:49.136Z", + "window_id": "SEP_10_2026", + "kind": "post_boundary_reality_observation", + "observed_at_utc": "2026-09-10T04:49:49.136Z", + "boundary_utc": "2026-09-10T00:00:00Z", + "baseline_btcusdt": 78474, + "observed_btcusdt": 78348.09, + "current_vs_baseline_pct": -0.1604, + "runtime_commit": "05a455ba1407f7b07de226f6c78eefda15b24880", + "market_crosscheck_btcusdt": 78348.10, + "protocol_tip_height": 966302, + "protocol_crosscheck": "runtime_source_status_live; independent ORION probe timed out", + "retroactive_rewrite": "forbidden", + "trading_signal": false +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/evidence/SEP_17_2026_PRECOMMIT.json b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/evidence/SEP_17_2026_PRECOMMIT.json new file mode 100644 index 0000000..e76d32b --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/evidence/SEP_17_2026_PRECOMMIT.json @@ -0,0 +1,16 @@ +{ + "schema": "bhrigu_temporal_precommit_v0_1", + "window_id": "SEP_17_2026", + "boundary_utc": "2026-09-17T00:00:00Z", + "captured_at_utc": "2026-09-10T04:49:49.136Z", + "btcusdt_last_price": 78348.09, + "btcusdt_24h_change_pct": -0.983, + "btcusdt_24h_high": 79760, + "btcusdt_24h_low": 77770, + "bitcoin_tip_height": 966302, + "source_runtime_commit": "05a455ba1407f7b07de226f6c78eefda15b24880", + "market_crosscheck_last_price_usdt": 78348.10, + "retroactive_rewrite": "forbidden", + "price_target": false, + "trading_signal": false +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/evidence.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/evidence.mjs new file mode 100644 index 0000000..4c697bd --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/evidence.mjs @@ -0,0 +1,38 @@ +export const SEP_10_POSTBOUNDARY_EVIDENCE = Object.freeze({ + schema: "bhrigu_temporal_evidence_v0_1", + id: "SEP_10_2026__2026-09-10T04:49:49.136Z", + window_id: "SEP_10_2026", + kind: "post_boundary_reality_observation", + observed_at_utc: "2026-09-10T04:49:49.136Z", + boundary_utc: "2026-09-10T00:00:00Z", + baseline: Object.freeze({ + captured_at_utc: "2026-09-08T11:25:23Z", + btcusdt_last_price: 78474 + }), + observation: Object.freeze({ + btcusdt_last_price: 78348.09, + current_vs_baseline_pct: -0.1604, + btcusdt_24h_change_pct: -0.983, + btcusdt_24h_high: 79760, + btcusdt_24h_low: 77770, + volume_24h_btc: 13960.82618, + bitcoin_tip_height: 966302 + }), + provenance: Object.freeze({ + runtime_endpoint: "https://bhrigu-bitcoin-research-state-api.vercel.app/v1/state", + runtime_commit: "05a455ba1407f7b07de226f6c78eefda15b24880", + market_source: "https://data-api.binance.vision/api/v3/ticker/24hr?symbol=BTCUSDT", + market_crosscheck_last_price_usdt: 78348.10, + market_crosscheck_abs_diff_usdt: 0.01, + protocol_source: "https://mempool.space/api/blocks/tip/height", + protocol_crosscheck: "runtime_source_status_live; independent ORION probe timed out" + }), + verdict: "POST_BOUNDARY_REALITY_CAPTURED", + invariants: Object.freeze({ + append_only: true, + retroactive_rewrite: "forbidden", + trading_signal: false + }) +}); + +export const EVIDENCE_LEDGER = Object.freeze([SEP_10_POSTBOUNDARY_EVIDENCE]); diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/http.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/http.mjs new file mode 100644 index 0000000..214d88f --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/http.mjs @@ -0,0 +1,14 @@ +export function sendJson(res, status, payload, cache = "no-store") { + res.statusCode = status; + res.setHeader("content-type", "application/json; charset=utf-8"); + res.setHeader("cache-control", cache); + res.setHeader("access-control-allow-origin", "*"); + res.setHeader("x-content-type-options", "nosniff"); + res.end(JSON.stringify(payload)); +} + +export function methodGate(req, res) { + if (req.method === "GET") return true; + sendJson(res, 405, { error: "METHOD_NOT_ALLOWED", allowed: ["GET"] }); + return false; +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/integrity.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/integrity.mjs new file mode 100644 index 0000000..e13aab6 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/integrity.mjs @@ -0,0 +1,17 @@ +export const WINDOW_INTEGRITY = Object.freeze({ + SEP_10_2026: Object.freeze({ + artifact_path: "lib/window.mjs", + sha256: "fd92dc8a578a2f5f393b87d3f0e65bdf2f8b9ff828ddccf21eabce66d6d39998" + }), + SEP_17_2026: Object.freeze({ + artifact_path: "evidence/SEP_17_2026_PRECOMMIT.json", + sha256: "19a27baa6c5f55efbfda84782cf4920374c82323f13f6eabce7d63ed2f0a13f2" + }) +}); + +export const EVIDENCE_INTEGRITY = Object.freeze({ + SEP_10_2026: Object.freeze({ + artifact_path: "evidence/SEP_10_2026_POSTBOUNDARY.json", + sha256: "80bc4e19efa6858371559815a08fbc6224a34c751658d410d6aa7d6ad3b57027" + }) +}); diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/live.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/live.mjs new file mode 100644 index 0000000..b17c125 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/live.mjs @@ -0,0 +1,42 @@ +const BINANCE_TICKER = "https://data-api.binance.vision/api/v3/ticker/24hr?symbol=BTCUSDT"; +const MEMPOOL_TIP = "https://mempool.space/api/blocks/tip/height"; + +async function timedFetch(url, fetchImpl = fetch) { + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), 8000); + try { + const response = await fetchImpl(url, { signal: controller.signal, headers: { accept: "application/json,text/plain" } }); + if (!response.ok) throw new Error(`HTTP_${response.status}`); + return response; + } finally { + clearTimeout(timer); + } +} + +export async function fetchMarket(fetchImpl = fetch) { + const response = await timedFetch(BINANCE_TICKER, fetchImpl); + const d = await response.json(); + return { + venue: "Binance Spot", + symbol: "BTCUSDT", + last_price_usdt: Number(d.lastPrice), + change_24h_pct: Number(d.priceChangePercent), + high_24h_usdt: Number(d.highPrice), + low_24h_usdt: Number(d.lowPrice), + volume_24h_btc: Number(d.volume), + source_close_time_ms: Number(d.closeTime), + source: BINANCE_TICKER, + security_type: "NONE" + }; +} + +export async function fetchProtocol(fetchImpl = fetch) { + try { + const response = await timedFetch(MEMPOOL_TIP, fetchImpl); + const height = Number(await response.text()); + if (!Number.isInteger(height) || height < 840000) throw new Error("INVALID_HEIGHT"); + return { height, source: MEMPOOL_TIP, status: "live" }; + } catch (error) { + return { height: null, source: MEMPOOL_TIP, status: "unavailable", error: String(error.message || error) }; + } +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/mcp.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/mcp.mjs new file mode 100644 index 0000000..ea8f690 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/mcp.mjs @@ -0,0 +1,285 @@ +import { buildState } from "./state.mjs"; +import { buildStrategyEvidence } from "./strategy-evidence.mjs"; +import { getWindow, listWindows } from "./windows.mjs"; + +export const MCP_MODERN_PROTOCOL_VERSION = "2026-07-28"; +export const MCP_LEGACY_PROTOCOL_VERSION = "2025-11-25"; +export const MCP_SUPPORTED_PROTOCOL_VERSIONS = Object.freeze([ + MCP_MODERN_PROTOCOL_VERSION, + MCP_LEGACY_PROTOCOL_VERSION, + "2025-03-26" +]); +export const MCP_PROTOCOL_VERSION = MCP_LEGACY_PROTOCOL_VERSION; + +const SERVER_INFO = Object.freeze({ + name: "bhrigu-olaxbt-strategy-evidence-agent", + title: "BHRIGU OlaXBT Strategy Evidence Agent", + version: "0.3.0" +}); +const SERVER_CAPABILITIES = Object.freeze({ tools: Object.freeze({ listChanged: false }) }); +const SERVER_INSTRUCTIONS = "Primary trading-track job: use bhrigu_get_olaxbt_strategy_evidence to inspect evidence context behind the current OlaXBT strategy signal. OlaXBT is strategy + signal authority; BHRIGU is read-only evidence interpretation. Inherited Bitcoin temporal-evidence tools remain available. No trading, wallet, payment, or second-signal authority."; +const CACHE_HINT = Object.freeze({ ttlMs: 300000, cacheScope: "public" }); +const PROTOCOL_META = "io.modelcontextprotocol/protocolVersion"; +const CLIENT_INFO_META = "io.modelcontextprotocol/clientInfo"; +const CLIENT_CAPS_META = "io.modelcontextprotocol/clientCapabilities"; +const SERVER_INFO_META = "io.modelcontextprotocol/serverInfo"; + +export const MCP_TOOLS = Object.freeze([ + { + name: "bhrigu_get_olaxbt_strategy_evidence", + title: "Get OlaXBT strategy evidence context", + description: "Read the current OlaXBT BTC/USDT strategy signal together with strategy metrics, recent trades, equity context, contradictions, limitations, and a bounded evidence-quality assessment. OlaXBT remains signal authority; BHRIGU does not create a second signal or execute trades.", + inputSchema: { + type: "object", additionalProperties: false, required: ["symbol"], + properties: { symbol: { type: "string", enum: ["BTC/USDT"] } } + }, + annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true } + }, + { + name: "bhrigu_get_bitcoin_research_state", + title: "Get live Bitcoin research state", + description: "Read the current BTCUSDT market state, Bitcoin protocol-time coordinates, source freshness, and temporal-evidence summary. Read-only; never trades, signs, pays, transfers, or accesses private account data.", + inputSchema: { type: "object", additionalProperties: false, properties: {} }, + annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true } + }, + { + name: "bhrigu_list_temporal_windows", + title: "List BHRIGU temporal windows", + description: "List public precommitted Bitcoin observation windows with phase, boundary, immutable-rewrite law, and durable evidence count.", + inputSchema: { type: "object", additionalProperties: false, properties: {} }, + annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false } + }, + { + name: "bhrigu_get_temporal_window", + title: "Get one temporal window and evidence", + description: "Read one frozen precommit together with durable post-boundary evidence already committed for that window.", + inputSchema: { + type: "object", additionalProperties: false, required: ["window_id"], + properties: { window_id: { type: "string", enum: ["SEP_10_2026", "SEP_17_2026"] } } + }, + annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false } + }, + { + name: "bhrigu_compare_window_to_reality", + title: "Compare a precommit with live reality", + description: "Read live public Bitcoin evidence and compare BTCUSDT against the selected precommitted baseline. No observation is written and no trading authority exists.", + inputSchema: { + type: "object", additionalProperties: false, required: ["window_id"], + properties: { window_id: { type: "string", enum: ["SEP_10_2026", "SEP_17_2026"] } } + }, + annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true } + } +]); + +const rpcResult = (id, result) => ({ jsonrpc: "2.0", id, result }); +const rpcError = (id, code, message, data) => ({ + jsonrpc: "2.0", id, error: { code, message, ...(data === undefined ? {} : { data }) } +}); +const modernMeta = () => ({ [SERVER_INFO_META]: SERVER_INFO }); +const completeResult = (value = {}, modern = false, cacheable = false) => modern + ? { resultType: "complete", ...value, ...(cacheable ? CACHE_HINT : {}), _meta: modernMeta() } + : value; +const toolResult = (value, modern = false) => completeResult({ + content: [{ type: "text", text: JSON.stringify(value) }], + structuredContent: value, + isError: false +}, modern); +const toolError = (code, message, modern = false) => completeResult({ + content: [{ type: "text", text: JSON.stringify({ error: { code, message } }) }], + structuredContent: { error: { code, message } }, + isError: true +}, modern); + +function parseRpc(body) { + if (!body || typeof body !== "object" || Array.isArray(body) || body.jsonrpc !== "2.0" || typeof body.method !== "string") return null; + if (body.id !== undefined && body.id !== null && typeof body.id !== "string" && typeof body.id !== "number") return null; + return body; +} + +function parseWindowId(args) { + const id = args?.window_id; + return typeof id === "string" ? id : null; +} + +function bodyProtocolVersion(rpc) { + return rpc.params?._meta?.[PROTOCOL_META] ?? null; +} + +function unsupportedVersion(rpc, requested) { + return rpcError(rpc.id ?? null, -32022, "Unsupported protocol version", { + supported: MCP_SUPPORTED_PROTOCOL_VERSIONS, + requested + }); +} + +function classifyEra(rpc, transportMeta = {}) { + const bodyVersion = bodyProtocolVersion(rpc); + const headerVersion = transportMeta.protocolVersion ?? null; + + if (bodyVersion && !MCP_SUPPORTED_PROTOCOL_VERSIONS.includes(bodyVersion)) { + return { error: unsupportedVersion(rpc, bodyVersion) }; + } + if (headerVersion && !MCP_SUPPORTED_PROTOCOL_VERSIONS.includes(headerVersion)) { + return { error: unsupportedVersion(rpc, headerVersion) }; + } + + const modern = rpc.method === "server/discover" + || bodyVersion !== null + || headerVersion === MCP_MODERN_PROTOCOL_VERSION; + return { modern, bodyVersion, headerVersion }; +} + +function validImplementation(value) { + return value + && typeof value === "object" + && !Array.isArray(value) + && typeof value.name === "string" + && value.name.length > 0 + && typeof value.version === "string" + && value.version.length > 0; +} + +function validateModernRequest(rpc, transportMeta = {}, classification) { + const envelope = rpc.params?._meta; + if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) { + return rpcError(rpc.id ?? null, -32602, "Invalid params", { + missing: [PROTOCOL_META, CLIENT_CAPS_META] + }); + } + + const version = envelope[PROTOCOL_META]; + if (typeof version !== "string" || version.length === 0) { + return rpcError(rpc.id ?? null, -32602, "Invalid params", { missing: [PROTOCOL_META] }); + } + if (version !== MCP_MODERN_PROTOCOL_VERSION) return unsupportedVersion(rpc, version); + + const clientCapabilities = envelope[CLIENT_CAPS_META]; + if (!clientCapabilities || typeof clientCapabilities !== "object" || Array.isArray(clientCapabilities)) { + return rpcError(rpc.id ?? null, -32602, "Invalid params", { missing: [CLIENT_CAPS_META] }); + } + + const clientInfo = envelope[CLIENT_INFO_META]; + if (clientInfo !== undefined && !validImplementation(clientInfo)) { + return rpcError(rpc.id ?? null, -32602, "Invalid params", { malformed: [CLIENT_INFO_META] }); + } + + const isNotification = rpc.method.startsWith("notifications/"); + if (transportMeta.requireHeaders && !isNotification) { + if (classification.headerVersion !== version || transportMeta.method !== rpc.method) { + return rpcError(rpc.id ?? null, -32020, "MCP header/body mismatch", { + expectedProtocolVersion: version, + expectedMethod: rpc.method + }); + } + if (rpc.method === "tools/call" && transportMeta.name !== rpc.params?.name) { + return rpcError(rpc.id ?? null, -32020, "MCP header/body mismatch", { + expectedName: rpc.params?.name ?? null + }); + } + } + return null; +} + +async function compareWindow(windowId, options) { + const record = getWindow(windowId, options.now); + if (!record) return null; + const state = await buildState(options); + const baseline = record.window.baseline.btcusdt_last_price; + const current = state.market.last_price_usdt; + return { + window_id: windowId, + boundary_utc: record.window.boundary_utc, + phase: record.phase, + observed_at_utc: state.observed_at_utc, + baseline_btcusdt: baseline, + current_btcusdt: current, + current_vs_baseline_pct: Number((((current - baseline) / baseline) * 100).toFixed(4)), + market_source: state.market.source, + market_freshness: state.market.freshness, + trading_authority: false + }; +} + +export async function handleMcpRpc(body, { fetchImpl = fetch, now = new Date(), transportMeta = {} } = {}) { + const rpc = parseRpc(body); + if (!rpc) return { status: 400, body: rpcError(null, -32600, "Invalid Request") }; + const id = rpc.id ?? null; + const classification = classifyEra(rpc, transportMeta); + if (classification.error) return { status: 400, body: classification.error }; + const modern = classification.modern; + + if (modern) { + const validationError = validateModernRequest(rpc, transportMeta, classification); + if (validationError) return { status: 400, body: validationError }; + if (rpc.method === "initialize" || rpc.method === "ping") { + return { status: 404, body: rpcError(id, -32601, "Method not found") }; + } + } + + if (rpc.method.startsWith("notifications/")) return { status: 202, body: null }; + if (rpc.method === "ping") return { status: 200, body: rpcResult(id, {}) }; + if (rpc.method === "server/discover") { + return { + status: 200, + body: rpcResult(id, completeResult({ + supportedVersions: MCP_SUPPORTED_PROTOCOL_VERSIONS, + capabilities: SERVER_CAPABILITIES, + instructions: SERVER_INSTRUCTIONS + }, true, true)) + }; + } + if (rpc.method === "initialize") { + const requested = rpc.params?.protocolVersion; + const protocolVersion = requested === "2025-03-26" ? "2025-03-26" : MCP_LEGACY_PROTOCOL_VERSION; + return { + status: 200, + body: rpcResult(id, { + protocolVersion, + capabilities: SERVER_CAPABILITIES, + serverInfo: SERVER_INFO, + instructions: SERVER_INSTRUCTIONS + }) + }; + } + if (rpc.method === "tools/list") { + return { status: 200, body: rpcResult(id, completeResult({ tools: MCP_TOOLS }, modern, modern)) }; + } + if (rpc.method !== "tools/call") return { status: 404, body: rpcError(id, -32601, "Method not found") }; + + const name = rpc.params?.name; + const args = rpc.params?.arguments ?? {}; + if (typeof name !== "string" || !args || typeof args !== "object" || Array.isArray(args)) { + return { status: 400, body: rpcError(id, -32602, "Invalid params") }; + } + + try { + if (name === "bhrigu_get_olaxbt_strategy_evidence") { + const symbol = args?.symbol; + if (symbol !== "BTC/USDT") { + return { status: 200, body: rpcResult(id, toolError("UNSUPPORTED_SYMBOL", "symbol must be BTC/USDT", modern)) }; + } + return { status: 200, body: rpcResult(id, toolResult(await buildStrategyEvidence({ symbol, fetchImpl, now }), modern)) }; + } + if (name === "bhrigu_get_bitcoin_research_state") { + return { status: 200, body: rpcResult(id, toolResult(await buildState({ fetchImpl, now }), modern)) }; + } + if (name === "bhrigu_list_temporal_windows") { + return { status: 200, body: rpcResult(id, toolResult({ windows: listWindows(now) }, modern)) }; + } + if (name === "bhrigu_get_temporal_window") { + const windowId = parseWindowId(args); + const record = windowId ? getWindow(windowId, now) : null; + if (!record) return { status: 200, body: rpcResult(id, toolError("WINDOW_NOT_FOUND", "Unknown or missing window_id.", modern)) }; + return { status: 200, body: rpcResult(id, toolResult(record, modern)) }; + } + if (name === "bhrigu_compare_window_to_reality") { + const windowId = parseWindowId(args); + const comparison = windowId ? await compareWindow(windowId, { fetchImpl, now }) : null; + if (!comparison) return { status: 200, body: rpcResult(id, toolError("WINDOW_NOT_FOUND", "Unknown or missing window_id.", modern)) }; + return { status: 200, body: rpcResult(id, toolResult(comparison, modern)) }; + } + return { status: 200, body: rpcResult(id, toolError("TOOL_NOT_FOUND", `Unknown tool: ${name}`, modern)) }; + } catch (error) { + return { status: 200, body: rpcResult(id, toolError("PUBLIC_SOURCE_UNAVAILABLE", String(error.message || error), modern)) }; + } +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/olaxbt-nexus.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/olaxbt-nexus.mjs new file mode 100644 index 0000000..73e910c --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/olaxbt-nexus.mjs @@ -0,0 +1,125 @@ +export const OLAXBT_NEXUS_URL = "https://nexus.olaxbt.xyz/api/mcp/tools/call"; + +export class OlaXbtNexusError extends Error { + constructor(code, message, { status = null, tool = null, detail = null } = {}) { + super(message); + this.name = "OlaXbtNexusError"; + this.code = code; + this.status = status; + this.tool = tool; + this.detail = detail; + } +} + +export function resolveOlaXbtApiKey(env = process.env) { + const key = String(env.OLAXBT_NEXUS_API_KEY || env.OLAXBT_API_KEY || "").trim(); + if (!key) { + throw new OlaXbtNexusError( + "OLAXBT_NEXUS_API_KEY_MISSING", + "Server-side OlaXBT Nexus API key is not configured." + ); + } + return key; +} + +function compactDetail(payload) { + if (payload == null) return null; + if (typeof payload === "string") return payload.slice(0, 500); + if (typeof payload === "object") { + const candidate = payload.error ?? payload.message ?? payload.detail ?? payload.reason ?? null; + if (candidate == null) return null; + return typeof candidate === "string" ? candidate.slice(0, 500) : JSON.stringify(candidate).slice(0, 500); + } + return String(payload).slice(0, 500); +} + +function parseTextContent(value) { + if (typeof value !== "string") return value; + const text = value.trim(); + if (!text) return value; + try { return JSON.parse(text); } catch { return value; } +} + +export function unwrapNexusPayload(payload) { + let current = payload; + for (let depth = 0; depth < 6; depth += 1) { + if (Array.isArray(current)) return current; + if (current == null || typeof current !== "object") return parseTextContent(current); + + if (Array.isArray(current.content) && current.content.length > 0) { + const textItem = current.content.find((item) => item && typeof item === "object" && typeof item.text === "string"); + if (textItem) { + current = parseTextContent(textItem.text); + continue; + } + } + + const wrapperKeys = ["result", "data", "output", "payload"]; + const key = wrapperKeys.find((candidate) => Object.prototype.hasOwnProperty.call(current, candidate)); + if (key) { + current = current[key]; + continue; + } + return current; + } + return current; +} + +export async function callOlaXbtTool(name, args = {}, { + fetchImpl = fetch, + apiKey = null, + timeoutMs = 15000 +} = {}) { + const key = apiKey || resolveOlaXbtApiKey(); + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), timeoutMs); + + let response; + try { + response = await fetchImpl(OLAXBT_NEXUS_URL, { + method: "POST", + headers: { + "content-type": "application/json", + "x-api-key": key + }, + body: JSON.stringify({ name, arguments: args }), + signal: controller.signal + }); + } catch (error) { + const code = error?.name === "AbortError" ? "OLAXBT_UPSTREAM_TIMEOUT" : "OLAXBT_UPSTREAM_UNAVAILABLE"; + throw new OlaXbtNexusError(code, `OlaXBT Nexus call failed for ${name}.`, { + tool: name, + detail: String(error?.message || error) + }); + } finally { + clearTimeout(timer); + } + + const raw = await response.text(); + let parsed; + try { + parsed = raw ? JSON.parse(raw) : null; + } catch { + throw new OlaXbtNexusError("OLAXBT_UPSTREAM_MALFORMED_RESPONSE", `OlaXBT Nexus returned non-JSON for ${name}.`, { + status: response.status, + tool: name + }); + } + + if (!response.ok) { + const code = response.status === 401 || response.status === 403 + ? "OLAXBT_UPSTREAM_AUTH_FAILED" + : "OLAXBT_UPSTREAM_HTTP_ERROR"; + throw new OlaXbtNexusError(code, `OlaXBT Nexus returned HTTP ${response.status} for ${name}.`, { + status: response.status, + tool: name, + detail: compactDetail(parsed) + }); + } + + return { + tool: name, + status: response.status, + payload: unwrapNexusPayload(parsed) + }; +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/openapi.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/openapi.mjs new file mode 100644 index 0000000..62d3d7f --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/openapi.mjs @@ -0,0 +1,29 @@ +import { runtimeCommit } from "./runtime.mjs"; + +export function openapiPayload() { + return { + openapi: "3.1.0", + info: { + title: "BHRIGU Strategy Evidence Agent", + version: "0.2.0", + description: "Read-only evidence interpretation around the current OlaXBT strategy signal. OlaXBT remains strategy + signal authority; BHRIGU creates no second signal and executes no trades." + }, + servers: [{ url: "/" }], + paths: { + "/v1/state": { get: { summary: "Live Bitcoin research state" } }, + "/v1/strategy-evidence": { post: { summary: "Read-only OlaXBT strategy evidence assessment; no new trading signal" } }, + "/v1/windows": { get: { summary: "List precommitted temporal windows" } }, + "/v1/windows/{id}": { get: { summary: "Get one window and durable evidence" } }, + "/mcp": { post: { summary: "Stateless Streamable HTTP MCP JSON-RPC endpoint" } }, + "/health": { get: { summary: "Health and exact commit binding" } } + }, + "x-bhrigu": { + commit: runtimeCommit(), + boundary: "RESEARCH_STATE_NOT_TRADE", + trading: false, + wallet: false, + payment: false, + olaxbt_strategy_evidence: "read_only" + } + }; +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/runtime.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/runtime.mjs new file mode 100644 index 0000000..b65df39 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/runtime.mjs @@ -0,0 +1,14 @@ +export const SLUG = "bhrigu-olaxbt-strategy-evidence-agent"; +export const SCHEMA = "bhrigu_bitcoin_research_state_v0_1"; + +export function runtimeCommit() { + return process.env.BHRIGU_COMMIT || process.env.VERCEL_GIT_COMMIT_SHA || "LOCAL_DEV"; +} + +export function healthPayload() { + return { status: "ok", commit: runtimeCommit() }; +} + +export function verificationPayload() { + return { schemaVersion: 1, slug: SLUG, commit: runtimeCommit() }; +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/state.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/state.mjs new file mode 100644 index 0000000..03cfebc --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/state.mjs @@ -0,0 +1,62 @@ +import { fetchMarket, fetchProtocol } from "./live.mjs"; +import { WINDOW } from "./window.mjs"; +import { SCHEMA, runtimeCommit } from "./runtime.mjs"; +import { temporalSummary } from "./windows.mjs"; + +export async function buildState({ fetchImpl = fetch, now = new Date() } = {}) { + const [market, protocol] = await Promise.all([ + fetchMarket(fetchImpl), fetchProtocol(fetchImpl) + ]); + const observedAt = now.toISOString(); + const sourceAgeMs = Math.max(0, now.getTime() - market.source_close_time_ms); + const freshness = sourceAgeMs <= 120000 ? "FRESH" : "STALE"; + const epochStart = 840000; + const nextEpoch = 1050000; + const height = protocol.height; + const progress = height === null ? null : Math.max(0, Math.min(1, (height - epochStart) / (nextEpoch - epochStart))); + const boundary = new Date(WINDOW.boundary_utc); + const phase = now < boundary ? "PRE_BOUNDARY" : "POST_BOUNDARY"; + const baseline = WINDOW.baseline.btcusdt_last_price; + const deltaPct = ((market.last_price_usdt - baseline) / baseline) * 100; + + return { + schema: SCHEMA, + commit: runtimeCommit(), + observed_at_utc: observedAt, + boundary: "RESEARCH_STATE_NOT_TRADE", + market: { ...market, freshness, source_age_ms: sourceAgeMs }, + protocol_time: { + halving_epoch: 4, + epoch_start_height: epochStart, + next_epoch_height: nextEpoch, + block_subsidy_btc: 3.125, + live_tip_height: height, + epoch_progress_pct: progress === null ? null : Number((progress * 100).toFixed(4)), + source: protocol.source, + source_status: protocol.status + }, + window: { + ...WINDOW, + phase, + current_vs_baseline_pct: Number(deltaPct.toFixed(4)), + comparison_status: phase === "PRE_BOUNDARY" ? "NOT_FINAL_BEFORE_BOUNDARY" : "REALITY_COMPARISON_OPEN" + }, + temporal_evidence: temporalSummary(now), + memory: { + law: "FIELD → WINDOW → REALITY → MEMORY", + append_only: true, + retroactive_rewrite: "forbidden" + }, + authority: { + trading: false, wallet: false, payment: false, withdrawal: false, + transfer: false, private_account_data: false, credentials_read: false + }, + limits: { + method: "GET", + symbol: "BTCUSDT only", + auth: "none", + market_source: "public Binance Spot", + protocol_source: "public mempool.space tip height" + } + }; +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/strategy-evidence.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/strategy-evidence.mjs new file mode 100644 index 0000000..23ce386 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/strategy-evidence.mjs @@ -0,0 +1,259 @@ +import { callOlaXbtTool, OlaXbtNexusError, resolveOlaXbtApiKey } from "./olaxbt-nexus.mjs"; + +const TOOL_SPECS = Object.freeze([ + ["signal", "get_strategy_signal"], + ["metrics", "get_strategy_metrics"], + ["trades", "get_strategy_trades"], + ["equity", "get_strategy_equity"] +]); + +function normalizeKey(key) { + return String(key).toLowerCase().replace(/[^a-z0-9]/g, ""); +} + +function walkObjects(value, visit, depth = 0) { + if (depth > 6 || value == null) return; + if (Array.isArray(value)) { + for (const item of value) walkObjects(item, visit, depth + 1); + return; + } + if (typeof value !== "object") return; + visit(value); + for (const child of Object.values(value)) walkObjects(child, visit, depth + 1); +} + +function findValue(root, aliases) { + const wanted = new Set(aliases.map(normalizeKey)); + let found; + walkObjects(root, (obj) => { + if (found !== undefined) return; + for (const [key, value] of Object.entries(obj)) { + if (wanted.has(normalizeKey(key)) && value !== null && value !== undefined) { + found = value; + return; + } + } + }); + return found; +} + +function findArray(root, aliases) { + if (Array.isArray(root)) return root; + const value = findValue(root, aliases); + return Array.isArray(value) ? value : null; +} + +function asFiniteNumber(value) { + if (typeof value === "number" && Number.isFinite(value)) return value; + if (typeof value !== "string") return null; + const normalized = value.trim().replace(/,/g, "").replace(/%$/, ""); + if (!normalized) return null; + const number = Number(normalized); + return Number.isFinite(number) ? number : null; +} + +function asString(value) { + if (value == null) return null; + if (typeof value === "string") return value; + if (typeof value === "number" || typeof value === "boolean") return String(value); + return null; +} + +function percentIsPositive(value) { + const number = asFiniteNumber(value); + return number == null ? null : number > 0; +} + +function winRateIsPositive(value) { + const number = asFiniteNumber(value); + if (number == null) return null; + return number <= 1 ? number >= 0.5 : number >= 50; +} + +function extractSignal(payload) { + return { + direction: asString(findValue(payload, ["signal", "direction", "trade_intent", "action", "side"])), + confidence: asFiniteNumber(findValue(payload, ["confidence", "confidence_score", "score"])), + reasoning_log: asString(findValue(payload, ["reasoning_log", "reasoning", "reason", "log"])) + }; +} + +function extractMetrics(payload) { + return { + sharpe_ratio: asFiniteNumber(findValue(payload, ["sharpe_ratio", "sharpe"])), + return_pct: asFiniteNumber(findValue(payload, ["return_pct", "return_percent", "total_return_pct", "total_return", "return"])), + win_rate: asFiniteNumber(findValue(payload, ["win_rate", "win_rate_pct", "winrate"])), + profit_factor: asFiniteNumber(findValue(payload, ["profit_factor", "profitfactor"])), + max_drawdown_pct: asFiniteNumber(findValue(payload, ["max_drawdown_pct", "max_drawdown_percent", "max_drawdown", "drawdown"])), + trade_count: asFiniteNumber(findValue(payload, ["trade_count", "trades_count", "num_trades", "total_trades"])) + }; +} + +function extractTrades(payload) { + const trades = findArray(payload, ["trades", "trade_list", "items", "records"]); + if (!trades) return { observed: false, sample_size: 0, positive_count: null, negative_count: null, positive_share: null, latest_exit_reason: null }; + const recent = trades.slice(-20); + const pnlValues = recent + .map((trade) => asFiniteNumber(findValue(trade, ["pnl", "profit", "profit_loss", "realized_pnl", "return_pct", "return"]))) + .filter((value) => value !== null); + const positive = pnlValues.filter((value) => value > 0).length; + const negative = pnlValues.filter((value) => value < 0).length; + const latest = recent.at(-1) ?? null; + return { + observed: true, + sample_size: recent.length, + positive_count: pnlValues.length ? positive : null, + negative_count: pnlValues.length ? negative : null, + positive_share: pnlValues.length ? positive / pnlValues.length : null, + latest_exit_reason: latest ? asString(findValue(latest, ["exit_reason", "reason", "close_reason"])) : null + }; +} + +function equityValue(point) { + if (typeof point === "number") return Number.isFinite(point) ? point : null; + if (typeof point === "string") return asFiniteNumber(point); + if (point && typeof point === "object") return asFiniteNumber(findValue(point, ["equity", "value", "balance", "portfolio_value", "nav"])); + return null; +} + +function extractEquity(payload) { + const series = findArray(payload, ["equity_curve", "equity", "points", "series", "values"]); + if (!series || series.length < 2) return { observed: false, point_count: series?.length || 0, first: null, last: null, change_pct: null }; + const values = series.map(equityValue).filter((value) => value !== null); + if (values.length < 2) return { observed: false, point_count: series.length, first: null, last: null, change_pct: null }; + const first = values[0]; + const last = values.at(-1); + return { + observed: true, + point_count: values.length, + first, + last, + change_pct: first !== 0 ? ((last - first) / Math.abs(first)) * 100 : null + }; +} + +function buildAssessment({ signal, metrics, trades, equity, sourceStatus }) { + const supports = []; + const contradictions = []; + const limitations = []; + let positive = 0; + let negative = 0; + let observed = 0; + + const observe = (condition, supportText, contradictionText) => { + if (condition == null) return; + observed += 1; + if (condition) { + positive += 1; + supports.push(supportText); + } else { + negative += 1; + contradictions.push(contradictionText); + } + }; + + observe(percentIsPositive(metrics.return_pct), "Historical strategy return is positive.", "Historical strategy return is non-positive."); + observe(metrics.sharpe_ratio == null ? null : metrics.sharpe_ratio > 0, "Historical Sharpe ratio is positive.", "Historical Sharpe ratio is non-positive."); + observe(metrics.profit_factor == null ? null : metrics.profit_factor > 1, "Historical profit factor is above 1.", "Historical profit factor is not above 1."); + observe(winRateIsPositive(metrics.win_rate), "Historical win rate is at least 50% on the source scale.", "Historical win rate is below 50% on the source scale."); + observe(equity.change_pct == null ? null : equity.change_pct > 0, "Observed equity curve ends above its starting point.", "Observed equity curve does not end above its starting point."); + observe(trades.positive_share == null ? null : trades.positive_share >= 0.5, "At least half of recent trades with numeric PnL are positive.", "Fewer than half of recent trades with numeric PnL are positive."); + + if (!signal.direction) limitations.push("Current OlaXBT signal direction is unavailable."); + if (metrics.trade_count != null && metrics.trade_count < 5) limitations.push("Historical trade count is very small; evidence is thin."); + for (const [name, status] of Object.entries(sourceStatus)) { + if (!status.ok) limitations.push(`${name} source unavailable: ${status.code}.`); + } + + let assessment = "MIXED"; + if (!signal.direction || observed < 3) assessment = "INSUFFICIENT"; + else if (positive >= 3 && negative <= 1) assessment = "SUPPORTED"; + else if (negative >= 3 && positive <= 1) assessment = "WEAK"; + + return { + assessment, + scope: "Historical strategy-evidence quality around the observed OlaXBT signal; not a new trading signal or forecast.", + observed_dimensions: observed, + positive_dimensions: positive, + negative_dimensions: negative, + supports, + contradictions, + limitations + }; +} + +export function normalizeStrategySymbol(input) { + const normalized = String(input || "").trim().toUpperCase().replace(/\s+/g, ""); + if (normalized === "BTCUSDT" || normalized === "BTC/USDT") return "BTC/USDT"; + throw new OlaXbtNexusError("UNSUPPORTED_SYMBOL", "Only BTC/USDT is supported in the minimum vertical slice."); +} + +export async function buildStrategyEvidence({ + symbol, + fetchImpl = fetch, + apiKey = null, + now = new Date() +} = {}) { + const normalizedSymbol = normalizeStrategySymbol(symbol); + const key = apiKey || resolveOlaXbtApiKey(); + + const settled = await Promise.allSettled(TOOL_SPECS.map(([kind, tool]) => callOlaXbtTool( + tool, + tool === "get_strategy_signal" ? { symbol: normalizedSymbol } : {}, + { fetchImpl, apiKey: key } + ).then((value) => ({ kind, ...value })))); + + const results = {}; + const sourceStatus = {}; + for (let i = 0; i < TOOL_SPECS.length; i += 1) { + const [kind, tool] = TOOL_SPECS[i]; + const item = settled[i]; + if (item.status === "fulfilled") { + results[kind] = item.value.payload; + sourceStatus[kind] = { ok: true, tool, http_status: item.value.status }; + } else { + const error = item.reason; + sourceStatus[kind] = { + ok: false, + tool, + code: error?.code || "OLAXBT_UPSTREAM_UNKNOWN_ERROR", + http_status: error?.status ?? null + }; + } + } + + const failures = settled.filter((item) => item.status === "rejected").map((item) => item.reason); + if (failures.length === TOOL_SPECS.length) { + const authFailure = failures.find((error) => error?.code === "OLAXBT_UPSTREAM_AUTH_FAILED"); + if (authFailure) throw authFailure; + } + + const signal = extractSignal(results.signal); + const metrics = extractMetrics(results.metrics); + const trades = extractTrades(results.trades); + const equity = extractEquity(results.equity); + const assessment = buildAssessment({ signal, metrics, trades, equity, sourceStatus }); + + return { + schema: "bhrigu_olaxbt_strategy_evidence_v0_1", + symbol: normalizedSymbol, + observed_at: now.toISOString(), + signal, + strategy_evidence: metrics, + recent_behavior: trades, + equity_context: equity, + assessment: assessment.assessment, + assessment_scope: assessment.scope, + supports: assessment.supports, + contradictions: assessment.contradictions, + limitations: assessment.limitations, + source_status: sourceStatus, + authority: { + strategy_and_signal: "OlaXBT Nexus MCP", + evidence_assessment: "BHRIGU derived read-only heuristic", + new_trading_signal_created: false, + trade_execution: false, + wallet_authority: false + } + }; +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/window-sep17.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/window-sep17.mjs new file mode 100644 index 0000000..4f385ef --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/window-sep17.mjs @@ -0,0 +1,24 @@ +export const SEP_17_2026 = Object.freeze({ + id: "SEP_17_2026", + boundary_utc: "2026-09-17T00:00:00Z", + role: "precommitted_observation_boundary", + baseline: Object.freeze({ + captured_at_utc: "2026-09-10T04:49:49.136Z", + btcusdt_last_price: 78348.09, + btcusdt_24h_change_pct: -0.983, + btcusdt_24h_high: 79760, + btcusdt_24h_low: 77770, + bitcoin_tip_height: 966302 + }), + provenance: Object.freeze({ + source_runtime_commit: "05a455ba1407f7b07de226f6c78eefda15b24880", + market_crosscheck_last_price_usdt: 78348.10, + market_crosscheck_abs_diff_usdt: 0.01, + note: "Captured after SEP_10 boundary and committed before SEP_17 boundary." + }), + invariants: Object.freeze({ + retroactive_rewrite: "forbidden", + price_target: false, + trading_signal: false + }) +}); diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/window.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/window.mjs new file mode 100644 index 0000000..da05e97 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/window.mjs @@ -0,0 +1,18 @@ +export const WINDOW = Object.freeze({ + id: "SEP_10_2026", + boundary_utc: "2026-09-10T00:00:00Z", + role: "precommitted_observation_boundary", + baseline: { + captured_at_utc: "2026-09-08T11:25:23Z", + btcusdt_last_price: 78474, + btcusdt_24h_change_pct: -1.226, + btcusdt_24h_high: 79643.5, + btcusdt_24h_low: 78179.98, + bitcoin_tip_height: 966060 + }, + invariants: { + retroactive_rewrite: "forbidden", + price_target: false, + trading_signal: false + } +}); diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/windows.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/windows.mjs new file mode 100644 index 0000000..1b95216 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/lib/windows.mjs @@ -0,0 +1,56 @@ +import { WINDOW as SEP_10_2026 } from "./window.mjs"; +import { SEP_17_2026 } from "./window-sep17.mjs"; +import { EVIDENCE_LEDGER } from "./evidence.mjs"; +import { WINDOW_INTEGRITY, EVIDENCE_INTEGRITY } from "./integrity.mjs"; + +export const WINDOWS = Object.freeze([SEP_10_2026, SEP_17_2026]); + +export function phaseForWindow(window, now = new Date()) { + return now < new Date(window.boundary_utc) ? "PRE_BOUNDARY" : "POST_BOUNDARY"; +} + +export function evidenceForWindow(windowId) { + return EVIDENCE_LEDGER.filter((item) => item.window_id === windowId); +} + +export function listWindows(now = new Date()) { + return WINDOWS.map((window) => ({ + id: window.id, + boundary_utc: window.boundary_utc, + baseline_captured_at_utc: window.baseline.captured_at_utc, + phase: phaseForWindow(window, now), + durable_evidence_count: evidenceForWindow(window.id).length, + precommit_sha256: WINDOW_INTEGRITY[window.id]?.sha256 ?? null, + retroactive_rewrite: window.invariants.retroactive_rewrite, + trading_signal: window.invariants.trading_signal + })); +} + +export function getWindow(windowId, now = new Date()) { + const window = WINDOWS.find((item) => item.id === windowId); + if (!window) return null; + return { + window, + phase: phaseForWindow(window, now), + integrity: { + precommit: WINDOW_INTEGRITY[windowId] ?? null, + evidence: EVIDENCE_INTEGRITY[windowId] ?? null + }, + evidence: evidenceForWindow(windowId) + }; +} + +export function temporalSummary(now = new Date()) { + const windows = listWindows(now); + const next = windows.find((item) => item.phase === "PRE_BOUNDARY") || null; + return { + schema: "bhrigu_temporal_evidence_index_v0_1", + law: "FIELD → WINDOW → REALITY → MEMORY → NEXT WINDOW", + append_only: true, + hash_bound_artifacts: true, + durable_evidence_count: EVIDENCE_LEDGER.length, + window_count: windows.length, + next_window_id: next?.id ?? null, + next_boundary_utc: next?.boundary_utc ?? null + }; +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/package-lock.json b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/package-lock.json new file mode 100644 index 0000000..cf32a80 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/package-lock.json @@ -0,0 +1,15 @@ +{ + "name": "bhrigu-olaxbt-strategy-evidence-agent", + "version": "0.3.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bhrigu-olaxbt-strategy-evidence-agent", + "version": "0.3.0", + "engines": { + "node": ">=22" + } + } + } +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/package.json b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/package.json new file mode 100644 index 0000000..1889657 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/package.json @@ -0,0 +1,14 @@ +{ + "name": "bhrigu-olaxbt-strategy-evidence-agent", + "version": "0.3.0", + "type": "module", + "description": "Read-only OlaXBT strategy-evidence agent with inherited Bitcoin temporal evidence for X-Agent.", + "scripts": { + "start": "node server.mjs", + "test": "node tests/acceptance.mjs && node tests/temporal.mjs && node tests/mcp.mjs && node tests/integrity.mjs && node tests/strategy-evidence.mjs && node tests/olaxbt-mcp.mjs", + "check": "npm test" + }, + "engines": { + "node": ">=22" + } +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/server.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/server.mjs new file mode 100644 index 0000000..3c5ed5b --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/server.mjs @@ -0,0 +1,94 @@ +import http from "node:http"; +import { buildState } from "./lib/state.mjs"; +import { healthPayload, verificationPayload } from "./lib/runtime.mjs"; +import { getWindow, listWindows, temporalSummary } from "./lib/windows.mjs"; +import { handleMcpRpc } from "./lib/mcp.mjs"; +import { openapiPayload } from "./lib/openapi.mjs"; +import { buildStrategyEvidence } from "./lib/strategy-evidence.mjs"; + +const port = Number(process.env.PORT || 3000); +const json = (res, status, body) => { + res.writeHead(status, { "content-type": "application/json", "access-control-allow-origin": "*" }); + res.end(body === null ? "" : JSON.stringify(body)); +}; +const readJson = (req) => new Promise((resolve, reject) => { + let raw = ""; + req.on("data", (chunk) => { + raw += chunk; + if (raw.length > 65536) reject(new Error("BODY_TOO_LARGE")); + }); + req.on("end", () => { + try { resolve(raw ? JSON.parse(raw) : null); } catch (error) { reject(error); } + }); + req.on("error", reject); +}); + +http.createServer(async (req, res) => { + const url = new URL(req.url, `http://${req.headers.host}`); + + if (url.pathname === "/mcp") { + if (req.method !== "POST") return json(res, 405, { error: "METHOD_NOT_ALLOWED", allowed: ["POST"] }); + try { + const result = await handleMcpRpc(await readJson(req), { + transportMeta: { + requireHeaders: true, + protocolVersion: req.headers["mcp-protocol-version"] ?? null, + method: req.headers["mcp-method"] ?? null, + name: req.headers["mcp-name"] ?? null + } + }); + if (result.status === 202) return json(res, 202, null); + return json(res, result.status, result.body); + } catch { + return json(res, 400, { jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } }); + } + } + + if (url.pathname === "/v1/strategy-evidence") { + if (req.method !== "POST") return json(res, 405, { error: "METHOD_NOT_ALLOWED", allowed: ["POST"] }); + try { + const body = await readJson(req); + if (!body || typeof body !== "object" || !body.symbol) { + return json(res, 400, { error: "INVALID_INPUT", required: { symbol: "BTC/USDT" } }); + } + return json(res, 200, await buildStrategyEvidence({ symbol: body.symbol })); + } catch (error) { + const status = error?.code === "UNSUPPORTED_SYMBOL" ? 400 + : error?.code === "OLAXBT_NEXUS_API_KEY_MISSING" ? 503 + : 502; + return json(res, status, { + error: error?.code || "OLAXBT_STRATEGY_EVIDENCE_UNAVAILABLE", + detail: String(error?.message || error), + trading_authority: false, + trade_execution: false + }); + } + } + + if (req.method !== "GET") return json(res, 405, { error: "METHOD_NOT_ALLOWED" }); + if (url.pathname === "/health") return json(res, 200, healthPayload()); + if (url.pathname === "/.well-known/xagent-verification.json") return json(res, 200, verificationPayload()); + if (url.pathname === "/openapi.json") return json(res, 200, openapiPayload()); + if (url.pathname === "/v1/windows") return json(res, 200, { ...temporalSummary(), windows: listWindows() }); + if (url.pathname.startsWith("/v1/windows/")) { + const id = decodeURIComponent(url.pathname.slice("/v1/windows/".length)); + const record = getWindow(id); + return record ? json(res, 200, record) : json(res, 404, { error: "WINDOW_NOT_FOUND" }); + } + if (url.pathname === "/") return json(res, 200, { + name: "BHRIGU Strategy Evidence Agent", + endpoint: "/v1/strategy-evidence", + strategy_evidence: "/v1/strategy-evidence", + temporal_state: "/v1/state", + windows: "/v1/windows", + mcp: "/mcp", + openapi: "/openapi.json", + boundary: "RESEARCH_STATE_NOT_TRADE" + }); + if (url.pathname !== "/v1/state") return json(res, 404, { error: "NOT_FOUND" }); + if ((url.searchParams.get("symbol") || "BTCUSDT").toUpperCase() !== "BTCUSDT") { + return json(res, 400, { error: "UNSUPPORTED_SYMBOL", supported: ["BTCUSDT"] }); + } + try { return json(res, 200, await buildState()); } + catch (error) { return json(res, 502, { error: "PUBLIC_MARKET_SOURCE_UNAVAILABLE", detail: String(error.message || error), trading_authority: false }); } +}).listen(port, () => console.log(`BHRIGU Strategy Evidence Agent listening on ${port}`)); diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/acceptance.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/acceptance.mjs new file mode 100644 index 0000000..7846afe --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/acceptance.mjs @@ -0,0 +1,75 @@ +import assert from "node:assert/strict"; +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { buildState } from "../lib/state.mjs"; +import { healthPayload, verificationPayload, SLUG } from "../lib/runtime.mjs"; + +process.env.BHRIGU_COMMIT = "a".repeat(40); + +const fakeFetch = async (url) => { + if (String(url).includes("data-api.binance.vision")) { + return new Response(JSON.stringify({ + lastPrice: "79000.00", + priceChangePercent: "1.25", + highPrice: "80000.00", + lowPrice: "77000.00", + volume: "12345.67", + closeTime: Date.parse("2026-09-08T12:00:00Z") + }), { status: 200, headers: { "content-type": "application/json" } }); + } + if (String(url).includes("mempool.space")) return new Response("966100", { status: 200 }); + throw new Error("UNEXPECTED_URL"); +}; + +const health = healthPayload(); +assert.equal(health.status, "ok"); +assert.match(health.commit, /^[a-f0-9]{40}$/); +assert.deepEqual(verificationPayload(), { schemaVersion: 1, slug: SLUG, commit: "a".repeat(40) }); + +const pre = await buildState({ fetchImpl: fakeFetch, now: new Date("2026-09-08T12:00:30Z") }); +assert.equal(pre.market.symbol, "BTCUSDT"); +assert.equal(pre.market.last_price_usdt, 79000); +assert.equal(pre.market.freshness, "FRESH"); +assert.equal(pre.protocol_time.halving_epoch, 4); +assert.equal(pre.protocol_time.live_tip_height, 966100); +assert.equal(pre.window.phase, "PRE_BOUNDARY"); +assert.equal(pre.window.comparison_status, "NOT_FINAL_BEFORE_BOUNDARY"); +assert.equal(pre.memory.append_only, true); +assert.equal(pre.memory.retroactive_rewrite, "forbidden"); +assert.deepEqual(pre.authority, { + trading: false, + wallet: false, + payment: false, + withdrawal: false, + transfer: false, + private_account_data: false, + credentials_read: false +}); + +const post = await buildState({ fetchImpl: fakeFetch, now: new Date("2026-09-10T01:00:00Z") }); +assert.equal(post.window.phase, "POST_BOUNDARY"); +assert.equal(post.window.comparison_status, "REALITY_COMPARISON_OPEN"); +assert.equal(Number.isFinite(post.window.current_vs_baseline_pct), true); + +const here = path.dirname(fileURLToPath(import.meta.url)); +const root = path.resolve(here, ".."); +const liveSource = fs.readFileSync(path.join(root, "lib/live.mjs"), "utf8"); +const urls = [...liveSource.matchAll(/https:\/\/[^"\s]+/g)].map((m) => m[0]); +assert.deepEqual(urls.sort(), [ + "https://data-api.binance.vision/api/v3/ticker/24hr?symbol=BTCUSDT", + "https://mempool.space/api/blocks/tip/height" +].sort()); +const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8")); +assert.equal(pkg.dependencies, undefined); + +await assert.rejects( + () => buildState({ fetchImpl: async () => { throw new Error("OFFLINE"); } }), + /OFFLINE/ +); + +console.log(JSON.stringify({ + schema: "bhrigu_bitcoin_research_state_acceptance_v0_1", + status: "PASS", + checks: 18 +}, null, 2)); diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/integrity.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/integrity.mjs new file mode 100644 index 0000000..9a2c79e --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/integrity.mjs @@ -0,0 +1,39 @@ +import assert from "node:assert/strict"; +import crypto from "node:crypto"; +import fs from "node:fs"; +import { SEP_10_POSTBOUNDARY_EVIDENCE } from "../lib/evidence.mjs"; +import { SEP_17_2026 } from "../lib/window-sep17.mjs"; +import { WINDOW_INTEGRITY, EVIDENCE_INTEGRITY } from "../lib/integrity.mjs"; + +const sha256 = (path) => crypto.createHash("sha256").update(fs.readFileSync(new URL(path, import.meta.url))).digest("hex"); + +assert.equal(sha256("../lib/window.mjs"), WINDOW_INTEGRITY.SEP_10_2026.sha256, "SEP_10_2026 precommit changed"); +assert.equal(sha256("../evidence/SEP_17_2026_PRECOMMIT.json"), WINDOW_INTEGRITY.SEP_17_2026.sha256, "SEP_17_2026 precommit proof changed"); +assert.equal(sha256("../evidence/SEP_10_2026_POSTBOUNDARY.json"), EVIDENCE_INTEGRITY.SEP_10_2026.sha256, "SEP_10_2026 evidence changed"); + +const sep10Json = JSON.parse(fs.readFileSync(new URL("../evidence/SEP_10_2026_POSTBOUNDARY.json", import.meta.url), "utf8")); +assert.equal(sep10Json.window_id, SEP_10_POSTBOUNDARY_EVIDENCE.window_id); +assert.equal(sep10Json.observed_btcusdt, SEP_10_POSTBOUNDARY_EVIDENCE.observation.btcusdt_last_price); +assert.equal(sep10Json.runtime_commit, SEP_10_POSTBOUNDARY_EVIDENCE.provenance.runtime_commit); + +const sep17Json = JSON.parse(fs.readFileSync(new URL("../evidence/SEP_17_2026_PRECOMMIT.json", import.meta.url), "utf8")); +assert.equal(sep17Json.window_id, SEP_17_2026.id); +assert.equal(sep17Json.boundary_utc, SEP_17_2026.boundary_utc); +assert.equal(sep17Json.btcusdt_last_price, SEP_17_2026.baseline.btcusdt_last_price); + +const stateSource = fs.readFileSync(new URL("../lib/state.mjs", import.meta.url), "utf8"); +const mcpSource = fs.readFileSync(new URL("../lib/mcp.mjs", import.meta.url), "utf8"); +const forbidden = [/apiKey/i, /secretKey/i, /withdraw/i, /placeOrder/i, /privateKey/i]; +for (const pattern of forbidden) assert.equal(pattern.test(mcpSource), false, `MCP source contains forbidden authority token ${pattern}`); +assert.match(stateSource, /trading: false/); +assert.match(stateSource, /wallet: false/); +assert.match(stateSource, /payment: false/); + +console.log(JSON.stringify({ + schema: "bhrigu_integrity_tests_v0_2", + status: "PASS", + sep10_window_sha256: WINDOW_INTEGRITY.SEP_10_2026.sha256, + sep10_evidence_sha256: EVIDENCE_INTEGRITY.SEP_10_2026.sha256, + sep17_precommit_sha256: WINDOW_INTEGRITY.SEP_17_2026.sha256, + checks: 15 +})); diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/mcp.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/mcp.mjs new file mode 100644 index 0000000..842358e --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/mcp.mjs @@ -0,0 +1,143 @@ +import assert from "node:assert/strict"; +import { + handleMcpRpc, + MCP_TOOLS, + MCP_MODERN_PROTOCOL_VERSION, + MCP_SUPPORTED_PROTOCOL_VERSIONS +} from "../lib/mcp.mjs"; + +let checks = 0; +const eq = (actual, expected, message) => { assert.equal(actual, expected, message); checks += 1; }; +const deep = (actual, expected, message) => { assert.deepEqual(actual, expected, message); checks += 1; }; + +const fakeFetch = async (url) => { + if (String(url).includes("data-api.binance.vision")) { + return new Response(JSON.stringify({ + lastPrice: "79000.00", priceChangePercent: "1.25", highPrice: "80000.00", + lowPrice: "77000.00", volume: "12345.67", closeTime: Date.parse("2026-09-16T12:00:00Z") + }), { status: 200 }); + } + if (String(url).includes("mempool.space")) return new Response("967000", { status: 200 }); + throw new Error("UNEXPECTED_URL"); +}; +const now = new Date("2026-09-16T12:00:30Z"); +const modernMeta = { + "io.modelcontextprotocol/protocolVersion": MCP_MODERN_PROTOCOL_VERSION, + "io.modelcontextprotocol/clientCapabilities": {}, + "io.modelcontextprotocol/clientInfo": { name: "bhrigu-test", version: "1.0.0" } +}; +const modernTransport = (method, name = null) => ({ requireHeaders: true, protocolVersion: MCP_MODERN_PROTOCOL_VERSION, method, name }); + +const init = await handleMcpRpc({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2025-11-25" } }, { fetchImpl: fakeFetch, now }); +eq(init.status, 200); +eq(init.body.result.protocolVersion, "2025-11-25"); +eq(init.body.result.serverInfo.version, "0.3.0"); +eq(init.body.result.resultType, undefined); + +const legacyList = await handleMcpRpc({ jsonrpc: "2.0", id: 2, method: "tools/list" }, { fetchImpl: fakeFetch, now }); +eq(legacyList.status, 200); +eq(legacyList.body.result.tools.length, 5); +eq(legacyList.body.result.ttlMs, undefined); + +const discover = await handleMcpRpc({ jsonrpc: "2.0", id: 3, method: "server/discover", params: { _meta: modernMeta } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("server/discover") }); +eq(discover.status, 200); +eq(discover.body.result.resultType, "complete"); +eq(discover.body.result.ttlMs, 300000); +eq(discover.body.result.cacheScope, "public"); +deep(discover.body.result.supportedVersions, MCP_SUPPORTED_PROTOCOL_VERSIONS); +eq(discover.body.result.serverInfo, undefined); +eq(discover.body.result._meta["io.modelcontextprotocol/serverInfo"].name, "bhrigu-olaxbt-strategy-evidence-agent"); + +const list = await handleMcpRpc({ jsonrpc: "2.0", id: 4, method: "tools/list", params: { _meta: modernMeta } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/list") }); +eq(list.status, 200); +eq(list.body.result.resultType, "complete"); +eq(list.body.result.tools.length, 5); +deep(list.body.result.tools.map((t) => t.name), MCP_TOOLS.map((t) => t.name)); +eq(list.body.result.tools.every((t) => t.annotations.readOnlyHint === true), true); +eq(list.body.result.ttlMs, 300000); +eq(list.body.result.cacheScope, "public"); + +const noClientInfo = await handleMcpRpc({ jsonrpc: "2.0", id: 41, method: "tools/list", params: { _meta: { + "io.modelcontextprotocol/protocolVersion": MCP_MODERN_PROTOCOL_VERSION, + "io.modelcontextprotocol/clientCapabilities": {} +} } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/list") }); +eq(noClientInfo.status, 200); + +const malformedClientInfo = await handleMcpRpc({ jsonrpc: "2.0", id: 42, method: "tools/list", params: { _meta: { + ...modernMeta, "io.modelcontextprotocol/clientInfo": { name: "missing-version" } +} } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/list") }); +eq(malformedClientInfo.status, 400); +eq(malformedClientInfo.body.error.code, -32602); + +const windowResult = await handleMcpRpc({ jsonrpc: "2.0", id: 5, method: "tools/call", params: { + name: "bhrigu_get_temporal_window", arguments: { window_id: "SEP_10_2026" }, _meta: modernMeta +} }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/call", "bhrigu_get_temporal_window") }); +eq(windowResult.status, 200); +eq(windowResult.body.result.resultType, "complete"); +eq(windowResult.body.result.isError, false); +eq(windowResult.body.result.structuredContent.window.id, "SEP_10_2026"); +eq(windowResult.body.result.structuredContent.evidence.length, 1); + +const compare = await handleMcpRpc({ jsonrpc: "2.0", id: 6, method: "tools/call", params: { + name: "bhrigu_compare_window_to_reality", arguments: { window_id: "SEP_17_2026" }, _meta: modernMeta +} }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/call", "bhrigu_compare_window_to_reality") }); +eq(compare.body.result.isError, false); +eq(compare.body.result.resultType, "complete"); +eq(compare.body.result.structuredContent.current_btcusdt, 79000); +eq(compare.body.result.structuredContent.baseline_btcusdt, 78348.09); +eq(compare.body.result.structuredContent.trading_authority, false); + +const headerMismatch = await handleMcpRpc({ jsonrpc: "2.0", id: 7, method: "tools/list", params: { _meta: modernMeta } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/call") }); +eq(headerMismatch.status, 400); +eq(headerMismatch.body.error.code, -32020); + +const missingCaps = await handleMcpRpc({ jsonrpc: "2.0", id: 8, method: "server/discover", params: { _meta: { + "io.modelcontextprotocol/protocolVersion": MCP_MODERN_PROTOCOL_VERSION +} } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("server/discover") }); +eq(missingCaps.status, 400); +eq(missingCaps.body.error.code, -32602); + +const missingVersion = await handleMcpRpc({ jsonrpc: "2.0", id: 81, method: "server/discover", params: { _meta: { + "io.modelcontextprotocol/clientCapabilities": {} +} } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("server/discover") }); +eq(missingVersion.status, 400); +eq(missingVersion.body.error.code, -32602); + +const unsupported = await handleMcpRpc({ jsonrpc: "2.0", id: 9, method: "server/discover", params: { _meta: { + ...modernMeta, "io.modelcontextprotocol/protocolVersion": "2099-01-01" +} } }, { fetchImpl: fakeFetch, now, transportMeta: { ...modernTransport("server/discover"), protocolVersion: "2099-01-01" } }); +eq(unsupported.status, 400); +eq(unsupported.body.error.code, -32022); +eq(unsupported.body.error.data.requested, "2099-01-01"); +deep(unsupported.body.error.data.supported, MCP_SUPPORTED_PROTOCOL_VERSIONS); + +const unsupportedOrdinary = await handleMcpRpc({ jsonrpc: "2.0", id: 10, method: "tools/list", params: { _meta: { + ...modernMeta, "io.modelcontextprotocol/protocolVersion": "2099-01-01" +} } }, { fetchImpl: fakeFetch, now, transportMeta: { ...modernTransport("tools/list"), protocolVersion: "2099-01-01" } }); +eq(unsupportedOrdinary.status, 400); +eq(unsupportedOrdinary.body.error.code, -32022); + +const unsupportedHeaderOnly = await handleMcpRpc({ jsonrpc: "2.0", id: 101, method: "tools/list" }, { fetchImpl: fakeFetch, now, + transportMeta: { requireHeaders: true, protocolVersion: "2099-01-01", method: "tools/list", name: null } }); +eq(unsupportedHeaderOnly.status, 400); +eq(unsupportedHeaderOnly.body.error.code, -32022); + +const modernPing = await handleMcpRpc({ jsonrpc: "2.0", id: 102, method: "ping", params: { _meta: modernMeta } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("ping") }); +eq(modernPing.status, 404); +eq(modernPing.body.error.code, -32601); + +const modernNotification = await handleMcpRpc({ jsonrpc: "2.0", method: "notifications/example", params: { _meta: modernMeta } }, { fetchImpl: fakeFetch, now, transportMeta: { requireHeaders: true } }); +eq(modernNotification.status, 202); +eq(modernNotification.body, null); + +const bad = await handleMcpRpc({ jsonrpc: "2.0", id: 11, method: "tools/call", params: { + name: "bhrigu_get_temporal_window", arguments: { window_id: "NOPE" }, _meta: modernMeta +} }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/call", "bhrigu_get_temporal_window") }); +eq(bad.body.result.isError, true); +eq(bad.body.result.structuredContent.error.code, "WINDOW_NOT_FOUND"); + +const invalid = await handleMcpRpc({ hello: "world" }); +eq(invalid.status, 400); +eq(invalid.body.error.code, -32600); + +console.log(JSON.stringify({ schema: "bhrigu_mcp_tests_v0_4", status: "PASS", checks })); diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/olaxbt-mcp.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/olaxbt-mcp.mjs new file mode 100644 index 0000000..fa955ec --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/olaxbt-mcp.mjs @@ -0,0 +1,33 @@ +import assert from "node:assert/strict"; +import { handleMcpRpc, MCP_TOOLS } from "../lib/mcp.mjs"; + +const payloads = { + get_strategy_signal: { ok: true, name: "get_strategy_signal", strategy_id: "str_test", content: { symbol: "BTC/USDT", trade_intent: "SELL", confidence: 0.16865581885564507, reasoning_log: "observed upstream shape" } }, + get_strategy_metrics: { ok: true, name: "get_strategy_metrics", strategy_id: "str_test", content: { sharpe_ratio: 1.7668, profit_factor: 1.6494, max_drawdown: "0.31%", total_return_pct: 0.3837, win_rate_pct: 52.94, trade_count: 17 } }, + get_strategy_trades: { result: { trades: [{ pnl: 1 }, { pnl: -1 }, { pnl: 2 }] } }, + get_strategy_equity: { data: { equity_curve: [100, 101, 102] } } +}; +const fakeFetch = async (_url, options) => { + const tool = JSON.parse(options.body).name; + return new Response(JSON.stringify(payloads[tool]), { status: 200, headers: { "content-type": "application/json" } }); +}; + +process.env.OLAXBT_NEXUS_API_KEY = "test-key"; + +const names = MCP_TOOLS.map((tool) => tool.name); +assert.equal(names.filter((name) => name === "bhrigu_get_olaxbt_strategy_evidence").length, 1); +const call = await handleMcpRpc({ jsonrpc: "2.0", id: 1, method: "tools/call", params: { name: "bhrigu_get_olaxbt_strategy_evidence", arguments: { symbol: "BTC/USDT" } } }, { fetchImpl: fakeFetch, now: new Date("2026-09-12T17:39:17Z") }); +assert.equal(call.status, 200); +assert.equal(call.body.result.isError, false); +const out = call.body.result.structuredContent; +assert.equal(out.signal.direction, "SELL"); +assert.equal(out.strategy_evidence.win_rate, 52.94); +assert.deepEqual(Object.values(out.source_status).map((item) => item.ok), [true, true, true, true]); +assert.equal(out.authority.trade_execution, false); +assert.equal(out.authority.new_trading_signal_created, false); +assert.equal(out.authority.wallet_authority, false); +const bad = await handleMcpRpc({ jsonrpc: "2.0", id: 2, method: "tools/call", params: { name: "bhrigu_get_olaxbt_strategy_evidence", arguments: { symbol: "ETH/USDT" } } }, { fetchImpl: fakeFetch }); +assert.equal(bad.body.result.isError, true); +assert.equal(bad.body.result.structuredContent.error.code, "UNSUPPORTED_SYMBOL"); +delete process.env.OLAXBT_NEXUS_API_KEY; +console.log(JSON.stringify({ schema: "bhrigu_olaxbt_mcp_tests_v0_1", status: "PASS", checks: 11 })); diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/strategy-evidence.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/strategy-evidence.mjs new file mode 100644 index 0000000..d56efef --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/strategy-evidence.mjs @@ -0,0 +1,114 @@ +import assert from "node:assert/strict"; +import { buildStrategyEvidence, normalizeStrategySymbol } from "../lib/strategy-evidence.mjs"; +import { OlaXbtNexusError } from "../lib/olaxbt-nexus.mjs"; + +function toolFromRequest(options) { + return JSON.parse(options.body).name; +} + +const successPayloads = { + get_strategy_signal: { + ok: true, + name: "get_strategy_signal", + strategy_id: "str_test", + content: { + symbol: "BTC/USDT", + trade_intent: "SELL", + reasoning_log: "technical factors aligned bearish", + timestamp: 1789205458, + confidence: 0.16865581885564507 + } + }, + get_strategy_metrics: { + ok: true, + name: "get_strategy_metrics", + strategy_id: "str_test", + content: { + sharpe_ratio: 1.7668, + trading_period_days: 179, + estimated_aum_usdt: 100000, + profit_factor: 1.6494, + max_drawdown: "0.31%", + total_return_pct: 0.3837, + win_rate_pct: 52.94, + trade_count: 17, + status: "NOT_QUALIFIED" + } + }, + get_strategy_trades: { result: { trades: [ + { pnl: 4, exit_reason: "take_profit" }, + { pnl: -1, exit_reason: "stop" }, + { pnl: 2, exit_reason: "rule" }, + { pnl: 1, exit_reason: "rule" } + ] } }, + get_strategy_equity: { data: { equity_curve: [100, 103, 109, 114] } } +}; + +const successFetch = async (_url, options) => new Response(JSON.stringify(successPayloads[toolFromRequest(options)]), { + status: 200, + headers: { "content-type": "application/json" } +}); + +assert.equal(normalizeStrategySymbol("BTCUSDT"), "BTC/USDT"); +assert.throws(() => normalizeStrategySymbol("ETH/USDT"), /Only BTC\/USDT/); + +const evidence = await buildStrategyEvidence({ + symbol: "BTC/USDT", + apiKey: "test-key", + fetchImpl: successFetch, + now: new Date("2026-09-12T07:30:00Z") +}); +assert.equal(evidence.signal.direction, "SELL"); +assert.equal(evidence.signal.confidence, 0.16865581885564507); +assert.equal(evidence.strategy_evidence.sharpe_ratio, 1.7668); +assert.equal(evidence.strategy_evidence.win_rate, 52.94); +assert.equal(evidence.recent_behavior.sample_size, 4); +assert.ok(Math.abs(evidence.equity_context.change_pct - 14) < 1e-9); +assert.equal(evidence.assessment, "SUPPORTED"); +assert.equal(evidence.authority.new_trading_signal_created, false); +assert.equal(evidence.authority.trade_execution, false); +assert.deepEqual(Object.values(evidence.source_status).map((item) => item.ok), [true, true, true, true]); + +const noDirectionPayloads = structuredClone(successPayloads); +delete noDirectionPayloads.get_strategy_signal.content.trade_intent; +noDirectionPayloads.get_strategy_signal.content.reasoning_log = "strongly bearish reasoning text must not become a direction"; +const noDirectionFetch = async (_url, options) => new Response(JSON.stringify(noDirectionPayloads[toolFromRequest(options)]), { status: 200 }); +const noDirection = await buildStrategyEvidence({ symbol: "BTC/USDT", apiKey: "test-key", fetchImpl: noDirectionFetch }); +assert.equal(noDirection.signal.direction, null); + +await assert.rejects( + () => buildStrategyEvidence({ symbol: "BTC/USDT", fetchImpl: successFetch, apiKey: "" }), + (error) => error instanceof OlaXbtNexusError && error.code === "OLAXBT_NEXUS_API_KEY_MISSING" +); + +const authFetch = async () => new Response(JSON.stringify({ error: "unauthorized" }), { + status: 401, + headers: { "content-type": "application/json" } +}); +await assert.rejects( + () => buildStrategyEvidence({ symbol: "BTC/USDT", apiKey: "bad-key", fetchImpl: authFetch }), + (error) => error instanceof OlaXbtNexusError && error.code === "OLAXBT_UPSTREAM_AUTH_FAILED" +); + +const partialFetch = async (_url, options) => { + const tool = toolFromRequest(options); + if (tool === "get_strategy_trades") return new Response(JSON.stringify({ error: "temporary" }), { status: 503 }); + return new Response(JSON.stringify(successPayloads[tool]), { status: 200 }); +}; +const partial = await buildStrategyEvidence({ symbol: "BTC/USDT", apiKey: "test-key", fetchImpl: partialFetch }); +assert.equal(partial.source_status.trades.ok, false); +assert.ok(partial.limitations.some((item) => item.includes("trades source unavailable"))); + +const malformedFetch = async (_url, options) => { + const tool = toolFromRequest(options); + if (tool === "get_strategy_equity") return new Response("bad gateway", { status: 200 }); + return new Response(JSON.stringify(successPayloads[tool]), { status: 200 }); +}; +const malformed = await buildStrategyEvidence({ symbol: "BTC/USDT", apiKey: "test-key", fetchImpl: malformedFetch }); +assert.equal(malformed.source_status.equity.code, "OLAXBT_UPSTREAM_MALFORMED_RESPONSE"); + +console.log(JSON.stringify({ + schema: "bhrigu_olaxbt_strategy_evidence_tests_v0_1", + status: "PASS", + checks: 21 +}, null, 2)); diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/temporal.mjs b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/temporal.mjs new file mode 100644 index 0000000..d36b031 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/tests/temporal.mjs @@ -0,0 +1,35 @@ +import assert from "node:assert/strict"; +import { getWindow, listWindows, temporalSummary } from "../lib/windows.mjs"; +import { SEP_10_POSTBOUNDARY_EVIDENCE } from "../lib/evidence.mjs"; + +const before = new Date("2026-09-16T23:59:59Z"); +const after = new Date("2026-09-17T00:00:01Z"); + +const windowsBefore = listWindows(before); +assert.equal(windowsBefore.length, 2); +assert.equal(windowsBefore[0].id, "SEP_10_2026"); +assert.equal(windowsBefore[0].phase, "POST_BOUNDARY"); +assert.equal(windowsBefore[0].durable_evidence_count, 1); +assert.equal(windowsBefore[1].id, "SEP_17_2026"); +assert.equal(windowsBefore[1].phase, "PRE_BOUNDARY"); + +const sep10 = getWindow("SEP_10_2026", before); +assert.equal(sep10.window.baseline.btcusdt_last_price, 78474); +assert.equal(sep10.evidence.length, 1); +assert.equal(sep10.evidence[0].id, SEP_10_POSTBOUNDARY_EVIDENCE.id); +assert.equal(sep10.evidence[0].observation.btcusdt_last_price, 78348.09); +assert.equal(sep10.evidence[0].invariants.append_only, true); + +const sep17 = getWindow("SEP_17_2026", before); +assert.equal(sep17.window.baseline.captured_at_utc, "2026-09-10T04:49:49.136Z"); +assert.equal(sep17.window.baseline.btcusdt_last_price, 78348.09); +assert.equal(sep17.evidence.length, 0); +assert.equal(getWindow("SEP_17_2026", after).phase, "POST_BOUNDARY"); + +const summary = temporalSummary(before); +assert.equal(summary.window_count, 2); +assert.equal(summary.durable_evidence_count, 1); +assert.equal(summary.next_window_id, "SEP_17_2026"); +assert.equal(summary.append_only, true); + +console.log(JSON.stringify({ schema: "bhrigu_temporal_tests_v0_1", status: "PASS", checks: 17 })); diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/vercel.json b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/vercel.json new file mode 100644 index 0000000..a81744b --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/source/vercel.json @@ -0,0 +1,40 @@ +{ + "rewrites": [ + { + "source": "/", + "destination": "/api/about" + }, + { + "source": "/health", + "destination": "/api/health" + }, + { + "source": "/.well-known/xagent-verification.json", + "destination": "/api/verification" + }, + { + "source": "/openapi.json", + "destination": "/api/openapi" + }, + { + "source": "/mcp", + "destination": "/api/mcp" + }, + { + "source": "/v1/state", + "destination": "/api/state" + }, + { + "source": "/v1/strategy-evidence", + "destination": "/api/strategy-evidence" + }, + { + "source": "/v1/windows", + "destination": "/api/windows" + }, + { + "source": "/v1/windows/:id", + "destination": "/api/window?id=:id" + } + ] +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/submission.json b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/submission.json new file mode 100644 index 0000000..5482515 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/submission.json @@ -0,0 +1,10 @@ +{ + "schemaVersion": 1, + "name": "BHRIGU OlaXBT Strategy Evidence Agent", + "slug": "bhrigu-olaxbt-strategy-evidence-agent", + "sourceRepository": "https://github.com/AiBhrigu/bhrigu-bitcoin-research-state-api", + "reviewCommit": "d29423daf121a4318dec063d0694b5fec8eb2ed3", + "apiBaseUrl": "https://bhrigu-bitcoin-research-state-rn4vpiwc8-aibhrigus-projects.vercel.app", + "healthCheckUrl": "https://bhrigu-bitcoin-research-state-rn4vpiwc8-aibhrigus-projects.vercel.app/health", + "deploymentProofUrl": "https://bhrigu-bitcoin-research-state-rn4vpiwc8-aibhrigus-projects.vercel.app/.well-known/xagent-verification.json" +} diff --git a/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/verification/README.md b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/verification/README.md new file mode 100644 index 0000000..8d00003 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-olaxbt-strategy-evidence-agent/verification/README.md @@ -0,0 +1,83 @@ +# Verification evidence — BHRIGU OlaXBT Strategy Evidence Agent + +## Prerequisites + +- Review commit: `d29423daf121a4318dec063d0694b5fec8eb2ed3` +- API base URL: `https://bhrigu-bitcoin-research-state-rn4vpiwc8-aibhrigus-projects.vercel.app` +- Authentication: no reviewer credential. The OlaXBT Nexus credential remains server-side. + +## 1. Health check + +```bash +curl --fail --silent --show-error https://bhrigu-bitcoin-research-state-rn4vpiwc8-aibhrigus-projects.vercel.app/health +``` + +Expected: + +```json +{"status":"ok","commit":"d29423daf121a4318dec063d0694b5fec8eb2ed3"} +``` + +## 2. Deployment proof + +```bash +curl --fail --silent --show-error https://bhrigu-bitcoin-research-state-rn4vpiwc8-aibhrigus-projects.vercel.app/.well-known/xagent-verification.json +``` + +Expected: + +```json +{"schemaVersion":1,"slug":"bhrigu-olaxbt-strategy-evidence-agent","commit":"d29423daf121a4318dec063d0694b5fec8eb2ed3"} +``` + +## 3. Real REST strategy-evidence call + +```bash +curl --fail --silent --show-error \ + --request POST https://bhrigu-bitcoin-research-state-rn4vpiwc8-aibhrigus-projects.vercel.app/v1/strategy-evidence \ + --header 'content-type: application/json' \ + --data '{"symbol":"BTC/USDT"}' +``` + +Real proof captured on 2026-09-12 returned HTTP 200. Review-critical fields were: + +```json +{ + "signal": {"direction":"SELL","confidence":0.16865581885564507}, + "strategy_evidence": {"win_rate":52.94,"sharpe_ratio":1.7668,"profit_factor":1.6494}, + "source_status": { + "signal": {"ok":true,"tool":"get_strategy_signal","http_status":200}, + "metrics": {"ok":true,"tool":"get_strategy_metrics","http_status":200}, + "trades": {"ok":true,"tool":"get_strategy_trades","http_status":200}, + "equity": {"ok":true,"tool":"get_strategy_equity","http_status":200} + }, + "authority": {"new_trading_signal_created":false,"trade_execution":false,"wallet_authority":false} +} +``` + +The direction is normalized only from the observed OlaXBT `trade_intent` field. The source win rate is normalized only from the observed OlaXBT `win_rate_pct` field. Reasoning text is not used to infer BUY/SELL/HOLD, and recent-trade positive share is not substituted for source win rate. + +## 4. Real MCP strategy-evidence call + +```bash +curl --fail --silent --show-error \ + --request POST https://bhrigu-bitcoin-research-state-rn4vpiwc8-aibhrigus-projects.vercel.app/mcp \ + --header 'content-type: application/json' \ + --data '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"bhrigu_get_olaxbt_strategy_evidence","arguments":{"symbol":"BTC/USDT"}}}' +``` + +Real proof captured on 2026-09-12 returned HTTP 200 with `result.isError=false`. `result.structuredContent` contained the same bounded Strategy Evidence object, including all four successful source statuses and the same false execution/second-signal/wallet authority flags. + +## 5. Safe failure + +Unsupported symbols are rejected explicitly and do not produce substitute evidence. Missing upstream data is surfaced under `source_status` / `limitations`; BHRIGU never fabricates direction, source win rate, or evidence. + +## Review boundary + +- OLAXBT = strategy + signal authority. +- BHRIGU = evidence interpretation layer. +- Read-only. +- No trading execution. +- No wallet authority. +- No second BHRIGU signal. +- No secret is returned.