revoluzen-flow 1.0.1.dev0__py3-none-any.whl
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.
- revoluzen_flow/CHANGELOG.md +724 -0
- revoluzen_flow/README.md +648 -0
- revoluzen_flow/__init__.py +17 -0
- revoluzen_flow/__main__.py +25 -0
- revoluzen_flow/ai/__init__.py +0 -0
- revoluzen_flow/ai/agent.py +1325 -0
- revoluzen_flow/ai/ai_metrics.py +185 -0
- revoluzen_flow/ai/anthropic_client.py +120 -0
- revoluzen_flow/ai/atlas/__init__.py +71 -0
- revoluzen_flow/ai/atlas/schema.py +275 -0
- revoluzen_flow/ai/atlas/topics_autogen.py +327 -0
- revoluzen_flow/ai/atlas/topics_handwritten.py +1165 -0
- revoluzen_flow/ai/budget.py +147 -0
- revoluzen_flow/ai/cache.py +153 -0
- revoluzen_flow/ai/clarify.py +317 -0
- revoluzen_flow/ai/clarify_draft.py +1706 -0
- revoluzen_flow/ai/clarify_to_template.py +396 -0
- revoluzen_flow/ai/column_refs.py +149 -0
- revoluzen_flow/ai/context.py +227 -0
- revoluzen_flow/ai/cost_rates.py +333 -0
- revoluzen_flow/ai/dialogue_state.py +454 -0
- revoluzen_flow/ai/direct_actions.py +333 -0
- revoluzen_flow/ai/draft_checks.py +175 -0
- revoluzen_flow/ai/draft_choices.py +785 -0
- revoluzen_flow/ai/draft_diff.py +219 -0
- revoluzen_flow/ai/draft_guess.py +289 -0
- revoluzen_flow/ai/dry_run_promoter.py +152 -0
- revoluzen_flow/ai/embedded.py +2053 -0
- revoluzen_flow/ai/fast_router.py +3883 -0
- revoluzen_flow/ai/foundation.py +99 -0
- revoluzen_flow/ai/governance.py +136 -0
- revoluzen_flow/ai/handles.py +124 -0
- revoluzen_flow/ai/hybrid.py +342 -0
- revoluzen_flow/ai/idempotency.py +119 -0
- revoluzen_flow/ai/interactive_cards.py +235 -0
- revoluzen_flow/ai/json_repair.py +280 -0
- revoluzen_flow/ai/multi_step.py +50 -0
- revoluzen_flow/ai/normalize.py +151 -0
- revoluzen_flow/ai/notification_summary.py +230 -0
- revoluzen_flow/ai/ollama_client.py +348 -0
- revoluzen_flow/ai/openai_client.py +281 -0
- revoluzen_flow/ai/openai_compatible_client.py +101 -0
- revoluzen_flow/ai/openrouter_client.py +230 -0
- revoluzen_flow/ai/product_knowledge.py +410 -0
- revoluzen_flow/ai/prompt_signing.py +116 -0
- revoluzen_flow/ai/rag/__init__.py +22 -0
- revoluzen_flow/ai/rag/embedder.py +73 -0
- revoluzen_flow/ai/rag/indexer.py +287 -0
- revoluzen_flow/ai/rag/retrieve.py +94 -0
- revoluzen_flow/ai/rag/store.py +242 -0
- revoluzen_flow/ai/rate_limit.py +341 -0
- revoluzen_flow/ai/rbac.py +153 -0
- revoluzen_flow/ai/roles.py +190 -0
- revoluzen_flow/ai/sanitize.py +191 -0
- revoluzen_flow/ai/schema_infer.py +341 -0
- revoluzen_flow/ai/semantic_cache.py +257 -0
- revoluzen_flow/ai/session_context.py +579 -0
- revoluzen_flow/ai/single_shot.py +206 -0
- revoluzen_flow/ai/sql_templates.py +565 -0
- revoluzen_flow/ai/step_params.py +35 -0
- revoluzen_flow/ai/tls.py +18 -0
- revoluzen_flow/ai/tool_only_mode.py +58 -0
- revoluzen_flow/ai/tool_selector.py +380 -0
- revoluzen_flow/ai/tools/__init__.py +252 -0
- revoluzen_flow/ai/tools/_edit_guards.py +534 -0
- revoluzen_flow/ai/tools/apply_pipeline_draft.py +165 -0
- revoluzen_flow/ai/tools/base.py +124 -0
- revoluzen_flow/ai/tools/compose_report.py +89 -0
- revoluzen_flow/ai/tools/draft_alert_rule.py +121 -0
- revoluzen_flow/ai/tools/draft_connector_from_openapi.py +198 -0
- revoluzen_flow/ai/tools/draft_connector_from_samples.py +146 -0
- revoluzen_flow/ai/tools/draft_pipeline_from_intent.py +220 -0
- revoluzen_flow/ai/tools/explain_step.py +252 -0
- revoluzen_flow/ai/tools/get_incidents.py +96 -0
- revoluzen_flow/ai/tools/get_installation_health.py +212 -0
- revoluzen_flow/ai/tools/get_next_scheduled.py +108 -0
- revoluzen_flow/ai/tools/get_pipeline_spec.py +138 -0
- revoluzen_flow/ai/tools/get_running_executions.py +88 -0
- revoluzen_flow/ai/tools/get_security_posture.py +152 -0
- revoluzen_flow/ai/tools/get_user_role.py +71 -0
- revoluzen_flow/ai/tools/inspect_connections.py +85 -0
- revoluzen_flow/ai/tools/inspect_step_columns.py +209 -0
- revoluzen_flow/ai/tools/list_alerts.py +53 -0
- revoluzen_flow/ai/tools/list_catalog.py +165 -0
- revoluzen_flow/ai/tools/list_executions.py +178 -0
- revoluzen_flow/ai/tools/list_pipelines.py +96 -0
- revoluzen_flow/ai/tools/list_projects.py +49 -0
- revoluzen_flow/ai/tools/list_quality_rule_sets.py +71 -0
- revoluzen_flow/ai/tools/list_schedules.py +77 -0
- revoluzen_flow/ai/tools/list_steward_findings.py +204 -0
- revoluzen_flow/ai/tools/list_storage.py +236 -0
- revoluzen_flow/ai/tools/list_templates.py +184 -0
- revoluzen_flow/ai/tools/lookup_business_terms.py +70 -0
- revoluzen_flow/ai/tools/lookup_help_topic.py +159 -0
- revoluzen_flow/ai/tools/modify_pipeline_step.py +462 -0
- revoluzen_flow/ai/tools/query_metrics.py +77 -0
- revoluzen_flow/ai/tools/recall_history.py +116 -0
- revoluzen_flow/ai/tools/registry.py +86 -0
- revoluzen_flow/ai/tools/suggest_join_keys.py +130 -0
- revoluzen_flow/ai/tools/summarize_pipeline.py +164 -0
- revoluzen_flow/ai/tools/test_connection.py +119 -0
- revoluzen_flow/ai/tools/test_pipeline_draft.py +313 -0
- revoluzen_flow/ai/tools/validate_pipeline.py +311 -0
- revoluzen_flow/ai/tools/web_fetch.py +108 -0
- revoluzen_flow/ai/tools/web_search.py +83 -0
- revoluzen_flow/ai/tools/workspace_overview.py +63 -0
- revoluzen_flow/ai/trace_store.py +483 -0
- revoluzen_flow/ai/usage_sources.py +175 -0
- revoluzen_flow/ai/wallet.py +287 -0
- revoluzen_flow/ai/web/__init__.py +108 -0
- revoluzen_flow/ai/web/fetch.py +110 -0
- revoluzen_flow/ai/web/search.py +235 -0
- revoluzen_flow/ai_config/__init__.py +5 -0
- revoluzen_flow/ai_config/store.py +447 -0
- revoluzen_flow/alerts/__init__.py +4 -0
- revoluzen_flow/alerts/models.py +125 -0
- revoluzen_flow/alerts/notifier.py +1442 -0
- revoluzen_flow/alerts/store.py +443 -0
- revoluzen_flow/api/__init__.py +149 -0
- revoluzen_flow/api/activity.py +354 -0
- revoluzen_flow/api/addons.py +99 -0
- revoluzen_flow/api/agent.py +2421 -0
- revoluzen_flow/api/agent_action.py +297 -0
- revoluzen_flow/api/ai.py +2467 -0
- revoluzen_flow/api/ai_config.py +662 -0
- revoluzen_flow/api/ai_cost_rates.py +83 -0
- revoluzen_flow/api/ai_roles.py +65 -0
- revoluzen_flow/api/ai_web.py +122 -0
- revoluzen_flow/api/alerts.py +292 -0
- revoluzen_flow/api/api_explorer.py +435 -0
- revoluzen_flow/api/app_meta.py +106 -0
- revoluzen_flow/api/auth.py +2030 -0
- revoluzen_flow/api/auth_health.py +56 -0
- revoluzen_flow/api/backfills.py +481 -0
- revoluzen_flow/api/backup.py +361 -0
- revoluzen_flow/api/catalog.py +370 -0
- revoluzen_flow/api/cert_matrix.py +954 -0
- revoluzen_flow/api/collaboration.py +186 -0
- revoluzen_flow/api/connections.py +1124 -0
- revoluzen_flow/api/connector_authoring.py +342 -0
- revoluzen_flow/api/connector_drafts.py +108 -0
- revoluzen_flow/api/contracts.py +357 -0
- revoluzen_flow/api/credentials.py +512 -0
- revoluzen_flow/api/dashboard.py +746 -0
- revoluzen_flow/api/deployments.py +332 -0
- revoluzen_flow/api/errors.py +200 -0
- revoluzen_flow/api/execution.py +1938 -0
- revoluzen_flow/api/execution_contracts.py +284 -0
- revoluzen_flow/api/execution_manager.py +200 -0
- revoluzen_flow/api/exports.py +259 -0
- revoluzen_flow/api/expressions.py +104 -0
- revoluzen_flow/api/extraction.py +207 -0
- revoluzen_flow/api/folders.py +405 -0
- revoluzen_flow/api/gateway.py +766 -0
- revoluzen_flow/api/git_copy.py +132 -0
- revoluzen_flow/api/glossary.py +106 -0
- revoluzen_flow/api/health_memory.py +338 -0
- revoluzen_flow/api/incidents.py +141 -0
- revoluzen_flow/api/intelligence.py +681 -0
- revoluzen_flow/api/legacy_files.py +104 -0
- revoluzen_flow/api/lineage.py +241 -0
- revoluzen_flow/api/local_hardening.py +437 -0
- revoluzen_flow/api/logs.py +184 -0
- revoluzen_flow/api/marketplace.py +166 -0
- revoluzen_flow/api/mcp.py +287 -0
- revoluzen_flow/api/metrics.py +443 -0
- revoluzen_flow/api/monitor.py +707 -0
- revoluzen_flow/api/notifications.py +384 -0
- revoluzen_flow/api/ollama.py +390 -0
- revoluzen_flow/api/pipeline_health.py +102 -0
- revoluzen_flow/api/planner.py +865 -0
- revoluzen_flow/api/plugins.py +92 -0
- revoluzen_flow/api/pool.py +748 -0
- revoluzen_flow/api/pool_allocation.py +212 -0
- revoluzen_flow/api/pre_publish.py +294 -0
- revoluzen_flow/api/product_knowledge.py +155 -0
- revoluzen_flow/api/projects.py +926 -0
- revoluzen_flow/api/publish_policy.py +129 -0
- revoluzen_flow/api/quality_rule_sets.py +149 -0
- revoluzen_flow/api/recipes.py +307 -0
- revoluzen_flow/api/report_builder.py +482 -0
- revoluzen_flow/api/reports.py +980 -0
- revoluzen_flow/api/router_audit.py +213 -0
- revoluzen_flow/api/router_coverage.py +314 -0
- revoluzen_flow/api/router_telemetry.py +258 -0
- revoluzen_flow/api/router_tests.py +428 -0
- revoluzen_flow/api/schedules.py +472 -0
- revoluzen_flow/api/schema_history.py +310 -0
- revoluzen_flow/api/security_headers.py +147 -0
- revoluzen_flow/api/steward.py +1691 -0
- revoluzen_flow/api/storage.py +2605 -0
- revoluzen_flow/api/sync_state.py +91 -0
- revoluzen_flow/api/system.py +207 -0
- revoluzen_flow/api/templates.py +358 -0
- revoluzen_flow/api/trust.py +421 -0
- revoluzen_flow/api/trust_checks.py +286 -0
- revoluzen_flow/api/types_meta.py +104 -0
- revoluzen_flow/api/uploads.py +256 -0
- revoluzen_flow/api/variables.py +150 -0
- revoluzen_flow/api/websocket.py +635 -0
- revoluzen_flow/api/workflows.py +4285 -0
- revoluzen_flow/api/workspace_settings.py +134 -0
- revoluzen_flow/api/workspaces.py +394 -0
- revoluzen_flow/app_meta.py +50 -0
- revoluzen_flow/audit.py +114 -0
- revoluzen_flow/auth/__init__.py +4 -0
- revoluzen_flow/auth/deps.py +340 -0
- revoluzen_flow/auth/models.py +247 -0
- revoluzen_flow/auth/password_policy.py +269 -0
- revoluzen_flow/auth/store.py +370 -0
- revoluzen_flow/backfills/__init__.py +45 -0
- revoluzen_flow/backfills/idempotency.py +128 -0
- revoluzen_flow/backfills/models.py +138 -0
- revoluzen_flow/backfills/orchestrator.py +368 -0
- revoluzen_flow/backfills/preflight.py +162 -0
- revoluzen_flow/backfills/store.py +269 -0
- revoluzen_flow/backfills/windows.py +152 -0
- revoluzen_flow/cli/__init__.py +1571 -0
- revoluzen_flow/cli/install_service.py +565 -0
- revoluzen_flow/cli/launcher.py +400 -0
- revoluzen_flow/cli/runtime_state.py +315 -0
- revoluzen_flow/collaboration/__init__.py +193 -0
- revoluzen_flow/common/__init__.py +1 -0
- revoluzen_flow/common/client_ip.py +179 -0
- revoluzen_flow/common/duckdb_compat.py +56 -0
- revoluzen_flow/common/http_reply.py +258 -0
- revoluzen_flow/common/safe_paths.py +103 -0
- revoluzen_flow/common/safe_xml.py +573 -0
- revoluzen_flow/common/unique_name.py +65 -0
- revoluzen_flow/compile/__init__.py +5 -0
- revoluzen_flow/compile/sql_preview.py +675 -0
- revoluzen_flow/connections/__init__.py +4 -0
- revoluzen_flow/connections/addon_installer.py +317 -0
- revoluzen_flow/connections/addons.py +67 -0
- revoluzen_flow/connections/capability_levels.py +310 -0
- revoluzen_flow/connections/catalog.py +1250 -0
- revoluzen_flow/connections/catalog_extensions.py +1804 -0
- revoluzen_flow/connections/cli.py +250 -0
- revoluzen_flow/connections/credentials.py +136 -0
- revoluzen_flow/connections/fanout_runner.py +325 -0
- revoluzen_flow/connections/file_share.py +563 -0
- revoluzen_flow/connections/http_auth.py +181 -0
- revoluzen_flow/connections/inline_secrets.py +253 -0
- revoluzen_flow/connections/kafka_settings.py +458 -0
- revoluzen_flow/connections/models.py +313 -0
- revoluzen_flow/connections/mssql_odbc.py +79 -0
- revoluzen_flow/connections/oauth_flows.py +251 -0
- revoluzen_flow/connections/oauth_health.py +156 -0
- revoluzen_flow/connections/oauth_session.py +232 -0
- revoluzen_flow/connections/odbc.py +180 -0
- revoluzen_flow/connections/paginator.py +218 -0
- revoluzen_flow/connections/runtime.py +118 -0
- revoluzen_flow/connections/sqlite_path.py +40 -0
- revoluzen_flow/connections/store.py +1397 -0
- revoluzen_flow/connections/tester.py +2386 -0
- revoluzen_flow/connections/vendor_db.py +138 -0
- revoluzen_flow/connections/verify_configs.json +77 -0
- revoluzen_flow/connections/versions.py +306 -0
- revoluzen_flow/connections/warehouse_clients.py +321 -0
- revoluzen_flow/connectors/__init__.py +17 -0
- revoluzen_flow/connectors/adapters/__init__.py +16 -0
- revoluzen_flow/connectors/adapters/odata.py +166 -0
- revoluzen_flow/connectors/adapters/rest.py +116 -0
- revoluzen_flow/connectors/ai_authoring.py +985 -0
- revoluzen_flow/connectors/attest.py +348 -0
- revoluzen_flow/connectors/cat.py +472 -0
- revoluzen_flow/connectors/cdc.py +308 -0
- revoluzen_flow/connectors/certify.py +122 -0
- revoluzen_flow/connectors/ci/cat_status.json +19 -0
- revoluzen_flow/connectors/ci/live_smoke.yml +54 -0
- revoluzen_flow/connectors/ci/source_watch_baseline.json +30 -0
- revoluzen_flow/connectors/ci/source_watch_status.json +119 -0
- revoluzen_flow/connectors/drafts.py +238 -0
- revoluzen_flow/connectors/jdbc.py +309 -0
- revoluzen_flow/connectors/jdbc_dialects.py +264 -0
- revoluzen_flow/connectors/manifest_v2.py +482 -0
- revoluzen_flow/connectors/manifests/airtable.json +30 -0
- revoluzen_flow/connectors/manifests/asana.json +41 -0
- revoluzen_flow/connectors/manifests/confluence.json +46 -0
- revoluzen_flow/connectors/manifests/datadog.json +51 -0
- revoluzen_flow/connectors/manifests/dynamics365.json +70 -0
- revoluzen_flow/connectors/manifests/elasticsearch.json +44 -0
- revoluzen_flow/connectors/manifests/elasticsearch.v2.json +177 -0
- revoluzen_flow/connectors/manifests/facebook_ads.json +46 -0
- revoluzen_flow/connectors/manifests/freshdesk.json +54 -0
- revoluzen_flow/connectors/manifests/github.json +54 -0
- revoluzen_flow/connectors/manifests/github.v2.json +150 -0
- revoluzen_flow/connectors/manifests/gitlab.json +54 -0
- revoluzen_flow/connectors/manifests/google_ads.json +55 -0
- revoluzen_flow/connectors/manifests/google_analytics.json +36 -0
- revoluzen_flow/connectors/manifests/hubspot.json +54 -0
- revoluzen_flow/connectors/manifests/hubspot.v2.json +194 -0
- revoluzen_flow/connectors/manifests/intercom.json +41 -0
- revoluzen_flow/connectors/manifests/jira.json +37 -0
- revoluzen_flow/connectors/manifests/jira.v2.json +139 -0
- revoluzen_flow/connectors/manifests/linkedin_ads.json +46 -0
- revoluzen_flow/connectors/manifests/mailchimp.json +42 -0
- revoluzen_flow/connectors/manifests/monday.json +26 -0
- revoluzen_flow/connectors/manifests/ms_teams.json +53 -0
- revoluzen_flow/connectors/manifests/netsuite.json +55 -0
- revoluzen_flow/connectors/manifests/notion.json +36 -0
- revoluzen_flow/connectors/manifests/notion.v2.json +140 -0
- revoluzen_flow/connectors/manifests/pagerduty.json +57 -0
- revoluzen_flow/connectors/manifests/pipedrive.json +46 -0
- revoluzen_flow/connectors/manifests/quickbooks.json +70 -0
- revoluzen_flow/connectors/manifests/rabbitmq.json +49 -0
- revoluzen_flow/connectors/manifests/redis.json +34 -0
- revoluzen_flow/connectors/manifests/salesforce.json +53 -0
- revoluzen_flow/connectors/manifests/salesforce.v2.json +155 -0
- revoluzen_flow/connectors/manifests/sap_odata.json +55 -0
- revoluzen_flow/connectors/manifests/sendgrid.json +48 -0
- revoluzen_flow/connectors/manifests/servicenow.json +62 -0
- revoluzen_flow/connectors/manifests/shopify.json +46 -0
- revoluzen_flow/connectors/manifests/shopify.v2.json +144 -0
- revoluzen_flow/connectors/manifests/slack.json +50 -0
- revoluzen_flow/connectors/manifests/slack.v2.json +142 -0
- revoluzen_flow/connectors/manifests/stripe.json +58 -0
- revoluzen_flow/connectors/manifests/stripe.v2.json +173 -0
- revoluzen_flow/connectors/manifests/twilio.json +49 -0
- revoluzen_flow/connectors/manifests/workday.json +52 -0
- revoluzen_flow/connectors/manifests/zendesk.json +43 -0
- revoluzen_flow/connectors/manifests/zoho_crm.json +61 -0
- revoluzen_flow/connectors/odbc_runtime.py +114 -0
- revoluzen_flow/connectors/openapi_import.py +149 -0
- revoluzen_flow/connectors/openapi_security.py +122 -0
- revoluzen_flow/connectors/openapi_source.py +172 -0
- revoluzen_flow/connectors/pgoutput.py +450 -0
- revoluzen_flow/connectors/request_connector.py +165 -0
- revoluzen_flow/connectors/rest_framework.py +1126 -0
- revoluzen_flow/connectors/source_watch.py +800 -0
- revoluzen_flow/connectors/vector_db.py +403 -0
- revoluzen_flow/connectors/wsdl_import.py +620 -0
- revoluzen_flow/contracts/__init__.py +39 -0
- revoluzen_flow/contracts/chain.py +82 -0
- revoluzen_flow/contracts/facts.py +153 -0
- revoluzen_flow/contracts/from_spec.py +137 -0
- revoluzen_flow/contracts/gate.py +85 -0
- revoluzen_flow/contracts/precommit.py +161 -0
- revoluzen_flow/contracts/schema.py +279 -0
- revoluzen_flow/contracts/service.py +84 -0
- revoluzen_flow/contracts/store.py +190 -0
- revoluzen_flow/contracts/verify.py +412 -0
- revoluzen_flow/credentials/__init__.py +4 -0
- revoluzen_flow/credentials/expiry.py +71 -0
- revoluzen_flow/credentials/models.py +77 -0
- revoluzen_flow/credentials/sensitive_fields.py +219 -0
- revoluzen_flow/credentials/store.py +232 -0
- revoluzen_flow/datastore/__init__.py +58 -0
- revoluzen_flow/datastore/models.py +241 -0
- revoluzen_flow/datastore/paths.py +173 -0
- revoluzen_flow/datastore/reader.py +526 -0
- revoluzen_flow/datastore/reconcile.py +198 -0
- revoluzen_flow/datastore/scaffold.py +240 -0
- revoluzen_flow/datastore/store.py +345 -0
- revoluzen_flow/datastore/table_monitor.py +253 -0
- revoluzen_flow/datastore/table_tests.py +208 -0
- revoluzen_flow/datastore/usage.py +454 -0
- revoluzen_flow/docs/NODE_REFERENCE.md +988 -0
- revoluzen_flow/docs/abstraction-boundary.md +126 -0
- revoluzen_flow/docs/ai-boundary-contract.md +207 -0
- revoluzen_flow/docs/ai-ops-contract.md +189 -0
- revoluzen_flow/docs/ai.md +123 -0
- revoluzen_flow/docs/api-explorer.md +130 -0
- revoluzen_flow/docs/api.md +634 -0
- revoluzen_flow/docs/architecture.md +125 -0
- revoluzen_flow/docs/benchmarks/postgres-competitive-2026-11.md +125 -0
- revoluzen_flow/docs/capability-matrix.md +140 -0
- revoluzen_flow/docs/compliance.md +102 -0
- revoluzen_flow/docs/connector-authoring.md +376 -0
- revoluzen_flow/docs/connectors/postgres.md +136 -0
- revoluzen_flow/docs/connectors/sqlserver.md +175 -0
- revoluzen_flow/docs/connectors.md +180 -0
- revoluzen_flow/docs/customer-faq.md +184 -0
- revoluzen_flow/docs/dashboard-metrics.md +300 -0
- revoluzen_flow/docs/deployment.md +367 -0
- revoluzen_flow/docs/design/00_overview.md +208 -0
- revoluzen_flow/docs/design/01_backend_lld.md +722 -0
- revoluzen_flow/docs/design/02_frontend_lld.md +574 -0
- revoluzen_flow/docs/design/03_functional_flows.md +652 -0
- revoluzen_flow/docs/design/backfill-ux-1.2.md +167 -0
- revoluzen_flow/docs/design/connection-pooling.md +189 -0
- revoluzen_flow/docs/design/consequence-grammar.md +279 -0
- revoluzen_flow/docs/design/decisions.md +109 -0
- revoluzen_flow/docs/design/execution-engines.md +142 -0
- revoluzen_flow/docs/design/executor-maturity-1.2.md +176 -0
- revoluzen_flow/docs/design/f01-manifest-v2.md +177 -0
- revoluzen_flow/docs/design/lineage-1.2.md +175 -0
- revoluzen_flow/docs/design/readme.md +43 -0
- revoluzen_flow/docs/design/sprint1-bulk-loaders.md +159 -0
- revoluzen_flow/docs/design/tier1-connector-uplift.md +146 -0
- revoluzen_flow/docs/design-data-wrangler-node.md +321 -0
- revoluzen_flow/docs/dev-guide.md +230 -0
- revoluzen_flow/docs/editions.md +69 -0
- revoluzen_flow/docs/eval-harness.md +122 -0
- revoluzen_flow/docs/examples/webhook-trigger.md +187 -0
- revoluzen_flow/docs/execution-timing.md +20 -0
- revoluzen_flow/docs/extend/build-a-connector.md +218 -0
- revoluzen_flow/docs/extend/build-a-node.md +118 -0
- revoluzen_flow/docs/faq.md +129 -0
- revoluzen_flow/docs/idempotency.md +113 -0
- revoluzen_flow/docs/install/database-drivers.md +340 -0
- revoluzen_flow/docs/install/security-hardening.md +247 -0
- revoluzen_flow/docs/nodes-and-canvas-reference.md +1965 -0
- revoluzen_flow/docs/nodes.md +85 -0
- revoluzen_flow/docs/performance.md +172 -0
- revoluzen_flow/docs/pipeline-documentation.md +73 -0
- revoluzen_flow/docs/product_facts/01_overview.md +35 -0
- revoluzen_flow/docs/product_facts/02_node_types.md +118 -0
- revoluzen_flow/docs/product_facts/03_editions.md +57 -0
- revoluzen_flow/docs/product_facts/04_concepts.md +96 -0
- revoluzen_flow/docs/product_facts/05_troubleshooting.md +76 -0
- revoluzen_flow/docs/product_facts/06_faq.md +88 -0
- revoluzen_flow/docs/product_facts/07_credentials.md +211 -0
- revoluzen_flow/docs/product_facts/08_connectors.md +131 -0
- revoluzen_flow/docs/product_facts/09_notifications.md +63 -0
- revoluzen_flow/docs/product_facts/10_ai_copilot.md +168 -0
- revoluzen_flow/docs/product_facts/11_workspace_rbac.md +75 -0
- revoluzen_flow/docs/product_facts/12_templates_expressions.md +79 -0
- revoluzen_flow/docs/product_facts/13_backup_recovery.md +76 -0
- revoluzen_flow/docs/product_facts/14_audit_lineage.md +97 -0
- revoluzen_flow/docs/product_facts/15_workers_scaling.md +69 -0
- revoluzen_flow/docs/product_facts/16_how_to.md +423 -0
- revoluzen_flow/docs/product_facts/17_where_to_find.md +246 -0
- revoluzen_flow/docs/product_facts/18_analytical_questions.md +404 -0
- revoluzen_flow/docs/product_facts/19_who_when_why.md +351 -0
- revoluzen_flow/docs/product_facts/20_pricing_resources.md +296 -0
- revoluzen_flow/docs/product_facts/21_multi_turn_dialogues.md +412 -0
- revoluzen_flow/docs/product_facts/22_real_world_scenarios.md +480 -0
- revoluzen_flow/docs/product_facts/23_code_generation.md +600 -0
- revoluzen_flow/docs/product_facts/24_decision_questions.md +604 -0
- revoluzen_flow/docs/product_facts/25_anti_patterns.md +488 -0
- revoluzen_flow/docs/quickstart.md +315 -0
- revoluzen_flow/docs/readme.md +60 -0
- revoluzen_flow/docs/releases/oss-release-checklist.md +106 -0
- revoluzen_flow/docs/releases/release-notes-1.0.md +150 -0
- revoluzen_flow/docs/reliability-1.2.md +246 -0
- revoluzen_flow/docs/repair-evaluation.md +326 -0
- revoluzen_flow/docs/roadmap/oss-1-1.md +264 -0
- revoluzen_flow/docs/roadmap/reliability-sprint.md +275 -0
- revoluzen_flow/docs/run-as-service.md +284 -0
- revoluzen_flow/docs/scaling.md +100 -0
- revoluzen_flow/docs/security/audit-2026-06-03.md +312 -0
- revoluzen_flow/docs/security-deployment.md +215 -0
- revoluzen_flow/docs/security-diagnostics.md +28 -0
- revoluzen_flow/docs/sop/README.md +73 -0
- revoluzen_flow/docs/sop/developer-operations.md +267 -0
- revoluzen_flow/docs/sop/go-live.md +265 -0
- revoluzen_flow/docs/sop/maintainer-operations.md +175 -0
- revoluzen_flow/docs/sop/security-response.md +119 -0
- revoluzen_flow/docs/sop/user-operations.md +264 -0
- revoluzen_flow/docs/sprint-b-cdc-runbook.md +87 -0
- revoluzen_flow/docs/steward/PROOF-2026-06-06/01-validation-run.txt +0 -0
- revoluzen_flow/docs/steward/PROOF-2026-06-06/02-memory-journal.jsonl +16 -0
- revoluzen_flow/docs/steward/PROOF-2026-06-06/05-test-suite-verbose.txt +0 -0
- revoluzen_flow/docs/steward/PROOF-2026-06-06/06-contract-snapshot.txt +0 -0
- revoluzen_flow/docs/steward/PROOF-2026-06-06/07-live-workspace-dryrun.txt +0 -0
- revoluzen_flow/docs/steward/PROOF-2026-06-06/09-memory-tab-journal.jsonl +12 -0
- revoluzen_flow/docs/steward/PROOF-2026-06-06/11-memory-verify-output.txt +0 -0
- revoluzen_flow/docs/steward/PROOF-2026-06-06/13-scenario-pack-v1.txt +0 -0
- revoluzen_flow/docs/steward/PROOF-2026-06-06/README.md +276 -0
- revoluzen_flow/docs/steward/PROOF-2026-06-08/overnight-verify.md +56 -0
- revoluzen_flow/docs/steward/architecture.md +742 -0
- revoluzen_flow/docs/steward/connector-health.md +132 -0
- revoluzen_flow/docs/steward/cost-tracking.md +182 -0
- revoluzen_flow/docs/steward/custom-rules.md +228 -0
- revoluzen_flow/docs/steward/governance.md +122 -0
- revoluzen_flow/docs/steward/memory-layer.md +254 -0
- revoluzen_flow/docs/steward/overview.md +626 -0
- revoluzen_flow/docs/steward/positioning.md +224 -0
- revoluzen_flow/docs/steward/quality-checks.md +155 -0
- revoluzen_flow/docs/steward/sample-memory.jsonl +16 -0
- revoluzen_flow/docs/steward/schema-drift.md +162 -0
- revoluzen_flow/docs/steward/validation-output.txt +88 -0
- revoluzen_flow/docs/steward/validation-scenarios.md +148 -0
- revoluzen_flow/docs/steward/volume-anomaly.md +86 -0
- revoluzen_flow/docs/storage.md +228 -0
- revoluzen_flow/docs/supported-models.md +107 -0
- revoluzen_flow/docs/testing.md +260 -0
- revoluzen_flow/docs/threat-model.md +227 -0
- revoluzen_flow/docs/trust.md +96 -0
- revoluzen_flow/docs/ui-language.md +137 -0
- revoluzen_flow/docs/user-guide.md +696 -0
- revoluzen_flow/docs/user-guides/connections.md +191 -0
- revoluzen_flow/docs/user-guides/external-triggers.md +251 -0
- revoluzen_flow/docs/user-guides/mainframe-and-legacy-files.md +236 -0
- revoluzen_flow/docs/user-guides/pipelines.md +624 -0
- revoluzen_flow/docs/user-guides/projects.md +302 -0
- revoluzen_flow/docs/user-guides/reports.md +78 -0
- revoluzen_flow/docs/user-guides/users-and-access.md +251 -0
- revoluzen_flow/docs/vs-airbyte.md +99 -0
- revoluzen_flow/docs/vs-talend.md +108 -0
- revoluzen_flow/docs/vs-visual-etl.md +96 -0
- revoluzen_flow/docs_static.py +98 -0
- revoluzen_flow/engine/__init__.py +4 -0
- revoluzen_flow/engine/admission.py +91 -0
- revoluzen_flow/engine/bulk_load/__init__.py +59 -0
- revoluzen_flow/engine/bulk_load/dialects/__init__.py +30 -0
- revoluzen_flow/engine/bulk_load/dialects/bigquery.py +233 -0
- revoluzen_flow/engine/bulk_load/dialects/mssql.py +254 -0
- revoluzen_flow/engine/bulk_load/dialects/postgres.py +299 -0
- revoluzen_flow/engine/bulk_load/dialects/redshift.py +232 -0
- revoluzen_flow/engine/bulk_load/dialects/snowflake.py +365 -0
- revoluzen_flow/engine/bulk_load/registry.py +70 -0
- revoluzen_flow/engine/bulk_load/runner.py +92 -0
- revoluzen_flow/engine/bulk_load/types.py +99 -0
- revoluzen_flow/engine/cancellation.py +341 -0
- revoluzen_flow/engine/checkpoint_store.py +384 -0
- revoluzen_flow/engine/connection_pool.py +291 -0
- revoluzen_flow/engine/engines.py +251 -0
- revoluzen_flow/engine/execution_log.py +641 -0
- revoluzen_flow/engine/execution_manager.py +1081 -0
- revoluzen_flow/engine/executor.py +2402 -0
- revoluzen_flow/engine/failure_class.py +233 -0
- revoluzen_flow/engine/global_governor.py +278 -0
- revoluzen_flow/engine/history_output.py +51 -0
- revoluzen_flow/engine/lookback.py +159 -0
- revoluzen_flow/engine/overlap.py +86 -0
- revoluzen_flow/engine/parameters.py +264 -0
- revoluzen_flow/engine/preview.py +85 -0
- revoluzen_flow/engine/queue/__init__.py +130 -0
- revoluzen_flow/engine/queue/descriptor.py +174 -0
- revoluzen_flow/engine/queue/inproc.py +87 -0
- revoluzen_flow/engine/queue/redis_queue.py +259 -0
- revoluzen_flow/engine/realtime.py +627 -0
- revoluzen_flow/engine/resource_monitor.py +116 -0
- revoluzen_flow/engine/retry_policy.py +247 -0
- revoluzen_flow/engine/run_time_limit.py +165 -0
- revoluzen_flow/engine/step_cache.py +316 -0
- revoluzen_flow/engine/step_output_store.py +243 -0
- revoluzen_flow/engine/subprocess_runner.py +402 -0
- revoluzen_flow/engine/sync_state_store.py +314 -0
- revoluzen_flow/engine/worker_pool.py +1319 -0
- revoluzen_flow/eval/__init__.py +18 -0
- revoluzen_flow/eval/cases.py +601 -0
- revoluzen_flow/eval/intent/__init__.py +6 -0
- revoluzen_flow/eval/intent/__main__.py +65 -0
- revoluzen_flow/eval/intent/cases.py +117 -0
- revoluzen_flow/eval/intent/runner.py +293 -0
- revoluzen_flow/eval/prompt_bank.csv +301 -0
- revoluzen_flow/eval/prompt_bank_README.md +162 -0
- revoluzen_flow/eval/repair/__init__.py +11 -0
- revoluzen_flow/eval/repair/__main__.py +90 -0
- revoluzen_flow/eval/repair/cases.py +665 -0
- revoluzen_flow/eval/repair/clients.py +174 -0
- revoluzen_flow/eval/repair/fresh_cases.py +898 -0
- revoluzen_flow/eval/repair/runner.py +656 -0
- revoluzen_flow/eval/repair/scoring.py +333 -0
- revoluzen_flow/eval/run.py +202 -0
- revoluzen_flow/eval/runner.py +885 -0
- revoluzen_flow/events/__init__.py +111 -0
- revoluzen_flow/events/bus.py +159 -0
- revoluzen_flow/events/consumers/__init__.py +21 -0
- revoluzen_flow/events/consumers/audit.py +114 -0
- revoluzen_flow/events/consumers/metrics.py +157 -0
- revoluzen_flow/events/factory.py +85 -0
- revoluzen_flow/events/in_process.py +374 -0
- revoluzen_flow/events/nats_bus.py +403 -0
- revoluzen_flow/events/types.py +327 -0
- revoluzen_flow/expression/__init__.py +5 -0
- revoluzen_flow/expression/resolver.py +437 -0
- revoluzen_flow/extraction/__init__.py +47 -0
- revoluzen_flow/extraction/engine.py +507 -0
- revoluzen_flow/extraction/events.py +285 -0
- revoluzen_flow/extraction/freshness.py +106 -0
- revoluzen_flow/extraction/manifest.py +112 -0
- revoluzen_flow/extraction/profile.py +214 -0
- revoluzen_flow/extraction/profiles/__init__.py +6 -0
- revoluzen_flow/extraction/profiles/endpoint_central_inventory.py +3 -0
- revoluzen_flow/extraction/schema_mapper.py +236 -0
- revoluzen_flow/extraction/session.py +101 -0
- revoluzen_flow/extraction/staging.py +144 -0
- revoluzen_flow/feature_flags.py +167 -0
- revoluzen_flow/flags/__init__.py +15 -0
- revoluzen_flow/flags/feature_flags.py +321 -0
- revoluzen_flow/folders/__init__.py +6 -0
- revoluzen_flow/folders/models.py +45 -0
- revoluzen_flow/folders/store.py +114 -0
- revoluzen_flow/frontend_dist/assets/AIPage-BYPVGmJh.js +1 -0
- revoluzen_flow/frontend_dist/assets/AIPage-DKegnQxk.css +1 -0
- revoluzen_flow/frontend_dist/assets/AccountPage-CvcS2tAT.js +1 -0
- revoluzen_flow/frontend_dist/assets/ActivityPage-DiBOgCn5.js +2 -0
- revoluzen_flow/frontend_dist/assets/Canvas-aJcYWw4p.js +18 -0
- revoluzen_flow/frontend_dist/assets/CatalogPicker-LlOV7Swa.js +1 -0
- revoluzen_flow/frontend_dist/assets/ChatPanel-B1Rmbh2q.js +11 -0
- revoluzen_flow/frontend_dist/assets/CodeEditorPanel-fti-K-cY.js +4 -0
- revoluzen_flow/frontend_dist/assets/ConfigPanel-D50wizn0.js +23 -0
- revoluzen_flow/frontend_dist/assets/ConnectionsPage-BkfNe3vr.js +8 -0
- revoluzen_flow/frontend_dist/assets/ConnectorIcons-CtcxUA-y.js +1 -0
- revoluzen_flow/frontend_dist/assets/CredentialsPage-Civ7fnck.js +1 -0
- revoluzen_flow/frontend_dist/assets/DataWranglerConfig-Bq7AUZLx.js +1 -0
- revoluzen_flow/frontend_dist/assets/DensityToggle-D_vc7f4K.js +1 -0
- revoluzen_flow/frontend_dist/assets/DetailDrawer-b7WTlgxL.js +5 -0
- revoluzen_flow/frontend_dist/assets/EmptyState-BmwJ2z6J.js +1 -0
- revoluzen_flow/frontend_dist/assets/ErrorBanner-DK-9ibrl.js +1 -0
- revoluzen_flow/frontend_dist/assets/ExecutionPoolPage-CuJu2POu.js +1 -0
- revoluzen_flow/frontend_dist/assets/ExecutionsPage-BL1EW0qq.js +6 -0
- revoluzen_flow/frontend_dist/assets/ExtractionPage-BOsvGayd.js +1 -0
- revoluzen_flow/frontend_dist/assets/FloatingAgentWidget-B4t9IIhD.js +25 -0
- revoluzen_flow/frontend_dist/assets/GlobalSearch-DMBtPW9d.js +1 -0
- revoluzen_flow/frontend_dist/assets/HelpPage-rxJG8CS-.js +15 -0
- revoluzen_flow/frontend_dist/assets/HeroCard-BOsNLJpN.js +1 -0
- revoluzen_flow/frontend_dist/assets/Icon-DxN4GgEB.js +1 -0
- revoluzen_flow/frontend_dist/assets/InlineConnectionForm-5QZ8BM5w.js +1 -0
- revoluzen_flow/frontend_dist/assets/LegacyFileSettings-BnZ_FBEC.js +4 -0
- revoluzen_flow/frontend_dist/assets/LineagePage-D6JrJtUP.js +1 -0
- revoluzen_flow/frontend_dist/assets/ModulesPanel-BzB1hpTx.js +1 -0
- revoluzen_flow/frontend_dist/assets/MoveToProjectButton-vnkZ7zP2.js +1 -0
- revoluzen_flow/frontend_dist/assets/NotificationsPage-CRh8nJmk.js +1 -0
- revoluzen_flow/frontend_dist/assets/OSSProductionPlaceholder-D-vkR9k_.js +1 -0
- revoluzen_flow/frontend_dist/assets/OllamaRecommendationBanner-BpoR-tDJ.js +1 -0
- revoluzen_flow/frontend_dist/assets/OnboardingWizard-DgPAFoF1.js +1 -0
- revoluzen_flow/frontend_dist/assets/OpenApiSecurityReview-xJk8X8Lr.js +1 -0
- revoluzen_flow/frontend_dist/assets/PipelinesPage-CKf4Zy-v.js +15 -0
- revoluzen_flow/frontend_dist/assets/PreviewPanel-C32L7tRg.js +1 -0
- revoluzen_flow/frontend_dist/assets/ProjectContextBar-BSGepbgh.js +1 -0
- revoluzen_flow/frontend_dist/assets/ProviderComparison-B4MSjt1U.js +1 -0
- revoluzen_flow/frontend_dist/assets/ReadOnlyBanner-eNYguvKN.js +1 -0
- revoluzen_flow/frontend_dist/assets/ReportsPage-DJGXEHxA.js +1 -0
- revoluzen_flow/frontend_dist/assets/ResizeHandle-mwbSI8pH.js +1 -0
- revoluzen_flow/frontend_dist/assets/RowActionButton-DQIunqva.js +1 -0
- revoluzen_flow/frontend_dist/assets/SettingsPage-CQFiD4wK.js +3 -0
- revoluzen_flow/frontend_dist/assets/Skeleton-DuGIRjgG.js +1 -0
- revoluzen_flow/frontend_dist/assets/StatusPill-jrbMCFBK.js +1 -0
- revoluzen_flow/frontend_dist/assets/StoragePage-CgUo90t0.js +4 -0
- revoluzen_flow/frontend_dist/assets/TableToolbar-DjQq6YGE.js +2 -0
- revoluzen_flow/frontend_dist/assets/TemplatesPage-CjDsK3ZX.js +1 -0
- revoluzen_flow/frontend_dist/assets/TimeAgo-BeeV8Lrr.js +1 -0
- revoluzen_flow/frontend_dist/assets/TransformHelper-tPKVox8f.js +8 -0
- revoluzen_flow/frontend_dist/assets/TriggersPage-CpyDnONN.js +6 -0
- revoluzen_flow/frontend_dist/assets/TrustPage-DpV4U9BF.js +3 -0
- revoluzen_flow/frontend_dist/assets/aiModels-Dg43c-RP.js +6 -0
- revoluzen_flow/frontend_dist/assets/apiExplorerDraft-ChblnxT2.js +1 -0
- revoluzen_flow/frontend_dist/assets/catalog-DD5ygzRr.js +1 -0
- revoluzen_flow/frontend_dist/assets/cost-CY27i4pI.js +1 -0
- revoluzen_flow/frontend_dist/assets/errorMessages-KxtxYOv6.js +1 -0
- revoluzen_flow/frontend_dist/assets/index-1mn3i83L.css +1 -0
- revoluzen_flow/frontend_dist/assets/index-DCmVwDXp.js +10 -0
- revoluzen_flow/frontend_dist/assets/index-Du7bxJKb.js +85 -0
- revoluzen_flow/frontend_dist/assets/markdown-L_vCpxjH.js +5 -0
- revoluzen_flow/frontend_dist/assets/revealNode-C3TarboN.js +1 -0
- revoluzen_flow/frontend_dist/assets/routePrefetch-BcihucMK.js +2 -0
- revoluzen_flow/frontend_dist/assets/triggerLabel-CSKClPlQ.js +1 -0
- revoluzen_flow/frontend_dist/assets/useEditorPreferences-BOpMX-PJ.js +1 -0
- revoluzen_flow/frontend_dist/assets/vendor-DVXy4IZ7.js +17 -0
- revoluzen_flow/frontend_dist/assets/vendor-flow-BZV40eAE.css +1 -0
- revoluzen_flow/frontend_dist/assets/vendor-flow-BsKbvqFG.js +7 -0
- revoluzen_flow/frontend_dist/assets/vendor-icons-BQwad7VI.js +141 -0
- revoluzen_flow/frontend_dist/assets/vendor-react-D2NtWQnz.js +49 -0
- revoluzen_flow/frontend_dist/connector-icons/README.md +31 -0
- revoluzen_flow/frontend_dist/connector-icons/adls.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/bigquery.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/cassandra.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/chroma.svg +8 -0
- revoluzen_flow/frontend_dist/connector-icons/clickhouse.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/cockroachdb.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/couchbase.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/databricks.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/datadog.svg +6 -0
- revoluzen_flow/frontend_dist/connector-icons/dropbox.svg +10 -0
- revoluzen_flow/frontend_dist/connector-icons/dynamodb.svg +13 -0
- revoluzen_flow/frontend_dist/connector-icons/elasticsearch.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/eventhub.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/firebase.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/gcs.svg +9 -0
- revoluzen_flow/frontend_dist/connector-icons/gdrive.svg +11 -0
- revoluzen_flow/frontend_dist/connector-icons/graphql.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/gsheet.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/jira.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/kafka.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/kinesis.svg +13 -0
- revoluzen_flow/frontend_dist/connector-icons/mariadb.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/minio.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/mongodb.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/mssql.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/mysql.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/neo4j.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/onedrive.svg +9 -0
- revoluzen_flow/frontend_dist/connector-icons/opensearch.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/oracle.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/pagerduty.svg +6 -0
- revoluzen_flow/frontend_dist/connector-icons/postgresql.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/pulsar.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/rabbitmq.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/redis.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/redshift.svg +14 -0
- revoluzen_flow/frontend_dist/connector-icons/s3.svg +13 -0
- revoluzen_flow/frontend_dist/connector-icons/salesforce.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/sap.svg +16 -0
- revoluzen_flow/frontend_dist/connector-icons/slack.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/snowflake.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/splunk.svg +6 -0
- revoluzen_flow/frontend_dist/connector-icons/sqlite.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/synapse.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/trino.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/twilio.svg +1 -0
- revoluzen_flow/frontend_dist/connector-icons/zendesk.svg +1 -0
- revoluzen_flow/frontend_dist/index.html +18 -0
- revoluzen_flow/frontend_dist/revoluzen-flow-logo-mark.png +0 -0
- revoluzen_flow/frontend_dist/revoluzen-flow-logo.png +0 -0
- revoluzen_flow/gateway/__init__.py +343 -0
- revoluzen_flow/gitcopy/__init__.py +17 -0
- revoluzen_flow/gitcopy/client.py +301 -0
- revoluzen_flow/gitcopy/files.py +328 -0
- revoluzen_flow/gitcopy/service.py +223 -0
- revoluzen_flow/gitcopy/settings.py +210 -0
- revoluzen_flow/gitcopy/store.py +152 -0
- revoluzen_flow/glossary/__init__.py +12 -0
- revoluzen_flow/glossary/store.py +240 -0
- revoluzen_flow/importers/__init__.py +2 -0
- revoluzen_flow/importers/dbt.py +530 -0
- revoluzen_flow/incidents/__init__.py +17 -0
- revoluzen_flow/incidents/policy.py +106 -0
- revoluzen_flow/incidents/service.py +295 -0
- revoluzen_flow/incidents/shared.py +127 -0
- revoluzen_flow/incidents/store.py +225 -0
- revoluzen_flow/intelligence/__init__.py +35 -0
- revoluzen_flow/intelligence/error_intel.py +558 -0
- revoluzen_flow/intelligence/execution_intel.py +471 -0
- revoluzen_flow/intelligence/flatten_engine.py +526 -0
- revoluzen_flow/intelligence/join_discovery.py +395 -0
- revoluzen_flow/intelligence/pre_validator.py +851 -0
- revoluzen_flow/intelligence/schema_contract.py +379 -0
- revoluzen_flow/intelligence/schema_detector.py +895 -0
- revoluzen_flow/intelligence/schema_history.py +228 -0
- revoluzen_flow/intelligence/schema_policy.py +616 -0
- revoluzen_flow/intelligence/type_normalization.py +705 -0
- revoluzen_flow/ir/__init__.py +8 -0
- revoluzen_flow/ir/docs.py +196 -0
- revoluzen_flow/ir/governance.py +119 -0
- revoluzen_flow/ir/lifecycle.py +151 -0
- revoluzen_flow/ir/migrations.py +297 -0
- revoluzen_flow/ir/node_metadata.py +255 -0
- revoluzen_flow/ir/plan_diff.py +203 -0
- revoluzen_flow/ir/preflight.py +186 -0
- revoluzen_flow/ir/published_refs.py +200 -0
- revoluzen_flow/ir/schema.py +689 -0
- revoluzen_flow/ir/spec.py +183 -0
- revoluzen_flow/ir/step_secrets.py +635 -0
- revoluzen_flow/ir/validator.py +390 -0
- revoluzen_flow/ir/versioning.py +1196 -0
- revoluzen_flow/ir/workflow_bin.py +311 -0
- revoluzen_flow/legacy_files/__init__.py +12 -0
- revoluzen_flow/legacy_files/codepages.py +166 -0
- revoluzen_flow/legacy_files/copybook.py +1202 -0
- revoluzen_flow/legacy_files/fixed_width.py +253 -0
- revoluzen_flow/legacy_files/landing.py +95 -0
- revoluzen_flow/legacy_files/records.py +221 -0
- revoluzen_flow/legacy_files/values.py +309 -0
- revoluzen_flow/licensing.py +81 -0
- revoluzen_flow/lifecycle/__init__.py +13 -0
- revoluzen_flow/lifecycle/store.py +193 -0
- revoluzen_flow/lineage/__init__.py +520 -0
- revoluzen_flow/lineage/openlineage.py +376 -0
- revoluzen_flow/main.py +2476 -0
- revoluzen_flow/marketplace/__init__.py +233 -0
- revoluzen_flow/monitoring/__init__.py +3 -0
- revoluzen_flow/monitoring/pipeline_health.py +242 -0
- revoluzen_flow/monitoring/status.py +148 -0
- revoluzen_flow/monitoring/store.py +481 -0
- revoluzen_flow/monitoring/timing.py +25 -0
- revoluzen_flow/nodes/__init__.py +3 -0
- revoluzen_flow/nodes/_column_mapping.py +66 -0
- revoluzen_flow/nodes/_kafka_positions.py +124 -0
- revoluzen_flow/nodes/_path_utils.py +77 -0
- revoluzen_flow/nodes/_remote_files.py +114 -0
- revoluzen_flow/nodes/_sftp.py +115 -0
- revoluzen_flow/nodes/_sync_mode_decl.py +141 -0
- revoluzen_flow/nodes/activities.py +2456 -0
- revoluzen_flow/nodes/advanced_transforms.py +371 -0
- revoluzen_flow/nodes/aggregate.py +173 -0
- revoluzen_flow/nodes/ai.py +428 -0
- revoluzen_flow/nodes/base.py +408 -0
- revoluzen_flow/nodes/cloud_files.py +1024 -0
- revoluzen_flow/nodes/cloud_storage.py +508 -0
- revoluzen_flow/nodes/control_extras.py +1216 -0
- revoluzen_flow/nodes/csv_source.py +53 -0
- revoluzen_flow/nodes/data_wrangler.py +738 -0
- revoluzen_flow/nodes/db_source.py +1373 -0
- revoluzen_flow/nodes/deduplicate.py +138 -0
- revoluzen_flow/nodes/file_node.py +1179 -0
- revoluzen_flow/nodes/filter_node.py +195 -0
- revoluzen_flow/nodes/flow_control.py +2741 -0
- revoluzen_flow/nodes/generic.py +279 -0
- revoluzen_flow/nodes/guardrails.py +166 -0
- revoluzen_flow/nodes/join.py +260 -0
- revoluzen_flow/nodes/local_table.py +815 -0
- revoluzen_flow/nodes/output.py +81 -0
- revoluzen_flow/nodes/pipeline_output.py +235 -0
- revoluzen_flow/nodes/quality.py +960 -0
- revoluzen_flow/nodes/reconcile.py +405 -0
- revoluzen_flow/nodes/registry.py +105 -0
- revoluzen_flow/nodes/retry_handler.py +96 -0
- revoluzen_flow/nodes/scd2.py +474 -0
- revoluzen_flow/nodes/sinks.py +2263 -0
- revoluzen_flow/nodes/sources.py +1328 -0
- revoluzen_flow/nodes/transform.py +122 -0
- revoluzen_flow/notifications/__init__.py +1 -0
- revoluzen_flow/notifications/models.py +32 -0
- revoluzen_flow/notifications/run_events.py +209 -0
- revoluzen_flow/notifications/service.py +746 -0
- revoluzen_flow/notifications/store.py +168 -0
- revoluzen_flow/openpgp/__init__.py +34 -0
- revoluzen_flow/openpgp/aead.py +251 -0
- revoluzen_flow/openpgp/algorithms.py +277 -0
- revoluzen_flow/openpgp/armor.py +210 -0
- revoluzen_flow/openpgp/credentials.py +105 -0
- revoluzen_flow/openpgp/keygen.py +165 -0
- revoluzen_flow/openpgp/keys.py +501 -0
- revoluzen_flow/openpgp/message.py +957 -0
- revoluzen_flow/openpgp/packets.py +445 -0
- revoluzen_flow/openpgp/signatures.py +545 -0
- revoluzen_flow/planner/__init__.py +4 -0
- revoluzen_flow/planner/ai_client.py +1144 -0
- revoluzen_flow/planner/ir_from_json.py +137 -0
- revoluzen_flow/planner/rule_planner.py +390 -0
- revoluzen_flow/planner/templates.py +450 -0
- revoluzen_flow/plugins/__init__.py +303 -0
- revoluzen_flow/pool/__init__.py +28 -0
- revoluzen_flow/pool/store.py +188 -0
- revoluzen_flow/projects/__init__.py +4 -0
- revoluzen_flow/projects/acl.py +143 -0
- revoluzen_flow/projects/models.py +95 -0
- revoluzen_flow/projects/store.py +147 -0
- revoluzen_flow/quality_rules/__init__.py +11 -0
- revoluzen_flow/quality_rules/store.py +248 -0
- revoluzen_flow/reports/__init__.py +22 -0
- revoluzen_flow/reports/builder/__init__.py +19 -0
- revoluzen_flow/reports/builder/catalog.py +329 -0
- revoluzen_flow/reports/builder/collect.py +1349 -0
- revoluzen_flow/reports/builder/deliver.py +276 -0
- revoluzen_flow/reports/builder/models.py +194 -0
- revoluzen_flow/reports/builder/render.py +468 -0
- revoluzen_flow/reports/builder/schedule.py +268 -0
- revoluzen_flow/reports/builder/store.py +274 -0
- revoluzen_flow/reports/cron_human.py +175 -0
- revoluzen_flow/reports/inventory.py +2108 -0
- revoluzen_flow/reports/inventory_docx.py +1209 -0
- revoluzen_flow/reports/inventory_pdf.py +1409 -0
- revoluzen_flow/runtime_config.py +290 -0
- revoluzen_flow/scheduling/__init__.py +4 -0
- revoluzen_flow/scheduling/lease.py +192 -0
- revoluzen_flow/scheduling/models.py +263 -0
- revoluzen_flow/scheduling/scheduler.py +1607 -0
- revoluzen_flow/scheduling/store.py +172 -0
- revoluzen_flow/security/__init__.py +25 -0
- revoluzen_flow/security/encryptor.py +414 -0
- revoluzen_flow/security/execution_codes.py +148 -0
- revoluzen_flow/security/migrate_existing.py +810 -0
- revoluzen_flow/security/route_posture_baseline.py +38 -0
- revoluzen_flow/security/sql_sandbox.py +335 -0
- revoluzen_flow/security/ssrf.py +207 -0
- revoluzen_flow/security/step_secret_routes.py +98 -0
- revoluzen_flow/security/win_acl.py +161 -0
- revoluzen_flow/seed_data/__init__.py +14 -0
- revoluzen_flow/seed_data/orders.csv +26 -0
- revoluzen_flow/sinks/__init__.py +26 -0
- revoluzen_flow/sinks/dedupe_store.py +300 -0
- revoluzen_flow/sinks/idempotency_helper.py +156 -0
- revoluzen_flow/sinks/tombstone.py +211 -0
- revoluzen_flow/state.py +169 -0
- revoluzen_flow/static/swagger-ui/LICENSES.md +29 -0
- revoluzen_flow/static/swagger-ui/favicon.png +0 -0
- revoluzen_flow/static/swagger-ui/redoc.standalone.js +1838 -0
- revoluzen_flow/static/swagger-ui/swagger-ui-bundle.js +2 -0
- revoluzen_flow/static/swagger-ui/swagger-ui.css +3 -0
- revoluzen_flow/steward/__init__.py +227 -0
- revoluzen_flow/steward/archeologist.py +481 -0
- revoluzen_flow/steward/cadence.py +256 -0
- revoluzen_flow/steward/connector_health.py +495 -0
- revoluzen_flow/steward/cost.py +421 -0
- revoluzen_flow/steward/coverage.py +108 -0
- revoluzen_flow/steward/foreseer.py +320 -0
- revoluzen_flow/steward/governance.py +299 -0
- revoluzen_flow/steward/ingest.py +220 -0
- revoluzen_flow/steward/lessons.py +550 -0
- revoluzen_flow/steward/memory.py +499 -0
- revoluzen_flow/steward/models.py +331 -0
- revoluzen_flow/steward/node_cardinality.py +331 -0
- revoluzen_flow/steward/notifier.py +256 -0
- revoluzen_flow/steward/null_rate.py +263 -0
- revoluzen_flow/steward/pii.py +286 -0
- revoluzen_flow/steward/quality.py +327 -0
- revoluzen_flow/steward/repeated_logic.py +172 -0
- revoluzen_flow/steward/row_delta.py +290 -0
- revoluzen_flow/steward/rules.py +394 -0
- revoluzen_flow/steward/schema_drift.py +380 -0
- revoluzen_flow/steward/settings.py +172 -0
- revoluzen_flow/steward/storage_intel.py +248 -0
- revoluzen_flow/steward/thresholds.py +94 -0
- revoluzen_flow/storage/__init__.py +5 -0
- revoluzen_flow/storage/backup.py +106 -0
- revoluzen_flow/storage/backup_scheduler.py +241 -0
- revoluzen_flow/storage/database.py +3542 -0
- revoluzen_flow/storage/database_factory.py +109 -0
- revoluzen_flow/storage/migrations.py +163 -0
- revoluzen_flow/storage/providers.py +392 -0
- revoluzen_flow/storage/storage_settings.py +214 -0
- revoluzen_flow/streams/__init__.py +29 -0
- revoluzen_flow/streams/connection.py +54 -0
- revoluzen_flow/streams/holds.py +94 -0
- revoluzen_flow/streams/pg_cdc.py +739 -0
- revoluzen_flow/streams/positions.py +139 -0
- revoluzen_flow/streams/rows.py +235 -0
- revoluzen_flow/telemetry/__init__.py +53 -0
- revoluzen_flow/telemetry/consent.py +83 -0
- revoluzen_flow/telemetry/sender.py +353 -0
- revoluzen_flow/templates/__init__.py +0 -0
- revoluzen_flow/templates/catalog_meta.py +186 -0
- revoluzen_flow/templates/gallery.py +18 -0
- revoluzen_flow/triggers/__init__.py +19 -0
- revoluzen_flow/triggers/chain.py +218 -0
- revoluzen_flow/triggers/file_listing.py +627 -0
- revoluzen_flow/triggers/file_watch.py +343 -0
- revoluzen_flow/triggers/gate.py +75 -0
- revoluzen_flow/triggers/store.py +272 -0
- revoluzen_flow/triggers/webhook_signing.py +139 -0
- revoluzen_flow/types/__init__.py +114 -0
- revoluzen_flow/types/canonical.py +256 -0
- revoluzen_flow/types/cast_safety.py +219 -0
- revoluzen_flow/types/drift.py +313 -0
- revoluzen_flow/types/from_mssql.py +323 -0
- revoluzen_flow/types/from_mysql.py +280 -0
- revoluzen_flow/types/from_oracle.py +306 -0
- revoluzen_flow/types/from_postgres.py +283 -0
- revoluzen_flow/types/policy.py +196 -0
- revoluzen_flow/types/to_mssql.py +234 -0
- revoluzen_flow/types/to_mysql.py +185 -0
- revoluzen_flow/types/to_oracle.py +202 -0
- revoluzen_flow/types/to_postgres.py +256 -0
- revoluzen_flow/variables/__init__.py +4 -0
- revoluzen_flow/variables/models.py +48 -0
- revoluzen_flow/variables/store.py +138 -0
- revoluzen_flow/workspaces/__init__.py +17 -0
- revoluzen_flow/workspaces/models.py +186 -0
- revoluzen_flow/workspaces/store.py +380 -0
- revoluzen_flow-1.0.1.dev0.dist-info/METADATA +826 -0
- revoluzen_flow-1.0.1.dev0.dist-info/RECORD +942 -0
- revoluzen_flow-1.0.1.dev0.dist-info/WHEEL +5 -0
- revoluzen_flow-1.0.1.dev0.dist-info/entry_points.txt +3 -0
- revoluzen_flow-1.0.1.dev0.dist-info/licenses/LICENSE +201 -0
- revoluzen_flow-1.0.1.dev0.dist-info/licenses/NOTICE +42 -0
- revoluzen_flow-1.0.1.dev0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,724 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Revoluzen Flow are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
API stability policy: see `docs/api.md`. The HTTP API surface under `/api/*`
|
|
9
|
+
follows the compatibility rules documented there.
|
|
10
|
+
|
|
11
|
+
## [Unreleased]
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Start a pipeline when a file arrives.** In a pipeline's Schedule dialog,
|
|
16
|
+
"A file arriving" watches a folder on the Flow server, on an SFTP server, on a
|
|
17
|
+
Windows file share, in Amazon S3 (or MinIO), Google Cloud Storage or Azure Blob
|
|
18
|
+
Storage. Each new file
|
|
19
|
+
whose name matches the pattern starts one run, with the file's path in the
|
|
20
|
+
parameter you choose. A file must stop changing for a set time before its run
|
|
21
|
+
starts, so one still being copied is not read half-written. What was seen is
|
|
22
|
+
remembered in the database, so a file never starts two runs, across restarts
|
|
23
|
+
and servers; a file replaced by a new version starts its own. Files already in
|
|
24
|
+
the folder are left alone unless you ask for them. Runs go one at a time, oldest
|
|
25
|
+
file first. "Check the folder now" shows what the trigger would see before you
|
|
26
|
+
save.
|
|
27
|
+
|
|
28
|
+
- **Run a pipeline after another one.** "Another pipeline finishing" starts it
|
|
29
|
+
when another pipeline succeeds, fails, or finishes either way. Runs started by
|
|
30
|
+
a schedule, a file, another pipeline or another application count; runs started
|
|
31
|
+
by hand do not. A loop is refused when it is saved, naming the pipelines in it,
|
|
32
|
+
and again at run time.
|
|
33
|
+
|
|
34
|
+
- **Signed calls to published endpoints.** An endpoint can require each call to
|
|
35
|
+
be signed with a secret Flow makes, shows once and keeps encrypted, in the open
|
|
36
|
+
Standard Webhooks format (`webhook-id`, `webhook-timestamp`,
|
|
37
|
+
`webhook-signature`). A changed call, a message already received, or one more
|
|
38
|
+
than 5 minutes old is refused. Works with or without an API key, and the
|
|
39
|
+
Triggers page writes the signing command for a terminal or PowerShell.
|
|
40
|
+
|
|
41
|
+
All three only ever run a published pipeline, at its published version, and
|
|
42
|
+
follow its overlap setting and run time limit. See
|
|
43
|
+
`docs/user-guides/pipelines.md` (Scheduling and triggers) and `docs/api.md`.
|
|
44
|
+
|
|
45
|
+
- **Windows file shares.** A new connection, **Windows File Share (SMB)**, reads
|
|
46
|
+
and writes `\\server\share` files with a saved sign-in (domain, user name,
|
|
47
|
+
password), the same whether Flow runs on Windows, Linux or Docker. Pick it in a
|
|
48
|
+
Source or Destination and the File step does the rest, so every format it reads
|
|
49
|
+
works on a share, including fixed-width text, COBOL copybook records, EBCDIC and
|
|
50
|
+
PGP-encrypted files; `*` and `?` in a file name read every matching file. A file
|
|
51
|
+
is written under a temporary name and renamed once complete, so a program
|
|
52
|
+
watching the folder never picks up half of it. Test connection signs in and
|
|
53
|
+
lists the folder. A file landing on a share can start a pipeline: choose "A
|
|
54
|
+
file arriving" and "A Windows file share" in the Schedule dialog, and each new
|
|
55
|
+
file starts one run with its full `\\server\share\...` path, which the File
|
|
56
|
+
step reads with the same connection. A file that the program writing it still
|
|
57
|
+
has open waits until it is closed. The client, `smbprotocol` (MIT, with
|
|
58
|
+
`pyspnego` and on Windows `sspilib`), now ships with Flow, and the connector
|
|
59
|
+
count is 67. See `docs/user-guides/mainframe-and-legacy-files.md`.
|
|
60
|
+
|
|
61
|
+
- **Kafka with a company's own certificate authority and client certificates.** A
|
|
62
|
+
Kafka connection that uses `SSL` or `SASL_SSL` now takes a CA certificate, so
|
|
63
|
+
Flow can reach brokers whose certificates the company signs itself, and a client
|
|
64
|
+
certificate with its private key (and the key's password, if it is locked) for
|
|
65
|
+
brokers that ask each client for one. They are pasted as text, so there is no
|
|
66
|
+
file to copy to the Flow server, and they reach both Kafka client libraries in
|
|
67
|
+
the Kafka Source, the Kafka Sink, Test connection and topic browsing. A
|
|
68
|
+
certificate that cannot be read, a wrong key password or a key that does not
|
|
69
|
+
belong to its certificate is named before Kafka is contacted. The private key and
|
|
70
|
+
its password are kept encrypted, never sent back to the browser and never
|
|
71
|
+
repeated in a message or a log line. Until now `SSL` trusted only the
|
|
72
|
+
certificates the computer trusts, and no client certificate could be given. See
|
|
73
|
+
`docs/nodes-and-canvas-reference.md` (Kafka Source).
|
|
74
|
+
|
|
75
|
+
- **Reports you design and schedule.** Insights > Reports used to offer one fixed
|
|
76
|
+
document. Now you choose the sections (runs, failures, successes, usage, storage,
|
|
77
|
+
AI use, environment, new builds, schedules, alerts, or a table you design), narrow
|
|
78
|
+
them to the period, projects and pipelines you care about, and save the report.
|
|
79
|
+
A saved report can be sent daily, weekly or monthly by email, Slack, Teams or
|
|
80
|
+
webhook, using the existing scheduler and notification settings. Each report keeps
|
|
81
|
+
a history of what went out, to whom, and why anything failed. The fixed inventory
|
|
82
|
+
document stays, as a starting point on the same page. See
|
|
83
|
+
`docs/user-guides/reports.md`.
|
|
84
|
+
|
|
85
|
+
- **The Bin for deleted pipelines.** Deleting a pipeline now moves it to the Bin
|
|
86
|
+
tab on the Pipelines page instead of removing it. It keeps its saved versions
|
|
87
|
+
and stays for 30 days (`REVOLUZEN_FLOW_BIN_RETENTION_DAYS`; `0` means never
|
|
88
|
+
removed automatically), then a daily job removes it for good. The Bin lives on
|
|
89
|
+
the server, so everyone in the workspace sees the same list, and the tab reads
|
|
90
|
+
it again each time it is opened: a pipeline someone else deleted or restored in
|
|
91
|
+
the meantime shows without reloading the page.
|
|
92
|
+
|
|
93
|
+
**Restore** brings a pipeline back as a draft, never published, with its
|
|
94
|
+
schedules back but paused. A name taken in the meantime gets a "(2)" suffix, and
|
|
95
|
+
a project or folder that is gone is replaced by Default or the project root; the
|
|
96
|
+
toast says which. **Delete forever** removes one at once, and admins can
|
|
97
|
+
**Empty Bin**. Deleting, restoring and removing need the Developer role, and
|
|
98
|
+
emptying needs Admin. Deleting a folder together with its pipelines goes to the
|
|
99
|
+
Bin too.
|
|
100
|
+
|
|
101
|
+
The API gains `GET /api/workflows/bin`, `POST /api/workflows/bin/{id}/restore`,
|
|
102
|
+
`DELETE /api/workflows/bin/{id}` and `DELETE /api/workflows/bin`.
|
|
103
|
+
`DELETE /api/workflows/{id}` now answers `{"deleted": true, "binned": true, ...}`,
|
|
104
|
+
and `?permanent=true` skips the Bin for scripts that must leave no copy (the app
|
|
105
|
+
has no button for it). Delete, restore and purge are recorded in the audit log.
|
|
106
|
+
A CDC pipeline gets new replication slots on restore and does not replay changes
|
|
107
|
+
made to its source while it was in the Bin.
|
|
108
|
+
|
|
109
|
+
- **Triggers page.** Workflows → Triggers lets another application start a
|
|
110
|
+
pipeline and pass it values: endpoints, API keys, and a ready-to-use command.
|
|
111
|
+
The runs appear on Executions with the trigger API, and the inventory report
|
|
112
|
+
lists endpoints and masked keys.
|
|
113
|
+
|
|
114
|
+
- **Credential expiry warnings.** Give a credential an expiry date and
|
|
115
|
+
administrators are warned on the bell and by email a week ahead, a day ahead
|
|
116
|
+
and when it expires. Settings → Notifications → Credential expiry warnings
|
|
117
|
+
turns them off.
|
|
118
|
+
|
|
119
|
+
- **Saved credentials fill a connection's fields.** Pick one under Saved
|
|
120
|
+
credential and the fields it holds fill themselves. A SaaS Connector step takes
|
|
121
|
+
a saved credential too.
|
|
122
|
+
|
|
123
|
+
- **The Copilot asks before drafting.** It asks where the data comes from and
|
|
124
|
+
where it goes, from the workspace's real connections, files and tables, and a
|
|
125
|
+
missing connection can be created in the chat.
|
|
126
|
+
|
|
127
|
+
- **`inspect_step_columns` Copilot tool.** Lists the columns a step receives, as
|
|
128
|
+
names and types only, so the agent can fix a renamed column instead of
|
|
129
|
+
guessing from an error message. It refuses if an upstream step could have a
|
|
130
|
+
side effect. The agent also gets guidance on repairing pipelines: draft instead
|
|
131
|
+
of describing, never guess a column, and leave a failing check in place.
|
|
132
|
+
|
|
133
|
+
- **Chained pipeline drafts.** `modify_pipeline_step` takes a `draft_id` to build
|
|
134
|
+
on an earlier edit, so a fix can span several steps. The editor now tells the
|
|
135
|
+
agent every step's id, which it needs to edit more than the selected step.
|
|
136
|
+
|
|
137
|
+
- **Repair evaluation for the Copilot.** `python -m revoluzen_flow.eval.repair`
|
|
138
|
+
runs broken pipelines through the real agent loop, then runs each draft on the
|
|
139
|
+
real engine against held-out data and answers computed in plain Python. It
|
|
140
|
+
scores repairs, whether failing checks were left alone, honest refusals and
|
|
141
|
+
false claims. CI gates the scripted ideal assistant at 100% and replays
|
|
142
|
+
recorded models. See `docs/repair-evaluation.md`.
|
|
143
|
+
|
|
144
|
+
- **The Copilot refuses to guess when repairing a pipeline.** An edit that
|
|
145
|
+
picks between columns, invents a replacement for one that is gone, or points a
|
|
146
|
+
source at something nobody named is refused until the person says which one.
|
|
147
|
+
Edits in one request now build on each other, a repair gets ten steps and must
|
|
148
|
+
end with an answer, and a refusal reaches the model whole. A draft test now
|
|
149
|
+
fails on a value that only breaks when rows are read.
|
|
150
|
+
|
|
151
|
+
- **The Copilot repairs from column names and types only.** It cannot see row
|
|
152
|
+
values, and an edit that writes a label, number or date nobody gave is refused.
|
|
153
|
+
A draft test's verdict is now `runs` rather than `passed`, and `output_checked`
|
|
154
|
+
says whether anything looked at the output.
|
|
155
|
+
|
|
156
|
+
- **More than one instance is now safe to run.** Two additions, together:
|
|
157
|
+
|
|
158
|
+
`REVOLUZEN_FLOW_ENABLE_SCHEDULER=0` makes a node API-only — it serves
|
|
159
|
+
requests without running the scheduler loop. Defaults on, so a single-node
|
|
160
|
+
install is unchanged.
|
|
161
|
+
|
|
162
|
+
`scheduling/lease.py` holds a durable single-row lease in the metadata
|
|
163
|
+
database; only the holder fires schedules. Acquire and renew are one
|
|
164
|
+
conditional `UPDATE` so two instances cannot both win between a read and a
|
|
165
|
+
write, the TTL is three tick intervals, and the holder renews every tick.
|
|
166
|
+
A clean `stop()` releases the lease so a standby takes over on its next
|
|
167
|
+
tick rather than waiting out the TTL.
|
|
168
|
+
|
|
169
|
+
Previously the scheduler tracked in-flight work in process-local dicts and
|
|
170
|
+
started unconditionally on every instance. Those dicts stop one process
|
|
171
|
+
double-running a schedule but say nothing about a second process, so two
|
|
172
|
+
instances behind a load balancer fired **every schedule twice** — silently,
|
|
173
|
+
with both runs looking legitimate. Verified with three instances over ten
|
|
174
|
+
ticks: ten firings, all from one node, where the old behaviour would have
|
|
175
|
+
produced thirty.
|
|
176
|
+
|
|
177
|
+
The lease fails closed. An instance that cannot reach the lease row does
|
|
178
|
+
not schedule, because missing a tick is recoverable and already alerted on
|
|
179
|
+
by schedule-miss detection, while a duplicate run can double-charge a
|
|
180
|
+
customer or duplicate rows in their warehouse.
|
|
181
|
+
|
|
182
|
+
Supported topology is now N API instances plus whichever one holds the
|
|
183
|
+
lease. A worker pool spanning machines is still not supported — see
|
|
184
|
+
`edition-matrix.md`.
|
|
185
|
+
|
|
186
|
+
- **Edition gate** — `revoluzen_flow/licensing.py` provides `is_plus()` and
|
|
187
|
+
`require_plus(feature)`, the first runtime enforcement of the Plus-only node
|
|
188
|
+
declarations in `edition-matrix.md`.
|
|
189
|
+
|
|
190
|
+
Those declarations previously had nothing behind them: CDC is listed
|
|
191
|
+
Plus-only in the edition matrix, in `ai/session_context.py` and in
|
|
192
|
+
anti-pattern rule 25, but `connectors/cdc.py` registered
|
|
193
|
+
`StepType.CDC_SOURCE` with no licence check and ran on free instances. No
|
|
194
|
+
node-level gate existed anywhere to follow — the `is_plus` checks in the
|
|
195
|
+
codebase were all in AI tools and catalog listings.
|
|
196
|
+
|
|
197
|
+
Detection fails closed: any import failure, missing `app_state` or
|
|
198
|
+
partially initialised licence manager reads as free, because an edition
|
|
199
|
+
check that defaults to paid when something breaks is not a check.
|
|
200
|
+
`PlusRequiredError` is its own type so the UI can offer an upgrade path, and
|
|
201
|
+
`engine/failure_class.py` maps it to `USER_INPUT` so the retry policy stops
|
|
202
|
+
— no number of attempts produces a licence.
|
|
203
|
+
|
|
204
|
+
The gate runs at **execution**, not registration, so a free instance still
|
|
205
|
+
shows the node and can build a pipeline against it. The catalog stays
|
|
206
|
+
identical across editions and the refusal names the feature when it runs.
|
|
207
|
+
|
|
208
|
+
CDC is gated. Vector DB sinks and the JDBC dialect registry were also
|
|
209
|
+
declared Plus-only with no enforcement; rather than add the gate, both
|
|
210
|
+
moved to OSS on 2026-10-23 — see below.
|
|
211
|
+
|
|
212
|
+
### Changed
|
|
213
|
+
|
|
214
|
+
- **Two things that were declared but never built are gone.** The schedule type
|
|
215
|
+
`event`, with `event_trigger` and `event_source_id`, never fired; the API no
|
|
216
|
+
longer takes it. A row saved with it is read as the trigger it described
|
|
217
|
+
("pipeline_completed" becomes "after another pipeline"), switched off, for
|
|
218
|
+
someone to check and turn on. The step type `webhook_trigger` had no
|
|
219
|
+
implementation and left the palette in May; it has left the step types too.
|
|
220
|
+
A saved pipeline that still holds one opens as before, rewritten to an API
|
|
221
|
+
source. Another system starts a pipeline through a published endpoint, which
|
|
222
|
+
can now require signed calls.
|
|
223
|
+
|
|
224
|
+
- **Vector DB sinks and the JDBC dialect registry are now OSS.** Both were
|
|
225
|
+
listed Plus-only and neither was ever enforced, so the choice was to add a
|
|
226
|
+
gate or drop the claim. Dropped it.
|
|
227
|
+
|
|
228
|
+
OSS already ships the entire local RAG stack — Ollama embeddings and a
|
|
229
|
+
SQLite-vec store — so charging to write pipeline output to a vector
|
|
230
|
+
database while embedding freely for our own features was the row a buyer
|
|
231
|
+
attacks first. The JDBC registry is the extensibility mechanism, and
|
|
232
|
+
Postgres, MySQL, MSSQL, SQLite and DuckDB all reach their databases
|
|
233
|
+
without touching it; gating it protected no revenue and only stopped
|
|
234
|
+
someone with an unusual database helping themselves. The *maintained*
|
|
235
|
+
enterprise dialects shipped through it (SAP HANA, Teradata, DB2, Informix)
|
|
236
|
+
stay Enterprise.
|
|
237
|
+
|
|
238
|
+
- **SSO is designated OSS**, and the matrix now says `planned` rather than
|
|
239
|
+
implying it ships — OIDC/SAML is not implemented in this repository at
|
|
240
|
+
all. Enterprise keeps SCIM provisioning and directory sync. The audit-log
|
|
241
|
+
row is clarified: the record, and the ability to read it, are OSS;
|
|
242
|
+
retention policy, signed export and SIEM formats are Enterprise.
|
|
243
|
+
|
|
244
|
+
- `edition-matrix.md` gains a **"which side does a new feature go on?"**
|
|
245
|
+
test, so the split is decided by rule rather than case by case. The
|
|
246
|
+
mechanism and the interface are OSS; maintained integrations,
|
|
247
|
+
administration-at-scale and governance over third parties are Enterprise.
|
|
248
|
+
Never gate correctness, and never gate security basics.
|
|
249
|
+
|
|
250
|
+
- **ELT on warehouses and the lakehouse.** `execute_sql_task` — the node that
|
|
251
|
+
fires SQL at a real connection rather than transforming in-memory — now
|
|
252
|
+
reaches `redshift`, `mssql`/`synapse`, `snowflake`, `bigquery` and
|
|
253
|
+
`databricks`, alongside the existing postgres, mysql/mariadb and sqlite.
|
|
254
|
+
|
|
255
|
+
Previously the matrix stopped at Postgres, MySQL and SQLite, so Revoluzen
|
|
256
|
+
Flow could *load into* Snowflake, BigQuery, Redshift and a lake but not
|
|
257
|
+
*transform in* them — the half of ELT that people mean by the word. The
|
|
258
|
+
dialect matrix is deliberately one function shared by Execute SQL and the
|
|
259
|
+
Lookup activity, so all of these arrived in one place.
|
|
260
|
+
|
|
261
|
+
This completes a Medallion pipeline end to end: land bronze as Parquet with
|
|
262
|
+
`adls_gen2_sink` or `s3_sink` (both emit `FORMAT PARQUET`, and parquet is
|
|
263
|
+
the default), build silver and gold with SQL running on Databricks or the
|
|
264
|
+
warehouse itself, then serve to SQL Server via `db_sink`, which routes
|
|
265
|
+
through the bulk loader. The intermediate layers never travel back through
|
|
266
|
+
the engine.
|
|
267
|
+
|
|
268
|
+
Drivers stay optional extras — `pip install revoluzen-flow[databricks]` and
|
|
269
|
+
friends — and a missing one now reports the install command rather than an
|
|
270
|
+
ImportError naming an unfamiliar module. Redshift needs no new dependency;
|
|
271
|
+
it is Postgres wire-compatible and uses psycopg2, differing only in its
|
|
272
|
+
default port.
|
|
273
|
+
|
|
274
|
+
### Security
|
|
275
|
+
|
|
276
|
+
Fixes from an internal penetration test. Upgrade before exposing an instance
|
|
277
|
+
to anyone but yourself.
|
|
278
|
+
|
|
279
|
+
- **Roles are enforced on every route that runs or authors a pipeline.**
|
|
280
|
+
Running, replaying, testing and previewing pipelines, editing or testing
|
|
281
|
+
connections, uploads, imports, deployments and backfills now need the
|
|
282
|
+
developer role or above; approving needs an admin, and the approver is the
|
|
283
|
+
signed-in user, never a name sent with the request.
|
|
284
|
+
- **Pipeline SQL can no longer reach the instance's own secrets.** In server
|
|
285
|
+
mode, DuckDB runs with an allowlist: the data folder's working folders and
|
|
286
|
+
the files a pipeline names. The master key, the app database, backups and
|
|
287
|
+
the config folder are never on it. `REVOLUZEN_FLOW_SQL_SANDBOX=1|0` forces it
|
|
288
|
+
on or off. A SQL Transform must be a single statement.
|
|
289
|
+
- **Secrets stay masked.** The notification settings (SMTP password, webhook
|
|
290
|
+
URLs) need an admin and never return secrets; secret variables are masked in
|
|
291
|
+
every response.
|
|
292
|
+
- **Anonymous access is closed in server mode** for notifications, run
|
|
293
|
+
history and system information, and the Docker image and compose file now
|
|
294
|
+
start in server mode. A local-mode instance refuses requests that arrive
|
|
295
|
+
over the network, however it was started.
|
|
296
|
+
- **The first account on a server needs a one-time setup token**, printed in
|
|
297
|
+
the log at startup and saved as `SETUP_TOKEN.txt`.
|
|
298
|
+
- **Password-reset links** use `REVOLUZEN_FLOW_PUBLIC_URL` only, never the
|
|
299
|
+
request's own headers.
|
|
300
|
+
- **Cross-site requests** with an opaque (`null`) origin are refused on a
|
|
301
|
+
local install, and connection tests no longer block the server.
|
|
302
|
+
- Workspace admins stay in their own workspaces, admins cannot grant a role
|
|
303
|
+
above their own, comments are tied to their author and workspace, and
|
|
304
|
+
`/register` no longer reveals which emails have accounts.
|
|
305
|
+
|
|
306
|
+
### Fixed
|
|
307
|
+
|
|
308
|
+
- **A Kafka Source read the same messages on every run.** Both Kafka readers
|
|
309
|
+
turned off Kafka's own position saving and never kept a position themselves,
|
|
310
|
+
so each run started again at the oldest message the topic still held, and an
|
|
311
|
+
append destination filled with copies. Each run now carries on after the last
|
|
312
|
+
message the previous successful run read. Flow keeps that position for each
|
|
313
|
+
pipeline step and saves it only when the whole run succeeds, so the messages of
|
|
314
|
+
a failed run are read again rather than lost: after a failure a message can
|
|
315
|
+
arrive twice, but none is skipped. Sample runs and Test Node leave the position
|
|
316
|
+
alone. The step no longer joins a consumer group, so two pipelines reading one
|
|
317
|
+
topic each get every message. A run also uses the brokers saved in the Kafka
|
|
318
|
+
connection (it ignored them and went to `localhost:9092` unless the step named
|
|
319
|
+
other servers), stops once it has caught up instead of waiting out its timeout,
|
|
320
|
+
and stops with a plain message when the topic does not exist or Kafka cannot be
|
|
321
|
+
reached, where it used to succeed with no rows. See
|
|
322
|
+
`docs/nodes-and-canvas-reference.md` (Kafka Source).
|
|
323
|
+
|
|
324
|
+
- **Kafka steps never signed in, so a secured cluster could not be used.** A Kafka
|
|
325
|
+
connection's security protocol, SASL mechanism, username and password reached no
|
|
326
|
+
Kafka client: the Kafka Source, the Kafka Sink, Test connection and topic
|
|
327
|
+
browsing all connected without signing in. They now sign in with `PLAIN`,
|
|
328
|
+
`SCRAM-SHA-256` or `SCRAM-SHA-512` over `SASL_PLAINTEXT` or `SASL_SSL`, with
|
|
329
|
+
either Kafka client library, and a refused sign-in stops the run with what Kafka
|
|
330
|
+
said. The password never appears in a message or a log line. The Kafka Sink also
|
|
331
|
+
read only the older `bootstrap_servers` key, so with a saved connection it wrote
|
|
332
|
+
to `localhost:9092`; it now uses the connection's brokers. It also finished as if
|
|
333
|
+
every message had gone even when Kafka took none; it now checks each message and
|
|
334
|
+
stops the run, saying how many were not written. Topic browsing now works with
|
|
335
|
+
the confluent-kafka add-on too.
|
|
336
|
+
|
|
337
|
+
- **The Kafka forms offered settings that runs ignored.** The Kafka Source's
|
|
338
|
+
Operation, Auto Offset Reset, Partition, Starting Offset and Value Deserializer,
|
|
339
|
+
and the Kafka Sink's Value Serializer and Compression, did nothing. The Source
|
|
340
|
+
now has "First run starts at": the oldest message Kafka keeps, or only new
|
|
341
|
+
messages. A step saved with Operation "consume from latest" keeps that choice.
|
|
342
|
+
The Sink's Compression now reaches Kafka. The other settings are gone, with the
|
|
343
|
+
steps' own broker and sign-in fields: a Kafka step uses a saved Kafka
|
|
344
|
+
connection, as every network step has since May. The Source form also shows the
|
|
345
|
+
step's saved read position with a Reset button, shows the defaults a run uses
|
|
346
|
+
(100 messages, not 1,000; a Sink batch of 500, not 16,384), and has a Timeout
|
|
347
|
+
field. Consumer Group is now optional.
|
|
348
|
+
|
|
349
|
+
- **Cron schedules that name a weekday ran a day late.** The scheduler counted
|
|
350
|
+
days from Monday, while the schedule dialog, the descriptions and the docs all
|
|
351
|
+
use standard cron, where 1 is Monday. A schedule set for Monday ran on Tuesday,
|
|
352
|
+
and `0 9 * * 1-5` ran Tuesday to Saturday. Now 0 and 7 are Sunday and 1 is
|
|
353
|
+
Monday. **Any such schedule moves one day earlier, to the day it has always
|
|
354
|
+
shown.** Hourly, daily, every-N-minutes and `weekly`-type schedules are not
|
|
355
|
+
affected.
|
|
356
|
+
|
|
357
|
+
- **A cron deployment could run twice in one minute.** The check for "already
|
|
358
|
+
ran" looked for a gap of under 30 seconds, and the next tick comes just over
|
|
359
|
+
30 seconds later. A cron schedule or deployment now fires once in a matching
|
|
360
|
+
minute, and a long run that ends inside the next matching minute no longer
|
|
361
|
+
costs that minute its run.
|
|
362
|
+
|
|
363
|
+
- **The NATS event bus never worked against a real server.** With
|
|
364
|
+
`REVOLUZEN_FLOW_EVENT_BUS=nats`, creating the JetStream stream failed with
|
|
365
|
+
"invalid JSON": the stream's retention age was converted to nanoseconds
|
|
366
|
+
twice and overflowed. And every durable event was published a second time
|
|
367
|
+
over core NATS "for live fan-out", which the stream also captured, so each
|
|
368
|
+
event took two sequence numbers and a replay returned everything twice.
|
|
369
|
+
One publish now, and the age is passed in seconds as the client expects.
|
|
370
|
+
Found by running the end-to-end test against a server in CI for the first
|
|
371
|
+
time.
|
|
372
|
+
|
|
373
|
+
- **A folder that held pipelines could not be deleted.** The confirm said its
|
|
374
|
+
pipelines would be "permanently deleted", but the screen sent no mode and the
|
|
375
|
+
server will not guess what to do with them (409), so the user only saw a failure.
|
|
376
|
+
The screen now asks the server what is inside, says how many pipelines will be
|
|
377
|
+
moved to the Bin and how to get them back (they return to the project's top
|
|
378
|
+
level, since the folder is gone), and sends `force`. An empty folder deletes as
|
|
379
|
+
before.
|
|
380
|
+
|
|
381
|
+
- **Creating a pipeline in a folder never checked the folder.** The check passed
|
|
382
|
+
an argument the folder store does not take, and its error was swallowed, so a
|
|
383
|
+
pipeline could be created in a folder that does not exist or belongs to another
|
|
384
|
+
project. It now answers 404 (400 for another project's folder).
|
|
385
|
+
|
|
386
|
+
- **Anyone signed in could delete a folder and the pipelines in it.** Deleting a
|
|
387
|
+
pipeline takes the Developer role, but `DELETE /api/folders/{id}?force=true` only
|
|
388
|
+
asked for a signed-in user, so an analyst or viewer could send every pipeline in
|
|
389
|
+
a folder to the Bin (before the Bin, delete them). It takes the Developer role
|
|
390
|
+
now. Creating and renaming folders, and moving pipelines between them, still ask
|
|
391
|
+
only for a signed-in user.
|
|
392
|
+
|
|
393
|
+
- **A "+ Sub-folder" button that always failed.** Every folder row on the Projects
|
|
394
|
+
page offered it, but folders are one level deep and the server has always refused
|
|
395
|
+
a parent folder ("Sub-folders are not supported"), so it only produced an error.
|
|
396
|
+
The button is gone. "+ Folder" on a project is unchanged, and a folder nested in
|
|
397
|
+
older data is still shown.
|
|
398
|
+
|
|
399
|
+
- **Deleting a folder could send published pipelines to the Bin.** The row menu
|
|
400
|
+
offers Delete only for a draft, failed or archived pipeline, because a published
|
|
401
|
+
one has to be revoked first, but deleting the folder around it never looked at
|
|
402
|
+
status. A folder with a published pipeline in it now refuses to be deleted: the
|
|
403
|
+
screen names the pipelines to revoke before it asks anything, and
|
|
404
|
+
`DELETE /api/folders/{id}?force=true` answers 409 (`published_pipelines_in_folder`)
|
|
405
|
+
without deleting the drafts either. `move_to_root=true`, which keeps the
|
|
406
|
+
pipelines, is not affected.
|
|
407
|
+
|
|
408
|
+
- **The Copilot could return another pipeline's draft.** The idempotency key
|
|
409
|
+
ignored which pipeline was open, so the same edit on a second pipeline returned
|
|
410
|
+
the first pipeline's draft for 24 hours. The key now covers the workspace,
|
|
411
|
+
environment and selection, and draft tools are never served from the cache.
|
|
412
|
+
|
|
413
|
+
- **The write-tool dry-run gate never unlocked.** It forced dry runs until a user
|
|
414
|
+
had 3 successes but counted only live ones. Forced dry runs now count, their
|
|
415
|
+
stub results are no longer cached, and draft-only tools skip the gate for named
|
|
416
|
+
users, because a dry run only replaced a useful draft with a stub.
|
|
417
|
+
|
|
418
|
+
- **Local models could not edit a failing pipeline.** A request mentioning a
|
|
419
|
+
failure filled the eight-tool cap, leaving out the edit tool. The editor's
|
|
420
|
+
repair tools now always keep their slots.
|
|
421
|
+
|
|
422
|
+
- **Execute SQL on MySQL silently discarded writes.** `pymysql` connects with
|
|
423
|
+
`autocommit=False` and the branch never committed, so an `INSERT` or
|
|
424
|
+
`UPDATE` was rolled back when the connection closed — while the cursor
|
|
425
|
+
still reported a rowcount and the node still reported success. A write that
|
|
426
|
+
is lost this way is indistinguishable from one that worked. Commit
|
|
427
|
+
semantics are now pinned per driver and covered by tests, because they
|
|
428
|
+
genuinely differ: psycopg2 commits on context-manager exit, pymysql and
|
|
429
|
+
pyodbc need an explicit commit, Snowflake autocommits, and BigQuery and
|
|
430
|
+
Databricks have no interactive transaction to commit.
|
|
431
|
+
|
|
432
|
+
- **Six screens said one thing and the product did another.**
|
|
433
|
+
- Projects: a project card now has an edit (pencil) button. The Edit Project
|
|
434
|
+
dialog existed but nothing opened it, so a project's name, description,
|
|
435
|
+
colour and icon could never be changed.
|
|
436
|
+
- Dashboard, Avg duration: it now averages successful runs only, as its note
|
|
437
|
+
says. It used to average every finished run, failed ones included. The
|
|
438
|
+
Executions page's Avg Elapsed card reads the same figure and now says so.
|
|
439
|
+
- Dashboard, Pipeline status: the ring mixed run counts with a pipeline total.
|
|
440
|
+
It is now Run outcome mix and counts runs only; the slices add up to the run
|
|
441
|
+
count in the middle.
|
|
442
|
+
- Dashboard, empty state: a workspace with only hand-started runs read "no
|
|
443
|
+
runs yet". The Run volume chart, the ring and the greeting now count every
|
|
444
|
+
run; the Success rate card stays automated-only.
|
|
445
|
+
- Account: the subtitle no longer promises a list of active sessions.
|
|
446
|
+
- Help: Node Reference lists the 45 nodes in the editor's node panel rather
|
|
447
|
+
than 91 entries, says the panel is on the left, and says Delete Data removes
|
|
448
|
+
rows only. A test holds the list to the palette.
|
|
449
|
+
|
|
450
|
+
- **Six more screens said one thing and the product did another.**
|
|
451
|
+
- Pipelines: the Bin tab and its "moved to Bin, auto-removed after 30 days"
|
|
452
|
+
wording described a list kept in one browser while the server deleted the
|
|
453
|
+
pipeline for good. The Bin is now real and on the server (see **The Bin**
|
|
454
|
+
under Added). An archived pipeline also has a **Restore** button now (the
|
|
455
|
+
endpoint existed; no screen called it).
|
|
456
|
+
- Projects: the Archive button's tooltip no longer promises deletion after 30
|
|
457
|
+
days. Nothing deletes an archived project automatically.
|
|
458
|
+
- Delete Data: the settings no longer offer a "files" target, which was never
|
|
459
|
+
implemented and failed when the pipeline ran. A step saved with it still fails,
|
|
460
|
+
and its settings offer "Switch to deleting rows". File cleanup is the File
|
|
461
|
+
System node.
|
|
462
|
+
- Help: the connector strip counts the 66 connectors you can set up, not the 102
|
|
463
|
+
types the catalog registers, and tallies the certification mix over those 66.
|
|
464
|
+
- The Copilot's first-pipeline answer says the node panel is on the left and that
|
|
465
|
+
a node's settings open on double-click, along the bottom of the editor.
|
|
466
|
+
- Canvas tooltips now exist for Delete Data, File System, Execute SQL, Data
|
|
467
|
+
Profile and SaaS Connector, and the Data Quality tooltip no longer lists a
|
|
468
|
+
"unique" rule the node does not have. `docs/nodes.md` lists the 45 nodes.
|
|
469
|
+
|
|
470
|
+
- **The built-in templates' Data Quality steps checked nothing.** Eleven steps in
|
|
471
|
+
nine templates used setting names the Data Quality node does not read (`type`,
|
|
472
|
+
`columns`, `check`, `min`, `max`, `on_fail`, `on_failure`), and a rule the node
|
|
473
|
+
cannot read lets every row through. "Drop empty rows" kept the empty rows, steps
|
|
474
|
+
meant to fail the run never failed it, and a range or pattern check only tested
|
|
475
|
+
for a missing value. Every step now uses the node's own rules and On Failure
|
|
476
|
+
modes, and a test runs each one on data with a bad row.
|
|
477
|
+
- The node has no unique-value rule, so the steps that asked for one now check
|
|
478
|
+
what the node can: SharePoint → Managed Table fails the run when an id is
|
|
479
|
+
missing, and Daily sync drops rows with no id. CSV cleanup keeps its
|
|
480
|
+
Deduplicate step, which is what removes duplicate keys.
|
|
481
|
+
- Data quality + dead-letter queue sent rows to a Switch Case step that cannot
|
|
482
|
+
read the settings the template gave it, so the run failed there. Passing rows
|
|
483
|
+
now leave the Data Quality step by its Pass output to the clean table and
|
|
484
|
+
failing rows by its Reject output to the dead-letter table. The description no
|
|
485
|
+
longer promises a failure reason; the node does not record one.
|
|
486
|
+
- Medallion: the Silver step now drops rows that fail its rules. It was set to
|
|
487
|
+
mark them, which let them into Silver and the Gold totals; Bronze still keeps
|
|
488
|
+
every raw row.
|
|
489
|
+
- Inmon 3NF: the two key checks are named for what they do (the key columns are
|
|
490
|
+
filled in) instead of "PK" and "FK", and the description no longer says it
|
|
491
|
+
validates referential integrity.
|
|
492
|
+
|
|
493
|
+
- **The rest of the built-in templates did not use the settings their steps read.**
|
|
494
|
+
Besides the Data Quality steps, 92 steps in all 27 templates were given setting
|
|
495
|
+
names their node ignores, left out one it requires, or used a step or connector
|
|
496
|
+
the app no longer has. The editor refused to run them ("Missing required field"),
|
|
497
|
+
or a step quietly did something else. Every step now uses its node's own settings,
|
|
498
|
+
and tests hold each one to the node's list of settings and run each template on
|
|
499
|
+
small data with a bad row.
|
|
500
|
+
- First pipeline, the demo that promises real output on a fresh install, stopped
|
|
501
|
+
at its Derived Column step, which wants a list of columns where the template
|
|
502
|
+
gave it a SQL query. It runs now, as do the 19 other steps set up the same way.
|
|
503
|
+
- Managed Table steps (eight templates) used `schema` and `name`, which the node
|
|
504
|
+
does not read, so Run was refused with "Missing required field: table_name".
|
|
505
|
+
- Aggregate, Join and Union steps used `aggregations`, `left_key` / `right_key`
|
|
506
|
+
and `distinct` where the nodes read `functions`, `join_key` and `mode`, so a Join
|
|
507
|
+
stopped with "at least one join key is required". Two Aggregate steps grouped by
|
|
508
|
+
an expression, which the node reads as a column name; the day (DB →
|
|
509
|
+
Warehouse) and the month (Medallion) are now worked out in an earlier step.
|
|
510
|
+
- Database destinations asked for `upsert` with `key_columns`; the node's mode is
|
|
511
|
+
merge, on `merge_on`. Incremental database sources wrote `:last_run`, which
|
|
512
|
+
nothing fills in; they now use the source's incremental setting (a sync mode and
|
|
513
|
+
a watermark column). REST steps set `method`, `auth_type`, a pagination object
|
|
514
|
+
and a URL, none of which the node reads from a template; they now set the path
|
|
515
|
+
to add to the saved connection and the node's own cursor settings, and an
|
|
516
|
+
incremental REST step carries its cursor in the path. Oracle Fusion → Managed
|
|
517
|
+
Table named a connector that does not exist (Oracle Fusion is a kind of saved
|
|
518
|
+
connection, used with the REST source), and SharePoint → Managed Table now uses
|
|
519
|
+
the SharePoint source.
|
|
520
|
+
- Fan-out by region and AI classify + conditional route used the retired Switch
|
|
521
|
+
Case step; they use Switch now, one branch per case. AI classify had no labels
|
|
522
|
+
with example phrases, which the Semantic Router needs, and its description now
|
|
523
|
+
says that the built-in hash provider is a demo (it only matches an example
|
|
524
|
+
phrase word for word) and a real embedding provider should be chosen. Its Spam
|
|
525
|
+
archive wrote a CSV that every run overwrote; it is a Managed Table in append
|
|
526
|
+
mode.
|
|
527
|
+
- Medallion, Kimball, Data Vault and One Big Table wrote to a Warehouse
|
|
528
|
+
destination, which needs a database connection that a Parquet path cannot give.
|
|
529
|
+
They write to Managed Tables now, so they run with nothing to pick: Bronze and
|
|
530
|
+
the facts append, Silver and the Data Vault tables merge by key, the rest
|
|
531
|
+
replace. Medallion gained an "Add month" step for its Gold roll-up.
|
|
532
|
+
- A webhook cannot hand a pipeline rows: the request body becomes the pipeline's
|
|
533
|
+
parameters. Webhook → Flatten → Managed Table and Webhook → enrich → DB
|
|
534
|
+
started from a Source and a trigger node that do not exist. They now declare an
|
|
535
|
+
`event_id` parameter and fetch that event from the sender's API; the enrich
|
|
536
|
+
template reads its users from a second Source, which makes five nodes. Templates
|
|
537
|
+
can declare parameters.
|
|
538
|
+
- Pipeline failure → Slack alert had a SQL step with nothing feeding it; it now
|
|
539
|
+
reads the latest runs from the Executions API. Scheduled alert tested a
|
|
540
|
+
`row_count` column that does not exist; it now tests each job's failure count.
|
|
541
|
+
Slack messages use `{column}`; `{{column}}` came out with stray braces.
|
|
542
|
+
- Smaller: `has_header` is `header` on eight CSV sources; Lookup's Return Columns
|
|
543
|
+
is a list; Dedupe by ID keeps the newest row; Trim whitespace names columns the
|
|
544
|
+
sample orders.csv has; CSV cleanup no longer promises a trim step; the Data Vault
|
|
545
|
+
Dedupe steps set an Order By; the editor's own Aggregation starter asked for
|
|
546
|
+
`aggregations` where Aggregate reads `functions`; the Oracle BIP → SQL Server
|
|
547
|
+
scaffold's Data Quality step uses the node's rules.
|
|
548
|
+
- The pipeline check no longer warns that a Switch adds `_split_output` to a
|
|
549
|
+
destination when its rows leave by one of its named outputs, which strip it.
|
|
550
|
+
Scheduled alert and AI classify say what Slack Notify does: one message per run,
|
|
551
|
+
from the first row that reaches it, sent even when no row does.
|
|
552
|
+
|
|
553
|
+
- **Incremental database sources read every row on every run.** A source set to
|
|
554
|
+
incremental is meant to save the newest value it read and ask only for rows after
|
|
555
|
+
it the next time. The save looked for its working table under the wrong name,
|
|
556
|
+
failed without a word, and nothing was ever stored, so every scheduled run read and
|
|
557
|
+
loaded the whole table again and "Last cursor" in the source's settings stayed
|
|
558
|
+
empty. The value now comes from the rows the run loaded. It is saved only for a
|
|
559
|
+
run that succeeds and really loads rows: a Sample run, which reads a capped number
|
|
560
|
+
of rows and writes nothing, no longer moves it (once the save worked, it would
|
|
561
|
+
have sent the next real run past rows that were never loaded), and a warning is
|
|
562
|
+
logged when the cursor column is not in the result. A test runs the source twice
|
|
563
|
+
against a SQLite file with the real cursor store.
|
|
564
|
+
- **The editor refused to run a pipeline whose database source used a SQL query.**
|
|
565
|
+
Once a saved connection was picked, the pipeline check asked every database source
|
|
566
|
+
for a table ("Missing required field: table"), even in the default SQL Query mode
|
|
567
|
+
and with the query filled in, so Run stayed blocked however the source was set up.
|
|
568
|
+
The check read a setting that no panel writes any more. It now follows the source's
|
|
569
|
+
Mode, as the node does: a query source needs its query, a table source its table, a
|
|
570
|
+
stored-procedure source its procedure, and a database or warehouse destination its
|
|
571
|
+
table. Every database template can be run from the editor once its connection is
|
|
572
|
+
picked, and a test loads each of the 27 templates, picks their connections and Slack
|
|
573
|
+
webhook the way a user does, and expects no error.
|
|
574
|
+
- **Data Quality: three fixes in the node and its settings.**
|
|
575
|
+
- A row a check could not answer passed when the step was set to fail the run. A
|
|
576
|
+
missing amount under "between", "greater than", "equals" or "matches a pattern"
|
|
577
|
+
gives no answer. The node dropped such a row or sent it to Reject, but in Fail
|
|
578
|
+
mode it counted the row as good, so the run went through, and in Tag mode it left
|
|
579
|
+
the mark empty. Every mode now treats the row as failed: Fail stops the run, Tag
|
|
580
|
+
marks it false, and Split keeps it with the failures.
|
|
581
|
+
- The settings could not set up a "between", "in" or "not in" check. They had one
|
|
582
|
+
text box that saved what you typed as plain text, so "10,100" or "a,b" matched
|
|
583
|
+
nothing and every row was dropped. "Between" now has a low and a high box, "in"
|
|
584
|
+
and "not in" take a comma-separated list, and a number you type is saved as a
|
|
585
|
+
number (a column known to hold text keeps it as text). A check that was saved the
|
|
586
|
+
old way shows a note asking you to type it again.
|
|
587
|
+
- The pipeline check warned that any Data Quality step before a destination
|
|
588
|
+
"injects internal metadata columns". Only Tag mode (`__dq_passed`), the quality
|
|
589
|
+
score option (`__dq_score`) and Reject mode, when the rows do not leave by its
|
|
590
|
+
Pass or Reject output, add columns. The warning now appears only then and names
|
|
591
|
+
the columns.
|
|
592
|
+
|
|
593
|
+
- **A Data Quality rule the step could not use let every row through, silently.**
|
|
594
|
+
A rule with no column, a check the step does not have, or a value it cannot read
|
|
595
|
+
(a "between" without both limits, an empty "in" list, a pattern that is not text,
|
|
596
|
+
a length that is not a whole number) was treated as true for every row. The step
|
|
597
|
+
now stops the run before it checks any row, and the error names each rule by its
|
|
598
|
+
number, its column and what it needs. A pipeline saved from the old templates,
|
|
599
|
+
whose checks used setting names the step never read, now stops with "no column
|
|
600
|
+
chosen" instead of passing every row. The editor says the same before Run: the
|
|
601
|
+
pipeline check lists such a rule as an error, and a low limit above the high one
|
|
602
|
+
as a warning.
|
|
603
|
+
|
|
604
|
+
- **The editor now warns about Data Quality settings the step ignores.** A rule is
|
|
605
|
+
read as a column, a check and a value, and nothing else; the step reads only
|
|
606
|
+
its rules, On Failure, pass-rate threshold, score and profiling settings. The old
|
|
607
|
+
templates wrote more than that, and the step ignored it without a word: a rule
|
|
608
|
+
written as `check: between` with `min` and `max` ran as a plain "not empty", and
|
|
609
|
+
an `on_failure` setting left the step dropping rows instead of failing the run.
|
|
610
|
+
The pipeline check now lists each such key as a warning, saying what the rule or
|
|
611
|
+
step does as written. In the step's settings the same keys show under the rule
|
|
612
|
+
(or under On Failure) with a Remove button.
|
|
613
|
+
|
|
614
|
+
### Changed
|
|
615
|
+
|
|
616
|
+
- `GET /api/connectors/cert-matrix` no longer returns the `by_tier` or
|
|
617
|
+
`production_total` aggregates. Certification is reported per connector:
|
|
618
|
+
each row carries `tier` and `cat_green`, and an attested connector also
|
|
619
|
+
carries `attested_at` and `attested_checks`.
|
|
620
|
+
|
|
621
|
+
A connector reaches an attested tier only once real vendor responses have
|
|
622
|
+
been recorded for it, so an unattested connector means "no fixtures
|
|
623
|
+
recorded yet" — not "this connector failed". An aggregate renders those
|
|
624
|
+
two states identically, and the reading that wins is the wrong one.
|
|
625
|
+
Callers that want a count can tally `rows` and own the framing.
|
|
626
|
+
|
|
627
|
+
- The Trust page drops the attestation totals and gains an **Attested**
|
|
628
|
+
column on the per-connector matrix, showing the date a connector's
|
|
629
|
+
acceptance suite last replayed green. Connectors without one show an
|
|
630
|
+
em-dash rather than a zero or a "not verified" badge.
|
|
631
|
+
|
|
632
|
+
### Added
|
|
633
|
+
|
|
634
|
+
- **Source Watch** — daily detection that a connector's upstream API changed,
|
|
635
|
+
in `backend/revoluzen_flow/connectors/source_watch.py` and
|
|
636
|
+
`.github/workflows/source-watch.yml`.
|
|
637
|
+
|
|
638
|
+
Nothing previously could notice this. The acceptance suite replays recorded
|
|
639
|
+
cassettes, which proves our parsing against *the responses we recorded* and
|
|
640
|
+
by construction never contacts the vendor; the live-smoke allow-list is
|
|
641
|
+
empty. So the first party to learn that a connector had broken was whoever
|
|
642
|
+
it broke for.
|
|
643
|
+
|
|
644
|
+
Four signals, none of which needs a vendor account:
|
|
645
|
+
- the vendor advertises a newer API version than a connector is pinned to
|
|
646
|
+
- an endpoint one of our streams reads is gone from the vendor's own spec
|
|
647
|
+
- the vendor's published spec or changelog moved at all
|
|
648
|
+
- RFC 8594 `Deprecation` / `Sunset` headers, harvested passively from
|
|
649
|
+
responses the product already received — no extra request, and it covers a
|
|
650
|
+
customer's own internal APIs too
|
|
651
|
+
|
|
652
|
+
Connectors opt in with a `source_watch` block in their runtime manifest
|
|
653
|
+
(`docs/connector-authoring.md`). Eight ship with one — Asana, GitHub,
|
|
654
|
+
Intercom, Mailchimp, PagerDuty, Slack, Stripe and Twilio — each verified
|
|
655
|
+
against the vendor's live spec before being added. A connector without a
|
|
656
|
+
block is reported as `unwatched` rather than healthy. Read the state at
|
|
657
|
+
`GET /api/connectors/source-watch`, which makes no outbound call of its own.
|
|
658
|
+
|
|
659
|
+
Version severity reflects what the evidence supports: `critical` only when
|
|
660
|
+
the vendor no longer lists the version a connector pins, `warn` when a newer
|
|
661
|
+
version exists but ours is still supported, `info` when we pin the newest.
|
|
662
|
+
A probe narrowed to a single value cannot establish support at all, so it is
|
|
663
|
+
capped at `warn`. GitHub currently reports `warn` — 2026-03-10 has shipped
|
|
664
|
+
and 2022-11-28 remains supported.
|
|
665
|
+
|
|
666
|
+
Spec comparison reconciles base prefixes from either side, since Swagger 2
|
|
667
|
+
puts them in `basePath` (Slack `/api`, Mailchimp `/3.0`) while OpenAPI 3
|
|
668
|
+
puts them in `servers[].url` (Stripe `/`, Twilio none). JSON and YAML specs
|
|
669
|
+
are both read; an unparseable one degrades to fingerprint-only rather than
|
|
670
|
+
asserting that endpoints vanished.
|
|
671
|
+
|
|
672
|
+
- `.github/workflows/connector-attest.yml` re-runs the connector acceptance
|
|
673
|
+
suite twice weekly and on manifest or fixture changes. A green CAT result
|
|
674
|
+
older than 14 days stops counting, so without this every attested
|
|
675
|
+
connector silently decayed back to Beta.
|
|
676
|
+
|
|
677
|
+
## [1.0.1] — 2026-10-18
|
|
678
|
+
|
|
679
|
+
First release published as **Revoluzen Flow**, by Revoluzen Private Limited.
|
|
680
|
+
|
|
681
|
+
The engine, connectors and UI are unchanged from the 1.0.x line; this release
|
|
682
|
+
renames the project and its published artifacts.
|
|
683
|
+
|
|
684
|
+
### Changed
|
|
685
|
+
|
|
686
|
+
- Distribution is now `revoluzen-flow` on PyPI. The CLI entry point is
|
|
687
|
+
`revoluzen` (alias `rz`); `python -m revoluzen_flow` works as well.
|
|
688
|
+
- Python package is `revoluzen_flow`.
|
|
689
|
+
- Environment variables use the `REVOLUZEN_FLOW_` prefix, and the config
|
|
690
|
+
directory is `.revoluzen-flow`.
|
|
691
|
+
- Docker image is `revoluzen/flow`; the Compose service is `flow` and the
|
|
692
|
+
data volume is `revoluzen_flow_data`.
|
|
693
|
+
- OpenLineage events are emitted with the `revoluzen-flow` namespace and a
|
|
694
|
+
producer URI pointing at this repository.
|
|
695
|
+
|
|
696
|
+
### Added
|
|
697
|
+
|
|
698
|
+
- `scripts/check_repo_coordinates.py`, run by the `architecture-invariants`
|
|
699
|
+
CI job. It fails the build when a self-referential GitHub slug disagrees
|
|
700
|
+
with `backend/revoluzen_flow/app_meta.py`, or when documentation tells a
|
|
701
|
+
reader to `cd` into a directory that `git clone` does not create.
|
|
702
|
+
|
|
703
|
+
### Notes for existing installs
|
|
704
|
+
|
|
705
|
+
**This is a clean break. There is no migration path, and none is planned.**
|
|
706
|
+
|
|
707
|
+
The rename is total — nothing keeps the old spelling. In particular, these
|
|
708
|
+
carry stored or externally-observed state, and all of them changed:
|
|
709
|
+
|
|
710
|
+
- **Workflow node type** `fpulseNode` → `revoluzenFlowNode`. Recorded inside
|
|
711
|
+
every saved workflow, so pipelines saved by an earlier release will not
|
|
712
|
+
load.
|
|
713
|
+
- **Database file** `fpulse.db` → `revoluzen_flow.db` (and
|
|
714
|
+
`fpulse_events.db` → `revoluzen_flow_events.db`). An existing data
|
|
715
|
+
directory will not be found; the instance starts empty.
|
|
716
|
+
- **Session cookies** `fpulse_token` / `fpulse_session` / `fpulse_csrf` →
|
|
717
|
+
`revoluzen_flow_*`. Everyone is signed out once.
|
|
718
|
+
- **Prometheus metrics** `fpulse_*` → `revoluzen_flow_*`. Existing
|
|
719
|
+
dashboards and alert rules stop matching.
|
|
720
|
+
- **Bootstrap account** `admin@fpulse.local` → `admin@revoluzen.local`.
|
|
721
|
+
- **CSS classes, DOM data-attributes and custom events** — internal, but
|
|
722
|
+
listed for anyone who has written custom styling against them.
|
|
723
|
+
|
|
724
|
+
Treat an upgrade as a fresh install.
|