dialectical-framework 2.0.2__tar.gz → 2.0.4__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 (229) hide show
  1. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/PKG-INFO +1 -1
  2. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/pyproject.toml +1 -1
  3. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/consultant/consultant.py +17 -25
  4. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/control_statements_check.py +16 -145
  5. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/synthesis_generation.py +14 -3
  6. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/tetrad_candidates.py +54 -63
  7. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/transformation_generation.py +13 -2
  8. dialectical_framework-2.0.4/src/dialectical_framework/concerns/transformation_sketch.py +366 -0
  9. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/view_sketch.py +8 -38
  10. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/edge_context.py +33 -0
  11. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/LICENSE +0 -0
  12. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/PATENTS +0 -0
  13. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/README.md +0 -0
  14. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/__init__.py +0 -0
  15. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/__init__.py +0 -0
  16. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/__init__.py +0 -0
  17. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/advisor.py +0 -0
  18. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/build_policy.py +0 -0
  19. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/migration.py +0 -0
  20. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/reply_hygiene.py +0 -0
  21. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/system_prompts.py +0 -0
  22. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/tools/__init__.py +0 -0
  23. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/tools/anchor.py +0 -0
  24. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/tools/deepen.py +0 -0
  25. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/tools/explore.py +0 -0
  26. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/tools/ingest.py +0 -0
  27. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/tools/note.py +0 -0
  28. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/tools/record_decision.py +0 -0
  29. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/tools/scoped.py +0 -0
  30. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/advisor/tools/sync.py +0 -0
  31. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/agent_context.py +0 -0
  32. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/analyst/__init__.py +0 -0
  33. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/analyst/analyst.py +0 -0
  34. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/analyst/skills/__init__.py +0 -0
  35. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/analyst/skills/anchor_theses.py +0 -0
  36. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/analyst/skills/edit_perspective.py +0 -0
  37. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/analyst/skills/expand_polarities.py +0 -0
  38. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/analyst/skills/find_polarities.py +0 -0
  39. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/analyst/skills/introduce_polarity.py +0 -0
  40. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/analyst/skills/sketch_tetrad.py +0 -0
  41. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/analyst/skills/surface_theses.py +0 -0
  42. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/analyst/system_prompts.py +0 -0
  43. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/analyst/tools/__init__.py +0 -0
  44. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/analyst/tools/place_statement.py +0 -0
  45. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/app_spec.py +0 -0
  46. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/apps.py +0 -0
  47. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/consultant/__init__.py +0 -0
  48. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/conversation_facilitator.py +0 -0
  49. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/execution_report.py +0 -0
  50. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/explorer/__init__.py +0 -0
  51. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/explorer/explorer.py +0 -0
  52. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/explorer/skills/__init__.py +0 -0
  53. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/explorer/skills/build_wheels.py +0 -0
  54. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/explorer/skills/explore_transformations.py +0 -0
  55. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/explorer/skills/generate_synthesis.py +0 -0
  56. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/explorer/system_prompts.py +0 -0
  57. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/explorer/tools/__init__.py +0 -0
  58. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/explorer/tools/create_nexus.py +0 -0
  59. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/explorer/tools/expand_nexus.py +0 -0
  60. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/explorer/tools/generate_synthesis.py +0 -0
  61. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/explorer/tools/present_exploration.py +0 -0
  62. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/orchestrator/__init__.py +0 -0
  63. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/orchestrator/tools/__init__.py +0 -0
  64. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/orchestrator/tools/add_input.py +0 -0
  65. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/orchestrator/tools/audit_feasibility.py +0 -0
  66. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/orchestrator/tools/create_dx_input.py +0 -0
  67. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/orchestrator/tools/digest_input.py +0 -0
  68. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/orchestrator/tools/discard.py +0 -0
  69. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/orchestrator/tools/get_schema.py +0 -0
  70. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/orchestrator/tools/inspect_node.py +0 -0
  71. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/orchestrator/tools/present_analysis.py +0 -0
  72. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/orchestrator/tools/query_graph.py +0 -0
  73. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/orchestrator/tools/read_digest.py +0 -0
  74. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/orchestrator/tools/read_input.py +0 -0
  75. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/reasonable_concern.py +0 -0
  76. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/stream_events.py +0 -0
  77. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/toolsets.py +0 -0
  78. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/agents/turn_timing.py +0 -0
  79. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/__init__.py +0 -0
  80. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/ac_re_taxonomy.py +0 -0
  81. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/action_extraction.py +0 -0
  82. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/add_input.py +0 -0
  83. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/ai_dto/__init__.py +0 -0
  84. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/ai_dto/statement_dto.py +0 -0
  85. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/ai_dto/statements_deck_dto.py +0 -0
  86. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/antithesis_classification.py +0 -0
  87. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/antithesis_extraction.py +0 -0
  88. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/antithetical_thesis_detection.py +0 -0
  89. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/aspect_classification.py +0 -0
  90. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/aspect_generation.py +0 -0
  91. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/build_status.py +0 -0
  92. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/causality/__init__.py +0 -0
  93. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/causality/causality_estimator.py +0 -0
  94. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/causality/causality_estimator_balanced.py +0 -0
  95. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/causality/causality_estimator_criteria.py +0 -0
  96. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/causality/causality_estimator_desirable.py +0 -0
  97. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/causality/causality_estimator_feasible.py +0 -0
  98. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/causality/causality_estimator_realistic.py +0 -0
  99. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/causality/causality_normalizer.py +0 -0
  100. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/causality/estimator_resolver.py +0 -0
  101. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/causality_estimation.py +0 -0
  102. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/create_dx_input.py +0 -0
  103. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/create_nexus.py +0 -0
  104. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/decision_coherence_check.py +0 -0
  105. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/decision_confirmation_check.py +0 -0
  106. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/diagonal_oppositions_check.py +0 -0
  107. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/dialectical_context.py +0 -0
  108. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/discard.py +0 -0
  109. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/display_text_edit.py +0 -0
  110. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/expand_nexus.py +0 -0
  111. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/perspective_combination.py +0 -0
  112. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/perspective_validation.py +0 -0
  113. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/positive_ac_re_apex_derivation.py +0 -0
  114. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/record_decision.py +0 -0
  115. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/scoring_scales.py +0 -0
  116. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/source_digest.py +0 -0
  117. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/statement_classification.py +0 -0
  118. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/statement_deduplication.py +0 -0
  119. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/statement_headline.py +0 -0
  120. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/statement_placement.py +0 -0
  121. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/tetrad_grounding.py +0 -0
  122. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/tetrad_sketch.py +0 -0
  123. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/thesis_extraction.py +0 -0
  124. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/concerns/transformation_audit.py +0 -0
  125. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/dialectical_reasoning.py +0 -0
  126. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/enums/__init__.py +0 -0
  127. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/enums/causality_preset.py +0 -0
  128. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/enums/di.py +0 -0
  129. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/events/__init__.py +0 -0
  130. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/events/graph_event.py +0 -0
  131. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/events/graph_event_bus.py +0 -0
  132. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/events/progress_event.py +0 -0
  133. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/exceptions/__init__.py +0 -0
  134. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/exceptions/node_errors.py +0 -0
  135. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/exceptions/resolver_errors.py +0 -0
  136. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/__init__.py +0 -0
  137. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/composite_input_resolver.py +0 -0
  138. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/dialexity_input_resolver.py +0 -0
  139. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/estimation_manager.py +0 -0
  140. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/mixins/__init__.py +0 -0
  141. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/mixins/incremental_build_mixin.py +0 -0
  142. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/mixins/intent_mixin.py +0 -0
  143. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/mixins/persistable_mixin.py +0 -0
  144. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/__init__.py +0 -0
  145. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/assessable_entity.py +0 -0
  146. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/base_node.py +0 -0
  147. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/case.py +0 -0
  148. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/cycle.py +0 -0
  149. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/decision.py +0 -0
  150. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/estimation.py +0 -0
  151. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/ideas.py +0 -0
  152. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/input.py +0 -0
  153. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/nexus.py +0 -0
  154. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/note.py +0 -0
  155. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/perspective.py +0 -0
  156. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/polarity.py +0 -0
  157. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/rationale.py +0 -0
  158. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/statement.py +0 -0
  159. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/synthesis.py +0 -0
  160. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/transformation.py +0 -0
  161. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/transition.py +0 -0
  162. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/nodes/wheel.py +0 -0
  163. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationship_manager.py +0 -0
  164. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/__init__.py +0 -0
  165. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/action_reflection_relationship.py +0 -0
  166. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/belongs_to_cycle_relationship.py +0 -0
  167. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/belongs_to_nexus_relationship.py +0 -0
  168. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/changed_to_relationship.py +0 -0
  169. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/contradiction_of_relationship.py +0 -0
  170. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/critiques_relationship.py +0 -0
  171. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/distilled_to_relationship.py +0 -0
  172. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/estimates_relationship.py +0 -0
  173. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/explains_relationship.py +0 -0
  174. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/grounded_in_relationship.py +0 -0
  175. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/has_input_relationship.py +0 -0
  176. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/has_statement_relationship.py +0 -0
  177. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/has_wheel_relationship.py +0 -0
  178. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/immutable_structure.py +0 -0
  179. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/is_source_of_relationship.py +0 -0
  180. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/is_target_of_relationship.py +0 -0
  181. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/negative_side_of_relationship.py +0 -0
  182. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/opposite_direction_relationship.py +0 -0
  183. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/opposite_of_relationship.py +0 -0
  184. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/polarity_relationship.py +0 -0
  185. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/positive_side_of_relationship.py +0 -0
  186. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/provides_relationship.py +0 -0
  187. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/relationships/synthesis_of_relationship.py +0 -0
  188. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/rendering.py +0 -0
  189. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/__init__.py +0 -0
  190. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/case_repository.py +0 -0
  191. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/cycle_repository.py +0 -0
  192. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/decision_repository.py +0 -0
  193. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/input_repository.py +0 -0
  194. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/nexus_repository.py +0 -0
  195. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/node_repository.py +0 -0
  196. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/note_repository.py +0 -0
  197. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/perspective_repository.py +0 -0
  198. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/polarity_repository.py +0 -0
  199. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/schema_repository.py +0 -0
  200. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/statement_repository.py +0 -0
  201. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/transformation_repository.py +0 -0
  202. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/repositories/wheel_repository.py +0 -0
  203. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/scope_context.py +0 -0
  204. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/verbatim_input_resolver.py +0 -0
  205. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/views.py +0 -0
  206. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/wheel_segment.py +0 -0
  207. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/graph/wheel_segment_polar_pair.py +0 -0
  208. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/protocols/__init__.py +0 -0
  209. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/protocols/has_config.py +0 -0
  210. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/protocols/input_resolver.py +0 -0
  211. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/py.typed +0 -0
  212. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/settings.py +0 -0
  213. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/__init__.py +0 -0
  214. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/async_drain.py +0 -0
  215. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/bedrock_provider.py +0 -0
  216. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/call_census.py +0 -0
  217. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/chunking.py +0 -0
  218. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/concurrency.py +0 -0
  219. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/dc_replace.py +0 -0
  220. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/decompose_probability_uniformly.py +0 -0
  221. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/effect_logger.py +0 -0
  222. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/input_context.py +0 -0
  223. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/order_transitions.py +0 -0
  224. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/progress.py +0 -0
  225. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/retry_accounting.py +0 -0
  226. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/sequence_generation.py +0 -0
  227. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/thinking_compat.py +0 -0
  228. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/use_brain.py +0 -0
  229. {dialectical_framework-2.0.2 → dialectical_framework-2.0.4}/src/dialectical_framework/utils/utterance.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dialectical-framework
3
- Version: 2.0.2
3
+ Version: 2.0.4
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 = "2.0.2"
3
+ version = "2.0.4"
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"
@@ -324,12 +324,7 @@ class Consultant:
324
324
  if messages:
325
325
  self._conversation.load_messages(messages)
326
326
  parts = [p for p in (preamble, method_prompt(include_decision)) if p]
327
- # Kept because the view turn's system prompt is this text plus the
328
- # static half of its request (`exploration_view`): appending keeps the
329
- # head a PREFIX of it, so the chat turns' cached prefix is readable by
330
- # the sketch turns instead of each paying for its own.
331
- self._system_prompt = "\n\n".join(parts)
332
- self._conversation.set_system_prompt(self._system_prompt)
327
+ self._conversation.set_system_prompt("\n\n".join(parts))
333
328
 
334
329
  async def chat(self, user_message: str) -> str:
335
330
  result = await self._conversation.submit(ChatResponse, user_message)
@@ -367,8 +362,7 @@ class Consultant:
367
362
  view shows what has been ESTABLISHED, and where `focus` asks for
368
363
  structure not yet worked out ("a perspective for the thesis you
369
364
  named") the turn builds it by the method first
370
- (`concerns/view_sketch.py`: the static instructions ride on the system
371
- prompt, the focus is the turn). What it built is
365
+ (`concerns/view_sketch.py::view_sketch_prompt`). What it built is
372
366
  kept in `messages` as the consultant's own words, so the next turn can
373
367
  be asked about a corner it just drew.
374
368
 
@@ -386,8 +380,7 @@ class Consultant:
386
380
  """
387
381
  from dialectical_framework.concerns.view_sketch import (
388
382
  ViewSketchDto, exploration_view_from_sketch, history_ask,
389
- history_text, perspective_from_sketch, view_sketch_focus,
390
- view_sketch_instructions)
383
+ history_text, perspective_from_sketch, view_sketch_prompt)
391
384
 
392
385
  import asyncio
393
386
  import dataclasses
@@ -397,19 +390,19 @@ class Consultant:
397
390
 
398
391
  level = self._conversation._thinking_kwargs().get("thinking")
399
392
  history = self._conversation._messages
400
- # The request travels in two places, not one. Its static half
401
- # (definitions, rules, the build procedure) goes on the SYSTEM prompt,
402
- # after this head's own, because that is where the provider's cache
403
- # breakpoint sits: as part of the user message it followed the history
404
- # and was re-prefilled at full rate on every draw (~1.2k tokens x N a
405
- # card, measured 2026-10-06). Only the focus — the person's own ask —
406
- # is the turn. Same words, and the history record is untouched
407
- # (`history_ask`, which is why the long request was never kept anyway).
408
- system = (
409
- f"{self._system_prompt}\n\n"
410
- f"{view_sketch_instructions(self._conversation.settings.component_length)}"
411
- )
412
- ask = view_sketch_focus(focus)
393
+ # The WHOLE request is the turn's user message, its "Answer with ONE
394
+ # JSON object" included — by measurement, not habit. For one day
395
+ # (2026-10-06) the static instructions rode on the system prompt so the
396
+ # cache would cover them (~$0.007 a card) and only "What to show: ..."
397
+ # was the turn. First cards did not notice; a RETRY did: its history
398
+ # already holds "Show me: ..." and the previous drawing in PROSE, and with
399
+ # a bare focus as the last user turn the model answered in prose too —
400
+ # 1.75 parse retries a retry card, 4.75 view-turn calls instead of 3,
401
+ # 33 s instead of 20 (`tests/e2e/probe_view_turn_retry_calls.py`, 8
402
+ # utterances; the first app had measured the same 4.6 calls and +17 s).
403
+ # The request->prose pair `history_ask` keeps OUT of the history is the
404
+ # same trap; the long request as the last turn is what holds the format.
405
+ request = view_sketch_prompt(focus, self._conversation.settings.component_length)
413
406
 
414
407
  async def draw() -> ViewSketchDto:
415
408
  # Each draw works on a COPY of the history: the turns run in
@@ -417,8 +410,7 @@ class Consultant:
417
410
  # read. What the view leaves behind is appended once, below.
418
411
  sketch_turn = ConversationFacilitator(format_mode="json", thinking=level)
419
412
  sketch_turn._messages = list(history)
420
- sketch_turn.set_system_prompt(system)
421
- return await sketch_turn.submit(ViewSketchDto, ask)
413
+ return await sketch_turn.submit(ViewSketchDto, request)
422
414
 
423
415
  n = clamp_attempts(attempts)
424
416
  # Fully parallel, deliberately. On a COLD cache all N draws write the
@@ -32,7 +32,7 @@ from __future__ import annotations
32
32
 
33
33
  import asyncio
34
34
  from dataclasses import dataclass
35
- from typing import TYPE_CHECKING, Optional, Sequence
35
+ from typing import TYPE_CHECKING
36
36
 
37
37
  from pydantic import BaseModel, Field
38
38
 
@@ -97,74 +97,15 @@ class CoherenceEvaluationDto(BaseModel):
97
97
  )
98
98
 
99
99
 
100
- class TetradCoherenceDto(BaseModel):
101
- """One tetrad's two control statements, from the JOINT call.
102
-
103
- No DV field, deliberately. DV is an annotation that only `resolve`
104
- persists (`DialecticalValidityEstimation`) and nothing reads it when
105
- choosing among drafts — `SketchVerdict` has no DV term — so asking for it
106
- here would buy output tokens and nothing else. A draft that goes on to be
107
- persisted is scored by `resolve` afterwards, DV and all.
108
- """
109
-
110
- tetrad: int = Field(
111
- description=(
112
- "The number of the tetrad this verdict scores, exactly as labelled "
113
- "in the request."
114
- )
115
- )
116
- t_plus_without_a_plus_yields_t_minus: float = Field(
117
- ge=0.0,
118
- le=1.0,
119
- description="Conceptual Coherence (0.0-1.0) of that tetrad's statement (a).",
120
- )
121
- a_plus_without_t_plus_yields_a_minus: float = Field(
122
- ge=0.0,
123
- le=1.0,
124
- description="Conceptual Coherence (0.0-1.0) of that tetrad's statement (b).",
125
- )
126
- reasoning: str = Field(
127
- description=(
128
- "One sentence on the weaker of that tetrad's two statements. A note, "
129
- "not an essay."
130
- )
131
- )
132
-
133
-
134
- class JointCoherenceEvaluationDto(BaseModel):
135
- """Every tetrad of one request, scored in one call."""
136
-
137
- verdicts: list[TetradCoherenceDto] = Field(
138
- description=(
139
- "One entry per tetrad in the request, in the request's order. Score "
140
- "every tetrad; omit none."
141
- )
142
- )
143
-
144
-
145
- @dataclass(frozen=True)
146
- class TetradTexts:
147
- """The four aspect texts of one tetrad — all the control statements need.
148
-
149
- What `score_texts_many` takes, so a caller holding several drafts as text
150
- cannot mix up the order of four positional strings.
151
- """
152
-
153
- t_plus: str
154
- t_minus: str
155
- a_plus: str
156
- a_minus: str
157
-
158
-
159
100
  def control_statements(
160
101
  *, t_plus: str, t_minus: str, a_plus: str, a_minus: str
161
102
  ) -> tuple[str, str]:
162
103
  """The paper's two control statements, built from four texts.
163
104
 
164
- One builder for all three askers (`resolve` off a committed Perspective,
165
- `score_texts` and `score_texts_many` off bare texts) so the quoting cannot
166
- drift: a verdict taken before persistence and one taken after must be the
167
- same question asked of the same words.
105
+ One builder for both askers (`resolve` off a committed Perspective,
106
+ `score_texts` off bare texts) so the quoting cannot drift: a verdict taken
107
+ before persistence and one taken after must be the same question asked of
108
+ the same words.
168
109
  """
169
110
  return (
170
111
  f'"{t_plus}" without "{a_plus}" yields "{t_minus}"',
@@ -172,13 +113,12 @@ def control_statements(
172
113
  )
173
114
 
174
115
 
175
- # --- Shared prompt text ---
116
+ # --- Prompt text ---
176
117
  #
177
- # Written once because two prompts ask for it: one statement at a time
178
- # (`_evaluate_control_statement`, for `resolve` and `score_texts`) and all of
179
- # several tetrads at once (`score_texts_many`). Re-typed inline the scales
180
- # would drift, and a verdict from one prompt is ranked against a verdict from
181
- # the other (`concerns/tetrad_candidates.py`).
118
+ # The pattern and the two scales of `_evaluate_control_statement`, as constants
119
+ # so a probe can put the SAME scales in front of a candidate judge
120
+ # (`tests/e2e/probe_joint_judge_stability.py` did, 2026-10-06, and rejected two
121
+ # cheaper shapes against this one).
182
122
 
183
123
  _PATTERN = """The pattern "[Positive] without [Balancing factor] yields [Negative]" tests whether
184
124
  the absence of a balancing positive aspect naturally leads to the negative/shadow aspect."""
@@ -372,14 +312,12 @@ class ControlStatementsCheck(ReasonableConcern[ControlStatementsCheckResult]):
372
312
  """The two control statements on bare texts — no Perspective, no graph.
373
313
 
374
314
  What `resolve` does after reading the four aspects off a committed
375
- node, for a caller holding ONE tetrad as text and wanting DV with it.
376
- Built by the same statement builder as `resolve`, so a verdict here is
377
- the same question as the one asked after persistence.
378
-
379
- Not what best-of-N selection uses: a field of drafts goes through
380
- `score_texts_many`, which asks once for all of them and leaves DV out
381
- (nothing in selection reads it). Two statements, two calls, both with
382
- reasoning, is the shape that made judging a third of a card's cost.
315
+ node, offered to callers that hold a tetrad as text: the best-of-N
316
+ selector (`concerns/tetrad_candidates.py`) and the harness. Built by
317
+ the same statement builder and asked with the same prompt as `resolve`,
318
+ so a verdict here is the same question as the one asked after
319
+ persistence. Two calls per tetrad is the cost of that: the cheaper
320
+ shapes measured against it disagreed (`tetrad_candidates.judge_sketches`).
383
321
  """
384
322
  stmt_1, stmt_2 = control_statements(
385
323
  t_plus=t_plus, t_minus=t_minus, a_plus=a_plus, a_minus=a_minus
@@ -389,73 +327,6 @@ class ControlStatementsCheck(ReasonableConcern[ControlStatementsCheckResult]):
389
327
  self._evaluate_control_statement(stmt_2, text),
390
328
  )
391
329
 
392
- async def score_texts_many(
393
- self,
394
- tetrads: Sequence[TetradTexts],
395
- *,
396
- text: str = "",
397
- ) -> list[Optional[TetradCoherenceDto]]:
398
- """Several tetrads' control statements, all in ONE call.
399
-
400
- What `score_texts` asks for one draft at a time, asked for a whole
401
- best-of-N field at once. Measured reason (2026-10-06, the first app's
402
- real entry points through `utils/call_census.py`): per-statement calls
403
- made judging 6 of the 11 provider calls behind one card and ~3.3k of
404
- its ~5.1k output tokens — about a third of the card's cost — because
405
- each call spent ~550 output tokens of reasoning on one sentence. One
406
- call with a short note per tetrad replaces six.
407
-
408
- The question is unchanged and so is its discipline: the judge sees
409
- only each tetrad's four aspects (never the thesis or antithesis, see
410
- `concerns/tetrad_candidates.py`), the statements are built by the same
411
- builder `resolve` uses, and the prompt forbids comparing the drafts —
412
- selection stays among independent draws. CC only; `TetradCoherenceDto`
413
- says why DV is not asked for here.
414
-
415
- Fail-soft per tetrad: a verdict the model omits, or labels with a
416
- number that is out of range or already filled, comes back `None` for
417
- that tetrad rather than shifting every later one onto the wrong draft.
418
- """
419
- if not tetrads:
420
- return []
421
-
422
- blocks = []
423
- for n, tetrad in enumerate(tetrads, 1):
424
- stmt_a, stmt_b = control_statements(
425
- t_plus=tetrad.t_plus,
426
- t_minus=tetrad.t_minus,
427
- a_plus=tetrad.a_plus,
428
- a_minus=tetrad.a_minus,
429
- )
430
- blocks.append(f"Tetrad {n}:\n(a) {stmt_a}\n(b) {stmt_b}")
431
-
432
- context_section = f"<context>\n{text}\n</context>\n\n" if text else ""
433
- joined = "\n\n".join(blocks)
434
- prompt = f"""{context_section}Rate the control statements of {len(tetrads)} tetrads. Each tetrad has two statements, (a) and (b).
435
-
436
- {joined}
437
-
438
- {_PATTERN}
439
-
440
- Rate every statement on one scale:
441
-
442
- {_CC_SCALE}
443
-
444
- Score each tetrad on its own, against the pattern above and nothing else. These are independent drafts: do not compare them with each other, do not rank them, do not pick a best, and do not let one tetrad's wording move another's score. The order they appear in carries no information. Return one verdict per tetrad, labelled with that tetrad's number."""
445
-
446
- conversation = ConversationFacilitator()
447
- result = await conversation.submit(
448
- response_model=JointCoherenceEvaluationDto,
449
- user_content=prompt,
450
- )
451
-
452
- placed: list[Optional[TetradCoherenceDto]] = [None] * len(tetrads)
453
- for verdict in result.verdicts:
454
- index = verdict.tetrad - 1
455
- if 0 <= index < len(placed) and placed[index] is None:
456
- placed[index] = verdict
457
- return placed
458
-
459
330
  async def _evaluate_control_statement(
460
331
  self,
461
332
  statement: str,
@@ -30,6 +30,8 @@ from dialectical_framework.agents.conversation_facilitator import (
30
30
  ConversationFacilitator,
31
31
  )
32
32
  from dialectical_framework.agents.reasonable_concern import ReasonableConcern
33
+ from dialectical_framework.concerns.transformation_sketch import (
34
+ SYNTHESIS_SHAPE, TRANSFORMATION_POSITIONS)
33
35
  from dialectical_framework.graph.nodes.statement import Statement
34
36
  from dialectical_framework.protocols.has_config import SettingsAware
35
37
 
@@ -39,7 +41,12 @@ if TYPE_CHECKING:
39
41
  from dialectical_framework.graph.nodes.wheel import Wheel
40
42
 
41
43
 
42
- SYSTEM_PROMPT = """You are an expert in dialectical synthesis — the emergent properties arising from circular causality loops.
44
+ #: "The shape of the inputs" is the framework's ONE statement of the
45
+ #: Transformation (`transformation_sketch.TRANSFORMATION_POSITIONS`) and of S±
46
+ #: (`SYNTHESIS_SHAPE`), not a copy: this prompt reads graph-built
47
+ #: Transformations and the one-shot writes them, and the two must not define
48
+ #: Ac-/Re- differently (2026-10-06 — this paragraph had dropped where Ac- GOES).
49
+ SYSTEM_PROMPT = f"""You are an expert in dialectical synthesis — the emergent properties arising from circular causality loops.
43
50
 
44
51
  ## What Synthesis IS
45
52
 
@@ -57,7 +64,7 @@ S+ produces new qualitative dimensions — it increases a system's capacity for
57
64
  ## S- (Negative Synthesis): Collapse Pattern (1+1<2)
58
65
 
59
66
  S- emerges when the failure modes (Ac- and Re-) reinforce each other:
60
- - Acting without reflecting yields Ac- (the action's own drift); reflecting without acting yields Re- (the reflection's own regression)
67
+ - Ac+ without Re+ yields Ac- (the action's own drift, which carries T+ into A-); Re+ without Ac+ yields Re- (the reflection's own regression, which carries A+ into T-)
61
68
  - Together these create downward spirals — dominance of one pole, or unstable oscillation between them
62
69
  - Diversity is reduced and qualitative growth is replaced by quantitative amplification
63
70
 
@@ -65,7 +72,11 @@ S- manifests as imitation rather than transformation: external forms, metrics, o
65
72
 
66
73
  ## The shape of the inputs, exactly
67
74
 
68
- Each Transformation is itself a tetrad: Ac (the action) and Re (the reflection) are its poles; Ac+/Ac- and Re+/Re- are their constructive and one-sided developments. So Ac- is the ACTION gone wrong and Re- is the REFLECTION gone wrong — they are not the segments' own traps (T-, A-) restated, and S- is not those traps either. S- is the ONE named state the degraded action and the degraded reflection produce together: a single way of failing that is neither trap on its own and not a choice between them. "Either X or Y", "X versus Y" and "X while Y" with X and Y the two traps are the inputs listed, not the collapse named. Likewise S+ is a gain in dimension the pathways produce together — not "both", not the two strengths listed side by side.
75
+ Each Transformation is itself a tetrad, built this way:
76
+
77
+ {TRANSFORMATION_POSITIONS}
78
+
79
+ {SYNTHESIS_SHAPE}
69
80
 
70
81
  ## Requirements
71
82
 
@@ -31,12 +31,13 @@ holding a text or an object with `.statement` (`TetradDto`'s `AspectDto`).
31
31
 
32
32
  from __future__ import annotations
33
33
 
34
+ import asyncio
34
35
  import logging
35
36
  from dataclasses import dataclass
36
37
  from typing import Any, Optional, Sequence
37
38
 
38
- from dialectical_framework.concerns.control_statements_check import (
39
- ControlStatementsCheck, TetradTexts)
39
+ from dialectical_framework.concerns.control_statements_check import \
40
+ ControlStatementsCheck
40
41
  from dialectical_framework.graph.nodes.estimation import \
41
42
  CONCEPTUAL_COHERENCE_THRESHOLD
42
43
 
@@ -108,78 +109,68 @@ def is_complete(candidate: Any) -> bool:
108
109
  async def judge_sketches(
109
110
  candidates: Sequence[Any], context: str = ""
110
111
  ) -> list[Optional[SketchVerdict]]:
111
- """The validator's two control statements for EVERY candidate, in ONE call.
112
+ """The validator's two control statements for every candidate, each draft
113
+ judged on its own, each statement in its own call (gathered).
112
114
 
113
115
  Statement texts are built by the same builder `ControlStatementsCheck.resolve`
114
- uses, so a verdict here and one taken after persistence are the same
115
- question asked of the same words. The judge still sees only the four
116
- aspects of each draft — never the thesis or the antithesis — and the
117
- prompt forbids comparing the drafts with each other, so selection stays
118
- "among independent draws" (this module's docstring) and this call cannot
119
- be turned into regeneration.
120
-
121
- Why one call: judging used to be a call per control statement per
122
- candidate — 6 of the 11 provider calls behind one best-of-3 card, and
123
- ~3.3k of its ~5.1k output tokens, about a third of its cost (measured
124
- 2026-10-06 on the first app's real entry points with
125
- `utils/call_census.py`). One call with a short note per tetrad replaces
126
- six long ones.
127
-
128
- Fail-soft twice over. A verdict the model omits is `None` for that
129
- candidate, which sorts last; a failed call leaves EVERY candidate
130
- unjudged, which keeps the first draw — exactly what `attempts=1` would
131
- have done. The second shape is new with the joint call and is the cost of
132
- it: per-statement calls could lose one candidate's verdict and keep the
133
- rest.
134
-
135
- OPEN, because this was a cost change and not a quality one. Judge
136
- stability was 92% on re-judging the same text when each statement had its
137
- own call (`docs/dev-notes/antithesis-selection.md`, "Best-of-N"); the
138
- joint call's stability, and its position bias (a candidate winning for
139
- being listed first), are unmeasured — measure both with the same probe,
140
- and the card quality with the app's paired eval, before reading any
141
- quality claim into this. If stability falls below ~85%, the rung down is
142
- one call per candidate with both statements in one DTO, which is still
143
- half the output of the per-statement shape.
116
+ uses, and the prompt is the one `resolve` asks, so a verdict here and one
117
+ taken after persistence are the same question asked of the same words. The
118
+ judge sees only the four aspects of each draft, never the thesis or the
119
+ antithesis. Fail-soft per candidate: a judging that fails is `None` for
120
+ that draft alone, which sorts last.
121
+
122
+ Deliberately NOT cheaper, by measurement (2026-10-06,
123
+ `tests/e2e/probe_joint_judge_stability.py`, 40 stored triples). Judging is
124
+ the costliest part of a best-of-3 card (6 of its 11 calls, about a third of
125
+ its cost), and two cheaper shapes were tried and rejected:
126
+ - one call for the whole field: pass/fail agreement with the stored verdict
127
+ 70% against this judge's own 92% on the same drafts, the same winner
128
+ across a reversed order in 7/40, the first-listed draft winning 29/40;
129
+ it picked by position and ties;
130
+ - one call per draft with both statements in it (the same lean prompt):
131
+ 73% against 90%, the same winner as this judge in 23/40 — stable with
132
+ itself, but measuring something else;
133
+ - THIS prompt with each reasoning field capped at one short sentence
134
+ (the score is written before the reasoning, so the cap looked free):
135
+ output 534 -> 181 tokens a call, but 78% against 90%, scores +0.05, the
136
+ same winner as this judge in 29/40. The reasoning is not dead weight.
137
+ A cheaper judge has to be measured against this one on that probe first;
138
+ the owner closed the cost question at this point (2026-10-06).
144
139
  """
145
- try:
146
- verdicts = await ControlStatementsCheck().score_texts_many(
147
- [
148
- TetradTexts(
149
- t_plus=aspect_text(c.t_plus),
150
- t_minus=aspect_text(c.t_minus),
151
- a_plus=aspect_text(c.a_plus),
152
- a_minus=aspect_text(c.a_minus),
153
- )
154
- for c in candidates
155
- ],
156
- text=context,
157
- )
158
- except Exception as exc: # noqa: BLE001 — degrade to "all unjudged"
159
- logger.warning("Judging the sketches failed; the first draw is kept: %s", exc)
160
- return [None] * len(candidates)
161
- return [
162
- None
163
- if v is None
164
- else SketchVerdict(
165
- t_plus_without_a_plus=v.t_plus_without_a_plus_yields_t_minus,
166
- a_plus_without_t_plus=v.a_plus_without_t_plus_yields_a_minus,
167
- reasoning=v.reasoning,
168
- )
169
- for v in verdicts
170
- ]
140
+
141
+ async def one(tension: Any) -> Optional[SketchVerdict]:
142
+ # Reading the verdict is inside the `try` too: a malformed response
143
+ # is a failed judging (sorts last), never a failed selection.
144
+ try:
145
+ first, second = await ControlStatementsCheck().score_texts(
146
+ t_plus=aspect_text(tension.t_plus),
147
+ t_minus=aspect_text(tension.t_minus),
148
+ a_plus=aspect_text(tension.a_plus),
149
+ a_minus=aspect_text(tension.a_minus),
150
+ text=context,
151
+ )
152
+ return SketchVerdict(
153
+ t_plus_without_a_plus=first.coherence_score,
154
+ a_plus_without_t_plus=second.coherence_score,
155
+ reasoning=f"{first.reasoning} / {second.reasoning}".strip(" /"),
156
+ )
157
+ except Exception as exc: # noqa: BLE001 — degrade to "unjudged"
158
+ logger.warning("Judging a sketch failed; it sorts last: %s", exc)
159
+ return None
160
+
161
+ return list(await asyncio.gather(*(one(c) for c in candidates)))
171
162
 
172
163
 
173
164
  async def select_sketch(
174
165
  candidates: Sequence[Any], context: str = ""
175
166
  ) -> tuple[int, list[Optional[SketchVerdict]]]:
176
- """Judge every candidate (one call) and return the index of the best plus
177
- all verdicts (None where a verdict did not come back).
167
+ """Judge every candidate (gathered) and return the index of the best plus
168
+ all verdicts (None where judging failed).
178
169
 
179
170
  Ranking: the weaker control statement first (the pass rule), then the
180
171
  mean, then the earlier draw — a deterministic tie-break, not a preference.
181
- An unjudged candidate sorts last; if no verdict came back at all the first
182
- draw is kept, which is exactly what `attempts=1` would have done.
172
+ A candidate whose judging failed sorts last; if every judging failed the
173
+ first draw is kept, which is exactly what `attempts=1` would have done.
183
174
 
184
175
  ONE candidate is never judged: there is nothing to select among, so
185
176
  `attempts=1` costs no extra call.
@@ -248,7 +248,17 @@ class ReSideCompletionDto(BaseModel):
248
248
  description="Proactiveness category for Re+"
249
249
  )
250
250
 
251
- # Re- fields
251
+ # Re- fields. The weak position of the staged generator, measured
252
+ # 2026-10-06 (`tests/e2e/probe_staged_endpoints.py`, 102 Transformations on
253
+ # 17 one-tension wheels, read with the theory-faithful `TransitionVerdict`):
254
+ # Re- valid 49% against Ac- 70%, and it is the LANDING that fails (59%
255
+ # land in T-; 27% valid on T->A edges). The prompt asked for "the
256
+ # reflection without the action", which the writer read as "keep watching,
257
+ # do nothing" — and wherever A is the passive pole, doing nothing is A's
258
+ # trap, not T's. Two `re_minus_from` / `re_minus_into` fields ahead of these
259
+ # (the one-shot's fix) moved it within noise and were reverted; the
260
+ # landing is now named in `_generate_re_side`'s Re- instruction instead.
261
+ # See docs/dev-notes/one-shot-transformation.md.
252
262
  re_minus_headline: str = Field(description="Re- headline (component length)")
253
263
  re_minus_statement: str = Field(description="Re- statement (fuller than the headline)")
254
264
  re_minus_explanation: str = Field(
@@ -641,7 +651,8 @@ Given their action, what reflection does it trigger that leads to growth?
641
651
 
642
652
  What happens when their action IS taken in, but nothing you do grounds that reflection?
643
653
  - What Re+ ITSELF degenerates into when Ac+ is absent — an overextension of the reflection, not the absence of one
644
- - Path: the Reflection Perspective's positive regresses you toward your negative
654
+ - Where it LANDS is what makes it Re-: it ends in the A- line of <reflection_perspective> — YOUR OWN trap. It starts from that block's T+ line (the other side's strength); you need not name the start, but the landing must be your trap
655
+ - The common miss: "keep watching and do nothing". When the other side is the passive one, doing nothing just leaves THEIR trap in place (the block's T- line) — that is not Re-. Re- is your reflecting, overdone, carrying YOU into your own trap
645
656
  - NOT the same failure as Ac-: Ac- is your action left unreflected, Re- is your reflection left unacted
646
657
  - Your Ac+ must CONTRADICT Re- (your positive action opposes this regression)
647
658
  - Usually lower insight than Re+