From bf4b592bf920b7be8900e0f335408df54f180873 Mon Sep 17 00:00:00 2001 From: jonahgabriel Date: Sun, 11 Oct 2026 17:37:08 -0400 Subject: [PATCH 1/2] ci(OMN-21005): call core imperative guard with caller-owned allowlist Move the historical omniintelligence allowlist unchanged under .github and pin the reusable and canonical-file-shape hook/job to the core revision that reads its declaration. Bind the three criteria to focused tests, including shrink-only and live-handler refusal controls. --- .github/imperative-contract-allowlist.yaml | 608 ++++++++++++++++++ .github/workflows/ci.yml | 5 +- .../workflows/imperative-contract-guard.yml | 5 +- .pre-commit-config.yaml | 10 +- contracts/OMN-21005.yaml | 67 ++ ...perative_contract_guard_caller_omn21005.py | 363 +++++++++++ 6 files changed, 1055 insertions(+), 3 deletions(-) create mode 100644 .github/imperative-contract-allowlist.yaml create mode 100644 contracts/OMN-21005.yaml create mode 100644 tests/ci/test_imperative_contract_guard_caller_omn21005.py diff --git a/.github/imperative-contract-allowlist.yaml b/.github/imperative-contract-allowlist.yaml new file mode 100644 index 00000000..6ab4b928 --- /dev/null +++ b/.github/imperative-contract-allowlist.yaml @@ -0,0 +1,608 @@ +--- +allowlisted_handlers: + - path: omniintelligence/nodes/node_agent_behavior_eval_compute/handlers/handler_agent_behavior_evaluation.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_anti_gaming_guardrails_compute/handlers/handler_guardrails.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_anti_gaming_alerter_effect/handlers/protocols.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_ast_extraction_compute/handlers/handler_ast_extract.py + violations: + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_ast_extraction_compute/handlers/handler_deterministic_classify.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_ast_extraction_compute/handlers/handler_extract_ast.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_ast_extraction_compute/handlers/handler_multilang_extract.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_ast_extraction_compute/handlers/handler_quality_score.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_ast_extraction_compute/handlers/handler_relationship_detect.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_bloom_eval_orchestrator/handlers/handler_bloom_eval_effect.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_ci_error_classifier_compute/handlers/handler_classifier.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_ci_failure_tracker_effect/handlers/handler_streak.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_ci_failure_tracker_effect/handlers/handler_trigger_record.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_ci_fingerprint_compute/handlers/handler_fingerprint.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_code_crawler_effect/handlers/handler_onextree_generator.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_code_crawler_effect/handlers/handler_onextree_query.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_code_entity_bridge_compute/handlers/handler_bridge.py + violations: + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_compliance_evaluate_effect/handlers/handler_compliance_evaluate.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_contract_eval_compute/handlers/handler_contract_eval.py + violations: + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_contract_eval_compute/handlers/validators.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_crawl_scheduler_effect/handlers/debounce_state.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_debug_fix_record_effect/handlers/handler_fix_record.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_debug_retrieval_compute/handlers/handler_retrieval.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_document_fetch_effect/handlers/protocol_blob_store.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_execution_trace_parser_compute/handlers/exceptions.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_execution_trace_parser_compute/handlers/handler_compute.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_execution_trace_parser_compute/handlers/handler_event_extraction.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_execution_trace_parser_compute/handlers/handler_trace_parsing.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_execution_trace_parser_compute/handlers/protocols.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_git_repo_crawler_effect/handlers/protocol_crawl_state.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_gmail_intent_evaluator_effect/handlers/handler_gmail_intent_evaluate.py + violations: + - undeclared_transport + ticket: OMN-11881 + - path: omniintelligence/nodes/node_intelligence_reducer/handlers/handler_pattern_lifecycle.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_intelligence_reducer/handlers/handler_process.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_intent_classifier_compute/handlers/exceptions.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_intent_classifier_compute/handlers/handler_adaptive_classification.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_intent_classifier_compute/handlers/handler_intent_classification.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_intent_classifier_compute/handlers/handler_langextract.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_intent_classifier_compute/handlers/handler_typed_classification.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_intent_cost_forecast_compute/handlers/handler_cost_forecast.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_intent_drift_detect_compute/handlers/handler_drift_detect.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_linear_crawler_effect/handlers/protocol_linear_state.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_memory_eval_compute/handlers/handler_memory_evaluation.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_assembler_orchestrator/handlers/exceptions.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_assembler_orchestrator/handlers/handler_orchestrate.py + violations: + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_assembler_orchestrator/handlers/handler_pattern_assembly.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_assembler_orchestrator/handlers/handler_workflow_coordination.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_assembler_orchestrator/handlers/protocols.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_compliance_effect/handlers/exceptions.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_compliance_effect/handlers/handler_compliance.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_compliance_effect/handlers/handler_compute.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_compliance_effect/handlers/protocols.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/exceptions.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_architecture_patterns.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_converters.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_core_models.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_error_patterns.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_extract_all_patterns.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_file_patterns.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_group_node_families.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_identity.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_match_pattern.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_merge.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_novelty.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_scan_role_occurrences.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_store_node_families.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_tool_failure_patterns.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_tool_patterns.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/protocols.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_extraction_compute/handlers/utils.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_feedback_effect/handlers/handler_attribution_binder.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_feedback_effect/handlers/heuristics.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_learning_compute/handlers/exceptions.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_learning_compute/handlers/handler_confidence_scoring.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_learning_compute/handlers/handler_deduplication.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_learning_compute/handlers/handler_feature_extraction.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_learning_compute/handlers/handler_pattern_clustering.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_learning_compute/handlers/handler_pattern_learning.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_learning_compute/handlers/presets.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_learning_compute/handlers/protocols.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_learning_compute/handlers/replay.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_learning_compute/handlers/union_find.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_learning_compute/handlers/utils.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_matching_compute/handlers/exceptions.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_matching_compute/handlers/handler_compute.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_matching_compute/handlers/handler_pattern_matching.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_matching_compute/handlers/protocols.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_promotion_effect/handlers/handler_auto_promote.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_promotion_effect/handlers/handler_metrics.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_storage_effect/handlers/handler_pattern_storage.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_storage_effect/handlers/model_state_transition.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_pattern_storage_effect/handlers/protocol_pattern_state_manager.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_plan_reviewer_multi_compute/handlers/handler_confidence_scorer.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_plan_reviewer_multi_compute/handlers/handler_plan_reviewer_multi_compute.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_plan_reviewer_multi_compute/handlers/strategies/handler_independent_merge.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_plan_reviewer_multi_compute/handlers/strategies/handler_panel_vote.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_plan_reviewer_multi_compute/handlers/strategies/handler_sequential_critique.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_plan_reviewer_multi_compute/handlers/strategies/handler_specialist_split.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_policy_state_reducer/handlers/handler_lifecycle.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_policy_state_reducer/handlers/protocols.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_quality_scoring_compute/handlers/enum_onex_strictness_level.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_quality_scoring_compute/handlers/exceptions.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_quality_scoring_compute/handlers/handler_compute.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_quality_scoring_compute/handlers/handler_quality_scoring.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_quality_scoring_compute/handlers/presets.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_quality_scoring_compute/handlers/protocols.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_scoring_reducer_compute/handlers/handler_scoring.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_semantic_analysis_compute/handlers/exceptions.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_semantic_analysis_compute/handlers/handler_compute_semantic_analysis.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_semantic_analysis_compute/handlers/handler_semantic_analysis.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_semantic_analysis_compute/handlers/protocols.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_success_criteria_matcher_compute/handlers/exceptions.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_success_criteria_matcher_compute/handlers/handler_compute.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_success_criteria_matcher_compute/handlers/handler_criteria_matching.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_success_criteria_matcher_compute/handlers/protocols.py + violations: + - missing_handler_routing + - logic_in_node + ticket: OMN-11881 + - path: omniintelligence/nodes/node_watchdog_effect/handlers/observer_factory.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_intent_graph_reducer/handlers/handler_intent_graph_update.py + violations: + - missing_handler_routing + ticket: OMN-11881 + - path: omniintelligence/nodes/node_objective_ab_framework_compute/handlers/handler_ab_framework.py + violations: + - logic_in_node + ticket: OMN-11881 + - path: src/omniintelligence/adapters/embedding_client.py + violations: + - raw_http_inference + ticket: OMN-12833 + - path: src/omniintelligence/adapters/embedding_client_local_openai.py + violations: + - raw_http_inference + ticket: OMN-12833 + - path: src/omniintelligence/adapters/eval_llm_client.py + violations: + - hardcoded_config + - raw_http_inference + ticket: OMN-12833 + - path: src/omniintelligence/adapters/gmail_intent_http_client.py + violations: + - direct_db + - hardcoded_config + - raw_http_inference + ticket: OMN-12833 + - path: src/omniintelligence/adapters/utilization_llm_client.py + violations: + - raw_http_inference + ticket: OMN-12833 + - path: src/omniintelligence/constants.py + violations: + - hardcoded_topic + ticket: OMN-12833 + - path: src/omniintelligence/models/events/model_llm_call_completed_event.py + violations: + - hardcoded_config + ticket: OMN-12833 + - path: src/omniintelligence/nodes/node_anti_gaming_alerter_effect/models/model_alerter_input.py + violations: + - hardcoded_topic + ticket: OMN-12833 + - path: src/omniintelligence/nodes/node_intent_classifier_compute/models/model_typed_intent_config.py + violations: + - hardcoded_config + ticket: OMN-12833 + - path: src/omniintelligence/nodes/node_pattern_demotion_effect/models/model_demotion_request.py + violations: + - hardcoded_config + ticket: OMN-12833 + - path: src/omniintelligence/runtime/dispatch_handler_code_embed_graph.py + violations: + - raw_http_inference + ticket: OMN-12833 + - path: src/omniintelligence/runtime/dispatch_handler_routing_feedback.py + violations: + - hardcoded_topic + ticket: OMN-12833 + - path: src/omniintelligence/runtime/dispatch_handler_utilization_scoring.py + violations: + - hardcoded_config + ticket: OMN-12833 + - path: src/omniintelligence/runtime/dispatch_handlers.py + violations: + - hardcoded_topic + ticket: OMN-12833 + - path: src/omniintelligence/topics.py + violations: + - hardcoded_topic + ticket: OMN-12833 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 85aef59a..ef46bafa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -273,6 +273,9 @@ jobs: cp "${lab_vocab}" "$(dirname "${vocab}")/public_repo_hygiene_lab_vocabulary.yaml" echo "OMNI_HYGIENE_VOCAB_PATH=${GITHUB_WORKSPACE}/${vocab}" >> "$GITHUB_ENV" + - name: Imperative guard caller and shrink-only allowlist (OMN-21005) + run: uv run pytest tests/ci/test_imperative_contract_guard_caller_omn21005.py -q -n 0 + # Verbose mode enables hook profiling - shows execution time for each hook # This helps identify slow hooks and track performance regressions # See .pre-commit-config.yaml for profiling documentation and thresholds @@ -1463,7 +1466,7 @@ jobs: runs-on: ${{ github.event_name != 'pull_request' && github.event_name != 'merge_group' && fromJSON(vars.OMNI_TRUSTED_CI_RUNS_ON_JSON || '["self-hosted","omnibase-ci"]') || fromJSON(vars.OMNI_PUBLIC_PR_RUNS_ON_JSON || '["ubuntu-latest"]') }} timeout-minutes: 15 env: - CANONICAL_FILE_SHAPE_CORE: "omnibase-core @ git+https://github.com/OmniNode-ai/omnibase_core@f50d00fc7918d0b12ccd0d3497160325e32e7ac5" + CANONICAL_FILE_SHAPE_CORE: "omnibase-core @ git+https://github.com/OmniNode-ai/omnibase_core@031148215620031436cba30619bbae67c0bb38ad" steps: - name: Checkout code uses: actions/checkout@v7 diff --git a/.github/workflows/imperative-contract-guard.yml b/.github/workflows/imperative-contract-guard.yml index 7d7e7dbd..5ee5e84c 100644 --- a/.github/workflows/imperative-contract-guard.yml +++ b/.github/workflows/imperative-contract-guard.yml @@ -18,4 +18,7 @@ permissions: jobs: imperative-contract-guard: # self-gating-ok: central guard is intentionally shared across repos; caller PRs do not modify the referenced workflow. - uses: OmniNode-ai/onex_change_control/.github/workflows/imperative-contract-guard.yml@c0c49e1240ffaa6db1fe36f74b50c0acd345d7b2 + # OMN-21005: caller-owned historical allowlist; core enforces shrink-only changes. + uses: OmniNode-ai/omnibase_core/.github/workflows/imperative-contract-guard.yml@031148215620031436cba30619bbae67c0bb38ad + with: + allowlist-path: .github/imperative-contract-allowlist.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 73be308a..30005902 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -310,7 +310,7 @@ repos: # (OMN-20304)"). The rev moved from 6363509770 to the OMN-20304 commit for # both hooks; the lifecycle validator's source is identical at the two commits. - repo: https://github.com/OmniNode-ai/omnibase_core - rev: f50d00fc7918d0b12ccd0d3497160325e32e7ac5 # pragma: allowlist secret + rev: 031148215620031436cba30619bbae67c0bb38ad # pragma: allowlist secret hooks: - id: no-noncanonical-lifecycle-classes args: [--allowlist, .onex_ratchets/noncanonical_class_allowlist.yaml, src/omniintelligence] @@ -778,6 +778,14 @@ repos: # --------------------------------------------------------------------------- - repo: local hooks: + - id: imperative-contract-guard-caller + name: Imperative guard caller and shrink-only allowlist (OMN-21005) + entry: uv run pytest tests/ci/test_imperative_contract_guard_caller_omn21005.py -q -n 0 + language: system + pass_filenames: false + files: ^(\.github/(workflows/(imperative-contract-guard|ci)\.yml|imperative-contract-allowlist\.yaml)|\.pre-commit-config\.yaml|tests/ci/test_imperative_contract_guard_caller_omn21005\.py|contracts/OMN-21005\.yaml)$ + stages: [pre-commit] + - id: workflow-script-refs name: Workflow-referenced repo-local scripts exist (OMN-16664) entry: uv run python tests/ci/test_workflow_script_refs_exist.py diff --git a/contracts/OMN-21005.yaml b/contracts/OMN-21005.yaml new file mode 100644 index 00000000..e818eba3 --- /dev/null +++ b/contracts/OMN-21005.yaml @@ -0,0 +1,67 @@ +--- +schema_version: 1.0.0 +ticket_id: OMN-21005 +title: omniintelligence's imperative contract guard calls core with its own shrink-only allowlist +summary: The imperative-contract-guard caller uses omnibase_core's reusable at 031148215620031436cba30619bbae67c0bb38ad + with the caller-owned allowlist moved unchanged from the historical guard. The canonical-file-shape + hook and CI job use the same core commit to read the caller's shrink-only declaration. The allowlist + is under .github/imperative-contract-allowlist.yaml and is declared by allowlist-path. +is_seam_ticket: false +interface_change: false +interfaces_touched: [] +requirements: + - id: req-core-guard-caller + statement: The caller uses core's reusable, owns the unchanged allowlist, and retains refusal behaviour. + acceptance: + - id: AC1 + statement: 'AC1: omniintelligence''s imperative-contract-guard caller uses omnibase_core''s reusable + at a full sha (031148215 or later on core dev) and no workflow in omniintelligence references + onex_change_control for this guard -- falsifier: a test in tests/ci added by the PR parses the + caller workflow and fails at the merge base (uv run pytest on that file)' + - id: AC2 + statement: 'AC2: omniintelligence carries its own allowlist file whose entries equal, path for + path, the omniintelligence entries the onex_change_control guard used at c0c49e12, and the reusable''s + ratchet refuses an allowlist that gains a path -- falsifier: the same test file compares the + allowlist to the recorded c0c49e12 entries and a planted extra path is refused by the core ratchet + handler (uv run pytest on that file)' + - id: AC3 + statement: 'AC3: The guard still refuses what it refused before on omniintelligence''s tree -- + falsifier: on a lab host, the core handler run over omniintelligence''s tree with a planted + imperative contract exits non-zero, and over the clean tree exits 0, with the same verdicts + as the onex_change_control script at c0c49e12 on both inputs, recorded on the PR body Lab: line' +evidence_requirements: + - kind: tests + description: Caller wiring, unchanged historical paths, shrink-only ratchet and live planted-handler + refusal. + command: uv run pytest tests/ci/test_imperative_contract_guard_caller_omn21005.py -q -n 0 +emergency_bypass: + enabled: false + justification: '' + follow_up_ticket_id: '' +dod_evidence: + - id: dod-omn21005-ac1-core-caller + description: The parsed caller pins core, retains its job/context and names its own allowlist. + source: manual + checks: + - check_type: test_passes + check_value: uv run pytest tests/ci/test_imperative_contract_guard_caller_omn21005.py -q -n 0 + binds_ac: + - AC1 + - id: dod-omn21005-ac2-own-shrink-only-allowlist + description: The recorded paths match; core admits unchanged and shrinking lists and refuses a planted + extra path. + source: manual + checks: + - check_type: test_passes + check_value: uv run pytest tests/ci/test_imperative_contract_guard_caller_omn21005.py -q -n 0 + binds_ac: + - AC2 + - id: dod-omn21005-ac3-live-guard-refusal + description: The core guard accepts the clean tree and refuses raw HTTP in the live demotion handler; + pinned core/OCC parity is recorded on the Lab line. + source: manual + checks: + - check_type: test_passes + check_value: uv run pytest tests/ci/test_imperative_contract_guard_caller_omn21005.py -q -n 0 + binds_ac: + - AC3 diff --git a/tests/ci/test_imperative_contract_guard_caller_omn21005.py b/tests/ci/test_imperative_contract_guard_caller_omn21005.py new file mode 100644 index 00000000..040f425c --- /dev/null +++ b/tests/ci/test_imperative_contract_guard_caller_omn21005.py @@ -0,0 +1,363 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT + +"""OMN-21005: the caller owns the unchanged allowlist and uses core's guard. + +The recorded paths come from the guard's omniintelligence allowlist at +c0c49e1240ffaa6db1fe36f74b50c0acd345d7b2. The project locks core 0.47.24, +which predates the ratchet handler, so behavioural probes use an isolated +0.47.41 validator environment without changing the application's lock. +""" + +from __future__ import annotations + +import hashlib +import json +import re +import shutil +import subprocess +from pathlib import Path + +import pytest +import yaml + +pytestmark = pytest.mark.unit + +ROOT = Path(__file__).resolve().parents[2] +WORKFLOWS = ROOT / ".github/workflows" +CALLER = WORKFLOWS / "imperative-contract-guard.yml" +ALLOWLIST = ROOT / ".github/imperative-contract-allowlist.yaml" +ALLOWLIST_PATH = ALLOWLIST.relative_to(ROOT).as_posix() +RECORDED_ALLOWLIST_DIGEST = bytes( + ( + 142, + 100, + 139, + 216, + 32, + 116, + 252, + 23, + 164, + 16, + 15, + 189, + 86, + 145, + 93, + 224, + 146, + 125, + 233, + 241, + 165, + 100, + 219, + 220, + 190, + 142, + 100, + 10, + 193, + 66, + 136, + 34, + ) +) +CORE_SHA_PREFIX = "031148215" +CORE_USES = "OmniNode-ai/omnibase_core/.github/workflows/imperative-contract-guard.yml" +RECORDED_PATHS = [ + "omniintelligence/nodes/node_agent_behavior_eval_compute/handlers/handler_agent_behavior_evaluation.py", + "omniintelligence/nodes/node_anti_gaming_guardrails_compute/handlers/handler_guardrails.py", + "omniintelligence/nodes/node_anti_gaming_alerter_effect/handlers/protocols.py", + "omniintelligence/nodes/node_ast_extraction_compute/handlers/handler_ast_extract.py", + "omniintelligence/nodes/node_ast_extraction_compute/handlers/handler_deterministic_classify.py", + "omniintelligence/nodes/node_ast_extraction_compute/handlers/handler_extract_ast.py", + "omniintelligence/nodes/node_ast_extraction_compute/handlers/handler_multilang_extract.py", + "omniintelligence/nodes/node_ast_extraction_compute/handlers/handler_quality_score.py", + "omniintelligence/nodes/node_ast_extraction_compute/handlers/handler_relationship_detect.py", + "omniintelligence/nodes/node_bloom_eval_orchestrator/handlers/handler_bloom_eval_effect.py", + "omniintelligence/nodes/node_ci_error_classifier_compute/handlers/handler_classifier.py", + "omniintelligence/nodes/node_ci_failure_tracker_effect/handlers/handler_streak.py", + "omniintelligence/nodes/node_ci_failure_tracker_effect/handlers/handler_trigger_record.py", + "omniintelligence/nodes/node_ci_fingerprint_compute/handlers/handler_fingerprint.py", + "omniintelligence/nodes/node_code_crawler_effect/handlers/handler_onextree_generator.py", + "omniintelligence/nodes/node_code_crawler_effect/handlers/handler_onextree_query.py", + "omniintelligence/nodes/node_code_entity_bridge_compute/handlers/handler_bridge.py", + "omniintelligence/nodes/node_compliance_evaluate_effect/handlers/handler_compliance_evaluate.py", + "omniintelligence/nodes/node_contract_eval_compute/handlers/handler_contract_eval.py", + "omniintelligence/nodes/node_contract_eval_compute/handlers/validators.py", + "omniintelligence/nodes/node_crawl_scheduler_effect/handlers/debounce_state.py", + "omniintelligence/nodes/node_debug_fix_record_effect/handlers/handler_fix_record.py", + "omniintelligence/nodes/node_debug_retrieval_compute/handlers/handler_retrieval.py", + "omniintelligence/nodes/node_document_fetch_effect/handlers/protocol_blob_store.py", + "omniintelligence/nodes/node_execution_trace_parser_compute/handlers/exceptions.py", + "omniintelligence/nodes/node_execution_trace_parser_compute/handlers/handler_compute.py", + "omniintelligence/nodes/node_execution_trace_parser_compute/handlers/handler_event_extraction.py", + "omniintelligence/nodes/node_execution_trace_parser_compute/handlers/handler_trace_parsing.py", + "omniintelligence/nodes/node_execution_trace_parser_compute/handlers/protocols.py", + "omniintelligence/nodes/node_git_repo_crawler_effect/handlers/protocol_crawl_state.py", + "omniintelligence/nodes/node_gmail_intent_evaluator_effect/handlers/handler_gmail_intent_evaluate.py", + "omniintelligence/nodes/node_intelligence_reducer/handlers/handler_pattern_lifecycle.py", + "omniintelligence/nodes/node_intelligence_reducer/handlers/handler_process.py", + "omniintelligence/nodes/node_intent_classifier_compute/handlers/exceptions.py", + "omniintelligence/nodes/node_intent_classifier_compute/handlers/handler_adaptive_classification.py", + "omniintelligence/nodes/node_intent_classifier_compute/handlers/handler_intent_classification.py", + "omniintelligence/nodes/node_intent_classifier_compute/handlers/handler_langextract.py", + "omniintelligence/nodes/node_intent_classifier_compute/handlers/handler_typed_classification.py", + "omniintelligence/nodes/node_intent_cost_forecast_compute/handlers/handler_cost_forecast.py", + "omniintelligence/nodes/node_intent_drift_detect_compute/handlers/handler_drift_detect.py", + "omniintelligence/nodes/node_linear_crawler_effect/handlers/protocol_linear_state.py", + "omniintelligence/nodes/node_memory_eval_compute/handlers/handler_memory_evaluation.py", + "omniintelligence/nodes/node_pattern_assembler_orchestrator/handlers/exceptions.py", + "omniintelligence/nodes/node_pattern_assembler_orchestrator/handlers/handler_orchestrate.py", + "omniintelligence/nodes/node_pattern_assembler_orchestrator/handlers/handler_pattern_assembly.py", + "omniintelligence/nodes/node_pattern_assembler_orchestrator/handlers/handler_workflow_coordination.py", + "omniintelligence/nodes/node_pattern_assembler_orchestrator/handlers/protocols.py", + "omniintelligence/nodes/node_pattern_compliance_effect/handlers/exceptions.py", + "omniintelligence/nodes/node_pattern_compliance_effect/handlers/handler_compliance.py", + "omniintelligence/nodes/node_pattern_compliance_effect/handlers/handler_compute.py", + "omniintelligence/nodes/node_pattern_compliance_effect/handlers/protocols.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/exceptions.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_architecture_patterns.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_converters.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_core_models.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_error_patterns.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_extract_all_patterns.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_file_patterns.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_group_node_families.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_identity.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_match_pattern.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_merge.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_novelty.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_scan_role_occurrences.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_store_node_families.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_tool_failure_patterns.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/handler_tool_patterns.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/protocols.py", + "omniintelligence/nodes/node_pattern_extraction_compute/handlers/utils.py", + "omniintelligence/nodes/node_pattern_feedback_effect/handlers/handler_attribution_binder.py", + "omniintelligence/nodes/node_pattern_feedback_effect/handlers/heuristics.py", + "omniintelligence/nodes/node_pattern_learning_compute/handlers/exceptions.py", + "omniintelligence/nodes/node_pattern_learning_compute/handlers/handler_confidence_scoring.py", + "omniintelligence/nodes/node_pattern_learning_compute/handlers/handler_deduplication.py", + "omniintelligence/nodes/node_pattern_learning_compute/handlers/handler_feature_extraction.py", + "omniintelligence/nodes/node_pattern_learning_compute/handlers/handler_pattern_clustering.py", + "omniintelligence/nodes/node_pattern_learning_compute/handlers/handler_pattern_learning.py", + "omniintelligence/nodes/node_pattern_learning_compute/handlers/presets.py", + "omniintelligence/nodes/node_pattern_learning_compute/handlers/protocols.py", + "omniintelligence/nodes/node_pattern_learning_compute/handlers/replay.py", + "omniintelligence/nodes/node_pattern_learning_compute/handlers/union_find.py", + "omniintelligence/nodes/node_pattern_learning_compute/handlers/utils.py", + "omniintelligence/nodes/node_pattern_matching_compute/handlers/exceptions.py", + "omniintelligence/nodes/node_pattern_matching_compute/handlers/handler_compute.py", + "omniintelligence/nodes/node_pattern_matching_compute/handlers/handler_pattern_matching.py", + "omniintelligence/nodes/node_pattern_matching_compute/handlers/protocols.py", + "omniintelligence/nodes/node_pattern_promotion_effect/handlers/handler_auto_promote.py", + "omniintelligence/nodes/node_pattern_promotion_effect/handlers/handler_metrics.py", + "omniintelligence/nodes/node_pattern_storage_effect/handlers/handler_pattern_storage.py", + "omniintelligence/nodes/node_pattern_storage_effect/handlers/model_state_transition.py", + "omniintelligence/nodes/node_pattern_storage_effect/handlers/protocol_pattern_state_manager.py", + "omniintelligence/nodes/node_plan_reviewer_multi_compute/handlers/handler_confidence_scorer.py", + "omniintelligence/nodes/node_plan_reviewer_multi_compute/handlers/handler_plan_reviewer_multi_compute.py", + "omniintelligence/nodes/node_plan_reviewer_multi_compute/handlers/strategies/handler_independent_merge.py", + "omniintelligence/nodes/node_plan_reviewer_multi_compute/handlers/strategies/handler_panel_vote.py", + "omniintelligence/nodes/node_plan_reviewer_multi_compute/handlers/strategies/handler_sequential_critique.py", + "omniintelligence/nodes/node_plan_reviewer_multi_compute/handlers/strategies/handler_specialist_split.py", + "omniintelligence/nodes/node_policy_state_reducer/handlers/handler_lifecycle.py", + "omniintelligence/nodes/node_policy_state_reducer/handlers/protocols.py", + "omniintelligence/nodes/node_quality_scoring_compute/handlers/enum_onex_strictness_level.py", + "omniintelligence/nodes/node_quality_scoring_compute/handlers/exceptions.py", + "omniintelligence/nodes/node_quality_scoring_compute/handlers/handler_compute.py", + "omniintelligence/nodes/node_quality_scoring_compute/handlers/handler_quality_scoring.py", + "omniintelligence/nodes/node_quality_scoring_compute/handlers/presets.py", + "omniintelligence/nodes/node_quality_scoring_compute/handlers/protocols.py", + "omniintelligence/nodes/node_scoring_reducer_compute/handlers/handler_scoring.py", + "omniintelligence/nodes/node_semantic_analysis_compute/handlers/exceptions.py", + "omniintelligence/nodes/node_semantic_analysis_compute/handlers/handler_compute_semantic_analysis.py", + "omniintelligence/nodes/node_semantic_analysis_compute/handlers/handler_semantic_analysis.py", + "omniintelligence/nodes/node_semantic_analysis_compute/handlers/protocols.py", + "omniintelligence/nodes/node_success_criteria_matcher_compute/handlers/exceptions.py", + "omniintelligence/nodes/node_success_criteria_matcher_compute/handlers/handler_compute.py", + "omniintelligence/nodes/node_success_criteria_matcher_compute/handlers/handler_criteria_matching.py", + "omniintelligence/nodes/node_success_criteria_matcher_compute/handlers/protocols.py", + "omniintelligence/nodes/node_watchdog_effect/handlers/observer_factory.py", + "omniintelligence/nodes/node_intent_graph_reducer/handlers/handler_intent_graph_update.py", + "omniintelligence/nodes/node_objective_ab_framework_compute/handlers/handler_ab_framework.py", + "src/omniintelligence/adapters/embedding_client.py", + "src/omniintelligence/adapters/embedding_client_local_openai.py", + "src/omniintelligence/adapters/eval_llm_client.py", + "src/omniintelligence/adapters/gmail_intent_http_client.py", + "src/omniintelligence/adapters/utilization_llm_client.py", + "src/omniintelligence/constants.py", + "src/omniintelligence/models/events/model_llm_call_completed_event.py", + "src/omniintelligence/nodes/node_anti_gaming_alerter_effect/models/model_alerter_input.py", + "src/omniintelligence/nodes/node_intent_classifier_compute/models/model_typed_intent_config.py", + "src/omniintelligence/nodes/node_pattern_demotion_effect/models/model_demotion_request.py", + "src/omniintelligence/runtime/dispatch_handler_code_embed_graph.py", + "src/omniintelligence/runtime/dispatch_handler_routing_feedback.py", + "src/omniintelligence/runtime/dispatch_handler_utilization_scoring.py", + "src/omniintelligence/runtime/dispatch_handlers.py", + "src/omniintelligence/topics.py", +] +LIVE_HANDLER = "src/omniintelligence/nodes/node_pattern_demotion_effect/handlers/handler_demotion.py" + + +def _mapping(path: Path) -> dict[str, object]: + data = yaml.safe_load(path.read_text(encoding="utf-8")) + assert isinstance(data, dict) + return data + + +def _core(*args: str, stdin: str | None = None) -> subprocess.CompletedProcess[str]: + return subprocess.run( + ["uv", "run", "--no-project", "--with", "omnibase-core==0.47.41", *args], + input=stdin, + capture_output=True, + text=True, + check=False, + timeout=90, + cwd=ROOT, + ) + + +def _caller_sha() -> str: + jobs = _mapping(CALLER)["jobs"] + assert isinstance(jobs, dict) + uses = jobs["imperative-contract-guard"]["uses"] + assert isinstance(uses, str) + repository, sha = uses.split("@") + assert repository == CORE_USES + assert re.fullmatch(r"[0-9a-f]{40}", sha) + assert sha.startswith(CORE_SHA_PREFIX) + return sha + + +def test_caller_uses_core_and_keeps_the_job_and_context() -> None: + workflow = _mapping(CALLER) + assert workflow["name"] == "Imperative Contract Guard" + jobs = workflow["jobs"] + assert isinstance(jobs, dict) + assert set(jobs) == {"imperative-contract-guard"} + job = jobs["imperative-contract-guard"] + assert job["uses"] == f"{CORE_USES}@{_caller_sha()}" + assert job["with"] == {"allowlist-path": ALLOWLIST_PATH} + assert workflow["permissions"] == {"contents": "read"} + for path in WORKFLOWS.iterdir(): + if path.suffix in {".yml", ".yaml"}: + text = path.read_text(encoding="utf-8") + assert not re.search( + r"onex_change_control/\.github/workflows/imperative-contract-guard\.yml", + text, + ), path + + +def test_canonical_shape_hook_and_ci_use_the_exemption_commit() -> None: + repos = _mapping(ROOT / ".pre-commit-config.yaml")["repos"] + assert isinstance(repos, list) + (hook_repo,) = [ + repo + for repo in repos + if any(hook["id"] == "canonical-file-shape" for hook in repo["hooks"]) + ] + assert hook_repo["repo"] == "https://github.com/OmniNode-ai/omnibase_core" + assert hook_repo["rev"] == _caller_sha() + jobs = _mapping(WORKFLOWS / "ci.yml")["jobs"] + assert isinstance(jobs, dict) + assert jobs["canonical-file-shape"]["env"]["CANONICAL_FILE_SHAPE_CORE"].endswith( + f"@{_caller_sha()}" + ) + + +def test_own_allowlist_matches_the_recorded_paths() -> None: + assert hashlib.sha256(ALLOWLIST.read_bytes()).digest() == RECORDED_ALLOWLIST_DIGEST + entries = _mapping(ALLOWLIST)["allowlisted_handlers"] + assert isinstance(entries, list) + assert [entry["path"] for entry in entries] == RECORDED_PATHS + + +def test_core_ratchet_accepts_unchanged_and_shrinking_but_refuses_an_extra_path() -> ( + None +): + text = ALLOWLIST.read_text(encoding="utf-8") + entries = _mapping(ALLOWLIST)["allowlisted_handlers"] + assert isinstance(entries, list) + extra = "src/omniintelligence/nodes/node_planted_effect/handlers/handler_planted.py" + request = { + "base": text, + "head": yaml.safe_dump({"allowlisted_handlers": [*entries, {"path": extra}]}), + "shrunk": yaml.safe_dump({"allowlisted_handlers": entries[:-1]}), + } + result = _core( + "python", + "-c", + "import json, sys; " + "from omnibase_core.handlers.handler_imperative_allowlist_ratchet import " + "HandlerImperativeAllowlistRatchet; " + "from omnibase_core.models.nodes.imperative_contract_guard." + "model_allowlist_ratchet_input import ModelAllowlistRatchetInput; " + "p=json.load(sys.stdin); h=HandlerImperativeAllowlistRatchet(); " + "reports=[h.handle(ModelAllowlistRatchetInput(base_text=p['base'], " + "head_text=p[k])) for k in ('base', 'shrunk', 'head')]; " + "print(json.dumps([dict(r.model_dump(), admitted=r.admitted) for r in reports]))", + stdin=json.dumps(request), + ) + assert result.returncode == 0, result.stdout + result.stderr + unchanged, shrunk, planted = json.loads(result.stdout) + assert unchanged == { + "added": [], + "removed": [], + "bootstrap": False, + "admitted": True, + } + assert shrunk["admitted"] is True + assert shrunk["removed"] == [RECORDED_PATHS[-1]] + assert planted["admitted"] is False + assert planted["bootstrap"] is False + assert planted["added"] == [extra] + + +def test_core_guard_accepts_clean_tree_and_refuses_a_planted_live_handler( + tmp_path: Path, +) -> None: + # Use the caller's input; the merge-base caller cannot provide it. + jobs = _mapping(CALLER)["jobs"] + assert isinstance(jobs, dict) + assert jobs["imperative-contract-guard"]["with"]["allowlist-path"] == ALLOWLIST_PATH + root = tmp_path / "omniintelligence" + shutil.copytree( + ROOT / "src", root / "src", ignore=shutil.ignore_patterns("__pycache__") + ) + shutil.copyfile(ROOT / "pyproject.toml", root / "pyproject.toml") + (root / ".github").mkdir() + shutil.copyfile(ALLOWLIST, root / ALLOWLIST_PATH) + args = ( + "check-imperative-contracts", + "--repo-root", + str(root), + "--allowlist-path", + ALLOWLIST_PATH, + "--scan-freestanding", + "--json", + ) + clean = _core(*args) + assert clean.returncode == 0, clean.stdout + clean.stderr + handler = root / LIVE_HANDLER + original = handler.read_text(encoding="utf-8") + # The scanner reads this source; it does not execute a network request. + handler.write_text( + original + '\nimport httpx\nhttpx.get("http://example.invalid/planted")\n', + encoding="utf-8", + ) + planted = _core(*args) + assert planted.returncode == 1, planted.stdout + planted.stderr + report = json.loads(planted.stdout)[0] + assert report["new_violation_count"] > 0 + (violation,) = [ + violation + for violation in report["new_violations"] + if violation["handler_path"].endswith("handlers/handler_demotion.py") + ] + assert violation["reachability"] == "live" + assert "HTTP" in violation["undeclared_transports"] + assert "undeclared_transport" in violation["violations"] From e026c5278575142bdaed85025e07982bc2df1edc Mon Sep 17 00:00:00 2001 From: jonahgabriel Date: Sun, 11 Oct 2026 19:55:32 -0400 Subject: [PATCH 2/2] ci(OMN-21005): align core pins and invoke the guard module Advance the shape-gate-independence and lifecycle-class CI git pins to 031148215, matching the canonical-file-shape job and hook revision that the caller-owned allowlist regression requires. Invoke the core guard's module in the regression test so a fresh project environment cannot select the retired guard through the shared console script name. Keep every assertion and the existing contract unchanged. --- .github/workflows/ci.yml | 4 ++-- tests/ci/test_imperative_contract_guard_caller_omn21005.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef46bafa..09752dd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1338,7 +1338,7 @@ jobs: - name: Shape-gate independence (OMN-20298) run: | uv run --no-project \ - --with 'omnibase-core @ git+https://github.com/OmniNode-ai/omnibase_core@f50d00fc7918d0b12ccd0d3497160325e32e7ac5' \ + --with 'omnibase-core @ git+https://github.com/OmniNode-ai/omnibase_core@031148215620031436cba30619bbae67c0bb38ad' \ python -m omnibase_core.handlers.handler_shape_gate_independence no-noncanonical-lifecycle-classes: @@ -1361,7 +1361,7 @@ jobs: - name: Ratchet non-canonical lifecycle-word classes against frozen allowlist (OMN-14350) run: | uv run --no-project \ - --with 'omnibase-core @ git+https://github.com/OmniNode-ai/omnibase_core@f50d00fc7918d0b12ccd0d3497160325e32e7ac5' \ + --with 'omnibase-core @ git+https://github.com/OmniNode-ai/omnibase_core@031148215620031436cba30619bbae67c0bb38ad' \ python -m omnibase_core.validators.no_noncanonical_lifecycle_classes \ --check-stale \ --allowlist .onex_ratchets/noncanonical_class_allowlist.yaml \ diff --git a/tests/ci/test_imperative_contract_guard_caller_omn21005.py b/tests/ci/test_imperative_contract_guard_caller_omn21005.py index 040f425c..d74b5df5 100644 --- a/tests/ci/test_imperative_contract_guard_caller_omn21005.py +++ b/tests/ci/test_imperative_contract_guard_caller_omn21005.py @@ -332,7 +332,9 @@ def test_core_guard_accepts_clean_tree_and_refuses_a_planted_live_handler( (root / ".github").mkdir() shutil.copyfile(ALLOWLIST, root / ALLOWLIST_PATH) args = ( - "check-imperative-contracts", + "python", + "-m", + "omnibase_core.handlers.handler_imperative_contract_guard_cli", "--repo-root", str(root), "--allowlist-path",