# Handoff — Tourism Vertical Slice ## Project - Path: `/Users/kunthawat/Gitea/set50-alternative-data-platform` - Branch: `main` - Verified code commit: `ba9114d` — `[verified] bind snapshots to manifests and raw hashes` - Current milestone: M2.5 integrity hardening complete; validated backtest blocked - Mode: research + paper only - Frontend: Vue 3 + Vite - Backend: Flask `0.5.0` - Current runtime source: BOT Tourism Indicators (`TOURISM_SOURCE=bot`) ## Completed - Tourism snapshot schema with source, publication, retrieval, vintage and raw hash fields. - Deterministic Tourism Pulse score: standardized surprise × exposure × confidence. - BOT ASP.NET form adapter with monthly history parsing and trailing 12-point YoY baseline. - Atomic raw HTML and normalized snapshot persistence under ignored `backend/data/`. - Read-only `/api/v1/data-health` endpoint. - Safe `/api/v1/replay/tourism?vintage_id=...` endpoint with identity and path validation. - Immutable `VintageStore` manifest with first-seen, last-seen, seen-count and revision metadata. - One-shot collector: `backend/scripts/collect_tourism_vintage.py`. - Point-in-time vintage query: `GET /api/v1/vintages?as_of=`. - Deterministic event-study engine with window, benchmark and cost calculations. - Backtest readiness gate: `GET /api/v1/backtest/tourism?min_events=12`. - Yahoo-backed daily price snapshot with SET symbol mapping and adjusted-close bars. - Price health: `GET /api/v1/prices/health`. - Frozen research runner: `POST /api/v1/research/tourism/run` and `GET /api/v1/research/tourism/latest`. - Headless runner: `backend/scripts/run_tourism_research.py`. - Durable atomic paper ledger under `backend/data/paper/ledger.json` when configured. - Raw and normalized snapshot integrity binding with explicit `sha256-json-canonical-v1` metadata. - Ranked target weights and LONG/SHORT/NEUTRAL classification. - English dashboard with live/provisional source label, sign-aware surprise copy and lineage fields. - HttpOnly paper session and internal paper ledger. - No external webhook or MT5 integration. Independent M1 review passed with no concrete security or logic blockers. Non-blocking backlog: add schema-drift, duplicate/reordered-row, and malformed-vintage regression fixtures. ## Current live vintage ```text source_id: bot.ec_ei_028_s2 published_at: 2026-07-31T14:30:00+07:00 as_of: 2026-06-30 status: provisional available_periods: 138 history_points: 12 vintage_id: bot.ec_ei_028_s2-2026-07-31-665981f88b4a raw_payload_hash: 665981f88b4a30c5bd30026cf1e96279c244ad83725558f4136d952b29756a31 theme_surprise: -0.35114754 ``` ## Verified commands and live checks ```text PYTHONPATH=backend .venv/bin/python -W error -m unittest discover -s backend/tests -v Ran 18 tests ... OK npm run build Vite build completed successfully. GET /api/v1/health HTTP 200; {"mode":"research","status":"ok","version":"0.5.0"} GET /api/v1/data-health HTTP 200; source_mode=bot, status=provisional, replayable=true GET /api/v1/replay/tourism?vintage_id=bot.ec_ei_028_s2-2026-07-31-665981f88b4a HTTP 200; replay theme surprise matched live summary exactly. GET /api/v1/vintages?as_of=2026-07-01T00:00:00Z HTTP 200; count=0 GET /api/v1/vintages?as_of=2026-08-01T00:00:00Z HTTP 200; count=1; manifest seen_count=4 GET /api/v1/backtest/tourism?min_events=12 HTTP 409; status=blocked, available_events=1, required_events=12, price_series_required=true GET /api/v1/prices/health HTTP 200; available=true, quality=revised_vendor_history, point_in_time=false, symbols=9 POST /api/v1/research/tourism/run HTTP 200; report status=blocked, reason=insufficient_vintages, immutable run_id persisted GET /api/v1/research/tourism/latest HTTP 200; same run_id returned on replay ``` Paper writes use a server-side token exchange and HttpOnly `paper_session` cookie; the token is not embedded in the frontend bundle. ## Known limitations - BOT data is provisional and may be revised. The vintage/hash contract preserves the fetched version, but this is not a final-data guarantee. - Only foreign-arrival YoY is live in this slice; occupancy and airport passenger metrics are not yet connected. - Snapshot storage is local filesystem and single-process; shared persistence is required before multi-worker deployment. - No investment edge, transaction-cost result, or backtest conclusion has been established. - One independent source release is not enough for a valid event study; current historical rows are not treated as point-in-time vintages. - The event-study engine is deterministic and tested. Yahoo price history is connected for plumbing, but it is revised vendor history, not point-in-time data. - Research runner is operational and replayable, but correctly emits a blocked report until both evidence gates pass. - Snapshot loads fail closed when raw files, normalized payloads or manifest metadata do not match their recorded hashes. - The hash boundary protects local artifacts against corruption/partial writes; hostile host-level rewrite of code, manifests and runtime environment is outside this local threat model. - Revisions are deduplicated by canonical `(source_id, published_at)`; the latest observed revision is selected once. - Event-study default execution is the next trading session, including weekend/holiday event dates. - Browser screenshot verification remains blocked by the Chrome remote-debugging permission prompt; served HTML/source, live API, fresh Vite build and replay integrity were verified instead. ## Exact next action Collect independent BOT releases over time and replace/supplement revised vendor history with a point-in-time daily price source. The operator can run the frozen research check now; only raise the gate when both requirements pass. Add a trusted deployment signing key before treating the app as a multi-user or hostile-host service.