Skip to content

v0.3.1

Choose a tag to compare

@meob meob released this 13 Aug 07:19
· 52 commits to main since this release
aa1e72b

v0.3.1 — 2026-08-13

Added

  • HTTP API authentication & TLS (integrations/euclid_api.py): opt-in EUCLID_API_KEY (or --api-key) requires Authorization: Bearer <key> on every POST (constant-time check, 401 otherwise, /health stays open for load balancers), and EUCLID_TLS_CERT / EUCLID_TLS_KEY (or --certfile / --keyfile) serve HTTPS directly. Setup and posture documented in docs/PRODUCTION.md → "Authentication & TLS".
  • Python 3.13 and 3.14 support: verified end-to-end (lint, mypy, full test suite) on CPython 3.13 and 3.14; CI matrix now runs on Python 3.10–3.14.
  • Stress & soak benchmark (benchmarks/euclid_bench.py): detects response mixing, KB pollution, and engine errors across periodic restarts; regression detector for the load+query atomicity and the periodic-restart policy.
  • Benchmark documentation: one detail page per benchmark plus a catalog of results and implementation choices (benchmarks/BENCHMARKS.md).
  • SWI-Prolog compatibility matrix: full suite passes on SWI-Prolog 8.4.2, 9.0.4, 9.2.9, and 10.0.2 (benchmarks/docs/06-swi-prolog-versions.md).

Performance

  • KB preload optimization: repeated loads of the same knowledge base skip re-parsing and re-asserting. Python-side parse+translate results are cached per KB source (_translate_cached), and the engine skips the workspace rebuild when the load carries the same kb_hash (reply skipped:true). A repeated identical 20 000-fact KB drops from ~196 ms to ~18 ms per load. assert/retract invalidate the fingerprint.

Fixed

  • Engine workspace sweep is SWI-Prolog 9.x-safe: clear_workspace/0 now retracts only the registered workspace predicates (workspace_predicate/1) instead of every dynamic predicate. On SWI-Prolog 9.x the broad sweep corrupted the autoloader (domain_error(file_type, prolog)); the registry fix is ~19% faster (513 vs ~429 req/s).
  • Periodic engine restart: now fires before the next load, never after a crossing request, so a relaunched engine always receives its workspace first.
  • Load+query atomicity gap: PrologServer.load_and_query holds the lock across both steps — a single atomic exchange; the workers=4 benchmark flips from FAIL to PASS.