agentflow-runtime 1.5.0__tar.gz → 1.6.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.
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/.gitignore +50 -5
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/CHANGELOG.md +275 -59
- agentflow_runtime-1.6.0/PKG-INFO +280 -0
- agentflow_runtime-1.6.0/README.md +219 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/pyproject.toml +61 -9
- agentflow_runtime-1.6.0/requirements.txt +15 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/constants.py +1 -1
- agentflow_runtime-1.6.0/src/db_concurrency.py +24 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/ingestion/cdc/normalizer.py +1 -1
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/orchestration/dags/daily_batch.py +2 -1
- agentflow_runtime-1.6.0/src/processing/clickhouse_sink.py +210 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/event_replayer.py +26 -19
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/flink_jobs/Dockerfile +1 -28
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/flink_jobs/session_aggregator.py +3 -2
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/flink_jobs/stream_processor.py +19 -10
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/iceberg_sink.py +24 -3
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/local_pipeline.py +57 -4
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/outbox.py +62 -3
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/alert_dispatcher.py +7 -9
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/alerts/dispatcher.py +16 -19
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/alerts/escalation.py +84 -24
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/alerts/evaluator.py +19 -4
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/alerts/history.py +30 -26
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/analytics.py +41 -16
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/auth/key_rotation.py +2 -2
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/auth/manager.py +16 -4
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/auth/middleware.py +7 -3
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/auth/usage_table.py +2 -2
- agentflow_runtime-1.6.0/src/serving/api/egress_guard.py +89 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/main.py +5 -10
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/rate_limiter.py +21 -11
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/routers/agent_query.py +29 -69
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/routers/alerts.py +26 -3
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/routers/batch.py +28 -82
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/routers/deadletter.py +163 -121
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/routers/lineage.py +53 -42
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/routers/search.py +1 -1
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/routers/slo.py +31 -10
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/routers/stream.py +21 -62
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/routers/webhooks.py +20 -2
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/templates/admin.html +1 -1
- agentflow_runtime-1.6.0/src/serving/api/webhook_dispatcher.py +682 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/audit_publisher.py +13 -1
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/backends/clickhouse_backend.py +226 -32
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/backends/duckdb_backend.py +5 -3
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/cache.py +15 -7
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/catalog.py +50 -6
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/contract_registry.py +18 -1
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_engine.py +208 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_sql_engine/__init__.py +69 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_sql_engine/_sql_envelope.py +89 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_sql_engine/context.py +162 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_sql_engine/engine.py +85 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_sql_engine/graph.py +180 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_sql_engine/guards.py +210 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_sql_engine/nodes.py +200 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_sql_engine/parsing.py +98 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_sql_engine/prompts/__init__.py +26 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_sql_engine/prompts/generate_sql.txt +63 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_sql_engine/prompts/repair_sql.txt +34 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_sql_engine/provider.py +128 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/nl_sql_engine/state.py +96 -0
- agentflow_runtime-1.6.0/src/serving/semantic_layer/query/engine.py +215 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/query/entity_queries.py +6 -3
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/query/nl_queries.py +26 -9
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/query/sql_builder.py +56 -25
- agentflow_runtime-1.6.0/src/serving/semantic_layer/query/sql_guard.py +6 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/search_index.py +8 -2
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/sql_guard.py +27 -0
- agentflow_runtime-1.5.0/PKG-INFO +0 -299
- agentflow_runtime-1.5.0/README.md +0 -238
- agentflow_runtime-1.5.0/requirements.txt +0 -4
- agentflow_runtime-1.5.0/src/serving/api/webhook_dispatcher.py +0 -424
- agentflow_runtime-1.5.0/src/serving/masking.py +0 -122
- agentflow_runtime-1.5.0/src/serving/semantic_layer/nl_engine.py +0 -189
- agentflow_runtime-1.5.0/src/serving/semantic_layer/query/engine.py +0 -82
- agentflow_runtime-1.5.0/src/serving/semantic_layer/query/sql_guard.py +0 -3
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/LICENSE +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/ingestion/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/ingestion/cdc/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/ingestion/connectors/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/ingestion/connectors/mysql_cdc.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/ingestion/connectors/postgres_cdc.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/ingestion/producers/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/ingestion/producers/event_producer.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/ingestion/schemas/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/ingestion/schemas/events.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/ingestion/tenant_router.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/logger.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/orchestration/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/orchestration/dags/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/flink_jobs/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/flink_jobs/checkpointing.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/flink_jobs/session_aggregation.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/tracing.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/transformations/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/processing/transformations/enrichment.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/quality/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/quality/monitors/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/quality/monitors/freshness_monitor.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/quality/monitors/metrics_collector.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/quality/validators/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/quality/validators/schema_validator.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/quality/validators/semantic_validator.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/alerts/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/auth/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/metrics.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/middleware/logging.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/middleware/metrics.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/middleware/tracing.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/routers/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/routers/admin.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/routers/admin_ui.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/routers/contracts.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/security.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/telemetry.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/api/versioning.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/backends/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/db_pool.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/duckdb_connection.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/entity_type_registry.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/query/__init__.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/query/contracts.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/query/metric_queries.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/query_engine.py +0 -0
- {agentflow_runtime-1.5.0 → agentflow_runtime-1.6.0}/src/serving/semantic_layer/schema_evolution.py +0 -0
|
@@ -72,7 +72,7 @@ node_modules/
|
|
|
72
72
|
# Mutation testing output
|
|
73
73
|
mutants/
|
|
74
74
|
|
|
75
|
-
#
|
|
75
|
+
# Local working notes (root-level temp .md created during dev sessions).
|
|
76
76
|
# NOTE: BCG_audit.md was removed from this list on 2026-04-19 -
|
|
77
77
|
# it was a release artifact, not a session note.
|
|
78
78
|
/codex_res.md
|
|
@@ -93,12 +93,14 @@ integrations/agentflow_integrations/**/*.py[cod]
|
|
|
93
93
|
agentflow_bench_debug*.duckdb*
|
|
94
94
|
agentflow_demo_api.duckdb*
|
|
95
95
|
|
|
96
|
-
# Local autopilot runtime state.
|
|
96
|
+
# Local autopilot tooling + runtime state (kept locally, not published).
|
|
97
97
|
.autopilot/
|
|
98
|
+
/scripts/autopilot.ps1
|
|
99
|
+
/scripts/install-autopilot-task.ps1
|
|
100
|
+
/tests/unit/test_autopilot_runner.py
|
|
98
101
|
|
|
99
|
-
#
|
|
100
|
-
#
|
|
101
|
-
# stay quiet without touching the files themselves.
|
|
102
|
+
# Local scratch notes at the repo root (audit prompts/results). Ignored so
|
|
103
|
+
# the clean-tree gate and git status stay quiet without touching the files.
|
|
102
104
|
/p[0-9].md
|
|
103
105
|
/p[0-9]_res*.md
|
|
104
106
|
/p_res*.md
|
|
@@ -106,3 +108,46 @@ agentflow_demo_api.duckdb*
|
|
|
106
108
|
|
|
107
109
|
# Security scan workdir (generated by .github/workflows/security.yml safety job)
|
|
108
110
|
.tmp-security/
|
|
111
|
+
|
|
112
|
+
# Internal working notes / autonomous-session artifacts — kept locally, not published.
|
|
113
|
+
# These are process/handoff/scratch docs, not product or engineering documentation.
|
|
114
|
+
/AGENT_STATE.md
|
|
115
|
+
/AUTOPILOT.md
|
|
116
|
+
/BACKLOG.md
|
|
117
|
+
/help.md
|
|
118
|
+
/res.md
|
|
119
|
+
/all-open-questions-closure-plan.md
|
|
120
|
+
/close-gaps-plan.md
|
|
121
|
+
/road-to-9.8.md
|
|
122
|
+
/desc_for_julia.md
|
|
123
|
+
/fable_*.md
|
|
124
|
+
/next-session-*.md
|
|
125
|
+
/second-opinion-*.md
|
|
126
|
+
/.pi/
|
|
127
|
+
/.workflow/
|
|
128
|
+
/res/
|
|
129
|
+
docs/dv2-multi-branch/kimi_*.md
|
|
130
|
+
docs/dv2-multi-branch/RECORDING_DAY.md
|
|
131
|
+
docs/dv2-multi-branch/pitch.md
|
|
132
|
+
docs/dv2-multi-branch/brief.md
|
|
133
|
+
docs/operations/local-verification-matrix.md
|
|
134
|
+
docs/release-readiness-archive/
|
|
135
|
+
docs/codex-tasks/
|
|
136
|
+
docs/plans/codex-archive/
|
|
137
|
+
docs/lessons/
|
|
138
|
+
docs/audits/
|
|
139
|
+
docs/exploration/
|
|
140
|
+
docs/audit-history.md
|
|
141
|
+
docs/SESSION_HANDOFF.md
|
|
142
|
+
docs/dv2-multi-branch/SESSION_HANDOFF*.md
|
|
143
|
+
docs/customer-discovery-*.md
|
|
144
|
+
docs/pricing-validation-plan.md
|
|
145
|
+
docs/v1-1-interview-prep.md
|
|
146
|
+
docs/v1-1-research.md
|
|
147
|
+
docs/operations/autonomous-compact-safe-process.md
|
|
148
|
+
docs/operations/external-gate-evidence-intake.md
|
|
149
|
+
docs/operations/external-pen-test-attestation-handoff.md
|
|
150
|
+
docs/operations/generated-external-gate-pack-*.md
|
|
151
|
+
docs/operations/guarded-autopilot-*.md
|
|
152
|
+
docs/operations/immutable-retention-evidence-handoff.md
|
|
153
|
+
docs/operations/security-evidence-template.md
|
|
@@ -4,6 +4,236 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.6.0] - 2026-07-02
|
|
8
|
+
|
|
9
|
+
### Added — vault-side PII governance on the engine (ADR 0006 Phase 2, executed 2026-07-02)
|
|
10
|
+
|
|
11
|
+
- **New `warehouse/agentflow/dv2/governance/`** — ClickHouse RBAC as the PII
|
|
12
|
+
boundary for the DV2 vault, replacing the removed app-level string-parse
|
|
13
|
+
gate with access control on resolved columns: `dv2_analyst` (cross-branch
|
|
14
|
+
analytics, fail-closed allow-list, contact-PII columns never granted) and
|
|
15
|
+
per-jurisdiction `dv2_pii_officer__<branch>` roles (own branch's
|
|
16
|
+
`bv_customer_mdm` view + personal satellite only), plus row policies
|
|
17
|
+
scoping the shared `rv.hub_customer` to the officer's jurisdiction (with
|
|
18
|
+
the mandatory catch-all keeping non-officer visibility independent of
|
|
19
|
+
`users_without_row_policies_can_read_rows`).
|
|
20
|
+
- **`bv_customer_mdm__*` views run `SQL SECURITY DEFINER`** so column-limited
|
|
21
|
+
grants on the views work without exposing the underlying
|
|
22
|
+
`sat_customer_personal__1c__*` satellites to readers.
|
|
23
|
+
- **`marts.customer_360` is PII-free by contract** — the cross-branch
|
|
24
|
+
materialized mart no longer selects `first_name`/`last_name`/`email`
|
|
25
|
+
(copying jurisdiction-bound PII past the column grants at build time);
|
|
26
|
+
`pii_source` metadata stays.
|
|
27
|
+
- **Verified live** against ClickHouse 26.7 (32/32 adversarial probes): every
|
|
28
|
+
PII shape denied for `dv2_analyst` — including the three historical
|
|
29
|
+
bypass forms of the removed app gate, two of which are not even expressible
|
|
30
|
+
on this engine — officers bounded to their jurisdiction, admin unaffected,
|
|
31
|
+
re-apply idempotent. Includes a root-caused ergonomic limitation of filter
|
|
32
|
+
pushdown over column-limited DEFINER views and its PII-safe subquery
|
|
33
|
+
workaround. Evidence: `docs/perf/vault-pii-governance-verify-2026-07-02.md`.
|
|
34
|
+
- `infrastructure/dv2/clickhouse-sts.yaml` sets
|
|
35
|
+
`CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: "1"` so the stand admin can apply
|
|
36
|
+
RBAC DDL; `tests/unit/test_dv2_governance_ddl.py` pins the boundary
|
|
37
|
+
structure (PII columns never granted, every satellite classified, catch-all
|
|
38
|
+
in sync with officer roles, DEFINER on the views, mart stays PII-free).
|
|
39
|
+
|
|
40
|
+
### Changed — ClickHouse is the shipped serving engine (ADR 0006 Phase 1, executed 2026-07-02)
|
|
41
|
+
|
|
42
|
+
- **`config/serving.yaml` defaults to `backend: clickhouse`.** `make demo`,
|
|
43
|
+
`docker-compose.yml`, and `docker-compose.prod.yml` bring the ClickHouse
|
|
44
|
+
service up by default (the `--profile clickhouse` gate is removed; the API
|
|
45
|
+
container `depends_on` its healthcheck). Rollback is config-only
|
|
46
|
+
(`SERVING_BACKEND=duckdb`). Tests stay pinned to DuckDB
|
|
47
|
+
(`tests/conftest.py`), and DuckDB remains the local-dev / test store.
|
|
48
|
+
- **The local pipeline writes the serving store** — new
|
|
49
|
+
`src/processing/clickhouse_sink.py`: when the configured backend is
|
|
50
|
+
ClickHouse, every validated event mirrors its serving-table writes and its
|
|
51
|
+
`pipeline_events` journal row there (dead-letter rows included), after the
|
|
52
|
+
DuckDB commit. A configured-but-unreachable ClickHouse fails loudly instead
|
|
53
|
+
of letting the demo serve a frozen seed.
|
|
54
|
+
- **Upserts are ReplacingMergeTree row versions.** The four mutable serving
|
|
55
|
+
tables move from `MergeTree` to `ReplacingMergeTree` versioned by a
|
|
56
|
+
`MATERIALIZED af_updated_at` column (invisible to `SELECT *`, inserts, and
|
|
57
|
+
`table_columns`); every backend read carries the `final=1` setting so
|
|
58
|
+
queries always see the latest version. **Existing demo ClickHouse volumes
|
|
59
|
+
must be dropped and re-seeded** (engine changes don't apply to existing
|
|
60
|
+
tables; the demo store is disposable by design).
|
|
61
|
+
- **The freshness-critical event scan goes through the serving backend.** New
|
|
62
|
+
`QueryEngine.fetch_pipeline_events()`; the webhook dispatcher (which also
|
|
63
|
+
drives metric-cache invalidation) and the `/v1/stream/events` SSE scan
|
|
64
|
+
delegate to it instead of reaching into the embedded DuckDB connection — so
|
|
65
|
+
event-driven freshness works when the writer is out-of-process and the
|
|
66
|
+
engine is external. Verified live against a real ClickHouse 26.7 server:
|
|
67
|
+
cross-process burst moved the served revenue metric, SSE streamed
|
|
68
|
+
ClickHouse-only events, upsert dedup read back one latest-version row
|
|
69
|
+
(`docs/perf/clickhouse-serving-verify-2026-07-02.md`).
|
|
70
|
+
- **Transpile safety net:** `ClickHouseBackend._translate_sql` now fails
|
|
71
|
+
closed if any table reference — including the tenant schema qualifier
|
|
72
|
+
applied by `_scope_sql` *before* the rewrite — does not survive the
|
|
73
|
+
duckdb→clickhouse transpile or does not re-parse. Guards the
|
|
74
|
+
rewrite-after-guard seam that produced the historical PII bypasses, now for
|
|
75
|
+
tenant isolation.
|
|
76
|
+
- **Fixed (found by the live verification):** the ClickHouse backend sent the
|
|
77
|
+
session-database URL parameter on the `CREATE DATABASE` bootstrap statement,
|
|
78
|
+
which fails with `UNKNOWN_DATABASE` on a bare server (Docker's
|
|
79
|
+
`CLICKHOUSE_DB` pre-creation masked it).
|
|
80
|
+
- **Helm:** new `serving.*` values wire `SERVING_BACKEND` /
|
|
81
|
+
`CLICKHOUSE_*` env (password via `existingSecret`); the chart default stays
|
|
82
|
+
the safe single-node DuckDB profile because the chart ships no ClickHouse
|
|
83
|
+
service. **ADR 0009** records the honest scaling gate: the control plane
|
|
84
|
+
(webhook queue, alert history, outbox, usage) is an embedded per-pod DuckDB
|
|
85
|
+
store, so `replicaCount`/`autoscaling` stay pinned even on the ClickHouse
|
|
86
|
+
profile until it is externalized.
|
|
87
|
+
|
|
88
|
+
### Removed
|
|
89
|
+
|
|
90
|
+
- **The serving-layer PII protection is removed — it guarded columns that do not
|
|
91
|
+
exist.** The demo serving warehouse holds no PII: `users_enriched` and
|
|
92
|
+
`orders_v2` (and every other serving table) carry only analytics columns
|
|
93
|
+
(aggregates, ids, timestamps) — none of the fields declared in the former
|
|
94
|
+
`config/pii_fields.yaml` (`email`, `phone`, `full_name`, `ip_address`,
|
|
95
|
+
`shipping_address`) exist in the catalog entity contracts or the physical DDL.
|
|
96
|
+
So the interim NL→SQL `assert_no_pii_access` deny-gate and the entity-path
|
|
97
|
+
`redact_entity` masker were operating on a surface that is never present in the
|
|
98
|
+
demo — defense-in-depth over an empty set. Both are deleted, along with
|
|
99
|
+
`src/serving/pii_policy.py`, `config/pii_fields.yaml`, their CI coverage /
|
|
100
|
+
mutation gates, the helm `piiFields` config, and the `X-PII-Masked` emission
|
|
101
|
+
(the versioned header stays reserved; the generic version-transform that would
|
|
102
|
+
strip it for older clients is unchanged). This also un-breaks the rule-based
|
|
103
|
+
`SELECT *` user/order lookups the deny-gate had been rejecting. The earlier
|
|
104
|
+
SQL-lineage masker (`src/serving/masking.py`, removed in the same cycle) is
|
|
105
|
+
likewise gone. **Real contact PII lives only in the DV2 business vault**
|
|
106
|
+
(`warehouse/agentflow/dv2/business_vault/bv_customer_mdm__*.sql`), and its
|
|
107
|
+
governance belongs engine-side there — ClickHouse row/column policies, tracked
|
|
108
|
+
as ADR 0006 Phase 2 — not in a dialect-pinned string parse in the serving tier.
|
|
109
|
+
|
|
110
|
+
### Changed
|
|
111
|
+
|
|
112
|
+
- **NL→SQL LLM path now routes through the GraceKelly orchestration API**
|
|
113
|
+
(`nl_engine._llm_translate`), not a direct provider SDK. It POSTs to
|
|
114
|
+
`${GRACEKELLY_URL}/api/v1/orchestrate` with the target model
|
|
115
|
+
(`GRACEKELLY_NL_SQL_MODEL`, default `claude-sonnet-5`); GraceKelly owns model
|
|
116
|
+
execution (browser-backed). LLM mode is gated on `GRACEKELLY_URL` (was
|
|
117
|
+
`ANTHROPIC_API_KEY`); engine detection across the query package, analytics, and
|
|
118
|
+
agent-query telemetry was realigned to match. The previous direct
|
|
119
|
+
`claude-sonnet-4-20250514` call is removed. The shipped demo still runs the
|
|
120
|
+
**rule-based** translator (GraceKelly is opt-in, unset in deploy configs);
|
|
121
|
+
when configured, GraceKelly serves `claude-sonnet-5`.
|
|
122
|
+
- **Serving engine decision: fixed on ClickHouse** (ADR 0006 + 0007). The demo
|
|
123
|
+
serving default moves DuckDB → ClickHouse, with DuckDB demoted to the
|
|
124
|
+
local-dev / test and compatibility store. This unblocks engine-native bounded
|
|
125
|
+
PII (ClickHouse row/column policies) and real Kubernetes horizontal API
|
|
126
|
+
scaling. Recorded as a decision and staged in `docs/clickhouse-cutover-plan.md`;
|
|
127
|
+
the config/compose/Helm cutover itself is **not yet executed**.
|
|
128
|
+
|
|
129
|
+
### Added
|
|
130
|
+
|
|
131
|
+
- **DV2 raw vault migrated from ClickHouse to PostgreSQL** with a cloud
|
|
132
|
+
supplier / product reference (`warehouse/agentflow/dv2/`). Hubs, links, and
|
|
133
|
+
satellites are emitted in a PostgreSQL dialect (`argMax` → `DISTINCT ON`,
|
|
134
|
+
`splitByString` → `split_part`); both ingestion feeds (the X5 loader and the
|
|
135
|
+
reference loader) repoint to a shared, parameterized `pg_vault_writer`; and
|
|
136
|
+
OLTP → vault promotion runs as an in-database `INSERT … SELECT` now that OLTP
|
|
137
|
+
and the vault share one engine. The ClickHouse dialect regenerates
|
|
138
|
+
byte-for-byte and is retained for optional mart-serving. Each generated
|
|
139
|
+
`INSERT` is parsed by `sqlglot` in `tests/unit/test_dv2_postgres_ingestion.py`
|
|
140
|
+
to assert every interpolated column exists in the committed DDL. (#91)
|
|
141
|
+
- **PyIceberg sink backed by a real MinIO object store** — the REST catalog
|
|
142
|
+
now writes through `S3FileIO` to `s3://agentflow-lake/warehouse` (the same
|
|
143
|
+
bucket the Flink path uses) instead of an ephemeral `/tmp/warehouse`
|
|
144
|
+
`HadoopFileIO`. A self-contained `docker-compose.iceberg.yml` (MinIO +
|
|
145
|
+
bucket-init + REST catalog) and env-overridable credentials in
|
|
146
|
+
`config/iceberg.yaml` make the local catalog object-store-backed; a no-Docker
|
|
147
|
+
guard asserts an `s3://` warehouse never triggers a local `mkdir`. (#92)
|
|
148
|
+
- **Event-driven OLTP → vault freshness via PostgreSQL `LISTEN`/`NOTIFY`** —
|
|
149
|
+
`AFTER INSERT/UPDATE` triggers on each `ops_<branch>` table emit
|
|
150
|
+
`pg_notify('dv2_vault_refresh', …)`, and a guarded listener runs an
|
|
151
|
+
idempotent promote on each event (push, not polling), the PostgreSQL
|
|
152
|
+
equivalent of the ClickHouse `MaterializedPostgreSQL` CDC path. Lag is
|
|
153
|
+
observed on the server clock (`db_now`) to stay free of host/container
|
|
154
|
+
clock skew. The driver-agnostic core is covered no-Docker by
|
|
155
|
+
`tests/unit/test_dv2_freshness_listen_notify.py`. (#93)
|
|
156
|
+
- OpenSSF Scorecard $0 supply-chain security posture channel:
|
|
157
|
+
`.github/workflows/scorecard.yml` (`ossf/scorecard-action@v2.4.3`) runs on
|
|
158
|
+
push to `main`, weekly, and on branch-protection changes with top-level
|
|
159
|
+
`read-all` permissions and a least-privilege analysis job
|
|
160
|
+
(`security-events`/`id-token` writes only), publishes the public Scorecard
|
|
161
|
+
result, and uploads SARIF to Code scanning. Shape-pinned by
|
|
162
|
+
`tests/unit/test_scorecard_workflow.py`. A companion
|
|
163
|
+
`docs/operations/openssf-security-posture.md` documents the channel and
|
|
164
|
+
carries a prepared OpenSSF Best Practices self-assessment for operator
|
|
165
|
+
submission. These are posture signals only — explicitly NOT a third-party
|
|
166
|
+
penetration-test attestation; backlog item 22 stays N/A and unclaimed.
|
|
167
|
+
- Backlog item 19 reopened with a real evidence channel: the production
|
|
168
|
+
source is the operator-owned Neon Postgres backing VacancyRadar
|
|
169
|
+
(`public.vacancies`), recorded with an honest solo-org decision record in
|
|
170
|
+
`docs/operations/cdc-production-onboarding.md`. New dispatch-only
|
|
171
|
+
`.github/workflows/cdc-production-capture.yml` builds the repo's Debezium
|
|
172
|
+
Kafka Connect image, reads connection material only from Actions secrets
|
|
173
|
+
via FileConfigProvider, snapshots the approved table scope over TLS, writes
|
|
174
|
+
an evidence artifact, and always tears down the connector, publication, and
|
|
175
|
+
replication slot (shape tests pin dispatch-only, secret sourcing, sslmode,
|
|
176
|
+
the teardown trap, and always-upload). The first run waits on the operator
|
|
177
|
+
enabling Logical Replication on the Neon project (irreversible
|
|
178
|
+
`wal_level` flip).
|
|
179
|
+
- Backlog item 21 closed with real evidence under an operator-amended
|
|
180
|
+
hardware class: `.github/workflows/benchmark-arm.yml` (dispatch-only) runs
|
|
181
|
+
the canonical benchmark on the free GitHub-hosted arm64 runner for public
|
|
182
|
+
repositories (`ubuntu-24.04-arm`, Neoverse-N2, 4 vCPU). First real run
|
|
183
|
+
(27012731848) recorded 554 requests / 0 failures, aggregate p50 6 ms /
|
|
184
|
+
p99 150 ms — every entity gate passed. Evidence in
|
|
185
|
+
`docs/perf/arm-server-benchmark-2026-06-05.md` plus raw artifacts; shape
|
|
186
|
+
tests pin dispatch-only/runner-label/artifact upload, and the job carries
|
|
187
|
+
an A06 dependency-profile target (`perf`). No `c8g.4xlarge` claim is made.
|
|
188
|
+
|
|
189
|
+
### Changed
|
|
190
|
+
|
|
191
|
+
- Dependency maintenance batch (consolidated from eight Dependabot PRs): the
|
|
192
|
+
Docker `python` base digest, `cp-kafka-connect-base` 7.9.7 → 7.9.8,
|
|
193
|
+
`apache-flink` 2.2.1 → 2.3.0 (validated by the Flink smoke job), and the SDK
|
|
194
|
+
`vitest` / `schemathesis` bumps, plus the GitHub Pages action major bumps
|
|
195
|
+
(`checkout` v7, `configure-pages` v6, `upload-pages-artifact` v5,
|
|
196
|
+
`deploy-pages` v5) — all SHA-pinned and validated on `main` by the Deploy
|
|
197
|
+
Pages and Flink Smoke runs. (#94)
|
|
198
|
+
- Production CDC onboarding, PMF/pricing evidence, a production-hardware
|
|
199
|
+
benchmark, and an external pen-test attestation are documented as out of
|
|
200
|
+
scope for the current plan. Their acceptance criteria require external
|
|
201
|
+
counterparties (production source owners, real customers, production-grade
|
|
202
|
+
hardware, a third-party tester) that are deliberate non-goals for this
|
|
203
|
+
reference project. The gated claims remain explicitly unmade: production CDC
|
|
204
|
+
is not enabled, PMF/pricing is not validated, no production-hardware results
|
|
205
|
+
exist, and no third-party attestation exists. Status is summarized in
|
|
206
|
+
`docs/release-readiness.md`.
|
|
207
|
+
|
|
208
|
+
### Security
|
|
209
|
+
|
|
210
|
+
- First OpenSSF Scorecard cycle acted on — published score **5.8 → 7.0**,
|
|
211
|
+
open Code-scanning findings **163 → 53**, every remainder classified
|
|
212
|
+
accepted-open (see `docs/operations/openssf-security-posture.md` §4 for the
|
|
213
|
+
fixed/accepted-open split):
|
|
214
|
+
- Every `uses:` in all 19 workflows (99 references, 20 unique actions) is
|
|
215
|
+
pinned to a full commit SHA with a trailing `# <version>` comment that
|
|
216
|
+
Dependabot's `github-actions` ecosystem keeps updating. The convention is
|
|
217
|
+
enforced by the new `tests/unit/test_workflow_action_pinning.py`;
|
|
218
|
+
per-workflow shape tests now assert action identity (prefix) instead of
|
|
219
|
+
mutable tags.
|
|
220
|
+
- Top-level `permissions: contents: read` added to the five workflows that
|
|
221
|
+
ran on the default token (`staging-deploy`, `e2e`, `contract`,
|
|
222
|
+
`cdc-production-capture`, `benchmark-arm`), and
|
|
223
|
+
`container-attestation.yml` no longer grants
|
|
224
|
+
`packages`/`id-token`/`attestations` writes at the top level — they moved
|
|
225
|
+
to the two operator-dispatched signing jobs, so the every-PR `build-smoke`
|
|
226
|
+
job runs read-only (pinned by a new shape test).
|
|
227
|
+
- All four Dockerfile `FROM` lines are digest-pinned to their current
|
|
228
|
+
manifest-list digests, and the Dependabot `docker` ecosystem now covers
|
|
229
|
+
every Dockerfile directory (`directories:` list) so the pins keep moving
|
|
230
|
+
with upstream tags.
|
|
231
|
+
- `warehouse/agentflow/dv2/loaders/x5_retail_hero/requirements.txt` floors
|
|
232
|
+
raised: `pydantic>=2.9` (GHSA-mr82-8j83-vxmv ReDoS range started at the
|
|
233
|
+
old 2.0 floor) and `tqdm>=4.66.3` (PYSEC-2017-74 and the 2024 CLI
|
|
234
|
+
injection both fall below it). Resolution-floor fixes only; runtime code
|
|
235
|
+
is unchanged.
|
|
236
|
+
|
|
7
237
|
## [1.5.0] - 2026-06-05
|
|
8
238
|
|
|
9
239
|
### Added
|
|
@@ -37,7 +267,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
37
267
|
observe the `hashed_key_count_exceeds_guidance` warning (the warning still
|
|
38
268
|
emits; only the capture goes blind). An autouse fixture now re-points the
|
|
39
269
|
package logger at a fresh uncached proxy per test, making the file
|
|
40
|
-
order-independent. Found while reproducing the 2026-06-03
|
|
270
|
+
order-independent. Found while reproducing the 2026-06-03 audit F-1
|
|
41
271
|
claim that the broad no-Docker full-repo pytest run is unreliable on this
|
|
42
272
|
host: on the canonical `.venv` the run completes with a normal summary and
|
|
43
273
|
leaves no orphan uvicorn child (the audit ran the shadow system Python),
|
|
@@ -111,7 +341,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
111
341
|
|
|
112
342
|
### Changed
|
|
113
343
|
|
|
114
|
-
- `scripts/` is now part of the CI Ruff gate (2026-06-03
|
|
344
|
+
- `scripts/` is now part of the CI Ruff gate (2026-06-03 audit F-2:
|
|
115
345
|
release/benchmark/backup/security tooling had drifted to 20 lint errors and
|
|
116
346
|
12 unformatted files that CI never checked). The 12 drifted scripts were
|
|
117
347
|
reformatted (no semantic changes), import order and `datetime.UTC` usages
|
|
@@ -163,7 +393,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
163
393
|
spec are unchanged (`export_openapi.py --check` green).
|
|
164
394
|
- The ClickHouse serving backend now translates DuckDB-flavored
|
|
165
395
|
semantic-layer SQL through a sqlglot parse → AST rewrite → generate
|
|
166
|
-
pipeline instead of the former regex chain (PR #41; closes
|
|
396
|
+
pipeline instead of the former regex chain (PR #41; closes audit finding
|
|
167
397
|
H-C2 in full — the earlier literal-masking commit was the narrow fix).
|
|
168
398
|
String literals are preserved structurally by the parser, and
|
|
169
399
|
unparseable or multi-statement SQL now fails loudly as
|
|
@@ -416,7 +646,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
416
646
|
- New module `src/serving/api/auth/usage_table.py` holds
|
|
417
647
|
`ensure_usage_table` / `record_usage` / `usage_by_tenant`, which used
|
|
418
648
|
to live alongside the ASGI middleware in
|
|
419
|
-
`src/serving/api/auth/middleware.py`. Closes
|
|
649
|
+
`src/serving/api/auth/middleware.py`. Closes audit L-C4
|
|
420
650
|
("DB utilities don't belong in a middleware file"). Public callers
|
|
421
651
|
go through `AuthManager.*` shim methods unchanged; the only direct
|
|
422
652
|
importer was `tests/unit/test_audit_publisher.py`, repointed to the
|
|
@@ -425,7 +655,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
425
655
|
|
|
426
656
|
### Performance
|
|
427
657
|
|
|
428
|
-
- The two Flink hot-path findings from
|
|
658
|
+
- The two Flink hot-path findings from the 2026-05 internal audit are closed
|
|
429
659
|
now that the runtime is on 2.2.1 (they were gated on the PR #23 upstream
|
|
430
660
|
wait). M-C3: `ValidateAndEnrich` emits `(event_id, payload)` pairs and the
|
|
431
661
|
dedup `key_by` reads the key from the tuple, dropping the second
|
|
@@ -443,7 +673,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
443
673
|
events to two enriched outputs. The JSON-in-MapState layout is
|
|
444
674
|
deliberately unchanged (checkpoint compatible).
|
|
445
675
|
- `scripts/perf/auth_bench.py` + `docs/perf/auth-bench-2026-05-26.md`
|
|
446
|
-
— perf-baseline microbench closing two deferred
|
|
676
|
+
— perf-baseline microbench closing two deferred audit findings.
|
|
447
677
|
Measured `authenticate()` worst-case at production `bcrypt_rounds=12`:
|
|
448
678
|
N=5 hit-last p95 = 1.9 s, N=20 hit-last p95 = 8.1 s (exceeds the
|
|
449
679
|
1100 ms POST load gate). M-C4 stays partial-deferred — steady-state
|
|
@@ -502,7 +732,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
502
732
|
counter branch and the `/metrics` exposure round trip.
|
|
503
733
|
- 6 new unit tests in `tests/unit/test_cdc_connector_configs.py`
|
|
504
734
|
exercise `src.ingestion.connectors.{mysql_cdc,postgres_cdc}`
|
|
505
|
-
pure-Python config builders. Closes
|
|
735
|
+
pure-Python config builders. Closes audit R4: both files
|
|
506
736
|
went from 0% to 100% combined (line+branch) unit coverage; total
|
|
507
737
|
`src.ingestion` rose 82% → ~85%. Tests pin the operational knobs
|
|
508
738
|
the `cdc-lag` runbook depends on (snapshot mode, heartbeat
|
|
@@ -514,7 +744,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
514
744
|
- `.github/workflows/contract.yml` now triggers on
|
|
515
745
|
`infrastructure/terraform/**`, `sdk-ts/**`, and `Dockerfile*`
|
|
516
746
|
paths in addition to the existing src/sdk/pyproject/workflows
|
|
517
|
-
set. Closes
|
|
747
|
+
set. Closes audit R2 and removes the last remaining
|
|
518
748
|
`--admin merge` workaround from session 18 for changes outside
|
|
519
749
|
the Python tree.
|
|
520
750
|
- `.github/workflows/ci.yml` main coverage gate
|
|
@@ -534,7 +764,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
534
764
|
`build-push-sign-attest` + `attest-and-sign` jobs are gated
|
|
535
765
|
behind `github.event_name == 'workflow_dispatch'` so a PR can
|
|
536
766
|
never accidentally fire the ghcr.io push / cosign sign path.
|
|
537
|
-
Closes
|
|
767
|
+
Closes audit R6. A new
|
|
538
768
|
`test_container_attestation_workflow_runs_smoke_on_pull_request`
|
|
539
769
|
unit test asserts the trigger paths, the PR-event gate, and
|
|
540
770
|
push/load shape. Local Docker Desktop 29.4.0 smoke verified the
|
|
@@ -548,7 +778,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
548
778
|
`int()` / `float()`) fixed with `cast()` at the JSON boundary.
|
|
549
779
|
mypy is now clean on all 98 source files including
|
|
550
780
|
`checkpointing`, `session_aggregation`, `session_aggregator`,
|
|
551
|
-
`stream_processor`. Closes
|
|
781
|
+
`stream_processor`. Closes audit R7.
|
|
552
782
|
|
|
553
783
|
### Fixed
|
|
554
784
|
|
|
@@ -563,7 +793,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
563
793
|
fails. The DuckDB insert is now retried in isolation; the audit
|
|
564
794
|
publish runs exactly once after a successful insert and a publish
|
|
565
795
|
failure is logged as `audit_publish_failed` instead of re-driving
|
|
566
|
-
the retry loop. Closes
|
|
796
|
+
the retry loop. Closes audit H-C3. Two regression tests in
|
|
567
797
|
`tests/unit/test_audit_publisher.py` pin the contract:
|
|
568
798
|
`test_record_usage_no_duplicate_insert_when_publish_raises` and
|
|
569
799
|
`test_record_usage_skips_publish_when_all_inserts_fail`.
|
|
@@ -573,7 +803,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
573
803
|
warning (`search_index_initial_rebuild_failed`) instead of
|
|
574
804
|
aborting startup. The 60-second periodic rebuilder (which already
|
|
575
805
|
catches its own exceptions) is still scheduled, so the search
|
|
576
|
-
surface can recover without a process restart. Closes
|
|
806
|
+
surface can recover without a process restart. Closes audit
|
|
577
807
|
M-C1. Regression test:
|
|
578
808
|
`tests/unit/test_lifespan_search_resilience.py::test_lifespan_survives_search_rebuild_failure`.
|
|
579
809
|
|
|
@@ -586,7 +816,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
586
816
|
literals (including `''`-escaped quotes) are masked with sentinel
|
|
587
817
|
placeholders and restored after the rewrites. The `INTERVAL '...'`
|
|
588
818
|
rewrite still runs first against raw SQL so quoted intervals
|
|
589
|
-
continue to collapse. Closes part of
|
|
819
|
+
continue to collapse. Closes part of audit H-C2 (literal
|
|
590
820
|
corruption vector). Seven regression tests in
|
|
591
821
|
`tests/unit/test_clickhouse_backend.py::TestTranslateSqlLiteralProtection`
|
|
592
822
|
pin the contract against `::FLOAT`, `NOW()`, `COUNT(*)`, `TRUE`,
|
|
@@ -595,7 +825,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
595
825
|
against the system trust store explicitly via
|
|
596
826
|
`ssl.create_default_context()` plumbed through to `urlopen`. Insecure
|
|
597
827
|
HTTP backends (default for local-compose) omit the context kwarg so
|
|
598
|
-
Python's `http.client` path is unchanged. Closes part of
|
|
828
|
+
Python's `http.client` path is unchanged. Closes part of audit
|
|
599
829
|
H-C2 (no explicit HTTPS validation). Two regression tests cover the
|
|
600
830
|
secure (CERT_REQUIRED + check_hostname True) and insecure (`None`
|
|
601
831
|
context) paths.
|
|
@@ -614,7 +844,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
614
844
|
rather than a 500. The latter parses its input through `sqlglot`
|
|
615
845
|
(DuckDB dialect) and rejects multi-statement or non-`SELECT`
|
|
616
846
|
payloads with `BackendExecutionError` before the `EXPLAIN` wrapper
|
|
617
|
-
runs. Closes
|
|
847
|
+
runs. Closes audit H-C1. 13 new regression tests in
|
|
618
848
|
`tests/unit/test_duckdb_backend_sql_hardening.py` pin both paths
|
|
619
849
|
against an injection corpus (semicolons, comments, UNION,
|
|
620
850
|
numeric-prefix names, dot-pathology, whitespace) plus
|
|
@@ -625,7 +855,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
625
855
|
prior hard-coded `223345` would collide on the replication stream the
|
|
626
856
|
moment a second instance came up against the same source. Default
|
|
627
857
|
preserved as `DEFAULT_MYSQL_SERVER_ID = 223345` so existing
|
|
628
|
-
deployments are unchanged. Closes
|
|
858
|
+
deployments are unchanged. Closes audit L-C2. Regression test
|
|
629
859
|
`test_mysql_server_id_overridable_via_env` covers env override,
|
|
630
860
|
invalid-int fallback, and unset-env fallback.
|
|
631
861
|
- `_CONNECT_SECRET_KEY` in `src/ingestion/connectors/{mysql,postgres}_cdc.py`
|
|
@@ -634,13 +864,13 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
634
864
|
`FileConfigProvider` `${file:/path:<key>}` syntax, not a credential).
|
|
635
865
|
The previous `"pass" + "word"` concatenation was security through
|
|
636
866
|
obscurity — bytecode collapses the expression and string scanners
|
|
637
|
-
still see the result. Closes
|
|
867
|
+
still see the result. Closes audit L-C1.
|
|
638
868
|
- Redundant `event_type == prefix` clauses dropped from
|
|
639
869
|
`src/quality/validators/{schema,semantic}_validator.py`. Python's
|
|
640
870
|
`str.startswith(prefix)` already returns True for the exact-equality
|
|
641
871
|
case (`"order.".startswith("order.")`), so the `or event_type == prefix`
|
|
642
872
|
branch could never fire when the prefix was a non-empty string.
|
|
643
|
-
Closes
|
|
873
|
+
Closes audit L-C3.
|
|
644
874
|
- `AuthManager` no longer grows its `_rate_windows`,
|
|
645
875
|
`_failed_auth_windows`, and `_runtime_plaintext_by_hash` dictionaries
|
|
646
876
|
unbounded. A new `_sweep_expired_windows()` helper drops entries
|
|
@@ -650,7 +880,7 @@ All notable changes to AgentFlow are documented in this file.
|
|
|
650
880
|
is cheap and bounds growth between reloads). `load()` also purges
|
|
651
881
|
cached plaintext-by-hash entries for hashes that no longer appear in
|
|
652
882
|
the live `_hashed_keys` list, so a revoked/rotated key's plaintext
|
|
653
|
-
cannot remain pinned in memory across reloads. Closes
|
|
883
|
+
cannot remain pinned in memory across reloads. Closes audit
|
|
654
884
|
H-C4. Regression tests in
|
|
655
885
|
`tests/unit/test_auth_manager_memory_bounds.py` cover the sweep on
|
|
656
886
|
load, the sweep on clear, the plaintext cache purge, and idempotency
|
|
@@ -664,15 +894,9 @@ wave 2 dependency bumps that landed in sessions 11–19.
|
|
|
664
894
|
|
|
665
895
|
### Documentation
|
|
666
896
|
|
|
667
|
-
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
(Tier A actionable Dependabot PRs, Tier B externally user-gated
|
|
671
|
-
A04/A05/A03, Tier C forward backlog), a compressed view of sessions
|
|
672
|
-
11 → 17, and the load-bearing lessons from session 17's regression
|
|
673
|
-
(Contract Tests path filter, Dependabot cascade transitive
|
|
674
|
-
conflicts, memory-staleness check before recommending). README
|
|
675
|
-
surfaces it at the top of the Documentation index.
|
|
897
|
+
- Curated the README Documentation index as the cold-start entry point,
|
|
898
|
+
grouping the architecture, API reference, on-call runbooks, and security
|
|
899
|
+
audit so the project's published docs are reachable in one hop.
|
|
676
900
|
|
|
677
901
|
### Fixed
|
|
678
902
|
|
|
@@ -793,7 +1017,7 @@ wave 2 dependency bumps that landed in sessions 11–19.
|
|
|
793
1017
|
optional-pyyaml `try/except ImportError` blocks (PyYAML is currently
|
|
794
1018
|
a hard runtime dependency, but the JSON-fallback machinery in
|
|
795
1019
|
`webhook_dispatcher.py`, `slo.py`, `alerts/dispatcher.py` etc. is
|
|
796
|
-
intentionally kept available
|
|
1020
|
+
intentionally kept available).
|
|
797
1021
|
- `types-redis` added to the dev extra. Two
|
|
798
1022
|
`# type: ignore[import-untyped,unused-ignore]` annotations on
|
|
799
1023
|
`import redis.asyncio as redis` retired in `src/serving/cache.py`
|
|
@@ -913,16 +1137,12 @@ wave 2 dependency bumps that landed in sessions 11–19.
|
|
|
913
1137
|
- Prepared npm publishing for Trusted Publishing through GitHub Actions OIDC:
|
|
914
1138
|
the TypeScript SDK publish workflow now requires npm CLI 11.5.1+ and no
|
|
915
1139
|
longer passes `NPM_TOKEN` to the production `npm publish` step.
|
|
916
|
-
- Recorded the npm Trusted Publishing handoff: the
|
|
917
|
-
|
|
918
|
-
setup succeeded for `brownjuly2003-code/agentflow` with workflow
|
|
919
|
-
`publish-npm.yml
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
- Documented the completed replacement npm account bootstrap for
|
|
923
|
-
`yulia.edomskikh@gmail.com`, the saved 2FA recovery-code reserve, and the
|
|
924
|
-
switch of future TypeScript SDK publishing to
|
|
925
|
-
`@yuliaedomskikh/agentflow-client`.
|
|
1140
|
+
- Recorded the npm Trusted Publishing handoff: the package
|
|
1141
|
+
`@yuliaedomskikh/agentflow-client@1.1.0` was first published and Trusted
|
|
1142
|
+
Publisher setup succeeded for `brownjuly2003-code/agentflow` with workflow
|
|
1143
|
+
`publish-npm.yml`; CLI `npm trust list` readback is complete.
|
|
1144
|
+
- Switched future TypeScript SDK publishing to the
|
|
1145
|
+
`@yuliaedomskikh/agentflow-client` npm scope.
|
|
926
1146
|
- Clarified that legacy `NPM_TOKEN` revocation remains blocked until a
|
|
927
1147
|
successful trusted-publish workflow run for `@yuliaedomskikh/agentflow-client`
|
|
928
1148
|
and accepted external-gate intake evidence exist.
|
|
@@ -946,11 +1166,10 @@ wave 2 dependency bumps that landed in sessions 11–19.
|
|
|
946
1166
|
|
|
947
1167
|
### Security (audit follow-up sprint 2026-04-27/28)
|
|
948
1168
|
|
|
949
|
-
Two
|
|
950
|
-
|
|
951
|
-
P0/P1/P2 findings.
|
|
1169
|
+
Two internal security audits were delivered against `4a13d36`. Six commits
|
|
1170
|
+
closed all P0/P1/P2 findings.
|
|
952
1171
|
|
|
953
|
-
**Tenant isolation across the control plane (
|
|
1172
|
+
**Tenant isolation across the control plane (audit p1 R3/R5, p2_1 #1-3,
|
|
954
1173
|
p3 #4):** `pipeline_events` and `dead_letter_events` got a
|
|
955
1174
|
`tenant_id VARCHAR DEFAULT 'default'` column with backwards-compatible
|
|
956
1175
|
`ALTER TABLE ADD COLUMN IF NOT EXISTS` migration in init paths. Writers
|
|
@@ -962,23 +1181,23 @@ normalizer accepts an explicit `topic=` argument and falls back through
|
|
|
962
1181
|
now scope to `request.state.tenant_id`. Cross-tenant regression tests
|
|
963
1182
|
added.
|
|
964
1183
|
|
|
965
|
-
**SQL guard centralization (
|
|
1184
|
+
**SQL guard centralization (audit p2_1 #4, p2_2 #4, p3 #1):** new
|
|
966
1185
|
`_prepare_nl_sql()` helper in `nl_queries.py` is the only path that
|
|
967
1186
|
validates translated SQL via `validate_nl_sql()`; called from
|
|
968
1187
|
`execute_nl_query`, `paginated_query`, and `explain` before tenant
|
|
969
1188
|
scoping and pagination wrapping. Closes the bypass on `/v1/query`
|
|
970
1189
|
(paginated) and `/v1/query/explain`. PII masking and explain
|
|
971
1190
|
`tables_accessed` rewritten on `sqlglot` AST so tenant-quoted SQL like
|
|
972
|
-
`"acme"."users_enriched"` is correctly extracted (
|
|
1191
|
+
`"acme"."users_enriched"` is correctly extracted (audit p3 #3).
|
|
973
1192
|
|
|
974
|
-
**Entity allowlist enforcement (
|
|
1193
|
+
**Entity allowlist enforcement (audit p2_1 #4, p3 #2):** new
|
|
975
1194
|
`tenant_key_allowed_tables()` helper in `auth/manager.py`. Applied to
|
|
976
1195
|
NL query / explain / paginated query, batch query/metric items,
|
|
977
1196
|
`/v1/search` (intersection with tenant key allowlist + post-filter so
|
|
978
1197
|
metric documents are not silently dropped for scoped keys), and
|
|
979
1198
|
`/v1/metrics/{metric}`.
|
|
980
1199
|
|
|
981
|
-
**Auth fail-closed + entropy + scopes (
|
|
1200
|
+
**Auth fail-closed + entropy + scopes (audit p2_1 #5, p2_2 #1-3):**
|
|
982
1201
|
auth middleware now fails closed with `503` when no API keys are
|
|
983
1202
|
configured; opt out with `AGENTFLOW_AUTH_DISABLED=true` for local dev
|
|
984
1203
|
or `app.state.auth_disabled = True` for tests. Failed-auth throttling
|
|
@@ -987,7 +1206,7 @@ immediate peer is in `AGENTFLOW_TRUSTED_PROXIES`. Generated API keys
|
|
|
987
1206
|
now use `secrets.token_urlsafe(32)` (256-bit) instead of
|
|
988
1207
|
`secrets.token_hex(4)` (32-bit).
|
|
989
1208
|
|
|
990
|
-
**Secret hygiene (
|
|
1209
|
+
**Secret hygiene (audit p2_2 #5/8, p9 #4-5):** rotated active webhook
|
|
991
1210
|
signing secret in `config/webhooks.yaml`, replaced tracked plaintext
|
|
992
1211
|
API keys in `k8s/staging/values-staging.yaml` with placeholders +
|
|
993
1212
|
`.yaml.example` schema reference, env-driven
|
|
@@ -1013,7 +1232,7 @@ capabilities, and applies `RuntimeDefault` seccomp; a memory `emptyDir`
|
|
|
1013
1232
|
mounts at `/tmp` for Python tempfile / httpx caches. NetworkPolicy is
|
|
1014
1233
|
off by default (enable per cluster).
|
|
1015
1234
|
|
|
1016
|
-
**Supply chain (
|
|
1235
|
+
**Supply chain (audit p9):** committed `sdk-ts/package-lock.json`
|
|
1017
1236
|
(closes ENOLOCK on `npm audit`); `publish-npm.yml` switched to
|
|
1018
1237
|
`npm ci` + `npm test` + `npm audit` before publish. New `npm-audit` job
|
|
1019
1238
|
added to `security.yml`. `aquasecurity/trivy-action` pinned from
|
|
@@ -1030,7 +1249,7 @@ SQL injection via dynamic partition keys), `langchain-core>=1.2.22`
|
|
|
1030
1249
|
bypass), `langsmith>=0.7.31`. Both `pyproject.toml` and
|
|
1031
1250
|
`integrations/pyproject.toml`.
|
|
1032
1251
|
|
|
1033
|
-
**OpenAPI drift gate (
|
|
1252
|
+
**OpenAPI drift gate (audit p4 #5):** `scripts/export_openapi.py`
|
|
1034
1253
|
gained a `--check` mode that diffs the regenerated `docs/openapi.json`
|
|
1035
1254
|
and `docs/agent-tools/*.json` against committed copies. Wired into
|
|
1036
1255
|
`contract.yml`; `docs/agent-tools/**` and `scripts/export_openapi.py`
|
|
@@ -1047,7 +1266,7 @@ branch gate; the job was removed
|
|
|
1047
1266
|
and DORA metrics fall back to the GitHub Actions API source
|
|
1048
1267
|
already wired into `scripts/dora_metrics.py`.
|
|
1049
1268
|
|
|
1050
|
-
**Python SDK alignment with server v1 contract (
|
|
1269
|
+
**Python SDK alignment with server v1 contract (audit p8 F1–F10):**
|
|
1051
1270
|
`api_version=` parameter and `X-AgentFlow-Version` header on sync and
|
|
1052
1271
|
async clients; capture of server version + deprecation headers into
|
|
1053
1272
|
`client.last_server_version` / `last_deprecation_warning`. Async
|
|
@@ -1069,7 +1288,7 @@ re-exported from `agentflow.__init__.__all__`. New
|
|
|
1069
1288
|
`sdk/agentflow/py.typed` marker; Hatch include rule keeps it in the
|
|
1070
1289
|
wheel/sdist.
|
|
1071
1290
|
|
|
1072
|
-
**Test coverage gaps (
|
|
1291
|
+
**Test coverage gaps (audit p5):** new unit suites covering
|
|
1073
1292
|
previously zero-coverage modules — `tests/unit/test_clickhouse_backend.py`
|
|
1074
1293
|
(14 tests: SQL translation, basic-auth POST, UNKNOWN_TABLE mapping,
|
|
1075
1294
|
URLError mapping, table_columns fallbacks, EXPLAIN, scalar, https
|
|
@@ -1087,9 +1306,9 @@ not exercise auth (sets `AGENTFLOW_AUTH_DISABLED=true`); opt out with
|
|
|
1087
1306
|
the new `requires_auth_enforcement` marker.
|
|
1088
1307
|
`app.state.auth_disabled = False` is reset on every lifespan startup
|
|
1089
1308
|
so the test bypass flag does not leak across `TestClient` instances
|
|
1090
|
-
(closes
|
|
1309
|
+
(closes review P2 on auth/middleware persistence).
|
|
1091
1310
|
|
|
1092
|
-
**Documentation hygiene (
|
|
1311
|
+
**Documentation hygiene (audit p6):** TypeScript SDK examples now
|
|
1093
1312
|
import from `"@yuliaedomskikh/agentflow-client"` (was `"agentflow"`); placeholder
|
|
1094
1313
|
`https://api.agentflow.dev` examples replaced with
|
|
1095
1314
|
`http://localhost:8000`; clone URL points at
|
|
@@ -1109,9 +1328,8 @@ reset on lifespan startup so the test bypass flag does not leak across
|
|
|
1109
1328
|
`670 passed, 4 skipped` on
|
|
1110
1329
|
`pytest tests/unit tests/integration tests/sdk tests/contract`.
|
|
1111
1330
|
|
|
1112
|
-
**
|
|
1113
|
-
|
|
1114
|
-
README that maps findings to the six closing commits.
|
|
1331
|
+
**Audit closure:** two internal security audits drove the work; their
|
|
1332
|
+
findings map to the six closing commits.
|
|
1115
1333
|
|
|
1116
1334
|
### Added
|
|
1117
1335
|
|
|
@@ -1248,8 +1466,6 @@ See [docs/migration/v1.1.md](docs/migration/v1.1.md) for upgrade instructions fr
|
|
|
1248
1466
|
|
|
1249
1467
|
### Documentation
|
|
1250
1468
|
|
|
1251
|
-
- v1.1 sprint task briefs under `docs/codex-tasks/2026-04-22/`
|
|
1252
|
-
(T01-T10, self-contained one-PR ТЗ). (f448626)
|
|
1253
1469
|
- `docs/operations/aws-oidc-setup.md`, `docs/operations/chaos-runbook.md`,
|
|
1254
1470
|
`docs/operations/codecov-setup.md`.
|
|
1255
1471
|
- `docs/contracts/how-to-add-entity.md`.
|