detectkit 0.36.0__tar.gz → 0.36.2__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 (138) hide show
  1. {detectkit-0.36.0/detectkit.egg-info → detectkit-0.36.2}/PKG-INFO +1 -1
  2. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/__init__.py +1 -1
  3. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/assets/claude/rules/cli.md +4 -2
  4. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/tuning/payload.py +48 -35
  5. {detectkit-0.36.0 → detectkit-0.36.2/detectkit.egg-info}/PKG-INFO +1 -1
  6. {detectkit-0.36.0 → detectkit-0.36.2}/LICENSE +0 -0
  7. {detectkit-0.36.0 → detectkit-0.36.2}/MANIFEST.in +0 -0
  8. {detectkit-0.36.0 → detectkit-0.36.2}/README.md +0 -0
  9. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/__init__.py +0 -0
  10. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/channels/__init__.py +0 -0
  11. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/channels/base.py +0 -0
  12. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/channels/branding.py +0 -0
  13. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/channels/email.py +0 -0
  14. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/channels/factory.py +0 -0
  15. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/channels/mattermost.py +0 -0
  16. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/channels/slack.py +0 -0
  17. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/channels/telegram.py +0 -0
  18. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/channels/webhook.py +0 -0
  19. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/orchestrator/__init__.py +0 -0
  20. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/orchestrator/_base.py +0 -0
  21. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/orchestrator/_cooldown.py +0 -0
  22. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/orchestrator/_decision.py +0 -0
  23. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/orchestrator/_dispatch.py +0 -0
  24. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/orchestrator/_recovery.py +0 -0
  25. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/orchestrator/_replay.py +0 -0
  26. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/orchestrator/_types.py +0 -0
  27. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/alerting/orchestrator/orchestrator.py +0 -0
  28. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/__init__.py +0 -0
  29. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/_base.py +0 -0
  30. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/_types.py +0 -0
  31. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/autotuner.py +0 -0
  32. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/config_emitter.py +0 -0
  33. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/crossval.py +0 -0
  34. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/detector_select.py +0 -0
  35. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/distribution.py +0 -0
  36. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/grid_search.py +0 -0
  37. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/html_labeler.py +0 -0
  38. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/label_server.py +0 -0
  39. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/labels.py +0 -0
  40. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/result.py +0 -0
  41. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/scoring.py +0 -0
  42. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/seasonality_search.py +0 -0
  43. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/settings.py +0 -0
  44. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/autotune/window_select.py +0 -0
  45. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/__init__.py +0 -0
  46. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/_output.py +0 -0
  47. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/assets/claude/CLAUDE.section.md +0 -0
  48. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/assets/claude/rules/alerting.md +0 -0
  49. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/assets/claude/rules/autotune.md +0 -0
  50. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/assets/claude/rules/detectors.md +0 -0
  51. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/assets/claude/rules/metrics.md +0 -0
  52. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/assets/claude/rules/overview.md +0 -0
  53. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/assets/claude/rules/project.md +0 -0
  54. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/assets/claude/skills/dtk-autotune/SKILL.md +0 -0
  55. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/assets/claude/skills/dtk-feedback/SKILL.md +0 -0
  56. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/assets/claude/skills/dtk-new-metric/SKILL.md +0 -0
  57. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/assets/claude/skills/dtk-setup-project/SKILL.md +0 -0
  58. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/commands/__init__.py +0 -0
  59. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/commands/autotune.py +0 -0
  60. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/commands/clean.py +0 -0
  61. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/commands/init.py +0 -0
  62. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/commands/init_claude.py +0 -0
  63. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/commands/run.py +0 -0
  64. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/commands/test_alert.py +0 -0
  65. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/commands/tune.py +0 -0
  66. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/commands/unlock.py +0 -0
  67. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/cli/main.py +0 -0
  68. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/config/__init__.py +0 -0
  69. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/config/metric_config.py +0 -0
  70. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/config/profile.py +0 -0
  71. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/config/project_config.py +0 -0
  72. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/config/validator.py +0 -0
  73. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/core/__init__.py +0 -0
  74. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/core/interval.py +0 -0
  75. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/core/models.py +0 -0
  76. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/__init__.py +0 -0
  77. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/_sql_manager.py +0 -0
  78. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/clickhouse_manager.py +0 -0
  79. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/internal_tables/__init__.py +0 -0
  80. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/internal_tables/_alert_states.py +0 -0
  81. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/internal_tables/_autotune_runs.py +0 -0
  82. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/internal_tables/_base.py +0 -0
  83. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/internal_tables/_datapoints.py +0 -0
  84. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/internal_tables/_detections.py +0 -0
  85. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/internal_tables/_maintenance.py +0 -0
  86. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/internal_tables/_metrics.py +0 -0
  87. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/internal_tables/_schema.py +0 -0
  88. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/internal_tables/_tasks.py +0 -0
  89. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/internal_tables/manager.py +0 -0
  90. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/manager.py +0 -0
  91. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/mysql_manager.py +0 -0
  92. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/postgres_manager.py +0 -0
  93. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/database/tables.py +0 -0
  94. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/detectors/__init__.py +0 -0
  95. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/detectors/base.py +0 -0
  96. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/detectors/factory.py +0 -0
  97. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/detectors/seasonality.py +0 -0
  98. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/detectors/statistical/__init__.py +0 -0
  99. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/detectors/statistical/_windowed.py +0 -0
  100. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/detectors/statistical/iqr.py +0 -0
  101. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/detectors/statistical/mad.py +0 -0
  102. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/detectors/statistical/manual_bounds.py +0 -0
  103. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/detectors/statistical/zscore.py +0 -0
  104. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/loaders/__init__.py +0 -0
  105. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/loaders/metric_loader.py +0 -0
  106. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/loaders/query_template.py +0 -0
  107. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/orchestration/__init__.py +0 -0
  108. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/orchestration/error_dispatch.py +0 -0
  109. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/orchestration/task_manager/__init__.py +0 -0
  110. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/orchestration/task_manager/_alert_step.py +0 -0
  111. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/orchestration/task_manager/_base.py +0 -0
  112. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/orchestration/task_manager/_detect_step.py +0 -0
  113. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/orchestration/task_manager/_load_step.py +0 -0
  114. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/orchestration/task_manager/_types.py +0 -0
  115. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/orchestration/task_manager/manager.py +0 -0
  116. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/reporting/__init__.py +0 -0
  117. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/reporting/assets/report.js +0 -0
  118. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/reporting/builder.py +0 -0
  119. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/reporting/html_report.py +0 -0
  120. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/tuning/__init__.py +0 -0
  121. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/tuning/assets/tune.js +0 -0
  122. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/tuning/config_writer.py +0 -0
  123. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/tuning/html.py +0 -0
  124. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/tuning/server.py +0 -0
  125. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/utils/__init__.py +0 -0
  126. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/utils/datetime_utils.py +0 -0
  127. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/utils/env_interpolation.py +0 -0
  128. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/utils/json_utils.py +0 -0
  129. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit/utils/stats.py +0 -0
  130. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit.egg-info/SOURCES.txt +0 -0
  131. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit.egg-info/dependency_links.txt +0 -0
  132. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit.egg-info/entry_points.txt +0 -0
  133. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit.egg-info/requires.txt +0 -0
  134. {detectkit-0.36.0 → detectkit-0.36.2}/detectkit.egg-info/top_level.txt +0 -0
  135. {detectkit-0.36.0 → detectkit-0.36.2}/pyproject.toml +0 -0
  136. {detectkit-0.36.0 → detectkit-0.36.2}/requirements.txt +0 -0
  137. {detectkit-0.36.0 → detectkit-0.36.2}/setup.cfg +0 -0
  138. {detectkit-0.36.0 → detectkit-0.36.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: detectkit
3
- Version: 0.36.0
3
+ Version: 0.36.2
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.36.0"
7
+ __version__ = "0.36.2"
8
8
 
9
9
  from detectkit.core.interval import Interval
10
10
  from detectkit.core.models import ColumnDefinition, TableModel
@@ -101,8 +101,10 @@ fall outside any real incident ("≈1 in N false"); only incidents within the lo
101
101
  window are scored. **Save incidents** writes a
102
102
  versioned `incidents/<metric>/*.yml` — the same store `dtk autotune` reads, so the
103
103
  same labels feed the next supervised tune (it seeds from the newest file on open,
104
- **widening the loaded window to cover seeded incidents** so older ones still render
105
- and count). Saving incidents does not end the session; only **Apply** does. A
104
+ **anchoring the budget-sized loaded window on the seeded incidents** ending just
105
+ past the latest one rather than at the last datapoint so they render/count
106
+ without an old outlier pulling the whole history in). Saving incidents does not end
107
+ the session; only **Apply** does. A
106
108
  **y = 0 line** toggle (shared with `dtk run --report`) shows the metric relative to zero.
107
109
 
108
110
  Safe write-back: the config is validated before anything is written, the previous
@@ -35,11 +35,6 @@ _TUNE_MAX_POINTS = 15000
35
35
  # scored region (the band never reaches its real width). Floor the shown points
36
36
  # at this many windows so the seeded window is actually exercised in the preview.
37
37
  _TUNE_WINDOW_COVERAGE = 3
38
- # Hard ceiling on the loaded point count when seeded incidents pull the window
39
- # back far into history — keeps a pathological (e.g. minute-grained, multi-year)
40
- # series from bloating the page. Any incident still left older than this slice
41
- # stays in the list but the client metrics ignore it (it cannot be scored).
42
- _TUNE_INCIDENT_MAX_POINTS = 60_000
43
38
 
44
39
 
45
40
  def default_window_points(seed_window: int) -> int:
@@ -82,25 +77,34 @@ def _normalize_seasonality_components(
82
77
  return groups or None
83
78
 
84
79
 
85
- def _earliest_incident_start(incidents: list[dict[str, str]]) -> datetime | None:
86
- """Earliest incident start (naive UTC) among seeded display dicts, or ``None``.
80
+ def _incident_span(incidents: list[dict[str, str]]) -> tuple[datetime, datetime] | None:
81
+ """``(earliest start, latest end)`` (naive UTC) over seeded display dicts, or ``None``.
87
82
 
88
83
  The display dicts carry ``"YYYY-MM-DD HH:MM:SS"`` naive-UTC strings (see
89
84
  ``autotune.labels.incidents_to_display``), matching the naive datetimes the
90
85
  builder compares against the loaded series bounds.
91
86
  """
92
- earliest: datetime | None = None
93
- for inc in incidents:
94
- raw = inc.get("start")
87
+
88
+ def _parse(raw: Any) -> datetime | None:
95
89
  if not raw:
96
- continue
90
+ return None
97
91
  try:
98
- dt = datetime.strptime(str(raw), "%Y-%m-%d %H:%M:%S")
92
+ return datetime.strptime(str(raw), "%Y-%m-%d %H:%M:%S")
99
93
  except ValueError:
100
- continue
101
- if earliest is None or dt < earliest:
102
- earliest = dt
103
- return earliest
94
+ return None
95
+
96
+ earliest: datetime | None = None
97
+ latest: datetime | None = None
98
+ for inc in incidents:
99
+ start = _parse(inc.get("start"))
100
+ end = _parse(inc.get("end")) or start
101
+ if start is not None and (earliest is None or start < earliest):
102
+ earliest = start
103
+ if end is not None and (latest is None or end > latest):
104
+ latest = end
105
+ if earliest is None or latest is None:
106
+ return None
107
+ return earliest, latest
104
108
 
105
109
 
106
110
  def _seed_detector(metric_config: MetricConfig) -> dict[str, Any]:
@@ -182,10 +186,12 @@ def build_tune_payload(
182
186
  (``default_window_points``), not the whole history.
183
187
 
184
188
  ``incidents`` seeds the synced labeler with already-marked spans (display dicts
185
- ``{start, end, label}`` from ``incidents_to_display``). When seeded incidents
186
- fall outside the recent default slice, the loaded window is pulled back to
187
- cover them so they render on the chart and count toward the live recall/FDR
188
- metrics (an explicit ``start``/``--from`` is still honored verbatim).
189
+ ``{start, end, label}`` from ``incidents_to_display``). When incidents are
190
+ seeded the (still budget-sized) window is anchored on the incident region — it
191
+ ends just past the latest incident rather than at the last datapoint so they
192
+ render on the chart and count toward the live recall/FDR metrics, while the
193
+ window stays bounded (a single old outlier incident can't pull the whole
194
+ history in). An explicit ``start``/``--from`` is still honored verbatim.
189
195
  ``capture_windows`` seeds the threshold-capture regime scope (display dicts
190
196
  ``{start, end}``). ``labels_save_url`` (the POST endpoint for **Save
191
197
  incidents**) is injected by the server, like ``save_url`` — it is ``None`` here.
@@ -208,22 +214,29 @@ def build_tune_payload(
208
214
  if start is None and end is not None:
209
215
  first = internal.get_first_datapoint_timestamp(name)
210
216
  default_points = default_window_points(int(seed["windowSize"]))
211
- lookback = end - timedelta(seconds=interval_seconds * default_points)
212
- # Pull the window back to cover any seeded incidents so they actually
213
- # render on the chart and can be scored otherwise an incident older than
214
- # the recent default slice shows in the list but never on the chart, and
215
- # never counts toward recall/FDR. Give the earliest incident a few windows
216
- # of leading context so the detector's trailing window can fill there.
217
- earliest = _earliest_incident_start(seed_incidents)
218
- if earliest is not None:
219
- context_points = max(_TUNE_WINDOW_COVERAGE * int(seed["windowSize"]), 200)
220
- lookback = min(
221
- lookback, earliest - timedelta(seconds=interval_seconds * context_points)
217
+ budget = timedelta(seconds=interval_seconds * default_points)
218
+ # When incidents are seeded, ANCHOR the (still budget-sized) window on the
219
+ # incident region instead of always ending at the last datapoint, so the
220
+ # incidents render and can be scored. Crucially the window stays bounded:
221
+ # the end is pulled back to just past the LATEST incident (a few windows of
222
+ # recovery context) only when that is older than the last datapoint, so a
223
+ # single old outlier incident can't drag the whole history in — it would
224
+ # blow the recompute budget (the page hangs). Incidents older than the
225
+ # bounded window stay in the list and are excluded from the live metrics.
226
+ span = _incident_span(seed_incidents)
227
+ if span is not None:
228
+ _, latest = span
229
+ # Align awareness to end (both represent UTC) so the comparison is valid
230
+ # on backends that return tz-aware timestamps.
231
+ if end.tzinfo is not None and latest.tzinfo is None:
232
+ latest = latest.replace(tzinfo=end.tzinfo)
233
+ elif end.tzinfo is None and latest.tzinfo is not None:
234
+ latest = latest.replace(tzinfo=None)
235
+ context = timedelta(
236
+ seconds=interval_seconds * max(_TUNE_WINDOW_COVERAGE * int(seed["windowSize"]), 200)
222
237
  )
223
- # Clamp to a hard point ceiling (a pathological history can't bloat the
224
- # page) and to the first datapoint.
225
- ceiling = end - timedelta(seconds=interval_seconds * _TUNE_INCIDENT_MAX_POINTS)
226
- start = max(lookback, ceiling)
238
+ end = min(end, latest + context)
239
+ start = end - budget
227
240
  if first is not None:
228
241
  start = max(start, first)
229
242
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: detectkit
3
- Version: 0.36.0
3
+ Version: 0.36.2
4
4
  Summary: Metric monitoring with automatic anomaly detection
5
5
  Author: detectkit team
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes