Схема результата — как читать *.result.json Kshana
Каждый прогон записывает рядом со сценарием версионированный самоописывающийся артефакт JSON (JavaScript Object Notation). Эта страница — написанное вручную руководство читателя по конверту обмена и по формам результатов для часов и орбиты: единица каждого поля, где оно вычисляется в исходном коде и как его читать. Канонический тип — RunResult в src/report.rs; показатели качества — FoMScores в src/fom.rs.
Это не полный справочник по полям. Движок диспетчеризует по гораздо большему числу видов, чем эти два, и каждый выдаёт собственный пакет. Полный справочник — единица, класс происхождения и определение для каждого числового поля каждого встроенного вида — формируется, а не пишется вручную: см. ниже Единицы и происхождение для каждого поля каждого вида.
Конверт обмена (KIF, Kshana Interchange Format) — распознавание артефакта и проверка версии#
Артефакты Kshana можно обернуть в нейтральный самоописывающийся конверт обмена, чтобы сторонний инструмент мог распознать файл и решить, может ли он его прочитать, до того, как возьмётся за схему полезной нагрузки. Канонический тип — Envelope в src/interchange.rs.
| Ключ | Тип | Значение |
|---|---|---|
format |
строка | Всегда "kshana-interchange" (FORMAT_TAG) — так сторонний инструмент распознаёт артефакт Kshana. |
schema_version |
строка | Версия схемы MAJOR.MINOR (SCHEMA_VERSION, единый источник истины для всего крейта). |
kind |
строка | Вид артефакта, например "scenario", "run-result", "trade-study" — позволяет потребителю направлять данные, не разбирая тело. |
engine_version |
строка | Версия крейта (Cargo.toml), создавшего полезную нагрузку. |
payload |
объект | Обёрнутый артефакт в виде канонического JSON (Scenario, RunResult, …). |
Контракт совместимости. Версии имеют вид MAJOR.MINOR. Новые поля добавляются с #[serde(default)] (аддитивная дисциплина), поэтому читатель может разобрать любой артефакт той же основной версии и такой же или более старой дополнительной (Compatible). Строго более новая дополнительная версия (ForwardIncompatible) может содержать поля, которые этот читатель не может учесть, а другая основная версия (MajorIncompatible) — структурный разрыв; оба случая отклоняет Envelope::parse, которая проверяет метку формата и версию на границе, а не молча неверно разбирает чужие входные данные.
Детерминированность. В конверте нет отметки времени — этого требует обещание воспроизводимости Kshana (scenario + seed + engine_version воспроизводит прогон). Происхождение хранится в engine_version и в собственном scenario_hash полезной нагрузки.
Типизированное обратное чтение (Envelope::payload_as::<T>()) работает для любой полезной нагрузки, реализующей Deserialize (например, Scenario). Артефакты результатов по замыслу только сериализуются и читаются как необработанное значение JSON payload.
Верхний уровень (пакеты часов и орбиты)#
| Ключ | Тип / единица | Значение | Источник |
|---|---|---|---|
schema_version |
строка | Версия схемы результата (не зависит от версии движка). | report.rs |
engine_version |
строка | Версия крейта (Cargo.toml), создавшего файл. |
report.rs |
scenario_hash |
шестнадцатеричная строка | SHA-256 (SHA: Secure Hash Algorithm) по каноническому JSON сценария — прогон воспроизводится по scenario + seed + engine_version. |
report.rs:hash_scenario |
seed |
u64 | Начальное значение ГСЧ (генератора случайных чисел) для квантового прогона (классический использует seed + 0x9e3779b97f4a7c15). |
run.rs |
threshold_ns |
наносекунды | Требование к синхронизации: ошибка в пределах ±threshold_ns «в допуске». |
сценарий |
quantum |
объект (ClockRun) |
Прогон квантового датчика (см. ниже). | report.rs |
classical |
объект (ClockRun) |
Прогон классического датчика для сравнения. | report.rs |
units |
объект | Карта единиц и происхождения каждого поля этого документа по пути поля. См. ниже §Единицы и происхождение. | field_schema.rs:units_block |
evidence |
объект | (0,40) Метка доказательств прогона: tier (VALIDATED, MODELLED или PARTNER: самый слабый статус среди строк, так что она никогда не заявляет больше, чем самая слабая строка), matrix (docs/VERIFICATION-MATRIX.md), id_rule и rows, по одной на каждую строку матрицы верификации, задействованную прогоном (строки, которые перечисляет его расширенный отчёт, из advanced_report::KIND_CAPABILITIES): id (VM- и первые 8 шестнадцатеричных цифр SHA-256 текста требования строки), requirement и status, всё считывается из матрицы, ничего не вводится вручную. Добавляется функцией api::run_toml к результату каждого вида, перед завершающим блоком figure_tiers, если он есть (этот блок остаётся последним ключом); evidence_label::strip_json удаляет её байт в байт. SVG-диаграмма и CSV-таблица того же прогона несут ту же метку (<metadata id="kshana-evidence"> и видимая строка под диаграммой; строки комментариев # evidence: в начале CSV). Члены кампании, встроенные в результат другого вида, не несут метки: она есть у внешнего документа. Чисел не содержит. |
evidence_label.rs |
figure_tiers |
объект | Уровень верификации каждого указанного показателя качества и всегда последний ключ документа. figures содержит по одной записи на каждый присутствующий показатель: path (например, quantum.fom.timing_p95_ns), tier (VALIDATED = проверено по независимому внешнему оракулу, MODELLED = из первых принципов, внутренне проверено тестами), requirement (строка матрицы верификации, из которой считывается уровень) и applicable. applicable равно false с reason для security в каждом сценарии, где атака не настроена: граница остаётся в fom.security, но не отвечает на вопрос, который задаёт сценарий. untiered перечисляет любые показатели, которыми не владеет ни одна строка матрицы (показатели положения hybrid и fusion), вместо присвоения им уровня. Его выдают виды clock (одиночный прогон и ансамбль Монте-Карло), orbit, hybrid и fusion, которые строят его внутри своего прогона, а также (0,36, RM-04) все остальные виды для своих ключевых показателей, добавляя после прогона из таблицы видов fom_label::kind_figures; api::without_figure_tiers побайтово возвращает документ к виду без уровней. Не выдаётся видом lunar-station-coverage, результат которого — замороженный заранее зарегистрированный прогноз (docs/predictions/lunar-reference-station.md): у этого вида нет figure_tiers, пока новый датированный прогноз не заменит его. Не выдаётся также видами leo-ppp, solar-system, optical-atmosphere (0,37; массивы по пунктам), sweep и sweep-nd, у которых нет скалярного ключевого показателя, видом lunar-attack-surface, документ которого — компактный JSON (fom_label::KINDS_EXCLUDED_FROM_FIGURE_TIERS указывает каждую причину), и встроенными документами участников кампании. Чисел не содержит. |
fom_label.rs:figure_tiers, fom_label.rs:kind_figure_tiers |
geometry |
объект, необязательный | Сводка геометрии пакета орбиты: samples_total, samples_with_fix, sigma_uere_m (м, смоделированный бюджет ошибки дальности для каждого спутника), best_pdop / median_pdop (безразмерные) и best_position_sigma_m / median_position_sigma_m (м, PDOP (геометрический фактор по положению) × sigma_uere_m). Только пакет орбиты. |
orbit.rs |
eci_track |
массив [x, y, z] км, необязательный |
Распространённая в земной инерциальной системе траектория пользовательского космического аппарата, по одной записи на каждый выбранный момент времени. Только пакет орбиты; иначе опускается. Только выходные данные — не хешируется. | report.rs |
meta |
объект (StudyMeta), необязательный |
Дополнительные метаданные отчёта (название исследования, отметка формирования, автор, оговорка). Опускаются, когда отсутствуют, поэтому прогон без метаданных побайтово идентичен прежнему выводу. Только выходные данные — не хешируется. | report.rs |
ClockRun (каждый из quantum / classical)#
| Ключ | Тип / единица | Значение |
|---|---|---|
spec.id |
строка | Идентификатор датчика (например, optical-sr-lattice). |
spec.kind |
строка | Вид модели (например, clock). |
spec.provenance |
строка | Ссылка на источник параметров датчика. |
spec.params |
объект | Использованные исходные параметры модели. |
series |
массив {t, error_ns, gnss} |
Временной ряд по шагам: t — секунды, error_ns — ошибка времени в наносекундах, gnss — одно из nominal/degraded/denied. |
fom |
объект (FoMScores) |
Оценённые показатели качества (ниже). |
adev_curve |
массив {tau_s, adev, n_samples, noise, edf, ci_lo, ci_hi} |
Перекрывающаяся девиация Аллана: tau_s — время усреднения (с), adev — безразмерная стабильность дробной частоты σ_y(τ), n_samples — число перекрытий в основе этой точки, noise — тип степенного закона, определённый по наклону MDEV (модифицированная девиация Аллана) (например, WhiteFm), edf — эффективное число степеней свободы для данного типа шума, а ci_lo/ci_hi — доверительная полоса 95% по χ² для adev при этом τ. Вычисляется в allan.rs:overlapping_adev_curve. |
filter_health |
объект, необязательный | Оценка согласованности фильтра Калмана (NIS/NEES (NIS: нормированный квадрат инновации; NEES: нормированный квадрат ошибки оценки) относительно их полос χ²), вычисляется в filter_health.rs; опускается для прогонов, которые её не оценивают. |
FoMScores (объект fom)#
| Поле | Единица | Значение | Источник | Оговорка |
|---|---|---|---|---|
timing_rms_ns |
нс | СКЗ (среднеквадратическая) ошибка фазы часов (времени) за время отказа. | fom.rs:score |
метрика времени, а не положения |
timing_p95_ns |
нс | 95-й процентиль ошибки времени за время отказа. | fom.rs:score |
|
holdover_s |
s | Наихудший (наименьший) выбег в допуске по участкам отказа. | fom.rs:worst_case_holdover |
ограничено сеткой — нижняя граница при разрешении шага по времени |
resilience_slope_ns_per_s |
ns/s | Скорость роста |ошибки| за время отказа по методу наименьших квадратов. | fom.rs:score |
|
availability |
доля [0 1] | Доля всего прогона с решением в допуске. | fom.rs:score |
|
integrity |
доля [0 1] или null | Самосогласованность фильтра: доля отсчётов отказа, в которых истинная ошибка остаётся в пределах границы k-σ фильтра Калмана. | run.rs |
НЕ целостность HPL/VPL/RAIM (HPL: горизонтальный уровень защиты; VPL: вертикальный уровень защиты; RAIM: автономный контроль целостности приёмником) — см. INTEGRITY.md |
security |
доля [0 1] или null | Аналитическая граница обнаруживаемости спуфинга по стабильности часов. | run.rs + security.rs |
имеет смысл только при настроенной атаке, поэтому пакеты часов и орбиты (в которых её нет) помечают её applicable: false в figure_tiers и выводят как n/a (no attack) в сводке; это не многоспутниковый детектор RAIM |
Как выглядит «хороший» результат#
- Более стабильные часы (меньше
adev_curve) дают более длинныйholdover_sи более высокую границу обнаруживаемостиsecurity— в этом контраст квантового и классического вариантов. availability, близкое к 1,0, означает, что система оставалась в допуске почти весь прогон; при долгом отказе оно снижается для более шумных часов.integrity, близкое к 1,0, означает, что собственная граница неопределённости фильтра честно отражала его ошибку — это утверждение о самосогласованности, а не гарантия безопасности жизни.
Другие виды сценариев#
Каждый другой вид выдаёт собственную форму результата. Несколько распространённых:
- inertial: показатели качества в области положения в метрах (
pos_rms_m,pos_p95_m) — одноосевые (1-DOF (DOF: степень свободы)), с одним начальным значением (seed) (см.CAPABILITY.md). - hybrid / fusion:
timing_spec_nsиposition_spec_mна верхнем уровне, а для каждой стороны показатели времени и положения одного набора датчиков (position_p95_m,position_holdover_sиpnt_holdover_s— время до нарушения любого из требований), с блокомfigure_tiers, как в пакете часов, в котором показатели положения перечислены какuntiered. - spoof: смещение спуфинга на каждом шаге относительно границы обнаружения часов, а также достигло ли смещение допуска до обнаружения (
src/spoof.rs). - skyline (
orbitиintegrityсuser_site,gnss-sim,jamming,leo-pvt,leo-pass; присутствует только если в сценарии есть раздел[skyline], поэтому сценарий без него не меняется): объект верхнего уровняskylineсsource(строка:preset:<name>,preset:<name>+overridesилиcustom),open_fraction(доля [0 1] телесного угла верхней полусферы вышеmax(mask_deg, skyline)) иprovenance(строка); для каждого отсчётаmasked_by_skyline(число спутников выше маски, но за линией горизонта:epochs[]дляintegrityиjamming,gnss_measurements[]дляgnss-sim,joint.epochs[]дляleo-pvt); а дляleo-pass—satellites[].pass.epochs_masked_by_skyline(число эпох). Их единицы и классы происхождения указаны в блокеunits(src/skyline.rsUNITS;SKYLINE.md).
Точный набор полей любого вида смотрите в его записи в field-units-schema.json (ниже), в разделе этого вида в SCENARIOS.md или в соответствующей структуре *Result в src/.
Другие файлы, которые записывает прогон#
Помимо <scenario>.result.json, CLI (интерфейс командной строки) записывает <scenario>.chart.svg, печатный <scenario>.report.html и тот же отчёт как <scenario>.report.json, блок reproducibility которого фиксирует версию движка, SHA-256 файла сценария, seed, платформу и точную команду (см. REPORTS.md и REPRODUCIBILITY.md). Виды, публикующие таблицу воспроизводимости, также записывают <scenario>.table.csv (CSV: значения, разделённые запятыми). --export записывает файлы обмена (см. INTEROP.md), а --animate — анимацию (см. ANIMATION.md).
Единицы и происхождение для каждого поля каждого вида#
Эта страница написана вручную и охватывает пакеты часов и орбиты. Машиночитаемый аналог охватывает каждый встроенный вид:
- В самом результате. Документ результата каждого сценария несёт объект
unitsверхнего уровня, сопоставляющий путь выдаваемого поля с{"unit", "provenance", "note"}. Грамматика путей (массив даёт один сегмент с суффиксом[], общий для его строк;*— подстановочный знак одного сегмента для объектов с ключами из данных) и закрытый словарь происхождения определены вsrc/field_schema.rs. - Единым файлом.
field-units-schema.json— собранное объединение: для каждого вида каждое числовое поле, которое он выдаёт в заявленном источнике, с его единицей, классом происхождения, уровнем доказательств и определением — а также, с указанием имён, а не с пропуском, каждое поле, у которого этого пока нет. Его блокcoverageсодержит счётчики.
Оба обеспечивает tests/field_units_global.rs, который запускает каждый зарегистрированный вид и завершается ошибкой, если у выдаваемого числового поля нет единицы и класса происхождения. Виды, ещё не охваченные, названы по отдельности в UNCOVERED_KINDS этого файла с причиной, по которой каждый остаётся открытым, а число закреплено, так что список может только сокращаться.
Сформируйте JSON заново после любого изменения формы отчёта или блока units:
cargo test --test field_units_global zzz_emit_field_units_schema -- --ignored