diff --git a/talent/daily_schedule.md b/talent/daily_schedule.md index b454f9fa9..55a388f7e 100644 --- a/talent/daily_schedule.md +++ b/talent/daily_schedule.md @@ -6,6 +6,7 @@ "schedule": "daily", "priority": 10, "output": "json", + "schema": "daily_schedule.schema.json", "hook": {"pre": "daily_schedule", "post": "daily_schedule"}, "color": "#455a64", "thinking_budget": 4096, diff --git a/talent/daily_schedule.schema.json b/talent/daily_schedule.schema.json new file mode 100644 index 000000000..2669d4e31 --- /dev/null +++ b/talent/daily_schedule.schema.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "additionalProperties": false, + "required": ["primary", "fallback"], + "properties": { + "primary": { + "type": "string", + "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$" + }, + "fallback": { + "type": "string", + "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$" + } + } +} diff --git a/tests/baselines/api/stats/stats.json b/tests/baselines/api/stats/stats.json index 23cdd1d3a..a700baf68 100644 --- a/tests/baselines/api/stats/stats.json +++ b/tests/baselines/api/stats/stats.json @@ -45,6 +45,7 @@ "path": "/talent/daily_schedule.md", "priority": 10, "schedule": "daily", + "schema": "daily_schedule.schema.json", "source": "system", "thinking_budget": 4096, "title": "Maintenance Window", diff --git a/tests/test_daily_schedule_schema.py b/tests/test_daily_schedule_schema.py new file mode 100644 index 000000000..6ce784111 --- /dev/null +++ b/tests/test_daily_schedule_schema.py @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright (c) 2026 sol pbc + +import json +from pathlib import Path + +from jsonschema import Draft202012Validator + +from think.talent import get_talent + +DAILY_SCHEDULE_SCHEMA_PATH = ( + Path(__file__).resolve().parents[1] / "talent" / "daily_schedule.schema.json" +) + + +def _load_daily_schedule_schema() -> dict: + return json.loads(DAILY_SCHEDULE_SCHEMA_PATH.read_text(encoding="utf-8")) + + +def test_daily_schedule_schema_file_is_valid_draft_2020_12(): + Draft202012Validator.check_schema(_load_daily_schedule_schema()) + + +def test_daily_schedule_loaded_json_schema_matches_on_disk_schema(): + assert get_talent("daily_schedule")["json_schema"] == _load_daily_schedule_schema() + + +def test_daily_schedule_pattern_accepts_and_rejects_expected_values(): + schema = _load_daily_schedule_schema() + validator = Draft202012Validator(schema) + + for value in ["00:00", "03:00", "09:00", "23:59"]: + assert validator.is_valid({"primary": value, "fallback": "00:00"}) + + for value in ["9:00", "03:00:00", "24:00", "03:60", "", "ab:cd"]: + assert not validator.is_valid({"primary": value, "fallback": "00:00"})