cfa-kernel 0.1.8__tar.gz → 0.1.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cfa_kernel-0.1.9/CFA_LLM_Demo_fixed (1).dbc +0 -0
- cfa_kernel-0.1.9/CFA_LLM_Demo_fixed.dbc +0 -0
- cfa_kernel-0.1.9/CFA_LLM_Demo_fixed.py +673 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/PKG-INFO +2 -2
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/README.md +1 -1
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/pyproject.toml +1 -1
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/__init__.py +1 -1
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/core/kernel.py +1 -1
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/normalizer/llm.py +2 -1
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/observability/promotion.py +2 -2
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/reporting/engine.py +1 -1
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/api.md +1 -1
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/faq.md +2 -2
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/intro.md +1 -1
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/whitepaper.md +2 -2
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docusaurus.config.ts +1 -1
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/api.md +1 -1
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/intro.md +1 -1
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/whitepaper.md +1 -1
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/src/pages/index.tsx +1 -1
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/.gitattributes +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/.github/workflows/ci.yml +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/.github/workflows/deploy-docs.yml +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/.github/workflows/deploy-pypi.yml +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/.github/workflows/governance.yml +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/.gitignore +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/.uv-cache/.gitignore +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/.uv-cache/.lock +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/.uv-cache/CACHEDIR.TAG +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/.uv-cache/sdists-v9/.gitignore +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/CFA_LLM_Demo.ipynb +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/CODE_OF_CONDUCT.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/CONTRIBUTING.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/LICENSE +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/MANUAL_TESTING_GUIDE.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/SECURITY.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/cfa_demo_complete.ipynb +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/examples/cfa_demo.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/examples/fiscal_governance.yaml +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/examples/full_pipeline.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/examples/llm_systematizer.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/examples/runtime_gate.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/examples/standalone_governance.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/examples/standalone_lifecycle.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/examples/standalone_resolution.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/integrations/airflow-governance-gate/README.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/integrations/airflow-governance-gate/dags/cfa_governance_gate_demo.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/integrations/airflow-governance-gate/requirements.txt +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/integrations/airflow-governance-gate/src/governance_gate.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/mcp.json +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/policies/compliance-strict-v1.yaml +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/policies/finops-strict-v1.yaml +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/policies/prod-v1.yaml +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/_lazy.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/adapters/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/adapters/autogen.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/adapters/crewai.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/adapters/dspy.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/adapters/langgraph.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/adapters/openai_agents.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/audit/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/audit/context.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/audit/hashing.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/audit/trail.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/backends/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/backends/dbt.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/backends/pyspark.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/backends/sql.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/behavior/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/behavior/llm.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/behavior/spec.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/behavior/systematizer.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/__main__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/_helpers.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/core/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/core/evaluate.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/core/validate.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/formatters.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/governance/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/governance/audit.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/governance/catalog.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/governance/policy.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/governance/rules.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/governance/signature.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/infrastructure/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/infrastructure/backend_list.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/infrastructure/storage.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/project/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/project/init.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/project/lifecycle.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/project/status.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/project/taxonomy.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/reporting/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/reporting/report.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/cli/reporting/serve.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/config.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/core/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/core/codegen.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/core/conditions.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/core/phases/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/core/phases/runner.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/core/planner.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/execution/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/execution/partial.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/execution/state_projection.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/governance/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/lifecycle/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/mcp/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/mcp/__main__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/normalizer/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/normalizer/base.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/observability/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/observability/indices.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/observability/metrics.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/observability/notify.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/observability/otel.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/policy/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/policy/bundle.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/policy/catalog.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/policy/engine.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/reporting/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/reporting/charts.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/resolution/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/runtime/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/runtime/gate.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/sandbox/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/sandbox/executor.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/sandbox/mock.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/sandbox/panic.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/storage/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/testing/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/testing/asserts.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/testing/evaluate.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/testing/fixtures.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/testing/markers.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/types.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/validation/__init__.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/validation/runtime.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/validation/signature.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/src/cfa/validation/static.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/conftest.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_adapters.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_airflow_governance_gate.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_audit_persistent.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_behavior.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_behavior_llm.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_catalog.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_cli_validation.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_codegen.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_config.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_context.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_context_persistent.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_dbt_backend.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_hashing.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_indices.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_integration.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_intensive.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_kernel.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_mcp.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_metrics.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_normalizer.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_normalizer_llm.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_notify.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_otel.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_partial_execution.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_planner.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_policy.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_policy_bundle.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_promotion.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_reporting.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_runtime.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_runtime_validation.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_sandbox.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_serialization.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_signature.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_sql_backend.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_state_projection.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_static_validation.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_storage.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_testing.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_types.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/tests/test_user_journeys.py +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/.gitignore +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/README.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/blog/2019-05-28-first-blog-post.mdx +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/blog/2019-05-29-long-blog-post.mdx +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/blog/2021-08-01-mdx-blog-post.mdx +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/blog/2021-08-26-welcome/index.mdx +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/blog/authors.yml +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/blog/tags.yml +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/architecture-notes.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/backends.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/behavior-spec.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/cli.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/getting-started.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/guide.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/integrations/airflow.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/integrations/langgraph.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/integrations/openai-agents.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/mcp-server.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/policy-bundles.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/docs/reporting.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/code.json +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/architecture-notes.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/backends.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/behavior-spec.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/cli.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/faq.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/getting-started.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/guide.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/integrations/airflow.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/integrations/langgraph.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/integrations/openai-agents.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/mcp-server.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/policy-bundles.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/i18n/pt-BR/docusaurus-plugin-content-docs/current/reporting.md +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/package-lock.json +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/package.json +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/sidebars.ts +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/src/components/HomepageFeatures/index.tsx +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/src/components/HomepageFeatures/styles.module.css +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/src/css/custom.css +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/src/pages/index.module.css +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/src/pages/markdown-page.mdx +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/static/.nojekyll +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/static/img/favicon.ico +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/static/img/logo.svg +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/static/img/undraw_docusaurus_mountain.svg +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/static/img/undraw_docusaurus_react.svg +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/static/img/undraw_docusaurus_tree.svg +0 -0
- {cfa_kernel-0.1.8 → cfa_kernel-0.1.9}/website/tsconfig.json +0 -0
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
# Databricks notebook source
|
|
2
|
+
# MAGIC %md
|
|
3
|
+
# MAGIC # CFA — Contextual Flux Architecture
|
|
4
|
+
# MAGIC ## LLM-Powered Governance Demo
|
|
5
|
+
# MAGIC
|
|
6
|
+
# MAGIC | Section | Feature | LLM Role |
|
|
7
|
+
# MAGIC |---|---|---|
|
|
8
|
+
# MAGIC | S1 | Setup & Secrets | Read API key from Databricks Secret Scope |
|
|
9
|
+
# MAGIC | S2 | Catalog | Operational metadata |
|
|
10
|
+
# MAGIC | S3 | LLM Normalizer | Semantic intent resolution (replaces keywords) |
|
|
11
|
+
# MAGIC | S4 | Strict Mode | LLM output validated against catalog |
|
|
12
|
+
# MAGIC | S5 | LLM Audit Trail | Every call SHA-256 traceable |
|
|
13
|
+
# MAGIC | S6 | LLM Systematizer | NL governance → BehaviorSpec → PolicyRules |
|
|
14
|
+
# MAGIC | S7 | Full Kernel + LLM | End-to-end governed execution |
|
|
15
|
+
# MAGIC | S8 | Runtime Gate + LLM | Guard with LLM-backed validation |
|
|
16
|
+
# MAGIC | S9 | Compare Normalizers | Rule-based vs LLM side-by-side |
|
|
17
|
+
# MAGIC | S10 | PolicyEngine + LLM Rules | Close the NL→Rules→Engine loop |
|
|
18
|
+
# MAGIC
|
|
19
|
+
# MAGIC **API key:** stored in Databricks Secret Scope `cfa-secrets`, never in code.
|
|
20
|
+
# MAGIC
|
|
21
|
+
# MAGIC ---
|
|
22
|
+
# MAGIC
|
|
23
|
+
|
|
24
|
+
# COMMAND ----------
|
|
25
|
+
|
|
26
|
+
# MAGIC %md
|
|
27
|
+
# MAGIC ## Section 0 — Install
|
|
28
|
+
# MAGIC
|
|
29
|
+
# MAGIC Run this cell first to install dependencies.
|
|
30
|
+
# MAGIC
|
|
31
|
+
|
|
32
|
+
# COMMAND ----------
|
|
33
|
+
|
|
34
|
+
# MAGIC %md
|
|
35
|
+
# MAGIC ## Section 1 — Setup & Secrets
|
|
36
|
+
# MAGIC
|
|
37
|
+
# MAGIC API key read from Databricks Secret Scope `cfa-secrets/openai-key` or `cfa-secrets/deepseek-key`.
|
|
38
|
+
# MAGIC Falls back to `OPENAI_API_KEY` / `DEEPSEEK_API_KEY` env vars for local testing.
|
|
39
|
+
# MAGIC
|
|
40
|
+
|
|
41
|
+
# COMMAND ----------
|
|
42
|
+
|
|
43
|
+
# MAGIC %pip install -q cfa-kernel[all] openai
|
|
44
|
+
|
|
45
|
+
# COMMAND ----------
|
|
46
|
+
|
|
47
|
+
# MAGIC %restart_python
|
|
48
|
+
|
|
49
|
+
# COMMAND ----------
|
|
50
|
+
|
|
51
|
+
# --- Test if openai is importable ---
|
|
52
|
+
HAS_OPENAI = False
|
|
53
|
+
try:
|
|
54
|
+
import openai
|
|
55
|
+
print(f"openai {openai.__version__} - OK")
|
|
56
|
+
HAS_OPENAI = True
|
|
57
|
+
except ImportError as e:
|
|
58
|
+
print(f"ERROR: openai not importable: {e}")
|
|
59
|
+
print("Run: %%pip install openai")
|
|
60
|
+
|
|
61
|
+
import cfa, os
|
|
62
|
+
from cfa.normalizer.llm import OpenAILMProvider, LLMNormalizerBackend
|
|
63
|
+
from cfa.normalizer.base import IntentNormalizer, RuleBasedNormalizerBackend
|
|
64
|
+
from cfa.runtime import RuntimeGate
|
|
65
|
+
from cfa.policy.engine import PolicyEngine
|
|
66
|
+
from cfa.types import StateSignature
|
|
67
|
+
from cfa.core.kernel import KernelConfig
|
|
68
|
+
|
|
69
|
+
print(f"CFA version: {cfa.__version__}")
|
|
70
|
+
|
|
71
|
+
# --- Read API keys from secret scope ---
|
|
72
|
+
def _try_secret(key):
|
|
73
|
+
try:
|
|
74
|
+
return dbutils.secrets.get("cfa-secrets", key)
|
|
75
|
+
except Exception:
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
# Try Databricks secrets, fall back to env vars
|
|
79
|
+
OPENAI_KEY = _try_secret("openai-key") or os.environ.get("OPENAI_API_KEY")
|
|
80
|
+
DEEPSEEK_KEY = _try_secret("deepseek-key") or os.environ.get("DEEPSEEK_API_KEY")
|
|
81
|
+
|
|
82
|
+
# Auto-select: prefer OpenAI (better reachability from Azure), fallback to DeepSeek
|
|
83
|
+
if OPENAI_KEY:
|
|
84
|
+
LLM_MODEL = "gpt-4o-mini"
|
|
85
|
+
LLM_BASE_URL = None # default api.openai.com
|
|
86
|
+
LLM_API_KEY = OPENAI_KEY
|
|
87
|
+
print(f"Using OpenAI ({LLM_MODEL})")
|
|
88
|
+
elif DEEPSEEK_KEY:
|
|
89
|
+
LLM_MODEL = "deepseek-chat"
|
|
90
|
+
LLM_BASE_URL = "https://api.deepseek.com"
|
|
91
|
+
LLM_API_KEY = DEEPSEEK_KEY
|
|
92
|
+
print(f"Using DeepSeek ({LLM_MODEL})")
|
|
93
|
+
else:
|
|
94
|
+
LLM_MODEL = None
|
|
95
|
+
LLM_BASE_URL = None
|
|
96
|
+
LLM_API_KEY = None
|
|
97
|
+
print("WARNING: No API key found.")
|
|
98
|
+
print(" Databricks: secrets create-scope cfa-secrets")
|
|
99
|
+
print(" Local: set OPENAI_API_KEY or DEEPSEEK_API_KEY env var")
|
|
100
|
+
|
|
101
|
+
# Combined gate: need both openai + API key
|
|
102
|
+
HAS_LLM = HAS_OPENAI and LLM_API_KEY is not None
|
|
103
|
+
|
|
104
|
+
# Helper: create an LLM provider with the auto-detected config
|
|
105
|
+
def make_provider():
|
|
106
|
+
"""Return OpenAILMProvider with auto-detected config."""
|
|
107
|
+
return OpenAILMProvider(
|
|
108
|
+
model=LLM_MODEL,
|
|
109
|
+
api_key=LLM_API_KEY,
|
|
110
|
+
base_url=LLM_BASE_URL,
|
|
111
|
+
temperature=0.0,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# COMMAND ----------
|
|
116
|
+
|
|
117
|
+
# MAGIC %md
|
|
118
|
+
# MAGIC ---
|
|
119
|
+
# MAGIC ## Section 2 — Data Catalog
|
|
120
|
+
# MAGIC
|
|
121
|
+
# MAGIC Catalog grounds the LLM. The LLM receives it in the prompt and MUST reference real datasets.
|
|
122
|
+
# MAGIC
|
|
123
|
+
|
|
124
|
+
# COMMAND ----------
|
|
125
|
+
|
|
126
|
+
CATALOG = {
|
|
127
|
+
'nfe_bronze': {
|
|
128
|
+
'type': 'delta', 'layer': 'bronze', 'size_gb': 50,
|
|
129
|
+
'classification': 'high_volume',
|
|
130
|
+
'partition_by': ['processing_date'], 'pii': False,
|
|
131
|
+
'pii_columns': [],
|
|
132
|
+
'description': 'Notas Fiscais Eletronicas brutas',
|
|
133
|
+
},
|
|
134
|
+
'clientes_bronze': {
|
|
135
|
+
'type': 'delta', 'layer': 'bronze', 'size_gb': 10,
|
|
136
|
+
'classification': 'sensitive',
|
|
137
|
+
'partition_by': ['processing_date'], 'pii': True,
|
|
138
|
+
'pii_columns': ['cpf', 'nome', 'endereco'],
|
|
139
|
+
'description': 'Dados cadastrais com CPF e endereco',
|
|
140
|
+
},
|
|
141
|
+
'vendas_bronze': {
|
|
142
|
+
'type': 'delta', 'layer': 'bronze', 'size_gb': 2000,
|
|
143
|
+
'classification': 'high_volume',
|
|
144
|
+
'partition_by': ['data_venda'], 'pii': False,
|
|
145
|
+
'pii_columns': [],
|
|
146
|
+
'description': 'Registros de transacoes de venda',
|
|
147
|
+
},
|
|
148
|
+
'fornecedores_bronze': {
|
|
149
|
+
'type': 'delta', 'layer': 'bronze', 'size_gb': 10,
|
|
150
|
+
'classification': 'internal',
|
|
151
|
+
'partition_by': ['updated_at'], 'pii': False,
|
|
152
|
+
'pii_columns': [],
|
|
153
|
+
'description': 'Cadastro de fornecedores',
|
|
154
|
+
},
|
|
155
|
+
'vendas_gold_agregado': {
|
|
156
|
+
'type': 'delta', 'layer': 'gold', 'size_gb': 500,
|
|
157
|
+
'classification': 'internal',
|
|
158
|
+
'partition_by': ['data_venda'], 'pii': False,
|
|
159
|
+
'pii_columns': [],
|
|
160
|
+
'description': 'Agregados de vendas para BI',
|
|
161
|
+
},
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
from cfa.policy.catalog import validate_catalog
|
|
165
|
+
result = validate_catalog(CATALOG)
|
|
166
|
+
print(f"Catalog valid: {result.valid}")
|
|
167
|
+
print(f" {len(CATALOG)} datasets registered")
|
|
168
|
+
print(" Classifications: nfe_bronze=high_volume, clientes_bronze=sensitive,")
|
|
169
|
+
print(" vendas_bronze=high_volume, fornecedores_bronze=internal,")
|
|
170
|
+
print(" vendas_gold_agregado=internal")
|
|
171
|
+
for msg in result.messages:
|
|
172
|
+
print(f" {msg}")
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# COMMAND ----------
|
|
176
|
+
|
|
177
|
+
# MAGIC %md
|
|
178
|
+
# MAGIC ---
|
|
179
|
+
# MAGIC ## Section 3 — LLM Normalizer: Semantic Intent Resolution
|
|
180
|
+
# MAGIC
|
|
181
|
+
# MAGIC Rule-based = keyword matching (`join`, `aggregate`, `anonymize`).
|
|
182
|
+
# MAGIC LLM = sends `intent + catalog` to DeepSeek, parses structured JSON.
|
|
183
|
+
# MAGIC
|
|
184
|
+
# MAGIC The `SemanticResolution` returned contains the resolved `StateSignature`.
|
|
185
|
+
# MAGIC
|
|
186
|
+
|
|
187
|
+
# COMMAND ----------
|
|
188
|
+
|
|
189
|
+
if not HAS_LLM:
|
|
190
|
+
print("SKIP: no API key configured.")
|
|
191
|
+
else:
|
|
192
|
+
provider = make_provider()
|
|
193
|
+
llm_backend = LLMNormalizerBackend(provider=provider, strict=False)
|
|
194
|
+
normalizer = IntentNormalizer(backend=llm_backend)
|
|
195
|
+
|
|
196
|
+
print("=" * 55)
|
|
197
|
+
print("LLM NORMALIZER -- Semantic Resolution")
|
|
198
|
+
print("=" * 55)
|
|
199
|
+
|
|
200
|
+
intents = [
|
|
201
|
+
"Join NFe with Clientes anonymize CPF and persist to Silver",
|
|
202
|
+
"Aggregate vendas by region persist to Gold",
|
|
203
|
+
"Export raw clientes PII to Gold",
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
for raw in intents:
|
|
207
|
+
print(f'\nIntent: "{raw}"')
|
|
208
|
+
res = normalizer.normalize(raw, {}, CATALOG)
|
|
209
|
+
sig = res.signature
|
|
210
|
+
print(f" Domain : {sig.domain}")
|
|
211
|
+
print(f" Intent : {sig.intent}")
|
|
212
|
+
print(f" Target layer : {sig.target_layer}")
|
|
213
|
+
ds_names = [d.name for d in sig.datasets]
|
|
214
|
+
print(f" Datasets : {ds_names}")
|
|
215
|
+
print(f" Confidence : {res.confidence_score:.2f}")
|
|
216
|
+
print(f" Ambiguity : {res.ambiguity_level}")
|
|
217
|
+
if res.reasoning:
|
|
218
|
+
print(f" Reasoning : {res.reasoning[:150]}...")
|
|
219
|
+
|
|
220
|
+
print("\nLLM normalizer baseline complete")
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# COMMAND ----------
|
|
224
|
+
|
|
225
|
+
# MAGIC %md
|
|
226
|
+
# MAGIC ---
|
|
227
|
+
# MAGIC ## Section 4 — Strict Mode: Catalog-Grounded LLM
|
|
228
|
+
# MAGIC
|
|
229
|
+
# MAGIC `strict=True` validates the LLM output against the catalog.
|
|
230
|
+
# MAGIC Hallucinated datasets/references raise `ValueError`.
|
|
231
|
+
# MAGIC
|
|
232
|
+
|
|
233
|
+
# COMMAND ----------
|
|
234
|
+
|
|
235
|
+
if not HAS_LLM:
|
|
236
|
+
print("SKIP: no API key available")
|
|
237
|
+
else:
|
|
238
|
+
sp = make_provider()
|
|
239
|
+
sb = LLMNormalizerBackend(provider=sp, strict=True)
|
|
240
|
+
sn = IntentNormalizer(backend=sb)
|
|
241
|
+
|
|
242
|
+
print("=" * 55)
|
|
243
|
+
print("STRICT MODE — Catalog-grounded LLM")
|
|
244
|
+
print("=" * 55)
|
|
245
|
+
print(" strict=True: LLM output validated against catalog.")
|
|
246
|
+
print(" Hallucinated datasets or invalid classifications raise ValueError.")
|
|
247
|
+
print()
|
|
248
|
+
|
|
249
|
+
test_cases = [
|
|
250
|
+
# (intent, expect_pass)
|
|
251
|
+
("Join NFe with Clientes anonymize CPF persist to Silver", True),
|
|
252
|
+
("Full scan vendas without partition to Gold", False),
|
|
253
|
+
]
|
|
254
|
+
|
|
255
|
+
for raw, expect_pass in test_cases:
|
|
256
|
+
print(f"Intent: \"{raw}\"")
|
|
257
|
+
try:
|
|
258
|
+
res = sn.normalize(raw, {}, CATALOG)
|
|
259
|
+
status = "PASSED " if expect_pass else "UNEXPECTED PASS"
|
|
260
|
+
print(f" {status} | confidence={res.confidence_score:.2f} layer={res.signature.target_layer}")
|
|
261
|
+
except ValueError as e:
|
|
262
|
+
status = "REJECTED (expected)" if not expect_pass else "REJECTED (unexpected)"
|
|
263
|
+
print(f" {status} | {str(e)[:120]}")
|
|
264
|
+
print()
|
|
265
|
+
|
|
266
|
+
print("Strict mode demo complete")
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
# COMMAND ----------
|
|
270
|
+
|
|
271
|
+
# MAGIC %md
|
|
272
|
+
# MAGIC ---
|
|
273
|
+
# MAGIC ## Section 5 — LLM Audit Trail
|
|
274
|
+
# MAGIC
|
|
275
|
+
# MAGIC Every LLM call is SHA-256 hashed (prompt, response, catalog).
|
|
276
|
+
# MAGIC Full traceability for compliance audits.
|
|
277
|
+
# MAGIC
|
|
278
|
+
|
|
279
|
+
# COMMAND ----------
|
|
280
|
+
|
|
281
|
+
if not HAS_LLM:
|
|
282
|
+
print("SKIP: no API key available")
|
|
283
|
+
else:
|
|
284
|
+
# 'sb' is the strict backend created in Section 4.
|
|
285
|
+
# Guard against running this cell out of order.
|
|
286
|
+
try:
|
|
287
|
+
records = sb.audit_records
|
|
288
|
+
except NameError:
|
|
289
|
+
print("NOTE: 'sb' not found — run Section 4 first, or re-run from Section 1.")
|
|
290
|
+
records = []
|
|
291
|
+
|
|
292
|
+
print("=" * 55)
|
|
293
|
+
print("LLM AUDIT TRAIL — Tamper-evident LLM calls")
|
|
294
|
+
print("=" * 55)
|
|
295
|
+
print(f" Total LLM calls recorded: {len(records)}")
|
|
296
|
+
|
|
297
|
+
for i, rec in enumerate(records):
|
|
298
|
+
print(f"\n Call {i+1}:")
|
|
299
|
+
print(f" Model : {rec.model}")
|
|
300
|
+
print(f" Prompt hash : {rec.prompt_hash[:16]}...")
|
|
301
|
+
print(f" Response hash : {rec.response_hash[:16]}...")
|
|
302
|
+
print(f" Catalog hash : {rec.catalog_hash[:16]}...")
|
|
303
|
+
if rec.catalog_validation_errors:
|
|
304
|
+
for err in rec.catalog_validation_errors:
|
|
305
|
+
print(f" Val. error : {err}")
|
|
306
|
+
if rec.parsed_json:
|
|
307
|
+
keys = list(rec.parsed_json.keys())
|
|
308
|
+
print(f" Parsed keys : {keys[:8]}")
|
|
309
|
+
|
|
310
|
+
print("\nLLM audit trail complete")
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
# COMMAND ----------
|
|
314
|
+
|
|
315
|
+
# MAGIC %md
|
|
316
|
+
# MAGIC ---
|
|
317
|
+
# MAGIC ## Section 6 — LLM Systematizer: NL → PolicyRules
|
|
318
|
+
# MAGIC
|
|
319
|
+
# MAGIC Describe governance in natural language. LLM produces `BehaviorSpec`.
|
|
320
|
+
# MAGIC `Systematizer` converts it to executable `PolicyRule` objects.
|
|
321
|
+
# MAGIC
|
|
322
|
+
|
|
323
|
+
# COMMAND ----------
|
|
324
|
+
|
|
325
|
+
from cfa.behavior.llm import OpenAISystematizerBackend
|
|
326
|
+
from cfa.behavior import Systematizer
|
|
327
|
+
|
|
328
|
+
taxonomy, rules = None, None
|
|
329
|
+
|
|
330
|
+
if not HAS_LLM:
|
|
331
|
+
print("SKIP: no LLM available (missing openai or API key)")
|
|
332
|
+
else:
|
|
333
|
+
try:
|
|
334
|
+
print("=" * 55)
|
|
335
|
+
print("LLM SYSTEMATIZER -- NL to Policy Rules")
|
|
336
|
+
print("=" * 55)
|
|
337
|
+
|
|
338
|
+
governance_desc = """\
|
|
339
|
+
Fiscal ETL pipeline governance:
|
|
340
|
+
1. All datasets moving from Bronze to Silver/Gold MUST anonymize PII (CPF, nome, endereco)
|
|
341
|
+
2. Every Silver and Gold write requires a merge_key (upsert, not append)
|
|
342
|
+
3. Datasets larger than 100GB MUST have partition_by defined
|
|
343
|
+
4. No raw PII columns may appear in Gold layer
|
|
344
|
+
5. Maximum cost per pipeline run: 50 DBU
|
|
345
|
+
"""
|
|
346
|
+
|
|
347
|
+
sys_backend = OpenAISystematizerBackend(
|
|
348
|
+
model=LLM_MODEL,
|
|
349
|
+
api_key=LLM_API_KEY,
|
|
350
|
+
base_url=LLM_BASE_URL,
|
|
351
|
+
temperature=0.0,
|
|
352
|
+
max_tokens=2048,
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
taxonomy, rules = Systematizer().systematize_from_nl(
|
|
356
|
+
governance_desc,
|
|
357
|
+
backend=sys_backend,
|
|
358
|
+
context="Fiscal ETL: NFe, Clientes, Vendas, Fornecedores on Databricks Delta Lake",
|
|
359
|
+
target_layer="silver",
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
print(f" Categories : {taxonomy.category_count}")
|
|
363
|
+
print(f" Rules generated : {len(rules)}")
|
|
364
|
+
print()
|
|
365
|
+
|
|
366
|
+
for rule in rules:
|
|
367
|
+
print(f" Rule : {rule.name}")
|
|
368
|
+
print(f" code : {rule.fault_code}")
|
|
369
|
+
print(f" action : {rule.action.value}")
|
|
370
|
+
print(f" severity : {rule.severity.value}")
|
|
371
|
+
print()
|
|
372
|
+
|
|
373
|
+
test_intents = taxonomy.generate_test_intents(3)
|
|
374
|
+
print(f" CI test intents generated: {len(test_intents)}")
|
|
375
|
+
for intent in test_intents:
|
|
376
|
+
print(f" - {intent}")
|
|
377
|
+
|
|
378
|
+
print("\nLLM Systematizer complete")
|
|
379
|
+
except Exception as e:
|
|
380
|
+
print(f" LLM call failed: {type(e).__name__}: {str(e)[:100]}")
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
# COMMAND ----------
|
|
384
|
+
|
|
385
|
+
# MAGIC %md
|
|
386
|
+
# MAGIC ---
|
|
387
|
+
# MAGIC ## Section 7 — Full Kernel with LLM Normalizer
|
|
388
|
+
# MAGIC
|
|
389
|
+
# MAGIC Same 5-phase pipeline (Formalize → Govern → Generate → Execute → Validate/Audit).
|
|
390
|
+
# MAGIC Only the **Formalize** phase switches from keyword-matching to DeepSeek.
|
|
391
|
+
# MAGIC
|
|
392
|
+
|
|
393
|
+
# COMMAND ----------
|
|
394
|
+
|
|
395
|
+
from cfa import KernelOrchestrator
|
|
396
|
+
|
|
397
|
+
if not HAS_LLM:
|
|
398
|
+
print("SKIP: no API key available")
|
|
399
|
+
else:
|
|
400
|
+
provider = make_provider()
|
|
401
|
+
# strict=False: LLM resolves intent semantically; catalog used for grounding
|
|
402
|
+
# but validation errors do not block execution (strict mode is for S4 demo only)
|
|
403
|
+
backend = LLMNormalizerBackend(provider=provider, strict=False)
|
|
404
|
+
|
|
405
|
+
kernel = KernelOrchestrator(
|
|
406
|
+
catalog=CATALOG,
|
|
407
|
+
config=KernelConfig(
|
|
408
|
+
policy_bundle_version="fiscal-prod-v1.0",
|
|
409
|
+
backend="pyspark",
|
|
410
|
+
),
|
|
411
|
+
normalizer_backend=backend,
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
print("=" * 55)
|
|
415
|
+
print("FULL KERNEL + LLM NORMALIZER")
|
|
416
|
+
print("=" * 55)
|
|
417
|
+
|
|
418
|
+
for intent in [
|
|
419
|
+
"Join NFe with Clientes anonymize CPF and persist to Silver",
|
|
420
|
+
"Aggregate vendas by region persist to Gold",
|
|
421
|
+
"Export raw clientes PII to Gold",
|
|
422
|
+
]:
|
|
423
|
+
print(f"\nIntent: \"{intent}\"")
|
|
424
|
+
try:
|
|
425
|
+
result = kernel.process(intent)
|
|
426
|
+
print(f" -> Decision : {result.state.value.upper()}")
|
|
427
|
+
if result.signature is not None:
|
|
428
|
+
print(f" -> Sig hash : {result.signature.signature_hash[:24]}...")
|
|
429
|
+
if result.replan_history:
|
|
430
|
+
print(f" -> Replans : {len(result.replan_history)}")
|
|
431
|
+
if result.generated_code and result.generated_code.code:
|
|
432
|
+
lines = result.generated_code.code.splitlines()
|
|
433
|
+
print(f" -> Code gen : {len(lines)} lines ({result.generated_code.language})")
|
|
434
|
+
preview = [l for l in lines if l.strip()][:6]
|
|
435
|
+
for line in preview:
|
|
436
|
+
print(f" {line}")
|
|
437
|
+
if len(lines) > 6:
|
|
438
|
+
print(f" ... ({len(lines) - 6} more lines)")
|
|
439
|
+
except Exception as e:
|
|
440
|
+
print(f" -> BLOCKED : {type(e).__name__} | {str(e)[:100]}")
|
|
441
|
+
|
|
442
|
+
calls = backend.audit_records
|
|
443
|
+
print(f"\n LLM calls by kernel: {len(calls)}")
|
|
444
|
+
for rec in calls:
|
|
445
|
+
print(f" prompt={rec.prompt_hash[:16]}... response={rec.response_hash[:16]}...")
|
|
446
|
+
|
|
447
|
+
print("\nFull kernel + LLM complete")
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
# COMMAND ----------
|
|
451
|
+
|
|
452
|
+
# MAGIC %md
|
|
453
|
+
# MAGIC ---
|
|
454
|
+
# MAGIC ## Section 8 — Runtime Gate
|
|
455
|
+
# MAGIC
|
|
456
|
+
# MAGIC `RuntimeGate` validates intents before execution.
|
|
457
|
+
# MAGIC With `policy_rules` from LLM Systematizer, the gate inherits NL-defined governance.
|
|
458
|
+
# MAGIC
|
|
459
|
+
|
|
460
|
+
# COMMAND ----------
|
|
461
|
+
|
|
462
|
+
import traceback
|
|
463
|
+
print("=" * 55)
|
|
464
|
+
print("RUNTIME GATE")
|
|
465
|
+
print("=" * 55)
|
|
466
|
+
|
|
467
|
+
# Guard: 'rules' is set by Section 6 (LLM Systematizer).
|
|
468
|
+
# If that section was skipped or failed, fall back to default rules gracefully.
|
|
469
|
+
try:
|
|
470
|
+
_rules = rules
|
|
471
|
+
except NameError:
|
|
472
|
+
_rules = None
|
|
473
|
+
|
|
474
|
+
if _rules is None:
|
|
475
|
+
print("NOTE: LLM-generated rules not available (Section 6 skipped or no API key).")
|
|
476
|
+
print(" Using default CFA policy rules instead.")
|
|
477
|
+
else:
|
|
478
|
+
print(f" Using {len(_rules)} LLM-generated rules from Section 6")
|
|
479
|
+
|
|
480
|
+
try:
|
|
481
|
+
gate = RuntimeGate(
|
|
482
|
+
catalog=CATALOG,
|
|
483
|
+
policy_rules=_rules,
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
result = gate.validate("Join NFe with Clientes and persist to Silver")
|
|
487
|
+
print(f" validate() -> state={result.state.value} passed={result.passed}")
|
|
488
|
+
print(f" gate_id={result.gate_id} execution_id={result.execution_id[:8]}...")
|
|
489
|
+
|
|
490
|
+
@gate.guard("aggregate sales data with PII protected")
|
|
491
|
+
def my_pipeline():
|
|
492
|
+
return "pipeline executed"
|
|
493
|
+
|
|
494
|
+
print(f" @gate.guard -> {my_pipeline()}")
|
|
495
|
+
print("\nRuntime Gate demo complete")
|
|
496
|
+
except Exception as e:
|
|
497
|
+
print(f" RUNTIME GATE FAILED: {type(e).__name__}")
|
|
498
|
+
traceback.print_exc()
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
# COMMAND ----------
|
|
502
|
+
|
|
503
|
+
# MAGIC %md
|
|
504
|
+
# MAGIC ---
|
|
505
|
+
# MAGIC ## Section 9 — Comparing Normalizers: Rule-Based vs LLM
|
|
506
|
+
# MAGIC
|
|
507
|
+
# MAGIC Same intent, two backends — side-by-side comparison.
|
|
508
|
+
# MAGIC
|
|
509
|
+
|
|
510
|
+
# COMMAND ----------
|
|
511
|
+
|
|
512
|
+
print("=" * 55)
|
|
513
|
+
print("NORMALIZER COMPARISON: Rule-Based vs LLM")
|
|
514
|
+
print("=" * 55)
|
|
515
|
+
|
|
516
|
+
rule_norm = IntentNormalizer(backend=RuleBasedNormalizerBackend())
|
|
517
|
+
llm_norm = None
|
|
518
|
+
if HAS_LLM:
|
|
519
|
+
provider = make_provider()
|
|
520
|
+
# strict=False for comparison — we want to see the LLM output, not block it
|
|
521
|
+
llm_norm = IntentNormalizer(backend=LLMNormalizerBackend(provider=provider, strict=False))
|
|
522
|
+
|
|
523
|
+
header = f"{'Intent':<50s} | {'Method':<12s} | {'Domain':<14s} | {'Layer':<8s} | {'Confidence':>10s}"
|
|
524
|
+
print(header)
|
|
525
|
+
print("-" * len(header))
|
|
526
|
+
|
|
527
|
+
for raw in [
|
|
528
|
+
"Join NFe with Clientes anonymize CPF and persist to Silver",
|
|
529
|
+
"Aggregate vendas by region persist to Gold",
|
|
530
|
+
"Export raw clientes PII to Gold",
|
|
531
|
+
]:
|
|
532
|
+
# Rule-based
|
|
533
|
+
rb = rule_norm.normalize(raw, {}, CATALOG)
|
|
534
|
+
sig_rb = rb.signature
|
|
535
|
+
print(f"{raw[:47]:<50s} | {'rule-based':<12s} | {sig_rb.domain:<14s} | {str(sig_rb.target_layer):<8s} | {rb.confidence_score:>9.2f}")
|
|
536
|
+
# LLM
|
|
537
|
+
if llm_norm is not None:
|
|
538
|
+
try:
|
|
539
|
+
llm = llm_norm.normalize(raw, {}, CATALOG)
|
|
540
|
+
sig_llm = llm.signature
|
|
541
|
+
print(f"{'':50s} | {'LLM':<12s} | {sig_llm.domain:<14s} | {str(sig_llm.target_layer):<8s} | {llm.confidence_score:>9.2f}")
|
|
542
|
+
except Exception as e:
|
|
543
|
+
print(f"{'':50s} | {'LLM':<12s} | ERROR: {type(e).__name__}: {str(e)[:60]}")
|
|
544
|
+
else:
|
|
545
|
+
print(f"{'':50s} | {'LLM':<12s} | (no API key)")
|
|
546
|
+
print()
|
|
547
|
+
|
|
548
|
+
print("Normalizer comparison complete")
|
|
549
|
+
|
|
550
|
+
# COMMAND ----------
|
|
551
|
+
|
|
552
|
+
# MAGIC %md
|
|
553
|
+
# MAGIC ---
|
|
554
|
+
# MAGIC ## Section 10 — PolicyEngine with LLM-Generated Rules
|
|
555
|
+
# MAGIC
|
|
556
|
+
# MAGIC Rules from `LLMSystematizer` (Section 6) feed `PolicyEngine`.
|
|
557
|
+
# MAGIC Closes the loop: NL governance → LLM → BehaviorSpec → PolicyRules → Engine.
|
|
558
|
+
# MAGIC
|
|
559
|
+
|
|
560
|
+
# COMMAND ----------
|
|
561
|
+
|
|
562
|
+
from cfa.types import DatasetRef, SignatureConstraints, TargetLayer, ExecutionContext
|
|
563
|
+
|
|
564
|
+
print("=" * 55)
|
|
565
|
+
print("POLICY ENGINE WITH LLM-GENERATED RULES")
|
|
566
|
+
print("=" * 55)
|
|
567
|
+
|
|
568
|
+
# Guard: 'rules' is set by Section 6 (LLM Systematizer).
|
|
569
|
+
try:
|
|
570
|
+
_rules_s10 = rules
|
|
571
|
+
except NameError:
|
|
572
|
+
_rules_s10 = None
|
|
573
|
+
|
|
574
|
+
if _rules_s10 is None:
|
|
575
|
+
print("NOTE: LLM-generated rules not available (Section 6 skipped or no API key).")
|
|
576
|
+
print(" Using default CFA policy rules instead.")
|
|
577
|
+
engine = PolicyEngine() # default rules
|
|
578
|
+
else:
|
|
579
|
+
print(f" Using {len(_rules_s10)} LLM-generated rules from Section 6")
|
|
580
|
+
engine = PolicyEngine(rules=_rules_s10)
|
|
581
|
+
|
|
582
|
+
# --- Safe signature ---
|
|
583
|
+
sig_safe = StateSignature(
|
|
584
|
+
domain="fiscal",
|
|
585
|
+
intent="Join NFe with Clientes anonymize CPF persist to Silver",
|
|
586
|
+
source_intent_raw="Join NFe with Clientes anonymize CPF persist to Silver",
|
|
587
|
+
target_layer=TargetLayer.SILVER,
|
|
588
|
+
datasets=(
|
|
589
|
+
DatasetRef(name="nfe_bronze"),
|
|
590
|
+
DatasetRef(name="clientes_bronze", pii_columns=("cpf", "nome")),
|
|
591
|
+
),
|
|
592
|
+
constraints=SignatureConstraints(
|
|
593
|
+
no_pii_raw=True,
|
|
594
|
+
merge_key_required=True,
|
|
595
|
+
partition_by=("processing_date",),
|
|
596
|
+
),
|
|
597
|
+
execution_context=ExecutionContext(
|
|
598
|
+
policy_bundle_version="v1.0",
|
|
599
|
+
catalog_snapshot_version="catalog_default",
|
|
600
|
+
context_registry_version_id="ctx-default",
|
|
601
|
+
),
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
r = engine.evaluate(sig_safe)
|
|
605
|
+
print(f"\n Safe signature -> {r.action.value.upper()} faults={len(r.faults)}")
|
|
606
|
+
|
|
607
|
+
# --- Unsafe signature ---
|
|
608
|
+
sig_unsafe = StateSignature(
|
|
609
|
+
domain="fiscal",
|
|
610
|
+
intent="Export raw clientes PII to Gold",
|
|
611
|
+
source_intent_raw="Export raw clientes PII to Gold",
|
|
612
|
+
target_layer=TargetLayer.GOLD,
|
|
613
|
+
datasets=(
|
|
614
|
+
DatasetRef(name="clientes_bronze", pii_columns=("cpf", "nome", "endereco")),
|
|
615
|
+
),
|
|
616
|
+
constraints=SignatureConstraints(
|
|
617
|
+
no_pii_raw=False,
|
|
618
|
+
merge_key_required=False,
|
|
619
|
+
partition_by=(),
|
|
620
|
+
),
|
|
621
|
+
execution_context=ExecutionContext(
|
|
622
|
+
policy_bundle_version="v1.0",
|
|
623
|
+
catalog_snapshot_version="catalog_default",
|
|
624
|
+
context_registry_version_id="ctx-default",
|
|
625
|
+
),
|
|
626
|
+
)
|
|
627
|
+
|
|
628
|
+
r2 = engine.evaluate(sig_unsafe)
|
|
629
|
+
print(f" Unsafe signature -> {r2.action.value.upper()} faults={len(r2.faults)}")
|
|
630
|
+
for fault in r2.faults[:4]:
|
|
631
|
+
print(f" [{fault.severity.value.upper():<10s}] {fault.code}")
|
|
632
|
+
|
|
633
|
+
print("\nLLM-rules PolicyEngine complete")
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
# COMMAND ----------
|
|
637
|
+
|
|
638
|
+
# MAGIC %md
|
|
639
|
+
# MAGIC ---
|
|
640
|
+
# MAGIC ## Summary
|
|
641
|
+
# MAGIC
|
|
642
|
+
# MAGIC | LLM Feature | Status | Notes |
|
|
643
|
+
# MAGIC |---|---|---|
|
|
644
|
+
# MAGIC | LLM Normalizer | ✓ | Semantic intent resolution via DeepSeek/OpenAI |
|
|
645
|
+
# MAGIC | Strict Mode | ✓ | LLM output validated against catalog |
|
|
646
|
+
# MAGIC | LLM Audit Trail | ✓ | Every call SHA-256 traceable |
|
|
647
|
+
# MAGIC | LLM Systematizer | ✓ | NL → BehaviorSpec → PolicyRules |
|
|
648
|
+
# MAGIC | Full Kernel + LLM | ✓ | End-to-end with LLM normalizer |
|
|
649
|
+
# MAGIC | Runtime Gate | ✓ | Guard with LLM-generated policy rules |
|
|
650
|
+
# MAGIC | Normalizer Comparison | ✓ | Rule-based vs LLM side-by-side |
|
|
651
|
+
# MAGIC | Secret Management | ✓ | Databricks Secret Scope `cfa-secrets` |
|
|
652
|
+
# MAGIC
|
|
653
|
+
# MAGIC **Key differences from rule-based:**
|
|
654
|
+
# MAGIC
|
|
655
|
+
# MAGIC - LLM understands intent **semantics**, not just keywords
|
|
656
|
+
# MAGIC - Natural language governance descriptions → executable rules
|
|
657
|
+
# MAGIC - Every LLM call is audited (prompt/response/catalog SHA-256)
|
|
658
|
+
# MAGIC - Strict mode prevents hallucinations by validating against catalog
|
|
659
|
+
# MAGIC - API key stored in **Databricks Secret Scope** — never in code
|
|
660
|
+
# MAGIC
|
|
661
|
+
# MAGIC **Secret scope setup (one-time):**
|
|
662
|
+
# MAGIC ```bash
|
|
663
|
+
# MAGIC databricks secrets create-scope cfa-secrets
|
|
664
|
+
# MAGIC databricks secrets put-secret cfa-secrets deepseek-key
|
|
665
|
+
# MAGIC ```
|
|
666
|
+
# MAGIC
|
|
667
|
+
# MAGIC ---
|
|
668
|
+
# MAGIC
|
|
669
|
+
# MAGIC **Links**
|
|
670
|
+
# MAGIC - [Documentation](https://marquesantero.github.io/cfa/docs/intro)
|
|
671
|
+
# MAGIC - [PyPI](https://pypi.org/project/cfa-kernel/)
|
|
672
|
+
# MAGIC - [GitHub](https://github.com/marquesantero/cfa)
|
|
673
|
+
# MAGIC
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cfa-kernel
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: CFA — Governed execution for AI agents and data systems
|
|
5
5
|
Project-URL: Homepage, https://marquesantero.github.io/cfa/
|
|
6
6
|
Project-URL: Repository, https://github.com/marquesantero/cfa
|
|
@@ -38,7 +38,7 @@ Provides-Extra: yaml
|
|
|
38
38
|
Requires-Dist: pyyaml>=6.0; extra == 'yaml'
|
|
39
39
|
Description-Content-Type: text/markdown
|
|
40
40
|
|
|
41
|
-
# CFA v0.1.
|
|
41
|
+
# CFA v0.1.9
|
|
42
42
|
|
|
43
43
|
[](https://github.com/marquesantero/cfa/actions/workflows/ci.yml)
|
|
44
44
|
[](https://codecov.io/github/marquesantero/cfa)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# CFA v0.1.
|
|
1
|
+
# CFA v0.1.9
|
|
2
2
|
|
|
3
3
|
[](https://github.com/marquesantero/cfa/actions/workflows/ci.yml)
|
|
4
4
|
[](https://codecov.io/github/marquesantero/cfa)
|