ltcai 11.1.0 → 11.4.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 (289) hide show
  1. package/README.md +47 -54
  2. package/docs/CHANGELOG.md +94 -0
  3. package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
  4. package/docs/DEVELOPMENT.md +1 -1
  5. package/docs/FEATURE_AUDIT_v11.2.0.md +393 -0
  6. package/docs/LAYOUT_REBUILD_SPEC.md +9 -1
  7. package/docs/MULTI_AGENT_RUNTIME.md +1 -1
  8. package/docs/ONBOARDING.md +1 -1
  9. package/docs/OPERATIONS.md +6 -2
  10. package/docs/PERMISSION_MODE.md +1 -1
  11. package/docs/TRUST_MODEL.md +1 -1
  12. package/docs/WHY_LATTICE.md +1 -1
  13. package/docs/architecture.md +6 -2
  14. package/docs/kg-schema.md +2 -2
  15. package/docs/v11.3.0_PLAN.md +202 -0
  16. package/docs/v11.4.0_RUST_FOUNDATION_PLAN.md +176 -0
  17. package/lattice_brain/__init__.py +1 -1
  18. package/lattice_brain/gates.py +125 -0
  19. package/lattice_brain/graph/_kg_common/__init__.py +287 -0
  20. package/lattice_brain/graph/_kg_common/extraction.py +516 -0
  21. package/lattice_brain/graph/_kg_common/relations.py +161 -0
  22. package/lattice_brain/graph/_kg_common/text.py +479 -0
  23. package/lattice_brain/graph/discovery_index/__init__.py +35 -0
  24. package/lattice_brain/graph/discovery_index/cleanup.py +182 -0
  25. package/lattice_brain/graph/discovery_index/extract.py +137 -0
  26. package/lattice_brain/graph/discovery_index/scan.py +411 -0
  27. package/lattice_brain/graph/discovery_index/upsert.py +495 -0
  28. package/lattice_brain/graph/fusion.py +35 -4
  29. package/lattice_brain/graph/projection/__init__.py +42 -0
  30. package/lattice_brain/graph/projection/curation.py +500 -0
  31. package/lattice_brain/graph/{projection.py → projection/v2_schema.py} +81 -485
  32. package/lattice_brain/graph/retrieval/__init__.py +54 -0
  33. package/lattice_brain/graph/retrieval/context.py +197 -0
  34. package/lattice_brain/graph/retrieval/graph_view.py +319 -0
  35. package/lattice_brain/graph/retrieval/hybrid.py +488 -0
  36. package/lattice_brain/graph/retrieval/maintenance.py +121 -0
  37. package/lattice_brain/graph/retrieval/signals.py +95 -0
  38. package/lattice_brain/graph/retrieval_vector/__init__.py +42 -0
  39. package/lattice_brain/graph/retrieval_vector/fingerprint.py +97 -0
  40. package/lattice_brain/graph/retrieval_vector/indexing.py +347 -0
  41. package/lattice_brain/graph/retrieval_vector/search.py +560 -0
  42. package/lattice_brain/graph/retrieval_vector/status.py +374 -0
  43. package/lattice_brain/graph/schema.py +9 -0
  44. package/lattice_brain/graph/store.py +9 -0
  45. package/lattice_brain/graph/vector_index/selector.py +32 -2
  46. package/lattice_brain/ingestion/__init__.py +130 -0
  47. package/lattice_brain/ingestion/_contract.py +90 -0
  48. package/lattice_brain/ingestion/constants.py +127 -0
  49. package/lattice_brain/ingestion/folder_scan.py +57 -0
  50. package/lattice_brain/ingestion/folders.py +258 -0
  51. package/lattice_brain/ingestion/hashing.py +26 -0
  52. package/lattice_brain/ingestion/jobs_api.py +107 -0
  53. package/lattice_brain/ingestion/models.py +80 -0
  54. package/lattice_brain/ingestion/pipeline.py +486 -0
  55. package/lattice_brain/ingestion/quality.py +209 -0
  56. package/lattice_brain/ingestion/routing.py +295 -0
  57. package/lattice_brain/multimodal/__init__.py +164 -0
  58. package/lattice_brain/multimodal/audio.py +77 -0
  59. package/lattice_brain/multimodal/common.py +118 -0
  60. package/lattice_brain/{multimodal.py → multimodal/images.py} +22 -262
  61. package/lattice_brain/multimodal/ports.py +169 -0
  62. package/lattice_brain/multimodal/video.py +410 -0
  63. package/lattice_brain/portability/__init__.py +90 -0
  64. package/lattice_brain/portability/_contract.py +42 -0
  65. package/lattice_brain/portability/backups.py +338 -0
  66. package/lattice_brain/portability/bundles.py +136 -0
  67. package/lattice_brain/portability/constants.py +93 -0
  68. package/lattice_brain/portability/fsops.py +138 -0
  69. package/lattice_brain/portability/service.py +41 -0
  70. package/lattice_brain/portability/sharing.py +714 -0
  71. package/lattice_brain/runtime/__init__.py +1 -1
  72. package/lattice_brain/runtime/multi_agent.py +1 -1
  73. package/lattice_brain/sealed_box.py +244 -0
  74. package/lattice_brain/synthesis.py +24 -1
  75. package/latticeai/__init__.py +1 -1
  76. package/latticeai/api/brain_intelligence.py +4 -0
  77. package/latticeai/api/chat.py +11 -0
  78. package/latticeai/api/chat_helpers.py +16 -3
  79. package/latticeai/api/chat_hybrid.py +32 -1
  80. package/latticeai/api/chronicle.py +63 -0
  81. package/latticeai/api/features.py +70 -0
  82. package/latticeai/api/local_files.py +102 -0
  83. package/latticeai/api/portability.py +39 -4
  84. package/latticeai/api/review_queue.py +126 -0
  85. package/latticeai/api/search.py +16 -2
  86. package/latticeai/core/agent/__init__.py +93 -0
  87. package/latticeai/core/agent/_contract.py +79 -0
  88. package/latticeai/core/agent/context.py +57 -0
  89. package/latticeai/core/agent/deps.py +125 -0
  90. package/latticeai/core/agent/execution.py +622 -0
  91. package/latticeai/core/agent/planning.py +145 -0
  92. package/latticeai/core/agent/recovery.py +157 -0
  93. package/latticeai/core/agent/runtime.py +210 -0
  94. package/latticeai/core/agent/verification.py +231 -0
  95. package/latticeai/core/config.py +4 -1
  96. package/latticeai/core/context_builder.py +6 -3
  97. package/latticeai/core/embedding_providers/__init__.py +151 -0
  98. package/latticeai/core/embedding_providers/base.py +199 -0
  99. package/latticeai/core/embedding_providers/captions.py +162 -0
  100. package/latticeai/core/embedding_providers/profiles.py +126 -0
  101. package/latticeai/core/embedding_providers/text.py +350 -0
  102. package/latticeai/core/embedding_providers/vision.py +352 -0
  103. package/latticeai/core/file_generation/__init__.py +115 -0
  104. package/latticeai/core/file_generation/bundles.py +76 -0
  105. package/latticeai/core/file_generation/extraction.py +154 -0
  106. package/latticeai/core/file_generation/inference.py +235 -0
  107. package/latticeai/core/file_generation/orchestration.py +152 -0
  108. package/latticeai/core/file_generation/prompting.py +117 -0
  109. package/latticeai/core/file_generation/repair.py +114 -0
  110. package/latticeai/core/file_generation/sanitize.py +61 -0
  111. package/latticeai/core/file_generation/validation.py +201 -0
  112. package/latticeai/core/legacy_compatibility.py +1 -1
  113. package/latticeai/core/marketplace.py +1 -1
  114. package/latticeai/core/messages.py +152 -0
  115. package/latticeai/core/model_compat.py +73 -2
  116. package/latticeai/core/workspace_os_constants.py +1 -1
  117. package/latticeai/integrations/telegram_bot/__init__.py +123 -0
  118. package/latticeai/integrations/telegram_bot/__main__.py +17 -0
  119. package/latticeai/integrations/telegram_bot/config.py +86 -0
  120. package/latticeai/integrations/telegram_bot/dispatch.py +311 -0
  121. package/latticeai/integrations/telegram_bot/flows.py +478 -0
  122. package/latticeai/integrations/telegram_bot/helpers.py +322 -0
  123. package/latticeai/integrations/telegram_bot/screens.py +394 -0
  124. package/latticeai/models/model_providers.py +12 -4
  125. package/latticeai/models/router/__init__.py +88 -0
  126. package/latticeai/models/router/_contract.py +66 -0
  127. package/latticeai/models/router/branding.py +56 -0
  128. package/latticeai/models/router/catalog.py +69 -0
  129. package/latticeai/models/router/documents.py +199 -0
  130. package/latticeai/models/router/errors.py +37 -0
  131. package/latticeai/models/router/generation.py +258 -0
  132. package/latticeai/models/router/loading.py +291 -0
  133. package/latticeai/models/router/local_models.py +85 -0
  134. package/latticeai/models/router/registry.py +147 -0
  135. package/latticeai/runtime/build_phases/__init__.py +82 -0
  136. package/latticeai/runtime/build_phases/features.py +407 -0
  137. package/latticeai/runtime/build_phases/foundation.py +555 -0
  138. package/latticeai/runtime/build_phases/web.py +492 -0
  139. package/latticeai/runtime/chat_wiring.py +4 -0
  140. package/latticeai/runtime/feature_toggle_wiring.py +163 -0
  141. package/latticeai/runtime/router_registration.py +11 -0
  142. package/latticeai/runtime/runtime_context.py +1 -0
  143. package/latticeai/services/app_context.py +8 -0
  144. package/latticeai/services/architecture_readiness.py +48 -19
  145. package/latticeai/services/automation_intelligence.py +22 -2
  146. package/latticeai/services/brain_intelligence/__init__.py +58 -0
  147. package/latticeai/services/brain_intelligence/_contract.py +71 -0
  148. package/latticeai/services/brain_intelligence/consistency.py +193 -0
  149. package/latticeai/services/brain_intelligence/constants.py +47 -0
  150. package/latticeai/services/brain_intelligence/digest.py +258 -0
  151. package/latticeai/services/brain_intelligence/health.py +331 -0
  152. package/latticeai/services/brain_intelligence/proposals.py +264 -0
  153. package/latticeai/services/brain_intelligence/sampling.py +84 -0
  154. package/latticeai/services/brain_intelligence/service.py +48 -0
  155. package/latticeai/services/chronicle.py +557 -0
  156. package/latticeai/services/command_center.py +10 -4
  157. package/latticeai/services/feature_toggles.py +502 -0
  158. package/latticeai/services/folder_watch.py +122 -1
  159. package/latticeai/services/hybrid_chat.py +56 -5
  160. package/latticeai/services/interop_bridges.py +978 -0
  161. package/latticeai/services/memory_service/__init__.py +52 -0
  162. package/latticeai/services/memory_service/_contract.py +100 -0
  163. package/latticeai/services/memory_service/brief.py +431 -0
  164. package/latticeai/services/memory_service/constants.py +57 -0
  165. package/latticeai/services/memory_service/maintenance.py +138 -0
  166. package/latticeai/services/memory_service/manager.py +186 -0
  167. package/latticeai/services/memory_service/proof.py +136 -0
  168. package/latticeai/services/memory_service/recall.py +225 -0
  169. package/latticeai/services/memory_service/service.py +48 -0
  170. package/latticeai/services/memory_service/stores.py +110 -0
  171. package/latticeai/services/model_capability_registry.py +434 -261
  172. package/latticeai/services/model_catalog.py +95 -61
  173. package/latticeai/services/model_recommendation.py +18 -11
  174. package/latticeai/services/model_runtime/__init__.py +322 -0
  175. package/latticeai/services/model_runtime/cloud.py +87 -0
  176. package/latticeai/services/model_runtime/download.py +282 -0
  177. package/latticeai/services/model_runtime/engines.py +341 -0
  178. package/latticeai/services/model_runtime/loading.py +178 -0
  179. package/latticeai/services/model_runtime/service.py +129 -0
  180. package/latticeai/services/model_runtime/state.py +131 -0
  181. package/latticeai/services/model_runtime/status.py +255 -0
  182. package/latticeai/services/multimodal_ports.py +26 -1
  183. package/latticeai/services/obsidian_bridge.py +16 -25
  184. package/latticeai/services/product_readiness.py +15 -7
  185. package/latticeai/services/search_service.py +149 -2
  186. package/latticeai/services/tool_dispatch.py +4 -0
  187. package/latticeai/setup/auto_setup.py +27 -30
  188. package/latticeai/setup/wizard/__init__.py +126 -0
  189. package/latticeai/setup/wizard/catalog.py +172 -0
  190. package/latticeai/setup/wizard/detect.py +323 -0
  191. package/latticeai/setup/wizard/install.py +348 -0
  192. package/latticeai/setup/wizard/paths.py +168 -0
  193. package/latticeai/setup/wizard/plans.py +74 -0
  194. package/latticeai/setup/wizard/recommend.py +320 -0
  195. package/package.json +6 -2
  196. package/scripts/bump_version.py +14 -0
  197. package/scripts/capture_release_evidence.mjs +33 -21
  198. package/scripts/check_current_release_docs.mjs +1 -1
  199. package/scripts/check_i18n_namespace_coverage.mjs +41 -4
  200. package/scripts/check_max_file_lines.mjs +102 -0
  201. package/scripts/check_release_evidence_bound.mjs +30 -15
  202. package/scripts/check_screenshot_pixel_delta.py +34 -4
  203. package/scripts/check_server_i18n.mjs +2 -0
  204. package/scripts/generate_rust_parity_fixtures.py +562 -0
  205. package/scripts/lib/mock_server_fingerprint.mjs +94 -0
  206. package/scripts/release_screen_claims.json +44 -2
  207. package/scripts/verify_hf_model_registry.py +253 -218
  208. package/src-tauri/Cargo.lock +361 -3
  209. package/src-tauri/Cargo.toml +6 -1
  210. package/src-tauri/src/backend.rs +349 -0
  211. package/src-tauri/src/folder.rs +33 -0
  212. package/src-tauri/src/main.rs +97 -399
  213. package/src-tauri/tauri.conf.json +1 -1
  214. package/static/app/asset-manifest.json +41 -37
  215. package/static/app/assets/Act-yYpYnn0v.js +1 -0
  216. package/static/app/assets/AdminConsole-DL3Cr5pL.js +1 -0
  217. package/static/app/assets/{Brain-CzCsI1mi.js → Brain-C1HBN0Wf.js} +2 -2
  218. package/static/app/assets/BrainHome-DoXRhUUC.js +2 -0
  219. package/static/app/assets/BrainSignals-6yR6ir5t.js +1 -0
  220. package/static/app/assets/Capture-CFIRsFNE.js +1 -0
  221. package/static/app/assets/Chronicle-BZbEgiwN.js +1 -0
  222. package/static/app/assets/CommandPalette-D2pMxC2I.js +1 -0
  223. package/static/app/assets/Library-DwO3yZST.js +1 -0
  224. package/static/app/assets/{LivingBrain-BXMWIK_2.js → LivingBrain-Jn1GK0-S.js} +1 -1
  225. package/static/app/assets/ProductFlow-B-w1R4Oo.js +1 -0
  226. package/static/app/assets/ReviewCard-6B27X8Vg.js +3 -0
  227. package/static/app/assets/System-DW8F-2xL.js +1 -0
  228. package/static/app/assets/arrow-left-DXvKg9U6.js +1 -0
  229. package/static/app/assets/{bot-4BvN07ux.js → bot-IM_E_Y12.js} +1 -1
  230. package/static/app/assets/brain-Ci1CkWjM.js +1 -0
  231. package/static/app/assets/{button-CDjtnAoU.js → button-COwyqfHM.js} +1 -1
  232. package/static/app/assets/circle-check-DfInj-qD.js +1 -0
  233. package/static/app/assets/{circle-pause-D_RMn7tp.js → circle-pause-DEM4A1Y5.js} +1 -1
  234. package/static/app/assets/{circle-play-B5OpB8ae.js → circle-play-C9djDuLd.js} +1 -1
  235. package/static/app/assets/{cpu-BIlWInHf.js → cpu-DFdo1gw-.js} +1 -1
  236. package/static/app/assets/{download-BtjXfL3z.js → download-SnJL6oqk.js} +1 -1
  237. package/static/app/assets/{folder-open-DefMpxI2.js → folder-open-CqZeDkjE.js} +1 -1
  238. package/static/app/assets/{hard-drive-BQ8NZVkw.js → hard-drive-j1jJXYYf.js} +1 -1
  239. package/static/app/assets/{index-vtEfYvQY.css → index-BLPb5lmE.css} +1 -1
  240. package/static/app/assets/index-_u5iUHDr.js +10 -0
  241. package/static/app/assets/input-B0lPdRQZ.js +1 -0
  242. package/static/app/assets/link-2-CoFbooHS.js +1 -0
  243. package/static/app/assets/{permissionCopy-BqZ5tsgL.js → permissionCopy-BsyLxtao.js} +1 -1
  244. package/static/app/assets/primitives-DEbN-d6p.js +1 -0
  245. package/static/app/assets/search-BybIWPNd.js +1 -0
  246. package/static/app/assets/{share-2-D5zg_0fY.js → share-2-CVtZ_ewX.js} +1 -1
  247. package/static/app/assets/{shield-alert-B5pZzkUb.js → shield-alert-CBi2GNWM.js} +1 -1
  248. package/static/app/assets/{textarea-nEVIweKY.js → textarea-DNMpB5ih.js} +1 -1
  249. package/static/app/assets/{useFocusTrap-Cm99AHlz.js → useFocusTrap-C83t3GXF.js} +1 -1
  250. package/static/app/assets/useMutation-DtbJDoyz.js +1 -0
  251. package/static/app/assets/{useQuery-Dm__N6bL.js → useQuery-Dcp1OChy.js} +1 -1
  252. package/static/app/assets/utils-BlZr7Pd4.js +4 -0
  253. package/static/app/assets/workspace-jJY4RuAV.js +1 -0
  254. package/static/app/index.html +4 -4
  255. package/static/sw.js +1 -1
  256. package/lattice_brain/graph/_kg_common.py +0 -1331
  257. package/lattice_brain/graph/discovery_index.py +0 -1141
  258. package/lattice_brain/graph/retrieval.py +0 -1120
  259. package/lattice_brain/graph/retrieval_vector.py +0 -1293
  260. package/lattice_brain/ingestion.py +0 -1377
  261. package/lattice_brain/portability.py +0 -1210
  262. package/latticeai/core/agent.py +0 -1412
  263. package/latticeai/core/embedding_providers.py +0 -1196
  264. package/latticeai/core/file_generation.py +0 -1047
  265. package/latticeai/integrations/telegram_bot.py +0 -1390
  266. package/latticeai/models/router.py +0 -1007
  267. package/latticeai/runtime/build_phases.py +0 -1422
  268. package/latticeai/services/brain_intelligence.py +0 -967
  269. package/latticeai/services/memory_service.py +0 -1177
  270. package/latticeai/services/model_runtime.py +0 -1281
  271. package/latticeai/setup/wizard.py +0 -1277
  272. package/static/app/assets/Act-D0HWqtn0.js +0 -1
  273. package/static/app/assets/AdminConsole-D-QDW-A4.js +0 -1
  274. package/static/app/assets/BrainHome-Btns-_TA.js +0 -2
  275. package/static/app/assets/BrainSignals-2dHQNkns.js +0 -1
  276. package/static/app/assets/Capture-CT8v1StE.js +0 -1
  277. package/static/app/assets/CommandPalette-DoLXC2KH.js +0 -1
  278. package/static/app/assets/Library-DDoxFE5c.js +0 -1
  279. package/static/app/assets/ProductFlow-DOYf7JIs.js +0 -1
  280. package/static/app/assets/ReviewCard-COQsqidK.js +0 -3
  281. package/static/app/assets/System-BRllvYXd.js +0 -1
  282. package/static/app/assets/arrow-left-DnyMzss-.js +0 -1
  283. package/static/app/assets/brain-uMb_5hnO.js +0 -1
  284. package/static/app/assets/index-0AvoEBzJ.js +0 -10
  285. package/static/app/assets/input-B_5ZJ9oy.js +0 -1
  286. package/static/app/assets/primitives-CVwew78r.js +0 -1
  287. package/static/app/assets/search-DkhnOKZt.js +0 -1
  288. package/static/app/assets/utils-DcDMoZIe.js +0 -4
  289. package/static/app/assets/workspace-LtRRSKTf.js +0 -1
@@ -0,0 +1,393 @@
1
+ # Feature Audit — v11.2.0
2
+
3
+ > **Status: reference** — a point-in-time, evidence-based sweep of every row in
4
+ > [`FEATURE_STATUS.md`](../FEATURE_STATUS.md). It records what was true when it
5
+ > was run, not what the current release claims; the canonical feature state
6
+ > stays in `FEATURE_STATUS.md`.
7
+
8
+ Audited against the `release/v11.2.0` working tree on 2026-08-10, starting from
9
+ the 11.1.0 feature table. Continues the evidence-based audit tradition started
10
+ in 3.3.0: **every row gets a verdict and a way to reproduce it**, and a row
11
+ whose sentence outruns its code is lowered rather than defended.
12
+
13
+ ## Method
14
+
15
+ Claims were checked by running the product, not by reading about it.
16
+
17
+ * **Hermetic full-app boot.** `latticeai.app_factory.build_runtime()` inside
18
+ `scripts/export_openapi.py`'s `isolated_runtime_environment`, which points
19
+ `HOME`, `LATTICEAI_DATA_DIR`, `LATTICEAI_BRAIN_DIR`, the agent workspace, the
20
+ vault dir and the static dir at a throwaway temp tree. No real HOME, no real
21
+ network, no live server. Endpoints were exercised through `TestClient`.
22
+ * **Three passes.** (1) anonymous read surface, (2) corrected paths with
23
+ redirect-following off plus API introspection, (3) a registered-and-signed-in
24
+ session driving the local-file approval dance end to end.
25
+ * **Route inventory** from the app's own route table and its generated OpenAPI
26
+ schema, cross-checked against the checked-in `frontend/openapi.json` that
27
+ `scripts/check_openapi_drift.mjs` already proves is regenerated from the live
28
+ app.
29
+ * **Code-level verification** for claims an endpoint cannot show (constants,
30
+ defaults, guard order, which collaborator writes which key).
31
+
32
+ Where a claim is pinned by an existing regression test, that test is the
33
+ evidence: it is cheaper to keep true than a paragraph.
34
+
35
+ ## Cross-cutting smoke
36
+
37
+ Measured on the hermetic boot described above.
38
+
39
+ | Measure | Value |
40
+ | --- | --- |
41
+ | Routers registered (`include_router` calls, all distinct) | 35 |
42
+ | Total routes on the app | 451 |
43
+ | Of those, API routes | 446 |
44
+ | Non-API routes | 4 (`/openapi.json`, `/docs`, `/docs/oauth2-redirect`, `/redoc`) |
45
+ | Static mounts | `/static` always; `/icons` only when `static/icons/` exists (it does in the repo; it did not in the sandboxed static dir) |
46
+ | OpenAPI paths | 404 |
47
+ | OpenAPI operations | 445 |
48
+ | `frontend/openapi.json` drift | clean (`node scripts/check_openapi_drift.mjs`) |
49
+ | Health snapshot | `status: ok`, `version 11.1.0`, `mode local`, `graph_enabled true`, `telegram_enabled false`, `autoload_models false` |
50
+ | Probes run | 70 (pass 1) + 42 (pass 2) + the signed-in pass; **zero 5xx, zero unhandled exceptions** |
51
+
52
+ Every non-200 in the sweep was a *designed* refusal, and each named its
53
+ reason: `403` on the share routes while `LATTICEAI_BRAIN_NETWORK` is off,
54
+ `401` on local-file routes without a session, `405` on a POST-only path,
55
+ `422` on a malformed body.
56
+
57
+ ### Frontend ↔ real routes
58
+
59
+ 320 server-path literals were extracted from `frontend/src`. **Every one
60
+ resolves to a real route.** Ten looked missing on a first pass and all ten are
61
+ template routes the client builds with an interpolated id (`/models/switch` →
62
+ `/models/switch/{model_id:path}`, `/mcp/connectors` → `/mcp/connectors/{mcp_id}`,
63
+ and so on); the eleventh, `/workspace-admin`, is a client-side hash route, not a
64
+ server path.
65
+
66
+ ### mock_server ↔ real routes
67
+
68
+ `tests/visual/mock_server.cjs` serves the twelve release-capture screens.
69
+
70
+ | Measure | Value |
71
+ | --- | --- |
72
+ | Exact path literals in the mock | 132 |
73
+ | Matching a real route (exact or template) | 131 |
74
+ | Mock-only | **1** — `/v3`, a legacy alias for `/app` that the server no longer serves |
75
+ | Prefix handlers in the mock | 17, all resolving to real routes or mounts |
76
+ | Real routes the frontend can call that the mock does not serve | 183 |
77
+
78
+ The 183 are capture-fidelity headroom, not product defects: the mock answers
79
+ what the twelve screens need and falls through for the rest. The gap is bounded
80
+ by a real gate — `tests/visual/v3.spec.js` asserts
81
+ `service-unavailable-banner` count is zero across all ten plain-mode routes, so
82
+ a mock gap that reaches a core panel fails the visual suite rather than shipping
83
+ a screenshot of a working feature rendered as broken.
84
+
85
+ ## Verdict table
86
+
87
+ `WORKS` — the claim was exercised and held. `PARTIAL` — the mechanism exists
88
+ and is tested, but a surface the sentence implies does not reach it.
89
+ `MISMATCH` — the doc said something the code does not do.
90
+
91
+ | # | Row | Verdict | Evidence |
92
+ | --- | --- | --- | --- |
93
+ | 1 | Brain Home | **MISMATCH → doc fixed** | Living Brain + composer in-viewport asserted at 1280×800 and 390×780 (`tests/visual/v3.spec.js`); the Brain Brief renders only inside `BrainHomeDock`'s `stats` tab, and `BrainHome.test.tsx` asserts the dock opens closed |
94
+ | 2 | Automation Intelligence | WORKS | `GET /api/automation/{overview,patterns,suggestions}` → 200 with `consent.default_state: "draft_disabled"`, `requires_user_enable: true`, `review_before_run: true` |
95
+ | 3 | Brain Intelligence | **PARTIAL → code fixed** | `GET /api/brain/health` → 200 with all four dimensions; on an empty Brain three read `unavailable` yet the composite reported `overall_score: 100, grade: "excellent"` (see Finding 3) |
96
+ | 4 | Temporal Knowledge | WORKS | `KnowledgeGraphStore.as_of(timestamp, …)` and `neighbors(…, as_of=None)` present with the documented defaults; `tests/unit/test_t2_temporal_schema.py`, `test_t2_temporal_reads.py`, `test_kg_temporal.py` |
97
+ | 5 | Proactive Synthesis | WORKS | `POST /api/brain/synthesize` → 200 with the four proposal kinds; `SYNTHESIS_THRESHOLD_ENV` / `DEFAULT_SYNTHESIS_THRESHOLD = 25`; `tests/unit/test_t2_synthesis_job.py` |
98
+ | 6 | Memory Decay | WORKS | `GET /api/brain/importance` → 200 (`half_life_days: 30.0`, `access_source: "metadata"`); `/api/brain/quality-report` carries `importance` + `tidying`; `tests/unit/test_t2_importance_decay.py` |
99
+ | 7 | Hybrid Recall | WORKS | `POST /api/memory/recall` → 200 with `quality_gate.gate == "hybrid-evidence/v2"`; `GET /api/search/hybrid` reports per-channel weights and recall detail |
100
+ | 8 | Folder Ingestion | WORKS | `GET /api/ingestion/jobs` → 200; `/api/ingestion/folder`, `/jobs/{id}`, `/jobs/{id}/resume` present |
101
+ | 9 | Extraction Quality | WORKS | `assess_extraction_quality` + observe-mode `_observe_quality_gate` (every failure path returns `None` and the ingest proceeds); `tests/unit/test_ingestion_quality_jobs.py` |
102
+ | 10 | Vector Freshness | **PARTIAL → code fixed** | `GET /api/brain/vector-freshness` returned only `{status, pending_items, total_items, detail}` while `vector_freshness_breakdown()` had **no product caller** (see Finding 4) |
103
+ | 11 | Vector Index Backends | WORKS | `resolve_vector_index({})` → `brute`/exact; an unknown name falls back **and says why** in `detail`; choices are exactly `brute`/`quantized`/`hnsw` |
104
+ | 12 | Background Embedding | WORKS | `IngestionPipeline.drain_vector_queue` present; the Known Limitation that nothing schedules it is accurate |
105
+ | 13 | Fusion Strategy | WORKS (off) | `LATTICEAI_FUSION_STRATEGY` unset in a clean boot; alpha fusion is what `/api/search/hybrid` reports |
106
+ | 14 | Graph Candidate Expansion | WORKS (off) | `graph_expansion_enabled()` false with no env; `GRAPH_EXPANSION_ENV` as documented |
107
+ | 15 | Self-Model (Personal Ontology) | WORKS | `POST /api/memory/self-model/propose` with `저는 …를 선호합니다` returned 1 candidate and **one pending review item**, nothing written; `apply` calls `review_queue.approve()` before `_write_fact`; summary capped at half the context budget |
108
+ | 16 | Workspace Reorganization | WORKS | one `folder_reorganization` proposal, targets always `topics/<주제>/`, `unplaced` reasons, **no delete path exists in the module**, skip-and-report on apply |
109
+ | 17 | Change Governance | WORKS | `MUTATING_TOOL_INVENTORY` + `assert_governance_coverage`; base-SHA conflict → 409; `_atomic_write` via `os.replace` under a lock; verifier fails closed to `NEEDS_REVIEW` |
110
+ | 18 | Brain Brief | WORKS | `/api/memory/brain-brief` and `/api/brain/proactive-brief` → 200; the proactive brief counts existing proposals and raises none |
111
+ | 19 | Conversation | WORKS | `tests/unit/test_chat_no_model.py`; the loaded-model list is empty in a clean boot and chat refuses rather than inventing output |
112
+ | 20 | Knowledge Graph | WORKS | `/api/graph`, `/knowledge-graph/stats`, `/api/knowledge-graph/provenance` → 200; v2 schema reported alongside v1 |
113
+ | 21 | Source Capture | WORKS | unified pipeline reachable from files/folders/notes/web; provenance keyed by origin (no wall-clock component) |
114
+ | 22 | Local Models | WORKS | `GET /models`, `/models/recommendations` → 200 with a real device profile; `allow_model_downloads: false` in a clean boot |
115
+ | 23 | Installer Audit | WORKS | `auto_setup` refuses to apply on a confirmation-token mismatch (`CommandConfirmationError`); `tests/unit/test_setup_wizard.py`, `test_cov_wp04_wizard_install.py` |
116
+ | 24 | Cloud Models | WORKS | `_load_cloud_model` raises `Missing API key env var: …` **before** the client is constructed; egress is audited before any call |
117
+ | 25 | Telegram | WORKS | `run_bot` returns without polling on any of: no token, empty allowlist, no server session; ACL check precedes `register_chat_id` on both message and callback paths |
118
+ | 26 | Agent Runtime | WORKS | `/agents/api/runtime/health` → `status: "unavailable"` with the honest reason ("No LLM-backed model is loaded; product execution API refuses simulation runs"); preview records no run; unknown roles rejected |
119
+ | 27 | Tool Registry / MCP | WORKS | `/tools/registry/diagnostics` → `registered_tools 47 / governed_tools 47`, empty `governance_without_handler` and `handler_without_governance`; `/mcp/installed`, `/mcp/tools` → 200 |
120
+ | 28 | Workspaces | WORKS | `/workspace/os` → 200 with the personal workspace default; admin surfaces on separate routes |
121
+ | 29 | VS Code Extension | WORKS | `/workspace/vscode/status` → 200 (`connected:false, status:"offline"`); `POST /agent` `stream:true` dispatches `agent_step`; 4xx never reads as success |
122
+ | 30 | Browser Extension | WORKS | every outbound call is `http://127.0.0.1:${port}`; an absent verdict renders `근거 확인 불가`; no approve/reject call exists in the extension |
123
+ | 31 | Telegram Review | WORKS | `/review` reads the same `/api/proposals`; 409 → "아무것도 쓰지 않았습니다", no retry |
124
+ | 32 | Knowledge Garden | WORKS | `GET /api/brain/garden` → 200 with exactly four beds; an unavailable graph yields empty beds |
125
+ | 33 | Agent File Tasks | WORKS | `executor_prompt_for(base, *, profile, self_model_summary)`; `EXECUTOR_PROMPT` itself carries no file-task hints; summary injected only when passed |
126
+ | 34 | Agent Profiles | WORKS | `COMPACT_MAX_PARAMS_B = 4.0`; an id naming no size keeps `standard`; a failed direct-path write is reported as not written |
127
+ | 35 | Folder Memory State | WORKS | `GET /knowledge-graph/local/health` → 200; vector freshness reported once and labelled `vector_freshness_global` |
128
+ | 36 | Voice Capture | WORKS | `GET /api/capture/voice/status` → `capture:true, transcription:false` with a plain-language reason; the transcriber really is one shared port (`ctx.MULTIMODAL_PORTS.transcriber` feeds both the pipeline and `VoiceCaptureService`) |
129
+ | 37 | Multi-modal Memories | WORKS | `ALLOW_MULTIMODAL_ENV` default `"0"`; both modes asserted in `tests/unit/test_t3_ingest_routing.py`; `NodeType.AUDIO` and `IMAGE` are first-class |
130
+ | 38 | Vision OCR / Caption / Embedding | WORKS | `VisionStub` is gone from product code and from the shipped wheel/sdist, with a test asserting its absence; `resolve_vision_embedder` has no hash fallback |
131
+ | 39 | Image Retrieval | **PARTIAL → code fixed** | late fusion, the separate `image_embeddings` table, width-mismatch skipping and the `multimodal` result block are all real and tested — but no production caller passed `multimodal=` to `context_quality_signal` (see Finding 5) |
132
+ | 40 | Evidence Thumbnails | WORKS | `THUMBNAIL_EDGE = 96`; the 24,000-char cap is enforced on write **and** on read; only `data:image/…` is accepted, server-side and client-side |
133
+ | 41 | Video Ingestion | WORKS | ingest returns `status:"unavailable"`, `indexing_status:"skipped"`, `node_id: None`; nothing is stored |
134
+ | 42 | Frontend Reliability | WORKS | `CoreServiceUnavailableBanner`; `ActionButton` does not fire success callbacks for `ok:false`; vitest 100% on all four metrics |
135
+ | 43 | Trusted Agent Loop | WORKS | `LoopTrace`, the `loop` payload on both the streaming and non-streaming terminals, python-literal repair, the agent-eval CI gate |
136
+ | 44 | Command Center | **MISMATCH → code fixed** | `/api/command/briefing` returned `health: {available:false, grade:null, score:null}` on a Brain reporting `grade: "excellent"` (see Finding 1) |
137
+ | 45 | Evidence → Action | WORKS | `POST /api/evidence/actions` with no resolvable citations → 200 with an explicit reason, never a silent empty list |
138
+ | 46 | Run Explanation | WORKS | `"ok": code == "done"`, reachable only from `state == "DONE"`; rendered on web, VS Code and Telegram |
139
+ | 47 | Project Sessions | WORKS | `GET /api/projects` → 200; `/agent` accepts `project_id`; a `NEEDS_REVIEW` run never becomes a project `done` |
140
+ | 48 | Citation Precision | WORKS | `tests/unit/test_typed_chunking.py`, `tests/unit/test_citation_grounding.py`; `plain` chunking stays byte-identical to the legacy walk |
141
+ | 49 | Graph Relation Evidence | WORKS | `tests/unit/test_relation_evidence.py` |
142
+ | 50 | Funnel Alerts | WORKS | `GET /api/admin/funnel-metrics` → 200 with named counters, `rates: null` and `alerts: []` below the 10-sample floor |
143
+ | 51 | Frontend Payload | **MISMATCH → doc fixed** | `npm run check:bundle` measures **103.0 KiB** gzip initial JS against the 150 KiB budget; the doc had read "~99 KiB" since 9.9.9 (see Finding 2) |
144
+ | 52 | Permission Modes | WORKS | `GET /api/permission-mode` → `strict` default with `proposal_first: true`; circuit breakers mode-invariant; the selector renders the server catalog and blocks `bypass` until acknowledged. One wording nuance: the home dial uses a confirmation dialog rather than a checkbox — consent is still explicit |
145
+ | 53 | Network Boundary | WORKS | `local_only` default; `hard_block_metadata_flags` = `do_not_share/local_only/private/sensitive` applied with no mode branch; `POST /api/network-boundary/preview` answers in `local_only` and reports `would_block` |
146
+ | 54 | Hybrid Cloud Chat | WORKS | all seven named modules exist; the adapter raises before opening a socket without `LATTICEAI_CLOUD_API_KEY`; the local path is a pure early return |
147
+ | 55 | Cloud Memory Write-Back | **MISMATCH → code fixed** | the enqueue was implemented and unit-tested, but both live call sites constructed `CloudResponseIngestor(store=knowledge_graph)` with no review sink (see Finding 6) |
148
+ | 56 | Obsidian Vault Bridge | WORKS | driven end to end in the signed-in pass: `permission_required` + token → `/permissions/approve/{token}` → `status: "dry_run"`, `scanned 2 / notes 2 / tags 1 / links.resolved 1` (see Finding 7 for the anonymous case) |
149
+ | 57 | Selective Brain Network | WORKS (flag off) | `GET /api/knowledge-graph/share` → `enabled:false` with the flag named; all four mutating share routes → 403 with the reason. **The encryption half of this row was being changed by a parallel track while this audit ran — see Caveat** |
150
+ | 58 | Release Assets | WORKS | package/pyproject/tauri/vsix all 11.1.0; `check_current_release_docs`, `check_doc_status`, `validate_release_artifacts`, `check_release_evidence_bound` all clean. Rolling the markers to 11.2.0 is the release lead's step, not this audit's |
151
+
152
+ **Totals as swept: 51 WORKS, 3 PARTIAL, 4 MISMATCH.** Of the four mismatches,
153
+ one was fixed in code during the sweep (Command Center), two were fixed in the
154
+ docs (Brain Home, Frontend Payload) and one was reported to its owning track
155
+ (Cloud Memory Write-Back). All three `PARTIAL` rows were reported rather than
156
+ changed: each needed a code change in a file another track owned this sprint,
157
+ or a behaviour decision that does not belong inside an audit. One Known
158
+ Limitation was retired as no longer true.
159
+
160
+ **Dispositions after the sweep (v11.2.0 integration close).** The four rows the
161
+ audit could not touch itself were closed once the parallel tracks had landed —
162
+ Findings 3, 4, 5 and 6 are all fixed in code, each with a regression test that
163
+ drives the shipped entry point rather than the collaborator (see
164
+ `tests/unit/test_t8_integration_close.py`). The verdict column above keeps the
165
+ *swept* verdict with its disposition appended, because a point-in-time audit
166
+ that silently rewrites itself is worth nothing; `FEATURE_STATUS.md` carries the
167
+ current state.
168
+
169
+ ## Findings
170
+
171
+ ### Finding 1 — the Command Center's health section was reading a key nothing writes (FIXED)
172
+
173
+ `CommandCenterService._health_section` read the Brain's health out of a nested
174
+ `overall` block:
175
+
176
+ ```python
177
+ overall = report.get("overall") or {}
178
+ "available": overall.get("score") is not None,
179
+ ```
180
+
181
+ `BrainIntelligenceService.health_report()` — the only producer — publishes
182
+ `overall_score` and `grade` at the **top level**. So the briefing's health
183
+ section was permanently `{available: false, grade: null, score: null}` while
184
+ `/api/brain/health` reported `grade: "excellent"` on the very same graph, and
185
+ the `check-health` quick action below it could never fire.
186
+
187
+ User-visible: `DailyBriefingPanel` renders
188
+ `{health.available && health.grade ? String(health.grade) : "—"}`, so Today's
189
+ Briefing showed a permanent dash with no reason beside it — the exact failure
190
+ mode the 9.9.7 rule ("a `—` must state why") exists to prevent.
191
+
192
+ Why the suite stayed green: `tests/unit/test_command_center.py`'s `FakeBrain`
193
+ returned `{"overall": {"score": …, "grade": …}}` — a shape no real collaborator
194
+ has ever produced. The test and the code agreed with each other and neither
195
+ agreed with production.
196
+
197
+ Fixed in `latticeai/services/command_center.py` (read the real shape), the fake
198
+ corrected to match its real counterpart, and pinned by
199
+ `tests/unit/test_a3_feature_audit.py`, which wires the two **real** services
200
+ together — the only arrangement that can catch this class of drift.
201
+
202
+ ### Finding 2 — the initial-JS figure had not been re-measured since 9.9.9 (FIXED)
203
+
204
+ FEATURE_STATUS claimed "~99 KiB gzip". `node scripts/check_bundle_budget.mjs`
205
+ measures **103.0 KiB** (index 66.1 + utils 29.2 + useQuery 7.6), against a build
206
+ `scripts/check_frontend_build_freshness.mjs` confirms is byte-identical to
207
+ source. The budget gate itself passes with room to spare — only the sentence was
208
+ stale. Lowered to the measured figure with the tool that measures it named.
209
+ The same stale number also appears in `ARCHITECTURE.md`.
210
+
211
+ ### Finding 3 — an empty Brain grades itself 100 / "excellent" (FIXED after the sweep)
212
+
213
+ `health_report()` averages only the dimensions it could measure. On a
214
+ first-run Brain, freshness, connectivity and consistency all report
215
+ `status: "unavailable", score: null` and embedding coverage reports 100 (zero
216
+ of zero indexed) — so the composite is `overall_score: 100, grade: "excellent"`
217
+ from a single dimension over an empty graph.
218
+
219
+ Each dimension is individually honest; the composite is not. This is a
220
+ behaviour question rather than a documentation one (the row does not promise a
221
+ specific empty-Brain grade), and changing the score would move a number the
222
+ frontend and its tests render — so it is named here rather than changed inside
223
+ an audit.
224
+
225
+ **Disposition.** The lie was upstream of the composite: an index holding
226
+ nothing reports `coverage_ratio: 1.0`, which is 100% of nothing. That dimension
227
+ now reads `unavailable` with the reason `"no indexable items yet"` whenever
228
+ `source_items` is zero, so the empty Brain has *no* measurable dimension and
229
+ the existing `scores or None` path already returns `overall_score: None,
230
+ grade: null` — which the frontend already renders as 데이터 없음 / "No data
231
+ yet". Two additions keep the partial cases honest too: every unavailable
232
+ dimension now carries a `reason` (the graph could not be read vs. nothing saved
233
+ yet vs. no relationships yet), and the report gains a `coverage` block
234
+ (`measured` / `total` / `unavailable` / `partial`) so a verdict drawn from two
235
+ of four checks says so. When nothing could be measured a top-level `reason`
236
+ names each gap — the 9.9.7 rule that a "—" must state why.
237
+
238
+ ### Finding 4 — `vector_freshness_breakdown()` has no surface (FIXED after the sweep)
239
+
240
+ The Vector Freshness row explains that "12 pending" hides the difference
241
+ between twelve never-embedded imports and twelve edits whose current answers
242
+ are quietly wrong, and names `vector_freshness_breakdown()` as the answer. The
243
+ method exists on the store and is tested — and has **zero product callers**.
244
+ `GET /api/brain/vector-freshness` still returns the aggregate
245
+ (`{status, pending_items, total_items, detail}`), so the distinction the
246
+ sentence sells is not visible anywhere in the product.
247
+
248
+ Either the endpoint should carry the breakdown or the row should say the split
249
+ is store-level only. The fix lives in store/API files owned by another track
250
+ this sprint, so it is reported rather than edited.
251
+
252
+ **Disposition.** The endpoint carries it. `BrainIntelligenceService.vector_freshness`
253
+ now returns the four-key contract from an unchanged private method and attaches
254
+ `breakdown` beside it when the store can compute one. The key is **omitted**
255
+ rather than zero-filled for every reason it cannot be had — graph off, an older
256
+ store without the method, an unreadable index, an empty answer — because a
257
+ zeroed backlog nobody measured is exactly the dishonesty the split exists to
258
+ remove. The frontend chip reads `pending_items` and is untouched.
259
+
260
+ ### Finding 5 — `context_quality` never gains its `multimodal` key in production (FIXED after the sweep)
261
+
262
+ The Image Retrieval row says `context_quality` "gains a `multimodal` key only
263
+ when image nodes are really in the context". The mechanism is real and tested,
264
+ but the only call site that passes `multimodal=` to `context_quality_signal` is
265
+ `context_for_query(with_meta=True)`, which has no production caller. Both live
266
+ producers of `context_quality` — `api/chat_helpers.build_context_quality` and
267
+ `core/context_builder` — discard the hybrid result's `multimodal` block. Net
268
+ effect: on every shipped surface `context_quality` keeps the four-key shape
269
+ even when the answer cites `Image` nodes. Owned by the multi-modal track.
270
+
271
+ **Disposition.** Both producers pass it now. `build_context_quality` calls
272
+ `multimodal_signal(matches)` on **both** of its arms — the hybrid store and the
273
+ lexical-only fallback, since a picture found by keyword is still a picture —
274
+ and `retrieve_context_for_generation` does the same for the document path. The
275
+ present-only-when-true contract is unchanged: `multimodal_signal` returns
276
+ `None` for an all-text result set and `context_quality_signal` omits the key,
277
+ so an all-text answer is byte-identical to what 11.1.0 returned.
278
+
279
+ ### Finding 6 — cloud write-back is never enqueued on the live path (FIXED after the sweep)
280
+
281
+ `CloudResponseIngestor.ingest` stages a `change_proposal` **only when a
282
+ `review_queue` sink is bound**. Both production call sites bind none:
283
+
284
+ ```
285
+ latticeai/services/hybrid_chat.py: ingestor = CloudResponseIngestor(store=knowledge_graph)
286
+ latticeai/services/hybrid_chat.py: ingest_status = CloudResponseIngestor(store=knowledge_graph).ingest(plan)
287
+ ```
288
+
289
+ With `plan.auto_commit` hardcoded `False`, `ingest()` returns
290
+ `{"status": "staged", "review_item_id": None, "written_nodes": 0}` — knowledge
291
+ extracted from a cloud answer is neither written nor queued. It is discarded
292
+ after the `hybrid_done` frame. The unit tests pass a `review_queue` directly to
293
+ the ingestor, so the wiring gap is invisible to CI. Related: the hybrid policy's
294
+ `auto_commit` flag is settable through `POST /api/network-boundary/policy` but
295
+ has no consumer.
296
+
297
+ The row's "is enqueued as a Review Center `change_proposal`" is therefore not
298
+ true as shipped. Threading a review sink through
299
+ `stream_hybrid_cloud_turn` / `run_hybrid_cloud_turn` / `maybe_hybrid_stream_response`
300
+ touches the chat router and the review-queue seam, both of which other tracks
301
+ were editing during this sweep — reported, not changed.
302
+
303
+ **Disposition.** Threaded, exactly there. Both turn functions take
304
+ `review_queue` and `auto_commit` as arguments (defaults `None` / `False`, so a
305
+ headless caller still stages nothing), `maybe_hybrid_stream_response` forwards
306
+ the sink and resolves the flag through the new
307
+ `chat_hybrid.resolve_hybrid_auto_commit`, and `/chat` supplies the live queue
308
+ through a new `AppContext.review_queue` **provider** — a callable rather than a
309
+ value, because `REVIEW_QUEUE` is produced in `phase_platform_features`, two
310
+ phases after the context is built, and a captured value would have been `None`
311
+ forever. `resolve_hybrid_auto_commit` treats an unreadable policy as the
312
+ default rather than as permission.
313
+
314
+ The reason CI could not see this — the unit tests handed the ingestor its
315
+ collaborator directly — is also the reason the new test drives `POST /chat`
316
+ with the dial on `cloud_allowed` and a fake adapter, and asserts the item
317
+ landed in the queue with `source: "change_proposal"`.
318
+
319
+ ### Finding 7 — the local-file 401 is a gate, not a defect (CLEARED)
320
+
321
+ Worth recording because it looks like a defect and is not. In the default local
322
+ profile (`require_auth = false`), `POST /api/ingestion/obsidian` and every other
323
+ local-file route answer **401** to an anonymous caller:
324
+ `PermissionGateway.require_local_user` resolves the raw session identity and
325
+ does **not** fall through to the anonymous local owner that `require_user`
326
+ returns. Reading only that line suggests the vault bridge is unreachable out of
327
+ the box.
328
+
329
+ It is not. Driven end to end in the signed-in pass — register (first user
330
+ becomes admin) → login → `POST /api/ingestion/obsidian` →
331
+ `permission_required: true` with an `approval_token` →
332
+ `POST /permissions/approve/{token}` → re-post with the token →
333
+ `status: "dry_run", scanned: 2, notes: 2, tags: 1, links.resolved: 1`. That
334
+ sequence *is* the "standard local-read approval dance" the row describes.
335
+ Filesystem access deliberately demands a named account even where the rest of
336
+ the local API accepts the anonymous owner. Verdict: WORKS.
337
+
338
+ ### Finding 8 — a retired Known Limitation
339
+
340
+ "The approval card under 작업 → 실행 still labels raw payload fields (`Action`,
341
+ `Action Label`, `User Email`) in plain mode" is no longer true. `Act.tsx`'s
342
+ `HumanPermissionDetails` renders a translated action badge, the target
343
+ filename, a free-text reason and a labelled requester line, with a regression
344
+ test forbidding raw i18n keys from reaching the DOM; the repo carries no
345
+ rendered `Action Label` / `User Email` literal. The screenshot the bullet cited
346
+ as proof — `output/release/v10.6.3/screenshots/09-automation-runs.png` — no
347
+ longer exists (release evidence now starts at v11.0.0). The bullet was removed;
348
+ carrying a fixed defect as a standing limitation is its own kind of dishonesty.
349
+
350
+ ## prefix-static hermeticity (wp19 / wp36) — re-confirmed
351
+
352
+ `Config.from_env` resolves a *missing* static dir to `sys.prefix/static` when
353
+ that exists, which on a pip-installed machine it genuinely does. `_empty_prefix`
354
+ in `tests/unit/test_cov_wp19_build_phases.py` and
355
+ `tests/unit/test_cov_wp36_build_phases_late.py` neutralizes that so the
356
+ assertions describe the resolver rather than the runner.
357
+
358
+ Re-verified by simulating the release-runner condition for a whole session: a
359
+ pytest plugin pointed `sys.prefix` at a temp directory that **does** carry
360
+ `static/` (with a sentinel file), and the two suites plus
361
+ `test_cov_wp19_cli_entrypoint.py` were run under it.
362
+
363
+ * **81 passed.**
364
+ * The simulated prefix's `static/` still contained only the sentinel afterwards
365
+ — no test wrote into it.
366
+ * The hazard itself was confirmed live under the same plugin: with a missing
367
+ configured static dir, `Config.from_env` resolves to the fake prefix's
368
+ `static/`. The hermeticity is load-bearing, not decorative.
369
+
370
+ ## Caveat — a concurrently mutating tree
371
+
372
+ This sweep ran while two other tracks were writing to the same working tree.
373
+ Files under `lattice_brain/` (portability, sealed box, multimodal, ingestion,
374
+ graph schema) and `latticeai/services/model_*` were changing during the run, and
375
+ one intermediate state was observed directly (a partially-rewired
376
+ `latticeai/services/obsidian_bridge.py` raising `NameError` mid-refactor, and a
377
+ `KnowledgeGraphStore` attribute warning at boot). Rows 37–41, 55 and 57 are
378
+ therefore reported **as of this snapshot**; their owning tracks are the
379
+ authority on where they land. Everything measured for rows outside those files
380
+ was stable across repeated runs.
381
+
382
+ ## Changes this audit made
383
+
384
+ * `latticeai/services/command_center.py` — read the health shape the Brain
385
+ actually publishes (Finding 1).
386
+ * `tests/unit/test_command_center.py` — corrected the `FakeBrain` fixture to
387
+ its real counterpart's shape.
388
+ * `tests/unit/test_a3_feature_audit.py` — new. Pins the two drift classes this
389
+ audit found: a doc naming an endpoint the app does not serve, and the
390
+ briefing reading a health score the Brain never published.
391
+ * `FEATURE_STATUS.md` — Brain Home (Brain Brief is on the dock, not the first
392
+ screen), Frontend Payload (103 KiB, measured), and the retired approval-card
393
+ limitation.
@@ -5,6 +5,13 @@
5
5
  이 문서의 모든 파일 경로와 줄 번호는 실제로 열어서 확인한 것이다.
6
6
  추측한 경로는 한 줄도 없다.
7
7
 
8
+ > **증거 기준선 안내 (v11.2.0 기준).** 이 설계서가 인용하는
9
+ > `output/release/v10.6.3/screenshots/` 는 **더 이상 리포에 없다** — 릴리스 증거는
10
+ > v11.0.0 부터만 보관한다(`output/release/v11.0.0` · `v11.0.1` · `v11.1.0`).
11
+ > 따라서 아래의 "이전 캡처와 해시 대조" 절차는 그대로는 재현할 수 없다.
12
+ > 문서는 당시 측정값을 기록한 사료로 남기고, 지금 다시 채점한다면 기준선은
13
+ > **가장 최근 릴리스의 `output/release/<버전>/screenshots/`** 로 바꿔서 읽는다.
14
+
8
15
  ---
9
16
 
10
17
  ## 0. 이 재구성이 존재하는 이유
@@ -706,7 +713,8 @@ npm run frontend:openapi:check # OpenAPI drift 게이트
706
713
 
707
714
  ### 7.1 릴리스 캡처 12개 화면 전부 변경 — **24점** (화면당 2점)
708
715
 
709
- **확인 명령:**
716
+ **확인 명령:** (기준선 경로는 문서 상단 안내대로 최신 릴리스 디렉터리로 바꿔 읽는다 —
717
+ `output/release/v10.6.3/` 는 리포에서 사라졌다.)
710
718
  ```
711
719
  npm run build:assets
712
720
  LTCAI_RELEASE_EVIDENCE_DIR=/tmp/lattice-after npm run release:evidence
@@ -2,7 +2,7 @@
2
2
 
3
3
  The Multi-Agent Runtime is the **orchestration layer** introduced in v2.0.0 and
4
4
  operationalized in v2.2.0. It sits
5
- *above* the v1.x single-agent state machine ([`SingleAgentRuntime`](../latticeai/core/agent.py))
5
+ *above* the v1.x single-agent state machine ([`SingleAgentRuntime`](../latticeai/core/agent/runtime.py))
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
 
@@ -1,6 +1,6 @@
1
1
  # Lattice AI Onboarding
2
2
 
3
- Current release: **11.1.0 — Product Intelligence**.
3
+ Current release: **11.4.0 — Rust Foundation**.
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.1.0)
1
+ # Lattice AI — Operations Guide (v11.4.0)
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
@@ -176,7 +176,11 @@ Ctrl+C 또는 kill <pid>
176
176
  캡처 → 오래된 버전 정리 → **픽셀 델타 검사**까지 한 번에 돈다.
177
177
  4. 결속 검사 — `SCREENSHOT_INDEX.md` 의 `asset-manifest.sha256` 과
178
178
  `mock-server.sha256` 이 각각 `static/app/asset-manifest.json`,
179
- `tests/visual/mock_server.cjs` 와 일치해야 `npm run lint` 가 통과한다.
179
+ 그리고 목 API 표면 전체(`tests/visual/mock_server.cjs` +
180
+ `tests/visual/mock_server/*.cjs`) 와 일치해야 `npm run lint` 가 통과한다.
181
+ v11.3.0 부터 지문이 진입 파일 하나가 아니라 라우트 모듈까지 덮으므로,
182
+ v11.3.0 이전에 찍은 증거는 재캡처 전까지 불일치로 보고된다
183
+ (지문 계산은 `scripts/lib/mock_server_fingerprint.mjs` 한 곳에만 있다).
180
184
 
181
185
  레이아웃을 바꿨다고 보고했는데 배치는 그대로인 경우를 잡기 위해 v10.7.0 부터
182
186
  `scripts/check_screenshot_pixel_delta.py` 가 12개 캡처를 직전 버전과 대조한다
@@ -101,7 +101,7 @@ before routers are mounted would otherwise pin the store to the fallback
101
101
  |--------|------|
102
102
  | `latticeai/core/permission_mode.py` | Pure decision table |
103
103
  | `latticeai/core/agent_permission.py` | Agent plan/tool gate helpers |
104
- | `latticeai/core/agent.py` | `SingleAgentRuntime` gates (mode-aware in-line) |
104
+ | `latticeai/core/agent/` | `SingleAgentRuntime` gates (mode-aware in-line: `planning.py` for the plan gate, `execution.py` for the per-tool gates) |
105
105
  | `frontend/src/components/PermissionModePanel.tsx` | Settings selector |
106
106
  | `latticeai/services/permission_mode_service.py` | Persistence |
107
107
  | `latticeai/runtime/permission_mode_wiring.py` | Process-wide service + router mount |
@@ -1,6 +1,6 @@
1
1
  # Lattice AI Trust Model
2
2
 
3
- Current release: **11.1.0 — Product Intelligence**.
3
+ Current release: **11.4.0 — Rust Foundation**.
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.1.0 — Product Intelligence**.
3
+ Current release: **11.4.0 — Rust Foundation**.
4
4
 
5
5
  **Lattice AI is a local-first Digital Brain that keeps your knowledge durable
6
6
  across any AI model.**
@@ -130,8 +130,12 @@ hardware scan
130
130
  -> download/install/load/verify
131
131
  ```
132
132
 
133
- The current default recommendation family is Gemma 4. Qwen3-VL and Llama 4
134
- remain current multimodal alternatives.
133
+ The current default recommendation family is Gemma 4. Qwen3.6 and Qwen3.5 are
134
+ the current multimodal alternatives; GPT-OSS 20B and LFM2.5 2.6B fill the
135
+ general-purpose and ultralight tiers as text-only models. Superseded families
136
+ (Qwen3-VL, Llama 4, Qwen2.5-VL, Llama 3.2 Vision) stay in the capability
137
+ registry as *recognised* entries so already-downloaded weights keep working,
138
+ but they never appear in the catalog or a download path. See MODEL_POLICY.md.
135
139
 
136
140
  ## Modes
137
141
 
package/docs/kg-schema.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Knowledge Graph Schema
2
2
 
3
- Current release: **11.1.0 — Product Intelligence**.
3
+ Current release: **11.4.0 — Rust Foundation**.
4
4
 
5
5
  명세 출처: `lattice_ai_full_spec.pptx` 슬라이드 20·21·22
6
6
  구현: `lattice_brain/graph/schema.py`
@@ -142,7 +142,7 @@ provenance(source_type, source_uri, content_hash, captured_at, modified_at,
142
142
  범위 없는 로컬 폴더는 개인 Brain으로 재투영하되 기존 노드 ID는 보존하며,
143
143
  같은 폴더를 다른 워크스페이스로 조용히 재할당하지 않는다.
144
144
 
145
- 구현: `lattice_brain/ingestion.py` (`IngestionPipeline`) 가 단일 진입점이며,
145
+ 구현: `lattice_brain/ingestion/` (`IngestionPipeline`) 가 단일 진입점이며,
146
146
  파일/로컬폴더/URL/브라우저 탭/텍스트를 모두 이 형태로 정규화한다.
147
147
 
148
148
  ---