ltcai 11.1.0 → 11.2.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.
- package/README.md +53 -53
- package/docs/CHANGELOG.md +33 -0
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/FEATURE_AUDIT_v11.2.0.md +393 -0
- package/docs/LAYOUT_REBUILD_SPEC.md +9 -1
- package/docs/ONBOARDING.md +1 -1
- package/docs/OPERATIONS.md +1 -1
- package/docs/TRUST_MODEL.md +1 -1
- package/docs/WHY_LATTICE.md +1 -1
- package/docs/architecture.md +6 -2
- package/docs/kg-schema.md +1 -1
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/gates.py +125 -0
- package/lattice_brain/graph/fusion.py +35 -4
- package/lattice_brain/graph/projection.py +66 -8
- package/lattice_brain/graph/schema.py +9 -0
- package/lattice_brain/graph/store.py +9 -0
- package/lattice_brain/graph/vector_index/selector.py +32 -2
- package/lattice_brain/ingestion.py +175 -27
- package/lattice_brain/multimodal.py +525 -5
- package/lattice_brain/portability.py +169 -32
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/lattice_brain/sealed_box.py +244 -0
- package/lattice_brain/synthesis.py +24 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/brain_intelligence.py +4 -0
- package/latticeai/api/chat.py +11 -0
- package/latticeai/api/chat_helpers.py +16 -3
- package/latticeai/api/chat_hybrid.py +32 -1
- package/latticeai/api/features.py +70 -0
- package/latticeai/api/local_files.py +102 -0
- package/latticeai/api/portability.py +39 -4
- package/latticeai/api/review_queue.py +126 -0
- package/latticeai/api/search.py +16 -2
- package/latticeai/core/agent.py +55 -2
- package/latticeai/core/config.py +4 -1
- package/latticeai/core/context_builder.py +6 -3
- package/latticeai/core/legacy_compatibility.py +1 -1
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/messages.py +143 -0
- package/latticeai/core/model_compat.py +73 -2
- package/latticeai/core/workspace_os_constants.py +1 -1
- package/latticeai/models/model_providers.py +12 -4
- package/latticeai/runtime/build_phases.py +28 -0
- package/latticeai/runtime/chat_wiring.py +4 -0
- package/latticeai/runtime/feature_toggle_wiring.py +163 -0
- package/latticeai/runtime/router_registration.py +11 -0
- package/latticeai/services/app_context.py +8 -0
- package/latticeai/services/architecture_readiness.py +1 -1
- package/latticeai/services/automation_intelligence.py +22 -2
- package/latticeai/services/brain_intelligence.py +123 -7
- package/latticeai/services/command_center.py +10 -4
- package/latticeai/services/feature_toggles.py +502 -0
- package/latticeai/services/folder_watch.py +122 -1
- package/latticeai/services/hybrid_chat.py +56 -5
- package/latticeai/services/interop_bridges.py +978 -0
- package/latticeai/services/model_capability_registry.py +434 -261
- package/latticeai/services/model_catalog.py +95 -61
- package/latticeai/services/model_recommendation.py +18 -11
- package/latticeai/services/model_runtime.py +1 -1
- package/latticeai/services/multimodal_ports.py +26 -1
- package/latticeai/services/obsidian_bridge.py +16 -25
- package/latticeai/services/product_readiness.py +1 -1
- package/latticeai/services/search_service.py +149 -2
- package/latticeai/services/tool_dispatch.py +4 -0
- package/latticeai/setup/auto_setup.py +27 -30
- package/latticeai/setup/wizard.py +77 -44
- package/package.json +1 -1
- package/scripts/check_current_release_docs.mjs +1 -1
- package/scripts/check_server_i18n.mjs +1 -0
- package/scripts/release_screen_claims.json +13 -0
- package/scripts/verify_hf_model_registry.py +253 -218
- package/src-tauri/Cargo.lock +1 -1
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +37 -37
- package/static/app/assets/{Act-D0HWqtn0.js → Act-AWf0SAKp.js} +1 -1
- package/static/app/assets/{AdminConsole-D-QDW-A4.js → AdminConsole-D0u8Tiyj.js} +1 -1
- package/static/app/assets/{Brain-CzCsI1mi.js → Brain-tuhI4sOC.js} +1 -1
- package/static/app/assets/BrainHome-Ts7G_Ila.js +2 -0
- package/static/app/assets/{BrainSignals-2dHQNkns.js → BrainSignals-jMYgQ2Ar.js} +1 -1
- package/static/app/assets/{Capture-CT8v1StE.js → Capture-CqOSzyPr.js} +1 -1
- package/static/app/assets/{CommandPalette-DoLXC2KH.js → CommandPalette-DC0Bzh-I.js} +1 -1
- package/static/app/assets/{Library-DDoxFE5c.js → Library-CX-bbhmK.js} +1 -1
- package/static/app/assets/{LivingBrain-BXMWIK_2.js → LivingBrain-DBwhto14.js} +1 -1
- package/static/app/assets/{ProductFlow-DOYf7JIs.js → ProductFlow-BHA2cfKI.js} +1 -1
- package/static/app/assets/{ReviewCard-COQsqidK.js → ReviewCard-BUhCKRNM.js} +1 -1
- package/static/app/assets/{System-BRllvYXd.js → System-Bu2t5hn1.js} +1 -1
- package/static/app/assets/arrow-left-Dzwa5zRb.js +1 -0
- package/static/app/assets/{bot-4BvN07ux.js → bot-Cia42c2h.js} +1 -1
- package/static/app/assets/brain-DJMoqrwx.js +1 -0
- package/static/app/assets/{button-CDjtnAoU.js → button-2j2Ijzgq.js} +1 -1
- package/static/app/assets/{circle-pause-D_RMn7tp.js → circle-pause-BEFeWpVW.js} +1 -1
- package/static/app/assets/{circle-play-B5OpB8ae.js → circle-play-ujXMcHxl.js} +1 -1
- package/static/app/assets/{cpu-BIlWInHf.js → cpu-k4awryFq.js} +1 -1
- package/static/app/assets/{download-BtjXfL3z.js → download-DFbLJ_ig.js} +1 -1
- package/static/app/assets/{folder-open-DefMpxI2.js → folder-open-7y_b6xkM.js} +1 -1
- package/static/app/assets/{hard-drive-BQ8NZVkw.js → hard-drive-Bidh02Kr.js} +1 -1
- package/static/app/assets/{index-0AvoEBzJ.js → index-BpYkzcVm.js} +3 -3
- package/static/app/assets/{index-vtEfYvQY.css → index-DwDl9-8Y.css} +1 -1
- package/static/app/assets/{input-B_5ZJ9oy.js → input-DSlJJxRs.js} +1 -1
- package/static/app/assets/{permissionCopy-BqZ5tsgL.js → permissionCopy-Bpb83Hx9.js} +1 -1
- package/static/app/assets/{primitives-CVwew78r.js → primitives-BCx6TvfG.js} +1 -1
- package/static/app/assets/search-Cgy8cCFJ.js +1 -0
- package/static/app/assets/{share-2-D5zg_0fY.js → share-2-BH1M-WNi.js} +1 -1
- package/static/app/assets/{shield-alert-B5pZzkUb.js → shield-alert-BlKdBXcG.js} +1 -1
- package/static/app/assets/{textarea-nEVIweKY.js → textarea-CCWbUfFB.js} +1 -1
- package/static/app/assets/{useFocusTrap-Cm99AHlz.js → useFocusTrap-YdHQ7pJ1.js} +1 -1
- package/static/app/assets/{useQuery-Dm__N6bL.js → useQuery-CXQiwbVT.js} +1 -1
- package/static/app/assets/{utils-DcDMoZIe.js → utils-zqPZJxdx.js} +2 -2
- package/static/app/assets/{workspace-LtRRSKTf.js → workspace-DXTihhfU.js} +1 -1
- package/static/app/index.html +4 -4
- package/static/sw.js +1 -1
- package/static/app/assets/BrainHome-Btns-_TA.js +0 -2
- package/static/app/assets/arrow-left-DnyMzss-.js +0 -1
- package/static/app/assets/brain-uMb_5hnO.js +0 -1
- package/static/app/assets/search-DkhnOKZt.js +0 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
[](https://github.com/TaeSooPark-PTS/LatticeAI/actions/workflows/ci.yml)
|
|
12
12
|
[](LICENSE)
|
|
13
13
|
|
|
14
|
-

|
|
15
15
|
|
|
16
16
|
Chat, files, folders, notes, and web pages all flow into one durable knowledge
|
|
17
17
|
graph on your computer. Any model — local MLX or cloud — can speak with that
|
|
@@ -24,10 +24,10 @@ memory. Nothing leaves your machine without explicit consent.
|
|
|
24
24
|
|
|
25
25
|
| | |
|
|
26
26
|
| --- | --- |
|
|
27
|
-
| **Chat with a Brain that remembers** — every conversation grows durable, source-linked memory  | **See how knowledge connects** — a real relationship graph, not a file list  |
|
|
28
|
+
| **Capture anything** — files, whole folders, notes, screenshots, web pages  | **Automate with review** — agent changes become proposals you approve first  |
|
|
29
|
+
| **Pick a model in one click** — recommended local models for your hardware  | **Stay in control** — audit, roles, retention in a separate admin surface  |
|
|
30
|
+
| **Watch a file become memory** — three named steps, not a pipeline diagram  | **Say how much it may do alone** — one dial in plain words; dangerous actions stay blocked either way  |
|
|
31
31
|
|
|
32
32
|
## Why Lattice AI
|
|
33
33
|
|
|
@@ -58,64 +58,63 @@ First-run flow — wake the Brain, pick the owner, load a recommended model:
|
|
|
58
58
|
|
|
59
59
|
| | | |
|
|
60
60
|
| --- | --- | --- |
|
|
61
|
-
|  |  |  |
|
|
62
62
|
|
|
63
63
|
Screenshot index and capture notes:
|
|
64
|
-
[output/release/v11.
|
|
64
|
+
[output/release/v11.2.0/SCREENSHOT_INDEX.md](output/release/v11.2.0/SCREENSHOT_INDEX.md)
|
|
65
65
|
|
|
66
66
|
## Current Release
|
|
67
67
|
|
|
68
|
-
The current release is **11.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
the
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
- **
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
with
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
statements and 10,658 branches**, verified on macOS 3.14, a fresh-resolve
|
|
68
|
+
The current release is **11.2.0 — All Systems On**:
|
|
69
|
+
|
|
70
|
+
11.1.0 built the intelligence layer; 11.2.0 makes sure **every part of it
|
|
71
|
+
actually works, ships today's models, and puts the switches in your hand.**
|
|
72
|
+
|
|
73
|
+
- **The model catalog is current and verified.** Every recommended model
|
|
74
|
+
was checked against the live Hugging Face API — no weights downloaded, no
|
|
75
|
+
model loaded, nothing run on your machine. Two models that had vanished
|
|
76
|
+
from the Hub (phi-3.5-vision, moondream2), four gated repos and three
|
|
77
|
+
obsolete generations left the catalog; the ten recommendations are all
|
|
78
|
+
2025–2026 builds (Gemma 4 line, Qwen3.5/3.6, gpt-oss-20b, LFM2.5 with
|
|
79
|
+
Korean support), RAM-tiered, with exact-case ids, real byte sizes (one
|
|
80
|
+
entry claimed 11.8 GB for a 61 GB repo) and a static-loadability verdict
|
|
81
|
+
whose limits are stated, not hidden. Already-downloaded older models stay
|
|
82
|
+
recognised so nobody's local weights become orphans.
|
|
83
|
+
- **Every switch is yours now.** A new 기능 drawer on the Brain home's dock
|
|
84
|
+
lists every opt-in capability — multimodal memories, video, brain
|
|
85
|
+
network sharing, vault watch, photo semantic search, RRF fusion, graph
|
|
86
|
+
expansion, automatic synthesis, background indexing, and the vector
|
|
87
|
+
backend choice — each with a plain-language line, its current source
|
|
88
|
+
(default / env / you), and a live switch. Toggles apply at runtime
|
|
89
|
+
through injected gate seams; an uninstalled backend says "install
|
|
90
|
+
needed" instead of pretending.
|
|
91
|
+
- **The scope-outs are in.** Notion-export, Git-history and mail/calendar
|
|
92
|
+
bridges (all through the single ingestion gate with approval and
|
|
93
|
+
dry-run), recipient public-key encryption for subgraph shares (X25519
|
|
94
|
+
sealed box; passphrase mode stays), video ingestion via guarded ffmpeg
|
|
95
|
+
keyframes with subtitle companions, vault watch mode, bulk review
|
|
96
|
+
approval, the Self-Model summary reaching the agent loop, and text→image
|
|
97
|
+
semantic photo search.
|
|
98
|
+
- **A 58-row evidence audit** verified every documented feature against
|
|
99
|
+
the running app: 51 worked as documented; the rest were fixed (a
|
|
100
|
+
permanently blank briefing health section, cloud memory write-back that
|
|
101
|
+
never reached the Review Center, an empty Brain scoring 100/excellent)
|
|
102
|
+
or the docs were lowered to the truth. The audit ships as
|
|
103
|
+
[docs/FEATURE_AUDIT_v11.2.0.md](docs/FEATURE_AUDIT_v11.2.0.md).
|
|
104
|
+
|
|
105
|
+
All of it lands with the floor intact: **6,490 tests, 100.00% of 39,054
|
|
106
|
+
statements and 11,014 branches**, verified on macOS 3.14, a fresh-resolve
|
|
108
107
|
python 3.11 environment, and a clean linux python:3.14 container.
|
|
109
108
|
|
|
110
109
|
Release notes: [RELEASE.md](RELEASE.md) · Full history: [docs/CHANGELOG.md](docs/CHANGELOG.md)
|
|
111
110
|
|
|
112
|
-
Expected artifacts for 11.
|
|
111
|
+
Expected artifacts for 11.2.0 release must use exact filenames:
|
|
113
112
|
|
|
114
|
-
- `dist/ltcai-11.
|
|
115
|
-
- `dist/ltcai-11.
|
|
116
|
-
- `ltcai-11.
|
|
117
|
-
- `dist/ltcai-11.
|
|
118
|
-
- `src-tauri/target/release/bundle/dmg/Lattice AI_11.
|
|
113
|
+
- `dist/ltcai-11.2.0-py3-none-any.whl`
|
|
114
|
+
- `dist/ltcai-11.2.0.tar.gz`
|
|
115
|
+
- `ltcai-11.2.0.tgz`
|
|
116
|
+
- `dist/ltcai-11.2.0.vsix`
|
|
117
|
+
- `src-tauri/target/release/bundle/dmg/Lattice AI_11.2.0_aarch64.dmg`
|
|
119
118
|
|
|
120
119
|
Do not use wildcard artifact uploads. Package registry publishing remains owner-run.
|
|
121
120
|
|
|
@@ -150,6 +149,7 @@ See [ARCHITECTURE.md](ARCHITECTURE.md) for details and
|
|
|
150
149
|
|
|
151
150
|
| Version | Theme |
|
|
152
151
|
| --- | --- |
|
|
152
|
+
| 11.2.0 | All Systems On |
|
|
153
153
|
| 11.1.0 | Product Intelligence |
|
|
154
154
|
| 11.0.1 | Both Branches |
|
|
155
155
|
| 11.0.0 | Full Measure |
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,39 @@ The top entry is either the current unreleased main-branch work or the current
|
|
|
4
4
|
release line. Older entries are historical and may describe behavior as it
|
|
5
5
|
existed at that release.
|
|
6
6
|
|
|
7
|
+
## [11.2.0] - 2026-08-11 — All Systems On
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- 모델 카탈로그 전수 최신화: HF API 무부하 검증(가중치 다운로드 0, 실로드
|
|
11
|
+
0) 후 추천 10종을 2025–2026 세대(Gemma 4 · Qwen3.5/3.6 · gpt-oss-20b ·
|
|
12
|
+
LFM2.5)로 재구성. Hub 소멸 2종·gated 3종·vllm 전용·구세대 제거(완전
|
|
13
|
+
삭제), 기존 다운로드 모델은 인식 전용 목록으로 보호. 검증기에서
|
|
14
|
+
`--deep`/`--test-load` 제거(무부하 원칙 구조화). 크기 오기(11.8→61.1GB)
|
|
15
|
+
등 부수 결함 8건 수정.
|
|
16
|
+
- 빈 Brain이 가용 1차원만으로 100/excellent를 받던 건강 채점을 정직화
|
|
17
|
+
(측정 불가 차원은 사유와 함께 unavailable, 전무 시 등급 없음).
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- Brain 홈 dock **기능 서랍**: opt-in 10종(멀티모달·비디오·브레인 네트워크
|
|
21
|
+
·볼트 감시·사진 의미 검색·RRF·이웃 확장·자동 합성·배경 인덱싱·벡터
|
|
22
|
+
백엔드)의 서버 카탈로그 라이브 토글 — `GET/POST /api/features`,
|
|
23
|
+
FeatureGate 시임으로 재시작 없이 반영, 사용자>env>기본.
|
|
24
|
+
- Interop 브릿지: Notion export · Git 히스토리 · 메일(.eml)/캘린더(.ics)
|
|
25
|
+
— 단일 인제스트 게이트+승인+dry_run(`/api/ingestion/interop`).
|
|
26
|
+
- 서브그래프 공유 수신자 공개키 암호화(X25519 sealed box, ephemeral 키)
|
|
27
|
+
+ `GET /api/knowledge-graph/share/recipient-key`.
|
|
28
|
+
- 비디오 인제스트(ffmpeg 가드 키프레임 + .srt/.vtt, NodeType.VIDEO),
|
|
29
|
+
볼트 감시 모드, 일괄 리뷰 승인/기각, Self-Model 요약의 에이전트 루프
|
|
30
|
+
도달, 텍스트→이미지 의미 검색(`/api/search/image-query`).
|
|
31
|
+
- 58행 증거 기반 기능 감사 문서 docs/FEATURE_AUDIT_v11.2.0.md.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
- 오늘의 브리핑 건강 섹션 영구 공백(스키마 불일치), 클라우드 유래 지식이
|
|
35
|
+
리뷰 센터에 도달하지 않던 write-back 미배선(+auto_commit 정책 연결),
|
|
36
|
+
vector-freshness 세분화 미노출, 멀티모달 context_quality 신호 미배선,
|
|
37
|
+
`kgv2_edges`가 canonical 엣지 타입을 ''로 읽던 뷰(`COALESCE(NULLIF)`),
|
|
38
|
+
죽은 자동화 저신뢰 게이트, 사어 grok id(→grok-4.5).
|
|
39
|
+
|
|
7
40
|
## [11.1.0] - 2026-08-10 — Product Intelligence Layer
|
|
8
41
|
|
|
9
42
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Community And Plugins
|
|
2
2
|
|
|
3
|
-
Current release: **11.
|
|
3
|
+
Current release: **11.2.0 — All Systems On**.
|
|
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
|
package/docs/DEVELOPMENT.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> **Status: canonical** — current contributor guidance, kept in sync with the
|
|
4
4
|
> current release.
|
|
5
5
|
|
|
6
|
-
Current release: **11.
|
|
6
|
+
Current release: **11.2.0 — All Systems On**.
|
|
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
|
|
@@ -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.
|