ADR 0029 - CorePure Structured Serialization

Adds explicit canonical JSON serialization for CorePure structured values while keeping string interpolation scalar-only.


On this page
  1. Status
  2. Context
  3. Decision
  4. Canonical JSON
  5. Budget And Failures
  6. No Generic Show
  7. Alternatives considered
  8. Consequences
  9. Positive
  10. Negative
  11. Obligations
  12. Related

ADR 0029 - CorePure Structured Serialization

Status

Proposed - fills the structured-stringification gap left open by ADR 0023.

Context

ADR 0023 intentionally keeps string interpolation scalar-only. This is the right default:

"Score: ${score}"

is readable, while:

"Items: ${items}"

should not accidentally commit Cortex to unspecified record/list formatting.

Real prompt and report templates will still need to include structured values. The first such use should not re-open generic Show semantics or host callbacks. CorePure needs an explicit, deterministic serialization primitive.

Decision

CorePure should add two structured serialization primitives:

toJson : JsonSerializable -> String
fromJson : String -> JsonValue

JsonSerializable is the recursive subset of CorePure values that can be represented as JSON:

  • null;
  • booleans;
  • numbers;
  • strings;
  • lists of JSON-serializable values;
  • records whose field values are JSON-serializable.

Lambdas and configured executor values are not serializable. Future opaque values are not serializable unless a later ADR admits them.

String interpolation remains scalar-only. Authors serialize structured values explicitly:

-> prompt: Prompt = ''
  Analyze these items:
  ${toJson evidence.items}
'' ;

Canonical JSON

toJson emits canonical JSON:

  • record keys are emitted in lexicographic order by UTF-8 byte sequence;
  • no insignificant whitespace is emitted;
  • strings use JSON escaping;
  • booleans, null, arrays, and objects use standard JSON tokens;
  • numbers are finite decimal values rendered without leading plus signs, insignificant leading zeroes, or insignificant fractional trailing zeroes;
  • exponent notation is not emitted in the first slice;
  • negative zero is rendered as 0;
  • NaN and infinity are impossible CorePure numbers and are not representable.

This is a serialization function, not a schema validator. It does not check that a value satisfies a Wire contract. Contract validation remains a Wire/runtime boundary concern.

fromJson accepts standard JSON text and returns the corresponding CorePure JSON value. It is a parser, not a contract validator: malformed JSON is a typed pure failure, and valid JSON still needs any contract checks required by a later boundary.

Budget And Failures

Serialization and parsing are budgeted. Cost must account for traversal and emitted or consumed text size. Budget exhaustion is a typed CorePure failure under ADR 0026.

Serializing a non-serializable value is a typed CorePure failure. Because toJson is ordinary CorePure, the failure occurs during elaboration when the argument is statically known and during runtime pure execution when it depends on input ports.

No Generic Show

CorePure should not add a generic show, implicit record interpolation, pretty-printer, or host-defined stringification in this slice. Pretty JSON, markdown tables, CSV, and contract-aware renderers can be proposed later as explicit closed stdlib additions.

Alternatives considered

  • Auto-stringify records and lists in interpolation. Rejected because it makes structural formatting implicit and hard to change.
  • Add a generic show function. Rejected because it creates an underspecified textual format for every value kind.
  • Use host callbacks for rendering. Rejected because CorePure is closed and authority-free.
  • Add both compact and pretty JSON now. Rejected because compact canonical JSON is enough for deterministic prompt/report embedding; pretty rendering can be admitted later if examples need it.

Consequences

Positive

  • Prompt templates can include structured values without unsafe implicit interpolation.
  • Serialization is deterministic, budgeted, and testable.
  • The first stdlib addition is narrow and contract-independent.
  • CorePure remains host-independent and authority-free.

Negative

  • Human-facing prompts may need explicit formatting helpers later.
  • Large structured values can exhaust budget when serialized.
  • Authors must write ${toJson value} explicitly for records and lists.

Obligations

  • Add toJson and fromJson to the closed CorePure stdlib.
  • Add canonical JSON golden tests for key ordering, escaping, nesting, and numbers.
  • Add typed failure tests for lambdas and non-serializable future values.
  • Add budget tests based on traversal and output size.
  • Keep interpolation scalar-only in parser and evaluator tests.