detectkit 0.66.0__tar.gz → 0.66.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. {detectkit-0.66.0/detectkit.egg-info → detectkit-0.66.1}/PKG-INFO +1 -1
  2. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/__init__.py +1 -1
  3. detectkit-0.66.1/detectkit/tuning/assets/tune.js +187 -0
  4. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/tuning/payload.py +8 -2
  5. {detectkit-0.66.0 → detectkit-0.66.1/detectkit.egg-info}/PKG-INFO +1 -1
  6. detectkit-0.66.0/detectkit/tuning/assets/tune.js +0 -187
  7. {detectkit-0.66.0 → detectkit-0.66.1}/LICENSE +0 -0
  8. {detectkit-0.66.0 → detectkit-0.66.1}/MANIFEST.in +0 -0
  9. {detectkit-0.66.0 → detectkit-0.66.1}/README.md +0 -0
  10. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/__init__.py +0 -0
  11. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/channels/__init__.py +0 -0
  12. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/channels/base.py +0 -0
  13. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/channels/branding.py +0 -0
  14. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/channels/discord.py +0 -0
  15. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/channels/email.py +0 -0
  16. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/channels/factory.py +0 -0
  17. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/channels/googlechat.py +0 -0
  18. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/channels/mattermost.py +0 -0
  19. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/channels/ntfy.py +0 -0
  20. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/channels/slack.py +0 -0
  21. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/channels/teams.py +0 -0
  22. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/channels/telegram.py +0 -0
  23. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/channels/webhook.py +0 -0
  24. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/orchestrator/__init__.py +0 -0
  25. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/orchestrator/_base.py +0 -0
  26. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/orchestrator/_cooldown.py +0 -0
  27. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/orchestrator/_decision.py +0 -0
  28. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/orchestrator/_dispatch.py +0 -0
  29. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/orchestrator/_recovery.py +0 -0
  30. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/orchestrator/_replay.py +0 -0
  31. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/orchestrator/_types.py +0 -0
  32. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/alerting/orchestrator/orchestrator.py +0 -0
  33. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/__init__.py +0 -0
  34. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/_base.py +0 -0
  35. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/_types.py +0 -0
  36. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/autotuner.py +0 -0
  37. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/axis_spec.py +0 -0
  38. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/config_emitter.py +0 -0
  39. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/crossval.py +0 -0
  40. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/detector_select.py +0 -0
  41. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/distribution.py +0 -0
  42. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/grid_search.py +0 -0
  43. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/labels.py +0 -0
  44. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/result.py +0 -0
  45. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/runner.py +0 -0
  46. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/scoring.py +0 -0
  47. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/seasonality_search.py +0 -0
  48. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/settings.py +0 -0
  49. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/autotune/window_select.py +0 -0
  50. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/__init__.py +0 -0
  51. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/_output.py +0 -0
  52. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/assets/claude/CLAUDE.section.md +0 -0
  53. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/assets/claude/rules/alerting.md +0 -0
  54. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/assets/claude/rules/autotune.md +0 -0
  55. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/assets/claude/rules/cli.md +0 -0
  56. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/assets/claude/rules/detectors.md +0 -0
  57. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/assets/claude/rules/metrics.md +0 -0
  58. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/assets/claude/rules/overview.md +0 -0
  59. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/assets/claude/rules/project.md +0 -0
  60. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/assets/claude/skills/dtk-autotune/SKILL.md +0 -0
  61. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/assets/claude/skills/dtk-feedback/SKILL.md +0 -0
  62. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/assets/claude/skills/dtk-new-metric/SKILL.md +0 -0
  63. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/assets/claude/skills/dtk-setup-project/SKILL.md +0 -0
  64. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/assets/claude/skills/dtk-tune/SKILL.md +0 -0
  65. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/commands/__init__.py +0 -0
  66. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/commands/autotune.py +0 -0
  67. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/commands/clean.py +0 -0
  68. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/commands/init.py +0 -0
  69. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/commands/init_claude.py +0 -0
  70. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/commands/mcp.py +0 -0
  71. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/commands/osi.py +0 -0
  72. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/commands/run.py +0 -0
  73. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/commands/test_alert.py +0 -0
  74. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/commands/tune.py +0 -0
  75. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/commands/ui.py +0 -0
  76. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/commands/unlock.py +0 -0
  77. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/cli/main.py +0 -0
  78. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/config/__init__.py +0 -0
  79. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/config/metric_config.py +0 -0
  80. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/config/metric_io.py +0 -0
  81. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/config/profile.py +0 -0
  82. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/config/project_config.py +0 -0
  83. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/config/validator.py +0 -0
  84. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/core/__init__.py +0 -0
  85. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/core/interval.py +0 -0
  86. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/core/models.py +0 -0
  87. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/__init__.py +0 -0
  88. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/_sql_manager.py +0 -0
  89. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/bigquery_manager.py +0 -0
  90. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/clickhouse_manager.py +0 -0
  91. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/duckdb_manager.py +0 -0
  92. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/internal_tables/__init__.py +0 -0
  93. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/internal_tables/_alert_states.py +0 -0
  94. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/internal_tables/_autotune_runs.py +0 -0
  95. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/internal_tables/_base.py +0 -0
  96. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/internal_tables/_datapoints.py +0 -0
  97. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/internal_tables/_detections.py +0 -0
  98. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/internal_tables/_maintenance.py +0 -0
  99. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/internal_tables/_metrics.py +0 -0
  100. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/internal_tables/_schema.py +0 -0
  101. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/internal_tables/_tasks.py +0 -0
  102. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/internal_tables/manager.py +0 -0
  103. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/manager.py +0 -0
  104. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/mysql_manager.py +0 -0
  105. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/postgres_manager.py +0 -0
  106. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/snowflake_manager.py +0 -0
  107. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/source_manager.py +0 -0
  108. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/database/tables.py +0 -0
  109. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/detectors/__init__.py +0 -0
  110. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/detectors/base.py +0 -0
  111. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/detectors/factory.py +0 -0
  112. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/detectors/seasonality.py +0 -0
  113. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/detectors/statistical/__init__.py +0 -0
  114. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/detectors/statistical/_windowed.py +0 -0
  115. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/detectors/statistical/autoreg.py +0 -0
  116. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/detectors/statistical/iqr.py +0 -0
  117. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/detectors/statistical/mad.py +0 -0
  118. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/detectors/statistical/manual_bounds.py +0 -0
  119. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/detectors/statistical/zscore.py +0 -0
  120. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/loaders/__init__.py +0 -0
  121. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/loaders/errors.py +0 -0
  122. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/loaders/metric_loader.py +0 -0
  123. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/loaders/query_template.py +0 -0
  124. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/mcp/__init__.py +0 -0
  125. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/mcp/context.py +0 -0
  126. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/mcp/errors.py +0 -0
  127. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/mcp/serialize.py +0 -0
  128. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/mcp/server.py +0 -0
  129. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/mcp/tools.py +0 -0
  130. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/orchestration/__init__.py +0 -0
  131. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/orchestration/error_dispatch.py +0 -0
  132. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/orchestration/task_manager/__init__.py +0 -0
  133. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/orchestration/task_manager/_alert_step.py +0 -0
  134. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/orchestration/task_manager/_base.py +0 -0
  135. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/orchestration/task_manager/_detect_step.py +0 -0
  136. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/orchestration/task_manager/_load_step.py +0 -0
  137. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/orchestration/task_manager/_types.py +0 -0
  138. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/orchestration/task_manager/manager.py +0 -0
  139. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/reporting/__init__.py +0 -0
  140. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/reporting/assets/report.js +0 -0
  141. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/reporting/builder.py +0 -0
  142. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/reporting/html_report.py +0 -0
  143. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/semantic/__init__.py +0 -0
  144. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/semantic/errors.py +0 -0
  145. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/semantic/exporter.py +0 -0
  146. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/semantic/importer.py +0 -0
  147. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/semantic/osi_model.py +0 -0
  148. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/semantic/query_gen.py +0 -0
  149. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/tuning/__init__.py +0 -0
  150. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/tuning/config_writer.py +0 -0
  151. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/tuning/html.py +0 -0
  152. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/tuning/server.py +0 -0
  153. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/ui/__init__.py +0 -0
  154. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/ui/assets/ui.js +0 -0
  155. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/ui/html.py +0 -0
  156. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/ui/jobs.py +0 -0
  157. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/ui/metric_files.py +0 -0
  158. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/ui/overview.py +0 -0
  159. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/ui/server.py +0 -0
  160. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/utils/__init__.py +0 -0
  161. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/utils/datetime_utils.py +0 -0
  162. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/utils/env_interpolation.py +0 -0
  163. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/utils/json_utils.py +0 -0
  164. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit/utils/stats.py +0 -0
  165. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit.egg-info/SOURCES.txt +0 -0
  166. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit.egg-info/dependency_links.txt +0 -0
  167. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit.egg-info/entry_points.txt +0 -0
  168. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit.egg-info/requires.txt +0 -0
  169. {detectkit-0.66.0 → detectkit-0.66.1}/detectkit.egg-info/top_level.txt +0 -0
  170. {detectkit-0.66.0 → detectkit-0.66.1}/pyproject.toml +0 -0
  171. {detectkit-0.66.0 → detectkit-0.66.1}/requirements.txt +0 -0
  172. {detectkit-0.66.0 → detectkit-0.66.1}/setup.cfg +0 -0
  173. {detectkit-0.66.0 → detectkit-0.66.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: detectkit
3
- Version: 0.66.0
3
+ Version: 0.66.1
4
4
  Summary: Metric monitoring with automatic anomaly detection
5
5
  Author: detectkit team
6
6
  License: MIT
@@ -4,7 +4,7 @@ detectk - Anomaly Detection for Time-Series Metrics
4
4
  A Python library for data analysts and engineers to monitor metrics with automatic anomaly detection.
5
5
  """
6
6
 
7
- __version__ = "0.66.0"
7
+ __version__ = "0.66.1"
8
8
 
9
9
  from detectkit.core.interval import Interval
10
10
  from detectkit.core.models import ColumnDefinition, TableModel
@@ -0,0 +1,187 @@
1
+ "use strict";(()=>{var Bo={"--term-bg":"#211e1a","--clay":"#d15b36","--st-anomaly":"#d63232","--st-recovery":"#36a64f","--st-nodata":"#f0ad4e","--st-error":"#5a7a8c","--faint":"#9a9384","--muted":"#6e675b","--border":"#332f29","--term-border":"#332f29"};function q(n){return getComputedStyle(document.documentElement).getPropertyValue(n).trim()||Bo[n]||"#888"}function jo(n){let i=n.replace("#","").trim();i.length===3&&(i=i[0]+i[0]+i[1]+i[1]+i[2]+i[2]);let h=parseInt(i,16);return i.length!==6||Number.isNaN(h)?[209,91,54]:[h>>16&255,h>>8&255,h&255]}function F(n,i){let[h,t,v]=jo(n);return`rgba(${h},${t},${v},${i})`}function bo(n){let i=Math.max(1,window.devicePixelRatio||1),h=n.clientWidth||n.offsetWidth||0,t=n.clientHeight||n.offsetHeight||0;return n.width=Math.round(h*i),n.height=Math.round(t*i),i}var Vn=Number.isFinite;function Un(n,i,h,t,v,w,C,g,x,E,A,O){let ae=i.length,Q=Math.max(1,Math.round(C)),U=v-t||1,he=0;for(let X=0;X<ae;X++){let a=h[X];!Vn(a)||i[X]<t||i[X]>v||he++}if(n.strokeStyle=E,n.lineWidth=A*O,n.lineJoin="round",n.beginPath(),he<=Q){let X=!1;for(let a=0;a<ae;a++){let y=h[a],L=i[a];if(!Vn(y)||L<t||L>v){X=!1;continue}let ne=g(L),ye=x(y);X?n.lineTo(ne,ye):(n.moveTo(ne,ye),X=!0)}}else{let X=new Array(Q).fill(null),a=new Array(Q).fill(null);for(let L=0;L<ae;L++){let ne=h[L],ye=i[L];if(!Vn(ne)||ye<t||ye>v)continue;let R=Math.floor((ye-t)/U*(Q-1));R=R<0?0:R>Q-1?Q-1:R,(X[R]===null||ne<X[R])&&(X[R]=ne),(a[R]===null||ne>a[R])&&(a[R]=ne)}let y=!1;for(let L=0;L<Q;L++){if(a[L]===null){y=!1;continue}let ne=w+L,ye=x(a[L]),R=x(X[L]);y?n.lineTo(ne,ye):(n.moveTo(ne,ye),y=!0),n.lineTo(ne,R)}}n.stroke()}function go(n){let i=Math.abs(n);return i>=1e3?n.toFixed(0):i>=10?n.toFixed(1):i>=1?n.toFixed(2):n.toFixed(3)}function vo(n,i){let h=new Date(n).toISOString();return i<2*864e5?h.slice(5,16).replace("T"," "):h.slice(5,10)}function Gn(n,i,h){return{left:i.l*h,top:i.t*h,right:n.width-i.r*h,bottom:n.height-i.b*h}}function yo(n,i,h,t,v,w,C){let g=Gn(i,h,t),x=Math.max(g.left,Math.min(v(w),g.right));x<=g.left+.5||(n.save(),n.fillStyle="rgba(17,15,13,0.42)",n.fillRect(g.left,g.top,x-g.left,g.bottom-g.top),n.strokeStyle=F(q("--faint"),.7),n.lineWidth=1*t,n.setLineDash([4*t,4*t]),n.beginPath(),n.moveTo(x,g.top),n.lineTo(x,g.bottom),n.stroke(),n.setLineDash([]),n.fillStyle=F(q("--faint"),.95),n.font=`${10*t}px ui-monospace, monospace`,n.textAlign="left",n.textBaseline="top",n.fillText(C,x+6*t,g.top+5*t),n.restore())}function wo(n,i,h,t,v){let w=Gn(i,h,t);if(w.right<=w.left||w.bottom<=w.top)return;n.save(),n.fillStyle="rgba(17,15,13,0.42)",n.fillRect(w.left,w.top,w.right-w.left,w.bottom-w.top),n.fillStyle=F(q("--faint"),.95),n.font=`${10*t}px ui-monospace, monospace`,n.textAlign="center",n.textBaseline="middle";let C=w.right-w.left-12*t;C>0&&n.fillText(v,(w.left+w.right)/2,w.top+(w.bottom-w.top)*.3,C),n.restore()}function xo(n,i,h,t,v,w,C){let g=Gn(i,h,t),x=5*t;n.save();for(let E=0;E<w.length;E++){let A=w[E],O=v(A.t);if(O<g.left-1||O>g.right+1)continue;let ae=C(A.kind);n.strokeStyle=F(ae,.45),n.lineWidth=1*t,n.beginPath(),n.moveTo(O,g.top),n.lineTo(O,g.bottom),n.stroke(),n.fillStyle=ae,n.beginPath(),n.moveTo(O-x,g.top),n.lineTo(O+x,g.top),n.lineTo(O,g.top+x*1.4),n.closePath(),n.fill()}n.restore()}var Vo={mad:1,zscore:2,iqr:4};function Uo(n,i){let h=n.seasonalityData;if(!h||h.length===0)return 0;let t=0;for(let v of i){let w=new Set;for(let C of h)w.add(v.map(g=>{var x;return String((x=C==null?void 0:C[g])!=null?x:"")}).join("|"));t=Math.max(t,w.size)}return t}function Go(n,i){var v;if(i.type==="manual_bounds")return i.inputType!=="values"?1:0;if(i.type==="autoreg"){let w=Math.max(1,Math.round((v=i.lags)!=null?v:5)),C=i.windowSize+w;return i.inputType!=="values"&&(C+=1),i.stabilization==="clamp"&&(C+=i.windowSize),C}let h=Math.max(i.minSamples,Vo[i.type]);if(i.smoothing==="sma"&&(h=Math.max(h,i.smoothingWindow-1)),i.smoothing==="ema"&&(h=Math.max(h,Math.ceil(5/i.smoothingAlpha))),i.inputType!=="values"&&(h=Math.max(h,1)),i.seasonalityComponents!==null&&i.seasonalityComponents.length>0&&Array.isArray(n.seasonalityData)&&n.seasonalityData.length>0){let w=Uo(n,i.seasonalityComponents);if(w>0){let C=i.minSamplesPerGroup*w;i.windowSize>=C&&(h=Math.max(h,C))}}return i.stabilization==="clamp"&&(h+=i.windowSize),h}function Pn(n,i){return Math.min(Go(n,i),n.timestamps.length)}var P={l:52,r:14,t:14,b:26},Yn=46,Yo=10,qo=13,_e=Number.isFinite,Dt=1e3,Pt=60*Dt,Lt=60*Pt,Me=24*Lt,qn=[Dt,2*Dt,5*Dt,10*Dt,15*Dt,30*Dt,Pt,2*Pt,5*Pt,10*Pt,15*Pt,30*Pt,Lt,2*Lt,3*Lt,6*Lt,12*Lt,Me,2*Me,3*Me,5*Me,7*Me,14*Me];function ko(n,i,h){let t=Math.max(i-n,1);if(t>h*14*Me){let g=[1,2,3,6,12,24,36,60,120,240],x=g[g.length-1];for(let U of g)if(t/(U*30.44*Me)<=h){x=U;break}let E=new Date(n),A=E.getUTCFullYear(),O=E.getUTCMonth();if(x>=12){let U=x/12;A=Math.floor(A/U)*U,O=0}else O=Math.floor(O/x)*x;let ae=[],Q=Date.UTC(A,O,1);for(;Q<=i;)Q>=n&&ae.push(Q),O+=x,A+=Math.floor(O/12),O%=12,Q=Date.UTC(A,O,1);return{ticks:ae,step:x*30*Me}}let v=qn[qn.length-1];for(let g of qn)if(t/g<=h){v=g;break}let w;if(v%Me===0){let g=new Date(n);w=Date.UTC(g.getUTCFullYear(),g.getUTCMonth(),g.getUTCDate());let x=v/Me,E=Math.round(w/Me);w+=(x-E%x)%x*Me}else w=Math.ceil(n/v)*v;let C=[];for(let g=w;g<=i;g+=v)g>=n&&C.push(g);return{ticks:C,step:v}}function Kn(n,i){let h=new Date(n).toISOString();return i>=320*Me?h.slice(0,4):i>=26*Me?h.slice(0,7):i>=Me?h.slice(5,10):i>=Lt?h.slice(5,16).replace("T"," "):h.slice(5,19).replace("T"," ")}function Mo(n,i={}){var ze;let h=n.getContext("2d");if(!h)throw new Error("chart: 2D context unavailable");let t=h,v=!!i.navigable,w=v&&i.showNavigator!==!1,C=i.yFit==="data",g=!!i.labeling,x=(ze=i.mode)!=null?ze:"tune",E=()=>g?x:"tune",A=()=>E()!=="label",O=()=>E()==="review"?.3:1,ae=()=>E()==="tune"?1:E()==="review"?.3:.85,Q=()=>g&&E()==="label",U=()=>E()==="label"?1:.55,he=()=>E()==="tune",X=()=>g&&(E()==="tune"||E()==="review"),a=1,y=null,L=-1,ne=0,ye=!!i.showZeroLine,R=[],oe=null,z=-1,W=null,Et=!1,be=!1,Fe="above",De=0,Pe=null,We=null,we=null,ge=null,Z=null,Le=!1,K=null,B=0,Y=1,re=0,Be=1,le=0,ue=1,Xt="";function zt(){a=bo(n)}let je=()=>w?(Yo+Yn)*a:0,Ve=()=>n.width-(P.l+P.r)*a,Ue=()=>n.height-(P.t+P.b)*a-je(),Qe=()=>v?le:B,Wt=()=>v?ue:Y,xe=()=>Wt()-Qe()||1,st=()=>Y-B||1,H=o=>P.l*a+(o-Qe())/xe()*Ve(),me=o=>n.height-P.b*a-je()-(o-re)/(Be-re||1)*Ue(),Ge=()=>n.height-Yn*a,Se=()=>(Yn-qo)*a,It=()=>n.width-(P.l+P.r)*a,Re=o=>P.l*a+(o-B)/st()*It(),cn=o=>Ge()+Se()-(o-re)/(Be-re||1)*Se(),Ot=(o,r,c)=>{let l=new Array(o.length).fill(!1);if(o.length===0)return l;let d=t.measureText(Kn(o[0],c)).width+16*a,u=-1/0;for(let f=0;f<o.length;f++){let M=r(o[f]);M-u>=d&&(l[f]=!0,u=M)}return l},ee=(o,r,c)=>Math.max(r,Math.min(c,o)),Ze=()=>{let o=y==null?void 0:y.series,r=o?o.timestamps.length:0,c=r>1?st()/(r-1):1e3;return Math.max(c*8,1e3)};function Ce(o,r){var d;let c=r-o,l=Ze();if(c<l){let u=(o+r)/2;o=u-l/2,r=u+l/2,c=l}c>=st()&&(o=B,r=Y),o<B&&(r+=B-o,o=B),r>Y&&(o-=r-Y,r=Y),le=ee(o,B,Y),ue=ee(r,B,Y),Et||(d=i.onViewChange)==null||d.call(i,le,ue),be&&ve(),j()}function ft(o,r){v&&(Et=!0,Ce(o,r),Et=!1)}let Ye=o=>{let r=(o-P.l*a)/(Ve()||1);return Qe()+ee(r,0,1)*xe()},ht=o=>{let r=(o-P.l*a)/(It()||1);return B+ee(r,0,1)*st()},et=o=>{let r=n.height-P.b*a-je(),c=ee((r-o)/(Ue()||1),0,1);return re+c*(Be-re)};function un(o){let r=y==null?void 0:y.series;if(!r||r.timestamps.length===0)return-1;let c=(o-P.l*a)/(Ve()||1),l=Qe()+c*xe(),d=r.timestamps,u=0,f=d.length-1;for(;u<f;){let M=u+f>>1;d[M]<l?u=M+1:f=M}return u>0&&l-d[u-1]<d[u]-l&&(u-=1),u}function bt(o,r){let c=o.timestamps;if(B=c[0],Y=c[c.length-1],v){let f=`${c.length}:${B}:${Y}`;f!==Xt?(Xt=f,le=B,ue=Y):(le=ee(le,B,Y),ue=ee(Math.max(ue,le+Ze()),B,Y))}let l=1/0,d=-1/0;for(let f of o.values)_e(f)&&(f<l&&(l=f),f>d&&(d=f));if(!C)for(let f of r)f.scored&&(_e(f.lower)&&f.lower<l&&(l=f.lower),_e(f.upper)&&f.upper>d&&(d=f.upper));(!_e(l)||!_e(d))&&(l=0,d=1),ye&&(l>0&&(l=0),d<0&&(d=0)),d<=l&&(d=l+1);let u=(d-l)*.06;re=l-u,Be=d+u}function de(o,r,c){let l=y.series.timestamps;Un(t,l,o,Qe(),Wt(),P.l*a,Ve(),H,me,r,c,a)}function Ht(o,r){let c=[],l=-1;for(let d=Math.max(0,r);d<o.length;d++){let u=o[d];u.scored&&_e(u.lower)&&_e(u.upper)?l===-1&&(l=d):l!==-1&&(c.push([l,d-1]),l=-1)}return l!==-1&&c.push([l,o.length-1]),c}function at(){if(ne=0,!y||n.width===0||n.height===0)return;let{series:o,scored:r,params:c,alerts:l}=y;if(o.timestamps.length===0){t.fillStyle=q("--term-bg"),t.fillRect(0,0,n.width,n.height);return}let d=q("--clay"),u=q("--st-anomaly"),f=q("--faint"),M=q("--muted");t.fillStyle=q("--term-bg"),t.fillRect(0,0,n.width,n.height),t.font=`${11*a}px ui-monospace, 'JetBrains Mono', monospace`,t.textBaseline="middle";for(let S=0;S<=4;S++){let V=re+(Be-re)*S/4,I=me(V);t.strokeStyle=F(f,.1),t.lineWidth=1*a,t.beginPath(),t.moveTo(P.l*a,I),t.lineTo(n.width-P.r*a,I),t.stroke(),t.fillStyle=M,t.textAlign="right",t.fillText(go(V),(P.l-8)*a,I)}if(ye&&re<=0&&Be>=0){let S=me(0);t.strokeStyle=F(M,.6),t.lineWidth=1.25*a,t.beginPath(),t.moveTo(P.l*a,S),t.lineTo(n.width-P.r*a,S),t.stroke(),t.fillStyle=M,t.textAlign="right",t.fillText("0",(P.l-8)*a,S)}t.textBaseline="top";let $=n.height-P.b*a-je();if(v){let S=ko(Qe(),Wt(),7),V=Ot(S.ticks,H,S.step);for(let I=0;I<S.ticks.length;I++){let se=S.ticks[I],ke=H(se);t.strokeStyle=F(f,.1),t.lineWidth=1*a,t.beginPath(),t.moveTo(ke,P.t*a),t.lineTo(ke,$),t.stroke(),V[I]&&(t.fillStyle=M,t.textAlign=ke<(P.l+24)*a?"left":ke>n.width-(P.r+24)*a?"right":"center",t.fillText(Kn(se,S.step),ke,$+7*a))}}else{let S=xe();for(let V=0;V<=5;V++){let I=B+S*V/5,se=H(I);t.fillStyle=M,t.textAlign=V===0?"left":V===5?"right":"center",t.fillText(vo(I,S),se,$+7*a)}}t.save(),t.beginPath(),t.rect(P.l*a,P.t*a,Ve(),Ue()),t.clip(),xt(),ct();let T=r.length,N=Math.min(Pn(o,c),T),G=N<T?o.timestamps[N]:void 0,te=O(),Ae=A()?Ht(r,N):[];t.fillStyle=F(d,.13*te);for(let[S,V]of Ae){t.beginPath(),t.moveTo(H(r[S].timestamp),me(r[S].upper));for(let I=S+1;I<=V;I++)t.lineTo(H(r[I].timestamp),me(r[I].upper));for(let I=V;I>=S;I--)t.lineTo(H(r[I].timestamp),me(r[I].lower));t.closePath(),t.fill()}t.strokeStyle=F(d,.4*te),t.lineWidth=1*a;for(let[S,V]of Ae)for(let I of["upper","lower"]){t.beginPath();for(let se=S;se<=V;se++){let ke=H(r[se].timestamp),Xe=me(r[se][I]);se===S?t.moveTo(ke,Xe):t.lineTo(ke,Xe)}t.stroke()}t.strokeStyle=F(f,.55*te),t.lineWidth=1*a,t.setLineDash([3*a,3*a]);for(let[S,V]of Ae){t.beginPath();for(let I=S;I<=V;I++){let se=r[I].center;if(!_e(se))continue;let ke=H(r[I].timestamp),Xe=me(se);I===S?t.moveTo(ke,Xe):t.lineTo(ke,Xe)}t.stroke()}if(t.setLineDash([]),c.type!=="autoreg"&&c.type!=="manual_bounds"&&c.smoothing!=="none"&&(!g||E()==="tune")){de(o.values,F(d,.28),1.25);let S=r.map(V=>V.processedValue);de(S,d,1.6)}else de(o.values,d,1.5);let ce=ae();for(let S=N;S<T;S++){let V=r[S];if(!V.scored||!_e(V.value))continue;let I=H(V.timestamp),se=me(V.value);V.isAnomaly?(t.fillStyle=F(u,.18*ce),t.beginPath(),t.arc(I,se,6*a,0,Math.PI*2),t.fill(),t.fillStyle=F(u,ce),t.beginPath(),t.arc(I,se,3*a,0,Math.PI*2),t.fill()):o.truthAnomaly[S]&&(t.strokeStyle=F(M,.7),t.lineWidth=1.25*a,t.beginPath(),t.arc(I,se,3.5*a,0,Math.PI*2),t.stroke())}(!g||E()==="tune")&&(T>0&&N>=T?wo(t,n,P,a,"all shown points are detector warm-up \u2014 nothing to score yet"):G!==void 0&&yo(t,n,P,a,H,G,"detection at full power \u2192")),L>=0&&L<r.length&&he()&&lt(L,c.windowSize,r,o,f),l&&l.length&&xo(t,n,P,a,H,l,S=>S==="anomaly"?q("--st-anomaly"):S==="anomaly-validated"?q("--st-recovery"):S==="anomaly-false"?q("--st-error"):S==="recovery"?q("--st-recovery"):q("--st-nodata")),mn(),Jt(r,N,T),t.restore(),w&&tt(o,l,d,f,M)}function tt(o,r,c,l,d){let u=Ge(),f=u+Se(),M=P.l*a,$=n.width-P.r*a,T=ko(B,Y,5);t.save(),t.beginPath(),t.rect(M,u,It(),Se()),t.clip(),t.strokeStyle=F(l,.1),t.lineWidth=1*a;for(let ie of T.ticks){let ce=Re(ie);t.beginPath(),t.moveTo(ce,u),t.lineTo(ce,f),t.stroke()}Un(t,o.timestamps,o.values,B,Y,M,It(),Re,cn,F(c,.7),1.1,a),t.restore();let N=Re(le),G=Re(ue);if(t.fillStyle="rgba(27,25,22,0.55)",t.fillRect(M,u,N-M,Se()),t.fillRect(G,u,$-G,Se()),R.length){let ie=q("--st-anomaly");t.fillStyle=F(ie,.28);for(let ce of R){let S=Re(ce.start),V=Math.max(Re(ce.end)-S,2*a);t.fillRect(S,u,V,Se())}}if(r&&r.length){let ie=q("--st-anomaly");t.fillStyle=F(ie,.85);for(let ce of r){let S=Re(ce.t);t.fillRect(S-1*a,u,2*a,Se())}}t.fillStyle="rgba(245,241,232,0.06)",t.fillRect(N,u,G-N,Se()),t.strokeStyle=c,t.lineWidth=1.5*a,t.strokeRect(N,u+1,G-N,Se()-2),t.fillStyle=c;let te=u+Se()/2-8*a;t.fillRect(N-2*a,te,4*a,16*a),t.fillRect(G-2*a,te,4*a,16*a),t.font=`${10*a}px ui-monospace, monospace`,t.textBaseline="top",t.fillStyle=d;let Ae=Ot(T.ticks,Re,T.step);for(let ie=0;ie<T.ticks.length;ie++){let ce=T.ticks[ie],S=Re(ce);t.strokeStyle=F(l,.25),t.lineWidth=1*a,t.beginPath(),t.moveTo(S,f),t.lineTo(S,f+3*a),t.stroke(),Ae[ie]&&(t.textAlign=S<(P.l+26)*a?"left":S>n.width-(P.r+26)*a?"right":"center",t.fillText(Kn(ce,T.step),S,f+5*a))}}function lt(o,r,c,l,d){let u=l.timestamps,f=Math.max(0,o-r),M=o-1,$=P.t*a,T=Ue();if(M>=f){let te=l.intervalSeconds*1e3/xe()*Ve()*.5,Ae=H(u[f])-te,ie=H(u[M])+te;t.fillStyle="rgba(255,255,255,0.05)",t.fillRect(Ae,$,ie-Ae,T),t.strokeStyle=F(d,.5),t.lineWidth=1*a,t.beginPath(),t.moveTo(Ae,$),t.lineTo(Ae,$+T),t.moveTo(ie,$),t.lineTo(ie,$+T),t.stroke()}let N=H(u[o]);t.strokeStyle=F(d,.85),t.lineWidth=1*a,t.setLineDash([2*a,2*a]),t.beginPath(),t.moveTo(N,$),t.lineTo(N,$+T),t.stroke(),t.setLineDash([]);let G=c[o];if(G.scored&&_e(G.lower)&&_e(G.upper)){let te=5*a;t.strokeStyle=F(q("--clay"),.85),t.lineWidth=1.5*a;for(let Ae of[G.lower,G.upper]){let ie=me(Ae);t.beginPath(),t.moveTo(N-te,ie),t.lineTo(N+te,ie),t.stroke()}}if(_e(G.value)){let te=me(G.value);t.fillStyle=q("--term-bg"),t.beginPath(),t.arc(N,te,4*a,0,Math.PI*2),t.fill(),t.strokeStyle=G.isAnomaly?q("--st-anomaly"):q("--clay"),t.lineWidth=2*a,t.beginPath(),t.arc(N,te,4*a,0,Math.PI*2),t.stroke()}}function gt(o,r,c,l,d){t.beginPath(),t.moveTo(o+d,r),t.arcTo(o+c,r,o+c,r+l,d),t.arcTo(o+c,r+l,o,r+l,d),t.arcTo(o,r+l,o,r,d),t.arcTo(o,r,o+c,r,d),t.closePath()}function dt(o,r){let c=q("--st-anomaly"),l=14*a,d=3*a,u=o-l-d,f=P.t*a+d;t.fillStyle=r?F(c,.95):"rgba(27,25,22,0.82)",t.strokeStyle=F(c,.9),t.lineWidth=1*a,gt(u,f,l,l,3*a),t.fill(),t.stroke(),t.strokeStyle=r?"#fff":c,t.lineWidth=1.5*a;let M=4*a;t.beginPath(),t.moveTo(u+M,f+M),t.lineTo(u+l-M,f+l-M),t.moveTo(u+l-M,f+M),t.lineTo(u+M,f+l-M),t.stroke()}let vt=()=>Pe!=null?Pe:We,yt=()=>{let o=Z||we;return o?[Math.min(o.a,o.b),Math.max(o.a,o.b)]:[Qe(),Wt()]};function wt(){let o=[],r=vt();if(r==null||!y)return o;let c=y.series.timestamps,l=y.series.values,[d,u]=yt(),f=-1,M=-1,$=0;for(let T=0;T<c.length;T++){if(c[T]<d||c[T]>u)continue;let N=l[T];_e(N)&&(Fe==="above"?N>r:N<r)?(f===-1&&(f=c[T]),M=c[T],$=0):f!==-1&&($++,$>De&&(o.push([f,M]),f=-1,$=0))}return f!==-1&&o.push([f,M]),o}function ve(){if(!i.onThresholdChange)return;let[o,r]=yt(),c=Z||we;i.onThresholdChange({value:vt(),locked:Pe!=null,runs:wt().length,window:c?{start:Math.min(c.a,c.b),end:Math.max(c.a,c.b)}:null,committed:we!=null,windowMs:r-o})}function Ne(o,r){let c=null;for(let l=R.length-1;l>=0;l--){let d=R[l];o<=d.end&&r>=d.start&&(c===null?(d.start=Math.min(d.start,o),d.end=Math.max(d.end,r),c=d):(c.start=Math.min(c.start,d.start),c.end=Math.max(c.end,d.end),oe===d&&(oe=c),R.splice(l,1)))}c===null&&R.push({start:o,end:r,label:""})}function xt(){if(!be||vt()==null)return;let r=P.t*a,c=Ue(),l=q("--st-nodata");for(let[d,u]of wt()){let f=H(d),M=Math.max(H(u)-f,2*a);t.fillStyle=F(l,.22),t.fillRect(f,r,M,c),t.strokeStyle=F(l,.6),t.lineWidth=1*a,t.strokeRect(f,r,M,c)}}function mn(){if(!be)return;let o=P.t*a,r=n.height-P.b*a-je(),c=P.l*a,l=n.width-P.r*a,d=q("--st-nodata"),[u,f]=yt(),M=!!(Z||we),$=ee(H(u),c,l),T=ee(H(f),c,l);M&&(t.fillStyle=F(q("--ink"),.5),t.fillRect(c,o,Math.max(0,$-c),Ue()),t.fillRect(T,o,Math.max(0,l-T),Ue()),t.strokeStyle=F(d,.7),t.lineWidth=1*a,t.setLineDash([3*a,3*a]),t.beginPath(),t.moveTo($,o),t.lineTo($,r),t.moveTo(T,o),t.lineTo(T,r),t.stroke(),t.setLineDash([]));let N=vt();if(N!=null&&N>=re&&N<=Be){let G=me(N);t.strokeStyle=d,t.lineWidth=1.5*a,t.setLineDash([6*a,4*a]),t.beginPath(),t.moveTo($,G),t.lineTo(T,G),t.stroke(),t.setLineDash([])}}let nt=()=>y?y.series.intervalSeconds*1e3:1e3;function pn(o,r,c){let l=!1;for(let d=0,u=c.length-1;d<c.length;u=d++){let f=c[d].x,M=c[d].y,$=c[u].x,T=c[u].y;M>r!=T>r&&o<($-f)*(r-M)/(T-M||1e-9)+f&&(l=!l)}return l}function kt(o,r,c){let l=[];if(!K||K.length<3)return l;for(let d=Math.max(0,r);d<c;d++){let u=o[d];!u.scored||!u.isAnomaly||!_e(u.value)||pn(H(u.timestamp),me(u.value),K)&&l.push(d)}return l}function Rn(o,r){var T;if(!r.length)return[];let c=nt(),d=(Math.max(1,(T=y==null?void 0:y.params.consecutiveAnomalies)!=null?T:1)+1)*c,u=c/2,f=[],M=r[0],$=r[0];for(let N=1;N<r.length;N++){let G=r[N];o[G].timestamp-o[$].timestamp>d&&(f.push([o[M].timestamp-u,o[$].timestamp+u]),M=G),$=G}return f.push([o[M].timestamp-u,o[$].timestamp+u]),f}function fn(o,r,c){if(!i.onLassoChange)return;let l=Le&&K?kt(o,r,c):[];i.onLassoChange({active:!!K,anomalies:l.length,incidents:Rn(o,l).length})}function ot(){if(!y||!K)return;let{scored:o}=y,r=o.length,c=Math.min(Pn(y.series,y.params),r),l=Rn(o,kt(o,c,r));for(let[d,u]of l)Ne(d,u);l.length&&Ft()}function Jt(o,r,c){if(!Le||!K||K.length<2)return;let l=q("--clay"),d=q("--st-anomaly");t.beginPath(),t.moveTo(K[0].x,K[0].y);for(let u=1;u<K.length;u++)t.lineTo(K[u].x,K[u].y);t.closePath(),t.fillStyle=F(l,.08),t.fill(),t.strokeStyle=F(l,.9),t.lineWidth=1.5*a,t.setLineDash([5*a,4*a]),t.stroke(),t.setLineDash([]);for(let u of kt(o,r,c)){let f=H(o[u].timestamp),M=me(o[u].value);t.strokeStyle=d,t.lineWidth=2*a,t.beginPath(),t.arc(f,M,7*a,0,Math.PI*2),t.stroke()}}function ct(){let o=P.t*a,r=Ue(),c=q("--st-anomaly"),l=P.l*a,d=n.width-P.r*a,u=Q(),f=U();for(let M=0;M<R.length;M++){let $=R[M],T=H($.start),N=H($.end);if(N<l-1||T>d+1)continue;let G=Math.max(N-T,2*a),te=u&&$===oe;t.fillStyle=F(c,(te?.3:.16)*f),t.fillRect(T,o,G,r),t.strokeStyle=F(c,(te?.95:.5)*f),t.lineWidth=(te?2:1)*a,t.strokeRect(T,o,G,r),u&&(t.fillStyle=F(c,.95),t.fillRect(T-1.5*a,o,3*a,r),t.fillRect(N-1.5*a,o,3*a,r),(N-T>=22*a||te)&&dt(N,te||M===z))}if(u&&W&&W.mode==="new"){let M=H(W.a),$=H(W.b);t.fillStyle=F(q("--st-nodata"),.28),t.fillRect(Math.min(M,$),o,Math.abs($-M),r)}}function Qt(o,r){if(!y||!y.alerts||!y.alerts.length||r>(P.t+22)*a)return-1;let c=-1,l=9*a;for(let d=0;d<y.alerts.length;d++){let u=Math.abs(o-H(y.alerts[d].t));u<=l&&(l=u,c=d)}return c}function Mt(o){var l;if(!y||!y.alerts)return;let r=y.alerts[o].kind,c=r==="anomaly"?"valid":r==="anomaly-validated"?"false":"unreviewed";(l=i.onAlertReviewChange)==null||l.call(i,y.alerts[o].t,c)}function Ft(o){var r;(r=i.onIncidentsChange)==null||r.call(i,R,o)}function hn(o){let r=R.indexOf(o);r<0||(R.splice(r,1),oe===o&&(oe=null),z=-1,Ft(o),j())}function ut(o,r){let c=P.t*a,l=6*a;for(let d=0;d<R.length;d++){let u=H(R[d].end);if(u-H(R[d].start)>=22*a||R[d]===oe){let f=14*a,M=3*a,$=u-f-M,T=c+M;if(o>=$&&o<=$+f&&r>=T&&r<=T+f)return{i:d,edge:"del"}}}for(let d=0;d<R.length;d++){let u=H(R[d].start),f=H(R[d].end);if(Math.abs(o-u)<=l)return{i:d,edge:"a"};if(Math.abs(o-f)<=l)return{i:d,edge:"b"}}for(let d=0;d<R.length;d++){let u=H(R[d].start),f=H(R[d].end);if(o>u+l&&o<f-l)return{i:d,edge:"move"}}return null}let bn=()=>{let o=y==null?void 0:y.series,r=o?o.timestamps.length:0;return r>1?Math.max(st()/(r-1),1):1e3};function j(){ne===0&&(ne=requestAnimationFrame(at))}function J(){if(!y)return;let o=y.scored.length,r=Math.min(Pn(y.series,y.params),o);fn(y.scored,r,o)}function $e(){var c;if(!i.onHover||!y)return;if(L<0){i.onHover(null);return}let o=(c=y.scored[L])!=null?c:null,r={index:L,point:o,windowStart:Math.max(0,L-y.params.windowSize),windowEnd:L-1};i.onHover(r)}let Te=null,pe=null,Oe=o=>{let r=n.getBoundingClientRect();return{x:(o.clientX-r.left)*a,y:(o.clientY-r.top)*a}},St=o=>w&&o>=Ge(),Ee=o=>{let r=Re(le),c=Re(ue),l=8*a;return Math.abs(o-r)<=l?"l":Math.abs(o-c)<=l?"r":o>r&&o<c?"move":"out"};function Ct(o){if(!y)return;let{x:r,y:c}=Oe(o);if(Te||pe||W)return;if(St(c)){L!==-1&&(L=-1,$e(),j());let u=Ee(r);n.style.cursor=u==="l"||u==="r"?"ew-resize":u==="move"?"grab":"pointer";return}let l=E();if(g&&l==="label"&&Le){L!==-1&&(L=-1,$e()),n.style.cursor="crosshair";return}if(g&&l==="label"&&be){L!==-1&&(L=-1,$e()),Pe==null&&!ge&&(We=et(c),ve(),j()),n.style.cursor="crosshair";return}if(g&&l==="label"){L!==-1&&(L=-1,$e());let u=ut(r,c),f=u&&u.edge==="del"?u.i:-1;f!==z&&(z=f,j()),n.style.cursor=u?u.edge==="del"?"pointer":u.edge==="move"?"grab":"ew-resize":"crosshair";return}if(g&&l==="review"){L!==-1&&(L=-1,$e()),n.style.cursor=Qt(r,c)>=0?"pointer":"grab";return}v&&(n.style.cursor=g&&Qt(r,c)>=0?"pointer":"grab");let d=un(r);d!==L&&(L=d,$e(),j())}function qe(){L!==-1&&(L=-1,$e(),j())}function Ke(o){if(!v||!y)return;let{x:r,y:c}=Oe(o);if(w&&c>=Ge()){let l=Ee(r);if(l==="l")pe={type:"l",grab:0,vMin:le,vMax:ue};else if(l==="r")pe={type:"r",grab:0,vMin:le,vMax:ue};else if(l==="move")pe={type:"move",grab:ht(r),vMin:le,vMax:ue};else{let d=ht(r),u=xe();Ce(d-u/2,d+u/2),pe={type:"move",grab:d,vMin:le,vMax:ue}}n.style.cursor="grabbing",o.preventDefault();return}if(c>P.t*a&&c<n.height-P.b*a-je()){let l=E();if(X()){let d=Qt(r,c);if(d>=0){Mt(d),o.preventDefault();return}}if(g&&l==="label"&&Le){K=[{x:r,y:c}],J(),n.style.cursor="crosshair",j(),o.preventDefault();return}if(g&&l==="label"&&be){ge={x:r,ts:Ye(r)},Pe==null&&(We=et(c)),ve(),j(),o.preventDefault();return}if(g&&l==="label"){let d=Ye(r),u=ut(r,c);if(u&&u.edge==="del"){hn(R[u.i]),o.preventDefault();return}if(u&&u.edge==="move"){let f=R[u.i];oe=f,W={mode:"move",iv:f,grab:d,a0:f.start,b0:f.end,moved:!1}}else if(u){let f=R[u.i];oe=f,W={mode:"edge",iv:f,edge:u.edge,moved:!1}}else oe=null,W={mode:"new",a:d,b:d,moved:!1};n.style.cursor="crosshair",j(),o.preventDefault();return}Te={x:r,vMin:le,vMax:ue},n.style.cursor="grabbing",o.preventDefault()}}function Zt(o){if(!y)return;let{x:r,y:c}=Oe(o);if(Le&&K){K.push({x:r,y:c}),J(),j();return}if(be&&ge){Math.abs(r-ge.x)>6*a?Z={a:ge.ts,b:Ye(r)}:(Z=null,Pe==null&&(We=et(c))),ve(),j();return}if(W){let l=Ye(r);if(W.mode==="new")W.b=l,Math.abs(H(W.b)-H(W.a))>4*a&&(W.moved=!0);else if(W.mode==="edge"){let d=W.iv,u=bn();W.edge==="a"?d.start=ee(Math.min(l,d.end-u),B,Y):d.end=ee(Math.max(l,d.start+u),B,Y),W.moved=!0}else{let d=W.iv,u=W.a0+(l-W.grab),f=W.b0+(l-W.grab);u<B&&(f+=B-u,u=B),f>Y&&(u-=f-Y,f=Y),d.start=ee(u,B,Y),d.end=ee(f,B,Y),W.moved=!0}j();return}if(Te){let l=(r-Te.x)*(Te.vMax-Te.vMin)/(Ve()||1);Ce(Te.vMin-l,Te.vMax-l)}else if(pe){let l=ht(r);pe.type==="l"?Ce(Math.min(l,ue-Ze()),ue):pe.type==="r"?Ce(le,Math.max(l,le+Ze())):Ce(pe.vMin+(l-pe.grab),pe.vMax+(l-pe.grab))}}function mt(o){if(Le&&K){ot(),K=null,J(),j();return}if(be&&ge){let{x:r,y:c}=Oe(o);if(Math.abs(r-ge.x)>6*a){let l=ge.ts,d=Ye(r);we={a:Math.min(l,d),b:Math.max(l,d)}}else Pe=et(c);ge=null,Z=null,ve(),j();return}if(W){let r=W;if(r.mode==="new")if(r.moved){let c=ee(Math.min(r.a,r.b),B,Y),l=ee(Math.max(r.a,r.b),B,Y),d={start:c,end:l,label:""};R.push(d),oe=d}else oe=null;else if(r.iv.start>r.iv.end){let c=r.iv.start;r.iv.start=r.iv.end,r.iv.end=c}W=null,n.style.cursor="crosshair",r.moved&&Ft(),j();return}(Te||pe)&&(Te=null,pe=null,n.style.cursor="grab")}function rt(o){let r=o.target,c=!!r&&(r.tagName==="INPUT"||r.tagName==="TEXTAREA"||r.isContentEditable);if(Le){o.key==="Escape"&&K&&(K=null,J(),j());return}be||c||!oe||(o.key==="Delete"||o.key==="Backspace"?(o.preventDefault(),hn(oe)):o.key==="Escape"&&(oe=null,j()))}function Bt(o){if(!v||!y)return;if(Le&&K){o.preventDefault();return}o.preventDefault();let{x:r,y:c}=Oe(o),l=ee(xe()*Math.pow(1.0015,o.deltaY),Ze(),st());if(c>=Ge()){let d=ht(r);Ce(d-l/2,d+l/2)}else{let d=Ye(r),u=(d-le)/(xe()||1);Ce(d-u*l,d-u*l+l)}}function jt(){v&&Ce(B,Y)}n.addEventListener("mousemove",Ct),n.addEventListener("mouseleave",qe),v&&(n.addEventListener("mousedown",Ke),n.addEventListener("wheel",Bt,{passive:!1}),n.addEventListener("dblclick",jt),window.addEventListener("mousemove",Zt),window.addEventListener("mouseup",mt)),g&&(window.addEventListener("keydown",rt),n.style.cursor=x==="tune"?"grab":"crosshair");function Tt(o){y=o,!g&&o.incidents&&(R=o.incidents),bt(o.series,o.scored),L>=o.series.timestamps.length&&(L=-1),j()}function gn(o){ye!==o&&(ye=o,y&&bt(y.series,y.scored),j())}function en(o){R=o,oe=null,z=-1,j()}function Vt(o){g&&(be=o,o?(oe=null,Le=!1,K=null,J()):(We=null,ge=null,Z=null),n.style.cursor="crosshair",ve(),j())}function tn(o){g&&(Le=o,o?(be=!1,ge=null,Z=null,We=null,oe=null,ve()):K=null,n.style.cursor="crosshair",J(),j())}function nn(o){!g||x===o||(x=o,o!=="label"&&(be=!1,ge=null,Z=null,We=null,Le=!1,K=null,oe=null,z=-1,ve(),J()),L=-1,n.style.cursor=o==="tune"?"grab":"crosshair",y&&bt(y.series,y.scored),j())}function Nn(o){Fe=o,ve(),j()}function vn(o){De=Math.max(0,Math.floor(o)||0),ve(),j()}function Ut(o){Pe=o!=null&&_e(o)?o:null,ve(),j()}function Gt(){let o=wt(),r=nt()/2;for(let[c,l]of o)Ne(c-r,l+r);return o.length&&Ft(),ve(),j(),o.length}function on(){we=null,Z=null,ve(),j()}function At(){return we?{start:Math.min(we.a,we.b),end:Math.max(we.a,we.b)}:null}function _t(o){we=o?{a:o.start,b:o.end}:null,ve(),j()}function rn(){zt(),y&&(bt(y.series,y.scored),j())}function sn(){n.removeEventListener("mousemove",Ct),n.removeEventListener("mouseleave",qe),v&&(n.removeEventListener("mousedown",Ke),n.removeEventListener("wheel",Bt),n.removeEventListener("dblclick",jt),window.removeEventListener("mousemove",Zt),window.removeEventListener("mouseup",mt)),g&&window.removeEventListener("keydown",rt),ne!==0&&cancelAnimationFrame(ne),ne=0,y=null}return zt(),{render:Tt,resize:rn,setMode:nn,setZeroLine:gn,setViewWindow:ft,setIncidents:en,setThresholdMode:Vt,setThresholdDirection:Nn,setThresholdGap:vn,setThresholdValue:Ut,applyThreshold:Gt,setLassoMode:tn,clearCaptureWindow:on,getCaptureWindow:At,setCaptureWindow:_t,destroy:sn}}function Ln(n){var h;if(n.type==="manual_bounds"){let t={};return n.lowerBound!=null&&(t.lower_bound=n.lowerBound),n.upperBound!=null&&(t.upper_bound=n.upperBound),n.inputType!=="values"&&(t.input_type=n.inputType),t}if(n.type==="autoreg"){let t=Math.max(1,Math.round((h=n.lags)!=null?h:5)),v={lags:t,threshold:n.threshold,window_size:n.windowSize,min_samples:Math.min(Math.max(n.minSamples,t+2),n.windowSize)};return n.stabilization!=="clamp"&&(v.stabilization=null),n.inputType!=="values"&&(v.input_type=n.inputType),v}let i={threshold:n.threshold,window_size:n.windowSize};return n.windowWeights!=="none"&&(i.window_weights=n.windowWeights,n.windowWeights==="exponential"&&n.halfLife!=null&&(i.half_life=n.halfLife)),n.detrend!=="none"&&(i.detrend=n.detrend),n.stabilization&&n.stabilization!=="none"&&(i.stabilization=n.stabilization),n.smoothing!=="none"&&(i.smoothing=n.smoothing),n.inputType!=="values"&&(i.input_type=n.inputType),n.seasonalityComponents&&n.seasonalityComponents.length&&(i.seasonality_components=n.seasonalityComponents,i.min_samples_per_group=n.minSamplesPerGroup),i}function So(n,i,h,t){let v=Ln(n),w=[`type: ${n.type}`];for(let[C,g]of Object.entries(v))w.push(`${C}=${typeof g=="object"?JSON.stringify(g):g}`);return n.direction&&n.direction!=="any"&&w.push(`direction=${n.direction}`),w.push(`consecutive_anomalies=${i}`),h!=null&&t!=null&&(w.push(`anomaly_window=${h}p`),w.push(`min_anomaly_share=${t}`)),w.join(" \xB7 ")}function m(n,i,h){let t=document.createElement(n);return i&&(t.className=i),h!=null&&(t.textContent=h),t}function $t(n,i){let h=m("label","dtk-ctl-label",n);if(i){h.title=i;let t=m("span","dtk-ctl-info","\u24D8");t.title=i,h.appendChild(document.createTextNode(" ")),h.appendChild(t)}return h}function Rt(n,i,h,t,v){let w=m("div","dtk-ctl");w.appendChild($t(n,v));let C=m("div","dtk-seg"),g=h,x=[],E=()=>{x.forEach(A=>A.classList.toggle("on",A.dataset.v===g))};return i.forEach(A=>{let O=m("button","dtk-seg-btn",A.label);O.type="button",O.dataset.v=A.value,O.onclick=()=>{g=A.value,E(),t(g)},x.push(O),C.appendChild(O)}),E(),w.appendChild(C),{row:w,get:()=>g,set:A=>{g=A,E()}}}function He(n,i,h){var E;let t=m("div","dtk-ctl"),v=m("div","dtk-ctl-head"),w=$t(n,i.hint),C=m("span","dtk-ctl-val"),g=(E=i.fmt)!=null?E:(A=>String(A));v.appendChild(w),v.appendChild(C),t.appendChild(v);let x=m("input","dtk-range");return x.type="range",x.min=String(i.min),x.max=String(i.max),x.step=String(i.step),x.value=String(i.value),C.textContent=g(i.value),x.oninput=()=>{C.textContent=g(Number(x.value))},x.onchange=()=>{let A=Number(x.value);C.textContent=g(A),h(A)},t.appendChild(x),{row:t,get:()=>Number(x.value),set:A=>{x.value=String(A),C.textContent=g(Number(x.value))},setMax:A=>{x.max=String(A),Number(x.value)>A&&(x.value=String(A),C.textContent=g(A))},setMin:A=>{x.min=String(A),Number(x.value)<A&&(x.value=String(A),C.textContent=g(A))}}}function Kt(n){if(!Number.isFinite(n))return"\u2014";let i=Math.abs(n);return i!==0&&(i<.01||i>=1e6)?n.toExponential(2):Number(n.toFixed(i<1?4:2)).toString()}function $n(n){return new Date(n).toISOString().slice(0,16).replace("T"," ")}function Nt(n){let i=Math.round(n/6e4);if(i<60)return`${i}m`;let h=Math.floor(i/60);if(h<24)return`${h}h`;let t=Math.floor(h/24),v=h%24;return v?`${t}d ${v}h`:`${t}d`}function Co(n){return n%86400===0?`${n/86400}d`:n%3600===0?`${n/3600}h`:n%60===0?`${n/60}min`:`${n}s`}function To(n,i){let h=i.tol,t=i.timestamps,v=(t.length?t[0]:0)-h,w=(t.length?t[t.length-1]:0)+h,C=a=>a.end>=v&&a.start<=w,g=(a,y)=>a.end>=y.start-h&&a.start<=y.end+h,x=i.incidents.filter(C),E=i.validatedSpans.filter(C).filter(a=>!x.some(y=>g(a,y))),A=[...x,...E],O=(a,y)=>a[1]>=y.start-h&&a[0]<=y.end+h,ae=0,Q=0,U=0;for(let a of n){let y=i.reviewFor(a[0],a[1]);y&&U++,y==="valid"&&Q++,(y==="valid"||y!=="false"&&A.some(L=>O(a,L)))&&ae++}let he=0;for(let a of A)n.some(y=>O(y,a))&&he++;let X=n.length;return{realIncidents:A.length,caught:he,recall:A.length?he/A.length:NaN,totalAlerts:X,correctAlerts:ae,falseAlerts:X-ae,fdr:X?(X-ae)/X:NaN,validated:Q,reviewed:U}}function Xn(n){return Number.isFinite(n)?`${Math.round(n*100)}%`:"\u2014"}function dn(n,i,h,t,v){return`<span class="dtk-m-chip${v!=null&&v.cls?" "+v.cls:""}"${v!=null&&v.title?` title="${v.title}"`:""}><span class="dtk-m-dot" style="background:${t}"></span><span class="dtk-m-v">${n}</span><span class="dtk-m-l">${i}</span>`+(h?`<span class="dtk-m-sub">${h}</span>`:"")+"</span>"}function Ao(n,i,h){let t=i.realIncidents>0,v=h!=null?`${Math.round(h*100)}%`:"",w=t&&i.totalAlerts>0&&h!=null&&Number.isFinite(i.fdr)&&i.fdr>h,C;if(!t)C="mark incidents to measure";else if(i.totalAlerts===0)C="no alerts";else if(i.falseAlerts===0)C=`${Xn(i.fdr)} \xB7 all correct`;else{let E=i.totalAlerts/i.falseAlerts,A=E>=9.5?String(Math.round(E)):String(Math.round(E*10)/10);C=`${Xn(i.fdr)} \xB7 \u22481 in ${A} false`}w&&(C+=` \xB7 \u25B2 over ${v} budget`);let g=i.totalAlerts===0?"no alerts":`${i.validated} valid${i.totalAlerts>i.reviewed?` \xB7 ${i.totalAlerts-i.reviewed} left`:" \xB7 all reviewed"}`,x=h?`Budget: at most ${v} of fired alerts false (false-alert rate / FDR). Set per metric or project via false_alert_budget. Labeling is optional \u2014 this just flags when you exceed the budget.`:"";n.innerHTML=dn(String(i.realIncidents),"real incidents","","var(--c)")+dn(t?`${i.caught}/${i.realIncidents}`:"\u2014","caught",t?`recall ${Xn(i.recall)}`:"mark or confirm","var(--green)")+dn(String(i.totalAlerts),"alerts","","var(--c)")+dn(t?String(i.falseAlerts):"\u2014","false alerts",C,"var(--anom)",{cls:w?"over":"",title:x})+dn(`${i.reviewed}/${i.totalAlerts}`,"reviewed",g,"var(--green)")}var _o=!1;function Do(){if(_o)return;_o=!0;let n=`
2
+ .dtk-tune{--c:#d15b36;--c7:#b4471f;--ink:#1b1916;--muted:#6e675b;--faint:#9a9384;
3
+ --paper:#f5f1e8;--surface:#fbf9f3;--border:#e6e0d4;--green:#2e9e73;--anom:#d63232;
4
+ --mono:'JetBrains Mono',ui-monospace,Menlo,monospace;
5
+ --sans:'Schibsted Grotesk',system-ui,-apple-system,Segoe UI,Roboto,sans-serif;}
6
+ .dtk-tune-root{max-width:1680px;margin:0 auto;padding:12px 16px;font-family:var(--sans);color:var(--ink);
7
+ height:100dvh;display:flex;flex-direction:column;gap:10px;overflow:hidden;}
8
+ .dtk-tune-header{flex:0 0 auto;}
9
+ .dtk-tune-titlerow{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;}
10
+ .dtk-tune-title{font-size:19px;margin:0;font-weight:700;}
11
+ .dtk-tune-badge{font-family:var(--mono);font-size:10px;text-transform:uppercase;letter-spacing:.06em;
12
+ color:#fff;background:var(--c);border-radius:999px;padding:3px 9px;}
13
+ .dtk-tune-sub{color:var(--muted);font-size:12px;margin-top:2px;font-family:var(--mono);}
14
+ .dtk-tune-desc{color:var(--muted);font-size:12px;margin-top:3px;white-space:pre-wrap;max-height:2.6em;overflow:auto;}
15
+ /* cockpit: chart-windshield (stage) + always-visible mode-aware control rail */
16
+ .dtk-tune-cockpit{display:flex;gap:12px;flex:1;min-height:0;}
17
+ .dtk-tune-stage{position:relative;display:flex;flex-direction:column;gap:8px;flex:1;min-width:0;min-height:0;}
18
+ .dtk-tune-hud{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;flex:0 0 auto;}
19
+ .dtk-tune-stagefoot{flex:0 0 auto;display:flex;flex-direction:column;gap:6px;}
20
+ .dtk-tune-rail{flex:0 0 340px;display:flex;flex-direction:column;min-height:0;background:var(--surface);
21
+ border:1px solid var(--border);border-radius:12px;overflow:hidden;}
22
+ .dtk-tune-railhead{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:8px;
23
+ padding:9px 12px;border-bottom:1px solid var(--border);}
24
+ .dtk-rail-title{font-family:var(--mono);font-size:11px;color:var(--muted);text-transform:uppercase;
25
+ letter-spacing:.06em;flex:1 1 auto;}
26
+ .dtk-tune-railfoot{flex:0 0 auto;display:flex;flex-direction:column;gap:8px;padding:11px 12px;
27
+ border-top:1px solid var(--border);background:var(--paper);}
28
+ .dtk-rail-open{position:absolute;top:50%;right:6px;transform:translateY(-50%);z-index:6;
29
+ border:1px solid var(--border);background:var(--surface);color:var(--ink);border-radius:8px;
30
+ padding:13px 7px;font-size:15px;cursor:pointer;box-shadow:0 1px 6px rgba(27,25,22,.14);}
31
+ .dtk-rail-open:hover{border-color:var(--c);color:var(--c7);}
32
+ .dtk-dock-toggle{flex:0 0 auto;border:1px solid var(--border);background:var(--surface);color:var(--muted);
33
+ border-radius:7px;padding:4px 10px;font-family:var(--sans);font-size:13px;font-weight:700;cursor:pointer;line-height:1;}
34
+ .dtk-dock-toggle:hover{border-color:var(--c);color:var(--c7);}
35
+ .dtk-tune-controls{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:14px;padding:14px;}
36
+ .dtk-rail-group{display:flex;flex-direction:column;gap:14px;}
37
+ .dtk-ctl{display:flex;flex-direction:column;gap:6px;}
38
+ .dtk-ctl-head{display:flex;justify-content:space-between;align-items:baseline;}
39
+ .dtk-ctl-label{font-size:12px;font-weight:600;color:var(--ink);}
40
+ .dtk-ctl-val{font-family:var(--mono);font-size:12px;color:var(--c7);}
41
+ .dtk-seg{display:flex;gap:4px;background:var(--paper);border:1px solid var(--border);border-radius:8px;padding:3px;}
42
+ .dtk-seg.dtk-wrap{flex-wrap:wrap;}
43
+ .dtk-seg-btn{flex:1 1 auto;border:0;background:transparent;color:var(--muted);font-family:var(--sans);
44
+ font-size:12px;padding:5px 8px;border-radius:6px;cursor:pointer;white-space:nowrap;}
45
+ .dtk-seg-btn:hover{color:var(--ink);}
46
+ .dtk-seg-btn.on{background:var(--c);color:#fff;font-weight:600;}
47
+ .dtk-range{width:100%;accent-color:var(--c);cursor:pointer;}
48
+ .dtk-check{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted);margin-top:2px;cursor:pointer;}
49
+ .dtk-tune-chart{position:relative;width:100%;flex:1;min-height:220px;background:var(--surface);
50
+ border:1px solid var(--border);border-radius:12px;overflow:hidden;}
51
+ .dtk-tune-chart canvas{width:100%;height:100%;display:block;}
52
+ .dtk-tune-readout{font-family:var(--mono);font-size:12px;color:var(--muted);min-height:18px;}
53
+ .dtk-tune-stat{font-family:var(--mono);font-size:12px;color:var(--ink);}
54
+ .dtk-tune-warn{font-family:var(--mono);font-size:12px;line-height:1.5;color:var(--c7);
55
+ background:rgba(240,173,78,0.13);border:1px solid rgba(240,173,78,0.5);border-radius:8px;padding:8px 11px;}
56
+ .dtk-tune-cfg{background:var(--ink);color:#c9c2b4;border-radius:8px;padding:8px 11px;font-family:var(--mono);
57
+ font-size:12px;overflow-x:auto;}
58
+ .dtk-tune-cfg-k{display:flex;width:100%;border:0;background:transparent;color:var(--faint);
59
+ font-family:var(--mono);font-size:11.5px;cursor:pointer;padding:0;text-align:left;}
60
+ .dtk-tune-cfg-k:hover{color:#e6e0d4;}
61
+ .dtk-tune-cfg-v{display:block;color:#e6e0d4;white-space:pre-wrap;word-break:break-word;margin-top:6px;}
62
+ .dtk-tune-apply{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
63
+ .dtk-apply-btn{background:var(--c);color:#fff;border:0;border-radius:8px;padding:10px 18px;font-family:var(--sans);
64
+ font-size:14px;font-weight:600;cursor:pointer;}
65
+ .dtk-apply-btn:hover{background:var(--c7);}
66
+ .dtk-apply-btn:disabled{opacity:.55;cursor:default;}
67
+ .dtk-apply-msg{font-size:13px;}
68
+ .dtk-apply-msg.ok{color:var(--green);}
69
+ .dtk-apply-msg.err{color:var(--anom);}
70
+ .dtk-apply-msg.info{color:var(--muted);}
71
+ .dtk-tune-note{font-size:13px;color:var(--muted);background:var(--surface);border:1px dashed var(--border);
72
+ border-radius:8px;padding:10px 12px;}
73
+ .dtk-ctl-info{color:var(--faint);font-size:10px;cursor:help;vertical-align:super;}
74
+ .dtk-tune-trim{display:flex;flex-direction:column;gap:6px;background:var(--surface);
75
+ border:1px solid var(--border);border-radius:10px;padding:9px 12px;}
76
+ .dtk-tune-trim-head{display:flex;justify-content:space-between;align-items:baseline;}
77
+ .dtk-tune-trim-val{font-family:var(--mono);font-size:12px;color:var(--c7);}
78
+ .dtk-tune-spin{position:absolute;top:10px;right:12px;display:none;align-items:center;gap:7px;
79
+ background:rgba(27,25,22,0.78);color:#e6e0d4;border:1px solid #332f29;border-radius:999px;
80
+ padding:4px 11px 4px 8px;font-family:var(--mono);font-size:11px;pointer-events:none;}
81
+ .dtk-tune-spin.on{display:inline-flex;}
82
+ .dtk-spin-ring{width:12px;height:12px;border-radius:50%;border:2px solid rgba(245,241,232,0.25);
83
+ border-top-color:var(--c);animation:dtk-spin .7s linear infinite;}
84
+ @keyframes dtk-spin{to{transform:rotate(360deg);}}
85
+ .dtk-tune-legend{flex:0 0 auto;display:flex;align-items:center;flex-wrap:wrap;gap:8px 16px;font-size:12px;
86
+ color:var(--muted);padding:6px 12px;background:var(--surface);border:1px solid var(--border);border-radius:9px;}
87
+ .dtk-leg-item{display:inline-flex;align-items:center;gap:6px;cursor:help;}
88
+ .dtk-leg-sw{display:inline-block;flex:0 0 auto;}
89
+ .dtk-leg-sw.line{width:16px;height:3px;background:var(--c);border-radius:2px;}
90
+ .dtk-leg-sw.band{width:16px;height:11px;background:rgba(209,91,54,0.18);
91
+ border:1px solid rgba(209,91,54,0.5);border-radius:2px;}
92
+ .dtk-leg-sw.center{width:16px;height:2px;
93
+ background:repeating-linear-gradient(90deg,var(--faint) 0 4px,transparent 4px 7px);}
94
+ .dtk-leg-sw.dot{width:9px;height:9px;border-radius:50%;background:var(--anom);}
95
+ .dtk-leg-sw.alert{width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;
96
+ border-top:7px solid var(--anom);}
97
+ .dtk-leg-sw.alert-ok{width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;
98
+ border-top:7px solid var(--green);}
99
+ .dtk-leg-sw.alert-no{width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;
100
+ border-top:7px solid #5a7a8c;}
101
+ .dtk-leg-txt{white-space:nowrap;}
102
+ .dtk-season-row{display:flex;align-items:center;justify-content:space-between;gap:8px;}
103
+ .dtk-season-col{font-family:var(--mono);font-size:11.5px;color:var(--muted);
104
+ overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
105
+ .dtk-season-seg{flex:0 0 auto;padding:2px;}
106
+ .dtk-season-seg .dtk-seg-btn{flex:0 0 auto;padding:3px 7px;font-family:var(--mono);font-size:11px;}
107
+ .dtk-tune-metrics{display:flex;flex-wrap:wrap;gap:8px;margin:0;flex:0 1 auto;}
108
+ .dtk-m-chip{display:inline-flex;align-items:center;gap:7px;padding:7px 13px;background:var(--surface);
109
+ border:1px solid var(--border);border-radius:10px;font-size:13px;}
110
+ .dtk-m-dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto;}
111
+ .dtk-m-v{font-family:var(--mono);font-weight:700;font-size:15px;color:var(--ink);}
112
+ .dtk-m-l{color:var(--faint);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.05em;}
113
+ .dtk-m-sub{color:var(--muted);font-family:var(--mono);font-size:11.5px;}
114
+ .dtk-m-chip.over{border-color:var(--anom);box-shadow:inset 0 0 0 1px rgba(214,50,50,.5);}
115
+ .dtk-m-chip.over .dtk-m-sub{color:var(--anom);font-weight:600;}
116
+ .dtk-tune-modes{display:inline-flex;gap:4px;background:var(--ink);border-radius:9px;padding:4px;margin:0;flex:0 0 auto;}
117
+ .dtk-mode-btn{border:0;background:transparent;color:#c9c2b4;font-family:var(--sans);font-size:13px;font-weight:600;
118
+ padding:7px 16px;border-radius:6px;cursor:pointer;transition:background .12s,color .12s;}
119
+ .dtk-mode-btn:hover{color:#fff;}
120
+ .dtk-mode-btn.on{background:var(--c);color:#fff;}
121
+ .dtk-tune-reviewbar{align-items:center;}
122
+ .dtk-tune-reviewbar .dtk-apply-btn{background:var(--green);}
123
+ .dtk-tune-reviewbar .dtk-apply-btn:hover{background:#27815d;}
124
+ .dtk-at-result{display:flex;flex-direction:column;gap:7px;background:var(--surface);
125
+ border:1px solid var(--border);border-radius:10px;padding:11px 13px;}
126
+ .dtk-at-head{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:8px;}
127
+ .dtk-at-winner{font-family:var(--mono);font-size:12.5px;font-weight:700;color:var(--ink);}
128
+ .dtk-at-score{font-family:var(--mono);font-size:11.5px;color:var(--c7);}
129
+ .dtk-at-meta{font-family:var(--mono);font-size:11px;color:var(--muted);word-break:break-word;}
130
+ .dtk-at-log{display:flex;flex-direction:column;gap:5px;max-height:240px;overflow:auto;margin-top:4px;}
131
+ .dtk-at-logline{display:flex;gap:8px;align-items:baseline;}
132
+ .dtk-at-stage{flex:0 0 auto;font-family:var(--mono);font-size:9.5px;text-transform:uppercase;
133
+ letter-spacing:.05em;color:#fff;background:var(--c);border-radius:4px;padding:1px 6px;}
134
+ .dtk-at-msg{font-family:var(--mono);font-size:11px;color:var(--ink);}
135
+ .dtk-th{display:flex;flex-direction:column;gap:8px;margin:2px 0 6px;}
136
+ .dtk-th-toggles{display:flex;gap:8px;flex-wrap:wrap;}
137
+ .dtk-th-toggle{align-self:flex-start;border:1px solid var(--border);background:var(--surface);
138
+ color:var(--muted);border-radius:8px;padding:6px 12px;font-family:var(--sans);font-size:12.5px;cursor:pointer;}
139
+ .dtk-th-toggle:hover{border-color:var(--c);color:var(--c7);}
140
+ .dtk-th-toggle.on{background:var(--c);border-color:var(--c);color:#fff;}
141
+ .dtk-th-bar{display:flex;flex-wrap:wrap;align-items:flex-end;gap:10px 14px;padding:11px 13px;
142
+ background:var(--surface);border:1px solid var(--border);border-radius:10px;}
143
+ .dtk-th-grp{display:flex;flex-direction:column;gap:3px;}
144
+ .dtk-th-lbl{font-family:var(--mono);font-size:10.5px;color:var(--faint);text-transform:uppercase;letter-spacing:.05em;}
145
+ .dtk-th-num,.dtk-th-sel{background:var(--paper);color:var(--ink);border:1px solid var(--border);
146
+ border-radius:6px;padding:5px 8px;font-family:var(--mono);font-size:12px;}
147
+ .dtk-th-num{width:96px;}
148
+ .dtk-th-num:focus,.dtk-th-sel:focus{outline:none;border-color:var(--c);}
149
+ .dtk-th-scope{font-family:var(--mono);font-size:11px;color:var(--muted);align-self:center;flex:1 1 160px;}
150
+ .dtk-th-add{padding:7px 14px;}
151
+ .dtk-th-add:disabled{opacity:.5;cursor:default;}
152
+ .dtk-incidents{gap:8px;}
153
+ .dtk-inc-list{display:flex;flex-direction:column;gap:6px;max-height:240px;overflow:auto;}
154
+ .dtk-inc-empty{font-size:12px;color:var(--faint);font-style:italic;}
155
+ .dtk-inc-row{display:flex;align-items:center;gap:6px;flex-wrap:wrap;background:var(--paper);
156
+ border:1px solid var(--border);border-radius:7px;padding:6px 8px;}
157
+ .dtk-inc-span{font-family:var(--mono);font-size:10.5px;color:var(--ink);}
158
+ .dtk-inc-dur{font-family:var(--mono);font-size:10.5px;color:var(--muted);}
159
+ .dtk-inc-label{flex:1 1 90px;min-width:70px;background:var(--surface);color:var(--ink);
160
+ border:1px solid var(--border);border-radius:5px;padding:4px 7px;font-family:var(--sans);font-size:11.5px;}
161
+ .dtk-inc-label:focus{outline:none;border-color:var(--c);}
162
+ .dtk-inc-btn{border:1px solid var(--border);background:var(--surface);color:var(--muted);border-radius:6px;
163
+ padding:3px 8px;font-size:11px;cursor:pointer;font-family:var(--sans);}
164
+ .dtk-inc-btn:hover{border-color:var(--c);color:var(--c7);}
165
+ .dtk-inc-del{color:var(--anom);}
166
+ .dtk-inc-fromalert{border-color:rgba(46,158,115,.5);background:rgba(46,158,115,.08);}
167
+ .dtk-inc-badge{flex:1 1 90px;min-width:70px;font-family:var(--mono);font-size:10.5px;color:var(--green);
168
+ display:inline-flex;align-items:center;font-weight:600;}
169
+ .dtk-setname{background:var(--surface);color:var(--ink);border:1px solid var(--border);border-radius:8px;
170
+ padding:9px 11px;font-family:var(--sans);font-size:13px;min-width:180px;}
171
+ .dtk-setname::placeholder{color:var(--faint);}
172
+ .dtk-setname:focus{outline:none;border-color:var(--c);}
173
+ .dtk-labels-btn{background:var(--surface);color:var(--ink);border:1px solid var(--border);}
174
+ .dtk-labels-btn:hover{background:var(--paper);border-color:var(--c);color:var(--c7);}
175
+ /* Narrow viewports: drop the cockpit to a scrolling stack (chart over rail). */
176
+ @media (max-width:900px){
177
+ .dtk-tune-root{height:auto;overflow:visible;}
178
+ .dtk-tune-cockpit{flex-direction:column;}
179
+ .dtk-tune-rail{flex:0 0 auto;width:100%;}
180
+ .dtk-tune-controls{overflow:visible;}
181
+ .dtk-tune-chart{flex:0 0 auto;height:54vh;min-height:320px;}
182
+ .dtk-rail-open{display:none!important;}
183
+ }
184
+ `,i=document.createElement("style");i.textContent=n,document.head.appendChild(i)}var Po={mad:3,zscore:3,iqr:1.5,autoreg:3},Lo={mad:10,zscore:3,iqr:4},$o={mad:1,zscore:1,iqr:4},Ro="dtk-tune";function No(n){let i=URL.createObjectURL(new Blob([n.src],{type:"text/javascript"})),h=n.series,t,v=0,w=!1,C=null,g=0,x=U=>{let he=U.data;he.type!=="result"||he.id!==v||!C||(w=!1,n.onResult(he,C))},E=()=>{w=!1,n.onError()};function A(){t=new Worker(i),t.onmessage=x,t.onerror=E,t.postMessage({type:"series",series:h})}A();let O=()=>{C=n.getParams(),n.onDispatch(C),v+=1,w&&(t.terminate(),A()),w=!0;let U=n.getShare();t.postMessage({type:"run",id:v,params:C,anomalyWindowPoints:U.windowPoints,minAnomalyShare:U.share})};return{postSeries:U=>{h=U,t.postMessage({type:"series",series:h})},recompute:()=>{g&&window.clearTimeout(g),g=window.setTimeout(O,130)},runNow:O}}function Ko(n,i){var so,ao,lo,co,uo,mo,po,fo,ho;Do(),i.classList.add(Ro),i.innerHTML="";let h=m("div","dtk-tune-root");i.appendChild(h);let t=n.points.length,v={timestamps:n.points.map(e=>e.t),values:n.points.map(e=>e.v==null?NaN:e.v),intervalSeconds:n.interval_seconds,truthAnomaly:new Array(t).fill(!1),seasonalityData:n.seasonality_columns.length?n.seasonality:void 0,seasonalityColumns:n.seasonality_columns.length?n.seasonality_columns:void 0},w=v,C=e=>{let s=Math.max(0,t-e);return s<=0?v:{timestamps:v.timestamps.slice(s),values:v.values.slice(s),intervalSeconds:v.intervalSeconds,truthAnomaly:v.truthAnomaly.slice(s),seasonalityData:v.seasonalityData?v.seasonalityData.slice(s):void 0,seasonalityColumns:v.seasonalityColumns}},g=e=>Date.parse(e.replace(" ","T")+"Z"),x=(n.incidents||[]).map(e=>({start:g(e.start),end:g(e.end),label:e.label||""})).filter(e=>Number.isFinite(e.start)&&Number.isFinite(e.end)).map(e=>({start:Math.min(e.start,e.end),end:Math.max(e.start,e.end),label:e.label})),E=(()=>{let e=(n.capture_windows||[])[0];if(!e)return null;let s=g(e.start),p=g(e.end);return!Number.isFinite(s)||!Number.isFinite(p)?null:{start:Math.min(s,p),end:Math.max(s,p)}})(),A=[],O=[],ae=[],Q=[],U=(n.alert_reviews||[]).map(e=>({start:g(e.start),end:g(e.end),verdict:e.verdict==="false"?"false":"valid"})).filter(e=>Number.isFinite(e.start)&&Number.isFinite(e.end)),he=()=>n.interval_seconds*1e3/2,X=(e,s)=>{let p=he();for(let k of U)if(s>=k.start-p&&e<=k.end+p)return k.verdict;return null},a=(e,s,p)=>{let k=he();for(let D=U.length-1;D>=0;D--){let b=U[D];s>=b.start-k&&e<=b.end+k&&U.splice(D,1)}p&&U.push({start:e,end:s,verdict:p})},y=(e,s)=>{let p=he();return e.end>=s.start-p&&e.start<=s.end+p},L=()=>U.filter(e=>e.verdict==="valid").map(e=>({start:e.start,end:e.end,label:"confirmed alert"})),ne=()=>L().filter(e=>!x.some(s=>y(e,s))),ye=()=>[...x,...ne()],R=e=>{let s=!1;for(let p=U.length-1;p>=0;p--)U[p].verdict==="valid"&&y(U[p],e)&&(U.splice(p,1),s=!0);return s},oe=()=>A.map((e,s)=>{var D;let p=(D=O[s])!=null?D:[e,e],k=X(p[0],p[1]);return{t:e,kind:k==="valid"?"anomaly-validated":k==="false"?"anomaly-false":"anomaly"}}),z=n.detector,W=null,Et=e=>{var s;return(s=Lo[e])!=null?s:10},be=e=>{var s;return(s=$o[e])!=null?s:1},Fe=n.consecutive_anomalies,De=(so=n.anomaly_window_points)!=null?so:0,Pe=(ao=n.min_anomaly_share)!=null?ao:.3,We=()=>De>=2?De:null,we=()=>De>=2?Pe:null,ge=n.detectors||[],Z=typeof n.detector_index=="number"?n.detector_index:null,Le=Z,K=new Set,B=new Map,Y=()=>{Z!=null&&K.add(Z)},re=v.values.filter(e=>Number.isFinite(e)).sort((e,s)=>e-s),Be=re.length?re[0]:0,le=re.length?re[re.length-1]:1,ue=e=>re.length?re[Math.min(re.length-1,Math.max(0,Math.round(e*(re.length-1))))]:0,Xt=Math.max((le-Be)*.05,1e-9),zt=Be-Xt,je=le+Xt,Ve=Math.max((je-zt)/400,1e-9),Ue=z.lowerBound!=null?z.lowerBound:ue(.05),Qe=z.upperBound!=null?z.upperBound:ue(.95),Wt=(lo=z.seasonalityComponents)!=null?lo:[],xe=new Map;Wt.forEach((e,s)=>e.forEach(p=>xe.set(p,s+1)));let st=()=>{let e=0;xe.forEach(p=>{p>e&&(e=p)});let s=[];for(let p=1;p<=e;p++){let k=n.seasonality_columns.filter(D=>xe.get(D)===p);k.length&&s.push(k)}return s.length?s:null},H=e=>{if(!e||!n.seasonality.length)return 0;let s=0;for(let p of e){let k=new Set;for(let D of n.seasonality)k.add(p.map(b=>{var _;return String((_=D==null?void 0:D[b])!=null?_:"")}).join("|"));s=Math.max(s,k.size)}return s},me=()=>{var e;return{type:f.get(),threshold:T.get(),windowSize:ce.get(),minSamples:z.minSamples,inputType:z.inputType,smoothing:yn.get(),smoothingAlpha:z.smoothingAlpha,smoothingWindow:z.smoothingWindow,windowWeights:V.get(),halfLife:V.get()==="exponential"?I.get():null,detrend:Xe.get(),stabilization:an.get(),seasonalityComponents:st(),minSamplesPerGroup:W?Math.round(W.get()):(e=z.minSamplesPerGroup)!=null?e:Et(f.get()),consecutiveAnomalies:Fe,direction:Qn.get(),lowerBound:M.get(),upperBound:$.get(),lags:S.get()}},Ge=m("div","dtk-tune-header"),Se=m("div","dtk-tune-titlerow");Se.appendChild(m("h1","dtk-tune-title",n.metric));let It=m("span","dtk-tune-badge",n.save_url?"manual tuning":"preview");Se.appendChild(It),Ge.appendChild(Se);let Re=n.project?`${n.project} \xB7 `:"";Ge.appendChild(m("div","dtk-tune-sub",`${Re}${t} points \xB7 ${Co(n.interval_seconds)} grid`)),n.description&&Ge.appendChild(m("div","dtk-tune-desc",n.description)),h.appendChild(Ge);let cn=m("div","dtk-tune-metrics"),Ot=m("div","dtk-tune-cockpit");h.appendChild(Ot);let ee=m("div","dtk-tune-stage");Ot.appendChild(ee);let Ze=m("div","dtk-tune-hud");Ze.appendChild(cn),ee.appendChild(Ze);let Ce=m("div","dtk-tune-stagefoot"),ft=m("div","dtk-tune-rail");Ot.appendChild(ft);let Ye=m("div","dtk-tune-railhead"),ht=m("span","dtk-rail-title","Tune \xB7 controls"),et=m("button","dtk-dock-toggle","\u27E9");et.type="button",et.title="Collapse the control rail to give the chart the whole width.",Ye.appendChild(ht),Ye.appendChild(et),ft.appendChild(Ye);let un=m("div","dtk-tune-controls");ft.appendChild(un);let bt=m("div","dtk-rail-group"),de=m("div","dtk-rail-group"),Ht=m("div","dtk-rail-group"),at=m("div","dtk-rail-group"),tt=m("div","dtk-rail-group"),lt=m("div","dtk-rail-group");Ht.style.display="none",at.style.display="none",tt.style.display="none",un.append(bt,de,Ht,at,tt,lt);let gt=m("div","dtk-tune-railfoot");ft.appendChild(gt);let dt=m("button","dtk-rail-open","\u2699");dt.type="button",dt.title="Show the control rail",dt.style.display="none",ee.appendChild(dt);let vt=e=>{ft.style.display=e?"":"none",dt.style.display=e?"none":""};et.onclick=()=>vt(!1),dt.onclick=()=>vt(!0);let yt=m("div","dtk-tune-trim"),wt=m("div","dtk-tune-trim-head");wt.appendChild($t("Points shown","Trim the active sample to the most-recent N points. Fewer points recompute faster (cost grows with points \xD7 window) and make a shorter period easier to read \u2014 handy once you can see a smaller window/period is enough."));let ve=m("span","dtk-tune-trim-val");wt.appendChild(ve),yt.appendChild(wt);let Ne=m("input","dtk-range");Ne.type="range",Ne.min=String(Math.min(t,200)),Ne.max=String(t),Ne.step=String(Math.max(1,Math.round(t/200))),Ne.value=String(t),yt.appendChild(Ne),bt.appendChild(yt);let xt=m("div","dtk-tune-chart"),mn=m("canvas");xt.appendChild(mn);let nt=m("div","dtk-tune-spin");nt.appendChild(m("span","dtk-spin-ring")),nt.appendChild(m("span","dtk-spin-txt","computing\u2026")),xt.appendChild(nt),ee.appendChild(xt),ee.appendChild(Ce);let pn=m("div","dtk-tune-modes"),kt={};[{v:"tune",label:"Tune",hint:"Steer the band \u2014 the confidence corridor leads; incidents recede to read-only context. Hover a point for its window."},{v:"review",label:"Review alerts",hint:"Confirm the fired alerts \u2014 click a marker to cycle un-reviewed \u2192 valid (green) \u2192 false (slate). The band ghosts so the alerts lead."},{v:"label",label:"Label incidents",hint:"Mark real incidents \u2014 drag a span, lasso the anomaly cloud, or threshold-capture. The band hides so incidents lead."},{v:"autotune",label:"Autotune",hint:"Let the autotune engine search for the best detector server-side, using your marked incidents as ground truth, then re-seed the knobs with the winner. Review the band, then Apply."}].forEach(e=>{let s=m("button","dtk-mode-btn",e.label);s.type="button",s.title=e.hint,s.dataset.v=e.v,s.onclick=()=>vn(e.v),kt[e.v]=s,pn.appendChild(s)}),Ze.appendChild(pn);let fn=m("div","dtk-tune-legend"),ot=(e,s,p)=>{let k=m("span","dtk-leg-item");k.title=p,k.appendChild(m("span",`dtk-leg-sw ${e}`)),k.appendChild(m("span","dtk-leg-txt",s)),fn.appendChild(k)};ot("alert","alert","A fired alert, not yet reviewed \u2014 enough consecutive anomalies to meet the rule."),ot("alert-ok","valid alert","An alert you confirmed is real (click a marker in Review mode). Counts toward recall."),ot("alert-no","false alarm","An alert you marked a false positive. Stays in the false-alert rate."),ot("dot","anomaly","A point the detector flagged as anomalous (outside the band)."),ot("line","metric","The metric value over time."),ot("band","expected range","The detector's confidence band \u2014 values inside it read as normal."),ot("center","band center","The expected value at the middle of the band."),ee.insertBefore(fn,xt);let Jt=m("div","dtk-tune-readout");Ce.appendChild(Jt);let ct=m("div","dtk-tune-warn");ct.style.display="none",Ce.appendChild(ct);let Qt=e=>{if(e.type==="autoreg"||e.type==="manual_bounds"){ct.style.display="none";return}let s=e.seasonalityComponents,p=H(s),k=e.minSamplesPerGroup*p;s&&p>0&&e.windowSize<k?(ct.textContent=`\u26A0 Seasonality inactive at this window: ${e.windowSize} < ${k} (min_samples_per_group ${e.minSamplesPerGroup} \xD7 ${p} key${p===1?"":"s"}). Each point keeps only ~${Math.floor(e.windowSize/p)} same-key point(s), so the band falls back to global statistics (seasonality has no effect) \u2014 this, not the smaller window itself, is why the band widened. Raise the window to \u2265 ${k}, or lower \u201CMin samples per group\u201D.`,ct.style.display=""):ct.style.display="none"},Mt=m("div","dtk-tune-warn");Mt.style.display="none",Ce.appendChild(Mt);let Ft=(e,s)=>{var _;let p=w.timestamps.length;if(p===0||e<p){Mt.style.display="none";return}let k=s.stabilization==="clamp",D=s.type==="autoreg"?` (window ${s.windowSize} + lags ${Math.max(1,Math.round((_=s.lags)!=null?_:5))}${s.inputType!=="values"?" + 1 for change input":""}${k?` + window ${s.windowSize} for stabilization`:""})`:k?` (incl. a full window of ${s.windowSize} stabilization warm-up)`:"",b=[];t>e&&b.push(`raise Points shown above ${e}`),(s.type==="autoreg"||k)&&b.push("lower the Window size"),k&&b.push("turn Stabilization off"),s.type!=="autoreg"&&!k&&b.push("reduce min_samples / smoothing / the seasonality grouping (they set this warm-up)"),Mt.textContent=`\u26A0 The whole view is detector warm-up: it needs ${e} pts${D} before full power, but only ${p} are shown \u2014 no band or anomaly dots can be drawn. To see the band: ${b.join(", or ")}.`,Mt.style.display=""},hn=typeof n.false_alert_budget=="number"&&n.false_alert_budget>0?n.false_alert_budget:null;function ut(){let e=To(O,{timestamps:w.timestamps,tol:he(),incidents:x,validatedSpans:L(),reviewFor:X});Ao(cn,e,hn)}let bn=()=>{},j=()=>{},J=Mo(mn,{navigable:!0,labeling:!0,mode:"tune",yFit:"data",onHover:e=>{if(!e||!e.point||!e.point.scored){Jt.textContent="";return}let s=e.point;Jt.textContent=`t=${$n(s.timestamp)} value=${Kt(s.value)} band=[${Kt(s.lower)}, ${Kt(s.upper)}]`+(s.isAnomaly?` \u26A0 ${s.direction} (sev ${s.severity.toFixed(2)})`:"")},onIncidentsChange:(e,s)=>{(s?R(s):!1)?$e():(Sn(),ut())},onThresholdChange:e=>bn(e),onLassoChange:e=>j(e),onAlertReviewChange:(e,s)=>{let p=A.indexOf(e),k=p>=0?O[p]:[e,e];a(k[0],k[1],s==="unreviewed"?null:s),$e()}});J.setIncidents(x),E&&J.setCaptureWindow(E);let $e=()=>{Q=oe(),rn&&J.render({series:w,scored:ae,params:rn,alerts:Q,incidents:x}),ut(),Sn()},Te=m("div","dtk-th"),pe=m("div","dtk-th-toggles"),Oe=m("button","dtk-th-toggle","Threshold capture");Oe.type="button",Oe.title="Mark incidents fast: set a horizontal line and grab every contiguous span above (or below) it. Click the chart to set the line, drag across it to limit the capture to a time window.",pe.appendChild(Oe);let St=m("button","dtk-th-toggle","Lasso anomalies");St.type="button",St.title="Draw a freeform loop around a cloud of anomaly dots on the chart below \u2014 each run of consecutive anomalies (small gaps bridged) becomes one incident span. The ideal way to turn what the detector already flags into ground-truth incidents.",pe.appendChild(St),Te.appendChild(pe);let Ee=m("div","dtk-th-bar"),Ct=m("select","dtk-th-sel");for(let[e,s]of[["above","above the line"],["below","below the line"]]){let p=m("option");p.value=e,p.textContent=s,Ct.appendChild(p)}let qe=m("input","dtk-th-num");qe.type="number",qe.step="any",qe.placeholder="hover chart";let Ke=m("input","dtk-th-num");Ke.type="number",Ke.min="0",Ke.step="1",Ke.value="0";let Zt=m("span","dtk-th-scope"),mt=m("button","dtk-inc-btn","\u21BA whole view");mt.type="button",mt.style.display="none";let rt=m("button","dtk-apply-btn dtk-th-add","Add 0 spans");rt.type="button",rt.disabled=!0;let Bt=m("button","dtk-inc-btn","Done");Bt.type="button";let jt=(e,s)=>{let p=m("label","dtk-th-grp");return p.appendChild(m("span","dtk-th-lbl",e)),p.appendChild(s),p};Ee.appendChild(jt("grab points",Ct)),Ee.appendChild(jt("line value",qe)),Ee.appendChild(jt("bridge gaps \u2264",Ke)),Ee.appendChild(Zt),Ee.appendChild(mt),Ee.appendChild(rt),Ee.appendChild(Bt),Ee.style.display="none",Te.appendChild(Ee);let Tt=m("div","dtk-th-bar"),gn=m("span","dtk-th-scope","draw a loop around the anomaly dots on the chart below"),en=m("button","dtk-inc-btn","Done");en.type="button",Tt.appendChild(gn),Tt.appendChild(en),Tt.style.display="none",Te.appendChild(Tt),at.appendChild(Te);let Vt=m("div","dtk-th-bar dtk-tune-reviewbar");Vt.appendChild(m("span","dtk-th-scope","Click a red alert marker to confirm it valid (green) or mark it a false alarm \u2014 cycle un-reviewed \u2192 valid \u2192 false."));let tn=m("button","dtk-apply-btn dtk-th-add","Confirm all unreviewed valid");tn.type="button",tn.onclick=()=>{for(let[e,s]of O)X(e,s)||a(e,s,"valid");$e()};let nn=m("button","dtk-inc-btn","Clear verdicts");nn.type="button",nn.onclick=()=>{U.length=0,$e()},Vt.appendChild(tn),Vt.appendChild(nn),Ht.appendChild(Vt);let Nn={tune:"Tune \xB7 controls",review:"Review \xB7 verdicts",label:"Label \xB7 incidents",autotune:"Autotune \xB7 search"};function vn(e){J.setMode(e==="autotune"?"tune":e),Object.keys(kt).forEach(s=>{var p;return(p=kt[s])==null?void 0:p.classList.toggle("on",s===e)}),e!=="label"&&(At(!1),_t(!1)),de.style.display=e==="tune"?"":"none",Ht.style.display=e==="review"?"":"none",at.style.display=e==="label"?"":"none",tt.style.display=e==="autotune"?"":"none",gt.style.display=e==="tune"||e==="autotune"?"":"none",ht.textContent=Nn[e]}let Ut=!1,Gt=!1,on=!1,At=e=>{Ut=e,Oe.classList.toggle("on",e),Ee.style.display=e?"flex":"none",J.setThresholdMode(e),e&&Gt&&_t(!1)},_t=e=>{Gt=e,St.classList.toggle("on",e),Tt.style.display=e?"flex":"none",J.setLassoMode(e),e&&Ut&&At(!1)};Oe.onclick=()=>At(!Ut),Bt.onclick=()=>At(!1),St.onclick=()=>_t(!Gt),en.onclick=()=>_t(!1),Ct.onchange=()=>J.setThresholdDirection(Ct.value),qe.oninput=()=>{let e=qe.value.trim();on=!0,J.setThresholdValue(e!==""&&!isNaN(Number(e))?Number(e):null),on=!1},Ke.oninput=()=>J.setThresholdGap(Number(Ke.value)||0),mt.onclick=()=>J.clearCaptureWindow(),rt.onclick=()=>{J.applyThreshold()},window.addEventListener("keydown",e=>{e.key==="Escape"&&(Ut?At(!1):Gt&&_t(!1))}),j=e=>{gn.textContent=e.active?`${e.anomalies} anomal${e.anomalies===1?"y":"ies"} \u2192 ${e.incidents} incident${e.incidents===1?"":"s"} \u2014 release to add`:"draw a loop around the anomaly dots on the chart below"},bn=e=>{rt.textContent=`Add ${e.runs} span${e.runs===1?"":"s"}`,rt.disabled=e.runs===0,e.locked&&e.value!=null&&!on&&(qe.value=String(Math.round(e.value*1e3)/1e3)),mt.style.display=e.committed?"":"none",Zt.textContent=e.window?`scope: ${Nt(e.windowMs)} painted`:"scope: current view \u2014 drag the chart to limit it"};let rn=null,sn=No({src:`"use strict";(()=>{var re={mad:1,zscore:2,iqr:4};function H(n){let e=0;for(let t of n)e+=t;return e}function le(n){let e=n.map((t,i)=>i);return e.sort((t,i)=>n[t]<n[i]?-1:n[t]>n[i]?1:t-i),e}function ce(n,e,t){let i=e.length;if(i===0)return NaN;if(n<=e[0])return t[0];if(n>=e[i-1])return t[i-1];for(let r=1;r<i;r++)if(n<=e[r]){let o=e[r-1],u=e[r],s=t[r-1],l=t[r];if(u===o)return s;let a=(n-o)/(u-o);return s+a*(l-s)}return t[i-1]}function $(n,e,t){let i=le(n),r=i.map(c=>n[c]),o=i.map(c=>e[c]),u=H(o),s=new Array(o.length),l=0;for(let c=0;c<o.length;c++)l+=o[c],s[c]=(l-.5*o[c])/u;let a=t/100;return ce(a,s,r)}function V(n,e){return $(n,e,50)}function ae(n,e,t){let i=t===void 0?V(n,e):t,r=n.map(o=>Math.abs(o-i));return V(r,e)}function fe(n,e){let t=H(e),i=0;for(let r=0;r<n.length;r++)i+=n[r]*(e[r]/t);return i}function me(n,e,t,i=0){let r=H(e),o=e.map(l=>l/r),u=t===void 0?H(n.map((l,a)=>l*o[a])):t,s=0;for(let l=0;l<n.length;l++)s+=o[l]*(n[l]-u)**2;if(i===1){let l=1-H(o.map(a=>a*a));l>1e-12&&(s/=l)}return Math.sqrt(s)}function de(n,e){return e.smoothing==="none"?n.slice():e.smoothing==="ema"?be(n,e.smoothingAlpha):pe(n,e.smoothingWindow)}function be(n,e){let t=n.length,i=new Array(t).fill(NaN);if(t===0)return i;let r=-1;for(let o=0;o<t;o++)if(!Number.isNaN(n[o])){r=o;break}if(r===-1)return i;i[r]=n[r];for(let o=r+1;o<t;o++)Number.isNaN(n[o])?i[o]=i[o-1]:i[o]=e*n[o]+(1-e)*i[o-1];return i}function pe(n,e){let t=n.length,i=new Array(t).fill(NaN);for(let r=0;r<t;r++){let o=Math.max(0,r-e+1),u=0,s=0;for(let l=o;l<=r;l++)Number.isNaN(n[l])||(u+=n[l],s+=1);i[r]=s>0?u/s:NaN}return i}function ee(n,e){let t=n.length;if(e.inputType==="values")return n.slice();let i=new Array(t).fill(NaN);for(let r=1;r<t;r++){let o=n[r-1],u=n[r];e.inputType==="changes"?i[r]=(u-o)/o:e.inputType==="absolute_changes"?i[r]=u-o:i[r]=Math.log(u+1)-Math.log(o+1)}return i}function he(n,e){return n.halfLife!==null?n.halfLife:Math.max(n.windowSize/20,e/2,1)}function ye(n,e){if(n.windowWeights==="none")return null;let t=n.windowSize,i=new Array(t);if(n.windowWeights==="exponential"){let r=he(n,e);for(let o=1;o<=t;o++){let u=Math.min(o/r,1e3);i[o-1]=Math.pow(.5,u)}return i}for(let r=1;r<=t;r++)i[r-1]=(t+1-r)/t;return i}function ne(n,e){return e===null?n.map(()=>1):n.map(t=>e[t-1])}function ge(n){let e=n[0];for(let t of n)t>e&&(e=t);return e}function we(n){let e=n[0];for(let t of n)t<e&&(e=t);return e}function Se(n,e,t){if(n.length<4)return 0;let i=(ge(e)+we(e))/2,r=e.map(y=>y>i),o=r.map(y=>!y),u=0,s=0;for(let y=0;y<e.length;y++)r[y]?u++:s++;if(u<2||s<2)return 0;let l=(y,_)=>_.filter((N,z)=>y[z]),a=l(o,n),c=l(r,n),w=l(o,e),p=l(r,e),v=l(o,t),d=l(r,t),A=V(a,v),f=V(c,d),k=V(w,v),h=V(p,d);return h===k?0:(A-f)/(h-k)}var Me={mad:[["median","center"],["mad","spread"]],zscore:[["mean","center"],["std","spread"]],iqr:[["q1","center"],["q3","center"],["iqr","spread"]]};function te(n,e,t){if(n==="mad"){let o=V(e,t);return{median:o,mad:ae(e,t,o)}}if(n==="zscore"){let o=fe(e,t);return{mean:o,std:me(e,t,o,1)}}let i=$(e,t,25),r=$(e,t,75);return{q1:i,q3:r,iqr:r-i}}function Ae(n,e,t){if(n==="mad"){if(e.mad===0)return[e.median-1e-10,e.median+1e-10];let i=t*1.4826*e.mad;return[e.median-i,e.median+i]}return n==="zscore"?e.std===0?[e.mean-1e-10,e.mean+1e-10]:[e.mean-t*e.std,e.mean+t*e.std]:e.iqr===0?[e.q1-1e-10,e.q3+1e-10]:[e.q1-t*e.iqr,e.q3+t*e.iqr]}function Ne(n,e,t){if(n==="mad"){let i=1.4826*e.mad;return i>0?t/i:1/0}return n==="zscore"?e.std>0?t/e.std:1/0:e.iqr>0?t/e.iqr:1/0}function ke(n,e){return n==="mad"?e.median:n==="zscore"?e.mean:(e.q1+e.q3)/2}function J(n,e,t,i,r){return{index:n,timestamp:e,value:t,processedValue:i,scored:!1,isAnomaly:!1,lower:NaN,upper:NaN,center:NaN,direction:null,severity:0,reason:r}}function xe(n,e){var a,c,w;let{timestamps:t,values:i}=n,r=t.length,o=ee(i,e),u=(a=e.lowerBound)!=null?a:null,s=(c=e.upperBound)!=null?c:null,l=[];for(let p=0;p<r;p++){let v=i[p],d=o[p],A=t[p];if(Number.isNaN(d)){l.push(J(p,A,v,d,"missing_data"));continue}let f=!1,k=null,h=0;u!==null&&d<u&&(f=!0,k="below",h=u-d),s!==null&&d>s&&(f=!0,k="above",h=d-s);let y=0;if(f)if(u!==null&&s!==null){let x=s-u;y=x>0?h/x:1/0}else y=h;let _=u!=null?u:-1/0,N=s!=null?s:1/0,z=u!==null&&s!==null?(u+s)/2:(w=u!=null?u:s)!=null?w:NaN;l.push({index:p,timestamp:A,value:v,processedValue:d,scored:!0,isAnomaly:f,lower:_,upper:N,center:z,direction:k,severity:y,reason:"ok"})}return l}function De(n,e){let t=e.length;for(let r=0;r<t;r++){let o=r;for(let s=r+1;s<t;s++)Math.abs(n[s][r])>Math.abs(n[o][r])&&(o=s);o!==r&&([n[r],n[o]]=[n[o],n[r]],[e[r],e[o]]=[e[o],e[r]]);let u=n[r][r];if(u!==0)for(let s=r+1;s<t;s++){let l=n[s][r]/u;if(l!==0){for(let a=r;a<t;a++)n[s][a]-=l*n[r][a];e[s]-=l*e[r]}}}let i=new Array(t).fill(0);for(let r=t-1;r>=0;r--){let o=e[r];for(let u=r+1;u<t;u++)o-=n[r][u]*i[u];i[r]=n[r][r]!==0?o/n[r][r]:0}return i}function ve(n,e){let t=n[0].length,i=Array.from({length:t},()=>new Array(t).fill(0)),r=new Array(t).fill(0);for(let s=0;s<n.length;s++){let l=n[s];for(let a=0;a<t;a++){r[a]+=l[a]*e[s];for(let c=a;c<t;c++)i[a][c]+=l[a]*l[c]}}for(let s=0;s<t;s++)for(let l=0;l<s;l++)i[s][l]=i[l][s];let o=0;for(let s=0;s<t;s++)o+=i[s][s];let u=1e-8*(o/t);for(let s=0;s<t;s++)i[s][s]+=u;return De(i,r)}function Pe(n,e){var v;let{timestamps:t,values:i}=n,r=t.length,o=Math.max(1,Math.round((v=e.lags)!=null?v:5)),u=e.windowSize,s=e.threshold,l=Math.max(e.minSamples,o+2),a=e.stabilization==="clamp",c=ee(i,e),w=a?c.slice():c,p=[];for(let d=0;d<r;d++){let A=i[d],f=c[d],k=t[d];if(Number.isNaN(f)){p.push(J(d,k,A,f,"missing_data"));continue}let h=d>=o;if(h){for(let m=d-o;m<d;m++)if(!Number.isFinite(w[m])){h=!1;break}}if(!h){p.push(J(d,k,A,f,"missing_lags"));continue}let y=Math.max(o,d-u),_=y-o,N=[],z=[];for(let m=y;m<d;m++){let S=w[m];if(!Number.isFinite(S))continue;let g=!0,D=new Array(o);for(let R=0;R<o;R++){let Y=w[m-o+R];if(!Number.isFinite(Y)){g=!1;break}D[R]=Y}g&&(N.push(S),z.push(D))}let x=N.length;if(x<l){p.push(J(d,k,A,f,"insufficient_data"));continue}let P=H(N)/x,O=0;for(let m of N)O+=(m-P)*(m-P);let T=Math.sqrt(O/x);Number.isFinite(P)||(P=0),(!Number.isFinite(T)||T<=0)&&(T=1);let j=new Array(x),I=new Array(x);for(let m=0;m<x;m++){let S=new Array(o+1);S[0]=1;for(let g=0;g<o;g++)S[g+1]=(z[m][g]-P)/T;j[m]=S,I[m]=(N[m]-P)/T}let Q=ve(j,I),U=0;for(let m=0;m<x;m++){let S=0;for(let D=0;D<=o;D++)S+=j[m][D]*Q[D];let g=I[m]-S;U+=g*g}let C=Math.sqrt(U/Math.max(x-(o+1),1))*T,q=Q[0];for(let m=0;m<o;m++)q+=(w[d-o+m]-P)/T*Q[m+1];let F=q*T+P,W=F-s*C,L=F+s*C,E=f<W||f>L;if(a&&E){let m=f<W?W:L,S=1/0,g=-1/0;for(let D=_;D<d;D++){let R=c[D];Number.isFinite(R)&&(R<S&&(S=R),R>g&&(g=R))}S<=g&&(m=Math.min(Math.max(m,S),g)),w[d]=m}let X=null,b=0;if(E){let m;f<W?(X="below",m=W-f):(X="above",m=f-L),b=C>0?m/C:1/0}p.push({index:d,timestamp:k,value:A,processedValue:f,scored:!0,isAnomaly:E,lower:W,upper:L,center:F,direction:X,severity:b,reason:"ok"})}return p}function oe(n,e){if(e.type==="manual_bounds")return xe(n,e);if(e.type==="autoreg")return Pe(n,e);let t=e.type,i=Math.max(e.minSamples,re[t]),r=Me[t],{timestamps:o,values:u}=n,s=o.length,l=de(u,e),a=ee(l,e),c=e.stabilization==="clamp",w=c?a.slice():a,p=e.seasonalityComponents!==null&&e.seasonalityComponents.length>0&&Array.isArray(n.seasonalityData)&&n.seasonalityData.length>0,v=n.seasonalityData,d=ye(e,i),A=[];for(let f=0;f<s;f++){let k=u[f],h=a[f],y=o[f];if(Number.isNaN(h)){A.push(J(f,y,k,h,"missing_data"));continue}let _=Math.max(0,f-e.windowSize),N=f-_,z=w.slice(_,f),x=z.map(b=>!Number.isNaN(b)),P=[];for(let b=0;b<z.length;b++)x[b]&&P.push(z[b]);if(P.length<i){A.push(J(f,y,k,h,"insufficient_data"));continue}let O=new Array(N);for(let b=0;b<N;b++)O[b]=N-b;let T=[];for(let b=0;b<N;b++)x[b]&&T.push(O[b]);let j=ne(T,d),I=0;e.detrend==="linear"&&(I=Se(P,T,j));let Q=I!==0?P.map((b,m)=>b+I*T[m]):P,U=te(t,Q,j),C={...U};if(p&&v){let b=v[f];for(let m of e.seasonalityComponents){let S=new Array(N).fill(!0);for(let M=0;M<N;M++){let B=v[_+M],G=!0;for(let Z of m)if(!B||B[Z]!==(b==null?void 0:b[Z])){G=!1;break}S[M]=G}let g=[],D=[];for(let M=0;M<N;M++)x[M]&&S[M]&&(g.push(z[M]),D.push(O[M]));if(g.length<e.minSamplesPerGroup)continue;let R=ne(D,d),Y=I!==0?g.map((M,B)=>M+I*D[B]):g,se=te(t,Y,R);for(let[M,B]of r){let G=U[M],ue=(B==="spread"?G>0:G!==0)?se[M]/G:1;C[M]*=ue}}}let[q,F]=Ae(t,C,e.threshold);q>F&&([q,F]=[F,q]);let W=h<q||h>F,L=null,E=0;if(W){let b;h<q?(L="below",b=q-h):(L="above",b=h-F),E=Ne(t,C,b)}c&&W&&(w[f]=h<q?q:F);let X=ke(t,C);A.push({index:f,timestamp:y,value:k,processedValue:h,scored:!0,isAnomaly:W,lower:q,upper:F,center:X,direction:L,severity:E,reason:"ok"})}return A}function Te(n,e){let t=n.seasonalityData;if(!t||t.length===0)return 0;let i=0;for(let r of e){let o=new Set;for(let u of t)o.add(r.map(s=>{var l;return String((l=u==null?void 0:u[s])!=null?l:"")}).join("|"));i=Math.max(i,o.size)}return i}function ie(n,e){var r;if(e.type==="manual_bounds")return e.inputType!=="values"?1:0;if(e.type==="autoreg"){let o=Math.max(1,Math.round((r=e.lags)!=null?r:5)),u=e.windowSize+o;return e.inputType!=="values"&&(u+=1),e.stabilization==="clamp"&&(u+=e.windowSize),u}let t=Math.max(e.minSamples,re[e.type]);if(e.smoothing==="sma"&&(t=Math.max(t,e.smoothingWindow-1)),e.smoothing==="ema"&&(t=Math.max(t,Math.ceil(5/e.smoothingAlpha))),e.inputType!=="values"&&(t=Math.max(t,1)),e.seasonalityComponents!==null&&e.seasonalityComponents.length>0&&Array.isArray(n.seasonalityData)&&n.seasonalityData.length>0){let o=Te(n,e.seasonalityComponents);if(o>0){let u=e.minSamplesPerGroup*o;e.windowSize>=u&&(t=Math.max(t,u))}}return e.stabilization==="clamp"&&(t+=e.windowSize),t}var K=null;function qe(n,e){if(!e||e==="any")return;let t=e==="up"?"above":"below";for(let i of n)i.isAnomaly&&i.direction!==t&&(i.isAnomaly=!1)}function Re(n,e,t){let i=[],r=n.length,o=0;for(;o<r;){if(!(n[o].scored&&n[o].isAnomaly)){o++;continue}let u=o;for(;u+1<r&&n[u+1].scored&&n[u+1].isAnomaly&&n[u+1].timestamp-n[u].timestamp===e;)u++;u-o+1>=t&&i.push({fire:o+t-1,startTs:n[o].timestamp,endTs:n[u].timestamp}),o=u+1}return i}function ze(n,e,t){let i=n.length,r=new Array(i);for(let c=0;c<i;c++)r[c]=n[c].scored&&n[c].isAnomaly;let o=t*e,u=[],s=null,l=-1/0,a=0;for(let c=0;c<i;c++)if(r[c]&&a++,c-e>=0&&r[c-e]&&a--,!(!r[c]||a<o)){if(s&&c-l<=e)s.endTs=n[c].timestamp;else{s&&u.push(s);let w=c;for(let p=Math.max(0,c-e+1);p<=c;p++)if(r[p]){w=p;break}s={fire:c,startTs:n[w].timestamp,endTs:n[c].timestamp}}l=c}return s&&u.push(s),u}function Fe(n,e){let t=new Set(n.map(r=>r.fire)),i=n.slice();for(let r of e)t.has(r.fire)||i.push(r);return i.sort((r,o)=>r.fire-o.fire),i}self.onmessage=n=>{var t,i;let e=n.data;if(e.type==="series"){K=e.series;return}if(e.type==="run"&&K){let r=e.params,o=oe(K,r);qe(o,r.direction);let u=K.intervalSeconds*1e3,s=Re(o,u,r.consecutiveAnomalies),l=(t=e.anomalyWindowPoints)!=null?t:null,a=(i=e.minAnomalyShare)!=null?i:null;l!==null&&a!==null&&l>=2&&a>0&&(s=Fe(s,ze(o,l,a)));let c=s.map(f=>f.fire),w=s.map(f=>[f.startTs,f.endTs]),p=ie(K,r),v=Math.min(p,K.timestamps.length),d=0;for(let f of o)f.scored&&f.isAnomaly&&d++;let A={type:"result",id:e.id,scored:o,fires:c,fireSpans:w,eff:v,need:p,flagged:d};self.postMessage(A)}};})();
185
+ `,series:w,getParams:me,getShare:()=>({windowPoints:We(),share:we()}),onDispatch:e=>{rn=e,Z!=null&&B.set(Z,e),nt.classList.add("on")},onResult:(e,s)=>{nt.classList.remove("on"),ae=e.scored,A=e.fires.map(p=>w.timestamps[p]),O=e.fireSpans,Q=oe(),J.render({series:w,scored:e.scored,params:s,alerts:Q,incidents:x}),ut(),Hn.textContent=`${e.flagged} flagged \xB7 ${e.fires.length} alert${e.fires.length===1?"":"s"} \xB7 warm-up ${e.need} pts`,Qt(s),Ft(e.need,s),Bn.textContent=So(s,Fe,We(),we())},onError:()=>{nt.classList.remove("on"),Hn.textContent="recompute failed \u2014 see the browser console"}}),ze=sn.recompute,o=e=>e>1?Nt(v.timestamps[t-1]-v.timestamps[t-e]):"\u2014",r=e=>{ve.textContent=e>=t?`${t} pts \xB7 full (${o(t)})`:`${e} pts \xB7 ${o(e)}`};r(t);function c(e){w=C(e),sn.postSeries(w),ke(),ze()}Ne.oninput=()=>{r(Number(Ne.value))},Ne.onchange=()=>{c(Number(Ne.value))};let l=()=>{Y(),ke(),ze()},d=ge.filter(e=>e.tunable),u=ge.filter(e=>!e.tunable);if(ge.length>1){let e=m("div","dtk-ctl dtk-tune-detpick");if(e.appendChild($t("Tuning detector","This metric has several detectors. Pick which one to tune here; every other detector is preserved unchanged when you Apply \u2014 so a manual_bounds floor or a min_detectors\u22652 quorum keeps working.")),d.length>1){let p=m("div","dtk-seg dtk-detpick-seg"),k=[],D=()=>k.forEach(b=>b.classList.toggle("on",Number(b.dataset.v)===Z));d.forEach(b=>{let _=m("button","dtk-seg-btn",`#${b.index+1} ${b.type}`);_.type="button",_.dataset.v=String(b.index),_.title=b.summary,_.onclick=()=>{Oo(b.index),D()},k.push(_),p.appendChild(_)}),D(),e.appendChild(p)}let s=[];u.length&&s.push(`Preserved (not tunable here): ${u.map(p=>p.summary).join("; ")}.`),s.push("Apply rewrites only the detector(s) you tune and keeps the rest verbatim."),e.appendChild(m("div","dtk-tune-note",s.join(" "))),de.appendChild(e)}let f=Rt("Detector",[{label:"MAD",value:"mad"},{label:"Z-Score",value:"zscore"},{label:"IQR",value:"iqr"},{label:"Autoreg",value:"autoreg"},{label:"Manual",value:"manual_bounds"}],z.type,e=>{var s;if(te((s=Po[e])!=null?s:3),W){let p=e;W.setMin(be(p)),W.set(Et(p))}Y(),Cn(),ke(),ze()},"The statistic for the band: MAD (robust median, default), Z-Score (mean/std) or IQR (quartiles) \u2014 all windowed \u2014 Autoreg (predicts each point from its previous values and flags dynamics breaks) or Manual (fixed lower/upper thresholds, no window/history).");de.appendChild(f.row);let M=He("Lower bound",{min:zt,max:je,step:Ve,value:Ue,fmt:e=>Kt(e),hint:"Manual bounds: values below this read as anomalous. Drag in from the data range to see how many points fall outside (and how many alerts that yields)."},l);de.appendChild(M.row);let $=He("Upper bound",{min:zt,max:je,step:Ve,value:Qe,fmt:e=>Kt(e),hint:"Manual bounds: values above this read as anomalous."},l);de.appendChild($.row);let T=He("Threshold (\u03C3-equivalent)",{min:.5,max:10,step:.1,value:z.threshold,fmt:e=>e.toFixed(1),hint:"Band half-width in \u03C3-equivalents. Lower = tighter band = more flags; higher = wider band = fewer flags."},l);de.appendChild(T.row);let N=T.row.querySelector("input"),G=T.row.querySelector(".dtk-ctl-val"),te=e=>{N&&(N.value=String(e)),G&&(G.textContent=e.toFixed(1))},Ae=(e,s,p,k,D)=>{let b=Math.floor(2*s/3)-(e==="autoreg"?p+(D?1:0):0),_=Math.floor(e==="autoreg"?b/(k?2:1):s/2);return Math.max(50,Math.min(2e3,_))},ie=Math.max(Ae(z.type,t,Math.max(1,Math.round((co=z.lags)!=null?co:5)),((uo=z.stabilization)!=null?uo:"none")==="clamp",z.inputType!=="values"),z.windowSize),ce=He("Window size (points)",{min:Math.max(1,Math.min(10,z.windowSize)),max:ie,step:1,value:z.windowSize,fmt:e=>`${e} \xB7 ${Nt(e*n.interval_seconds*1e3)}`,hint:"How many trailing points form the baseline window for each scored point. Larger = steadier baseline (more history); smaller = adapts faster to shifts."},l);de.appendChild(ce.row);let S=He("Lags (AR order)",{min:1,max:24,step:1,value:Math.max(1,Math.round((mo=z.lags)!=null?mo:5)),fmt:e=>String(e),hint:"Autoreg: how many immediately-preceding values predict the current one. More lags capture longer short-range patterns but need more history per fit."},l);de.appendChild(S.row);let V=Rt("Recency weighting",[{label:"none",value:"none"},{label:"exponential",value:"exponential"},{label:"linear",value:"linear"}],z.windowWeights,()=>{Y(),Cn(),ze()},"Weight recent points in the window more heavily: none (flat), exponential (half-life decay) or linear. Helps the baseline track a drifting level.");de.appendChild(V.row);let I=He("Half-life (points)",{min:1,max:ie,step:1,value:(po=z.halfLife)!=null?po:Math.max(5,Math.round(z.windowSize/20)),fmt:e=>`${e} \xB7 ${Nt(e*n.interval_seconds*1e3)}`,hint:"Exponential weighting only: the age (in points) at which a point counts half as much as the newest. Smaller = faster decay = fresher baseline."},l),se=I.row;se.style.display=z.windowWeights==="exponential"?"":"none",de.appendChild(se);let ke=()=>{var s;let e=Math.max(Ae(f.get(),w.timestamps.length,Math.max(1,Math.round(S.get())),an.get()==="clamp",z.inputType!=="values"),z.windowSize,ce.get());ce.setMax(e),I.setMax(Math.max(e,(s=z.halfLife)!=null?s:0,I.get()))},Xe=Rt("Detrend",[{label:"none",value:"none"},{label:"linear",value:"linear"}],z.detrend,l,"Remove a robust linear trend from each window before computing the band, so a steadily rising/falling metric is not flagged for the trend itself.");de.appendChild(Xe.row);let an=Rt("Stabilization",[{label:"none",value:"none"},{label:"clamp",value:"clamp"}],(fo=z.stabilization)!=null?fo:"none",l,"Anomaly-robust baseline: flagged points enter later windows clamped to the bound they violated, so a long incident cannot inflate the band and mask itself mid-incident.");de.appendChild(an.row);let yn=Rt("Smoothing",[{label:"none",value:"none"},{label:"EMA",value:"ema"},{label:"SMA",value:"sma"}],z.smoothing,l,"Smooth the series before detection (EMA or SMA) so single-point jitter does not flag. The detector judges the smoothed line; the raw values show as a faint ghost.");de.appendChild(yn.row);let En=null,Jn=()=>{};if(n.seasonality_columns.length){let e=n.seasonality_columns,s=m("div","dtk-ctl");En=s,s.appendChild($t("Seasonality groups","Condition the band on seasonal keys. Pick a group per column: columns in the SAME group are combined into one key (e.g. dow\xD7hour); separate groups each apply their own correction. Off = ignore that column."));let p=e.length,k=[{label:"\u2014",value:"0"}];for(let b=1;b<=p;b++)k.push({label:`G${b}`,value:String(b)});let D=[];e.forEach(b=>{let _=m("div","dtk-season-row");_.appendChild(m("span","dtk-season-col",b));let Ie=m("div","dtk-seg dtk-season-seg"),pt=[],Dn=()=>{var fe;return(fe=xe.get(b))!=null?fe:0},qt=()=>pt.forEach(fe=>fe.classList.toggle("on",Number(fe.dataset.v)===Dn()));D.push(qt),k.forEach(fe=>{let Je=m("button","dtk-seg-btn",fe.label);Je.type="button",Je.dataset.v=fe.value,Je.title=fe.value==="0"?`ignore ${b}`:`put ${b} in group ${fe.value}`,Je.onclick=()=>{xe.set(b,Number(fe.value)),qt(),l()},pt.push(Je),Ie.appendChild(Je)}),qt(),_.appendChild(Ie),s.appendChild(_)}),de.appendChild(s),Jn=b=>{xe.clear(),b.forEach((_,Ie)=>_.forEach(pt=>xe.set(pt,Ie+1))),D.forEach(_=>_())},W=He("Min samples per group",{min:be(z.type),max:Math.max(50,z.minSamplesPerGroup),step:1,value:Math.max(be(z.type),z.minSamplesPerGroup),fmt:b=>String(b),hint:"Per-seasonal-key minimum: a seasonality group only gets its own band once the window holds this many points sharing the current key \u2014 below it the group falls back to the global band (the seasonality has no effect). Lower it to keep seasonality active on a smaller window; raise it for steadier per-key statistics."},l),de.appendChild(W.row)}let Qn=Rt("Direction",[{label:"both",value:"any"},{label:"up",value:"up"},{label:"down",value:"down"}],(ho=n.direction)!=null?ho:"any",ze,"Which anomalies to show and count toward alerts: both directions, only spikes ABOVE the band (up) or only drops BELOW it (down). A preview filter mirroring the alert direction policy \u2014 it never changes the band itself.");lt.appendChild(Qn.row);let Zn=He("Alert: consecutive anomalies",{min:1,max:10,step:1,value:Fe,fmt:e=>String(e),hint:"How many anomalies in a row are required before an alert fires. Higher = fewer, more-confident alerts (the \u25BC markers on the chart)."},e=>{Fe=e,ze()});lt.appendChild(Zn.row);let wn=He("Alert: anomaly window (points)",{min:0,max:Math.max(96,De),step:1,value:De,fmt:e=>e>=2?`${e} \xB7 ${Nt(e*n.interval_seconds*1e3)}`:"off",hint:"Fraction rule (OR-ed with the consecutive rule): also fire when at least the share below of the trailing window is anomalous AND the latest point is anomalous. Set to off (< 2) for the classic consecutive-only alert."},e=>{De=e,Wn(),ze()});lt.appendChild(wn.row);let zn=He("Alert: min share in window",{min:.05,max:1,step:.05,value:Pe,fmt:e=>`${Math.round(e*100)}%`,hint:"Fraction rule: the share of the anomaly window that must be flagged for the alert to fire. Missing points count against the share (an outage never makes it easier)."},e=>{Pe=e,ze()});lt.appendChild(zn.row);let Wn=()=>{zn.row.style.display=De>=2?"":"none"};Wn();let eo=m("div","dtk-ctl"),xn=m("label","dtk-check"),kn=m("input");kn.type="checkbox",kn.onchange=()=>{J.setZeroLine(kn.checked)},xn.title="Draw a horizontal line at y = 0 and include zero in the scale \u2014 for real-valued metrics best read relative to zero.",xn.appendChild(kn),xn.appendChild(document.createTextNode(" Show y = 0 line")),eo.appendChild(xn),lt.appendChild(eo);let In=m("div","dtk-ctl dtk-incidents");In.appendChild($t("Marked incidents","The real incidents you marked (in Label mode). Edit a label, focus to zoom the chart to it, or remove it. Save the set below to incidents/<metric>/ \u2014 the same store dtk autotune reads."));let Mn=m("div","dtk-inc-list");In.appendChild(Mn),at.appendChild(In);function Eo(e){let s=Math.max((e.end-e.start)*.5,n.interval_seconds*1e3*5);J.setViewWindow(e.start-s,e.end+s)}function zo(e){let s=x.indexOf(e);s>=0&&x.splice(s,1);let p=R(e);J.setIncidents(x),p?$e():(Sn(),ut())}function Wo(e){a(e.start,e.end,null),J.setIncidents(x),$e()}function Sn(){Mn.innerHTML="";let e=[...x.map(s=>({iv:s,kind:"manual"})),...ne().map(s=>({iv:s,kind:"alert"}))].sort((s,p)=>s.iv.start-p.iv.start);if(!e.length){Mn.appendChild(m("div","dtk-inc-empty","None yet \u2014 switch to Label mode and drag across the chart, or confirm alerts in Review mode."));return}for(let{iv:s,kind:p}of e){let k=m("div","dtk-inc-row"+(p==="alert"?" dtk-inc-fromalert":""));if(k.appendChild(m("span","dtk-inc-span",`${$n(s.start)} \u2192 ${$n(s.end)}`)),k.appendChild(m("span","dtk-inc-dur",Nt(Math.max(0,s.end-s.start)))),p==="alert"){let _=m("span","dtk-inc-badge","\u2713 confirmed alert");_.title="A fired alert you confirmed valid (in Review mode). It counts as a real incident \u2014 remove it here to un-confirm the alert.",k.appendChild(_)}else{let _=m("input","dtk-inc-label");_.type="text",_.value=s.label||"",_.placeholder="label (optional)",_.oninput=()=>{s.label=_.value},k.appendChild(_)}let D=m("button","dtk-inc-btn","focus");D.type="button",D.onclick=()=>Eo(s),k.appendChild(D);let b=m("button","dtk-inc-btn dtk-inc-del","\u2715");b.type="button",b.title=p==="alert"?"un-confirm this alert":"remove this incident",b.onclick=()=>p==="alert"?Wo(s):zo(s),k.appendChild(b),Mn.appendChild(k)}}let Io=[T.row,ce.row,an.row],On=[V.row,Xe.row,yn.row];En&&On.push(En),W&&On.push(W.row);function Cn(){let e=f.get(),s=e==="manual_bounds",p=e==="autoreg";for(let k of Io)k.style.display=s?"none":"";for(let k of On)k.style.display=s||p?"none":"";S.row.style.display=p?"":"none",M.row.style.display=s?"":"none",$.row.style.display=s?"":"none",se.style.display=!s&&!p&&V.get()==="exponential"?"":"none"}Cn();function to(e){var s,p;z=e,f.set(e.type),T.set(e.threshold),ke(),ce.set(e.windowSize),V.set(e.windowWeights),e.windowWeights==="exponential"&&e.halfLife!=null&&I.set(e.halfLife),Xe.set(e.detrend),an.set((s=e.stabilization)!=null?s:"none"),yn.set(e.smoothing),Jn(e.seasonalityComponents||[]),W&&(W.setMin(be(e.type)),W.setMax(Math.max(50,e.minSamplesPerGroup,W.get())),W.set(Math.max(be(e.type),e.minSamplesPerGroup))),e.lowerBound!=null&&M.set(e.lowerBound),e.upperBound!=null&&$.set(e.upperBound),(e.lags!=null||e.type==="autoreg")&&S.set(Math.max(1,Math.round((p=e.lags)!=null?p:5))),Cn()}function Oo(e){var p;if(e===Z)return;let s=ge.find(k=>k.index===e);!s||!s.tunable||!s.seed||(Z!=null&&B.set(Z,me()),Z=e,to((p=B.get(e))!=null?p:s.seed),ze())}let Hn=m("div","dtk-tune-stat");Ce.appendChild(Hn);let Fn=m("div","dtk-tune-cfg"),ln=m("button","dtk-tune-cfg-k");ln.type="button",ln.title="Show or hide the exact config that will be written on Apply.";let Bn=m("code","dtk-tune-cfg-v"),no=!1,oo=e=>{no=e,Bn.style.display=e?"":"none",ln.textContent=`${e?"\u25BE":"\u25B8"} // effective config`};if(ln.onclick=()=>oo(!no),Fn.appendChild(ln),Fn.appendChild(Bn),oo(!1),gt.appendChild(Fn),n.save_url){let e=m("div","dtk-tune-apply"),s=m("button","dtk-apply-btn","Apply to metric");s.type="button",s.title="Write this detector config back into the metric YAML (the previous version is archived under metrics/.history/). Trimming the sample does not change what is written.";let p=m("span","dtk-apply-msg");s.onclick=()=>{let k=me();Z!=null&&B.set(Z,k);let D=[];if(Le!=null)for(let b of new Set([Le,...K])){let _=B.get(b);_&&D.push({index:b,type:_.type,params:Ln(_)})}else D.push({index:null,type:k.type,params:Ln(k)});s.disabled=!0,p.className="dtk-apply-msg info",p.textContent="Applying\u2026",fetch(n.save_url,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({detectors:D,consecutive_anomalies:Fe,anomaly_window:We()?`${We()*n.interval_seconds}s`:null,min_anomaly_share:we()})}).then(b=>b.ok?b.json():b.text().then(_=>{throw new Error(_||`HTTP ${b.status}`)})).then(b=>{var Ie;p.className="dtk-apply-msg ok";let _=b.preserved&&b.preserved.length?` Kept: ${b.preserved.join(", ")}.`:"";p.textContent=`Applied \u2192 ${(Ie=b.saved)!=null?Ie:"metric"} (previous archived).${_} You can close this tab.`}).catch(b=>{s.disabled=!1,p.className="dtk-apply-msg err",p.textContent=`Apply failed: ${b.message}`})},e.appendChild(s),e.appendChild(p),gt.appendChild(e)}else gt.appendChild(m("div","dtk-tune-note","Static preview \u2014 sliders recompute live, but there is no write-back. Run `dtk tune` (without --no-serve) to apply a config."));let Ho=e=>'"'+e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')+'"',Yt=e=>new Date(e).toISOString().slice(0,19).replace("T"," "),ro=()=>{let e=[`metric: ${n.metric}`,"timezone: UTC"],s=new Set,p=ye().sort((D,b)=>D.start-b.start).filter(D=>{let b=`${Math.round(D.start)}:${Math.round(D.end)}`;return s.has(b)?!1:(s.add(b),!0)});if(!p.length)e.push("incidents: []");else{e.push("incidents:");for(let D of p){let b=D.label?`, label: ${Ho(D.label)}`:"";e.push(` - {start: "${Yt(D.start)}", end: "${Yt(D.end)}"${b}}`)}}let k=J.getCaptureWindow();if(k&&(e.push("capture_windows:"),e.push(` - {start: "${Yt(k.start)}", end: "${Yt(k.end)}"}`)),U.length){e.push("alert_reviews:");for(let D of[...U].sort((b,_)=>b.start-_.start))e.push(` - {start: "${Yt(D.start)}", end: "${Yt(D.end)}", verdict: ${D.verdict}}`)}return e.join(`
186
+ `)+`
187
+ `},Tn=m("div","dtk-tune-apply"),An=m("input","dtk-setname");An.type="text",An.placeholder="name this set (optional)";let _n=m("button","dtk-apply-btn dtk-labels-btn",n.labels_save_url?"Save incidents":"Download incidents");_n.type="button",_n.title="Write the marked incidents to incidents/<metric>/ (versioned) so they also feed the next `dtk autotune`. Saving labels does not end tuning \u2014 keep adjusting and apply the detector when ready.";let it=m("span","dtk-apply-msg");_n.onclick=()=>{let e=ro();if(!n.labels_save_url){let s=new Blob([e],{type:"text/yaml"}),p=m("a");p.href=URL.createObjectURL(s),p.download=`${n.metric}.yml`,p.click(),URL.revokeObjectURL(p.href),it.className="dtk-apply-msg ok",it.textContent=`Downloaded \u2014 drop it into incidents/${n.metric}/`;return}it.className="dtk-apply-msg info",it.textContent="Saving\u2026",fetch(n.labels_save_url,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:An.value,yaml:e})}).then(s=>s.ok?s.json():s.text().then(p=>{throw new Error(p||`HTTP ${s.status}`)})).then(s=>{var p;it.className="dtk-apply-msg ok",it.textContent=`Saved \u2192 ${(p=s.saved)!=null?p:"incidents"} (keep tuning, or Apply the detector)`}).catch(s=>{it.className="dtk-apply-msg err",it.textContent=`Save failed: ${s.message}`})},Tn.appendChild(An),Tn.appendChild(_n),Tn.appendChild(it),at.appendChild(Tn);function Fo(e){to(e.detector),Y(),e.consecutive_anomalies!=null&&(Fe=e.consecutive_anomalies,Zn.set(Fe)),e.anomaly_window_points!=null&&e.min_anomaly_share!=null?(De=e.anomaly_window_points,Pe=e.min_anomaly_share,wn.setMax(Math.max(96,De)),wn.set(De),zn.set(Pe)):(De=0,wn.set(0)),Wn(),ze()}if(tt.appendChild(m("div","dtk-tune-note","Run the full autotune engine server-side over the window shown (the \u2018Points shown\u2019 trim \u2014 the same series you see and score here), using the incidents you\u2019ve marked (and confirmed alerts) as ground truth. It re-seeds the knobs with the winning detector \u2014 review the band, then Apply (here or in Tune). Nothing is written until you Apply; the next `dtk run` is the source of truth.")),n.autotune_url){let e=m("div","dtk-tune-apply"),s=m("button","dtk-apply-btn","Run autotune");s.type="button",s.title="Search for the best detector over the window shown (the \u2018Points shown\u2019 trim). Uses your marked incidents as ground truth when present (supervised), else an unsupervised objective. Can take a few seconds on a long window.";let p=m("span","dtk-apply-msg");e.appendChild(s),e.appendChild(p),tt.appendChild(e);let k=m("div","dtk-at-result");k.style.display="none",tt.appendChild(k);let D=b=>{k.innerHTML="",k.style.display="";let _=m("div","dtk-at-head");_.appendChild(m("span","dtk-at-winner",b.winner)),_.appendChild(m("span","dtk-at-score",`${b.scoring_metric} ${Number.isFinite(b.score)?b.score.toFixed(3):"\u2014"} \xB7 ${b.mode}`)),k.appendChild(_),k.appendChild(m("div","dtk-at-meta",`${b.n_candidates} candidate${b.n_candidates===1?"":"s"} \xB7 ${b.n_points} pts`+(b.consecutive_anomalies!=null?` \xB7 consecutive ${b.consecutive_anomalies}`:"")+(b.anomaly_window_points!=null&&b.min_anomaly_share!=null?` \xB7 window ${b.anomaly_window_points}p \xD7 ${b.min_anomaly_share}`:"")+(b.seasonality&&b.seasonality.length?` \xB7 seasonality ${JSON.stringify(b.seasonality)}`:" \xB7 no seasonality")));let Ie=m("button","dtk-tune-cfg-k");Ie.type="button";let pt=m("div","dtk-at-log"),Dn=!1,qt=fe=>{Dn=fe,pt.style.display=fe?"":"none",Ie.textContent=`${fe?"\u25BE":"\u25B8"} decision log (${b.decision_log.length})`};Ie.onclick=()=>qt(!Dn);for(let fe of b.decision_log){let Je=m("div","dtk-at-logline");Je.appendChild(m("span","dtk-at-stage",fe.stage)),Je.appendChild(m("span","dtk-at-msg",fe.message)),pt.appendChild(Je)}qt(!1),k.appendChild(Ie),k.appendChild(pt)};s.onclick=()=>{s.disabled=!0,p.className="dtk-apply-msg info",p.textContent="Autotuning over the shown window\u2026 this can take a moment.",fetch(n.autotune_url,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({yaml:ro(),window:w.timestamps.length?{start:w.timestamps[0],end:w.timestamps[w.timestamps.length-1]}:null})}).then(b=>b.ok?b.json():b.text().then(_=>{throw new Error(_||`HTTP ${b.status}`)})).then(b=>{s.disabled=!1,Fo(b),D(b);let _=b.mode==="supervised"?" \u2014 supervised by your incidents":" \u2014 unsupervised (mark incidents for a supervised tune)";p.className="dtk-apply-msg ok",p.textContent=`Tuned${_}. Knobs updated; review the band, then Apply.`}).catch(b=>{s.disabled=!1,p.className="dtk-apply-msg err",p.textContent=`Autotune failed: ${b.message}`})}}else tt.appendChild(m("div","dtk-tune-note","Autotune needs the live server \u2014 run `dtk tune` without --no-serve."));vn("tune"),Sn(),sn.runNow(),ut();let jn=0,io=()=>{jn&&cancelAnimationFrame(jn),jn=requestAnimationFrame(()=>J.resize())};typeof ResizeObserver!="undefined"?new ResizeObserver(io).observe(xt):window.addEventListener("resize",io)}window.__DTK_TUNE__={render:Ko};})();
@@ -154,8 +154,14 @@ def seed_detector_params(dtype: str, params: dict[str, Any]) -> dict[str, Any]:
154
154
  ),
155
155
  "detrend": params.get("detrend") or "none",
156
156
  "stabilization": params.get("stabilization") or "none",
157
- "seasonalityComponents": _normalize_seasonality_components(
158
- params.get("seasonality_components")
157
+ # Seasonality is a windowed-detector concept (autoreg v1 rejects it;
158
+ # manual_bounds ignores it) — a stray key in a hand-edited config must
159
+ # not seed the cockpit's shared group selector through a detector that
160
+ # can never consume it.
161
+ "seasonalityComponents": (
162
+ _normalize_seasonality_components(params.get("seasonality_components"))
163
+ if dtype in _WINDOWED_TYPES
164
+ else None
159
165
  ),
160
166
  "minSamplesPerGroup": params.get(
161
167
  "min_samples_per_group", _MIN_SAMPLES_PER_GROUP_DEFAULT.get(dtype, 10)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: detectkit
3
- Version: 0.66.0
3
+ Version: 0.66.1
4
4
  Summary: Metric monitoring with automatic anomaly detection
5
5
  Author: detectkit team
6
6
  License: MIT