Hosted Synthetic Tape Redesign
This plan redesigns the hosted synthetic market so the tape feels more like a real market session while still surfacing all six smart-money categories during a demo window. It keeps the public labels stable, adds richer hidden scenario families underneath them, and introduces an internal control surface for shaping the hosted simulator.
Simplified Summary
Today the simulator does the important part mechanically: it hits the categories. The problem is that the surrounding market behavior does not always look convincing. Options bursts, equity prints, quote quality, and event timing can feel loosely stitched together instead of driven by one believable market state.
The redesign fixes that by introducing a shared regime engine. Both synthetic options and synthetic equities will respond to the same session conditions, such as event ramps, dealer-gamma chop, retail chase, quiet range trading, and neutral arbitrage-heavy periods. The result should be a tape that still teaches the product, but no longer feels obviously scripted.
institutional_directional, retail_whale, event_driven, vol_seller, arbitrage, and hedge_reactive.
Scope
- Hosted synthetic market regime engine
- Options and equities synthetic generator redesign
- Hidden subtype scenario families
- Soft coverage logic
- Internal control API and UI
- Documentation and tests for the new behavior
- Changing public smart-money profile IDs
- General settings page work
- User profile or token-spend features
- Live market feed changes
- Public-facing simulator controls
Services Affected
| Area | Primary files | Role in the redesign |
|---|---|---|
| Shared types | packages/types/src/synthetic-market.ts, packages/types/src/events.ts |
Add the shared regime model and internal synthetic-control schemas. |
| Hosted API | services/api/src/index.ts |
Add internal control endpoints and expose hosted simulator status. |
| Options ingest | services/ingest-options/src/index.ts, services/ingest-options/src/adapters/synthetic.ts |
Adopt the new regime engine, scenario families, and soft coverage logic. |
| Equities ingest | services/ingest-equities/src/index.ts, services/ingest-equities/src/adapters/synthetic.ts |
Synchronize synthetic quotes and prints with the same latent market regime. |
| Web and Electron shell | apps/web/app/terminal.tsx, apps/web/app/api/admin/synthetic/* |
Add the internal gear-triggered control drawer and server-side proxy routes. |
| Tests | services/ingest-options/tests/synthetic.test.ts, web tests, API tests |
Protect classification alignment, determinism, coverage behavior, and control-plane behavior. |
Full Plan Contents
Product Decisions Locked
- Keep the current six public smart-money categories.
- Add richer hidden sub-scenarios beneath them.
- Use soft coverage guarantees, not hard forced sequencing.
- Prioritize cross-asset coupling first.
- Controls affect the hosted synthetic backend.
- Controls are internal-only.
- Do not build a general settings page, user-info work, or token-spend work in this effort.
- Use a bottom-right gear that opens a synthetic-control drawer.
Architecture
1. Replace the simple burst pulse with a shared regime engine
Expand packages/types/src/synthetic-market.ts into the shared deterministic market-state engine used by both ingest services.
Shared functions:
getSyntheticSessionState(ts, control)getSyntheticUnderlyingState(symbol, ts, control, sessionState)getSyntheticScenarioWeights(symbol, ts, control, sessionState)getSyntheticCoverageBoost(profileId, coverageState, control)
sessionState includes:
session_phase:open | midday | power_hour | after_eventregime:trend_up | trend_down | mean_revert | retail_chase | event_ramp | dealer_gamma | arb_calmvolatility_levelliquidity_levelquote_cleanlinessfocus_symbolsevent_symbolsseed_bucket
2. Add hosted synthetic control state
Add internal control schemas in packages/types:
SyntheticControlPresetIdSyntheticControlStateSyntheticProfileWeightMapSyntheticCoverageConfigSyntheticDerivedStatus
type SyntheticControlState = {
preset_id: "balanced_demo" | "event_day" | "dealer_day" | "retail_chase" | "quiet_range";
coverage_assist: boolean;
coverage_window_minutes: 10 | 20 | 30;
shared_seed: number;
profile_weights: {
institutional_directional: 0.6 | 1.0 | 1.6;
retail_whale: 0.6 | 1.0 | 1.6;
event_driven: 0.6 | 1.0 | 1.6;
vol_seller: 0.6 | 1.0 | 1.6;
arbitrage: 0.6 | 1.0 | 1.6;
hedge_reactive: 0.6 | 1.0 | 1.6;
};
updated_at: number;
updated_by: string;
};
Defaults:
preset_id: balanced_democoverage_assist: truecoverage_window_minutes: 20- All profile weights
1.0
3. Persist and distribute control state through NATS
- Use JetStream KV bucket
synthetic_control - Use key
global services/apireads and writes the KV entryservices/ingest-optionsloads on boot and watches for updatesservices/ingest-equitiesdoes the same
4. Rebuild options scenarios as hidden subtype families
Keep public profiles the same, but generate them through richer hidden subtype families.
institutional_directional:call_sweep,put_sweep,ask_lift_accumulation,far_dated_convictionretail_whale:0dte_call_chase,short_dated_put_panic,attention_contract_spikeevent_driven:earnings_vol_probe,pre_event_directional_ramp,post_gap_followthroughvol_seller:covered_call_overwrite,cash_secured_put_write,short_straddle_harvestarbitrage:parity_vertical,conversion_reversal,box_spreadhedge_reactive:gamma_pinch_call_hedge,reactive_put_wall,dealer_unwindneutral_noise:single_print_mid,two_sided_scalp,stale_quote_noise
5. Make equities and options react to the same latent state
Equities changes:
- Remove the fixed dark-sequence loop
- Make lit versus dark balance regime-dependent
- Make spread, quote cleanliness, off-exchange frequency, and clustering regime-dependent
- Use shared focus symbols
- During
event_rampandretail_chase, create modest trend and wider quotes - During
dealer_gamma, create choppier reversals and denser quote changes - During
arb_calm, create quieter underlying motion and more neutral execution context
Options changes:
- Replace hardcoded coverage forcing with weighted family selection plus coverage debt
- Make venue count, placement, stale or missing quote probability, and structure prevalence regime-sensitive
- Derive
execution_iv_shock,underlying_move_bps, andnbbo_spread_zfrom shared state - Generate event-driven timestamps and symbols from shared regime state
6. Add soft coverage accounting
- Track rolling coverage debt per public profile inside each ingest service
- Maintain a rolling counter across the selected
coverage_window_minutes - Only public profiles count toward coverage
- Missing profiles get a bounded weight boost
- Noise and low-key scenarios continue to appear between labeled bursts
7. Add internal hosted control endpoints
Add routes in services/api/src/index.ts:
GET /admin/synthetic/statusGET /admin/synthetic/controlPUT /admin/synthetic/control
{
enabled: boolean;
backend_mode: "synthetic" | "mixed" | "live";
adapters: {
options: string;
equities: string;
};
control: SyntheticControlState | null;
derived: {
session_phase: string;
regime: string;
focus_symbols: string[];
profile_hit_counts: Record<SmartMoneyProfileId, number>;
coverage_window_minutes: number;
} | null;
disabled_reason?: string;
}
Behavior:
- Return
404when admin mode is disabled - Return
409when hosted adapters are not synthetic - Validate full payloads on
PUT - Keep all existing public smart-money, history, replay, and websocket endpoints unchanged
8. Keep secrets out of the browser with Next.js proxy routes
Add server-side proxy routes:
apps/web/app/api/admin/synthetic/status/route.tsapps/web/app/api/admin/synthetic/control/route.ts
Proxy behavior:
- Read server-only
SYNTHETIC_ADMIN_TOKEN - Forward to backend admin endpoints at
NEXT_PUBLIC_API_URL - Return
404when the internal UI flag is off - Never send the token to the browser
9. Add an internal control surface
UI surface:
- A small floating gear button in the bottom-right corner
- Opens a right-edge non-modal drawer
- Internal-only visibility
Drawer sections:
PresetCoverageProfile BiasLive Status
Controls:
- Preset dropdown:
Balanced Demo,Event Day,Dealer Day,Retail Chase,Quiet Range - Coverage assist toggle
- Coverage window selector:
10m,20m,30m - Six profile weight controls with
Low,Normal,High
Public and Internal Interfaces
Public contracts unchanged
SmartMoneyProfileIdSmartMoneyEvent/flow/smart-money/history/smart-money/replay/smart-money/ws/smart-money
New internal contracts
SyntheticControlStateSyntheticControlPresetIdSyntheticDerivedStatus
New internal endpoints
GET /admin/synthetic/statusGET /admin/synthetic/controlPUT /admin/synthetic/control
New environment variables
Backend:
SYNTHETIC_CONTROL_ENABLED=0|1SYNTHETIC_ADMIN_TOKEN=...
Web:
NEXT_PUBLIC_SYNTHETIC_ADMIN=0|1SYNTHETIC_ADMIN_TOKEN=...for the Next server proxy only
Implementation Sequence
-
Phase 1. Shared types and regime engine
Touch
packages/types/src/synthetic-market.tsand related exports and tests. Deliver control schemas, preset definitions, deterministic session and regime functions, and coverage boost helpers. -
Phase 2. Hosted control plane
Touch
services/api/src/index.tsand NATS or KV helpers as needed. Deliver admin endpoints, KV persistence, status payloads, and disabled or error behavior. -
Phase 3. Ingest service coupling
Touch both ingest services and their synthetic adapters. Deliver boot-time control loading, KV watch updates, shared regime-driven generation, and removal of visibly scripted fixed sequences.
-
Phase 4. Internal control UI
Touch
apps/web/app/terminal.tsxand the internal admin proxy routes. Deliver the floating gear, non-modal drawer, polling, optimistic updates, and disabled state. -
Phase 5. Regression and realism tests
Deliver determinism tests, control API tests, scenario coverage tests, UI visibility tests, and classifier-alignment tests for hidden subtype families.
Test Cases and Scenarios
Shared engine
- Same
timestamp + control snapshot + seedyields the same regime and focus symbols in both ingest services. - Presets materially change regime weights without breaking determinism.
balanced_demoyields mixed regimes over a session.quiet_rangeyields lower volatility, tighter spreads, and fewer labeled events thanretail_chase.
Cross-asset coupling
event_rampproduces event-aligned option scenarios and synchronized underlying drift and spread behavior.dealer_gammaproduces short-dated ATM-heavy options plus choppier underlying reversals.arb_calmincreases neutral multi-leg structures without strong directional underlying moves.retail_chaseincreases short-dated OTM call behavior, IV shock, and louder underlying momentum.
Coverage behavior
- With default controls, every public smart-money profile appears at least once in a 20-minute synthetic session sample.
- With
coverage_assist=false, there is no forced coverage logic. - Raising one profile to
Highincreases its frequency without starving all other categories. - The quiet preset still emits noise and occasional signals rather than a dead tape.
Classification alignment
- Each hidden subtype family still classifies primarily into its intended public profile.
- Neutral noise remains below the smart-money emission threshold.
- Nearby wrong profiles stay below threshold in subtype template tests.
Admin API and UI
- Disabled admin mode returns
404. - Non-synthetic hosted mode returns
409with a useful reason. - Valid
PUTpersists to KV and becomes visible to both ingest services. - The floating gear is hidden when
NEXT_PUBLIC_SYNTHETIC_ADMINis off. - The browser client never receives the backend admin token.
Assumptions and Defaults
- Hosted synthetic control applies only when both options and equities ingest adapters are synthetic.
- No general settings page, user-info work, or token-spend work is in scope here.
- Hidden subtype labels remain internal and test-only and never attach to emitted prints.
- The first pass uses polling for admin status rather than a new admin websocket.
- The default operator experience is
Balanced Demowith soft coverage on and a 20-minute window. - The repo currently lacks local
PRODUCT.md,DESIGN.md, and the local impeccable loader path, so UI implementation should use the existing terminal shell as the visual source of truth unless those design-context files are added later.