hyf

Context-aware query service for Radroots
git clone https://radroots.dev/git/hyf.git
Log | Files | Refs | README | LICENSE

commit 4b513e66d3b3e81e73b94b8262b89824f4c6acd4
parent ab73834876afd342327510849579bc572f6286d2
Author: triesap <tyson@radroots.org>
Date:   Thu, 24 Sep 2026 16:05:55 +0000

C004: verify escaped duplicate keys, drop dead helpers and correct semantic-case owners

Diffstat:
Mschemas/hyf_ops_v2/semantic-cases.json | 4+++-
Msrc/hyf_core/operation_context.mojo | 11-----------
Mtests/test_hyf.mojo | 28++++++++++++++++++++++++++++
3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/schemas/hyf_ops_v2/semantic-cases.json b/schemas/hyf_ops_v2/semantic-cases.json @@ -4,7 +4,9 @@ "revision": "hyf_ops_v2", "note": "Semantic obligations that JSON Schema alone cannot express. Each case is labelled with the enforcing owner and the C004 control that exercises it. No case is claimed enforced by a regex or by the reference validator; C008/C009/C023 own the full typed/semantic enforcement.", "cases": [ - {"id": "duplicate_key_identity", "path": "input.source.revision", "expect": "reject", "wire": "invalid_request", "owner": "C004", "enforced_by": "strict duplicate-key detection in hyf_core.operation_context and Mojo control test"}, + {"id": "duplicate_key_identity", "path": "context/versions duplicate object keys", "expect": "reject", "wire": "invalid_request", "owner": "C004", "enforced_by": "strict duplicate-key detection in hyf_core.operation_context and Mojo control test"}, + {"id": "input_duplicate_key_identity", "path": "input.* duplicate object keys", "expect": "reject", "wire": "invalid_request", "owner": "C008/C009", "enforced_by": "C004 keeps input as a Value; typed strict input decode is C008/C009"}, + {"id": "whitespace_only_identity_strings", "path": "blank-only actor_id/farm_id/version strings", "expect": "reject", "wire": "invalid_request", "owner": "C004", "enforced_by": "runtime _require_nonblank is intentionally stricter than schema minLength:1; Mojo control test"}, {"id": "escaped_duplicate_key_identity", "path": "context.actor_id vs context.\\u0061ctor_id", "expect": "reject", "wire": "invalid_request", "owner": "C004", "enforced_by": "decoded key identity in duplicate detection"}, {"id": "taxonomy_version_mismatch", "path": "context.versions.taxonomy != input.references.taxonomy.version", "expect": "reject", "wire": "invalid_request", "owner": "C023", "enforced_by": "C004 labelled semantic script; C023 typed consistency"}, {"id": "normalization_version_mismatch", "path": "context.versions.normalization != input.references.normalization.version", "expect": "reject", "wire": "invalid_request", "owner": "C023", "enforced_by": "C004 labelled semantic script; C023 typed consistency"}, diff --git a/src/hyf_core/operation_context.mojo b/src/hyf_core/operation_context.mojo @@ -74,11 +74,6 @@ def _require_allowed_keys( raise Error(context + " contains unexpected field '" + key + "'") -def _require_non_empty(value: String, context: String) raises: - if value == "": - raise Error(context + " must not be empty") - - def _has_nonblank(value: String) -> Bool: return String(value).strip().byte_length() > 0 @@ -108,12 +103,6 @@ def _required_string( return String(raw) -def _object_or_empty(value: Value, key: String) -> Value: - if _has_key(value, key): - return value[key].clone() - return Value(None) - - @fieldwise_init struct OperationVersions(Copyable, Movable): var schema: String diff --git a/tests/test_hyf.mojo b/tests/test_hyf.mojo @@ -1888,3 +1888,31 @@ def test_c004_v2_schema_assets_and_manifest_integrity() raises: assert_true(len(entries) >= 30) for entry in entries: assert_true(exists(schema_dir / entry["file"].string_value())) + + +def test_c004_operation_v2_escaped_duplicate_key_is_rejected() raises: + # \u0061 is 'a'; the parser decodes key escapes, so the second key is a + # duplicate actor_id and must be rejected by decoded-key identity. + var escaped = _v2_farm_request_with_context( + '"evaluation_time":"2026-09-24T09:00:00-07:00",' + + _v2_versions_json() + + ',"actor_id":"farm-1","\\u0061ctor_id":"farm-2","farm_id":"farm-1"' + ) + assert_true(_decode_error_message(escaped).find("duplicate") >= 0) + + +def test_c004_operation_v2_whitespace_only_identity_is_rejected() raises: + var blank_actor = _v2_farm_request_with_context( + '"evaluation_time":"2026-09-24T09:00:00-07:00",' + + _v2_versions_json() + + ',"actor_id":" ","farm_id":"farm-1"' + ) + assert_true(_decode_error_message(blank_actor).find("blank") >= 0) + + var blank_version = _v2_farm_request_with_context( + '"evaluation_time":"2026-09-24T09:00:00-07:00","versions":{' + '"schema":"hyf_ops_v2","taxonomy":" ","normalization":"n",' + '"review_policy":"r","ranking_policy":"k","question_bundle":"q",' + '"model":"m"},"actor_id":"farm-1","farm_id":"farm-1"' + ) + assert_true(_decode_error_message(blank_version).find("blank") >= 0)