ltcai 10.3.0 → 10.5.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 (153) hide show
  1. package/README.md +47 -36
  2. package/docs/CHANGELOG.md +144 -0
  3. package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
  4. package/docs/DEVELOPMENT.md +1 -1
  5. package/docs/MYPY_BACKLOG.md +59 -92
  6. package/docs/ONBOARDING.md +1 -1
  7. package/docs/OPERATIONS.md +1 -1
  8. package/docs/PERMISSION_MODE.md +15 -4
  9. package/docs/SURFACE_PARITY.md +33 -6
  10. package/docs/TRUST_MODEL.md +1 -1
  11. package/docs/WHY_LATTICE.md +1 -1
  12. package/docs/kg-schema.md +1 -1
  13. package/lattice_brain/__init__.py +1 -1
  14. package/lattice_brain/context.py +23 -3
  15. package/lattice_brain/graph/_kg_common.py +164 -9
  16. package/lattice_brain/graph/_kg_contract.py +223 -0
  17. package/lattice_brain/graph/_kg_fsutil.py +1 -1
  18. package/lattice_brain/graph/curator.py +4 -4
  19. package/lattice_brain/graph/discovery.py +12 -1
  20. package/lattice_brain/graph/discovery_index.py +12 -1
  21. package/lattice_brain/graph/documents.py +17 -2
  22. package/lattice_brain/graph/ingest.py +12 -1
  23. package/lattice_brain/graph/proactive.py +9 -5
  24. package/lattice_brain/graph/projection.py +12 -1
  25. package/lattice_brain/graph/provenance.py +12 -1
  26. package/lattice_brain/graph/retrieval.py +12 -1
  27. package/lattice_brain/graph/retrieval_docgen.py +12 -1
  28. package/lattice_brain/graph/retrieval_reads.py +12 -1
  29. package/lattice_brain/graph/retrieval_vector.py +12 -1
  30. package/lattice_brain/graph/schema.py +6 -2
  31. package/lattice_brain/graph/write_master.py +12 -1
  32. package/lattice_brain/ingestion.py +1 -1
  33. package/lattice_brain/quality.py +5 -5
  34. package/lattice_brain/runtime/contracts.py +2 -1
  35. package/lattice_brain/runtime/multi_agent.py +1 -1
  36. package/lattice_brain/workflow.py +10 -7
  37. package/latticeai/__init__.py +1 -1
  38. package/latticeai/api/admin.py +2 -2
  39. package/latticeai/api/chat.py +19 -15
  40. package/latticeai/api/chat_agent_http.py +19 -7
  41. package/latticeai/api/chat_helpers.py +9 -8
  42. package/latticeai/api/chat_stream.py +2 -2
  43. package/latticeai/api/computer_use.py +2 -2
  44. package/latticeai/api/hooks.py +4 -2
  45. package/latticeai/api/local_files.py +8 -4
  46. package/latticeai/api/mcp.py +2 -2
  47. package/latticeai/api/models.py +5 -5
  48. package/latticeai/api/permissions.py +2 -2
  49. package/latticeai/api/search.py +5 -3
  50. package/latticeai/api/security_dashboard.py +3 -5
  51. package/latticeai/api/setup.py +3 -3
  52. package/latticeai/api/static_routes.py +7 -2
  53. package/latticeai/api/tools.py +9 -4
  54. package/latticeai/api/workspace.py +25 -22
  55. package/latticeai/app_factory.py +132 -1322
  56. package/latticeai/cli/entrypoint.py +1 -1
  57. package/latticeai/core/agent.py +28 -14
  58. package/latticeai/core/audit.py +5 -3
  59. package/latticeai/core/embedding_providers.py +19 -6
  60. package/latticeai/core/legacy_compatibility.py +1 -1
  61. package/latticeai/core/marketplace.py +2 -2
  62. package/latticeai/core/mcp_catalog.py +3 -1
  63. package/latticeai/core/model_compat.py +1 -1
  64. package/latticeai/core/plugins.py +1 -1
  65. package/latticeai/core/project_sessions.py +1 -1
  66. package/latticeai/core/run_explain.py +6 -4
  67. package/latticeai/core/workspace_os.py +0 -4
  68. package/latticeai/core/workspace_os_constants.py +1 -1
  69. package/latticeai/core/workspace_os_state.py +1 -1
  70. package/latticeai/core/workspace_snapshots.py +3 -3
  71. package/latticeai/integrations/telegram_bot.py +52 -3
  72. package/latticeai/models/router.py +61 -34
  73. package/latticeai/runtime/access_runtime.py +3 -1
  74. package/latticeai/runtime/build_phases.py +1417 -0
  75. package/latticeai/runtime/review_wiring.py +6 -1
  76. package/latticeai/runtime/runtime_context.py +276 -0
  77. package/latticeai/runtime/sso_config_runtime.py +1 -1
  78. package/latticeai/runtime/stages.py +8 -2
  79. package/latticeai/services/app_context.py +23 -0
  80. package/latticeai/services/architecture_readiness.py +1 -1
  81. package/latticeai/services/brain_intelligence.py +4 -2
  82. package/latticeai/services/cloud_streaming.py +5 -3
  83. package/latticeai/services/command_center.py +1 -1
  84. package/latticeai/services/evidence_actions.py +2 -1
  85. package/latticeai/services/hybrid_chat.py +1 -1
  86. package/latticeai/services/local_knowledge.py +25 -9
  87. package/latticeai/services/memory_service.py +8 -4
  88. package/latticeai/services/model_catalog.py +12 -12
  89. package/latticeai/services/model_engines.py +15 -17
  90. package/latticeai/services/model_loading.py +1 -1
  91. package/latticeai/services/model_runtime.py +31 -33
  92. package/latticeai/services/multimodal_streaming.py +10 -4
  93. package/latticeai/services/openai_compatible_adapter.py +4 -3
  94. package/latticeai/services/product_readiness.py +1 -1
  95. package/latticeai/services/run_executor.py +12 -3
  96. package/latticeai/services/search_service.py +1 -1
  97. package/latticeai/services/triggers.py +1 -1
  98. package/latticeai/setup/auto_setup.py +1 -1
  99. package/latticeai/setup/wizard.py +12 -3
  100. package/latticeai/tools/computer.py +3 -1
  101. package/latticeai/tools/documents.py +2 -2
  102. package/package.json +1 -1
  103. package/scripts/capture_release_evidence.mjs +32 -8
  104. package/scripts/check_current_release_docs.mjs +1 -1
  105. package/src-tauri/Cargo.lock +1 -1
  106. package/src-tauri/Cargo.toml +1 -1
  107. package/src-tauri/tauri.conf.json +1 -1
  108. package/static/app/asset-manifest.json +38 -38
  109. package/static/app/assets/{Act-DrKIGZeJ.js → Act-CLsUUE4V.js} +1 -1
  110. package/static/app/assets/{AdminConsole-CEV1VefA.js → AdminConsole-D1PBR5Mk.js} +1 -1
  111. package/static/app/assets/{Brain-BZSXnwWU.js → Brain-Cnb_YCYH.js} +2 -2
  112. package/static/app/assets/BrainHome-DMMhKb8j.js +2 -0
  113. package/static/app/assets/{BrainSignals-O4s6R7av.js → BrainSignals-CcvYpBGn.js} +1 -1
  114. package/static/app/assets/Capture-DU1HZWqB.js +1 -0
  115. package/static/app/assets/{CommandPalette-CeqBjCn2.js → CommandPalette-tU229JbI.js} +1 -1
  116. package/static/app/assets/Library-BeutJd8j.js +1 -0
  117. package/static/app/assets/{LivingBrain-D9Iei2ZJ.js → LivingBrain-BVFU-llN.js} +1 -1
  118. package/static/app/assets/{ProductFlow-JlXiDfMM.js → ProductFlow-CZp8oHh_.js} +1 -1
  119. package/static/app/assets/{ReviewCard-QQly2bTV.js → ReviewCard-DODh3z_D.js} +1 -1
  120. package/static/app/assets/System-CTYfZXfv.js +1 -0
  121. package/static/app/assets/{activity-CxRPOQ2F.js → activity-DYlZpTrt.js} +1 -1
  122. package/static/app/assets/{bot-1bcsWB2s.js → bot-BBmfPYKv.js} +1 -1
  123. package/static/app/assets/brain-RRpEg40e.js +1 -0
  124. package/static/app/assets/{button-ZYFqGan7.js → button-DXSLgXUl.js} +1 -1
  125. package/static/app/assets/{circle-pause-B5NOIqvk.js → circle-pause-B8TPRvnt.js} +1 -1
  126. package/static/app/assets/{circle-play-BiJVFXf7.js → circle-play-C5aQnYUv.js} +1 -1
  127. package/static/app/assets/{cpu-Vvq0OKTr.js → cpu-BvOUS0hg.js} +1 -1
  128. package/static/app/assets/{download-SEcXzkx1.js → download-BM2Y4baa.js} +1 -1
  129. package/static/app/assets/{folder-open-Dw1ff_Qa.js → folder-open-DATq5giq.js} +1 -1
  130. package/static/app/assets/{hard-drive-B00fR7_r.js → hard-drive-D2iumtyP.js} +1 -1
  131. package/static/app/assets/{index-CEkL4_M-.css → index-B1n87vO-.css} +1 -1
  132. package/static/app/assets/{index-Dm9VXl1o.js → index-D10Yd0gh.js} +3 -3
  133. package/static/app/assets/{input-DtdWYQEa.js → input-Ptpha52f.js} +1 -1
  134. package/static/app/assets/permissionCopy-DLSOKW1h.js +1 -0
  135. package/static/app/assets/{primitives-CwsudBwc.js → primitives-BvxTiz4R.js} +1 -1
  136. package/static/app/assets/search-DtMikKf0.js +1 -0
  137. package/static/app/assets/{shield-alert-CpjBc-gQ.js → shield-alert-B6RHxSXi.js} +1 -1
  138. package/static/app/assets/{textarea-DUPyjHQs.js → textarea-CCZqVitr.js} +1 -1
  139. package/static/app/assets/{useFocusTrap-BWcMtCWH.js → useFocusTrap-QR9BiUDX.js} +1 -1
  140. package/static/app/assets/{useQuery-Dg5fPqTS.js → useQuery-B42HOaUm.js} +1 -1
  141. package/static/app/assets/{users-BgcdTQGM.js → users-D9PLGmAE.js} +1 -1
  142. package/static/app/assets/{utils-a3YXFtEO.js → utils-CAuwfT8i.js} +1 -1
  143. package/static/app/assets/workspace-DT2v1d3T.js +1 -0
  144. package/static/app/index.html +4 -4
  145. package/static/sw.js +1 -1
  146. package/static/app/assets/BrainHome-CEBd86k6.js +0 -2
  147. package/static/app/assets/Capture-AGbOxsg-.js +0 -1
  148. package/static/app/assets/Library-CXnbNiQW.js +0 -1
  149. package/static/app/assets/System-Bp9ZY4ER.js +0 -1
  150. package/static/app/assets/brain-CxaeKCRM.js +0 -1
  151. package/static/app/assets/network-CpjBu0kI.js +0 -1
  152. package/static/app/assets/search-CwEJWBEA.js +0 -1
  153. package/static/app/assets/workspace-BMUEiXUm.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
- ![v10.3.0 Living Brain walkthrough](output/release/v10.3.0/gifs/v10.3.0-living-brain-walkthrough.gif)
14
+ ![v10.5.0 Living Brain walkthrough](output/release/v10.5.0/gifs/v10.5.0-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,9 +24,10 @@ memory. Nothing leaves your machine without explicit consent.
24
24
 
25
25
  | | |
26
26
  | --- | --- |
27
- | **Chat with a Brain that remembers** — every conversation grows durable, source-linked memory ![Brain Chat](output/release/v10.3.0/screenshots/04-brain-chat-home.png) | **See how knowledge connects** — a real relationship graph, not a file list ![Memory Graph](output/release/v10.3.0/screenshots/05-memory-graph.png) |
28
- | **Capture anything** — files, whole folders, notes, screenshots, web pages ![Capture](output/release/v10.3.0/screenshots/06-capture.png) | **Automate with review** — agent changes become proposals you approve first ![Review Center](output/release/v10.3.0/screenshots/12-review-center.png) |
29
- | **Pick a model in one click** — recommended local models for your hardware ![Recommended Models](output/release/v10.3.0/screenshots/02-recommended-models.png) | **Stay in control** — audit, roles, retention in a separate admin surface ![Admin Console](output/release/v10.3.0/screenshots/10-admin-console.png) |
27
+ | **Chat with a Brain that remembers** — every conversation grows durable, source-linked memory ![Brain Chat](output/release/v10.5.0/screenshots/04-brain-chat-home.png) | **See how knowledge connects** — a real relationship graph, not a file list ![Memory Graph](output/release/v10.5.0/screenshots/05-memory-graph.png) |
28
+ | **Capture anything** — files, whole folders, notes, screenshots, web pages ![Capture](output/release/v10.5.0/screenshots/06-capture.png) | **Automate with review** — agent changes become proposals you approve first ![Review Center](output/release/v10.5.0/screenshots/12-review-center.png) |
29
+ | **Pick a model in one click** — recommended local models for your hardware ![Recommended Models](output/release/v10.5.0/screenshots/02-recommended-models.png) | **Stay in control** — audit, roles, retention in a separate admin surface ![Admin Console](output/release/v10.5.0/screenshots/10-admin-console.png) |
30
+ | **Watch a file become memory** — three named steps, not a pipeline diagram ![Material to memory](output/release/v10.5.0/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/v10.5.0/screenshots/08-system.png) |
30
31
 
31
32
  ## Why Lattice AI
32
33
 
@@ -57,47 +58,55 @@ First-run flow — wake the Brain, pick the owner, load a recommended model:
57
58
 
58
59
  | | | |
59
60
  | --- | --- | --- |
60
- | ![Login](output/release/v10.3.0/screenshots/01-login.png) | ![Model install](output/release/v10.3.0/screenshots/03-install-load-progress.png) | ![Model library](output/release/v10.3.0/screenshots/07-model-library.png) |
61
+ | ![Login](output/release/v10.5.0/screenshots/01-login.png) | ![Model install](output/release/v10.5.0/screenshots/03-install-load-progress.png) | ![Model library](output/release/v10.5.0/screenshots/07-model-library.png) |
61
62
 
62
63
  Screenshot index and capture notes:
63
- [output/release/v10.3.0/SCREENSHOT_INDEX.md](output/release/v10.3.0/SCREENSHOT_INDEX.md)
64
+ [output/release/v10.5.0/SCREENSHOT_INDEX.md](output/release/v10.5.0/SCREENSHOT_INDEX.md)
64
65
 
65
66
  ## Current Release
66
67
 
67
- The current release is **10.3.0 — Measured Ground**:
68
-
69
- 10.2.0 answered a code review. 10.3.0 is about knowing where things actually
70
- stand: several numbers this project reported about itself turned out to be
71
- wrong, and those corrections matter more than the features around them.
72
-
73
- - **Frontend coverage was never really measured.** Vitest only reports files a
74
- test already imports, so every untested module quietly left the denominator
75
- and the tool read 54%. With `all: true` the honest figure is **28.5%** — and
76
- 208 tests now cover pages that had none, including every settings and memory
77
- screen.
78
- - **Python coverage was reported as 80%. It is 71.6%.** The `omit` pattern did
79
- not match the paths coverage records, so the suite was counting itself — and
80
- test files run start to finish by construction.
81
- - **mypy went from 13 modules to 193 of 270**, finding three real defects on
82
- the way: a log line inside an error handler referenced an attribute that does
83
- not exist (turning a recoverable failure into a crash), an annotation used a
84
- name that was never imported, and one call could dereference `None`.
85
- - **The chat-turn writer left the composition root.** 66 lines that decide what
86
- a message looks like after redaction, and what the audit log records about
87
- it, are now a module with 14 tests instead of a closure nothing could reach.
88
- - **What is not measured is written down.** `docs/MYPY_BACKLOG.md` lists the 77
89
- modules still outside type checking with their error counts, so the boundary
90
- is a fact rather than an intention.
68
+ The current release is **10.5.0 — Everyday Words**:
69
+
70
+ 10.4.0 named the ground the code stands on. 10.5.0 renames the ground the
71
+ *reader* stands on: every screen a first-time user lands on now says what
72
+ Lattice is doing in the words that user would use. No feature was removed —
73
+ the engine's own vocabulary moved behind the advanced mode switch, where it
74
+ belongs to the people who asked for it.
75
+
76
+ - **The autonomy dial is a sentence, not a mode name.** 엄격 / 신뢰 / 바이패스
77
+ became 먼저 물어보기 / 웬만하면 알아서 / 거의 다 알아서, each with one line
78
+ about what it will and will not do on its own. The home dial and Settings
79
+ now draw that copy from one module, so the same setting is never named two
80
+ ways — and a mode the server adds later still renders, from the server's own
81
+ label.
82
+ - **The path from a file to a memory is three named steps.** 진행 상황 was
83
+ hidden from plain mode and held two raw API payloads. It now shows
84
+ 내용 읽기 → 뜻 파악하기 → 기억에 연결하기 as a labelled ordered list, with
85
+ each step saying what it does to your file. 파싱 · 임베딩 · 인덱싱 are gone
86
+ from that screen.
87
+ - **Automations are named the way you named them.** A run shows its workflow's
88
+ name rather than a database id, and its state is spoken — `awaiting_approval`
89
+ reads as "내 승인 기다리는 중". Unknown states say so instead of printing the
90
+ token. Advanced mode still shows the id.
91
+ - **A model your machine cannot run says so in one sentence** instead of a
92
+ registry line half-translated word by word.
93
+ - **The published screenshots were wrong before this release.** Capture ran in
94
+ `advanced`, so every README frame showed payload panels, storage engines and
95
+ hook logs that no first-run user is ever shown. Captures now run in the app's
96
+ real default, `basic` — this page's images are what you will actually see.
97
+ - **Guarded, not asserted.** A visual sweep walks ten plain-mode routes and
98
+ fails if any of them renders empty or puts engine vocabulary in front of a
99
+ reader who never asked for it.
91
100
 
92
101
  Release notes: [RELEASE.md](RELEASE.md) · Full history: [docs/CHANGELOG.md](docs/CHANGELOG.md)
93
102
 
94
- Expected artifacts for 10.3.0 release must use exact filenames:
103
+ Expected artifacts for 10.5.0 release must use exact filenames:
95
104
 
96
- - `dist/ltcai-10.3.0-py3-none-any.whl`
97
- - `dist/ltcai-10.3.0.tar.gz`
98
- - `ltcai-10.3.0.tgz`
99
- - `dist/ltcai-10.3.0.vsix`
100
- - `src-tauri/target/release/bundle/dmg/Lattice AI_10.3.0_aarch64.dmg`
105
+ - `dist/ltcai-10.5.0-py3-none-any.whl`
106
+ - `dist/ltcai-10.5.0.tar.gz`
107
+ - `ltcai-10.5.0.tgz`
108
+ - `dist/ltcai-10.5.0.vsix`
109
+ - `src-tauri/target/release/bundle/dmg/Lattice AI_10.5.0_aarch64.dmg`
101
110
 
102
111
  Do not use wildcard artifact uploads. Package registry publishing remains owner-run.
103
112
 
@@ -132,6 +141,8 @@ See [ARCHITECTURE.md](ARCHITECTURE.md) for details and
132
141
 
133
142
  | Version | Theme |
134
143
  | --- | --- |
144
+ | 10.5.0 | Everyday Words |
145
+ | 10.4.0 | Named Ground |
135
146
  | 10.3.0 | Measured Ground |
136
147
  | 10.2.0 | Load-Bearing Fixes |
137
148
  | 10.1.1 | Reachable Boundary |
package/docs/CHANGELOG.md CHANGED
@@ -4,6 +4,150 @@ 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
+ ## [10.5.0] - 2026-08-03
8
+
9
+ A UI/UX pass for the person who did not build this. No feature was removed;
10
+ vocabulary, ordering, and the default mode a first-run user lands in changed.
11
+ Backend behaviour is unchanged — `frontend/openapi.json` differs from 10.4.0
12
+ only in `info.version`.
13
+
14
+ ### Changed
15
+ - **Permission modes are named by what they do to you, not by their enum.**
16
+ 엄격 / 신뢰 / 바이패스 → 먼저 물어보기 / 웬만하면 알아서 / 거의 다 알아서
17
+ (`Strict` / `Trusted` / `Bypass` → `Ask me first` / `Mostly on its own` /
18
+ `Almost everything on its own`), each with a one-line summary of what it does
19
+ without asking. The bypass warning now says which kind of action stays
20
+ blocked rather than naming the mode.
21
+ - **`#/pipeline` is reachable in basic mode and named 진행 상황.** Its two raw
22
+ API payload panels are replaced (in basic mode) by an `aria-label`ed ordered
23
+ list of three steps — 내용 읽기 / 뜻 파악하기 / 기억에 연결하기 — with a
24
+ per-step waiting/working/done state. Advanced mode keeps both payload panels.
25
+ - **Ingestion stage names describe the reader's file, not the machine's job**:
26
+ 준비 → 파일 여는 중, 파싱 → 내용 읽는 중, 임베딩 → 뜻 파악하는 중, 인덱싱 →
27
+ 기억에 연결하는 중, 메모리화 완료 → 기억 완료. The stale-embedding prompt
28
+ became "찾는 방식이 바뀌었어요 / 기억 다시 정리하기".
29
+ - **Run rows are titled by workflow name** (then goal, then title/query, then
30
+ "n번째 작업" in basic mode) instead of a database id; the id moves to a
31
+ secondary line in advanced mode only.
32
+ - **Run and trigger states are translated per token.**
33
+ `act.runStatus.<token>` covers ok/succeeded/completed/retried_ok/
34
+ awaiting_approval/waiting_approval/running/queued/pending/failed/error/
35
+ cancelled/stopped/interrupted/rejected/partial; an unmapped token renders
36
+ "알 수 없음" rather than itself.
37
+ - **Brain stats answer a person's question** — 저장 위치 / 내 컴퓨터 and
38
+ 가져가기 / 언제든 내보낼 수 있어요 in place of `schema_version` and the
39
+ storage engine name (both still shown in advanced).
40
+ - **`scripts/capture_release_evidence.mjs` captures in `basic`**, the app's real
41
+ default, instead of `advanced`. Every README screenshot before this release
42
+ showed panels a first-run user never sees. `09-model-setup-status.png` (a
43
+ duplicate of the Brain home once captured in basic) is replaced by
44
+ `09-automation-runs.png`, and `11-knowledge-journey.png` is added.
45
+ - **The walkthrough GIF is encoded against a palette generated from the clip**
46
+ (`palettegen=stats_mode=diff` + `paletteuse=dither=sierra2_4a`) instead of
47
+ ffmpeg's default 256-colour cube, which had been rendering the ivory
48
+ background as dithered yellow and the greens as olive. 1.5 MB → 2.8 MB.
49
+
50
+ ### Added
51
+ - `frontend/src/lib/permissionCopy.ts` — one source for permission-mode copy,
52
+ shared by `BrainQuickControls` (home dial) and `PermissionModePanel`
53
+ (Settings), which had each been translating the server catalog separately.
54
+ Lookup is by mode id, falling back to the server's own localized label, so a
55
+ mode added server-side still renders; `PermissionModePanel.test.tsx` asserts
56
+ that fallback so the table cannot become an accidental allowlist.
57
+ - A basic-mode "자동으로 실행되는 작업" summary on the workflows surface:
58
+ workflow name plus 새 자료가 들어오면 / 정해진 시간에 / 내가 눌렀을 때만 /
59
+ 조건이 맞으면, and 켜져 있어요 / 지금은 멈춰 있어요. The node canvas and the
60
+ paste-JSON box are author tools and stay in advanced mode.
61
+ - `tests/visual/v3.spec.js`: a sweep over ten plain-mode routes asserting each
62
+ renders, shows no service-unavailable banner, and contains none of a list of
63
+ engine terms; plus a test that the three journey steps render under their
64
+ accessible name. `#/runs` failed the vocabulary assertion before this pass.
65
+ - `Library.test.tsx` covers registry prose that is English-only: a sentence with
66
+ no Hangul and six or more words is now replaced by a written Korean
67
+ explanation instead of being substituted term by term into word salad.
68
+
69
+ ### Known gaps
70
+ - The approval card under 작업 → 실행 still labels raw payload fields `Action`,
71
+ `Action Label`, `User Email`. It is visible in `09-automation-runs.png` and is
72
+ published rather than cropped.
73
+
74
+ ## [10.4.0] - 2026-08-02
75
+
76
+ ### Changed
77
+ - **`app_factory._build` is decomposed.** 1,318 lines → 26. The assembly now
78
+ lives in `latticeai/runtime/build_phases.py` as ten ordered phases sharing a
79
+ typed `latticeai/runtime/runtime_context.py::RuntimeContext`:
80
+ `platform → config → identity → brain → domain → web → services →
81
+ foundation_routes → platform_features → interaction`.
82
+ The single closure worked because closures resolve free variables at call
83
+ time; several sections depend on names bound far below them. The
84
+ RuntimeContext preserves that late binding while naming the shared state.
85
+ `tests/unit/test_runtime_context.py` fixes the phase order, which phase
86
+ produces which attribute, and that reading one early fails by name.
87
+ - **mypy covers the whole tree: 274 of 274 modules, 0 errors** (was 193 of 270
88
+ with 1,407 outstanding). `pyproject.toml`'s `[tool.mypy] files` is no longer
89
+ a curated subset.
90
+ - `lattice_brain/graph/_kg_common.py`'s `__all__` is a literal instead of a
91
+ comprehension over `globals()`. The computed form was invisible to a type
92
+ checker, so twelve modules resolved no names behind
93
+ `from ._kg_common import *` (~750 false `name-defined` errors).
94
+ `tests/unit/test_kg_common_exports.py` keeps the literal honest.
95
+ - The star import of `._kg_fsutil` inside `_kg_common` is now an explicit list
96
+ for the same reason.
97
+ - JSON-shaped payloads in `services/model_runtime.py`, `model_engines.py`,
98
+ `model_catalog.py`, `api/setup.py` and `api/models.py` are typed
99
+ `Dict[str, Any]` rather than `Dict[str, object]`, which forced a cast at
100
+ every nested access without catching anything.
101
+ - Optional dependencies (`AsyncOpenAI`, `mx`, `vlm_load`, `lm_load`,
102
+ `pyautogui`) are aliased on import and re-exported as `Any`, so "installed"
103
+ and "absent" have one declared type.
104
+
105
+ ### Added
106
+ - `lattice_brain/graph/_kg_contract.py` — the 23-member surface the eleven
107
+ graph mixins share, written down for the first time. Typing-only: `_Core` is
108
+ `object` at runtime, so `KnowledgeGraphStore`'s MRO is unchanged.
109
+ `tests/unit/test_kg_contract.py` asserts both the contract and that it never
110
+ becomes a real base class.
111
+ - `AppContext.require(field)` — binds a dependency a router cannot run without,
112
+ so an absent one names itself at router construction instead of surfacing as
113
+ `'NoneType' object is not callable` inside a request handler.
114
+ - VS Code `ltcai.captureFolder` — folder ingestion through the same
115
+ `/api/ingestion/folder` endpoint and the same local-read approval dance the
116
+ web Capture view uses.
117
+ - VS Code `ltcai.showArtifacts` — `artifacts[]` rendered as cards with the
118
+ server's repair and validation flags, so a deterministically repaired
119
+ scaffold no longer looks identical to clean model output.
120
+ - VS Code model picker now shows the hardware-derived recommendation from
121
+ `GET /setup/scan`, with the server's own reasoning. No scan, no banner.
122
+ - Telegram sends the same `artifacts[]` card summary before the files.
123
+ - Frontend tests for four previously untested modules with real logic:
124
+ `routes.ts`, `store/appStore.ts`, `api/base.ts` error translation, and
125
+ `pages/brain/graphExplorer.ts`.
126
+
127
+ ### Fixed
128
+ - **`python -m latticeai.server_app` raised `AttributeError`.** `main` was a
129
+ local inside the old `_build` closure and was never on the export allowlist,
130
+ so `get_shared_runtime().main()` could never resolve it. `main()` now serves
131
+ the shared runtime directly and needs no export.
132
+ - `core/workspace_os.py`: four lines duplicated after a `return` in
133
+ `remove_member` — dead since the merge that introduced them.
134
+ - `models/router.py`: a `str` shadowed a `dict` in the custom cloud-model loop,
135
+ so those entries built their ids from the wrong variable.
136
+ - `lattice_brain/context.py`: an unconfigured retrieval seam was called
137
+ unguarded and died as a `TypeError` inside failure isolation instead of
138
+ naming itself.
139
+ - `runtime/review_wiring.py` declared its injected `HTTPException` as
140
+ `type[Exception]`, which does not accept `(status_code=, detail=)`.
141
+ - `api/security_dashboard.py`: a defensive `isinstance(rows, list)` re-check
142
+ that every branch above already guaranteed.
143
+
144
+ ### Documentation
145
+ - `docs/MYPY_BACKLOG.md` is now the record of how the boundary closed, not a
146
+ list of what is left — including the conventions the sweep settled on.
147
+ - `docs/SURFACE_PARITY.md`: no ◐ remains in the matrix. A stale v9.9.6 note
148
+ claiming the live step timeline was web-only is corrected (v9.9.7's
149
+ `runAgentLive` provides it).
150
+
7
151
  ## [10.3.0] - 2026-07-29
8
152
 
9
153
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  # Community And Plugins
2
2
 
3
- Current release: **10.3.0 — Measured Ground**.
3
+ Current release: **10.5.0 — Everyday Words**.
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: **10.3.0 — Measured Ground**.
6
+ Current release: **10.5.0 — Everyday Words**.
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
@@ -1,98 +1,65 @@
1
1
  # mypy backlog
2
2
 
3
- `[tool.mypy] files` in `pyproject.toml` lists every module that type-checks
4
- today — **193 of 270** as of 10.3.0, up from 13 in 10.2.0.
5
- This file is the remainder, smallest first, so the boundary is a measured
6
- fact rather than an open-ended intention.
3
+ > **Status: reference**
4
+ > 10.2.0: 13 modules checked. 10.3.0: 193 of 270, with the remaining 77 listed
5
+ > here by error count. **10.4.0: 274 of 274 — the backlog is empty.**
7
6
 
8
- Adding a module to the checked set is a decision to fix that module, not its
9
- dependencies (`follow_imports = silent`). Work from the top: the short ones
10
- are usually one missing annotation.
7
+ `[tool.mypy] files` in `pyproject.toml` now lists **every** module in
8
+ `lattice_brain/` and `latticeai/`. There is no "adopted set" any more; adding a
9
+ module to the tree adds it to the checked set, and CI fails if it does not
10
+ type-check.
11
11
 
12
- Three of these turned out to be real defects when 10.3.0 measured them:
13
- `hooks.py` referenced a non-existent `self._path` inside the handler for an
14
- unreadable registry, `_kg_fsutil.py` used `Iterable` without importing it,
15
- and `agent_runtime.py` called `.get` on a value that could be `None`. Those
16
- are fixed; the list below is what is left.
12
+ This file stays as the record of how the boundary closed, because two of the
13
+ 1,407 errors 10.3.0 measured turned out to be worth more than the annotations.
17
14
 
18
- | errors | module | dominant codes |
19
- | ---: | --- | --- |
20
- | 1 | `lattice_brain/graph/_kg_fsutil.py` | `union-attr` ×1 |
21
- | 1 | `latticeai/api/admin.py` | `call-overload` ×1 |
22
- | 1 | `latticeai/api/computer_use.py` | `var-annotated` ×1 |
23
- | 1 | `latticeai/api/hooks.py` | `unreachable` ×1 |
24
- | 1 | `latticeai/api/local_files.py` | `arg-type` ×1 |
25
- | 1 | `latticeai/api/static_routes.py` | `assignment` ×1 |
26
- | 1 | `latticeai/core/marketplace.py` | `arg-type` ×1 |
27
- | 1 | `latticeai/core/model_compat.py` | `unreachable` ×1 |
28
- | 1 | `latticeai/core/plugins.py` | `unreachable` ×1 |
29
- | 1 | `latticeai/core/project_sessions.py` | `var-annotated` ×1 |
30
- | 1 | `latticeai/core/workspace_os.py` | `unreachable` ×1 |
31
- | 1 | `latticeai/core/workspace_os_state.py` | `arg-type` ×1 |
32
- | 1 | `latticeai/runtime/sso_config_runtime.py` | `arg-type` ×1 |
33
- | 1 | `latticeai/services/command_center.py` | `assignment` ×1 |
34
- | 1 | `latticeai/services/search_service.py` | `assignment` ×1 |
35
- | 1 | `latticeai/services/triggers.py` | `truthy-function` ×1 |
36
- | 1 | `latticeai/setup/auto_setup.py` | `attr-defined` ×1 |
37
- | 2 | `lattice_brain/ingestion.py` | `assignment` ×2 |
38
- | 2 | `latticeai/api/chat_stream.py` | `var-annotated` ×1, `arg-type` ×1 |
39
- | 2 | `latticeai/api/mcp.py` | `var-annotated` ×2 |
40
- | 2 | `latticeai/core/mcp_registry.py` | `index` ×1, `return-value` ×1 |
41
- | 2 | `latticeai/core/run_explain.py` | `union-attr` ×1, `call-overload` ×1 |
42
- | 2 | `latticeai/core/workspace_snapshots.py` | `var-annotated` ×2 |
43
- | 2 | `latticeai/runtime/review_wiring.py` | `call-arg` ×2 |
44
- | 2 | `latticeai/services/brain_intelligence.py` | `operator` ×1, `index` ×1 |
45
- | 2 | `latticeai/services/memory_service.py` | `misc` ×1, `index` ×1 |
46
- | 2 | `latticeai/services/model_loading.py` | `arg-type` ×1, `call-overload` ×1 |
47
- | 2 | `latticeai/services/multimodal_streaming.py` | `attr-defined` ×1, `arg-type` ×1 |
48
- | 2 | `latticeai/setup/wizard.py` | `attr-defined` ×1, `dict-item` ×1 |
49
- | 2 | `latticeai/tools/documents.py` | `arg-type` ×2 |
50
- | 3 | `lattice_brain/quality.py` | `var-annotated` ×2, `return-value` ×1 |
51
- | 3 | `latticeai/api/models.py` | `call-overload` ×2, `attr-defined` ×1 |
52
- | 3 | `latticeai/cli/entrypoint.py` | `operator` ×1, `union-attr` ×1, `arg-type` ×1 |
53
- | 3 | `latticeai/core/audit.py` | `assignment` ×1, `index` ×1, `operator` ×1 |
54
- | 3 | `latticeai/integrations/telegram_bot.py` | `union-attr` ×2, `arg-type` ×1 |
55
- | 3 | `latticeai/runtime/stages.py` | `arg-type` ×3 |
56
- | 3 | `latticeai/services/cloud_streaming.py` | `arg-type` ×2, `attr-defined` ×1 |
57
- | 3 | `latticeai/services/hybrid_chat.py` | `arg-type` ×3 |
58
- | 3 | `latticeai/services/tool_dispatch.py` | `arg-type` ×3 |
59
- | 4 | `lattice_brain/graph/_kg_common.py` | `misc` ×3, `return-value` ×1 |
60
- | 4 | `latticeai/api/chat_agent_http.py` | `arg-type` ×2, `misc` ×1, `assignment` ×1 |
61
- | 4 | `latticeai/api/chat_helpers.py` | `call-overload` ×2, `union-attr` ×1, `arg-type` ×1 |
62
- | 4 | `latticeai/api/security_dashboard.py` | `assignment` ×3, `unreachable` ×1 |
63
- | 4 | `latticeai/services/evidence_actions.py` | `union-attr` ×4 |
64
- | 5 | `lattice_brain/context.py` | `arg-type` ×4, `misc` ×1 |
65
- | 5 | `latticeai/api/permissions.py` | `arg-type` ×5 |
66
- | 5 | `latticeai/services/model_engines.py` | `attr-defined` ×2, `call-overload` ×2, `unreachable` ×1 |
67
- | 5 | `latticeai/services/run_executor.py` | `unreachable` ×3, `arg-type` ×1, `return-value` ×1 |
68
- | 6 | `lattice_brain/runtime/contracts.py` | `union-attr` ×6 |
69
- | 6 | `latticeai/core/agent.py` | `arg-type` ×4, `return-value` ×2 |
70
- | 7 | `lattice_brain/graph/proactive.py` | `assignment` ×2, `arg-type` ×2, `index` ×1 |
71
- | 7 | `latticeai/app_factory.py` | `arg-type` ×3, `assignment` ×2, `attr-defined` ×2 |
72
- | 7 | `latticeai/core/embedding_providers.py` | `unreachable` ×2, `assignment` ×2, `union-attr` ×2 |
73
- | 7 | `latticeai/services/openai_compatible_adapter.py` | `arg-type` ×7 |
74
- | 8 | `lattice_brain/graph/curator.py` | `operator` ×8 |
75
- | 8 | `lattice_brain/workflow.py` | `arg-type` ×5, `index` ×2, `assignment` ×1 |
76
- | 8 | `latticeai/api/setup.py` | `index` ×5, `attr-defined` ×3 |
77
- | 8 | `latticeai/services/local_knowledge.py` | `union-attr` ×3, `misc` ×2, `operator` ×2 |
78
- | 10 | `latticeai/api/tools.py` | `arg-type` ×10 |
79
- | 13 | `latticeai/api/search.py` | `return` ×12, `return-value` ×1 |
80
- | 15 | `lattice_brain/graph/store.py` | `name-defined` ×15 |
81
- | 16 | `latticeai/api/chat.py` | `arg-type` ×12, `misc` ×3, `call-overload` ×1 |
82
- | 16 | `latticeai/tools/computer.py` | `union-attr` ×16 |
83
- | 19 | `lattice_brain/graph/retrieval_docgen.py` | `name-defined` ×12, `attr-defined` ×7 |
84
- | 35 | `latticeai/services/model_runtime.py` | `index` ×15, `arg-type` ×8, `attr-defined` ×6 |
85
- | 45 | `lattice_brain/graph/retrieval_reads.py` | `name-defined` ×30, `attr-defined` ×15 |
86
- | 46 | `latticeai/models/router.py` | `arg-type` ×26, `assignment` ×7, `attr-defined` ×4 |
87
- | 57 | `lattice_brain/graph/write_master.py` | `name-defined` ×48, `attr-defined` ×9 |
88
- | 64 | `lattice_brain/graph/documents.py` | `name-defined` ×45, `attr-defined` ×19 |
89
- | 71 | `lattice_brain/graph/provenance.py` | `name-defined` ×59, `attr-defined` ×12 |
90
- | 77 | `lattice_brain/graph/retrieval.py` | `name-defined` ×61, `attr-defined` ×16 |
91
- | 79 | `lattice_brain/graph/discovery.py` | `name-defined` ×72, `attr-defined` ×7 |
92
- | 107 | `lattice_brain/graph/retrieval_vector.py` | `name-defined` ×68, `attr-defined` ×39 |
93
- | 108 | `latticeai/api/workspace.py` | `misc` ×105, `arg-type` ×2, `call-overload` ×1 |
94
- | 127 | `lattice_brain/graph/discovery_index.py` | `name-defined` ×98, `attr-defined` ×29 |
95
- | 143 | `lattice_brain/graph/projection.py` | `name-defined` ×122, `attr-defined` ×21 |
96
- | 177 | `lattice_brain/graph/ingest.py` | `name-defined` ×122, `attr-defined` ×55 |
15
+ ## Two root causes were 68% of the backlog
97
16
 
98
- Total outstanding: **1407** errors across **77** modules.
17
+ **`_kg_common.__all__` was computed** (`[name for name in globals() if not
18
+ name.startswith("__")]`). Correct at runtime, opaque to a checker: mypy could
19
+ not resolve a single name behind `from ._kg_common import *`, so twelve graph
20
+ modules reported **~750 false `name-defined` errors** and stayed unchecked.
21
+ Freezing the list to a literal fixed all of them.
22
+ `tests/unit/test_kg_common_exports.py` asserts the literal still equals what
23
+ the expression would produce, so it cannot drift.
24
+
25
+ **The eleven graph mixins had an unwritten contract.** `ingest` calls
26
+ `_upsert_node` from `write_master`, which calls `_v2_project_node` from
27
+ `projection`, and everything calls `_connect` — 229 `attr-defined` errors,
28
+ because from a checker's position each mixin is a bare class calling methods it
29
+ does not have. `lattice_brain/graph/_kg_contract.py` writes that contract down:
30
+ 23 declared members, typing-only (`_Core` is `object` at runtime, so the MRO is
31
+ unchanged), verified by `tests/unit/test_kg_contract.py`.
32
+
33
+ Neither was a typing problem. Both were *readability* problems that a reader
34
+ had to solve by grepping eleven files.
35
+
36
+ ## Real defects the remaining work surfaced
37
+
38
+ | defect | module | why it mattered |
39
+ | --- | --- | --- |
40
+ | four lines duplicated after a `return` | `core/workspace_os.py` | dead since the merge that introduced it; `remove_member` looked like it did its work twice |
41
+ | `main` was never exported | `app_factory.py` | `python -m latticeai.server_app` raised `AttributeError` — the module entrypoint did not run |
42
+ | `str` shadowed a `dict` in a loop | `models/router.py` | the custom-cloud-model branch built ids from the wrong variable |
43
+ | `Optional` seam called unguarded | `lattice_brain/context.py` | an unconfigured retrieval port raised `TypeError` inside failure isolation instead of naming itself |
44
+
45
+ (10.3.0 found three more the same way: `self._path` inside an error handler,
46
+ `Iterable` used without importing it, and `.get` on a possible `None`.)
47
+
48
+ ## Conventions the sweep settled on
49
+
50
+ * **JSON-shaped payloads are `Dict[str, Any]`, not `Dict[str, object]`.**
51
+ `object` forced a cast at every nested access without catching anything;
52
+ the value really is arbitrary JSON.
53
+ * **Optional dependencies are aliased, then re-exported as `Any`**
54
+ (`AsyncOpenAI`, `mx`, `vlm_load`, `pyautogui`), so "installed" and "absent"
55
+ have the same declared type and call sites keep their historical name.
56
+ * **Async generators in Protocols are declared with `def`, not `async def`.**
57
+ `async def … -> AsyncIterator[T]` says "a coroutine resolving to an
58
+ iterator", which no implementation does.
59
+ * **A router dependency it cannot run without is bound through
60
+ `AppContext.require("name")`** — an absent dependency names itself at router
61
+ construction instead of surfacing as `'NoneType' object is not callable`
62
+ inside a request handler.
63
+ * **A defensive `isinstance` check on a parameter means the annotation is
64
+ wrong.** Widen the parameter (`Any`, `Optional[str]`) rather than deleting
65
+ the guard: the guard is what the callers actually need.
@@ -1,6 +1,6 @@
1
1
  # Lattice AI Onboarding
2
2
 
3
- Current release: **10.3.0 — Measured Ground**.
3
+ Current release: **10.5.0 — Everyday Words**.
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 (v10.3.0)
1
+ # Lattice AI — Operations Guide (v10.5.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
@@ -36,10 +36,21 @@ Env default: `LATTICEAI_PERMISSION_MODE=strict|trusted|bypass`.
36
36
 
37
37
  ## UI
38
38
 
39
- `PermissionModePanel` renders in **환경설정 → 에이전트 자율성** (`SystemPage`
40
- settings tab). It renders the catalog `/api/permission-mode` returns rather
41
- than a hardcoded mode list, so adding or renaming a mode server-side needs no
42
- frontend change, and it keeps the apply button disabled until
39
+ `PermissionModePanel` renders in **설정 → 혼자 해도 되는 일** (`SystemPage`
40
+ settings tab; the section was called 에이전트 자율성 before 10.5.0). The same
41
+ dial is reachable on the home screen through `BrainQuickControls`.
42
+
43
+ It still renders whatever modes the catalog `/api/permission-mode/catalog`
44
+ returns rather than a hardcoded list, so a mode added server-side appears with
45
+ no frontend change. Since 10.5.0 the *wording* is no longer taken from the
46
+ server for modes the app knows: `frontend/src/lib/permissionCopy.ts` maps mode
47
+ id → plain-language label and summary (`strict` → 먼저 물어보기, `trusted` →
48
+ 웬만하면 알아서, `bypass` → 거의 다 알아서), and both surfaces read that one
49
+ module so the dial cannot be named two ways. The server's own localized label
50
+ is the fallback for an id the map does not know — renaming a mode server-side
51
+ therefore changes the UI only for ids the app has no copy for.
52
+
53
+ The apply button stays disabled until
43
54
 
44
55
  * a *different* mode is selected, and
45
56
  * for a mode whose catalog entry sets `requires_ack`, the risk acknowledgement
@@ -2,7 +2,8 @@
2
2
 
3
3
  > **Status: reference**
4
4
  > 도입: v9.9.4 (2026-07-25, 리뷰 Wave 1.4 "표면 패리티 체크리스트").
5
- > 갱신: v9.9.7 — 표에 남아 있던 ✖ 갭을 **전부** 해소. Browser 확장도 캡처 전용 경계를 넘어 회상/승인 가시성을 갖췄다.
5
+ > 갱신: v9.9.7 — 표에 남아 있던 ✖ 갭을 **전부** 해소.
6
+ > 갱신: **v10.4.0 — 남아 있던 ◐(부분 제공)를 전부 해소.** 표에 ◐ 는 더 이상 없다.
6
7
  > 목적: 각 표면(서피스)이 Brain 계약의 어디까지를 제공하는지 **정직하게** 기록한다.
7
8
  > "앱마다 다른 Lattice"를 방지하는 기준표이며, 기능을 과장하지 않는다.
8
9
 
@@ -22,9 +23,9 @@
22
23
 
23
24
  | 루프 순간 | Web `/app` | Desktop | VS Code | Browser | Telegram |
24
25
  | --- | --- | --- | --- | --- | --- |
25
- | 첫 저장 (Capture) | ✅ DnD·폴더·웹 수집, 품질 경고 | ✅ (웹과 동일) | ◐ `sendToLattice` 선택 영역 전송 | ✅ 페이지 캡처 (단일 목적) | ◐ 메시지 수집 |
26
+ | 첫 저장 (Capture) | ✅ DnD·폴더·웹 수집, 품질 경고 | ✅ (웹과 동일) | ✅ `sendToLattice` 파일/선택 + `captureFolder` 폴더 수집 (v10.4.0) | ✅ 페이지 캡처 (단일 목적) | ✅ 메시지 + 문서/사진 업로드 수집 |
26
27
  | 첫 회상 (Recall) | ✅ 하이브리드 검색 + grounding 배지 + 출처→청크 | ✅ (동일) | ✅ `askCurrentFile`/`askBrain` — 동일 `/chat` grounding 배지 | ✅ 팝업 질문 + 동일 grounding 배지 (v9.9.7) | ✅ 답변 + grounding 배지 (v9.9.7) |
27
- | 첫 산출물 (Artifact) | ✅ artifacts[] 카드·미리보기·Brain 기억 칩 | ✅ (동일) | ◐ `createFile` + `runAgent`/`runAgentLive` 스텝·파일 요약, 카드 UI 없음 | — (의도: 브라우저에서 파일 쓰기 없음) | ◐ 파일 전송만 |
28
+ | 첫 산출물 (Artifact) | ✅ artifacts[] 카드·미리보기·Brain 기억 칩 | ✅ (동일) | ✅ `createFile` + `showArtifacts` 카드(보정/검증 플래그 포함, v10.4.0) | — (의도: 브라우저에서 파일 쓰기 없음) | ✅ 파일 + artifacts[] 카드 요약 (v10.4.0) |
28
29
  | 첫 보호 (Approval) | ✅ 승인 카드 + TTL 카운트다운 + 재시작 생존 | ✅ (동일) | ✅ List/Approve/Reject 커맨드 + 토큰 캐시 | ✅ 대기 건수 표시 (승인은 웹에서, v9.9.7) | ✅ 인라인 Done/Cancel + run_id/token 재개 |
29
30
 
30
31
  ## 기능 상세 × 표면
@@ -42,14 +43,14 @@
42
43
  | Watch 상태 신호 (v9.9.4) | ✅ 홈 카드 | ✅ | — | — | — |
43
44
  | Review Center (제안 승인/거절) | ✅ | ✅ | ✅ `ltcai.reviewCenter` (409 충돌 정직 보고) | — (의도: 승인은 웹/에디터/봇에서) | ✅ `/review` + 인라인 승인/거절 (v9.9.7) |
44
45
  | 데모 코퍼스 First Value Loop | ✅ | ✅ | — | — | — |
45
- | 모델 로드/추천 | ✅ | ✅ | ◐ `loadModel` | — | — |
46
+ | 모델 로드/추천 | ✅ | ✅ | ✅ `loadModel` + 하드웨어 기반 추천·근거 (v10.4.0) | — (의도) | — (의도) |
46
47
  | 코드 편집 보조 (edit/explain/refactor/tests) | — | — | ✅ | — | — |
47
48
 
48
49
  ## 규칙
49
50
 
50
51
  1. **API 계약이 기준이다.** 모든 표면은 동일한 sidecar API를 소비한다. 표면별 전용 API를 만들지 않는다.
51
52
  2. **◐/✖ 는 문서화된 상태로만 존재한다.** 새 기능을 Web에 추가할 때 이 표를 갱신하고, 다른 표면에 제공하지 않을 경우 "—(의도)" 인지 "✖(갭)" 인지 명시한다.
52
- 3. **✖ 갭은 릴리스 노트의 Honest Limitations 후보다.** v9.9.7 기준 표에 남은 ✖는 **없다**.
53
+ 3. **✖ 갭은 릴리스 노트의 Honest Limitations 후보다.** v9.9.7 이후 표에 남은 ✖는 **없고**, v10.4.0 이후 ◐ 도 **없다**.
53
54
  - 남은 "—"는 전부 **설계 경계**이며, 각 항목에 이유를 함께 적는다. 예: 브라우저 확장은 파일을 쓰지 않으므로 산출물 생성이 없고, 승인 *결정*은 서명된 토큰이 필요한 흐름이라 대기 건수만 보여 주고 승인은 웹/에디터/봇에서 한다.
54
55
  - 경계를 새로 만들 때는 "왜 제공하지 않는가"를 이 문서에 남긴다. 이유 없는 "—"는 갭이지 경계가 아니다.
55
56
  4. 릴리스마다 이 표를 검토한다 (release checklist의 docs 단계).
@@ -63,7 +64,7 @@
63
64
 
64
65
  - **회상 배지**: `askCurrentFile` / `askBrain`은 웹과 동일한 `POST /chat` 응답의 `grounding` 판정을 그대로 읽는다. 판정이 없으면 "근거 있음"으로 승격하지 않고 `unknown`으로 보고한다 (`vscode-extension/surface.ts::groundingBadge`).
65
66
  - **Review Center**: `ltcai.reviewCenter`는 웹과 같은 `/api/proposals` 표면을 쓴다. 승인은 검토한 내용 그대로 적용하고, 409(스테이징 이후 파일 변경)는 "아무것도 쓰지 않았다"고 정직하게 알린다.
66
- - **스텝 요약**: `ltcai.runAgent`는 실행 후 `steps`/`created_files`/`explanation`을 출력 채널에 요약한다. 라이브 SSE 타임라인은 아직 웹 전용이다 (◐).
67
+ - **스텝 요약**: `ltcai.runAgent`는 실행 후 `steps`/`created_files`/`explanation`을 출력 채널에 요약한다. (라이브 SSE 타임라인은 v9.9.7의 `ltcai.runAgentLive`가 같은 `agent_step` 프레임으로 제공한다 — 이 메모는 v9.9.6 시점 기준이었다.)
67
68
  - 파싱 계약은 `tests/vscode-extension.test.cjs`가 sidecar 페이로드 모양 그대로 검증한다.
68
69
 
69
70
  ## v9.9.7 — 남은 갭을 닫은 방법
@@ -81,3 +82,29 @@
81
82
  - **Browser 확장**: 캡처 전용 경계를 넘어 `/chat` 질문과 `agent/approvals` 대기
82
83
  건수를 보여 준다. **판정을 로컬에서 계산하지 않는다** — 판정이 없으면
83
84
  "근거 확인 불가"이며 절대 "근거 있음"으로 승격하지 않는다.
85
+
86
+ ## v10.4.0 — 마지막 ◐ 셋을 닫은 방법
87
+
88
+ 세 갭 모두 **계약의 문제가 아니라 렌더링의 문제**였다. 사이드카는 이미 필요한
89
+ 데이터를 내고 있었고, 에디터/봇이 그것을 버리고 있었다.
90
+
91
+ - **VS Code 폴더 수집** (`ltcai.captureFolder`): 웹 Capture 와 **같은**
92
+ `POST /api/ingestion/folder` 를 쓴다. 로컬 디스크를 읽으므로 승인 절차도
93
+ 동일하다 — 토큰 없는 첫 호출은 `permission_required` 이고, 확장은 그것을
94
+ 그대로 보여 준다(조용히 재시도하지 않는다). 백그라운드 job 으로 큐잉되며
95
+ 진행 상황은 웹에서 본다.
96
+ - **VS Code 산출물 카드** (`ltcai.showArtifacts`): `/agent` 응답의
97
+ `artifacts[]` 를 그대로 읽는다. 결정적으로 **보정된(repaired) 스캐폴드와
98
+ 깨끗한 모델 출력이 구분된다** — 이전에는 평평한 경로 목록이라 둘이 같아
99
+ 보였다. 서버의 `valid=false` 판정을 확장이 성공으로 승격하지 않는다.
100
+ 구형 사이드카(`created_files` 만 있는 응답)는 "세부 정보 없음"이라고
101
+ 정직하게 말한다.
102
+ - **VS Code 모델 추천**: `GET /setup/scan` 의 `zero_config.recommend` 를
103
+ 읽어 **이 기기에 왜 이 모델인지**를 근거와 함께 보여 준다. 스캔이 없으면
104
+ 배너도 없다 — 이유를 지어내지 않는다.
105
+ - **Telegram 산출물 카드**: 같은 `artifacts[]` 플래그를 파일 전송 직전에
106
+ 요약한다. 8개까지 나열하고 나머지는 `… +N` 으로 정직하게 줄인다.
107
+
108
+ 계약 테스트: `tests/vscode-extension.test.cjs` (19), `tests/unit/test_telegram_security.py`.
109
+ 전부 사이드카 페이로드 모양 그대로 검증하며, 확장/봇이 서버 판정을 재계산하지
110
+ 않는지도 함께 고정한다.
@@ -1,6 +1,6 @@
1
1
  # Lattice AI Trust Model
2
2
 
3
- Current release: **10.3.0 — Measured Ground**.
3
+ Current release: **10.5.0 — Everyday Words**.
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: **10.3.0 — Measured Ground**.
3
+ Current release: **10.5.0 — Everyday Words**.
4
4
 
5
5
  **Lattice AI is a local-first Digital Brain that keeps your knowledge durable
6
6
  across any AI model.**
package/docs/kg-schema.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Knowledge Graph Schema
2
2
 
3
- Current release: **10.3.0 — Measured Ground**.
3
+ Current release: **10.5.0 — Everyday Words**.
4
4
 
5
5
  명세 출처: `lattice_ai_full_spec.pptx` 슬라이드 20·21·22
6
6
  구현: `lattice_brain/graph/schema.py`
@@ -26,7 +26,7 @@ from .storage import (
26
26
  storage_from_env,
27
27
  )
28
28
 
29
- __version__ = "10.3.0"
29
+ __version__ = "10.5.0"
30
30
 
31
31
  __all__ = [
32
32
  "AgentRuntime",