ltcai 11.5.1 → 11.5.2

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 (176) hide show
  1. package/README.md +85 -53
  2. package/docs/CHANGELOG.md +54 -0
  3. package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
  4. package/docs/DEVELOPMENT.md +1 -1
  5. package/docs/HYBRID_CLOUD_KG_STREAMING.md +8 -4
  6. package/docs/MULTI_AGENT_RUNTIME.md +1 -1
  7. package/docs/ONBOARDING.md +1 -1
  8. package/docs/OPERATIONS.md +1 -1
  9. package/docs/TRUST_MODEL.md +1 -1
  10. package/docs/WHY_LATTICE.md +1 -1
  11. package/docs/WORKFLOW_DESIGNER.md +1 -1
  12. package/docs/architecture.md +4 -4
  13. package/docs/kg-schema.md +1 -1
  14. package/docs/v11.5.2_TIGHT_SHIP_PLAN.md +144 -0
  15. package/lattice_brain/__init__.py +1 -1
  16. package/lattice_brain/graph/proactive.py +1 -1
  17. package/lattice_brain/graph/projection/v2_schema.py +0 -28
  18. package/lattice_brain/graph/vector_index/base.py +0 -3
  19. package/lattice_brain/graph/vector_index/brute_force.py +0 -4
  20. package/lattice_brain/graph/vector_index/hnsw.py +0 -3
  21. package/lattice_brain/graph/vector_index/quantized.py +0 -3
  22. package/lattice_brain/ingestion_jobs.py +0 -3
  23. package/lattice_brain/memory.py +0 -27
  24. package/lattice_brain/portability/sharing.py +0 -4
  25. package/lattice_brain/quality.py +0 -49
  26. package/lattice_brain/runtime/agent_runtime.py +1 -1
  27. package/lattice_brain/runtime/hooks.py +0 -13
  28. package/lattice_brain/runtime/multi_agent.py +1 -1
  29. package/lattice_brain/sealed_box.py +0 -4
  30. package/latticeai/__init__.py +1 -1
  31. package/latticeai/api/admin.py +12 -12
  32. package/latticeai/api/auth.py +25 -2
  33. package/latticeai/api/chat.py +3 -3
  34. package/latticeai/api/chat_agent_http.py +3 -12
  35. package/latticeai/api/chat_helpers.py +10 -13
  36. package/latticeai/api/computer_use.py +31 -42
  37. package/latticeai/api/health.py +21 -1
  38. package/latticeai/api/local_files.py +14 -0
  39. package/latticeai/api/permissions.py +38 -12
  40. package/latticeai/api/search.py +24 -0
  41. package/latticeai/api/static_routes.py +4 -1
  42. package/latticeai/cli/runtime.py +7 -3
  43. package/latticeai/core/config.py +47 -3
  44. package/latticeai/core/csrf.py +28 -2
  45. package/latticeai/core/embedding_providers/__init__.py +3 -5
  46. package/latticeai/core/embedding_providers/base.py +1 -1
  47. package/latticeai/core/embedding_providers/text.py +1 -1
  48. package/latticeai/core/enterprise.py +1 -4
  49. package/latticeai/core/http_origin.py +146 -0
  50. package/latticeai/core/invitations.py +3 -2
  51. package/latticeai/core/io_utils.py +2 -11
  52. package/latticeai/core/legacy_compatibility.py +1 -1
  53. package/latticeai/core/marketplace.py +1 -1
  54. package/latticeai/core/messages.py +5 -0
  55. package/latticeai/core/model_compat.py +2 -8
  56. package/latticeai/core/module_probe.py +37 -0
  57. package/latticeai/core/run_explain.py +5 -2
  58. package/latticeai/core/run_store.py +2 -2
  59. package/latticeai/core/security.py +13 -0
  60. package/latticeai/core/sessions.py +3 -2
  61. package/latticeai/core/sse.py +25 -0
  62. package/latticeai/core/users.py +0 -9
  63. package/latticeai/core/workspace_graph_trace.py +2 -8
  64. package/latticeai/core/workspace_os.py +0 -10
  65. package/latticeai/core/workspace_os_constants.py +1 -1
  66. package/latticeai/core/workspace_os_utils.py +34 -0
  67. package/latticeai/core/workspace_review_items.py +2 -8
  68. package/latticeai/core/workspace_runs.py +2 -8
  69. package/latticeai/core/workspace_skills.py +2 -7
  70. package/latticeai/models/router/documents.py +0 -35
  71. package/latticeai/models/router/registry.py +0 -4
  72. package/latticeai/runtime/access_runtime.py +16 -4
  73. package/latticeai/runtime/build_phases/features.py +2 -0
  74. package/latticeai/runtime/build_phases/web.py +2 -0
  75. package/latticeai/runtime/feature_toggle_wiring.py +12 -18
  76. package/latticeai/runtime/network_boundary_wiring.py +8 -19
  77. package/latticeai/runtime/permission_mode_wiring.py +6 -13
  78. package/latticeai/runtime/router_registration.py +4 -0
  79. package/latticeai/runtime/runtime_context.py +1 -13
  80. package/latticeai/runtime/service_singletons.py +55 -0
  81. package/latticeai/services/architecture_readiness.py +1 -1
  82. package/latticeai/services/brain_intelligence/proposals.py +0 -5
  83. package/latticeai/services/change_proposals.py +2 -36
  84. package/latticeai/services/chronicle.py +4 -6
  85. package/latticeai/services/command_center.py +4 -4
  86. package/latticeai/services/evidence_actions.py +5 -2
  87. package/latticeai/services/hybrid_chat.py +2 -2
  88. package/latticeai/services/hybrid_policy.py +8 -57
  89. package/latticeai/services/mode_store.py +132 -0
  90. package/latticeai/services/model_capability_registry.py +0 -15
  91. package/latticeai/services/model_catalog.py +0 -7
  92. package/latticeai/services/model_loading.py +3 -2
  93. package/latticeai/services/model_runtime/__init__.py +0 -57
  94. package/latticeai/services/model_runtime/engines.py +27 -128
  95. package/latticeai/services/model_runtime/loading.py +2 -2
  96. package/latticeai/services/network_boundary_service.py +7 -44
  97. package/latticeai/services/permission_mode_service.py +8 -56
  98. package/latticeai/services/product_readiness.py +1 -1
  99. package/latticeai/services/setup_detection.py +67 -1
  100. package/latticeai/services/tool_dispatch.py +0 -4
  101. package/latticeai/services/upload_service.py +7 -20
  102. package/latticeai/services/workspace_service.py +0 -6
  103. package/latticeai/setup/auto_setup.py +15 -26
  104. package/latticeai/setup/wizard/catalog.py +5 -2
  105. package/latticeai/setup/wizard/detect.py +6 -27
  106. package/latticeai/setup/wizard/paths.py +2 -5
  107. package/latticeai/setup/wizard/plans.py +2 -2
  108. package/package.json +2 -4
  109. package/scripts/bump_version.py +14 -1
  110. package/scripts/check_current_release_docs.mjs +1 -1
  111. package/scripts/check_legacy_debt.mjs +1 -1
  112. package/scripts/generate_agent_loop_fixtures.py +87 -0
  113. package/scripts/generate_rust_parity_fixtures.py +3 -95
  114. package/scripts/parity_fixture_corpus_context.py +162 -0
  115. package/scripts/release_screen_claims.json +10 -0
  116. package/src-tauri/Cargo.lock +7 -7
  117. package/src-tauri/Cargo.toml +1 -1
  118. package/src-tauri/src/backend.rs +76 -2
  119. package/src-tauri/src/main.rs +13 -3
  120. package/src-tauri/tauri.conf.json +2 -2
  121. package/static/app/asset-manifest.json +40 -40
  122. package/static/app/assets/{Act-Drs_jd-O.js → Act-DcQizkl1.js} +1 -1
  123. package/static/app/assets/{AdminConsole-BqNx5oF6.js → AdminConsole-cf4npybT.js} +1 -1
  124. package/static/app/assets/{Brain-C7bdNmz-.js → Brain-3VCSHFcn.js} +1 -1
  125. package/static/app/assets/{BrainHome-DcTnINcI.js → BrainHome-Qm8eaztx.js} +1 -1
  126. package/static/app/assets/{BrainSignals-Df1MRIPD.js → BrainSignals-DS9BtKOW.js} +1 -1
  127. package/static/app/assets/{Capture-Dgsxvnbx.js → Capture-DiQ219jW.js} +1 -1
  128. package/static/app/assets/{Chronicle-BrkTxJK1.js → Chronicle-BGvuAchH.js} +1 -1
  129. package/static/app/assets/{CommandPalette-DDziw7Oj.js → CommandPalette-Bqhm0Urn.js} +1 -1
  130. package/static/app/assets/{Library-CYxeuraA.js → Library-BV6NnF0a.js} +1 -1
  131. package/static/app/assets/{LivingBrain-CNp6mvCm.js → LivingBrain-GzenJchP.js} +1 -1
  132. package/static/app/assets/{ProductFlow-BVsowu3Z.js → ProductFlow-DEP6-vML.js} +1 -1
  133. package/static/app/assets/{ReviewCard-D1LbOfJS.js → ReviewCard-CNZ7XjWG.js} +1 -1
  134. package/static/app/assets/{System-DcRAq7wj.js → System-CieofHQa.js} +1 -1
  135. package/static/app/assets/arrow-left-kfsrk0mv.js +1 -0
  136. package/static/app/assets/{bot-BK2xQ9mN.js → bot-B_K1Tdmw.js} +1 -1
  137. package/static/app/assets/{brain-BZNztFBb.js → brain-DWyaV1L1.js} +1 -1
  138. package/static/app/assets/{button-CjueubVZ.js → button-aTn4s84A.js} +1 -1
  139. package/static/app/assets/circle-check-qqLug9nU.js +1 -0
  140. package/static/app/assets/{circle-pause-HRjSmpyY.js → circle-pause-xKgeGXkT.js} +1 -1
  141. package/static/app/assets/{circle-play-CMcKDVwu.js → circle-play-DkT6tYPX.js} +1 -1
  142. package/static/app/assets/{cpu-B_MyTfYr.js → cpu-85xYObUC.js} +1 -1
  143. package/static/app/assets/{download-CTy0EByV.js → download-B5Fm7YXo.js} +1 -1
  144. package/static/app/assets/{folder-open-DF6bLhTg.js → folder-open-kk2Xa52u.js} +1 -1
  145. package/static/app/assets/{hard-drive-CpWHG77C.js → hard-drive-DkA3zBW_.js} +1 -1
  146. package/static/app/assets/{index-Dd6abJHX.js → index-BMPdTmlY.js} +3 -3
  147. package/static/app/assets/{input-bVgIRN3s.js → input-B0nRf2jO.js} +1 -1
  148. package/static/app/assets/{link-2-bg6CG5Vk.js → link-2-Dwb4gnTc.js} +1 -1
  149. package/static/app/assets/{permissionCopy-DFTf1HDZ.js → permissionCopy-CQDUBrOZ.js} +1 -1
  150. package/static/app/assets/{primitives-D7D-sQ3T.js → primitives-SNp0LRJz.js} +1 -1
  151. package/static/app/assets/search-BcHqkjoy.js +1 -0
  152. package/static/app/assets/{share-2-BLzo7U4L.js → share-2-BsrxFglO.js} +1 -1
  153. package/static/app/assets/{shield-alert-BmngqnsJ.js → shield-alert-5BStfp2_.js} +1 -1
  154. package/static/app/assets/{textarea-DOSlAQQ3.js → textarea-Cg8IUA-k.js} +1 -1
  155. package/static/app/assets/{useFocusTrap-pZhgeee4.js → useFocusTrap-CYKvE46M.js} +1 -1
  156. package/static/app/assets/{useMutation-BMDwNk4I.js → useMutation-CSn9t1op.js} +1 -1
  157. package/static/app/assets/{useQuery-CSjKttRo.js → useQuery-CY2OI2uy.js} +1 -1
  158. package/static/app/assets/{utils-D3u_yv7B.js → utils-Ddol2RWD.js} +1 -1
  159. package/static/app/assets/{workspace-H3bMjYXC.js → workspace-BqDwOz_p.js} +1 -1
  160. package/static/app/index.html +3 -3
  161. package/static/sw.js +1 -1
  162. package/desktop/electron/README.md +0 -9
  163. package/desktop/electron/main.cjs +0 -58
  164. package/desktop/electron/preload.cjs +0 -5
  165. package/latticeai/core/graph_curator.py +0 -11
  166. package/latticeai/core/hooks.py +0 -11
  167. package/latticeai/core/local_embeddings.py +0 -104
  168. package/latticeai/core/multi_agent.py +0 -11
  169. package/latticeai/core/workflow_engine.py +0 -11
  170. package/latticeai/services/ingestion.py +0 -11
  171. package/latticeai/services/kg_portability.py +0 -11
  172. package/latticeai/services/multimodal_streaming.py +0 -129
  173. package/scripts/measure_brain_home_fill.mjs +0 -141
  174. package/static/app/assets/arrow-left-BHYmOTWU.js +0 -1
  175. package/static/app/assets/circle-check-CLeWJr67.js +0 -1
  176. package/static/app/assets/search-BgSVX6NG.js +0 -1
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  [![CI Status](https://github.com/TaeSooPark-PTS/LatticeAI/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/TaeSooPark-PTS/LatticeAI/actions/workflows/ci.yml)
12
12
  [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
13
13
 
14
- ![v11.5.1 Living Brain walkthrough](output/release/v11.5.1/gifs/v11.5.1-living-brain-walkthrough.gif)
14
+ ![v11.5.2 Living Brain walkthrough](output/release/v11.5.2/gifs/v11.5.2-living-brain-walkthrough.gif)
15
15
 
16
16
  Chat, files, folders, notes, and web pages all flow into one durable knowledge
17
17
  graph on your computer. Any model — local MLX or cloud — can speak with that
@@ -24,10 +24,10 @@ memory. Nothing leaves your machine without explicit consent.
24
24
 
25
25
  | | |
26
26
  | --- | --- |
27
- | **See your Brain's story in time** — a growth curve, an activity heatmap, and each day's story, rewindable to any past moment ![Brain Chronicle](output/release/v11.5.1/screenshots/13-chronicle.png) | **Chat with a Brain that remembers** — every conversation grows durable, source-linked memory ![Brain Chat](output/release/v11.5.1/screenshots/04-brain-chat-home.png) |
28
- | **See how knowledge connects** — a real relationship graph, not a file list ![Memory Graph](output/release/v11.5.1/screenshots/05-memory-graph.png) | **Capture anything** — files, whole folders, notes, screenshots, web pages ![Capture](output/release/v11.5.1/screenshots/06-capture.png) |
29
- | **Automate with review** — agent changes become proposals you approve first ![Review Center](output/release/v11.5.1/screenshots/12-review-center.png) | **Pick a model in one click** — recommended local models for your hardware ![Recommended Models](output/release/v11.5.1/screenshots/02-recommended-models.png) |
30
- | **Watch a file become memory** — three named steps, not a pipeline diagram ![Material to memory](output/release/v11.5.1/screenshots/11-knowledge-journey.png) | **Say how much it may do alone** — one dial in plain words; dangerous actions stay blocked either way ![Settings](output/release/v11.5.1/screenshots/08-system.png) |
27
+ | **See your Brain's story in time** — a growth curve, an activity heatmap, and each day's story, rewindable to any past moment ![Brain Chronicle](output/release/v11.5.2/screenshots/13-chronicle.png) | **Chat with a Brain that remembers** — every conversation grows durable, source-linked memory ![Brain Chat](output/release/v11.5.2/screenshots/04-brain-chat-home.png) |
28
+ | **See how knowledge connects** — a real relationship graph, not a file list ![Memory Graph](output/release/v11.5.2/screenshots/05-memory-graph.png) | **Capture anything** — files, whole folders, notes, screenshots, web pages ![Capture](output/release/v11.5.2/screenshots/06-capture.png) |
29
+ | **Automate with review** — agent changes become proposals you approve first ![Review Center](output/release/v11.5.2/screenshots/12-review-center.png) | **Pick a model in one click** — recommended local models for your hardware ![Recommended Models](output/release/v11.5.2/screenshots/02-recommended-models.png) |
30
+ | **Watch a file become memory** — three named steps, not a pipeline diagram ![Material to memory](output/release/v11.5.2/screenshots/11-knowledge-journey.png) | **Say how much it may do alone** — one dial in plain words; dangerous actions stay blocked either way ![Settings](output/release/v11.5.2/screenshots/08-system.png) |
31
31
 
32
32
  ## Why Lattice AI
33
33
 
@@ -58,63 +58,94 @@ First-run flow — wake the Brain, pick the owner, load a recommended model:
58
58
 
59
59
  | | | |
60
60
  | --- | --- | --- |
61
- | ![Login](output/release/v11.5.1/screenshots/01-login.png) | ![Model install](output/release/v11.5.1/screenshots/03-install-load-progress.png) | ![Model library](output/release/v11.5.1/screenshots/07-model-library.png) |
61
+ | ![Login](output/release/v11.5.2/screenshots/01-login.png) | ![Model install](output/release/v11.5.2/screenshots/03-install-load-progress.png) | ![Model library](output/release/v11.5.2/screenshots/07-model-library.png) |
62
62
 
63
63
  Screenshot index and capture notes:
64
- [output/release/v11.5.1/SCREENSHOT_INDEX.md](output/release/v11.5.1/SCREENSHOT_INDEX.md)
64
+ [output/release/v11.5.2/SCREENSHOT_INDEX.md](output/release/v11.5.2/SCREENSHOT_INDEX.md)
65
65
 
66
66
  ## Current Release
67
67
 
68
- The current release is **11.5.1 — Rust Full Loop**:
69
-
70
- The two explicitly-remaining items are done: the agent loop orchestrator
71
- now runs in Rust — proven by replaying the real Python runtime on scripted
72
- LLM transcripts (**10 trajectories, byte-identical**) and by a live smoke
73
- against the real worker — and the document-generation context builder is
74
- native (53 new goldens, 247 total). Every Rust box in the target diagram
75
- is implemented; Python remains exactly the AI Worker that diagram draws:
76
- LLM inference, tool-handler execution, and all graph writes behind three
77
- new fully-covered worker seams with server-side circuit breakers intact.
78
-
79
- - **The desktop's front door is now the Rust gateway.** The Tauri shell
80
- boots the supervisor + gateway topology by default and the webview
81
- lives at the gateway origin. The one real blocker — a CSRF policy
82
- bound to the worker's own port — is dissolved by environment
83
- injection, proven live against the real Python worker (trusted
84
- origins 200, foreign origins 403). Three escape hatches preserve the
85
- previous topologies.
86
- - **The native surface grew fourfold.** `lattice-retrieval` now serves
87
- the three-channel service search, graph reads (search /
88
- relationships / traverse), the full history read family, and the
89
- chat context assembler — **191/191 exact-parity goldens, zero
90
- epsilon**. `lattice-ingest` carries the typed chunker (332 golden
91
- chunks, and a 26/26 mutation-test pass proving every constant
92
- load-bearing) plus the polling folder watcher; writes stay delegated
93
- to the worker, the single writer. `lattice-agent` carries the
94
- permission kernel — **2,452 exact decision-table verdicts** — and
95
- natively executes only validated read-only commands in a replaced
96
- environment. `lattice-jobs` closes a documented gap: the durable
97
- embed queue now has a scheduler (60s ticks, honest backoff,
98
- `/host/jobs` status) driving a new fully-covered drain endpoint.
99
- - **The honest boundary, stated.** The Python worker keeps the document
100
- parser matrix, embedding production, LLM inference, mutating tool
101
- execution, and all graph writes. The agent loop orchestration port
102
- remains for a future release, for reasons written down in the plan.
103
-
104
- All of it lands with the floor intact: **6,861 Python + 1,761 frontend
105
- tests at 100.00% statement and branch coverage — now 7,006 Python +
106
- 1,761 frontend — and 739 Rust workspace tests**, four bidirectional golden families, mypy/ruff/clippy clean,
107
- verified on macOS 3.14 and a fresh-resolve python 3.11 environment.
68
+ The current release is **11.5.2 — Tight Ship**:
69
+
70
+ A cleanup-and-correctness release built from three audits of the settled
71
+ 11.5.1 tree — a Rust↔Python duplication map, an arc-level dead-code and
72
+ test audit, and a live front-door parity sweep across 192 endpoints
73
+ (gateway vs. direct worker). The duplication map's verdict was that the
74
+ boundary itself is sound: **zero cross-boundary deletions**, because every
75
+ twin is either the live Python-direct surface or a copy pinned by a parity
76
+ golden. The real duplication was inside each language, and that is what
77
+ this release removes.
78
+
79
+ - **About 1,100 lines gone.** Six moved-module shims, a multimodal
80
+ streaming seam that was never wired, roughly 27 zero-caller symbols
81
+ whose only callers were their own tests, an interface method
82
+ (`metadata_for`) no consumer ever called, a dead measurement script,
83
+ and the **legacy Electron shell** — superseded by Tauri, yet still
84
+ shipping inside the npm tarball. Every deletion came with per-assertion
85
+ test surgery so the 100% line **and** branch floor never moved, and a
86
+ new guard forbids the `sys.modules[__name__]` shim pattern from coming
87
+ back. The 183 coverage work-package test files were all verified
88
+ load-bearing (ten of them are the sole owners of 79 branch arcs); seven
89
+ coverage-redundant feature tests were deliberately kept for their
90
+ regression value.
91
+ - **One home per thing.** The byte-identical embedder pair is
92
+ single-sourced on the golden-pinned copy — silent vector drift between
93
+ two write paths was the failure mode. The workspace selector's four
94
+ verbatim re-derivations now use the canonical rule, an intended
95
+ behaviour change: chat, agent, upload, computer-use and admin **403 on
96
+ disagreement** where the copies silently preferred the header. sha256,
97
+ SSE frame builders, the data-dir default, the mode services and the
98
+ module-importability probe each collapsed to one implementation, and
99
+ seven byte-identical Rust copies were consolidated (including a
100
+ wholesale duplicate of `clock.rs`).
101
+ - **The front door, fixed with live before/after proof.** Proxied
102
+ redirects now pass through with `Set-Cookie` and `Location` intact —
103
+ the invite gate was a hard dead-end, SSO login silently never
104
+ authenticated, and twelve deep links lost their fragment. Absolute
105
+ `Location` values naming the internal worker are rewritten to the
106
+ gateway origin. The native `/rust/*` and `/host/status|jobs` lanes are
107
+ **posture-gated fail-closed**: they used to serve the whole graph
108
+ unauthenticated while the worker required auth. `X-Forwarded-For/Proto/
109
+ Host` cross the hop and are honoured only from a loopback or listed
110
+ trusted-proxy peer, which fixes `--no-spawn` CSRF refusals and the
111
+ invite links, notifications and SSO URLs that named the internal worker
112
+ port. The supervisor injects CORS origins alongside the CSRF ones,
113
+ stale `ws://` CSP entries are gone, and the Tauri shell no longer
114
+ navigates to a dead origin when the gateway fails to bind.
115
+ - **What the audits surfaced.** `POST /api/search/graph` was allow-listed
116
+ but unreachable until now; `GET /api/ingestion/multimodal` was
117
+ documented but unwired. Two golden families were added: a `recent_chat`
118
+ family pinning the `build_recent_chat_context` the live `/chat` path
119
+ actually calls — it caught a real divergence, where Python's `limit=0`
120
+ tail slice keeps everything and Rust returned empty (**Python is the
121
+ reference; Rust was fixed**) — plus `document_targets` and
122
+ `agent_profiles` helper goldens, 97 rows. The corpus stands at **251
123
+ golden files**.
124
+ - **The boundaries, stated plainly.** The native lanes are an
125
+ open-posture, single-local-owner surface (a closed or unknown posture
126
+ answers 401). The recent-chat context seam is still owned by the ad-hoc
127
+ prepends in `/chat` rather than the assembler — wiring it changes the
128
+ shape of a live prompt, which is a minor-release item, not something to
129
+ ship quietly here. `workspace_scope_from_request` itself remains
130
+ lenient for its two remaining callers. And the proxy hop deliberately
131
+ carries no request timeout: a blanket timeout would kill long-lived SSE.
132
+
133
+ The floor holds: **7,022 Python tests (11 skipped) at 100.00% statement
134
+ and branch coverage — 40,307 statements, 10,970 branches, `fail_under=100`
135
+ with the pragma budget untouched — 1,761 frontend tests across 101 files
136
+ at 100% on all four metrics, and 760 Rust workspace tests**, with the
137
+ OpenAPI schema regenerated at 421 paths and the whole suite re-verified in
138
+ a fresh-resolve Python 3.11 environment.
108
139
 
109
140
  Release notes: [RELEASE.md](RELEASE.md) · Full history: [docs/CHANGELOG.md](docs/CHANGELOG.md)
110
141
 
111
- Expected artifacts for 11.5.1 release must use exact filenames:
142
+ Expected artifacts for 11.5.2 release must use exact filenames:
112
143
 
113
- - `dist/ltcai-11.5.1-py3-none-any.whl`
114
- - `dist/ltcai-11.5.1.tar.gz`
115
- - `ltcai-11.5.1.tgz`
116
- - `dist/ltcai-11.5.1.vsix`
117
- - `src-tauri/target/release/bundle/dmg/Lattice AI_11.5.1_aarch64.dmg`
144
+ - `dist/ltcai-11.5.2-py3-none-any.whl`
145
+ - `dist/ltcai-11.5.2.tar.gz`
146
+ - `ltcai-11.5.2.tgz`
147
+ - `dist/ltcai-11.5.2.vsix`
148
+ - `src-tauri/target/release/bundle/dmg/Lattice AI_11.5.2_aarch64.dmg`
118
149
 
119
150
  Do not use wildcard artifact uploads. Package registry publishing remains owner-run.
120
151
 
@@ -149,6 +180,7 @@ See [ARCHITECTURE.md](ARCHITECTURE.md) for details and
149
180
 
150
181
  | Version | Theme |
151
182
  | --- | --- |
183
+ | 11.5.2 | Tight Ship |
152
184
  | 11.5.1 | Rust Full Loop |
153
185
  | 11.5.0 | Rust Complete |
154
186
  | 11.4.0 | Rust Foundation |
package/docs/CHANGELOG.md CHANGED
@@ -4,6 +4,60 @@ The top entry is either the current unreleased main-branch work or the current
4
4
  release line. Older entries are historical and may describe behavior as it
5
5
  existed at that release.
6
6
 
7
+ ## [11.5.2] - 2026-08-12 — Tight Ship
8
+
9
+ ### Added
10
+ - `POST /api/search/graph` — 세 번째 검색 채널의 라우트. 허용 목록에는
11
+ 있었지만 도달 경로가 없었습니다(감사 산출).
12
+ - `GET /api/ingestion/multimodal` — FEATURE_STATUS가 사용자 표면으로
13
+ 기술하던 멀티모달 상태 조회를 실제 라우트에 배선.
14
+ - 골든 신규 2계열(코퍼스 총 **251 파일**): 실제 `/chat`이 호출하는
15
+ `build_recent_chat_context`를 못박는 `recent_chat`, 그리고
16
+ `document_targets`/`agent_profiles` 헬퍼 97행.
17
+ - 재발 금지 가드: `latticeai/` 아래 `sys.modules[__name__]` shim 패턴
18
+ 금지(legacy-debt 게이트 확장).
19
+ - `scripts/bump_version.py`가 rust workspace **여섯 크레이트 전부**를
20
+ 두 Cargo.lock에서 동기화합니다(11.5.0 이후 Phase 2/3/4 크레이트 세
21
+ 개가 매 bump마다 스테일로 남아 테스트 실행이 트리를 더럽혔습니다).
22
+
23
+ ### Changed
24
+ - **워크스페이스 선택자 통합(동작 변경, 의도됨)**: chat/agent/upload/
25
+ computer-use/admin의 축자 재구현이 정본 규칙을 사용합니다 — 헤더와
26
+ 쿼리가 불일치하면 조용히 헤더를 택하는 대신 **403**.
27
+ - 임베더 byte-identical 쌍을 골든에 못박힌 사본으로 단일화(두 쓰기
28
+ 경로 사이의 조용한 벡터 드리프트가 실패 양식이었습니다).
29
+ - sha256 헬퍼·SSE 프레임 빌더(출력 byte-identical)·데이터 디렉터리
30
+ 기본값·모드 서비스 삼형제·모듈 임포트 프로브를 각각 한 곳으로.
31
+ - Rust byte-identical 사본 7건 통합(통째로 복사돼 있던 `clock.rs` 포함).
32
+ `lattice-agent`의 독립 `pystr`는 의도된 경계로 유지.
33
+ - `recent_chat` 골든이 실제 발산을 잡아냄: Python의 `limit=0` 꼬리
34
+ 슬라이스는 전부를 남기는데 Rust는 빈 결과를 돌려주고 있었습니다.
35
+ **Python이 기준**이며 Rust를 수정했습니다.
36
+
37
+ ### Fixed
38
+ - **프록시 리다이렉트**: 3xx가 `Set-Cookie`·`Location`을 온전히 달고
39
+ 통과합니다. 초대 게이트의 막다른 길, SSO 로그인이 조용히 인증되지
40
+ 않던 문제, 딥링크 12개의 프래그먼트 분실이 함께 해소됩니다. 내부
41
+ 워커 오리진을 가리키는 절대 `Location`은 게이트웨이 오리진으로
42
+ 재작성됩니다.
43
+ - **네이티브 레인 posture 게이팅(fail-closed)**: `/rust/*`와
44
+ `/host/status|jobs`는 워커가 인증을 요구하는 상태에서 그래프 전체를
45
+ 무인증으로 서빙하고 있었습니다. posture가 닫힘/알 수 없음이면 401.
46
+ - **프록시 신원**: `X-Forwarded-For/Proto/Host`가 홉을 건너가고, 루프백
47
+ 또는 `LATTICEAI_TRUSTED_PROXIES` 피어에서 온 것만 존중됩니다.
48
+ `--no-spawn` CSRF 거절과 내부 워커 포트를 적어 보내던 초대 링크·
49
+ 권한 알림·SSO 리다이렉트 URL이 고쳐집니다.
50
+ - 수퍼바이저가 CSRF 오리진과 나란히 CORS 오리진도 주입합니다.
51
+ - 존재하지 않는 WebSocket 엔드포인트를 가리키던 CSP `ws://` 항목 제거.
52
+ - 게이트웨이 바인드 실패 시 Tauri 셸이 죽은 오리진으로 이동하지 않습니다.
53
+
54
+ ### Removed
55
+ - 이사 간 모듈 shim 6종, 배선된 적 없는 멀티모달 스트리밍 시임,
56
+ 호출자 0 심볼 약 27개(삭제마다 테스트 수술 동반), 소비자 없는
57
+ `metadata_for` 인터페이스(ABC + 구현 4곳), 죽은 측정 스크립트,
58
+ 그리고 npm tarball에 아직 실려 나가던 **레거시 Electron 셸**
59
+ (Tauri가 대체) — 약 1,100줄.
60
+
7
61
  ## [11.5.1] - 2026-08-12 — Rust Full Loop
8
62
 
9
63
  ### Added
@@ -1,6 +1,6 @@
1
1
  # Community And Plugins
2
2
 
3
- Current release: **11.5.1 — Rust Full Loop**.
3
+ Current release: **11.5.2 — Tight Ship**.
4
4
 
5
5
  LatticeAI defines the path from a strong local-first framework (8.4.0
6
6
  action-aware baseline, 8.5.0 registry+DI hardening, 8.6.0 capture/navigation
@@ -3,7 +3,7 @@
3
3
  > **Status: canonical** — current contributor guidance, kept in sync with the
4
4
  > current release.
5
5
 
6
- Current release: **11.5.1 — Rust Full Loop**.
6
+ Current release: **11.5.2 — Tight Ship**.
7
7
 
8
8
  This document is for contributors working on the local-first Digital Brain
9
9
  codebase. Product positioning and quick start stay in `README.md`; release
@@ -43,10 +43,14 @@ POST /api/network-boundary/policy
43
43
  Users approve cloud-derived memory growth in the existing Review Center.
44
44
 
45
45
  ### Multimodal / video
46
- `latticeai/services/multimodal_streaming.py`:
47
- - Same `NetworkBoundaryMode.CLOUD_ALLOWED` gate
48
- - Additional `allow_multimodal` policy flag
49
- - Adapter protocol for future Runway/Luma/Veo-compatible providers
46
+ There is no cloud multi-modal *streaming* path. A `multimodal_streaming` module
47
+ was written to a provider-adapter shape and never wired to a provider or a
48
+ route; 11.5.2 deleted it rather than keep a design sketch reading as a feature.
49
+
50
+ Multi-modal ingestion itself is local and unrelated to this document's cloud
51
+ boundary — see `lattice_brain/ingestion/routing.py` and the `allow_multimodal`
52
+ gate. If a cloud video provider ever lands, the module is recoverable from git
53
+ history (`latticeai/services/multimodal_streaming.py`, removed in 11.5.2).
50
54
 
51
55
  ### UI
52
56
  `NetworkBoundaryPanel` (React) + `GET /api/network-boundary/ui-state`:
@@ -6,7 +6,7 @@ operationalized in v2.2.0. It sits
6
6
  and coordinates a pipeline of named **roles** that hand off work to one another,
7
7
  retry on a failing review, and emit a fully observable, replayable timeline.
8
8
 
9
- - **Source of truth:** `latticeai/core/multi_agent.py`
9
+ - **Source of truth:** `lattice_brain/runtime/multi_agent.py`
10
10
  - **HTTP surface:** `latticeai/api/agents.py`
11
11
  - **Persistence / Knowledge Graph integration:** `latticeai/core/workspace_os.py`
12
12
  (`WorkspaceOSStore.record_agent_run`, `replay_agent_run`, `list_handoffs`)
@@ -1,6 +1,6 @@
1
1
  # Lattice AI Onboarding
2
2
 
3
- Current release: **11.5.1 — Rust Full Loop**.
3
+ Current release: **11.5.2 — Tight Ship**.
4
4
 
5
5
  The first-run goal is a five-minute path from "I opened the app" to "my Brain
6
6
  has a source, a question, and proof." This page is the product contract behind
@@ -1,4 +1,4 @@
1
- # Lattice AI — Operations Guide (v11.5.1)
1
+ # Lattice AI — Operations Guide (v11.5.2)
2
2
 
3
3
  > **Status: canonical** — kept in sync with the current release. Storage layout
4
4
  > below reflects the SQLite live Brain store and workspace scoping, not the
@@ -1,6 +1,6 @@
1
1
  # Lattice AI Trust Model
2
2
 
3
- Current release: **11.5.1 — Rust Full Loop**.
3
+ Current release: **11.5.2 — Tight Ship**.
4
4
 
5
5
  Lattice AI is local-first, explicit about external communication, and honest
6
6
  when a capability is unavailable.
@@ -1,6 +1,6 @@
1
1
  # Why Lattice AI Exists
2
2
 
3
- Current release: **11.5.1 — Rust Full Loop**.
3
+ Current release: **11.5.2 — Tight Ship**.
4
4
 
5
5
  **Lattice AI is a local-first Digital Brain that keeps your knowledge durable
6
6
  across any AI model.**
@@ -8,7 +8,7 @@ node to an injected *runner* that calls the real tool registry, skill registry,
8
8
  plugin registry, or multi-agent orchestrator.
9
9
 
10
10
  The execution model lives in
11
- [`latticeai/core/workflow_engine.py`](../latticeai/core/workflow_engine.py)
11
+ [`lattice_brain/workflow.py`](../lattice_brain/workflow.py)
12
12
  (pure logic with injected runners) and the HTTP surface lives in
13
13
  [`latticeai/api/workflow_designer.py`](../latticeai/api/workflow_designer.py).
14
14
  Persistence reuses the existing `WorkspaceOSStore`, so pre-2.0 workflow history
@@ -7,10 +7,10 @@
7
7
  > are intentionally frozen at that point in time.
8
8
 
9
9
  > v3.6.0 — **Knowledge Graph First.** Every data source converges into the graph
10
- > through one unified ingestion pipeline (`latticeai/services/ingestion.py`), with
10
+ > through one unified ingestion pipeline (`lattice_brain/ingestion/pipeline.py`), with
11
11
  > formalized entities/relationships (`docs/kg-schema.md`), browser/web inputs,
12
12
  > per-node provenance, and local export/import/backup
13
- > (`latticeai/services/kg_portability.py`). The agent ecosystem, long-term memory,
13
+ > (`lattice_brain/portability/`). The agent ecosystem, long-term memory,
14
14
  > and skills/hooks/tool/MCP registries are all operable from `/app`. Enterprise
15
15
  > controls remain future work.
16
16
 
@@ -158,8 +158,8 @@ Basic mode and advanced mode have the same feature access.
158
158
  | `knowledge_graph.py` | Graph storage, extraction, local folder knowledge graph context |
159
159
  | `latticeai/core/context_builder.py` | Graph context for generation |
160
160
  | `latticeai/core/workspace_os.py` | Workspace state, timeline, snapshots, durable context |
161
- | `latticeai/core/multi_agent.py` | Planner/executor/reviewer/researcher orchestration |
162
- | `latticeai/core/workflow_engine.py` | Workflow definitions and run history |
161
+ | `lattice_brain/runtime/multi_agent.py` | Planner/executor/reviewer/researcher orchestration |
162
+ | `lattice_brain/workflow.py` | Workflow definitions and run history |
163
163
  | `latticeai/core/plugins.py` | Plugin manifest, registry, permission boundary |
164
164
  | `latticeai/core/security.py` | Local security primitives |
165
165
 
package/docs/kg-schema.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Knowledge Graph Schema
2
2
 
3
- Current release: **11.5.1 — Rust Full Loop**.
3
+ Current release: **11.5.2 — Tight Ship**.
4
4
 
5
5
  명세 출처: `lattice_ai_full_spec.pptx` 슬라이드 20·21·22
6
6
  구현: `lattice_brain/graph/schema.py`
@@ -0,0 +1,144 @@
1
+ # v11.5.2 — Tight Ship (design plan)
2
+
3
+ Three audits ran against the settled v11.5.1 tree: AUDIT-A (Rust↔Python
4
+ duplication map), AUDIT-B (dead code and no-longer-needed tests, arc-level
5
+ verified against the 100% line+branch gate), AUDIT-C (live front-door parity:
6
+ Rust gateway vs. direct Python worker, 192-endpoint sweep plus targeted
7
+ batteries). This plan is the design synthesis; implementation is delegated in
8
+ two waves. Nothing in this release changes the migration's final form: Python
9
+ remains the AI Worker and the sole client-facing implementation of every
10
+ `/api/*` route; the Rust surface stays pinned by parity goldens.
11
+
12
+ ## Audit verdicts that shape the release
13
+
14
+ 1. **Cross-boundary duplication is all by design.** Every Rust module's Python
15
+ twin either serves a live route in Python-direct mode or feeds a parity
16
+ golden. Zero cross-boundary deletions. The real duplication is intra-Python
17
+ and intra-Rust.
18
+ 2. **The dead code is pre-Rust debt.** Six moved-module shims with zero
19
+ non-test importers, one never-wired streaming seam, and 27 zero-caller
20
+ symbols whose only callers are their own tests ("dead code wearing a
21
+ test" — invisible to the coverage gate by construction).
22
+ 3. **The 183 `test_cov_wp*` files are all load-bearing.** Ten look deletable
23
+ by line analysis and are collectively sole owners of 79 branch arcs. The
24
+ seven coverage-redundant feature-test files carry behavioural regression
25
+ value and are deliberately kept.
26
+ 4. **The front door has seven real gaps (G1–G7)**, one of which (Set-Cookie
27
+ destroyed on proxied redirects) makes the invite gate a hard dead-end and
28
+ silently breaks SSO login.
29
+
30
+ ## Workstream 1 — deletions (paired, gate-preserving)
31
+
32
+ - Six moved-module shims: `latticeai/core/{graph_curator,hooks,multi_agent,workflow_engine}.py`,
33
+ `latticeai/services/{ingestion,kg_portability}.py` + the shim-existence
34
+ tests + their `[tool.mypy] files` entries.
35
+ - `latticeai/services/multimodal_streaming.py` (never wired; restorable from
36
+ git if a provider ever lands).
37
+ - 25 of AUDIT-B's 27 dead symbols, with per-test surgery on the enumerated
38
+ collateral lines so `fail_under = 100` (lines AND branch arcs) holds.
39
+ Decisions on the three flagged items: `delete_conversation` **stays**
40
+ (public store API, exercised as a fixture by the read-equivalence suite);
41
+ `propose_file_delete` **goes together with** the now-uncreatable
42
+ `file_delete` limb of `approve()`; `multimodal_status` **is wired, not
43
+ deleted** (Workstream 3) — FEATURE_STATUS already documents it as
44
+ user-facing behaviour.
45
+ - `metadata_for` interface method (declared on the vector-index ABC,
46
+ implemented four times, called zero times) — removed from ABC and all
47
+ four implementations.
48
+ - `scripts/measure_brain_home_fill.mjs`, `tests/fixtures/filegen/` (12 unread
49
+ data files), and the legacy `desktop/electron/` shell (hardcodes 4825,
50
+ injects none of the safety flags, superseded by Tauri) after verifying it is
51
+ not referenced by any release artifact or workflow.
52
+ - A new guard extends the legacy-shim gate inward: no
53
+ `sys.modules[__name__] = _impl` shim may exist under `latticeai/` again.
54
+
55
+ ## Workstream 2 — consolidation (behaviour-preserving unless stated)
56
+
57
+ Python (the canonical copy is named; the direction always keeps
58
+ `lattice_brain` import-free of `latticeai`):
59
+
60
+ - **Embedder pair**: `latticeai/core/local_embeddings.py` is byte-identical to
61
+ the golden-pinned `lattice_brain/embeddings.py`. The unpinned copy is
62
+ deleted and importers rewired — silent vector drift between two write paths
63
+ was the failure mode.
64
+ - **`workspace_scope_from_request`**: the four verbatim re-derivations
65
+ (`chat_helpers`, `upload_service`, `computer_use`, `admin`) import the
66
+ canonical `api/workspace_scope.py`. Behaviour change, intended: the copies
67
+ silently preferred the header where the canonical rule 403s on
68
+ disagreement.
69
+ - `_default_data_dir` ×4 → `core/config.py`; sha256-hex ×6 → one helper;
70
+ SSE frame builders ×5 → one `sse_frame` (byte-identical output);
71
+ `model_runtime/engines.py` delegator/dead-fragment cleanup;
72
+ the AST-identical mode-service triplet → a `JsonBackedModeService` base;
73
+ module-importability ×4 → one helper (`find_spec` default, real-import
74
+ `strict=True` kept where native-lib load failures matter, e.g. mlx);
75
+ `parse_iso` → `lattice_brain/utils` (the golden-pinned copy);
76
+ `_detect_gpu`/`_detect_cpu` → `setup/wizard/detect.py`; the small ×2
77
+ helpers and the workspace-store mixin where mechanical.
78
+
79
+ Rust: `gateway/clock.rs` (wholesale copy) deleted in favour of
80
+ `lattice_retrieval::routes::naive_local_now`; `brain_not_found` shared;
81
+ `haystack`/`json_opt` lifted into `shape.rs`; `in_set`/`bad_request` lifted
82
+ within `lattice-agent`; `is_py_space`/`round3` shared from `lattice-core` into
83
+ `lattice-ingest`. `lattice-agent`'s independent `pystr` stays — its
84
+ zero-dependency isolation is a deliberate boundary.
85
+
86
+ Deliberately **not** done in a patch release: splitting the three oversized
87
+ route factories (`create_workspace_router` 706 lines et al.) — recorded as
88
+ future work, not silently dropped.
89
+
90
+ ## Workstream 3 — front-door and feature gaps
91
+
92
+ - **G1/G4 (redirects)**: the proxy gets its own reqwest client with redirect
93
+ following disabled; 3xx responses pass through with their `Set-Cookie` and
94
+ `Location` intact; absolute `Location` values naming the internal worker
95
+ origin are rewritten to the request's gateway origin. Fixes the invite
96
+ gate, SSO login, and the twelve legacy deep links.
97
+ - **G2/G3 (native-lane auth)**: the native `/rust/*` and `/host/*` lanes
98
+ mirror Python's `trusted_local_owner` posture exactly. The worker's health
99
+ payload gains the posture facts; the gateway caches them from its existing
100
+ health polling and **fails closed** (posture unknown → native lanes refuse).
101
+ With `LATTICEAI_REQUIRE_AUTH=true` the native lanes answer 401 with a
102
+ machine-readable reason instead of serving the graph unauthenticated (G2)
103
+ or dying mid-loop on a seam 401 (G3). FEATURE_STATUS states the boundary:
104
+ the native lanes are an open-posture, single-local-owner surface in 11.5.2.
105
+ - **G5/G7 (proxied identity)**: the proxy adds `X-Forwarded-For/Proto/Host`;
106
+ the worker computes its effective external origin from `X-Forwarded-Host`
107
+ only when the direct peer is loopback or listed in
108
+ `LATTICEAI_TRUSTED_PROXIES`. CSRF's `Origin == Host` fallback and the three
109
+ absolute-URL producers (admin invite link, permission notifications, SSO
110
+ redirect default) use it. Threat model note: browsers cannot set
111
+ `X-Forwarded-Host`, and a local non-browser caller could already forge
112
+ `Origin`, so this widens nothing.
113
+ - **G6 (CORS)**: the supervisor injects `LATTICEAI_CORS_ALLOWED_ORIGINS` with
114
+ the gateway origins, mirroring the CSRF injection — the browser extension
115
+ and any cross-origin local client work through the front door.
116
+ - **Feature gaps surfaced by the audits**: `graph_search` gains its missing
117
+ route (`POST /api/search/graph` — it was allow-listed but unreachable);
118
+ `multimodal_status` is wired to the route FEATURE_STATUS describes; the
119
+ `recent_chat` context seam is investigated and either wired into the live
120
+ assembler or the golden amended to match reality (whichever the original
121
+ intent supports — the current state, a golden pinning behaviour the product
122
+ never executes, is the one option that stays wrong); `tools/documents.py`
123
+ and `core/agent_profiles.py` — live `/agent` hot-path twins with no golden —
124
+ enter the fixture generators.
125
+ - Small honest fixes: stale `ws://` removed from both CSPs (no WebSocket
126
+ endpoint exists); the Tauri shell no longer navigates to a dead origin when
127
+ the gateway fails to bind.
128
+
129
+ Recorded, not fixed (with reasons): no request timeout on the proxy hop (a
130
+ blanket timeout would kill long-lived SSE; the 15-minute model endpoints rely
131
+ on the current behaviour), `request.is_disconnected()` seeing the gateway's
132
+ socket (inherent to proxying), per-IP buckets collapsing on loopback (the
133
+ gateway is loopback-only; the direct topology behaved identically).
134
+
135
+ ## Release mechanics
136
+
137
+ Both waves verified on the settled tree (dev 3.14 + fresh-resolve 3.11) before
138
+ the machinery runs: bump to 11.5.2 (Cargo.lock joins the sync so the suite
139
+ stops dirtying the tree), OpenAPI regenerated (new routes), release theme
140
+ "Tight Ship", OPERATIONS title, screen-claims entry (backend-only:
141
+ all thirteen measured, none gated), release notes / CHANGELOG / README /
142
+ extension README, screenshots + GIF re-shot at 11.5.2, ARCHITECTURE System
143
+ Map labels updated (proxy semantics, posture-gated native lanes), DMG via
144
+ release:artifacts, tag + GitHub Release, main push, CI green.
@@ -26,7 +26,7 @@ from .storage import (
26
26
  storage_from_env,
27
27
  )
28
28
 
29
- __version__ = "11.5.1"
29
+ __version__ = "11.5.2"
30
30
 
31
31
  __all__ = [
32
32
  "AgentRuntime",
@@ -644,7 +644,7 @@ def gate_ingest_candidate(
644
644
  """Score whether new content should be ingested into the graph.
645
645
 
646
646
  Pure function — no store access, no side effects. Intended adoption point
647
- for the ingestion pipeline (``services/ingestion.py`` /
647
+ for the ingestion pipeline (``lattice_brain.ingestion`` /
648
648
  ``lattice_brain.graph.ingest``), which passes a closure over its own
649
649
  scoped search, e.g.::
650
650
 
@@ -516,31 +516,3 @@ class KnowledgeGraphV2SchemaMixin(_Core):
516
516
  except Exception as ex:
517
517
  logging.debug("knowledge_graph: v2 edge delete mirror skipped: %s", ex)
518
518
 
519
- def _v2_sync_report(self) -> Dict[str, Any]:
520
- """Diagnose the dual-write invariant: legacy node/edge id sets must equal
521
- the v2 projection's. Returns counts + any drift (ids missing from / extra
522
- in v2). ``in_sync`` is True only when both id sets match exactly.
523
-
524
- All legacy writes go through _upsert_node/_upsert_edge (which dual-write)
525
- and every legacy delete is mirrored, so a non-empty drift signals a
526
- bypassed write path — this is the runtime guard for that invariant.
527
- """
528
- if KGStoreV2 is None:
529
- return {"available": False, "in_sync": True}
530
- with self._connect() as conn:
531
- legacy_nodes = {r[0] for r in conn.execute("SELECT id FROM nodes")}
532
- v2_nodes = {r[0] for r in conn.execute("SELECT id FROM nodes_v2")}
533
- legacy_edges = {r[0] for r in conn.execute("SELECT id FROM edges")}
534
- v2_edges = {r[0] for r in conn.execute("SELECT id FROM edges_v2")}
535
- return {
536
- "available": True,
537
- "in_sync": legacy_nodes == v2_nodes and legacy_edges == v2_edges,
538
- "nodes_legacy": len(legacy_nodes),
539
- "nodes_v2": len(v2_nodes),
540
- "edges_legacy": len(legacy_edges),
541
- "edges_v2": len(v2_edges),
542
- "nodes_missing_from_v2": sorted(legacy_nodes - v2_nodes),
543
- "nodes_extra_in_v2": sorted(v2_nodes - legacy_nodes),
544
- "edges_missing_from_v2": sorted(legacy_edges - v2_edges),
545
- "edges_extra_in_v2": sorted(v2_edges - legacy_edges),
546
- }
@@ -142,9 +142,6 @@ class VectorIndex(Protocol):
142
142
  def rebuild(self, items: Iterable[IndexItem]) -> None:
143
143
  raise NotImplementedError
144
144
 
145
- def metadata_for(self, id: str) -> Dict[str, Any]:
146
- raise NotImplementedError
147
-
148
145
  def search(
149
146
  self,
150
147
  query: Sequence[float],
@@ -80,10 +80,6 @@ class BruteForceIndex:
80
80
  for item_id, vector, metadata in items:
81
81
  self.add(item_id, vector, metadata)
82
82
 
83
- def metadata_for(self, id: str) -> Dict[str, Any]:
84
- """Metadata stored alongside ``id`` (empty dict when unknown)."""
85
- return dict(self._metadata.get(str(id), {}))
86
-
87
83
  def search(
88
84
  self,
89
85
  query: Sequence[float],
@@ -150,9 +150,6 @@ class HnswIndex:
150
150
  self.add(item_id, vector, metadata)
151
151
  self._dirty = True
152
152
 
153
- def metadata_for(self, id: str) -> Dict[str, Any]:
154
- return dict(self._metadata.get(str(id), {}))
155
-
156
153
  # ── graph construction ───────────────────────────────────────────────────
157
154
  def _new_graph(self, module: Any, capacity: int) -> Any:
158
155
  graph = module.Index(space=self._space, dim=self._dim)
@@ -109,9 +109,6 @@ class QuantizedIndex:
109
109
  for item_id, vector, metadata in items:
110
110
  self.add(item_id, vector, metadata)
111
111
 
112
- def metadata_for(self, id: str) -> Dict[str, Any]:
113
- return dict(self._metadata.get(str(id), {}))
114
-
115
112
  def search(
116
113
  self,
117
114
  query: Sequence[float],