socratic-engine 0.2.2__tar.gz → 0.2.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. {socratic_engine-0.2.2/socratic_engine.egg-info → socratic_engine-0.2.4}/PKG-INFO +112 -11
  2. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/README.md +110 -9
  3. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/pyproject.toml +3 -3
  4. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine/__init__.py +1 -1
  5. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine/engine.py +51 -1
  6. socratic_engine-0.2.4/socratic_engine/mcp_server.py +435 -0
  7. socratic_engine-0.2.4/socratic_engine/multi_bridge.py +528 -0
  8. socratic_engine-0.2.4/socratic_engine/providers/__init__.py +1 -0
  9. socratic_engine-0.2.4/socratic_engine/providers/vsm_doc.py +184 -0
  10. socratic_engine-0.2.4/socratic_engine/semantics.py +230 -0
  11. {socratic_engine-0.2.2 → socratic_engine-0.2.4/socratic_engine.egg-info}/PKG-INFO +112 -11
  12. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine.egg-info/SOURCES.txt +9 -1
  13. socratic_engine-0.2.4/tests/test_falsification.py +1501 -0
  14. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/tests/test_mcp_server.py +1 -1
  15. socratic_engine-0.2.4/tests/test_multi_bridge.py +389 -0
  16. socratic_engine-0.2.4/tests/test_semantics.py +458 -0
  17. socratic_engine-0.2.4/tests/test_vsm_doc.py +141 -0
  18. socratic_engine-0.2.2/socratic_engine/mcp_server.py +0 -249
  19. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/LICENSE +0 -0
  20. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/setup.cfg +0 -0
  21. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine/bridge_statecanon.py +0 -0
  22. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine/cli.py +0 -0
  23. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine/tree.py +0 -0
  24. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine.egg-info/dependency_links.txt +0 -0
  25. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine.egg-info/entry_points.txt +0 -0
  26. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine.egg-info/requires.txt +0 -0
  27. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine.egg-info/top_level.txt +0 -0
  28. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/tests/test_bridge_statecanon.py +0 -0
  29. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/tests/test_cli.py +0 -0
  30. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/tests/test_engine.py +0 -0
  31. {socratic_engine-0.2.2 → socratic_engine-0.2.4}/tests/test_state_canon_integration.py +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: socratic-engine
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Externalized epistemic scaffolding for AI agents. Recursive boolean certification trees.
5
5
  License: Apache-2.0
6
6
  Keywords: socratic,epistemic,verification,certification,boolean-trees,trivalent-logic,mcp
7
7
  Classifier: Development Status :: 3 - Alpha
8
8
  Classifier: Intended Audience :: Developers
9
9
  Classifier: Intended Audience :: Science/Research
10
- Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: License :: OSI Approved :: Apache Software License
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
@@ -32,7 +32,7 @@ Dynamic: license-file
32
32
 
33
33
  The engine is deliberately small. It does not try to make an LLM "smarter". It gives the model a formal structure in which complex questioning can be proposed, executed recursively, inspected, and diagnosed **outside the model's token-generation loop**.
34
34
 
35
- **Status:** v0.2.2 published on PyPI — core engine, VSL tree parser, CLI, MCP bridge, dialectical operator, pragmatic predicates, caching, rate limiting, CI (pytest 3.10–3.12 + coverage gate at 90%), benchmarks, a 189-test suite at 100% statement coverage, and the official state-canon bridge ([`bridge_statecanon.py`](./socratic_engine/bridge_statecanon.py)) with end-to-end examples are working. The broader claim — that externalizing recursive structure improves reliability on tasks that exceed a model's implicit recursive reasoning capacity — is an experimental hypothesis, not a proclamation.
35
+ **Status:** v0.2.3 published on PyPI — core engine, VSL tree parser, CLI, MCP bridge, multi-bridge (route canon_* to multiple providers by domain with health tracking + routing observability), VsmDocProvider, dialectical operator, pragmatic predicates, semantic simplification (NOT flattening, contradiction/tautology, dedup, absorption), short-circuit evaluation, tree DoS prevention (depth≤100, nodes≤10K), caching, rate limiting, CI (pytest 3.10–3.12 + coverage gate at 90%), 382-test suite + 46 adversarial tests (6 categories), benchmarks, and the official state-canon bridge ([`bridge_statecanon.py`](./socratic_engine/bridge_statecanon.py)) with end-to-end examples are working. The broader claim — that externalizing recursive structure improves reliability on tasks that exceed a model's implicit recursive reasoning capacity — is an experimental hypothesis, not a proclamation.
36
36
 
37
37
  ---
38
38
 
@@ -647,7 +647,12 @@ The current bridge exposes:
647
647
  | `socratic_build` | validate a proposed reasoning tree |
648
648
  | `socratic_evaluate` | execute a tree against context |
649
649
  | `socratic_diagnose` | return inverse failure traces |
650
- | `socratic_canon_query` | (opt-in) query state-canon through the registered bridge |
650
+ | `socratic_canon_query` | (opt-in) query a data source through the registered bridge |
651
+ | `socratic_canon_matches` | (opt-in, multi-bridge) check if records match expected values |
652
+ | `socratic_canon_field_equals` | (opt-in, multi-bridge) check if a field equals expected value |
653
+ | `socratic_canon_drift` | (opt-in, multi-bridge) detect declared vs observed drift |
654
+ | `socratic_canon_domains` | (opt-in, multi-bridge) list all available domains |
655
+ | `socratic_canon_providers` | (opt-in, multi-bridge) list all registered providers |
651
656
 
652
657
  The MCP layer is intentionally thin.
653
658
 
@@ -709,6 +714,45 @@ The MCP server accepts an optional `provider` (opt-in, R6): when set, the
709
714
  `canon_*` predicates are registered and `socratic_canon_query` appears in
710
715
  `tools/list`.
711
716
 
717
+ ### Multi-bridge (new)
718
+
719
+ For scenarios requiring certification across multiple data sources, the
720
+ `MultiBridge` routes `canon_*` predicates to different providers by domain:
721
+
722
+ ```python
723
+ from socratic_engine.multi_bridge import MultiBridge
724
+
725
+ bridge = MultiBridge()
726
+ bridge.add_provider("agent-state", vsm_provider, ["tasks", "sessions"])
727
+ bridge.add_provider("infra-state", ssh_provider, ["services", "lxcs"])
728
+ bridge.add_provider("vsm-docs", doc_provider, ["boot", "s1-operations"])
729
+ bridge.register(eng)
730
+
731
+ # Now the engine can certify across all domains:
732
+ ev = eng.evaluate({"op": "AND", "children": [
733
+ {"predicate": "canon_query", "args": ["services", '{"name": "api"}']},
734
+ {"predicate": "canon_query", "args": ["boot", '{"name": "covenant"}']},
735
+ ]})
736
+ ```
737
+
738
+ Or load from config:
739
+
740
+ ```bash
741
+ SOCRATIC_BRIDGE_CONFIG=bridge_config.json python -m socratic_engine.mcp_server
742
+ ```
743
+
744
+ **Provider health tracking**: each provider tracks consecutive failures.
745
+ After 3 failures, the provider is marked unhealthy and `canon_providers`
746
+ returns `UNKNOWN`. Failed queries return `UNKNOWN` (not FALSE) — a
747
+ provider crash is indetermination, not falsity.
748
+
749
+ **Routing observability**: every `canon_*` predicate includes routing
750
+ info in its evidence: provider name, domain, latency_ms, record_count.
751
+ This makes provider selection inspectable in the evaluation tree.
752
+
753
+ See [`socratic_engine/multi_bridge.py`](./socratic_engine/multi_bridge.py) for
754
+ the full API and config format.
755
+
712
756
  ---
713
757
 
714
758
  ## CLI
@@ -734,7 +778,7 @@ This makes the same engine usable from:
734
778
 
735
779
  ## Install
736
780
 
737
- ### From PyPI (v0.2.2)
781
+ ### From PyPI (v0.2.3)
738
782
 
739
783
  ```bash
740
784
  pip install socratic-engine
@@ -765,7 +809,7 @@ python3 -m pytest tests/ -q
765
809
  The current repository snapshot passes:
766
810
 
767
811
  ```text
768
- 189 passed
812
+ 382 passed
769
813
  ```
770
814
 
771
815
  at 100% statement coverage (CI gates at 90%; uncovered lines are
@@ -775,6 +819,47 @@ inline in the source).
775
819
  (includes integration tests with `state-canon`, available when that
776
820
  package is installed or reachable at `~/state-canon-mcp`)
777
821
 
822
+ ### Releases (GitHub ↔ PyPI sync)
823
+
824
+ The release pipeline is automated via GitHub Actions
825
+ ([`.github/workflows/release.yml`](./.github/workflows/release.yml)),
826
+ triggered by a tag. To ship a new version:
827
+
828
+ ```bash
829
+ # 1. Bump the version in ALL four places (must match exactly):
830
+ # pyproject.toml → version = "X.Y.Z"
831
+ # socratic_engine/__init__.py → __version__ = "X.Y.Z"
832
+ # socratic_engine/mcp_server.py → serverInfo version
833
+ # tests/test_mcp_server.py → the assert string
834
+ # 2. Update README status + ROADMAP, commit, push to main
835
+ git commit -am "release: vX.Y.Z — <what changed>"
836
+ git push origin main
837
+
838
+ # 3. Tag and push — the workflow verifies tag ↔ pyproject ↔ __init__
839
+ # match, runs the full suite, checks metadata (Apache-2.0 only),
840
+ # publishes to PyPI, and creates the GitHub Release.
841
+ git tag vX.Y.Z
842
+ git push origin vX.Y.Z
843
+ ```
844
+
845
+ Prerequisites (one-time):
846
+ - `PYPI_TOKEN` secret configured in
847
+ **GitHub → Settings → Secrets and variables → Actions**
848
+ (token from https://pypi.org/manage/account/token/)
849
+ - workflow permissions: `contents: write` (set in the workflow file)
850
+
851
+ The workflow FAILS loudly (it does not publish) if:
852
+ - the tag version ≠ pyproject version ≠ `__init__.__version__`
853
+ - the test suite or coverage gate fails
854
+ - the wheel metadata contains anything other than Apache-2.0
855
+ (guard against the MIT-classifier regression that hit 0.2.2)
856
+
857
+ Validated end-to-end 2026-08-19 (tag `v0.2.3` test run):
858
+ sync guard ✓ → suite ✓ → build ✓ → metadata guard ✓ → publish reached
859
+ PyPI with the token authenticated (server answered `400 File already
860
+ exists` for the intentionally-republished version — a bad token would
861
+ have answered 401/403, not 400).
862
+
778
863
  ---
779
864
 
780
865
  ## Repository layout
@@ -797,12 +882,18 @@ socratic-engine/
797
882
  │ ├── tree.py # builder + VSL parser + tree routing
798
883
  │ ├── cli.py # command-line interface
799
884
  │ ├── mcp_server.py # MCP / JSON-RPC bridge + rate limiter
800
- │ └── bridge_statecanon.py # official state-canon bridge (opt-in)
885
+ │ ├── multi_bridge.py # multi-provider routing (canon_* by domain)
886
+ │ ├── bridge_statecanon.py # official state-canon bridge (opt-in)
887
+ │ └── providers/
888
+ │ ├── __init__.py
889
+ │ └── vsm_doc.py # VSM documentation filesystem provider
801
890
  └── tests/
802
891
  ├── test_engine.py
803
892
  ├── test_mcp_server.py
804
893
  ├── test_cli.py
805
894
  ├── test_bridge_statecanon.py
895
+ ├── test_multi_bridge.py
896
+ ├── test_vsm_doc.py
806
897
  └── test_state_canon_integration.py
807
898
  ```
808
899
 
@@ -1005,14 +1096,24 @@ Its purpose is narrower:
1005
1096
  - [x] dialectical operator for legitimate contradictions
1006
1097
  - [x] temporal / pragmatic predicates
1007
1098
  - [x] caching and rate limiting for expensive predicates
1008
- - [x] published on PyPI (v0.2.0 → v0.2.2; bridge + ejemplos incluidos desde 0.2.2)
1099
+ - [x] published on PyPI (v0.2.0 → v0.2.3; bridge + ejemplos desde 0.2.2; license metadata Apache-only desde 0.2.3)
1009
1100
  - [x] official state-canon bridge + end-to-end examples (Claude Code, OpenCode)
1101
+ - [x] multi-bridge: route canon_* predicates to multiple providers by domain
1102
+ - [x] VsmDocProvider: VSM documentation as queryable records
1103
+ - [x] config-driven provider loading (bridge_config.json)
1104
+ - [x] provider health tracking (3-failure threshold → UNKNOWN)
1105
+ - [x] routing observability (provider, domain, latency, record count in evidence)
1106
+ - [x] semantic simplification: NOT flattening, contradiction/tautology, dedup, absorption
1107
+ - [x] short-circuit evaluation (AND stops at first FALSE, OR at first certified TRUE)
1108
+ - [x] tree DoS prevention (depth ≤ 100, nodes ≤ 10,000)
1109
+ - [x] 382-test suite + 46 adversarial tests (6 categories)
1010
1110
 
1011
1111
  ### v0.3.x — formal extension
1012
1112
 
1013
- - [ ] paraconsistent logic
1014
- - [ ] contextual / frame semantics
1015
- - [ ] stakeholder participation graphs
1113
+ - [x] DIALECTICAL_AND — certified contradiction (exists since v0.1)
1114
+ - [ ] paraconsistent logic (full: beyond pairwise contradiction)
1115
+ - [ ] contextual / frame semantics (hermeneutica: meaning from context)
1116
+ - [ ] stakeholder participation graphs (discursive ethics)
1016
1117
  - [ ] formal VSM → Socratic Engine derivation
1017
1118
 
1018
1119
  The roadmap is intentionally open: the next features should be driven by failures observed in the experimental programme, not by feature accumulation.
@@ -8,7 +8,7 @@
8
8
 
9
9
  The engine is deliberately small. It does not try to make an LLM "smarter". It gives the model a formal structure in which complex questioning can be proposed, executed recursively, inspected, and diagnosed **outside the model's token-generation loop**.
10
10
 
11
- **Status:** v0.2.2 published on PyPI — core engine, VSL tree parser, CLI, MCP bridge, dialectical operator, pragmatic predicates, caching, rate limiting, CI (pytest 3.10–3.12 + coverage gate at 90%), benchmarks, a 189-test suite at 100% statement coverage, and the official state-canon bridge ([`bridge_statecanon.py`](./socratic_engine/bridge_statecanon.py)) with end-to-end examples are working. The broader claim — that externalizing recursive structure improves reliability on tasks that exceed a model's implicit recursive reasoning capacity — is an experimental hypothesis, not a proclamation.
11
+ **Status:** v0.2.3 published on PyPI — core engine, VSL tree parser, CLI, MCP bridge, multi-bridge (route canon_* to multiple providers by domain with health tracking + routing observability), VsmDocProvider, dialectical operator, pragmatic predicates, semantic simplification (NOT flattening, contradiction/tautology, dedup, absorption), short-circuit evaluation, tree DoS prevention (depth≤100, nodes≤10K), caching, rate limiting, CI (pytest 3.10–3.12 + coverage gate at 90%), 382-test suite + 46 adversarial tests (6 categories), benchmarks, and the official state-canon bridge ([`bridge_statecanon.py`](./socratic_engine/bridge_statecanon.py)) with end-to-end examples are working. The broader claim — that externalizing recursive structure improves reliability on tasks that exceed a model's implicit recursive reasoning capacity — is an experimental hypothesis, not a proclamation.
12
12
 
13
13
  ---
14
14
 
@@ -623,7 +623,12 @@ The current bridge exposes:
623
623
  | `socratic_build` | validate a proposed reasoning tree |
624
624
  | `socratic_evaluate` | execute a tree against context |
625
625
  | `socratic_diagnose` | return inverse failure traces |
626
- | `socratic_canon_query` | (opt-in) query state-canon through the registered bridge |
626
+ | `socratic_canon_query` | (opt-in) query a data source through the registered bridge |
627
+ | `socratic_canon_matches` | (opt-in, multi-bridge) check if records match expected values |
628
+ | `socratic_canon_field_equals` | (opt-in, multi-bridge) check if a field equals expected value |
629
+ | `socratic_canon_drift` | (opt-in, multi-bridge) detect declared vs observed drift |
630
+ | `socratic_canon_domains` | (opt-in, multi-bridge) list all available domains |
631
+ | `socratic_canon_providers` | (opt-in, multi-bridge) list all registered providers |
627
632
 
628
633
  The MCP layer is intentionally thin.
629
634
 
@@ -685,6 +690,45 @@ The MCP server accepts an optional `provider` (opt-in, R6): when set, the
685
690
  `canon_*` predicates are registered and `socratic_canon_query` appears in
686
691
  `tools/list`.
687
692
 
693
+ ### Multi-bridge (new)
694
+
695
+ For scenarios requiring certification across multiple data sources, the
696
+ `MultiBridge` routes `canon_*` predicates to different providers by domain:
697
+
698
+ ```python
699
+ from socratic_engine.multi_bridge import MultiBridge
700
+
701
+ bridge = MultiBridge()
702
+ bridge.add_provider("agent-state", vsm_provider, ["tasks", "sessions"])
703
+ bridge.add_provider("infra-state", ssh_provider, ["services", "lxcs"])
704
+ bridge.add_provider("vsm-docs", doc_provider, ["boot", "s1-operations"])
705
+ bridge.register(eng)
706
+
707
+ # Now the engine can certify across all domains:
708
+ ev = eng.evaluate({"op": "AND", "children": [
709
+ {"predicate": "canon_query", "args": ["services", '{"name": "api"}']},
710
+ {"predicate": "canon_query", "args": ["boot", '{"name": "covenant"}']},
711
+ ]})
712
+ ```
713
+
714
+ Or load from config:
715
+
716
+ ```bash
717
+ SOCRATIC_BRIDGE_CONFIG=bridge_config.json python -m socratic_engine.mcp_server
718
+ ```
719
+
720
+ **Provider health tracking**: each provider tracks consecutive failures.
721
+ After 3 failures, the provider is marked unhealthy and `canon_providers`
722
+ returns `UNKNOWN`. Failed queries return `UNKNOWN` (not FALSE) — a
723
+ provider crash is indetermination, not falsity.
724
+
725
+ **Routing observability**: every `canon_*` predicate includes routing
726
+ info in its evidence: provider name, domain, latency_ms, record_count.
727
+ This makes provider selection inspectable in the evaluation tree.
728
+
729
+ See [`socratic_engine/multi_bridge.py`](./socratic_engine/multi_bridge.py) for
730
+ the full API and config format.
731
+
688
732
  ---
689
733
 
690
734
  ## CLI
@@ -710,7 +754,7 @@ This makes the same engine usable from:
710
754
 
711
755
  ## Install
712
756
 
713
- ### From PyPI (v0.2.2)
757
+ ### From PyPI (v0.2.3)
714
758
 
715
759
  ```bash
716
760
  pip install socratic-engine
@@ -741,7 +785,7 @@ python3 -m pytest tests/ -q
741
785
  The current repository snapshot passes:
742
786
 
743
787
  ```text
744
- 189 passed
788
+ 382 passed
745
789
  ```
746
790
 
747
791
  at 100% statement coverage (CI gates at 90%; uncovered lines are
@@ -751,6 +795,47 @@ inline in the source).
751
795
  (includes integration tests with `state-canon`, available when that
752
796
  package is installed or reachable at `~/state-canon-mcp`)
753
797
 
798
+ ### Releases (GitHub ↔ PyPI sync)
799
+
800
+ The release pipeline is automated via GitHub Actions
801
+ ([`.github/workflows/release.yml`](./.github/workflows/release.yml)),
802
+ triggered by a tag. To ship a new version:
803
+
804
+ ```bash
805
+ # 1. Bump the version in ALL four places (must match exactly):
806
+ # pyproject.toml → version = "X.Y.Z"
807
+ # socratic_engine/__init__.py → __version__ = "X.Y.Z"
808
+ # socratic_engine/mcp_server.py → serverInfo version
809
+ # tests/test_mcp_server.py → the assert string
810
+ # 2. Update README status + ROADMAP, commit, push to main
811
+ git commit -am "release: vX.Y.Z — <what changed>"
812
+ git push origin main
813
+
814
+ # 3. Tag and push — the workflow verifies tag ↔ pyproject ↔ __init__
815
+ # match, runs the full suite, checks metadata (Apache-2.0 only),
816
+ # publishes to PyPI, and creates the GitHub Release.
817
+ git tag vX.Y.Z
818
+ git push origin vX.Y.Z
819
+ ```
820
+
821
+ Prerequisites (one-time):
822
+ - `PYPI_TOKEN` secret configured in
823
+ **GitHub → Settings → Secrets and variables → Actions**
824
+ (token from https://pypi.org/manage/account/token/)
825
+ - workflow permissions: `contents: write` (set in the workflow file)
826
+
827
+ The workflow FAILS loudly (it does not publish) if:
828
+ - the tag version ≠ pyproject version ≠ `__init__.__version__`
829
+ - the test suite or coverage gate fails
830
+ - the wheel metadata contains anything other than Apache-2.0
831
+ (guard against the MIT-classifier regression that hit 0.2.2)
832
+
833
+ Validated end-to-end 2026-08-19 (tag `v0.2.3` test run):
834
+ sync guard ✓ → suite ✓ → build ✓ → metadata guard ✓ → publish reached
835
+ PyPI with the token authenticated (server answered `400 File already
836
+ exists` for the intentionally-republished version — a bad token would
837
+ have answered 401/403, not 400).
838
+
754
839
  ---
755
840
 
756
841
  ## Repository layout
@@ -773,12 +858,18 @@ socratic-engine/
773
858
  │ ├── tree.py # builder + VSL parser + tree routing
774
859
  │ ├── cli.py # command-line interface
775
860
  │ ├── mcp_server.py # MCP / JSON-RPC bridge + rate limiter
776
- │ └── bridge_statecanon.py # official state-canon bridge (opt-in)
861
+ │ ├── multi_bridge.py # multi-provider routing (canon_* by domain)
862
+ │ ├── bridge_statecanon.py # official state-canon bridge (opt-in)
863
+ │ └── providers/
864
+ │ ├── __init__.py
865
+ │ └── vsm_doc.py # VSM documentation filesystem provider
777
866
  └── tests/
778
867
  ├── test_engine.py
779
868
  ├── test_mcp_server.py
780
869
  ├── test_cli.py
781
870
  ├── test_bridge_statecanon.py
871
+ ├── test_multi_bridge.py
872
+ ├── test_vsm_doc.py
782
873
  └── test_state_canon_integration.py
783
874
  ```
784
875
 
@@ -981,14 +1072,24 @@ Its purpose is narrower:
981
1072
  - [x] dialectical operator for legitimate contradictions
982
1073
  - [x] temporal / pragmatic predicates
983
1074
  - [x] caching and rate limiting for expensive predicates
984
- - [x] published on PyPI (v0.2.0 → v0.2.2; bridge + ejemplos incluidos desde 0.2.2)
1075
+ - [x] published on PyPI (v0.2.0 → v0.2.3; bridge + ejemplos desde 0.2.2; license metadata Apache-only desde 0.2.3)
985
1076
  - [x] official state-canon bridge + end-to-end examples (Claude Code, OpenCode)
1077
+ - [x] multi-bridge: route canon_* predicates to multiple providers by domain
1078
+ - [x] VsmDocProvider: VSM documentation as queryable records
1079
+ - [x] config-driven provider loading (bridge_config.json)
1080
+ - [x] provider health tracking (3-failure threshold → UNKNOWN)
1081
+ - [x] routing observability (provider, domain, latency, record count in evidence)
1082
+ - [x] semantic simplification: NOT flattening, contradiction/tautology, dedup, absorption
1083
+ - [x] short-circuit evaluation (AND stops at first FALSE, OR at first certified TRUE)
1084
+ - [x] tree DoS prevention (depth ≤ 100, nodes ≤ 10,000)
1085
+ - [x] 382-test suite + 46 adversarial tests (6 categories)
986
1086
 
987
1087
  ### v0.3.x — formal extension
988
1088
 
989
- - [ ] paraconsistent logic
990
- - [ ] contextual / frame semantics
991
- - [ ] stakeholder participation graphs
1089
+ - [x] DIALECTICAL_AND — certified contradiction (exists since v0.1)
1090
+ - [ ] paraconsistent logic (full: beyond pairwise contradiction)
1091
+ - [ ] contextual / frame semantics (hermeneutica: meaning from context)
1092
+ - [ ] stakeholder participation graphs (discursive ethics)
992
1093
  - [ ] formal VSM → Socratic Engine derivation
993
1094
 
994
1095
  The roadmap is intentionally open: the next features should be driven by failures observed in the experimental programme, not by feature accumulation.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "socratic-engine"
7
- version = "0.2.2"
7
+ version = "0.2.4"
8
8
  description = "Externalized epistemic scaffolding for AI agents. Recursive boolean certification trees."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -14,7 +14,7 @@ classifiers = [
14
14
  "Development Status :: 3 - Alpha",
15
15
  "Intended Audience :: Developers",
16
16
  "Intended Audience :: Science/Research",
17
- "License :: OSI Approved :: MIT License",
17
+ "License :: OSI Approved :: Apache Software License",
18
18
  "Programming Language :: Python :: 3",
19
19
  "Programming Language :: Python :: 3.10",
20
20
  "Programming Language :: Python :: 3.11",
@@ -32,7 +32,7 @@ socratic-engine = "socratic_engine.cli:main"
32
32
  socratic-engine-mcp = "socratic_engine.mcp_server:main"
33
33
 
34
34
  [tool.setuptools]
35
- packages = ["socratic_engine"]
35
+ packages = ["socratic_engine", "socratic_engine.providers"]
36
36
 
37
37
  [tool.pytest.ini_options]
38
38
  testpaths = ["tests"]
@@ -56,4 +56,4 @@ __all__ = [
56
56
  "tree_home",
57
57
  ]
58
58
 
59
- __version__ = "0.2.2"
59
+ __version__ = "0.2.4"
@@ -593,6 +593,47 @@ class SocraticEngine:
593
593
  # Evaluación de operadores lógicos
594
594
  # --------------------------------------------------------
595
595
 
596
+ def _evaluate_short_circuit(
597
+ self,
598
+ children_nodes: List[Any],
599
+ ctx: Dict[str, Any],
600
+ stop_on: Truth,
601
+ ) -> List[Evaluation]:
602
+ """Evaluate children lazily, stopping on a DECISIVE result.
603
+
604
+ For AND: stop on first FALSE (always decisive).
605
+ For OR: stop on first certified TRUE (uncertified TRUE is not
606
+ decisive — a later sibling may be certified).
607
+
608
+ Unevaluated children are recorded as UNKNOWN with source
609
+ 'short_circuit'. If we exhaust all children without a decisive
610
+ stop, returns full list (caller applies _apply_operator as usual).
611
+ """
612
+ children: List[Evaluation] = []
613
+ for child_node in children_nodes:
614
+ ev = self.evaluate(child_node, ctx)
615
+ children.append(ev)
616
+
617
+ if stop_on == Truth.FALSE:
618
+ # AND: FALSE is always decisive
619
+ if ev.truth == Truth.FALSE:
620
+ for _ in children_nodes[len(children):]:
621
+ children.append(Evaluation(
622
+ truth=Truth.UNKNOWN, certified=False,
623
+ source="short_circuit", context=ctx.copy(),
624
+ ))
625
+ break
626
+ elif stop_on == Truth.TRUE:
627
+ # OR: certified TRUE is decisive; uncertified is NOT
628
+ if ev.truth == Truth.TRUE and ev.certified:
629
+ for _ in children_nodes[len(children):]:
630
+ children.append(Evaluation(
631
+ truth=Truth.UNKNOWN, certified=False,
632
+ source="short_circuit", context=ctx.copy(),
633
+ ))
634
+ break
635
+ return children
636
+
596
637
  def _evaluate_operator(
597
638
  self,
598
639
  node: Dict[str, Any],
@@ -603,7 +644,16 @@ class SocraticEngine:
603
644
  raise ValueError(f"Operador desconocido: {op}")
604
645
 
605
646
  children_nodes = node.get("children", [])
606
- children = [self.evaluate(child, ctx) for child in children_nodes]
647
+
648
+ # Short-circuit evaluation for AND/OR (semantic optimization)
649
+ if op == "AND":
650
+ children = self._evaluate_short_circuit(children_nodes, ctx,
651
+ stop_on=Truth.FALSE)
652
+ elif op == "OR":
653
+ children = self._evaluate_short_circuit(children_nodes, ctx,
654
+ stop_on=Truth.TRUE)
655
+ else:
656
+ children = [self.evaluate(child, ctx) for child in children_nodes]
607
657
 
608
658
  truth = self._apply_operator(op, children)
609
659