{"openapi":"3.1.0","info":{"title":"FIBER API","description":"\n# FIBER — AI Data Center Optical Intelligence Platform\n\nUnified multi-vendor optical monitoring, GPU workload impact analysis, and predictive maintenance intelligence.\n\n## Authentication\n\nAll endpoints (except `/api/health`, `/api/otel/metrics`, `/api/validation/results`, `/api/roi`) require Bearer token authentication:\n\n```\nAuthorization: Bearer <your-api-key>\n```\n\n## Roles\n\n| Role | Permissions |\n|------|------------|\n| **admin** | Full access — read, write, delete, export, diagnosis, audit, key management |\n| **operator** | Read, write, export, diagnosis |\n| **viewer** | Read-only access |\n\n## Rate Limits\n\nCurrently no rate limiting applied. Enterprise customers may request rate limiting configuration.\n\n## Speed Types\n\n| Speed | Form Factor | Optics Type | Use Case |\n|-------|------------|-------------|----------|\n| 400G | QSFP-DD | direct_detect | Standard leaf-spine links |\n| 800G | OSFP | direct_detect | High-bandwidth spine uplinks |\n| 400ZR | QSFP-DD | coherent | DCI (Data Center Interconnect) links |\n\n## Risk Score\n\nPorts are scored 0-100 based on three tiers:\n- **Tier 1 (Rules)**: Threshold violations (+25 per violation)\n- **Tier 2 (Statistical)**: IQR anomaly detection (+10 base)\n- **Tier 3 (ML)**: RandomForest prediction (+30 max)\n- **Severity**: Normal (<30), Warning (30-69), Critical (>=70)\n","version":"2.5.1"},"paths":{"/api/demo/trigger":{"post":{"tags":["Demo"],"summary":"Trigger Demo Scenario","description":"Inject a pre-defined failure scenario into the simulator for demonstration purposes. Available scenarios: 'degradation' (4 ports on leaf-015 with degrading optics), 'thermal' (48 ports on leaf-020 with thermal stress), 'failure' (1 port on spine-003 at end-of-life), 'cpo_bank_failure' (all 6 ports of shared laser bank 0 on spine-cpo-050 — fires the correlated bank-failure rule), 'cpo_fau_drift' (FAU alignment drift on spine-cpo-051), 'cpo_die_thermal' (ASIC die thermal runaway on spine-cpo-052), 'reset' (clear all overrides). Admin only.","operationId":"trigger_demo_api_demo_trigger_post","parameters":[{"name":"scenario","in":"query","required":false,"schema":{"type":"string","description":"degradation | thermal | failure | cpo_bank_failure | cpo_fau_drift | cpo_die_thermal | reset","default":"degradation","title":"Scenario"},"description":"degradation | thermal | failure | cpo_bank_failure | cpo_fau_drift | cpo_die_thermal | reset"}],"responses":{"200":{"description":"Confirmation with scenario name and number of overrides applied","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/validation/results":{"get":{"tags":["Validation"],"summary":"ML Validation Results","description":"Returns Risk Engine backtesting results including precision, recall, F1 score, and average lead time across multiple lookahead windows (1h, 6h, 12h, 24h). No authentication required. Results are generated by running validation/run_validation.sh.\n\nSince 2026-09-05 the payload also carries the ML-honesty evidence blocks `tfm_rebench`, `tfm_embedding`, `ranking`, `anomaly_zero_shot` (+ `ml_honesty` index). Each is a tolerant mirror of evidence/ml_honesty_20260905/*; `{available: false, reason}` when the file is absent.","operationId":"validation_results_api_validation_results_get","responses":{"200":{"description":"Backtesting metrics (precision, recall, F1, lead time) per lookahead window + 2026-09-05 ML-honesty evidence blocks","content":{"application/json":{"schema":{}}}}}}},"/api/health":{"get":{"tags":["System"],"summary":"Health Check","description":"Returns system health status including ClickHouse and PostgreSQL connectivity. No authentication required. Returns 'ok' when all databases are reachable, 'degraded' if any connection fails.","operationId":"health_api_health_get","responses":{"200":{"description":"Health status with per-database connectivity flags and UTC timestamp","content":{"application/json":{"schema":{}}}}}}},"/api/info":{"get":{"tags":["System"],"summary":"API Information","description":"Returns API version, supported features, scale benchmarks, and ML validation metrics. No authentication required. Version also exposed via 'X-Fiber-Version' response header and /api/version plain-text endpoint.","operationId":"api_info_api_info_get","responses":{"200":{"description":"API metadata including version, feature list, scale benchmarks, and ML validation metrics","content":{"application/json":{"schema":{}}}}}}},"/api/version":{"get":{"tags":["System"],"summary":"Plain-text version","description":"Returns the current API version as plain text (no JSON, no 'version' key) to bypass content-filter false positives.","operationId":"api_version_api_version_get","responses":{"200":{"description":"Version string (e.g., '2.0.0')","content":{"application/json":{"schema":{}}}}}}},"/api/notifications/test-email":{"post":{"tags":["Notifications"],"summary":"Test Email","description":"Send a test email to verify SMTP configuration.","operationId":"test_email_api_notifications_test_email_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/overview":{"get":{"tags":["Monitoring"],"summary":"Cluster Overview","description":"Returns aggregated cluster health: port counts by severity, speed distribution, average risk score, and active UFM predictions. This is the primary dashboard endpoint providing a single-glance view of the entire optical infrastructure.","operationId":"overview_api_overview_get","responses":{"200":{"description":"Cluster summary with port counts, severity percentages, average risk score, active UFM prediction count, and speed distribution breakdown","content":{"application/json":{"schema":{}}}}}}},"/api/ports":{"get":{"tags":["Ports"],"summary":"List Ports","description":"List all monitored optical ports with real-time telemetry, risk scores, and severity classification. Supports filtering by vendor, severity, and speed. Coherent ports (400ZR) include additional metrics: SNR, OSNR, CD, PMD, pre-FEC BER. When the ClickHouse schema carries the OpenConfig transceiver v1.0.0 per-channel extension, each port also includes rx_los_count, tx_los_count, rx_lol_count, tx_lol_count, tx_fault_count (cumulative, summed over lanes) and media_snr / host_snr (worst lane, dB; null = not reported) plus `link_integrity_reported` — false when the device does not expose these leaves (all of those fields are then null rather than 0); `link_integrity_columns` lists which of those the deployment provides.","operationId":"list_ports_api_ports_get","parameters":[{"name":"vendor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by vendor","title":"Vendor"},"description":"Filter by vendor"},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by severity: normal, warning, critical","title":"Severity"},"description":"Filter by severity: normal, warning, critical"},{"name":"speed","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by speed: 400G, 800G, 400ZR","title":"Speed"},"description":"Filter by speed: 400G, 800G, 400ZR"},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Substring match on switch name, port name, or serial","title":"Search"},"description":"Substring match on switch name, port name, or serial"},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","description":"Sort key","default":"risk_score","title":"Sort By"},"description":"Sort key"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":5000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Paginated list of ports with telemetry readings, risk scores, and severity labels","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ports/{switch_name}/{port_name}/history":{"get":{"tags":["Ports"],"summary":"Port Telemetry History","description":"Retrieve time-series telemetry history for a specific port. Returns rx_power, tx_power, temperature, bias_current, voltage, and FEC counters over the requested time window. Coherent ports include SNR, OSNR, CD, PMD, and pre-FEC BER history. With `include_link_integrity=true` (opt-in, when the schema has the columns) each sample also carries the raw cumulative OpenConfig v1.0.0 link-integrity counters (rx/tx LOS, rx/tx LOL, tx fault) and media/host SNR for charting; for current values and 24h/1h deltas use the cheaper `/link-integrity` sibling endpoint instead. Use URL-encoded port names (e.g., Ethernet1/1 becomes Ethernet1-1).","operationId":"port_history_api_ports__switch_name___port_name__history_get","parameters":[{"name":"switch_name","in":"path","required":true,"schema":{"type":"string","title":"Switch Name"}},{"name":"port_name","in":"path","required":true,"schema":{"type":"string","title":"Port Name"}},{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":168,"minimum":1,"description":"Time range in hours — accepts 1 / 6 / 24 / 48; max 168 (7 days).","default":1,"title":"Hours"},"description":"Time range in hours — accepts 1 / 6 / 24 / 48; max 168 (7 days)."},{"name":"include_link_integrity","in":"query","required":false,"schema":{"type":"boolean","description":"Opt-in: append the raw cumulative OpenConfig v1.0.0 link-integrity counters and media/host SNR to every sample (7 extra fields × samples — ~+30% payload). Deltas are served by /link-integrity.","default":false,"title":"Include Link Integrity"},"description":"Opt-in: append the raw cumulative OpenConfig v1.0.0 link-integrity counters and media/host SNR to every sample (7 extra fields × samples — ~+30% payload). Deltas are served by /link-integrity."}],"responses":{"200":{"description":"Time-series array of telemetry readings for the specified port and time range","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ports/{switch_name}/{port_name}/link-integrity":{"get":{"tags":["Ports"],"summary":"Port Link Integrity (OpenConfig transceiver v1.0.0)","description":"Current OpenConfig transceiver v1.0.0 per-channel link-integrity state for one port: cumulative rx/tx LOS, rx/tx LOL and tx-fault counters (summed over lanes), worst-lane media/host SNR, and the counter increase over the last 24 h and 1 h (reset-safe sum of positive steps, same definition as the risk engine's LOS precursor rule). Computed by one bounded ClickHouse aggregate (24 h, single port) — poll this instead of downloading the 24 h history. `available` is false when the deployment's schema lacks the columns; `reported` is false when the device does not expose these leaves (every field is then null — a device that reports nothing is not a device with zero events).","operationId":"port_link_integrity_api_ports__switch_name___port_name__link_integrity_get","parameters":[{"name":"switch_name","in":"path","required":true,"schema":{"type":"string","title":"Switch Name"}},{"name":"port_name","in":"path","required":true,"schema":{"type":"string","title":"Port Name"}}],"responses":{"200":{"description":"Current counters/SNR with 24h and 1h increases, or nulls when unavailable/unreported","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/alerts":{"get":{"tags":["Alerts"],"summary":"List Alerts","description":"List risk alerts generated by the 3-tier scoring engine. Supports filtering by severity (warning/critical) and alert type (threshold/anomaly/ml). Alerts include the triggering port, risk score, and human-readable message.","operationId":"list_alerts_api_alerts_get","parameters":[{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"}},{"name":"alert_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alert Type"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Paginated list of risk alerts sorted by creation time (newest first)","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/alerts/top":{"get":{"tags":["Alerts"],"summary":"Top Risky Ports","description":"Returns the highest-risk ports ranked by risk score (descending). Each entry includes the port's current telemetry snapshot, tier 1/2 flag counts, and alert details. Useful for NOC dashboards and triage workflows.","operationId":"top_risky_ports_api_alerts_top_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Ranked list of ports by risk score with current telemetry and alert details","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/topology":{"get":{"tags":["Topology"],"summary":"Network Topology Map","description":"Returns the full spine-leaf network topology including switches (with role, rack, pod), inter-switch links, GPU node mappings, and currently running jobs. Powers the topology visualization in the dashboard.","operationId":"topology_api_topology_get","responses":{"200":{"description":"Complete topology graph with switches, links, GPU nodes, and active jobs","content":{"application/json":{"schema":{}}}}}}},"/api/topology/simulate-failure":{"post":{"tags":["Topology"],"summary":"Simulate Link Failure","description":"Simulate a link failure on a specific switch port. Returns affected GPU nodes, running jobs, estimated cost per hour, and available alternative paths through the spine-leaf topology. Request body requires 'switch_name' and 'port' fields.","operationId":"topology_simulate_failure_api_topology_simulate_failure_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Impact analysis with affected GPUs, jobs, hourly cost estimate, and alternative paths","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/predictions":{"get":{"tags":["Predictions"],"summary":"UFM Failure Predictions","description":"Returns failure predictions from NVIDIA UFM Cyber-AI. Each prediction includes failure probability (0-1), estimated hours to failure, confidence level, and contributing factors. Predictions are refreshed every 5 minutes via REST polling.","operationId":"predictions_api_predictions_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"List of UFM Cyber-AI failure predictions sorted by prediction time (newest first)","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ml/rul/info":{"get":{"tags":["ML"],"summary":"RUL Model Info","description":"Information about the LSTM-based Remaining Useful Life regression model. Also returns `ranking`: the offline ranking evaluation of the RUL ordering served by /api/ml/rul/top-risky — capture@5/10/20% of true within-horizon failures for H=24 h and 48 h (KDD 2026 'Don't Predict, Prioritize', arXiv:2607.15115), with rule/random baselines, an oracle ceiling and port-bootstrap CIs. `ranking.available=false` when the evidence file is absent.","operationId":"ml_rul_info_api_ml_rul_info_get","responses":{"200":{"description":"RUL model metadata (availability, validation MAE, training sample counts) + ranking evaluation headline","content":{"application/json":{"schema":{}}}}}}},"/api/ml/rul/{switch_name}/{port_name}":{"get":{"tags":["ML"],"summary":"Port RUL Prediction","description":"Return the LSTM-predicted remaining useful life (in hours) for a specific port. Uses the last 24 optical readings (2 min window) as input. Pass ?heatmap=true to also receive the W9 channel × timestep saliency heatmap (24 × 10).","operationId":"ml_rul_predict_api_ml_rul__switch_name___port_name__get","parameters":[{"name":"switch_name","in":"path","required":true,"schema":{"type":"string","title":"Switch Name"}},{"name":"port_name","in":"path","required":true,"schema":{"type":"string","title":"Port Name"}},{"name":"heatmap","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Heatmap"}}],"responses":{"200":{"description":"Predicted RUL hours and input sample count (+ optional heatmap)","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ml/rul/top-risky":{"get":{"tags":["ML"],"summary":"Top Risky Ports by RUL","description":"Return ports with the shortest predicted RUL across the fleet. Useful for maintenance prioritization.","operationId":"ml_rul_top_risky_api_ml_rul_top_risky_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"List of ports sorted by predicted RUL ascending","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ml/anomaly/info":{"get":{"tags":["ML"],"summary":"VAE Model Info","description":"Information about the variational autoencoder used for unsupervised anomaly detection.","operationId":"ml_vae_info_api_ml_anomaly_info_get","responses":{"200":{"description":"VAE model metadata (threshold, precision/recall, training size)","content":{"application/json":{"schema":{}}}}}}},"/api/ml/anomaly/scan":{"get":{"tags":["ML"],"summary":"VAE Anomaly Scan","description":"Scan all ports using the VAE reconstruction error. Returns ports whose reconstruction error exceeds the learned p99 threshold.","operationId":"ml_anomaly_scan_api_ml_anomaly_scan_get","responses":{"200":{"description":"List of anomalous ports with score and severity_ratio (score/threshold)","content":{"application/json":{"schema":{}}}}}}},"/api/ml/anomaly/conformal/{switch_name}/{port_name}":{"get":{"tags":["ML"],"summary":"Conformal anomaly detection (finite-sample FPR guarantee)","description":"Inductive conformal anomaly detection on a single port's latest reading.\n\nProvides a **finite-sample, distribution-free** false-positive guarantee: under exchangeability of calibration + test samples, P(p < alpha | normal) ≤ alpha.\n\nDiffers from VAE threshold gating which is a single learned cut-off — conformal returns a calibrated p-value against an empirical null built from recent normal readings (last 60 minutes, rx > -7 dBm, temp < 55 °C, fec_uncorrectable = 0).\n\nReference: Vovk & Shafer 'Conformal Prediction'; arXiv:2604.20122 (applied to network anomaly detection, 2026).\n\n`shift` = the online exchangeability test (rolling-window mixture power martingale over the conformal p-values): `martingale`, `threshold`, `shift_detected`, `n_pvalues`, `recent_events` …. When it fires the 1 h calibration cache is invalidated and rebuilt on the next call. Measured false-alarm rate at the defaults (window 100, threshold 20): 17-23 % per 2,000 exchangeable p-values — not the 5 % per-window Ville bound (evidence/ml_honesty_20260905/conformal).","operationId":"ml_anomaly_conformal_api_ml_anomaly_conformal__switch_name___port_name__get","parameters":[{"name":"switch_name","in":"path","required":true,"schema":{"type":"string","title":"Switch Name"}},{"name":"port_name","in":"path","required":true,"schema":{"type":"string","title":"Port Name"}},{"name":"alpha","in":"query","required":false,"schema":{"type":"number","maximum":0.5,"minimum":0.0001,"default":0.01,"title":"Alpha"}}],"responses":{"200":{"description":"p-value, alpha, conformal/threshold decisions + online shift-test status","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ml/anomaly/conformal/calibrate":{"post":{"tags":["ML"],"summary":"Force re-calibration of the conformal null distribution","description":"Rebuilds the conformal calibration set (sampling normal optical readings from the last `lookback_minutes`). Calibration is otherwise auto-cached for 1h, or invalidated earlier when the online exchangeability test fires. The response carries the post-rebuild `shift` status (window reset, `last_reset_reason` = recalibrated).","operationId":"ml_anomaly_conformal_calibrate_api_ml_anomaly_conformal_calibrate_post","parameters":[{"name":"lookback_minutes","in":"query","required":false,"schema":{"type":"integer","maximum":1440,"minimum":15,"default":60,"title":"Lookback Minutes"}},{"name":"n","in":"query","required":false,"schema":{"type":"integer","maximum":20000,"minimum":100,"default":2000,"title":"N"}}],"responses":{"200":{"description":"Calibration metadata (n, score quantiles, p_min) + post-rebuild shift status","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ml/anomaly/conformal/shift":{"get":{"tags":["ML"],"summary":"Conformal online shift-test status (exchangeability martingale)","description":"Snapshot of the online exchangeability test that guards the conformal calibration cache — no port is scored. Returns the current martingale value, threshold, `shift_detected`, the number of p-values in the rolling window, the last reset reason and the recent shift events, plus the measured operating characteristics (`notes`): detection delay and the long-run false-alarm rate from evidence/ml_honesty_20260905/conformal. Honesty note: the feed is dormant in production until a continuous p-value stream is wired (see `notes.feed_status`).","operationId":"ml_anomaly_conformal_shift_api_ml_anomaly_conformal_shift_get","responses":{"200":{"description":"conformal_shift_status() + measured notes","content":{"application/json":{"schema":{}}}}}}},"/api/cpo/banks":{"get":{"tags":["CPO"],"summary":"CPO Switch Bank Status","description":"Return per-switch, per-bank status for CPO (Co-Packaged Optics) switches. Aggregates FAU alignment loss, die temperature, rx power droop across all 6 ports in each shared laser bank. Flags banks where correlation threshold is crossed — these require switch-level RMA, not port replacement.","operationId":"cpo_banks_api_cpo_banks_get","responses":{"200":{"description":"List of CPO banks with mean/max metrics and correlation flags","content":{"application/json":{"schema":{}}}}}}},"/api/ml/explain/{switch_name}/{port_name}":{"get":{"tags":["ML"],"summary":"Explain ML predictions (VAE + LSTM RUL)","description":"Return per-feature breakdown of the current anomaly score (VAE reconstruction error per feature) alongside the LSTM RUL gradient × input saliency (which feature drove the prediction). Designed so NOC engineers can answer \"why is this port flagged?\" at a glance.","operationId":"ml_explain_api_ml_explain__switch_name___port_name__get","parameters":[{"name":"switch_name","in":"path","required":true,"schema":{"type":"string","title":"Switch Name"}},{"name":"port_name","in":"path","required":true,"schema":{"type":"string","title":"Port Name"}}],"responses":{"200":{"description":"per-feature contribution + top 5 features","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/digital-twin/scenarios":{"get":{"tags":["Digital Twin"],"summary":"Predefined Scenario Catalog","description":"Return the 10 predefined one-click failure scenarios. Each carries a category (switch_failure / backbone / infrastructure / thermal / cpo / lpo / coherent / maintenance / drill), a severity tier (medium / high / critical), and a human-readable description.","operationId":"digital_twin_scenarios_list_api_digital_twin_scenarios_get","responses":{"200":{"description":"Array of scenario metadata","content":{"application/json":{"schema":{}}}}}}},"/api/digital-twin/scenarios/{scenario_id}/run":{"post":{"tags":["Digital Twin"],"summary":"Run a Predefined Scenario","description":"Resolve the scenario's (switch, port) links against the current PostgreSQL topology, then dispatch them through monte_carlo_scenarios(). Override iterations / failure_rate via the request body.","operationId":"digital_twin_scenarios_run_api_digital_twin_scenarios__scenario_id__run_post","parameters":[{"name":"scenario_id","in":"path","required":true,"schema":{"type":"string","title":"Scenario Id"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"default":{},"title":"Body"}}}},"responses":{"200":{"description":"Monte Carlo result + resolved link count + interpretation metadata","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/digital-twin/monte-carlo":{"post":{"tags":["Digital Twin"],"summary":"Monte Carlo Failure Scenario","description":"Run Monte Carlo what-if analysis on the fabric. Samples link failures probabilistically and aggregates GPU-hours lost, $ cost (checkpoint rollback + recovery overhead), and impact distribution. Supports pinned fixed_links that always fail in every iteration.","operationId":"digital_twin_monte_carlo_api_digital_twin_monte_carlo_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body","default":{}}}}},"responses":{"200":{"description":"Percentile distributions of GPU-hours lost, cost USD, and impact bucket counts","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/digital-twin/deterministic-trace":{"post":{"tags":["Digital Twin"],"summary":"Deterministic BFS reachability trace (Forward Networks-style)","description":"Pure SQL/graph reachability proof — given a list of failed links, walk the topology BFS from spines outward and emit each hop. Output is byte-identical for the same (topology snapshot, failed_links) input — no probability, no LLM.\n\nUse cases:\n  · Audit / compliance — show *why* a leaf became unreachable.\n  · Diff against Monte Carlo — deterministic baseline vs probabilistic spread.\n  · Root-cause closure — capture the exact spine→leaf path that broke.\n\nReference: Forward Networks 'deterministic network query' (2026 Forward AI launch).","operationId":"digital_twin_deterministic_trace_api_digital_twin_deterministic_trace_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body","default":{}}}}},"responses":{"200":{"description":"hop-by-hop BFS trace + reachable/unreachable leaf sets + input hash","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/digital-twin/compare":{"post":{"tags":["Digital Twin"],"summary":"Compare What-if Scenarios","description":"Compare multiple link-failure scenarios side by side. Each scenario defines a list of (switch, port) links assumed to fail simultaneously. Returns impact, GPU-hours, and cost per scenario — useful for deciding which maintenance ordering minimizes blast radius.","operationId":"digital_twin_compare_api_digital_twin_compare_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Per-scenario impact summary suitable for side-by-side bar charts","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/nccl/ingest":{"post":{"tags":["NCCL"],"summary":"Ingest NCCL Inspector Events","description":"Accept NCCL Inspector JSON events (per-rank per-collective bandwidth/duration). Events are persisted to ClickHouse hikari.nccl_events for later correlation with optical telemetry. Expected payload: {\"events\": [{\"ts\", \"comm\", \"rank\", \"node\", \"collective\", \"count\", \"duration_us\", \"bw_GBps\", \"job\"}, ...]}.","operationId":"nccl_ingest_endpoint_api_nccl_ingest_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Count of inserted/skipped events","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/nccl/ingest-prometheus":{"post":{"tags":["NCCL"],"summary":"Ingest NCCL Inspector Prometheus Exposition (2.29.2+, 2.31.2 names)","description":"Accept NCCL Inspector Prometheus-format output (supported since NCCL 2.29.2) as a text/plain body — e.g. `curl -X POST --data-binary @nccl_inspector.prom this-endpoint`. The four official NCCL 2.31.2 metric names are mapped exactly: `nccl_bus_bandwidth_gbs` / `nccl_p2p_bus_bandwidth_gbs` → bandwidth_gbps, `nccl_collective_exec_time_microseconds` / `nccl_p2p_exec_time_microseconds` → duration_ms (µs→ms); event_type collective|p2p comes from the metric name. Labels honoured: `version` (v5.1 aggregated / v5.2 verbose), `message_size` bucket strings (stored verbatim, e.g. \"4-5GB\"), `coll_sn`/`p2p_sn` (per-op identity in verbose mode), `p2p_peer`, `comm_id`, `rank`, `coll`, `hostname`. Other nccl_* names fall back to a tolerant token mapping (bandwidth/duration/count); unknown metrics are ignored. Samples sharing (comm, rank, collective, node, event_type, message_size, sn, peer) merge into one event. `?node=`/`?job=` supply defaults when the labels lack them (typical for the textfile route).","operationId":"nccl_ingest_prometheus_endpoint_api_nccl_ingest_prometheus_post","parameters":[{"name":"node","in":"query","required":false,"schema":{"type":"string","description":"Default hostname when samples carry no node/hostname label","default":"","title":"Node"},"description":"Default hostname when samples carry no node/hostname label"},{"name":"job","in":"query","required":false,"schema":{"type":"string","description":"Default job id when samples carry no job label","default":"","title":"Job"},"description":"Default job id when samples carry no job label"}],"responses":{"200":{"description":"Count of parsed/inserted events + Inspector schema version histogram","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/nccl/ingest-otlp":{"post":{"tags":["NCCL"],"summary":"Ingest NCCL Inspector OTLP/HTTP JSON (NCCL 2.31.2 NCCL_INSPECTOR_OTEL_EXPORT=1)","description":"OTLP/HTTP **JSON** metrics receiver for the NCCL 2.31.2 Inspector OTel export (`NCCL_INSPECTOR_OTEL_EXPORT=1`, HTTP only) — or for an OpenTelemetry Collector `otlphttp` exporter with `encoding: json` in front of it. Body: ExportMetricsServiceRequest `{resourceMetrics[].scopeMetrics[].metrics[]}` with gauge/sum dataPoints and attributes; `Content-Encoding: gzip` is accepted. The same four metrics as /api/nccl/ingest-prometheus produce the same nccl_events rows (resource attribute `host.name` becomes the node when data points carry none). Protobuf bodies (`application/x-protobuf`) are rejected with 415 — set `OTEL_EXPORTER_OTLP_PROTOCOL=http/json` or put a Collector in between. Alias: POST /api/nccl/otlp/v1/metrics (so `OTEL_EXPORTER_OTLP_ENDPOINT=<api>/api/nccl/otlp` works with exporters that append the standard `/v1/metrics` path).","operationId":"nccl_ingest_otlp_endpoint_api_nccl_ingest_otlp_post","parameters":[{"name":"node","in":"query","required":false,"schema":{"type":"string","description":"Default hostname when data points carry no node/host.name attribute","default":"","title":"Node"},"description":"Default hostname when data points carry no node/host.name attribute"},{"name":"job","in":"query","required":false,"schema":{"type":"string","description":"Default job id when data points carry no job attribute","default":"","title":"Job"},"description":"Default job id when data points carry no job attribute"}],"responses":{"200":{"description":"Count of parsed/inserted events + Inspector schema version histogram","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/nccl/summary":{"get":{"tags":["NCCL"],"summary":"NCCL Events Summary (collective + P2P + RAS)","description":"Aggregate NCCL Inspector events over the last N minutes.\n\nReturns:\n  • Window-level percentiles — mean/p50/p05 bandwidth, p95/p99 duration\n  • `by_type` block — collective (NCCL ≤ 2.29) + P2P sendrecv (NCCL 2.30+) with separate low-bandwidth thresholds (50 GB/s vs 5 GB/s)\n  • `ras` block — NCCL RAS subsystem (NCCL 2.24+) totals: critical / warning / max_hang_seconds. RAS events are ingested via POST /api/nccl/ras and automatically reflected here.\n  • `ras.diag` block — NCCL 2.31.2 `ncclras -D` diagnostics (24 h lookback, latest result per check × node): checks / nodes / ok / warning / failed / last_run + `failed_checks[]` with the FAIL detail line.","operationId":"nccl_summary_endpoint_api_nccl_summary_get","parameters":[{"name":"minutes","in":"query","required":false,"schema":{"type":"integer","maximum":180,"minimum":1,"default":15,"title":"Minutes"}}],"responses":{"200":{"description":"Window aggregates with bandwidth/duration percentiles, by_type breakdown, RAS rollup","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/nccl/correlation":{"get":{"tags":["NCCL"],"summary":"NCCL ↔ Optical Correlation","description":"Correlate low-bandwidth NCCL events with optical telemetry anomalies on the GPU-node's upstream port. For each low-bw event, fetches ±30s optical samples and flags whether rx_power/temperature/FEC were anomalous. Produces the 'NCCL drop ↔ optical root cause' evidence that closes the loop between GPU performance and the physical layer — Hikari's flagship IR story.","operationId":"nccl_correlation_endpoint_api_nccl_correlation_get","parameters":[{"name":"minutes","in":"query","required":false,"schema":{"type":"integer","maximum":180,"minimum":1,"default":15,"title":"Minutes"}},{"name":"low_bw_threshold","in":"query","required":false,"schema":{"type":"number","description":"GB/s threshold below which event is considered slow (static mode)","default":50.0,"title":"Low Bw Threshold"},"description":"GB/s threshold below which event is considered slow (static mode)"},{"name":"mode","in":"query","required":false,"schema":{"type":"string","pattern":"^(static|dynamic)$","description":"static = fixed 50/5 GB/s; dynamic = per-(node,event_type) EMA - 2σ (Spectrum-X NetInspector style, W13)","default":"static","title":"Mode"},"description":"static = fixed 50/5 GB/s; dynamic = per-(node,event_type) EMA - 2σ (Spectrum-X NetInspector style, W13)"}],"responses":{"200":{"description":"Correlations with per-event optical window and hit rate","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/nccl/ras":{"post":{"tags":["NCCL"],"summary":"Ingest NCCL RAS (Reliability/Availability/Serviceability) events","description":"Accept NCCL RAS subsystem events (NCCL 2.24+) — rank_hang, op_timeout, init_failure, collective_mismatch, comm_abort, watchdog_timeout. Events are stored alongside Inspector telemetry and become available to /api/nccl/correlation for L1 (optical) ↔ L2 (IB) ↔ application-health (RAS) cross-layer root-cause evidence — FIBER's 3-layer fault chain. Payload: {\"events\":[{\"ts\",\"comm\",\"rank\",\"node\",\"ras_event\",\"ras_severity\",\"hang_duration_sec\"}, ...]}.\n\nNCCL 2.31.2 RAS diagnostics: add an optional `diagnostics` field — either the raw text of `ncclras -D` / `NCCL_RUN_RAS_DIAGNOSTICS=1` output (lines `NCCL DIAG [OK] <check>` / `NCCL DIAG [FAIL] <check>: <detail>`; the NCCL log prefix `host:pid:tid [dev]` is understood and sets the node) or a list of `{check, status: OK|FAIL|WARN|SKIP, detail, node?}`. Each check becomes one nccl_events row with ras_event_type=`diag_<check>` (gpu_inventory, cuda_driver, volatile_ecc, nvlink_state, nccl_env_consistency, ...), ras_severity critical for FAIL / warning for WARN / info for OK, ras_detail = the reason. Top-level `node`, `ts`, `job` are defaults for the diagnostics. `events` may be empty when only diagnostics are posted.","operationId":"nccl_ras_ingest_endpoint_api_nccl_ras_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Insert + breakdown counts (RAS critical / warning, ib errors, diag_checks / diag_failed)","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/counterfactual/port/{switch_name}/{port_name}":{"get":{"tags":["Counterfactual"],"summary":"Port Counterfactual Impact","description":"'If this port had been healthy' — computes GPU-hours and $ that would have been avoided over the past N hours, based on historical critical alert segments × current affected GPUs × (checkpoint rollback + recovery overhead).","operationId":"counterfactual_port_api_counterfactual_port__switch_name___port_name__get","parameters":[{"name":"switch_name","in":"path","required":true,"schema":{"type":"string","title":"Switch Name"}},{"name":"port_name","in":"path","required":true,"schema":{"type":"string","title":"Port Name"}},{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":720,"minimum":1,"default":168,"title":"Hours"}},{"name":"checkpoint_interval_min","in":"query","required":false,"schema":{"type":"number","default":15,"title":"Checkpoint Interval Min"}},{"name":"recovery_overhead_min","in":"query","required":false,"schema":{"type":"number","default":5,"title":"Recovery Overhead Min"}}],"responses":{"200":{"description":"Incident segments with avoided GPU-hours and USD per segment, plus totals","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/counterfactual/cluster":{"get":{"tags":["Counterfactual"],"summary":"Cluster Counterfactual Rollup","description":"Top N ports ranked by avoidable cost. Sums across ports to estimate the total GPU-hours and USD the cluster could have avoided had those ports been healthy.","operationId":"counterfactual_cluster_api_counterfactual_cluster_get","parameters":[{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":720,"minimum":1,"default":168,"title":"Hours"}},{"name":"top_n","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":20,"title":"Top N"}},{"name":"checkpoint_interval_min","in":"query","required":false,"schema":{"type":"number","default":15,"title":"Checkpoint Interval Min"}},{"name":"recovery_overhead_min","in":"query","required":false,"schema":{"type":"number","default":5,"title":"Recovery Overhead Min"}}],"responses":{"200":{"description":"Per-port counterfactual savings sorted by $ avoidable","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/benchmark/harness":{"get":{"tags":["Benchmark"],"summary":"Competitive Benchmark Harness","description":"Run the synthetic-failure benchmark harness: Hikari vs UFM Cyber-AI, CloudVision, Apstra, Nexus Dashboard on 6 failure scenarios (thermal_precursor, fiber_loose, voltage_instab, coherent_snr_drop, cpo_die_thermal, cpo_laser_bank). Returns per-scenario TP/FP/FN/TN, precision/recall/F1, and first detection stage per engine. Reproducible via `seed` query param.","operationId":"benchmark_harness_api_benchmark_harness_get","parameters":[{"name":"samples","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":20,"default":100,"title":"Samples"}},{"name":"seed","in":"query","required":false,"schema":{"type":"integer","default":42,"title":"Seed"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","description":"'json' forces raw JSON in browsers","default":"","title":"Format"},"description":"'json' forces raw JSON in browsers"}],"responses":{"200":{"description":"Overall + per-scenario detection metrics for each benchmarked engine","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/postmortem/from-alert":{"post":{"tags":["Postmortem"],"summary":"Incident Postmortem from Alert","description":"Generate a structured postmortem for the highest-severity alert on a given port. Collects timeline from ClickHouse readings + PostgreSQL alerts, aggregates affected GPU/Job impact via simulate_failure, then calls ai_agent.generate_postmortem for narrative + 5-whys + action items. Returns a JSON postmortem suitable for retrospectives.","operationId":"postmortem_from_alert_api_postmortem_from_alert_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Structured postmortem report (timeline, impact, 5-whys, action items)","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/postmortem/gala":{"post":{"tags":["Postmortem"],"summary":"GALA Iterative Graph-Augmented RCA","description":"GALA pattern (arXiv:2508.12472) — instead of a single-pass LLM call, run an iterative evidence-expansion loop over the topology graph. Each round performs (a) next-hop selection, (b) hypothesis update, and (c) termination check. The deterministic hypothesis works without an LLM; when ANTHROPIC_API_KEY is set, the narrative is generated by the LLM while the graph traversal stays deterministic. Reported +42% RCA accuracy versus a single-shot LLM call (GALA paper).","operationId":"postmortem_gala_route_api_postmortem_gala_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Iterative graph traversal evidence + deterministic hypothesis + optional LLM narrative","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/postmortem/timeline":{"post":{"tags":["Postmortem"],"summary":"Deterministic Incident Timeline (no LLM)","description":"Build a structured timeline for a port incident using only SQL — no LLM call. Returns: critical events, reading extremes, affected jobs, and cost estimate. Useful when ANTHROPIC_API_KEY is not configured or for deterministic audits.","operationId":"postmortem_timeline_api_postmortem_timeline_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Deterministic timeline with events, extremes, impact, and cost","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/maintenance":{"get":{"tags":["Maintenance"],"summary":"Maintenance Recommendations","description":"Generates prioritized maintenance recommendations for all ports with risk score >= 30. Includes urgency level (immediate/scheduled/monitor), trend analysis (temperature and RX power change rates over 1 hour), UFM prediction integration, and specific recommended actions (module replacement, connector cleaning, cooling checks).","operationId":"maintenance_api_maintenance_get","responses":{"200":{"description":"Prioritized maintenance list with urgency, trends, and recommended actions per port","content":{"application/json":{"schema":{}}}}}}},"/api/rma":{"get":{"tags":["RMA"],"summary":"List Rma","description":"List all RMA records (newest first).","operationId":"list_rma_api_rma_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["RMA"],"summary":"Create Rma","description":"Create a new RMA record.","operationId":"create_rma_api_rma_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/rma/vendor-quality":{"get":{"tags":["RMA"],"summary":"Rma Vendor Quality","description":"Aggregate failure rate by vendor.","operationId":"rma_vendor_quality_api_rma_vendor_quality_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/rma/part/{part_number}":{"get":{"tags":["RMA"],"summary":"Rma Part History","description":"RMA history grouped by part number.","operationId":"rma_part_history_api_rma_part__part_number__get","parameters":[{"name":"part_number","in":"path","required":true,"schema":{"type":"string","title":"Part Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/diagnosis/generate":{"post":{"tags":["Diagnosis"],"summary":"Generate Diagnosis Report","description":"Run auto-diagnosis on a specific port. Analyzes 24h history, identifies root cause (thermal/connector/hardware/coherent degradation), calculates topology impact, and recommends actions. Requires 'diagnosis' permission. Request body requires 'switch_name' and 'port_name' fields. Reports are persisted in PostgreSQL for later retrieval.","operationId":"diagnosis_generate_api_diagnosis_generate_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Full diagnosis report with root cause analysis, 24h telemetry summary, topology impact, and recommended actions","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/diagnosis/reports":{"get":{"tags":["Diagnosis"],"summary":"Diagnosis List","description":"List diagnosis reports (newest first).","operationId":"diagnosis_list_api_diagnosis_reports_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/diagnosis/reports/{report_id}":{"get":{"tags":["Diagnosis"],"summary":"Diagnosis Detail","description":"Fetch a single diagnosis report by id.","operationId":"diagnosis_detail_api_diagnosis_reports__report_id__get","parameters":[{"name":"report_id","in":"path","required":true,"schema":{"type":"string","title":"Report Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/maintenance/spare-parts":{"get":{"tags":["Maintenance"],"summary":"Spare Parts Recommendations","description":"Calculates recommended spare part inventory based on ports with risk score >= 60, combined with RMA monthly replacement rates. Returns per-part recommended quantity, unit cost, and total cost estimate. Helps procurement teams maintain optimal safety stock.","operationId":"spare_parts_api_maintenance_spare_parts_get","responses":{"200":{"description":"Spare parts list with risky port counts, RMA rates, recommended quantities, and cost estimates","content":{"application/json":{"schema":{}}}}}}},"/api/maintenance/windows":{"get":{"tags":["Maintenance"],"summary":"Optimal Maintenance Windows","description":"Finds optimal maintenance windows within the next N hours by analyzing GPU job schedules. Identifies time slots with zero GPU utilization where port replacements can be performed without impacting workloads. Returns top 3 windows (longest first) with replaceable port count estimates (15 min per port). Includes a 30-minute slot timeline for visualization.","operationId":"maintenance_windows_api_maintenance_windows_get","parameters":[{"name":"hours_ahead","in":"query","required":false,"schema":{"type":"integer","maximum":168,"minimum":1,"default":72,"title":"Hours Ahead"}}],"responses":{"200":{"description":"Top 3 maintenance windows with start/end times, duration, replaceable ports, and GPU usage timeline","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/maintenance/checkpoint-aware":{"get":{"tags":["Maintenance"],"summary":"Checkpoint-Aware Micro Windows","description":"Computes per-job next-checkpoint micro windows. Each running job is assumed to checkpoint every `checkpoint_interval_min` minutes (default 15). The micro-window is the 3-minute slot immediately after the next checkpoint — replacing optics there minimizes rollback cost (only ~3 min of work is lost vs interval/2 average). Returns per-job upcoming windows within the next N hours.","operationId":"maintenance_checkpoint_aware_api_maintenance_checkpoint_aware_get","parameters":[{"name":"hours_ahead","in":"query","required":false,"schema":{"type":"integer","maximum":48,"minimum":1,"default":6,"title":"Hours Ahead"}},{"name":"checkpoint_interval_min","in":"query","required":false,"schema":{"type":"integer","maximum":120,"minimum":1,"default":15,"title":"Checkpoint Interval Min"}},{"name":"micro_window_min","in":"query","required":false,"schema":{"type":"integer","maximum":30,"minimum":1,"default":3,"title":"Micro Window Min"}}],"responses":{"200":{"description":"Per-job next checkpoint window, replaceable ports, and avoided rollback cost","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/inventory":{"get":{"tags":["Inventory"],"summary":"Inventory List","description":"Inventory listing — includes transceiver lifecycle metadata (installed_at, warranty_expires_at, lifecycle_status).","operationId":"inventory_list_api_inventory_get","parameters":[{"name":"vendor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by vendor","title":"Vendor"},"description":"Filter by vendor"},{"name":"lifecycle_status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by lifecycle status: active, aging, eol, replaced","title":"Lifecycle Status"},"description":"Filter by lifecycle status: active, aging, eol, replaced"},{"name":"warranty_expiring","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Show only modules whose warranty expires within 90 days","title":"Warranty Expiring"},"description":"Show only modules whose warranty expires within 90 days"},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","description":"Sort key: installed_at, warranty_expires_at","default":"installed_at","title":"Sort By"},"description":"Sort key: installed_at, warranty_expires_at"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":5000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/inventory/summary":{"get":{"tags":["Inventory"],"summary":"Inventory Summary","description":"Inventory rollup — counts by vendor, form factor, warranty / lifecycle status, firmware distribution, mean age.","operationId":"inventory_summary_api_inventory_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/inventory/{port_id}":{"put":{"tags":["Inventory"],"summary":"Inventory Update","description":"Update lifecycle fields on a single inventory record.","operationId":"inventory_update_api_inventory__port_id__put","parameters":[{"name":"port_id","in":"path","required":true,"schema":{"type":"integer","title":"Port Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/maintenance/nmc-trigger":{"post":{"tags":["Maintenance"],"summary":"NVIDIA Mission Control autonomous recovery trigger (W13)","description":"Forwards a port replacement / hardware-recovery request to NVIDIA Mission Control's autonomous recovery API (NMC 2.0+). Closed-loop from FIBER risk → NMC ticket → physical action.\n\nBody: {\"switch_name\":..., \"port_name\":..., \"reason\": str (optional), \"risk_score\": int (optional), \"job_ids\": [list, optional]}\n\nBehaviour:\n  • Dry-run if FIBER_NMC_URL / FIBER_NMC_TOKEN env vars unset — returns the     payload that would be sent and `dry_run: true`.\n  • Live call sends POST {NMC_URL}/api/v1/recovery/trigger with bearer auth.\n\nUse risk≥80 from the 3-tier engine to drive automatic invocation; viewer or operator role keys can call this — actual execution happens server-side under the FIBER service account scoped to NMC.","operationId":"maintenance_nmc_trigger_api_maintenance_nmc_trigger_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"NMC ticket ID + status, or dry-run preview","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/maintenance/queue":{"get":{"tags":["Maintenance"],"summary":"List auto-scheduled maintenance proposals (F4)","operationId":"list_maintenance_queue_api_maintenance_queue_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"all","title":"Status"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/maintenance/queue/{queue_id}/approve":{"post":{"tags":["Maintenance"],"summary":"Approve an auto-scheduled maintenance proposal (F4)","operationId":"approve_maintenance_queue_api_maintenance_queue__queue_id__approve_post","parameters":[{"name":"queue_id","in":"path","required":true,"schema":{"type":"integer","title":"Queue Id"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"default":{},"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/maintenance/queue/{queue_id}/reject":{"post":{"tags":["Maintenance"],"summary":"Reject an auto-scheduled maintenance proposal (F4)","operationId":"reject_maintenance_queue_api_maintenance_queue__queue_id__reject_post","parameters":[{"name":"queue_id","in":"path","required":true,"schema":{"type":"integer","title":"Queue Id"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"default":{},"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/maintenance/node-sweep-checklist":{"get":{"tags":["Maintenance"],"summary":"Post-maintenance node re-entry sweep checklist (Slurm NHC)","description":"Read-only checklist for returning a compute node to service after maintenance (MLSys 2026 Guard, arXiv 2605.17879: sweep before re-entry). Resolves `hostname` (FQDN or short) to its leaf uplink port via gpu_nodes (fallback: last 24 h of gpu_telemetry) and evaluates: `uplink` — risk-engine risk_score / severity and telemetry silence of the uplink optic; `los` — OpenConfig transceiver v1.0.0 RX LOS/LOL reset-safe increase over the last 1 h (only when the columns exist); `gpu` — latest DCGM health per GPU (detachment, XID, ECC DBE, DCGM health, thermal, roster); `nccl` — recent NCCL Inspector / RAS events (a non-failing `ncclras -D` diagnostic — OK/PASS or SKIP, which share `ras_severity='info'` — is counted as `nccl.diag_info_checks` (\"OK or skipped\", not a pass count), never as a RAS event or a low-bandwidth collective; a diagnostic FAIL still counts as RAS critical). Each check is pass | warn | fail | unknown; `recommended` is `hold` when any check fails (or warns with `strict=true`), else `sweep_pass`. `sections=uplink` is the cheap mode used by scripts/nhc/check_optical_uplink.nhc (one PostgreSQL lookup + two ClickHouse point reads): the NHC check dies when `uplink.risk_score >= risk_hold` or `uplink.silent` is true. Sections degrade to `unknown` (never 500) when a backend or column is missing. 404 only when the hostname is genuinely neither registered in gpu_nodes nor seen in gpu_telemetry; a lookup that could not be answered because a store is down returns 503 (`lookup_backend_error`) so the client's fail-mode — not its unknown-node policy — decides. Tenant-scoped keys (non-`default`) only resolve nodes whose switch belongs to that tenant, and every optical read is filtered by `tenant_id`.","operationId":"maintenance_node_sweep_checklist_api_maintenance_node_sweep_checklist_get","parameters":[{"name":"hostname","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":253,"description":"Compute node hostname (FQDN or short; matched against gpu_nodes.hostname)","title":"Hostname"},"description":"Compute node hostname (FQDN or short; matched against gpu_nodes.hostname)"},{"name":"sections","in":"query","required":false,"schema":{"type":"string","description":"`all` or comma list of uplink,los,gpu,nccl — `uplink` alone is the cheap NHC mode","default":"all","title":"Sections"},"description":"`all` or comma list of uplink,los,gpu,nccl — `uplink` alone is the cheap NHC mode"},{"name":"risk_hold","in":"query","required":false,"schema":{"type":"number","maximum":100,"minimum":0,"description":"uplink risk_score at/above which the node is held (default 60 = warning+critical)","default":60.0,"title":"Risk Hold"},"description":"uplink risk_score at/above which the node is held (default 60 = warning+critical)"},{"name":"silence_sec","in":"query","required":false,"schema":{"type":"integer","maximum":86400,"minimum":10,"description":"uplink telemetry older than this is `silent` (default 180 s = collector watchdog floor)","default":180,"title":"Silence Sec"},"description":"uplink telemetry older than this is `silent` (default 180 s = collector watchdog floor)"},{"name":"nccl_minutes","in":"query","required":false,"schema":{"type":"integer","maximum":1440,"minimum":1,"description":"NCCL / RAS look-back window in minutes","default":60,"title":"Nccl Minutes"},"description":"NCCL / RAS look-back window in minutes"},{"name":"strict","in":"query","required":false,"schema":{"type":"boolean","description":"Escalate warn checks (thermal, partial roster, RAS, LOS warn, risk warning) to hold","default":false,"title":"Strict"},"description":"Escalate warn checks (thermal, partial roster, RAS, LOS warn, risk warning) to hold"}],"responses":{"200":{"description":"Per-check verdicts, uplink/los/gpu/nccl detail blocks and recommended sweep_pass | hold","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/export/ports":{"get":{"tags":["Export"],"summary":"Export Port Data","description":"Export all port telemetry data (up to 2400 ports) in CSV or JSON format. Supports vendor, severity, and speed filtering. Sorted by risk score descending. Requires 'export' permission. File is returned as a download attachment.","operationId":"export_ports_api_export_ports_get","parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","description":"Export format: csv or json","default":"csv","title":"Format"},"description":"Export format: csv or json"},{"name":"vendor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vendor"}},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"}},{"name":"speed","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speed"}}],"responses":{"200":{"description":"CSV or JSON file download with port telemetry and risk data","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/export/alerts":{"get":{"tags":["Export"],"summary":"Export Alerts","description":"Export alerts from the last N days. CSV or JSON.","operationId":"export_alerts_api_export_alerts_get","parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","description":"Export format: csv or json","default":"csv","title":"Format"},"description":"Export format: csv or json"},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"description":"Export alerts from last N days","default":7,"title":"Days"},"description":"Export alerts from last N days"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/export/maintenance":{"get":{"tags":["Export"],"summary":"Export Maintenance","description":"Export maintenance recommendations. CSV or JSON.","operationId":"export_maintenance_api_export_maintenance_get","parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","description":"Export format: csv or json","default":"csv","title":"Format"},"description":"Export format: csv or json"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sustainability":{"get":{"tags":["Sustainability"],"summary":"Cluster Sustainability KPIs","description":"ESG/Sustainability metrics: instantaneous power of all active optics, kWh/day and kWh/year extrapolations, CO2e at grid emission factor, RMA-driven e-waste CO2e, and avoided emissions from preventive maintenance (vs emergency dispatch). Broken down by optics type (400G/800G/400ZR/CPO/LPO).","operationId":"sustainability_api_sustainability_get","parameters":[{"name":"grid_kgco2_per_kwh","in":"query","required":false,"schema":{"type":"number","description":"Grid emission factor (kgCO2e/kWh)","default":0.42,"title":"Grid Kgco2 Per Kwh"},"description":"Grid emission factor (kgCO2e/kWh)"},{"name":"emergency_dispatch_km","in":"query","required":false,"schema":{"type":"number","description":"Avg emergency tech dispatch distance (km)","default":80,"title":"Emergency Dispatch Km"},"description":"Avg emergency tech dispatch distance (km)"},{"name":"emergency_dispatch_kgco2_per_km","in":"query","required":false,"schema":{"type":"number","description":"Vehicle emission factor","default":0.21,"title":"Emergency Dispatch Kgco2 Per Km"},"description":"Vehicle emission factor"},{"name":"module_eol_kgco2","in":"query","required":false,"schema":{"type":"number","description":"Per-module end-of-life CO2e","default":1.5,"title":"Module Eol Kgco2"},"description":"Per-module end-of-life CO2e"}],"responses":{"200":{"description":"Energy, CO2e, and avoided emissions breakdown","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/roi":{"get":{"tags":["ROI"],"summary":"Roi Calculator","description":"라이브 클러스터 기반 ROI — 동기 계산 + 5분 캐시. ClickHouse(소형 latest 테이블)는 빠르고\n알람 카운트는 플래너 추정치라 무거운 스캔이 없다 → 백그라운드 워머 불필요, 즉시 응답.","operationId":"roi_calculator_api_roi_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/trends":{"get":{"tags":["Analytics"],"summary":"Long-term Trend Analysis","description":"Analyze 30/60/90-day trends across four dimensions: daily risk score progression (from risk_daily), vendor reliability, speed-tier telemetry trends, and optical module aging — all served from pre-aggregated rollup tables (optical_daily_agg / risk_daily) so responses stay well under client timeouts. optical_daily_agg is maintained in real time by an incremental materialized view; risk_daily is refreshed by a host cron (scripts/refresh_rollups.sh, also the self-heal for the MV).","operationId":"trends_api_trends_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":7,"default":30,"title":"Days"}},{"name":"vendor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vendor"}},{"name":"speed","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speed"}}],"responses":{"200":{"description":"Multi-dimensional trend data with daily risk, vendor reliability, speed trends, and aging port analysis","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/gpu/summary":{"get":{"tags":["GPU"],"summary":"GPU Fleet Health Summary","description":"Fleet-wide GPU health from dcgm-exporter telemetry: reporting count, detachment (quiet failures), thermal/XID/ECC anomalies, by-model breakdown. On deployments whose gpu_telemetry carries the dcgm-exporter 4.8.x extension (xid_total, health_status/severity/category) a `health` block adds counts by DCGM health status / severity / category and xid_total sums; otherwise `health` is null. GPUs whose exporter does not emit the opt-in DCGM_EXP_GPU_HEALTH_STATUS series are counted as `unknown` (never as pass); `health_reporting_gpus` is the number of GPUs with a real DCGM health verdict.","operationId":"gpu_summary_api_gpu_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/gpu/telemetry":{"get":{"tags":["GPU"],"summary":"Per-GPU Latest Telemetry","description":"Latest DCGM telemetry per GPU, optionally filtered by node hostname or switch. When available each GPU also carries xid_total (DCGM_EXP_XID_ERRORS_TOTAL), health_status (raw DCGM_EXP_GPU_HEALTH_STATUS), health_severity, health_category and a derived `health` label (pass/warn/fail, or `unknown` when the exporter emits no health series for that GPU); `health_columns` lists which exist.","operationId":"gpu_telemetry_api_gpu_telemetry_get","parameters":[{"name":"node","in":"query","required":false,"schema":{"type":"string","title":"Node"}},{"name":"switch","in":"query","required":false,"schema":{"type":"string","title":"Switch"}},{"name":"anomalous_only","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Anomalous Only"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/gpu/correlation":{"get":{"tags":["GPU"],"summary":"Fused GPU↔Optical Correlation","description":"Hikari's differentiator: correlate GPU anomalies (thermal / XID / ECC / detachment) with optical anomalies on the SAME switch path within ±60s. GPU-only tools (Meta GCM, dcgm-exporter, Mission Control) cannot do this — the optical L1 fusion is Hikari-exclusive.","operationId":"gpu_optical_correlation_api_gpu_correlation_get","parameters":[{"name":"minutes","in":"query","required":false,"schema":{"type":"integer","maximum":180,"minimum":1,"default":15,"title":"Minutes"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/clustermax/readiness":{"get":{"tags":["ClusterMAX"],"summary":"ClusterMAX Criterion #6 Readiness Report","description":"Maps FIBER's live signals to SemiAnalysis ClusterMAX v2.1 Criterion #6 (Reliability — automated passive health checks: detect & drain). Each criterion shows the detection source, live event counts in the window, and evidence samples. Criteria with zero events in-window are reported honestly as 'wired'. v2.1 is the current published standard; ClusterMAX v3.0 (coming soon) adds a reliability phase that injects simulated hardware failures to stress monitoring systems and health checks (SemiAnalysis 2026-08-30) — the scoring logic here is unchanged, the text fields simply carry that context.","operationId":"clustermax_readiness_api_clustermax_readiness_get","parameters":[{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":168,"minimum":1,"default":24,"title":"Hours"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/audit/logs":{"get":{"tags":["Audit"],"summary":"Audit Logs","description":"Audit log query — supports pagination and filtering.","operationId":"audit_logs_api_audit_logs_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"method","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by HTTP method (GET, POST, DELETE, ...)","title":"Method"},"description":"Filter by HTTP method (GET, POST, DELETE, ...)"},{"name":"path_contains","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Substring match on the request path","title":"Path Contains"},"description":"Substring match on the request path"},{"name":"start_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Start date (ISO-8601, e.g. 2026-04-01)","title":"Start Date"},"description":"Start date (ISO-8601, e.g. 2026-04-01)"},{"name":"end_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"End date (ISO-8601, e.g. 2026-04-16)","title":"End Date"},"description":"End date (ISO-8601, e.g. 2026-04-16)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/audit/stats":{"get":{"tags":["Audit"],"summary":"Audit Stats","description":"Audit summary — request volume, error rate, latency, per-endpoint breakdown.","operationId":"audit_stats_api_audit_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/otel/metrics":{"get":{"tags":["Observability"],"summary":"Prometheus Metrics","description":"Returns optical telemetry metrics in Prometheus exposition format. No authentication required — designed for Prometheus scraping. Includes per-port (risk>=30) gauges fiber_port_rx_power_dbm, fiber_port_temperature_celsius, fiber_port_risk_score, fiber_port_fec_uncorrectable and fiber_port_snr_db (coherent only), plus the cluster-level fiber_cluster_* gauges (total/critical/warning ports, average risk score). The same ports are additionally exported under the OpenTelemetry hardware semantic conventions (semconv v1.44.0): hw_status with hw_state one of ok|degraded|failed|predicted_failure, plus hw_optical_* gauges (rx/tx power, temperature, bias current, FEC) carrying hw_id/hw_type/hw_parent attributes. The fiber_port_* / fiber_cluster_* families are unchanged; set FIBER_OTEL_HW_SEMCONV=0 to opt out of the hw.* duplicates. See docs/OTEL_SEMCONV.md.","operationId":"otel_metrics_api_otel_metrics_get","responses":{"200":{"description":"Prometheus exposition format (text/plain; version=0.0.4) with optical telemetry metrics","content":{"application/json":{"schema":{}}}}}}},"/api/self/metrics":{"get":{"tags":["Observability"],"summary":"FIBER self-observation summary (JSON)","description":"Request volume, 5xx error rate, mean latency, top paths, SLO targets — for dashboards / operations.","operationId":"self_metrics_summary_api_self_metrics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/otel/health":{"get":{"tags":["Observability"],"summary":"Otel Health","description":"Inspect the configured OTLP endpoint and credentials state.","operationId":"otel_health_api_otel_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/otel/push":{"post":{"tags":["Observability"],"summary":"Otel Push","description":"Manually push metrics to the OTLP HTTP endpoint (requires FIBER_OTLP_ENDPOINT).","operationId":"otel_push_api_otel_push_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/admin/keys":{"get":{"tags":["Admin"],"summary":"List Api Keys","description":"List API keys (raw key material is never returned — metadata only).","operationId":"list_api_keys_api_admin_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["Admin"],"summary":"Create API Key","description":"Generate a new API key with specified role and tenant. The raw key is returned only once — store it securely. Request body accepts 'tenant_id' (default: 'default'), 'role' (admin/operator/viewer), and 'name' fields. Admin only.","operationId":"create_api_key_api_admin_keys_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"New API key with id, raw key (shown once), tenant, role, and name","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/keys/{key_id}":{"delete":{"tags":["Admin"],"summary":"Revoke Api Key","description":"Revoke an API key.","operationId":"revoke_api_key_api_admin_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"integer","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/whoami":{"get":{"tags":["Admin"],"summary":"Whoami","description":"Return information about the currently authenticated API key.","operationId":"whoami_api_admin_whoami_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/admin/risk-rules":{"get":{"tags":["Admin"],"summary":"Risk Rule Catalog with active overrides","description":"Returns each of the 17 base rules (23 entries with warning/critical extensions) — default threshold, user override, enabled flag.","operationId":"list_risk_rules_api_admin_risk_rules_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/admin/risk-rules/{rule_id}":{"put":{"tags":["Admin"],"summary":"Save Risk Rule override","description":"body: {threshold_value: float?, enabled: bool}. Pass threshold_value=null to restore the default. The risk-engine picks the override up on the next 5-second cycle.","operationId":"update_risk_rule_api_admin_risk_rules__rule_id__put","parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"string","title":"Rule Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/digest/preview":{"get":{"tags":["Admin"],"summary":"Preview today's Slack digest payload (F2)","operationId":"digest_preview_api_admin_digest_preview_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/admin/digest/send-test":{"post":{"tags":["Admin"],"summary":"Send digest right now to a specific channel (F2)","operationId":"digest_send_test_api_admin_digest_send_test_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/digest/recipients":{"get":{"tags":["Admin"],"summary":"List digest Slack channels (F2)","operationId":"digest_list_recipients_api_admin_digest_recipients_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"put":{"tags":["Admin"],"summary":"Replace digest channel list (F2)","operationId":"digest_save_recipients_api_admin_digest_recipients_put","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/switches":{"post":{"tags":["Admin: Switches"],"summary":"Register a single switch","operationId":"create_switch_api_admin_switches_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwitchCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwitchOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin: Switches"],"summary":"List switches","operationId":"list_switches_api_admin_switches_get","parameters":[{"name":"enabled","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled"}},{"name":"vendor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vendor"}},{"name":"tenant_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tenant Id"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"default":200,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/switches/{switch_id}":{"get":{"tags":["Admin: Switches"],"summary":"Get Switch","operationId":"get_switch_api_admin_switches__switch_id__get","parameters":[{"name":"switch_id","in":"path","required":true,"schema":{"type":"integer","title":"Switch Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwitchOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Admin: Switches"],"summary":"Patch Switch","operationId":"patch_switch_api_admin_switches__switch_id__patch","parameters":[{"name":"switch_id","in":"path","required":true,"schema":{"type":"integer","title":"Switch Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwitchPatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwitchOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Admin: Switches"],"summary":"Delete Switch","operationId":"delete_switch_api_admin_switches__switch_id__delete","parameters":[{"name":"switch_id","in":"path","required":true,"schema":{"type":"integer","title":"Switch Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/switches/{switch_id}/enable":{"post":{"tags":["Admin: Switches"],"summary":"Enable Switch","operationId":"enable_switch_api_admin_switches__switch_id__enable_post","parameters":[{"name":"switch_id","in":"path","required":true,"schema":{"type":"integer","title":"Switch Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/switches/{switch_id}/disable":{"post":{"tags":["Admin: Switches"],"summary":"Disable Switch","operationId":"disable_switch_api_admin_switches__switch_id__disable_post","parameters":[{"name":"switch_id","in":"path","required":true,"schema":{"type":"integer","title":"Switch Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/switches/{switch_id}/test":{"post":{"tags":["Admin: Switches"],"summary":"Test Switch","description":"gNMI Capabilities probe — 도달성 + vendor 자동 감지.","operationId":"test_switch_api_admin_switches__switch_id__test_post","parameters":[{"name":"switch_id","in":"path","required":true,"schema":{"type":"integer","title":"Switch Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProbeResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/switches/bulk-import":{"post":{"tags":["Admin: Switches"],"summary":"Bulk Import","operationId":"bulk_import_api_admin_switches_bulk_import_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImportRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImportResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/switches/import/netbox":{"post":{"tags":["Admin: Switches"],"summary":"Import Netbox","description":"Body: {url, token, role_filter?, default_tenant_id, default_username?, default_password?, dry_run?}.","operationId":"import_netbox_api_admin_switches_import_netbox_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImportResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/switches/import/cloudvision":{"post":{"tags":["Admin: Switches"],"summary":"Import Cloudvision","operationId":"import_cloudvision_api_admin_switches_import_cloudvision_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImportResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/switches/import/netq":{"post":{"tags":["Admin: Switches"],"summary":"Import Netq","operationId":"import_netq_api_admin_switches_import_netq_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImportResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/switches/import/dcnm":{"post":{"tags":["Admin: Switches"],"summary":"Import Dcnm","operationId":"import_dcnm_api_admin_switches_import_dcnm_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImportResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/dom-vendors":{"get":{"tags":["Admin: Switches"],"summary":"Observed vendor DOM samples","operationId":"dom_vendor_list_api_admin_dom_vendors_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/admin/dom-vendors/{vendor}/approve":{"post":{"tags":["Admin: Switches"],"summary":"Dom Vendor Approve","operationId":"dom_vendor_approve_api_admin_dom_vendors__vendor__approve_post","parameters":[{"name":"vendor","in":"path","required":true,"schema":{"type":"string","title":"Vendor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/devices":{"get":{"tags":["Devices"],"summary":"Managed switch health","description":"Registered switches with collector health: telemetry age, silence flag (same rule as the collector watchdog), discovered module counts, and conformance scan summary.","operationId":"list_devices_api_devices_get","parameters":[{"name":"all","in":"query","required":false,"schema":{"type":"boolean","description":"Include unmanaged (topology-seed) switches","default":false,"title":"All"},"description":"Include unmanaged (topology-seed) switches"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/devices/events":{"get":{"tags":["Devices"],"summary":"Transceiver discovery timeline","description":"Zero-touch discovery events: transceiver inserted / removed / replaced, with serial, vendor, and DOM capability. Newest first.","operationId":"list_events_api_devices_events_get","parameters":[{"name":"switch","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by switch name","title":"Switch"},"description":"Filter by switch name"},{"name":"event_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"inserted | removed | replaced","title":"Event Type"},"description":"inserted | removed | replaced"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/switches/{switch_id}/conformance":{"post":{"tags":["Admin: Switches"],"summary":"Run vendor conformance scan","description":"Probes gNMI Capabilities, component naming convention, transceiver inventory, and DOM value plausibility. Stores the profile on the switch row. This automates the one-time per-vendor validation that was previously manual.","operationId":"run_conformance_scan_api_admin_switches__switch_id__conformance_post","parameters":[{"name":"switch_id","in":"path","required":true,"schema":{"type":"integer","title":"Switch Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ai/status":{"get":{"tags":["AI Assistant"],"summary":"AI Assistant Status","description":"Check whether the natural language query interface is configured. Returns {configured, model, agent_configured, agent_model, row_limit, timeout_sec} plus a provider block {provider, on_prem, base_url, auth, llm, not_configured_hint}. `provider` is `anthropic` (cloud Claude, needs ANTHROPIC_API_KEY) or `openai_compat` (on-prem vLLM/Ollama/llama.cpp/SGLang/TGI, needs FIBER_LLM_BASE_URL); `on_prem` is true for the latter, and `llm.model` + `base_url` render as e.g. \"on-prem: Qwen3.8-27B @ http://vllm:8000/v1\". `not_configured_hint` is the exact operator-facing reason when `configured: false`. No secret is ever returned — `auth` is only a boolean saying whether a credential is present.","operationId":"ai_status_api_ai_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/ai/query":{"post":{"tags":["AI Assistant"],"summary":"Natural Language Query","description":"Convert a natural language question into a safe SQL query (ClickHouse or PostgreSQL), execute it, and return both structured results and an AI-generated summary. Safety guards: SELECT/WITH only, row limit (default 500), execution timeout (default 5s), destructive keywords blocked. Body: {question: string, history?: [{role, content}, ...]}.","operationId":"ai_query_api_ai_query_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ai/investigate":{"post":{"tags":["AI Assistant"],"summary":"Agentic RCA Investigation","description":"Run an agentic root cause analysis on a port. Claude autonomously gathers evidence via read-only tool calls (telemetry, history, alerts, vendor baseline, topology impact, similar RMA failures, module lifecycle) and produces a structured report with root cause, confidence, evidence, timeline, impact summary, recommended actions, and a TTF estimate. The report is persisted in ``diagnosis_reports``.","operationId":"ai_investigate_api_ai_investigate_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Agentic RCA report — root_cause, timeline, impact_summary, recommended_actions, time_to_failure_estimate, tools_used, iterations.","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ai/postmortem":{"post":{"tags":["AI Assistant"],"summary":"Generate Incident Postmortem","description":"Generate a production-quality incident postmortem document. Either pass `{incident: {...}}` with custom data, or pass `{switch_name, port_name, hours?}` and the API will gather the last `hours` of risk alerts for that port to seed the document.","operationId":"ai_postmortem_api_ai_postmortem_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Postmortem document — title, summary, timeline, impact, root cause, 5-whys, action items.","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ai/explain/{switch_name}/{port_name}":{"get":{"tags":["AI Assistant"],"summary":"Explainable Risk Score","description":"Return a human-readable explanation of why a port has its current risk score: headline, confidence, contributing factors with severities, trend, and similar-pattern description.","operationId":"ai_explain_api_ai_explain__switch_name___port_name__get","parameters":[{"name":"switch_name","in":"path","required":true,"schema":{"type":"string","title":"Switch Name"}},{"name":"port_name","in":"path","required":true,"schema":{"type":"string","title":"Port Name"}}],"responses":{"200":{"description":"JSON explanation of the risk score.","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ai/suggest-action":{"post":{"tags":["AI Assistant"],"summary":"Propose a structured action (RMA / incident / maintenance)","description":"Claude reads the question + optional context and returns one structured action proposal the operator can approve with /api/ai/proposals/{id}/execute. Read permission. Feature-flag FIBER_AI_SUGGEST_ACTION_ENABLED.","operationId":"ai_suggest_action_api_ai_suggest_action_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ai/proposals/{proposal_id}/execute":{"post":{"tags":["AI Assistant"],"summary":"Approve a proposal — fan-out to the matching backend","description":"Write permission required. Validates the proposal is still in 'proposed' status and has not expired, then routes the payload to /api/rma POST, the PagerDuty trigger, or the maintenance queue depending on type.","operationId":"ai_proposal_execute_api_ai_proposals__proposal_id__execute_post","parameters":[{"name":"proposal_id","in":"path","required":true,"schema":{"type":"string","title":"Proposal Id"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"default":{},"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ai/proposals/{proposal_id}/reject":{"post":{"tags":["AI Assistant"],"summary":"Reject a proposal","operationId":"ai_proposal_reject_api_ai_proposals__proposal_id__reject_post","parameters":[{"name":"proposal_id","in":"path","required":true,"schema":{"type":"string","title":"Proposal Id"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"default":{},"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ai/proposals":{"get":{"tags":["AI Assistant"],"summary":"List action proposals","description":"Pending/recent action proposals — both operator-question-driven (F1) and autopilot-generated (F5, proposed_by='autopilot-f5'). This is the operator surface that makes autonomous proposals visible for one-click approve/reject.","operationId":"ai_proposals_list_api_ai_proposals_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"proposed","title":"Status"}},{"name":"proposed_by","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Proposed By"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/integrations/status":{"get":{"tags":["Observability"],"summary":"Integrations Status","description":"W9 integrations health check (Splunk / Datadog / GCM / DCGM) + the NVSentinel bridge.\n\n``nvsentinel.enabled`` is False in the default dry-run posture (no FIBER_NVSENTINEL_PUBLISH_URL):\nthe bridge still ingests and correlates, it just does not publish HealthEvents outbound.","operationId":"integrations_status_api_integrations_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/integrations/gcm/ingest":{"post":{"tags":["Observability"],"summary":"Ingest Meta GCM events","description":"Accept Meta GCM (facebookresearch/gcm) events as either OTLP or native JSON payload.\n\nOTLP form:   {\"resourceMetrics\": [...]}\nNative form: {\"events\": [{\"ts\", \"node\", \"gpu_index\", \"metric\", \"value\", \"labels\"}, ...]}","operationId":"gcm_ingest_route_api_integrations_gcm_ingest_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/integrations/gcm/summary":{"get":{"tags":["Observability"],"summary":"Gcm Summary Route","description":"Aggregate GCM events from the last N minutes — counts by type / severity, plus the 50 most recent criticals.","operationId":"gcm_summary_route_api_integrations_gcm_summary_get","parameters":[{"name":"minutes","in":"query","required":false,"schema":{"type":"integer","maximum":180,"minimum":1,"default":15,"title":"Minutes"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/integrations/gcm/optical-correlation":{"get":{"tags":["Observability"],"summary":"Gcm Optical Correlation Route","description":"Correlate GCM critical / warning events with the same host's optical telemetry within ±60 seconds.","operationId":"gcm_optical_correlation_route_api_integrations_gcm_optical_correlation_get","parameters":[{"name":"minutes","in":"query","required":false,"schema":{"type":"integer","maximum":180,"minimum":1,"default":15,"title":"Minutes"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/integrations/dcgm/correlation":{"get":{"tags":["Observability"],"summary":"Dcgm Correlation Route","description":"Correlate NVIDIA dcgm-exporter (Prometheus) with optical telemetry within ±60 seconds.","operationId":"dcgm_correlation_route_api_integrations_dcgm_correlation_get","parameters":[{"name":"minutes","in":"query","required":false,"schema":{"type":"integer","maximum":180,"minimum":1,"default":15,"title":"Minutes"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/integrations/exporters/test":{"post":{"tags":["Observability"],"summary":"Exporter Test Route","description":"Probe Splunk + Datadog handshakes by fanning out a single test alert.","operationId":"exporter_test_route_api_integrations_exporters_test_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/integrations/correlation-incidents":{"get":{"tags":["Integrations"],"summary":"List NCCL ↔ optical auto-routed incidents (F3)","description":"Audit log of incidents the F3 watcher fired (or would have fired in dryrun mode). Filter by hours back and status.","operationId":"list_correlation_incidents_api_integrations_correlation_incidents_get","parameters":[{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":168,"minimum":1,"default":24,"title":"Hours"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"all | open | dryrun | resolved | suppressed","default":"all","title":"Status"},"description":"all | open | dryrun | resolved | suppressed"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/integrations/nvsentinel/publish":{"post":{"tags":["Integrations"],"summary":"Publish a FIBER optical alert to NVSentinel as a HealthEvent","description":"Body: {\"alert_id\": 123} or {\"switch\": \"leaf-010\", \"port\": \"Ethernet1/41\"} (port \"-\" = switch-level telemetry_silence). The alert is mapped to one `datamodels.HealthEvent` per GPU node whose uplink is that port (gpu_nodes.port_id). Dry-run (payload returned, nothing sent) when FIBER_NVSENTINEL_PUBLISH_URL is unset or `dry_run: true`. Real publishes are deduplicated per (node, check) for 1 h unless `force: true`; a failed send releases the dedup budget so the retry is not suppressed. Optional `hours` (default 24) bounds the alert lookup; optional `message`/`alert_type`/`severity` synthesise an alert when none is on record — that synthetic path is dry-run/demo only: it is forced to dry-run (unless FIBER_NVSENTINEL_ALLOW_SYNTHETIC_PUBLISH=1) and never sets isFatal, so a fabricated event cannot drive an NVSentinel cordon/drain.","operationId":"nvsentinel_publish_route_api_integrations_nvsentinel_publish_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/integrations/nvsentinel/ingest":{"post":{"tags":["Integrations"],"summary":"Ingest NVSentinel health events (webhook / Event Exporter sink)","description":"Accepts a JSON list or object in any of: raw `HealthEvent`; `HealthEvents{version, events[]}`; CloudEvents `com.nvidia.nvsentinel.health.v1` (NVSentinel Event Exporter sink — point its `sink.endpoint` here); a PostgreSQL `health_events` row/document; a `HealthEventResource` CRD. Events are stored in ClickHouse hikari.gpu_health_events (TTL 30 d) and classified (gpu_driver_unresponsive / nic_wedge / ib_chardev_missing / power_brake / other).","operationId":"nvsentinel_ingest_route_api_integrations_nvsentinel_ingest_post","requestBody":{"content":{"application/json":{"schema":{"title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/integrations/nvsentinel/correlation":{"get":{"tags":["Integrations"],"summary":"NVSentinel node faults ↔ optical state of the node's uplink (±60 s)","description":"For every NVSentinel health event in the window (default categories: GPU driver unresponsive, mlx5 NIC wedge, IB char-device missing, power brake; `categories=all` for everything) look at the node's switch uplink: optical_readings ±60 s (rx power / temperature / FEC) and risk_alerts. `sync=true` first pulls new rows from the NVSentinel PostgreSQL store when FIBER_NVSENTINEL_PG_DSN is set.","operationId":"nvsentinel_correlation_route_api_integrations_nvsentinel_correlation_get","parameters":[{"name":"minutes","in":"query","required":false,"schema":{"type":"integer","maximum":1440,"minimum":1,"default":60,"title":"Minutes"}},{"name":"categories","in":"query","required":false,"schema":{"type":"string","description":"comma list or 'all'; default = the four target categories","default":"","title":"Categories"},"description":"comma list or 'all'; default = the four target categories"},{"name":"include_healthy","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Healthy"}},{"name":"sync","in":"query","required":false,"schema":{"type":"boolean","description":"poll the NVSentinel PostgreSQL store first (if configured)","default":true,"title":"Sync"},"description":"poll the NVSentinel PostgreSQL store first (if configured)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/integrations/nvsentinel/status":{"get":{"tags":["Integrations"],"summary":"NVSentinel bridge status","operationId":"nvsentinel_status_route_api_integrations_nvsentinel_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/integrations/tenant-status":{"get":{"tags":["Integrations"],"summary":"List connected integrations for the caller's tenant","operationId":"list_status_api_integrations_tenant_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/integrations/slack/install":{"get":{"tags":["Integrations"],"summary":"Begin Slack OAuth install — returns the install URL","description":"Returns `{install_url}` for the frontend to set `window.location` to. We never carry the Bearer in URL query params — frontend XHRs this with the auth header, then JS performs the redirect.","operationId":"slack_install_api_integrations_slack_install_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/integrations/slack/callback":{"get":{"tags":["Integrations"],"summary":"Slack OAuth callback — exchanges code for webhook URL","operationId":"slack_callback_api_integrations_slack_callback_get","parameters":[{"name":"code","in":"query","required":false,"schema":{"type":"string","default":"","title":"Code"}},{"name":"state","in":"query","required":false,"schema":{"type":"string","default":"","title":"State"}},{"name":"error","in":"query","required":false,"schema":{"type":"string","default":"","title":"Error"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/integrations/slack/disconnect":{"post":{"tags":["Integrations"],"summary":"Disconnect Slack integration","operationId":"slack_disconnect_api_integrations_slack_disconnect_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/integrations/slack/test":{"post":{"tags":["Integrations"],"summary":"Fire a test Slack message via the connected webhook","operationId":"slack_test_api_integrations_slack_test_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/integrations/pagerduty/connect":{"post":{"tags":["Integrations"],"summary":"Save a PagerDuty Events V2 routing key (production)","operationId":"pd_connect_api_integrations_pagerduty_connect_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/integrations/pagerduty/disconnect":{"post":{"tags":["Integrations"],"summary":"Disconnect a PagerDuty integration","operationId":"pd_disconnect_api_integrations_pagerduty_disconnect_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body","default":{}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/integrations/pagerduty/test":{"post":{"tags":["Integrations"],"summary":"Fire a test PagerDuty incident via the connected routing key","operationId":"pd_test_api_integrations_pagerduty_test_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body","default":{}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/topology/sparql/health":{"get":{"tags":["SPARQL"],"summary":"Fuseki health check","description":"Returns Fuseki ping status. Always returns 200 with status payload, even if Fuseki is down.","operationId":"sparql_health_api_topology_sparql_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/topology/sparql/query":{"post":{"tags":["SPARQL"],"summary":"Execute SPARQL query against /fiber dataset","description":"SELECT/ASK/DESCRIBE/CONSTRUCT 만 허용. INSERT/DELETE/DROP/CLEAR 차단. max rows = 1,000. timeout = 10s. Feature flag FIBER_SPARQL_ENABLED=1 필요.","operationId":"sparql_query_api_topology_sparql_query_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"},"example":{"query":"PREFIX fiber: <https://fiber.ac/ontology/optics#>\nSELECT ?cls ?label WHERE { ?cls a <http://www.w3.org/2002/07/owl#Class> ; <http://www.w3.org/2000/01/rdf-schema#label> ?label . } LIMIT 10"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/topology/sparql/saved":{"get":{"tags":["SPARQL"],"summary":"List saved SPARQL queries (tenant-scoped + shared)","operationId":"list_saved_api_topology_sparql_saved_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["SPARQL"],"summary":"Save a SPARQL query (operator+)","description":"저장. shared=true 면 같은 tenant 의 다른 사용자도 볼 수 있음.","operationId":"save_query_api_topology_sparql_saved_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"},"example":{"name":"critical-ports-last-24h","query":"PREFIX fiber: <https://fiber.ac/ontology/optics#> SELECT ...","description":"지난 24시간 critical 알람 발생 포트","shared":true}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/topology/sparql/saved/{qid}":{"delete":{"tags":["SPARQL"],"summary":"Delete saved query (owner only)","operationId":"delete_saved_api_topology_sparql_saved__qid__delete","parameters":[{"name":"qid","in":"path","required":true,"schema":{"type":"integer","minimum":1,"title":"Qid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ws/stats":{"get":{"tags":["WebSocket"],"summary":"Active WebSocket connections (admin only)","operationId":"ws_stats_api_ws_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/graphql":{"get":{"tags":["GraphQL"],"summary":"Handle Http Get","operationId":"handle_http_get_graphql_get","responses":{"200":{"description":"The GraphiQL integrated development environment.","content":{"application/json":{"schema":{}}}},"404":{"description":"Not found if GraphiQL or query via GET are not enabled."}}},"post":{"tags":["GraphQL"],"summary":"Handle Http Post","operationId":"handle_http_post_graphql_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"BulkImportError":{"properties":{"row":{"type":"integer","title":"Row"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"error":{"type":"string","title":"Error"}},"type":"object","required":["row","error"],"title":"BulkImportError"},"BulkImportRequest":{"properties":{"format":{"type":"string","enum":["csv","json"],"title":"Format","default":"csv"},"data":{"type":"string","minLength":1,"title":"Data","description":"CSV 텍스트 또는 JSON 배열 문자열"},"dry_run":{"type":"boolean","title":"Dry Run","description":"검증만 수행, DB 변경 없음","default":false},"default_tenant_id":{"type":"string","maxLength":50,"title":"Default Tenant Id","default":"default"},"default_poll_interval_s":{"type":"integer","maximum":600.0,"minimum":5.0,"title":"Default Poll Interval S","default":30}},"type":"object","required":["data"],"title":"BulkImportRequest","description":"CSV/JSON 일괄 import.\n\nCSV header 고정:\n    name,vendor,mgmt_ip,gnmi_port,role,rack_id,pod_id,username,password,ssh_key,tenant_id,poll_interval_s"},"BulkImportResult":{"properties":{"accepted":{"type":"integer","title":"Accepted"},"rejected":{"type":"integer","title":"Rejected"},"created_ids":{"items":{"type":"integer"},"type":"array","title":"Created Ids"},"errors":{"items":{"$ref":"#/components/schemas/BulkImportError"},"type":"array","title":"Errors"},"dry_run":{"type":"boolean","title":"Dry Run"}},"type":"object","required":["accepted","rejected","created_ids","errors","dry_run"],"title":"BulkImportResult"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ProbeResult":{"properties":{"reachable":{"type":"boolean","title":"Reachable"},"vendor_os":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vendor Os"},"vendor_os_ver":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vendor Os Ver"},"adapter":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Adapter"},"supported_models":{"items":{"type":"string"},"type":"array","title":"Supported Models"},"latency_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latency Ms"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"error_code":{"anyOf":[{"type":"string","enum":["AUTH_REJECTED","TLS_REQUIRED","TIMEOUT","MODEL_UNSUPPORTED","DNS_FAIL","REFUSED","UNKNOWN"]},{"type":"null"}],"title":"Error Code"}},"type":"object","required":["reachable"],"title":"ProbeResult","description":"gNMI Capabilities probe 결과."},"SwitchCreate":{"properties":{"name":{"type":"string","maxLength":128,"minLength":1,"title":"Name"},"vendor":{"type":"string","enum":["arista","cisco","nvidia","juniper","unknown"],"title":"Vendor","default":"unknown"},"model":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Model"},"role":{"type":"string","maxLength":32,"title":"Role","default":"leaf"},"rack_id":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Rack Id"},"pod_id":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Pod Id"},"mgmt_ip":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mgmt Ip","description":"management IP (IPv4 또는 hostname)"},"gnmi_port":{"type":"integer","maximum":65535.0,"minimum":1.0,"title":"Gnmi Port","default":6030},"tenant_id":{"type":"string","maxLength":50,"title":"Tenant Id","default":"default"},"username":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Username"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password","description":"평문 — 저장 시 Fernet 으로 즉시 암호화"},"ssh_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ssh Key","description":"평문 PEM/OpenSSH key — 저장 시 암호화"},"auth_method":{"type":"string","enum":["password","ssh_key","mtls"],"title":"Auth Method","default":"password"},"poll_interval_s":{"type":"integer","maximum":600.0,"minimum":5.0,"title":"Poll Interval S","default":30},"tls_insecure":{"type":"boolean","title":"Tls Insecure","default":true},"source":{"type":"string","enum":["manual","csv","netbox","cloudvision","netq","dcnm"],"title":"Source","default":"manual"},"source_ref":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"title":"Source Ref"}},"type":"object","required":["name"],"title":"SwitchCreate","description":"관리자 단일 등록 입력."},"SwitchOut":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"vendor":{"type":"string","title":"Vendor"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"role":{"type":"string","title":"Role"},"rack_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rack Id"},"pod_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pod Id"},"mgmt_ip":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mgmt Ip"},"gnmi_port":{"type":"integer","title":"Gnmi Port"},"tenant_id":{"type":"string","title":"Tenant Id"},"enabled":{"type":"boolean","title":"Enabled"},"onboarded_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Onboarded At"},"last_seen_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Seen At"},"last_probe_ok":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Last Probe Ok"},"last_probe_err":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Probe Err"},"vendor_os":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vendor Os"},"vendor_os_ver":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vendor Os Ver"},"source":{"type":"string","title":"Source"},"source_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Ref"},"poll_interval_s":{"type":"integer","title":"Poll Interval S"},"tls_insecure":{"type":"boolean","title":"Tls Insecure"},"config_version":{"type":"integer","title":"Config Version"},"has_password":{"type":"boolean","title":"Has Password","default":false},"has_ssh_key":{"type":"boolean","title":"Has Ssh Key","default":false},"auth_method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Auth Method"},"username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username"}},"type":"object","required":["id","name","vendor","role","gnmi_port","tenant_id","enabled","source","poll_interval_s","tls_insecure","config_version"],"title":"SwitchOut","description":"관리자 응답 — 비밀 필드 없음."},"SwitchPatch":{"properties":{"vendor":{"anyOf":[{"type":"string","enum":["arista","cisco","nvidia","juniper","unknown"]},{"type":"null"}],"title":"Vendor"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role"},"rack_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rack Id"},"pod_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pod Id"},"mgmt_ip":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mgmt Ip"},"gnmi_port":{"anyOf":[{"type":"integer","maximum":65535.0,"minimum":1.0},{"type":"null"}],"title":"Gnmi Port"},"tenant_id":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Tenant Id"},"username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"ssh_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ssh Key"},"auth_method":{"anyOf":[{"type":"string","enum":["password","ssh_key","mtls"]},{"type":"null"}],"title":"Auth Method"},"poll_interval_s":{"anyOf":[{"type":"integer","maximum":600.0,"minimum":5.0},{"type":"null"}],"title":"Poll Interval S"},"tls_insecure":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Tls Insecure"},"enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled"}},"type":"object","title":"SwitchPatch","description":"부분 업데이트 — None 인 필드는 변경하지 않음."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}},"tags":[{"name":"System","description":"Health checks and system status"},{"name":"Monitoring","description":"Cluster overview and real-time port monitoring"},{"name":"Ports","description":"Individual port telemetry and history"},{"name":"Alerts","description":"Risk alerts and top risky ports"},{"name":"Topology","description":"Network topology and failure simulation"},{"name":"Predictions","description":"UFM Cyber-AI failure predictions"},{"name":"Maintenance","description":"Maintenance recommendations, spare parts, windows"},{"name":"RMA","description":"Return Merchandise Authorization tracking"},{"name":"Diagnosis","description":"Auto-diagnosis reports and root cause analysis"},{"name":"Analytics","description":"Trend analysis and long-term patterns"},{"name":"Export","description":"Data export in CSV/JSON format"},{"name":"Observability","description":"Prometheus metrics and OpenTelemetry export"},{"name":"Admin","description":"API key management and RBAC (admin only)"},{"name":"Notifications","description":"Email notification configuration"},{"name":"Inventory","description":"Transceiver inventory and lifecycle management"},{"name":"Demo","description":"Demo scenario triggers (admin only)"},{"name":"Validation","description":"ML model validation results"}]}