Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Consumers are whoever needs the number now: humans, dashboards, downstream servi
- **Published release line through `v2.0.0`** on PyPI (`agentflow-runtime`, `agentflow-client`) and npm (`@yuliaedomskikh/agentflow-client`) via OIDC Trusted Publishers with SLSA provenance on every artifact
- **Tested and gated** — 1,500+ unit tests plus a broad Windows no-Docker suite; CI enforces 13 required status checks (lint, schema, unit, integration, helm, perf, terraform, bandit, safety, npm-audit, trivy, contract, build-smoke) through branch protection
- **Dual SDK parity** across Python and TypeScript — retries, circuit breakers, batching, pagination, contract pinning, idempotency keys, `as_of` historical reads — over sub-second entity lookups (p50 `38–55 ms`, p99 `167 ms` on local hardware)
- **Security in the hot path** — a tenant boundary that lives in each serving table's write key and is applied at a single read chokepoint ([ADR-004](docs/decisions/004-tenant-id-column-over-schema-per-tenant.md); proven against DuckDB, [not yet proven on ClickHouse](docs/STATUS.md#known-issues)), parameterized queries, `sqlglot` AST validation for NL-to-SQL, fail-closed auth, secret scrubbing, and a Bandit gate for new findings
- **Security in the hot path** — a tenant boundary that lives in each serving table's write key and is applied at a single read chokepoint ([ADR-004](docs/decisions/004-tenant-id-column-over-schema-per-tenant.md); proven against DuckDB and live ClickHouse 25.3 — see [STATUS](docs/STATUS.md#proven)), parameterized queries, `sqlglot` AST validation for NL-to-SQL, fail-closed auth, secret scrubbing, and a Bandit gate for new findings
- **Production-shaped extras** — two CDC paths (hardened Debezium/Kafka Connect + a ClickHouse per-branch fan-out), on-call [runbooks](docs/runbooks/README.md), and a [narrated demo](docs/dv2-multi-branch/) of the DV2 multi-branch warehouse

## Quick start
Expand Down
37 changes: 14 additions & 23 deletions docs/STATUS.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Engineering Status

> Updated: **2026-07-11** (post S13 + #183 live re-verify) · release line **`v2.0.0`** ·
> `main` green across all 13 required checks. Numbers below come only from
> measured, in-repo evidence — see the linked reports for methodology and
> reproduction commands.
> Updated: **2026-07-16** (post audit P0–P2-4 merge; CH multi-tenant live) ·
> release line **`v2.0.0`** · `main` green across required checks. Numbers
> below come only from measured, in-repo evidence — see the linked reports
> for methodology and reproduction commands.

AgentFlow's product axis — **event → live metric** on the real streaming path
(Kafka → Flink → serving bridge → ClickHouse → API with Redis push
Expand All @@ -22,6 +22,7 @@ passed ones (endurance, scale, delivery topology).
| 4 h endurance soak (real path + API reads) | bounded lag (peak 2 915 → 0), bridge RSS/FD flat, one faulted batch replayed exactly-once by the journal guard, **zero cache drift** | [perf/soak-s11-2026-07-10.md](perf/soak-s11-2026-07-10.md) |
| At-scale on own data (S13) | **51.2 M rows / 2.87 M orders / 4 years of legend history**, analyst queries 20–730 ms, all 17 §12 invariants pass incl. full-scan GTIN validation | [perf/scale-own-data-2026-07-11.md](perf/scale-own-data-2026-07-11.md) |
| Security pass (offline/unit remainder) | closed; third-party pen-test **not** claimed | [security-s12-2026-07-09.md](security-s12-2026-07-09.md), [security-audit.md](security-audit.md) |
| Multi-tenant ClickHouse write key | adversarial two-tenant suite green on live CH 25.3 (CI `test-integration` + audit stand) | [security-audit.md](security-audit.md), `tests/integration/test_clickhouse_tenant_isolation_live.py` |

## Bridge write-path throughput — burst target met

Expand All @@ -44,25 +45,15 @@ stressed; the ≥ 100 eps stretch bar stays open. Semantics of the batched path

## Known issues

- **Multi-tenant ClickHouse — implemented, not yet proven live.** Tenant
isolation used to be a schema qualification that nothing provisioned: no
`CREATE SCHEMA` existed anywhere in `src/`, so on DuckDB every *authenticated*
entity read failed on a relation that was never created, and on ClickHouse the
same name meant a database nobody creates. With the qualification dropped, two
tenants sharing an `order_id` were two versions of one `ReplacingMergeTree`
row and the later insert destroyed the earlier — data loss no read filter can
undo. The boundary is now the `tenant_id` **column**, leading each serving
table's write key on both stores
([ADR-004](decisions/004-tenant-id-column-over-schema-per-tenant.md)).
**DuckDB is proven**: two tenants with identical entity ids resolve to
different rows, cross-tenant lookups 404, aggregates sum only the caller's
rows, and an unscoped read against a shared store is refused — asserted both
by example (`tests/integration/test_tenant_isolation.py`) and over generated
tenant/entity ids (`tests/property/test_tenant_isolation_properties.py`).
**ClickHouse is not**: its adversarial two-tenant suite
(`tests/integration/test_clickhouse_tenant_isolation_live.py`) needs a live
server and has not been run yet. Until it is green, multi-tenant ClickHouse is
not a supported claim; the single-tenant profile is unaffected.
- **Multi-tenant ClickHouse — proven live (audit P0-1).** The boundary is the
`tenant_id` **column**, leading each serving table's write key on both stores
([ADR-004](decisions/004-tenant-id-column-over-schema-per-tenant.md)). DuckDB
remains covered by example and property suites; ClickHouse is covered by
`tests/integration/test_clickhouse_tenant_isolation_live.py` on live server
25.3 (CI `test-integration` service + audit Mac stand). Cross-tenant lookups
404, aggregates stay tenant-scoped, and `assert_tenant_key()` refuses an old
single-column sorting key. Broader isolation across every external dependency
is still out of scope — see [security-audit.md](security-audit.md).

- **API RSS growth under steady load — fixed and verified live** (was 175 MB
→ 1.67 GB over the 4 h soak; the bridge stayed flat). The webhook
Expand Down
2 changes: 1 addition & 1 deletion docs/security-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Reads pass through one chokepoint. `SQLBuilderMixin._qualify_table` returns a te
What the evidence supports today:

- **DuckDB** — proven. Two tenants with identical `order_id` resolve to different rows; cross-tenant lookups return `404`; aggregates sum only the caller's rows; an unscoped read fails closed. Property tests assert the invariant over generated tenant and entity ids, not just the two-tenant example.
- **ClickHouse** — the same model is implemented and provisioned (`assert_tenant_key()` refuses to serve a store still on the old sorting key; `provision --migrate` rebuilds one). The adversarial two-tenant suite for it is `tests/integration/test_clickhouse_tenant_isolation_live.py`, which requires a live server and runs on the CI integration job. **Until that suite is green on a real server, treat multi-tenant ClickHouse as unproven and do not claim it.**
- **ClickHouse** — the same model is implemented, provisioned, and proven live. `assert_tenant_key()` refuses to serve a store still on the old sorting key; `provision --migrate` rebuilds one. The adversarial two-tenant suite (`tests/integration/test_clickhouse_tenant_isolation_live.py`) runs against ClickHouse 25.3 on the CI `test-integration` job and was green on the audit stand (full live suite including tenant isolation). Multi-tenant ClickHouse is a supported claim for the write-key + read-chokepoint model described above.

It does not support broader claims such as end-to-end isolation across every external dependency.

Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ dependencies = [
"opentelemetry-sdk>=1.41,<2",
"pandera>=0.20,<1",
"prometheus-client>=0.21,<1",
"pyarrow>=17,<25",
"pyarrow>=17,<26",
"pydantic>=2.9,<3",
"pydantic-settings>=2.5,<3",
"pyyaml>=6,<7",
Expand Down Expand Up @@ -73,7 +73,7 @@ integrations = [
"llama-index-core>=0.12,<1",
]
contract = [
"schemathesis==4.22.3",
"schemathesis==4.22.4",
]
dev = [
"bandit>=1.9,<2",
Expand Down
10 changes: 5 additions & 5 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.