modwire 9.0.0__tar.gz → 9.2.0__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 (363) hide show
  1. {modwire-9.0.0 → modwire-9.2.0}/.dev/modwire.egg-info/SOURCES.txt +19 -0
  2. {modwire-9.0.0 → modwire-9.2.0}/Makefile +4 -1
  3. {modwire-9.0.0 → modwire-9.2.0}/PKG-INFO +53 -1
  4. {modwire-9.0.0 → modwire-9.2.0}/README.md +52 -0
  5. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/application.py +78 -2
  6. modwire-9.2.0/src/modwire/cli/cache/application.py +230 -0
  7. modwire-9.2.0/src/modwire/cli/cache/domain.py +27 -0
  8. modwire-9.2.0/src/modwire/cli/cache/models/cache_entry.py +8 -0
  9. modwire-9.2.0/src/modwire/cli/cache/models/cache_key.py +11 -0
  10. modwire-9.2.0/src/modwire/cli/cache/models/cache_options.py +25 -0
  11. modwire-9.2.0/src/modwire/cli/cache/models/cache_outcome.py +44 -0
  12. modwire-9.2.0/src/modwire/cli/cache/models/cached_result.py +29 -0
  13. modwire-9.2.0/src/modwire/cli/cache/models/extraction_snapshot.py +8 -0
  14. modwire-9.2.0/src/modwire/cli/cache/models/source_entry.py +9 -0
  15. modwire-9.2.0/src/modwire/cli/cache/models/source_inventory.py +9 -0
  16. modwire-9.2.0/src/modwire/cli/cache/services/cache_codec.py +40 -0
  17. modwire-9.2.0/src/modwire/cli/cache/services/cache_identity.py +106 -0
  18. modwire-9.2.0/src/modwire/cli/cache/services/filesystem_cache_storage.py +147 -0
  19. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/facade.py +60 -6
  20. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/domain.py +13 -0
  21. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/command_request.py +5 -1
  22. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/batch_source_reader.py +57 -15
  23. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/command_line.py +11 -1
  24. modwire-9.2.0/tests/application/test_07_cache.py +230 -0
  25. modwire-9.2.0/tests/extraction/cache_benchmark/run.py +155 -0
  26. modwire-9.2.0/tests/extraction/scan_benchmark/__init__.py +0 -0
  27. modwire-9.2.0/tests/shared/__init__.py +0 -0
  28. modwire-9.2.0/tests/shared/code/__init__.py +0 -0
  29. modwire-9.2.0/tests/support/__init__.py +0 -0
  30. {modwire-9.0.0 → modwire-9.2.0}/.github/workflows/ci.yml +0 -0
  31. {modwire-9.0.0 → modwire-9.2.0}/.github/workflows/release.yml +0 -0
  32. {modwire-9.0.0 → modwire-9.2.0}/.gitignore +0 -0
  33. {modwire-9.0.0 → modwire-9.2.0}/AGENTS.md +0 -0
  34. {modwire-9.0.0 → modwire-9.2.0}/LICENSE +0 -0
  35. {modwire-9.0.0 → modwire-9.2.0}/MANIFEST.in +0 -0
  36. {modwire-9.0.0 → modwire-9.2.0}/docs/target-language-ownership.md +0 -0
  37. {modwire-9.0.0 → modwire-9.2.0}/pyproject.toml +0 -0
  38. {modwire-9.0.0 → modwire-9.2.0}/scripts/check_extractors.py +0 -0
  39. {modwire-9.0.0 → modwire-9.2.0}/scripts/generate_docs.py +0 -0
  40. {modwire-9.0.0 → modwire-9.2.0}/scripts/verify_consumer.py +0 -0
  41. {modwire-9.0.0 → modwire-9.2.0}/setup.cfg +0 -0
  42. {modwire-9.0.0 → modwire-9.2.0}/setup.py +0 -0
  43. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/__init__.py +0 -0
  44. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/__main__.py +0 -0
  45. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/__init__.py +0 -0
  46. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/__init__.py +0 -0
  47. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/application.py +0 -0
  48. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/domain.py +0 -0
  49. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/models/__init__.py +0 -0
  50. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/models/edge_rule_violation.py +0 -0
  51. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/models/flow_report.py +0 -0
  52. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/models/flow_violation.py +0 -0
  53. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/models/types.py +0 -0
  54. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/services/__init__.py +0 -0
  55. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/services/backward_flow_analyzer.py +0 -0
  56. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/services/boundaries_flow_analyzer.py +0 -0
  57. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/services/module_boundary_analyzer.py +0 -0
  58. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/services/no_cycles_flow_analyzer.py +0 -0
  59. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/boundaries/services/no_reentry_flow_analyzer.py +0 -0
  60. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/__init__.py +0 -0
  61. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/application.py +0 -0
  62. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/__init__.py +0 -0
  63. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/architecture_config.py +0 -0
  64. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/boundaries_config.py +0 -0
  65. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/boundary_rule.py +0 -0
  66. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/configuration_value.py +0 -0
  67. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/flow_realm.py +0 -0
  68. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/flow_rules.py +0 -0
  69. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/shape_config.py +0 -0
  70. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/shape_realm.py +0 -0
  71. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/shape_rules.py +0 -0
  72. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/config/models/tag_rule.py +0 -0
  73. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/facade.py +0 -0
  74. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/__init__.py +0 -0
  75. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/application.py +0 -0
  76. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/domain.py +0 -0
  77. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/__init__.py +0 -0
  78. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/callable_report_entry.py +0 -0
  79. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/callables_report.py +0 -0
  80. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/clusters_report.py +0 -0
  81. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/clusters_report_item.py +0 -0
  82. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/coherence_report.py +0 -0
  83. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/exports_report.py +0 -0
  84. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/exports_report_item.py +0 -0
  85. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/hotspots_report.py +0 -0
  86. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/hotspots_report_item.py +0 -0
  87. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/models/insight_report.py +0 -0
  88. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/__init__.py +0 -0
  89. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/callables_reporter.py +0 -0
  90. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/clusters_reporter.py +0 -0
  91. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/coherence_reporter.py +0 -0
  92. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/exports_reporter.py +0 -0
  93. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/hotspots_reporter.py +0 -0
  94. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/insights/services/insight_report_field_map.py +0 -0
  95. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/__init__.py +0 -0
  96. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/application.py +0 -0
  97. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/domain.py +0 -0
  98. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/models/__init__.py +0 -0
  99. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/models/architecture_map.py +0 -0
  100. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/models/architecture_realm.py +0 -0
  101. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/models/tag_map.py +0 -0
  102. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/models/tag_match.py +0 -0
  103. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/services/__init__.py +0 -0
  104. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/services/architecture_map_loader.py +0 -0
  105. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/map/services/tag_matcher.py +0 -0
  106. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/__init__.py +0 -0
  107. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/application.py +0 -0
  108. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/domain.py +0 -0
  109. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/__init__.py +0 -0
  110. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/architecture_group.py +0 -0
  111. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/map_report.py +0 -0
  112. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/report_catalog.py +0 -0
  113. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/report_descriptor.py +0 -0
  114. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/report_item.py +0 -0
  115. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/report_metadata.py +0 -0
  116. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/report_node.py +0 -0
  117. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/models/report_section.py +0 -0
  118. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/services/__init__.py +0 -0
  119. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/report/services/map_report_collector.py +0 -0
  120. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/__init__.py +0 -0
  121. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/application.py +0 -0
  122. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/domain.py +0 -0
  123. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/models/__init__.py +0 -0
  124. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/models/shape_realm_architecture_map.py +0 -0
  125. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/models/shape_report.py +0 -0
  126. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/models/shape_violation.py +0 -0
  127. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/__init__.py +0 -0
  128. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/abstract_class_resolver.py +0 -0
  129. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/callable_resolver.py +0 -0
  130. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/class_resolver.py +0 -0
  131. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/file_resolver.py +0 -0
  132. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/import_resolver.py +0 -0
  133. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/property_resolver.py +0 -0
  134. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/signature_resolver.py +0 -0
  135. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/architecture/shape/services/symbol_resolver.py +0 -0
  136. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/autowiring.py +0 -0
  137. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/__init__.py +0 -0
  138. {modwire-9.0.0/src/modwire/cli/resources/models → modwire-9.2.0/src/modwire/cli/cache}/__init__.py +0 -0
  139. {modwire-9.0.0/src/modwire/extraction → modwire-9.2.0/src/modwire/cli/cache/models}/__init__.py +0 -0
  140. {modwire-9.0.0/src/modwire/shared → modwire-9.2.0/src/modwire/cli/cache/services}/__init__.py +0 -0
  141. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/documentation/__init__.py +0 -0
  142. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/documentation/application.py +0 -0
  143. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/documentation/services/__init__.py +0 -0
  144. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/documentation/services/documentation_generator.py +0 -0
  145. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/initialization/__init__.py +0 -0
  146. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/initialization/application.py +0 -0
  147. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/initialization/models/__init__.py +0 -0
  148. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/initialization/models/initialization_result.py +0 -0
  149. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/initialization/services/__init__.py +0 -0
  150. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/initialization/services/initialization_service.py +0 -0
  151. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/__init__.py +0 -0
  152. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/application.py +0 -0
  153. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/__init__.py +0 -0
  154. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/extractor_batch_input.py +0 -0
  155. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/extractor_command_input.py +0 -0
  156. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/extractor_source_input.py +0 -0
  157. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/report_pipeline_context.py +0 -0
  158. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/models/scan_policy.py +0 -0
  159. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/__init__.py +0 -0
  160. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/callables_insight.py +0 -0
  161. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/clusters_insight.py +0 -0
  162. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/coherence_insight.py +0 -0
  163. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/configuration_loader.py +0 -0
  164. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/extractor_command.py +0 -0
  165. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/flow_violations.py +0 -0
  166. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/hotspots_insight.py +0 -0
  167. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/map_tree.py +0 -0
  168. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/output_console.py +0 -0
  169. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/shape_violations.py +0 -0
  170. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/success.py +0 -0
  171. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/unknown_files_warning.py +0 -0
  172. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/pipeline/services/unused_exports_insight.py +0 -0
  173. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/__init__.py +0 -0
  174. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/application.py +0 -0
  175. {modwire-9.0.0/src/modwire/shared/values → modwire-9.2.0/src/modwire/cli/resources}/models/__init__.py +0 -0
  176. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/models/defaults.py +0 -0
  177. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/models/init_asset.py +0 -0
  178. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/AGENTS.md +0 -0
  179. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/ARCHITECTURE.md +0 -0
  180. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/INDEX.md +0 -0
  181. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/MODWIRE.md +0 -0
  182. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/RULES.md +0 -0
  183. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/TESTING.md +0 -0
  184. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/WORKFLOW.md +0 -0
  185. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/cli/resources/templates/architecture.yaml +0 -0
  186. {modwire-9.0.0/tests → modwire-9.2.0/src/modwire/extraction}/__init__.py +0 -0
  187. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/__init__.py +0 -0
  188. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/application.py +0 -0
  189. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/domain.py +0 -0
  190. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/services/__init__.py +0 -0
  191. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/services/graph_builder.py +0 -0
  192. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/services/import_resolver.py +0 -0
  193. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/dependency/services/suffix_index.py +0 -0
  194. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/__init__.py +0 -0
  195. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/application.py +0 -0
  196. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/domain.py +0 -0
  197. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/models/__init__.py +0 -0
  198. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/models/batch_config.py +0 -0
  199. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/models/extraction_request.py +0 -0
  200. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/models/extractor_resource.py +0 -0
  201. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/models/extractor_runtime.py +0 -0
  202. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/models/python_call_context.py +0 -0
  203. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/__init__.py +0 -0
  204. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/php/build.php +0 -0
  205. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/php/build.py +0 -0
  206. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/php/composer.json +0 -0
  207. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/php/composer.lock +0 -0
  208. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/php/script.php +0 -0
  209. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/php/script.src.php +0 -0
  210. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/python/__init__.py +0 -0
  211. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/python/script.py +0 -0
  212. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/build.mjs +0 -0
  213. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/build.py +0 -0
  214. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/package-lock.json +0 -0
  215. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/package.json +0 -0
  216. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/script.js +0 -0
  217. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/script.ts +0 -0
  218. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/resources/typescript/tsconfig.json +0 -0
  219. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/services/__init__.py +0 -0
  220. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/services/php_extractor.py +0 -0
  221. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/services/python_call_reader.py +0 -0
  222. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/services/python_extractor.py +0 -0
  223. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/services/python_syntax_parser.py +0 -0
  224. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/extractors/services/type_script_extractor.py +0 -0
  225. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/extraction/facade.py +0 -0
  226. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/py.typed +0 -0
  227. {modwire-9.0.0/tests/application → modwire-9.2.0/src/modwire/shared}/__init__.py +0 -0
  228. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/__init__.py +0 -0
  229. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/application.py +0 -0
  230. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/domain.py +0 -0
  231. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/__init__.py +0 -0
  232. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/code_map.py +0 -0
  233. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/code_package.py +0 -0
  234. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/dependency_edge_result.py +0 -0
  235. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/dependency_graph.py +0 -0
  236. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/dependency_node_result.py +0 -0
  237. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/duplicate_identity_error.py +0 -0
  238. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/edge.py +0 -0
  239. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/edge_resolution.py +0 -0
  240. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/identity.py +0 -0
  241. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/node.py +0 -0
  242. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/query_builder.py +0 -0
  243. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/query_types.py +0 -0
  244. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/queryable_code_map.py +0 -0
  245. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_abstract_class.py +0 -0
  246. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_call.py +0 -0
  247. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_callable.py +0 -0
  248. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_callable_symbol.py +0 -0
  249. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_class.py +0 -0
  250. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_class_method.py +0 -0
  251. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_class_property.py +0 -0
  252. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_export.py +0 -0
  253. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_extraction.py +0 -0
  254. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_file.py +0 -0
  255. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_file_result.py +0 -0
  256. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_function.py +0 -0
  257. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_import.py +0 -0
  258. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_imported_symbol.py +0 -0
  259. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_interface.py +0 -0
  260. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_item_result.py +0 -0
  261. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_parameter.py +0 -0
  262. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_signature.py +0 -0
  263. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_symbol.py +0 -0
  264. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_type.py +0 -0
  265. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/source_value.py +0 -0
  266. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/models/types.py +0 -0
  267. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/services/__init__.py +0 -0
  268. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/services/glob_path_matcher.py +0 -0
  269. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/code/services/identity_resolver.py +0 -0
  270. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/values/__init__.py +0 -0
  271. {modwire-9.0.0/tests/architecture → modwire-9.2.0/src/modwire/shared/values/models}/__init__.py +0 -0
  272. {modwire-9.0.0 → modwire-9.2.0}/src/modwire/shared/values/models/value_model.py +0 -0
  273. {modwire-9.0.0/tests/architecture/boundaries → modwire-9.2.0/tests}/__init__.py +0 -0
  274. {modwire-9.0.0/tests/architecture/config → modwire-9.2.0/tests/application}/__init__.py +0 -0
  275. {modwire-9.0.0 → modwire-9.2.0}/tests/application/base_test.py +0 -0
  276. {modwire-9.0.0 → modwire-9.2.0}/tests/application/test_01_attacks.py +0 -0
  277. {modwire-9.0.0 → modwire-9.2.0}/tests/application/test_06_happy_path.py +0 -0
  278. {modwire-9.0.0/tests/architecture/insights → modwire-9.2.0/tests/architecture}/__init__.py +0 -0
  279. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/base_test.py +0 -0
  280. {modwire-9.0.0/tests/architecture/map → modwire-9.2.0/tests/architecture/boundaries}/__init__.py +0 -0
  281. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/boundaries/base_test.py +0 -0
  282. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/boundaries/test_01_attacks.py +0 -0
  283. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/boundaries/test_02_invariants.py +0 -0
  284. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/boundaries/test_03_public_api.py +0 -0
  285. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/boundaries/test_04_paths.py +0 -0
  286. {modwire-9.0.0/tests/architecture/report → modwire-9.2.0/tests/architecture/config}/__init__.py +0 -0
  287. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/config/test_01_attacks.py +0 -0
  288. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/config/test_02_invariants.py +0 -0
  289. {modwire-9.0.0/tests/architecture/shape → modwire-9.2.0/tests/architecture/insights}/__init__.py +0 -0
  290. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/insights/base_test.py +0 -0
  291. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/insights/test_02_invariants.py +0 -0
  292. {modwire-9.0.0/tests/cli → modwire-9.2.0/tests/architecture/map}/__init__.py +0 -0
  293. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/map/test_02_patterns.py +0 -0
  294. {modwire-9.0.0/tests/cli/documentation → modwire-9.2.0/tests/architecture/report}/__init__.py +0 -0
  295. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/report/test_02_invariants.py +0 -0
  296. {modwire-9.0.0/tests/cli/initialization → modwire-9.2.0/tests/architecture/shape}/__init__.py +0 -0
  297. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/shape/base_test.py +0 -0
  298. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/shape/test_01_limits.py +0 -0
  299. {modwire-9.0.0 → modwire-9.2.0}/tests/architecture/shape/test_02_invariants.py +0 -0
  300. {modwire-9.0.0/tests/cli/pipeline → modwire-9.2.0/tests/cli}/__init__.py +0 -0
  301. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/base_test.py +0 -0
  302. {modwire-9.0.0/tests/extraction → modwire-9.2.0/tests/cli/documentation}/__init__.py +0 -0
  303. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/documentation/test_02_invariants.py +0 -0
  304. {modwire-9.0.0/tests/extraction/big_projects → modwire-9.2.0/tests/cli/initialization}/__init__.py +0 -0
  305. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/initialization/test_01_attacks.py +0 -0
  306. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/initialization/test_02_invariants.py +0 -0
  307. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/initialization/test_03_interruption.py +0 -0
  308. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/initialization/test_04_cleanup.py +0 -0
  309. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/initialization/test_05_recovery.py +0 -0
  310. {modwire-9.0.0/tests/extraction/dependency → modwire-9.2.0/tests/cli/pipeline}/__init__.py +0 -0
  311. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/base_test.py +0 -0
  312. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/test_01_attacks.py +0 -0
  313. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/test_02_invariants.py +0 -0
  314. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/test_03_interruption.py +0 -0
  315. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/test_04_command_transport.py +0 -0
  316. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/test_05_recovery.py +0 -0
  317. {modwire-9.0.0 → modwire-9.2.0}/tests/cli/pipeline/test_06_happy_path.py +0 -0
  318. {modwire-9.0.0 → modwire-9.2.0}/tests/conftest.py +0 -0
  319. {modwire-9.0.0/tests/extraction/extractors → modwire-9.2.0/tests/extraction}/__init__.py +0 -0
  320. {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/base_test.py +0 -0
  321. {modwire-9.0.0/tests/extraction/scan_benchmark → modwire-9.2.0/tests/extraction/big_projects}/__init__.py +0 -0
  322. {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/big_projects/project.py +0 -0
  323. {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/big_projects/projects.json +0 -0
  324. {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/big_projects/resolution_results.json +0 -0
  325. {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/big_projects/results.json +0 -0
  326. {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/big_projects/run.py +0 -0
  327. {modwire-9.0.0/tests/shared → modwire-9.2.0/tests/extraction/cache_benchmark}/__init__.py +0 -0
  328. {modwire-9.0.0/tests/shared/code → modwire-9.2.0/tests/extraction/dependency}/__init__.py +0 -0
  329. {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/dependency/test_02_invariants.py +0 -0
  330. {modwire-9.0.0/tests/support → modwire-9.2.0/tests/extraction/extractors}/__init__.py +0 -0
  331. {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/extractors/test_01_attacks.py +0 -0
  332. {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/extractors/test_02_invariants.py +0 -0
  333. {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/extractors/test_03_native_symbols.py +0 -0
  334. {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/scan_benchmark/prepare.py +0 -0
  335. {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/scan_benchmark/results.json +0 -0
  336. {modwire-9.0.0 → modwire-9.2.0}/tests/extraction/scan_benchmark/run.py +0 -0
  337. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/php/ignored/example_generated.php +0 -0
  338. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/php/src/example_application/example_actions/example_action.php +0 -0
  339. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/php/src/example_domain/example_model/example_record.php +0 -0
  340. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/php/src/example_domain/example_services/example_policy.php +0 -0
  341. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/php/src/example_interfaces/example_http/example_controller.php +0 -0
  342. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/python/ignored/example_generated.py +0 -0
  343. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/python/src/example_application/example_actions/example_action.py +0 -0
  344. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/python/src/example_domain/example_model/example_record.py +0 -0
  345. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/python/src/example_domain/example_services/example_policy.py +0 -0
  346. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/python/src/example_interfaces/example_http/example_controller.py +0 -0
  347. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/ignored/example_generated.ts +0 -0
  348. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_application/example_actions/example_action.ts +0 -0
  349. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_domain/example_model/example_record.ts +0 -0
  350. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_domain/example_model/example_view.tsx +0 -0
  351. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_audit.js +0 -0
  352. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_callables.ts +0 -0
  353. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_policy.ts +0 -0
  354. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_interfaces/example_http/example_controller.ts +0 -0
  355. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/languages/typescript/src/example_interfaces/example_http/example_view.jsx +0 -0
  356. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/syntax/php/example_shapes.php +0 -0
  357. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/syntax/python/example_shapes.py +0 -0
  358. {modwire-9.0.0 → modwire-9.2.0}/tests/fixtures/syntax/typescript/example_shapes.ts +0 -0
  359. {modwire-9.0.0 → modwire-9.2.0}/tests/shared/code/test_02_invariants.py +0 -0
  360. {modwire-9.0.0 → modwire-9.2.0}/tests/support/base_test.py +0 -0
  361. {modwire-9.0.0 → modwire-9.2.0}/tests/support/code_map.py +0 -0
  362. {modwire-9.0.0 → modwire-9.2.0}/tests/support/service_test.py +0 -0
  363. {modwire-9.0.0 → modwire-9.2.0}/uv.lock +0 -0
@@ -112,6 +112,22 @@ src/modwire/architecture/shape/services/signature_resolver.py
112
112
  src/modwire/architecture/shape/services/symbol_resolver.py
113
113
  src/modwire/cli/__init__.py
114
114
  src/modwire/cli/facade.py
115
+ src/modwire/cli/cache/__init__.py
116
+ src/modwire/cli/cache/application.py
117
+ src/modwire/cli/cache/domain.py
118
+ src/modwire/cli/cache/models/__init__.py
119
+ src/modwire/cli/cache/models/cache_entry.py
120
+ src/modwire/cli/cache/models/cache_key.py
121
+ src/modwire/cli/cache/models/cache_options.py
122
+ src/modwire/cli/cache/models/cache_outcome.py
123
+ src/modwire/cli/cache/models/cached_result.py
124
+ src/modwire/cli/cache/models/extraction_snapshot.py
125
+ src/modwire/cli/cache/models/source_entry.py
126
+ src/modwire/cli/cache/models/source_inventory.py
127
+ src/modwire/cli/cache/services/__init__.py
128
+ src/modwire/cli/cache/services/cache_codec.py
129
+ src/modwire/cli/cache/services/cache_identity.py
130
+ src/modwire/cli/cache/services/filesystem_cache_storage.py
115
131
  src/modwire/cli/documentation/__init__.py
116
132
  src/modwire/cli/documentation/application.py
117
133
  src/modwire/cli/documentation/services/__init__.py
@@ -253,6 +269,7 @@ tests/application/__init__.py
253
269
  tests/application/base_test.py
254
270
  tests/application/test_01_attacks.py
255
271
  tests/application/test_06_happy_path.py
272
+ tests/application/test_07_cache.py
256
273
  tests/architecture/__init__.py
257
274
  tests/architecture/base_test.py
258
275
  tests/architecture/boundaries/__init__.py
@@ -301,6 +318,8 @@ tests/extraction/big_projects/projects.json
301
318
  tests/extraction/big_projects/resolution_results.json
302
319
  tests/extraction/big_projects/results.json
303
320
  tests/extraction/big_projects/run.py
321
+ tests/extraction/cache_benchmark/__init__.py
322
+ tests/extraction/cache_benchmark/run.py
304
323
  tests/extraction/dependency/__init__.py
305
324
  tests/extraction/dependency/test_02_invariants.py
306
325
  tests/extraction/extractors/__init__.py
@@ -7,7 +7,7 @@ PROJECT_ROOT := $(CURDIR)
7
7
  export PYTHONPYCACHEPREFIX := $(PROJECT_ROOT)/$(DEV_DIR)/cache/python
8
8
  export UV_CACHE_DIR := $(PROJECT_ROOT)/$(DEV_DIR)/cache/uv
9
9
 
10
- .PHONY: big-projects build ci docs docs-check extractor-check format format-check host-check lint package-check scan-benchmark scan-benchmark-fixture test type-check
10
+ .PHONY: big-projects build cache-benchmark ci docs docs-check extractor-check format format-check host-check lint package-check scan-benchmark scan-benchmark-fixture test type-check
11
11
 
12
12
  format:
13
13
  uv run ruff format src tests scripts
@@ -34,6 +34,9 @@ scan-benchmark-fixture:
34
34
  scan-benchmark:
35
35
  uv run python -m tests.extraction.scan_benchmark.run --root .dev/benchmarks/scan-project --language "$(SCAN_BENCHMARK_LANGUAGE)" --excluded-pattern 'example_excluded/**'
36
36
 
37
+ cache-benchmark:
38
+ uv run python -m tests.extraction.cache_benchmark.run --root "$(CACHE_BENCHMARK_ROOT)" --language "$(CACHE_BENCHMARK_LANGUAGE)" --cache-directory .dev/benchmarks/cache --incremental-source "$(CACHE_BENCHMARK_SOURCE)" --replacement-source "$(CACHE_BENCHMARK_REPLACEMENT)"
39
+
37
40
  docs-check:
38
41
  uv run python scripts/generate_docs.py --check
39
42
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modwire
3
- Version: 9.0.0
3
+ Version: 9.2.0
4
4
  Summary: Code extraction, architecture analysis and the Modwire CLI.
5
5
  Author: Tomasz Szpak
6
6
  License-Expression: MIT
@@ -48,6 +48,14 @@ Return the available architecture reports.
48
48
 
49
49
  Analyze a code map with a validated architecture configuration.
50
50
 
51
+ ### `analyze_cached`
52
+
53
+ Analyze a code map, reusing reports for an exact map and configuration identity.
54
+
55
+ ### `analyze_cached_with_diagnostics`
56
+
57
+ Analyze a code map and report the public outcome of report-cache reuse.
58
+
51
59
  ### `discover`
52
60
 
53
61
  Discover supported source languages beneath a root using the caller's scan policy.
@@ -64,6 +72,26 @@ descendants are deliberately unobserved and are not included in file counts.
64
72
 
65
73
  Extract source files and return a queryable code map.
66
74
 
75
+ ### `generate_map_cached`
76
+
77
+ Return a code map with content-addressed source and complete-manifest reuse.
78
+
79
+ ### `generate_map_cached_with_diagnostics`
80
+
81
+ Return a code map and public outcomes for extraction and complete-map reuse.
82
+
83
+ ### `generate_queryable_map_cached`
84
+
85
+ Return a queryable code map with content-addressed persistent reuse.
86
+
87
+ ### `generate_queryable_map_cached_with_diagnostics`
88
+
89
+ Return a queryable code map and public outcomes for every applicable cache stage.
90
+
91
+ ### `clear_cache`
92
+
93
+ Clear only the Modwire-owned directory for one cache namespace.
94
+
67
95
  ### `load_configuration`
68
96
 
69
97
  Load and validate an architecture configuration from a directory.
@@ -84,6 +112,30 @@ Run the native extractor transport for one supported language.
84
112
 
85
113
  Run the Modwire command line interface and return its process status.
86
114
 
115
+ ## `CacheStage`
116
+
117
+ Public stages reported by cached Modwire operations.
118
+
119
+ ## `CacheOutcome`
120
+
121
+ Content-safe lifecycle counts for one stage of a cached operation.
122
+
123
+ Extraction counts describe current source records. Code-map and report counts
124
+ describe one entry. Invalidated entries are also misses. Diagnostics include
125
+ the configured namespace but never cache keys, source identities, or content.
126
+
127
+ ## `CachedResult`
128
+
129
+ A cached operation value together with one outcome per applicable stage.
130
+
131
+ ### `outcome`
132
+
133
+ Return the outcome for one applicable cache stage.
134
+
135
+ ## `CacheOptions`
136
+
137
+ Generic persistent-cache settings supplied by a caller.
138
+
87
139
  ## `ScanPolicy`
88
140
 
89
141
  Caller-owned filesystem traversal policy with explicit exclusions and opt-in symlink following.
@@ -20,6 +20,14 @@ Return the available architecture reports.
20
20
 
21
21
  Analyze a code map with a validated architecture configuration.
22
22
 
23
+ ### `analyze_cached`
24
+
25
+ Analyze a code map, reusing reports for an exact map and configuration identity.
26
+
27
+ ### `analyze_cached_with_diagnostics`
28
+
29
+ Analyze a code map and report the public outcome of report-cache reuse.
30
+
23
31
  ### `discover`
24
32
 
25
33
  Discover supported source languages beneath a root using the caller's scan policy.
@@ -36,6 +44,26 @@ descendants are deliberately unobserved and are not included in file counts.
36
44
 
37
45
  Extract source files and return a queryable code map.
38
46
 
47
+ ### `generate_map_cached`
48
+
49
+ Return a code map with content-addressed source and complete-manifest reuse.
50
+
51
+ ### `generate_map_cached_with_diagnostics`
52
+
53
+ Return a code map and public outcomes for extraction and complete-map reuse.
54
+
55
+ ### `generate_queryable_map_cached`
56
+
57
+ Return a queryable code map with content-addressed persistent reuse.
58
+
59
+ ### `generate_queryable_map_cached_with_diagnostics`
60
+
61
+ Return a queryable code map and public outcomes for every applicable cache stage.
62
+
63
+ ### `clear_cache`
64
+
65
+ Clear only the Modwire-owned directory for one cache namespace.
66
+
39
67
  ### `load_configuration`
40
68
 
41
69
  Load and validate an architecture configuration from a directory.
@@ -56,6 +84,30 @@ Run the native extractor transport for one supported language.
56
84
 
57
85
  Run the Modwire command line interface and return its process status.
58
86
 
87
+ ## `CacheStage`
88
+
89
+ Public stages reported by cached Modwire operations.
90
+
91
+ ## `CacheOutcome`
92
+
93
+ Content-safe lifecycle counts for one stage of a cached operation.
94
+
95
+ Extraction counts describe current source records. Code-map and report counts
96
+ describe one entry. Invalidated entries are also misses. Diagnostics include
97
+ the configured namespace but never cache keys, source identities, or content.
98
+
99
+ ## `CachedResult`
100
+
101
+ A cached operation value together with one outcome per applicable stage.
102
+
103
+ ### `outcome`
104
+
105
+ Return the outcome for one applicable cache stage.
106
+
107
+ ## `CacheOptions`
108
+
109
+ Generic persistent-cache settings supplied by a caller.
110
+
59
111
  ## `ScanPolicy`
60
112
 
61
113
  Caller-owned filesystem traversal policy with explicit exclusions and opt-in symlink following.
@@ -10,13 +10,25 @@ from .architecture.config.models.architecture_config import ArchitectureConfig
10
10
  from .architecture.facade import ArchitectureFacade
11
11
  from .architecture.report.models.report_catalog import ReportCatalog
12
12
  from .architecture.report.models.report_node import ReportNode
13
+ from .cli.cache.models.cache_options import CacheOptions
14
+ from .cli.cache.models.cache_outcome import CacheOutcome, CacheStage
15
+ from .cli.cache.models.cached_result import CachedResult
13
16
  from .cli.facade import CliFacade
14
17
  from .cli.pipeline.models.scan_policy import ScanPolicy
15
18
  from .extraction.facade import ExtractionFacade
16
19
  from .shared.code.models.code_map import CodeMap
17
20
  from .shared.code.models.queryable_code_map import QueryableCodeMap
18
21
 
19
- __all__ = ["CodeMap", "ModwireApplication", "QueryableCodeMap", "ScanPolicy"]
22
+ __all__ = [
23
+ "CacheOptions",
24
+ "CacheOutcome",
25
+ "CacheStage",
26
+ "CachedResult",
27
+ "CodeMap",
28
+ "ModwireApplication",
29
+ "QueryableCodeMap",
30
+ "ScanPolicy",
31
+ ]
20
32
 
21
33
 
22
34
  @dataclass(frozen=True)
@@ -56,6 +68,26 @@ class ModwireApplication:
56
68
 
57
69
  return self.architecture.analyze(code_map, config)
58
70
 
71
+ def analyze_cached(
72
+ self, code_map: QueryableCodeMap, config: ArchitectureConfig, options: CacheOptions
73
+ ) -> tuple[ReportNode, ...]:
74
+ """Analyze a code map, reusing reports for an exact map and configuration identity."""
75
+
76
+ return self.analyze_cached_with_diagnostics(code_map, config, options).value
77
+
78
+ def analyze_cached_with_diagnostics(
79
+ self, code_map: QueryableCodeMap, config: ArchitectureConfig, options: CacheOptions
80
+ ) -> CachedResult[tuple[ReportNode, ...]]:
81
+ """Analyze a code map and report the public outcome of report-cache reuse."""
82
+
83
+ cached = self.cli.cached_reports(code_map.code_map, config, options)
84
+ if cached.value is not None:
85
+ return CachedResult(value=cached.value, outcomes=cached.outcomes)
86
+ reports = self.architecture.analyze(code_map, config)
87
+ self.cli.store_reports(code_map.code_map, config, reports, options)
88
+ outcome = cached.outcome(CacheStage.REPORTS).model_copy(update={"computed": 1, "stored": 1})
89
+ return CachedResult(value=reports, outcomes=(outcome,))
90
+
59
91
  def discover(self, root: str, policy: ScanPolicy) -> tuple[str, ...]:
60
92
  """Discover supported source languages beneath a root using the caller's scan policy."""
61
93
 
@@ -81,6 +113,48 @@ class ModwireApplication:
81
113
 
82
114
  return QueryableCodeMap(code_map=self.generate_map(language, root, policy))
83
115
 
116
+ def generate_map_cached(self, language: str, root: str, policy: ScanPolicy, options: CacheOptions) -> CodeMap:
117
+ """Return a code map with content-addressed source and complete-manifest reuse."""
118
+
119
+ return self.generate_map_cached_with_diagnostics(language, root, policy, options).value
120
+
121
+ def generate_map_cached_with_diagnostics(
122
+ self, language: str, root: str, policy: ScanPolicy, options: CacheOptions
123
+ ) -> CachedResult[CodeMap]:
124
+ """Return a code map and public outcomes for extraction and complete-map reuse."""
125
+
126
+ request = self.extraction.request(language, str(root))
127
+ snapshot = self.cli.extract_cached(request, policy, options)
128
+ cached = self.cli.cached_code_map(snapshot.value, options)
129
+ outcome = cached.outcome(CacheStage.CODE_MAP)
130
+ if cached.value is not None:
131
+ code_map = cached.value
132
+ else:
133
+ code_map = self.extraction.generate_map(language, snapshot.value.extraction)
134
+ self.cli.store_code_map(snapshot.value, code_map, options)
135
+ outcome = outcome.model_copy(update={"computed": 1, "stored": 1})
136
+ return CachedResult(value=code_map, outcomes=(*snapshot.outcomes, outcome))
137
+
138
+ def generate_queryable_map_cached(
139
+ self, language: str, root: str, policy: ScanPolicy, options: CacheOptions
140
+ ) -> QueryableCodeMap:
141
+ """Return a queryable code map with content-addressed persistent reuse."""
142
+
143
+ return self.generate_queryable_map_cached_with_diagnostics(language, root, policy, options).value
144
+
145
+ def generate_queryable_map_cached_with_diagnostics(
146
+ self, language: str, root: str, policy: ScanPolicy, options: CacheOptions
147
+ ) -> CachedResult[QueryableCodeMap]:
148
+ """Return a queryable code map and public outcomes for every applicable cache stage."""
149
+
150
+ cached = self.generate_map_cached_with_diagnostics(language, root, policy, options)
151
+ return CachedResult(value=QueryableCodeMap(code_map=cached.value), outcomes=cached.outcomes)
152
+
153
+ def clear_cache(self, options: CacheOptions) -> None:
154
+ """Clear only the Modwire-owned directory for one cache namespace."""
155
+
156
+ self.cli.clear_cache(options)
157
+
84
158
  def load_configuration(self, dot_dir: str) -> ArchitectureConfig:
85
159
  """Load and validate an architecture configuration from a directory."""
86
160
 
@@ -94,7 +168,9 @@ class ModwireApplication:
94
168
  def generate_documentation(self, readme: str, check: bool) -> int:
95
169
  """Generate this README from the published interface docstrings, or check that it is current."""
96
170
 
97
- return self.cli.generate_documentation(str(readme), (type(self), ScanPolicy), check)
171
+ return self.cli.generate_documentation(
172
+ str(readme), (type(self), CacheStage, CacheOutcome, CachedResult, CacheOptions, ScanPolicy), check
173
+ )
98
174
 
99
175
  def run_extractor(self, language: str) -> int:
100
176
  """Run the native extractor transport for one supported language."""
@@ -0,0 +1,230 @@
1
+ import importlib
2
+ from dataclasses import dataclass
3
+ from typing import Any, cast
4
+
5
+ from pydantic import BaseModel, ValidationError
6
+ from wireup import injectable
7
+
8
+ from ...architecture.config.models.architecture_config import ArchitectureConfig
9
+ from ...architecture.report.models.report_node import ReportNode
10
+ from ...extraction.extractors.models.extraction_request import ExtractionRequest
11
+ from ...shared.code.models.code_map import CodeMap
12
+ from ...shared.code.models.duplicate_identity_error import DuplicateIdentityError
13
+ from ...shared.code.models.identity import FileId, ModuleId
14
+ from ...shared.code.models.source_extraction import SourceExtraction
15
+ from ...shared.code.models.source_file import SourceFile
16
+ from ..pipeline.domain import SourceReader
17
+ from ..pipeline.models.scan_policy import ScanPolicy
18
+ from .domain import CacheStorage
19
+ from .models.cache_key import CacheKey
20
+ from .models.cache_options import CacheOptions
21
+ from .models.cache_outcome import CacheOutcome, CacheStage
22
+ from .models.cached_result import CachedResult
23
+ from .models.extraction_snapshot import ExtractionSnapshot
24
+ from .services.cache_codec import CacheCodec
25
+ from .services.cache_identity import CacheIdentity
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class _CacheRead:
30
+ value: object | None
31
+ invalidated: bool
32
+
33
+
34
+ @injectable
35
+ @dataclass(frozen=True)
36
+ class CacheApplication:
37
+ reader: SourceReader
38
+ storage: CacheStorage
39
+ identity: CacheIdentity
40
+ codec: CacheCodec
41
+
42
+ def has_source_files(self, request: ExtractionRequest, policy: ScanPolicy) -> bool:
43
+ return self.reader.has_source_files(request, policy)
44
+
45
+ def extract(self, request: ExtractionRequest, policy: ScanPolicy) -> SourceExtraction:
46
+ self.reader.ensure_available(request.runtime)
47
+ return self.reader.extract_source(request, policy)
48
+
49
+ def extract_cached(
50
+ self, request: ExtractionRequest, policy: ScanPolicy, options: CacheOptions
51
+ ) -> CachedResult[ExtractionSnapshot]:
52
+ inventory = self.reader.inventory(request, policy)
53
+ keys = {entry.source_id: self.identity.source(request, policy, entry) for entry in inventory.entries}
54
+ files: dict[FileId, SourceFile] = {}
55
+ misses: list[FileId] = []
56
+ hits = 0
57
+ invalidated = 0
58
+ for entry in inventory.entries:
59
+ key = keys[entry.source_id]
60
+ cached = self._read(options, key)
61
+ try:
62
+ source_file = SourceFile.model_validate(cached.value)
63
+ if source_file.file_id != entry.source_id:
64
+ raise ValueError("Cached source identity does not match its key.")
65
+ files[entry.source_id] = source_file
66
+ hits += 1
67
+ except (TypeError, ValueError, ValidationError):
68
+ if cached.value is not None and not cached.invalidated:
69
+ self.storage.delete(options, key)
70
+ invalidated += int(cached.invalidated or cached.value is not None)
71
+ misses.append(entry.source_id)
72
+
73
+ if misses or not inventory.entries:
74
+ self.reader.ensure_available(request.runtime)
75
+ extracted = self.reader.extract_entries(request, inventory, tuple(misses))
76
+ for source_id in misses:
77
+ source_file = extracted.get(source_id)
78
+ if source_file is None:
79
+ raise RuntimeError(f"Extractor omitted a requested source file: {source_id}")
80
+ files[source_id] = source_file
81
+ self._write(options, keys[source_id], source_file.model_dump(mode="json"))
82
+
83
+ ordered_files = {entry.source_id: files[entry.source_id] for entry in inventory.entries}
84
+ modules: dict[ModuleId, FileId] = {}
85
+ for file_id, source_file in ordered_files.items():
86
+ existing = modules.get(source_file.module_id)
87
+ if existing is not None:
88
+ raise DuplicateIdentityError("module", source_file.module_id, existing, file_id)
89
+ modules[source_file.module_id] = file_id
90
+
91
+ extraction = SourceExtraction(
92
+ files=ordered_files,
93
+ modules=modules,
94
+ files_found=inventory.files_found,
95
+ files_excluded=inventory.files_excluded,
96
+ directories_pruned=inventory.directories_pruned,
97
+ )
98
+ manifest = self.identity.manifest(request, policy, inventory.entries)
99
+ self._write(
100
+ options,
101
+ manifest,
102
+ {
103
+ "sources": [
104
+ {
105
+ "relative_path": entry.relative_path,
106
+ "content_digest": entry.content_digest,
107
+ "source_key": keys[entry.source_id].digest,
108
+ }
109
+ for entry in inventory.entries
110
+ ]
111
+ },
112
+ )
113
+ self.prune(options)
114
+ return CachedResult(
115
+ value=ExtractionSnapshot(extraction=extraction, manifest=manifest),
116
+ outcomes=(
117
+ CacheOutcome(
118
+ stage=CacheStage.EXTRACTION,
119
+ namespace=options.namespace,
120
+ hits=hits,
121
+ misses=len(misses),
122
+ invalidated=invalidated,
123
+ computed=len(misses),
124
+ stored=len(misses),
125
+ ),
126
+ ),
127
+ )
128
+
129
+ def code_map(self, snapshot: ExtractionSnapshot, options: CacheOptions) -> CachedResult[CodeMap | None]:
130
+ key = self.identity.code_map("", snapshot.manifest)
131
+ cached = self._read(options, key)
132
+ try:
133
+ value = CodeMap.model_validate(cached.value)
134
+ outcome = CacheOutcome(stage=CacheStage.CODE_MAP, namespace=options.namespace, hits=1)
135
+ except (TypeError, ValueError, ValidationError):
136
+ if cached.value is not None and not cached.invalidated:
137
+ self.storage.delete(options, key)
138
+ value = None
139
+ outcome = CacheOutcome(
140
+ stage=CacheStage.CODE_MAP,
141
+ namespace=options.namespace,
142
+ misses=1,
143
+ invalidated=int(cached.invalidated or cached.value is not None),
144
+ )
145
+ return CachedResult[CodeMap | None](value=value, outcomes=(outcome,))
146
+
147
+ def store_code_map(self, snapshot: ExtractionSnapshot, code_map: CodeMap, options: CacheOptions) -> None:
148
+ self._write(options, self.identity.code_map("", snapshot.manifest), code_map.model_dump(mode="json"))
149
+ self.prune(options)
150
+
151
+ def reports(
152
+ self, code_map: CodeMap, config: ArchitectureConfig, options: CacheOptions
153
+ ) -> CachedResult[tuple[ReportNode, ...] | None]:
154
+ key = self.identity.reports(code_map, config)
155
+ cached = self._read(options, key)
156
+ cached_value: object | None = cached.value
157
+ invalidated = cached.invalidated or cached_value is not None
158
+ try:
159
+ if not isinstance(cached_value, list):
160
+ raise ValueError("Cached reports must be a list.")
161
+ reports = tuple(self._report(item) for item in cast(list[object], cached_value))
162
+ value = tuple(sorted(reports, key=lambda item: (item.metadata.order, item.metadata.id)))
163
+ outcome = CacheOutcome(stage=CacheStage.REPORTS, namespace=options.namespace, hits=1)
164
+ except (AttributeError, ImportError, KeyError, TypeError, ValueError, ValidationError):
165
+ if cached_value is not None and not cached.invalidated:
166
+ self.storage.delete(options, key)
167
+ value = None
168
+ outcome = CacheOutcome(
169
+ stage=CacheStage.REPORTS,
170
+ namespace=options.namespace,
171
+ misses=1,
172
+ invalidated=int(invalidated),
173
+ )
174
+ return CachedResult[tuple[ReportNode, ...] | None](value=value, outcomes=(outcome,))
175
+
176
+ def store_reports(
177
+ self,
178
+ code_map: CodeMap,
179
+ config: ArchitectureConfig,
180
+ reports: tuple[ReportNode, ...],
181
+ options: CacheOptions,
182
+ ) -> None:
183
+ value = [
184
+ {
185
+ "model": f"{type(report).__module__}.{type(report).__qualname__}",
186
+ "payload": report.model_dump(mode="json", exclude_computed_fields=True),
187
+ }
188
+ for report in reports
189
+ ]
190
+ self._write(options, self.identity.reports(code_map, config), value)
191
+ self.prune(options)
192
+
193
+ def clear(self, options: CacheOptions) -> None:
194
+ self.storage.clear(options)
195
+
196
+ def prune(self, options: CacheOptions) -> None:
197
+ entries = self.storage.entries(options)
198
+ total = sum(entry.size for entry in entries)
199
+ for entry in sorted(entries, key=lambda item: (item.last_access_ns, item.key.kind, item.key.digest)):
200
+ if total <= options.max_bytes:
201
+ break
202
+ self.storage.delete(options, entry.key)
203
+ total -= entry.size
204
+
205
+ def _read(self, options: CacheOptions, key: CacheKey) -> _CacheRead:
206
+ payload = self.storage.read(options, key)
207
+ if payload is None:
208
+ return _CacheRead(value=None, invalidated=False)
209
+ value = self.codec.decode(key, payload)
210
+ if value is None:
211
+ self.storage.delete(options, key)
212
+ return _CacheRead(value=None, invalidated=True)
213
+ return _CacheRead(value=value, invalidated=False)
214
+
215
+ def _write(self, options: CacheOptions, key: CacheKey, value: object) -> None:
216
+ self.storage.write(options, key, self.codec.encode(key, value))
217
+
218
+ def _report(self, value: object) -> ReportNode:
219
+ if not isinstance(value, dict):
220
+ raise ValueError("Cached report entry must be an object.")
221
+ entry = cast(dict[str, object], value)
222
+ model_name = entry["model"]
223
+ payload = entry["payload"]
224
+ if not isinstance(model_name, str) or not model_name.startswith("modwire.architecture."):
225
+ raise ValueError("Cached report model is outside the architecture package.")
226
+ module_name, _, class_name = model_name.rpartition(".")
227
+ model: Any = getattr(importlib.import_module(module_name), class_name)
228
+ if not isinstance(model, type) or not issubclass(model, BaseModel) or not issubclass(model, ReportNode):
229
+ raise ValueError("Cached report model is not a report node.")
230
+ return model.model_validate(payload)
@@ -0,0 +1,27 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from .models.cache_entry import CacheEntry
4
+ from .models.cache_key import CacheKey
5
+ from .models.cache_options import CacheOptions
6
+
7
+
8
+ class CacheStorage(ABC):
9
+ @abstractmethod
10
+ def read(self, options: CacheOptions, key: CacheKey) -> bytes | None:
11
+ raise NotImplementedError
12
+
13
+ @abstractmethod
14
+ def write(self, options: CacheOptions, key: CacheKey, payload: bytes) -> None:
15
+ raise NotImplementedError
16
+
17
+ @abstractmethod
18
+ def entries(self, options: CacheOptions) -> tuple[CacheEntry, ...]:
19
+ raise NotImplementedError
20
+
21
+ @abstractmethod
22
+ def delete(self, options: CacheOptions, key: CacheKey) -> None:
23
+ raise NotImplementedError
24
+
25
+ @abstractmethod
26
+ def clear(self, options: CacheOptions) -> None:
27
+ raise NotImplementedError
@@ -0,0 +1,8 @@
1
+ from ....shared.values.models.value_model import ValueModel
2
+ from .cache_key import CacheKey
3
+
4
+
5
+ class CacheEntry(ValueModel):
6
+ key: CacheKey
7
+ size: int
8
+ last_access_ns: int
@@ -0,0 +1,11 @@
1
+ from typing import Literal
2
+
3
+ from ....shared.values.models.value_model import ValueModel
4
+
5
+ type CacheKind = Literal["source", "manifest", "code-map", "reports"]
6
+
7
+
8
+ class CacheKey(ValueModel):
9
+ schema_version: Literal[1] = 1
10
+ kind: CacheKind
11
+ digest: str
@@ -0,0 +1,25 @@
1
+ from pydantic import field_validator
2
+
3
+ from ....shared.values.models.value_model import ValueModel
4
+
5
+
6
+ class CacheOptions(ValueModel):
7
+ """Generic persistent-cache settings supplied by a caller."""
8
+
9
+ directory: str
10
+ namespace: str
11
+ max_bytes: int
12
+
13
+ @field_validator("directory", "namespace")
14
+ @classmethod
15
+ def _non_empty(cls, value: str) -> str:
16
+ if not value.strip():
17
+ raise ValueError("Cache directory and namespace must not be empty.")
18
+ return value
19
+
20
+ @field_validator("max_bytes")
21
+ @classmethod
22
+ def _positive_size(cls, value: int) -> int:
23
+ if value < 1:
24
+ raise ValueError("Cache max_bytes must be at least one.")
25
+ return value
@@ -0,0 +1,44 @@
1
+ from enum import StrEnum
2
+
3
+ from pydantic import field_validator
4
+
5
+ from ....shared.values.models.value_model import ValueModel
6
+
7
+
8
+ class CacheStage(StrEnum):
9
+ """Public stages reported by cached Modwire operations."""
10
+
11
+ EXTRACTION = "extraction"
12
+ CODE_MAP = "code-map"
13
+ REPORTS = "reports"
14
+
15
+
16
+ class CacheOutcome(ValueModel):
17
+ """Content-safe lifecycle counts for one stage of a cached operation.
18
+
19
+ Extraction counts describe current source records. Code-map and report counts
20
+ describe one entry. Invalidated entries are also misses. Diagnostics include
21
+ the configured namespace but never cache keys, source identities, or content.
22
+ """
23
+
24
+ stage: CacheStage
25
+ namespace: str
26
+ hits: int = 0
27
+ misses: int = 0
28
+ invalidated: int = 0
29
+ computed: int = 0
30
+ stored: int = 0
31
+
32
+ @field_validator("namespace")
33
+ @classmethod
34
+ def _non_empty_namespace(cls, value: str) -> str:
35
+ if not value.strip():
36
+ raise ValueError("Cache outcome namespace must not be empty.")
37
+ return value
38
+
39
+ @field_validator("hits", "misses", "invalidated", "computed", "stored")
40
+ @classmethod
41
+ def _non_negative_count(cls, value: int) -> int:
42
+ if value < 0:
43
+ raise ValueError("Cache outcome counts must not be negative.")
44
+ return value