package responseschema import ( "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "strings" ) // Key identifies one structured response schema used by Audita. type Key string const ( CorrectionSetKey Key = "correction_set" ValidatorDecisionSetKey Key = "validator_decision_set" correctionSetSchemaID = "audita.correction_set" validatorDecisionSchemaID = "audita.validator_decision_set" schemaVersionV1 = "v1" ) // Schema describes one registered structured response schema. type Schema struct { ID string `json:"id"` Version string `json:"version"` Name string `json:"name"` JSONSchema json.RawMessage `json:"json_schema"` SHA256 string `json:"sha256"` } var registry = map[Key]Schema{ CorrectionSetKey: mustBuildSchema( correctionSetSchemaID, schemaVersionV1, "audita_correction_set_v1", []byte(`{"type":"object","additionalProperties":false,"required":["corrections"],"properties":{"corrections":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["id","original_text","corrected_text","confidence"],"properties":{"id":{"type":"integer","minimum":1},"original_text":{"type":"string","minLength":1},"corrected_text":{"type":"string","minLength":1},"confidence":{"type":"number","minimum":0,"maximum":1}}}}}}`), ), ValidatorDecisionSetKey: mustBuildSchema( validatorDecisionSchemaID, schemaVersionV1, "audita_validator_decision_set_v1", []byte(`{"type":"object","additionalProperties":false,"required":["validations"],"properties":{"validations":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["correction_index","approved","confidence","reason"],"properties":{"correction_index":{"type":"integer","minimum":0},"approved":{"type":"boolean"},"confidence":{"type":"number","minimum":0,"maximum":1},"reason":{"type":"string"}}}}}}`), ), } // Lookup returns a copy of the registered schema for the provided key. func Lookup(key Key) (Schema, bool) { schema, ok := registry[key] if !ok { return Schema{}, false } return cloneSchema(schema), true } // MustLookup returns a copy of the registered schema and panics when missing. func MustLookup(key Key) Schema { schema, ok := Lookup(key) if !ok { panic(fmt.Sprintf("unknown structured response schema key %q", key)) } return schema } func cloneSchema(in Schema) Schema { out := in if in.JSONSchema != nil { out.JSONSchema = append(json.RawMessage(nil), in.JSONSchema...) } return out } func mustBuildSchema(id string, version string, name string, rawSchema []byte) Schema { id = strings.TrimSpace(id) version = strings.TrimSpace(version) name = strings.TrimSpace(name) if id == "" { panic("schema id must not be empty") } if version == "" { panic("schema version must not be empty") } if name == "" { panic("schema name must not be empty") } if !json.Valid(rawSchema) { panic(fmt.Sprintf("schema %s:%s is not valid JSON", id, version)) } hash := sha256.Sum256(rawSchema) return Schema{ ID: id, Version: version, Name: name, JSONSchema: append(json.RawMessage(nil), rawSchema...), SHA256: hex.EncodeToString(hash[:]), } }