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.
- {socratic_engine-0.2.2/socratic_engine.egg-info → socratic_engine-0.2.4}/PKG-INFO +112 -11
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/README.md +110 -9
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/pyproject.toml +3 -3
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine/__init__.py +1 -1
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine/engine.py +51 -1
- socratic_engine-0.2.4/socratic_engine/mcp_server.py +435 -0
- socratic_engine-0.2.4/socratic_engine/multi_bridge.py +528 -0
- socratic_engine-0.2.4/socratic_engine/providers/__init__.py +1 -0
- socratic_engine-0.2.4/socratic_engine/providers/vsm_doc.py +184 -0
- socratic_engine-0.2.4/socratic_engine/semantics.py +230 -0
- {socratic_engine-0.2.2 → socratic_engine-0.2.4/socratic_engine.egg-info}/PKG-INFO +112 -11
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine.egg-info/SOURCES.txt +9 -1
- socratic_engine-0.2.4/tests/test_falsification.py +1501 -0
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/tests/test_mcp_server.py +1 -1
- socratic_engine-0.2.4/tests/test_multi_bridge.py +389 -0
- socratic_engine-0.2.4/tests/test_semantics.py +458 -0
- socratic_engine-0.2.4/tests/test_vsm_doc.py +141 -0
- socratic_engine-0.2.2/socratic_engine/mcp_server.py +0 -249
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/LICENSE +0 -0
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/setup.cfg +0 -0
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine/bridge_statecanon.py +0 -0
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine/cli.py +0 -0
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine/tree.py +0 -0
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine.egg-info/dependency_links.txt +0 -0
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine.egg-info/entry_points.txt +0 -0
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine.egg-info/requires.txt +0 -0
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/socratic_engine.egg-info/top_level.txt +0 -0
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/tests/test_bridge_statecanon.py +0 -0
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/tests/test_cli.py +0 -0
- {socratic_engine-0.2.2 → socratic_engine-0.2.4}/tests/test_engine.py +0 -0
- {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.
|
|
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 ::
|
|
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.
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
│
|
|
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.
|
|
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
|
-
- [
|
|
1014
|
-
- [ ]
|
|
1015
|
-
- [ ]
|
|
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.
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
│
|
|
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.
|
|
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
|
-
- [
|
|
990
|
-
- [ ]
|
|
991
|
-
- [ ]
|
|
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.
|
|
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 ::
|
|
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"]
|
|
@@ -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
|
-
|
|
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
|
|