dialectical-framework 2.0.1__tar.gz → 2.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/PKG-INFO +1 -1
  2. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/pyproject.toml +1 -1
  3. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/consultant/consultant.py +47 -11
  4. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/control_statements_check.py +58 -21
  5. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/synthesis_generation.py +14 -3
  6. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/tetrad_candidates.py +58 -27
  7. dialectical_framework-2.0.3/src/dialectical_framework/concerns/transformation_sketch.py +348 -0
  8. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/view_sketch.py +38 -8
  9. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/views.py +6 -0
  10. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/bedrock_provider.py +80 -5
  11. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/LICENSE +0 -0
  12. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/PATENTS +0 -0
  13. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/README.md +0 -0
  14. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/__init__.py +0 -0
  15. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/__init__.py +0 -0
  16. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/__init__.py +0 -0
  17. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/advisor.py +0 -0
  18. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/build_policy.py +0 -0
  19. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/migration.py +0 -0
  20. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/reply_hygiene.py +0 -0
  21. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/system_prompts.py +0 -0
  22. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/tools/__init__.py +0 -0
  23. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/tools/anchor.py +0 -0
  24. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/tools/deepen.py +0 -0
  25. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/tools/explore.py +0 -0
  26. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/tools/ingest.py +0 -0
  27. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/tools/note.py +0 -0
  28. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/tools/record_decision.py +0 -0
  29. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/tools/scoped.py +0 -0
  30. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/advisor/tools/sync.py +0 -0
  31. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/agent_context.py +0 -0
  32. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/analyst/__init__.py +0 -0
  33. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/analyst/analyst.py +0 -0
  34. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/analyst/skills/__init__.py +0 -0
  35. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/analyst/skills/anchor_theses.py +0 -0
  36. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/analyst/skills/edit_perspective.py +0 -0
  37. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/analyst/skills/expand_polarities.py +0 -0
  38. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/analyst/skills/find_polarities.py +0 -0
  39. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/analyst/skills/introduce_polarity.py +0 -0
  40. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/analyst/skills/sketch_tetrad.py +0 -0
  41. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/analyst/skills/surface_theses.py +0 -0
  42. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/analyst/system_prompts.py +0 -0
  43. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/analyst/tools/__init__.py +0 -0
  44. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/analyst/tools/place_statement.py +0 -0
  45. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/app_spec.py +0 -0
  46. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/apps.py +0 -0
  47. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/consultant/__init__.py +0 -0
  48. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/conversation_facilitator.py +0 -0
  49. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/execution_report.py +0 -0
  50. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/explorer/__init__.py +0 -0
  51. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/explorer/explorer.py +0 -0
  52. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/explorer/skills/__init__.py +0 -0
  53. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/explorer/skills/build_wheels.py +0 -0
  54. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/explorer/skills/explore_transformations.py +0 -0
  55. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/explorer/skills/generate_synthesis.py +0 -0
  56. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/explorer/system_prompts.py +0 -0
  57. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/explorer/tools/__init__.py +0 -0
  58. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/explorer/tools/create_nexus.py +0 -0
  59. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/explorer/tools/expand_nexus.py +0 -0
  60. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/explorer/tools/generate_synthesis.py +0 -0
  61. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/explorer/tools/present_exploration.py +0 -0
  62. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/orchestrator/__init__.py +0 -0
  63. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/orchestrator/tools/__init__.py +0 -0
  64. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/orchestrator/tools/add_input.py +0 -0
  65. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/orchestrator/tools/audit_feasibility.py +0 -0
  66. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/orchestrator/tools/create_dx_input.py +0 -0
  67. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/orchestrator/tools/digest_input.py +0 -0
  68. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/orchestrator/tools/discard.py +0 -0
  69. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/orchestrator/tools/get_schema.py +0 -0
  70. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/orchestrator/tools/inspect_node.py +0 -0
  71. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/orchestrator/tools/present_analysis.py +0 -0
  72. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/orchestrator/tools/query_graph.py +0 -0
  73. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/orchestrator/tools/read_digest.py +0 -0
  74. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/orchestrator/tools/read_input.py +0 -0
  75. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/reasonable_concern.py +0 -0
  76. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/stream_events.py +0 -0
  77. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/toolsets.py +0 -0
  78. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/agents/turn_timing.py +0 -0
  79. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/__init__.py +0 -0
  80. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/ac_re_taxonomy.py +0 -0
  81. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/action_extraction.py +0 -0
  82. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/add_input.py +0 -0
  83. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/ai_dto/__init__.py +0 -0
  84. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/ai_dto/statement_dto.py +0 -0
  85. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/ai_dto/statements_deck_dto.py +0 -0
  86. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/antithesis_classification.py +0 -0
  87. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/antithesis_extraction.py +0 -0
  88. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/antithetical_thesis_detection.py +0 -0
  89. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/aspect_classification.py +0 -0
  90. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/aspect_generation.py +0 -0
  91. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/build_status.py +0 -0
  92. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/causality/__init__.py +0 -0
  93. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/causality/causality_estimator.py +0 -0
  94. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/causality/causality_estimator_balanced.py +0 -0
  95. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/causality/causality_estimator_criteria.py +0 -0
  96. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/causality/causality_estimator_desirable.py +0 -0
  97. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/causality/causality_estimator_feasible.py +0 -0
  98. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/causality/causality_estimator_realistic.py +0 -0
  99. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/causality/causality_normalizer.py +0 -0
  100. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/causality/estimator_resolver.py +0 -0
  101. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/causality_estimation.py +0 -0
  102. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/create_dx_input.py +0 -0
  103. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/create_nexus.py +0 -0
  104. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/decision_coherence_check.py +0 -0
  105. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/decision_confirmation_check.py +0 -0
  106. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/diagonal_oppositions_check.py +0 -0
  107. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/dialectical_context.py +0 -0
  108. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/discard.py +0 -0
  109. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/display_text_edit.py +0 -0
  110. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/expand_nexus.py +0 -0
  111. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/perspective_combination.py +0 -0
  112. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/perspective_validation.py +0 -0
  113. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/positive_ac_re_apex_derivation.py +0 -0
  114. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/record_decision.py +0 -0
  115. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/scoring_scales.py +0 -0
  116. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/source_digest.py +0 -0
  117. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/statement_classification.py +0 -0
  118. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/statement_deduplication.py +0 -0
  119. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/statement_headline.py +0 -0
  120. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/statement_placement.py +0 -0
  121. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/tetrad_grounding.py +0 -0
  122. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/tetrad_sketch.py +0 -0
  123. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/thesis_extraction.py +0 -0
  124. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/transformation_audit.py +0 -0
  125. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/concerns/transformation_generation.py +0 -0
  126. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/dialectical_reasoning.py +0 -0
  127. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/enums/__init__.py +0 -0
  128. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/enums/causality_preset.py +0 -0
  129. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/enums/di.py +0 -0
  130. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/events/__init__.py +0 -0
  131. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/events/graph_event.py +0 -0
  132. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/events/graph_event_bus.py +0 -0
  133. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/events/progress_event.py +0 -0
  134. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/exceptions/__init__.py +0 -0
  135. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/exceptions/node_errors.py +0 -0
  136. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/exceptions/resolver_errors.py +0 -0
  137. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/__init__.py +0 -0
  138. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/composite_input_resolver.py +0 -0
  139. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/dialexity_input_resolver.py +0 -0
  140. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/estimation_manager.py +0 -0
  141. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/mixins/__init__.py +0 -0
  142. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/mixins/incremental_build_mixin.py +0 -0
  143. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/mixins/intent_mixin.py +0 -0
  144. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/mixins/persistable_mixin.py +0 -0
  145. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/__init__.py +0 -0
  146. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/assessable_entity.py +0 -0
  147. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/base_node.py +0 -0
  148. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/case.py +0 -0
  149. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/cycle.py +0 -0
  150. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/decision.py +0 -0
  151. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/estimation.py +0 -0
  152. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/ideas.py +0 -0
  153. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/input.py +0 -0
  154. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/nexus.py +0 -0
  155. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/note.py +0 -0
  156. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/perspective.py +0 -0
  157. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/polarity.py +0 -0
  158. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/rationale.py +0 -0
  159. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/statement.py +0 -0
  160. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/synthesis.py +0 -0
  161. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/transformation.py +0 -0
  162. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/transition.py +0 -0
  163. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/nodes/wheel.py +0 -0
  164. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationship_manager.py +0 -0
  165. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/__init__.py +0 -0
  166. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/action_reflection_relationship.py +0 -0
  167. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/belongs_to_cycle_relationship.py +0 -0
  168. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/belongs_to_nexus_relationship.py +0 -0
  169. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/changed_to_relationship.py +0 -0
  170. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/contradiction_of_relationship.py +0 -0
  171. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/critiques_relationship.py +0 -0
  172. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/distilled_to_relationship.py +0 -0
  173. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/estimates_relationship.py +0 -0
  174. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/explains_relationship.py +0 -0
  175. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/grounded_in_relationship.py +0 -0
  176. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/has_input_relationship.py +0 -0
  177. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/has_statement_relationship.py +0 -0
  178. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/has_wheel_relationship.py +0 -0
  179. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/immutable_structure.py +0 -0
  180. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/is_source_of_relationship.py +0 -0
  181. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/is_target_of_relationship.py +0 -0
  182. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/negative_side_of_relationship.py +0 -0
  183. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/opposite_direction_relationship.py +0 -0
  184. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/opposite_of_relationship.py +0 -0
  185. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/polarity_relationship.py +0 -0
  186. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/positive_side_of_relationship.py +0 -0
  187. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/provides_relationship.py +0 -0
  188. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/relationships/synthesis_of_relationship.py +0 -0
  189. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/rendering.py +0 -0
  190. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/__init__.py +0 -0
  191. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/case_repository.py +0 -0
  192. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/cycle_repository.py +0 -0
  193. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/decision_repository.py +0 -0
  194. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/input_repository.py +0 -0
  195. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/nexus_repository.py +0 -0
  196. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/node_repository.py +0 -0
  197. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/note_repository.py +0 -0
  198. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/perspective_repository.py +0 -0
  199. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/polarity_repository.py +0 -0
  200. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/schema_repository.py +0 -0
  201. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/statement_repository.py +0 -0
  202. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/transformation_repository.py +0 -0
  203. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/repositories/wheel_repository.py +0 -0
  204. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/scope_context.py +0 -0
  205. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/verbatim_input_resolver.py +0 -0
  206. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/wheel_segment.py +0 -0
  207. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/graph/wheel_segment_polar_pair.py +0 -0
  208. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/protocols/__init__.py +0 -0
  209. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/protocols/has_config.py +0 -0
  210. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/protocols/input_resolver.py +0 -0
  211. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/py.typed +0 -0
  212. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/settings.py +0 -0
  213. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/__init__.py +0 -0
  214. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/async_drain.py +0 -0
  215. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/call_census.py +0 -0
  216. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/chunking.py +0 -0
  217. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/concurrency.py +0 -0
  218. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/dc_replace.py +0 -0
  219. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/decompose_probability_uniformly.py +0 -0
  220. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/edge_context.py +0 -0
  221. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/effect_logger.py +0 -0
  222. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/input_context.py +0 -0
  223. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/order_transitions.py +0 -0
  224. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/progress.py +0 -0
  225. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/retry_accounting.py +0 -0
  226. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/sequence_generation.py +0 -0
  227. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/thinking_compat.py +0 -0
  228. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/src/dialectical_framework/utils/use_brain.py +0 -0
  229. {dialectical_framework-2.0.1 → dialectical_framework-2.0.3}/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.1
3
+ Version: 2.0.3
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.1"
3
+ version = "2.0.3"
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"
@@ -51,7 +51,7 @@ from dialectical_framework.agents.conversation_facilitator import (
51
51
  FROM_SETTINGS, ConversationFacilitator)
52
52
  from dialectical_framework.agents.stream_events import StreamEvent
53
53
  from dialectical_framework.agents.turn_timing import TurnTiming
54
- from dialectical_framework.graph.views import ExplorationView
54
+ from dialectical_framework.graph.views import ExplorationView, PerspectiveView
55
55
 
56
56
  #: Tool verbs → mental acts. These are REWRITES, not drops: dropping every
57
57
  #: paragraph that mentions a tool name would also delete the discrimination test
@@ -324,7 +324,12 @@ 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
- self._conversation.set_system_prompt("\n\n".join(parts))
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)
328
333
 
329
334
  async def chat(self, user_message: str) -> str:
330
335
  result = await self._conversation.submit(ChatResponse, user_message)
@@ -362,7 +367,8 @@ class Consultant:
362
367
  view shows what has been ESTABLISHED, and where `focus` asks for
363
368
  structure not yet worked out ("a perspective for the thesis you
364
369
  named") the turn builds it by the method first
365
- (`concerns/view_sketch.py::view_sketch_prompt`). What it built is
370
+ (`concerns/view_sketch.py`: the static instructions ride on the system
371
+ prompt, the focus is the turn). What it built is
366
372
  kept in `messages` as the consultant's own words, so the next turn can
367
373
  be asked about a corner it just drew.
368
374
 
@@ -380,16 +386,30 @@ class Consultant:
380
386
  """
381
387
  from dialectical_framework.concerns.view_sketch import (
382
388
  ViewSketchDto, exploration_view_from_sketch, history_ask,
383
- history_text, view_sketch_prompt)
389
+ history_text, perspective_from_sketch, view_sketch_focus,
390
+ view_sketch_instructions)
384
391
 
385
392
  import asyncio
393
+ import dataclasses
386
394
 
387
395
  from dialectical_framework.concerns.tetrad_candidates import (
388
- clamp_attempts, select_sketch)
396
+ clamp_attempts, ranking, select_sketch)
389
397
 
390
398
  level = self._conversation._thinking_kwargs().get("thinking")
391
399
  history = self._conversation._messages
392
- request = view_sketch_prompt(focus, self._conversation.settings.component_length)
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
413
 
394
414
  async def draw() -> ViewSketchDto:
395
415
  # Each draw works on a COPY of the history: the turns run in
@@ -397,9 +417,20 @@ class Consultant:
397
417
  # read. What the view leaves behind is appended once, below.
398
418
  sketch_turn = ConversationFacilitator(format_mode="json", thinking=level)
399
419
  sketch_turn._messages = list(history)
400
- return await sketch_turn.submit(ViewSketchDto, request)
420
+ sketch_turn.set_system_prompt(system)
421
+ return await sketch_turn.submit(ViewSketchDto, ask)
401
422
 
402
423
  n = clamp_attempts(attempts)
424
+ # Fully parallel, deliberately. On a COLD cache all N draws write the
425
+ # ~12k system head instead of one writing and the rest reading (~$0.06
426
+ # a card at list prices, 2026-10-06), and the fix would be to await the
427
+ # first draw before firing the rest — but these turns do not stream, so
428
+ # nothing here can tell a cold cache from a warm one, and the stagger
429
+ # would spend a whole draw's latency (~6 s) on EVERY card to save money
430
+ # on the rare one. The 1h breakpoint TTL
431
+ # (`utils/bedrock_provider.py::_CACHE_TTL`) attacks the same cost
432
+ # without the latency, which is the trade taken. Revisit only with a
433
+ # measured cold-start rate.
403
434
  drawn = await asyncio.gather(*(draw() for _ in range(n)), return_exceptions=True)
404
435
  sketches = [d for d in drawn if not isinstance(d, BaseException)]
405
436
  if not sketches:
@@ -407,19 +438,24 @@ class Consultant:
407
438
  # With several draws the framework's own coherence check picks the one
408
439
  # whose FIRST tension holds best (`concerns/tetrad_candidates.py`); a
409
440
  # draw with no complete first tension sorts last. The card a blindspot
410
- # screen shows is that first tension.
441
+ # screen shows is that first tension. The judged draws that lost come
442
+ # back too, best first, as `runners_up` — a host's "again"/"another"
443
+ # can serve one without a new call (the module's stated intent).
444
+ runners_up: list[PerspectiveView] = []
411
445
  if len(sketches) > 1:
412
446
  firsts = [s.tensions[0] if s.tensions else None for s in sketches]
413
447
  judgeable = [i for i, t in enumerate(firsts) if t is not None and all(
414
448
  (getattr(t, k) or "").strip() for k in ("thesis", "antithesis", "t_plus", "t_minus", "a_plus", "a_minus"))]
415
449
  if len(judgeable) > 1:
416
- best_among, _verdicts = await select_sketch([firsts[i] for i in judgeable])
417
- sketch = sketches[judgeable[best_among]]
450
+ _best, verdicts = await select_sketch([firsts[i] for i in judgeable])
451
+ order = ranking(verdicts)
452
+ sketch = sketches[judgeable[order[0]]]
453
+ runners_up = [perspective_from_sketch(firsts[judgeable[i]]) for i in order[1:]]
418
454
  else:
419
455
  sketch = sketches[judgeable[0]] if judgeable else sketches[0]
420
456
  else:
421
457
  sketch = sketches[0]
422
- view = exploration_view_from_sketch(sketch)
458
+ view = dataclasses.replace(exploration_view_from_sketch(sketch), runners_up=runners_up)
423
459
  # What the turn leaves behind is NOT what it sent: the long request and
424
460
  # the DTO come off, and the person's ask plus the drawing in words go
425
461
  # on. Kept as a request→prose pair, the long request taught the next
@@ -97,6 +97,47 @@ class CoherenceEvaluationDto(BaseModel):
97
97
  )
98
98
 
99
99
 
100
+ def control_statements(
101
+ *, t_plus: str, t_minus: str, a_plus: str, a_minus: str
102
+ ) -> tuple[str, str]:
103
+ """The paper's two control statements, built from four texts.
104
+
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.
109
+ """
110
+ return (
111
+ f'"{t_plus}" without "{a_plus}" yields "{t_minus}"',
112
+ f'"{a_plus}" without "{t_plus}" yields "{a_minus}"',
113
+ )
114
+
115
+
116
+ # --- Prompt text ---
117
+ #
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).
122
+
123
+ _PATTERN = """The pattern "[Positive] without [Balancing factor] yields [Negative]" tests whether
124
+ the absence of a balancing positive aspect naturally leads to the negative/shadow aspect."""
125
+
126
+ _CC_SCALE = """Conceptual Coherence (CC) — is the statement logically meaningful?
127
+ - 0.9-1.0: Highly coherent, clear logical/causal relationship
128
+ - 0.7-0.9: Coherent, reasonable logical connection
129
+ - 0.5-0.7: Somewhat coherent, plausible but weak
130
+ - 0.3-0.5: Weak coherence, tenuous connection
131
+ - 0.0-0.3: Not coherent, no clear logical relationship"""
132
+
133
+ _DV_SCALE = """Dialectical Validity (DV) — is the dialectical relationship natural, judged
134
+ independently of coherence? A statement can be perfectly coherent yet dialectically
135
+ distorted (e.g. one pole arbitrarily privileged, outcomes enforced by coercion or
136
+ ideology rather than natural system dynamics). 1.0 = natural, balanced, generative;
137
+ 0.0 = forced, artificial, distorted. Ignore factual correctness; evaluate only the
138
+ quality of the dialectical relationship as a generative principle."""
139
+
140
+
100
141
  # --- Result ---
101
142
 
102
143
 
@@ -182,8 +223,12 @@ class ControlStatementsCheck(ReasonableConcern[ControlStatementsCheckResult]):
182
223
  a_minus = perspective.get_component(POSITION_A_MINUS)
183
224
 
184
225
  # Build control statements
185
- stmt_1 = f'"{t_plus.prompt_text}" without "{a_plus.prompt_text}" yields "{t_minus.prompt_text}"'
186
- stmt_2 = f'"{a_plus.prompt_text}" without "{t_plus.prompt_text}" yields "{a_minus.prompt_text}"'
226
+ stmt_1, stmt_2 = control_statements(
227
+ t_plus=t_plus.prompt_text,
228
+ t_minus=t_minus.prompt_text,
229
+ a_plus=a_plus.prompt_text,
230
+ a_minus=a_minus.prompt_text,
231
+ )
187
232
 
188
233
  # Evaluate both statements in parallel using isolated conversations
189
234
  result_1, result_2 = await asyncio.gather(
@@ -268,12 +313,15 @@ class ControlStatementsCheck(ReasonableConcern[ControlStatementsCheckResult]):
268
313
 
269
314
  What `resolve` does after reading the four aspects off a committed
270
315
  node, offered to callers that hold a tetrad as text: the best-of-N
271
- selector (`concerns/tetrad_candidates.py`) and the harness. Built with
272
- the same quoting as `resolve`'s statements so a verdict here is the
273
- same question as the one asked after persistence.
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`).
274
321
  """
275
- stmt_1 = f'"{t_plus}" without "{a_plus}" yields "{t_minus}"'
276
- stmt_2 = f'"{a_plus}" without "{t_plus}" yields "{a_minus}"'
322
+ stmt_1, stmt_2 = control_statements(
323
+ t_plus=t_plus, t_minus=t_minus, a_plus=a_plus, a_minus=a_minus
324
+ )
277
325
  return await asyncio.gather(
278
326
  self._evaluate_control_statement(stmt_1, text),
279
327
  self._evaluate_control_statement(stmt_2, text),
@@ -291,22 +339,11 @@ class ControlStatementsCheck(ReasonableConcern[ControlStatementsCheckResult]):
291
339
 
292
340
  {statement}
293
341
 
294
- The pattern "[Positive] without [Balancing factor] yields [Negative]" tests whether
295
- the absence of a balancing positive aspect naturally leads to the negative/shadow aspect.
342
+ {_PATTERN}
296
343
 
297
- 1. Conceptual Coherence (CC) — is the statement logically meaningful?
298
- - 0.9-1.0: Highly coherent, clear logical/causal relationship
299
- - 0.7-0.9: Coherent, reasonable logical connection
300
- - 0.5-0.7: Somewhat coherent, plausible but weak
301
- - 0.3-0.5: Weak coherence, tenuous connection
302
- - 0.0-0.3: Not coherent, no clear logical relationship
344
+ 1. {_CC_SCALE}
303
345
 
304
- 2. Dialectical Validity (DV) — is the dialectical relationship natural, judged
305
- independently of coherence? A statement can be perfectly coherent yet dialectically
306
- distorted (e.g. one pole arbitrarily privileged, outcomes enforced by coercion or
307
- ideology rather than natural system dynamics). 1.0 = natural, balanced, generative;
308
- 0.0 = forced, artificial, distorted. Ignore factual correctness; evaluate only the
309
- quality of the dialectical relationship as a generative principle."""
346
+ 2. {_DV_SCALE}"""
310
347
 
311
348
  conversation = ConversationFacilitator()
312
349
  return await conversation.submit(
@@ -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
 
@@ -106,25 +106,54 @@ def is_complete(candidate: Any) -> bool:
106
106
  )
107
107
 
108
108
 
109
- async def judge_sketch(tension: Any, context: str = "") -> SketchVerdict:
110
- """The validator's two control statements, on the candidate's texts, graph-free.
111
-
112
- Statement texts are built exactly as `ControlStatementsCheck.resolve`
113
- builds them from committed Statements, so a verdict here and one taken
114
- after persistence are the same question asked of the same words.
109
+ async def judge_sketches(
110
+ candidates: Sequence[Any], context: str = ""
111
+ ) -> list[Optional[SketchVerdict]]:
112
+ """The validator's two control statements for every candidate, each draft
113
+ judged on its own, each statement in its own call (gathered).
114
+
115
+ Statement texts are built by the same builder `ControlStatementsCheck.resolve`
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
+ A cheaper judge has to be measured against this one on that probe first.
115
134
  """
116
- first, second = await ControlStatementsCheck().score_texts(
117
- t_plus=aspect_text(tension.t_plus),
118
- t_minus=aspect_text(tension.t_minus),
119
- a_plus=aspect_text(tension.a_plus),
120
- a_minus=aspect_text(tension.a_minus),
121
- text=context,
122
- )
123
- return SketchVerdict(
124
- t_plus_without_a_plus=first.coherence_score,
125
- a_plus_without_t_plus=second.coherence_score,
126
- reasoning=f"{first.reasoning} / {second.reasoning}".strip(" /"),
127
- )
135
+
136
+ async def one(tension: Any) -> Optional[SketchVerdict]:
137
+ # Reading the verdict is inside the `try` too: a malformed response
138
+ # is a failed judging (sorts last), never a failed selection.
139
+ try:
140
+ first, second = await ControlStatementsCheck().score_texts(
141
+ t_plus=aspect_text(tension.t_plus),
142
+ t_minus=aspect_text(tension.t_minus),
143
+ a_plus=aspect_text(tension.a_plus),
144
+ a_minus=aspect_text(tension.a_minus),
145
+ text=context,
146
+ )
147
+ return SketchVerdict(
148
+ t_plus_without_a_plus=first.coherence_score,
149
+ a_plus_without_t_plus=second.coherence_score,
150
+ reasoning=f"{first.reasoning} / {second.reasoning}".strip(" /"),
151
+ )
152
+ except Exception as exc: # noqa: BLE001 — degrade to "unjudged"
153
+ logger.warning("Judging a sketch failed; it sorts last: %s", exc)
154
+ return None
155
+
156
+ return list(await asyncio.gather(*(one(c) for c in candidates)))
128
157
 
129
158
 
130
159
  async def select_sketch(
@@ -137,18 +166,21 @@ async def select_sketch(
137
166
  mean, then the earlier draw — a deterministic tie-break, not a preference.
138
167
  A candidate whose judging failed sorts last; if every judging failed the
139
168
  first draw is kept, which is exactly what `attempts=1` would have done.
169
+
170
+ ONE candidate is never judged: there is nothing to select among, so
171
+ `attempts=1` costs no extra call.
140
172
  """
141
173
  if len(candidates) == 1:
142
174
  return 0, [None]
143
175
 
144
- async def one(tension: Any) -> Optional[SketchVerdict]:
145
- try:
146
- return await judge_sketch(tension, context)
147
- except Exception as exc: # noqa: BLE001 — degrade to "unjudged"
148
- logger.warning("Judging a sketch failed; it sorts last: %s", exc)
149
- return None
176
+ verdicts = await judge_sketches(candidates, context)
177
+ return ranking(verdicts)[0], verdicts
178
+
150
179
 
151
- verdicts = list(await asyncio.gather(*(one(c) for c in candidates)))
180
+ def ranking(verdicts: Sequence[Optional[SketchVerdict]]) -> list[int]:
181
+ """Candidate indices best first, by `select_sketch`'s rule: the weaker
182
+ control statement, then the mean, then the earlier draw; unjudged last.
183
+ `[0]` is the winner; the rest are the runners-up in order."""
152
184
 
153
185
  def key(index: int) -> tuple[int, float, float, int]:
154
186
  verdict = verdicts[index]
@@ -157,5 +189,4 @@ async def select_sketch(
157
189
  mean = (verdict.t_plus_without_a_plus + verdict.a_plus_without_t_plus) / 2
158
190
  return (1, verdict.floor, mean, -index)
159
191
 
160
- best = max(range(len(candidates)), key=key)
161
- return best, verdicts
192
+ return sorted(range(len(verdicts)), key=key, reverse=True)