| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- """Opt-in V54 deterministic model-offline degradation acceptance."""
- import os
- import pytest
- from sqlalchemy import create_engine, text
- from app.core.common.identifiers import new_governance_uid
- from app.core.mcp.identity import AgentIdentity
- from app.core.mcp.persistence import PostgresAuditSink
- from app.core.orchestration.agent.planner import SchedulingPlanner
- pytestmark = pytest.mark.integration
- DATABASE_URL = "postgresql://dataops:dataops-test-password@127.0.0.1:15432/dataops"
- class OfflineModel:
- provider = "deepseek"
- model_name = "deepseek-chat"
- def generate(self, **_kwargs):
- raise TimeoutError("the model provider is unavailable")
- class ContextTools:
- def call_tool(self, name, _arguments):
- return {
- "get_sla_constraints": {"deadline": "08:00"},
- "list_datasource_capabilities": {
- "items": [],
- "count": 0,
- "truncated": False,
- },
- "get_execution_history": {
- "items": [{"status": "success"}],
- "count": 1,
- "truncated": False,
- },
- }[name]
- class ForbiddenSchedulingTools:
- def call_tool(self, name, _arguments):
- raise AssertionError(f"offline model must not call scheduling tool {name}")
- class ForbiddenVerifier:
- def verify(self, *_args, **_kwargs):
- raise AssertionError("offline model must not start Canary verification")
- def test_model_offline_keeps_fixed_schedule_and_persists_trace():
- if os.environ.get("RUN_V54_AGENT_L3") != "1":
- pytest.skip("set RUN_V54_AGENT_L3=1 for the V54 Agent acceptance")
- engine = create_engine(DATABASE_URL, pool_pre_ping=True)
- correlation_id = new_governance_uid()
- dataflow_uid = new_governance_uid()
- source_uid = new_governance_uid()
- identity = AgentIdentity(
- subject="v54-model-offline",
- roles=frozenset({"scheduler"}),
- business_domains=frozenset({"sales"}),
- environments=frozenset({"test"}),
- correlation_id=correlation_id,
- )
- planner = SchedulingPlanner(
- model=OfflineModel(),
- context_tools=ContextTools(),
- scheduling_tools=ForbiddenSchedulingTools(),
- canary_verifier=ForbiddenVerifier(),
- audit=PostgresAuditSink(engine),
- model_timeout_seconds=1,
- )
- try:
- result = planner.run(
- identity,
- {
- "business_goal": "Keep the published schedule stable",
- "dataflow_uid": dataflow_uid,
- "business_domain": "sales",
- "environment": "test",
- "available_window": {
- "start": "2026-07-20T06:00:00+08:00",
- "end": "2026-07-20T08:00:00+08:00",
- },
- "authorized_resources": [source_uid],
- "canary_inputs": {},
- },
- )
- assert result == {
- "status": "degraded",
- "mode": "fixed_schedule",
- "reason_code": "model_unavailable",
- "action": "continue_published_schedule",
- "formal_engine_changed": False,
- "correlation_id": correlation_id,
- }
- with engine.connect() as connection:
- row = (
- connection.execute(
- text(
- "SELECT actor_subject, model_provider, model_name, "
- "prompt_version, schema_version, decision, decision_detail "
- "FROM public.workflow_plan_audits "
- "WHERE correlation_id = CAST(:id AS uuid) "
- "AND action = 'ai_planning_closed_loop'"
- ),
- {"id": correlation_id},
- )
- .mappings()
- .one()
- )
- assert row["actor_subject"] == "v54-model-offline"
- assert row["model_provider"] == "deepseek"
- assert row["schema_version"] == "v54"
- assert row["decision"] == "failed"
- assert row["decision_detail"]["reason_code"] == "model_unavailable"
- assert "provider is unavailable" not in str(row["decision_detail"])
- finally:
- with engine.begin() as connection:
- connection.execute(
- text(
- "DELETE FROM public.workflow_plan_audits "
- "WHERE correlation_id = CAST(:id AS uuid)"
- ),
- {"id": correlation_id},
- )
- engine.dispose()
|