hyf

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

operation_context.mojo (10813B)


      1 # ADR-0025 D45 CB01-CB05 — corrected hyf_ops_v2 capability context.
      2 #
      3 # This module owns only the strict, capability-aware operation context for the
      4 # three corrected operations selected by ``context.versions.schema ==
      5 # "hyf_ops_v2"``. It does not implement the operation pipelines (C008/C009),
      6 # typed semantic consistency (C023) or activation (C042-C046). A recognized v2
      7 # request is parsed here and then refused by the pre-activation guard in
      8 # hyf_stdio.server; it must never reach the legacy shortcut handlers.
      9 
     10 from std.collections import Dict, List, Optional
     11 
     12 from json import Value
     13 from json.deserialize import get_bool, get_int, get_string
     14 
     15 
     16 comptime OPERATION_CONTRACT_SCHEMA_V2: String = "hyf_ops_v2"
     17 comptime OPERATION_CONTEXT_DEFAULT_DEADLINE_MS: Int = 2500
     18 
     19 
     20 def corrected_operation_selector() -> String:
     21     return OPERATION_CONTRACT_SCHEMA_V2
     22 
     23 
     24 def is_corrected_operation(capability: String) -> Bool:
     25     return (
     26         capability == "farm_update.interpret"
     27         or capability == "buyer_request.interpret"
     28         or capability == "buyer_request.match"
     29     )
     30 
     31 
     32 def corrected_operation_requires_farm_id(capability: String) -> Bool:
     33     return capability == "farm_update.interpret"
     34 
     35 
     36 def corrected_operation_activation_enabled() -> Bool:
     37     """Activation boundary owned by C042-C046; C004 binds but never activates.
     38     """
     39     return False
     40 
     41 
     42 def _has_key(value: Value, key: String) -> Bool:
     43     for candidate in value.object_keys():
     44         if candidate == key:
     45             return True
     46     return False
     47 
     48 
     49 def _require_object(value: Value, context: String) raises:
     50     if not value.is_object():
     51         raise Error(context + " must be a JSON object")
     52 
     53 
     54 def _require_no_duplicate_keys(value: Value, context: String) raises:
     55     # ADR-0026 D46 CR04: bounded linear seen-key admission. The previous
     56     # all-pairs scan was quadratic in the decoded key count; this visits each
     57     # entry once and rejects the first repeated decoded key.
     58     var seen = Dict[String, Bool]()
     59     for item in value.object_items():
     60         var key = String(item[0])
     61         if key in seen:
     62             raise Error(context + " contains duplicate field '" + key + "'")
     63         seen[key] = True
     64 
     65 
     66 def _require_allowed_keys(
     67     value: Value, allowed_keys: List[String], context: String
     68 ) raises:
     69     for key in value.object_keys():
     70         var allowed = False
     71         for allowed_key in allowed_keys:
     72             if key == allowed_key:
     73                 allowed = True
     74                 break
     75         if not allowed:
     76             raise Error(context + " contains unexpected field '" + key + "'")
     77 
     78 
     79 def _has_nonblank(value: String) -> Bool:
     80     return String(value).strip().byte_length() > 0
     81 
     82 
     83 def _require_nonblank(value: String, context: String) raises:
     84     if not _has_nonblank(value):
     85         raise Error(context + " must not be blank")
     86 
     87 
     88 def _optional_string(
     89     value: Value, key: String, context: String
     90 ) raises -> Optional[String]:
     91     if not _has_key(value, key):
     92         return None
     93     var raw = get_string(value, key)
     94     _require_nonblank(raw, context)
     95     return String(raw)
     96 
     97 
     98 def _required_string(
     99     value: Value, key: String, context: String
    100 ) raises -> String:
    101     if not _has_key(value, key):
    102         raise Error(context + " is required")
    103     var raw = get_string(value, key)
    104     _require_nonblank(raw, context)
    105     return String(raw)
    106 
    107 
    108 @fieldwise_init
    109 struct OperationVersions(Copyable, Movable):
    110     var schema: String
    111     var taxonomy: String
    112     var normalization: String
    113     var review_policy: String
    114     var ranking_policy: String
    115     var question_bundle: String
    116     var model: String
    117 
    118 
    119 def _parse_operation_versions(
    120     json: Value, context: String
    121 ) raises -> OperationVersions:
    122     _require_object(json, context)
    123     _require_no_duplicate_keys(json, context)
    124 
    125     var allowed_keys = List[String]()
    126     for key in [
    127         "schema",
    128         "taxonomy",
    129         "normalization",
    130         "review_policy",
    131         "ranking_policy",
    132         "question_bundle",
    133         "model",
    134     ]:
    135         allowed_keys.append(key)
    136     _require_allowed_keys(json, allowed_keys, context)
    137 
    138     var schema = _required_string(json, "schema", context + " schema")
    139     if schema != OPERATION_CONTRACT_SCHEMA_V2:
    140         raise Error(
    141             context
    142             + " selects unsupported operation contract schema '"
    143             + schema
    144             + "'"
    145         )
    146 
    147     return OperationVersions(
    148         schema=schema,
    149         taxonomy=_required_string(json, "taxonomy", context + " taxonomy"),
    150         normalization=_required_string(
    151             json, "normalization", context + " normalization"
    152         ),
    153         review_policy=_required_string(
    154             json, "review_policy", context + " review_policy"
    155         ),
    156         ranking_policy=_required_string(
    157             json, "ranking_policy", context + " ranking_policy"
    158         ),
    159         question_bundle=_required_string(
    160             json, "question_bundle", context + " question_bundle"
    161         ),
    162         model=_required_string(json, "model", context + " model"),
    163     )
    164 
    165 
    166 @fieldwise_init
    167 struct OperationContext(Copyable, Movable):
    168     var consumer: String
    169     var execution_mode_preference: String
    170     var deadline_ms: Int
    171     var evaluation_time: String
    172     var timezone: Optional[String]
    173     var locale: Optional[String]
    174     var versions: OperationVersions
    175     var return_provenance: Bool
    176     var actor_id: String
    177     var farm_id: Optional[String]
    178 
    179 
    180 def default_operation_context() -> OperationContext:
    181     return OperationContext(
    182         consumer="unknown",
    183         execution_mode_preference="deterministic",
    184         deadline_ms=OPERATION_CONTEXT_DEFAULT_DEADLINE_MS,
    185         evaluation_time="",
    186         timezone=None,
    187         locale=None,
    188         versions=OperationVersions(
    189             schema="",
    190             taxonomy="",
    191             normalization="",
    192             review_policy="",
    193             ranking_policy="",
    194             question_bundle="",
    195             model="",
    196         ),
    197         return_provenance=False,
    198         actor_id="",
    199         farm_id=None,
    200     )
    201 
    202 
    203 def operation_context_selects_v2(context_json: Value) raises -> Bool:
    204     """True only for a well-typed ``context.versions.schema == hyf_ops_v2``.
    205 
    206     Missing, null, wrong-type and unknown selectors are not recognized here;
    207     they fall through to the unchanged legacy parser, which rejects
    208     ``versions`` for unrelated capabilities and returns invalid_request.
    209 
    210     ADR-0026 D46 CR04: this first-wins lookup is only used after the envelope
    211     root duplicate gate has rejected any ambiguous v2-targeting envelope; use
    212     ``context_selects_v2_any`` when duplicate-aware inspection is required.
    213     """
    214     if not context_json.is_object():
    215         return False
    216     if not _has_key(context_json, "versions"):
    217         return False
    218     var versions = context_json["versions"]
    219     if not versions.is_object():
    220         return False
    221     if not _has_key(versions, "schema"):
    222         return False
    223     var schema = versions["schema"]
    224     if not schema.is_string():
    225         return False
    226     return String(schema.string_value()) == OPERATION_CONTRACT_SCHEMA_V2
    227 
    228 
    229 def context_selects_v2_any(context_json: Value) raises -> Bool:
    230     """Duplicate-aware v2 selector inspection for the envelope admission gate.
    231 
    232     Scans every decoded ``versions`` member and every decoded ``schema`` entry
    233     instead of the first match, so a duplicate key cannot hide a v2 selector
    234     behind an earlier legacy value. Not a substitute for unambiguous parsing:
    235     the caller rejects the whole envelope when duplicate root keys are found.
    236     """
    237     if not context_json.is_object():
    238         return False
    239     for item in context_json.object_items():
    240         if item[0] != "versions":
    241             continue
    242         var versions = item[1].copy()
    243         if not versions.is_object():
    244             continue
    245         for member in versions.object_items():
    246             if member[0] == "schema" and member[1].is_string():
    247                 if (
    248                     String(member[1].string_value())
    249                     == OPERATION_CONTRACT_SCHEMA_V2
    250                 ):
    251                     return True
    252     return False
    253 
    254 
    255 def parse_operation_context(
    256     json: Value, capability: String
    257 ) raises -> OperationContext:
    258     if not is_corrected_operation(capability):
    259         raise Error(
    260             "operation context is only defined for corrected operations, not '"
    261             + capability
    262             + "'"
    263         )
    264 
    265     _require_object(json, "operation context")
    266     _require_no_duplicate_keys(json, "operation context")
    267 
    268     var requires_farm = corrected_operation_requires_farm_id(capability)
    269     var allowed_keys = List[String]()
    270     for key in [
    271         "consumer",
    272         "execution_mode_preference",
    273         "deadline_ms",
    274         "evaluation_time",
    275         "timezone",
    276         "locale",
    277         "versions",
    278         "return_provenance",
    279         "actor_id",
    280     ]:
    281         allowed_keys.append(key)
    282     if requires_farm:
    283         allowed_keys.append("farm_id")
    284     _require_allowed_keys(json, allowed_keys, "operation context")
    285 
    286     var context = default_operation_context()
    287 
    288     var consumer = _optional_string(
    289         json, "consumer", "operation context consumer"
    290     )
    291     if consumer:
    292         context.consumer = consumer.value()
    293 
    294     if _has_key(json, "execution_mode_preference"):
    295         var preference = get_string(json, "execution_mode_preference")
    296         if preference != "deterministic" and preference != "assisted":
    297             raise Error(
    298                 "operation context execution_mode_preference must be"
    299                 " 'deterministic' or 'assisted'"
    300             )
    301         context.execution_mode_preference = String(preference)
    302 
    303     if _has_key(json, "deadline_ms"):
    304         context.deadline_ms = get_int(json, "deadline_ms")
    305         if context.deadline_ms <= 0:
    306             raise Error(
    307                 "operation context deadline_ms must be greater than zero"
    308             )
    309 
    310     context.evaluation_time = _required_string(
    311         json, "evaluation_time", "operation context evaluation_time"
    312     )
    313 
    314     context.timezone = _optional_string(
    315         json, "timezone", "operation context timezone"
    316     )
    317     context.locale = _optional_string(
    318         json, "locale", "operation context locale"
    319     )
    320 
    321     if not _has_key(json, "versions"):
    322         raise Error("operation context versions is required")
    323     context.versions = _parse_operation_versions(
    324         json["versions"].clone(), "operation context versions"
    325     )
    326 
    327     if _has_key(json, "return_provenance"):
    328         context.return_provenance = get_bool(json, "return_provenance")
    329 
    330     context.actor_id = _required_string(
    331         json, "actor_id", "operation context actor_id"
    332     )
    333 
    334     if requires_farm:
    335         context.farm_id = _required_string(
    336             json, "farm_id", "operation context farm_id"
    337         )
    338 
    339     return context^