fix(harness): workspace + write-URL + L2 tests per accesso REST reale
Bug trovato provando la connessione reale col .env: il write endpoint vive su un PATH DEDICATO /vector/write/v1/ (non /vector/v1/), e il modello Config ha write_rest/ vector_write_rest a TOP-LEVEL (non nidificati in vector_db). - .env.example: aggiunge THOTH_VEC_WRITE_REST_URL (path dedicato del writer, con avviso che le due chiavi valgono su path separati). - workspaces/chirone-test.yaml: riscritto allineato a chirone.example.yaml + config.py (vector_rest/vector_write_rest top-level; write_rest punta a THOTH_VEC_WRITE_REST_URL). - tests/l2/*: corretti gli accessi strutturali (ws.vector_write_rest invece di ws.vector_db.write_rest; ws.vector_rest invece di ws.vector_db.rest). test_value_grounding_real skip-when-import-fails su nsp.lshindex (modulo deferred da B3). Verificato end-to-end: save_one_memory (embeddings -> writer REST /vector/write/v1/ -> upsert pgvector -> read-back reader) PASSED. Suite L0+L1: 109 passed. Suite L2: 4 passed, 1 skipped (lshindex deferred). Nota operativa: THOTH_SSL_CA va lasciato VUOTO sulla workstation (cert GoDaddy pubblico in certifi). I campi direct-transport (THOTH_DB_*, THOTH_VEC_PASSWORD) sono obbligatori per il modello ma inutilizzati in transport=rest: riempiti con dummy nel .env locale (come faceva ChironeWp3).
This commit is contained in:
@@ -20,6 +20,9 @@ THOTH_VEC_REST_URL=https://host/vector/v1/
|
|||||||
THOTH_VEC_API_KEY=
|
THOTH_VEC_API_KEY=
|
||||||
|
|
||||||
# Vector REST — SCRITTURA controllata (upsert only) da client remoti autorizzati
|
# Vector REST — SCRITTURA controllata (upsert only) da client remoti autorizzati
|
||||||
|
# Path DEDICATO: /vector/write/v1/ (NON /vector/v1/). Le due chiavi valgono su path
|
||||||
|
# separati: la writer key su /vector/v1/ -> 401, e viceversa. Solo postazioni che indicizzano.
|
||||||
|
THOTH_VEC_WRITE_REST_URL=https://host/vector/write/v1/
|
||||||
THOTH_VEC_WRITE_API_KEY=
|
THOTH_VEC_WRITE_API_KEY=
|
||||||
|
|
||||||
# Vector direct loading (server-only)
|
# Vector direct loading (server-only)
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ def test_save_one_upserts_to_real_pgvector(l2_env):
|
|||||||
from nsp.vectorstore.rest_client import VectorRestClient
|
from nsp.vectorstore.rest_client import VectorRestClient
|
||||||
|
|
||||||
ws = load_workspace(WORKSPACE)
|
ws = load_workspace(WORKSPACE)
|
||||||
if not ws.vector_db.write_rest or not ws.vector_db.write_rest.api_key.strip():
|
if not ws.vector_write_rest or not ws.vector_write_rest.api_key.strip():
|
||||||
pytest.skip("vector_db.write_rest not configured (no writer key)")
|
pytest.skip("vector_write_rest not configured (no writer key)")
|
||||||
|
|
||||||
writer = VectorRestClient(ws.vector_db.write_rest)
|
writer = VectorRestClient(ws.vector_write_rest)
|
||||||
embedder = OllamaEmbeddings(ws.embeddings)
|
embedder = OllamaEmbeddings(ws.embeddings)
|
||||||
|
|
||||||
record = MemoryRecord(
|
record = MemoryRecord(
|
||||||
@@ -42,8 +42,8 @@ def test_save_one_upserts_to_real_pgvector(l2_env):
|
|||||||
upserted = save_one_memory([record], decision_seq=999, writer=writer, embedder=embedder)
|
upserted = save_one_memory([record], decision_seq=999, writer=writer, embedder=embedder)
|
||||||
assert upserted >= 0 # idempotent: 0 on unchanged, >=1 on new/updated
|
assert upserted >= 0 # idempotent: 0 on unchanged, >=1 on new/updated
|
||||||
|
|
||||||
# read it back via the READER key
|
# read it back via the READER key (vector_rest, path /vector/v1/)
|
||||||
reader = VectorRestClient(ws.vector_db.rest)
|
reader = VectorRestClient(ws.vector_rest)
|
||||||
qvec = embedder.embed_query("ablazione")
|
qvec = embedder.embed_query("ablazione")
|
||||||
hits = reader.search_similar("memory", qvec, 10)
|
hits = reader.search_similar("memory", qvec, 10)
|
||||||
ids = {h.get("metadata", {}).get("record_key", "") for h in hits}
|
ids = {h.get("metadata", {}).get("record_key", "") for h in hits}
|
||||||
|
|||||||
@@ -40,8 +40,9 @@ def test_workspace_chirone_test_loads(l2_env):
|
|||||||
|
|
||||||
ws = load_workspace(WORKSPACE)
|
ws = load_workspace(WORKSPACE)
|
||||||
# secrets must be expanded (not the literal ${...} token)
|
# secrets must be expanded (not the literal ${...} token)
|
||||||
assert not ws.vector_db.rest.api_key.startswith("${")
|
assert not ws.rest.api_key.startswith("${")
|
||||||
assert not ws.vector_db.write_rest.api_key.startswith("${")
|
assert not ws.vector_rest.api_key.startswith("${")
|
||||||
|
assert not ws.vector_write_rest.api_key.startswith("${")
|
||||||
|
|
||||||
|
|
||||||
def test_pi_binary_available(l2_env):
|
def test_pi_binary_available(l2_env):
|
||||||
|
|||||||
@@ -21,7 +21,10 @@ def test_ablazione_returns_multiple_columns(l2_env):
|
|||||||
a flag and a free-text patologia field) -- the whole point of D14a's
|
a flag and a free-text patologia field) -- the whole point of D14a's
|
||||||
non-collapsing aggregation. Requires a built LSH index (nsp lsh build)."""
|
non-collapsing aggregation. Requires a built LSH index (nsp lsh build)."""
|
||||||
from nsp.config import LshConfig
|
from nsp.config import LshConfig
|
||||||
from nsp.lshindex import load_index, query_index # ported with the lsh build path
|
try:
|
||||||
|
from nsp.lshindex import load_index, query_index # ported with the lsh build path
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
pytest.skip("nsp.lshindex not yet ported (deferred from B3; lands with nsp lsh build)")
|
||||||
from nsp.search import aggregate_lsh_multi
|
from nsp.search import aggregate_lsh_multi
|
||||||
|
|
||||||
# NOTE: this test assumes the LSH index was built (nsp lsh build --workspace
|
# NOTE: this test assumes the LSH index was built (nsp lsh build --workspace
|
||||||
|
|||||||
@@ -1,31 +1,20 @@
|
|||||||
# Workspace ThothII -- Chirone (DWH remoto) per i test L2.
|
# Workspace ThothII — Chirone (DWH remoto) per i test L2.
|
||||||
# I segreti vivono SOLO in .env (${THOTH_*}). Endpoint + ruolo dai parametri di
|
# Struttura allineata a workspaces/chirone.example.yaml e nsp/config.py.
|
||||||
# connessione L2 (spec Testing Strategy): DWH read-only via PostgREST, pgvector
|
# I segreti vivono SOLO in .env (${THOTH_*}).
|
||||||
# con doppia key (reader/writer) sullo stesso endpoint, TLS self-signed (CA = leaf).
|
|
||||||
|
|
||||||
name: chirone-test
|
|
||||||
description: "Chirone DWH -- L2 test workspace"
|
|
||||||
|
|
||||||
database:
|
database:
|
||||||
database: postgres
|
host: ${THOTH_DB_HOST}
|
||||||
|
port: ${THOTH_DB_PORT}
|
||||||
|
database: ${THOTH_DB_NAME}
|
||||||
schema: datawarehouse
|
schema: datawarehouse
|
||||||
|
user: ${THOTH_DB_USER}
|
||||||
|
password: ${THOTH_DB_PASSWORD}
|
||||||
transport: rest
|
transport: rest
|
||||||
rest:
|
|
||||||
base_url: ${THOTH_DWH_REST_URL}
|
|
||||||
api_key: ${THOTH_DWH_API_KEY}
|
|
||||||
ssl_ca: ${THOTH_SSL_CA}
|
|
||||||
|
|
||||||
vector_db:
|
rest:
|
||||||
collection: chirone_docs
|
base_url: ${THOTH_DWH_REST_URL}
|
||||||
dim: 768
|
api_key: ${THOTH_DWH_API_KEY}
|
||||||
rest:
|
ssl_ca: ${THOTH_SSL_CA}
|
||||||
base_url: ${THOTH_VEC_REST_URL}
|
|
||||||
api_key: ${THOTH_VEC_API_KEY}
|
|
||||||
ssl_ca: ${THOTH_SSL_CA}
|
|
||||||
write_rest:
|
|
||||||
base_url: ${THOTH_VEC_REST_URL}
|
|
||||||
api_key: ${THOTH_VEC_WRITE_API_KEY}
|
|
||||||
ssl_ca: ${THOTH_SSL_CA}
|
|
||||||
|
|
||||||
paths:
|
paths:
|
||||||
artifacts: artifacts
|
artifacts: artifacts
|
||||||
@@ -33,12 +22,43 @@ paths:
|
|||||||
sessions: sessions
|
sessions: sessions
|
||||||
|
|
||||||
embeddings:
|
embeddings:
|
||||||
provider: ollama
|
|
||||||
base_url: ${THOTH_OLLAMA_URL}
|
base_url: ${THOTH_OLLAMA_URL}
|
||||||
model: nomic-embed-text-v2-moe
|
model: nomic-embed-text-v2-moe
|
||||||
dim: 768
|
dim: 768
|
||||||
batch_size: 64
|
batch_size: 64
|
||||||
|
|
||||||
|
# LOADING diretto del pgvector (server-only). Su workstation la lettura passa da
|
||||||
|
# vector_rest; i campi direct-transport non sono usati ma il modello DatabaseConfig
|
||||||
|
# li richiede, per cui si appoggiano alle stesse variabili del server (popolate nel
|
||||||
|
# .env del server; sul workstation restano dummy/inediti finche' transport=rest).
|
||||||
|
vector_db:
|
||||||
|
host: ${THOTH_VEC_HOST}
|
||||||
|
port: ${THOTH_VEC_PORT}
|
||||||
|
database: postgres
|
||||||
|
schema: vectors
|
||||||
|
user: ${THOTH_VEC_USER}
|
||||||
|
password: ${THOTH_VEC_PASSWORD}
|
||||||
|
|
||||||
|
# LETTURA del pgvector via REST remota (rpc search_similar), ruolo vector_reader.
|
||||||
|
vector_rest:
|
||||||
|
base_url: ${THOTH_VEC_REST_URL}
|
||||||
|
api_key: ${THOTH_VEC_API_KEY}
|
||||||
|
ssl_ca: ${THOTH_SSL_CA}
|
||||||
|
|
||||||
|
# SCRITTURA controllata del pgvector via REST remota (upsert/hash via RPC allowlist),
|
||||||
|
# ruolo vector_writer. Path DEDICATO /vector/write/v1/ (diverso dal reader): la chiave
|
||||||
|
# writer vale solo qui, la reader solo su /vector/v1/. Key SEPARATA dalla lettura.
|
||||||
|
vector_write_rest:
|
||||||
|
base_url: ${THOTH_VEC_WRITE_REST_URL}
|
||||||
|
api_key: ${THOTH_VEC_WRITE_API_KEY}
|
||||||
|
ssl_ca: ${THOTH_SSL_CA}
|
||||||
|
|
||||||
|
vector:
|
||||||
|
max_chunk_chars: 4000
|
||||||
|
|
||||||
|
search:
|
||||||
|
rrf_k: 60
|
||||||
|
|
||||||
execution:
|
execution:
|
||||||
allow: [cte_test, explain, preview, aggregate, export]
|
allow: [cte_test, explain, preview, aggregate, export]
|
||||||
max_preview_rows: 10
|
max_preview_rows: 10
|
||||||
|
|||||||
Reference in New Issue
Block a user