dialectical-framework 1.6.1__tar.gz → 1.6.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/PKG-INFO +1 -1
  2. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/pyproject.toml +1 -1
  3. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/orchestrator/tools/inspect_node.py +11 -0
  4. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/causality/causality_estimator.py +13 -1
  5. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/causality/causality_estimator_balanced.py +119 -54
  6. dialectical_framework-1.6.2/src/dialectical_framework/concerns/causality/causality_estimator_criteria.py +35 -0
  7. dialectical_framework-1.6.2/src/dialectical_framework/concerns/causality/causality_estimator_desirable.py +13 -0
  8. dialectical_framework-1.6.2/src/dialectical_framework/concerns/causality/causality_estimator_feasible.py +13 -0
  9. dialectical_framework-1.6.2/src/dialectical_framework/concerns/causality/causality_estimator_realistic.py +13 -0
  10. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/causality_estimation.py +85 -24
  11. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/synthesis_generation.py +6 -2
  12. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/transformation_generation.py +1 -0
  13. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/repositories/node_repository.py +41 -0
  14. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/utils/dc_replace.py +5 -4
  15. dialectical_framework-1.6.1/src/dialectical_framework/concerns/causality/causality_estimator_criteria.py +0 -71
  16. dialectical_framework-1.6.1/src/dialectical_framework/concerns/causality/causality_estimator_desirable.py +0 -50
  17. dialectical_framework-1.6.1/src/dialectical_framework/concerns/causality/causality_estimator_feasible.py +0 -50
  18. dialectical_framework-1.6.1/src/dialectical_framework/concerns/causality/causality_estimator_realistic.py +0 -50
  19. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/LICENSE +0 -0
  20. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/README.md +0 -0
  21. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/__init__.py +0 -0
  22. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/__init__.py +0 -0
  23. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/advisor/__init__.py +0 -0
  24. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/advisor/advisor.py +0 -0
  25. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/advisor/system_prompts.py +0 -0
  26. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/advisor/tools/__init__.py +0 -0
  27. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/advisor/tools/anchor.py +0 -0
  28. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/advisor/tools/explore.py +0 -0
  29. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/advisor/tools/ingest.py +0 -0
  30. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/advisor/tools/sync.py +0 -0
  31. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/agent_context.py +0 -0
  32. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/analyst/__init__.py +0 -0
  33. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/analyst/analyst.py +0 -0
  34. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/analyst/skills/__init__.py +0 -0
  35. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/analyst/skills/anchor_theses.py +0 -0
  36. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/analyst/skills/edit_perspective.py +0 -0
  37. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/analyst/skills/expand_polarities.py +0 -0
  38. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/analyst/skills/find_polarities.py +0 -0
  39. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/analyst/skills/introduce_polarity.py +0 -0
  40. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/analyst/skills/surface_theses.py +0 -0
  41. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/analyst/system_prompts.py +0 -0
  42. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/analyst/tools/__init__.py +0 -0
  43. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/analyst/tools/create_dx_input.py +0 -0
  44. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/analyst/tools/place_statement.py +0 -0
  45. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/apps.py +0 -0
  46. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/conversation_facilitator.py +0 -0
  47. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/execution_report.py +0 -0
  48. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/explorer/__init__.py +0 -0
  49. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/explorer/explorer.py +0 -0
  50. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/explorer/skills/__init__.py +0 -0
  51. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/explorer/skills/build_wheels.py +0 -0
  52. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/explorer/skills/explore_transformations.py +0 -0
  53. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/explorer/skills/generate_synthesis.py +0 -0
  54. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/explorer/system_prompts.py +0 -0
  55. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/explorer/tools/__init__.py +0 -0
  56. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/explorer/tools/create_nexus.py +0 -0
  57. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/explorer/tools/expand_nexus.py +0 -0
  58. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/explorer/tools/generate_synthesis.py +0 -0
  59. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/explorer/tools/present_exploration.py +0 -0
  60. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/orchestrator/__init__.py +0 -0
  61. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/orchestrator/tools/__init__.py +0 -0
  62. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/orchestrator/tools/add_input.py +0 -0
  63. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/orchestrator/tools/digest_input.py +0 -0
  64. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/orchestrator/tools/discard.py +0 -0
  65. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/orchestrator/tools/get_schema.py +0 -0
  66. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/orchestrator/tools/present_analysis.py +0 -0
  67. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/orchestrator/tools/query_graph.py +0 -0
  68. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/orchestrator/tools/read_digest.py +0 -0
  69. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/orchestrator/tools/read_input.py +0 -0
  70. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/reasonable_concern.py +0 -0
  71. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/agents/stream_events.py +0 -0
  72. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/__init__.py +0 -0
  73. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/ac_re_taxonomy.py +0 -0
  74. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/action_extraction.py +0 -0
  75. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/add_input.py +0 -0
  76. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/ai_dto/__init__.py +0 -0
  77. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/ai_dto/statement_dto.py +0 -0
  78. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/ai_dto/statements_deck_dto.py +0 -0
  79. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/antithesis_classification.py +0 -0
  80. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/antithesis_extraction.py +0 -0
  81. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/aspect_classification.py +0 -0
  82. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/aspect_generation.py +0 -0
  83. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/causality/__init__.py +0 -0
  84. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/causality/causality_normalizer.py +0 -0
  85. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/causality/estimator_resolver.py +0 -0
  86. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/control_statements_check.py +0 -0
  87. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/create_dx_input.py +0 -0
  88. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/create_nexus.py +0 -0
  89. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/diagonal_oppositions_check.py +0 -0
  90. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/dialectical_context.py +0 -0
  91. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/discard.py +0 -0
  92. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/display_text_edit.py +0 -0
  93. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/expand_nexus.py +0 -0
  94. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/perspective_combination.py +0 -0
  95. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/perspective_validation.py +0 -0
  96. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/positive_ac_re_apex_derivation.py +0 -0
  97. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/scoring_scales.py +0 -0
  98. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/source_digest.py +0 -0
  99. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/statement_classification.py +0 -0
  100. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/statement_deduplication.py +0 -0
  101. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/statement_headline.py +0 -0
  102. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/statement_placement.py +0 -0
  103. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/thesis_extraction.py +0 -0
  104. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/concerns/transformation_audit.py +0 -0
  105. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/dialectical_reasoning.py +0 -0
  106. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/enums/__init__.py +0 -0
  107. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/enums/causality_preset.py +0 -0
  108. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/enums/di.py +0 -0
  109. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/events/__init__.py +0 -0
  110. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/events/graph_event.py +0 -0
  111. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/events/graph_event_bus.py +0 -0
  112. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/exceptions/__init__.py +0 -0
  113. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/exceptions/node_errors.py +0 -0
  114. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/exceptions/resolver_errors.py +0 -0
  115. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/__init__.py +0 -0
  116. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/composite_input_resolver.py +0 -0
  117. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/dialexity_input_resolver.py +0 -0
  118. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/estimation_manager.py +0 -0
  119. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/mixins/__init__.py +0 -0
  120. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/mixins/incremental_build_mixin.py +0 -0
  121. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/mixins/intent_mixin.py +0 -0
  122. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/mixins/persistable_mixin.py +0 -0
  123. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/__init__.py +0 -0
  124. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/assessable_entity.py +0 -0
  125. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/base_node.py +0 -0
  126. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/case.py +0 -0
  127. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/cycle.py +0 -0
  128. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/estimation.py +0 -0
  129. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/ideas.py +0 -0
  130. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/input.py +0 -0
  131. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/nexus.py +0 -0
  132. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/perspective.py +0 -0
  133. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/polarity.py +0 -0
  134. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/rationale.py +0 -0
  135. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/statement.py +0 -0
  136. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/synthesis.py +0 -0
  137. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/transformation.py +0 -0
  138. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/transition.py +0 -0
  139. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/nodes/wheel.py +0 -0
  140. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationship_manager.py +0 -0
  141. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/__init__.py +0 -0
  142. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/action_reflection_relationship.py +0 -0
  143. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/belongs_to_cycle_relationship.py +0 -0
  144. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/belongs_to_nexus_relationship.py +0 -0
  145. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/changed_to_relationship.py +0 -0
  146. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/contradiction_of_relationship.py +0 -0
  147. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/critiques_relationship.py +0 -0
  148. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/distilled_to_relationship.py +0 -0
  149. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/estimates_relationship.py +0 -0
  150. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/explains_relationship.py +0 -0
  151. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/has_input_relationship.py +0 -0
  152. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/has_statement_relationship.py +0 -0
  153. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/has_wheel_relationship.py +0 -0
  154. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/immutable_structure.py +0 -0
  155. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/is_source_of_relationship.py +0 -0
  156. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/is_target_of_relationship.py +0 -0
  157. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/negative_side_of_relationship.py +0 -0
  158. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/opposite_direction_relationship.py +0 -0
  159. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/opposite_of_relationship.py +0 -0
  160. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/polarity_relationship.py +0 -0
  161. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/positive_side_of_relationship.py +0 -0
  162. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/provides_relationship.py +0 -0
  163. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/relationships/synthesis_of_relationship.py +0 -0
  164. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/rendering.py +0 -0
  165. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/repositories/__init__.py +0 -0
  166. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/repositories/case_repository.py +0 -0
  167. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/repositories/cycle_repository.py +0 -0
  168. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/repositories/input_repository.py +0 -0
  169. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/repositories/nexus_repository.py +0 -0
  170. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/repositories/perspective_repository.py +0 -0
  171. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/repositories/polarity_repository.py +0 -0
  172. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/repositories/schema_repository.py +0 -0
  173. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/repositories/statement_repository.py +0 -0
  174. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/repositories/transformation_repository.py +0 -0
  175. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/repositories/wheel_repository.py +0 -0
  176. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/scope_context.py +0 -0
  177. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/verbatim_input_resolver.py +0 -0
  178. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/wheel_segment.py +0 -0
  179. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/graph/wheel_segment_polar_pair.py +0 -0
  180. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/protocols/__init__.py +0 -0
  181. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/protocols/has_config.py +0 -0
  182. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/protocols/input_resolver.py +0 -0
  183. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/settings.py +0 -0
  184. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/utils/__init__.py +0 -0
  185. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/utils/bedrock_provider.py +0 -0
  186. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/utils/concurrency.py +0 -0
  187. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/utils/decompose_probability_uniformly.py +0 -0
  188. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/utils/edge_context.py +0 -0
  189. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/utils/effect_logger.py +0 -0
  190. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/utils/input_context.py +0 -0
  191. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/utils/order_transitions.py +0 -0
  192. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/utils/sequence_generation.py +0 -0
  193. {dialectical_framework-1.6.1 → dialectical_framework-1.6.2}/src/dialectical_framework/utils/use_brain.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dialectical-framework
3
- Version: 1.6.1
3
+ Version: 1.6.2
4
4
  Summary: A dialectical framework for augmented intelligence. AI reasoning powered with dialectics supports humans in: system optimization (psychology, engineering, business, politics, etc.); dispute resolution (mediation, conflicts, negotiations, etc.); decision-making (dilemmas, challenging situations, win-win, etc.).
5
5
  License: MIT
6
6
  Keywords: dialectics,dialectical-reasoning,synthesis,thesis-antithesis,ai,artificial-intelligence,llm,reasoning-framework,philosophy,logic,argumentation,conflict-resolution,decision-making,critical-thinking,semantic-graph,mirascope,pydantic,perspectives,polarity-reasoning
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "dialectical-framework"
3
- version = "1.6.1"
3
+ version = "1.6.2"
4
4
  description = "A dialectical framework for augmented intelligence. AI reasoning powered with dialectics supports humans in: system optimization (psychology, engineering, business, politics, etc.); dispute resolution (mediation, conflicts, negotiations, etc.); decision-making (dilemmas, challenging situations, win-win, etc.)."
5
5
  authors = ["Evaldas Taroza <evaldas@dialexity.com>"]
6
6
  readme = "README.md"
@@ -431,6 +431,17 @@ def _inspect_wheel(wheel: Wheel) -> str:
431
431
  spiral_seq = format_spiral(wheel, pp_index)
432
432
  if spiral_seq:
433
433
  lines.append(f"Spiral: {spiral_seq}")
434
+
435
+ # Per-edge causation (rationales attached to edge Transitions)
436
+ edge_causations = []
437
+ for edge in wheel.edges:
438
+ for rationale, _ in edge.rationales.all():
439
+ if rationale.text:
440
+ label = format_edge_label(edge, pp_index)
441
+ edge_causations.append(f" {label}: {rationale.text}")
442
+ if edge_causations:
443
+ lines.append("Step causation:")
444
+ lines.extend(edge_causations)
434
445
  lines.append("")
435
446
 
436
447
  # Parent cycle
@@ -11,7 +11,7 @@ The CausalityEstimation concern handles normalization and database persistence.
11
11
  from __future__ import annotations
12
12
 
13
13
  from abc import ABC, abstractmethod
14
- from dataclasses import dataclass
14
+ from dataclasses import dataclass, field
15
15
  from typing import TYPE_CHECKING, Union
16
16
 
17
17
  if TYPE_CHECKING:
@@ -19,6 +19,17 @@ if TYPE_CHECKING:
19
19
  from dialectical_framework.graph.nodes.wheel import Wheel
20
20
 
21
21
 
22
+ @dataclass
23
+ class StepCausation:
24
+ """Per-step causal justification within a sequence (aliases resolved)."""
25
+
26
+ source_hash: str
27
+ target_hash: str
28
+ source_text: str
29
+ target_text: str
30
+ causation: str # Why source naturally leads to target
31
+
32
+
22
33
  @dataclass
23
34
  class EstimationStructured:
24
35
  """Raw AI estimation result for a single structure (Cycle or Wheel)."""
@@ -26,6 +37,7 @@ class EstimationStructured:
26
37
  probability: float # Raw AI probability (0-1), NOT normalized
27
38
  reasoning: str # Why this sequence might occur
28
39
  argumentation: str # Circumstances where applicable
40
+ steps: list[StepCausation] = field(default_factory=list) # Per-step causation
29
41
 
30
42
 
31
43
  class CausalityEstimator(ABC):
@@ -17,6 +17,7 @@ from dialectical_framework.graph.nodes.wheel import Wheel
17
17
  from dialectical_framework.concerns.causality.causality_estimator import (
18
18
  CausalityEstimator,
19
19
  EstimationStructured,
20
+ StepCausation,
20
21
  )
21
22
  from dialectical_framework.protocols.input_resolver import InputResolver
22
23
 
@@ -24,7 +25,34 @@ from dialectical_framework.utils.dc_replace import dc_replace
24
25
  from dialectical_framework.utils.use_brain import use_brain
25
26
 
26
27
 
28
+ class StepCausationDto(BaseModel):
29
+ from_alias: str = Field(
30
+ default="",
31
+ description="Technical alias of the step's source, exactly as given in the sequence (e.g. C1_1).",
32
+ )
33
+ to_alias: str = Field(
34
+ default="",
35
+ description="Technical alias of the step's target, exactly as given in the sequence (e.g. C1_2).",
36
+ )
37
+ causation: str = Field(
38
+ default="",
39
+ description=(
40
+ "One sentence: the causal mechanism why the source naturally leads to "
41
+ "the target. Use the actual statement wording, never aliases."
42
+ ),
43
+ )
44
+
45
+
27
46
  class CausalCycleAssessmentDto(BaseModel):
47
+ # steps comes FIRST: justifying each step before scoring is deliberate
48
+ # chain-of-thought — the holistic probability must be informed by them
49
+ steps: list[StepCausationDto] = Field(
50
+ default_factory=list,
51
+ description=(
52
+ "One entry per consecutive step of the sequence, in order, "
53
+ "including the final wrap-around step back to the first element."
54
+ ),
55
+ )
28
56
  probability: float = Field(
29
57
  default=0,
30
58
  description="The probability 0 to 1 of the arranged cycle to exist in reality.",
@@ -45,6 +73,61 @@ class CausalCycleDto(CausalCycleAssessmentDto):
45
73
  )
46
74
 
47
75
 
76
+ def _resolve_steps(
77
+ step_dtos: list[StepCausationDto],
78
+ sequence: list[Statement],
79
+ seq_idx: int,
80
+ alias_translations: dict[str, str],
81
+ ) -> list[StepCausation]:
82
+ """
83
+ Resolve step DTOs (alias-identified) to StepCausation (hash/text-identified).
84
+
85
+ Primary path: parse C{seq}_{comp} aliases against the sequence.
86
+ Fallback: if aliases are garbled but the step count matches the sequence
87
+ length, map positionally (step i = statements[i] → statements[i+1 mod n]).
88
+ Otherwise drop the steps — per-step causation is best-effort enrichment.
89
+ """
90
+ n = len(sequence)
91
+ if not step_dtos or n == 0:
92
+ return []
93
+
94
+ def parse(alias: str) -> Optional[Statement]:
95
+ parts = alias.strip().split("_")
96
+ if len(parts) != 2 or not parts[0].startswith("C"):
97
+ return None
98
+ try:
99
+ s, c = int(parts[0][1:]), int(parts[1])
100
+ except ValueError:
101
+ return None
102
+ if s != seq_idx or not (1 <= c <= n):
103
+ return None
104
+ return sequence[c - 1]
105
+
106
+ resolved: list[StepCausation] = []
107
+ for i, dto in enumerate(step_dtos):
108
+ source = parse(dto.from_alias)
109
+ target = parse(dto.to_alias)
110
+ if source is None or target is None:
111
+ if len(step_dtos) != n:
112
+ return [] # aliases garbled and counts don't line up — drop all
113
+ source = sequence[i]
114
+ target = sequence[(i + 1) % n]
115
+ causation = dto.causation
116
+ for technical_alias, text in alias_translations.items():
117
+ causation = dc_replace(causation, technical_alias, text)
118
+ assert source.hash is not None and target.hash is not None
119
+ resolved.append(
120
+ StepCausation(
121
+ source_hash=source.hash,
122
+ target_hash=target.hash,
123
+ source_text=source.text,
124
+ target_text=target.text,
125
+ causation=causation,
126
+ )
127
+ )
128
+ return resolved
129
+
130
+
48
131
  class CausalCyclesDeckDto(BaseModel):
49
132
  causal_cycles: list[CausalCycleDto] = Field(
50
133
  ...,
@@ -121,41 +204,37 @@ class CausalityEstimatorBalanced(CausalityEstimator):
121
204
  def input_resolver(self) -> InputResolver:
122
205
  return self._input_resolver
123
206
 
124
- def prompt_assess_multiple_sequences(
125
- self, *, sequences: list[str]
126
- ) -> list:
127
- sequences_text = "\n".join(f"- {s}" for s in sequences)
128
- return [llm.messages.user(
129
- f"Which of the following circular causality sequences provides the best assessment "
130
- f"considering realism, desirability, and feasibility "
131
- f"(given that the final step cycles back to the first step):\n"
132
- f"{sequences_text}\n\n"
133
- f"<instructions>\n"
134
- f"For each sequence:\n"
135
- f"1) Estimate the numeric probability (0 to 1) considering realistic existence, optimal outcomes, and (implementation) feasibility — weigh these together holistically into a single plausibility score\n"
136
- f"2) Explain why this sequence might occur (or already occurs) in reality\n"
137
- f"3) Describe circumstances or contexts where this sequence would be most applicable or useful\n\n"
138
- f"- Only use the sequences **exactly as provided**, do not shorten, skip, collapse, or reorder steps.\n"
139
- f"</instructions>\n\n"
140
- f"<formatting>\n"
141
- f"- Output each circular causality sequence (cycle) as ordered aliases (technical placeholders) of statements as provided e.g. C1_1, C1_2, C1_3, ...\n"
142
- f"- In the explanations, for fluency, use explicit wording instead of aliases.\n"
143
- f"- Probability is a float between 0 and 1.\n"
144
- f"</formatting>"
145
- )]
207
+ def _lens_phrase(self) -> str:
208
+ """Assessment lens inserted after 'Assess the following circular causality sequence'."""
209
+ return "considering realism, desirability, and feasibility"
210
+
211
+ def _probability_instruction(self) -> str:
212
+ """Qualifier inserted after 'Estimate the numeric probability (0 to 1)'."""
213
+ return (
214
+ "considering realistic existence, optimal outcomes, and (implementation) "
215
+ "feasibility — weigh these together holistically into a single plausibility score"
216
+ )
146
217
 
147
218
  def prompt_assess_single_sequence(self, *, sequence: str) -> list:
219
+ """
220
+ Single prompt template shared by all estimator variants.
221
+
222
+ Subclasses customize only _lens_phrase() and _probability_instruction();
223
+ the sequence handling, instructions, and formatting rules stay identical.
224
+ """
148
225
  return [llm.messages.user(
149
- f"Assess the following circular causality sequence considering realism, desirability, and feasibility "
226
+ f"Assess the following circular causality sequence {self._lens_phrase()}\n"
150
227
  f"(given that the final step cycles back to the first step):\n"
151
228
  f"{sequence}\n\n"
152
229
  f"<instructions>\n"
153
- f"1) Estimate the numeric probability (0 to 1) considering realistic existence, optimal outcomes, and (implementation) feasibility weigh these together holistically into a single plausibility score\n"
154
- f"2) Explain why this sequence might occur (or already occurs) in reality\n"
155
- f"3) Describe circumstances or contexts where this sequence would be most applicable or useful\n\n"
230
+ f"1) For each consecutive step of the sequence (including the final wrap-around step back to the first element), state in one sentence the causal mechanism: why does the source naturally lead to the target?\n"
231
+ f"2) Only then, informed by the step-by-step causation, estimate the numeric probability (0 to 1) {self._probability_instruction()}\n"
232
+ f"3) Explain why this sequence might occur (or already occurs) in reality\n"
233
+ f"4) Describe circumstances or contexts where this sequence would be most applicable or useful\n\n"
156
234
  f"- Only use the sequence **exactly as provided**, do not shorten, skip, collapse, or reorder steps.\n"
157
235
  f"</instructions>\n\n"
158
236
  f"<formatting>\n"
237
+ f"- In each step, identify source and target by their technical aliases exactly as given in the sequence; write the causation sentence itself using the actual statement wording, never aliases.\n"
159
238
  f"- In the explanations and argumentation, for fluency, try to use explicit wording instead of technical aliases.\n"
160
239
  f"- Probability is a float between 0 and 1.\n"
161
240
  f"</formatting>"
@@ -289,6 +368,7 @@ class CausalityEstimatorBalanced(CausalityEstimator):
289
368
  assessment: CausalCycleAssessmentDto = await _estimate_single_call()
290
369
  return CausalCycleDto(
291
370
  aliases=aliases,
371
+ steps=assessment.steps,
292
372
  probability=assessment.probability,
293
373
  reasoning_explanation=assessment.reasoning_explanation,
294
374
  argumentation=assessment.argumentation,
@@ -364,33 +444,14 @@ class CausalityEstimatorBalanced(CausalityEstimator):
364
444
  i: structure for i, structure in enumerate(structures)
365
445
  }
366
446
 
367
- # Build component-alias translations for text replacement
368
- components_with_aliases: list[tuple[Statement, str]] = []
369
- for sequence in sequences:
370
- for comp in sequence:
371
- assert comp.hash is not None
372
- alias = None
373
- for existing_comp, existing_alias in components_with_aliases:
374
- if existing_comp.hash == comp.hash:
375
- alias = existing_alias
376
- break
377
- if alias is None:
378
- alias = f"C{len(components_with_aliases) + 1}"
379
- components_with_aliases.append((comp, alias))
380
-
381
- # Build alias translation map
382
- id_to_original_alias: dict[str, str] = {}
383
- for comp, original_alias in components_with_aliases:
384
- assert comp.hash is not None
385
- id_to_original_alias[comp.hash] = original_alias
447
+ # Translate technical aliases to statement text. Aliases are
448
+ # batch-relative and must never survive into persisted rationale
449
+ # prose statement text is the only durable identifier.
386
450
  alias_translations: dict[str, str] = {}
387
451
  for seq_idx, sequence in enumerate(sequences, 1):
388
452
  for comp_idx, component in enumerate(sequence, 1):
389
453
  technical_alias = f"C{seq_idx}_{comp_idx}"
390
- assert component.hash is not None
391
- original_alias = id_to_original_alias.get(component.hash)
392
- if original_alias:
393
- alias_translations[technical_alias] = original_alias
454
+ alias_translations[technical_alias] = component.text
394
455
 
395
456
  # Map results
396
457
  results: dict[str, EstimationStructured] = {}
@@ -417,18 +478,22 @@ class CausalityEstimatorBalanced(CausalityEstimator):
417
478
  # Translate aliases in text
418
479
  reasoning_text = causal_cycle.reasoning_explanation
419
480
  argumentation_text = causal_cycle.argumentation
420
- for technical_alias, original_alias in alias_translations.items():
421
- reasoning_text = dc_replace(
422
- reasoning_text, technical_alias, original_alias
423
- )
481
+ for technical_alias, text in alias_translations.items():
482
+ reasoning_text = dc_replace(reasoning_text, technical_alias, text)
424
483
  argumentation_text = dc_replace(
425
- argumentation_text, technical_alias, original_alias
484
+ argumentation_text, technical_alias, text
426
485
  )
427
486
 
428
487
  results[matched_structure.hash] = EstimationStructured(
429
488
  probability=causal_cycle.probability,
430
489
  reasoning=reasoning_text,
431
490
  argumentation=argumentation_text,
491
+ steps=_resolve_steps(
492
+ causal_cycle.steps,
493
+ sequences[seq_idx],
494
+ seq_idx + 1,
495
+ alias_translations,
496
+ ),
432
497
  )
433
498
 
434
499
  return results
@@ -0,0 +1,35 @@
1
+ from __future__ import annotations
2
+
3
+ from dependency_injector.wiring import Provide, inject
4
+
5
+ from dialectical_framework.enums.di import DI
6
+ from dialectical_framework.concerns.causality.causality_estimator_balanced import \
7
+ CausalityEstimatorBalanced
8
+ from dialectical_framework.protocols.input_resolver import InputResolver
9
+
10
+
11
+ class CausalityEstimatorCriteria(CausalityEstimatorBalanced):
12
+ """
13
+ Causality estimator that uses custom assessment criteria.
14
+
15
+ Instead of the balanced/realistic/desirable/feasible perspective,
16
+ this estimator evaluates sequences against pre-formulated criteria
17
+ derived from a free-form exploration intent.
18
+
19
+ Criteria formulation happens upstream (in BuildWheels).
20
+ """
21
+
22
+ @inject
23
+ def __init__(
24
+ self,
25
+ criteria: str,
26
+ input_resolver: InputResolver = Provide[DI.input_resolver],
27
+ ):
28
+ super().__init__(input_resolver=input_resolver)
29
+ self._criteria = criteria
30
+
31
+ def _lens_phrase(self) -> str:
32
+ return f"with focus on the following assessment criteria: {self._criteria}"
33
+
34
+ def _probability_instruction(self) -> str:
35
+ return "with emphasis on the assessment criteria above"
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+
3
+ from dialectical_framework.concerns.causality.causality_estimator_balanced import \
4
+ CausalityEstimatorBalanced
5
+
6
+
7
+ class CausalityEstimatorDesirable(CausalityEstimatorBalanced):
8
+
9
+ def _lens_phrase(self) -> str:
10
+ return "considering desirability, i.e. producing optimal outcomes and maximum results"
11
+
12
+ def _probability_instruction(self) -> str:
13
+ return "regarding how beneficial/optimal this sequence would be if implemented"
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+
3
+ from dialectical_framework.concerns.causality.causality_estimator_balanced import \
4
+ CausalityEstimatorBalanced
5
+
6
+
7
+ class CausalityEstimatorFeasible(CausalityEstimatorBalanced):
8
+
9
+ def _lens_phrase(self) -> str:
10
+ return "considering feasibility, i.e. best achievable with minimum resistance"
11
+
12
+ def _probability_instruction(self) -> str:
13
+ return "regarding how easily this sequence could be implemented given current constraints"
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+
3
+ from dialectical_framework.concerns.causality.causality_estimator_balanced import \
4
+ CausalityEstimatorBalanced
5
+
6
+
7
+ class CausalityEstimatorRealistic(CausalityEstimatorBalanced):
8
+
9
+ def _lens_phrase(self) -> str:
10
+ return "for realism, i.e. what typically happens in natural systems"
11
+
12
+ def _probability_instruction(self) -> str:
13
+ return "regarding its realistic existence in natural/existing systems"
@@ -3,8 +3,7 @@ CausalityEstimation: Concern for estimating causality on Cycles and Wheels.
3
3
 
4
4
  This is the "smart" orchestrator that:
5
5
  - Groups structures by type and size for parallel estimation
6
- - Decides what to estimate: if the requested group matches what's in the DB,
7
- re-estimates everything; if DB has more, only estimates what was requested
6
+ - (Re-)estimates exactly the structures requested
8
7
  - Normalizes probabilities across ALL structures of same type+size in the DB
9
8
 
10
9
  Usage:
@@ -61,9 +60,8 @@ class CausalityEstimation(ReasonableConcern[EstimationResult], SettingsAware):
61
60
  of same type+size in the DB
62
61
 
63
62
  Estimation logic per group:
64
- - If the requested group IS the full set in the DB → re-estimate all
65
- - If the DB has more structures only estimate the ones requested
66
- - Either way, normalization covers everything in the DB
63
+ - (Re-)estimates exactly the structures requested
64
+ - Normalization covers everything of same type+size in the DB
67
65
  """
68
66
 
69
67
  def __init__(self) -> None:
@@ -164,25 +162,17 @@ class CausalityEstimation(ReasonableConcern[EstimationResult], SettingsAware):
164
162
  Estimate a group of same-type, same-size structures.
165
163
 
166
164
  Logic:
167
- - Find all structures of same type+size in DB
168
- - If requested set IS the full DB set estimate all (forced re-estimation)
169
- - If DB has more → only estimate the requested ones
170
- - Normalize probabilities across all DB structures
165
+ - (Re-)estimate exactly the requested structures
166
+ - Normalize probabilities across all structures of same type+size in DB
171
167
 
172
168
  Returns list of structures that were estimated.
173
169
  """
174
170
  # Find all structures of same type+size in DB
175
171
  all_in_db = self._find_all_in_layer(requested)
176
- requested_hashes = {s.hash for s in requested}
177
- db_hashes = {s.hash for s in all_in_db}
178
172
 
179
- # Determine what to estimate
180
- if requested_hashes == db_hashes:
181
- # Requested set IS the full DB set → estimate all
182
- to_estimate = requested
183
- else:
184
- # DB has more → only estimate what was requested
185
- to_estimate = requested
173
+ # Always (re-)estimate exactly what was requested; normalization
174
+ # below covers everything in the DB layer.
175
+ to_estimate = requested
186
176
 
187
177
  # Run AI estimation (returns raw, non-normalized results)
188
178
  raw_estimations = await estimator.estimate(to_estimate)
@@ -258,7 +248,11 @@ class CausalityEstimation(ReasonableConcern[EstimationResult], SettingsAware):
258
248
  """
259
249
  Persist raw estimations to the database.
260
250
 
261
- Creates Rationale + CausalityProbabilityEstimation for each structure.
251
+ Per structure: replaces prior causality rationales (holistic and
252
+ per-step), then creates Rationale + CausalityProbabilityEstimation
253
+ plus one per-step causation Rationale per sequence step (wheel steps
254
+ target their edge Transition; cycle steps target the Cycle itself,
255
+ self-identified by statement-text headers).
262
256
  """
263
257
  estimation_manager = EstimationManager()
264
258
 
@@ -268,15 +262,82 @@ class CausalityEstimation(ReasonableConcern[EstimationResult], SettingsAware):
268
262
 
269
263
  est = raw_estimations[structure.hash]
270
264
 
271
- # Create Rationale
272
- rationale = Rationale(
273
- text=est.reasoning,
274
- summary=est.argumentation,
275
- )
265
+ # Replace: re-estimation supersedes prior explanations, on the
266
+ # structure itself and (for wheels) on its edge Transitions
267
+ self._delete_prior_rationales(structure)
268
+
269
+ # Create Rationale (argumentation folded into text — it used to be
270
+ # stored as an undeclared, write-only `summary` field)
271
+ rationale_text = est.reasoning
272
+ if est.argumentation:
273
+ rationale_text = (
274
+ f"{est.reasoning}\n\n**Applicable contexts:** {est.argumentation}"
275
+ )
276
+ rationale = Rationale(text=rationale_text)
276
277
  rationale.set_explanation_target(structure)
277
278
  rationale.commit()
279
+ self._report.node_created(rationale)
278
280
 
279
281
  # Store raw AI score as CausalityProbabilityEstimation
280
282
  estimation_manager.upsert_estimation(
281
283
  structure, CausalityProbabilityEstimation, est.probability, provider=rationale
282
284
  )
285
+
286
+ self._persist_step_causations(structure, est)
287
+
288
+ def _delete_prior_rationales(self, structure: Union[Cycle, Wheel]) -> None:
289
+ """Delete rationales explaining the structure (and its wheel edges)."""
290
+ from dialectical_framework.graph.repositories.node_repository import (
291
+ NodeRepository,
292
+ )
293
+
294
+ node_repo = NodeRepository()
295
+ targets: list = [structure]
296
+ if isinstance(structure, Wheel):
297
+ targets.extend(structure.edges)
298
+
299
+ for target in targets:
300
+ for old_rationale, _ in target.rationales.all():
301
+ self._report.node_deleted(old_rationale)
302
+ node_repo.delete_explanation_rationales(target)
303
+
304
+ def _persist_step_causations(
305
+ self, structure: Union[Cycle, Wheel], est: EstimationStructured
306
+ ) -> None:
307
+ """
308
+ Persist per-step causation rationales.
309
+
310
+ Wheel: each step attaches to the edge Transition matched by
311
+ (source hash, target hash) — never by index, since edge ordering
312
+ starts at an arbitrary edge. Cycle has no edge nodes, so steps
313
+ attach to the Cycle itself with a statement-text header; the same
314
+ header fallback applies to wheel steps that match no edge.
315
+ """
316
+ if not est.steps:
317
+ return
318
+
319
+ edge_by_hashes: dict[tuple[str, str], object] = {}
320
+ if isinstance(structure, Wheel):
321
+ for edge in structure.edges:
322
+ source_result = edge.source.get()
323
+ target_result = edge.target.get()
324
+ if source_result and target_result:
325
+ key = (source_result[0].hash, target_result[0].hash)
326
+ edge_by_hashes[key] = edge
327
+
328
+ for step in est.steps:
329
+ if not step.causation:
330
+ continue
331
+ edge = edge_by_hashes.get((step.source_hash, step.target_hash))
332
+ if edge is not None:
333
+ # The edge Transition itself identifies source/target
334
+ rationale = Rationale(text=step.causation)
335
+ rationale.set_explanation_target(edge)
336
+ else:
337
+ # No anchor node — the header makes the step self-describing
338
+ rationale = Rationale(
339
+ text=f"**{step.source_text} → {step.target_text}**\n{step.causation}"
340
+ )
341
+ rationale.set_explanation_target(structure)
342
+ rationale.commit()
343
+ self._report.node_created(rationale)
@@ -261,17 +261,21 @@ class SynthesisGeneration(ReasonableConcern[Optional[SynthesisResult]], Settings
261
261
  source_label = "?"
262
262
  target_label = "?"
263
263
 
264
+ # Alias + statement text: aliases alone are wheel-relative and would be
265
+ # the LLM's only grounding — self-describing labels prevent alias leaks
264
266
  if source_segment:
265
267
  core = source_segment.t.get()
266
268
  if core:
267
269
  stmt, rel = core
268
- source_label = rel.alias if hasattr(rel, "alias") else stmt.text
270
+ alias = getattr(rel, "alias", None)
271
+ source_label = f"{alias} ({stmt.text})" if alias else stmt.text
269
272
 
270
273
  if target_segment:
271
274
  core = target_segment.t.get()
272
275
  if core:
273
276
  stmt, rel = core
274
- target_label = rel.alias if hasattr(rel, "alias") else stmt.text
277
+ alias = getattr(rel, "alias", None)
278
+ target_label = f"{alias} ({stmt.text})" if alias else stmt.text
275
279
 
276
280
  return f"### Step {index}: {source_label} → {target_label}"
277
281
 
@@ -158,6 +158,7 @@ APEX
158
158
  5. **Ac+ must contradict Re-** (positive action opposes regression toward T-)
159
159
  6. Re- and Ac- typically have lower insight than the "+" aspects
160
160
  7. Statements are a fuller actionable form, longer than the headline
161
+ 8. In headline/statement/explanation prose, refer to concepts by their actual statement wording — never by T/A/T+/A-/Ac+/Re- notation. The notation is context-relative and meaningless to anyone reading the stored text later.
161
162
 
162
163
  ## Example (1-PP: T = Love, A = Indifference)
163
164
 
@@ -134,3 +134,44 @@ class NodeRepository:
134
134
  if node_type is not None and not isinstance(node, node_type):
135
135
  raise TypeError(f"Expected {node_type.__name__}, got {type(node).__name__}")
136
136
  return node
137
+
138
+ @inject
139
+ def delete_explanation_rationales(
140
+ self,
141
+ node: BaseNode,
142
+ sid: Optional[str] = Provide[DI.sid],
143
+ graph_db: Union[Memgraph, Neo4j] = Provide[DI.graph_db],
144
+ ) -> list[str]:
145
+ """
146
+ Delete all Rationales that EXPLAIN the given node (with their critiques).
147
+
148
+ Used to replace prior analytical explanations before persisting fresh
149
+ ones (e.g. re-estimation of causality). Critique rationales attached
150
+ to the deleted rationales are removed as well.
151
+
152
+ Args:
153
+ node: The explained node (must be saved and in current scope)
154
+ sid: Case ID (injected from DI context)
155
+
156
+ Returns:
157
+ Hashes of the deleted Rationale nodes (for event emission)
158
+ """
159
+ if node._id is None:
160
+ return []
161
+
162
+ # Validate node belongs to current scope
163
+ if sid and node.sid != sid:
164
+ return []
165
+
166
+ query = """
167
+ MATCH (rat:Rationale)-[:EXPLAINS]->(n)
168
+ WHERE id(n) = $node_id
169
+ OPTIONAL MATCH (crit:Rationale)-[:CRITIQUES]->(rat)
170
+ WITH collect(DISTINCT rat) + collect(DISTINCT crit) AS to_delete
171
+ UNWIND to_delete AS r
172
+ WITH DISTINCT r, r.hash AS rat_hash
173
+ DETACH DELETE r
174
+ RETURN rat_hash
175
+ """
176
+ results = list(graph_db.execute_and_fetch(query, {"node_id": node._id}))
177
+ return [r["rat_hash"] for r in results if r["rat_hash"] is not None]
@@ -24,14 +24,15 @@ def dc_replace(text: str, alias: str, replace_to: str) -> str:
24
24
  - `(?<!\\w)`: Not preceded by word character (prevents "AT-" matching)
25
25
  - `(["'([{]?)`: Optional opening bracket/quote (captured)
26
26
  - `<alias>`: The literal alias (escaped)
27
- - `(\\s|[]'"}).,!?:]|$)`: Followed by space, punctuation, or end (captured)
27
+ - `(\\s|[]'"});,.!?:/—-]|$)`: Followed by space, punctuation, or end (captured)
28
28
  """
29
29
  return re.sub(
30
30
  r'(?<!\w)(["\'\(\[\{]?)'
31
31
  rf"{re.escape(alias)}"
32
- r"(\s|[\]\'\"\)\},.!?:]|$)",
33
- # Replacement pattern (preserves surrounding characters and spaces)
34
- r"\1" rf"{replace_to}" r"\2",
32
+ r"(\s|[\]\'\"\)\};,.!?:/—-]|$)",
33
+ # Function replacement: replace_to is arbitrary prose and must not be
34
+ # interpreted as a regex replacement template (backslashes, \1, etc.)
35
+ lambda m: m.group(1) + replace_to + m.group(2),
35
36
  text,
36
37
  flags=re.VERBOSE,
37
38
  )