ltcai 11.5.0 → 11.5.1
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 +25 -18
- package/docs/CHANGELOG.md +22 -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/docs/v11.5.1_RUST_FULL_LOOP_PLAN.md +85 -0
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/agent_worker_seam.py +389 -0
- package/latticeai/core/legacy_compatibility.py +1 -1
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/messages.py +35 -0
- package/latticeai/core/workspace_os_constants.py +1 -1
- package/latticeai/runtime/build_phases/features.py +23 -2
- package/latticeai/services/architecture_readiness.py +1 -1
- package/latticeai/services/product_readiness.py +1 -1
- package/package.json +1 -1
- package/scripts/check_current_release_docs.mjs +1 -1
- package/scripts/check_server_i18n.mjs +1 -0
- package/scripts/generate_agent_loop_fixtures.py +907 -0
- package/scripts/generate_rust_parity_fixtures.py +70 -67
- package/scripts/parity_fixture_corpus_docgen.py +341 -0
- package/scripts/release_screen_claims.json +10 -0
- package/src-tauri/Cargo.lock +13 -7
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +41 -41
- package/static/app/assets/{Act-CWnxSCgN.js → Act-Drs_jd-O.js} +1 -1
- package/static/app/assets/{AdminConsole-BEQYU6kF.js → AdminConsole-BqNx5oF6.js} +1 -1
- package/static/app/assets/{Brain-DWu1BhFg.js → Brain-C7bdNmz-.js} +1 -1
- package/static/app/assets/{BrainHome-95Hilr9R.js → BrainHome-DcTnINcI.js} +1 -1
- package/static/app/assets/{BrainSignals-QdeqCpAF.js → BrainSignals-Df1MRIPD.js} +1 -1
- package/static/app/assets/{Capture-BHpCxnzb.js → Capture-Dgsxvnbx.js} +1 -1
- package/static/app/assets/{Chronicle-B4xYKoed.js → Chronicle-BrkTxJK1.js} +1 -1
- package/static/app/assets/{CommandPalette-BVXnttSz.js → CommandPalette-DDziw7Oj.js} +1 -1
- package/static/app/assets/{Library-DgYcHome.js → Library-CYxeuraA.js} +1 -1
- package/static/app/assets/{LivingBrain-CrJLDbf7.js → LivingBrain-CNp6mvCm.js} +1 -1
- package/static/app/assets/{ProductFlow-DFlScKoJ.js → ProductFlow-BVsowu3Z.js} +1 -1
- package/static/app/assets/{ReviewCard-Cy5f48Pj.js → ReviewCard-D1LbOfJS.js} +1 -1
- package/static/app/assets/{System-NF8IfhTa.js → System-DcRAq7wj.js} +1 -1
- package/static/app/assets/arrow-left-BHYmOTWU.js +1 -0
- package/static/app/assets/{bot-CucuhLhm.js → bot-BK2xQ9mN.js} +1 -1
- package/static/app/assets/{brain-BBnSryW_.js → brain-BZNztFBb.js} +1 -1
- package/static/app/assets/{button-C2GUj2Ai.js → button-CjueubVZ.js} +1 -1
- package/static/app/assets/circle-check-CLeWJr67.js +1 -0
- package/static/app/assets/{circle-pause-CbkWzBmG.js → circle-pause-HRjSmpyY.js} +1 -1
- package/static/app/assets/{circle-play-7lEaqHdJ.js → circle-play-CMcKDVwu.js} +1 -1
- package/static/app/assets/{cpu-DAlCXlIy.js → cpu-B_MyTfYr.js} +1 -1
- package/static/app/assets/{download-RNhuuJwh.js → download-CTy0EByV.js} +1 -1
- package/static/app/assets/{folder-open-CLW4odzM.js → folder-open-DF6bLhTg.js} +1 -1
- package/static/app/assets/{hard-drive-NKEiDIAJ.js → hard-drive-CpWHG77C.js} +1 -1
- package/static/app/assets/{index-DMurvUuR.js → index-Dd6abJHX.js} +3 -3
- package/static/app/assets/index-DxmOfNRi.css +2 -0
- package/static/app/assets/{input-D2UhPC1X.js → input-bVgIRN3s.js} +1 -1
- package/static/app/assets/{link-2-6amKbP_P.js → link-2-bg6CG5Vk.js} +1 -1
- package/static/app/assets/{permissionCopy-Cu9TZtdR.js → permissionCopy-DFTf1HDZ.js} +1 -1
- package/static/app/assets/{primitives-gPsccucr.js → primitives-D7D-sQ3T.js} +1 -1
- package/static/app/assets/search-BgSVX6NG.js +1 -0
- package/static/app/assets/{share-2-Bau7KkPq.js → share-2-BLzo7U4L.js} +1 -1
- package/static/app/assets/{shield-alert-BufNYypi.js → shield-alert-BmngqnsJ.js} +1 -1
- package/static/app/assets/{textarea-BQnVWhYs.js → textarea-DOSlAQQ3.js} +1 -1
- package/static/app/assets/{useFocusTrap-B3_w60si.js → useFocusTrap-pZhgeee4.js} +1 -1
- package/static/app/assets/{useMutation-BHhCflT6.js → useMutation-BMDwNk4I.js} +1 -1
- package/static/app/assets/{useQuery-rBWfI-5t.js → useQuery-CSjKttRo.js} +1 -1
- package/static/app/assets/{utils-V_5-wxr5.js → utils-D3u_yv7B.js} +1 -1
- package/static/app/assets/{workspace-K1zjYUHj.js → workspace-H3bMjYXC.js} +1 -1
- package/static/app/index.html +4 -4
- package/static/sw.js +1 -1
- package/static/app/assets/arrow-left-DwkSYrjR.js +0 -1
- package/static/app/assets/circle-check-CxOVPwYq.js +0 -1
- package/static/app/assets/index-BLPb5lmE.css +0 -2
- package/static/app/assets/search-Cj_TKk_2.js +0 -1
|
@@ -6,27 +6,23 @@ something keeps proving it is still one. This script is the Python half of that
|
|
|
6
6
|
proof: it builds a small, fully deterministic Brain with the **real** write path
|
|
7
7
|
(``KnowledgeGraphStore._upsert_node`` / ``_upsert_chunk`` / ``_upsert_edge``,
|
|
8
8
|
the real hash embedder, the real v2 projection and trigram FTS index), then runs
|
|
9
|
-
the real
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Determinism is the whole design constraint: every timestamp is written by the
|
|
27
|
-
real code and then **backdated**; the two ``datetime.now()`` calls the ports
|
|
28
|
-
reach are frozen at :data:`FROZEN_NOW` (recorded in the manifest); LLM concept
|
|
29
|
-
extraction is forced off; every environment knob is pinned to its default.
|
|
9
|
+
the real engines over it and writes their answers to ``rust/fixtures/golden/``.
|
|
10
|
+
The suite set widens with the port (:data:`SUITES`): the search engines
|
|
11
|
+
(v11.4.0); the KG relationship/traverse reads, the service layer, the durable
|
|
12
|
+
history reads and the context assembler (v11.5.0); the document-generation
|
|
13
|
+
search, traversal and context builder (v11.5.1, whose corpus and runners live
|
|
14
|
+
in ``scripts/parity_fixture_corpus_docgen.py``).
|
|
15
|
+
|
|
16
|
+
Two consumers read what it writes: ``tests/unit/test_rust_parity_contract.py``
|
|
17
|
+
re-runs the Python entry points against the committed database and asserts the
|
|
18
|
+
goldens still hold — so a change to Python semantics fails loudly instead of
|
|
19
|
+
silently invalidating the contract the Rust side is pinned to — and
|
|
20
|
+
``rust/lattice-retrieval/tests/{parity,suites}.rs`` run the Rust ports against
|
|
21
|
+
the same database and the same goldens. Determinism is the whole design
|
|
22
|
+
constraint: every timestamp is written by the real code and then **backdated**;
|
|
23
|
+
every ``datetime.now()`` the ports reach is frozen at :data:`FROZEN_NOW`
|
|
24
|
+
(recorded in the manifest); LLM concept extraction is forced off; every
|
|
25
|
+
environment knob is pinned to its default.
|
|
30
26
|
|
|
31
27
|
Usage::
|
|
32
28
|
|
|
@@ -47,8 +43,14 @@ from pathlib import Path
|
|
|
47
43
|
from typing import Any, Callable, Dict, Iterator, List, Optional, Tuple
|
|
48
44
|
|
|
49
45
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
# The repo (for the product packages) and this directory: `scripts` is not a
|
|
47
|
+
# package, so the docgen corpus is imported by name off the script directory —
|
|
48
|
+
# the same by-path convention the contract test uses to import this file.
|
|
49
|
+
for _import_root in (REPO_ROOT, Path(__file__).resolve().parent):
|
|
50
|
+
if str(_import_root) not in sys.path:
|
|
51
|
+
sys.path.insert(0, str(_import_root))
|
|
52
|
+
|
|
53
|
+
import parity_fixture_corpus_docgen as docgen # noqa: E402
|
|
52
54
|
|
|
53
55
|
FIXTURE_DIR = REPO_ROOT / "rust" / "fixtures"
|
|
54
56
|
GOLDEN_DIR = FIXTURE_DIR / "golden"
|
|
@@ -80,11 +82,11 @@ WS_BETA = "ws-beta"
|
|
|
80
82
|
# (node_id, type, title, summary, metadata, workspace_id, updated_at)
|
|
81
83
|
#
|
|
82
84
|
# Shaped on purpose: every ``type_boost`` type appears and so do types outside it;
|
|
83
|
-
# titles/summaries are half Korean (
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
85
|
+
# titles/summaries are half Korean (tokenizer, classifier and extractor all branch
|
|
86
|
+
# on script); the ``tie:`` block is five rows sharing one timestamp, one type and
|
|
87
|
+
# nothing to match, pinning the (hits, boost, updated_at) → id ASC tie-break; two
|
|
88
|
+
# workspaces plus NULL-workspace rows cover all three scoping answers (no scoping
|
|
89
|
+
# / empty set / a specific workspace). The v11.5.1 tail is in the docgen corpus.
|
|
88
90
|
NODES: List[Tuple[str, str, str, str, Dict[str, Any], Optional[str], str]] = [
|
|
89
91
|
("dec:fusion-alpha", "Decision", "Hybrid retrieval fusion stays alpha weighted",
|
|
90
92
|
"We decided the ranking keeps alpha fusion: lexical rank plus max normalized vector score.",
|
|
@@ -186,14 +188,14 @@ NODES: List[Tuple[str, str, str, str, Dict[str, Any], Optional[str], str]] = [
|
|
|
186
188
|
("legacy:global-note", "Document", "Legacy global note",
|
|
187
189
|
"A legacy row with no workspace, visible only with include_legacy_global.",
|
|
188
190
|
{}, None, "2026-06-20T10:00:00"),
|
|
191
|
+
*docgen.DOCGEN_NODES,
|
|
189
192
|
]
|
|
190
193
|
|
|
191
194
|
# (chunk_id, parent_node_id, index, node_title, text, chunk_fields, workspace, updated_at)
|
|
192
195
|
#
|
|
193
196
|
# The shape mirrors ``KnowledgeGraphIngestMixin``: every chunk is BOTH a ``Chunk``
|
|
194
|
-
# node (lexical lane + workspace scoping) and a ``chunks`` row with its own
|
|
195
|
-
#
|
|
196
|
-
# the whole reason chunk-heavy queries are in the query set.
|
|
197
|
+
# node (lexical lane + workspace scoping) and a ``chunks`` row with its own embedding
|
|
198
|
+
# (vector lane, rolled up to its parent) — the duality chunk-heavy queries pin.
|
|
197
199
|
CHUNKS: List[Tuple[str, str, int, str, str, Dict[str, Any], Optional[str], str]] = [
|
|
198
200
|
("chunk:handbook:1", "doc:handbook", 0, "handbook.pdf chunk 1",
|
|
199
201
|
"온보딩 체크리스트: 첫째, 폴더를 연결합니다. 둘째, 질문을 합니다. 셋째, 근거를 확인합니다.",
|
|
@@ -218,10 +220,10 @@ CHUNKS: List[Tuple[str, str, int, str, str, Dict[str, Any], Optional[str], str]]
|
|
|
218
220
|
# orders by ``weight DESC, created_at DESC, id ASC`` and ``traverse`` caps every BFS
|
|
219
221
|
# round with ``ORDER BY weight DESC, id ASC``, so an edge set sharing one weight and
|
|
220
222
|
# one clock proves nothing. Three shapes are deliberate — a weight tie broken by
|
|
221
|
-
# ``created_at`` (
|
|
222
|
-
#
|
|
223
|
-
#
|
|
224
|
-
#
|
|
223
|
+
# ``created_at`` (``org:lattice``), a weight *and* clock tie broken by edge id
|
|
224
|
+
# (``topic:quality``/``deck:review``), and legacy-global endpoints for scoping. The
|
|
225
|
+
# write door canonicalizes types (``relates_to``/``owns`` → ``MENTIONS``), which is
|
|
226
|
+
# why the goldens record uppercase names the fixture never spells.
|
|
225
227
|
EDGES: List[Tuple[str, str, str, float, str]] = [
|
|
226
228
|
("dec:fusion-alpha", "concept:retrieval", "mentions", 0.9, "2026-07-01T00:00:00"),
|
|
227
229
|
("dec:fusion-alpha", "concept:ranking", "mentions", 0.8, "2026-07-02T00:00:00"),
|
|
@@ -246,6 +248,7 @@ EDGES: List[Tuple[str, str, str, float, str]] = [
|
|
|
246
248
|
("task:onboarding-checklist", "page:onboarding", "relates_to", 0.15, "2026-05-01T00:00:00"),
|
|
247
249
|
("doc:handbook", "doc:retrieval-spec", "relates_to", 0.1, "2026-05-02T00:00:00"),
|
|
248
250
|
("tie:a", "tie:b", "relates_to", 1.0, "2026-07-03T00:00:00"),
|
|
251
|
+
*docgen.DOCGEN_EDGES,
|
|
249
252
|
]
|
|
250
253
|
|
|
251
254
|
# ── the conversation corpus (episodic memory, same database file) ────────────
|
|
@@ -257,7 +260,7 @@ EDGES: List[Tuple[str, str, str, float, str]] = [
|
|
|
257
260
|
# ``conversation_id`` (the ``legacy-previous-history`` bucket), a whitespace-only
|
|
258
261
|
# first message (the ``새 대화`` placeholder and its later upgrade), an
|
|
259
262
|
# assistant-first conversation (no upgrade), an empty timestamp (the ``or ""``
|
|
260
|
-
# fallbacks), extra keys ``metadata_json`` merges flat,
|
|
263
|
+
# fallbacks), extra keys ``metadata_json`` merges flat, ko/en content.
|
|
261
264
|
MESSAGES: List[Tuple[Any, ...]] = [
|
|
262
265
|
("conv-a", "user", "온보딩 체크리스트 어떻게 시작해?", "jiwon@lattice.ai", "지원", "web", "2026-07-20T09:00:00", WS_ALPHA, "org-1", {}),
|
|
263
266
|
("conv-a", "assistant", "먼저 폴더를 연결하세요. 그다음 질문하면 됩니다.", "jiwon@lattice.ai", None, "web", "2026-07-20T09:00:05", WS_ALPHA, "org-1", {}),
|
|
@@ -307,17 +310,15 @@ QUERIES: List[Dict[str, Any]] = [
|
|
|
307
310
|
{"key": "ws_alpha", "query": "hybrid retrieval ranking", "allowed": [WS_ALPHA]},
|
|
308
311
|
{"key": "ws_alpha_legacy", "query": "회의 결정 사항", "allowed": [WS_ALPHA], "legacy": True},
|
|
309
312
|
{"key": "ws_beta", "query": "온보딩 체크리스트", "allowed": [WS_BETA]},
|
|
310
|
-
# A vector floor nothing clears
|
|
311
|
-
#
|
|
313
|
+
# A vector floor nothing clears: the stale-embedder probe and the
|
|
314
|
+
# lexical-only fusion label, without breaking the store.
|
|
312
315
|
{"key": "min_vector_floor", "query": "hybrid retrieval ranking", "min_vector": 0.95},
|
|
313
316
|
# top_k small enough that the rerank window (top_k * 2) cuts the candidates.
|
|
314
317
|
{"key": "top_k_small", "query": "hybrid retrieval ranking", "top_k": 3},
|
|
315
|
-
# Pinned alpha: no policy, so no class
|
|
316
|
-
# query that would otherwise be recency-classed.
|
|
318
|
+
# Pinned alpha: no policy, so no class/rewrite/age decay on a recency query.
|
|
317
319
|
{"key": "alpha_pinned", "query": "지난주 회의 기록", "alpha": 0.2},
|
|
318
|
-
# A limit below the FTS hit count, so `ORDER BY rank LIMIT ?` decides which
|
|
319
|
-
#
|
|
320
|
-
# version difference between the two runtimes) is observable.
|
|
320
|
+
# A limit below the FTS hit count, so `ORDER BY rank LIMIT ?` decides which rows
|
|
321
|
+
# exist at all — the one place bm25 ordering (a SQLite version difference) shows.
|
|
321
322
|
{"key": "fts_rank_cut", "query": "Tie candidate", "limit": 2, "top_k": 2},
|
|
322
323
|
]
|
|
323
324
|
|
|
@@ -403,8 +404,8 @@ SUITES: Dict[str, List[Dict[str, Any]]] = {
|
|
|
403
404
|
{"key": "en_code", "query": "vector_search() returns"},
|
|
404
405
|
{"key": "ko_person", "query": "담당자 누구"},
|
|
405
406
|
{"key": "en_filler", "query": " what is the retrieval specification please "},
|
|
406
|
-
# Explicit weights disable BOTH
|
|
407
|
-
#
|
|
407
|
+
# Explicit weights disable BOTH rewrite and age decay on a query that
|
|
408
|
+
# would otherwise get both — that asymmetry is the contract.
|
|
408
409
|
{"key": "pinned_recency", "query": "지난주 회의 기록", "weights": {"keyword": 0.5, "vector": 0.3, "graph": 0.2}},
|
|
409
410
|
{"key": "pinned_partial", "query": "hybrid retrieval ranking", "weights": {"graph": 1.0}},
|
|
410
411
|
{"key": "pinned_zero", "query": "회의 결정 사항", "weights": {"keyword": 0.0, "vector": 0.0, "graph": 0.0}},
|
|
@@ -476,6 +477,8 @@ SUITES: Dict[str, List[Dict[str, Any]]] = {
|
|
|
476
477
|
{"key": "budget_zero", "query": "회의 결정 사항", "memories": CONTEXT_MEMORIES, "notes": "노트", "budget": 0},
|
|
477
478
|
{"key": "knowledge_limit_one", "query": "hybrid retrieval ranking", "knowledge_limit": 1},
|
|
478
479
|
],
|
|
480
|
+
# v11.5.1: the document-generation ports, specs and runners alike.
|
|
481
|
+
**docgen.DOCGEN_SUITES,
|
|
479
482
|
}
|
|
480
483
|
|
|
481
484
|
#: Texts whose tokenizer output, hashes and vectors pin the embedding port.
|
|
@@ -517,10 +520,12 @@ def pinned_environment() -> Iterator[None]:
|
|
|
517
520
|
def frozen_clock() -> Iterator[None]:
|
|
518
521
|
"""Freeze every ported ``datetime.now()`` at :data:`FROZEN_NOW`.
|
|
519
522
|
|
|
520
|
-
Only the recency
|
|
521
|
-
|
|
522
|
-
|
|
523
|
+
Only the recency decay reads the clock, through the ``datetime`` name its
|
|
524
|
+
module imported, so rebinding that name is the whole patch. Three modules
|
|
525
|
+
reach it: the graph-layer and service-layer ``hybrid_search``, and the
|
|
526
|
+
document-generation search's own 14-day half-life.
|
|
523
527
|
"""
|
|
528
|
+
from lattice_brain.graph import retrieval_docgen as docgen_module
|
|
524
529
|
from lattice_brain.graph.retrieval import hybrid as hybrid_module
|
|
525
530
|
from latticeai.services import search_service as service_module
|
|
526
531
|
|
|
@@ -531,7 +536,7 @@ def frozen_clock() -> Iterator[None]:
|
|
|
531
536
|
def now(cls, tz=None): # noqa: ARG003 — mirrors datetime.now's signature
|
|
532
537
|
return frozen
|
|
533
538
|
|
|
534
|
-
modules = (hybrid_module, service_module)
|
|
539
|
+
modules = (hybrid_module, service_module, docgen_module)
|
|
535
540
|
originals = [module.datetime for module in modules]
|
|
536
541
|
for module in modules:
|
|
537
542
|
module.datetime = _FrozenDatetime
|
|
@@ -546,8 +551,8 @@ def frozen_clock() -> Iterator[None]:
|
|
|
546
551
|
def rules_only_extraction() -> Iterator[None]:
|
|
547
552
|
"""Force ``_topic_candidates`` down its rule-based path.
|
|
548
553
|
|
|
549
|
-
The LLM path needs a bound router no fixture run has, but "no router
|
|
550
|
-
to be bound" is an accident
|
|
554
|
+
The LLM path needs a bound router no fixture run has, but "no router
|
|
555
|
+
happens to be bound" is an accident this contract cannot rest on.
|
|
551
556
|
"""
|
|
552
557
|
from lattice_brain.graph._kg_common import extraction
|
|
553
558
|
|
|
@@ -618,13 +623,12 @@ def build_store(db_path: Path) -> None:
|
|
|
618
623
|
for from_node, to_node, edge_type, weight, stamp in EDGES:
|
|
619
624
|
# ``_upsert_edge`` stamps ``created_at`` from the wall clock in BOTH
|
|
620
625
|
# tables, and the read path is the ``kgv2_edges`` view over ``edges_v2``:
|
|
621
|
-
# backdating only the legacy table
|
|
622
|
-
# the relationship ordering moving with the clock.
|
|
626
|
+
# backdating only the legacy table left the ordering moving with the clock.
|
|
623
627
|
edge_id = store._upsert_edge(conn, from_node, to_node, edge_type, weight, {})
|
|
624
628
|
conn.execute("UPDATE edges SET created_at=? WHERE id=?", (stamp, edge_id))
|
|
625
629
|
conn.execute("UPDATE edges_v2 SET created_at=? WHERE id=?", (stamp, edge_id))
|
|
626
|
-
# ``indexed_at`` decides the candidate scan order (and, when the cap
|
|
627
|
-
# which candidates exist
|
|
630
|
+
# ``indexed_at`` decides the candidate scan order (and, when the cap
|
|
631
|
+
# bites, which candidates exist), so it is assigned rather than inherited.
|
|
628
632
|
item_ids = [row["item_id"] for row in conn.execute(
|
|
629
633
|
"SELECT item_id FROM vector_embeddings ORDER BY item_id ASC"
|
|
630
634
|
).fetchall()]
|
|
@@ -636,8 +640,8 @@ def build_store(db_path: Path) -> None:
|
|
|
636
640
|
store.record_embedder_fingerprint()
|
|
637
641
|
write_conversations(db_path)
|
|
638
642
|
|
|
639
|
-
#
|
|
640
|
-
#
|
|
643
|
+
# One self-contained file: checkpoint the WAL, drop to a rollback journal
|
|
644
|
+
# so no sidecar is committed, and compact.
|
|
641
645
|
with sqlite3.connect(str(db_path)) as conn:
|
|
642
646
|
conn.execute("PRAGMA wal_checkpoint(TRUNCATE)")
|
|
643
647
|
conn.execute("PRAGMA journal_mode=DELETE")
|
|
@@ -678,18 +682,18 @@ def run_engine(store, engine: str, spec: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
678
682
|
return ENGINES[engine](store, spec)
|
|
679
683
|
|
|
680
684
|
|
|
681
|
-
# ── suites (v11.5.0)
|
|
685
|
+
# ── the suites beyond search (v11.5.0/v11.5.1) ───────────────────────────────
|
|
682
686
|
#
|
|
683
687
|
# The Phase-1 engines share one query shape (a query set × an engine set); the
|
|
684
|
-
#
|
|
685
|
-
#
|
|
688
|
+
# later ports do not, so each gets its own spec list and runner, both carried in
|
|
689
|
+
# the manifest so Rust and Python enumerate exactly the same work.
|
|
686
690
|
|
|
687
691
|
|
|
688
692
|
class Harness:
|
|
689
693
|
"""Every Python entry point the v11.5.0 goldens are produced from.
|
|
690
694
|
|
|
691
695
|
``require_auth=False`` is the loopback-owner configuration the native routes
|
|
692
|
-
reproduce: the history scope is whatever the caller passes
|
|
696
|
+
reproduce: the history scope is whatever the caller passes.
|
|
693
697
|
"""
|
|
694
698
|
|
|
695
699
|
def __init__(self, db_path: Path):
|
|
@@ -718,8 +722,7 @@ def _history_scope(spec: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
718
722
|
"""The identity/workspace scope every history read takes.
|
|
719
723
|
|
|
720
724
|
``include_legacy_global`` defaults to ``True`` — ``ConversationStore``'s own
|
|
721
|
-
default, the opposite of the graph layer's and
|
|
722
|
-
gets wrong.
|
|
725
|
+
default, the opposite of the graph layer's and an asymmetry a port gets wrong.
|
|
723
726
|
"""
|
|
724
727
|
allowed = spec.get("allowed")
|
|
725
728
|
return {
|
|
@@ -801,7 +804,7 @@ def _context_seams(h: Harness, spec: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
801
804
|
|
|
802
805
|
``memories`` / ``artifacts`` / ``notes`` are *data* seams: the payload is the
|
|
803
806
|
spec, so both runtimes feed the assembler the same bytes and what is under
|
|
804
|
-
test is the assembler. ``knowledge`` and ``recent`` are real — the
|
|
807
|
+
test is the assembler. ``knowledge`` and ``recent`` are real engines — the
|
|
805
808
|
service-layer hybrid search and the durable history reader.
|
|
806
809
|
"""
|
|
807
810
|
from latticeai.api.chat_helpers import build_recent_chat_context
|
|
@@ -868,6 +871,7 @@ SUITE_RUNNERS: Dict[str, Callable[[Harness, Dict[str, Any]], Any]] = {
|
|
|
868
871
|
"conversation_messages": _run_conversation_messages,
|
|
869
872
|
"history_search": _run_history_search,
|
|
870
873
|
"context_assemble": _run_context_assemble,
|
|
874
|
+
**docgen.DOCGEN_RUNNERS,
|
|
871
875
|
}
|
|
872
876
|
|
|
873
877
|
|
|
@@ -901,7 +905,7 @@ def suite_payload(suite: str, spec: Dict[str, Any], result: Any) -> Dict[str, An
|
|
|
901
905
|
"""One suite golden: the spec that produced it, verbatim, and the answer.
|
|
902
906
|
|
|
903
907
|
The spec rides along rather than being flattened into a fixed ``params``
|
|
904
|
-
block
|
|
908
|
+
block — these entry points share no parameter shape.
|
|
905
909
|
"""
|
|
906
910
|
return {"suite": suite, "key": spec["key"], "spec": spec, "result": result}
|
|
907
911
|
|
|
@@ -982,8 +986,7 @@ def main() -> int:
|
|
|
982
986
|
_dump(GOLDEN_DIR / "embeddings_golden.json", embeddings_golden())
|
|
983
987
|
_dump(GOLDEN_DIR / "rounding_golden.json", rounding_golden())
|
|
984
988
|
_dump(GOLDEN_DIR / "manifest.json", manifest())
|
|
985
|
-
#
|
|
986
|
-
# fixture has no blobs; an empty directory beside an artefact is just noise.
|
|
989
|
+
# The store creates its blob directory eagerly and the fixture has no blobs.
|
|
987
990
|
blob_dir = STORE_PATH.parent / "blobs"
|
|
988
991
|
if blob_dir.is_dir() and not any(blob_dir.iterdir()):
|
|
989
992
|
blob_dir.rmdir()
|