import Foundation /// A Sendable, fully-Codable representation of arbitrary JSON, for the contract's open-shape /// `[String: Any]?` fields (ai_suggestion, md_frontmatter, md_extraction_quality, memo_task_state, /// source_metadata, freshness_debug, debug). Plain Codable cannot decode those; this can. /// /// Numeric note (B-1 review): on Foundation's JSONDecoder, a JSON boolean fails `Int` decode /// (no silent 1/0 coercion), so Bool ordering is harmless. The real disambiguation is Int-before-Double /// so integral numbers stay `.int`. BUT whole-valued floats like `1.0` can land as `.int` depending on /// toolchain — so numeric meaning MUST be read through `doubleValue`/`intValue` (which cross-convert), /// never by pattern-matching the raw case. public enum JSONValue: Codable, Sendable, Hashable { case string(String) case int(Int) case double(Double) case bool(Bool) case object([String: JSONValue]) case array([JSONValue]) case null public init(from decoder: Decoder) throws { let c = try decoder.singleValueContainer() if c.decodeNil() { self = .null; return } if let b = try? c.decode(Bool.self) { self = .bool(b); return } if let i = try? c.decode(Int.self) { self = .int(i); return } if let d = try? c.decode(Double.self) { self = .double(d); return } if let s = try? c.decode(String.self) { self = .string(s); return } if let o = try? c.decode([String: JSONValue].self) { self = .object(o); return } if let a = try? c.decode([JSONValue].self) { self = .array(a); return } throw DecodingError.dataCorruptedError(in: c, debugDescription: "Unsupported JSON value") } public func encode(to encoder: Encoder) throws { var c = encoder.singleValueContainer() switch self { case .string(let s): try c.encode(s) case .int(let i): try c.encode(i) case .double(let d): try c.encode(d) case .bool(let b): try c.encode(b) case .object(let o): try c.encode(o) case .array(let a): try c.encode(a) case .null: try c.encodeNil() } } // Accessors cross-convert so numeric reads are robust regardless of int/double storage. public var stringValue: String? { if case .string(let s) = self { return s }; return nil } public var intValue: Int? { switch self { case .int(let i): return i case .double(let d): return Int(d) default: return nil } } public var doubleValue: Double? { switch self { case .double(let d): return d case .int(let i): return Double(i) default: return nil } } public var boolValue: Bool? { if case .bool(let b) = self { return b }; return nil } public var objectValue: [String: JSONValue]? { if case .object(let o) = self { return o }; return nil } public var arrayValue: [JSONValue]? { if case .array(let a) = self { return a }; return nil } public subscript(key: String) -> JSONValue? { objectValue?[key] } public subscript(index: Int) -> JSONValue? { guard let a = arrayValue, index >= 0, index < a.count else { return nil } return a[index] } }