project-ghost 0.2.0__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. {project_ghost-0.2.0 → project_ghost-0.2.1}/.github/workflows/ci.yml +103 -11
  2. {project_ghost-0.2.0 → project_ghost-0.2.1}/CHANGELOG.md +84 -1
  3. {project_ghost-0.2.0 → project_ghost-0.2.1}/CITATION.cff +16 -16
  4. {project_ghost-0.2.0 → project_ghost-0.2.1}/PKG-INFO +26 -2
  5. {project_ghost-0.2.0 → project_ghost-0.2.1}/README.md +25 -1
  6. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/index.md +45 -13
  7. project_ghost-0.2.1/docs/paper/arxiv/README.md +147 -0
  8. project_ghost-0.2.1/docs/paper/arxiv/main.tex +656 -0
  9. project_ghost-0.2.1/docs/paper/arxiv/refs.bib +148 -0
  10. project_ghost-0.2.1/docs/paper/outputs/metrics.json +1084 -0
  11. project_ghost-0.2.1/docs/paper/outputs/violation_showcase.json +55 -0
  12. project_ghost-0.2.1/docs/paper/project_ghost_v0_2.md +895 -0
  13. project_ghost-0.2.1/docs/paper/scripts/measure_metrics.py +344 -0
  14. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/proofs/README.md +14 -6
  15. project_ghost-0.2.1/docs/proofs/Rlb.cfg +23 -0
  16. project_ghost-0.2.1/docs/proofs/Rlb.tla +167 -0
  17. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/properties/index.md +14 -9
  18. {project_ghost-0.2.0 → project_ghost-0.2.1}/pyproject.toml +7 -1
  19. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/app/main.py +94 -70
  20. project_ghost-0.2.1/src/project_ghost/examples/closed_loop_smoke_violated.py +407 -0
  21. {project_ghost-0.2.0 → project_ghost-0.2.1}/.github/workflows/docs.yml +0 -0
  22. {project_ghost-0.2.0 → project_ghost-0.2.1}/.github/workflows/release.yml +0 -0
  23. {project_ghost-0.2.0 → project_ghost-0.2.1}/.gitignore +0 -0
  24. {project_ghost-0.2.0 → project_ghost-0.2.1}/.pre-commit-config.yaml +0 -0
  25. {project_ghost-0.2.0 → project_ghost-0.2.1}/.streamlit/config.toml +0 -0
  26. {project_ghost-0.2.0 → project_ghost-0.2.1}/CONTRIBUTING.md +0 -0
  27. {project_ghost-0.2.0 → project_ghost-0.2.1}/LICENSE +0 -0
  28. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0000-vision.md +0 -0
  29. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0001-hal-first.md +0 -0
  30. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0002-deterministic-simulation.md +0 -0
  31. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0003-telemetry-everywhere.md +0 -0
  32. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0004-backend-independence.md +0 -0
  33. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0005-canonical-vehicle-state.md +0 -0
  34. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0006-event-driven-core.md +0 -0
  35. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0007-hardware-migration-strategy.md +0 -0
  36. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0008-perception-failure-modes.md +0 -0
  37. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0009-autonomy-under-uncertainty.md +0 -0
  38. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0010-revised-perception-mode-catalog.md +0 -0
  39. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0011-t0-safety-vetoes-pilot.md +0 -0
  40. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0012-run-retention-policy.md +0 -0
  41. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0013-run-analysis-artifacts.md +0 -0
  42. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0014-behavior-traceability-v1.md +0 -0
  43. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0015-noisy-ground-truth-estimator.md +0 -0
  44. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0016-belief-traceability-report-v1.md +0 -0
  45. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0017-belief-consistency-analysis-v1.md +0 -0
  46. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0018-comparative-belief-analysis.md +0 -0
  47. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0019-belief-calibration-honesty-check-v1.md +0 -0
  48. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0020-belief-self-assessment-v1.md +0 -0
  49. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0021-belief-to-action-contract-layer-v1.md +0 -0
  50. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0022-decision-trace-verification-v1.md +0 -0
  51. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0023-action-emission-contract-layer-v1.md +0 -0
  52. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0024-belief-forward-prediction-contract-v1.md +0 -0
  53. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0025-prediction-observation-divergence-check-v1.md +0 -0
  54. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0026-closed-loop-feedback-v1.md +0 -0
  55. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0027-calibration-aware-decision-context-v1.md +0 -0
  56. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0028-sensor-to-belief-fusion-contract-v1.md +0 -0
  57. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0029-trajectory-controller-reference-v1.md +0 -0
  58. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0030-replay-verification-v1.md +0 -0
  59. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0031-bounded-action-under-drift-property-v1.md +0 -0
  60. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0032-eventual-reactivation-under-recovery-property-v1.md +0 -0
  61. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0033-monotonic-degradation-property-v1.md +0 -0
  62. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0034-recovery-latency-bound-property-v1.md +0 -0
  63. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0035-false-positive-bound-property-v1.md +0 -0
  64. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/0036-tla-plus-mechanical-verification-of-baud-erur.md +0 -0
  65. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/adr/README.md +0 -0
  66. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/architecture.md +0 -0
  67. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/proofs/BaudErur.cfg +0 -0
  68. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/proofs/BaudErur.tla +0 -0
  69. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/properties/baud.md +0 -0
  70. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/properties/erur.md +0 -0
  71. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/properties/fpb.md +0 -0
  72. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/properties/md.md +0 -0
  73. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/properties/proofs.md +0 -0
  74. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/properties/rlb.md +0 -0
  75. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/reviews/architecture_red_team_review.md +0 -0
  76. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/reviews/uncertainty_red_team_review.md +0 -0
  77. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/roadmaps/phase1.md +0 -0
  78. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/roadmaps/research_track_uncertainty.md +0 -0
  79. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/specs/README.md +0 -0
  80. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/specs/actuators.md +0 -0
  81. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/specs/clock.md +0 -0
  82. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/specs/events.md +0 -0
  83. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/specs/hal.md +0 -0
  84. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/specs/mission.md +0 -0
  85. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/specs/perception.md +0 -0
  86. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/specs/sensors.md +0 -0
  87. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/specs/state.md +0 -0
  88. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/specs/telemetry.md +0 -0
  89. {project_ghost-0.2.0 → project_ghost-0.2.1}/docs/specs/uncertainty.md +0 -0
  90. {project_ghost-0.2.0 → project_ghost-0.2.1}/mkdocs.yml +0 -0
  91. {project_ghost-0.2.0 → project_ghost-0.2.1}/requirements.txt +0 -0
  92. {project_ghost-0.2.0 → project_ghost-0.2.1}/scripts/check_no_global_random.py +0 -0
  93. {project_ghost-0.2.0 → project_ghost-0.2.1}/scripts/check_no_unstable_collections.py +0 -0
  94. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/__init__.py +0 -0
  95. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/actuators/__init__.py +0 -0
  96. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/analysis/__init__.py +0 -0
  97. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/analysis/belief_consistency.py +0 -0
  98. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/analysis/belief_traceability.py +0 -0
  99. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/analysis/calibration.py +0 -0
  100. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/analysis/comparison.py +0 -0
  101. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/analysis/decision_trace.py +0 -0
  102. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/analysis/models.py +0 -0
  103. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/analysis/report.py +0 -0
  104. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/analysis/self_assessment.py +0 -0
  105. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/analysis/summary.py +0 -0
  106. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/app/__init__.py +0 -0
  107. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/cli.py +0 -0
  108. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/__init__.py +0 -0
  109. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/actuation/__init__.py +0 -0
  110. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/actuation/attitude_hold_policy.py +0 -0
  111. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/actuation/orchestration.py +0 -0
  112. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/actuation/protocols.py +0 -0
  113. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/actuation/reference_policy.py +0 -0
  114. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/actuation/sinks.py +0 -0
  115. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/actuation/types.py +0 -0
  116. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/clock/__init__.py +0 -0
  117. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/clock/error_sink.py +0 -0
  118. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/clock/random_source.py +0 -0
  119. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/clock/sim_clock.py +0 -0
  120. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/clock/types.py +0 -0
  121. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/decisions/__init__.py +0 -0
  122. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/decisions/orchestration.py +0 -0
  123. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/decisions/protocols.py +0 -0
  124. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/decisions/reference_policy.py +0 -0
  125. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/decisions/sinks.py +0 -0
  126. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/decisions/types.py +0 -0
  127. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/feedback/__init__.py +0 -0
  128. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/feedback/orchestration.py +0 -0
  129. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/feedback/protocols.py +0 -0
  130. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/feedback/reference_policy.py +0 -0
  131. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/feedback/types.py +0 -0
  132. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/fusion/__init__.py +0 -0
  133. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/fusion/orchestration.py +0 -0
  134. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/fusion/protocols.py +0 -0
  135. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/fusion/reference_policy.py +0 -0
  136. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/fusion/sinks.py +0 -0
  137. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/fusion/types.py +0 -0
  138. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/prediction/__init__.py +0 -0
  139. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/prediction/divergence.py +0 -0
  140. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/prediction/orchestration.py +0 -0
  141. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/prediction/protocols.py +0 -0
  142. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/prediction/reference_predictor.py +0 -0
  143. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/prediction/sinks.py +0 -0
  144. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/prediction/types.py +0 -0
  145. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/uncertainty/__init__.py +0 -0
  146. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/uncertainty/composition.py +0 -0
  147. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/uncertainty/estimate.py +0 -0
  148. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/uncertainty/inflation.py +0 -0
  149. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/uncertainty/mode_detector.py +0 -0
  150. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/uncertainty/mode_events.py +0 -0
  151. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/uncertainty/sealing.py +0 -0
  152. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/uncertainty/self_assessment.py +0 -0
  153. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/core/uncertainty/types.py +0 -0
  154. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/estimation/__init__.py +0 -0
  155. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/estimation/config.py +0 -0
  156. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/estimation/noisy_gt.py +0 -0
  157. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/events/__init__.py +0 -0
  158. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/events/adapters.py +0 -0
  159. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/events/bus.py +0 -0
  160. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/events/types.py +0 -0
  161. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/examples/__init__.py +0 -0
  162. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/examples/closed_loop_smoke.py +0 -0
  163. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/examples/closed_loop_smoke_with_recovery.py +0 -0
  164. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/examples/replay_verification.py +0 -0
  165. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/hal/__init__.py +0 -0
  166. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/hal/messages/__init__.py +0 -0
  167. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/hal/messages/actuators.py +0 -0
  168. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/hal/messages/runtime.py +0 -0
  169. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/hal/messages/sensors.py +0 -0
  170. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/hal/protocols.py +0 -0
  171. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/properties/__init__.py +0 -0
  172. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/properties/baud.py +0 -0
  173. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/properties/erur.py +0 -0
  174. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/properties/fpb.py +0 -0
  175. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/properties/md.py +0 -0
  176. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/properties/rlb.py +0 -0
  177. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/py.typed +0 -0
  178. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/sensors/__init__.py +0 -0
  179. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/simulation/__init__.py +0 -0
  180. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/state/__init__.py +0 -0
  181. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/state/aggregator.py +0 -0
  182. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/state/messages.py +0 -0
  183. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/state/transforms.py +0 -0
  184. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/telemetry/__init__.py +0 -0
  185. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/telemetry/adapters.py +0 -0
  186. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/telemetry/channels.py +0 -0
  187. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/telemetry/mcap_sink.py +0 -0
  188. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/telemetry/replay.py +0 -0
  189. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/telemetry/serialization.py +0 -0
  190. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/telemetry/sink.py +0 -0
  191. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/traceability/__init__.py +0 -0
  192. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/traceability/analysis.py +0 -0
  193. {project_ghost-0.2.0 → project_ghost-0.2.1}/src/project_ghost/traceability/models.py +0 -0
  194. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/__init__.py +0 -0
  195. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/__init__.py +0 -0
  196. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/conftest.py +0 -0
  197. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_belief_consistency.py +0 -0
  198. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_belief_consistency_cli.py +0 -0
  199. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_belief_traceability.py +0 -0
  200. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_belief_traceability_cli.py +0 -0
  201. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_calibration.py +0 -0
  202. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_calibration_cli.py +0 -0
  203. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_cli.py +0 -0
  204. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_comparison.py +0 -0
  205. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_comparison_cli_build_manifest.py +0 -0
  206. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_comparison_cli_compare_belief.py +0 -0
  207. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_decision_trace.py +0 -0
  208. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_decision_trace_cli.py +0 -0
  209. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_determinism.py +0 -0
  210. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_integration.py +0 -0
  211. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_models.py +0 -0
  212. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_report.py +0 -0
  213. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_self_assessment_analysis.py +0 -0
  214. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_self_assessment_cli.py +0 -0
  215. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/analysis/test_summary.py +0 -0
  216. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/conftest.py +0 -0
  217. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/__init__.py +0 -0
  218. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/actuation/__init__.py +0 -0
  219. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/actuation/test_actuation.py +0 -0
  220. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/actuation/test_attitude_hold_policy.py +0 -0
  221. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/clock/__init__.py +0 -0
  222. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/clock/test_handle.py +0 -0
  223. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/clock/test_random_source.py +0 -0
  224. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/clock/test_scheduler.py +0 -0
  225. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/clock/test_sim_clock.py +0 -0
  226. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/decisions/__init__.py +0 -0
  227. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/decisions/test_calibration_aware.py +0 -0
  228. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/decisions/test_decisions.py +0 -0
  229. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/feedback/__init__.py +0 -0
  230. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/feedback/test_feedback.py +0 -0
  231. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/fusion/__init__.py +0 -0
  232. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/fusion/test_fusion.py +0 -0
  233. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/prediction/__init__.py +0 -0
  234. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/prediction/test_divergence.py +0 -0
  235. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/prediction/test_prediction.py +0 -0
  236. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/strategies.py +0 -0
  237. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/test_aging.py +0 -0
  238. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/test_composition.py +0 -0
  239. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/test_estimate.py +0 -0
  240. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/test_inflation.py +0 -0
  241. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/test_mode_detector.py +0 -0
  242. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/test_mode_events.py +0 -0
  243. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/test_nav_uncertainty.py +0 -0
  244. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/test_sealing.py +0 -0
  245. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/test_types.py +0 -0
  246. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/test_unstable_collections_linter.py +0 -0
  247. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/core/uncertainty/test_self_assessment.py +0 -0
  248. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/estimation/__init__.py +0 -0
  249. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/estimation/conftest.py +0 -0
  250. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/estimation/test_config.py +0 -0
  251. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/estimation/test_determinism.py +0 -0
  252. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/estimation/test_noisy_gt.py +0 -0
  253. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/events/__init__.py +0 -0
  254. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/events/test_adapters.py +0 -0
  255. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/events/test_bus.py +0 -0
  256. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/events/test_types.py +0 -0
  257. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/examples/__init__.py +0 -0
  258. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/examples/test_replay_verification.py +0 -0
  259. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/hal/__init__.py +0 -0
  260. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/hal/messages/__init__.py +0 -0
  261. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/hal/messages/test_actuators.py +0 -0
  262. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/hal/messages/test_runtime.py +0 -0
  263. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/hal/messages/test_sensors.py +0 -0
  264. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/hal/test_protocols.py +0 -0
  265. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/integration/__init__.py +0 -0
  266. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/integration/test_closed_loop_smoke.py +0 -0
  267. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/integration/test_closed_loop_smoke_with_recovery.py +0 -0
  268. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/properties/__init__.py +0 -0
  269. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/properties/test_baud_property.py +0 -0
  270. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/properties/test_cli_verify_properties.py +0 -0
  271. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/properties/test_erur_property.py +0 -0
  272. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/properties/test_fpb_property.py +0 -0
  273. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/properties/test_md_property.py +0 -0
  274. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/properties/test_rlb_property.py +0 -0
  275. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/properties/test_verify_baud_smoke.py +0 -0
  276. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/properties/test_verify_erur_smoke.py +0 -0
  277. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/properties/test_verify_fpb_smoke.py +0 -0
  278. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/properties/test_verify_md_smoke.py +0 -0
  279. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/properties/test_verify_rlb_smoke.py +0 -0
  280. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/state/__init__.py +0 -0
  281. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/state/test_aggregator.py +0 -0
  282. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/state/test_messages.py +0 -0
  283. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/state/test_transforms.py +0 -0
  284. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/__init__.py +0 -0
  285. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_actuation_adapter.py +0 -0
  286. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_adapters.py +0 -0
  287. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_calibrated_assessment_adapter.py +0 -0
  288. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_channels.py +0 -0
  289. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_decision_adapter.py +0 -0
  290. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_forward_prediction_adapter.py +0 -0
  291. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_fusion_result_adapter.py +0 -0
  292. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_in_memory_sink.py +0 -0
  293. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_integration.py +0 -0
  294. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_mcap_sink.py +0 -0
  295. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_prediction_outcome_adapter.py +0 -0
  296. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_replay.py +0 -0
  297. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_self_assessment_adapter.py +0 -0
  298. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/telemetry/test_serialization.py +0 -0
  299. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/test_smoke.py +0 -0
  300. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/traceability/__init__.py +0 -0
  301. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/traceability/conftest.py +0 -0
  302. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/traceability/test_analysis.py +0 -0
  303. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/traceability/test_cli.py +0 -0
  304. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/traceability/test_determinism.py +0 -0
  305. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/traceability/test_integration.py +0 -0
  306. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/traceability/test_models.py +0 -0
  307. {project_ghost-0.2.0 → project_ghost-0.2.1}/tests/traceability/test_report.py +0 -0
@@ -149,15 +149,98 @@ jobs:
149
149
  closed_loop_smoke.mcap
150
150
  closed_loop_smoke_with_recovery.mcap
151
151
 
152
+ determinism-cross-machine:
153
+ # Paper §8.4 self-enforcement: the reference smoke must produce
154
+ # byte-identical MCAPs and property-report JSON across Linux and
155
+ # Windows runners. This job runs the smoke + verifier on a matrix
156
+ # and uploads a single-line SHA-256 + JSON SHA-256 per runner;
157
+ # the aggregator step downloads both artifacts and asserts equality.
158
+ # If the assertion ever fires, some non-determinism leaked into
159
+ # either the pipeline (smoke MCAP) or the verifier (report JSON).
160
+ name: Cross-machine determinism (paper §8.4)
161
+ needs: test
162
+ strategy:
163
+ fail-fast: false
164
+ matrix:
165
+ os: [ubuntu-latest, windows-latest]
166
+ runs-on: ${{ matrix.os }}
167
+ steps:
168
+ - uses: actions/checkout@v4
169
+ - uses: actions/setup-python@v5
170
+ with:
171
+ python-version: "3.12"
172
+ cache: pip
173
+ - name: Install
174
+ shell: bash
175
+ run: |
176
+ python -m pip install --upgrade pip
177
+ pip install -e ".[dev]"
178
+ - name: Smoke + verify + hash
179
+ shell: bash
180
+ run: |
181
+ python -m project_ghost.examples.closed_loop_smoke
182
+ # Normalise the JSON output before hashing: parse, drop
183
+ # platform-dependent fields (mcap_path; path separators differ
184
+ # between Linux / Windows), and re-serialise canonically.
185
+ ghost verify-properties \
186
+ --mcap closed_loop_smoke.mcap --json \
187
+ > property_report_raw.json
188
+ python -c "
189
+ import hashlib, json, sys
190
+ mcap_sha = hashlib.sha256(open('closed_loop_smoke.mcap','rb').read()).hexdigest()
191
+ report = json.load(open('property_report_raw.json'))
192
+ report.pop('mcap_path', None)
193
+ canonical = json.dumps(report, sort_keys=True, separators=(',', ':'))
194
+ report_sha = hashlib.sha256(canonical.encode('utf-8')).hexdigest()
195
+ with open('determinism_${{ matrix.os }}.txt', 'w', newline='\n') as f:
196
+ f.write(f'MCAP {mcap_sha}\nREPORT {report_sha}\n')
197
+ "
198
+ cat determinism_${{ matrix.os }}.txt
199
+ - name: Upload determinism hash
200
+ uses: actions/upload-artifact@v4
201
+ with:
202
+ name: determinism-${{ matrix.os }}
203
+ path: determinism_${{ matrix.os }}.txt
204
+
205
+ determinism-cross-machine-assert:
206
+ # Downloads both runners' hash files and asserts byte-equality of
207
+ # the MCAP and JSON SHA-256 across Linux and Windows.
208
+ name: Cross-machine determinism assert (paper §8.4)
209
+ needs: determinism-cross-machine
210
+ runs-on: ubuntu-latest
211
+ steps:
212
+ - name: Download Linux hash
213
+ uses: actions/download-artifact@v4
214
+ with:
215
+ name: determinism-ubuntu-latest
216
+ path: linux/
217
+ - name: Download Windows hash
218
+ uses: actions/download-artifact@v4
219
+ with:
220
+ name: determinism-windows-latest
221
+ path: windows/
222
+ - name: Assert byte-equality
223
+ run: |
224
+ set -eo pipefail
225
+ echo "== Linux =="
226
+ cat linux/determinism_ubuntu-latest.txt
227
+ echo "== Windows =="
228
+ cat windows/determinism_windows-latest.txt
229
+ diff linux/determinism_ubuntu-latest.txt windows/determinism_windows-latest.txt
230
+ echo "::notice::Smoke MCAP and property-report JSON are byte-identical across Linux and Windows runners."
231
+
152
232
  tla-plus:
153
- # ADR-0036 self-enforcement: every push must keep the TLA+
154
- # specification's invariants satisfiable. TLC enumerates the full
155
- # reachable state space (bounded by M=2, K=1, W=3) and asserts
156
- # INV_BAUD, INV_ERUR, INV_PARTITION, INV_NO_INVENTED_CONFIDENCE
157
- # and INV_HISTORY_BOUND all hold. Any violation indicates a bug
158
- # in the spec, the policy encoding, or the property statements
159
- # themselves release-blocking.
160
- name: TLA+ mechanical verification (ADR-0036)
233
+ # ADR-0036 + paper §6 self-enforcement: every push must keep both
234
+ # TLA+ specifications' invariants satisfiable. TLC enumerates the
235
+ # full reachable state space and asserts every invariant. Any
236
+ # violation indicates a bug in the spec, the policy encoding, or
237
+ # the property statements themselves release-blocking.
238
+ #
239
+ # BaudErur.tla (M=2, K=1, W=3): INV_BAUD, INV_ERUR, INV_PARTITION,
240
+ # INV_NO_INVENTED_CONFIDENCE, INV_HISTORY_BOUND.
241
+ # Rlb.tla (W=4, MAX_DIRTY_RUN=12): INV_RLB (Theorem 1),
242
+ # INV_PEAK_BOUNDED, INV_WINDOW_BOUND.
243
+ name: TLA+ mechanical verification (ADR-0036 + paper §6)
161
244
  needs: test
162
245
  runs-on: ubuntu-latest
163
246
  steps:
@@ -186,14 +269,23 @@ jobs:
186
269
  # non-zero exit from java OR a broken pipe fails this step.
187
270
  java -cp ../../tla2tools.jar tlc2.TLC \
188
271
  -config BaudErur.cfg \
189
- BaudErur.tla 2>&1 | tee tlc_output.log
272
+ BaudErur.tla 2>&1 | tee tlc_output_baud_erur.log
190
273
  # Belt-and-braces success check: TLC exit code already gated
191
274
  # by pipefail, this just asserts the canonical success
192
275
  # signature is in the log we are about to archive.
193
- grep -q "Model checking completed" tlc_output.log
276
+ grep -q "Model checking completed" tlc_output_baud_erur.log
277
+ - name: Run TLC on Rlb spec (Theorem 1)
278
+ working-directory: docs/proofs
279
+ run: |
280
+ java -cp ../../tla2tools.jar tlc2.TLC \
281
+ -config Rlb.cfg \
282
+ Rlb.tla 2>&1 | tee tlc_output_rlb.log
283
+ grep -q "Model checking completed" tlc_output_rlb.log
194
284
  - name: Upload TLC output
195
285
  if: always()
196
286
  uses: actions/upload-artifact@v4
197
287
  with:
198
288
  name: tlc-output
199
- path: docs/proofs/tlc_output.log
289
+ path: |
290
+ docs/proofs/tlc_output_baud_erur.log
291
+ docs/proofs/tlc_output_rlb.log
@@ -7,6 +7,88 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.1] - 2026-06-11
11
+
12
+ Paper-readiness pass: artifacts in support of the v0.2.x academic
13
+ write-up at [`docs/paper/project_ghost_v0_2.md`](docs/paper/project_ghost_v0_2.md),
14
+ the LaTeX arXiv source at [`docs/paper/arxiv/main.tex`](docs/paper/arxiv/main.tex),
15
+ and a second TLA+ specification mechanically verifying Theorem 1
16
+ (the tight recovery latency bound `L ≤ peak + W − 1`).
17
+
18
+ ### Added
19
+
20
+ - **TLA+ `Rlb.tla` specification** mechanically verifying Theorem 1
21
+ ([`docs/proofs/Rlb.tla`](docs/proofs/Rlb.tla),
22
+ [`docs/proofs/Rlb.cfg`](docs/proofs/Rlb.cfg)). Mirrors the
23
+ verifier algorithm of
24
+ [`src/project_ghost/properties/rlb.py`](src/project_ghost/properties/rlb.py)
25
+ and checks three invariants over the full reachable state space
26
+ (`W=4, MAX_DIRTY_RUN=12`): `INV_RLB` (the formal recovery latency
27
+ bound `L ≤ peak + W − 1`), `INV_PEAK_BOUNDED`, and
28
+ `INV_WINDOW_BOUND`. CI-enforced on every push alongside
29
+ `BaudErur.tla`.
30
+ - **Violation showcase**
31
+ ([`closed_loop_smoke_violated.py`](src/project_ghost/examples/closed_loop_smoke_violated.py)):
32
+ a smoke that swaps the reference calibrator for
33
+ `_BuggyPassthroughCalibrator` (never downgrades), proving the
34
+ property verifier detects the bug — `BAUD-v1: VIOLATED`,
35
+ `violation_count: 12` (6 cycles × 2 postconditions), exit code 1.
36
+ Companion artifact for paper §8.2 demonstrating detection capacity
37
+ of the reproducibility primitive (contribution C3).
38
+ - **Cross-machine determinism CI jobs**
39
+ (`determinism-cross-machine` + `determinism-cross-machine-assert`
40
+ in [`ci.yml`](.github/workflows/ci.yml)): the reference smoke runs
41
+ on a `{ubuntu-latest, windows-latest}` matrix, each runner
42
+ publishes the SHA-256 of its MCAP and property-report JSON, and
43
+ the aggregator step `diff`s the two files. Any disagreement fails
44
+ the build, operationalising paper §8.4.
45
+ - **Parametric metrics script**
46
+ ([`docs/paper/scripts/measure_metrics.py`](docs/paper/scripts/measure_metrics.py)):
47
+ reproducibly measures verifier runtime, MCAP size, smoke runtime,
48
+ and HOLDS verdict across 3 calibrator parameterisations
49
+ `(M=4,K=2), (M=3,K=1), (M=5,K=3)` × 3 trace lengths `n ∈ {10, 50, 200}`.
50
+ Writes results to
51
+ [`docs/paper/outputs/metrics.json`](docs/paper/outputs/metrics.json).
52
+ All 9 combinations report all 5 properties HOLDS.
53
+ - **Paper draft** at
54
+ [`docs/paper/project_ghost_v0_2.md`](docs/paper/project_ghost_v0_2.md)
55
+ with:
56
+ - 4 contributions formulated as C1–C4: tight recovery latency
57
+ bound (Theorem 1), mechanically verified partition theorem,
58
+ reproducibility primitive with demonstrated detection capacity,
59
+ end-to-end safety citation pattern.
60
+ - **§6 Theorem 1 with rigorous proof by sliding-window trace**
61
+ (accumulation → saturation → flush → recovery) and two
62
+ corollaries on the operational regime and structural sanity.
63
+ - §2 Related work with 10 prior tools cited (RTAMT, MoonLight,
64
+ ROSMonitoring, ROSRV, Shielding, CBF Toolbox, Conformal
65
+ prediction, Timed Automata SC, Rizaldi survey) and §2.3
66
+ 9-dimension comparison matrix.
67
+ - §8 Evaluation with violation-showcase JSON output and the
68
+ 9-run parametric policy table.
69
+ - 18 references (vs. 7 in the initial draft).
70
+ - **arXiv submission package** at
71
+ [`docs/paper/arxiv/`](docs/paper/arxiv/):
72
+ - [`main.tex`](docs/paper/arxiv/main.tex) — self-contained
73
+ LaTeX source (~600 lines, `article` class, compiles with
74
+ pdflatex + bibtex).
75
+ - [`refs.bib`](docs/paper/arxiv/refs.bib) — BibTeX bibliography
76
+ (21 entries).
77
+ - [`README.md`](docs/paper/arxiv/README.md) — submission
78
+ instructions for arXiv (categories: cs.SE primary, cs.LO +
79
+ cs.RO secondary; MSC 68N30, 68V20), plus adaptation notes for
80
+ RV 2026 and FMAS 2026 workshop versions.
81
+ - Per-file ruff ignore for [`docs/paper/scripts/`](docs/paper/scripts/)
82
+ to permit `M`, `K` math notation matching the ADRs and the
83
+ Unicode `×` matching the paper's table captions.
84
+
85
+ ### Notes
86
+
87
+ - Suite remains 1665 tests passing, ruff + mypy strict + deptry
88
+ clean after the additions. The new smoke, script, and TLA+ spec
89
+ are wired into the same lint / type / TLC infrastructure as the
90
+ rest of the repo.
91
+
10
92
  ## [0.2.0] - 2026-06-10
11
93
 
12
94
  Major addition: a fourth layer of evidence for the property set —
@@ -172,7 +254,8 @@ safety property set as the project's central contribution.
172
254
  - All property reports are deterministic: same MCAP bytes produce
173
255
  byte-identical JSON output across machines.
174
256
 
175
- [Unreleased]: https://github.com/JFHelvetius/ghost/compare/v0.2.0...HEAD
257
+ [Unreleased]: https://github.com/JFHelvetius/ghost/compare/v0.2.1...HEAD
258
+ [0.2.1]: https://github.com/JFHelvetius/ghost/compare/v0.2.0...v0.2.1
176
259
  [0.2.0]: https://github.com/JFHelvetius/ghost/compare/v0.1.1...v0.2.0
177
260
  [0.1.1]: https://github.com/JFHelvetius/ghost/compare/v0.1.0...v0.1.1
178
261
  [0.1.0]: https://github.com/JFHelvetius/ghost/releases/tag/v0.1.0
@@ -18,12 +18,12 @@ abstract: >-
18
18
  and self-enforced on every push by CI.
19
19
  type: software
20
20
  authors:
21
- - family-names: Mateos
22
- given-names: J. M.
21
+ - family-names: Menéndez Mateos
22
+ given-names: Javier
23
23
  email: jfhelvetius@gmail.com
24
24
  affiliation: Independent
25
- version: 0.2.0
26
- date-released: 2026-06-10
25
+ version: 0.2.1
26
+ date-released: 2026-06-11
27
27
  url: "https://github.com/JFHelvetius/ghost"
28
28
  repository-code: "https://github.com/JFHelvetius/ghost"
29
29
  repository-artifact: "https://pypi.org/project/project-ghost/"
@@ -45,8 +45,8 @@ preferred-citation:
45
45
  type: software
46
46
  title: "Project Ghost: Autonomy under uncertainty"
47
47
  authors:
48
- - family-names: Mateos
49
- given-names: J. M.
48
+ - family-names: Menéndez Mateos
49
+ given-names: Javier
50
50
  email: jfhelvetius@gmail.com
51
51
  version: 0.2.0
52
52
  date-released: 2026-06-10
@@ -56,8 +56,8 @@ references:
56
56
  - type: software
57
57
  title: "ADR-0031 — Bounded Action Under Drift Property v1 (BAUD)"
58
58
  authors:
59
- - family-names: Mateos
60
- given-names: J. M.
59
+ - family-names: Menéndez Mateos
60
+ given-names: Javier
61
61
  url: "https://github.com/JFHelvetius/ghost/blob/main/docs/adr/0031-bounded-action-under-drift-property-v1.md"
62
62
  notes: >-
63
63
  Formal statement of the BAUD-v1 property: when prediction
@@ -66,8 +66,8 @@ references:
66
66
  - type: software
67
67
  title: "ADR-0032 — Eventual Reactivation Under Recovery Property v1 (ERUR)"
68
68
  authors:
69
- - family-names: Mateos
70
- given-names: J. M.
69
+ - family-names: Menéndez Mateos
70
+ given-names: Javier
71
71
  url: "https://github.com/JFHelvetius/ghost/blob/main/docs/adr/0032-eventual-reactivation-under-recovery-property-v1.md"
72
72
  notes: >-
73
73
  Formal statement of the ERUR-v1 property: when drift is
@@ -75,8 +75,8 @@ references:
75
75
  - type: software
76
76
  title: "ADR-0033 — Monotonic Degradation Property v1 (MD)"
77
77
  authors:
78
- - family-names: Mateos
79
- given-names: J. M.
78
+ - family-names: Menéndez Mateos
79
+ given-names: Javier
80
80
  url: "https://github.com/JFHelvetius/ghost/blob/main/docs/adr/0033-monotonic-degradation-property-v1.md"
81
81
  notes: >-
82
82
  Formal statement of the MD-v1 property: the reference
@@ -84,8 +84,8 @@ references:
84
84
  - type: software
85
85
  title: "ADR-0034 — Recovery Latency Bound Property v1 (RLB)"
86
86
  authors:
87
- - family-names: Mateos
88
- given-names: J. M.
87
+ - family-names: Menéndez Mateos
88
+ given-names: Javier
89
89
  url: "https://github.com/JFHelvetius/ghost/blob/main/docs/adr/0034-recovery-latency-bound-property-v1.md"
90
90
  notes: >-
91
91
  Formal statement of the RLB-v1 property: dirty-run length
@@ -93,8 +93,8 @@ references:
93
93
  - type: software
94
94
  title: "ADR-0035 — False Positive Bound Property v1 (FPB)"
95
95
  authors:
96
- - family-names: Mateos
97
- given-names: J. M.
96
+ - family-names: Menéndez Mateos
97
+ given-names: Javier
98
98
  url: "https://github.com/JFHelvetius/ghost/blob/main/docs/adr/0035-false-positive-bound-property-v1.md"
99
99
  notes: >-
100
100
  Formal statement of the FPB-v1 property: empirical BAUD
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: project-ghost
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Autonomy under uncertainty: closed-loop reference pipeline + 5 formal safety properties verifiable byte-exact from any MCAP + TLA+ mechanically-verified BAUD/ERUR/MD/partition over the abstract state space.
5
5
  Project-URL: Homepage, https://github.com/JFHelvetius/ghost
6
6
  Project-URL: Repository, https://github.com/JFHelvetius/ghost
@@ -78,7 +78,31 @@ Five properties, five citable claims, exit code `0` iff every property holds. Ea
78
78
  | **RLB-v1** | Recovery Latency Bound ([ADR-0034](docs/adr/0034-recovery-latency-bound-property-v1.md)) | Dirty-run length is bounded by `peak + W - 1` where W is the window size |
79
79
  | **FPB-v1** | False Positive Bound observer ([ADR-0035](docs/adr/0035-false-positive-bound-property-v1.md)) | Empirical BAUD fire rate is exposed and bounded for regression gating |
80
80
 
81
- The honest part: the individual ideas (uncertainty calibration, action gating on confidence, fault detection) are decades-old robotics research. The contribution of Ghost is not new theory — it's **the specific combination, end-to-end, with byte-exact replay verification and a CLI-grade external surface**. See [ADR-0031 §Context](docs/adr/0031-bounded-action-under-drift-property-v1.md) for the honest framing.
81
+ ### Contributions
82
+
83
+ Project Ghost makes five concrete, citable contributions on top of the
84
+ existing literature on uncertainty in robotics. The underlying
85
+ ingredients (Bayesian filters, calibration, FDI, runtime supervisors)
86
+ are well-established; **the contributions are in how they are
87
+ combined, stated, and verified**:
88
+
89
+ | # | Contribution | Status |
90
+ |---|---|---|
91
+ | **PV-1** | A **reproducibility primitive** — `ghost verify-properties --mcap <log>` reduces "is this run safe?" to a single shell command returning a byte-exact verdict with exit code `0` iff every property holds. Verifier is a pure function over content-addressed MCAP; no replay, no simulation, no trust in the producer. | Shipped (CLI v0.2.0) |
92
+ | **PV-2** | A **formal partition theorem**: BAUD-v1 + ERUR-v1 partition the space of per-cycle conditional behaviour. Stated in TLA+ as `INV_PARTITION`, **mechanically verified by TLC** over the full reachable state space of the abstract model ([ADR-0036](docs/adr/0036-tla-plus-mechanical-verification-of-baud-erur.md)). Promoted from "observed on one trace" to "proved on the model". | Shipped (CI green) |
93
+ | **PV-3** | A **structural recovery latency bound** `L ≤ peak + W − 1` for sliding-window calibration histories with `MahalanobisDowngradePolicy(M, K)` ([ADR-0034](docs/adr/0034-recovery-latency-bound-property-v1.md)). Drift-then-recovery smoke fires at the bound exactly (38 = 7 + 32 − 1), proving the bound is tight. | Shipped (RLB-v1) |
94
+ | **PV-4** | A **safe-reason set encoding pattern** for safety properties: `S_BAUD-v1 = {"attitude_hold_hold", "kill_zero_throttle"}` — a closed taxonomy of strings classifying which non-PROCEED actuator commands count as conservative, replacing fragile `command is None` checks with an extensible, externally-auditable allowlist. | Shipped (ADR-0031) |
95
+ | **PV-5** | A **citation pattern** for safety claims: content-addressed MCAP + ADR + pure-function verifier + Hypothesis property test + CI gate + tagged release + OIDC-signed PyPI wheel — assembled as one coherent reproducibility unit. The headline claim is operationally re-runnable from `pip install project-ghost==0.2.0`. | Shipped (this release) |
96
+
97
+ For each, the binding ADR is the formal statement; the verifier is
98
+ the executable test; the inline witness in `SmokeSummary.*_report`
99
+ is the self-evidence; and CI is the continuous guarantee.
100
+
101
+ Theoretically novel? No: this is an engineering and citation
102
+ contribution, not a new theorem. **Operationally novel? Yes** —
103
+ this is the pattern getting actually built and shipped, in a form
104
+ that lets third parties verify their own runs without trusting
105
+ the producer.
82
106
 
83
107
  ## Try it without installing anything
84
108
 
@@ -33,7 +33,31 @@ Five properties, five citable claims, exit code `0` iff every property holds. Ea
33
33
  | **RLB-v1** | Recovery Latency Bound ([ADR-0034](docs/adr/0034-recovery-latency-bound-property-v1.md)) | Dirty-run length is bounded by `peak + W - 1` where W is the window size |
34
34
  | **FPB-v1** | False Positive Bound observer ([ADR-0035](docs/adr/0035-false-positive-bound-property-v1.md)) | Empirical BAUD fire rate is exposed and bounded for regression gating |
35
35
 
36
- The honest part: the individual ideas (uncertainty calibration, action gating on confidence, fault detection) are decades-old robotics research. The contribution of Ghost is not new theory — it's **the specific combination, end-to-end, with byte-exact replay verification and a CLI-grade external surface**. See [ADR-0031 §Context](docs/adr/0031-bounded-action-under-drift-property-v1.md) for the honest framing.
36
+ ### Contributions
37
+
38
+ Project Ghost makes five concrete, citable contributions on top of the
39
+ existing literature on uncertainty in robotics. The underlying
40
+ ingredients (Bayesian filters, calibration, FDI, runtime supervisors)
41
+ are well-established; **the contributions are in how they are
42
+ combined, stated, and verified**:
43
+
44
+ | # | Contribution | Status |
45
+ |---|---|---|
46
+ | **PV-1** | A **reproducibility primitive** — `ghost verify-properties --mcap <log>` reduces "is this run safe?" to a single shell command returning a byte-exact verdict with exit code `0` iff every property holds. Verifier is a pure function over content-addressed MCAP; no replay, no simulation, no trust in the producer. | Shipped (CLI v0.2.0) |
47
+ | **PV-2** | A **formal partition theorem**: BAUD-v1 + ERUR-v1 partition the space of per-cycle conditional behaviour. Stated in TLA+ as `INV_PARTITION`, **mechanically verified by TLC** over the full reachable state space of the abstract model ([ADR-0036](docs/adr/0036-tla-plus-mechanical-verification-of-baud-erur.md)). Promoted from "observed on one trace" to "proved on the model". | Shipped (CI green) |
48
+ | **PV-3** | A **structural recovery latency bound** `L ≤ peak + W − 1` for sliding-window calibration histories with `MahalanobisDowngradePolicy(M, K)` ([ADR-0034](docs/adr/0034-recovery-latency-bound-property-v1.md)). Drift-then-recovery smoke fires at the bound exactly (38 = 7 + 32 − 1), proving the bound is tight. | Shipped (RLB-v1) |
49
+ | **PV-4** | A **safe-reason set encoding pattern** for safety properties: `S_BAUD-v1 = {"attitude_hold_hold", "kill_zero_throttle"}` — a closed taxonomy of strings classifying which non-PROCEED actuator commands count as conservative, replacing fragile `command is None` checks with an extensible, externally-auditable allowlist. | Shipped (ADR-0031) |
50
+ | **PV-5** | A **citation pattern** for safety claims: content-addressed MCAP + ADR + pure-function verifier + Hypothesis property test + CI gate + tagged release + OIDC-signed PyPI wheel — assembled as one coherent reproducibility unit. The headline claim is operationally re-runnable from `pip install project-ghost==0.2.0`. | Shipped (this release) |
51
+
52
+ For each, the binding ADR is the formal statement; the verifier is
53
+ the executable test; the inline witness in `SmokeSummary.*_report`
54
+ is the self-evidence; and CI is the continuous guarantee.
55
+
56
+ Theoretically novel? No: this is an engineering and citation
57
+ contribution, not a new theorem. **Operationally novel? Yes** —
58
+ this is the pattern getting actually built and shipped, in a form
59
+ that lets third parties verify their own runs without trusting
60
+ the producer.
37
61
 
38
62
  ## Try it without installing anything
39
63
 
@@ -87,19 +87,51 @@ shows the five property veredictos inline. Same code that
87
87
 
88
88
  [See the full overview →](properties/index.md)
89
89
 
90
- ## Honest framing
91
-
92
- The individual ideas Ghost relies on — uncertainty calibration,
93
- action gating on confidence, fault detection and isolation,
94
- calibrated probabilistic predictions are well-established robotics
95
- research, much of it decades old. **The contribution of Project
96
- Ghost is not new theory.** It is the specific opinionated combination,
97
- end-to-end, with byte-exact replay verification and a CLI-grade
98
- external surface that third parties can use against any captured run
99
- without trusting the producer.
100
-
101
- In other words: a *carefully built reference of a pattern that is
102
- discussed more often than it is implemented*.
90
+ ## Contributions
91
+
92
+ The underlying ingredients (Bayesian filters, calibration, FDI,
93
+ runtime supervisors) are well-established. Project Ghost makes five
94
+ concrete, citable contributions in **how they are combined, stated,
95
+ and verified**:
96
+
97
+ - **PV-1 Reproducibility primitive.**
98
+ `ghost verify-properties --mcap <log>` reduces "is this run safe?"
99
+ to one shell command returning a byte-exact verdict with exit code
100
+ `0` iff every property holds. Verifier is a pure function over
101
+ content-addressed MCAP no replay, no simulation, no trust in the
102
+ producer.
103
+ - **PV-2 — Formal partition theorem.**
104
+ BAUD-v1 + ERUR-v1 partition the space of per-cycle conditional
105
+ behaviour. Stated in TLA+ as `INV_PARTITION`, **mechanically
106
+ verified by TLC** over the full reachable state space of the
107
+ abstract model ([ADR-0036](adr/0036-tla-plus-mechanical-verification-of-baud-erur.md)).
108
+ Promoted from "observed on one trace" to "proved on the model".
109
+ - **PV-3 — Structural recovery latency bound.**
110
+ `L ≤ peak + W − 1` for sliding-window calibration histories with
111
+ `MahalanobisDowngradePolicy(M, K)`. Drift-then-recovery smoke fires
112
+ at the bound exactly (38 = 7 + 32 − 1), proving the bound is tight
113
+ ([ADR-0034](adr/0034-recovery-latency-bound-property-v1.md)).
114
+ - **PV-4 — Safe-reason set encoding pattern.**
115
+ `S_BAUD-v1 = {"attitude_hold_hold", "kill_zero_throttle"}` — a
116
+ closed taxonomy of strings classifying which non-PROCEED actuator
117
+ commands count as conservative, replacing fragile `command is None`
118
+ checks with an extensible, externally-auditable allowlist
119
+ ([ADR-0031](adr/0031-bounded-action-under-drift-property-v1.md)).
120
+ - **PV-5 — End-to-end safety citation pattern.**
121
+ Content-addressed MCAP + ADR + pure-function verifier + Hypothesis
122
+ property test + CI gate + tagged release + OIDC-signed PyPI wheel
123
+ — assembled as one coherent reproducibility unit. The headline
124
+ claim is operationally re-runnable from `pip install project-ghost==0.2.0`.
125
+
126
+ For each, the binding ADR is the formal statement, the verifier is
127
+ the executable test, the inline witness in `SmokeSummary.*_report`
128
+ is the self-evidence, and CI is the continuous guarantee.
129
+
130
+ Theoretically novel? No — this is an engineering and citation
131
+ contribution, not a new theorem. **Operationally novel? Yes** —
132
+ this is the pattern getting actually built and shipped, in a form
133
+ that lets third parties verify their own runs against the captured
134
+ MCAP without trusting the producer.
103
135
 
104
136
  ## Architecture in one diagram
105
137
 
@@ -0,0 +1,147 @@
1
+ # arXiv submission package
2
+
3
+ This directory contains the LaTeX source ready for arXiv submission
4
+ and as the starting point for RV 2026 / FMAS 2026 workshop versions.
5
+
6
+ ## Files
7
+
8
+ | File | Purpose |
9
+ |---|---|
10
+ | [`main.tex`](main.tex) | Paper source (article class, ~600 lines, self-contained) |
11
+ | [`refs.bib`](refs.bib) | BibTeX bibliography (18 entries) |
12
+ | `main.pdf` | Generated locally; not committed |
13
+
14
+ The Markdown extended version lives at
15
+ [`../project_ghost_v0_2.md`](../project_ghost_v0_2.md) and is the
16
+ authoritative narrative source. The LaTeX is a faithful condensed
17
+ rendering suitable for venue submission.
18
+
19
+ ## Building locally
20
+
21
+ Requires TeX Live or MiKTeX with `pdflatex` + `bibtex`.
22
+
23
+ ```bash
24
+ cd docs/paper/arxiv/
25
+ pdflatex main
26
+ bibtex main
27
+ pdflatex main
28
+ pdflatex main
29
+ ```
30
+
31
+ Output: `main.pdf` (~12 pages).
32
+
33
+ ## arXiv submission checklist
34
+
35
+ ### 1. Account and credentials
36
+
37
+ - Sign in at <https://arxiv.org/user/login>.
38
+ - If you do not already have a moderator endorsement, you will need
39
+ one for first-time submission in **cs.SE** or **cs.LO**. Endorsement
40
+ is per-archive; once you have it for one, you can cross-list to the
41
+ others. See <https://arxiv.org/help/endorsement>.
42
+
43
+ ### 2. Upload bundle
44
+
45
+ arXiv accepts either a single PDF (simpler) or a tarball with the
46
+ LaTeX source (preferred — arXiv extracts metadata, indexes the
47
+ abstract, and renders the references correctly).
48
+
49
+ **Preferred: source tarball.**
50
+
51
+ ```bash
52
+ cd docs/paper/arxiv/
53
+ tar czf project_ghost_v0_2_arxiv.tar.gz main.tex refs.bib main.bbl
54
+ ```
55
+
56
+ (Include `main.bbl` so arXiv does not have to re-run `bibtex`.)
57
+
58
+ Upload at <https://arxiv.org/submit>. arXiv will compile your source
59
+ server-side and show you the rendered preview. Iterate until it
60
+ looks correct.
61
+
62
+ ### 3. Categories
63
+
64
+ Primary and secondary classifications for the submission form:
65
+
66
+ - **Primary:** `cs.SE` — Software Engineering. The paper is
67
+ fundamentally about a build-and-ship pattern with reproducibility
68
+ as the headline.
69
+ - **Secondary 1:** `cs.LO` — Logic in Computer Science. Theorem 1
70
+ + the TLA+/TLC mechanisation belong here.
71
+ - **Secondary 2:** `cs.RO` — Robotics. The application domain.
72
+
73
+ MSC classification: `68N30` (Mathematical aspects of software
74
+ engineering), `68V20` (Formal methods).
75
+
76
+ ACM Computing Classification System (optional, free-text):
77
+ `Software and its engineering → Software verification and validation`;
78
+ `Computing methodologies → Robotics`.
79
+
80
+ ### 4. Title, abstract, and metadata
81
+
82
+ - **Title:** `Project Ghost: A Verifiable Safety-Property Surface for Autonomy Under Uncertainty`
83
+ - **Authors:** `Javier Menéndez Mateos` (single author).
84
+ - **Comments line** (free text, displayed under the abstract):
85
+ ```
86
+ 12 pages, 2 tables. Code, MCAPs, TLA+ specs, and TLC verification
87
+ output reproducible from https://github.com/JFHelvetius/ghost
88
+ (release v0.2.0) and from pip install project-ghost==0.2.0.
89
+ ```
90
+ - **Abstract:** copy verbatim from the `\begin{abstract}` block in
91
+ `main.tex` (arXiv accepts plain text; strip the LaTeX commands).
92
+ - **Report-no, journal-ref, DOI:** leave empty for v0.2.0 preprint.
93
+ Update on resubmission after a workshop accepts the paper.
94
+ - **License:** the source is Apache-2.0; on arXiv select
95
+ `arXiv.org perpetual, non-exclusive license to distribute` (the
96
+ default — does not transfer copyright). The CC-BY option is also
97
+ appropriate if you prefer it.
98
+
99
+ ### 5. After submission
100
+
101
+ - arXiv assigns a paper ID of the form `arXiv:2606.NNNNN` (the
102
+ prefix is YYMM).
103
+ - Once accepted, update the project repository:
104
+ - `CITATION.cff`: add the arXiv ID and DOI under `identifiers`.
105
+ - `README.md`: add a "Cite this work" badge linking to the arXiv
106
+ abstract page.
107
+ - This `README.md`: record the arXiv ID and submission date here.
108
+ - arXiv DOIs become routable via `https://arxiv.org/abs/<id>` and via
109
+ `https://doi.org/10.48550/arXiv.<id>`.
110
+
111
+ ## RV 2026 (Runtime Verification) submission
112
+
113
+ The same `main.tex` is reusable as the basis for an RV 2026 tool
114
+ paper or regular paper submission. RV typically uses Springer LNCS.
115
+
116
+ 1. Download the LNCS class files:
117
+ <https://www.springer.com/gp/computer-science/lncs/conference-proceedings-guidelines>.
118
+ 2. Replace the top of `main.tex`:
119
+ ```latex
120
+ \documentclass[runningheads]{llncs}
121
+ ```
122
+ Remove the `\usepackage{geometry}` line (LNCS sets its own
123
+ margins).
124
+ 3. Replace the author block with the LNCS form:
125
+ ```latex
126
+ \author{Javier Menéndez Mateos\inst{1}}
127
+ \institute{Independent\\\email{jfhelvetius@gmail.com}}
128
+ ```
129
+ 4. Adjust page count to the venue limit (RV regular ~16, tool ~6).
130
+ The current paper at ~12 pages fits regular comfortably; for a
131
+ tool paper, trim §1.2 + §9 and condense §6's proof.
132
+ 5. Submit via the RV 2026 EasyChair URL when the CFP opens
133
+ (typically March–July).
134
+
135
+ ## FMAS 2026 (Formal Methods for Autonomous Systems)
136
+
137
+ FMAS uses EPTCS or LNCS depending on the year. Check the CFP at
138
+ <https://fmasworkshop.github.io/FMAS2026/>. The current `main.tex`
139
+ adapts directly; FMAS tends to weight the autonomy-domain framing
140
+ higher than RV does, so consider expanding §1's motivation
141
+ paragraph for FMAS submission.
142
+
143
+ ## Versioning
144
+
145
+ This package corresponds to **Project Ghost v0.2.0**, released
146
+ 2026-06-10. Update version + date in `main.tex` (\\date and
147
+ abstract) when bumping for resubmission.