From 52038b192cb4952f78358fbcbc028863f66345bc Mon Sep 17 00:00:00 2001 From: witbrock Date: Sun, 13 Sep 2026 19:17:54 -0400 Subject: [PATCH] Fix strict coding result schema while preserving retained results --- scripts/codex_von_worker.py | 5 +++-- scripts/codex_von_worker_prompt.md | 2 +- tests/backend/test_codex_von_worker.py | 26 ++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/scripts/codex_von_worker.py b/scripts/codex_von_worker.py index 232e8938..4cfe0777 100755 --- a/scripts/codex_von_worker.py +++ b/scripts/codex_von_worker.py @@ -44,7 +44,7 @@ "deploy_commit": {"type": "string"}, "blocker": retry_policy.BLOCKER_SCHEMA, }, - "required": ["status", "summary", "evidence", "question", "deploy_commit"], + "required": ["status", "summary", "evidence", "question", "deploy_commit", "blocker"], "additionalProperties": False, } @@ -442,7 +442,8 @@ def check_task(config, api, task_id): def validate_result(value): - fields = set(RESULT_SCHEMA["required"]) + # Strict output requires every property; retained old results may omit blocker. + fields = set(RESULT_SCHEMA["required"]) - {"blocker"} if not isinstance(value, dict) or set(value) - {"blocker"} not in ( fields, fields - {"deploy_commit"}, diff --git a/scripts/codex_von_worker_prompt.md b/scripts/codex_von_worker_prompt.md index 79199edd..69e0cc51 100644 --- a/scripts/codex_von_worker_prompt.md +++ b/scripts/codex_von_worker_prompt.md @@ -76,7 +76,7 @@ include `blocker`: key (stable dependency name), kind (dependency or transient), owner, recovery, scope_json (JSON object of relevant revision/profile/scope), required_observations_json (JSON object of exact observations that demonstrate repair), and probe_key (null unless an applicable operator probe is supplied). -Use null or omit blocker otherwise. Report observed facts, not an inferred ready +Use null for blocker otherwise. Report observed facts, not an inferred ready flag; authentication/profile prerequisites must include their actual observations. The controller adds the task/actor/organisation and failed-attempt binding. Do not classify code you can safely repair as a controller dependency. Continue diff --git a/tests/backend/test_codex_von_worker.py b/tests/backend/test_codex_von_worker.py index 3f2307bb..ea785d2d 100644 --- a/tests/backend/test_codex_von_worker.py +++ b/tests/backend/test_codex_von_worker.py @@ -18,6 +18,32 @@ spec.loader.exec_module(worker) +def test_result_schema_meets_strict_provider_contract_and_preserves_old_results(): + # The provider rejects an object before execution if any declared property + # is absent from required, even when the property's value permits null. + def check_objects(schema): + if "properties" in schema: + assert set(schema["required"]) == set(schema["properties"]) + assert schema["additionalProperties"] is False + for child in schema["properties"].values(): + check_objects(child) + + check_objects(worker.RESULT_SCHEMA) + legacy = { + "status": "completed", + "summary": "Done", + "evidence": "Verified", + "question": "", + "deploy_commit": "", + } + assert worker.validate_result(legacy) == legacy + current = dict(legacy, blocker=None) + assert worker.validate_result(current) == current + assert "null" in worker.RESULT_SCHEMA["properties"]["blocker"]["type"] + older = {key: value for key, value in legacy.items() if key != "deploy_commit"} + assert worker.validate_result(older) == older + + @pytest.fixture(autouse=True) def isolated_archive_boundary(monkeypatch): # Existing controller tests isolate publication; canonical archive capture