flowsense-engine 0.4.0__tar.gz → 0.5.0__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 (129) hide show
  1. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/CHANGELOG.md +52 -0
  2. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/MANIFEST.in +1 -0
  3. {flowsense_engine-0.4.0/src/flowsense_engine.egg-info → flowsense_engine-0.5.0}/PKG-INFO +47 -4
  4. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/README.md +45 -3
  5. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/docs/architecture.md +8 -0
  6. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/docs/authentication.md +11 -3
  7. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/docs/grafana.md +5 -1
  8. flowsense_engine-0.5.0/docs/migrating-to-0.5.md +63 -0
  9. flowsense_engine-0.5.0/docs/production-quickstart.md +235 -0
  10. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/docs/prometheus.md +8 -1
  11. flowsense_engine-0.5.0/docs/release-0.5.0.md +48 -0
  12. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/docs/releasing.md +6 -5
  13. flowsense_engine-0.5.0/examples/dags/flowsense_demo.py +48 -0
  14. flowsense_engine-0.5.0/examples/python/production_batch.py +86 -0
  15. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/pyproject.toml +21 -1
  16. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/__init__.py +8 -0
  17. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/application/__init__.py +8 -0
  18. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/application/output.py +7 -2
  19. flowsense_engine-0.5.0/src/flowsense/application/policy_document.py +35 -0
  20. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/application/serialization.py +4 -0
  21. flowsense_engine-0.5.0/src/flowsense/cli/doctor.py +110 -0
  22. flowsense_engine-0.5.0/src/flowsense/cli/main.py +551 -0
  23. flowsense_engine-0.5.0/src/flowsense/cli/policy.py +103 -0
  24. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/domain/__init__.py +2 -0
  25. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/domain/enums.py +6 -0
  26. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/domain/policy.py +6 -0
  27. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/domain/results.py +3 -0
  28. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/engine/drift.py +16 -15
  29. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/infrastructure/airflow/client.py +185 -35
  30. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/infrastructure/airflow/dto.py +1 -0
  31. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/mcp/server.py +4 -0
  32. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/observability/service.py +23 -2
  33. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0/src/flowsense_engine.egg-info}/PKG-INFO +47 -4
  34. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense_engine.egg-info/SOURCES.txt +12 -0
  35. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense_engine.egg-info/requires.txt +1 -0
  36. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_airflow_auth.py +66 -1
  37. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_airflow_client.py +177 -12
  38. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_airflow_compatibility.py +1 -1
  39. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_airflow_contract.py +2 -0
  40. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_airflow_resilience.py +4 -1
  41. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_analysis_golden.py +1 -1
  42. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_analysis_output.py +6 -0
  43. flowsense_engine-0.5.0/tests/test_analysis_policy_document.py +33 -0
  44. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_benchmark_analysis.py +1 -1
  45. flowsense_engine-0.5.0/tests/test_cli.py +778 -0
  46. flowsense_engine-0.5.0/tests/test_cli_policy.py +58 -0
  47. flowsense_engine-0.5.0/tests/test_doctor.py +84 -0
  48. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_domain.py +1 -1
  49. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_drift.py +38 -2
  50. flowsense_engine-0.5.0/tests/test_examples.py +22 -0
  51. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_mcp_integration.py +6 -2
  52. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_mcp_server.py +17 -3
  53. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_package_metadata.py +1 -1
  54. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_policy.py +34 -11
  55. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_prometheus.py +66 -2
  56. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_public_api.py +4 -0
  57. flowsense_engine-0.4.0/src/flowsense/cli/main.py +0 -225
  58. flowsense_engine-0.4.0/tests/test_cli.py +0 -286
  59. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/LICENSE +0 -0
  60. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/docs/alerting.md +0 -0
  61. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/docs/benchmarks.md +0 -0
  62. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/docs/migrating-to-0.3.md +0 -0
  63. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/docs/python-api.md +0 -0
  64. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/setup.cfg +0 -0
  65. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/application/analysis_engine.py +0 -0
  66. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/application/analyzer.py +0 -0
  67. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/application/batch.py +0 -0
  68. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/application/client.py +0 -0
  69. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/application/pipeline.py +0 -0
  70. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/application/ports.py +0 -0
  71. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/application/request.py +0 -0
  72. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/application/use_cases.py +0 -0
  73. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/cli/__init__.py +0 -0
  74. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/cli/report.py +0 -0
  75. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/collector/__init__.py +0 -0
  76. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/collector/airflow_client.py +0 -0
  77. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/config.py +0 -0
  78. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/domain/exceptions.py +0 -0
  79. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/domain/models.py +0 -0
  80. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/engine/__init__.py +0 -0
  81. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/engine/analyzer.py +0 -0
  82. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/engine/change_point.py +0 -0
  83. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/engine/history.py +0 -0
  84. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/engine/impact.py +0 -0
  85. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/engine/propagation.py +0 -0
  86. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/engine/root_cause.py +0 -0
  87. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/engine/timing.py +0 -0
  88. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/engine/trend.py +0 -0
  89. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/engine/validation.py +0 -0
  90. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/infrastructure/__init__.py +0 -0
  91. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/infrastructure/airflow/__init__.py +0 -0
  92. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/infrastructure/airflow/auth.py +0 -0
  93. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/infrastructure/airflow/config.py +0 -0
  94. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/infrastructure/airflow/exceptions.py +0 -0
  95. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/infrastructure/airflow/factory.py +0 -0
  96. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/infrastructure/airflow/mapper.py +0 -0
  97. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/mcp/__init__.py +0 -0
  98. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/models/__init__.py +0 -0
  99. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/models/dag_analysis.py +0 -0
  100. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/models/task_run.py +0 -0
  101. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/observability/__init__.py +0 -0
  102. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/observability/prometheus.py +0 -0
  103. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/py.typed +0 -0
  104. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense/version.py +0 -0
  105. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense_engine.egg-info/dependency_links.txt +0 -0
  106. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense_engine.egg-info/entry_points.txt +0 -0
  107. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/src/flowsense_engine.egg-info/top_level.txt +0 -0
  108. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_airflow_client_integration.py +0 -0
  109. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_airflow_factory.py +0 -0
  110. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_airflow_mapper.py +0 -0
  111. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_analysis_pipeline.py +0 -0
  112. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_analysis_request.py +0 -0
  113. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_analysis_use_case.py +0 -0
  114. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_analyzer.py +0 -0
  115. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_architecture.py +0 -0
  116. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_batch_analysis_output.py +0 -0
  117. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_change_point.py +0 -0
  118. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_cli_report.py +0 -0
  119. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_dag_summary.py +0 -0
  120. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_deprecations.py +0 -0
  121. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_history.py +0 -0
  122. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_impact.py +0 -0
  123. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_library_client.py +0 -0
  124. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_observability_assets.py +0 -0
  125. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_observation_validation.py +0 -0
  126. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_propagation.py +0 -0
  127. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_root_cause.py +0 -0
  128. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_timing.py +0 -0
  129. {flowsense_engine-0.4.0 → flowsense_engine-0.5.0}/tests/test_trend.py +0 -0
@@ -5,6 +5,58 @@ All notable changes to FlowSense are documented in this file. The project uses
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ### Added
9
+
10
+ ### Changed
11
+
12
+ ### Fixed
13
+
14
+ ## [0.5.0] - 2026-09-23
15
+
16
+ ### Added
17
+
18
+ - Added a production quickstart and executable bounded batch-analysis example.
19
+ - Added `flowsense doctor` for safe configuration, Airflow API, authentication,
20
+ and DAG-visibility diagnostics.
21
+ - Added `flowsense dags` for read-only DAG discovery with table and JSON output.
22
+ - Added `flowsense analyze-batch` for bounded multi-DAG CLI analysis with the
23
+ versioned batch JSON contract.
24
+ - Added severity-based CI exit thresholds to batch analysis.
25
+ - Added full analysis-policy configuration to the batch CLI.
26
+ - Added bounded DAG discovery to batch analysis with `--all-dags`,
27
+ `--dag-limit`, and optional paused-DAG inclusion.
28
+ - Added CLI access to the versioned batch output JSON Schema through
29
+ `flowsense schema --document batch`.
30
+ - Added reliable versioned JSON file output to single-DAG analysis through
31
+ `flowsense analyze --output-file`.
32
+ - Added reusable, versioned JSON analysis policies for single and batch CLI
33
+ commands, with explicit command-line overrides and JSON Schema export.
34
+ - Added versioned analysis-policy support to the optional Prometheus metrics
35
+ command and propagated the selected policy through every collection cycle.
36
+ - Added a validated per-cycle history limit to the Prometheus metrics command
37
+ so Airflow collection remains explicitly bounded.
38
+ - Added expanded Ruff quality rules, a 90% CI coverage gate, and graceful MCP
39
+ test skipping when the optional dependency is not installed.
40
+ - Reduced Airflow collection overhead with bounded server-side DAG run filters
41
+ and batched task-instance retrieval, including compatibility fallbacks for
42
+ deployments that do not support the optimized endpoints.
43
+ - Added explicit drift direction and effective MAD fields to analysis results,
44
+ plus configurable relative and absolute dispersion floors.
45
+
46
+ ### Changed
47
+
48
+ - Airflow login tokens are now refreshed once after an unauthorized API
49
+ response, while static bearer, Basic, and custom authentication lifecycles
50
+ remain application-owned.
51
+ - Advanced the analysis output schema to version `1.2` for the new drift and
52
+ policy fields.
53
+
54
+ ### Fixed
55
+
56
+ - Constant and near-constant baselines no longer classify negligible timing
57
+ noise as an automatic critical anomaly when raw MAD is zero or extremely
58
+ small.
59
+
8
60
  ## [0.4.0] - 2026-09-20
9
61
 
10
62
  ### Added
@@ -1,2 +1,3 @@
1
1
  include CHANGELOG.md
2
2
  recursive-include docs *.md
3
+ recursive-include examples *.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flowsense-engine
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Temporal drift and anomaly detection for Apache Airflow
5
5
  Author: Omer Cengiz
6
6
  License-Expression: Apache-2.0
@@ -28,6 +28,7 @@ Provides-Extra: dev
28
28
  Requires-Dist: build>=1.2; extra == "dev"
29
29
  Requires-Dist: pyright>=1.1.400; extra == "dev"
30
30
  Requires-Dist: pytest>=8.0; extra == "dev"
31
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
31
32
  Requires-Dist: ruff>=0.6; extra == "dev"
32
33
  Provides-Extra: mcp
33
34
  Requires-Dist: mcp[cli]>=2.0; extra == "mcp"
@@ -37,10 +38,12 @@ Dynamic: license-file
37
38
 
38
39
  Temporal drift, anomaly detection, and dependency-aware propagation analysis for Apache Airflow.
39
40
 
40
- Current package release: `0.4.0`. See [CHANGELOG.md](CHANGELOG.md) for release
41
+ Current package release: `0.5.0`. See [CHANGELOG.md](CHANGELOG.md) for release
41
42
  notes, [docs/architecture.md](docs/architecture.md) for the system architecture,
42
43
  [docs/benchmarks.md](docs/benchmarks.md) for performance measurement, and
43
- [docs/migrating-to-0.3.md](docs/migrating-to-0.3.md) for migration guidance.
44
+ [docs/production-quickstart.md](docs/production-quickstart.md) for a production
45
+ walkthrough. See [docs/migrating-to-0.5.md](docs/migrating-to-0.5.md) for the
46
+ current migration guidance.
44
47
  Maintainers can use [docs/releasing.md](docs/releasing.md) as the release checklist.
45
48
 
46
49
  FlowSense analyzes historical DAG executions to identify abnormal task behavior and trace how anomalies propagate through downstream dependencies.
@@ -153,6 +156,9 @@ Once published on PyPI, install the distribution with:
153
156
  pip install flowsense-engine
154
157
  ```
155
158
 
159
+ For an end-to-end Airflow setup, follow the
160
+ [production quickstart](docs/production-quickstart.md).
161
+
156
162
  The distribution name is `flowsense-engine`; Python imports and CLI commands
157
163
  remain `flowsense`.
158
164
 
@@ -218,9 +224,15 @@ export $(grep -v '^#' .env | xargs)
218
224
  Then run:
219
225
 
220
226
  ```bash
227
+ flowsense doctor
228
+ flowsense dags
221
229
  flowsense analyze <dag_id>
230
+ flowsense analyze-batch <dag_id> [<dag_id> ...]
222
231
  ```
223
232
 
233
+ Both single and batch analysis commands support `--fail-on` for CI severity
234
+ gates.
235
+
224
236
  The CLI report includes a DAG summary and separate tables for task drift,
225
237
  handoff drift, change points, trends, propagation paths, and diagnostics.
226
238
  Results are ordered by severity or subject so repeated analyses remain easy to
@@ -230,14 +242,30 @@ For automation and CI/CD integrations, request the versioned JSON document:
230
242
 
231
243
  ```bash
232
244
  flowsense analyze <dag_id> --output json
245
+ flowsense analyze <dag_id> --output-file flowsense-analysis.json
233
246
  ```
234
247
 
248
+ `--output-file` always writes the versioned JSON contract and avoids relying on
249
+ shell redirection in CI jobs.
250
+
235
251
  CI jobs can also fail when the analysis reaches a selected severity:
236
252
 
237
253
  ```bash
238
254
  flowsense analyze <dag_id> --output json --fail-on high
239
255
  ```
240
256
 
257
+ Store reusable analysis settings in a versioned JSON policy file and share it
258
+ between single and batch analysis:
259
+
260
+ ```bash
261
+ flowsense analyze <dag_id> --policy-file flowsense-policy.json
262
+ flowsense analyze-batch --all-dags --dag-limit 10 \
263
+ --policy-file flowsense-policy.json
264
+ ```
265
+
266
+ Explicit policy options override values loaded from the file. Generate its JSON
267
+ Schema with `flowsense schema --document policy`.
268
+
241
269
  `--fail-on` accepts `medium`, `high`, or `critical`. The report is always
242
270
  written before FlowSense exits: code `0` means the severity is below the
243
271
  threshold, code `2` means the threshold was reached, and code `1` remains
@@ -265,6 +293,8 @@ flowsense analyze <dag_id> --dag-run-id <dag_run_id>
265
293
 
266
294
  The MCP tool exposes the same option as `dag_run_id`. Analysis output includes
267
295
  `current_dag_run_id`; this field was introduced in output schema version `1.1`.
296
+ Output schema version `1.2` adds drift `direction`, the regularized
297
+ `effective_mad`, and the dispersion-floor policy values.
268
298
 
269
299
  The JSON document and MCP tool response share the same serialization contract
270
300
  and include a `schema_version` field. The serializer is also available from the
@@ -279,8 +309,13 @@ The same schema can be emitted without connecting to Airflow:
279
309
 
280
310
  ```bash
281
311
  flowsense schema > flowsense-analysis.schema.json
312
+ flowsense schema --document batch > flowsense-batch.schema.json
282
313
  ```
283
314
 
315
+ The default remains the single-DAG analysis schema. Use `--document batch` to
316
+ emit the versioned batch envelope schema, including successful analyses and
317
+ per-DAG failure records.
318
+
284
319
  This output is deterministic and can be used in CI contract checks, editor
285
320
  tooling, or client code generation.
286
321
 
@@ -332,6 +367,8 @@ policy = AnalysisPolicy(
332
367
  medium_threshold=2.5,
333
368
  high_threshold=4.0,
334
369
  critical_threshold=6.0,
370
+ minimum_relative_dispersion=0.01,
371
+ minimum_absolute_dispersion=0.001,
335
372
  mapped_task_aggregation=MappedTaskAggregation.MAX,
336
373
  change_point_minimum_segment_size=4,
337
374
  change_point_score_threshold=4.0,
@@ -344,6 +381,8 @@ policy = AnalysisPolicy(
344
381
  `baseline_window` limits the number of historical values used before the current
345
382
  run. Mapped task durations can be aggregated with `MAX`, `MEAN`, or `SUM`. The
346
383
  same policy options are available through the CLI and MCP tool.
384
+ The dispersion floors prevent constant or nearly constant baselines from
385
+ turning negligible timing noise into an automatic critical anomaly.
347
386
  Change-point and trend detection can also be disabled independently with
348
387
  `change_point_detection_enabled=False` or `trend_detection_enabled=False`.
349
388
 
@@ -383,7 +422,11 @@ information for a DAG.
383
422
  Run continuous analysis and expose the latest DAG and bounded task-level metrics:
384
423
 
385
424
  ```bash
386
- flowsense serve-metrics example_dag --host 0.0.0.0 --port 9108
425
+ flowsense serve-metrics example_dag \
426
+ --host 0.0.0.0 \
427
+ --port 9108 \
428
+ --history-run-limit 50 \
429
+ --policy-file flowsense-policy.json
387
430
  ```
388
431
 
389
432
  See [docs/prometheus.md](docs/prometheus.md) for the metric contract,
@@ -2,10 +2,12 @@
2
2
 
3
3
  Temporal drift, anomaly detection, and dependency-aware propagation analysis for Apache Airflow.
4
4
 
5
- Current package release: `0.4.0`. See [CHANGELOG.md](CHANGELOG.md) for release
5
+ Current package release: `0.5.0`. See [CHANGELOG.md](CHANGELOG.md) for release
6
6
  notes, [docs/architecture.md](docs/architecture.md) for the system architecture,
7
7
  [docs/benchmarks.md](docs/benchmarks.md) for performance measurement, and
8
- [docs/migrating-to-0.3.md](docs/migrating-to-0.3.md) for migration guidance.
8
+ [docs/production-quickstart.md](docs/production-quickstart.md) for a production
9
+ walkthrough. See [docs/migrating-to-0.5.md](docs/migrating-to-0.5.md) for the
10
+ current migration guidance.
9
11
  Maintainers can use [docs/releasing.md](docs/releasing.md) as the release checklist.
10
12
 
11
13
  FlowSense analyzes historical DAG executions to identify abnormal task behavior and trace how anomalies propagate through downstream dependencies.
@@ -118,6 +120,9 @@ Once published on PyPI, install the distribution with:
118
120
  pip install flowsense-engine
119
121
  ```
120
122
 
123
+ For an end-to-end Airflow setup, follow the
124
+ [production quickstart](docs/production-quickstart.md).
125
+
121
126
  The distribution name is `flowsense-engine`; Python imports and CLI commands
122
127
  remain `flowsense`.
123
128
 
@@ -183,9 +188,15 @@ export $(grep -v '^#' .env | xargs)
183
188
  Then run:
184
189
 
185
190
  ```bash
191
+ flowsense doctor
192
+ flowsense dags
186
193
  flowsense analyze <dag_id>
194
+ flowsense analyze-batch <dag_id> [<dag_id> ...]
187
195
  ```
188
196
 
197
+ Both single and batch analysis commands support `--fail-on` for CI severity
198
+ gates.
199
+
189
200
  The CLI report includes a DAG summary and separate tables for task drift,
190
201
  handoff drift, change points, trends, propagation paths, and diagnostics.
191
202
  Results are ordered by severity or subject so repeated analyses remain easy to
@@ -195,14 +206,30 @@ For automation and CI/CD integrations, request the versioned JSON document:
195
206
 
196
207
  ```bash
197
208
  flowsense analyze <dag_id> --output json
209
+ flowsense analyze <dag_id> --output-file flowsense-analysis.json
198
210
  ```
199
211
 
212
+ `--output-file` always writes the versioned JSON contract and avoids relying on
213
+ shell redirection in CI jobs.
214
+
200
215
  CI jobs can also fail when the analysis reaches a selected severity:
201
216
 
202
217
  ```bash
203
218
  flowsense analyze <dag_id> --output json --fail-on high
204
219
  ```
205
220
 
221
+ Store reusable analysis settings in a versioned JSON policy file and share it
222
+ between single and batch analysis:
223
+
224
+ ```bash
225
+ flowsense analyze <dag_id> --policy-file flowsense-policy.json
226
+ flowsense analyze-batch --all-dags --dag-limit 10 \
227
+ --policy-file flowsense-policy.json
228
+ ```
229
+
230
+ Explicit policy options override values loaded from the file. Generate its JSON
231
+ Schema with `flowsense schema --document policy`.
232
+
206
233
  `--fail-on` accepts `medium`, `high`, or `critical`. The report is always
207
234
  written before FlowSense exits: code `0` means the severity is below the
208
235
  threshold, code `2` means the threshold was reached, and code `1` remains
@@ -230,6 +257,8 @@ flowsense analyze <dag_id> --dag-run-id <dag_run_id>
230
257
 
231
258
  The MCP tool exposes the same option as `dag_run_id`. Analysis output includes
232
259
  `current_dag_run_id`; this field was introduced in output schema version `1.1`.
260
+ Output schema version `1.2` adds drift `direction`, the regularized
261
+ `effective_mad`, and the dispersion-floor policy values.
233
262
 
234
263
  The JSON document and MCP tool response share the same serialization contract
235
264
  and include a `schema_version` field. The serializer is also available from the
@@ -244,8 +273,13 @@ The same schema can be emitted without connecting to Airflow:
244
273
 
245
274
  ```bash
246
275
  flowsense schema > flowsense-analysis.schema.json
276
+ flowsense schema --document batch > flowsense-batch.schema.json
247
277
  ```
248
278
 
279
+ The default remains the single-DAG analysis schema. Use `--document batch` to
280
+ emit the versioned batch envelope schema, including successful analyses and
281
+ per-DAG failure records.
282
+
249
283
  This output is deterministic and can be used in CI contract checks, editor
250
284
  tooling, or client code generation.
251
285
 
@@ -297,6 +331,8 @@ policy = AnalysisPolicy(
297
331
  medium_threshold=2.5,
298
332
  high_threshold=4.0,
299
333
  critical_threshold=6.0,
334
+ minimum_relative_dispersion=0.01,
335
+ minimum_absolute_dispersion=0.001,
300
336
  mapped_task_aggregation=MappedTaskAggregation.MAX,
301
337
  change_point_minimum_segment_size=4,
302
338
  change_point_score_threshold=4.0,
@@ -309,6 +345,8 @@ policy = AnalysisPolicy(
309
345
  `baseline_window` limits the number of historical values used before the current
310
346
  run. Mapped task durations can be aggregated with `MAX`, `MEAN`, or `SUM`. The
311
347
  same policy options are available through the CLI and MCP tool.
348
+ The dispersion floors prevent constant or nearly constant baselines from
349
+ turning negligible timing noise into an automatic critical anomaly.
312
350
  Change-point and trend detection can also be disabled independently with
313
351
  `change_point_detection_enabled=False` or `trend_detection_enabled=False`.
314
352
 
@@ -348,7 +386,11 @@ information for a DAG.
348
386
  Run continuous analysis and expose the latest DAG and bounded task-level metrics:
349
387
 
350
388
  ```bash
351
- flowsense serve-metrics example_dag --host 0.0.0.0 --port 9108
389
+ flowsense serve-metrics example_dag \
390
+ --host 0.0.0.0 \
391
+ --port 9108 \
392
+ --history-run-limit 50 \
393
+ --policy-file flowsense-policy.json
352
394
  ```
353
395
 
354
396
  See [docs/prometheus.md](docs/prometheus.md) for the metric contract,
@@ -81,6 +81,14 @@ Authentication is supplied through `AirflowAuthProvider`. Built-in providers
81
81
  cover Basic Auth, Airflow login-token exchange, static bearer tokens, and custom
82
82
  headers without coupling request collection to a deployment's identity system.
83
83
 
84
+ Collection is bounded at the Airflow API boundary whenever the configured API
85
+ supports it. Airflow 2 uses the stable batch POST endpoints, while Airflow 3
86
+ uses filtered collection endpoints for successful DAG runs and task instances.
87
+ Unsupported filter or batch responses fall back to the paginated per-run API,
88
+ preserving compatibility with older Airflow 2 deployments. This optimization
89
+ belongs exclusively to the infrastructure adapter and does not leak transport
90
+ capabilities into application or domain contracts.
91
+
84
92
  ### Delivery adapters
85
93
 
86
94
  `flowsense.cli`, `flowsense.mcp`, and `flowsense.observability` translate user input into an
@@ -16,8 +16,11 @@ AIRFLOW_USERNAME=airflow
16
16
  AIRFLOW_PASSWORD=secret
17
17
  ```
18
18
 
19
- FlowSense exchanges the credentials once and caches the returned bearer token
20
- for the lifetime of the client.
19
+ FlowSense exchanges the credentials and caches the returned bearer token for
20
+ the lifetime of the client. If an Airflow API request returns `401`, FlowSense
21
+ invalidates a login-issued token, obtains a fresh token, and retries that API
22
+ request once. A second `401` is returned as `AirflowApiError`; it is never
23
+ retried indefinitely.
21
24
 
22
25
  ### Basic authentication
23
26
 
@@ -42,6 +45,9 @@ AIRFLOW_BEARER_TOKEN=secret-token
42
45
  Username and password are not required in bearer mode. Secrets are excluded
43
46
  from the `AirflowConfig` representation, but applications must still keep them
44
47
  out of logs, shell history, source control, and command-line arguments.
48
+ Static bearer tokens are not automatically replaced after `401`; their
49
+ lifecycle remains owned by the application or identity provider that issued
50
+ them.
45
51
 
46
52
  ## Custom provider
47
53
 
@@ -74,4 +80,6 @@ provider = BearerTokenAuthProvider(load_current_token)
74
80
 
75
81
  Custom providers should return only authentication material and leave request
76
82
  execution, retry, timeout, payload validation, and error translation to
77
- `AirflowClient`.
83
+ `AirflowClient`. A `401` from a custom provider is not interpreted as permission
84
+ to rotate external credentials; the owning application decides how to refresh
85
+ them.
@@ -12,9 +12,13 @@ Configure the required `AIRFLOW_*` environment variables, then run:
12
12
  flowsense serve-metrics example_dag another_dag \
13
13
  --host 0.0.0.0 \
14
14
  --port 9108 \
15
- --interval-seconds 60
15
+ --interval-seconds 60 \
16
+ --history-run-limit 50 \
17
+ --policy-file flowsense-policy.json
16
18
  ```
17
19
 
20
+ Omit `--policy-file` to use the default analysis policy.
21
+
18
22
  Binding to `0.0.0.0` makes the endpoint reachable from the local Prometheus
19
23
  container. Do not expose this port to untrusted networks without an appropriate
20
24
  network policy or reverse proxy.
@@ -0,0 +1,63 @@
1
+ # Migrating to FlowSense 0.5
2
+
3
+ FlowSense 0.5 improves production-scale Airflow collection, authentication
4
+ resilience, and statistical drift accuracy. Existing Python, CLI, and MCP entry
5
+ points remain available, but JSON consumers must account for analysis output
6
+ schema version `1.2`.
7
+
8
+ ## Analysis output schema 1.2
9
+
10
+ Each task and handoff drift result now includes:
11
+
12
+ - `direction`: `INCREASE`, `DECREASE`, or `UNCHANGED`;
13
+ - `effective_mad`: the regularized dispersion used to calculate the robust
14
+ z-score.
15
+
16
+ The embedded policy also includes `minimum_relative_dispersion` and
17
+ `minimum_absolute_dispersion`. Consumers that validate JSON should regenerate
18
+ their model or schema with:
19
+
20
+ ```bash
21
+ flowsense schema --document analysis
22
+ ```
23
+
24
+ The batch envelope remains at schema version `1.0`; each successful analysis
25
+ inside it now uses schema version `1.2`.
26
+
27
+ ## Drift behavior
28
+
29
+ Raw MAD is still reported without modification. Score calculation now uses the
30
+ largest of raw MAD, the configured relative floor, and the configured absolute
31
+ floor. This prevents negligible timing noise on constant baselines from being
32
+ classified as an automatic critical anomaly.
33
+
34
+ The defaults are:
35
+
36
+ ```json
37
+ {
38
+ "minimum_relative_dispersion": 0.01,
39
+ "minimum_absolute_dispersion": 0.001
40
+ }
41
+ ```
42
+
43
+ Pin explicit values in a policy file if existing alert thresholds were tuned
44
+ around the previous zero-MAD behavior.
45
+
46
+ ## Airflow collection and authentication
47
+
48
+ Recent successful DAG runs and task instances use bounded or batch API calls
49
+ when supported. Older Airflow deployments automatically fall back to the
50
+ paginated per-run endpoints.
51
+
52
+ Airflow login tokens obtained through `AIRFLOW_AUTH_MODE=token` are refreshed
53
+ once after a `401` response. Basic, static bearer, and custom authentication
54
+ providers retain application-owned credential lifecycles.
55
+
56
+ ## Validation checklist
57
+
58
+ 1. Regenerate and compare the analysis JSON Schema.
59
+ 2. Validate alerting against representative historical DAG runs.
60
+ 3. Confirm the configured Airflow identity can use batch endpoints or fallback
61
+ endpoints.
62
+ 4. Run `flowsense doctor` against the target Airflow environment.
63
+ 5. Perform a canary analysis before replacing a pinned 0.4 installation.
@@ -0,0 +1,235 @@
1
+ # Production quickstart
2
+
3
+ This guide runs FlowSense as an installed Python package against an existing
4
+ Apache Airflow deployment. FlowSense remains an in-process library and CLI; it
5
+ does not require a separate hosted service or database.
6
+
7
+ ## 1. Install an isolated version
8
+
9
+ FlowSense requires Python 3.12 or 3.13.
10
+
11
+ ```bash
12
+ python3.12 -m venv .venv
13
+ source .venv/bin/activate
14
+ python -m pip install "flowsense-engine==0.5.0"
15
+ flowsense --version
16
+ ```
17
+
18
+ The expected version is `0.5.0`. Pin the version in production dependency files
19
+ and upgrade deliberately after reviewing the changelog.
20
+
21
+ ## 2. Configure Airflow access
22
+
23
+ Keep credentials in a secret manager or injected environment variables rather
24
+ than source control.
25
+
26
+ For an Airflow 3 deployment using login-token exchange:
27
+
28
+ ```bash
29
+ export AIRFLOW_BASE_URL="https://airflow.example.com"
30
+ export AIRFLOW_API_VERSION="v2"
31
+ export AIRFLOW_AUTH_MODE="token"
32
+ export AIRFLOW_USERNAME="flowsense"
33
+ export AIRFLOW_PASSWORD="replace-from-secret-manager"
34
+ ```
35
+
36
+ For an Airflow 2 deployment using Basic Auth:
37
+
38
+ ```bash
39
+ export AIRFLOW_BASE_URL="https://airflow.example.com"
40
+ export AIRFLOW_API_VERSION="v1"
41
+ export AIRFLOW_AUTH_MODE="basic"
42
+ export AIRFLOW_USERNAME="flowsense"
43
+ export AIRFLOW_PASSWORD="replace-from-secret-manager"
44
+ ```
45
+
46
+ Static bearer tokens use `AIRFLOW_AUTH_MODE=bearer` and
47
+ `AIRFLOW_BEARER_TOKEN`. Custom identity gateways can use the Python
48
+ authentication provider API described in [authentication.md](authentication.md).
49
+
50
+ Use a read-only Airflow identity with access to DAG definitions, DAG runs, and
51
+ task instances. Configure conservative network and history bounds:
52
+
53
+ ```bash
54
+ export AIRFLOW_CONNECT_TIMEOUT="10"
55
+ export AIRFLOW_READ_TIMEOUT="30"
56
+ export AIRFLOW_MAX_RETRIES="2"
57
+ export AIRFLOW_RETRY_BACKOFF="0.5"
58
+ export AIRFLOW_HISTORY_RUN_LIMIT="100"
59
+ ```
60
+
61
+ ## 3. Run a single-DAG smoke test
62
+
63
+ Validate configuration, authentication, API routing, and DAG visibility without
64
+ running an analysis:
65
+
66
+ ```bash
67
+ flowsense doctor
68
+ ```
69
+
70
+ For automation, `flowsense doctor --output json` emits structured checks and
71
+ returns exit code `1` when a required check fails.
72
+
73
+ List the active DAGs visible to the configured identity:
74
+
75
+ ```bash
76
+ flowsense dags
77
+ flowsense dags --output json
78
+ ```
79
+
80
+ Paused DAGs are excluded unless `--include-paused` is provided.
81
+
82
+ Analyze an explicit, bounded DAG set directly from the CLI:
83
+
84
+ ```bash
85
+ flowsense analyze-batch orders payments inventory \
86
+ --history-run-limit 50 \
87
+ --max-concurrency 3 \
88
+ --fail-on high \
89
+ --output-file flowsense-batch.json
90
+ ```
91
+
92
+ The command always writes the versioned batch JSON when analysis completes. It
93
+ returns exit code `1` if any DAG has an expected failure, while preserving all
94
+ successful results and failure records in the output file.
95
+
96
+ Batch analysis accepts the same policy controls as single-DAG analysis,
97
+ including history requirements, severity thresholds, mapped-task aggregation,
98
+ and change-point or trend detector settings.
99
+
100
+ For repeatable analysis across environments, create `flowsense-policy.json`:
101
+
102
+ ```json
103
+ {
104
+ "schema_version": "1.0",
105
+ "minimum_history": 10,
106
+ "baseline_window": 30,
107
+ "medium_threshold": 2.0,
108
+ "high_threshold": 3.5,
109
+ "critical_threshold": 5.0,
110
+ "minimum_relative_dispersion": 0.01,
111
+ "minimum_absolute_dispersion": 0.001,
112
+ "mapped_task_aggregation": "MAX"
113
+ }
114
+ ```
115
+
116
+ Use the same file with either command:
117
+
118
+ ```bash
119
+ flowsense analyze orders --policy-file flowsense-policy.json
120
+ flowsense analyze-batch orders payments \
121
+ --policy-file flowsense-policy.json \
122
+ --minimum-history 15
123
+ ```
124
+
125
+ Explicit CLI policy options override file values. Unknown fields, unsupported
126
+ schema versions, malformed JSON, and invalid domain settings fail before an
127
+ Airflow analysis begins. Export the policy schema with
128
+ `flowsense schema --document policy`.
129
+
130
+ To discover active DAGs automatically, keep the workload explicitly bounded:
131
+
132
+ ```bash
133
+ flowsense analyze-batch \
134
+ --all-dags \
135
+ --dag-limit 10 \
136
+ --history-run-limit 50 \
137
+ --max-concurrency 3 \
138
+ --output-file flowsense-batch.json
139
+ ```
140
+
141
+ Discovery excludes paused DAGs by default. Add `--include-paused` only when
142
+ paused workflows are intentionally part of the analysis scope. Explicit DAG
143
+ ids and `--all-dags` are mutually exclusive.
144
+
145
+ With `--fail-on`, exit code `2` means at least one successful DAG analysis
146
+ reached the selected severity. Operational DAG failures take precedence and
147
+ retain exit code `1`.
148
+
149
+ Export the matching JSON Schema for validation in downstream automation:
150
+
151
+ ```bash
152
+ flowsense schema --document batch > flowsense-batch.schema.json
153
+ ```
154
+
155
+ Start with a DAG that has several successful historical runs:
156
+
157
+ ```bash
158
+ flowsense analyze example_dag --output json
159
+ ```
160
+
161
+ Exit code `0` means analysis completed. Exit code `1` represents a configuration,
162
+ Airflow, or analysis failure. When `--fail-on` is used, exit code `2` means the
163
+ selected severity threshold was reached.
164
+
165
+ For CI:
166
+
167
+ ```bash
168
+ flowsense analyze example_dag \
169
+ --output-file analysis.json \
170
+ --fail-on high
171
+ ```
172
+
173
+ ## 4. Discover and analyze several DAGs
174
+
175
+ The repository includes a bounded production example:
176
+
177
+ ```bash
178
+ python examples/python/production_batch.py \
179
+ --dag-limit 10 \
180
+ --history-run-limit 50 \
181
+ --max-concurrency 3 \
182
+ --output flowsense-batch.json
183
+ ```
184
+
185
+ The example:
186
+
187
+ 1. loads validated Airflow configuration;
188
+ 2. discovers active DAGs through the paginated Airflow API;
189
+ 3. limits the number of selected DAGs;
190
+ 4. runs independent analyses with bounded concurrency;
191
+ 5. writes the versioned batch output contract.
192
+
193
+ Paused DAGs are excluded unless `--include-paused` is supplied. The command
194
+ returns exit code `1` when one or more expected DAG-level failures are present,
195
+ while still writing successful results and failure records.
196
+
197
+ ## 5. Size the workload
198
+
199
+ Each DAG analysis reads DAG runs, task instances for the selected successful
200
+ runs, and the current DAG structure. Start with:
201
+
202
+ - `--dag-limit 5` or `10`;
203
+ - `--history-run-limit 30` to `100`;
204
+ - `--max-concurrency 1` to `3`.
205
+
206
+ Increase these values only after observing Airflow API latency and rate limits.
207
+ FlowSense retries transient `429`, `502`, `503`, and `504` responses, but
208
+ concurrency should remain below the capacity of the Airflow webserver.
209
+
210
+ ## 6. Operate safely
211
+
212
+ - Pin the FlowSense package version.
213
+ - Inject secrets at runtime and never log them.
214
+ - Use a read-only Airflow account.
215
+ - Retain the output `schema_version` fields with stored JSON.
216
+ - Treat batch `failures` separately from anomaly severity.
217
+ - Alert when analysis stops succeeding, not only when severity increases.
218
+ - Validate upgrades in a staging Airflow environment.
219
+
220
+ Prometheus and Grafana are optional adapters. See [prometheus.md](prometheus.md),
221
+ [grafana.md](grafana.md), and [alerting.md](alerting.md) when metrics-based
222
+ operation is required.
223
+
224
+ ## Troubleshooting
225
+
226
+ `401` or `403` responses usually indicate a mismatched authentication mode or
227
+ insufficient Airflow permissions. Confirm the API version and auth backend.
228
+
229
+ Insufficient-history diagnostics mean the DAG has fewer successful observations
230
+ than the active analysis policy requires. Increase the available history or
231
+ adjust the policy deliberately; do not treat missing history as a normal result.
232
+
233
+ For timeouts or rate limiting, lower batch concurrency and history limits before
234
+ increasing retry counts. See [authentication.md](authentication.md) and
235
+ [python-api.md](python-api.md) for deeper integration options.