hypertopos 0.7.0__tar.gz → 0.7.2__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 (329) hide show
  1. {hypertopos-0.7.0 → hypertopos-0.7.2}/CHANGELOG.md +44 -0
  2. {hypertopos-0.7.0 → hypertopos-0.7.2}/LICENSE.md +1 -1
  3. {hypertopos-0.7.0 → hypertopos-0.7.2}/PKG-INFO +6 -1
  4. {hypertopos-0.7.0 → hypertopos-0.7.2}/README.md +2 -1
  5. {hypertopos-0.7.0 → hypertopos-0.7.2}/SECURITY.md +1 -1
  6. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/api-reference.md +1 -0
  7. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/concepts.md +2 -1
  8. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/configuration.md +56 -0
  9. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/data-format.md +2 -1
  10. hypertopos-0.7.2/docs/patent-implementation-map.md +123 -0
  11. hypertopos-0.7.2/docs/refutations.md +71 -0
  12. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/__init__.py +1 -1
  13. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/builder/builder.py +455 -6
  14. hypertopos-0.7.2/hypertopos/builder/conformance_mapping.py +246 -0
  15. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/cli/build.py +36 -0
  16. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/cli/main.py +9 -0
  17. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/cli/schema.py +79 -0
  18. hypertopos-0.7.2/hypertopos/engine/calibration_label_aware.py +167 -0
  19. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/chains.py +60 -1
  20. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/counterfactual.py +44 -0
  21. hypertopos-0.7.2/hypertopos/engine/diagnostics.py +107 -0
  22. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/dim_audit.py +88 -0
  23. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/geometry.py +42 -2
  24. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/model/objects.py +7 -0
  25. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/model/sphere.py +49 -6
  26. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/navigation/navigator.py +743 -42
  27. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/storage/_schemas.py +6 -0
  28. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/storage/calibration_history.py +2 -0
  29. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/storage/reader.py +45 -3
  30. {hypertopos-0.7.0 → hypertopos-0.7.2}/pyproject.toml +6 -1
  31. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/conftest.py +34 -2
  32. hypertopos-0.7.2/tests/test_audit_label_alignment.py +245 -0
  33. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_builder.py +95 -0
  34. hypertopos-0.7.2/tests/test_calibration_label_aware.py +225 -0
  35. hypertopos-0.7.2/tests/test_chain_edge_potentials.py +156 -0
  36. hypertopos-0.7.2/tests/test_cli_label_aware_flag.py +112 -0
  37. hypertopos-0.7.2/tests/test_conformance_mapping.py +600 -0
  38. hypertopos-0.7.2/tests/test_conftest_magicmock_restore.py +50 -0
  39. hypertopos-0.7.2/tests/test_counterfactual_frozen_trajectory.py +278 -0
  40. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_delta_dim_aggregation_consumers.py +80 -34
  41. hypertopos-0.7.2/tests/test_delta_norm_signed.py +362 -0
  42. hypertopos-0.7.2/tests/test_diagnostics.py +115 -0
  43. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_dim_audit.py +81 -0
  44. hypertopos-0.7.2/tests/test_dim_quality_warnings.py +430 -0
  45. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_edge_dim_aggregations_builder.py +76 -0
  46. hypertopos-0.7.2/tests/test_kind_tag_mismatch_warning.py +277 -0
  47. hypertopos-0.7.2/tests/test_label_audit_schema.py +233 -0
  48. hypertopos-0.7.2/tests/test_m1_1_builder_wiring.py +368 -0
  49. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_model.py +67 -0
  50. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_navigation.py +9 -3
  51. hypertopos-0.7.2/tests/test_signed_confidence_ranking.py +401 -0
  52. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_simulate_dimension_change.py +38 -40
  53. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_sphere_format_version.py +27 -2
  54. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_topology_anomalies.py +3 -0
  55. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_topology_trajectory_anomalies.py +3 -0
  56. hypertopos-0.7.0/tests/test_dim_quality_warnings.py +0 -217
  57. {hypertopos-0.7.0 → hypertopos-0.7.2}/.github/workflows/publish-pypi.yml +0 -0
  58. {hypertopos-0.7.0 → hypertopos-0.7.2}/.gitignore +0 -0
  59. {hypertopos-0.7.0 → hypertopos-0.7.2}/ROADMAP.md +0 -0
  60. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/README.md +0 -0
  61. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/architecture.md +0 -0
  62. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/LICENSE +0 -0
  63. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/README.md +0 -0
  64. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/README.md +0 -0
  65. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/SUMMARY.md +0 -0
  66. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r1/0.1.0-exp-a-report.md +0 -0
  67. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r1/0.1.0-exp-a-scoring.md +0 -0
  68. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r1/0.1.0-exp-b-report.md +0 -0
  69. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r1/0.1.0-exp-b-scoring.md +0 -0
  70. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r1/0.1.0-settings.md +0 -0
  71. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r2/0.1.0-exp-a-report.md +0 -0
  72. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r2/0.1.0-exp-a-scoring.md +0 -0
  73. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r2/0.1.0-exp-b-report.md +0 -0
  74. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r2/0.1.0-exp-b-scoring.md +0 -0
  75. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r2/0.1.0-settings.md +0 -0
  76. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r3/0.1.0-exp-a-report.md +0 -0
  77. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r3/0.1.0-exp-a-scoring.md +0 -0
  78. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r3/0.1.0-exp-b-report.md +0 -0
  79. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r3/0.1.0-exp-b-scoring.md +0 -0
  80. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r3/0.1.0-settings.md +0 -0
  81. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r4/0.1.0-exp-a-report.md +0 -0
  82. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r4/0.1.0-exp-a-scoring.md +0 -0
  83. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r4/0.1.0-exp-b-report.md +0 -0
  84. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r4/0.1.0-exp-b-scoring.md +0 -0
  85. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r4/0.1.0-settings.md +0 -0
  86. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r5/0.1.0-exp-a-report.md +0 -0
  87. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r5/0.1.0-exp-a-scoring.md +0 -0
  88. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r5/0.1.0-exp-b-report.md +0 -0
  89. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r5/0.1.0-exp-b-scoring.md +0 -0
  90. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r5/0.1.0-settings.md +0 -0
  91. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r6/0.1.0-exp-a-report.md +0 -0
  92. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r6/0.1.0-exp-a-scoring.md +0 -0
  93. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r6/0.1.0-exp-b-report.md +0 -0
  94. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r6/0.1.0-exp-b-scoring.md +0 -0
  95. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/results/0.1.0/r6/0.1.0-settings.md +0 -0
  96. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/sphere/prepare_accounts.py +0 -0
  97. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/sphere/prepare_cpty_banks.py +0 -0
  98. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/sphere/prepare_districts.py +0 -0
  99. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/sphere/prepare_loan_accounts.py +0 -0
  100. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/sphere/prepare_operations.py +0 -0
  101. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/sphere/prepare_orders.py +0 -0
  102. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/sphere/prepare_transactions.py +0 -0
  103. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/sphere/prepare_tx_types.py +0 -0
  104. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/berka/sphere/sphere.yaml +0 -0
  105. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/README.md +0 -0
  106. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/_layer2_cross_eval.py +0 -0
  107. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/_layer3_cross_eval.py +0 -0
  108. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/hi_small_sphere/prepare_accounts.py +0 -0
  109. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/hi_small_sphere/prepare_currencies.py +0 -0
  110. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/hi_small_sphere/prepare_payment_formats.py +0 -0
  111. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/hi_small_sphere/prepare_transactions.py +0 -0
  112. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/hi_small_sphere/sphere.yaml +0 -0
  113. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/layer1_passive_scan.py +0 -0
  114. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/layer2_xgboost_sweep.py +0 -0
  115. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/layer3_typology_filter.py +0 -0
  116. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/li_small_sphere/prepare_accounts.py +0 -0
  117. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/li_small_sphere/prepare_currencies.py +0 -0
  118. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/li_small_sphere/prepare_payment_formats.py +0 -0
  119. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/li_small_sphere/prepare_transactions.py +0 -0
  120. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/li_small_sphere/sphere.yaml +0 -0
  121. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/ibm-aml/passive-scan-calibration.md +0 -0
  122. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/README.md +0 -0
  123. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/SUMMARY.md +0 -0
  124. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r1/0.1.0-exp-a-report.md +0 -0
  125. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r1/0.1.0-exp-a-scoring.md +0 -0
  126. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r1/0.1.0-exp-b-report.md +0 -0
  127. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r1/0.1.0-exp-b-scoring.md +0 -0
  128. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r1/0.1.0-exp-c-report.md +0 -0
  129. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r1/0.1.0-settings.md +0 -0
  130. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r2/0.1.0-exp-a-report.md +0 -0
  131. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r2/0.1.0-exp-a-scoring.md +0 -0
  132. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r2/0.1.0-exp-b-report.md +0 -0
  133. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r2/0.1.0-exp-b-scoring.md +0 -0
  134. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r2/0.1.0-exp-c-report.md +0 -0
  135. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r2/0.1.0-settings.md +0 -0
  136. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r3/0.1.0-exp-a-report.md +0 -0
  137. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r3/0.1.0-exp-a-scoring.md +0 -0
  138. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r3/0.1.0-exp-b-report.md +0 -0
  139. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r3/0.1.0-exp-b-scoring.md +0 -0
  140. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r3/0.1.0-exp-c-report.md +0 -0
  141. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/results/0.1.0/r3/0.1.0-settings.md +0 -0
  142. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/sphere/prepare_trips.py +0 -0
  143. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmark/nyc-taxi/sphere/sphere.yaml +0 -0
  144. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/benchmarks.md +0 -0
  145. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/external-chains-as-anchor-line.md +0 -0
  146. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/images/build-pipeline.svg +0 -0
  147. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/images/core-objects.svg +0 -0
  148. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/images/cutting-plane.svg +0 -0
  149. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/images/directory-layout.svg +0 -0
  150. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/images/hypertopos-overview.svg +0 -0
  151. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/images/model-lifecycle.svg +0 -0
  152. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/images/navigation-primitives.svg +0 -0
  153. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/images/three-scales.svg +0 -0
  154. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/introduction.md +0 -0
  155. {hypertopos-0.7.0 → hypertopos-0.7.2}/docs/quickstart.md +0 -0
  156. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/builder/__init__.py +0 -0
  157. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/builder/_bootstrap.py +0 -0
  158. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/builder/_bregman.py +0 -0
  159. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/builder/_scatter.py +0 -0
  160. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/builder/_stats.py +0 -0
  161. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/builder/_theta_sensitivity.py +0 -0
  162. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/builder/_writer.py +0 -0
  163. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/builder/conformance.py +0 -0
  164. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/builder/derived.py +0 -0
  165. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/builder/dim_blocks.py +0 -0
  166. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/builder/mapping.py +0 -0
  167. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/builder/temporal_bucket.py +0 -0
  168. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/cli/__init__.py +0 -0
  169. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/cli/__main__.py +0 -0
  170. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/cli/info.py +0 -0
  171. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/cli/sources.py +0 -0
  172. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/__init__.py +0 -0
  173. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/adjacency.py +0 -0
  174. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/aggregation.py +0 -0
  175. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/calibration.py +0 -0
  176. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/composition.py +0 -0
  177. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/conformance.py +0 -0
  178. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/density_gaps.py +0 -0
  179. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/edge_features.py +0 -0
  180. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/explanation.py +0 -0
  181. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/fdr.py +0 -0
  182. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/forecast.py +0 -0
  183. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/graph_algorithms.py +0 -0
  184. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/heredity.py +0 -0
  185. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/hop_predicate.py +0 -0
  186. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/invalidation.py +0 -0
  187. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/investigation.py +0 -0
  188. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/lance_sql_agg.py +0 -0
  189. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/p_value_calibration.py +0 -0
  190. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/selection.py +0 -0
  191. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/structuring.py +0 -0
  192. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/engine/topology.py +0 -0
  193. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/model/__init__.py +0 -0
  194. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/model/manifest.py +0 -0
  195. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/navigation/__init__.py +0 -0
  196. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/navigation/scanner.py +0 -0
  197. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/sphere.py +0 -0
  198. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/storage/__init__.py +0 -0
  199. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/storage/_lance_versions.py +0 -0
  200. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/storage/_tag_timestamps.py +0 -0
  201. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/storage/cache.py +0 -0
  202. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/storage/exceptions.py +0 -0
  203. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/storage/topology_cache.py +0 -0
  204. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/storage/writer.py +0 -0
  205. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/utils/__init__.py +0 -0
  206. {hypertopos-0.7.0 → hypertopos-0.7.2}/hypertopos/utils/arrow.py +0 -0
  207. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/.gitkeep +0 -0
  208. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/fixtures/generate_fixtures.py +0 -0
  209. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/fixtures/synthetic_chain_sphere.py +0 -0
  210. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_adjacency.py +0 -0
  211. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_adjacency_vectorized.py +0 -0
  212. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_aggregation_engine.py +0 -0
  213. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_anomaly_propagation_in_chain.py +0 -0
  214. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_arrow_utils.py +0 -0
  215. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_bootstrap.py +0 -0
  216. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_bregman.py +0 -0
  217. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_builder_alias.py +0 -0
  218. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_builder_chunking.py +0 -0
  219. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_builder_contagion.py +0 -0
  220. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_builder_derived.py +0 -0
  221. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_builder_edges.py +0 -0
  222. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_builder_fdr_hierarchy.py +0 -0
  223. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_builder_fdr_hierarchy_inject.py +0 -0
  224. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_builder_fdr_yaml_end_to_end.py +0 -0
  225. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_builder_rolling_z.py +0 -0
  226. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_builder_scatter.py +0 -0
  227. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_builder_temporal_bucket.py +0 -0
  228. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_builder_temporal_perf.py +0 -0
  229. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_cache.py +0 -0
  230. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_calibration.py +0 -0
  231. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_calibration_drift.py +0 -0
  232. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_calibration_history.py +0 -0
  233. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_calibration_history_builder.py +0 -0
  234. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_calibration_history_reader.py +0 -0
  235. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_chain_coherent_anomaly.py +0 -0
  236. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_chain_coherent_synthetic.py +0 -0
  237. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_chain_drift_trajectory.py +0 -0
  238. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_chain_investigation_summary.py +0 -0
  239. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_chain_typology_and_extend.py +0 -0
  240. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_chain_witness_intersection.py +0 -0
  241. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_chains.py +0 -0
  242. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_cli.py +0 -0
  243. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_cli_alias.py +0 -0
  244. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_cli_sources.py +0 -0
  245. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_compaction.py +0 -0
  246. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_composition.py +0 -0
  247. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_conformance.py +0 -0
  248. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_continuous_event_dims.py +0 -0
  249. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_counterfactual.py +0 -0
  250. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_data_quality_prop.py +0 -0
  251. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_decompose_drift.py +0 -0
  252. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_density_gaps_engine.py +0 -0
  253. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_detection.py +0 -0
  254. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_dim_blocks.py +0 -0
  255. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_distinct_neighbor_count.py +0 -0
  256. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_edge_dim_aggregations.py +0 -0
  257. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_edge_dim_aggregations_chain.py +0 -0
  258. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_edge_dim_aggregations_engine.py +0 -0
  259. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_edge_dim_aggregations_roundtrip.py +0 -0
  260. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_edge_dimensions_builder.py +0 -0
  261. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_edge_dimensions_yaml.py +0 -0
  262. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_edge_features.py +0 -0
  263. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_edge_features_reader.py +0 -0
  264. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_edge_potential.py +0 -0
  265. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_edge_table.py +0 -0
  266. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_engine.py +0 -0
  267. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_fdr.py +0 -0
  268. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_fdr_multi_resolution.py +0 -0
  269. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_fdr_per_dim.py +0 -0
  270. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_find_calibration_influencers.py +0 -0
  271. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_find_density_gaps.py +0 -0
  272. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_find_diverse_explanations.py +0 -0
  273. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_find_lead_lag.py +0 -0
  274. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_find_lead_lag_significance.py +0 -0
  275. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_find_motif_by_hops.py +0 -0
  276. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_forecast.py +0 -0
  277. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_fts.py +0 -0
  278. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_generate_sar_rationale.py +0 -0
  279. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_geometric_path.py +0 -0
  280. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_geometry_stats.py +0 -0
  281. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_gradient_alignment.py +0 -0
  282. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_graph_algorithms.py +0 -0
  283. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_graph_geometry_tension.py +0 -0
  284. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_heredity.py +0 -0
  285. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_hop_predicate_engine.py +0 -0
  286. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_hub_safety_caps.py +0 -0
  287. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_hybrid_search.py +0 -0
  288. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_incremental.py +0 -0
  289. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_invalidation.py +0 -0
  290. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_investigate_chain.py +0 -0
  291. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_investigate_entity.py +0 -0
  292. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_investigation.py +0 -0
  293. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_kind_detect.py +0 -0
  294. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_lance_sql_agg.py +0 -0
  295. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_mapping.py +0 -0
  296. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_motif.py +0 -0
  297. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_mvcc_session.py +0 -0
  298. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_native_mvcc_geometry.py +0 -0
  299. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_navigator_alerts.py +0 -0
  300. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_navigator_fdr_resolution.py +0 -0
  301. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_navigator_fdr_select.py +0 -0
  302. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_neighbors_window.py +0 -0
  303. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_observability.py +0 -0
  304. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_p_value_calibration.py +0 -0
  305. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_pattern_fdr_hierarchy.py +0 -0
  306. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_precision_stack.py +0 -0
  307. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_profile_motif_perf_smoke.py +0 -0
  308. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_reliability_flags.py +0 -0
  309. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_reputation.py +0 -0
  310. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_root_cause_trace.py +0 -0
  311. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_row_id_cache.py +0 -0
  312. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_scanner.py +0 -0
  313. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_schema_chain_eda_validation.py +0 -0
  314. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_selection.py +0 -0
  315. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_sphere.py +0 -0
  316. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_sphere_overview_perf.py +0 -0
  317. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_sphere_validation_cheap_tier.py +0 -0
  318. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_stats_guard.py +0 -0
  319. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_storage.py +0 -0
  320. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_streaming_reads.py +0 -0
  321. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_structuring_engine.py +0 -0
  322. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_tag_timestamps.py +0 -0
  323. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_temporal_centroids.py +0 -0
  324. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_theta_sensitivity.py +0 -0
  325. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_topology.py +0 -0
  326. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_topology_cache.py +0 -0
  327. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_trajectory_ann.py +0 -0
  328. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_witness_cohort.py +0 -0
  329. {hypertopos-0.7.0 → hypertopos-0.7.2}/tests/test_witness_set.py +0 -0
@@ -7,6 +7,50 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.7.2] — 2026-05-21
11
+
12
+ ### Added
13
+ - `GDSNavigator.π5_attract_anomaly` / `find_anomalies` accept `rank_by="signed_confidence"` — composes `delta_norm_signed`, the Fisher LDA alignment, and the reliability flags into one confidence-weighted score: `score = delta_norm_signed × |lda_alignment| × (1 − reliability_penalty)` where `reliability_penalty = 0.5 × single_dim_driven + 0.5 × low_confidence_bucket`. Survivors carry `signed_confidence_score`, `lda_alignment`, `reliability_penalty` per polygon. Pattern without `label_aware_calibration` raises `GDSNavigationError` — no silent fallback to `delta_norm` ranking.
14
+ - New per-dim `kind_mismatch` warning class on `sphere_overview.dim_quality_warnings`. Fires when a `kind='gaussian'` dim shows `|direction_component| < 0.05` (LDA assigns near-zero weight) AND `cohens_d_pos_neg >= 0.3` (raw class stats separate) — the dim's variance is captured by another dim's Fisher axis, suggesting kind re-declaration or split. Composes with label-aware calibration; suppressed for dims already flagged `negative_space`. Pattern-level prerequisite: `Pattern.label_aware_calibration` must be non-None.
15
+ - `GDSNavigator.audit_label_alignment(pattern_id, *, top_n=10)` — reports Fisher LDA direction's discrimination power as AUROC of `delta_norm_signed` against the binary label column declared in `sphere.yaml`'s `label_audit:` block. Returns `{pattern_id, auroc, n_pos, n_neg, top_dims}` where `top_dims` carries the `top_n` dims sorted by `|direction_component|` desc (most label-discriminating axes first). Returns fallback shape with `auroc: null` and `label_aware_available: False` on patterns built without `label_audit:`.
16
+ - `Chain.to_dict()` carries an additional `edge_potentials: list[float | null]` field — one Euclidean distance `||delta(keys[i]) - delta(keys[i+1])||` per consecutive-pair hop, computed against a caller-supplied anchor pattern delta lookup. `null` on hops with missing polygon, mismatched delta shapes, or non-finite distance (NaN / inf strict-JSON sanitised). Length equals `len(keys) - 1` (empty list for single-entity chains). Surfaces high-distance behavioural jumps inside multi-hop chains for downstream chain investigation primitives.
17
+ - `GDSNavigator.π3_dive_solid` accepts `counterfactual_frozen_population: bool = False` — when `True`, each `SolidSlice` on the returned solid carries an additional `delta_norm_frozen_pop` field reporting the per-slice L2 norm recomputed against the FIRST slice's raw shape as the entity-relative reference epoch (sigma stays at the current pattern's diagonal). Answers "is this entity's apparent normalization a real shift, or just population drift around a stationary entity?" — a stationary entity yields `delta_norm_frozen_pop = 0` across all slices. Default `False` preserves the existing return shape (`delta_norm_frozen_pop = None`).
18
+ - `engine.counterfactual.recompute_delta_norm_against_frozen(shape, mu_frozen, sigma)` — pure-NumPy helper used by the frozen-trajectory path. Sigma-dead dims contribute zero (same convention as the per-edge counterfactual primitives).
19
+ - `SolidSlice.delta_norm_frozen_pop: float | None` — new optional field on the model dataclass populated by the frozen-trajectory path; `None` for the default build path.
20
+ - `docs/refutations.md` — record of tested-and-closed hypotheses: pattern-level σ-estimator swap, per-dim heuristic σ-swap, lazy-chain sampled calibration, Bregman-based `is_anomaly` flag, plus a methodology refutation on cycle-compression. Each entry states the hypothesis, dataset, numeric verdict, root cause, and closure rule.
21
+ - `docs/patent-implementation-map.md` — descriptive map of nine architectural-claim clusters (per-entity geometric position, counterfactual closure, multi-resolution FDR, persistent-homology cycle persistence, declarative compliance, HMP detector composition, chain-coherent investigation, reliability triage, build-time dim quality auditing) to their shipped surfaces. No internal tracker IDs.
22
+
23
+ ### Changed
24
+ - README adds CI test workflow badge linking to the public-mirror Actions run.
25
+
26
+ ## [0.7.1] — 2026-05-20
27
+
28
+ ### Added
29
+
30
+ - `GDSBuilder` now invokes `engine.calibration_label_aware.calibrate_label_aware` per pattern listed in `sphere.yaml`'s `label_audit:` block when the `--label-aware-calibration` build flag is set. The result is persisted onto `Pattern.label_aware_calibration` (new field, type `dict[str, dict[str, float]] | None`) and `signed_direction_vector` populates the `delta_norm_signed` Lance column. Closes the wiring gap that left `audit_pattern_dims` MCP tool in fallback mode on every sphere prior to this build path.
31
+ - `Pattern.heteroscedasticity_diagnostic` — optional per-pattern dict, keyed by the `group_by_property` column name, persisted at build time when a pattern carries `group_by_property`. Each entry is a Brown-Forsythe (median-centred Levene) test result on `delta_norm` partitioned by the grouping column: `{W_statistic, p_value, k_groups, per_group_variance, per_group_n, skipped_groups_low_n}`. Groups with N < 30 are dropped from the test (low Levene power) and counted in `skipped_groups_low_n`. When all qualifying groups have zero residual variance Levene returns NaN; the diagnostic encodes that as `null` for `W_statistic` / `p_value` so the JSON is well-formed and consumers can treat "computed-but-degenerate" the same way as "fewer than two qualifying groups".
32
+ - `sphere_overview.dim_quality_warnings[]` gains a new pattern-level type `"heteroscedasticity"` — fires when the persisted Levene `p_value < 0.01` on a pattern's grouping variable. The `dim_label` carries the grouping column name (a categorical line property), not a δ-dim — the warning's role is to flag that the global θ / Cohen's d pooled-σ / APS global-percentile assumptions are violated for this pattern. Carries `evidence_value` (p-value) and `threshold` (0.01) so the agent can rank patterns by severity. Advice: keep the per-group θ calibration the pattern already carries, or apply a variance-stabilizing transform (`log1p`) on `delta_norm` before thresholding if per-group θ is undesirable downstream.
33
+ - `engine.diagnostics.levene_test_per_group(values, group_ids)` — pure-math primitive (NumPy + scipy.stats) returning `{W_statistic, p_value, k_groups, per_group_variance, per_group_n, skipped_groups_low_n}`. Uses Brown-Forsythe (median-centred) variant of Levene for robustness on skewed distributions. Independent of any builder state — callable on any `(values, group_ids)` pair.
34
+ - `engine.dim_audit.normality_test_per_dim(values)` — per-dim normality test primitive. Selects Shapiro-Wilk for samples up to 5000 observations and Kolmogorov-Smirnov against a fitted normal for larger samples; returns `{test_name, statistic, p_value, n}`. Strips NaN before testing and returns a `nan` p-value for samples with fewer than three finite values or zero variance, letting callers treat those cases as "insufficient data" without pre-filtering.
35
+ - `Pattern.dim_normality_pvalues` and `CalibrationFit.dim_normality_pvalues` — optional `{dim_name: p_value}` mapping populated at build time by walking the same float columns the `dim_percentiles` cache covers (entity-line columns plus aggregated edge dims). Persisted to `sphere.json` and the calibration history; legacy spheres lacking the field continue to load unchanged.
36
+ - New `non_normal_dim` warning class on `sphere_overview.dim_quality_warnings`. Fires when a dim declared with `kind='gaussian'` has a build-time normality p-value below 0.01 — surfaces dims where the z-score `(x - mu) / sigma` is a poor anomaly scorer because the empirical distribution is heavy-tailed. The warning carries `reason`, `advice` (suggesting `log1p` / `sqrt` / `rank` transform or kind re-declaration), `evidence_value` (the p-value), and `threshold` (0.01). Suppressed for dims already flagged by `negative_space` to avoid double-flagging when the kind itself is the bug. Bernoulli and poisson dims are silently skipped — normality testing does not apply to binary or discrete-count kinds.
37
+ - `Pattern.dim_percentiles` now covers aggregated edge dimensions on anchor patterns. Each `{source_dim}_{aggregate}` label declared via `edge_dim_aggregations` receives the same six-key entry (`min / p25 / p50 / p75 / p99 / max`) that the cache already provided for `event_dimensions` and `prop_columns`. Consumers of the percentile cache — `dim_quality_warnings` in `sphere_overview`, `dominant_dim_mass` / `negative_space` auditors, the percentile-driven scoring path in `find_anomalies` — now see aggregated edge dims uniformly alongside the other dim families.
38
+ - `engine.calibration_label_aware.calibrate_label_aware(deltas, labels, dim_labels=None, regularization=1e-6)` — per-dim label-aware calibration producing `{mu_pos, sigma_pos, mu_neg, sigma_neg, direction}` per dim plus the unit-norm Fisher LDA direction vector across all dims; opt-in calibration path layered on top of standard mu/sigma stats.
39
+ - `hypertopos build --label-aware-calibration` CLI flag — opt-in switch that activates label-aware calibration during build. No-op until the sphere config declares a `label_audit` block selecting patterns; behavior unchanged on unlabeled spheres.
40
+ - `delta_norm_signed` Lance column in the geometry dataset — per-polygon projection of the delta vector onto the label-aware Fisher LDA direction, signed so positive values mean the polygon is pushed toward the positive-labelled centroid and negative values toward the negative. Nullable float32; populated only for patterns whose builder calibration produced a `signed_direction_vector`. Patterns without label-aware calibration emit the column as all-null, preserving the existing unsigned `delta_norm` magnitude untouched.
41
+ - `sphere.yaml` now accepts a top-level `label_audit:` block — `{label_column, label_positive_value, patterns: [...]}` — naming the binary-label column on the entity line, the value treated as the positive class, and the patterns to calibrate. The parser rejects malformed blocks (missing `label_column`, missing `label_positive_value`, missing or empty `patterns`, unknown pattern names). The block is persisted into `sphere.json` and surfaced to consumers via `Sphere.label_audit`.
42
+ - Sphere format minor `3.1` — stamped on `sphere.json` only when the build registers a `label_audit` block; otherwise spheres continue to stamp `3.0`. Readers compare on the major component only, so older 3.x readers transparently load newer 3.x spheres and ignore the new optional field.
43
+ - `Pattern.edge_dim_names: list[str]` — edge-derived dim names persisted on event patterns that declared an `edge_dimensions:` block in `sphere.yaml`. The block is written into `pattern.json` and surfaced via `Pattern.dim_labels` and `Pattern.dim_index(name)` in storage order (after event dims, before prop columns), so every stored delta dim now has a labelled name. `Pattern.delta_dim()` matches the stored mu / sigma / theta width for these patterns; empty list for patterns without `edge_dimensions:`. Rebuild required to surface labels on existing spheres.
44
+
45
+ ### Changed
46
+ - `storage.reader.GDSReader.read_sphere` accepts any sphere with format major 3; pre-3.x and malformed `format_version` strings continue to raise `GDSVersionError` with a rebuild hint.
47
+ - `builder.conformance_mapping.parse_conformance_rules(raw_block, *, pattern_id, available_columns=None)` — YAML loader for the per-pattern `conformance_rules:` block. Accepts the declarative predicate AST (`and`, `or`, `not`, `==`, `!=`, `<`, `<=`, `>`, `>=`, `in`) and the `severity` literals `low`, `medium`, `high`, `critical`. Validates structural shape (logical compounds require non-empty `terms`, `not` requires exactly one term, `in` requires an iterable `value`), assigns `rule_id` of the form `r0`, `r1`, … when absent, rejects duplicate `rule_id`s, and — when `available_columns` is supplied — fails fast on any leaf `prop` that is not a column on the entity points table. Returns a list of `ConformanceRule` ready to attach to `Pattern.conformance_rules`.
48
+ - `sphere.yaml` patterns now accept a `conformance_rules:` block. The block is a list of entries shaped `{rule_id?, severity, description?, violates_when}` where `violates_when` is the predicate AST mirroring the on-disk JSON shape. The build pipeline parses, validates against the entity-line points table, attaches the rule set to the pattern, and writes the violations sidecar alongside the geometry — every entity matching `violates_when` lands in the sidecar tagged with the rule's `rule_id` and `severity`.
49
+ - `builder.add_pattern(..., conformance_rules=...)` keyword — programmatic equivalent of the YAML block, accepting a list of `ConformanceRule` directly for callers using the builder API without YAML.
50
+
51
+ ### Fixed
52
+ - `anomaly_summary` no longer falls back to synthesized `dim_{i}` labels for the `top_driving_dimensions` block on event patterns that declared `edge_dimensions:`. Every reported dim now resolves to the labelled name persisted on the pattern; the per-cluster `dim_sq_totals` accumulator is sized by `len(pattern.dim_labels)` and the round-trip is consistent with `Pattern.delta_dim()`.
53
+
10
54
  ## [0.7.0] — 2026-05-18
11
55
 
12
56
  ### Added
@@ -26,7 +26,7 @@ For purposes of this License:
26
26
  - **Internal use** within an organization is not a competitive offering. Your
27
27
  organization includes entities under common control.
28
28
 
29
- **Change Date:** 2029-05-18
29
+ **Change Date:** 2029-05-21
30
30
 
31
31
  **Change License:** Apache License, Version 2.0
32
32
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hypertopos
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: Understand the structure of your data — without training machine learning models
5
5
  Project-URL: Homepage, https://github.com/hypertopos/hypertopos-py
6
6
  Project-URL: Documentation, https://github.com/hypertopos/hypertopos-py/tree/main/docs
@@ -11,13 +11,17 @@ License: BSL-1.1
11
11
  License-File: LICENSE.md
12
12
  Requires-Python: >=3.12
13
13
  Requires-Dist: numpy>=1.26
14
+ Requires-Dist: packaging>=23.0
15
+ Requires-Dist: pandas>=2.0
14
16
  Requires-Dist: pyarrow>=14.0
15
17
  Requires-Dist: pylance<7.0,>=6.0
16
18
  Requires-Dist: pyyaml>=6.0
19
+ Requires-Dist: scipy>=1.11
17
20
  Provides-Extra: dev
18
21
  Requires-Dist: igraph>=0.11; extra == 'dev'
19
22
  Requires-Dist: mypy; extra == 'dev'
20
23
  Requires-Dist: pytest; extra == 'dev'
24
+ Requires-Dist: pytest-asyncio; extra == 'dev'
21
25
  Requires-Dist: pytest-cov; extra == 'dev'
22
26
  Requires-Dist: ruff; extra == 'dev'
23
27
  Provides-Extra: graph
@@ -28,3 +32,4 @@ Requires-Dist: tzdata>=2024.1; extra == 'mcp'
28
32
  Provides-Extra: topology
29
33
  Requires-Dist: persim>=0.3.5; extra == 'topology'
30
34
  Requires-Dist: ripser>=0.6.14; extra == 'topology'
35
+ Requires-Dist: scikit-learn>=1.3; extra == 'topology'
@@ -2,13 +2,14 @@
2
2
 
3
3
  > A behavioral feature layer for graph and temporal data — turning behavior into coordinates, trajectories, and explanations.
4
4
 
5
+ [![Test](https://github.com/hypertopos/hypertopos-py/actions/workflows/test.yml/badge.svg)](https://github.com/hypertopos/hypertopos-py/actions/workflows/test.yml)
5
6
  [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
6
7
  [![License: BSL 1.1](https://img.shields.io/badge/license-BSL%201.1-orange.svg)](LICENSE.md)
7
8
  [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.19482069.svg)](https://doi.org/10.5281/zenodo.19482069)
8
9
  [![PyArrow](https://img.shields.io/badge/format-PyArrow-red.svg)](https://arrow.apache.org/docs/python/)
9
10
  [![Lance](https://img.shields.io/badge/storage-Lance-blueviolet.svg)](https://github.com/lance-format/lance)
10
11
  [![MCP](https://img.shields.io/badge/MCP-compatible-green.svg)](https://modelcontextprotocol.io)
11
- [![Version](https://img.shields.io/badge/version-0.7.0-%235500FF.svg)](pyproject.toml)
12
+ [![Version](https://img.shields.io/badge/version-0.7.2-%235500FF.svg)](pyproject.toml)
12
13
 
13
14
  hypertopos is not a database, and not a machine learning model. It is a layer that turns relational data into a coordinate system where every entity gets a position derived from its relationships and the population around it.
14
15
 
@@ -1,6 +1,6 @@
1
1
  # Security
2
2
 
3
- ## Current version: 0.7.0
3
+ ## Current version: 0.7.2
4
4
 
5
5
  hypertopos runs locally. No network services, no auth layer, no multi-tenancy.
6
6
 
@@ -688,6 +688,7 @@ Key methods: `slice_at(timestamp)` -- binary search for the slice active at a gi
688
688
  | `population_size` | `int` | Total entity count at calibration time |
689
689
  | `version` | `int` | Pattern version |
690
690
  | `prop_columns` | `list[str]` | Boolean property columns tracked as dimensions |
691
+ | `edge_dim_names` | `list[str]` | Edge-derived dim names for event patterns that declared an `edge_dimensions:` block in `sphere.yaml`. Order matches the storage layout (after `event_dimensions`, before `prop_columns`). Empty for patterns without `edge_dimensions:`. |
691
692
  | `dimension_weights` | `np.ndarray \| None` | Per-dimension importance weights |
692
693
  | `dimension_kinds` | `list[str] \| None` | Per-dimension distribution family: `"gaussian"`, `"poisson"`, or `"bernoulli"`. Populated at build time; `None` on pre-2.3 spheres. |
693
694
 
@@ -108,12 +108,13 @@ Override via `kind:` on individual dimension entries in `sphere.yaml`. The resul
108
108
 
109
109
  ### Dim-quality warnings
110
110
 
111
- `sphere_overview` surfaces a `dim_quality_warnings[]` block per pattern that catches silent build-time failures of z-score / `delta_norm` semantics. Every warning carries `type`, `dim_label`, `reason`, `advice`. `dominant_dim_mass` additionally carries numeric `evidence_value` (the actual share) and `threshold` (the firing cutoff) so the agent can rank patterns by severity. Computed from cached pattern state (`sigma_diag`, `mu`, `dim_percentiles`, `dimension_kinds`) — sub-millisecond, no storage scan. Four auditor types:
111
+ `sphere_overview` surfaces a `dim_quality_warnings[]` block per pattern that catches silent build-time failures of z-score / `delta_norm` semantics. Every warning carries `type`, `dim_label`, `reason`, `advice`. `dominant_dim_mass` and `heteroscedasticity` additionally carry numeric `evidence_value` (the firing metric) and `threshold` (the firing cutoff) so the agent can rank patterns by severity. Computed from cached pattern state (`sigma_diag`, `mu`, `dim_percentiles`, `dimension_kinds`, `heteroscedasticity_diagnostic`) — sub-millisecond, no storage scan. Five auditor types:
112
112
 
113
113
  - `dead_dim` — per-dim signal. Fires on dims with `sigma_diag[i] < 1e-10`. The z-score `(x − mu) / sigma` is undefined; the dim contributes nothing meaningful and silently dilutes other dims' signal. Advice: drop the dim from the pattern, or investigate the data source for a constant column.
114
114
  - `sparse_dim` — per-dim signal. Fires on dims with `dim_percentiles[label].p50 == 0` and `p99 > 0` (mostly-zero with rare nonzero tail). The gaussian z-score assumption is wrong because the empirical distribution is point-mass-at-zero plus a tail. Advice: switch to Bregman with `kind='poisson'` or `kind='bernoulli'`, or split into `is_active` + `value_when_active` dims.
115
115
  - `dominant_dim_mass` — pattern-level signal. Computed as the max share of `((p99 − μ_d) / σ_d)²` across all dims with `dim_percentiles` coverage; fires when one dim's share ≥ 0.70 (matches the per-polygon `single_dim_driven` threshold). Means the pattern's `delta_norm` ranking is effectively single-dim; investigator should cross-check the per-polygon `reliability_flags.single_dim_driven` incidence on top-N anomalies. Aggregated edge dims without `dim_percentiles` entries are silently skipped.
116
116
  - `negative_space` — per-dim signal. Fires on dims with `dim_percentiles[label].p50 == 0` AND `dimension_kinds[i] == "gaussian"`. The gaussian z-score is wrong for these dims because the empirical distribution is point-mass-at-zero, not centered. Advice: re-declare with `kind='bernoulli'` (presence/absence) or `kind='poisson'` (count), or split into a binary `is_active` dim plus a continuous `value_when_active` dim.
117
+ - `heteroscedasticity` — pattern-level signal, keyed by the pattern's `group_by_property`. Computed at build time from a Brown-Forsythe (median-centred Levene) test on `delta_norm` partitioned by the grouping column; fires when `p < 0.01`. The `dim_label` carries the grouping variable name (the categorical line property), not a δ-dim. Means the global θ assumption is statistically violated for this pattern — per-group θ calibration is statistically warranted. Advice: keep the per-group calibration the pattern already carries, or consider a variance-stabilizing transform (`log1p`) on `delta_norm` before thresholding. Groups with N < 30 are silently dropped from the test (low Levene power) and surfaced in the persisted entry as `skipped_groups_low_n`.
117
118
 
118
119
  ## Anomaly Confidence
119
120
 
@@ -376,6 +376,7 @@ patterns:
376
376
  | `edge_table` | dict | `null` | Explicit edge table config (see below). Auto-emitted for event patterns with 2+ FK relations to same anchor line. |
377
377
  | `edge_dimensions` | list | `null` | Build-time per-edge dims for event patterns. Each item is either a bare dim name or a single-key dict with overrides. Five dims available: `pair_edge_count`, `position_in_chain` (`min_position` ≥ 3, default 5), `time_since_pair_last_edge`, `pair_amount_zscore` (LOW_VAR pairs only), `find_motif_structuring`. |
378
378
  | `edge_dim_aggregations` | dict | `null` | **Anchor patterns only.** Aggregate per-edge sidecar dims of an event pattern up to per-anchor `_mean` / `_max` columns baked into the anchor polygon. `from: <event_pid>` is required and must reference an event pattern that declares `edge_dimensions:`. `dims: [...]` is required — must be a non-empty list of source dim names from the referenced sidecar (the previous "omit `dims` to aggregate everything" shorthand was removed; explicit declaration prevents build-vs-runtime label drift). Anchor regimes: `single` (account-style, anchor PK matches edge `from_key` OR `to_key`) and `pair` (composite-key, anchor PK = `<from>__<to>`); `chain` raises `NotImplementedError`. Builder switches to a two-phase build (events first, anchors second) when this block is present. |
379
+ | `conformance_rules` | list | `null` | Declarative compliance predicates evaluated at build time against the entity-line points table. Each entry has shape `{rule_id?, severity, description?, violates_when}` where `severity` is one of `low` / `medium` / `high` / `critical` and `violates_when` is a predicate AST. `rule_id` is auto-assigned as `r0`, `r1`, ... when omitted; duplicate `rule_id`s are rejected. Predicate ops: `and`, `or`, `not` (logical compounds carry `terms`), `==`, `!=`, `<`, `<=`, `>`, `>=` (carry `prop` + scalar `value`), and `in` (carries `prop` + list `value`). The `prop` field references a raw column on the entity-line points table — unknown columns fail the build immediately. Violators land in a sidecar Lance dataset read by `find_conformance_violations`. |
379
380
  | `bootstrap_iterations` | int | `200` | Number of bootstrap resamples used to compute `anomaly_confidence` per entity. Skipped automatically for N > 50K, `group_by_property`, or `use_mahalanobis`. |
380
381
 
381
382
  ### Edge Table
@@ -444,6 +445,61 @@ patterns:
444
445
 
445
446
  Dimension prefixes (`g:`, `t:`, `s:`) appear in `explain_anomaly` output, making it clear which block a dimension belongs to.
446
447
 
448
+ ### Conformance Rules
449
+
450
+ Patterns optionally accept a `conformance_rules:` block that declares compliance predicates evaluated at build time against the entity-line points table. Violators land in a sidecar Lance dataset surfaced by the `find_conformance_violations` navigator primitive and MCP tool.
451
+
452
+ ```yaml
453
+ patterns:
454
+ account_pattern:
455
+ type: anchor
456
+ entity_line: accounts
457
+ relations: []
458
+ conformance_rules:
459
+ - rule_id: high_amount
460
+ severity: high
461
+ description: account average above compliance ceiling
462
+ violates_when:
463
+ op: ">"
464
+ prop: avg_amount # Column on the entity-line points table.
465
+ value: 10000
466
+
467
+ - rule_id: sanctioned_region
468
+ severity: critical
469
+ violates_when:
470
+ op: in
471
+ prop: country
472
+ value: [XX, ZZ]
473
+
474
+ - rule_id: high_value_and_sanctioned
475
+ severity: critical
476
+ violates_when:
477
+ op: and
478
+ terms:
479
+ - op: ">"
480
+ prop: avg_amount
481
+ value: 10000
482
+ - op: in
483
+ prop: country
484
+ value: [XX, ZZ]
485
+ ```
486
+
487
+ Predicate language:
488
+
489
+ | Op | Shape | Description |
490
+ |----|-------|-------------|
491
+ | `and`, `or` | `{op, terms: [...]}` | Logical compound — non-empty list of child predicates. |
492
+ | `not` | `{op, terms: [child]}` | Logical negation — exactly one child predicate. |
493
+ | `==`, `!=`, `<`, `<=`, `>`, `>=` | `{op, prop, value}` | Comparison on a single column against a scalar literal. |
494
+ | `in` | `{op, prop, value: [...]}` | Membership in a list literal. |
495
+
496
+ Rules:
497
+
498
+ - `severity` is one of `low`, `medium`, `high`, `critical`.
499
+ - `rule_id` is optional; when omitted, rules are auto-assigned `r0`, `r1`, ... in YAML order. Duplicate `rule_id`s within a pattern are rejected at parse time.
500
+ - `description` is optional and surfaced in violation responses for audit context.
501
+ - `prop` references a raw column on the entity-line points table — not a dim label. An unknown column fails the build immediately.
502
+
447
503
  ### Multiple patterns on the same entity line
448
504
 
449
505
  You can define multiple patterns for the same anchor line with different calibration:
@@ -51,11 +51,12 @@ The central config file. Loaded once on `open_sphere` (typically a few KB). Cont
51
51
  | Field | Type | Description |
52
52
  |-------|------|-------------|
53
53
  | `sphere_id` | string | Unique sphere identifier |
54
- | `format_version` | string | On-disk layout version. Current: `"3.0"` (flat single-dataset geometry with native Lance epoch tags). Reader rejects earlier values and points to a clean rebuild from source. |
54
+ | `format_version` | string | On-disk layout version, written as `"<major>.<minor>"`. Major `3` is required; minor bumps (e.g. `"3.1"`) ride a backward-compatible field addition and load on any major-3 reader. Pre-3.x and malformed values are rejected with a rebuild hint. |
55
55
  | `lines` | dict | Line definitions: versions, columns, partition config, descriptions |
56
56
  | `patterns` | dict | Pattern stats: `mu`, `sigma_diag`, `theta`, `edge_max`, `dimension_weights`, `group_stats` |
57
57
  | `aliases` | dict | Alias definitions: `base_pattern`, cutting plane (`normal` vector, `bias`) |
58
58
  | `storage` | dict | Storage config per layer (format, partition mode) |
59
+ | `label_audit` | dict, optional | Top-level label-aware calibration metadata — `{label_column, label_positive_value, patterns: [...]}`. Present only when the build registered a YAML `label_audit:` block; absent on spheres built without one. When present, `format_version` is stamped `"3.1"`. |
59
60
 
60
61
  Example (abridged pattern entry):
61
62
 
@@ -0,0 +1,123 @@
1
+ # Patent implementation map
2
+
3
+ This document maps the architectural claims behind hypertopos to the shipped implementation surfaces in the current release.
4
+
5
+ Each cluster names a load-bearing idea, the navigator or MCP surface that ships it, and the method one-line. The point is to make it easy for a reviewer or external auditor to walk from "this is what the project claims to do" to "this is the function that does it and the test that verifies it".
6
+
7
+ There are no claim numbers (`IC-XX`, `DC-XX.Y`) in this document — those are internal tracker IDs. Each cluster is named by its descriptive function.
8
+
9
+ ---
10
+
11
+ ## Per-entity geometric position derived from a population
12
+
13
+ **What it is.** Every entity carries a position in a multi-dimensional space whose axes are not raw column values but population-relative statistics — z-scores against the population mean, ratios against population percentiles, signed projections onto label-discriminating axes. The position is computed once at build time and stored as a Lance column.
14
+
15
+ **Surfaces.** `Pattern.mu_diag`, `Pattern.sigma_diag`, `Pattern.theta_diag` (population-level statistics persisted on every pattern). `Pattern.label_aware_calibration` (per-class moments + Fisher LDA direction, opt-in via `sphere.yaml`'s `label_audit:` block). `delta_norm` and `delta_norm_signed` Lance columns on every geometry table.
16
+
17
+ **Method.** Welford one-pass for mu / sigma. Quantile sketches for theta. Linear discriminant analysis with diagonal-covariance approximation for label-aware direction. All computations are deterministic and reproducible from the source data plus `sphere.yaml`.
18
+
19
+ **Tests.** `tests/test_calibration.py`, `tests/test_calibration_label_aware.py`, `tests/test_m1_1_builder_wiring.py`.
20
+
21
+ ---
22
+
23
+ ## Counterfactual closure — what changes if X is removed
24
+
25
+ **What it is.** For an anomalous entity, ask "would it still be anomalous if this edge, this counterparty, or this dim were removed?" — and answer with a closed-form recomputation of `delta_norm` against the same population statistics, no model retraining.
26
+
27
+ **Surfaces.** `GDSNavigator.simulate_edge_removal`, `simulate_counterparty_removal`, `select_minimal_joint_edge_removal`, `simulate_dimension_change`. Each surfaces as an MCP tool with the same name.
28
+
29
+ **Method.** Closed-form exp-family delta recomputation. For each candidate removal, recompute the entity's polygon contribution to `delta_norm` as `mu_diag - new_centroid`, take the ratio against `sigma_diag`, project against `theta_diag` percentile — same calibration, different inputs. Greedy selection for the minimal joint set.
30
+
31
+ **Tests.** `tests/test_counterfactual_*.py`.
32
+
33
+ ---
34
+
35
+ ## Multi-resolution false-discovery-rate control
36
+
37
+ **What it is.** Standard Benjamini-Hochberg FDR on a per-entity anomaly score answers one question — "is this entity anomalous?" — but ignores that entities live in nested cells (region × time × kind). Multi-resolution FDR aggregates per-cell p-values up a hierarchy with Tippett min-p and reports `q`-values at every level, surviving the more conservative join.
38
+
39
+ **Surfaces.** `Pattern.fdr_hierarchy` and `Pattern.fdr_temporal_hierarchy` (declarative schema in `sphere.yaml`). `find_anomalies(fdr_resolution, fdr_temporal_resolution)` MCP tool returns `cell_q_spatial` and `cell_q_temporal` per survivor. `engine.fdr.fdr_multi_resolution` (pure-math primitive).
40
+
41
+ **Method.** Per-cell Fisher exact 2×2 on an anomaly indicator vs background. BH or Storey correction within each cell. Tippett min-p aggregation up each declared level. Independent per-axis adjustment for spatial vs temporal hierarchies.
42
+
43
+ **Tests.** `tests/test_fdr_*.py`.
44
+
45
+ ---
46
+
47
+ ## Persistent-homology cycle persistence at the entity level
48
+
49
+ **What it is.** Treat each entity's k-nearest-neighbour ball in the polygon space as a small point cloud and ask whether that cloud carries persistent topological cycles. An entity with high `h1_max_persistence` sits inside a non-trivial topological structure — a ring, a hub, a cluster boundary — that single-entity z-scores cannot see.
50
+
51
+ **Surfaces.** `find_topological_anomalies` MCP tool. `engine.topology` module (Vietoris-Rips persistent homology backed by `ripser` when the optional `[topology]` extra is installed). `storage.topology_cache` for memoised per-entity persistence values.
52
+
53
+ **Method.** Per-entity k-NN ball (k ≈ 50 by default), PCA reduction to 10 dims, Vietoris-Rips H_1 persistence computed with `ripser`. Score = max `h1` death-birth interval. Cached because the computation is expensive; invalidated when calibration epochs bump.
54
+
55
+ **Tests.** `tests/test_topology_*.py`.
56
+
57
+ ---
58
+
59
+ ## Declarative compliance rules as a first-class build-time predicate language
60
+
61
+ **What it is.** Compliance officers write rules in YAML using a small declarative AST (`and / or / not` over `==, !=, <, <=, >, >=, in`); the builder evaluates them at build time and materialises a violations sidecar Lance dataset; a runtime MCP tool reads the sidecar with rule-id and severity pushdown. Separate from `delta_norm` anomaly flags — an entity can be one, the other, or both.
62
+
63
+ **Surfaces.** `Pattern.conformance_rules` (model field). `builder.conformance_mapping.parse_conformance_rules` (YAML loader with column-existence validation). `find_conformance_violations` MCP tool.
64
+
65
+ **Method.** Vectorised PyArrow expression evaluation. Severity literals `low < medium < high < critical`. Rule-id stamping. Sidecar Lance dataset alongside the geometry table.
66
+
67
+ **Tests.** `tests/test_conformance_mapping.py`, `tests/test_find_conformance_violations_mcp.py`.
68
+
69
+ ---
70
+
71
+ ## Detector composition via harmonic-mean p-value
72
+
73
+ **What it is.** Five independent detectors — `delta_norm`, `neighbor_contamination`, `segment_shift`, `trajectory_continuous`, `density_gap` — score each entity. A correct composition treats these as multiple hypothesis tests on the same null and combines them via the Wilson harmonic-mean p-value (HMP), not via score averaging. The combined `hmp` is rank-stable across detector subsets and exact under the null.
74
+
75
+ **Surfaces.** `combine_anomaly_pvalues`, `classify_detector_consensus`, `composite_risk`, `composite_risk_batch` MCP tools. `engine.composition.harmonic_mean_p` (pure-math primitive). `engine.p_value_calibration` (per-detector score-to-p-value adapters).
76
+
77
+ **Method.** Per-detector calibrated p-values. Wilson HMP combiner. Null-simulation lookup for the `L`-test threshold at level `alpha`. Per-detector weighting optional.
78
+
79
+ **Tests.** `tests/test_composition_*.py`, `tests/test_detector_consensus_*.py`.
80
+
81
+ ---
82
+
83
+ ## Chain-coherent investigation primitives
84
+
85
+ **What it is.** A chain is a multi-hop path through an event graph (`from_account → to_account` over time). Investigating a chain means asking whether the chain itself carries anomaly signal (`investigate_chain`), whether its members move together in regime space (`chain_drift_trajectory`), whether their explanatory witness sets intersect (`chain_witness_intersection`), and whether the chain's typology matches a known pattern (`classify_chain_typology`). The chain becomes a first-class investigation entity, not just a list of vertices.
86
+
87
+ **Surfaces.** `chain_lines:` YAML block. `extract_chains` build pass. `chain_pattern` derived geometry. `find_chains_with_coherent_anomaly`, `chain_witness_intersection`, `chain_drift_trajectory`, `classify_chain_typology`, `extend_chain`, `investigate_chain`, `generate_sar_rationale` MCP tools.
88
+
89
+ **Method.** Seeded BFS over the event graph with multi-criteria seed selection (`fan_out`, `cross_bank`, `multi_currency`, `pass_through`). Chain feature extraction at build time (`hop_count`, `is_cyclic`, `time_span_hours`, `amount_decay`, etc.). Same pattern-level calibration applied to chains as to entities, so `delta_norm` carries the same population-relative semantics.
90
+
91
+ **Tests.** `tests/test_chain_*.py`.
92
+
93
+ ---
94
+
95
+ ## Reliability triage on every flagged polygon
96
+
97
+ **What it is.** A polygon flagged anomalous can be flagged because one dim dominates the score (an artefact of that dim's calibration, not a real anomaly) or because the bootstrap confidence on `is_anomaly` is fragile (the flag would flip if the population were resampled). Both surfaces are reported as boolean flags alongside the score, so an investigator can corroborate before opening a case.
98
+
99
+ **Surfaces.** `reliability_flags` field on `find_anomalies`, `explain_anomaly`, `composite_risk`, `combine_anomaly_pvalues`, `investigate_entity`. Shape `{single_dim_driven, dominant_dim, dominant_dim_share, low_confidence_bucket, confidence, flags}`.
100
+
101
+ **Method.** `single_dim_driven` fires when one dim's attribution share exceeds 70 %. `low_confidence_bucket` fires when bootstrap-resampled `anomaly_confidence` falls below 0.5. Both computed at flag time, no extra MCP roundtrip.
102
+
103
+ **Tests.** `tests/test_reliability_flags.py`.
104
+
105
+ ---
106
+
107
+ ## Build-time dim quality auditing — silent calibration failure modes surfaced
108
+
109
+ **What it is.** Five build-time auditors catch the silent failure modes that break z-score / `delta_norm` semantics: dead dims (zero variance), sparse dims (mostly zero), dominant-dim mass (one dim accounts for ≥70 % of tail variance), negative-space dims (gaussian-declared but empirically zero-modal), non-normal dims (gaussian-declared but Shapiro-Wilk / KS `p < 0.01`), and per-pattern heteroscedasticity (Brown-Forsythe Levene `p < 0.01` on the grouping variable).
110
+
111
+ **Surfaces.** `sphere_overview.dim_quality_warnings[]` block. `engine.diagnostics` and `engine.dim_audit` modules.
112
+
113
+ **Method.** Build-time statistical tests on the calibrated geometry table. Each auditor returns a structured warning with `dim_label`, `reason`, `advice`, `evidence_value`, `threshold` — enough for a downstream consumer to either raise a calibration ticket or apply the recommended transform.
114
+
115
+ **Tests.** `tests/test_dim_quality_warnings.py`, `tests/test_diagnostics.py`.
116
+
117
+ ---
118
+
119
+ ## Notes
120
+
121
+ This document is a living artefact. As new architectural surfaces ship, they are added here. As surfaces are deprecated or refactored, the entries update with the cycle they shipped in.
122
+
123
+ Internal tracker IDs (`IC-XX`, `DC-XX.Y`, `OPF-XX`, `IDEA-XXX`) are kept out of this document by project rule — they are private bookkeeping and would look like dead hyperlinks to anyone reading from the public mirror. Each cluster is named by what it does, not by which ticket tracks it.
@@ -0,0 +1,71 @@
1
+ # Refutations
2
+
3
+ This document records hypotheses that were tested, found wrong, and closed. Each entry follows the discipline: state the hypothesis, name the dataset, give the numeric evidence, and link the commit or PR that closed the line of work.
4
+
5
+ The point is not to celebrate failures. It is to leave a record so the same idea is not re-investigated six months later under a different name, and so a reviewer can see that the project takes negative results seriously.
6
+
7
+ ---
8
+
9
+ ## Pattern-level σ-estimator swap (refuted 0.6.6, PR #435)
10
+
11
+ **Hypothesis.** Replacing the population standard deviation σ used in `delta_norm` calibration with a robust estimator (MAD, IQR, Qn) would lift downstream anomaly detection by being less sensitive to outlier leak.
12
+
13
+ **What was tested.** Four σ estimators (`std`, `mad`, `iqr`, `qn`) plugged into `Pattern.sigma_diag` calibration. Evaluation on a money-laundering account-level pattern with binary `is_laundering` labels.
14
+
15
+ **Verdict.** AUROC and top-K precision differences across the four estimators sat inside the bootstrap noise band (±0.005 on AUROC). MAD and IQR did not deliver any robustness lift on this distribution. The "robust σ" line of work was closed.
16
+
17
+ **Why it failed.** Account-level features are already log-transformed or rank-normalised upstream of calibration. Outliers no longer drive σ when the input is approximately normal post-transform. The σ-swap intervention had no surface to act on.
18
+
19
+ **Citation.** PR #435 retrospective + `MEMORY.md` entry `project_population_robust_sigma_refuted`.
20
+
21
+ ---
22
+
23
+ ## Per-dim heuristic σ-estimator swap (refuted 0.6.6, PR #436)
24
+
25
+ **Hypothesis.** σ-swap might work if applied per-dim rather than population-wide — pick the estimator per column based on a heuristic (skewness, kurtosis, sparsity).
26
+
27
+ **What was tested.** Per-dim heuristic dispatcher selecting `std` / `mad` / `iqr` based on column statistics. Same evaluation setup as PR #435.
28
+
29
+ **Verdict.** Same outcome — ΔAUROC < 0.005, inside bootstrap noise. The heuristic dispatcher added complexity without measurable lift.
30
+
31
+ **Why it failed.** Same root cause as PR #435 — when upstream features are normalised, σ-estimator choice does not materially change the calibration. The dispatcher was solving a problem that did not exist on this data shape.
32
+
33
+ **Closure rule.** The entire "calibration robustness via σ-estimator swap" theme is closed for the project unless a new dataset surfaces with un-normalised, heavy-tailed inputs where the assumption is testable from scratch. The closure rule is enforced via the session memory `project_population_robust_sigma_refuted` — re-opening requires a different dataset or methodology.
34
+
35
+ ---
36
+
37
+ ## Lazy-chain geometry sampled calibration (refuted 0.5.x, retired 2026-04-19)
38
+
39
+ **Hypothesis.** Computing chain-pattern calibration on a sampled subset of chains rather than the full population would scale linearly with sphere size and preserve detection quality.
40
+
41
+ **What was tested.** Sampled-calibration variant against full-calibration baseline on the money-laundering chain pattern. Compared `delta_norm` rankings and downstream chain-level anomaly recall.
42
+
43
+ **Verdict.** Sampled calibration produced a sub-null `delta_norm` distribution — calibration estimates were biased low because the sampled tail underrepresented the true variance. Bias roughly 24 % on the most affected dims. Chain recall on labelled bad chains dropped materially.
44
+
45
+ **Why it failed.** Chains are a long-tail distribution by structure. Uniform sampling under-weights long chains, which carry the discriminating signal. A weighted sampler would have helped in theory but the engineering cost outweighed the expected gain.
46
+
47
+ **Closure.** The lazy-chain-geometry document carries an in-doc retired banner dated 2026-04-19. The work was superseded by treating chains as first-class geometric entities (the `chain_lines:` YAML block and the chain investigation primitives shipped in 0.6.x and 0.7.0).
48
+
49
+ ---
50
+
51
+ ## Bregman-based `is_anomaly` flag (refuted 2026-04-16)
52
+
53
+ **Hypothesis.** Replacing the Mahalanobis-distance-based anomaly flag with a Bregman-divergence-based flag would lift top-K precision on money-laundering account-level detection by giving exp-family-correct distance semantics for non-gaussian dims (counts, ratios).
54
+
55
+ **What was tested.** Bregman-flag variant evaluated against Mahalanobis baseline at K ∈ {50, 100, 200, 500}, top-K precision and recall on labelled laundering accounts.
56
+
57
+ **Verdict.** ΔF1 ≤ +0.005 across all K values — inside bootstrap noise. The Bregman variant did not deliver measurable lift on this data shape.
58
+
59
+ **Why it failed.** The dimension-kind tags in production are mostly `gaussian` or `mahalanobis` with a few `bernoulli` flags. Bregman's correctness advantage only matters when a substantial fraction of dims are explicitly `poisson` or `bernoulli` and carry top-of-rank load. On the tested pattern, no such dim dominated.
60
+
61
+ **Closure.** The `is_anomaly` flag stays Mahalanobis-based. Bregman remains a per-dim choice via `dimension_kinds: poisson` / `bernoulli` declarations but is not promoted to the global flag computation. Tracked as a closed direction in session memory.
62
+
63
+ ---
64
+
65
+ ## Process refutation — emergent cycle-compression (0.7.0 retrospective)
66
+
67
+ This one is not algorithmic. The 0.7.0 cycle landed five PRs in a 24-hour window, four of which had been originally planned as 0.7.1 milestones. The result was a tag that shipped on the planned date but with a release-prep state that drifted across packages.
68
+
69
+ **Lesson.** Items that emerge during a cycle and feel ready to ship should not skip cycle boundaries unless the truth-in-CHANGELOG cost of leaving them is concrete. The hard cycle-window rule is enforced going forward: feature PRs land outside the seven-day pre-tag window; the release-prep PR is the literal last PR before the tag; emerged-during-execution items defer to the next cycle by default.
70
+
71
+ **Why this entry exists.** Methodology refutations are as load-bearing as algorithmic ones — they keep the cycle cadence honest. The 0.7.1 cycle deliberately sized smaller to test the rule under real conditions.
@@ -44,4 +44,4 @@ __all__ = [
44
44
  "IntrinsicExtrinsicReport",
45
45
  "LeadLagReport",
46
46
  ]
47
- __version__ = "0.7.0"
47
+ __version__ = "0.7.2"