superlocalmemory 4.0.9 → 4.1.0

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 (165) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +245 -0
  3. package/README.md +7 -7
  4. package/package.json +4 -2
  5. package/plugin/.claude-plugin/plugin.json +2 -2
  6. package/plugin/CLAUDE.md +3 -3
  7. package/plugin/agents/slm-governance-advisor.md +1 -1
  8. package/plugin/agents/slm-loop-runner.md +4 -4
  9. package/plugin/agents/slm-memory-advisor.md +1 -1
  10. package/plugin/agents/slm-optimize-advisor.md +1 -1
  11. package/plugin/requirements.txt +1 -1
  12. package/plugin/skills/slm-cache/SKILL.md +1 -1
  13. package/plugin/skills/slm-compress/SKILL.md +1 -1
  14. package/plugin/skills/slm-governance/SKILL.md +1 -1
  15. package/plugin/skills/slm-graph/SKILL.md +1 -1
  16. package/plugin/skills/slm-loop/SKILL.md +2 -2
  17. package/plugin/skills/slm-mesh/SKILL.md +1 -1
  18. package/plugin/skills/slm-profile/SKILL.md +5 -5
  19. package/plugin/skills/slm-recall/SKILL.md +102 -15
  20. package/plugin/skills/slm-remember/SKILL.md +35 -3
  21. package/plugin/skills/slm-scope/SKILL.md +1 -1
  22. package/plugin/skills/slm-session/SKILL.md +29 -3
  23. package/plugin/skills/slm-status/SKILL.md +1 -1
  24. package/plugin-src/rules/AGENTS.md +16 -8
  25. package/plugin-src/skills/slm-cache/SKILL.md +1 -1
  26. package/plugin-src/skills/slm-compress/SKILL.md +1 -1
  27. package/plugin-src/skills/slm-governance/SKILL.md +1 -1
  28. package/plugin-src/skills/slm-graph/SKILL.md +1 -1
  29. package/plugin-src/skills/slm-loop/SKILL.md +2 -2
  30. package/plugin-src/skills/slm-mesh/SKILL.md +1 -1
  31. package/plugin-src/skills/slm-profile/SKILL.md +5 -5
  32. package/plugin-src/skills/slm-recall/SKILL.md +102 -15
  33. package/plugin-src/skills/slm-remember/SKILL.md +35 -3
  34. package/plugin-src/skills/slm-scope/SKILL.md +1 -1
  35. package/plugin-src/skills/slm-session/SKILL.md +29 -3
  36. package/plugin-src/skills/slm-status/SKILL.md +1 -1
  37. package/pyproject.toml +1 -1
  38. package/src/superlocalmemory/__init__.py +1 -1
  39. package/src/superlocalmemory/cli/commands.py +308 -20
  40. package/src/superlocalmemory/cli/daemon.py +30 -0
  41. package/src/superlocalmemory/cli/db_migrate.py +71 -1
  42. package/src/superlocalmemory/cli/gdpr_cmd.py +15 -2
  43. package/src/superlocalmemory/cli/main.py +26 -4
  44. package/src/superlocalmemory/code_graph/bridge/maintenance.py +8 -0
  45. package/src/superlocalmemory/code_graph/database.py +44 -0
  46. package/src/superlocalmemory/compliance/gdpr.py +449 -39
  47. package/src/superlocalmemory/core/admission.py +231 -11
  48. package/src/superlocalmemory/core/backend_orchestrator.py +190 -84
  49. package/src/superlocalmemory/core/config.py +90 -11
  50. package/src/superlocalmemory/core/consolidation_engine.py +34 -0
  51. package/src/superlocalmemory/core/engine.py +140 -11
  52. package/src/superlocalmemory/core/fact_consolidator.py +316 -125
  53. package/src/superlocalmemory/core/graph_analyzer.py +76 -112
  54. package/src/superlocalmemory/core/graph_metrics.py +597 -0
  55. package/src/superlocalmemory/core/graph_pruner.py +121 -0
  56. package/src/superlocalmemory/core/maintenance.py +44 -6
  57. package/src/superlocalmemory/core/maintenance_scheduler.py +205 -0
  58. package/src/superlocalmemory/core/memory_health.py +266 -0
  59. package/src/superlocalmemory/core/mode_capability.py +111 -0
  60. package/src/superlocalmemory/core/ollama_validator.py +315 -0
  61. package/src/superlocalmemory/core/operation_policy_registry.py +1 -1
  62. package/src/superlocalmemory/core/operation_request.py +1 -1
  63. package/src/superlocalmemory/core/ops_remediation.py +2 -2
  64. package/src/superlocalmemory/core/projection_drain.py +380 -0
  65. package/src/superlocalmemory/core/recall_pipeline.py +390 -3
  66. package/src/superlocalmemory/core/recall_worker.py +6 -3
  67. package/src/superlocalmemory/core/scale_autopromote.py +196 -0
  68. package/src/superlocalmemory/core/scale_engine.py +16 -2
  69. package/src/superlocalmemory/core/score_contract.py +21 -1
  70. package/src/superlocalmemory/core/session_identity.py +85 -0
  71. package/src/superlocalmemory/core/status_contract.py +108 -0
  72. package/src/superlocalmemory/core/store_pipeline.py +78 -3
  73. package/src/superlocalmemory/core/worker_pool.py +4 -4
  74. package/src/superlocalmemory/core/working_memory.py +288 -0
  75. package/src/superlocalmemory/encoding/cognitive_consolidator.py +51 -7
  76. package/src/superlocalmemory/encoding/context_generator.py +1 -1
  77. package/src/superlocalmemory/encoding/entity_resolver.py +38 -0
  78. package/src/superlocalmemory/encoding/fact_extractor.py +18 -14
  79. package/src/superlocalmemory/encoding/prospective_markers.py +262 -0
  80. package/src/superlocalmemory/encoding/type_router.py +12 -12
  81. package/src/superlocalmemory/evolution/mutation_generator.py +30 -4
  82. package/src/superlocalmemory/graph/cozo_adjacency.py +122 -0
  83. package/src/superlocalmemory/graph/cozo_backend.py +103 -138
  84. package/src/superlocalmemory/hooks/portable_kit.py +10 -2
  85. package/src/superlocalmemory/learning/bandit.py +43 -0
  86. package/src/superlocalmemory/learning/consolidation_worker.py +54 -0
  87. package/src/superlocalmemory/learning/database.py +60 -3
  88. package/src/superlocalmemory/learning/entity_compiler.py +21 -58
  89. package/src/superlocalmemory/learning/feedback.py +3 -1
  90. package/src/superlocalmemory/learning/outcomes.py +47 -16
  91. package/src/superlocalmemory/learning/pattern_miner.py +28 -3
  92. package/src/superlocalmemory/learning/pattern_miner_constants.py +43 -0
  93. package/src/superlocalmemory/learning/pcos.py +291 -0
  94. package/src/superlocalmemory/learning/reward_from_outcomes.py +365 -0
  95. package/src/superlocalmemory/learning/reward_proxy.py +100 -10
  96. package/src/superlocalmemory/learning/signal_kinds.py +79 -0
  97. package/src/superlocalmemory/mcp/profiles.py +14 -2
  98. package/src/superlocalmemory/mcp/server.py +1 -1
  99. package/src/superlocalmemory/mcp/session_binding.py +92 -0
  100. package/src/superlocalmemory/mcp/tools_active.py +2 -1
  101. package/src/superlocalmemory/mcp/tools_core.py +71 -42
  102. package/src/superlocalmemory/mcp/tools_ops.py +2 -2
  103. package/src/superlocalmemory/mcp/tools_v28.py +20 -1
  104. package/src/superlocalmemory/parameterization/pattern_extractor.py +14 -1
  105. package/src/superlocalmemory/parameterization/soft_prompt_generator.py +98 -0
  106. package/src/superlocalmemory/retrieval/bm25_channel.py +68 -11
  107. package/src/superlocalmemory/retrieval/channel_status.py +117 -0
  108. package/src/superlocalmemory/retrieval/engine.py +106 -11
  109. package/src/superlocalmemory/retrieval/entity_channel.py +217 -257
  110. package/src/superlocalmemory/retrieval/graph_adjacency.py +219 -0
  111. package/src/superlocalmemory/retrieval/scope_policy.py +42 -1
  112. package/src/superlocalmemory/retrieval/semantic_channel.py +47 -5
  113. package/src/superlocalmemory/retrieval/spreading.py +288 -0
  114. package/src/superlocalmemory/retrieval/temporal_channel.py +13 -1
  115. package/src/superlocalmemory/retrieval/vector_store.py +63 -0
  116. package/src/superlocalmemory/server/api.py +26 -2
  117. package/src/superlocalmemory/server/asset_versions.py +171 -0
  118. package/src/superlocalmemory/server/bandit_loops.py +17 -1
  119. package/src/superlocalmemory/server/rbac_enforce.py +26 -6
  120. package/src/superlocalmemory/server/recall_serializer.py +9 -0
  121. package/src/superlocalmemory/server/routes/abstraction.py +201 -0
  122. package/src/superlocalmemory/server/routes/behavioral.py +75 -10
  123. package/src/superlocalmemory/server/routes/compliance.py +98 -18
  124. package/src/superlocalmemory/server/routes/config_api.py +186 -4
  125. package/src/superlocalmemory/server/routes/data_io.py +29 -1
  126. package/src/superlocalmemory/server/routes/entity.py +13 -1
  127. package/src/superlocalmemory/server/routes/evolution.py +178 -0
  128. package/src/superlocalmemory/server/routes/ingest.py +8 -0
  129. package/src/superlocalmemory/server/routes/learning_telemetry.py +2 -1
  130. package/src/superlocalmemory/server/routes/memories.py +49 -7
  131. package/src/superlocalmemory/server/routes/mesh.py +1 -1
  132. package/src/superlocalmemory/server/routes/timeline.py +4 -0
  133. package/src/superlocalmemory/server/routes/v3_api.py +193 -17
  134. package/src/superlocalmemory/server/ui.py +24 -1
  135. package/src/superlocalmemory/server/unified_daemon.py +292 -9
  136. package/src/superlocalmemory/storage/_migration_internals.py +35 -0
  137. package/src/superlocalmemory/storage/_schema_version.py +24 -3
  138. package/src/superlocalmemory/storage/database.py +598 -82
  139. package/src/superlocalmemory/storage/embedding_codec.py +71 -0
  140. package/src/superlocalmemory/storage/lineage_retention.py +236 -0
  141. package/src/superlocalmemory/storage/logical_edges.py +43 -2
  142. package/src/superlocalmemory/storage/migration_runner.py +130 -0
  143. package/src/superlocalmemory/storage/migrations/M043_quarantine_display_summaries.py +488 -0
  144. package/src/superlocalmemory/storage/migrations/M044_play_carries_its_own_evidence.py +127 -0
  145. package/src/superlocalmemory/storage/migrations/M045_fact_outcome_score.py +158 -0
  146. package/src/superlocalmemory/storage/migrations/M046_prospective_memory_has_its_own_name.py +620 -0
  147. package/src/superlocalmemory/storage/migrations/M047_fisher_vectors_are_stored_like_every_other_vector.py +306 -0
  148. package/src/superlocalmemory/storage/migrations/M048_upcoming_holds_only_what_is_upcoming.py +207 -0
  149. package/src/superlocalmemory/storage/migrations/M049_a_schema_version_marker_is_one_row.py +201 -0
  150. package/src/superlocalmemory/storage/migrations.py +18 -2
  151. package/src/superlocalmemory/storage/models.py +40 -1
  152. package/src/superlocalmemory/storage/projection_outbox.py +346 -0
  153. package/src/superlocalmemory/storage/retention_policy.py +860 -0
  154. package/src/superlocalmemory/storage/schema.py +110 -1
  155. package/src/superlocalmemory/storage/write_coordinator.py +19 -2
  156. package/src/superlocalmemory/summaries/base.py +1 -1
  157. package/src/superlocalmemory/summaries/non_answer.py +223 -0
  158. package/src/superlocalmemory/trust/scorer.py +43 -1
  159. package/src/superlocalmemory/ui/index.html +10 -19
  160. package/src/superlocalmemory/ui/js/event-delegation.js +12 -1
  161. package/src/superlocalmemory/ui/js/od-health.js +28 -6
  162. package/src/superlocalmemory/ui/js/od-memories.js +209 -1
  163. package/src/superlocalmemory/ui/js/od-ops-health.js +1 -1
  164. package/src/superlocalmemory/ui/js/od-settings.js +87 -1
  165. package/src/superlocalmemory/ui/js/recall-lab.js +78 -3
@@ -35,6 +35,59 @@ def _resolve_paths(args: Namespace) -> tuple[Path, Path]:
35
35
  return Path(learning), Path(memory)
36
36
 
37
37
 
38
+ def _end_state_disagreements(learning_db, memory_db) -> dict[str, str]:
39
+ """Migrations recorded complete whose own verification no longer passes.
40
+
41
+ ``--status`` reads ``migration_log``, which records what was *done*. The
42
+ daemon re-runs each completed migration's ``verify()`` on every start, which
43
+ checks whether what was done still *holds*. When those two answers differ
44
+ the log says ``complete`` and the health endpoint says the migration failed,
45
+ and until now nothing on any surface showed the two were even asking
46
+ different questions -- so the only available reading was that one of them
47
+ was lying. Reported as #125.
48
+
49
+ Read-only and fail-quiet: this is a diagnostic printed beside a status line,
50
+ and it must never be the reason a status command exits non-zero.
51
+ """
52
+ import sqlite3
53
+
54
+ from superlocalmemory.storage._migration_internals import _MODULES
55
+ from superlocalmemory.storage.migration_runner import MIGRATIONS
56
+
57
+ try:
58
+ from superlocalmemory.storage.migration_runner import DEFERRED_MIGRATIONS
59
+ except ImportError: # pragma: no cover — older layouts
60
+ DEFERRED_MIGRATIONS = ()
61
+
62
+ out: dict[str, str] = {}
63
+ for migration in list(MIGRATIONS) + list(DEFERRED_MIGRATIONS):
64
+ verify_fn = getattr(_MODULES.get(migration.name), "verify", None)
65
+ if not callable(verify_fn):
66
+ continue
67
+ db_path = memory_db if migration.db_target != "learning" else learning_db
68
+ try:
69
+ conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
70
+ except sqlite3.Error:
71
+ continue
72
+ try:
73
+ row = conn.execute(
74
+ "SELECT status FROM migration_log WHERE name = ? LIMIT 1",
75
+ (migration.name,),
76
+ ).fetchone()
77
+ if not row or row[0] != "complete":
78
+ continue
79
+ if not bool(verify_fn(conn)):
80
+ out[migration.name] = " <- recorded complete, end-state no longer holds"
81
+ except Exception: # noqa: BLE001 — a diagnostic must not break status
82
+ pass
83
+ finally:
84
+ try:
85
+ conn.close()
86
+ except sqlite3.Error: # pragma: no cover
87
+ pass
88
+ return out
89
+
90
+
38
91
  def cmd_db_migrate(args: Namespace) -> int:
39
92
  """Apply pending migrations or report status.
40
93
 
@@ -57,8 +110,25 @@ def cmd_db_migrate(args: Namespace) -> int:
57
110
  if not report:
58
111
  print("(no migrations registered)")
59
112
  else:
113
+ disagreements = _end_state_disagreements(learning_db, memory_db)
60
114
  for name, state in report.items():
61
- print(f" {name}: {state}")
115
+ note = disagreements.get(name, "")
116
+ print(f" {name}: {state}{note}")
117
+ if disagreements:
118
+ print()
119
+ print(
120
+ " A migration marked complete is re-checked on every start "
121
+ "by its own\n"
122
+ " verification. The ones flagged above are recorded as done "
123
+ "and their\n"
124
+ " end-state no longer holds, which is what the daemon "
125
+ "reports as a\n"
126
+ " migration failure while this log still reads complete. "
127
+ "Run `slm db\n"
128
+ " migrate` to let each one try to repair itself, and see "
129
+ "`migration_failure_reasons`\n"
130
+ " in `slm health --json` for what specifically did not hold."
131
+ )
62
132
  return 0
63
133
 
64
134
  dry_run = bool(getattr(args, "dry_run", False))
@@ -427,9 +427,14 @@ def _cmd_gdpr_erase(args: Namespace) -> None:
427
427
  sys.exit(1)
428
428
 
429
429
  complete = counts.get("erasure_complete", 0)
430
+ # Whether it can be SHOWN to have happened is a separate answer, and
431
+ # printing COMPLETE while the tamper-evident receipt failed to persist is
432
+ # how the command line came to disagree with the API about the same erasure.
433
+ provable = counts.get("erasure_provable", complete)
430
434
  result_data = {
431
435
  "profile": profile,
432
436
  "erasure_complete": bool(complete),
437
+ "erasure_provable": bool(provable),
433
438
  "counts": counts,
434
439
  "note": (
435
440
  "Erasure recorded in audit_chain.db. "
@@ -441,7 +446,15 @@ def _cmd_gdpr_erase(args: Namespace) -> None:
441
446
  if use_json:
442
447
  _print_json(_json_envelope("gdpr-erase", data=result_data))
443
448
  else:
444
- status_str = "COMPLETE" if complete else "INCOMPLETE (check counts)"
449
+ if not complete:
450
+ status_str = "INCOMPLETE (check counts)"
451
+ elif not provable:
452
+ status_str = (
453
+ "COMPLETE, BUT NOT PROVABLE — the data is gone and the "
454
+ "tamper-evident receipt did not persist"
455
+ )
456
+ else:
457
+ status_str = "COMPLETE"
445
458
  print(f"Art.17 erasure for profile '{profile}': {status_str}")
446
459
  for k, v in counts.items():
447
460
  print(f" {k}: {v}")
@@ -449,7 +462,7 @@ def _cmd_gdpr_erase(args: Namespace) -> None:
449
462
  print(" Backups/ contain outstanding obligation — see C1 gap.")
450
463
  print(" Verify receipts: slm gdpr verify --profile", profile)
451
464
 
452
- if not complete:
465
+ if not complete or not provable:
453
466
  sys.exit(1)
454
467
 
455
468
 
@@ -24,7 +24,10 @@ _os.environ.setdefault('TORCH_DEVICE', 'cpu')
24
24
  import argparse
25
25
  import sys
26
26
 
27
- from superlocalmemory.core.config import CANONICAL_RECALL_LIMIT
27
+ from superlocalmemory.core.config import (
28
+ CANONICAL_LIST_LIMIT,
29
+ CANONICAL_RECALL_LIMIT,
30
+ )
28
31
 
29
32
  _HELP_EPILOG = """\
30
33
  operating modes:
@@ -344,6 +347,19 @@ def main() -> None:
344
347
  db_scale_p.add_argument("--stage-id", help="Stage identifier required by verify/promote")
345
348
  db_scale_p.add_argument("--backup-id", help="Backup identifier required by rollback")
346
349
 
350
+ db_regraph_p = db_sub.add_parser(
351
+ "regraph",
352
+ help="Re-derive the graph copy of your memories from the store",
353
+ )
354
+ db_regraph_p.add_argument(
355
+ "--check", action="store_true",
356
+ help="Report how far the graph copy has drifted; change nothing",
357
+ )
358
+ db_regraph_p.add_argument(
359
+ "--profile", default="",
360
+ help="Workspace to re-derive. Default: all of them",
361
+ )
362
+
347
363
  db_reembed_p = db_sub.add_parser(
348
364
  "reembed",
349
365
  help="Backfill NULL embeddings (facts never embedded)",
@@ -503,7 +519,8 @@ def main() -> None:
503
519
 
504
520
  list_p = sub.add_parser("list", help="List recent memories chronologically (shows IDs for delete/update)")
505
521
  list_p.add_argument(
506
- "--limit", "-n", type=int, default=20, help="Number of entries (default 20)",
522
+ "--limit", "-n", type=int, default=CANONICAL_LIST_LIMIT,
523
+ help=f"Number of entries (default {CANONICAL_LIST_LIMIT})",
507
524
  )
508
525
  list_p.add_argument("--json", action="store_true", help="Output structured JSON (agent-native)")
509
526
 
@@ -530,6 +547,11 @@ def main() -> None:
530
547
  "--quick", action="store_true",
531
548
  help="Run only the fast checks (deps + config); skip daemon/embedding probes",
532
549
  )
550
+ doctor_p.add_argument(
551
+ "--deep", action="store_true",
552
+ help="Read every database page (PRAGMA integrity_check) instead of the "
553
+ "structural check; slow on a large store",
554
+ )
533
555
  doctor_p.add_argument(
534
556
  "--fix", action="store_true",
535
557
  help="Auto-repair fixable components (re-download missing models, "
@@ -977,7 +999,7 @@ def main() -> None:
977
999
 
978
1000
  register_summary_parser(sub)
979
1001
 
980
- # Wave-3 / V4.0.6: GDPR subject-rights CLI (Art.15/17/20)
1002
+ # V4.0.6: GDPR subject-rights CLI (Art.15/17/20)
981
1003
  gdpr_p = sub.add_parser(
982
1004
  "gdpr",
983
1005
  help="GDPR subject rights: status, export (Art.15/20), erase (Art.17), verify",
@@ -1051,7 +1073,7 @@ def main() -> None:
1051
1073
  "--json", action="store_true", help="Output structured JSON",
1052
1074
  )
1053
1075
 
1054
- # Wave-3: operational recovery & admin remediation
1076
+ # Operational recovery & admin remediation
1055
1077
  ops_p = sub.add_parser(
1056
1078
  "ops",
1057
1079
  help="Operational recovery: list failures, resolve stuck ops, check status",
@@ -103,6 +103,14 @@ def _fact_rows(
103
103
  # the pass linked happily in tests and would have linked NOTHING for any
104
104
  # actual user — 3,608 of 3,608 facts filtered out on this machine.
105
105
  sql += "AND COALESCE(archive_status, 'live') != 'archived' "
106
+ # Same reasoning for withheld rows: a model's non-answer has no code
107
+ # entities worth resolving, and a link from one would surface it in the
108
+ # bridge's enrichment text.
109
+ try:
110
+ if memory_db._has_quarantine_column():
111
+ sql += "AND COALESCE(quarantined, 0) = 0 "
112
+ except Exception: # pragma: no cover - helper absent on an unusual manager
113
+ pass
106
114
 
107
115
  params: list[Any] = [profile_id]
108
116
  if since:
@@ -37,6 +37,49 @@ _MAX_RETRIES = 5
37
37
  _RETRY_BASE_SECONDS = 0.1
38
38
 
39
39
 
40
+ def _load_vector_extension(conn: sqlite3.Connection) -> bool:
41
+ """Make vector search available on this connection. Returns whether it loaded.
42
+
43
+ Without this the vector table cannot be created, so every semantic lookup
44
+ over the code graph returned nothing — not an error, just an empty result,
45
+ with one line in the maintenance log saying embeddings were disabled. The
46
+ extension was installed and working the whole time; no connection ever asked
47
+ for it.
48
+
49
+ Loaded per connection because that is the only scope SQLite offers: an
50
+ extension is bound to a connection, not to a database file, and this class
51
+ opens a fresh connection per statement.
52
+
53
+ The import stays inside the function. At module level it would make the
54
+ whole code graph unimportable wherever the wheel is unavailable, which is a
55
+ platform detail and not a reason to lose the rest of the feature.
56
+ """
57
+ try:
58
+ import sqlite_vec
59
+ except Exception as exc: # ImportError, or a broken native build
60
+ logger.debug("vector search unavailable: %s", exc)
61
+ return False
62
+ try:
63
+ conn.enable_load_extension(True)
64
+ except AttributeError as exc:
65
+ # Python built against a SQLite without extension support.
66
+ logger.debug("this SQLite cannot load extensions: %s", exc)
67
+ return False
68
+ try:
69
+ sqlite_vec.load(conn)
70
+ return True
71
+ except Exception as exc:
72
+ logger.debug("vector extension failed to load: %s", exc)
73
+ return False
74
+ finally:
75
+ # Closed again either way. Leaving extension loading enabled on a
76
+ # connection widens what any later SQL on it is allowed to do.
77
+ try:
78
+ conn.enable_load_extension(False)
79
+ except Exception: # pragma: no cover — defensive
80
+ pass
81
+
82
+
40
83
  class CodeGraphDatabase:
41
84
  """SQLite database manager for code_graph.db.
42
85
 
@@ -70,6 +113,7 @@ class CodeGraphDatabase:
70
113
  conn.execute("PRAGMA journal_mode=WAL")
71
114
  conn.execute("PRAGMA foreign_keys=ON")
72
115
  conn.execute("PRAGMA synchronous=NORMAL")
116
+ _load_vector_extension(conn)
73
117
  return conn
74
118
 
75
119
  def execute(