modwire 9.2.1__tar.gz → 9.2.3__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 (374) hide show
  1. {modwire-9.2.1 → modwire-9.2.3}/.dev/modwire.egg-info/SOURCES.txt +10 -3
  2. {modwire-9.2.1 → modwire-9.2.3}/Makefile +4 -1
  3. {modwire-9.2.1 → modwire-9.2.3}/PKG-INFO +6 -4
  4. {modwire-9.2.1 → modwire-9.2.3}/README.md +5 -3
  5. {modwire-9.2.1 → modwire-9.2.3}/docs/target-language-ownership.md +7 -6
  6. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/application.py +20 -6
  7. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/config/models/shape_rules.py +1 -0
  8. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/services/file_resolver.py +22 -7
  9. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/cache/application.py +70 -75
  10. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/cache/domain.py +14 -3
  11. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/cache/models/cache_outcome.py +6 -13
  12. modwire-9.2.3/src/modwire/cli/cache/models/cache_plan.py +22 -0
  13. modwire-9.2.3/src/modwire/cli/cache/models/cache_stage.py +9 -0
  14. modwire-9.2.3/src/modwire/cli/cache/models/cache_storage_state.py +11 -0
  15. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/cache/models/cached_result.py +2 -1
  16. modwire-9.2.3/src/modwire/cli/cache/models/source_cache_entry.py +8 -0
  17. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/cache/services/cache_identity.py +11 -8
  18. modwire-9.2.3/src/modwire/cli/cache/services/filesystem_cache_storage.py +284 -0
  19. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/facade.py +25 -13
  20. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/domain.py +1 -1
  21. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/batch_source_reader.py +2 -2
  22. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/resources/templates/ARCHITECTURE.md +4 -0
  23. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/resources/templates/architecture.yaml +1 -0
  24. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/php/script.php +0 -0
  25. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/php/script.src.php +7 -2
  26. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/typescript/script.js +16 -20
  27. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/typescript/script.ts +18 -22
  28. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/services/python_syntax_parser.py +38 -3
  29. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/code_map.py +1 -1
  30. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_value.py +2 -0
  31. modwire-9.2.3/src/modwire/shared/code/models/source_value_scope.py +7 -0
  32. {modwire-9.2.1 → modwire-9.2.3}/tests/application/test_07_cache.py +48 -0
  33. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/base_test.py +1 -1
  34. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/insights/base_test.py +2 -2
  35. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/insights/test_02_invariants.py +19 -10
  36. modwire-9.2.3/tests/architecture/report_benchmark/__init__.py +1 -0
  37. modwire-9.2.3/tests/architecture/report_benchmark/benchmark_process_timeout.py +6 -0
  38. modwire-9.2.3/tests/architecture/report_benchmark/run.py +424 -0
  39. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/shape/base_test.py +3 -1
  40. modwire-9.2.3/tests/architecture/shape/test_01_limits.py +241 -0
  41. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/shape/test_02_invariants.py +38 -0
  42. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/initialization/test_02_invariants.py +1 -0
  43. modwire-9.2.3/tests/extraction/cache_benchmark/run.py +318 -0
  44. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/extractors/test_03_native_symbols.py +21 -0
  45. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/syntax/php/example_shapes.php +3 -0
  46. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/syntax/python/example_shapes.py +3 -0
  47. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/syntax/typescript/example_shapes.ts +3 -0
  48. {modwire-9.2.1 → modwire-9.2.3}/tests/shared/code/test_02_invariants.py +13 -10
  49. {modwire-9.2.1 → modwire-9.2.3}/tests/support/code_map.py +30 -24
  50. modwire-9.2.1/src/modwire/cli/cache/models/extraction_snapshot.py +0 -8
  51. modwire-9.2.1/src/modwire/cli/cache/services/filesystem_cache_storage.py +0 -147
  52. modwire-9.2.1/tests/architecture/shape/test_01_limits.py +0 -126
  53. modwire-9.2.1/tests/extraction/cache_benchmark/run.py +0 -155
  54. {modwire-9.2.1 → modwire-9.2.3}/.github/workflows/ci.yml +0 -0
  55. {modwire-9.2.1 → modwire-9.2.3}/.github/workflows/release.yml +0 -0
  56. {modwire-9.2.1 → modwire-9.2.3}/.gitignore +0 -0
  57. {modwire-9.2.1 → modwire-9.2.3}/AGENTS.md +0 -0
  58. {modwire-9.2.1 → modwire-9.2.3}/LICENSE +0 -0
  59. {modwire-9.2.1 → modwire-9.2.3}/MANIFEST.in +0 -0
  60. {modwire-9.2.1 → modwire-9.2.3}/pyproject.toml +0 -0
  61. {modwire-9.2.1 → modwire-9.2.3}/scripts/check_extractors.py +0 -0
  62. {modwire-9.2.1 → modwire-9.2.3}/scripts/generate_docs.py +0 -0
  63. {modwire-9.2.1 → modwire-9.2.3}/scripts/verify_consumer.py +0 -0
  64. {modwire-9.2.1 → modwire-9.2.3}/setup.cfg +0 -0
  65. {modwire-9.2.1 → modwire-9.2.3}/setup.py +0 -0
  66. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/__init__.py +0 -0
  67. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/__main__.py +0 -0
  68. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/__init__.py +0 -0
  69. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/__init__.py +0 -0
  70. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/application.py +0 -0
  71. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/domain.py +0 -0
  72. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/models/__init__.py +0 -0
  73. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/models/edge_rule_violation.py +0 -0
  74. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/models/flow_report.py +0 -0
  75. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/models/flow_violation.py +0 -0
  76. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/models/types.py +0 -0
  77. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/services/__init__.py +0 -0
  78. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/services/backward_flow_analyzer.py +0 -0
  79. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/services/boundaries_flow_analyzer.py +0 -0
  80. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/services/module_boundary_analyzer.py +0 -0
  81. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/services/no_cycles_flow_analyzer.py +0 -0
  82. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/boundaries/services/no_reentry_flow_analyzer.py +0 -0
  83. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/config/__init__.py +0 -0
  84. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/config/application.py +0 -0
  85. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/config/models/__init__.py +0 -0
  86. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/config/models/architecture_config.py +0 -0
  87. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/config/models/boundaries_config.py +0 -0
  88. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/config/models/boundary_rule.py +0 -0
  89. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/config/models/configuration_value.py +0 -0
  90. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/config/models/flow_realm.py +0 -0
  91. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/config/models/flow_rules.py +0 -0
  92. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/config/models/shape_config.py +0 -0
  93. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/config/models/shape_realm.py +0 -0
  94. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/config/models/tag_rule.py +0 -0
  95. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/facade.py +0 -0
  96. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/__init__.py +0 -0
  97. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/application.py +0 -0
  98. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/domain.py +0 -0
  99. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/models/__init__.py +0 -0
  100. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/models/callable_report_entry.py +0 -0
  101. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/models/callables_report.py +0 -0
  102. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/models/clusters_report.py +0 -0
  103. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/models/clusters_report_item.py +0 -0
  104. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/models/coherence_report.py +0 -0
  105. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/models/exports_report.py +0 -0
  106. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/models/exports_report_item.py +0 -0
  107. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/models/hotspots_report.py +0 -0
  108. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/models/hotspots_report_item.py +0 -0
  109. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/models/insight_report.py +0 -0
  110. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/services/__init__.py +0 -0
  111. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/services/callables_reporter.py +0 -0
  112. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/services/clusters_reporter.py +0 -0
  113. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/services/coherence_reporter.py +0 -0
  114. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/services/exports_reporter.py +0 -0
  115. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/services/hotspots_reporter.py +0 -0
  116. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/insights/services/insight_report_field_map.py +0 -0
  117. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/map/__init__.py +0 -0
  118. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/map/application.py +0 -0
  119. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/map/domain.py +0 -0
  120. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/map/models/__init__.py +0 -0
  121. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/map/models/architecture_map.py +0 -0
  122. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/map/models/architecture_realm.py +0 -0
  123. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/map/models/tag_map.py +0 -0
  124. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/map/models/tag_match.py +0 -0
  125. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/map/services/__init__.py +0 -0
  126. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/map/services/architecture_map_loader.py +0 -0
  127. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/map/services/tag_matcher.py +0 -0
  128. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/__init__.py +0 -0
  129. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/application.py +0 -0
  130. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/domain.py +0 -0
  131. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/models/__init__.py +0 -0
  132. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/models/architecture_group.py +0 -0
  133. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/models/map_report.py +0 -0
  134. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/models/report_catalog.py +0 -0
  135. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/models/report_descriptor.py +0 -0
  136. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/models/report_item.py +0 -0
  137. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/models/report_metadata.py +0 -0
  138. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/models/report_node.py +0 -0
  139. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/models/report_section.py +0 -0
  140. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/services/__init__.py +0 -0
  141. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/report/services/map_report_collector.py +0 -0
  142. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/__init__.py +0 -0
  143. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/application.py +0 -0
  144. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/domain.py +0 -0
  145. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/models/__init__.py +0 -0
  146. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/models/shape_realm_architecture_map.py +0 -0
  147. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/models/shape_report.py +0 -0
  148. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/models/shape_violation.py +0 -0
  149. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/services/__init__.py +0 -0
  150. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/services/abstract_class_resolver.py +0 -0
  151. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/services/callable_resolver.py +0 -0
  152. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/services/class_resolver.py +0 -0
  153. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/services/import_resolver.py +0 -0
  154. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/services/property_resolver.py +0 -0
  155. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/services/signature_resolver.py +0 -0
  156. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/architecture/shape/services/symbol_resolver.py +0 -0
  157. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/autowiring.py +0 -0
  158. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/__init__.py +0 -0
  159. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/cache/__init__.py +0 -0
  160. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/cache/models/__init__.py +0 -0
  161. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/cache/models/cache_entry.py +0 -0
  162. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/cache/models/cache_key.py +0 -0
  163. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/cache/models/cache_options.py +0 -0
  164. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/cache/services/__init__.py +0 -0
  165. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/cache/services/cache_codec.py +0 -0
  166. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/documentation/__init__.py +0 -0
  167. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/documentation/application.py +0 -0
  168. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/documentation/services/__init__.py +0 -0
  169. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/documentation/services/documentation_generator.py +0 -0
  170. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/initialization/__init__.py +0 -0
  171. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/initialization/application.py +0 -0
  172. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/initialization/models/__init__.py +0 -0
  173. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/initialization/models/initialization_result.py +0 -0
  174. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/initialization/services/__init__.py +0 -0
  175. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/initialization/services/initialization_service.py +0 -0
  176. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/__init__.py +0 -0
  177. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/application.py +0 -0
  178. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/models/__init__.py +0 -0
  179. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/models/command_request.py +0 -0
  180. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/models/extractor_batch_input.py +0 -0
  181. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/models/extractor_command_input.py +0 -0
  182. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/models/extractor_source_input.py +0 -0
  183. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/models/report_pipeline_context.py +0 -0
  184. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/models/scan_policy.py +0 -0
  185. {modwire-9.2.1/src/modwire/cli/cache → modwire-9.2.3/src/modwire/cli/pipeline}/models/source_entry.py +0 -0
  186. {modwire-9.2.1/src/modwire/cli/cache → modwire-9.2.3/src/modwire/cli/pipeline}/models/source_inventory.py +0 -0
  187. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/__init__.py +0 -0
  188. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/callables_insight.py +0 -0
  189. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/clusters_insight.py +0 -0
  190. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/coherence_insight.py +0 -0
  191. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/command_line.py +0 -0
  192. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/configuration_loader.py +0 -0
  193. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/extractor_command.py +0 -0
  194. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/flow_violations.py +0 -0
  195. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/hotspots_insight.py +0 -0
  196. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/map_tree.py +0 -0
  197. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/output_console.py +0 -0
  198. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/shape_violations.py +0 -0
  199. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/success.py +0 -0
  200. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/unknown_files_warning.py +0 -0
  201. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/pipeline/services/unused_exports_insight.py +0 -0
  202. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/resources/__init__.py +0 -0
  203. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/resources/application.py +0 -0
  204. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/resources/models/__init__.py +0 -0
  205. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/resources/models/defaults.py +0 -0
  206. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/resources/models/init_asset.py +0 -0
  207. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/resources/templates/AGENTS.md +0 -0
  208. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/resources/templates/INDEX.md +0 -0
  209. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/resources/templates/MODWIRE.md +0 -0
  210. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/resources/templates/RULES.md +0 -0
  211. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/resources/templates/TESTING.md +0 -0
  212. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/cli/resources/templates/WORKFLOW.md +0 -0
  213. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/__init__.py +0 -0
  214. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/dependency/__init__.py +0 -0
  215. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/dependency/application.py +0 -0
  216. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/dependency/domain.py +0 -0
  217. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/dependency/services/__init__.py +0 -0
  218. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/dependency/services/graph_builder.py +0 -0
  219. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/dependency/services/import_resolver.py +0 -0
  220. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/dependency/services/suffix_index.py +0 -0
  221. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/__init__.py +0 -0
  222. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/application.py +0 -0
  223. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/domain.py +0 -0
  224. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/models/__init__.py +0 -0
  225. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/models/batch_config.py +0 -0
  226. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/models/extraction_request.py +0 -0
  227. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/models/extractor_resource.py +0 -0
  228. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/models/extractor_runtime.py +0 -0
  229. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/models/python_call_context.py +0 -0
  230. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/__init__.py +0 -0
  231. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/php/build.php +0 -0
  232. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/php/build.py +0 -0
  233. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/php/composer.json +0 -0
  234. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/php/composer.lock +0 -0
  235. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/python/__init__.py +0 -0
  236. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/python/script.py +0 -0
  237. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/typescript/build.mjs +0 -0
  238. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/typescript/build.py +0 -0
  239. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/typescript/package-lock.json +0 -0
  240. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/typescript/package.json +0 -0
  241. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/resources/typescript/tsconfig.json +0 -0
  242. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/services/__init__.py +0 -0
  243. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/services/php_extractor.py +0 -0
  244. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/services/python_call_reader.py +0 -0
  245. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/services/python_extractor.py +0 -0
  246. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/extractors/services/type_script_extractor.py +0 -0
  247. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/extraction/facade.py +0 -0
  248. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/py.typed +0 -0
  249. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/__init__.py +0 -0
  250. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/__init__.py +0 -0
  251. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/application.py +0 -0
  252. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/domain.py +0 -0
  253. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/__init__.py +0 -0
  254. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/code_package.py +0 -0
  255. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/dependency_edge_result.py +0 -0
  256. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/dependency_graph.py +0 -0
  257. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/dependency_node_result.py +0 -0
  258. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/duplicate_identity_error.py +0 -0
  259. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/edge.py +0 -0
  260. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/edge_resolution.py +0 -0
  261. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/identity.py +0 -0
  262. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/node.py +0 -0
  263. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/query_builder.py +0 -0
  264. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/query_types.py +0 -0
  265. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/queryable_code_map.py +0 -0
  266. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_abstract_class.py +0 -0
  267. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_call.py +0 -0
  268. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_callable.py +0 -0
  269. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_callable_symbol.py +0 -0
  270. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_class.py +0 -0
  271. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_class_method.py +0 -0
  272. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_class_property.py +0 -0
  273. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_export.py +0 -0
  274. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_extraction.py +0 -0
  275. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_file.py +0 -0
  276. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_file_result.py +0 -0
  277. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_function.py +0 -0
  278. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_import.py +0 -0
  279. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_imported_symbol.py +0 -0
  280. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_interface.py +0 -0
  281. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_item_result.py +0 -0
  282. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_parameter.py +0 -0
  283. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_signature.py +0 -0
  284. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_symbol.py +0 -0
  285. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/source_type.py +0 -0
  286. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/models/types.py +0 -0
  287. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/services/__init__.py +0 -0
  288. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/services/glob_path_matcher.py +0 -0
  289. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/code/services/identity_resolver.py +0 -0
  290. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/values/__init__.py +0 -0
  291. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/values/models/__init__.py +0 -0
  292. {modwire-9.2.1 → modwire-9.2.3}/src/modwire/shared/values/models/value_model.py +0 -0
  293. {modwire-9.2.1 → modwire-9.2.3}/tests/__init__.py +0 -0
  294. {modwire-9.2.1 → modwire-9.2.3}/tests/application/__init__.py +0 -0
  295. {modwire-9.2.1 → modwire-9.2.3}/tests/application/base_test.py +0 -0
  296. {modwire-9.2.1 → modwire-9.2.3}/tests/application/test_01_attacks.py +0 -0
  297. {modwire-9.2.1 → modwire-9.2.3}/tests/application/test_06_happy_path.py +0 -0
  298. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/__init__.py +0 -0
  299. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/boundaries/__init__.py +0 -0
  300. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/boundaries/base_test.py +0 -0
  301. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/boundaries/test_01_attacks.py +0 -0
  302. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/boundaries/test_02_invariants.py +0 -0
  303. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/boundaries/test_03_public_api.py +0 -0
  304. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/boundaries/test_04_paths.py +0 -0
  305. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/config/__init__.py +0 -0
  306. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/config/test_01_attacks.py +0 -0
  307. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/config/test_02_invariants.py +0 -0
  308. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/insights/__init__.py +0 -0
  309. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/map/__init__.py +0 -0
  310. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/map/test_02_patterns.py +0 -0
  311. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/report/__init__.py +0 -0
  312. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/report/test_02_invariants.py +0 -0
  313. {modwire-9.2.1 → modwire-9.2.3}/tests/architecture/shape/__init__.py +0 -0
  314. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/__init__.py +0 -0
  315. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/base_test.py +0 -0
  316. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/documentation/__init__.py +0 -0
  317. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/documentation/test_02_invariants.py +0 -0
  318. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/initialization/__init__.py +0 -0
  319. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/initialization/test_01_attacks.py +0 -0
  320. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/initialization/test_03_interruption.py +0 -0
  321. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/initialization/test_04_cleanup.py +0 -0
  322. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/initialization/test_05_recovery.py +0 -0
  323. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/pipeline/__init__.py +0 -0
  324. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/pipeline/base_test.py +0 -0
  325. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/pipeline/test_01_attacks.py +0 -0
  326. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/pipeline/test_02_invariants.py +0 -0
  327. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/pipeline/test_03_interruption.py +0 -0
  328. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/pipeline/test_04_command_transport.py +0 -0
  329. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/pipeline/test_05_recovery.py +0 -0
  330. {modwire-9.2.1 → modwire-9.2.3}/tests/cli/pipeline/test_06_happy_path.py +0 -0
  331. {modwire-9.2.1 → modwire-9.2.3}/tests/conftest.py +0 -0
  332. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/__init__.py +0 -0
  333. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/base_test.py +0 -0
  334. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/big_projects/__init__.py +0 -0
  335. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/big_projects/project.py +0 -0
  336. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/big_projects/projects.json +0 -0
  337. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/big_projects/resolution_results.json +0 -0
  338. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/big_projects/results.json +0 -0
  339. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/big_projects/run.py +0 -0
  340. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/cache_benchmark/__init__.py +0 -0
  341. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/dependency/__init__.py +0 -0
  342. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/dependency/test_02_invariants.py +0 -0
  343. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/extractors/__init__.py +0 -0
  344. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/extractors/test_01_attacks.py +0 -0
  345. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/extractors/test_02_invariants.py +0 -0
  346. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/scan_benchmark/__init__.py +0 -0
  347. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/scan_benchmark/prepare.py +0 -0
  348. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/scan_benchmark/results.json +0 -0
  349. {modwire-9.2.1 → modwire-9.2.3}/tests/extraction/scan_benchmark/run.py +0 -0
  350. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/php/ignored/example_generated.php +0 -0
  351. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/php/src/example_application/example_actions/example_action.php +0 -0
  352. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/php/src/example_domain/example_model/example_record.php +0 -0
  353. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/php/src/example_domain/example_services/example_policy.php +0 -0
  354. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/php/src/example_interfaces/example_http/example_controller.php +0 -0
  355. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/python/ignored/example_generated.py +0 -0
  356. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/python/src/example_application/example_actions/example_action.py +0 -0
  357. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/python/src/example_domain/example_model/example_record.py +0 -0
  358. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/python/src/example_domain/example_services/example_policy.py +0 -0
  359. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/python/src/example_interfaces/example_http/example_controller.py +0 -0
  360. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/typescript/ignored/example_generated.ts +0 -0
  361. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/typescript/src/example_application/example_actions/example_action.ts +0 -0
  362. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/typescript/src/example_domain/example_model/example_record.ts +0 -0
  363. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/typescript/src/example_domain/example_model/example_view.tsx +0 -0
  364. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_audit.js +0 -0
  365. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_callables.ts +0 -0
  366. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_policy.ts +0 -0
  367. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/typescript/src/example_interfaces/example_http/example_controller.ts +0 -0
  368. {modwire-9.2.1 → modwire-9.2.3}/tests/fixtures/languages/typescript/src/example_interfaces/example_http/example_view.jsx +0 -0
  369. {modwire-9.2.1 → modwire-9.2.3}/tests/shared/__init__.py +0 -0
  370. {modwire-9.2.1 → modwire-9.2.3}/tests/shared/code/__init__.py +0 -0
  371. {modwire-9.2.1 → modwire-9.2.3}/tests/support/__init__.py +0 -0
  372. {modwire-9.2.1 → modwire-9.2.3}/tests/support/base_test.py +0 -0
  373. {modwire-9.2.1 → modwire-9.2.3}/tests/support/service_test.py +0 -0
  374. {modwire-9.2.1 → modwire-9.2.3}/uv.lock +0 -0
@@ -120,10 +120,11 @@ src/modwire/cli/cache/models/cache_entry.py
120
120
  src/modwire/cli/cache/models/cache_key.py
121
121
  src/modwire/cli/cache/models/cache_options.py
122
122
  src/modwire/cli/cache/models/cache_outcome.py
123
+ src/modwire/cli/cache/models/cache_plan.py
124
+ src/modwire/cli/cache/models/cache_stage.py
125
+ src/modwire/cli/cache/models/cache_storage_state.py
123
126
  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/models/source_cache_entry.py
127
128
  src/modwire/cli/cache/services/__init__.py
128
129
  src/modwire/cli/cache/services/cache_codec.py
129
130
  src/modwire/cli/cache/services/cache_identity.py
@@ -148,6 +149,8 @@ src/modwire/cli/pipeline/models/extractor_command_input.py
148
149
  src/modwire/cli/pipeline/models/extractor_source_input.py
149
150
  src/modwire/cli/pipeline/models/report_pipeline_context.py
150
151
  src/modwire/cli/pipeline/models/scan_policy.py
152
+ src/modwire/cli/pipeline/models/source_entry.py
153
+ src/modwire/cli/pipeline/models/source_inventory.py
151
154
  src/modwire/cli/pipeline/services/__init__.py
152
155
  src/modwire/cli/pipeline/services/batch_source_reader.py
153
156
  src/modwire/cli/pipeline/services/callables_insight.py
@@ -256,6 +259,7 @@ src/modwire/shared/code/models/source_signature.py
256
259
  src/modwire/shared/code/models/source_symbol.py
257
260
  src/modwire/shared/code/models/source_type.py
258
261
  src/modwire/shared/code/models/source_value.py
262
+ src/modwire/shared/code/models/source_value_scope.py
259
263
  src/modwire/shared/code/models/types.py
260
264
  src/modwire/shared/code/services/__init__.py
261
265
  src/modwire/shared/code/services/glob_path_matcher.py
@@ -288,6 +292,9 @@ tests/architecture/map/__init__.py
288
292
  tests/architecture/map/test_02_patterns.py
289
293
  tests/architecture/report/__init__.py
290
294
  tests/architecture/report/test_02_invariants.py
295
+ tests/architecture/report_benchmark/__init__.py
296
+ tests/architecture/report_benchmark/benchmark_process_timeout.py
297
+ tests/architecture/report_benchmark/run.py
291
298
  tests/architecture/shape/__init__.py
292
299
  tests/architecture/shape/base_test.py
293
300
  tests/architecture/shape/test_01_limits.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 cache-benchmark 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 report-benchmark scan-benchmark scan-benchmark-fixture test type-check
11
11
 
12
12
  format:
13
13
  uv run ruff format src tests scripts
@@ -37,6 +37,9 @@ scan-benchmark:
37
37
  cache-benchmark:
38
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
39
 
40
+ report-benchmark:
41
+ uv run python -m tests.architecture.report_benchmark.run --root "$(REPORT_BENCHMARK_ROOT)" --language "$(REPORT_BENCHMARK_LANGUAGE)" --cache-directory "$(REPORT_BENCHMARK_CACHE)" --cache-namespace "$(REPORT_BENCHMARK_NAMESPACE)"
42
+
40
43
  docs-check:
41
44
  uv run python scripts/generate_docs.py --check
42
45
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modwire
3
- Version: 9.2.1
3
+ Version: 9.2.3
4
4
  Summary: Code extraction, architecture analysis and the Modwire CLI.
5
5
  Author: Tomasz Szpak
6
6
  License-Expression: MIT
@@ -120,9 +120,11 @@ Public stages reported by cached Modwire operations.
120
120
 
121
121
  Content-safe lifecycle counts for one stage of a cached operation.
122
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.
123
+ Extraction counts describe current source records. An exact code-map hit
124
+ reports its digest-backed manifest sources as extraction hits without loading
125
+ individual source payloads. Code-map and report counts describe one entry.
126
+ Invalidated entries are also misses. Diagnostics include the configured
127
+ namespace but never cache keys, source identities, or content.
126
128
 
127
129
  ## `CachedResult`
128
130
 
@@ -92,9 +92,11 @@ Public stages reported by cached Modwire operations.
92
92
 
93
93
  Content-safe lifecycle counts for one stage of a cached operation.
94
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.
95
+ Extraction counts describe current source records. An exact code-map hit
96
+ reports its digest-backed manifest sources as extraction hits without loading
97
+ individual source payloads. Code-map and report counts describe one entry.
98
+ Invalidated entries are also misses. Diagnostics include the configured
99
+ namespace but never cache keys, source identities, or content.
98
100
 
99
101
  ## `CachedResult`
100
102
 
@@ -16,16 +16,17 @@ Shared code, dependency resolution, architecture analysis, traversal, consumer v
16
16
  orchestration must not contain supported-language tables, runtime commands, extension tables, or language-selection
17
17
  branches. Callers select a registered extractor explicitly.
18
18
 
19
- ## Shared contract version 2
19
+ ## Shared contract version 3
20
20
 
21
- The class-level `CodeMap.schema_version` is `2` while the existing serialized envelope remains stable. Callable kinds
22
- are `function`, `instance_method`, `type_method`, `static_method`,
21
+ The class-level `CodeMap.schema_version` is `3`. Every runtime `SourceValue` declares a language-neutral `module`,
22
+ `local`, or `member` scope. Extractors distinguish variable assignments from constants and keep type aliases and export
23
+ metadata out of runtime values. Callable kinds are `function`, `instance_method`, `type_method`, `static_method`,
23
24
  `constructor`, `callable_value`, and `anonymous`. Parameter kinds are `positional`, `variadic_positional`,
24
25
  `named_only`, and `variadic_named`.
25
26
 
26
- Version 1 serialized maps used extractor-specific callable and parameter vocabulary. They are not accepted as version
27
- 2 values. Regenerate them from their source with the same registered extractor; persistent reuse does not yet exist,
28
- so there is no cache migration or silent compatibility alias.
27
+ Version 1 serialized maps used extractor-specific callable and parameter vocabulary, while version 2 values have no
28
+ explicit value scope. Neither is accepted as version 3. Regenerate them from source with the same registered extractor;
29
+ the cache identity includes the code-map schema and invalidates older maps instead of migrating them silently.
29
30
 
30
31
  ## Adding an extractor
31
32
 
@@ -11,7 +11,8 @@ 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
13
  from .cli.cache.models.cache_options import CacheOptions
14
- from .cli.cache.models.cache_outcome import CacheOutcome, CacheStage
14
+ from .cli.cache.models.cache_outcome import CacheOutcome
15
+ from .cli.cache.models.cache_stage import CacheStage
15
16
  from .cli.cache.models.cached_result import CachedResult
16
17
  from .cli.facade import CliFacade
17
18
  from .cli.pipeline.models.scan_policy import ScanPolicy
@@ -82,9 +83,11 @@ class ModwireApplication:
82
83
 
83
84
  cached = self.cli.cached_reports(code_map.code_map, config, options)
84
85
  if cached.value is not None:
86
+ self.cli.maintain_cache(options)
85
87
  return CachedResult(value=cached.value, outcomes=cached.outcomes)
86
88
  reports = self.architecture.analyze(code_map, config)
87
89
  self.cli.store_reports(code_map.code_map, config, reports, options)
90
+ self.cli.maintain_cache(options)
88
91
  outcome = cached.outcome(CacheStage.REPORTS).model_copy(update={"computed": 1, "stored": 1})
89
92
  return CachedResult(value=reports, outcomes=(outcome,))
90
93
 
@@ -124,16 +127,27 @@ class ModwireApplication:
124
127
  """Return a code map and public outcomes for extraction and complete-map reuse."""
125
128
 
126
129
  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)
130
+ plan = self.cli.prepare_cache(request, policy)
131
+ cached = self.cli.cached_code_map(plan, options)
129
132
  outcome = cached.outcome(CacheStage.CODE_MAP)
130
133
  if cached.value is not None:
131
134
  code_map = cached.value
135
+ extraction_outcomes = (
136
+ CacheOutcome(
137
+ stage=CacheStage.EXTRACTION,
138
+ namespace=options.namespace,
139
+ hits=len(plan.sources),
140
+ ),
141
+ )
132
142
  else:
133
- code_map = self.extraction.generate_map(language, snapshot.value.extraction)
134
- self.cli.store_code_map(snapshot.value, code_map, options)
143
+ sources = self.cli.cached_sources(request, plan, options)
144
+ self.cli.maintain_manifest(plan, options)
145
+ code_map = self.extraction.generate_map(language, sources.value)
146
+ self.cli.store_code_map(plan, code_map, options)
135
147
  outcome = outcome.model_copy(update={"computed": 1, "stored": 1})
136
- return CachedResult(value=code_map, outcomes=(*snapshot.outcomes, outcome))
148
+ extraction_outcomes = sources.outcomes
149
+ self.cli.maintain_cache(options)
150
+ return CachedResult(value=code_map, outcomes=(*extraction_outcomes, outcome))
137
151
 
138
152
  def generate_queryable_map_cached(
139
153
  self, language: str, root: str, policy: ScanPolicy, options: CacheOptions
@@ -9,6 +9,7 @@ class ShapeRules(ConfigurationValue):
9
9
  max_types_per_file: int = Field(default=-1, ge=-1)
10
10
  max_abstract_classes_per_file: int = Field(default=-1, ge=-1)
11
11
  max_functions_per_file: int = Field(default=0, ge=-1)
12
+ max_variables_per_file: int = Field(default=0, ge=-1)
12
13
  max_methods_per_class: int = Field(default=-1, ge=-1)
13
14
  max_declared_args: int = Field(default=-1, ge=-1)
14
15
  max_function_lines: int = Field(default=-1, ge=-1)
@@ -2,6 +2,8 @@ from dataclasses import dataclass
2
2
 
3
3
  from wireup import injectable
4
4
 
5
+ from ....shared.code.models.identity import FileId
6
+ from ....shared.code.models.source_value_scope import SourceValueScope
5
7
  from ...config.models.shape_rules import ShapeRules
6
8
  from ..domain import BaseShapeResolver, ShapeResolverInterface
7
9
  from ..models.shape_realm_architecture_map import ShapeRealmArchitectureMap
@@ -23,12 +25,16 @@ class FileResolver(ShapeResolverInterface, BaseShapeResolver):
23
25
  violations: list[ShapeViolation | None] = []
24
26
  code_map = architecture_map.code_map
25
27
  for source_id in self.realm_source_ids(architecture_map):
28
+ source_result = code_map.source_file(FileId(source_id))
29
+ if source_result is None:
30
+ raise RuntimeError(f"Shape realm references missing source: {source_id}")
31
+ source_file = source_result.file
26
32
  violations.extend(
27
33
  [
28
34
  self.limit_violation(
29
35
  source_id=source_id,
30
36
  rule_name="max_classes_per_file",
31
- actual=code_map.classes().where_equal(lambda result: result.source_id, source_id).count(),
37
+ actual=len(source_file.classes),
32
38
  limit=config.max_classes_per_file,
33
39
  symbol_kind="file",
34
40
  symbol_name="",
@@ -36,7 +42,7 @@ class FileResolver(ShapeResolverInterface, BaseShapeResolver):
36
42
  self.limit_violation(
37
43
  source_id=source_id,
38
44
  rule_name="max_interfaces_per_file",
39
- actual=code_map.interfaces().where_equal(lambda result: result.source_id, source_id).count(),
45
+ actual=len(source_file.interfaces),
40
46
  limit=config.max_interfaces_per_file,
41
47
  symbol_kind="file",
42
48
  symbol_name="",
@@ -44,7 +50,7 @@ class FileResolver(ShapeResolverInterface, BaseShapeResolver):
44
50
  self.limit_violation(
45
51
  source_id=source_id,
46
52
  rule_name="max_types_per_file",
47
- actual=code_map.types().where_equal(lambda result: result.source_id, source_id).count(),
53
+ actual=len(source_file.types),
48
54
  limit=config.max_types_per_file,
49
55
  symbol_kind="file",
50
56
  symbol_name="",
@@ -52,9 +58,7 @@ class FileResolver(ShapeResolverInterface, BaseShapeResolver):
52
58
  self.limit_violation(
53
59
  source_id=source_id,
54
60
  rule_name="max_abstract_classes_per_file",
55
- actual=code_map.abstract_classes()
56
- .where_equal(lambda result: result.source_id, source_id)
57
- .count(),
61
+ actual=len(source_file.abstract_classes),
58
62
  limit=config.max_abstract_classes_per_file,
59
63
  symbol_kind="file",
60
64
  symbol_name="",
@@ -62,11 +66,22 @@ class FileResolver(ShapeResolverInterface, BaseShapeResolver):
62
66
  self.limit_violation(
63
67
  source_id=source_id,
64
68
  rule_name="max_functions_per_file",
65
- actual=code_map.functions().where_equal(lambda result: result.source_id, source_id).count(),
69
+ actual=len(source_file.functions),
66
70
  limit=config.max_functions_per_file,
67
71
  symbol_kind="file",
68
72
  symbol_name="",
69
73
  ),
74
+ self.limit_violation(
75
+ source_id=source_id,
76
+ rule_name="max_variables_per_file",
77
+ actual=sum(
78
+ value.scope == SourceValueScope.MODULE and value.declaration_kind == "assignment"
79
+ for value in source_file.values
80
+ ),
81
+ limit=config.max_variables_per_file,
82
+ symbol_kind="file",
83
+ symbol_name="",
84
+ ),
70
85
  ]
71
86
  )
72
87
  return tuple(violation for violation in violations if violation is not None)
@@ -18,19 +18,15 @@ from ..pipeline.models.scan_policy import ScanPolicy
18
18
  from .domain import CacheStorage
19
19
  from .models.cache_key import CacheKey
20
20
  from .models.cache_options import CacheOptions
21
- from .models.cache_outcome import CacheOutcome, CacheStage
21
+ from .models.cache_outcome import CacheOutcome
22
+ from .models.cache_plan import CachePlan
23
+ from .models.cache_stage import CacheStage
22
24
  from .models.cached_result import CachedResult
23
- from .models.extraction_snapshot import ExtractionSnapshot
25
+ from .models.source_cache_entry import SourceCacheEntry
24
26
  from .services.cache_codec import CacheCodec
25
27
  from .services.cache_identity import CacheIdentity
26
28
 
27
29
 
28
- @dataclass(frozen=True)
29
- class _CacheRead:
30
- value: object | None
31
- invalidated: bool
32
-
33
-
34
30
  @injectable
35
31
  @dataclass(frozen=True)
36
32
  class CacheApplication:
@@ -46,41 +42,58 @@ class CacheApplication:
46
42
  self.reader.ensure_available(request.runtime)
47
43
  return self.reader.extract_source(request, policy)
48
44
 
49
- def extract_cached(
50
- self, request: ExtractionRequest, policy: ScanPolicy, options: CacheOptions
51
- ) -> CachedResult[ExtractionSnapshot]:
45
+ def prepare(self, request: ExtractionRequest, policy: ScanPolicy) -> CachePlan:
52
46
  inventory = self.reader.inventory(request, policy)
53
- keys = {entry.source_id: self.identity.source(request, policy, entry) for entry in inventory.entries}
47
+ sources = tuple(
48
+ SourceCacheEntry(entry=entry, key=self.identity.source(request, policy, entry))
49
+ for entry in inventory.entries
50
+ )
51
+ return CachePlan(
52
+ inventory=inventory,
53
+ sources=sources,
54
+ manifest=self.identity.manifest(request, policy, sources),
55
+ )
56
+
57
+ def sources(
58
+ self, request: ExtractionRequest, plan: CachePlan, options: CacheOptions
59
+ ) -> CachedResult[SourceExtraction]:
60
+ payloads = self.storage.read_many(options, tuple(source.key for source in plan.sources))
54
61
  files: dict[FileId, SourceFile] = {}
55
62
  misses: list[FileId] = []
63
+ invalid_keys: list[CacheKey] = []
56
64
  hits = 0
57
65
  invalidated = 0
58
- for entry in inventory.entries:
59
- key = keys[entry.source_id]
60
- cached = self._read(options, key)
66
+ sources_by_id = {source.entry.source_id: source for source in plan.sources}
67
+ for source, payload in zip(plan.sources, payloads, strict=True):
68
+ cached_value = self.codec.decode(source.key, payload) if payload is not None else None
69
+ cached_invalidated = payload is not None and cached_value is None
61
70
  try:
62
- source_file = SourceFile.model_validate(cached.value)
63
- if source_file.file_id != entry.source_id:
71
+ source_file = SourceFile.model_validate(cached_value)
72
+ if source_file.file_id != source.entry.source_id:
64
73
  raise ValueError("Cached source identity does not match its key.")
65
- files[entry.source_id] = source_file
74
+ files[source.entry.source_id] = source_file
66
75
  hits += 1
67
76
  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)
77
+ if payload is not None:
78
+ invalid_keys.append(source.key)
79
+ invalidated += int(cached_invalidated or cached_value is not None)
80
+ misses.append(source.entry.source_id)
81
+ self.storage.delete_many(options, tuple(invalid_keys))
72
82
 
73
- if misses or not inventory.entries:
83
+ if misses or not plan.inventory.entries:
74
84
  self.reader.ensure_available(request.runtime)
75
- extracted = self.reader.extract_entries(request, inventory, tuple(misses))
85
+ extracted = self.reader.extract_entries(request, plan.inventory, tuple(misses))
86
+ writes: list[tuple[CacheKey, bytes]] = []
76
87
  for source_id in misses:
77
88
  source_file = extracted.get(source_id)
78
89
  if source_file is None:
79
90
  raise RuntimeError(f"Extractor omitted a requested source file: {source_id}")
80
91
  files[source_id] = source_file
81
- self._write(options, keys[source_id], source_file.model_dump(mode="json"))
92
+ source = sources_by_id[source_id]
93
+ writes.append((source.key, self.codec.encode(source.key, source_file.model_dump(mode="json"))))
94
+ self.storage.write_many(options, tuple(writes))
82
95
 
83
- ordered_files = {entry.source_id: files[entry.source_id] for entry in inventory.entries}
96
+ ordered_files = {source.entry.source_id: files[source.entry.source_id] for source in plan.sources}
84
97
  modules: dict[ModuleId, FileId] = {}
85
98
  for file_id, source_file in ordered_files.items():
86
99
  existing = modules.get(source_file.module_id)
@@ -91,28 +104,12 @@ class CacheApplication:
91
104
  extraction = SourceExtraction(
92
105
  files=ordered_files,
93
106
  modules=modules,
94
- files_found=inventory.files_found,
95
- files_excluded=inventory.files_excluded,
96
- directories_pruned=inventory.directories_pruned,
107
+ files_found=plan.inventory.files_found,
108
+ files_excluded=plan.inventory.files_excluded,
109
+ directories_pruned=plan.inventory.directories_pruned,
97
110
  )
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
111
  return CachedResult(
115
- value=ExtractionSnapshot(extraction=extraction, manifest=manifest),
112
+ value=extraction,
116
113
  outcomes=(
117
114
  CacheOutcome(
118
115
  stage=CacheStage.EXTRACTION,
@@ -126,35 +123,40 @@ class CacheApplication:
126
123
  ),
127
124
  )
128
125
 
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)
126
+ def maintain_manifest(self, plan: CachePlan, options: CacheOptions) -> bool:
127
+ expected = plan.manifest_value()
128
+ payload = self.storage.read(options, plan.manifest)
129
+ if payload is not None and self.codec.decode(plan.manifest, payload) == expected:
130
+ return False
131
+ return self._write(options, plan.manifest, expected)
132
+
133
+ def code_map(self, plan: CachePlan, options: CacheOptions) -> CachedResult[CodeMap | None]:
134
+ key = self.identity.code_map("", plan.manifest)
135
+ cached_value, cached_invalidated = self._read(options, key)
132
136
  try:
133
- value = CodeMap.model_validate(cached.value)
137
+ value = CodeMap.model_validate(cached_value)
134
138
  outcome = CacheOutcome(stage=CacheStage.CODE_MAP, namespace=options.namespace, hits=1)
135
139
  except (TypeError, ValueError, ValidationError):
136
- if cached.value is not None and not cached.invalidated:
140
+ if cached_value is not None and not cached_invalidated:
137
141
  self.storage.delete(options, key)
138
142
  value = None
139
143
  outcome = CacheOutcome(
140
144
  stage=CacheStage.CODE_MAP,
141
145
  namespace=options.namespace,
142
146
  misses=1,
143
- invalidated=int(cached.invalidated or cached.value is not None),
147
+ invalidated=int(cached_invalidated or cached_value is not None),
144
148
  )
145
149
  return CachedResult[CodeMap | None](value=value, outcomes=(outcome,))
146
150
 
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)
151
+ def store_code_map(self, plan: CachePlan, code_map: CodeMap, options: CacheOptions) -> None:
152
+ self._write(options, self.identity.code_map("", plan.manifest), code_map.model_dump(mode="json"))
150
153
 
151
154
  def reports(
152
155
  self, code_map: CodeMap, config: ArchitectureConfig, options: CacheOptions
153
156
  ) -> CachedResult[tuple[ReportNode, ...] | None]:
154
157
  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
+ cached_value, cached_invalidated = self._read(options, key)
159
+ invalidated = cached_invalidated or cached_value is not None
158
160
  try:
159
161
  if not isinstance(cached_value, list):
160
162
  raise ValueError("Cached reports must be a list.")
@@ -162,7 +164,7 @@ class CacheApplication:
162
164
  value = tuple(sorted(reports, key=lambda item: (item.metadata.order, item.metadata.id)))
163
165
  outcome = CacheOutcome(stage=CacheStage.REPORTS, namespace=options.namespace, hits=1)
164
166
  except (AttributeError, ImportError, KeyError, TypeError, ValueError, ValidationError):
165
- if cached_value is not None and not cached.invalidated:
167
+ if cached_value is not None and not cached_invalidated:
166
168
  self.storage.delete(options, key)
167
169
  value = None
168
170
  outcome = CacheOutcome(
@@ -188,32 +190,25 @@ class CacheApplication:
188
190
  for report in reports
189
191
  ]
190
192
  self._write(options, self.identity.reports(code_map, config), value)
191
- self.prune(options)
193
+
194
+ def maintain(self, options: CacheOptions) -> bool:
195
+ return self.storage.enforce_capacity(options)
192
196
 
193
197
  def clear(self, options: CacheOptions) -> None:
194
198
  self.storage.clear(options)
195
199
 
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:
200
+ def _read(self, options: CacheOptions, key: CacheKey) -> tuple[object | None, bool]:
206
201
  payload = self.storage.read(options, key)
207
202
  if payload is None:
208
- return _CacheRead(value=None, invalidated=False)
203
+ return None, False
209
204
  value = self.codec.decode(key, payload)
210
205
  if value is None:
211
206
  self.storage.delete(options, key)
212
- return _CacheRead(value=None, invalidated=True)
213
- return _CacheRead(value=value, invalidated=False)
207
+ return None, True
208
+ return value, False
214
209
 
215
- def _write(self, options: CacheOptions, key: CacheKey, value: object) -> None:
216
- self.storage.write(options, key, self.codec.encode(key, value))
210
+ def _write(self, options: CacheOptions, key: CacheKey, value: object) -> bool:
211
+ return self.storage.write(options, key, self.codec.encode(key, value))
217
212
 
218
213
  def _report(self, value: object) -> ReportNode:
219
214
  if not isinstance(value, dict):
@@ -1,6 +1,5 @@
1
1
  from abc import ABC, abstractmethod
2
2
 
3
- from .models.cache_entry import CacheEntry
4
3
  from .models.cache_key import CacheKey
5
4
  from .models.cache_options import CacheOptions
6
5
 
@@ -11,17 +10,29 @@ class CacheStorage(ABC):
11
10
  raise NotImplementedError
12
11
 
13
12
  @abstractmethod
14
- def write(self, options: CacheOptions, key: CacheKey, payload: bytes) -> None:
13
+ def read_many(self, options: CacheOptions, keys: tuple[CacheKey, ...]) -> tuple[bytes | None, ...]:
15
14
  raise NotImplementedError
16
15
 
17
16
  @abstractmethod
18
- def entries(self, options: CacheOptions) -> tuple[CacheEntry, ...]:
17
+ def write(self, options: CacheOptions, key: CacheKey, payload: bytes) -> bool:
18
+ raise NotImplementedError
19
+
20
+ @abstractmethod
21
+ def write_many(self, options: CacheOptions, payloads: tuple[tuple[CacheKey, bytes], ...]) -> tuple[CacheKey, ...]:
19
22
  raise NotImplementedError
20
23
 
21
24
  @abstractmethod
22
25
  def delete(self, options: CacheOptions, key: CacheKey) -> None:
23
26
  raise NotImplementedError
24
27
 
28
+ @abstractmethod
29
+ def delete_many(self, options: CacheOptions, keys: tuple[CacheKey, ...]) -> None:
30
+ raise NotImplementedError
31
+
32
+ @abstractmethod
33
+ def enforce_capacity(self, options: CacheOptions) -> bool:
34
+ raise NotImplementedError
35
+
25
36
  @abstractmethod
26
37
  def clear(self, options: CacheOptions) -> None:
27
38
  raise NotImplementedError
@@ -1,24 +1,17 @@
1
- from enum import StrEnum
2
-
3
1
  from pydantic import field_validator
4
2
 
5
3
  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"
4
+ from .cache_stage import CacheStage
14
5
 
15
6
 
16
7
  class CacheOutcome(ValueModel):
17
8
  """Content-safe lifecycle counts for one stage of a cached operation.
18
9
 
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.
10
+ Extraction counts describe current source records. An exact code-map hit
11
+ reports its digest-backed manifest sources as extraction hits without loading
12
+ individual source payloads. Code-map and report counts describe one entry.
13
+ Invalidated entries are also misses. Diagnostics include the configured
14
+ namespace but never cache keys, source identities, or content.
22
15
  """
23
16
 
24
17
  stage: CacheStage
@@ -0,0 +1,22 @@
1
+ from ....shared.values.models.value_model import ValueModel
2
+ from ...pipeline.models.source_inventory import SourceInventory
3
+ from .cache_key import CacheKey
4
+ from .source_cache_entry import SourceCacheEntry
5
+
6
+
7
+ class CachePlan(ValueModel):
8
+ inventory: SourceInventory
9
+ sources: tuple[SourceCacheEntry, ...]
10
+ manifest: CacheKey
11
+
12
+ def manifest_value(self) -> dict[str, object]:
13
+ return {
14
+ "sources": [
15
+ {
16
+ "relative_path": source.entry.relative_path,
17
+ "content_digest": source.entry.content_digest,
18
+ "source_key": source.key.digest,
19
+ }
20
+ for source in sorted(self.sources, key=lambda item: item.entry.relative_path)
21
+ ]
22
+ }
@@ -0,0 +1,9 @@
1
+ from enum import StrEnum
2
+
3
+
4
+ class CacheStage(StrEnum):
5
+ """Public stages reported by cached Modwire operations."""
6
+
7
+ EXTRACTION = "extraction"
8
+ CODE_MAP = "code-map"
9
+ REPORTS = "reports"
@@ -0,0 +1,11 @@
1
+ from typing import Literal
2
+
3
+ from pydantic import Field
4
+
5
+ from ....shared.values.models.value_model import ValueModel
6
+
7
+
8
+ class CacheStorageState(ValueModel):
9
+ schema_version: Literal[1] = 1
10
+ total_bytes: int = Field(ge=0)
11
+ entry_count: int = Field(ge=0)
@@ -1,7 +1,8 @@
1
1
  from pydantic import field_validator
2
2
 
3
3
  from ....shared.values.models.value_model import ValueModel
4
- from .cache_outcome import CacheOutcome, CacheStage
4
+ from .cache_outcome import CacheOutcome
5
+ from .cache_stage import CacheStage
5
6
 
6
7
 
7
8
  class CachedResult[Result](ValueModel):
@@ -0,0 +1,8 @@
1
+ from ....shared.values.models.value_model import ValueModel
2
+ from ...pipeline.models.source_entry import SourceEntry
3
+ from .cache_key import CacheKey
4
+
5
+
6
+ class SourceCacheEntry(ValueModel):
7
+ entry: SourceEntry
8
+ key: CacheKey