detectkit 0.16.0__tar.gz → 0.16.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 (105) hide show
  1. {detectkit-0.16.0/detectkit.egg-info → detectkit-0.16.1}/PKG-INFO +1 -1
  2. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/__init__.py +1 -1
  3. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/webhook.py +25 -11
  4. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/rules/alerting.md +5 -3
  5. {detectkit-0.16.0 → detectkit-0.16.1/detectkit.egg-info}/PKG-INFO +1 -1
  6. {detectkit-0.16.0 → detectkit-0.16.1}/LICENSE +0 -0
  7. {detectkit-0.16.0 → detectkit-0.16.1}/MANIFEST.in +0 -0
  8. {detectkit-0.16.0 → detectkit-0.16.1}/README.md +0 -0
  9. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/__init__.py +0 -0
  10. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/__init__.py +0 -0
  11. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/base.py +0 -0
  12. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/branding.py +0 -0
  13. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/email.py +0 -0
  14. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/factory.py +0 -0
  15. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/mattermost.py +0 -0
  16. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/slack.py +0 -0
  17. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/telegram.py +0 -0
  18. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/__init__.py +0 -0
  19. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/_base.py +0 -0
  20. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/_cooldown.py +0 -0
  21. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/_decision.py +0 -0
  22. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/_dispatch.py +0 -0
  23. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/_recovery.py +0 -0
  24. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/_types.py +0 -0
  25. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/orchestrator.py +0 -0
  26. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/__init__.py +0 -0
  27. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/_output.py +0 -0
  28. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/CLAUDE.section.md +0 -0
  29. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/rules/cli.md +0 -0
  30. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/rules/detectors.md +0 -0
  31. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/rules/metrics.md +0 -0
  32. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/rules/overview.md +0 -0
  33. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/rules/project.md +0 -0
  34. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/skills/dtk-feedback/SKILL.md +0 -0
  35. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/skills/dtk-new-metric/SKILL.md +0 -0
  36. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/skills/dtk-setup-project/SKILL.md +0 -0
  37. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/__init__.py +0 -0
  38. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/clean.py +0 -0
  39. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/init.py +0 -0
  40. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/init_claude.py +0 -0
  41. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/run.py +0 -0
  42. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/test_alert.py +0 -0
  43. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/unlock.py +0 -0
  44. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/main.py +0 -0
  45. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/config/__init__.py +0 -0
  46. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/config/metric_config.py +0 -0
  47. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/config/profile.py +0 -0
  48. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/config/project_config.py +0 -0
  49. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/config/validator.py +0 -0
  50. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/core/__init__.py +0 -0
  51. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/core/interval.py +0 -0
  52. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/core/models.py +0 -0
  53. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/__init__.py +0 -0
  54. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/_sql_manager.py +0 -0
  55. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/clickhouse_manager.py +0 -0
  56. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/__init__.py +0 -0
  57. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_alert_states.py +0 -0
  58. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_base.py +0 -0
  59. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_datapoints.py +0 -0
  60. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_detections.py +0 -0
  61. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_maintenance.py +0 -0
  62. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_metrics.py +0 -0
  63. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_schema.py +0 -0
  64. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_tasks.py +0 -0
  65. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/manager.py +0 -0
  66. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/manager.py +0 -0
  67. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/mysql_manager.py +0 -0
  68. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/postgres_manager.py +0 -0
  69. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/tables.py +0 -0
  70. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/__init__.py +0 -0
  71. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/base.py +0 -0
  72. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/factory.py +0 -0
  73. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/seasonality.py +0 -0
  74. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/statistical/__init__.py +0 -0
  75. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/statistical/_windowed.py +0 -0
  76. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/statistical/iqr.py +0 -0
  77. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/statistical/mad.py +0 -0
  78. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/statistical/manual_bounds.py +0 -0
  79. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/statistical/zscore.py +0 -0
  80. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/loaders/__init__.py +0 -0
  81. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/loaders/metric_loader.py +0 -0
  82. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/loaders/query_template.py +0 -0
  83. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/__init__.py +0 -0
  84. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/error_dispatch.py +0 -0
  85. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/__init__.py +0 -0
  86. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/_alert_step.py +0 -0
  87. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/_base.py +0 -0
  88. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/_detect_step.py +0 -0
  89. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/_load_step.py +0 -0
  90. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/_types.py +0 -0
  91. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/manager.py +0 -0
  92. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/utils/__init__.py +0 -0
  93. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/utils/datetime_utils.py +0 -0
  94. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/utils/env_interpolation.py +0 -0
  95. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/utils/json_utils.py +0 -0
  96. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/utils/stats.py +0 -0
  97. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit.egg-info/SOURCES.txt +0 -0
  98. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit.egg-info/dependency_links.txt +0 -0
  99. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit.egg-info/entry_points.txt +0 -0
  100. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit.egg-info/requires.txt +0 -0
  101. {detectkit-0.16.0 → detectkit-0.16.1}/detectkit.egg-info/top_level.txt +0 -0
  102. {detectkit-0.16.0 → detectkit-0.16.1}/pyproject.toml +0 -0
  103. {detectkit-0.16.0 → detectkit-0.16.1}/requirements.txt +0 -0
  104. {detectkit-0.16.0 → detectkit-0.16.1}/setup.cfg +0 -0
  105. {detectkit-0.16.0 → detectkit-0.16.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: detectkit
3
- Version: 0.16.0
3
+ Version: 0.16.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.16.0"
7
+ __version__ = "0.16.1"
8
8
 
9
9
  from detectkit.core.interval import Interval
10
10
  from detectkit.core.models import ColumnDefinition, TableModel
@@ -293,20 +293,21 @@ class WebhookChannel(BaseAlertChannel):
293
293
  err = f"{ctx['error_type']}: {ctx['error_message']}".strip(": ")
294
294
  full("Error", code(err))
295
295
 
296
- # Optional links block (dashboard_url is already the clickable title;
297
- # surface bare URLs here too so they're visible/linkified on both).
298
- link_lines = []
296
+ # Links block kept as its own flexible field, but every entry is a
297
+ # compact clickable label, never a raw URL string. A Grafana dashboard
298
+ # URL can be a paragraph long once it carries variables; nobody should
299
+ # read that in an alert, so we hide it behind the label and render in the
300
+ # platform's link syntax. Holds dashboard + any extra links + the "how to
301
+ # read this alert" guide, joined by " · ".
302
+ link_parts = []
299
303
  if alert_data.dashboard_url:
300
- link_lines.append(f"Dashboard: {alert_data.dashboard_url}")
304
+ link_parts.append(self._link_markup(alert_data.dashboard_url, "Dashboard"))
301
305
  for label, url in alert_data.links.items():
302
- link_lines.append(f"{label}: {url}")
303
- if link_lines:
304
- full("Links", "\n".join(link_lines))
305
-
306
- # "How to read this alert" — the last field, a bare URL (auto-linkified on
307
- # both Slack and Mattermost) pointing readers at the interpretation guide.
306
+ link_parts.append(self._link_markup(url, label))
308
307
  if ctx["help_url"]:
309
- full(ctx["help_label"], ctx["help_url"])
308
+ link_parts.append(self._link_markup(ctx["help_url"], ctx["help_label"]))
309
+ if link_parts:
310
+ full("Links", " · ".join(link_parts))
310
311
 
311
312
  # A plain-text one-liner for notification previews / unsupported clients.
312
313
  if kind == "no_data":
@@ -328,6 +329,19 @@ class WebhookChannel(BaseAlertChannel):
328
329
  "mrkdwn_in": ["text", "fields"],
329
330
  }
330
331
 
332
+ def _link_markup(self, url: str, label: str) -> str:
333
+ """Render *label* as a clickable link in the target platform's syntax.
334
+
335
+ Slack incoming webhooks (``hooks.slack.com``) use ``<url|label>``;
336
+ Mattermost and other webhooks use markdown ``[label](url)``. This keeps a
337
+ link a short clickable phrase instead of a raw URL — important because a
338
+ real dashboard URL (e.g. Grafana with many variables) can be extremely
339
+ long, and no one should have to read it inside an alert.
340
+ """
341
+ if "hooks.slack.com" in self.webhook_url:
342
+ return f"<{url}|{label}>"
343
+ return f"[{label}]({url})"
344
+
331
345
  @staticmethod
332
346
  def _unix_ts(ts: Any) -> int | None:
333
347
  """Epoch seconds (UTC) for a naive-UTC timestamp, or None on failure."""
@@ -167,9 +167,11 @@ config needed. Control it project-wide with `alert_help_url` in
167
167
  Per-channel rendering (defaults only; resolved by
168
168
  `ProjectConfig.resolve_alert_help_url`):
169
169
 
170
- - **Slack / Mattermost / generic webhook** — a bottom full-width attachment field
171
- titled `How to read this alert` whose value is the bare URL (auto-linkified on
172
- both platforms).
170
+ - **Slack / Mattermost / generic webhook** — a clickable `How to read this alert`
171
+ label in the compact `Links` field (alongside `Dashboard` + any extra links),
172
+ never a raw URL. Rendered in the platform's link syntax (Slack `<url|label>`,
173
+ Mattermost/generic markdown links) so a long dashboard URL stays hidden behind
174
+ its label.
173
175
  - **Telegram** — appended to the links line (after the optional "Open dashboard"
174
176
  link) as an `<a>` link reading `How to read this alert`.
175
177
  - **Email** — in the footer, after `Sent by detectkit · <project>` (and any CC),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: detectkit
3
- Version: 0.16.0
3
+ Version: 0.16.1
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