clm-kernel 0.0.0__py3-none-any.whl
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.
- clm/__init__.py +230 -0
- clm/__main__.py +25 -0
- clm/cross_cutting/__init__.py +50 -0
- clm/cross_cutting/_test_runner.py +36 -0
- clm/cross_cutting/async_utils.py +25 -0
- clm/cross_cutting/cel_builder.py +123 -0
- clm/cross_cutting/cel_converter.py +697 -0
- clm/cross_cutting/cel_engine.py +252 -0
- clm/cross_cutting/cel_ops.py +72 -0
- clm/cross_cutting/cel_ops_db.py +157 -0
- clm/cross_cutting/cel_ops_files.py +99 -0
- clm/cross_cutting/cel_ops_state.py +71 -0
- clm/cross_cutting/cel_ops_strings.py +64 -0
- clm/cross_cutting/cel_resolver.py +63 -0
- clm/cross_cutting/cel_slices.py +56 -0
- clm/cross_cutting/cel_store.py +330 -0
- clm/cross_cutting/clm_logger.py +140 -0
- clm/cross_cutting/config/__init__.py +155 -0
- clm/cross_cutting/config/config_constants.py +392 -0
- clm/cross_cutting/config/env_parameters.py +90 -0
- clm/cross_cutting/config/logging.py +378 -0
- clm/cross_cutting/config/settings.py +504 -0
- clm/cross_cutting/context.py +5 -0
- clm/cross_cutting/domain_models.py +55 -0
- clm/cross_cutting/domain_types.py +61 -0
- clm/cross_cutting/effects.py +67 -0
- clm/cross_cutting/errors.py +153 -0
- clm/cross_cutting/governance.py +331 -0
- clm/cross_cutting/guards.py +41 -0
- clm/cross_cutting/mcard.py +321 -0
- clm/cross_cutting/native.py +185 -0
- clm/cross_cutting/observability.py +289 -0
- clm/cross_cutting/pcard.py +434 -0
- clm/cross_cutting/registry.py +71 -0
- clm/cross_cutting/resources.py +84 -0
- clm/cross_cutting/secrets.py +44 -0
- clm/cross_cutting/subprocess_utils.py +118 -0
- clm/cross_cutting/telemetry.py +164 -0
- clm/cross_cutting/testing/__init__.py +8 -0
- clm/cross_cutting/testing/comparator.py +187 -0
- clm/cross_cutting/testing/datasets.py +87 -0
- clm/cross_cutting/timeutil.py +20 -0
- clm/cross_cutting/types/new_type_check.py +0 -0
- clm/cross_cutting/utils/__init__.py +1 -0
- clm/cross_cutting/utils/url_safety.py +50 -0
- clm/cross_cutting/vcard.py +560 -0
- clm/cross_cutting/writer.py +118 -0
- clm/layer0/README.md +50 -0
- clm/layer0/__init__.py +223 -0
- clm/layer0/algebra.py +60 -0
- clm/layer0/algebra_baldwin.py +133 -0
- clm/layer0/algebra_baldwin_generators.py +36 -0
- clm/layer0/algebra_equivalence.py +262 -0
- clm/layer0/algebra_ingest.py +306 -0
- clm/layer0/algebra_manifest_io.py +156 -0
- clm/layer0/assembler.py +481 -0
- clm/layer0/cel/__init__.py +23 -0
- clm/layer0/cel_eval.py +491 -0
- clm/layer0/codec.py +106 -0
- clm/layer0/context.py +122 -0
- clm/layer0/db.py +160 -0
- clm/layer0/exceptions.py +73 -0
- clm/layer0/fibration.py +106 -0
- clm/layer0/gates.py +50 -0
- clm/layer0/hash.py +80 -0
- clm/layer0/loader.py +826 -0
- clm/layer0/math_utils.py +163 -0
- clm/layer0/mcard.py +96 -0
- clm/layer0/model/__init__.py +0 -0
- clm/layer0/model/action.py +223 -0
- clm/layer0/model/card.py +280 -0
- clm/layer0/model/card_triad.py +427 -0
- clm/layer0/model/compatibility.py +60 -0
- clm/layer0/model/dictionary.py +46 -0
- clm/layer0/model/dots.py +331 -0
- clm/layer0/model/event_producer.py +88 -0
- clm/layer0/model/g_time.py +89 -0
- clm/layer0/model/handle.py +163 -0
- clm/layer0/model/hash/__init__.py +6 -0
- clm/layer0/model/hash/algorithms/__init__.py +3 -0
- clm/layer0/model/hash/algorithms/custom_hash.py +7 -0
- clm/layer0/model/hash/algorithms/local_sha256.py +178 -0
- clm/layer0/model/hash/constants.py +53 -0
- clm/layer0/model/hash/enums.py +60 -0
- clm/layer0/model/hash/validator.py +307 -0
- clm/layer0/model/interpreter.py +275 -0
- clm/layer0/model/pagination.py +45 -0
- clm/layer0/model/pcard.py +716 -0
- clm/layer0/model/schema.py +44 -0
- clm/layer0/model/utils/__init__.py +1 -0
- clm/layer0/model/utils/content_analyzer.py +152 -0
- clm/layer0/model/validators/__init__.py +1 -0
- clm/layer0/model/validators/base_validator.py +44 -0
- clm/layer0/model/validators/binary_validator.py +66 -0
- clm/layer0/model/validators/text_validator.py +82 -0
- clm/layer0/model/validators/validation_registry.py +49 -0
- clm/layer0/model/vcard.py +823 -0
- clm/layer0/model/vcard_ext/__init__.py +39 -0
- clm/layer0/model/vcard_ext/core.py +60 -0
- clm/layer0/model/vcard_ext/network.py +23 -0
- clm/layer0/model/vcard_ext/observability.py +63 -0
- clm/layer0/model/vcard_ext/storage.py +60 -0
- clm/layer0/model/vcard_ext/vendors.py +211 -0
- clm/layer0/model/vcard_sandwich.py +119 -0
- clm/layer0/model/vcard_vocabulary.py +463 -0
- clm/layer0/model/workflow.py +274 -0
- clm/layer0/narrative.py +431 -0
- clm/layer0/ontology/collection.py +125 -0
- clm/layer0/parser.py +429 -0
- clm/layer0/relations.py +73 -0
- clm/layer0/rule_evaluator.py +251 -0
- clm/layer0/schema/__init__.py +38 -0
- clm/layer0/schema/ddl.py +97 -0
- clm/layer0/templates/abstract.yaml +99 -0
- clm/layer0/templates/balanced.yaml +253 -0
- clm/layer0/templates/concrete.yaml +172 -0
- clm/layer0/type_registry.py +223 -0
- clm/layer0/types.py +204 -0
- clm/layer0/utils.py +886 -0
- clm/layer0/verifier_core.py +262 -0
- clm/layer1/__init__.py +31 -0
- clm/layer1/action_dispatcher.py +275 -0
- clm/layer1/adapter_registry.py +233 -0
- clm/layer1/algebra_baldwin_generators.py +192 -0
- clm/layer1/arrow_compiler.py +525 -0
- clm/layer1/batch_processor.py +152 -0
- clm/layer1/cel/__init__.py +27 -0
- clm/layer1/cel/builder.py +173 -0
- clm/layer1/engine.py +759 -0
- clm/layer1/engine_async.py +89 -0
- clm/layer1/eval_callback.py +49 -0
- clm/layer1/gate_composer.py +229 -0
- clm/layer1/hoare_sandwich.py +298 -0
- clm/layer1/identity_guard.py +348 -0
- clm/layer1/matrix.py +138 -0
- clm/layer1/neural_runtime.py +221 -0
- clm/layer1/operations/__init__.py +123 -0
- clm/layer1/operations/augment.py +156 -0
- clm/layer1/operations/base.py +109 -0
- clm/layer1/operations/builtins.py +338 -0
- clm/layer1/operations/dispatch.py +144 -0
- clm/layer1/operations/exclude.py +107 -0
- clm/layer1/operations/handle.py +197 -0
- clm/layer1/operations/identity.py +139 -0
- clm/layer1/operations/invert.py +66 -0
- clm/layer1/operations/loader.py +116 -0
- clm/layer1/operations/manipulators/__init__.py +23 -0
- clm/layer1/operations/manipulators/document.py +211 -0
- clm/layer1/operations/manipulators/media.py +134 -0
- clm/layer1/operations/manipulators/structured.py +159 -0
- clm/layer1/operations/manipulators/tabular.py +334 -0
- clm/layer1/operations/port.py +65 -0
- clm/layer1/operations/services.py +529 -0
- clm/layer1/operations/split.py +117 -0
- clm/layer1/operations/substitute.py +75 -0
- clm/layer1/petri.py +1052 -0
- clm/layer1/pocketflow_orchestrator.py +408 -0
- clm/layer1/pocketflow_scheduler.py +519 -0
- clm/layer1/protocols.py +197 -0
- clm/layer1/runtime_adapter.py +718 -0
- clm/layer1/runtimes/__init__.py +71 -0
- clm/layer1/runtimes/_generated_assertions.py +125 -0
- clm/layer1/runtimes/_generated_types.py +42 -0
- clm/layer1/runtimes/base.py +265 -0
- clm/layer1/runtimes/binary.py +101 -0
- clm/layer1/runtimes/factory.py +203 -0
- clm/layer1/runtimes/javascript.py +321 -0
- clm/layer1/runtimes/javascript_runtime.js +33 -0
- clm/layer1/runtimes/js_scripts/isomorphism.mjs +22 -0
- clm/layer1/runtimes/js_scripts/loader.mjs +52 -0
- clm/layer1/runtimes/lambda_calc.py +126 -0
- clm/layer1/runtimes/python.py +288 -0
- clm/layer1/runtimes/python_runtime.py +41 -0
- clm/layer1/runtimes/script.py +114 -0
- clm/layer1/sandbox.py +334 -0
- clm/layer1/savepoint_guard.py +136 -0
- clm/layer1/sparse_net.py +122 -0
- clm/layer1/spec_tester.py +165 -0
- clm/layer1/store.py +295 -0
- clm/layer1/test_runner.py +498 -0
- clm/layer1/type_inspector.py +166 -0
- clm/layer1/verifier.py +772 -0
- clm/layer1/vm.py +91 -0
- clm/layer2/__init__.py +78 -0
- clm/layer2/card_collection.py +678 -0
- clm/layer2/classifier.py +479 -0
- clm/layer2/engine/__init__.py +1 -0
- clm/layer2/engine/abstract_sql_engine.py +320 -0
- clm/layer2/engine/base.py +193 -0
- clm/layer2/engine/duckdb_engine.py +576 -0
- clm/layer2/engine/sqlite_engine.py +518 -0
- clm/layer2/fiber/__init__.py +31 -0
- clm/layer2/fiber/context.py +89 -0
- clm/layer2/fiber/disposable.py +163 -0
- clm/layer2/fiber/fiber.py +125 -0
- clm/layer2/fiber/hoare.py +191 -0
- clm/layer2/file_io.py +376 -0
- clm/layer2/file_registrar.py +77 -0
- clm/layer2/ingest.py +202 -0
- clm/layer2/lineage.py +322 -0
- clm/layer2/mcard_fs.py +262 -0
- clm/layer2/merkle.py +11 -0
- clm/layer2/mime.py +244 -0
- clm/layer2/mime_detector.py +245 -0
- clm/layer2/private_collection.py +118 -0
- clm/layer2/shared_store.py +11 -0
- clm/layer2/storage/__init__.py +190 -0
- clm/layer2/storage/db_bitemporal.py +141 -0
- clm/layer2/storage/db_driver.py +331 -0
- clm/layer2/storage/db_hyperlinks.py +214 -0
- clm/layer2/storage/db_pool.py +139 -0
- clm/layer2/storage/db_repository.py +229 -0
- clm/layer2/storage/savepoint.py +78 -0
- clm/layer2/storage/sqlite_wal.py +74 -0
- clm/layer2/tridb.py +245 -0
- clm/layer2/vcard_receipt.py +71 -0
- clm/layer2/vfs.py +17 -0
- clm/layer3/__init__.py +141 -0
- clm/layer3/agency/__init__.py +19 -0
- clm/layer3/agency/config.py +220 -0
- clm/layer3/agency/providers/__init__.py +15 -0
- clm/layer3/agency/providers/base.py +91 -0
- clm/layer3/agency/providers/mlc_llm.py +169 -0
- clm/layer3/agency/providers/ollama.py +203 -0
- clm/layer3/agency/router.py +71 -0
- clm/layer3/agency/runtime.py +524 -0
- clm/layer3/gateway.py +353 -0
- clm/layer3/open_interpreter_adapter.py +159 -0
- clm/layer3/rag/__init__.py +70 -0
- clm/layer3/rag/cli.py +228 -0
- clm/layer3/rag/config.py +153 -0
- clm/layer3/rag/embeddings/__init__.py +16 -0
- clm/layer3/rag/embeddings/base.py +79 -0
- clm/layer3/rag/embeddings/ollama.py +211 -0
- clm/layer3/rag/embeddings/vision.py +290 -0
- clm/layer3/rag/engine.py +276 -0
- clm/layer3/rag/graph/__init__.py +22 -0
- clm/layer3/rag/graph/community.py +198 -0
- clm/layer3/rag/graph/engine.py +433 -0
- clm/layer3/rag/graph/extractor.py +255 -0
- clm/layer3/rag/graph/schema.py +115 -0
- clm/layer3/rag/graph/store.py +641 -0
- clm/layer3/rag/indexer.py +333 -0
- clm/layer3/rag/llm_providers.json +52 -0
- clm/layer3/rag/semantic_versioning.py +313 -0
- clm/layer3/rag/vector/__init__.py +28 -0
- clm/layer3/rag/vector/handle_vector_store.py +749 -0
- clm/layer3/rag/vector/schema.py +151 -0
- clm/layer3/rag/vector/store.py +632 -0
- clm/layer3/reticulum/__init__.py +55 -0
- clm/layer3/reticulum/bridge.py +74 -0
- clm/layer3/reticulum/daemon.py +88 -0
- clm/layer3/reticulum/discovery.py +164 -0
- clm/layer3/reticulum/identity.py +107 -0
- clm/layer3/reticulum/media.py +148 -0
- clm/layer3/reticulum/transport.py +133 -0
- clm/layer3/satori/__init__.py +209 -0
- clm/layer3/satori/alpha_conversion.py +168 -0
- clm/layer3/satori/beta_reduction.py +359 -0
- clm/layer3/satori/continuation.py +38 -0
- clm/layer3/satori/eta_conversion.py +205 -0
- clm/layer3/satori/free_variables.py +163 -0
- clm/layer3/satori/io_effects.py +370 -0
- clm/layer3/satori/lambda_runtime.py +726 -0
- clm/layer3/satori/lambda_term.py +230 -0
- clm/layer3/satori/sheaf_audit.py +261 -0
- clm/layer3/satori/speech_act.py +279 -0
- clm/layer4/README.md +9 -0
- clm/layer4/__init__.py +67 -0
- clm/layer4/_sovereign_executor.py +580 -0
- clm/layer4/action_commands.py +719 -0
- clm/layer4/api.py +236 -0
- clm/layer4/bootstrap/__init__.py +13 -0
- clm/layer4/bootstrap/bootstrapper.py +118 -0
- clm/layer4/bootstrap/cleanup.py +44 -0
- clm/layer4/bootstrap/clm_hooks.py +49 -0
- clm/layer4/bootstrap/genesis.py +77 -0
- clm/layer4/bootstrap/injection.py +125 -0
- clm/layer4/cli.py +549 -0
- clm/layer4/collection_manager.py +553 -0
- clm/layer4/commands/__init__.py +81 -0
- clm/layer4/commands/action_cmd.py +42 -0
- clm/layer4/commands/check_cmd.py +82 -0
- clm/layer4/commands/envelope.py +73 -0
- clm/layer4/commands/evaluate_cmd.py +224 -0
- clm/layer4/commands/mcard_cmd.py +24 -0
- clm/layer4/commands/petri_cmd.py +92 -0
- clm/layer4/commands/tridb_cmd.py +319 -0
- clm/layer4/commands/version_cmd.py +27 -0
- clm/layer4/diff_commands.py +167 -0
- clm/layer4/eoa_sponsor.py +232 -0
- clm/layer4/events.py +69 -0
- clm/layer4/flux_gateway.py +133 -0
- clm/layer4/gateway.py +91 -0
- clm/layer4/loader.py +307 -0
- clm/layer4/mcard_commands.py +166 -0
- clm/layer4/membrane.py +273 -0
- clm/layer4/navigation.py +50 -0
- clm/layer4/protocol/protocol_entry_python.py +108 -0
- clm/layer4/protocol/python_sync.py +126 -0
- clm/layer4/runner.py +150 -0
- clm/layer4/satori.py +262 -0
- clm/layer4/server/python_sync_client.py +150 -0
- clm/layer4/server/python_sync_server.py +139 -0
- clm/layer4/server/service_api.py +315 -0
- clm/layer4/server/start_servers.py +107 -0
- clm/layer4/server/stop_servers.py +24 -0
- clm/layer4/simulated_optimization_fix.py +0 -0
- clm/layer4/storage.py +463 -0
- clm/layer4/tridb_admin.py +268 -0
- clm/layer4/websocket/test_ws_client.py +104 -0
- clm/layer4/websocket/test_ws_server.py +138 -0
- clm/layer4/websocket/ws_server_local.py +160 -0
- clm/layer5/__init__.py +51 -0
- clm/layer5/async_batch_writer.py +133 -0
- clm/layer5/learning.py +276 -0
- clm/layer5/telemetry_hook.py +107 -0
- clm/layer5/type_lattice.py +238 -0
- clm/py.typed +0 -0
- clm/schemas/__init__.py +652 -0
- clm/schemas/abstract_face_schema.yaml +77 -0
- clm/schemas/cel_schema.yaml +416 -0
- clm/schemas/lifecycle/__init__.py +45 -0
- clm/schemas/lifecycle/models.py +123 -0
- clm/schemas/lifecycle/service.py +364 -0
- clm/schemas/mcard_schema.sql +192 -0
- clm/schemas/mcard_vector_schema.sql +283 -0
- clm/schemas/mlp-context-v1.json +91 -0
- clm_kernel-0.0.0.dist-info/METADATA +121 -0
- clm_kernel-0.0.0.dist-info/RECORD +333 -0
- clm_kernel-0.0.0.dist-info/WHEEL +4 -0
- clm_kernel-0.0.0.dist-info/entry_points.txt +3 -0
- clm_kernel-0.0.0.dist-info/licenses/LICENSE +21 -0
clm/schemas/__init__.py
ADDED
|
@@ -0,0 +1,652 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCard Unified Schema Loader (Singleton)
|
|
3
|
+
|
|
4
|
+
This module provides the ONLY access point to MCard database schemas.
|
|
5
|
+
All schemas are loaded from: schema/mcard_schema.sql
|
|
6
|
+
|
|
7
|
+
This implements a Singleton pattern to ensure:
|
|
8
|
+
1. Schema file is read only once
|
|
9
|
+
2. All code uses the same schema definitions
|
|
10
|
+
3. NO duplicate CREATE TABLE statements exist elsewhere
|
|
11
|
+
|
|
12
|
+
IMPORTANT: The SQL file MUST exist. There are no fallbacks.
|
|
13
|
+
If the file is missing, an explicit error is raised.
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
from clm.schemas import MCardSchema
|
|
17
|
+
|
|
18
|
+
# Get the singleton instance
|
|
19
|
+
schema = MCardSchema.get_instance()
|
|
20
|
+
|
|
21
|
+
# Get a specific table's CREATE statement
|
|
22
|
+
card_schema = schema.get_table('card')
|
|
23
|
+
|
|
24
|
+
# Initialize all tables on a connection
|
|
25
|
+
schema.init_all_tables(conn)
|
|
26
|
+
|
|
27
|
+
Single Source of Truth:
|
|
28
|
+
schema/mcard_schema.sql
|
|
29
|
+
|
|
30
|
+
See: docs/architecture/Handle_Vector_Similarity_Design.md
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
import re
|
|
36
|
+
import sqlite3
|
|
37
|
+
import threading
|
|
38
|
+
from pathlib import Path
|
|
39
|
+
from typing import TYPE_CHECKING
|
|
40
|
+
|
|
41
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
42
|
+
# Schema File Loading (Delegated to Core)
|
|
43
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
import mcard_core_py # type: ignore
|
|
47
|
+
except ImportError:
|
|
48
|
+
import logging
|
|
49
|
+
|
|
50
|
+
logging.getLogger(__name__).error(
|
|
51
|
+
"mcard_core_py native extension not found! Schema loading will fail."
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _find_project_root() -> Path:
|
|
56
|
+
from clm.cross_cutting.config.config_constants import _find_project_root
|
|
57
|
+
return _find_project_root()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _find_schema_path() -> Path:
|
|
61
|
+
"""Return the canonical core schema SQL path."""
|
|
62
|
+
local_path = Path(__file__).resolve().parent / "mcard_schema.sql"
|
|
63
|
+
if local_path.exists():
|
|
64
|
+
return local_path
|
|
65
|
+
schema_path = _find_project_root() / "schema" / "mcard_schema.sql"
|
|
66
|
+
if not schema_path.exists():
|
|
67
|
+
raise FileNotFoundError(f"Canonical schema file not found in {local_path} or {schema_path}")
|
|
68
|
+
return schema_path
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _get_core_sql() -> str:
|
|
72
|
+
"""Retrieve the unified core schema file from the canonical SQL file on disk,
|
|
73
|
+
falling back to the Rust foundation if file reading fails."""
|
|
74
|
+
try:
|
|
75
|
+
path = _find_schema_path()
|
|
76
|
+
if path.exists():
|
|
77
|
+
return path.read_text(encoding="utf-8")
|
|
78
|
+
except Exception:
|
|
79
|
+
pass
|
|
80
|
+
return mcard_core_py.get_core_schema() # type: ignore
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _get_vector_sql() -> str:
|
|
84
|
+
"""Retrieve the vector schema file from the canonical SQL file on disk,
|
|
85
|
+
falling back to the Rust foundation if file reading fails."""
|
|
86
|
+
try:
|
|
87
|
+
local_path = Path(__file__).resolve().parent / "mcard_vector_schema.sql"
|
|
88
|
+
if local_path.exists():
|
|
89
|
+
return local_path.read_text(encoding="utf-8")
|
|
90
|
+
schema_path = (
|
|
91
|
+
_find_project_root() / "schema" / "mcard_vector_schema.sql"
|
|
92
|
+
)
|
|
93
|
+
if schema_path.exists():
|
|
94
|
+
return schema_path.read_text(encoding="utf-8")
|
|
95
|
+
except Exception:
|
|
96
|
+
pass
|
|
97
|
+
return mcard_core_py.get_vector_schema() # type: ignore
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class MCardSchema:
|
|
101
|
+
"""
|
|
102
|
+
Singleton class for MCard database schema management.
|
|
103
|
+
|
|
104
|
+
This class ensures that ALL schema definitions come exclusively from:
|
|
105
|
+
schema/mcard_schema.sql
|
|
106
|
+
|
|
107
|
+
There are NO hardcoded SQL fallbacks in this class.
|
|
108
|
+
|
|
109
|
+
Thread-safe singleton implementation.
|
|
110
|
+
|
|
111
|
+
Usage:
|
|
112
|
+
schema = MCardSchema.get_instance()
|
|
113
|
+
schema.get_table('card') # Get CREATE TABLE statement
|
|
114
|
+
schema.init_core_tables(conn) # Initialize core tables
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
_instance: MCardSchema | None = None
|
|
118
|
+
_lock = threading.Lock()
|
|
119
|
+
|
|
120
|
+
# Table-to-layer mapping (defines the architecture)
|
|
121
|
+
TABLE_LAYERS = {
|
|
122
|
+
# Layer 1: Core
|
|
123
|
+
"card": "core",
|
|
124
|
+
"card_tombstone": "core",
|
|
125
|
+
"documents": "core", # Legacy FTS table for backward compatibility
|
|
126
|
+
# Layer 2: Handle System
|
|
127
|
+
"handle_registry": "handle",
|
|
128
|
+
"handle_history": "handle",
|
|
129
|
+
# Layer 3: CRDT Federation
|
|
130
|
+
"learning_event": "federation",
|
|
131
|
+
# Layer 4: Vector Storage
|
|
132
|
+
"mcard_vector_metadata": "vector",
|
|
133
|
+
"mcard_embeddings": "vector",
|
|
134
|
+
"mcard_fts": "vector",
|
|
135
|
+
# Layer 4: Semantic Versioning
|
|
136
|
+
"handle_version_vectors": "semantic",
|
|
137
|
+
"version_similarity_cache": "semantic",
|
|
138
|
+
# Layer 5: Knowledge Graph
|
|
139
|
+
"graph_entities": "graph",
|
|
140
|
+
"graph_relationships": "graph",
|
|
141
|
+
"graph_communities": "graph",
|
|
142
|
+
"graph_extractions": "graph",
|
|
143
|
+
# Metadata
|
|
144
|
+
"schema_version": "metadata",
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
def __init__(self) -> None:
|
|
148
|
+
"""Private constructor - use get_instance() instead."""
|
|
149
|
+
self._schema_path: Path | None = None
|
|
150
|
+
self._raw_sql: str | None = None
|
|
151
|
+
self._statements: list[str] = []
|
|
152
|
+
self._tables: dict[str, str] = {}
|
|
153
|
+
self._indexes: dict[str, str] = {}
|
|
154
|
+
self._loaded: bool = False
|
|
155
|
+
|
|
156
|
+
@classmethod
|
|
157
|
+
def get_instance(cls) -> MCardSchema:
|
|
158
|
+
"""
|
|
159
|
+
Get the singleton instance of MCardSchema.
|
|
160
|
+
|
|
161
|
+
Thread-safe lazy initialization.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
The single MCardSchema instance
|
|
165
|
+
|
|
166
|
+
Raises:
|
|
167
|
+
FileNotFoundError: If schema/mcard_schema.sql cannot be found
|
|
168
|
+
"""
|
|
169
|
+
if cls._instance is None:
|
|
170
|
+
with cls._lock:
|
|
171
|
+
# Double-check locking
|
|
172
|
+
if cls._instance is None:
|
|
173
|
+
cls._instance = cls()
|
|
174
|
+
cls._instance._load()
|
|
175
|
+
return cls._instance
|
|
176
|
+
|
|
177
|
+
@classmethod
|
|
178
|
+
def reset_instance(cls) -> None:
|
|
179
|
+
"""Reset the singleton (primarily for testing)."""
|
|
180
|
+
with cls._lock:
|
|
181
|
+
cls._instance = None
|
|
182
|
+
|
|
183
|
+
def _load(self) -> None:
|
|
184
|
+
"""Load and parse the schema file(s)."""
|
|
185
|
+
if self._loaded:
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
self._schema_path = _find_schema_path()
|
|
189
|
+
|
|
190
|
+
# Fetch SQL string definitions straight from the C FFI pointer
|
|
191
|
+
self._raw_sql = _get_core_sql()
|
|
192
|
+
|
|
193
|
+
vector_sql = _get_vector_sql()
|
|
194
|
+
if vector_sql:
|
|
195
|
+
self._raw_sql += "\n\n" + vector_sql
|
|
196
|
+
|
|
197
|
+
self._statements = self._parse_statements(self._raw_sql)
|
|
198
|
+
self._tables = {}
|
|
199
|
+
self._indexes = {}
|
|
200
|
+
|
|
201
|
+
for stmt in self._statements:
|
|
202
|
+
name = self._extract_name(stmt)
|
|
203
|
+
if name:
|
|
204
|
+
if (
|
|
205
|
+
"CREATE TABLE" in stmt.upper()
|
|
206
|
+
or "CREATE VIRTUAL TABLE" in stmt.upper()
|
|
207
|
+
):
|
|
208
|
+
self._tables[name.lower()] = stmt
|
|
209
|
+
elif "CREATE INDEX" in stmt.upper():
|
|
210
|
+
self._indexes[name.lower()] = stmt
|
|
211
|
+
|
|
212
|
+
self._loaded = True
|
|
213
|
+
|
|
214
|
+
def _parse_statements(self, sql: str) -> list[str]:
|
|
215
|
+
"""Parse SQL file into individual statements."""
|
|
216
|
+
# Remove block comments
|
|
217
|
+
sql = re.sub(r"/\*.*?\*/", "", sql, flags=re.DOTALL)
|
|
218
|
+
|
|
219
|
+
statements = []
|
|
220
|
+
current = []
|
|
221
|
+
|
|
222
|
+
for line in sql.split("\n"):
|
|
223
|
+
# Skip line comments and empty lines
|
|
224
|
+
line_stripped = line.split("--")[0].strip()
|
|
225
|
+
if not line_stripped:
|
|
226
|
+
continue
|
|
227
|
+
|
|
228
|
+
current.append(line_stripped)
|
|
229
|
+
|
|
230
|
+
if line_stripped.endswith(";"):
|
|
231
|
+
statement = " ".join(current)
|
|
232
|
+
# Skip INSERT statements (version tracking)
|
|
233
|
+
if not statement.strip().upper().startswith("INSERT"):
|
|
234
|
+
statements.append(statement)
|
|
235
|
+
current = []
|
|
236
|
+
|
|
237
|
+
return [s.strip() for s in statements if s.strip()]
|
|
238
|
+
|
|
239
|
+
def _extract_name(self, statement: str) -> str | None:
|
|
240
|
+
"""Extract table or index name from a CREATE statement."""
|
|
241
|
+
# Handle CREATE TABLE
|
|
242
|
+
match = re.search(
|
|
243
|
+
r"CREATE\s+(?:VIRTUAL\s+)?TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)",
|
|
244
|
+
statement,
|
|
245
|
+
re.IGNORECASE,
|
|
246
|
+
)
|
|
247
|
+
if match:
|
|
248
|
+
return match.group(1)
|
|
249
|
+
|
|
250
|
+
# Handle CREATE INDEX
|
|
251
|
+
match = re.search(
|
|
252
|
+
r"CREATE\s+INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)", statement, re.IGNORECASE
|
|
253
|
+
)
|
|
254
|
+
if match:
|
|
255
|
+
return match.group(1)
|
|
256
|
+
|
|
257
|
+
return None
|
|
258
|
+
|
|
259
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
260
|
+
# Schema Access
|
|
261
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def schema_path(self) -> Path:
|
|
265
|
+
"""Get the path to the schema file."""
|
|
266
|
+
return self._schema_path or _find_schema_path()
|
|
267
|
+
|
|
268
|
+
def get_table(self, table_name: str) -> str | None:
|
|
269
|
+
"""
|
|
270
|
+
Get CREATE TABLE statement for a table.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
table_name: Name of the table
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
CREATE TABLE SQL statement, or None if not found
|
|
277
|
+
"""
|
|
278
|
+
return self._tables.get(table_name.lower())
|
|
279
|
+
|
|
280
|
+
def get_index(self, index_name: str) -> str | None:
|
|
281
|
+
"""
|
|
282
|
+
Get CREATE INDEX statement for an index.
|
|
283
|
+
|
|
284
|
+
Args:
|
|
285
|
+
index_name: Name of the index
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
CREATE INDEX SQL statement, or None if not found
|
|
289
|
+
"""
|
|
290
|
+
return self._indexes.get(index_name.lower())
|
|
291
|
+
|
|
292
|
+
def get_all_tables(self) -> dict[str, str]:
|
|
293
|
+
"""Get all table CREATE statements."""
|
|
294
|
+
return dict(self._tables)
|
|
295
|
+
|
|
296
|
+
def get_all_indexes(self) -> dict[str, str]:
|
|
297
|
+
"""Get all index CREATE statements."""
|
|
298
|
+
return dict(self._indexes)
|
|
299
|
+
|
|
300
|
+
def get_all_statements(self) -> list[str]:
|
|
301
|
+
"""Get all CREATE statements."""
|
|
302
|
+
return list(self._statements)
|
|
303
|
+
|
|
304
|
+
def get_tables_by_layer(self, layer: str) -> list[str]:
|
|
305
|
+
"""Get table names for a specific layer."""
|
|
306
|
+
return [
|
|
307
|
+
name
|
|
308
|
+
for name, layer_name in self.TABLE_LAYERS.items()
|
|
309
|
+
if layer_name == layer
|
|
310
|
+
]
|
|
311
|
+
|
|
312
|
+
def get_layer_statements(self, layer: str) -> list[str]:
|
|
313
|
+
"""Get all CREATE statements for a layer (tables + indexes)."""
|
|
314
|
+
statements = []
|
|
315
|
+
tables = self.get_tables_by_layer(layer)
|
|
316
|
+
|
|
317
|
+
# Add tables
|
|
318
|
+
for table in tables:
|
|
319
|
+
stmt = self.get_table(table)
|
|
320
|
+
if stmt:
|
|
321
|
+
statements.append(stmt)
|
|
322
|
+
|
|
323
|
+
# Add indexes for these tables
|
|
324
|
+
for _idx_name, stmt in self._indexes.items():
|
|
325
|
+
match = re.search(r"ON\s+(\w+)", stmt, re.IGNORECASE)
|
|
326
|
+
if match and match.group(1).lower() in [t.lower() for t in tables]:
|
|
327
|
+
statements.append(stmt)
|
|
328
|
+
|
|
329
|
+
return statements
|
|
330
|
+
|
|
331
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
332
|
+
# Database Initialization
|
|
333
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
334
|
+
|
|
335
|
+
def init_layer(self, conn: sqlite3.Connection, layer: str) -> int:
|
|
336
|
+
"""
|
|
337
|
+
Initialize tables for a specific layer.
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
conn: SQLite connection
|
|
341
|
+
layer: Layer name
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
Number of statements executed
|
|
345
|
+
"""
|
|
346
|
+
cursor = conn.cursor()
|
|
347
|
+
statements = self.get_layer_statements(layer)
|
|
348
|
+
|
|
349
|
+
for stmt in statements:
|
|
350
|
+
cursor.execute(stmt)
|
|
351
|
+
|
|
352
|
+
conn.commit()
|
|
353
|
+
return len(statements)
|
|
354
|
+
|
|
355
|
+
def init_core_tables(self, conn: sqlite3.Connection) -> int:
|
|
356
|
+
"""
|
|
357
|
+
Initialize Monadic Core tables (Card, Handle, Version).
|
|
358
|
+
|
|
359
|
+
This initializes both 'core' and 'handle' layers, as they constitute
|
|
360
|
+
the minimal functional unit of the MCard system.
|
|
361
|
+
"""
|
|
362
|
+
count = self.init_layer(conn, "core")
|
|
363
|
+
count += self.init_layer(conn, "handle")
|
|
364
|
+
return count
|
|
365
|
+
|
|
366
|
+
def init_handle_tables(self, conn: sqlite3.Connection) -> int:
|
|
367
|
+
"""Initialize handle system tables."""
|
|
368
|
+
return self.init_layer(conn, "handle")
|
|
369
|
+
|
|
370
|
+
def init_vector_tables(
|
|
371
|
+
self, conn: sqlite3.Connection, enable_fts: bool = True
|
|
372
|
+
) -> int:
|
|
373
|
+
"""Initialize vector storage tables."""
|
|
374
|
+
cursor = conn.cursor()
|
|
375
|
+
count = 0
|
|
376
|
+
|
|
377
|
+
for stmt in self.get_layer_statements("vector"):
|
|
378
|
+
if not enable_fts and "fts" in stmt.lower():
|
|
379
|
+
continue
|
|
380
|
+
cursor.execute(stmt)
|
|
381
|
+
count += 1
|
|
382
|
+
|
|
383
|
+
conn.commit()
|
|
384
|
+
return count
|
|
385
|
+
|
|
386
|
+
def init_semantic_tables(self, conn: sqlite3.Connection) -> int:
|
|
387
|
+
"""Initialize semantic versioning tables."""
|
|
388
|
+
return self.init_layer(conn, "semantic")
|
|
389
|
+
|
|
390
|
+
def init_graph_tables(self, conn: sqlite3.Connection) -> int:
|
|
391
|
+
"""Initialize knowledge graph tables."""
|
|
392
|
+
return self.init_layer(conn, "graph")
|
|
393
|
+
|
|
394
|
+
def init_all_tables(
|
|
395
|
+
self,
|
|
396
|
+
conn: sqlite3.Connection,
|
|
397
|
+
include_fts: bool = True,
|
|
398
|
+
include_graph: bool = True,
|
|
399
|
+
include_semantic: bool = True,
|
|
400
|
+
) -> int:
|
|
401
|
+
"""
|
|
402
|
+
Initialize all MCard tables on a database.
|
|
403
|
+
|
|
404
|
+
Args:
|
|
405
|
+
conn: SQLite connection
|
|
406
|
+
include_fts: Whether to include FTS tables
|
|
407
|
+
include_graph: Whether to include graph tables
|
|
408
|
+
include_semantic: Whether to include semantic versioning tables
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
Number of statements executed
|
|
412
|
+
"""
|
|
413
|
+
count = 0
|
|
414
|
+
count += self.init_core_tables(conn)
|
|
415
|
+
count += self.init_handle_tables(conn)
|
|
416
|
+
count += self.init_vector_tables(conn, enable_fts=include_fts)
|
|
417
|
+
|
|
418
|
+
if include_semantic:
|
|
419
|
+
count += self.init_semantic_tables(conn)
|
|
420
|
+
|
|
421
|
+
if include_graph:
|
|
422
|
+
count += self.init_graph_tables(conn)
|
|
423
|
+
|
|
424
|
+
return count
|
|
425
|
+
|
|
426
|
+
def init_vec0_table(self, conn: sqlite3.Connection, dimensions: int) -> None:
|
|
427
|
+
"""
|
|
428
|
+
Initialize sqlite-vec virtual table.
|
|
429
|
+
|
|
430
|
+
Note: This is the ONLY dynamically generated schema because
|
|
431
|
+
dimensions are determined at runtime.
|
|
432
|
+
|
|
433
|
+
Args:
|
|
434
|
+
conn: SQLite connection
|
|
435
|
+
dimensions: Embedding vector dimensions
|
|
436
|
+
"""
|
|
437
|
+
conn.execute(
|
|
438
|
+
f"""
|
|
439
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS mcard_vec USING vec0(
|
|
440
|
+
metadata_id INTEGER PRIMARY KEY,
|
|
441
|
+
embedding float[{dimensions}]
|
|
442
|
+
)
|
|
443
|
+
"""
|
|
444
|
+
)
|
|
445
|
+
conn.commit()
|
|
446
|
+
|
|
447
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
448
|
+
# Schema Version Management
|
|
449
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
450
|
+
|
|
451
|
+
def get_schema_version(self, conn: sqlite3.Connection) -> str | None:
|
|
452
|
+
"""Get the current schema version from the database."""
|
|
453
|
+
try:
|
|
454
|
+
cursor = conn.execute(
|
|
455
|
+
"SELECT version FROM schema_version ORDER BY applied_at DESC LIMIT 1"
|
|
456
|
+
)
|
|
457
|
+
row = cursor.fetchone()
|
|
458
|
+
return row[0] if row else None
|
|
459
|
+
except sqlite3.OperationalError:
|
|
460
|
+
return None
|
|
461
|
+
|
|
462
|
+
def set_schema_version(
|
|
463
|
+
self, conn: sqlite3.Connection, version: str, description: str = ""
|
|
464
|
+
) -> None:
|
|
465
|
+
"""Record a schema version in the database."""
|
|
466
|
+
conn.execute(
|
|
467
|
+
"""
|
|
468
|
+
INSERT OR REPLACE INTO schema_version (version, applied_at, description)
|
|
469
|
+
VALUES (?, datetime('now'), ?)
|
|
470
|
+
""",
|
|
471
|
+
(version, description),
|
|
472
|
+
)
|
|
473
|
+
conn.commit()
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
477
|
+
# Convenience Functions (use singleton internally)
|
|
478
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def get_instance() -> MCardSchema:
|
|
482
|
+
"""Get the singleton MCardSchema instance."""
|
|
483
|
+
return MCardSchema.get_instance()
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
def get_schema(table_or_index_name: str) -> str | None:
|
|
487
|
+
"""Get CREATE statement for a table or index."""
|
|
488
|
+
schema = MCardSchema.get_instance()
|
|
489
|
+
result = schema.get_table(table_or_index_name)
|
|
490
|
+
if result is None:
|
|
491
|
+
result = schema.get_index(table_or_index_name)
|
|
492
|
+
return result
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
def get_all_statements() -> list[str]:
|
|
496
|
+
"""Get all CREATE statements from the schema file."""
|
|
497
|
+
return MCardSchema.get_instance().get_all_statements()
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def get_schemas_by_layer(layer: str) -> dict[str, str]:
|
|
501
|
+
"""Get all schemas for a specific layer."""
|
|
502
|
+
schema = MCardSchema.get_instance()
|
|
503
|
+
result = {}
|
|
504
|
+
for table in schema.get_tables_by_layer(layer):
|
|
505
|
+
stmt = schema.get_table(table)
|
|
506
|
+
if stmt:
|
|
507
|
+
result[table] = stmt
|
|
508
|
+
return result
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def get_tables_by_layer(layer: str) -> list[str]:
|
|
512
|
+
"""Get table names for a specific layer."""
|
|
513
|
+
return MCardSchema.get_instance().get_tables_by_layer(layer)
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
def init_all_tables(
|
|
517
|
+
conn: sqlite3.Connection, include_fts: bool = True, include_graph: bool = True
|
|
518
|
+
) -> int:
|
|
519
|
+
"""Initialize all MCard tables."""
|
|
520
|
+
return MCardSchema.get_instance().init_all_tables(conn, include_fts, include_graph)
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
def init_core_tables(conn: sqlite3.Connection) -> int:
|
|
524
|
+
"""Initialize core tables."""
|
|
525
|
+
return MCardSchema.get_instance().init_core_tables(conn)
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
def init_handle_tables(conn: sqlite3.Connection) -> int:
|
|
529
|
+
"""Initialize handle tables."""
|
|
530
|
+
return MCardSchema.get_instance().init_handle_tables(conn)
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def init_vector_tables(conn: sqlite3.Connection, enable_fts: bool = True) -> int:
|
|
534
|
+
"""Initialize vector tables."""
|
|
535
|
+
return MCardSchema.get_instance().init_vector_tables(conn, enable_fts)
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def init_semantic_tables(conn: sqlite3.Connection) -> int:
|
|
539
|
+
"""Initialize semantic versioning tables."""
|
|
540
|
+
return MCardSchema.get_instance().init_semantic_tables(conn)
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def init_graph_tables(conn: sqlite3.Connection) -> int:
|
|
544
|
+
"""Initialize graph tables."""
|
|
545
|
+
return MCardSchema.get_instance().init_graph_tables(conn)
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
def init_vec0_table(conn: sqlite3.Connection, dimensions: int) -> None:
|
|
549
|
+
"""Initialize sqlite-vec table."""
|
|
550
|
+
MCardSchema.get_instance().init_vec0_table(conn, dimensions)
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
def get_schema_version(conn: sqlite3.Connection) -> str | None:
|
|
554
|
+
"""Get schema version."""
|
|
555
|
+
return MCardSchema.get_instance().get_schema_version(conn)
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
def set_schema_version(
|
|
559
|
+
conn: sqlite3.Connection, version: str, description: str = ""
|
|
560
|
+
) -> None:
|
|
561
|
+
"""Set schema version."""
|
|
562
|
+
MCardSchema.get_instance().set_schema_version(conn, version, description)
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
566
|
+
# Backward Compatibility Exports
|
|
567
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
568
|
+
|
|
569
|
+
# These provide lazy-loaded access to commonly used schemas for backward
|
|
570
|
+
# compatibility with code that imports constants like CARD_TABLE_SCHEMA.
|
|
571
|
+
#
|
|
572
|
+
# IMPORTANT: These load ONLY from the SQL file. There are NO hardcoded fallbacks.
|
|
573
|
+
# If the SQL file is missing, an error will be raised.
|
|
574
|
+
|
|
575
|
+
_CARD_TABLE_SCHEMA: str | None = None
|
|
576
|
+
_HANDLE_REGISTRY_SCHEMA: str | None = None
|
|
577
|
+
_HANDLE_HISTORY_SCHEMA: str | None = None
|
|
578
|
+
_HANDLE_INDEX_SCHEMA: str | None = None
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
def __getattr__(name: str):
|
|
582
|
+
"""
|
|
583
|
+
Lazy attribute access for backward compatibility constants.
|
|
584
|
+
|
|
585
|
+
All schemas are loaded from schema/mcard_schema.sql.
|
|
586
|
+
There are NO hardcoded fallbacks - the SQL file MUST exist.
|
|
587
|
+
"""
|
|
588
|
+
global _CARD_TABLE_SCHEMA, _HANDLE_REGISTRY_SCHEMA, _HANDLE_HISTORY_SCHEMA, _HANDLE_INDEX_SCHEMA
|
|
589
|
+
|
|
590
|
+
schema = MCardSchema.get_instance()
|
|
591
|
+
|
|
592
|
+
if name == "CARD_TABLE_SCHEMA":
|
|
593
|
+
if _CARD_TABLE_SCHEMA is None:
|
|
594
|
+
_CARD_TABLE_SCHEMA = schema.get_table("card")
|
|
595
|
+
return _CARD_TABLE_SCHEMA
|
|
596
|
+
|
|
597
|
+
elif name == "HANDLE_REGISTRY_SCHEMA":
|
|
598
|
+
if _HANDLE_REGISTRY_SCHEMA is None:
|
|
599
|
+
_HANDLE_REGISTRY_SCHEMA = schema.get_table("handle_registry")
|
|
600
|
+
return _HANDLE_REGISTRY_SCHEMA
|
|
601
|
+
|
|
602
|
+
elif name == "HANDLE_HISTORY_SCHEMA":
|
|
603
|
+
if _HANDLE_HISTORY_SCHEMA is None:
|
|
604
|
+
_HANDLE_HISTORY_SCHEMA = schema.get_table("handle_history")
|
|
605
|
+
return _HANDLE_HISTORY_SCHEMA
|
|
606
|
+
|
|
607
|
+
elif name == "HANDLE_INDEX_SCHEMA":
|
|
608
|
+
if _HANDLE_INDEX_SCHEMA is None:
|
|
609
|
+
_HANDLE_INDEX_SCHEMA = schema.get_index("idx_handle_current_hash")
|
|
610
|
+
return _HANDLE_INDEX_SCHEMA
|
|
611
|
+
|
|
612
|
+
elif name == "TABLE_LAYERS":
|
|
613
|
+
return MCardSchema.TABLE_LAYERS
|
|
614
|
+
|
|
615
|
+
raise AttributeError(f"module 'mcard.schema' has no attribute '{name}'")
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
if TYPE_CHECKING:
|
|
619
|
+
CARD_TABLE_SCHEMA: str
|
|
620
|
+
HANDLE_REGISTRY_SCHEMA: str
|
|
621
|
+
HANDLE_HISTORY_SCHEMA: str
|
|
622
|
+
HANDLE_INDEX_SCHEMA: str
|
|
623
|
+
TABLE_LAYERS: dict[str, str]
|
|
624
|
+
|
|
625
|
+
__all__ = [
|
|
626
|
+
# Singleton class
|
|
627
|
+
"MCardSchema",
|
|
628
|
+
"get_instance",
|
|
629
|
+
"_find_schema_path",
|
|
630
|
+
# Primary API
|
|
631
|
+
"get_schema",
|
|
632
|
+
"get_all_statements",
|
|
633
|
+
"get_schemas_by_layer",
|
|
634
|
+
"get_tables_by_layer",
|
|
635
|
+
# Initialization
|
|
636
|
+
"init_all_tables",
|
|
637
|
+
"init_core_tables",
|
|
638
|
+
"init_handle_tables",
|
|
639
|
+
"init_vector_tables",
|
|
640
|
+
"init_semantic_tables",
|
|
641
|
+
"init_graph_tables",
|
|
642
|
+
"init_vec0_table",
|
|
643
|
+
# Version management
|
|
644
|
+
"get_schema_version",
|
|
645
|
+
"set_schema_version",
|
|
646
|
+
# Backward compatibility (loaded from SQL file only)
|
|
647
|
+
"CARD_TABLE_SCHEMA",
|
|
648
|
+
"HANDLE_REGISTRY_SCHEMA",
|
|
649
|
+
"HANDLE_HISTORY_SCHEMA",
|
|
650
|
+
"HANDLE_INDEX_SCHEMA",
|
|
651
|
+
"TABLE_LAYERS",
|
|
652
|
+
]
|