fluxrules 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fluxrules-0.1.0/.github/CODEOWNERS +4 -0
- fluxrules-0.1.0/.github/workflows/ci.yml +72 -0
- fluxrules-0.1.0/.github/workflows/docs.yml +49 -0
- fluxrules-0.1.0/.github/workflows/package-artifacts.yml +59 -0
- fluxrules-0.1.0/.github/workflows/release.yml +190 -0
- fluxrules-0.1.0/.gitignore +74 -0
- fluxrules-0.1.0/CHANGELOG.md +121 -0
- fluxrules-0.1.0/CODE_OF_CONDUCT.md +133 -0
- fluxrules-0.1.0/CONTRIBUTING.md +126 -0
- fluxrules-0.1.0/LICENSE +21 -0
- fluxrules-0.1.0/Makefile +67 -0
- fluxrules-0.1.0/PKG-INFO +274 -0
- fluxrules-0.1.0/README.md +166 -0
- fluxrules-0.1.0/SECURITY.md +62 -0
- fluxrules-0.1.0/alembic/env.py +77 -0
- fluxrules-0.1.0/alembic/script.py.mako +28 -0
- fluxrules-0.1.0/alembic/versions/001_initial_schema.py +144 -0
- fluxrules-0.1.0/alembic.ini +66 -0
- fluxrules-0.1.0/docker-compose.yml +63 -0
- fluxrules-0.1.0/docs/action-registry.md +107 -0
- fluxrules-0.1.0/docs/algorithm-fidelity.md +53 -0
- fluxrules-0.1.0/docs/api.md +129 -0
- fluxrules-0.1.0/docs/architecture.md +292 -0
- fluxrules-0.1.0/docs/benchmarks.md +97 -0
- fluxrules-0.1.0/docs/changelog.md +46 -0
- fluxrules-0.1.0/docs/choosing-an-engine.md +52 -0
- fluxrules-0.1.0/docs/complex-conditions.md +584 -0
- fluxrules-0.1.0/docs/concepts.md +245 -0
- fluxrules-0.1.0/docs/conditions.md +240 -0
- fluxrules-0.1.0/docs/contributing.md +71 -0
- fluxrules-0.1.0/docs/cross-fact-rules.md +90 -0
- fluxrules-0.1.0/docs/custom-actions.md +180 -0
- fluxrules-0.1.0/docs/custom-engines.md +82 -0
- fluxrules-0.1.0/docs/custom-transforms-answered.md +543 -0
- fluxrules-0.1.0/docs/custom-transforms-cheatsheet.md +402 -0
- fluxrules-0.1.0/docs/custom-transforms.md +130 -0
- fluxrules-0.1.0/docs/decision-guide.md +122 -0
- fluxrules-0.1.0/docs/dependency-injection.md +61 -0
- fluxrules-0.1.0/docs/deployment.md +133 -0
- fluxrules-0.1.0/docs/development/index.md +87 -0
- fluxrules-0.1.0/docs/development/testing.md +42 -0
- fluxrules-0.1.0/docs/domains-and-tags.md +286 -0
- fluxrules-0.1.0/docs/engine-comparison.md +98 -0
- fluxrules-0.1.0/docs/engine-scope-and-limits.md +149 -0
- fluxrules-0.1.0/docs/examples.md +606 -0
- fluxrules-0.1.0/docs/extension-points.md +115 -0
- fluxrules-0.1.0/docs/fact-pipeline.md +115 -0
- fluxrules-0.1.0/docs/features.md +155 -0
- fluxrules-0.1.0/docs/getting-started.md +65 -0
- fluxrules-0.1.0/docs/id-generation.md +77 -0
- fluxrules-0.1.0/docs/index.md +44 -0
- fluxrules-0.1.0/docs/installation.md +123 -0
- fluxrules-0.1.0/docs/load-testing.md +518 -0
- fluxrules-0.1.0/docs/nested-facts.md +107 -0
- fluxrules-0.1.0/docs/observability-exporters.md +434 -0
- fluxrules-0.1.0/docs/observability.md +121 -0
- fluxrules-0.1.0/docs/persistence.md +150 -0
- fluxrules-0.1.0/docs/pydantic-rule-guide.md +161 -0
- fluxrules-0.1.0/docs/quickstart.md +148 -0
- fluxrules-0.1.0/docs/reference/http-endpoints.md +21 -0
- fluxrules-0.1.0/docs/reference/index.md +18 -0
- fluxrules-0.1.0/docs/reference/public-api.md +122 -0
- fluxrules-0.1.0/docs/rest-api.md +222 -0
- fluxrules-0.1.0/docs/rule-analysis.md +92 -0
- fluxrules-0.1.0/docs/rule-builder.md +153 -0
- fluxrules-0.1.0/docs/rule-lifecycle.md +184 -0
- fluxrules-0.1.0/docs/rule-types.md +112 -0
- fluxrules-0.1.0/docs/security.md +157 -0
- fluxrules-0.1.0/docs/sessions.md +124 -0
- fluxrules-0.1.0/docs/troubleshooting.md +95 -0
- fluxrules-0.1.0/docs/usage/advanced-capabilities.md +83 -0
- fluxrules-0.1.0/docs/usage/configuration.md +34 -0
- fluxrules-0.1.0/docs/usage/engines.md +36 -0
- fluxrules-0.1.0/docs/usage/examples.md +89 -0
- fluxrules-0.1.0/docs/usage/http-api.md +59 -0
- fluxrules-0.1.0/docs/usage/index.md +10 -0
- fluxrules-0.1.0/docs/usage/python-api.md +94 -0
- fluxrules-0.1.0/docs/usecases.md +71 -0
- fluxrules-0.1.0/docs/validation-framework.md +274 -0
- fluxrules-0.1.0/docs/working-memory.md +145 -0
- fluxrules-0.1.0/docs/yaml-rules.md +90 -0
- fluxrules-0.1.0/examples/00_getting_started.py +37 -0
- fluxrules-0.1.0/examples/01_conditions.py +110 -0
- fluxrules-0.1.0/examples/02_complex_conditions.py +38 -0
- fluxrules-0.1.0/examples/03_domains_and_tags.py +36 -0
- fluxrules-0.1.0/examples/04_validation.py +44 -0
- fluxrules-0.1.0/examples/05_persistence.py +39 -0
- fluxrules-0.1.0/examples/06_working_memory.py +37 -0
- fluxrules-0.1.0/examples/07_yaml_rules.py +50 -0
- fluxrules-0.1.0/examples/09_custom_engines.py +31 -0
- fluxrules-0.1.0/examples/10_pluggable_engines.py +49 -0
- fluxrules-0.1.0/examples/11_cli_usage.py +29 -0
- fluxrules-0.1.0/examples/12_api_usage.py +36 -0
- fluxrules-0.1.0/examples/13_complex_rules.py +34 -0
- fluxrules-0.1.0/examples/14_error_handling.py +43 -0
- fluxrules-0.1.0/examples/15_action_system.py +31 -0
- fluxrules-0.1.0/examples/16_fact_store.py +31 -0
- fluxrules-0.1.0/examples/17_id_generation.py +46 -0
- fluxrules-0.1.0/examples/18_unified_rule.py +41 -0
- fluxrules-0.1.0/examples/19_advanced_features.py +34 -0
- fluxrules-0.1.0/examples/20_streaming_mode.py +31 -0
- fluxrules-0.1.0/examples/21_action_registry.py +39 -0
- fluxrules-0.1.0/examples/22_real_world_workflow.py +36 -0
- fluxrules-0.1.0/examples/23_streaming_vs_stateless.py +27 -0
- fluxrules-0.1.0/examples/24_cross_fact_joins.py +29 -0
- fluxrules-0.1.0/examples/25_nested_facts.py +28 -0
- fluxrules-0.1.0/examples/26_fact_loader.py +30 -0
- fluxrules-0.1.0/examples/27_factpipeline.py +38 -0
- fluxrules-0.1.0/examples/28_factpipeline_tier1.py +30 -0
- fluxrules-0.1.0/examples/29_custom_transforms.py +37 -0
- fluxrules-0.1.0/examples/30_conflict_detection.py +42 -0
- fluxrules-0.1.0/examples/README.md +398 -0
- fluxrules-0.1.0/examples/rules.yaml +71 -0
- fluxrules-0.1.0/examples/shared_use_case.py +208 -0
- fluxrules-0.1.0/mkdocs.yml +104 -0
- fluxrules-0.1.0/pyproject.toml +179 -0
- fluxrules-0.1.0/scripts/artifact_smoke_test.py +36 -0
- fluxrules-0.1.0/scripts/check_uv.py +59 -0
- fluxrules-0.1.0/src/fluxrules/__init__.py +209 -0
- fluxrules-0.1.0/src/fluxrules/adapters/__init__.py +3 -0
- fluxrules-0.1.0/src/fluxrules/adapters/caches/__init__.py +100 -0
- fluxrules-0.1.0/src/fluxrules/adapters/loaders/__init__.py +5 -0
- fluxrules-0.1.0/src/fluxrules/adapters/loaders/yaml_loader.py +47 -0
- fluxrules-0.1.0/src/fluxrules/adapters/observability/__init__.py +3 -0
- fluxrules-0.1.0/src/fluxrules/adapters/observability/noop.py +27 -0
- fluxrules-0.1.0/src/fluxrules/adapters/persistence/__init__.py +7 -0
- fluxrules-0.1.0/src/fluxrules/adapters/persistence/sqlalchemy_adapter.py +168 -0
- fluxrules-0.1.0/src/fluxrules/adapters/queues/__init__.py +101 -0
- fluxrules-0.1.0/src/fluxrules/adapters/repository/__init__.py +15 -0
- fluxrules-0.1.0/src/fluxrules/adapters/repository/database.py +59 -0
- fluxrules-0.1.0/src/fluxrules/adapters/repository/in_memory.py +60 -0
- fluxrules-0.1.0/src/fluxrules/analytics/__init__.py +11 -0
- fluxrules-0.1.0/src/fluxrules/api/__init__.py +10 -0
- fluxrules-0.1.0/src/fluxrules/api/analytics/__init__.py +1 -0
- fluxrules-0.1.0/src/fluxrules/api/analytics/coverage_report.py +20 -0
- fluxrules-0.1.0/src/fluxrules/api/analytics/explanation_engine.py +21 -0
- fluxrules-0.1.0/src/fluxrules/api/analytics/metrics.py +23 -0
- fluxrules-0.1.0/src/fluxrules/api/analytics/store.py +149 -0
- fluxrules-0.1.0/src/fluxrules/api/app.py +108 -0
- fluxrules-0.1.0/src/fluxrules/api/config.py +136 -0
- fluxrules-0.1.0/src/fluxrules/api/database.py +172 -0
- fluxrules-0.1.0/src/fluxrules/api/deps.py +69 -0
- fluxrules-0.1.0/src/fluxrules/api/engines/__init__.py +16 -0
- fluxrules-0.1.0/src/fluxrules/api/engines/adapter.py +434 -0
- fluxrules-0.1.0/src/fluxrules/api/engines/engine_pool.py +229 -0
- fluxrules-0.1.0/src/fluxrules/api/engines/holder.py +0 -0
- fluxrules-0.1.0/src/fluxrules/api/handlers.py +110 -0
- fluxrules-0.1.0/src/fluxrules/api/models/__init__.py +7 -0
- fluxrules-0.1.0/src/fluxrules/api/models/audit.py +20 -0
- fluxrules-0.1.0/src/fluxrules/api/models/audit_policy.py +65 -0
- fluxrules-0.1.0/src/fluxrules/api/models/conflicted_rule.py +44 -0
- fluxrules-0.1.0/src/fluxrules/api/models/rule.py +72 -0
- fluxrules-0.1.0/src/fluxrules/api/models/user.py +24 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/__init__.py +0 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/admin.py +65 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/analytics.py +53 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/audit.py +56 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/audit_policy.py +160 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/auth.py +61 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/brms_analyze.py +525 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/dependency_graph.py +203 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/engines.py +397 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/evaluate.py +42 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/evaluation.py +219 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/events.py +97 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/explain.py +25 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/health.py +37 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/metrics.py +49 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/rules.py +1119 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/rulesets.py +109 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/sdk.py +109 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/sessions.py +205 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/simulate.py +28 -0
- fluxrules-0.1.0/src/fluxrules/api/routes/validate.py +34 -0
- fluxrules-0.1.0/src/fluxrules/api/schema_manager.py +98 -0
- fluxrules-0.1.0/src/fluxrules/api/schemas/__init__.py +30 -0
- fluxrules-0.1.0/src/fluxrules/api/schemas/analytics.py +57 -0
- fluxrules-0.1.0/src/fluxrules/api/schemas/audit_policy.py +79 -0
- fluxrules-0.1.0/src/fluxrules/api/schemas/event.py +15 -0
- fluxrules-0.1.0/src/fluxrules/api/schemas/rule.py +98 -0
- fluxrules-0.1.0/src/fluxrules/api/schemas/session.py +38 -0
- fluxrules-0.1.0/src/fluxrules/api/schemas/user.py +37 -0
- fluxrules-0.1.0/src/fluxrules/api/schemas.py +30 -0
- fluxrules-0.1.0/src/fluxrules/api/security.py +82 -0
- fluxrules-0.1.0/src/fluxrules/api/services/__init__.py +0 -0
- fluxrules-0.1.0/src/fluxrules/api/services/analytics_service.py +207 -0
- fluxrules-0.1.0/src/fluxrules/api/services/audit_runner.py +265 -0
- fluxrules-0.1.0/src/fluxrules/api/services/audit_scheduler.py +157 -0
- fluxrules-0.1.0/src/fluxrules/api/services/audit_service.py +118 -0
- fluxrules-0.1.0/src/fluxrules/api/services/auth_service.py +38 -0
- fluxrules-0.1.0/src/fluxrules/api/services/brms_service.py +135 -0
- fluxrules-0.1.0/src/fluxrules/api/services/rule_service.py +196 -0
- fluxrules-0.1.0/src/fluxrules/api/services/rule_validation_service.py +468 -0
- fluxrules-0.1.0/src/fluxrules/api/utils/__init__.py +0 -0
- fluxrules-0.1.0/src/fluxrules/api/utils/metrics.py +198 -0
- fluxrules-0.1.0/src/fluxrules/api/utils/redis_client.py +38 -0
- fluxrules-0.1.0/src/fluxrules/api/workers/__init__.py +0 -0
- fluxrules-0.1.0/src/fluxrules/api/workers/event_worker.py +83 -0
- fluxrules-0.1.0/src/fluxrules/api/workers/validation_worker.py +212 -0
- fluxrules-0.1.0/src/fluxrules/cli/__init__.py +0 -0
- fluxrules-0.1.0/src/fluxrules/cli/main.py +200 -0
- fluxrules-0.1.0/src/fluxrules/compat/__init__.py +3 -0
- fluxrules-0.1.0/src/fluxrules/compat/contracts.py +17 -0
- fluxrules-0.1.0/src/fluxrules/config/__init__.py +208 -0
- fluxrules-0.1.0/src/fluxrules/config/deployment.py +355 -0
- fluxrules-0.1.0/src/fluxrules/config/manager.py +77 -0
- fluxrules-0.1.0/src/fluxrules/core/__init__.py +11 -0
- fluxrules-0.1.0/src/fluxrules/di/__init__.py +334 -0
- fluxrules-0.1.0/src/fluxrules/domain/__init__.py +35 -0
- fluxrules-0.1.0/src/fluxrules/domain/actions.py +338 -0
- fluxrules-0.1.0/src/fluxrules/domain/dsl/__init__.py +179 -0
- fluxrules-0.1.0/src/fluxrules/domain/dsl/evaluator.py +180 -0
- fluxrules-0.1.0/src/fluxrules/domain/dsl/expression_parser.py +94 -0
- fluxrules-0.1.0/src/fluxrules/domain/dsl/parser.py +147 -0
- fluxrules-0.1.0/src/fluxrules/domain/dsl/validation.py +183 -0
- fluxrules-0.1.0/src/fluxrules/domain/errors.py +108 -0
- fluxrules-0.1.0/src/fluxrules/domain/factory.py +177 -0
- fluxrules-0.1.0/src/fluxrules/domain/models.py +236 -0
- fluxrules-0.1.0/src/fluxrules/domain/predicates.py +37 -0
- fluxrules-0.1.0/src/fluxrules/domain/rule_builder.py +462 -0
- fluxrules-0.1.0/src/fluxrules/domain/schemas.py +87 -0
- fluxrules-0.1.0/src/fluxrules/domain/unified_rule.py +456 -0
- fluxrules-0.1.0/src/fluxrules/engine/__init__.py +156 -0
- fluxrules-0.1.0/src/fluxrules/engine/base.py +339 -0
- fluxrules-0.1.0/src/fluxrules/engine/configuration.py +61 -0
- fluxrules-0.1.0/src/fluxrules/engine/cross_fact/__init__.py +48 -0
- fluxrules-0.1.0/src/fluxrules/engine/cross_fact/_engine.py +574 -0
- fluxrules-0.1.0/src/fluxrules/engine/cross_fact/models.py +324 -0
- fluxrules-0.1.0/src/fluxrules/engine/cross_fact/working_memory.py +133 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/__init__.py +72 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/agenda.py +111 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/bitmask_linker.py +363 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/engine_metrics.py +146 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/evaluation_filter.py +26 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/evaluation_result.py +15 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/fact_store.py +184 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/field_index.py +85 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/global_rule_repository.py +329 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/lazy_evaluation.py +173 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/node_memory.py +178 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/scope_guard.py +402 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/segment_network.py +139 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/token_propagator.py +62 -0
- fluxrules-0.1.0/src/fluxrules/engine/infrastructure/working_memory.py +141 -0
- fluxrules-0.1.0/src/fluxrules/engine/interfaces.py +13 -0
- fluxrules-0.1.0/src/fluxrules/engine/operator_registry.py +83 -0
- fluxrules-0.1.0/src/fluxrules/engine/operators.py +175 -0
- fluxrules-0.1.0/src/fluxrules/engine/phreak/__init__.py +34 -0
- fluxrules-0.1.0/src/fluxrules/engine/phreak/_engine.py +1333 -0
- fluxrules-0.1.0/src/fluxrules/engine/phreak/condition_compiler.py +204 -0
- fluxrules-0.1.0/src/fluxrules/engine/profiler.py +62 -0
- fluxrules-0.1.0/src/fluxrules/engine/runtime/__init__.py +43 -0
- fluxrules-0.1.0/src/fluxrules/engine/runtime/action_dispatcher.py +277 -0
- fluxrules-0.1.0/src/fluxrules/engine/runtime/dedup_cache.py +247 -0
- fluxrules-0.1.0/src/fluxrules/engine/runtime/worker_pool.py +120 -0
- fluxrules-0.1.0/src/fluxrules/exceptions.py +132 -0
- fluxrules-0.1.0/src/fluxrules/features.py +61 -0
- fluxrules-0.1.0/src/fluxrules/initialization.py +111 -0
- fluxrules-0.1.0/src/fluxrules/logging.py +70 -0
- fluxrules-0.1.0/src/fluxrules/persistence/__init__.py +27 -0
- fluxrules-0.1.0/src/fluxrules/persistence/database_config.py +141 -0
- fluxrules-0.1.0/src/fluxrules/persistence/db_connection_manager.py +201 -0
- fluxrules-0.1.0/src/fluxrules/persistence/execution_repository.py +67 -0
- fluxrules-0.1.0/src/fluxrules/persistence/mappers.py +178 -0
- fluxrules-0.1.0/src/fluxrules/persistence/persistence_manager.py +229 -0
- fluxrules-0.1.0/src/fluxrules/persistence/rule_repository.py +131 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/__init__.py +156 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/base.py +179 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/core.py +410 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/error_policy.py +106 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/exporters.py +320 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/loaders.py +173 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/observability.py +206 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/registry.py +96 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/schema.py +118 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/transforms/__init__.py +33 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/transforms/builtin.py +240 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/transforms/composed.py +196 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/utils/__init__.py +13 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/utils/dict_utils.py +189 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/validators.py +128 -0
- fluxrules-0.1.0/src/fluxrules/pipeline/versioning.py +137 -0
- fluxrules-0.1.0/src/fluxrules/plugins/__init__.py +0 -0
- fluxrules-0.1.0/src/fluxrules/plugins/actions.py +446 -0
- fluxrules-0.1.0/src/fluxrules/plugins/discovery.py +106 -0
- fluxrules-0.1.0/src/fluxrules/plugins/operators.py +88 -0
- fluxrules-0.1.0/src/fluxrules/ports/__init__.py +19 -0
- fluxrules-0.1.0/src/fluxrules/ports/circuit_breaker.py +35 -0
- fluxrules-0.1.0/src/fluxrules/ports/execution_store.py +22 -0
- fluxrules-0.1.0/src/fluxrules/ports/health.py +33 -0
- fluxrules-0.1.0/src/fluxrules/ports/observability.py +30 -0
- fluxrules-0.1.0/src/fluxrules/ports/persistence.py +97 -0
- fluxrules-0.1.0/src/fluxrules/ports/queue.py +78 -0
- fluxrules-0.1.0/src/fluxrules/ports/repository.py +27 -0
- fluxrules-0.1.0/src/fluxrules/ports/rule.py +23 -0
- fluxrules-0.1.0/src/fluxrules/ports/rule_cache.py +69 -0
- fluxrules-0.1.0/src/fluxrules/ports/validation.py +44 -0
- fluxrules-0.1.0/src/fluxrules/prefilter/__init__.py +76 -0
- fluxrules-0.1.0/src/fluxrules/prefilter/pipeline.py +115 -0
- fluxrules-0.1.0/src/fluxrules/prefilter/predicate.py +304 -0
- fluxrules-0.1.0/src/fluxrules/prefilter/predicate_index.py +307 -0
- fluxrules-0.1.0/src/fluxrules/prefilter/sql_store.py +238 -0
- fluxrules-0.1.0/src/fluxrules/py.typed +0 -0
- fluxrules-0.1.0/src/fluxrules/services/__init__.py +4 -0
- fluxrules-0.1.0/src/fluxrules/services/audit_service.py +29 -0
- fluxrules-0.1.0/src/fluxrules/services/circuit_breaker.py +98 -0
- fluxrules-0.1.0/src/fluxrules/services/compilation/__init__.py +7 -0
- fluxrules-0.1.0/src/fluxrules/services/compilation/rule_compiler.py +81 -0
- fluxrules-0.1.0/src/fluxrules/services/evaluation_service.py +21 -0
- fluxrules-0.1.0/src/fluxrules/services/execution/__init__.py +25 -0
- fluxrules-0.1.0/src/fluxrules/services/execution/agenda.py +51 -0
- fluxrules-0.1.0/src/fluxrules/services/execution/scheduler.py +37 -0
- fluxrules-0.1.0/src/fluxrules/services/execution/session_context.py +187 -0
- fluxrules-0.1.0/src/fluxrules/services/execution/session_manager.py +242 -0
- fluxrules-0.1.0/src/fluxrules/services/execution/session_storage.py +227 -0
- fluxrules-0.1.0/src/fluxrules/services/execution/storage_backend.py +302 -0
- fluxrules-0.1.0/src/fluxrules/services/execution/working_memory.py +96 -0
- fluxrules-0.1.0/src/fluxrules/services/health.py +59 -0
- fluxrules-0.1.0/src/fluxrules/services/persistence_service.py +67 -0
- fluxrules-0.1.0/src/fluxrules/services/reference_evaluator.py +127 -0
- fluxrules-0.1.0/src/fluxrules/services/rule_loader.py +73 -0
- fluxrules-0.1.0/src/fluxrules/services/rule_service.py +229 -0
- fluxrules-0.1.0/src/fluxrules/services/session.py +105 -0
- fluxrules-0.1.0/src/fluxrules/services/validation/__init__.py +39 -0
- fluxrules-0.1.0/src/fluxrules/services/validation/_compiled_cache.py +230 -0
- fluxrules-0.1.0/src/fluxrules/services/validation/_interval_index.py +200 -0
- fluxrules-0.1.0/src/fluxrules/services/validation/_normalization.py +110 -0
- fluxrules-0.1.0/src/fluxrules/services/validation/conflict_detection.py +375 -0
- fluxrules-0.1.0/src/fluxrules/services/validation/coverage_analysis.py +55 -0
- fluxrules-0.1.0/src/fluxrules/services/validation/dead_rule_detection.py +75 -0
- fluxrules-0.1.0/src/fluxrules/services/validation/duplicate_detection.py +24 -0
- fluxrules-0.1.0/src/fluxrules/services/validation/gap_detection.py +40 -0
- fluxrules-0.1.0/src/fluxrules/services/validation/priority_collision_detection.py +26 -0
- fluxrules-0.1.0/src/fluxrules/services/validation/redundancy_detection.py +42 -0
- fluxrules-0.1.0/src/fluxrules/services/validation/sat_validation.py +281 -0
- fluxrules-0.1.0/src/fluxrules/services/validation_enforcer.py +142 -0
- fluxrules-0.1.0/src/fluxrules/services/validation_gateway.py +213 -0
- fluxrules-0.1.0/src/fluxrules/services/validation_service.py +115 -0
- fluxrules-0.1.0/src/fluxrules/services/validators/__init__.py +35 -0
- fluxrules-0.1.0/src/fluxrules/services/validators/action_validator.py +73 -0
- fluxrules-0.1.0/src/fluxrules/services/validators/base.py +207 -0
- fluxrules-0.1.0/src/fluxrules/services/validators/brms_validator.py +151 -0
- fluxrules-0.1.0/src/fluxrules/services/validators/duplicate_validator.py +139 -0
- fluxrules-0.1.0/src/fluxrules/services/validators/priority_validator.py +90 -0
- fluxrules-0.1.0/src/fluxrules/services/validators/referential_validator.py +83 -0
- fluxrules-0.1.0/src/fluxrules/services/validators/stateful_dsl_validator.py +195 -0
- fluxrules-0.1.0/src/fluxrules/services/validators/structural_validator.py +199 -0
- fluxrules-0.1.0/src/fluxrules/testing/__init__.py +193 -0
- fluxrules-0.1.0/src/fluxrules/utils/__init__.py +16 -0
- fluxrules-0.1.0/src/fluxrules/utils/dependency_graph.py +67 -0
- fluxrules-0.1.0/src/fluxrules/utils/dependency_graph_analyzer.py +114 -0
- fluxrules-0.1.0/src/fluxrules/utils/id_generators.py +379 -0
- fluxrules-0.1.0/src/fluxrules/utils/metrics.py +93 -0
- fluxrules-0.1.0/src/fluxrules/version.py +5 -0
- fluxrules-0.1.0/tests/__init__.py +0 -0
- fluxrules-0.1.0/tests/api/test_engine_adapter.py +223 -0
- fluxrules-0.1.0/tests/api/test_engine_holder.py +146 -0
- fluxrules-0.1.0/tests/api/test_routers_load.py +111 -0
- fluxrules-0.1.0/tests/conftest.py +273 -0
- fluxrules-0.1.0/tests/contract/test_engine_contract.py +13 -0
- fluxrules-0.1.0/tests/contract/test_engine_contract_battery.py +149 -0
- fluxrules-0.1.0/tests/contract/test_plugin_contract.py +142 -0
- fluxrules-0.1.0/tests/contract/test_public_api_contracts.py +90 -0
- fluxrules-0.1.0/tests/contract/test_quickstart_contract.py +142 -0
- fluxrules-0.1.0/tests/docs/__init__.py +0 -0
- fluxrules-0.1.0/tests/docs/_extract.py +156 -0
- fluxrules-0.1.0/tests/docs/test_doc_imports.py +75 -0
- fluxrules-0.1.0/tests/docs/test_doc_snippets.py +157 -0
- fluxrules-0.1.0/tests/docs/test_nav_completeness.py +58 -0
- fluxrules-0.1.0/tests/engine/test_action_dispatcher.py +160 -0
- fluxrules-0.1.0/tests/engine/test_agenda_cancellation.py +238 -0
- fluxrules-0.1.0/tests/engine/test_agenda_unscheduling.py +451 -0
- fluxrules-0.1.0/tests/engine/test_bitmask_linker.py +383 -0
- fluxrules-0.1.0/tests/engine/test_capability_matrix.py +85 -0
- fluxrules-0.1.0/tests/engine/test_concurrency_thread_safety.py +165 -0
- fluxrules-0.1.0/tests/engine/test_conflict_resolution_ordering.py +87 -0
- fluxrules-0.1.0/tests/engine/test_cross_fact_engine.py +859 -0
- fluxrules-0.1.0/tests/engine/test_cross_fact_oracle_differential.py +212 -0
- fluxrules-0.1.0/tests/engine/test_dedup.py +145 -0
- fluxrules-0.1.0/tests/engine/test_default_engine_wiring.py +19 -0
- fluxrules-0.1.0/tests/engine/test_differential_fuzz.py +309 -0
- fluxrules-0.1.0/tests/engine/test_explanation_contract.py +53 -0
- fluxrules-0.1.0/tests/engine/test_finding_unhashable_values.py +69 -0
- fluxrules-0.1.0/tests/engine/test_flat_evaluation.py +154 -0
- fluxrules-0.1.0/tests/engine/test_flat_segments.py +124 -0
- fluxrules-0.1.0/tests/engine/test_nested_fact_contract.py +53 -0
- fluxrules-0.1.0/tests/engine/test_node_memory.py +300 -0
- fluxrules-0.1.0/tests/engine/test_parallel_worker_pool.py +76 -0
- fluxrules-0.1.0/tests/engine/test_phreak_infrastructure_integration.py +531 -0
- fluxrules-0.1.0/tests/engine/test_realistic_rules_smoke.py +121 -0
- fluxrules-0.1.0/tests/engine/test_scope_guard.py +371 -0
- fluxrules-0.1.0/tests/engine/test_single_discovery_parity.py +211 -0
- fluxrules-0.1.0/tests/engine/test_stateless_streaming_equivalence.py +285 -0
- fluxrules-0.1.0/tests/engine/test_stateless_streaming_parity_strict.py +96 -0
- fluxrules-0.1.0/tests/engine/test_streaming_guardrail.py +122 -0
- fluxrules-0.1.0/tests/engine/test_streaming_mode_feature.py +749 -0
- fluxrules-0.1.0/tests/engine/test_strict_facts.py +33 -0
- fluxrules-0.1.0/tests/engine/test_working_memory_contract.py +58 -0
- fluxrules-0.1.0/tests/factories.py +38 -0
- fluxrules-0.1.0/tests/infrastructure/test_node_memory_lru.py +150 -0
- fluxrules-0.1.0/tests/infrastructure/test_working_memory_watchdog.py +89 -0
- fluxrules-0.1.0/tests/integration/__init__.py +0 -0
- fluxrules-0.1.0/tests/integration/api_endpoints_functional_test_script.py +253 -0
- fluxrules-0.1.0/tests/integration/conftest.py +15 -0
- fluxrules-0.1.0/tests/integration/test_alembic_migrations.py +143 -0
- fluxrules-0.1.0/tests/integration/test_analytics.py +132 -0
- fluxrules-0.1.0/tests/integration/test_api.py +160 -0
- fluxrules-0.1.0/tests/integration/test_api_evaluate.py +61 -0
- fluxrules-0.1.0/tests/integration/test_audit_policy.py +915 -0
- fluxrules-0.1.0/tests/integration/test_audit_policy_service.py +94 -0
- fluxrules-0.1.0/tests/integration/test_comprehensive_integration.py +1302 -0
- fluxrules-0.1.0/tests/integration/test_dependency_graph_api.py +122 -0
- fluxrules-0.1.0/tests/integration/test_e2e_admin_integration.py +448 -0
- fluxrules-0.1.0/tests/integration/test_engines_router.py +176 -0
- fluxrules-0.1.0/tests/integration/test_factpipeline_e2e.py +197 -0
- fluxrules-0.1.0/tests/integration/test_hybrid_validation_e2e.py +565 -0
- fluxrules-0.1.0/tests/integration/test_persistence_performance.py +177 -0
- fluxrules-0.1.0/tests/integration/test_redis_session_storage.py +136 -0
- fluxrules-0.1.0/tests/integration/test_rules_validate.py +677 -0
- fluxrules-0.1.0/tests/integration/test_session_api.py +119 -0
- fluxrules-0.1.0/tests/integration/test_session_storage_integration.py +144 -0
- fluxrules-0.1.0/tests/integration/test_unified_engine_e2e.py +190 -0
- fluxrules-0.1.0/tests/integration/test_validation_integration.py +263 -0
- fluxrules-0.1.0/tests/integration/test_validation_worker_db.py +63 -0
- fluxrules-0.1.0/tests/observability/test_engine_metrics.py +206 -0
- fluxrules-0.1.0/tests/performance/__init__.py +0 -0
- fluxrules-0.1.0/tests/performance/conftest.py +32 -0
- fluxrules-0.1.0/tests/performance/generators.py +448 -0
- fluxrules-0.1.0/tests/performance/perf_alpha_network.py +225 -0
- fluxrules-0.1.0/tests/performance/perf_and_heavy_rules.py +463 -0
- fluxrules-0.1.0/tests/performance/perf_baseline_vs_optimized.py +143 -0
- fluxrules-0.1.0/tests/performance/perf_condition_compiler.py +194 -0
- fluxrules-0.1.0/tests/performance/perf_dedup.py +98 -0
- fluxrules-0.1.0/tests/performance/perf_massive_scale.py +618 -0
- fluxrules-0.1.0/tests/performance/perf_parallel.py +115 -0
- fluxrules-0.1.0/tests/performance/perf_prefilter.py +165 -0
- fluxrules-0.1.0/tests/performance/perf_real_world_scenarios.py +294 -0
- fluxrules-0.1.0/tests/performance/perf_realistic_rules.py +730 -0
- fluxrules-0.1.0/tests/performance/perf_risk_areas.py +372 -0
- fluxrules-0.1.0/tests/performance/perf_scale_quick.py +233 -0
- fluxrules-0.1.0/tests/performance/perf_scale_validation.py +286 -0
- fluxrules-0.1.0/tests/performance/perf_streaming_validation.py +394 -0
- fluxrules-0.1.0/tests/performance/test_benchmark.py +179 -0
- fluxrules-0.1.0/tests/performance/test_load_scenarios.py +108 -0
- fluxrules-0.1.0/tests/performance/test_phreak_engine_perf.py +351 -0
- fluxrules-0.1.0/tests/performance/test_scale_readiness.py +261 -0
- fluxrules-0.1.0/tests/plugins/test_action_registry.py +395 -0
- fluxrules-0.1.0/tests/prefilter/__init__.py +1 -0
- fluxrules-0.1.0/tests/prefilter/test_alpha_adaptive_gate.py +137 -0
- fluxrules-0.1.0/tests/prefilter/test_alpha_primary_soundness.py +149 -0
- fluxrules-0.1.0/tests/prefilter/test_condition_compiler.py +214 -0
- fluxrules-0.1.0/tests/prefilter/test_engine_alpha_integration.py +76 -0
- fluxrules-0.1.0/tests/prefilter/test_predicate_index.py +150 -0
- fluxrules-0.1.0/tests/prefilter/test_soundness.py +177 -0
- fluxrules-0.1.0/tests/regression/__init__.py +1 -0
- fluxrules-0.1.0/tests/regression/test_condition_dsl_storage_shape.py +282 -0
- fluxrules-0.1.0/tests/regression/test_public_error_surface.py +125 -0
- fluxrules-0.1.0/tests/regression/test_rule_ingestion_matrix.py +639 -0
- fluxrules-0.1.0/tests/regression/test_validator_vocabulary.py +172 -0
- fluxrules-0.1.0/tests/security/__init__.py +0 -0
- fluxrules-0.1.0/tests/security/conftest.py +15 -0
- fluxrules-0.1.0/tests/security/test_reliability_hardening.py +633 -0
- fluxrules-0.1.0/tests/security/test_security_hardening.py +587 -0
- fluxrules-0.1.0/tests/unit/__init__.py +0 -0
- fluxrules-0.1.0/tests/unit/conftest.py +14 -0
- fluxrules-0.1.0/tests/unit/perf_results/full_benchmark_report.json +90 -0
- fluxrules-0.1.0/tests/unit/pipeline/__init__.py +0 -0
- fluxrules-0.1.0/tests/unit/pipeline/test_base.py +170 -0
- fluxrules-0.1.0/tests/unit/pipeline/test_builtin_transforms.py +155 -0
- fluxrules-0.1.0/tests/unit/pipeline/test_composed_transforms.py +117 -0
- fluxrules-0.1.0/tests/unit/pipeline/test_core.py +177 -0
- fluxrules-0.1.0/tests/unit/pipeline/test_dict_utils.py +84 -0
- fluxrules-0.1.0/tests/unit/pipeline/test_error_policy.py +110 -0
- fluxrules-0.1.0/tests/unit/pipeline/test_exporters.py +394 -0
- fluxrules-0.1.0/tests/unit/pipeline/test_loaders.py +169 -0
- fluxrules-0.1.0/tests/unit/pipeline/test_observability.py +140 -0
- fluxrules-0.1.0/tests/unit/pipeline/test_registry.py +110 -0
- fluxrules-0.1.0/tests/unit/pipeline/test_versioning.py +65 -0
- fluxrules-0.1.0/tests/unit/test_action_execution.py +168 -0
- fluxrules-0.1.0/tests/unit/test_api_handlers.py +23 -0
- fluxrules-0.1.0/tests/unit/test_api_routes_evaluation.py +263 -0
- fluxrules-0.1.0/tests/unit/test_api_routes_rules.py +88 -0
- fluxrules-0.1.0/tests/unit/test_brms_validation.py +296 -0
- fluxrules-0.1.0/tests/unit/test_brms_validation_edge_cases.py +241 -0
- fluxrules-0.1.0/tests/unit/test_candidate_rule_ids.py +109 -0
- fluxrules-0.1.0/tests/unit/test_circuit_breaker.py +116 -0
- fluxrules-0.1.0/tests/unit/test_cli_main.py +170 -0
- fluxrules-0.1.0/tests/unit/test_compiled_cache_invalidation.py +73 -0
- fluxrules-0.1.0/tests/unit/test_config_manager.py +77 -0
- fluxrules-0.1.0/tests/unit/test_conflict_detection.py +225 -0
- fluxrules-0.1.0/tests/unit/test_conflict_detection_categorical.py +230 -0
- fluxrules-0.1.0/tests/unit/test_cycle_detection.py +98 -0
- fluxrules-0.1.0/tests/unit/test_dependency_fallbacks.py +78 -0
- fluxrules-0.1.0/tests/unit/test_dependency_graph.py +46 -0
- fluxrules-0.1.0/tests/unit/test_domain_factory.py +119 -0
- fluxrules-0.1.0/tests/unit/test_domain_models.py +11 -0
- fluxrules-0.1.0/tests/unit/test_dsl_ast.py +305 -0
- fluxrules-0.1.0/tests/unit/test_dsl_parser.py +48 -0
- fluxrules-0.1.0/tests/unit/test_dsl_validation.py +133 -0
- fluxrules-0.1.0/tests/unit/test_event_worker.py +132 -0
- fluxrules-0.1.0/tests/unit/test_exceptions.py +80 -0
- fluxrules-0.1.0/tests/unit/test_fact_store.py +160 -0
- fluxrules-0.1.0/tests/unit/test_health_service.py +44 -0
- fluxrules-0.1.0/tests/unit/test_id_generator.py +499 -0
- fluxrules-0.1.0/tests/unit/test_mappers.py +225 -0
- fluxrules-0.1.0/tests/unit/test_memory_session_storage.py +92 -0
- fluxrules-0.1.0/tests/unit/test_null_handling_comprehensive.py +84 -0
- fluxrules-0.1.0/tests/unit/test_operator_edge_matrix.py +102 -0
- fluxrules-0.1.0/tests/unit/test_operator_parity.py +86 -0
- fluxrules-0.1.0/tests/unit/test_operator_registry.py +61 -0
- fluxrules-0.1.0/tests/unit/test_persistence.py +350 -0
- fluxrules-0.1.0/tests/unit/test_persistence_port.py +67 -0
- fluxrules-0.1.0/tests/unit/test_phreak_engine.py +304 -0
- fluxrules-0.1.0/tests/unit/test_public_api.py +80 -0
- fluxrules-0.1.0/tests/unit/test_reference_evaluator.py +45 -0
- fluxrules-0.1.0/tests/unit/test_rule_consolidation.py +449 -0
- fluxrules-0.1.0/tests/unit/test_rule_file_loaders.py +64 -0
- fluxrules-0.1.0/tests/unit/test_rule_loader.py +131 -0
- fluxrules-0.1.0/tests/unit/test_rule_repository.py +160 -0
- fluxrules-0.1.0/tests/unit/test_rule_service.py +34 -0
- fluxrules-0.1.0/tests/unit/test_rule_service_persistence.py +107 -0
- fluxrules-0.1.0/tests/unit/test_schemas.py +71 -0
- fluxrules-0.1.0/tests/unit/test_service_factory.py +426 -0
- fluxrules-0.1.0/tests/unit/test_services.py +65 -0
- fluxrules-0.1.0/tests/unit/test_session_context.py +77 -0
- fluxrules-0.1.0/tests/unit/test_session_manager.py +73 -0
- fluxrules-0.1.0/tests/unit/test_session_persistence.py +150 -0
- fluxrules-0.1.0/tests/unit/test_unified_engine_core.py +441 -0
- fluxrules-0.1.0/tests/unit/test_unified_rule.py +571 -0
- fluxrules-0.1.0/tests/unit/test_unified_validators.py +519 -0
- fluxrules-0.1.0/tests/unit/test_validation_enforcer.py +145 -0
- fluxrules-0.1.0/tests/unit/test_validation_gateway.py +175 -0
- fluxrules-0.1.0/tests/unit/test_validation_performance.py +73 -0
- fluxrules-0.1.0/tests/unit/test_validation_plugins.py +77 -0
- fluxrules-0.1.0/tests/unit/test_validation_worker.py +91 -0
- fluxrules-0.1.0/tests/unit/test_working_memory.py +64 -0
- fluxrules-0.1.0/tests/unit/validators/test_stateful_dsl_validator.py +333 -0
- fluxrules-0.1.0/uv.lock +2804 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- master
|
|
8
|
+
pull_request:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
quality:
|
|
13
|
+
name: Python ${{ matrix.python-version }}
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
timeout-minutes: 30
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
strategy:
|
|
19
|
+
fail-fast: false
|
|
20
|
+
matrix:
|
|
21
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- name: Check out repository
|
|
25
|
+
uses: actions/checkout@v4
|
|
26
|
+
|
|
27
|
+
- name: Set up uv
|
|
28
|
+
uses: astral-sh/setup-uv@v4
|
|
29
|
+
with:
|
|
30
|
+
enable-cache: true
|
|
31
|
+
version: ">=0.8"
|
|
32
|
+
|
|
33
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
34
|
+
uses: actions/setup-python@v5
|
|
35
|
+
with:
|
|
36
|
+
python-version: ${{ matrix.python-version }}
|
|
37
|
+
|
|
38
|
+
- name: Install project dependencies
|
|
39
|
+
run: uv sync --extra dev --extra docs
|
|
40
|
+
|
|
41
|
+
- name: Ruff
|
|
42
|
+
run: uv run ruff check src/ tests/
|
|
43
|
+
|
|
44
|
+
- name: Mypy
|
|
45
|
+
run: uv run mypy src/fluxrules --ignore-missing-imports
|
|
46
|
+
|
|
47
|
+
- name: Quickstart contract (first-run experience)
|
|
48
|
+
run: uv run pytest tests/contract/test_quickstart_contract.py -q
|
|
49
|
+
|
|
50
|
+
- name: Non-performance test suite
|
|
51
|
+
run: uv run pytest tests/ -q -m "not performance"
|
|
52
|
+
|
|
53
|
+
- name: Docs snippet tests
|
|
54
|
+
run: uv run pytest tests/docs/test_doc_snippets.py -q
|
|
55
|
+
|
|
56
|
+
- name: MkDocs build
|
|
57
|
+
run: uv run mkdocs build
|
|
58
|
+
|
|
59
|
+
- name: Bandit security scan
|
|
60
|
+
run: uv run bandit -r src/fluxrules -c pyproject.toml
|
|
61
|
+
|
|
62
|
+
- name: Dependency audit
|
|
63
|
+
run: uv run pip-audit --skip-editable
|
|
64
|
+
|
|
65
|
+
- name: Fresh API-extra dependency audit
|
|
66
|
+
run: |
|
|
67
|
+
set -euo pipefail
|
|
68
|
+
api_env="$(mktemp -d)/venv"
|
|
69
|
+
uv venv --python "${{ matrix.python-version }}" "$api_env"
|
|
70
|
+
uv pip install --python "$api_env/bin/python" '.[api]'
|
|
71
|
+
api_site_packages="$("$api_env/bin/python" -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])')"
|
|
72
|
+
uv run --no-sync pip-audit --path "$api_site_packages"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
paths:
|
|
8
|
+
- "docs/**"
|
|
9
|
+
- "mkdocs.yml"
|
|
10
|
+
- "src/**" # API reference regenerates on source changes
|
|
11
|
+
- ".github/workflows/docs.yml"
|
|
12
|
+
workflow_dispatch: # allow manual deploys from the Actions tab
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: write # mkdocs gh-deploy pushes to the gh-pages branch
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
deploy:
|
|
19
|
+
name: Build and deploy MkDocs site
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
timeout-minutes: 15
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- name: Check out repository
|
|
25
|
+
uses: actions/checkout@v4
|
|
26
|
+
with:
|
|
27
|
+
fetch-depth: 0 # full history so git-revision-date plugins work
|
|
28
|
+
|
|
29
|
+
- name: Set up uv
|
|
30
|
+
uses: astral-sh/setup-uv@v4
|
|
31
|
+
with:
|
|
32
|
+
enable-cache: true
|
|
33
|
+
version: ">=0.8"
|
|
34
|
+
|
|
35
|
+
- name: Set up Python 3.12
|
|
36
|
+
uses: actions/setup-python@v5
|
|
37
|
+
with:
|
|
38
|
+
python-version: "3.12"
|
|
39
|
+
|
|
40
|
+
- name: Install project with docs extras
|
|
41
|
+
run: uv sync --extra docs
|
|
42
|
+
|
|
43
|
+
- name: Configure git for gh-deploy
|
|
44
|
+
run: |
|
|
45
|
+
git config user.name "github-actions[bot]"
|
|
46
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
47
|
+
|
|
48
|
+
- name: Build and deploy to gh-pages branch
|
|
49
|
+
run: uv run mkdocs gh-deploy --force --clean --verbose
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: Package artifact gate
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- master
|
|
8
|
+
tags:
|
|
9
|
+
- "v*"
|
|
10
|
+
pull_request:
|
|
11
|
+
branches:
|
|
12
|
+
- main
|
|
13
|
+
- master
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
package-smoke:
|
|
18
|
+
name: Build + install smoke test (Python ${{ matrix.python-version }})
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
timeout-minutes: 30
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
strategy:
|
|
24
|
+
fail-fast: false
|
|
25
|
+
matrix:
|
|
26
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
27
|
+
|
|
28
|
+
steps:
|
|
29
|
+
- name: Check out repository
|
|
30
|
+
uses: actions/checkout@v4
|
|
31
|
+
|
|
32
|
+
- name: Set up uv
|
|
33
|
+
uses: astral-sh/setup-uv@v4
|
|
34
|
+
with:
|
|
35
|
+
enable-cache: true
|
|
36
|
+
version: ">=0.8"
|
|
37
|
+
|
|
38
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
39
|
+
uses: actions/setup-python@v5
|
|
40
|
+
with:
|
|
41
|
+
python-version: ${{ matrix.python-version }}
|
|
42
|
+
|
|
43
|
+
- name: Build sdist and wheel
|
|
44
|
+
run: uv build
|
|
45
|
+
|
|
46
|
+
- name: Install each artifact in a clean venv and run a core smoke test
|
|
47
|
+
shell: bash
|
|
48
|
+
run: |
|
|
49
|
+
set -euo pipefail
|
|
50
|
+
for artifact in dist/*.tar.gz dist/*.whl; do
|
|
51
|
+
venv_dir=".artifact-venv-$(basename "$artifact" | tr -cs '[:alnum:]' '_')"
|
|
52
|
+
python -m venv "$venv_dir"
|
|
53
|
+
. "$venv_dir/bin/activate"
|
|
54
|
+
python -m pip install --upgrade pip --quiet
|
|
55
|
+
python -m pip install --force-reinstall "$artifact" --quiet
|
|
56
|
+
python scripts/artifact_smoke_test.py
|
|
57
|
+
deactivate
|
|
58
|
+
rm -rf "$venv_dir"
|
|
59
|
+
done
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Triggers only on version tags — never on branch pushes.
|
|
4
|
+
# Pushing v0.1.0 starts build → smoke-test → (manual gate) → PyPI.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags:
|
|
8
|
+
- "v*"
|
|
9
|
+
|
|
10
|
+
# No top-level permissions: every job declares its own minimal set.
|
|
11
|
+
permissions: {}
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
# ── 1. Build ──────────────────────────────────────────────────────────────
|
|
15
|
+
build:
|
|
16
|
+
name: Build sdist + wheel
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
timeout-minutes: 15
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read # checkout only
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- name: Check out repository
|
|
24
|
+
uses: actions/checkout@v4
|
|
25
|
+
with:
|
|
26
|
+
fetch-depth: 0 # full history for SCM-based version tools
|
|
27
|
+
|
|
28
|
+
- name: Set up uv
|
|
29
|
+
uses: astral-sh/setup-uv@v4
|
|
30
|
+
with:
|
|
31
|
+
enable-cache: true
|
|
32
|
+
version: ">=0.8"
|
|
33
|
+
|
|
34
|
+
- name: Set up Python 3.12
|
|
35
|
+
uses: actions/setup-python@v5
|
|
36
|
+
with:
|
|
37
|
+
python-version: "3.12"
|
|
38
|
+
|
|
39
|
+
# Reject runs triggered by a tag that is not reachable from main.
|
|
40
|
+
# This prevents a tag pushed from a feature branch from publishing.
|
|
41
|
+
- name: Assert tag commit is on main
|
|
42
|
+
shell: bash
|
|
43
|
+
run: |
|
|
44
|
+
set -euo pipefail
|
|
45
|
+
git fetch origin main --depth=50
|
|
46
|
+
if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then
|
|
47
|
+
echo "::error::Tag $GITHUB_REF_NAME was pushed from a commit not on main."
|
|
48
|
+
echo "Only tags on main may trigger a release."
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
echo "tag-on-main-gate: $GITHUB_SHA is reachable from origin/main OK"
|
|
52
|
+
|
|
53
|
+
- name: Build sdist and wheel
|
|
54
|
+
run: uv build
|
|
55
|
+
|
|
56
|
+
# Verify the tag version matches pyproject.toml before uploading anything.
|
|
57
|
+
- name: Assert tag matches package version
|
|
58
|
+
shell: bash
|
|
59
|
+
run: |
|
|
60
|
+
set -euo pipefail
|
|
61
|
+
TAG="${GITHUB_REF_NAME}" # e.g. "v0.1.0"
|
|
62
|
+
PKG_VERSION="$(python3 -c "
|
|
63
|
+
import tomllib, pathlib
|
|
64
|
+
print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])
|
|
65
|
+
")"
|
|
66
|
+
EXPECTED_TAG="v${PKG_VERSION}"
|
|
67
|
+
if [ "$TAG" != "$EXPECTED_TAG" ]; then
|
|
68
|
+
echo "::error::Tag '$TAG' does not match pyproject.toml version 'v${PKG_VERSION}'."
|
|
69
|
+
echo "Update pyproject.toml and src/fluxrules/version.py, then re-tag."
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
echo "tag-version-gate: $TAG == v$PKG_VERSION OK"
|
|
73
|
+
|
|
74
|
+
# Verify both version fields are in sync — read version.py with grep,
|
|
75
|
+
# no package import needed (avoids pydantic not being installed yet).
|
|
76
|
+
- name: Assert pyproject.toml and version.py agree
|
|
77
|
+
shell: bash
|
|
78
|
+
run: |
|
|
79
|
+
set -euo pipefail
|
|
80
|
+
PY_VERSION="$(grep -m1 '^__version__' src/fluxrules/version.py | sed 's/.*"\(.*\)".*/\1/')"
|
|
81
|
+
PKG_VERSION="$(python3 -c "
|
|
82
|
+
import tomllib, pathlib
|
|
83
|
+
print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])
|
|
84
|
+
")"
|
|
85
|
+
if [ "$PY_VERSION" != "$PKG_VERSION" ]; then
|
|
86
|
+
echo "::error::src/fluxrules/version.py (__version__='$PY_VERSION') differs from pyproject.toml ('$PKG_VERSION')."
|
|
87
|
+
exit 1
|
|
88
|
+
fi
|
|
89
|
+
echo "version-sync-gate: $PY_VERSION OK"
|
|
90
|
+
|
|
91
|
+
- name: twine check
|
|
92
|
+
run: |
|
|
93
|
+
uv tool install twine
|
|
94
|
+
uv tool run twine check dist/* --strict
|
|
95
|
+
|
|
96
|
+
- name: Upload dist artifacts
|
|
97
|
+
uses: actions/upload-artifact@v4
|
|
98
|
+
with:
|
|
99
|
+
name: dist
|
|
100
|
+
path: dist/
|
|
101
|
+
if-no-files-found: error
|
|
102
|
+
retention-days: 7
|
|
103
|
+
|
|
104
|
+
# ── 2. Install smoke test (sdist + wheel, 3 Python versions) ─────────────
|
|
105
|
+
smoke-test:
|
|
106
|
+
name: Install smoke (${{ matrix.python-version }})
|
|
107
|
+
needs: build
|
|
108
|
+
runs-on: ubuntu-latest
|
|
109
|
+
timeout-minutes: 15
|
|
110
|
+
permissions:
|
|
111
|
+
contents: read
|
|
112
|
+
strategy:
|
|
113
|
+
fail-fast: true
|
|
114
|
+
matrix:
|
|
115
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
116
|
+
|
|
117
|
+
steps:
|
|
118
|
+
- name: Check out repository
|
|
119
|
+
uses: actions/checkout@v4
|
|
120
|
+
|
|
121
|
+
- name: Download dist artifacts
|
|
122
|
+
uses: actions/download-artifact@v4
|
|
123
|
+
with:
|
|
124
|
+
name: dist
|
|
125
|
+
path: dist/
|
|
126
|
+
|
|
127
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
128
|
+
uses: actions/setup-python@v5
|
|
129
|
+
with:
|
|
130
|
+
python-version: ${{ matrix.python-version }}
|
|
131
|
+
|
|
132
|
+
- name: Smoke-test each artifact
|
|
133
|
+
shell: bash
|
|
134
|
+
run: |
|
|
135
|
+
set -euo pipefail
|
|
136
|
+
for artifact in dist/*.tar.gz dist/*.whl; do
|
|
137
|
+
venv_dir="$(mktemp -d)/smoke-venv"
|
|
138
|
+
python -m venv "$venv_dir"
|
|
139
|
+
. "$venv_dir/bin/activate"
|
|
140
|
+
pip install --upgrade pip --quiet
|
|
141
|
+
pip install --force-reinstall "$artifact" --quiet
|
|
142
|
+
python scripts/artifact_smoke_test.py
|
|
143
|
+
deactivate
|
|
144
|
+
rm -rf "$venv_dir"
|
|
145
|
+
done
|
|
146
|
+
|
|
147
|
+
# ── 3. Publish to PyPI ───────────────────────────────────────────────────
|
|
148
|
+
#
|
|
149
|
+
# TestPyPI skipped: name is unavailable on test.pypi.org.
|
|
150
|
+
# Validation is covered by build gates + smoke-test on 3 Python versions.
|
|
151
|
+
#
|
|
152
|
+
# Requires secret PYPI_API_TOKEN set at:
|
|
153
|
+
# https://github.com/saurabh2mishra/fluxrules/settings/secrets/actions
|
|
154
|
+
#
|
|
155
|
+
# The pypi GitHub environment gate gives a manual confirmation click
|
|
156
|
+
# before the upload proceeds. Set up at:
|
|
157
|
+
# https://github.com/saurabh2mishra/fluxrules/settings/environments
|
|
158
|
+
#
|
|
159
|
+
publish-pypi:
|
|
160
|
+
name: Publish → PyPI
|
|
161
|
+
needs: [build, smoke-test]
|
|
162
|
+
runs-on: ubuntu-latest
|
|
163
|
+
timeout-minutes: 10
|
|
164
|
+
environment:
|
|
165
|
+
name: pypi
|
|
166
|
+
url: https://pypi.org/p/fluxrules
|
|
167
|
+
permissions:
|
|
168
|
+
contents: write # create GitHub release
|
|
169
|
+
|
|
170
|
+
steps:
|
|
171
|
+
- name: Download dist artifacts
|
|
172
|
+
uses: actions/download-artifact@v4
|
|
173
|
+
with:
|
|
174
|
+
name: dist
|
|
175
|
+
path: dist/
|
|
176
|
+
|
|
177
|
+
- name: Publish to PyPI
|
|
178
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
179
|
+
with:
|
|
180
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
181
|
+
print-hash: true
|
|
182
|
+
verbose: true
|
|
183
|
+
|
|
184
|
+
# Create a GitHub release automatically on successful PyPI publish.
|
|
185
|
+
- name: Create GitHub Release
|
|
186
|
+
uses: softprops/action-gh-release@v2
|
|
187
|
+
with:
|
|
188
|
+
files: dist/*
|
|
189
|
+
generate_release_notes: true
|
|
190
|
+
fail_on_unmatched_files: true
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Python virtual environments
|
|
2
|
+
.venv/
|
|
3
|
+
venv/
|
|
4
|
+
env/
|
|
5
|
+
ENV/
|
|
6
|
+
.python-version
|
|
7
|
+
|
|
8
|
+
# Python bytecode and build artifacts
|
|
9
|
+
# Python creates these directories throughout the source and test trees.
|
|
10
|
+
**/__pycache__/
|
|
11
|
+
*.py[cod]
|
|
12
|
+
*.so
|
|
13
|
+
*.pyo
|
|
14
|
+
*.pyd
|
|
15
|
+
*.egg-info/
|
|
16
|
+
.eggs/
|
|
17
|
+
dist/
|
|
18
|
+
build/
|
|
19
|
+
site/
|
|
20
|
+
*.egg
|
|
21
|
+
|
|
22
|
+
# Test, coverage, and tooling caches
|
|
23
|
+
.pytest_cache/
|
|
24
|
+
.hypothesis/
|
|
25
|
+
.coverage
|
|
26
|
+
.coverage.*
|
|
27
|
+
htmlcov/
|
|
28
|
+
.tox/
|
|
29
|
+
.nox/
|
|
30
|
+
.mypy_cache/
|
|
31
|
+
.ruff_cache/
|
|
32
|
+
.pyre/
|
|
33
|
+
.pytype/
|
|
34
|
+
|
|
35
|
+
# Local environment and secrets
|
|
36
|
+
.env
|
|
37
|
+
.env.*
|
|
38
|
+
*.local
|
|
39
|
+
*.pem
|
|
40
|
+
credentials*.json
|
|
41
|
+
|
|
42
|
+
# Editors and OS files
|
|
43
|
+
.vscode/
|
|
44
|
+
.idea/
|
|
45
|
+
*.swp
|
|
46
|
+
*.swo
|
|
47
|
+
.DS_Store
|
|
48
|
+
Thumbs.db
|
|
49
|
+
|
|
50
|
+
# Project-specific generated files
|
|
51
|
+
logs/
|
|
52
|
+
*.log
|
|
53
|
+
/.github/agents/
|
|
54
|
+
/.github/skills/
|
|
55
|
+
|
|
56
|
+
# SQLite / database runtime artifacts
|
|
57
|
+
*.db
|
|
58
|
+
*.sqlite
|
|
59
|
+
*.sqlite3
|
|
60
|
+
*.db-wal
|
|
61
|
+
*.db-shm
|
|
62
|
+
*_wal
|
|
63
|
+
*_shm
|
|
64
|
+
rune_engine.db
|
|
65
|
+
fluxrules_dev.db
|
|
66
|
+
rule_engine.db
|
|
67
|
+
rule_engine.db-wal
|
|
68
|
+
rule_engine.db-shm
|
|
69
|
+
|
|
70
|
+
# Optional generated docs/assets
|
|
71
|
+
mkdocs_material/
|
|
72
|
+
|
|
73
|
+
# Claude Code — keep local only, do not publish to remote.
|
|
74
|
+
.claude/
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be 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
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-10-06
|
|
11
|
+
|
|
12
|
+
First release intended for publication. The changes below tighten the public
|
|
13
|
+
API surface so that one concept has one name and one type. `0.0.1` was never
|
|
14
|
+
published, so these are breaking relative to an unreleased baseline only and
|
|
15
|
+
carry no deprecation shims — carrying a shim for `matched_rule_ids` was
|
|
16
|
+
rejected precisely because the name's meaning was the defect.
|
|
17
|
+
|
|
18
|
+
### Changed — breaking
|
|
19
|
+
|
|
20
|
+
- **One `EvaluationResult`.** There were two classes of that name: the domain
|
|
21
|
+
one, whose `matched_rule_ids` meant *the rules that fired*, and the engine
|
|
22
|
+
one, whose `matched_rule_ids` meant *the rules discovery considered*. Both
|
|
23
|
+
were exported as `EvaluationResult`, so the same attribute answered a
|
|
24
|
+
different question depending on which function you called, and the engine's
|
|
25
|
+
answer was a superset that silently over-reported matches. They are now a
|
|
26
|
+
single class owned by `fluxrules.domain.models`;
|
|
27
|
+
`fluxrules.engine.infrastructure.EvaluationResult` re-exports it.
|
|
28
|
+
- **`fired_rules` is the only name for what matched.** `matched_rule_ids` is
|
|
29
|
+
removed from the attribute set, the constructor, and the persisted schema.
|
|
30
|
+
`candidate_rule_ids` remains the discovery prefilter's output and is
|
|
31
|
+
guaranteed to be a superset of `fired_rules` on every evaluation path,
|
|
32
|
+
including the reference evaluator.
|
|
33
|
+
- **`Rule(...)` no longer touches the database.** `persist` now defaults to
|
|
34
|
+
`False`, so constructing a rule is a pure in-memory operation; previously the
|
|
35
|
+
default `True` meant importing a module that defined rules opened a
|
|
36
|
+
connection and created a `.db` file, then swallowed any failure as a log
|
|
37
|
+
warning. Persist explicitly with the new `Rule.save()` or `persist=True`.
|
|
38
|
+
The redundant `except Exception` around persistence is gone —
|
|
39
|
+
`PersistenceManager.persist_rule` already degrades to a local ID, so anything
|
|
40
|
+
escaping it is a real fault.
|
|
41
|
+
- **`RuleBuilder.build()` returns `Rule`**, not the internal `EngineRule`, so a
|
|
42
|
+
built rule goes straight into `load_rules()` or `evaluate()`. Use the new
|
|
43
|
+
`build_engine_rule()` for the internal representation. `RuleBuilder`'s
|
|
44
|
+
`persist` default is now `False` to match `Rule`.
|
|
45
|
+
- **`evaluate()` and `validate()` take rules directly.** Both accept a single
|
|
46
|
+
`Rule`, any iterable of `Rule`, or a `Ruleset`; the first parameter is
|
|
47
|
+
renamed `ruleset` → `rules`. Building a `Ruleset` of `to_engine_rule()`
|
|
48
|
+
conversions is no longer required to evaluate a list of rules.
|
|
49
|
+
- **`explain()` returns `fired_rules`** instead of `matched_rules`, matching
|
|
50
|
+
`EvaluationResult`. The HTTP API's own `matched_rules` response field is a
|
|
51
|
+
separate wire contract and is unchanged.
|
|
52
|
+
- The `evaluation_results` table's `matched_rule_ids` column is now
|
|
53
|
+
`fired_rules`. The table is created by `create_all()` rather than Alembic, so
|
|
54
|
+
an existing development database needs to be recreated.
|
|
55
|
+
|
|
56
|
+
### Fixed
|
|
57
|
+
|
|
58
|
+
- `RuleBuilder()` with no explicit ID allocated from a second, builder-local
|
|
59
|
+
sequential generator that also started at 1, so the first built rule and the
|
|
60
|
+
first directly-constructed rule were assigned the same ID and evaluating them
|
|
61
|
+
together failed with "Ruleset has duplicate rule ids". The builder now defers
|
|
62
|
+
to the same shared generator `Rule` uses.
|
|
63
|
+
- `docs/rule-builder.md` documented a `RuleBuilder` API that did not exist
|
|
64
|
+
(`.domain()`, `.tags()`, `.condition_dsl()`, and a snippet that was not valid
|
|
65
|
+
Python) while never demonstrating the real builder. Every block on the page
|
|
66
|
+
is now executable and covered by the documentation harness.
|
|
67
|
+
|
|
68
|
+
### Added
|
|
69
|
+
|
|
70
|
+
- `Rule.save()` — explicit persistence for a rule built in memory.
|
|
71
|
+
- `RuleBuilder`, `ConditionBuilder`, and the `Rules` input alias are exported
|
|
72
|
+
from the top-level `fluxrules` namespace.
|
|
73
|
+
- `RuleBuilder.build_engine_rule()` for the internal `EngineRule` shape.
|
|
74
|
+
- A quickstart contract test (`tests/contract/test_quickstart_contract.py`) that
|
|
75
|
+
runs the documented ten-line example in a clean subprocess, asserts it emits
|
|
76
|
+
no warnings, and asserts it writes nothing to disk. CI runs it as its own step
|
|
77
|
+
ahead of the main suite so a broken first-run experience fails loudly.
|
|
78
|
+
|
|
79
|
+
## [0.0.1] - 2026-09-14
|
|
80
|
+
|
|
81
|
+
Initial, unpublished development version. FluxRules is a Python rule-evaluation
|
|
82
|
+
library built on a single engine, PHREAK, with stateless (default) and streaming
|
|
83
|
+
evaluation modes.
|
|
84
|
+
|
|
85
|
+
### Added
|
|
86
|
+
|
|
87
|
+
- Core evaluation API — `evaluate()`, `validate()`, `explain()` over a typed
|
|
88
|
+
`Ruleset` of rules, with a curated public `__all__` and a shipped `py.typed`
|
|
89
|
+
marker.
|
|
90
|
+
- PHREAK engine (`PhreakEngine`): lazy, agenda-driven evaluation in stateless
|
|
91
|
+
(default) and streaming modes. Correctness is checked against the
|
|
92
|
+
dependency-free `ReferenceEvaluator` oracle and by stateless/streaming parity.
|
|
93
|
+
- Condition operators — 13 distinct operators plus 6 word aliases: `==`/`eq`,
|
|
94
|
+
`!=`/`ne`, `>`/`gt`, `>=`/`gte`, `<`/`lt`, `<=`/`lte`, `in`, `not_in`,
|
|
95
|
+
`contains`, `not_contains`, `starts_with`, `ends_with`, `regex`; combined with
|
|
96
|
+
arbitrary AND/OR/NOT nesting.
|
|
97
|
+
- Extensibility — public `register_engine()` / `unregister_engine()` (a custom
|
|
98
|
+
`BaseEngine` becomes selectable via `get_engine()`, the HTTP API, and the CLI
|
|
99
|
+
`--engine` flag; the built-in engine is protected), registries for custom
|
|
100
|
+
operators/actions/transforms/validators, entry-point auto-discovery
|
|
101
|
+
(`fluxrules.plugins.discovery.load_plugins`), and a public conformance kit
|
|
102
|
+
(`fluxrules.testing.assert_engine_contract`).
|
|
103
|
+
- Fact pipeline — `Flatten`, `Rename`, `Defaults`, `Require`, `FieldType`, and
|
|
104
|
+
user-defined transforms.
|
|
105
|
+
- Validation framework (structure, conflicts, dead/redundant rules) and an audit
|
|
106
|
+
trail with integrity hashing.
|
|
107
|
+
- Optional adapters behind extras: FastAPI HTTP API (`api`), SQLAlchemy/Alembic
|
|
108
|
+
persistence (`sql`), Redis sessions (`redis`), OpenTelemetry (`otel`), YAML
|
|
109
|
+
rules (`yaml`), and a Typer CLI (`cli`).
|
|
110
|
+
- Documentation (MkDocs Material), 31 runnable examples, a suite of 2,000+ tests,
|
|
111
|
+
and a CI-gated scale test.
|
|
112
|
+
|
|
113
|
+
### Security
|
|
114
|
+
|
|
115
|
+
- Scoped flake8-bandit (`S`) ruff rule set enforced in the lint gate
|
|
116
|
+
(exec/eval/pickle/marshal/weak-hash/SQL-injection/try-except-pass).
|
|
117
|
+
- CI security job (`bandit` + `pip-audit`) and a pull-request `dependency-review`
|
|
118
|
+
job; SPDX SBOM generation and Sigstore signing in the release workflow.
|
|
119
|
+
- `SECURITY.md` (supported versions, response targets, coordinated disclosure), a
|
|
120
|
+
threat model in `docs/security.md`, `CODEOWNERS`, and branch-protection
|
|
121
|
+
guidance in `CONTRIBUTING.md`.
|