From 7a8d2097e74a7be948688e543cf1c66b22b477f6 Mon Sep 17 00:00:00 2001 From: Brummel Date: Thu, 4 Jun 2026 19:06:59 +0200 Subject: [PATCH] docs(aura-engine): document to_json JSON schema + integer-token rendering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves the two doc-level findings from the cycle-0009 fieldtest (docs/specs/fieldtest-0009-run-metrics.md), both the same doc pass on RunReport::to_json's rustdoc: - spec_gap: the JSON key names and {manifest,metrics} nesting were not on the public surface — a consumer parsing the JSON (the C18 registry, the deferred aura run printer) could not author against it from rustdoc alone. Now stated: keys mirror the struct field names in fixed order, window is a 2-element [from,to] array, params is an insertion-order object, with a worked sample object. Ratifies field-name-mirroring as the contract for the C14 face. - friction: a whole-valued f64 renders without a fractional part (12.0 -> 12), so one f64 field may appear as an integer or decimal token across runs. Now documented, with the consumer guidance to parse as a number, never key off token shape. Doc-only change; no behaviour change. The sample is a `text` fence (not a doctest). Verified: RUSTDOCFLAGS="-D warnings" cargo doc -p aura-engine clean; clippy -p aura-engine --all-targets -D warnings clean; doctests 0. refs #6 --- crates/aura-engine/src/report.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/crates/aura-engine/src/report.rs b/crates/aura-engine/src/report.rs index a525c5c..973e2d7 100644 --- a/crates/aura-engine/src/report.rs +++ b/crates/aura-engine/src/report.rs @@ -58,9 +58,25 @@ pub struct RunReport { impl RunReport { /// Render canonical, machine-readable JSON (C14). Hand-rolled — the schema /// is tiny, closed, and flat, so the deliberately zero-dependency workspace - /// stays so. Field order is fixed; `f64` uses the round-trippable `{}` - /// shortest form (finite values only — pip equity and exposure are finite - /// by construction); `params` renders as a JSON object in insertion order. + /// stays so. + /// + /// # Shape + /// + /// The JSON keys mirror the struct field names, in fixed order, nested as + /// `{"manifest": {…}, "metrics": {…}}`. `window` is a 2-element + /// `[from, to]` array of epoch-ns integers; `params` is a JSON object of + /// `name: value` pairs in insertion order. A run renders as, e.g.: + /// + /// ```text + /// {"manifest":{"commit":"abc123","params":{"sma_fast":2,"sma_slow":4},"window":[1,6],"seed":0,"broker":"sim-optimal(pip_size=0.0001)"},"metrics":{"total_pips":12,"max_drawdown":1,"exposure_sign_flips":1}} + /// ``` + /// + /// `f64` fields use the round-trippable `{}` shortest form (finite values + /// only — pip equity and exposure are finite by construction), so a + /// whole-valued float renders **without** a fractional part (`12.0` → `12`): + /// one `f64` field may appear as an integer token in one run and a decimal + /// token in another. Consumers must parse the value as a number, never key + /// off the token shape. pub fn to_json(&self) -> String { let m = &self.manifest; let mut params = String::from("{");