dialectical-framework 2.1.0__tar.gz → 2.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/PKG-INFO +2 -2
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/pyproject.toml +8 -2
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/consultant/consultant.py +39 -3
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/antithesis_extraction.py +17 -4
- dialectical_framework-2.1.2/src/dialectical_framework/concerns/attribution_check.py +148 -0
- dialectical_framework-2.1.2/src/dialectical_framework/concerns/tetrad_candidates.py +359 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/tetrad_sketch.py +18 -3
- dialectical_framework-2.1.2/src/dialectical_framework/concerns/thesis_fit_check.py +165 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/view_sketch.py +135 -11
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/views.py +9 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/bedrock_provider.py +211 -44
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/format_compat.py +65 -1
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/thinking_compat.py +21 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/use_brain.py +11 -1
- dialectical_framework-2.1.0/src/dialectical_framework/concerns/tetrad_candidates.py +0 -197
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/LICENSE +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/PATENTS +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/README.md +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/advisor.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/build_policy.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/migration.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/reply_hygiene.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/system_prompts.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/tools/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/tools/anchor.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/tools/deepen.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/tools/explore.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/tools/ingest.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/tools/note.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/tools/record_decision.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/tools/scoped.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/advisor/tools/sync.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/agent_context.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/analyst/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/analyst/analyst.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/analyst/skills/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/analyst/skills/anchor_theses.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/analyst/skills/edit_perspective.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/analyst/skills/expand_polarities.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/analyst/skills/find_polarities.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/analyst/skills/introduce_polarity.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/analyst/skills/sketch_tetrad.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/analyst/skills/surface_theses.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/analyst/system_prompts.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/analyst/tools/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/analyst/tools/place_statement.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/app_spec.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/apps.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/consultant/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/conversation_facilitator.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/execution_report.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/explorer/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/explorer/explorer.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/explorer/skills/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/explorer/skills/build_wheels.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/explorer/skills/explore_transformations.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/explorer/skills/generate_synthesis.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/explorer/system_prompts.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/explorer/tools/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/explorer/tools/create_nexus.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/explorer/tools/expand_nexus.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/explorer/tools/generate_synthesis.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/explorer/tools/present_exploration.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/orchestrator/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/orchestrator/tools/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/orchestrator/tools/add_input.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/orchestrator/tools/audit_feasibility.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/orchestrator/tools/create_dx_input.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/orchestrator/tools/digest_input.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/orchestrator/tools/discard.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/orchestrator/tools/get_schema.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/orchestrator/tools/inspect_node.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/orchestrator/tools/present_analysis.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/orchestrator/tools/query_graph.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/orchestrator/tools/read_digest.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/orchestrator/tools/read_input.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/reasonable_concern.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/stream_events.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/toolsets.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/agents/turn_timing.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/ac_re_taxonomy.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/action_extraction.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/add_input.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/ai_dto/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/ai_dto/statement_dto.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/ai_dto/statements_deck_dto.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/antithesis_classification.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/antithetical_thesis_detection.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/aspect_classification.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/aspect_generation.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/build_status.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/causality/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/causality/causality_estimator.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/causality/causality_estimator_balanced.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/causality/causality_estimator_criteria.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/causality/causality_estimator_desirable.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/causality/causality_estimator_feasible.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/causality/causality_estimator_realistic.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/causality/causality_normalizer.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/causality/estimator_resolver.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/causality_estimation.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/control_statements_check.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/create_dx_input.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/create_nexus.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/decision_coherence_check.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/decision_confirmation_check.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/diagonal_oppositions_check.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/dialectical_context.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/discard.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/display_text_edit.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/expand_nexus.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/perspective_combination.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/perspective_validation.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/positive_ac_re_apex_derivation.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/record_decision.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/scoring_scales.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/source_digest.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/statement_classification.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/statement_deduplication.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/statement_headline.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/statement_placement.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/synthesis_generation.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/tetrad_grounding.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/thesis_extraction.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/transformation_audit.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/transformation_generation.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/concerns/transformation_sketch.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/dialectical_reasoning.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/enums/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/enums/causality_preset.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/enums/di.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/events/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/events/graph_event.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/events/graph_event_bus.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/events/progress_event.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/exceptions/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/exceptions/node_errors.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/exceptions/provider_errors.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/exceptions/resolver_errors.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/composite_input_resolver.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/dialexity_input_resolver.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/estimation_manager.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/mixins/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/mixins/incremental_build_mixin.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/mixins/intent_mixin.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/mixins/persistable_mixin.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/assessable_entity.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/base_node.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/case.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/cycle.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/decision.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/estimation.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/ideas.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/input.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/nexus.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/note.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/perspective.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/polarity.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/rationale.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/statement.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/synthesis.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/transformation.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/transition.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/nodes/wheel.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationship_manager.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/action_reflection_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/belongs_to_cycle_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/belongs_to_nexus_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/changed_to_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/contradiction_of_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/critiques_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/distilled_to_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/estimates_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/explains_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/grounded_in_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/has_input_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/has_statement_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/has_wheel_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/immutable_structure.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/is_source_of_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/is_target_of_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/negative_side_of_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/opposite_direction_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/opposite_of_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/polarity_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/positive_side_of_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/provides_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/relationships/synthesis_of_relationship.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/rendering.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/case_repository.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/cycle_repository.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/decision_repository.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/input_repository.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/nexus_repository.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/node_repository.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/note_repository.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/perspective_repository.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/polarity_repository.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/schema_repository.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/statement_repository.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/transformation_repository.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/repositories/wheel_repository.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/scope_context.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/verbatim_input_resolver.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/wheel_segment.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/graph/wheel_segment_polar_pair.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/protocols/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/protocols/has_config.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/protocols/input_resolver.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/py.typed +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/settings.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/settings_context.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/__init__.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/async_drain.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/call_census.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/chunking.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/concurrency.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/dc_replace.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/decompose_probability_uniformly.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/edge_context.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/effect_logger.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/input_context.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/order_transitions.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/progress.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/retry_accounting.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/src/dialectical_framework/utils/sequence_generation.py +0 -0
- {dialectical_framework-2.1.0 → dialectical_framework-2.1.2}/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.1.
|
|
3
|
+
Version: 2.1.2
|
|
4
4
|
Summary: A dialectical framework for augmented intelligence. AI reasoning powered with dialectics supports humans in: system optimization (psychology, engineering, business, politics, etc.); dispute resolution (mediation, conflicts, negotiations, etc.); decision-making (dilemmas, challenging situations, win-win, etc.).
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: dialectics,dialectical-reasoning,synthesis,thesis-antithesis,ai,artificial-intelligence,llm,reasoning-framework,philosophy,logic,argumentation,conflict-resolution,decision-making,critical-thinking,semantic-graph,mirascope,pydantic,perspectives,polarity-reasoning
|
|
@@ -32,7 +32,7 @@ Requires-Dist: broadcaster (>=0.3.1,<0.4.0)
|
|
|
32
32
|
Requires-Dist: dependency-injector (>=4.48.2,<5.0.0)
|
|
33
33
|
Requires-Dist: gqlalchemy (>=1.8.0,<2.0.0)
|
|
34
34
|
Requires-Dist: langfuse (>=4.5.1,<5.0.0)
|
|
35
|
-
Requires-Dist: mirascope[anthropic,openai,ops] (>=2.
|
|
35
|
+
Requires-Dist: mirascope[anthropic,openai,ops] (>=2.8.2,<3.0.0)
|
|
36
36
|
Requires-Dist: python-dotenv (>=1.2.1,<2.0.0)
|
|
37
37
|
Requires-Dist: tabulate (>=0.9.0,<0.10.0)
|
|
38
38
|
Project-URL: Homepage, https://github.com/dialexity/dialectical-framework
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "dialectical-framework"
|
|
3
|
-
version = "2.1.
|
|
3
|
+
version = "2.1.2"
|
|
4
4
|
description = "A dialectical framework for augmented intelligence. AI reasoning powered with dialectics supports humans in: system optimization (psychology, engineering, business, politics, etc.); dispute resolution (mediation, conflicts, negotiations, etc.); decision-making (dilemmas, challenging situations, win-win, etc.)."
|
|
5
5
|
authors = ["Evaldas Taroza <evaldas@dialexity.com>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -43,11 +43,17 @@ from = "src"
|
|
|
43
43
|
|
|
44
44
|
[tool.poetry.dependencies]
|
|
45
45
|
python = "^3.11"
|
|
46
|
+
# 2.8.2 is the FLOOR, not a preference: below it Mirascope's Anthropic encoder
|
|
47
|
+
# sends extended thinking as the legacy token budget, which every Claude 5 model
|
|
48
|
+
# rejects with a 400 — so a thinking structured call (the view turn, TetradSketch)
|
|
49
|
+
# cannot run on the native `anthropic/` provider at all. The framework's own
|
|
50
|
+
# `thinking_compat` covers this for `bedrock/` only. Measured 2026-10-26, story in
|
|
51
|
+
# docs/dev-notes/antithesis-selection.md.
|
|
46
52
|
mirascope = {extras = [
|
|
47
53
|
"openai",
|
|
48
54
|
"anthropic",
|
|
49
55
|
"ops"
|
|
50
|
-
], version = "^2.
|
|
56
|
+
], version = "^2.8.2"}
|
|
51
57
|
python-dotenv = "^1.2.1"
|
|
52
58
|
tabulate = "^0.9.0"
|
|
53
59
|
dependency-injector = "^4.48.2"
|
|
@@ -425,11 +425,15 @@ class Consultant:
|
|
|
425
425
|
"""
|
|
426
426
|
from dialectical_framework.concerns.view_sketch import (
|
|
427
427
|
ViewSketchDto, exploration_view_from_sketch, history_ask,
|
|
428
|
-
history_text, perspective_from_sketch,
|
|
428
|
+
history_text, judge_context, perspective_from_sketch,
|
|
429
|
+
view_sketch_prompt)
|
|
429
430
|
|
|
430
431
|
import asyncio
|
|
431
432
|
import dataclasses
|
|
432
433
|
|
|
434
|
+
from dialectical_framework.agents.advisor.migration import person_turns
|
|
435
|
+
from dialectical_framework.concerns.attribution_check import \
|
|
436
|
+
drop_unborne_holders
|
|
433
437
|
from dialectical_framework.concerns.tetrad_candidates import (
|
|
434
438
|
clamp_attempts, ranking, select_sketch)
|
|
435
439
|
|
|
@@ -459,7 +463,6 @@ class Consultant:
|
|
|
459
463
|
sketch_turn._messages = list(history)
|
|
460
464
|
return await sketch_turn.submit(ViewSketchDto, request)
|
|
461
465
|
|
|
462
|
-
n = clamp_attempts(attempts)
|
|
463
466
|
# Fully parallel, deliberately. On a COLD cache all N draws write the
|
|
464
467
|
# ~12k system head instead of one writing and the rest reading (~$0.06
|
|
465
468
|
# a card at list prices, 2026-10-06), and the fix would be to await the
|
|
@@ -470,6 +473,13 @@ class Consultant:
|
|
|
470
473
|
# (`utils/bedrock_provider.py::_CACHE_TTL`) attacks the same cost
|
|
471
474
|
# without the latency, which is the trade taken. Revisit only with a
|
|
472
475
|
# measured cold-start rate.
|
|
476
|
+
n = clamp_attempts(attempts)
|
|
477
|
+
# The SAME request N times, by measurement: N identical requests draw
|
|
478
|
+
# the same opposition N times, reworded (the first app, 52/52 cards),
|
|
479
|
+
# and asking draw 2..N for a different one made the spares differ and
|
|
480
|
+
# the winner worse (CC 19/40 against 27/40, 2026-10-13,
|
|
481
|
+
# `tests/e2e/probe_view_turn_ask.py`) — so this is a coherence re-roll,
|
|
482
|
+
# and a host's "another" served from `runners_up` is a rewording.
|
|
473
483
|
drawn = await asyncio.gather(*(draw() for _ in range(n)), return_exceptions=True)
|
|
474
484
|
sketches = [d for d in drawn if not isinstance(d, BaseException)]
|
|
475
485
|
failures = [d for d in drawn if isinstance(d, BaseException)]
|
|
@@ -497,19 +507,45 @@ class Consultant:
|
|
|
497
507
|
for drawn_sketch in sketches:
|
|
498
508
|
if drawn_sketch.tensions:
|
|
499
509
|
drawn_sketch.tensions[0].thesis = pinned
|
|
510
|
+
# A pinned position is the host's own words for the
|
|
511
|
+
# person's own position: never someone else's.
|
|
512
|
+
drawn_sketch.tensions[0].thesis_held_by = ""
|
|
513
|
+
# The person's turns, for the judges below. Also the words a named
|
|
514
|
+
# holder is checked against.
|
|
515
|
+
words = judge_context(person_turns(history))
|
|
516
|
+
# A holder the words do not bear is dropped, in code, on every draw
|
|
517
|
+
# (`concerns/attribution_check.py`, 2026-10-27): the prompt rule
|
|
518
|
+
# halved the misquotation on pasted material and did not end it, and a
|
|
519
|
+
# runner-up served later must not carry one either. No call where no
|
|
520
|
+
# holder is named — the person's own words cost nothing here.
|
|
521
|
+
firsts_to_check = [s.tensions[0] for s in sketches if s.tensions]
|
|
522
|
+
for dropped in await drop_unborne_holders(firsts_to_check, words):
|
|
523
|
+
logger.info("A drawn holder was dropped: %s", dropped)
|
|
500
524
|
# With several draws the framework's own coherence check picks the one
|
|
501
525
|
# whose FIRST tension holds best (`concerns/tetrad_candidates.py`); a
|
|
502
526
|
# draw with no complete first tension sorts last. The card a blindspot
|
|
503
527
|
# screen shows is that first tension. The judged draws that lost come
|
|
504
528
|
# back too, best first, as `runners_up` — a host's "again"/"another"
|
|
505
529
|
# can serve one without a new call (the module's stated intent).
|
|
530
|
+
# The judge reads the PERSON's turns as its context (`judge_context`):
|
|
531
|
+
# it never sees T or A, and called blind — as it was here until
|
|
532
|
+
# 2026-10-13, while the build and the persisted path passed their
|
|
533
|
+
# material — it scored the four aspects against nothing.
|
|
506
534
|
runners_up: list[PerspectiveView] = []
|
|
507
535
|
if len(sketches) > 1:
|
|
508
536
|
firsts = [s.tensions[0] if s.tensions else None for s in sketches]
|
|
509
537
|
judgeable = [i for i, t in enumerate(firsts) if t is not None and all(
|
|
510
538
|
(getattr(t, k) or "").strip() for k in ("thesis", "antithesis", "t_plus", "t_minus", "a_plus", "a_minus"))]
|
|
511
539
|
if len(judgeable) > 1:
|
|
512
|
-
|
|
540
|
+
# This writer CHOOSES the thesis, so a second judge reads each
|
|
541
|
+
# draw's T, A and A+ against the person's words — the claim
|
|
542
|
+
# they would sign, an opposition they have not granted
|
|
543
|
+
# (`tetrad_candidates.judge_fit`, 2026-10-20). With a pinned T
|
|
544
|
+
# the first read is the same on every draw and the second
|
|
545
|
+
# still tells them apart.
|
|
546
|
+
_best, verdicts = await select_sketch(
|
|
547
|
+
[firsts[i] for i in judgeable], context=words, fit_against=words
|
|
548
|
+
)
|
|
513
549
|
order = ranking(verdicts)
|
|
514
550
|
sketch = sketches[judgeable[order[0]]]
|
|
515
551
|
runners_up = [perspective_from_sketch(firsts[judgeable[i]]) for i in order[1:]]
|
|
@@ -66,7 +66,17 @@ _AwaitedT = TypeVar("_AwaitedT")
|
|
|
66
66
|
# because the previous ask ("an antithesis that represents Negation of the
|
|
67
67
|
# thesis") was complied with exactly — and at the high rungs exact compliance
|
|
68
68
|
# is a caricature (measured 19/19, `tests/probe_blindspot_paths.py`).
|
|
69
|
-
|
|
69
|
+
#
|
|
70
|
+
# The second failure, the caricature's mirror (2026-10-20, the first app's
|
|
71
|
+
# handoff `docs/dev-notes/antithesis-selection.md`, "The hedge wins on coherence"): "in the thesis's own
|
|
72
|
+
# terms" was complied with exactly too, and when the thesis's own words NAME
|
|
73
|
+
# their opponent and concede it ("not only schools, but also …"), that
|
|
74
|
+
# opponent is the most literal answer — the writer drew it as A on Sonnet 5.5
|
|
75
|
+
# in every configuration, and the card handed the person their own clause as
|
|
76
|
+
# the blind spot they were not seeing. This ask was one-sided: tuned against
|
|
77
|
+
# the strawman end, it had nothing to say about the granted end. UNMEASURED
|
|
78
|
+
# as a rule; the shape is the caricature rule's, in the same place.
|
|
79
|
+
_OPPOSING_POSITION_ASK = """The antithesis is a POSITION someone holds for its own value, that functionally opposes the role the thesis plays — at this rung's mechanism, in the thesis's own terms. It is not the thesis's absence or degradation restated as a stance. Example: for "Quit my job and start my own company", Negation is "Keep the security and craft of employed work", not "Never quit, stay employed forever"; the second is a caricature nobody holds, and a caricature cannot be developed constructively — rate such a candidate's tetrad potential low rather than dressing it up. The mirror failure: an opposition the thesis's own words already name AND concede ("not only X but also Y", "X matters, but …") is seen, not missing — its constructive side is something the person has already granted, and a tetrad built on it shows them their own concession as a blind spot. Rate such a candidate's tetrad potential low as well, and oppose the claim they actually make."""
|
|
70
80
|
|
|
71
81
|
|
|
72
82
|
# --- Extraction-specific DTOs ---
|
|
@@ -94,7 +104,9 @@ class ModePointResultDto(BaseModel):
|
|
|
94
104
|
"A is a position someone holds for its own value, it can be developed so "
|
|
95
105
|
"that it also strengthens what T is for (an A+ exists), and it has its own "
|
|
96
106
|
"one-sided failure (an A-). Low: A is T's absence or degradation dressed as "
|
|
97
|
-
"a position,
|
|
107
|
+
"a position, a caricature nobody would hold — nothing to develop — or an "
|
|
108
|
+
"opposition the thesis's own words already name and concede, whose A+ the "
|
|
109
|
+
"person has granted."
|
|
98
110
|
),
|
|
99
111
|
)
|
|
100
112
|
arousal_label: str = Field(
|
|
@@ -132,7 +144,8 @@ class OptimumARankingDto(BaseModel):
|
|
|
132
144
|
"functionally opposes the role the thesis plays; it can be developed so "
|
|
133
145
|
"that it also strengthens what the thesis is for, and it has its own "
|
|
134
146
|
"one-sided failure. Worst = the thesis's absence or degradation dressed "
|
|
135
|
-
"as a stance,
|
|
147
|
+
"as a stance, a caricature nobody holds, or an opposition the thesis's own "
|
|
148
|
+
"words already concede."
|
|
136
149
|
)
|
|
137
150
|
)
|
|
138
151
|
reasoning: str = Field(
|
|
@@ -542,7 +555,7 @@ Thesis: "{thesis.prompt_text}"
|
|
|
542
555
|
Candidates:
|
|
543
556
|
{numbered}
|
|
544
557
|
|
|
545
|
-
The best antithesis is the one most likely to yield a coherent tetrad with the thesis: a POSITION someone holds for its own value that functionally opposes the role the thesis plays — it can be developed constructively so that it also strengthens what the thesis is for, and it has its own one-sided failure. Rank lower any candidate that is the thesis's absence or degradation dressed as a stance, a caricature nobody would hold, or the thesis
|
|
558
|
+
The best antithesis is the one most likely to yield a coherent tetrad with the thesis: a POSITION someone holds for its own value that functionally opposes the role the thesis plays — it can be developed constructively so that it also strengthens what the thesis is for, and it has its own one-sided failure. Rank lower any candidate that is the thesis's absence or degradation dressed as a stance, a caricature nobody would hold, the thesis merely hedged, or an opposition the thesis's own words already name and concede. Return every number exactly once."""
|
|
546
559
|
try:
|
|
547
560
|
verdict = await self._conversation.isolate().submit(
|
|
548
561
|
response_model=OptimumARankingDto, user_content=prompt
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AttributionCheck: do the words bear the holder a drawn pole names?
|
|
3
|
+
|
|
4
|
+
WHY A CHECK IN CODE
|
|
5
|
+
===================
|
|
6
|
+
The view turn names WHO holds each pole when it is not the person's own
|
|
7
|
+
(`ViewSketchPerspectiveDto.thesis_held_by` / `antithesis_held_by`, carried as
|
|
8
|
+
`PoleView.held_by`, since 2026-10-26), and a prompt rule says a party is
|
|
9
|
+
named only for a position its own words take (`view_sketch.HOLDER_FROM_THE_WORDS`,
|
|
10
|
+
2026-10-27). Measured on 37 pieces of pasted material, two draws each, the
|
|
11
|
+
rule HALVED the misquotation and did not end it: about one draw in twenty
|
|
12
|
+
still named a party for words the text does not bear — a speaker given the
|
|
13
|
+
inverse of their own position, two sides swapped — and a screen shows that
|
|
14
|
+
as "the Minister's position" over words the Minister never said. Prompt
|
|
15
|
+
enforcement scales with compliance (CLAUDE.md, the machinery leak), so the
|
|
16
|
+
last step is the same shape as the thesis pin: enforced by code after the
|
|
17
|
+
draw, not asked for again.
|
|
18
|
+
|
|
19
|
+
WHAT IT DOES
|
|
20
|
+
============
|
|
21
|
+
One structured call per NAMED holder, shown the person's words and one pole,
|
|
22
|
+
asked whether the text attributes that position to that party — stated in
|
|
23
|
+
their own words or reported as theirs (a role and the person in it are one
|
|
24
|
+
party). NOT attributed: the holder is dropped, so the pole reads as a built
|
|
25
|
+
opposition (A) or as unattributed (T) instead of a misquotation. Attributed:
|
|
26
|
+
kept. Never a replacement: the judge is not handed the right to put a
|
|
27
|
+
different name on the screen. Free where it matters most — on the person's
|
|
28
|
+
own words every holder is empty and no call is made.
|
|
29
|
+
|
|
30
|
+
Fail-soft the way the fit judge is: a failed judging KEEPS the holder. The
|
|
31
|
+
alternative, dropping on error, would turn "the Minister's position" into
|
|
32
|
+
"your position" on a provider hiccup, which is the 2026-10-26 defect back.
|
|
33
|
+
A missing holder is also what `held_by` means on the graph path, so a host
|
|
34
|
+
must already handle None.
|
|
35
|
+
|
|
36
|
+
THE VERDICT'S WORDING IS VERSION 2. Version 1 asked whether the text
|
|
37
|
+
"attributes this position" to the party and, applied to the 130 named
|
|
38
|
+
holders of the gate's WITH-arm draws, dropped 28 — 18 of the 27 the probe's
|
|
39
|
+
own judge had flagged, and 10 it had grounded: it read an elaboration as a
|
|
40
|
+
misquotation ("opponents of trophy hunting" refused "killing for pleasure is
|
|
41
|
+
wrong" because the text says only that the controversy is about the morality
|
|
42
|
+
of hunting for pleasure; a rhetorical question that takes a side was "no
|
|
43
|
+
stance"). A dropped true holder costs what this check exists to prevent in
|
|
44
|
+
reverse — "the Minister's position" shown as "your position" — so version 2
|
|
45
|
+
says a fair condensation of the stance the text gives them is theirs, and
|
|
46
|
+
NOT_ATTRIBUTED is no stance at all, the opposite side, or someone else's.
|
|
47
|
+
|
|
48
|
+
MEASURED (2026-10-27, `tests/e2e/rescore_attribution_check.py`): see
|
|
49
|
+
`docs/dev-notes/views.md`, "A name on words never said" — applied to the
|
|
50
|
+
saved WITH-arm draws of the holder-rule gate and then live on the 37-case
|
|
51
|
+
finding run.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
from __future__ import annotations
|
|
55
|
+
|
|
56
|
+
import asyncio
|
|
57
|
+
import logging
|
|
58
|
+
from typing import Any, Literal, Sequence
|
|
59
|
+
|
|
60
|
+
from pydantic import BaseModel, Field
|
|
61
|
+
|
|
62
|
+
from dialectical_framework.agents.conversation_facilitator import \
|
|
63
|
+
ConversationFacilitator
|
|
64
|
+
|
|
65
|
+
logger = logging.getLogger(__name__)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class AttributionDto(BaseModel):
|
|
69
|
+
"""One verdict; the safe value first (the mocked suite fills the first)."""
|
|
70
|
+
|
|
71
|
+
verdict: Literal["attributed", "not_attributed"] = Field(
|
|
72
|
+
description=(
|
|
73
|
+
"ATTRIBUTED: the text gives that party this position — stated in their "
|
|
74
|
+
"own words, reported as what they hold, argue, claim or did, or a fair "
|
|
75
|
+
"condensation of the stance the text gives them (an opponent of X holds "
|
|
76
|
+
"that X is wrong; a rhetorical question that takes a side takes it; a "
|
|
77
|
+
"role and the person in it, or a group and a member named as its voice, "
|
|
78
|
+
"are one party). Wording that goes a little beyond their words while "
|
|
79
|
+
"keeping their side is still theirs. NOT_ATTRIBUTED: the text gives that "
|
|
80
|
+
"party no stance on this at all, gives them the OPPOSITE side, or gives "
|
|
81
|
+
"this position to someone else; a party who is only described, who "
|
|
82
|
+
"disagrees with it, or who is merely asked about it does not hold it."
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
reasoning: str = Field(
|
|
86
|
+
description="One sentence: the words that attribute it, or that none do."
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class AttributionCheck:
|
|
91
|
+
"""Text-only, graph-free, no report: a check the view turn runs."""
|
|
92
|
+
|
|
93
|
+
async def score_texts(
|
|
94
|
+
self, *, position: str, held_by: str, text: str
|
|
95
|
+
) -> AttributionDto:
|
|
96
|
+
prompt = f"""<text>
|
|
97
|
+
{text}
|
|
98
|
+
</text>
|
|
99
|
+
|
|
100
|
+
Does this text attribute the following position to {held_by.strip()} — stated in their own words, or reported as what they hold, argue, claim or did?
|
|
101
|
+
|
|
102
|
+
"{position.strip()}\""""
|
|
103
|
+
return await ConversationFacilitator().submit(
|
|
104
|
+
response_model=AttributionDto, user_content=prompt
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
#: The (pole, holder) attribute pairs a tension carries.
|
|
109
|
+
_POLES = (("thesis", "thesis_held_by"), ("antithesis", "antithesis_held_by"))
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
async def drop_unborne_holders(tensions: Sequence[Any], text: str) -> list[str]:
|
|
113
|
+
"""Blank every named holder the text does not bear, IN PLACE, on every
|
|
114
|
+
tension given (the winner and the spares alike — a host serving a
|
|
115
|
+
runner-up must not get the misquotation back). Returns one line per
|
|
116
|
+
holder dropped, for the log. No call where no holder is named; a failed
|
|
117
|
+
judging keeps the holder (fail-soft, see the module)."""
|
|
118
|
+
words = (text or "").strip()
|
|
119
|
+
if not words:
|
|
120
|
+
return []
|
|
121
|
+
jobs: list[tuple[Any, str, str, str]] = []
|
|
122
|
+
for tension in tensions:
|
|
123
|
+
for pole, holder_attr in _POLES:
|
|
124
|
+
holder = (getattr(tension, holder_attr, "") or "").strip()
|
|
125
|
+
position = (getattr(tension, pole, "") or "").strip()
|
|
126
|
+
if holder and position:
|
|
127
|
+
jobs.append((tension, pole, holder_attr, holder))
|
|
128
|
+
|
|
129
|
+
async def one(job: tuple[Any, str, str, str]) -> bool:
|
|
130
|
+
tension, pole, _attr, holder = job
|
|
131
|
+
try:
|
|
132
|
+
dto = await AttributionCheck().score_texts(
|
|
133
|
+
position=getattr(tension, pole), held_by=holder, text=words
|
|
134
|
+
)
|
|
135
|
+
except Exception as exc: # noqa: BLE001 — not judged, the holder stays
|
|
136
|
+
logger.warning("Checking a pole's holder failed; it stays: %s", exc)
|
|
137
|
+
return False
|
|
138
|
+
if not isinstance(dto, AttributionDto):
|
|
139
|
+
return False
|
|
140
|
+
return dto.verdict == "not_attributed"
|
|
141
|
+
|
|
142
|
+
verdicts = await asyncio.gather(*(one(j) for j in jobs))
|
|
143
|
+
dropped: list[str] = []
|
|
144
|
+
for (tension, pole, holder_attr, holder), unborne in zip(jobs, verdicts):
|
|
145
|
+
if unborne:
|
|
146
|
+
setattr(tension, holder_attr, "")
|
|
147
|
+
dropped.append(f"{pole} held_by {holder!r}: the words do not bear it")
|
|
148
|
+
return dropped
|