#!/usr/bin/env python3 """Validate granular VISION tool grant candidate manifest.""" from __future__ import annotations import json from pathlib import Path ROOT = Path(__file__).resolve().parents[1] CURRENT_TOOLS = [ "vision.image_analyze", "vision.image_generate", "vision.palette_extract", "vision.background_cutout", ] PLANNED_TOOLS = [ "vision.ocr_read", "vision.screenshot_observe", "vision.browser_observe", "vision.document_layout_read", "vision.chart_read", "vision.table_read", "vision.diagram_read", "vision.object_detect", "vision.visual_ground", "vision.segment", "vision.video_read", "vision.image_edit", ] def main() -> int: errors: list[str] = [] path = ROOT / "candidate-manifests/vision-tool-grants.json" manifest = _read_json(path, errors) if manifest: _expect(manifest.get("canonical_sense") == "VISION", "canonical_sense_not_vision", errors) _expect(manifest.get("wildcard_grant_allowed") is False, "wildcard_grant_allowed", errors) _expect( manifest.get("package_default_grants_all_tools") is False, "package_default_grants_all_tools", errors, ) current = manifest.get("current_tool_candidates", []) current_tool_ids = [item.get("tool_id") for item in current] _expect(current_tool_ids == CURRENT_TOOLS, "current_tool_ids_mismatch", errors) _expect(manifest.get("planned_tool_candidates") == PLANNED_TOOLS, "planned_tools_mismatch", errors) for item in current: if item.get("grant_default") is not False: errors.append(f"grant_default_enabled:{item.get('tool_id')}") disclosures = manifest.get("required_disclosures", {}) for field in ( "producing_package_id", "producing_tool_id", "capability_surface", "provider_mode", "retention_disclosure", "validation_status", ): if disclosures.get(field) is not True: errors.append(f"required_disclosure_missing:{field}") forbidden = set(manifest.get("forbidden_effects", [])) for effect in ( "research_synthesis", "textual_web_search", "textual_page_fetch", "deep_research_workflow", "wildcard_tool_exposure", ): if effect not in forbidden: errors.append(f"forbidden_effect_missing:{effect}") result = { "ok": not errors, "validator": "vision-tool-grants-v1", "checked": ["candidate-manifests/vision-tool-grants.json"], "errors": errors, "warnings": [], } print(json.dumps(result, indent=2, sort_keys=True)) return 0 if result["ok"] else 1 def _read_json(path: Path, errors: list[str]) -> dict | None: if not path.exists(): errors.append(f"missing:{path.relative_to(ROOT)}") return None try: return json.loads(path.read_text(encoding="utf-8")) except json.JSONDecodeError as exc: errors.append(f"{path.relative_to(ROOT)}:json:{exc}") return None def _expect(condition: bool, error: str, errors: list[str]) -> None: if not condition: errors.append(error) if __name__ == "__main__": raise SystemExit(main())