agenticdome-python-sdk 1.2.39__tar.gz → 1.2.41__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.
Files changed (100) hide show
  1. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/PKG-INFO +1 -1
  2. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_python_sdk.egg-info/PKG-INFO +1 -1
  3. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_python_sdk.egg-info/SOURCES.txt +2 -0
  4. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/catalog_snapshot.json +3 -3
  5. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/connect.py +2 -2
  6. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/guided_integration.py +3 -2
  7. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/onboarding_cli.py +98 -16
  8. agenticdome_python_sdk-1.2.41/agenticdome_sdk/onboarding_observations.py +74 -0
  9. agenticdome_python_sdk-1.2.41/agenticdome_sdk/report_scope.py +58 -0
  10. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/customer-onboarding.md +27 -7
  11. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/pyproject.toml +1 -1
  12. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/CONTRIBUTING.md +0 -0
  13. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/LICENSE +0 -0
  14. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/MANIFEST.in +0 -0
  15. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/NOTICE +0 -0
  16. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/README.md +0 -0
  17. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/SECURITY.md +0 -0
  18. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_python_sdk.egg-info/dependency_links.txt +0 -0
  19. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_python_sdk.egg-info/entry_points.txt +0 -0
  20. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_python_sdk.egg-info/requires.txt +0 -0
  21. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_python_sdk.egg-info/top_level.txt +0 -0
  22. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/__init__.py +0 -0
  23. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/_framework_firewall.py +0 -0
  24. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/_mode.py +0 -0
  25. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/action_path_proof.py +0 -0
  26. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/agno.py +0 -0
  27. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/attestation.py +0 -0
  28. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/autogen.py +0 -0
  29. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/aws_bedrock.py +0 -0
  30. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/claude.py +0 -0
  31. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/client.py +0 -0
  32. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/copilot_ir.py +0 -0
  33. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/copilot_ir_collector.cjs +0 -0
  34. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/crewai.py +0 -0
  35. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/demo.py +0 -0
  36. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/existing_integration.py +0 -0
  37. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/framework_edits.py +0 -0
  38. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/generic_python.py +0 -0
  39. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/google_adk.py +0 -0
  40. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/hook_catalog.py +0 -0
  41. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/identity.py +0 -0
  42. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/langgraph.py +0 -0
  43. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/lifecycle.py +0 -0
  44. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/llamaindex.py +0 -0
  45. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/mcp_host.py +0 -0
  46. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/mcp_http_gateway.py +0 -0
  47. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/mcp_rehearsal_server.py +0 -0
  48. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/mcp_verification.py +0 -0
  49. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/microsoft_agent_framework.py +0 -0
  50. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/microsoft_ai_foundry.py +0 -0
  51. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/openai_agents.py +0 -0
  52. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/outcomes.py +0 -0
  53. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/proof.py +0 -0
  54. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/pydantic.py +0 -0
  55. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/simulation.py +0 -0
  56. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/agenticdome_sdk/smolagents.py +0 -0
  57. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/README.md +0 -0
  58. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/agno.md +0 -0
  59. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/autogen.md +0 -0
  60. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/aws-bedrock.md +0 -0
  61. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/claude-agent-sdk.md +0 -0
  62. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/crewai.md +0 -0
  63. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/custom-python.md +0 -0
  64. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/google-adk.md +0 -0
  65. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/langgraph.md +0 -0
  66. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/llamaindex.md +0 -0
  67. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/microsoft-agent-framework.md +0 -0
  68. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/microsoft-ai-foundry.md +0 -0
  69. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/openai-agents.md +0 -0
  70. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/pydanticai.md +0 -0
  71. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/frameworks/smolagents.md +0 -0
  72. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/mcp-integration.md +0 -0
  73. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/performance-evidence.md +0 -0
  74. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/docs/runtime-deployment.md +0 -0
  75. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/PRODUCTION_INTEGRATION.md +0 -0
  76. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/README.md +0 -0
  77. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/attack_demo.py +0 -0
  78. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/crewai_agenticdome_firewall.py +0 -0
  79. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/README.md +0 -0
  80. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/_shared.py +0 -0
  81. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/agno.py +0 -0
  82. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/autogen.py +0 -0
  83. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/aws_bedrock.py +0 -0
  84. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/claude_agent_sdk.py +0 -0
  85. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/crewai.py +0 -0
  86. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/custom_python.py +0 -0
  87. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/google_adk.py +0 -0
  88. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/langgraph.py +0 -0
  89. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/llamaindex.py +0 -0
  90. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/mcp.py +0 -0
  91. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/microsoft_agent_framework.py +0 -0
  92. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/microsoft_ai_foundry.py +0 -0
  93. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/openai_agents.py +0 -0
  94. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/pydanticai.py +0 -0
  95. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/frameworks/smolagents.py +0 -0
  96. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/langgraph_agenticdome_firewall.py +0 -0
  97. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/local_simulation_gallery.py +0 -0
  98. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/examples/mcp_gateway_action_firewall.py +0 -0
  99. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/setup.cfg +0 -0
  100. {agenticdome_python_sdk-1.2.39 → agenticdome_python_sdk-1.2.41}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agenticdome-python-sdk
3
- Version: 1.2.39
3
+ Version: 1.2.41
4
4
  Summary: Official Python SDK for AgenticDome security guardrails, DLP, tool authorization, and multi-agent delegation enforcement.
5
5
  Author: AgenticDome
6
6
  License-Expression: Apache-2.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agenticdome-python-sdk
3
- Version: 1.2.39
3
+ Version: 1.2.41
4
4
  Summary: Official Python SDK for AgenticDome security guardrails, DLP, tool authorization, and multi-agent delegation enforcement.
5
5
  Author: AgenticDome
6
6
  License-Expression: Apache-2.0
@@ -45,10 +45,12 @@ agenticdome_sdk/mcp_verification.py
45
45
  agenticdome_sdk/microsoft_agent_framework.py
46
46
  agenticdome_sdk/microsoft_ai_foundry.py
47
47
  agenticdome_sdk/onboarding_cli.py
48
+ agenticdome_sdk/onboarding_observations.py
48
49
  agenticdome_sdk/openai_agents.py
49
50
  agenticdome_sdk/outcomes.py
50
51
  agenticdome_sdk/proof.py
51
52
  agenticdome_sdk/pydantic.py
53
+ agenticdome_sdk/report_scope.py
52
54
  agenticdome_sdk/simulation.py
53
55
  agenticdome_sdk/smolagents.py
54
56
  docs/customer-onboarding.md
@@ -2,12 +2,12 @@
2
2
  "schema": "agenticdome.catalog-snapshot.v1",
3
3
  "catalog_schema": "agenticdome.hook-catalog.v1",
4
4
  "verified_at": "2026-10-02",
5
- "python_sdk_version": "1.2.39",
5
+ "python_sdk_version": "1.2.41",
6
6
  "published_packages": {
7
7
  "agenticdome-python-sdk": {
8
8
  "registry": "pypi",
9
- "version": "1.2.39",
10
- "url": "https://pypi.org/project/agenticdome-python-sdk/1.2.39/"
9
+ "version": "1.2.41",
10
+ "url": "https://pypi.org/project/agenticdome-python-sdk/1.2.41/"
11
11
  },
12
12
  "agenticdome-sdk": {
13
13
  "registry": "npm",
@@ -253,9 +253,9 @@ def run_connect(root: Path, args: Any) -> Dict[str, Any]:
253
253
  broker_setup["sdk_mode"] = effective_config.get("execution_broker_mode", "existing_sdk_or_environment_default")
254
254
  cross_part_review_required = semantic.get("workload_coverage", {}).get("cross_part_flow_proven") is False
255
255
  next_action = (
256
- "Review the generated pull request and run agenticdome verify. Then review cross-part call paths and workload-specific tests in the portal before activation."
256
+ "Review the generated pull request and run agenticdome verify. Cross-part limitations will be recorded as optional observations in .agenticdome/DISCLAIMER.md; no acknowledgement is required solely for them."
257
257
  if args.open_pr else
258
- "Review the generated patch, apply it on a branch, and run agenticdome verify. Then review cross-part call paths and workload-specific tests in the portal before activation."
258
+ "Review the generated patch, apply it on a branch, and run agenticdome verify. Cross-part limitations will be recorded as optional observations in .agenticdome/DISCLAIMER.md; no acknowledgement is required solely for them."
259
259
  ) if cross_part_review_required else (
260
260
  "Review the generated pull request and run agenticdome verify."
261
261
  if args.open_pr else "Review the generated patch, apply it on a branch, then run agenticdome verify."
@@ -490,9 +490,10 @@ def preview(root: Path, plan: Optional[Dict[str, Any]] = None, *, target: str =
490
490
  + ", A2A " + str(existing.get("a2a_call_candidates", 0))
491
491
  + ", MCP " + str(existing_surfaces.get("mcp", 0))
492
492
  + " (categories may overlap; no customer action was exercised)",
493
- "- Action-required semantic findings: " + str(semantic_gate.get("action_required", "not assessed")),
494
- "- Review-required semantic findings: " + str(semantic_gate.get("review_required", "not assessed")),
493
+ "- Raw semantic action candidates (lower severity may be optional): " + str(semantic_gate.get("action_required", "not assessed")),
494
+ "- Optional review observations: " + str(semantic_gate.get("review_required", "not assessed")),
495
495
  "",
496
+ "Optional observations are written to .agenticdome/DISCLAIMER.md on verification; high-severity and required protection/test failures remain blocking.", "",
496
497
  "## Framework hooks to attach or verify", "",
497
498
  ]
498
499
  for recommendation in plan.get("hook_recommendations", []):
@@ -1645,6 +1645,17 @@ def integration_plan(root: Path) -> Dict[str, Any]:
1645
1645
  hook["required_actions"].append("No candidate use of " + hook["recommended_attachment"]["method"] + " was observed in this selected source; attach it at the real execution path or document the external integration.")
1646
1646
  semantic_bypasses = semantic.get("bypass_risks", []) if isinstance(semantic, dict) else []
1647
1647
  semantic_reviews = semantic.get("review_findings", []) if isinstance(semantic, dict) else []
1648
+ from .onboarding_observations import POLICY as observations_policy
1649
+ workload_coverage = semantic.get("workload_coverage", {})
1650
+ assessment_complete = (
1651
+ workload_coverage.get("complete", True) is True
1652
+ and all(item.get("severity") in {"high", "medium", "low"} for item in semantic_bypasses)
1653
+ and workload_coverage.get("portal_display_capped") is not True
1654
+ and not any(item in {"attachment_points", "bypass_risks", "review_findings"}
1655
+ for item in workload_coverage.get("result_lists_at_cap", []))
1656
+ and (not workload_coverage.get("selected_parts")
1657
+ or workload_coverage.get("selected_parts") == workload_coverage.get("analyzed_parts"))
1658
+ )
1648
1659
  return {
1649
1660
  "schema": "agenticdome.integration-plan.v1",
1650
1661
  "inspection_report_sha256": _exportable_inspection(report).get("report_sha256"),
@@ -1684,10 +1695,12 @@ def integration_plan(root: Path) -> Dict[str, Any]:
1684
1695
  "unresolved_bypasses": len(semantic_bypasses),
1685
1696
  "high_severity_bypasses": sum(1 for item in semantic_bypasses if item.get("severity") == "high"),
1686
1697
  "review_required": len(semantic_reviews),
1687
- "production_ready": not semantic_bypasses and not semantic_reviews and semantic.get("confidence") in {"high", "partial"}
1688
- and semantic.get("workload_coverage", {}).get("cross_part_flow_proven", True)
1689
- and not any(item in {"attachment_points", "bypass_risks", "review_findings"}
1690
- for item in semantic.get("workload_coverage", {}).get("result_lists_at_cap", [])),
1698
+ "review_policy": "advisory",
1699
+ "assessment_complete": assessment_complete,
1700
+ "onboarding_policy": observations_policy,
1701
+ "production_ready": not any(item.get("severity") == "high" for item in semantic_bypasses)
1702
+ and semantic.get("confidence") in {"high", "partial"}
1703
+ and assessment_complete,
1691
1704
  "cross_workload_review_required": semantic.get("workload_coverage", {}).get("cross_part_flow_proven") is False,
1692
1705
  "cross_part_edges_observed": int(semantic.get("workload_coverage", {}).get("cross_part_edges", {}).get("observed_count", 0)),
1693
1706
  },
@@ -2498,6 +2511,7 @@ def verify_project(root: Path, live: bool = False, run_tests: bool = False,
2498
2511
  *, plan: Optional[Dict[str, Any]] = None) -> Tuple[int, Dict[str, Any]]:
2499
2512
  from .client import AgenticDomeClient
2500
2513
  from .action_path_proof import load_action_path_proof
2514
+ from .onboarding_observations import POLICY as observations_policy, observations_summary
2501
2515
 
2502
2516
  plan = plan or integration_plan(root)
2503
2517
  config_path = _agenticdome_dir(root) / "config.json"
@@ -2548,10 +2562,18 @@ def verify_project(root: Path, live: bool = False, run_tests: bool = False,
2548
2562
  }
2549
2563
  semantic_gate = plan.get("semantic_gate", {})
2550
2564
  cross_part_review_required = bool(semantic_gate.get("cross_workload_review_required"))
2565
+ observations = observations_summary(semantic_gate)
2566
+ bypass_rows = plan.get("semantic_analysis", {}).get("bypass_risks", [])
2567
+ if not isinstance(bypass_rows, list) or any(
2568
+ not isinstance(row, dict) or row.get("severity") not in {"high", "medium", "low"}
2569
+ for row in bypass_rows
2570
+ ):
2571
+ observations["classification_complete"] = False
2551
2572
  semantic_ready = (
2552
2573
  semantic_gate.get("confidence") in {"high", "partial"}
2553
- and int(semantic_gate.get("unresolved_bypasses", 0)) == 0
2554
- and int(semantic_gate.get("review_required", 0)) == 0
2574
+ and observations["classification_complete"]
2575
+ and int(semantic_gate.get("high_severity_bypasses", 0)) == 0
2576
+ and semantic_gate.get("assessment_complete", True) is True
2555
2577
  )
2556
2578
  result = {
2557
2579
  "schema": "agenticdome.verification-result.v1",
@@ -2559,6 +2581,8 @@ def verify_project(root: Path, live: bool = False, run_tests: bool = False,
2559
2581
  "mode": "live_sidecar_fixed_payload" if live else "local_sim_fixed_payload",
2560
2582
  "source_upload": False,
2561
2583
  "framework_runtime_instantiated": False,
2584
+ "onboarding_policy": observations_policy,
2585
+ "onboarding_observations": observations,
2562
2586
  "decision_cases": outcomes,
2563
2587
  "static_coverage": plan["coverage"],
2564
2588
  "semantic_gate": {
@@ -2569,10 +2593,13 @@ def verify_project(root: Path, live: bool = False, run_tests: bool = False,
2569
2593
  "unresolved_bypasses": int(semantic_gate.get("unresolved_bypasses", 0)),
2570
2594
  "high_severity_bypasses": int(semantic_gate.get("high_severity_bypasses", 0)),
2571
2595
  "review_required": int(semantic_gate.get("review_required", 0)),
2596
+ "review_policy": "advisory",
2597
+ "review_owner": "coding_assistant_or_agenticdome",
2598
+ "assessment_complete": semantic_gate.get("assessment_complete", True) is True,
2572
2599
  "passed": semantic_ready,
2573
2600
  "cross_part_review_required": cross_part_review_required,
2574
2601
  "cross_part_edges_observed": int(semantic_gate.get("cross_part_edges_observed", 0)),
2575
- "production_ready": semantic_ready and not cross_part_review_required,
2602
+ "production_ready": semantic_ready,
2576
2603
  },
2577
2604
  "application_tests": application_tests,
2578
2605
  "action_path_proof": load_action_path_proof(root),
@@ -2580,17 +2607,39 @@ def verify_project(root: Path, live: bool = False, run_tests: bool = False,
2580
2607
  and not plan["coverage"]["gaps"]
2581
2608
  and (not run_tests or semantic_ready)
2582
2609
  and (not run_tests or application_tests["passed"] is True),
2583
- "clarification": "Decision cases use fixed payloads. ready=true means local checks passed, not production approval. Split analyses also require a tenant-admin review of cross-part paths, workload-specific integration tests and live runtime evidence; dynamic paths remain outside static proof.",
2610
+ "clarification": "ready=true means required local checks passed, not production activation. Lower-severity static candidates, reviews and cross-part limitations are optional observations in .agenticdome/DISCLAIMER.md. High-severity findings, incomplete source, missing protection, failing tests and runtime proof failures remain blocking. Fixed decision cases do not execute customer actions.",
2584
2611
  }
2585
2612
  canonical = json.dumps(result, sort_keys=True, separators=(",", ":")).encode("utf-8")
2586
2613
  result["report_sha256"] = hashlib.sha256(canonical).hexdigest()
2614
+ _write_onboarding_disclaimer(root, plan, result)
2587
2615
  return (0 if result["ready"] else 2), result
2588
2616
 
2589
2617
 
2618
+ def _write_onboarding_disclaimer(root: Path, plan: Dict[str, Any], verification: Dict[str, Any],
2619
+ *, evidence_status: str = "Current local verification") -> None:
2620
+ from .onboarding_observations import FILE, disclaimer_markdown
2621
+ target = root / FILE
2622
+ if target.is_symlink() or not target.resolve().is_relative_to(root.resolve()):
2623
+ raise SystemExit("The disclaimer output is a symlink or leaves this workload; use a regular local output path.")
2624
+ # Reject symlinked ancestors even when they happen to point inside the root.
2625
+ if any(parent.is_symlink() for parent in target.parents if parent != root and root in parent.parents):
2626
+ raise SystemExit("The disclaimer output directory is a symlink; use a regular local output path.")
2627
+ _write_local_text(target, disclaimer_markdown(plan, verification, evidence_status=evidence_status))
2628
+
2629
+
2590
2630
  def _reconciliation_markdown(plan: Dict[str, Any], verification: Dict[str, Any], report_digest: str) -> str:
2591
2631
  """Give a bounded, source-free worklist without accepting AI claims as proof."""
2592
2632
  semantic = plan.get("semantic_analysis") if isinstance(plan.get("semantic_analysis"), dict) else {}
2593
2633
  gate = verification.get("semantic_gate") if isinstance(verification.get("semantic_gate"), dict) else {}
2634
+ from .onboarding_observations import POLICY as observations_policy
2635
+ bypass_rows = semantic.get("bypass_risks", [])
2636
+ known_severities = isinstance(bypass_rows, list) and all(
2637
+ isinstance(row, dict) and row.get("severity") in {"high", "medium", "low"}
2638
+ for row in bypass_rows
2639
+ )
2640
+ optional_policy = (verification.get("onboarding_policy") == observations_policy
2641
+ and verification.get("onboarding_observations", {}).get("classification_complete") is True
2642
+ and known_severities)
2594
2643
 
2595
2644
  def groups(field: str) -> List[Tuple[str, str, int, List[int]]]:
2596
2645
  grouped: Dict[Tuple[str, str], List[int]] = {}
@@ -2598,6 +2647,8 @@ def _reconciliation_markdown(plan: Dict[str, Any], verification: Dict[str, Any],
2598
2647
  for item in rows[:100]:
2599
2648
  if not isinstance(item, dict):
2600
2649
  continue
2650
+ if optional_policy and field == "bypass_risks" and item.get("severity") != "high":
2651
+ continue
2601
2652
  boundary = str(item.get("boundary") or "unknown")
2602
2653
  if boundary not in {"prompt_ingress", "tool_execution", "output_egress"}:
2603
2654
  boundary = "unknown"
@@ -2627,11 +2678,16 @@ def _reconciliation_markdown(plan: Dict[str, Any], verification: Dict[str, Any],
2627
2678
  "This is a local, source-free worklist for the current validation run. It is not a bypass waiver, a code patch, or live tenant proof.",
2628
2679
  "The AI-authored AgenticDome_Integration.md remains an assertion until these checks and real-path tests pass.", "",
2629
2680
  f"- AI report SHA-256: `{report_digest}`",
2630
- f"- Action-required candidates: {int(gate.get('unresolved_bypasses', 0))}",
2631
- f"- Review-required internal or indirect paths: {int(gate.get('review_required', 0))}",
2681
+ f"- Blocking findings: {int(gate.get('high_severity_bypasses' if optional_policy else 'unresolved_bypasses', 0))}",
2682
+ f"- Advisory internal or indirect paths: {int(gate.get('review_required', 0))} (owner: coding assistant or AgenticDome; not a local readiness blocker)",
2632
2683
  f"- Semantic confidence: {gate.get('confidence', 'unavailable')}", "",
2684
+ "## Who does what", "",
2685
+ "The coding assistant traces grouped code candidates and runs real-path tests. The customer reviews the change summary, intended routes and deployment location—not scanner line numbers.",
2686
+ "Lower-severity candidates and review notes are optional tenant observations in .agenticdome/DISCLAIMER.md. They do not require an acknowledgement or AgenticDome clearance before onboarding continues." if optional_policy else "If an action-required candidate is already protected in a real-path test, supply a minimal reproduction to AgenticDome. Stop unchanged retries; do not add duplicate guards or waive the finding.",
2687
+ "Pending deployment settings and live proof belong to the service operator and are separate from optional observations.", "",
2633
2688
  ]
2634
- for field, title in (("bypass_risks", "Action required"), ("review_findings", "Trace and classify")):
2689
+ sections = (("bypass_risks", "Action required"),) if optional_policy else (("bypass_risks", "Action required"), ("review_findings", "Trace and classify"))
2690
+ for field, title in sections:
2635
2691
  lines.extend([f"## {title}", ""])
2636
2692
  found = groups(field)
2637
2693
  if not found:
@@ -2652,10 +2708,14 @@ def _reconciliation_markdown(plan: Dict[str, Any], verification: Dict[str, Any],
2652
2708
  lines.append("- The AI report itself says a relevant path was NOT ASSESSED or unprotected. Inspect and protect that path, then update the report; its zero-count rows cannot clear this scope gap.")
2653
2709
  if plan.get("coverage", {}).get("gaps"):
2654
2710
  lines.append("- Required boundary categories are missing from the inspected workload. Attach and test them before retrying.")
2655
- if gate.get("cross_part_review_required"):
2711
+ if gate.get("assessment_complete") is False or not known_severities:
2712
+ lines.append("- Source assessment or severity classification is incomplete. The coding assistant must resolve that required check; unclassified candidates are not optional observations.")
2713
+ if gate.get("cross_part_review_required") and not optional_policy:
2656
2714
  lines.append("- Analysis was split across parts; trace cross-part calls and alternate entry paths. Separate parts are not a proof of guard dominance.")
2657
2715
  if tests.get("passed") is not True:
2658
2716
  lines.append("- Workload tests did not pass or were not detected. Run the local test command directly to see its output; no test log is uploaded.")
2717
+ if report_scope.get("activation_pending"):
2718
+ lines.append("- Local source assessment and operator activation are separate. Complete the report's exact runtime handoff and safe staging proof before production activation.")
2659
2719
  lines.extend([
2660
2720
  "- Give these grouped paths to your coding assistant together with the real source. Keep the assistant's changes reviewable and update only the canonical AgenticDome_Integration.md.",
2661
2721
  "- Rerun `agenticdome validate-report --report AgenticDome_Integration.md` after code and test changes. Do not edit the JSON evidence by hand.",
@@ -2688,7 +2748,19 @@ def validate_ai_integration_report(root: Path, report_path: Path) -> Tuple[int,
2688
2748
  scope = (quoted.group(1) if quoted else scope_match.group(1).split()[0]).strip().rstrip("/")
2689
2749
  if Path(scope).name.casefold() != root.name.casefold() or ".." in Path(scope).parts:
2690
2750
  raise SystemExit("The report's Workload scope does not match this workload root. Run from the correct deployable service.")
2691
- rows = re.findall(r"^\|\s*([1-8])\.([^\r\n]*)", markdown, re.MULTILINE)
2751
+ # Numbered operator steps are not interception categories. Older reports
2752
+ # without a table heading remain readable, with the original strict counts.
2753
+ inventory_lines = []
2754
+ has_header = bool(re.search(r"^\s*\|\s*Category\s*\|", markdown, re.MULTILINE))
2755
+ in_inventory = not has_header
2756
+ for line in markdown.splitlines():
2757
+ if has_header and not line.lstrip().startswith("|"):
2758
+ in_inventory = False
2759
+ if re.match(r"^\s*\|\s*Category\s*\|", line):
2760
+ in_inventory = True
2761
+ if in_inventory:
2762
+ inventory_lines.append(line)
2763
+ rows = re.findall(r"^\s*\|\s*\*?\*?([1-8])\.([^\r\n]*)", "\n".join(inventory_lines), re.MULTILINE)
2692
2764
  if len(rows) != 8 or {number for number, _ in rows} != {str(index) for index in range(1, 9)}:
2693
2765
  raise SystemExit("The integration report needs one valid row for each of the eight interception categories.")
2694
2766
  reported_unprotected = 0
@@ -2700,7 +2772,9 @@ def validate_ai_integration_report(root: Path, report_path: Path) -> Tuple[int,
2700
2772
  if any(value > 10000 for value in (found, existing, new, unprotected, live)) or existing + new + unprotected != found or live > existing + new:
2701
2773
  raise SystemExit("The report counts do not reconcile. Correct the AI integration inventory before validation.")
2702
2774
  reported_unprotected += unprotected
2703
- scope_incomplete = bool(re.search(r"\bNOT ASSESSED\b", markdown, re.IGNORECASE))
2775
+ from .report_scope import assessment_scope
2776
+ report_scope = assessment_scope(markdown)
2777
+ scope_incomplete = report_scope["scope_incomplete"]
2704
2778
  digest = hashlib.sha256(markdown.encode("utf-8")).hexdigest()
2705
2779
 
2706
2780
  inspection = _exportable_inspection(inspect_repository(root))
@@ -2719,6 +2793,7 @@ def validate_ai_integration_report(root: Path, report_path: Path) -> Tuple[int,
2719
2793
  local_checks_passed = exit_code == 0 and verification.get("ready") is True
2720
2794
  verification["ai_report_scope"] = {
2721
2795
  "scope_incomplete": scope_incomplete,
2796
+ "activation_pending": report_scope["activation_pending"],
2722
2797
  "reported_unprotected": reported_unprotected,
2723
2798
  }
2724
2799
  if scope_incomplete or reported_unprotected:
@@ -2739,18 +2814,25 @@ def validate_ai_integration_report(root: Path, report_path: Path) -> Tuple[int,
2739
2814
  _write_json(inspection_path, inspection)
2740
2815
  _write_json(verification_path, verification)
2741
2816
  _write_local_text(reconciliation_path, _reconciliation_markdown(plan, verification, digest))
2817
+ _write_onboarding_disclaimer(root, plan, verification)
2818
+ has_observations = int(verification.get("onboarding_observations", {}).get("total_count", 0)) > 0
2742
2819
  partial_coverage = local_checks_passed and not verification["ready"]
2743
2820
  return exit_code, {
2744
- "status": "validation_passed" if verification["ready"] else (
2821
+ "status": ("validation_passed_with_observations" if has_observations else "validation_passed") if verification["ready"] else (
2745
2822
  "partial_coverage" if partial_coverage else "validation_needs_attention"
2746
2823
  ),
2747
2824
  "inspection": str(inspection_path.relative_to(root)),
2748
2825
  "verification": str(verification_path.relative_to(root)),
2749
2826
  "reconciliation": str(reconciliation_path.relative_to(root)),
2827
+ "disclaimer": ".agenticdome/DISCLAIMER.md",
2828
+ "optional_observations": int(verification.get("onboarding_observations", {}).get("total_count", 0)),
2750
2829
  "ai_integration_report_sha256": digest,
2751
2830
  "ready": verification["ready"],
2831
+ "local_status": ("passed_with_observations" if has_observations else "passed") if verification["ready"] else "needs_code_or_test_fix",
2832
+ "activation_status": "pending_operator_checks",
2833
+ "review_owner": "coding_assistant_or_agenticdome",
2752
2834
  "next_action": (
2753
- "Import both JSON files in Onboarding; then run the assigned-runtime check and test a real action path. No customer action executes in these fixed decision cases."
2835
+ "Import both JSON files and continue tenant verification. Optional observations are in .agenticdome/DISCLAIMER.md; investigating them is the tenant's choice. Prove a safe real action before production activation."
2754
2836
  if verification["ready"] else (
2755
2837
  "Import both JSON files as partial evidence and run a tenant-policy diagnostic if connected. "
2756
2838
  "Open .agenticdome/RECONCILIATION.md, assess or protect the remaining paths, then rerun validate-report. "
@@ -0,0 +1,74 @@
1
+ """Optional static observations, separate from runtime enforcement and proof."""
2
+
3
+ import re
4
+ from pathlib import Path
5
+
6
+
7
+ POLICY = "pass_with_observations_v1"
8
+ SCHEMA = "agenticdome.onboarding-observations.v1"
9
+ FILE = ".agenticdome/DISCLAIMER.md"
10
+
11
+
12
+ def observations_summary(gate):
13
+ names = ("action_required", "unresolved_bypasses", "review_required", "high_severity_bypasses")
14
+ values = {name: gate.get(name, 0) for name in names}
15
+ valid = "high_severity_bypasses" in gate and all(
16
+ isinstance(value, int) and not isinstance(value, bool) and 0 <= value <= 10000
17
+ for value in values.values()
18
+ )
19
+ counts = {name: value if isinstance(value, int) and not isinstance(value, bool) and 0 <= value <= 10000 else 0
20
+ for name, value in values.items()}
21
+ actions = max(counts["action_required"], counts["unresolved_bypasses"])
22
+ high = counts["high_severity_bypasses"]
23
+ valid = valid and high <= actions
24
+ candidates = max(0, actions - high)
25
+ cross_part = bool(gate.get("cross_part_review_required") or gate.get("cross_workload_review_required"))
26
+ return {
27
+ "schema": SCHEMA, "policy": POLICY, "file": FILE,
28
+ "classification_complete": valid,
29
+ "candidate_count": candidates, "review_count": counts["review_required"],
30
+ "cross_part_note": cross_part,
31
+ "total_count": candidates + counts["review_required"] + int(cross_part),
32
+ }
33
+
34
+
35
+ def disclaimer_markdown(plan, verification, *, evidence_status="Current local verification"):
36
+ gate = verification.get("semantic_gate", {})
37
+ observations = verification.get("onboarding_observations") or observations_summary(gate)
38
+ semantic = plan.get("semantic_analysis", {})
39
+ lines = [
40
+ "# AgenticDome onboarding observations and disclaimer", "",
41
+ f"Evidence status: {evidence_status}", "",
42
+ "These observations are optional. The tenant may investigate or improve these paths later; no acknowledgement or AgenticDome clearance is required to continue onboarding solely because of these observations.",
43
+ "Passing local checks does not certify every execution branch or activate production. High-severity bypass findings, missing protection, uninspected source, failed tests and runtime/tenant proof failures remain blocking. Runtime BLOCKED decisions, unknown verdicts and policy failures still stop execution.", "",
44
+ "| Observation | Count | Tenant action |",
45
+ "|---|---:|---|",
46
+ f"| Lower-severity analyzer candidates | {observations['candidate_count'] if observations['classification_complete'] else 0} | Optional investigation |",
47
+ f"| Review-only paths | {observations['review_count']} | Optional investigation |",
48
+ f"| Cross-part flow not automatically proven | {int(observations['cross_part_note'])} | Optional additional path tests |", "",
49
+ "## Optional locations", "",
50
+ ]
51
+ if not observations["classification_complete"]:
52
+ lines.extend(["Severity classification is incomplete. Unclassified candidates remain in RECONCILIATION.md for the coding assistant to resolve; they are not optional observations.", ""])
53
+ for field in ("bypass_risks", "review_findings"):
54
+ rows = semantic.get(field, [])
55
+ if not isinstance(rows, list):
56
+ continue
57
+ for item in rows[:100]:
58
+ if not isinstance(item, dict) or (field == "bypass_risks" and (
59
+ not observations["classification_complete"] or item.get("severity") not in {"medium", "low"}
60
+ )):
61
+ continue
62
+ raw = str(item.get("path") or "")[:500].replace("\\", "/")
63
+ if not raw or raw.startswith("/") or ".." in Path(raw).parts:
64
+ location = "[invalid relative path]"
65
+ else:
66
+ location = re.sub(r"[^A-Za-z0-9_./ -]", "_", raw)
67
+ line = item.get("line", 1)
68
+ line = max(1, min(line, 10000000)) if isinstance(line, int) and not isinstance(line, bool) else 1
69
+ kind = "analyzer candidate" if field == "bypass_risks" else "review-only path"
70
+ lines.append(f"- `{location}:{line}` — {kind}; static metadata may not observe an existing shared or downstream guard.")
71
+ if observations["total_count"] == 0:
72
+ lines.append("No optional observations in this run.")
73
+ lines.extend(["", "This file is replaced in place on verification; it is a local note, not a protection certificate or an authorization to execute a business action.", ""])
74
+ return "\n".join(lines)
@@ -0,0 +1,58 @@
1
+ """Separate current source assessment from historical and operator handoff text.
2
+
3
+ Markdown remains an assertion; inspection, semantic bypass and test gates still
4
+ run independently. Unknown application read sites remain source gaps.
5
+ """
6
+ import re
7
+
8
+
9
+ OPERATOR_SECTIONS = {
10
+ "runtime configuration handoff", "must do steps to activate firewall",
11
+ "activation prerequisites", "production activation",
12
+ }
13
+ HISTORY_SECTIONS = {"preserved historical baseline and unique evidence", "historical evidence"}
14
+
15
+
16
+ def assessment_scope(markdown):
17
+ headings = []
18
+ source_incomplete = False
19
+ activation_pending = False
20
+ source_rows = 0
21
+ structured = False
22
+ for line in markdown.splitlines():
23
+ match = re.match(r"^\s*(#{1,6})\s+(.+?)\s*$", line)
24
+ if match:
25
+ level, title = len(match[1]), match[2].casefold()
26
+ headings = [(depth, name) for depth, name in headings if depth < level]
27
+ headings.append((level, title))
28
+ structured = structured or title == "source assessment scope"
29
+ continue
30
+ sections = {name for _, name in headings}
31
+ if sections & HISTORY_SECTIONS:
32
+ continue
33
+ cells = [cell.strip().strip("*`").strip() for cell in line.strip().strip("|").split("|")] if line.lstrip().startswith("|") else []
34
+ if "source assessment scope" in sections and cells:
35
+ if cells[0].casefold() == "runtime source paths":
36
+ source_rows += 1
37
+ source_incomplete |= len(cells) < 2 or cells[1].upper() != "ASSESSED" or bool(re.search(r"\bNOT ASSESSED\b", line, re.I))
38
+ continue
39
+ if cells[0].casefold() == "production activation":
40
+ activation_pending |= len(cells) < 2 or cells[1].upper() != "VERIFIED"
41
+ continue
42
+ # A missing code read site is a source defect, even in an operator table.
43
+ if cells and cells[0].startswith(("AGENTICDOME_", "AGENTIC_ORCHESTRATOR_")):
44
+ if len(cells) < 2 or re.search(r"NOT ASSESSED|Not found|Unknown", cells[1], re.I):
45
+ source_incomplete = True
46
+ not_assessed = bool(re.search(r"\bNOT ASSESSED\b", line, re.I))
47
+ operator_row = bool(cells and (
48
+ cells[0].startswith(("AGENTICDOME_", "AGENTIC_ORCHESTRATOR_"))
49
+ or (len(cells) == 4 and re.match(r"^[1-6]\.", cells[0]))
50
+ ))
51
+ if sections & OPERATOR_SECTIONS:
52
+ activation_pending |= (not_assessed and operator_row) or bool(re.search(r"REQUIRED BEFORE LIVE|LIVE VERIFICATION PENDING|\bPENDING\b", line, re.I))
53
+ # Arbitrary uninspected source prose cannot be hidden in handoff.
54
+ source_incomplete |= not_assessed and not operator_row
55
+ else:
56
+ source_incomplete |= not_assessed
57
+ source_incomplete |= structured and source_rows != 1
58
+ return {"scope_incomplete": bool(source_incomplete), "activation_pending": bool(activation_pending)}
@@ -69,11 +69,10 @@ agenticdome validate-report --report AgenticDome_Integration.md
69
69
 
70
70
  This does not edit the application. It checks current source-free structure,
71
71
  requests the tenant-bound semantic assessment and runs detected workload tests.
72
- The command also writes a local `.agenticdome/RECONCILIATION.md` worklist. If
73
- it exits non-zero or says `ready=false`, open that file: it groups possible
74
- bypasses and uncertain internal paths by source file, with the next check for
75
- each boundary. Review the actual source, fix or investigate those paths, rerun
76
- the workload tests and validation, and update the canonical AI report. The
72
+ The command replaces a local `.agenticdome/RECONCILIATION.md` worklist in place.
73
+ Give it to your coding assistant. The assistant owns code investigation, repairs
74
+ and tests; you review its short change summary, intended routes and deployment
75
+ location. You do not have to interpret scanner line numbers. High-severity findings, uninspected source, missing hooks and failing tests block local readiness. Lower-severity static candidates and review-only paths are optional tenant observations in `.agenticdome/DISCLAIMER.md`. They do not block onboarding or require an acknowledgement, scanner-count cleanup or AgenticDome clearance. The tenant may investigate these observations later if they wish; no manual source classification is required solely for them. A tested protected path still flagged at lower severity remains an optional observation; add no duplicate guard and do not repeat validation solely to clear it. High-severity findings still need a repair or verified path explanation. The
77
76
  worklist is not uploaded and cannot waive a finding. You may import both
78
77
  generated files, `agenticdome-inspection.json` and
79
78
  `.agenticdome/verification.json`, together in the same onboarding workload even
@@ -87,6 +86,28 @@ OpenClaw workloads use their specialist onboarding journeys rather than this
87
86
  application shortcut. The validation command cannot turn an AI report or a
88
87
  fixed synthetic decision into proof that real customer traffic is intercepted.
89
88
 
89
+ Record current source scope separately from operator activation:
90
+
91
+ ```markdown
92
+ ## Source assessment scope
93
+
94
+ | Scope | Status | Owner / evidence |
95
+ |---|---|---|
96
+ | Runtime source paths | ASSESSED | Assistant: real routes and tests reviewed |
97
+ | Production activation | PENDING | Service operator: exact runtime handoff |
98
+ ```
99
+
100
+ Use `NOT ASSESSED` for genuinely uninspected current source; it still blocks.
101
+ Known application read sites with pending running-process configuration checks
102
+ belong in `Runtime configuration handoff`; numbered operator steps belong in
103
+ `MUST Do Steps to Activate Firewall`. Their pending status is tracked separately
104
+ as `ai_report_scope.activation_pending`. An unknown code read site or uninspected
105
+ source prose cannot be hidden in an operator section. Retain old evidence under
106
+ `Preserved historical baseline and unique evidence`; do not append another full
107
+ report on each run. `ready=true` means required local checks passed; `onboarding_policy=pass_with_observations_v1` keeps raw finding counts and reports optional totals in `onboarding_observations`. Explicit valid high-severity classification is required; absent or malformed counts cannot silently pass. The portal recognizes this policy only in fresh bound evidence; legacy results keep their original strict readiness. The portal retains
108
+ pending deployment checks and tenant verification before activation; no source
109
+ report or SDK import proves that workers loaded the reviewed release.
110
+
90
111
  The local Integration Assistant collects source-free structure and prepares a
91
112
  reviewable local diff. Guided `integrate preview` obtains a signed, tenant-bound
92
113
  plan through the assigned sidecar; only source-free structural IR reaches the
@@ -132,8 +153,7 @@ parts sequentially through the assigned sidecar. Completed parts are cached
132
153
  locally and reused on retry, so a later failure does not restart the entire
133
154
  analysis. Each part receives tenant-bound private analysis; the SDK merges the
134
155
  results and inventories resolvable calls between parts. This does not prove
135
- cross-part guard coverage, and the portal requires a documented review of
136
- those paths and workload-specific tests before marking a split workload ready.
156
+ cross-part guard coverage. With pass_with_observations_v1, that limitation is an optional note in .agenticdome/DISCLAIMER.md and does not require a review form or acknowledgement. Legacy evidence retains its original cross-part review gate. Workload tests and real runtime checks remain required.
137
157
  Source text is not uploaded. A plan remains a static proposal, not proof that
138
158
  a customer action is intercepted. A single source file over 2 MB or a scope
139
159
  that exceeds the collection limits remains an explicit gap; do not exclude a
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "agenticdome-python-sdk"
7
- version = "1.2.39"
7
+ version = "1.2.41"
8
8
  description = "Official Python SDK for AgenticDome security guardrails, DLP, tool authorization, and multi-agent delegation enforcement."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"