ltcai 10.6.0 → 10.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -52
- package/docs/CHANGELOG.md +126 -0
- package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
- package/docs/DEVELOPMENT.md +1 -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/kg-schema.md +1 -1
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/graph/_kg_contract.py +15 -0
- package/lattice_brain/graph/provenance.py +61 -5
- package/lattice_brain/graph/retrieval.py +16 -4
- package/lattice_brain/graph/retrieval_reads.py +136 -23
- package/lattice_brain/graph/retrieval_vector.py +156 -8
- package/lattice_brain/ingestion.py +14 -1
- package/lattice_brain/ingestion_jobs.py +255 -5
- package/lattice_brain/portability.py +5 -2
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/browser.py +8 -14
- package/latticeai/api/knowledge_graph.py +46 -16
- package/latticeai/api/workspace.py +4 -11
- package/latticeai/api/workspace_scope.py +125 -0
- package/latticeai/core/agent.py +68 -3
- package/latticeai/core/config.py +6 -0
- package/latticeai/core/csrf.py +293 -0
- package/latticeai/core/legacy_compatibility.py +1 -1
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/workspace_os_constants.py +1 -1
- package/latticeai/models/router.py +61 -16
- package/latticeai/runtime/build_phases.py +2 -0
- package/latticeai/runtime/config_runtime.py +2 -0
- package/latticeai/runtime/runtime_context.py +1 -0
- package/latticeai/runtime/web_runtime.py +31 -4
- package/latticeai/services/architecture_readiness.py +1 -1
- package/latticeai/services/product_readiness.py +1 -1
- package/latticeai/services/search_service.py +9 -1
- package/latticeai/services/tool_dispatch.py +13 -7
- package/latticeai/tools/__init__.py +1 -0
- package/latticeai/tools/documents.py +44 -13
- package/package.json +1 -1
- package/scripts/build_frontend_assets.mjs +21 -4
- package/scripts/check_current_release_docs.mjs +1 -1
- package/scripts/check_frontend_build_freshness.mjs +170 -0
- 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 +39 -39
- package/static/app/assets/{Act-B3MSgNsJ.js → Act-aNud-lKL.js} +1 -1
- package/static/app/assets/{AdminConsole-Ds8u36lf.js → AdminConsole-QiCTH68K.js} +1 -1
- package/static/app/assets/{Brain-XdHCIB6a.js → Brain-CMFh5q6k.js} +1 -1
- package/static/app/assets/{BrainHome-Dp8gzQoF.js → BrainHome-B4Ar3atu.js} +2 -2
- package/static/app/assets/{BrainSignals-D4yZflVt.js → BrainSignals-RVMlmTGC.js} +1 -1
- package/static/app/assets/{Capture-BwSZmiZ8.js → Capture-DEBo-0vZ.js} +1 -1
- package/static/app/assets/{CommandPalette-Ds0DnRSC.js → CommandPalette-bW5WxWWZ.js} +1 -1
- package/static/app/assets/{Library-SqzHjyfx.js → Library-5gFexm83.js} +1 -1
- package/static/app/assets/{LivingBrain-DpKt-NKE.js → LivingBrain-FlHFfu9i.js} +1 -1
- package/static/app/assets/ProductFlow-CFUNDOHu.js +1 -0
- package/static/app/assets/{ReviewCard-DVPi1LPZ.js → ReviewCard-BHj86h2Z.js} +2 -2
- package/static/app/assets/{System-w-9miIG8.js → System-CeNHoZRu.js} +1 -1
- package/static/app/assets/{activity-C0QavXjd.js → activity-7_ZmZqN0.js} +1 -1
- package/static/app/assets/arrow-left-Dv2Tiwhe.js +1 -0
- package/static/app/assets/{bot-C1-MbzCF.js → bot-D1gX4xks.js} +1 -1
- package/static/app/assets/{brain-CeRqzJVc.js → brain-Dn_bDfl4.js} +1 -1
- package/static/app/assets/{button-Z-2N8PUb.js → button-DPFZ9lGw.js} +1 -1
- package/static/app/assets/{circle-pause-CgjCLdmO.js → circle-pause-B2P72YOO.js} +1 -1
- package/static/app/assets/{circle-play-Bj45uClm.js → circle-play-BiC8z2vg.js} +1 -1
- package/static/app/assets/{cpu-B-2Chwfy.js → cpu-Cx-wRR_V.js} +1 -1
- package/static/app/assets/{download-CKmiOG3C.js → download-CKxlzxsK.js} +1 -1
- package/static/app/assets/{folder-open-fE7lLvhZ.js → folder-open-Bbjju0tt.js} +1 -1
- package/static/app/assets/{hard-drive-rDl1xsJ1.js → hard-drive-Bon1VBvq.js} +1 -1
- package/static/app/assets/index-DYUs0cWy.css +2 -0
- package/static/app/assets/{index-AEIqmjwZ.js → index-mLP0-YNO.js} +3 -3
- package/static/app/assets/{input-BflJYT5-.js → input-DrMc0Xns.js} +1 -1
- package/static/app/assets/{permissionCopy-BNNvkXSX.js → permissionCopy-BGUsI7vw.js} +1 -1
- package/static/app/assets/{primitives-CP68OWk2.js → primitives-CEMTjBz1.js} +1 -1
- package/static/app/assets/search-HsIji1wY.js +1 -0
- package/static/app/assets/{share-2-CyjG2_yY.js → share-2-D7THHq5K.js} +1 -1
- package/static/app/assets/{shield-alert-C_JBPWYd.js → shield-alert-BoU4_8r9.js} +1 -1
- package/static/app/assets/{textarea-Ds1Exelb.js → textarea-rU1Lb7ia.js} +1 -1
- package/static/app/assets/{useFocusTrap-BgIZQ4if.js → useFocusTrap-BgvK4Nkx.js} +1 -1
- package/static/app/assets/{useQuery-6Bu27NQe.js → useQuery-CT2ChyuU.js} +1 -1
- package/static/app/assets/{users-31lxlciQ.js → users-DlbfHBQV.js} +1 -1
- package/static/app/assets/{utils-C0-C5mZc.js → utils-fEGWreKB.js} +1 -1
- package/static/app/assets/workspace-ClDBz_0f.js +1 -0
- package/static/app/index.html +4 -4
- package/static/sw.js +1 -1
- package/static/app/assets/ProductFlow-BimeVtWH.js +0 -1
- package/static/app/assets/arrow-left-TsAKz-s_.js +0 -1
- package/static/app/assets/index-DcMODGjM.css +0 -2
- package/static/app/assets/search-B4O4iIgg.js +0 -1
- package/static/app/assets/workspace-DAB-urHL.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,62 +58,69 @@ 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/v10.6.
|
|
64
|
+
[output/release/v10.6.2/SCREENSHOT_INDEX.md](output/release/v10.6.2/SCREENSHOT_INDEX.md)
|
|
65
65
|
|
|
66
66
|
## Current Release
|
|
67
67
|
|
|
68
|
-
The current release is **10.6.
|
|
69
|
-
|
|
70
|
-
10.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
- **
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
- **The
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
68
|
+
The current release is **10.6.2 — Ask First**:
|
|
69
|
+
|
|
70
|
+
10.6.1 rebuilt five screens, and the Brain home is the one it only half
|
|
71
|
+
rebuilt: the order changed, the shape did not. A large Brain and a centred
|
|
72
|
+
headline still ran down the middle of the screen before the box you type into,
|
|
73
|
+
and the three suggestions still sat between that box and its own toolbar — so
|
|
74
|
+
the alternative to typing wore the same border as typing, and the composer was
|
|
75
|
+
separated from its own controls by an unrelated block. This release splits the
|
|
76
|
+
screen into two surfaces. Nothing was removed; the second choice stopped
|
|
77
|
+
sharing a card with the first.
|
|
78
|
+
|
|
79
|
+
- **The greeting introduces the composer instead of headlining the screen.**
|
|
80
|
+
The Brain and the greeting were a centred column above the input; they are a
|
|
81
|
+
compact banner across the top of the card now — a small Brain beside the title
|
|
82
|
+
and the memory count, on a tinted strip closed by a hairline. The Brain is
|
|
83
|
+
still the button that opens the memory map, and the banner stacks back into a
|
|
84
|
+
centred column on a phone.
|
|
85
|
+
- **One card is the first move, and only the first move.** The station reads
|
|
86
|
+
greeting → the box you type into → one row for 자료 추가 and 혼자 해도 되는 일,
|
|
87
|
+
with nothing between the box and its own controls.
|
|
88
|
+
- **What to try is a card of its own.** The three suggestions moved out of the
|
|
89
|
+
station onto a second surface below it, where they read as an offer rather
|
|
90
|
+
than a step. That card is a named `<section>`, so a screen reader announces it
|
|
91
|
+
as a region — the label used to sit on a plain `<div>`, where the browser
|
|
92
|
+
discards it.
|
|
93
|
+
- **The empty state is designed rather than inherited.** A Brain with nothing to
|
|
94
|
+
suggest yet — every Brain on its first day — shows starter pills instead of
|
|
95
|
+
suggestion cards. That row had never been styled for this screen: it borrowed
|
|
96
|
+
a pill height drawn for live conversations and sat noticeably taller than the
|
|
97
|
+
cards it stands in for. Both branches read as peers now, and a pill fills the
|
|
98
|
+
composer rather than sending a question you did not choose to ask.
|
|
99
|
+
- **Three bugs that only moving things could find.** The Brain's halo is written
|
|
100
|
+
as an inline `box-shadow`, so no stylesheet could shrink it — a 60px glow
|
|
101
|
+
stayed wrapped around a 58px Brain until the blur became a CSS variable the
|
|
102
|
+
host can set (every other screen keeps its old value through the fallback).
|
|
103
|
+
Clipping the card would have hidden the 노트 / 웹 popover and turned the card
|
|
104
|
+
into a scroll container that scrolls the greeting away on focus, so the banner
|
|
105
|
+
clips its own corners instead. And the reduced-motion rule that cancels the
|
|
106
|
+
card lift had to follow the cards to their new selector, or a reader who asked
|
|
107
|
+
the system to hold still would have got the animation back.
|
|
108
|
+
- **Guarded, not asserted.** Unit tests hold the split itself — station, deck
|
|
109
|
+
and footer as three siblings, with the suggestions provably *not* inside the
|
|
110
|
+
station. Browser tests hold what only a browser can see: the popover opens
|
|
111
|
+
unclipped, the cards fill their card, they collapse to chips under 900px and
|
|
112
|
+
stay visible under 760px, reduced motion is honoured, the empty-state pill row
|
|
113
|
+
renders, and the halo is measured against the Brain it surrounds.
|
|
107
114
|
|
|
108
115
|
Release notes: [RELEASE.md](RELEASE.md) · Full history: [docs/CHANGELOG.md](docs/CHANGELOG.md)
|
|
109
116
|
|
|
110
|
-
Expected artifacts for 10.6.
|
|
117
|
+
Expected artifacts for 10.6.2 release must use exact filenames:
|
|
111
118
|
|
|
112
|
-
- `dist/ltcai-10.6.
|
|
113
|
-
- `dist/ltcai-10.6.
|
|
114
|
-
- `ltcai-10.6.
|
|
115
|
-
- `dist/ltcai-10.6.
|
|
116
|
-
- `src-tauri/target/release/bundle/dmg/Lattice AI_10.6.
|
|
119
|
+
- `dist/ltcai-10.6.2-py3-none-any.whl`
|
|
120
|
+
- `dist/ltcai-10.6.2.tar.gz`
|
|
121
|
+
- `ltcai-10.6.2.tgz`
|
|
122
|
+
- `dist/ltcai-10.6.2.vsix`
|
|
123
|
+
- `src-tauri/target/release/bundle/dmg/Lattice AI_10.6.2_aarch64.dmg`
|
|
117
124
|
|
|
118
125
|
Do not use wildcard artifact uploads. Package registry publishing remains owner-run.
|
|
119
126
|
|
|
@@ -148,6 +155,8 @@ See [ARCHITECTURE.md](ARCHITECTURE.md) for details and
|
|
|
148
155
|
|
|
149
156
|
| Version | Theme |
|
|
150
157
|
| --- | --- |
|
|
158
|
+
| 10.6.2 | Ask First |
|
|
159
|
+
| 10.6.1 | First Things |
|
|
151
160
|
| 10.6.0 | Promoted Panels |
|
|
152
161
|
| 10.5.0 | Everyday Words |
|
|
153
162
|
| 10.4.0 | Named Ground |
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,132 @@ 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.6.2] - 2026-08-03
|
|
8
|
+
|
|
9
|
+
The Brain home, re-shaped rather than re-ordered. 10.6.1 gave this screen a new
|
|
10
|
+
order and left its shape alone: a 5.4rem organism and a centred headline ran
|
|
11
|
+
down the middle before the composer, and the suggestion strip sat between the
|
|
12
|
+
composer and its own toolbar. It is two surfaces now — a station holding the
|
|
13
|
+
first move, and a deck below it holding the alternatives. No feature was
|
|
14
|
+
removed. Backend behaviour is unchanged; `frontend/openapi.json` differs from
|
|
15
|
+
10.6.1 only in `info.version`.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- **The greeting is a banner, not a headline.** `.brain-home-station > .brain-hero`
|
|
19
|
+
is a `row` instead of a `column`: organism 5.4rem → 3.2rem beside the title and
|
|
20
|
+
the memory counts (`.brain-hero-header-text`), on a tinted strip with a
|
|
21
|
+
hairline foot. It stacks back to a centred column under 640px, and the
|
|
22
|
+
short-window rule now shrinks the organism to 2.6rem rather than growing it.
|
|
23
|
+
- **The station holds the first move and nothing else.** Greeting → composer →
|
|
24
|
+
one toolbar (`자료 추가` left, `혼자 해도 되는 일` right) with nothing between
|
|
25
|
+
the composer and its own controls.
|
|
26
|
+
- **The suggestions are their own card.** `.brain-secondary-deck` is a sibling
|
|
27
|
+
of the station under `.brain-centered-home`, which now carries three direct
|
|
28
|
+
children: station, deck, quiet row. The stage widened 44rem → 50rem.
|
|
29
|
+
- **The empty branch is styled for this screen.** With no `suggested_questions`,
|
|
30
|
+
the deck renders `.brain-prompt-pills-row`, scoped and sized here (notably
|
|
31
|
+
`min-height: 0`, against `conversation.css`'s 2.65rem pill floor) so both
|
|
32
|
+
branches read as peers. A pill fills the composer instead of sending.
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
- **The Brain's halo could not be scaled by any stylesheet.** `LivingBrain`
|
|
36
|
+
writes the aura's `box-shadow` inline, so a `.brain-hero-organism .brain-aura`
|
|
37
|
+
rule had no effect and a 60px blur stayed around a 58px organism, clipped into
|
|
38
|
+
a flat smudge. The blur reads `var(--aura-blur, 60px)`; the banner sets 14px.
|
|
39
|
+
Every other host is pixel-identical through the fallback.
|
|
40
|
+
- **`aria-label` on a plain `<div>` was being discarded.** The suggestion block
|
|
41
|
+
reached assistive tech unnamed. The label moved to the deck's `<section>`
|
|
42
|
+
(named ⇒ `region`); the inner strip carries none.
|
|
43
|
+
- **Reduced motion stopped covering the suggestion cards.** `affordance.css`'s
|
|
44
|
+
hover-lift and `prefers-reduced-motion` selectors still named
|
|
45
|
+
`.brain-home-prompt-strip > button`, which matches nothing after the grid; they
|
|
46
|
+
are re-pointed at `.brain-prompt-grid button`. The `white-space` opt-in entry
|
|
47
|
+
is deliberately not re-added — `home-simple.css` flips those cards to `nowrap`
|
|
48
|
+
chips under 900px and a matching selector in the last-loaded sheet would win
|
|
49
|
+
that media rule.
|
|
50
|
+
- **The station must not clip.** `overflow: hidden` there would hide the capture
|
|
51
|
+
popover (anchored to the toolbar, opening below it) and make the card a scroll
|
|
52
|
+
container that scrolls the greeting away on focus. The station stays visible;
|
|
53
|
+
the banner uses `overflow: clip` and rounds its own top corners.
|
|
54
|
+
|
|
55
|
+
### Tests
|
|
56
|
+
- `BrainHome.test.tsx`: station/deck/quiet are direct siblings of the stage in
|
|
57
|
+
order; the station contains neither the strip nor the deck; the deck is a named
|
|
58
|
+
`region` and the inner strip is unlabelled; the starter-pill branch renders.
|
|
59
|
+
- `tests/visual/v3.spec.js`: the popover opens unclipped without scrolling the
|
|
60
|
+
station; the grid fills ≥98% of the deck's inner width; the cards stay visible
|
|
61
|
+
and become chips at 900/760/640/420px; reduced motion drops both `transform`
|
|
62
|
+
and `transition` while hover still answers in colour; the aura's blur is
|
|
63
|
+
measured against the organism and its box against the banner.
|
|
64
|
+
|
|
65
|
+
## [10.6.1] - 2026-08-03
|
|
66
|
+
|
|
67
|
+
The second half of the layout rebuild. 10.6.0 promoted one panel per main screen
|
|
68
|
+
and left five screens untouched: sign-in, the recommended model, the Brain home,
|
|
69
|
+
the automation runs list, and the review center. Each of those now opens on the
|
|
70
|
+
one thing it exists for, with everything else grouped beneath it. No feature was
|
|
71
|
+
removed. Backend behaviour is unchanged; `frontend/openapi.json` differs from
|
|
72
|
+
10.6.0 only in `info.version`.
|
|
73
|
+
|
|
74
|
+
### Changed
|
|
75
|
+
- **Login is one card.** The three-card promise bar moved from between the
|
|
76
|
+
greeting and the form to a quiet hairline strip below it
|
|
77
|
+
(`.ritual-promise.is-quiet`), leaving the form as the only raised surface. The
|
|
78
|
+
password-stays-local note and the existing-Brain note now read after the
|
|
79
|
+
submit button instead of between the last field and it.
|
|
80
|
+
- **The recommendation screen names its top pick once.** The duplicate CTA above
|
|
81
|
+
the list is gone; rank, size, name, reason, time estimate and the action live
|
|
82
|
+
in one `.ritual-primary-hero-card`, with the other two models under a labelled
|
|
83
|
+
`다른 선택지` grid as `.ritual-model-card.is-compact`. The footer splits 뒤로 to
|
|
84
|
+
one end and the hint + 모델 없이 Brain 열기 to the other.
|
|
85
|
+
- **The Brain home leads with the composer.** It gained its own bordered wrapper
|
|
86
|
+
and focus ring; the suggestion strip moved directly under it and became a card
|
|
87
|
+
grid that shows each suggestion's detail line (previously `title`-only); the
|
|
88
|
+
add-material dock and the autonomy dial dropped to the station floor as one
|
|
89
|
+
toolbar; the past-conversation count reads as a badge.
|
|
90
|
+
- **The runs tab stacks by urgency.** `승인함` moved from the bottom to the top
|
|
91
|
+
with an attention treatment (`.data-panel.is-attention`), installed automations
|
|
92
|
+
became visible from this tab with their last run — mode, result, timestamp,
|
|
93
|
+
summary — inside the card, and the agent and workflow run tables moved to the
|
|
94
|
+
end as history.
|
|
95
|
+
- **A review item is evidence beside a decision.** `ReviewCard` splits into a
|
|
96
|
+
7/5 grid: proposal diff, snooze state, risk/class/tool provenance and the
|
|
97
|
+
technical `<details>` on the left; an always-visible decision panel with
|
|
98
|
+
approve / reject / snooze / run-now and the reject reason on the right. Items
|
|
99
|
+
with no evidence render as a single column instead of an empty left half.
|
|
100
|
+
|
|
101
|
+
### Accessibility
|
|
102
|
+
- Login: `<label for>` on every field, form named by the page heading,
|
|
103
|
+
`aria-invalid` + `aria-describedby` wired to the error only once it exists.
|
|
104
|
+
- Recommendation: hero card labelled by the model name it recommends.
|
|
105
|
+
- Brain home: greeting is the page `<h1>`; station header and footer scoped so
|
|
106
|
+
they do not register as page landmarks; suggestion strip and station toolbar
|
|
107
|
+
carry accessible names.
|
|
108
|
+
- Review: each item is an `<article>` named by its `<h3>`, the decision block is
|
|
109
|
+
an `<h4>`, the approve/reject cluster is a named `role="group"`, and the status
|
|
110
|
+
and source filters have visible captions referenced by `aria-labelledby`.
|
|
111
|
+
|
|
112
|
+
### Fixed
|
|
113
|
+
- `p-6` on the Brain home stage added padding on top of children that already
|
|
114
|
+
pad themselves and pushed the quiet shelves under the fixed mobile nav, where
|
|
115
|
+
the tap hit the nav. The project's stylesheets are unlayered and therefore beat
|
|
116
|
+
Tailwind's `@layer utilities` for properties they set — but not for properties
|
|
117
|
+
they leave unset, which is why this one applied.
|
|
118
|
+
`frontend/src/styles/cssLayering.test.ts` asserts the project ships no
|
|
119
|
+
`@layer`, which is what makes that rule hold.
|
|
120
|
+
- The installed-automations empty state pointed at "the suggestions above" from
|
|
121
|
+
a tab that has none above it; `act.installed.empty` now names the 레시피 tab in
|
|
122
|
+
both languages.
|
|
123
|
+
|
|
124
|
+
### Tests
|
|
125
|
+
- New: `LoginScreen.test.tsx`, `RecommendationScreen.test.tsx`,
|
|
126
|
+
`BrainHome.test.tsx`, `ReviewCard.test.tsx`, `ReviewInbox.test.tsx`,
|
|
127
|
+
`cssLayering.test.ts`; `Act.test.tsx` gained runs-tab ordering coverage.
|
|
128
|
+
- `tests/visual/mock_server.cjs` serves `/api/proposals/counts`, two installed
|
|
129
|
+
automations with last-run detail, and a `change_proposal` review item with a
|
|
130
|
+
real diff — without them the promoted approval block and the new evidence
|
|
131
|
+
column are captured empty.
|
|
132
|
+
|
|
7
133
|
## [10.6.0] - 2026-08-03
|
|
8
134
|
|
|
9
135
|
A layout rebuild, not a copy pass. Every main screen used to open as a row of
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Community And Plugins
|
|
2
2
|
|
|
3
|
-
Current release: **10.6.
|
|
3
|
+
Current release: **10.6.2 — Ask First**.
|
|
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: **10.6.
|
|
6
|
+
Current release: **10.6.2 — Ask First**.
|
|
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
|
package/docs/ONBOARDING.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Lattice AI Onboarding
|
|
2
2
|
|
|
3
|
-
Current release: **10.6.
|
|
3
|
+
Current release: **10.6.2 — Ask First**.
|
|
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
|
package/docs/OPERATIONS.md
CHANGED
package/docs/TRUST_MODEL.md
CHANGED
package/docs/WHY_LATTICE.md
CHANGED
package/docs/kg-schema.md
CHANGED
|
@@ -158,6 +158,21 @@ class KnowledgeGraphCore:
|
|
|
158
158
|
) -> List[str]:
|
|
159
159
|
raise NotImplementedError
|
|
160
160
|
|
|
161
|
+
# ── retrieval_vector.py: derived vector index ────────────────────────────
|
|
162
|
+
def rebuild_vector_index(
|
|
163
|
+
self,
|
|
164
|
+
*,
|
|
165
|
+
full: bool = False,
|
|
166
|
+
include_nodes: bool = True,
|
|
167
|
+
include_chunks: bool = True,
|
|
168
|
+
) -> Dict[str, Any]:
|
|
169
|
+
"""Re-derive the vector index; also records the embedder fingerprint."""
|
|
170
|
+
raise NotImplementedError
|
|
171
|
+
|
|
172
|
+
def vector_freshness(self) -> Dict[str, Any]:
|
|
173
|
+
"""``{status, pending_items, total_items, detail}`` — never raises."""
|
|
174
|
+
raise NotImplementedError
|
|
175
|
+
|
|
161
176
|
# ── retrieval_reads.py: workspace scoping ────────────────────────────────
|
|
162
177
|
def filter_scoped_nodes(
|
|
163
178
|
self,
|
|
@@ -217,8 +217,10 @@ class KnowledgeGraphProvenanceMixin(_Core):
|
|
|
217
217
|
include_legacy_global: bool = False,
|
|
218
218
|
) -> Dict[str, Any]:
|
|
219
219
|
"""Raw, lossless logical export of the graph (nodes/edges/chunks/sources/
|
|
220
|
-
provenance). Vector embeddings are intentionally omitted —
|
|
221
|
-
re-
|
|
220
|
+
provenance). Vector embeddings are intentionally omitted — the importer
|
|
221
|
+
re-derives them with *its own* embedder (:meth:`import_graph_data`
|
|
222
|
+
embeds on write and then reindexes, reporting the result under
|
|
223
|
+
``index``) — so the artifact stays portable and small. Use
|
|
222
224
|
:meth:`backup_database` for a faithful binary copy incl. embeddings.
|
|
223
225
|
|
|
224
226
|
``workspace_id`` REALLY filters (v4): the artifact contains only nodes
|
|
@@ -274,15 +276,68 @@ class KnowledgeGraphProvenanceMixin(_Core):
|
|
|
274
276
|
data["counts"] = {k: len(v) for k, v in data.items()}
|
|
275
277
|
return data
|
|
276
278
|
|
|
279
|
+
def _reindex_after_import(self) -> Dict[str, Any]:
|
|
280
|
+
"""Bring the vector index in line with what was just imported.
|
|
281
|
+
|
|
282
|
+
A logical artifact carries no embeddings (see :meth:`export_graph_data`)
|
|
283
|
+
so they have to be re-derived on this machine. The write door
|
|
284
|
+
(``_upsert_node`` / ``_upsert_chunk``) already embeds inline, which
|
|
285
|
+
makes this pass a *verification* in the common case — but "the index is
|
|
286
|
+
consistent after an import" has to be a guarantee the import makes, not
|
|
287
|
+
an accident of where the embedding call happens to live. It also
|
|
288
|
+
records the embedder fingerprint, which the inline write path never
|
|
289
|
+
does; without it ``index_status()`` reports ``recorded: None`` and the
|
|
290
|
+
``stale_embedder`` honesty signal is dead after every import.
|
|
291
|
+
|
|
292
|
+
Never raises. The graph rows are already committed at this point, so an
|
|
293
|
+
embedding provider that dies here means "content imported, recall
|
|
294
|
+
degraded" — reported with the repo's existing ``vector_freshness``
|
|
295
|
+
vocabulary (``ready`` / ``pending`` / ``stale_embedder`` /
|
|
296
|
+
``unavailable``) plus an explicit ``degraded`` flag — never a rollback
|
|
297
|
+
of work that already landed, and never a silent success.
|
|
298
|
+
"""
|
|
299
|
+
reindexed = 0
|
|
300
|
+
try:
|
|
301
|
+
outcome = self.rebuild_vector_index(full=False) or {}
|
|
302
|
+
reindexed = int(outcome.get("items_indexed") or 0)
|
|
303
|
+
except Exception as exc: # noqa: BLE001 — the import already committed
|
|
304
|
+
return {
|
|
305
|
+
"status": "unavailable",
|
|
306
|
+
"degraded": True,
|
|
307
|
+
"detail": (
|
|
308
|
+
"imported content is stored, but the vector index could not "
|
|
309
|
+
f"be rebuilt ({exc}); search stays lexical-only for the new "
|
|
310
|
+
"items until a rebuild succeeds"
|
|
311
|
+
),
|
|
312
|
+
"reindexed_items": 0,
|
|
313
|
+
}
|
|
314
|
+
report = self.vector_freshness() or {}
|
|
315
|
+
status = str(report.get("status") or "unavailable")
|
|
316
|
+
return {
|
|
317
|
+
"status": status,
|
|
318
|
+
"degraded": status != "ready",
|
|
319
|
+
"detail": report.get("detail"),
|
|
320
|
+
"pending_items": int(report.get("pending_items") or 0),
|
|
321
|
+
"total_items": int(report.get("total_items") or 0),
|
|
322
|
+
"reindexed_items": reindexed,
|
|
323
|
+
}
|
|
324
|
+
|
|
277
325
|
def import_graph_data(
|
|
278
326
|
self, data: Dict[str, Any], *, mode: str = "merge", dry_run: bool = False
|
|
279
327
|
) -> Dict[str, Any]:
|
|
280
328
|
"""Import a logical export back into the store.
|
|
281
329
|
|
|
282
330
|
``mode='merge'`` upserts on top of existing data (id collisions update);
|
|
283
|
-
``mode='replace'`` clears the graph first
|
|
284
|
-
|
|
285
|
-
|
|
331
|
+
``mode='replace'`` clears the graph first (including the derived vector
|
|
332
|
+
rows — the re-import re-embeds them inside the same transaction, so a
|
|
333
|
+
failed artifact rolls back to the previous index rather than an empty
|
|
334
|
+
one). ``dry_run=True`` reports the plan without writing. Refuses
|
|
335
|
+
artifacts from a NEWER graph schema than this build.
|
|
336
|
+
|
|
337
|
+
A completed import carries an ``index`` block reporting the state of
|
|
338
|
+
the re-derived vector index (see :meth:`_reindex_after_import`); when
|
|
339
|
+
``index["degraded"]`` is true, retrieval for the imported scope is
|
|
340
|
+
lexical-only until the index is rebuilt.
|
|
286
341
|
"""
|
|
287
342
|
nodes = data.get("nodes") or []
|
|
288
343
|
edges = data.get("edges") or []
|
|
@@ -418,6 +473,7 @@ class KnowledgeGraphProvenanceMixin(_Core):
|
|
|
418
473
|
),
|
|
419
474
|
)
|
|
420
475
|
plan["imported"] = True
|
|
476
|
+
plan["index"] = self._reindex_after_import()
|
|
421
477
|
return plan
|
|
422
478
|
|
|
423
479
|
def backup_database(self, dest_path) -> Path:
|
|
@@ -454,17 +454,25 @@ class KnowledgeGraphRetrievalMixin(_Core):
|
|
|
454
454
|
mode = "hybrid"
|
|
455
455
|
detail: Optional[str] = None
|
|
456
456
|
vector_matches: List[Dict[str, Any]] = []
|
|
457
|
+
vector_recall: Optional[Dict[str, Any]] = None
|
|
457
458
|
vector_fn = getattr(self, "vector_search", None)
|
|
458
459
|
if not callable(vector_fn):
|
|
459
460
|
mode = "lexical_only"
|
|
460
461
|
detail = "vector search is not available on this store"
|
|
461
462
|
else:
|
|
462
463
|
try:
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
)
|
|
464
|
+
vector_payload = (
|
|
465
|
+
vector_fn(search_query, limit=vec_fetch, min_score=min_vector_score)
|
|
466
|
+
or {}
|
|
467
467
|
)
|
|
468
|
+
vector_matches = list(vector_payload.get("matches", []))
|
|
469
|
+
# Partial recall must reach the caller: the vector channel can
|
|
470
|
+
# only score a capped slice of a large index (see
|
|
471
|
+
# retrieval_vector.vector_search), and a fused answer built on
|
|
472
|
+
# a truncated scan is not the same claim as a complete one.
|
|
473
|
+
recall = vector_payload.get("recall")
|
|
474
|
+
if isinstance(recall, dict) and recall.get("truncated"):
|
|
475
|
+
vector_recall = dict(recall)
|
|
468
476
|
except Exception as exc: # noqa: BLE001 — degrade, never fail the search
|
|
469
477
|
mode = "lexical_only"
|
|
470
478
|
detail = f"vector index unavailable: {exc}"
|
|
@@ -619,6 +627,10 @@ class KnowledgeGraphRetrievalMixin(_Core):
|
|
|
619
627
|
}
|
|
620
628
|
if vector_degraded is not None:
|
|
621
629
|
result["vector_degraded"] = vector_degraded
|
|
630
|
+
if vector_recall is not None:
|
|
631
|
+
result["vector_recall"] = vector_recall
|
|
632
|
+
if vector_degraded is None:
|
|
633
|
+
result["vector_degraded"] = "partial_recall"
|
|
622
634
|
return result
|
|
623
635
|
|
|
624
636
|
def context_for_query(
|