flowsense-engine 0.2.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.
- flowsense_engine-0.2.1/CHANGELOG.md +48 -0
- flowsense_engine-0.2.1/LICENSE +17 -0
- flowsense_engine-0.2.1/MANIFEST.in +2 -0
- flowsense_engine-0.2.1/PKG-INFO +447 -0
- flowsense_engine-0.2.1/README.md +412 -0
- flowsense_engine-0.2.1/docs/releasing.md +43 -0
- flowsense_engine-0.2.1/pyproject.toml +79 -0
- flowsense_engine-0.2.1/setup.cfg +4 -0
- flowsense_engine-0.2.1/src/flowsense/__init__.py +77 -0
- flowsense_engine-0.2.1/src/flowsense/application/__init__.py +20 -0
- flowsense_engine-0.2.1/src/flowsense/application/analyzer.py +68 -0
- flowsense_engine-0.2.1/src/flowsense/application/output.py +128 -0
- flowsense_engine-0.2.1/src/flowsense/application/pipeline.py +210 -0
- flowsense_engine-0.2.1/src/flowsense/application/ports.py +11 -0
- flowsense_engine-0.2.1/src/flowsense/application/request.py +32 -0
- flowsense_engine-0.2.1/src/flowsense/application/serialization.py +177 -0
- flowsense_engine-0.2.1/src/flowsense/cli/__init__.py +0 -0
- flowsense_engine-0.2.1/src/flowsense/cli/main.py +195 -0
- flowsense_engine-0.2.1/src/flowsense/cli/report.py +233 -0
- flowsense_engine-0.2.1/src/flowsense/collector/__init__.py +0 -0
- flowsense_engine-0.2.1/src/flowsense/collector/airflow_client.py +5 -0
- flowsense_engine-0.2.1/src/flowsense/config.py +72 -0
- flowsense_engine-0.2.1/src/flowsense/domain/__init__.py +52 -0
- flowsense_engine-0.2.1/src/flowsense/domain/enums.py +47 -0
- flowsense_engine-0.2.1/src/flowsense/domain/exceptions.py +25 -0
- flowsense_engine-0.2.1/src/flowsense/domain/models.py +19 -0
- flowsense_engine-0.2.1/src/flowsense/domain/policy.py +55 -0
- flowsense_engine-0.2.1/src/flowsense/domain/results.py +187 -0
- flowsense_engine-0.2.1/src/flowsense/engine/__init__.py +0 -0
- flowsense_engine-0.2.1/src/flowsense/engine/analyzer.py +17 -0
- flowsense_engine-0.2.1/src/flowsense/engine/change_point.py +87 -0
- flowsense_engine-0.2.1/src/flowsense/engine/drift.py +80 -0
- flowsense_engine-0.2.1/src/flowsense/engine/history.py +34 -0
- flowsense_engine-0.2.1/src/flowsense/engine/impact.py +51 -0
- flowsense_engine-0.2.1/src/flowsense/engine/propagation.py +173 -0
- flowsense_engine-0.2.1/src/flowsense/engine/root_cause.py +148 -0
- flowsense_engine-0.2.1/src/flowsense/engine/timing.py +221 -0
- flowsense_engine-0.2.1/src/flowsense/engine/trend.py +82 -0
- flowsense_engine-0.2.1/src/flowsense/infrastructure/__init__.py +1 -0
- flowsense_engine-0.2.1/src/flowsense/infrastructure/airflow/__init__.py +13 -0
- flowsense_engine-0.2.1/src/flowsense/infrastructure/airflow/client.py +373 -0
- flowsense_engine-0.2.1/src/flowsense/infrastructure/airflow/dto.py +33 -0
- flowsense_engine-0.2.1/src/flowsense/infrastructure/airflow/exceptions.py +31 -0
- flowsense_engine-0.2.1/src/flowsense/infrastructure/airflow/mapper.py +27 -0
- flowsense_engine-0.2.1/src/flowsense/mcp/__init__.py +0 -0
- flowsense_engine-0.2.1/src/flowsense/mcp/server.py +75 -0
- flowsense_engine-0.2.1/src/flowsense/models/__init__.py +7 -0
- flowsense_engine-0.2.1/src/flowsense/models/dag_analysis.py +3 -0
- flowsense_engine-0.2.1/src/flowsense/models/task_run.py +3 -0
- flowsense_engine-0.2.1/src/flowsense/py.typed +0 -0
- flowsense_engine-0.2.1/src/flowsense/version.py +6 -0
- flowsense_engine-0.2.1/src/flowsense_engine.egg-info/PKG-INFO +447 -0
- flowsense_engine-0.2.1/src/flowsense_engine.egg-info/SOURCES.txt +81 -0
- flowsense_engine-0.2.1/src/flowsense_engine.egg-info/dependency_links.txt +1 -0
- flowsense_engine-0.2.1/src/flowsense_engine.egg-info/entry_points.txt +3 -0
- flowsense_engine-0.2.1/src/flowsense_engine.egg-info/requires.txt +14 -0
- flowsense_engine-0.2.1/src/flowsense_engine.egg-info/top_level.txt +1 -0
- flowsense_engine-0.2.1/tests/test_airflow_client.py +313 -0
- flowsense_engine-0.2.1/tests/test_airflow_client_integration.py +73 -0
- flowsense_engine-0.2.1/tests/test_airflow_compatibility.py +237 -0
- flowsense_engine-0.2.1/tests/test_airflow_mapper.py +58 -0
- flowsense_engine-0.2.1/tests/test_airflow_resilience.py +150 -0
- flowsense_engine-0.2.1/tests/test_analysis_output.py +76 -0
- flowsense_engine-0.2.1/tests/test_analysis_pipeline.py +46 -0
- flowsense_engine-0.2.1/tests/test_analysis_request.py +36 -0
- flowsense_engine-0.2.1/tests/test_analyzer.py +473 -0
- flowsense_engine-0.2.1/tests/test_change_point.py +53 -0
- flowsense_engine-0.2.1/tests/test_cli.py +248 -0
- flowsense_engine-0.2.1/tests/test_cli_report.py +140 -0
- flowsense_engine-0.2.1/tests/test_dag_summary.py +134 -0
- flowsense_engine-0.2.1/tests/test_domain.py +46 -0
- flowsense_engine-0.2.1/tests/test_drift.py +85 -0
- flowsense_engine-0.2.1/tests/test_history.py +128 -0
- flowsense_engine-0.2.1/tests/test_impact.py +149 -0
- flowsense_engine-0.2.1/tests/test_mcp_integration.py +54 -0
- flowsense_engine-0.2.1/tests/test_mcp_server.py +319 -0
- flowsense_engine-0.2.1/tests/test_package_metadata.py +11 -0
- flowsense_engine-0.2.1/tests/test_policy.py +97 -0
- flowsense_engine-0.2.1/tests/test_propagation.py +426 -0
- flowsense_engine-0.2.1/tests/test_public_api.py +51 -0
- flowsense_engine-0.2.1/tests/test_root_cause.py +281 -0
- flowsense_engine-0.2.1/tests/test_timing.py +260 -0
- flowsense_engine-0.2.1/tests/test_trend.py +54 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to FlowSense are documented in this file. The project uses
|
|
4
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
5
|
+
|
|
6
|
+
## [0.2.1] - 2026-09-10
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
|
|
10
|
+
- Renamed the Python distribution to `flowsense-engine` while preserving the
|
|
11
|
+
`flowsense` import package and CLI command.
|
|
12
|
+
- Added tokenless PyPI publishing through GitHub Actions Trusted Publishing.
|
|
13
|
+
|
|
14
|
+
## [0.2.0] - 2026-09-10
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Task handoff drift, impact classification, propagation, and root-cause analysis.
|
|
19
|
+
- Configurable drift, mapped-task aggregation, change-point, and trend policies.
|
|
20
|
+
- Apache Airflow 2 and 3 API compatibility with pagination and bounded history.
|
|
21
|
+
- Retry, timeout, backoff, and `Retry-After` handling for Airflow requests.
|
|
22
|
+
- Historical DAG run analysis with preceding-history isolation.
|
|
23
|
+
- Rich CLI reports, JSON output, severity-based exit thresholds, and schema output.
|
|
24
|
+
- MCP analysis tool with the same policy and versioned response contract as the CLI.
|
|
25
|
+
- Typed `AnalysisRequest` and `AnalysisDocument` contracts with JSON Schema support.
|
|
26
|
+
- Supported top-level library API, typed package marker, and Python 3.12/3.13 CI.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- Split the analysis workflow into domain, application, infrastructure, and adapter
|
|
31
|
+
boundaries.
|
|
32
|
+
- Analysis output schema advanced to version `1.1` with `current_dag_run_id`.
|
|
33
|
+
- Expected configuration, Airflow API, and payload failures now use a unified error
|
|
34
|
+
hierarchy.
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- Preserved anomaly origins across normal dependency gaps.
|
|
39
|
+
- Detected drift when the historical median absolute deviation is zero.
|
|
40
|
+
- Aggregated dynamically mapped task instances before analysis.
|
|
41
|
+
- Reported insufficient history and invalid handoff timing as diagnostics.
|
|
42
|
+
|
|
43
|
+
## [0.1.0] - 2026-08-18
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- Initial FlowSense prototype with Airflow task-duration collection and robust
|
|
48
|
+
median/MAD drift detection.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Copyright 2026 Omer Cengiz
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flowsense-engine
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Temporal drift and anomaly detection for Apache Airflow
|
|
5
|
+
Author: Omer Cengiz
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/omercengiz/flowsense-engine
|
|
8
|
+
Project-URL: Issues, https://github.com/omercengiz/flowsense-engine/issues
|
|
9
|
+
Project-URL: Repository, https://github.com/omercengiz/flowsense-engine
|
|
10
|
+
Project-URL: Changelog, https://github.com/omercengiz/flowsense-engine/blob/master/CHANGELOG.md
|
|
11
|
+
Keywords: airflow,anomaly-detection,data-engineering,observability
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: httpx>=0.27
|
|
23
|
+
Requires-Dist: pydantic>=2.8
|
|
24
|
+
Requires-Dist: numpy>=2.0
|
|
25
|
+
Requires-Dist: typer>=0.12
|
|
26
|
+
Requires-Dist: rich>=13.7
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
29
|
+
Requires-Dist: pyright>=1.1.400; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
32
|
+
Provides-Extra: mcp
|
|
33
|
+
Requires-Dist: mcp[cli]>=2.0; extra == "mcp"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# FlowSense Engine
|
|
37
|
+
|
|
38
|
+
Temporal drift, anomaly detection, and dependency-aware propagation analysis for Apache Airflow.
|
|
39
|
+
|
|
40
|
+
Current package release: `0.2.1`. See [CHANGELOG.md](CHANGELOG.md) for release
|
|
41
|
+
notes and [docs/releasing.md](docs/releasing.md) for the release checklist.
|
|
42
|
+
|
|
43
|
+
FlowSense analyzes historical DAG executions to identify abnormal task behavior and trace how anomalies propagate through downstream dependencies.
|
|
44
|
+
|
|
45
|
+
## Why FlowSense?
|
|
46
|
+
|
|
47
|
+
Airflow provides rich execution metadata, but identifying behavioral drift across historical runs still requires manual analysis.
|
|
48
|
+
|
|
49
|
+
FlowSense is designed to answer questions such as:
|
|
50
|
+
|
|
51
|
+
- Which task started behaving differently?
|
|
52
|
+
- How large is the deviation from its historical baseline?
|
|
53
|
+
- Is the anomaly isolated or affecting downstream tasks?
|
|
54
|
+
- Where is the most likely origin of the slowdown?
|
|
55
|
+
|
|
56
|
+
## Current Features
|
|
57
|
+
|
|
58
|
+
- Apache Airflow 3 REST API integration
|
|
59
|
+
- JWT-based Airflow authentication
|
|
60
|
+
- DAG run collection
|
|
61
|
+
- Task instance collection
|
|
62
|
+
- Automatic DAG dependency discovery
|
|
63
|
+
- Task duration history generation
|
|
64
|
+
- Median-based historical baselines
|
|
65
|
+
- MAD-based robust Z-score drift detection
|
|
66
|
+
- Severity classification
|
|
67
|
+
- Task handoff delay analysis
|
|
68
|
+
- Task impact classification (`OWN_DRIFT`, `INHERITED_DELAY`, and `COMBINED`)
|
|
69
|
+
- Multi-hop and branching propagation analysis
|
|
70
|
+
- Primary root-cause selection
|
|
71
|
+
- CLI-based DAG analysis
|
|
72
|
+
- MCP server integration
|
|
73
|
+
|
|
74
|
+
## Example
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
flowsense analyze flowsense_demo
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Example output:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
FlowSense Analysis — flowsense_demo
|
|
84
|
+
|
|
85
|
+
┏━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━┓
|
|
86
|
+
┃ Task ┃ Baseline ┃ Current ┃ Deviation ┃ Z-Score ┃ Severity ┃ Impact ┃
|
|
87
|
+
┡━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━┩
|
|
88
|
+
│ extract │ 1.56s │ 1.61s │ +3.4% │ 0.17 │ NORMAL │ NORMAL │
|
|
89
|
+
│ transform │ 3.34s │ 9.61s │ +187.6% │ 7.61 │ CRITICAL │ OWN_DRIFT │
|
|
90
|
+
│ load │ 1.40s │ 2.11s │ +50.2% │ 3.17 │ MEDIUM │ COMBINED │
|
|
91
|
+
└───────────┴──────────┴─────────┴───────────┴─────────┴──────────┴───────────┘
|
|
92
|
+
|
|
93
|
+
Overall Severity: CRITICAL
|
|
94
|
+
Primary Origin: transform
|
|
95
|
+
Reason: OWN_DRIFT
|
|
96
|
+
Severity: CRITICAL
|
|
97
|
+
Propagation Score: 0.33
|
|
98
|
+
|
|
99
|
+
Propagation Analysis
|
|
100
|
+
|
|
101
|
+
Origin: transform
|
|
102
|
+
Path: transform -> load
|
|
103
|
+
Propagation Score: 0.33
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Architecture
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
Apache Airflow
|
|
110
|
+
│
|
|
111
|
+
▼
|
|
112
|
+
Collector
|
|
113
|
+
│
|
|
114
|
+
▼
|
|
115
|
+
Task Run and Handoff History
|
|
116
|
+
│
|
|
117
|
+
▼
|
|
118
|
+
Drift and Impact Analysis
|
|
119
|
+
│
|
|
120
|
+
▼
|
|
121
|
+
Propagation and Root-Cause Analysis
|
|
122
|
+
│
|
|
123
|
+
├── CLI
|
|
124
|
+
└── MCP Server
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Installation
|
|
128
|
+
|
|
129
|
+
FlowSense currently requires Python 3.12 or newer.
|
|
130
|
+
Python 3.12 and 3.13 are covered by the CI test matrix.
|
|
131
|
+
|
|
132
|
+
Clone the repository:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
git clone <repository-url>
|
|
136
|
+
cd flowsense-engine
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Create a virtual environment and install the project:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
uv venv --python 3.12
|
|
143
|
+
source .venv/bin/activate
|
|
144
|
+
uv pip install -e ".[dev,mcp]"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Once published on PyPI, install the distribution with:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
pip install flowsense-engine
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The distribution name is `flowsense-engine`; Python imports and CLI commands
|
|
154
|
+
remain `flowsense`.
|
|
155
|
+
|
|
156
|
+
Check the installed package version:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
flowsense --version
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Configuration
|
|
163
|
+
|
|
164
|
+
FlowSense connects to Apache Airflow through its REST API.
|
|
165
|
+
|
|
166
|
+
Copy the example environment file:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
cp .env.example .env
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Configure:
|
|
173
|
+
|
|
174
|
+
```env
|
|
175
|
+
AIRFLOW_BASE_URL=http://localhost:8080
|
|
176
|
+
AIRFLOW_USERNAME=your_username
|
|
177
|
+
AIRFLOW_PASSWORD=your_password
|
|
178
|
+
AIRFLOW_API_VERSION=v2
|
|
179
|
+
AIRFLOW_AUTH_MODE=token
|
|
180
|
+
AIRFLOW_CONNECT_TIMEOUT=10
|
|
181
|
+
AIRFLOW_READ_TIMEOUT=10
|
|
182
|
+
AIRFLOW_MAX_RETRIES=2
|
|
183
|
+
AIRFLOW_RETRY_BACKOFF=0.5
|
|
184
|
+
AIRFLOW_HISTORY_RUN_LIMIT=100
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Use `AIRFLOW_API_VERSION=v1` with `AIRFLOW_AUTH_MODE=basic` for Airflow 2.x
|
|
188
|
+
Stable REST API deployments. Airflow 3.x uses the `v2` API and typically uses
|
|
189
|
+
token authentication. Authentication still depends on the API auth backend
|
|
190
|
+
configured in the Airflow deployment.
|
|
191
|
+
|
|
192
|
+
Transient transport failures and HTTP `429`, `502`, `503`, and `504` responses
|
|
193
|
+
are retried with exponential backoff. `Retry-After` is honored when Airflow
|
|
194
|
+
provides it. Connect/read timeouts, retry count, and base backoff can be tuned
|
|
195
|
+
with the environment variables above; permanent client errors are returned
|
|
196
|
+
without retrying.
|
|
197
|
+
|
|
198
|
+
Load the environment variables:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
export $(grep -v '^#' .env | xargs)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Then run:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
flowsense analyze <dag_id>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
The CLI report includes a DAG summary and separate tables for task drift,
|
|
211
|
+
handoff drift, change points, trends, propagation paths, and diagnostics.
|
|
212
|
+
Results are ordered by severity or subject so repeated analyses remain easy to
|
|
213
|
+
compare.
|
|
214
|
+
|
|
215
|
+
For automation and CI/CD integrations, request the versioned JSON document:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
flowsense analyze <dag_id> --output json
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
CI jobs can also fail when the analysis reaches a selected severity:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
flowsense analyze <dag_id> --output json --fail-on high
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
`--fail-on` accepts `medium`, `high`, or `critical`. The report is always
|
|
228
|
+
written before FlowSense exits: code `0` means the severity is below the
|
|
229
|
+
threshold, code `2` means the threshold was reached, and code `1` remains
|
|
230
|
+
reserved for analysis or Airflow request failures.
|
|
231
|
+
|
|
232
|
+
By default, FlowSense collects task instances for the most recent 100
|
|
233
|
+
successful DAG runs. This prevents long-lived DAGs from generating an
|
|
234
|
+
unbounded number of task-instance API requests. Change the default with
|
|
235
|
+
`AIRFLOW_HISTORY_RUN_LIMIT`, or override it for one CLI analysis:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
flowsense analyze <dag_id> --history-run-limit 250
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
The MCP tool exposes the same override as `history_run_limit`. The limit must
|
|
242
|
+
be at least `2` and cannot be lower than `minimum_history`; contradictory
|
|
243
|
+
requests are rejected before FlowSense connects to Airflow.
|
|
244
|
+
|
|
245
|
+
To investigate or backtest a specific successful DAG run, select it as the
|
|
246
|
+
current observation. FlowSense excludes every newer run from its baseline:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
flowsense analyze <dag_id> --dag-run-id <dag_run_id>
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
The MCP tool exposes the same option as `dag_run_id`. Analysis output includes
|
|
253
|
+
`current_dag_run_id`; this field was introduced in output schema version `1.1`.
|
|
254
|
+
|
|
255
|
+
The JSON document and MCP tool response share the same serialization contract
|
|
256
|
+
and include a `schema_version` field. The serializer is also available from the
|
|
257
|
+
public library API as `flowsense.serialize_analysis`.
|
|
258
|
+
|
|
259
|
+
For typed integrations, `flowsense.build_analysis_document` returns a
|
|
260
|
+
validated Pydantic `AnalysisDocument`. Its versioned JSON Schema is available
|
|
261
|
+
through `flowsense.analysis_json_schema()`, allowing consumers to validate or
|
|
262
|
+
generate models for the CLI and MCP response contract.
|
|
263
|
+
|
|
264
|
+
The same schema can be emitted without connecting to Airflow:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
flowsense schema > flowsense-analysis.schema.json
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
This output is deterministic and can be used in CI contract checks, editor
|
|
271
|
+
tooling, or client code generation.
|
|
272
|
+
|
|
273
|
+
## Library API
|
|
274
|
+
|
|
275
|
+
FlowSense can also be used as a Python library through its supported top-level
|
|
276
|
+
API:
|
|
277
|
+
|
|
278
|
+
```python
|
|
279
|
+
from flowsense import AirflowClient, analyze_dag
|
|
280
|
+
|
|
281
|
+
with AirflowClient() as source:
|
|
282
|
+
analysis = analyze_dag(
|
|
283
|
+
dag_id="flowsense_demo",
|
|
284
|
+
source=source,
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
print(analysis.overall_severity)
|
|
288
|
+
print(analysis.primary_origin)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Analysis behavior can be customized with an immutable policy:
|
|
292
|
+
|
|
293
|
+
```python
|
|
294
|
+
from flowsense import AnalysisPolicy, MappedTaskAggregation
|
|
295
|
+
|
|
296
|
+
policy = AnalysisPolicy(
|
|
297
|
+
minimum_history=10,
|
|
298
|
+
baseline_window=30,
|
|
299
|
+
medium_threshold=2.5,
|
|
300
|
+
high_threshold=4.0,
|
|
301
|
+
critical_threshold=6.0,
|
|
302
|
+
mapped_task_aggregation=MappedTaskAggregation.MAX,
|
|
303
|
+
change_point_minimum_segment_size=4,
|
|
304
|
+
change_point_score_threshold=4.0,
|
|
305
|
+
trend_minimum_observations=8,
|
|
306
|
+
trend_score_threshold=4.0,
|
|
307
|
+
trend_minimum_directional_consistency=0.75,
|
|
308
|
+
)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
`baseline_window` limits the number of historical values used before the current
|
|
312
|
+
run. Mapped task durations can be aggregated with `MAX`, `MEAN`, or `SUM`. The
|
|
313
|
+
same policy options are available through the CLI and MCP tool.
|
|
314
|
+
Change-point and trend detection can also be disabled independently with
|
|
315
|
+
`change_point_detection_enabled=False` or `trend_detection_enabled=False`.
|
|
316
|
+
|
|
317
|
+
CLI and MCP inputs are normalized into an immutable `AnalysisRequest` before
|
|
318
|
+
execution. Library integrations may use the same public DTO when they need to
|
|
319
|
+
validate a DAG id, policy, and explicit history collection limit together.
|
|
320
|
+
|
|
321
|
+
Every `DAGAnalysis` exposes a derived `summary` with task-analysis coverage,
|
|
322
|
+
severity distribution, anomalous task and handoff counts, uniquely affected
|
|
323
|
+
tasks, structural signals, and diagnostics. The same DAG-level summary is
|
|
324
|
+
included in CLI and MCP output.
|
|
325
|
+
|
|
326
|
+
Custom data sources can implement the `DAGDataSource` protocol and be passed to
|
|
327
|
+
`analyze_dag`. Names exported directly from `flowsense` form the supported public
|
|
328
|
+
API. Imports from internal packages such as `flowsense.engine` should be treated
|
|
329
|
+
as implementation details and may change before version 1.0.
|
|
330
|
+
|
|
331
|
+
Expected operational failures derive from `FlowSenseError`. Library consumers
|
|
332
|
+
can catch `ConfigurationError`, `AirflowApiError`, or `AirflowDataError` for
|
|
333
|
+
more specific handling. CLI failures return exit code `1`; MCP converts these
|
|
334
|
+
failures into tool errors without exposing response bodies or parser details.
|
|
335
|
+
|
|
336
|
+
## MCP Server
|
|
337
|
+
|
|
338
|
+
Start the FlowSense MCP server over stdio:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
flowsense-mcp
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
The server exposes the `analyze_airflow_dag` tool, which returns task drift,
|
|
345
|
+
handoff drift, impact classification, propagation paths, and primary root-cause
|
|
346
|
+
information for a DAG.
|
|
347
|
+
|
|
348
|
+
## Development
|
|
349
|
+
|
|
350
|
+
Run unit tests:
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
python -m pytest -m "not integration" -v
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Run the complete test suite when a local Airflow instance is available:
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
python -m pytest -v
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Lint:
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
ruff check .
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
Check formatting:
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
ruff format --check .
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Apply formatting:
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
ruff format .
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Project Structure
|
|
381
|
+
|
|
382
|
+
```text
|
|
383
|
+
src/flowsense/
|
|
384
|
+
├── application/
|
|
385
|
+
│ ├── analyzer.py
|
|
386
|
+
│ ├── pipeline.py
|
|
387
|
+
│ └── ports.py
|
|
388
|
+
├── domain/
|
|
389
|
+
├── engine/
|
|
390
|
+
│ ├── change_point.py
|
|
391
|
+
│ ├── trend.py
|
|
392
|
+
│ ├── drift.py
|
|
393
|
+
│ ├── history.py
|
|
394
|
+
│ ├── impact.py
|
|
395
|
+
│ ├── propagation.py
|
|
396
|
+
│ ├── root_cause.py
|
|
397
|
+
│ └── timing.py
|
|
398
|
+
├── infrastructure/
|
|
399
|
+
│ └── airflow/
|
|
400
|
+
├── cli/
|
|
401
|
+
├── mcp/
|
|
402
|
+
├── collector/ # backward-compatible imports
|
|
403
|
+
└── models/ # backward-compatible imports
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## Detection Approach
|
|
407
|
+
|
|
408
|
+
The current drift detector uses robust statistics rather than machine learning.
|
|
409
|
+
|
|
410
|
+
For each task, historical execution durations are used to calculate a median baseline and Median Absolute Deviation (MAD).
|
|
411
|
+
|
|
412
|
+
The latest execution is compared against that baseline using a robust Z-score.
|
|
413
|
+
|
|
414
|
+
This makes the detector less sensitive to historical outliers than approaches based only on mean and standard deviation.
|
|
415
|
+
|
|
416
|
+
Propagation scores are normalized to the `0.0–1.0` range. Downstream task
|
|
417
|
+
severity is weighted by graph distance with a `0.8` decay per hop, so anomalies
|
|
418
|
+
closer to the origin contribute more strongly than anomalies farther along the
|
|
419
|
+
same path.
|
|
420
|
+
|
|
421
|
+
FlowSense also scans ordered task-duration and handoff-delay histories for
|
|
422
|
+
persistent level shifts. Each candidate split must leave at least three
|
|
423
|
+
observations on both sides. Candidates are compared with a robust, MAD-based
|
|
424
|
+
score, and detected changes report their location, direction, before/after
|
|
425
|
+
medians, percentage change, and score. This prevents a single latest-run outlier
|
|
426
|
+
from being reported as a structural change.
|
|
427
|
+
|
|
428
|
+
FlowSense detects sustained increasing and decreasing trends in ordered task
|
|
429
|
+
durations and handoff delays with a robust Theil-Sen slope. A trend must contain
|
|
430
|
+
at least five observations, meet a minimum directional-consistency ratio, and
|
|
431
|
+
exceed a MAD-based score threshold. Results include the per-run slope, estimated
|
|
432
|
+
total and percentage change, direction, consistency, and score.
|
|
433
|
+
|
|
434
|
+
The application layer coordinates analysis through explicit task and handoff
|
|
435
|
+
pipeline stages. Each stage returns typed drift, structural-signal, and
|
|
436
|
+
diagnostic results, while `analyze_dag` remains the composition point for impact,
|
|
437
|
+
propagation, root-cause, and DAG-level output.
|
|
438
|
+
|
|
439
|
+
## Project Status
|
|
440
|
+
|
|
441
|
+
FlowSense is currently in early development.
|
|
442
|
+
|
|
443
|
+
The current implementation should be considered experimental and is not yet intended for production use.
|
|
444
|
+
|
|
445
|
+
## License
|
|
446
|
+
|
|
447
|
+
Licensed under the Apache License 2.0.
|