compass-kb-validation 2.6.0__tar.gz → 2.6.1__tar.gz
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.
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/PKG-INFO +1 -1
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/compass_kb_validation.egg-info/PKG-INFO +1 -1
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/discover_and_validate.py +7 -7
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/__init__.py +1 -1
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/cli.py +23 -12
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/grounding.py +8 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/profiler.py +7 -3
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/remediation.py +11 -6
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/report/__init__.py +11 -2
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_grounding.py +15 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_neptune_bugfixes2.py +13 -1
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_profiler.py +2 -2
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_reporting.py +26 -2
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/LICENSE +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/README.md +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/compass_kb_validation.egg-info/SOURCES.txt +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/compass_kb_validation.egg-info/dependency_links.txt +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/compass_kb_validation.egg-info/entry_points.txt +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/compass_kb_validation.egg-info/requires.txt +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/compass_kb_validation.egg-info/top_level.txt +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/__main__.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/ask.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/baseline.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/chunk_coherence.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/config/__init__.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/config_lint.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/content_inspect.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/corpus.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/corpus_health.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/diagnostics.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/embedding_drift.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/eval_interop.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/init_wizard.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/live_dashboard.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/mcp_server.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/models/__init__.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/notifications.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/pipeline/__init__.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/provenance.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/providers/__init__.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/providers/embedding.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/providers/graph.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/providers/source.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/providers/storage.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/providers/vectorstore.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/report/_report_css.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/report/_report_js.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/report/analysis.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/report/export.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/report/shell.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/retrieval_analysis.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/trend_tracker.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/utils/__init__.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/validators/__init__.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/validators/api_upload.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/validators/base.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/validators/base_sparql.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/validators/cross_stage.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/validators/graphdb_metadata.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/validators/neptune_metadata.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/validators/redis_chunks.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/validators/registry.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/validators/retrieval_quality.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/validators/s3_storage.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/profile_kb.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/pyproject.toml +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/run_validation.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/setup.cfg +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_alt_adapters.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_analysis_report.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_api_upload.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_ask.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_baseline.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_benchmark.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_check_catalog.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_cli.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_config.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_config_lint.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_content_inspect.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_corpus.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_corpus_health.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_coverage.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_cross_stage.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_diagnostics.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_discover_cli.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_discovery_parallel.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_embedding_drift.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_eval_interop.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_gate.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_graph_transport.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_graph_validators.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_init_wizard.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_manifest.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_mcp.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_migration.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_models.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_neptune_bugfixes.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_notifications.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_pipeline.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_providers.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_redis_chunks.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_registry.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_remediation.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_retrieval_assertions.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_retrieval_quality.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_run_cli.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_sources.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_storage_validator.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_trends.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_universal_concerns.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_utils.py +0 -0
- {compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_vectorstore_filters.py +0 -0
|
@@ -138,14 +138,14 @@ def _resolve_skip_steps(settings, *, include_graphdb: bool, include_retrieval: b
|
|
|
138
138
|
(BUG-22). ``--keep s3_storage`` overrides the auto-skip.
|
|
139
139
|
"""
|
|
140
140
|
skip = ["API Upload"]
|
|
141
|
-
# Graph validation runs by default when
|
|
142
|
-
# sparql_query
|
|
143
|
-
#
|
|
144
|
-
#
|
|
141
|
+
# Graph validation runs by default when THIS PROJECT declares a per-document graph
|
|
142
|
+
# query (sparql_query) - the signal that graph validation is actually intended. It must
|
|
143
|
+
# NOT key off `neptune.endpoint`, which resolves from a shared NEPTUNE_ENDPOINT env var:
|
|
144
|
+
# doing so turned graph on for every project whenever that env var was set, so a project
|
|
145
|
+
# with no graph block inherited another project's Neptune and failed all 19 graph checks
|
|
146
|
+
# (regression). Opt out with --skip neptune_metadata; --include-graphdb still forces on.
|
|
145
147
|
nep, gdb = settings.neptune, settings.graphdb
|
|
146
|
-
graph_configured = bool(
|
|
147
|
-
getattr(nep, "sparql_query", "") or getattr(nep, "endpoint", "")
|
|
148
|
-
or getattr(gdb, "sparql_query", "") or getattr(gdb, "base_url", ""))
|
|
148
|
+
graph_configured = bool(getattr(nep, "sparql_query", "") or getattr(gdb, "sparql_query", ""))
|
|
149
149
|
if not (include_graphdb or graph_configured):
|
|
150
150
|
skip += ["GraphDB Metadata", "Neptune Metadata"]
|
|
151
151
|
if not include_retrieval:
|
|
@@ -1318,7 +1318,7 @@ def cmd_grounding_audit(argv: list[str]) -> int:
|
|
|
1318
1318
|
g = p.add_mutually_exclusive_group(required=True)
|
|
1319
1319
|
g.add_argument("--eval-result", metavar="FILE", help="One eval record as a single JSON object.")
|
|
1320
1320
|
g.add_argument("--eval-results", metavar="FILE",
|
|
1321
|
-
help="Batch:
|
|
1321
|
+
help="Batch: JSONL (one object per line) or a JSON array - both accepted. "
|
|
1322
1322
|
"`compass ask --format eval` emits a compatible file.")
|
|
1323
1323
|
p.add_argument("--format", choices=["markdown", "json"], default="markdown")
|
|
1324
1324
|
p.add_argument("--output", help="Write the report to a file (default: stdout).")
|
|
@@ -1352,15 +1352,23 @@ def cmd_grounding_audit(argv: list[str]) -> int:
|
|
|
1352
1352
|
return 2
|
|
1353
1353
|
records = [one]
|
|
1354
1354
|
else:
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1355
|
+
raw = Path(args.eval_results).read_text(encoding="utf-8")
|
|
1356
|
+
# Accept BOTH a JSON array and JSONL (one object per line) - a whole-file array
|
|
1357
|
+
# is a natural thing to pass, so handle it instead of erroring.
|
|
1358
|
+
stripped = raw.lstrip()
|
|
1359
|
+
if stripped.startswith("["):
|
|
1360
|
+
arr = _json.loads(raw)
|
|
1361
|
+
records = [r for r in arr if isinstance(r, dict)]
|
|
1362
|
+
else:
|
|
1363
|
+
for n, line in enumerate(raw.splitlines(), 1):
|
|
1364
|
+
if not line.strip():
|
|
1365
|
+
continue
|
|
1366
|
+
try:
|
|
1367
|
+
records.append(_json.loads(line))
|
|
1368
|
+
except Exception: # noqa: BLE001 - point at the offending line, not char 1
|
|
1369
|
+
print(f" --eval-results: line {n} is not valid JSON. Expected JSONL "
|
|
1370
|
+
"(one object per line) or a single JSON array.")
|
|
1371
|
+
return 2
|
|
1364
1372
|
except Exception as exc: # noqa: BLE001 - clean message, never a traceback
|
|
1365
1373
|
print(f" Could not read eval input: {exc}")
|
|
1366
1374
|
return 2
|
|
@@ -1381,9 +1389,12 @@ def cmd_grounding_audit(argv: list[str]) -> int:
|
|
|
1381
1389
|
else:
|
|
1382
1390
|
print(body)
|
|
1383
1391
|
|
|
1384
|
-
|
|
1392
|
+
# Gate on fabrications in EITHER path: a count that disagrees with the KB, or a cited
|
|
1393
|
+
# document absent from it. (Previously only structured count mismatches counted, so a
|
|
1394
|
+
# semantic fabricated-source case exited 0 despite being flagged.)
|
|
1395
|
+
fabricated = sum(1 for r in results if r.has_fabrication)
|
|
1385
1396
|
if fabricated:
|
|
1386
|
-
print(f"\n {fabricated}/{len(results)} case(s) contain
|
|
1397
|
+
print(f"\n {fabricated}/{len(results)} case(s) contain a claim or citation not backed by the KB.")
|
|
1387
1398
|
if args.fail_on_fabrication:
|
|
1388
1399
|
return 1
|
|
1389
1400
|
return 0
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/grounding.py
RENAMED
|
@@ -309,6 +309,14 @@ class GroundingResult:
|
|
|
309
309
|
def verified_claims(self) -> list[ClaimVerdict]:
|
|
310
310
|
return [v for v in self.claim_verdicts if v.verifiable]
|
|
311
311
|
|
|
312
|
+
@property
|
|
313
|
+
def has_fabrication(self) -> bool:
|
|
314
|
+
"""A count that disagrees with the KB, OR a cited document absent from the KB -
|
|
315
|
+
the two deterministic 'the model asserted something not in the KB' signals that
|
|
316
|
+
--fail-on-fabrication gates on (semantic fabrications were previously missed)."""
|
|
317
|
+
return bool(self.wrong_claims) or any(
|
|
318
|
+
"not found in KB" in s.get("label", "") for s in self.signals)
|
|
319
|
+
|
|
312
320
|
def layer_diagnosis(self) -> str:
|
|
313
321
|
"""Deterministic layer attribution - which stage is implicated, no quality score."""
|
|
314
322
|
if self.query_type == "structured" and self.wrong_claims:
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/profiler.py
RENAMED
|
@@ -242,11 +242,15 @@ def _configured_graph(settings: Any) -> tuple[Any, str]:
|
|
|
242
242
|
configured Neptune endpoint. Returns ``(None, "")`` when neither is set.
|
|
243
243
|
"""
|
|
244
244
|
gdb = getattr(settings, "graphdb", None)
|
|
245
|
-
if gdb is not None and
|
|
246
|
-
|
|
245
|
+
if gdb is not None and getattr(gdb, "sparql_query", "") and (
|
|
246
|
+
getattr(gdb, "endpoint", "") or (getattr(gdb, "base_url", "") and getattr(gdb, "repository", ""))):
|
|
247
247
|
return gdb, gdb.provider
|
|
248
248
|
nep = getattr(settings, "neptune", None)
|
|
249
|
-
|
|
249
|
+
# Require the project to declare a per-document sparql_query, NOT just a reachable
|
|
250
|
+
# endpoint: neptune.endpoint resolves from the shared NEPTUNE_ENDPOINT env var, so keying
|
|
251
|
+
# only off it made an unrelated project profile (and then validate) another project's
|
|
252
|
+
# graph when the env var was set.
|
|
253
|
+
if nep is not None and getattr(nep, "sparql_query", "") and getattr(nep, "endpoint", ""):
|
|
250
254
|
return nep, "neptune"
|
|
251
255
|
return None, ""
|
|
252
256
|
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/remediation.py
RENAMED
|
@@ -116,14 +116,19 @@ _HINTS: list[tuple[str, str]] = [
|
|
|
116
116
|
"Stored vectors were embedded with a different model than the one declared/serving: retrieval is "
|
|
117
117
|
"silently wrong. Re-embed the corpus with the declared model, or correct the declared model."),
|
|
118
118
|
(r"exact-term retrieval|keyword-index completeness|findable lexically",
|
|
119
|
-
"
|
|
120
|
-
"
|
|
119
|
+
"Exact-keyword retrieval is weak. Either the text field is not indexed for lexical search, OR - in a "
|
|
120
|
+
"large corpus of similar documents - a common term returns many near-identical hits and the right one "
|
|
121
|
+
"does not rank first. Confirm the text field is indexed; if it is, add hybrid (keyword+vector) or a "
|
|
122
|
+
"metadata filter, or raise the similarity threshold."),
|
|
121
123
|
(r"negative retrieval|off-topic",
|
|
122
|
-
"An off-topic query still scored high: embeddings
|
|
123
|
-
"boilerplate
|
|
124
|
+
"An off-topic query still scored high: embeddings may be too generic, or the corpus is dense with "
|
|
125
|
+
"similar/boilerplate content so unrelated queries still match. Strip boilerplate and consider a "
|
|
126
|
+
"higher similarity threshold or metadata pre-filtering."),
|
|
124
127
|
(r"recall|mrr|paraphrase|boundary|empty query",
|
|
125
|
-
"
|
|
126
|
-
"path, or
|
|
128
|
+
"Retrieval is weak for real queries. This can be a config problem (embeddings not matching the query "
|
|
129
|
+
"path, or an unindexed filter field) OR corpus-specific: a large set of highly similar documents makes "
|
|
130
|
+
"paraphrase/boundary disambiguation genuinely hard. Verify the retrieval config first; if it is sound, "
|
|
131
|
+
"adjust the similarity threshold or filter by metadata."),
|
|
127
132
|
|
|
128
133
|
# ---- Ingestion API / storage / connectivity --------------------------------------
|
|
129
134
|
(r"http status|graphql|success status|valid json|api ",
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/report/__init__.py
RENAMED
|
@@ -46,6 +46,10 @@ def _step_icons() -> dict:
|
|
|
46
46
|
_BAND = {"PASSED": "ok", "FAILED": "bad", "ERROR": "bad", "PARTIAL": "warn", "SKIPPED": "na", "EMPTY": "na"}
|
|
47
47
|
# Cap RDF triples embedded per step for the knowledge-graph view (bounds payload size).
|
|
48
48
|
_KG_TRIPLE_CAP = 80
|
|
49
|
+
# At scale, a passed document keeps its chunk previews if it has at most this many - small
|
|
50
|
+
# docs are cheap and their preview is what you drill into. Only large docs (heavy previews)
|
|
51
|
+
# are trimmed, per document, rather than a corpus-wide blanket that emptied even 1-chunk docs.
|
|
52
|
+
_CHUNK_ITEMS_KEEP = 10
|
|
49
53
|
# Max folder/category rows in the readiness roll-up (worst pass-rate first); keeps it
|
|
50
54
|
# a signal rather than one row per document when folders are fine-grained.
|
|
51
55
|
_FOLDER_DISPLAY_CAP = 20
|
|
@@ -1875,8 +1879,13 @@ def generate_batch_dashboard(
|
|
|
1875
1879
|
]
|
|
1876
1880
|
if not drillable:
|
|
1877
1881
|
trimmed += 1
|
|
1878
|
-
|
|
1879
|
-
|
|
1882
|
+
# Drop chunk previews PER DOCUMENT by its own size, not a corpus-wide
|
|
1883
|
+
# blanket: a doc with a handful of chunks costs almost nothing and its
|
|
1884
|
+
# preview is exactly what you drill into, so keep it. Only large docs
|
|
1885
|
+
# (where the previews are actually heavy) are trimmed.
|
|
1886
|
+
ch = c.get("chunks")
|
|
1887
|
+
if ch and len(ch.get("items") or []) > _CHUNK_ITEMS_KEEP:
|
|
1888
|
+
c["chunks"] = {**ch, "items": []}
|
|
1880
1889
|
trim_note = (
|
|
1881
1890
|
f'<div class="meta-item"><span class="meta-key">Detail:</span> triples + verbose fields '
|
|
1882
1891
|
f'trimmed for {trimmed} passed doc(s); check names + status kept</div>'
|
|
@@ -248,3 +248,18 @@ def test_emit_config_suggests_aggregatable_fields():
|
|
|
248
248
|
out = emit_project_config(profiles, project="demo")
|
|
249
249
|
assert "aggregatable_fields:" in out
|
|
250
250
|
assert "field: document_type" in out and "count_by: file_name" in out
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def test_fabrication_gate_covers_semantic_fabricated_source():
|
|
254
|
+
# --fail-on-fabrication must fire on a cited document absent from the KB (semantic),
|
|
255
|
+
# not only structured count mismatches - previously it exited 0 on a fabricated source.
|
|
256
|
+
class KB:
|
|
257
|
+
supports_aggregation = True
|
|
258
|
+
def text_search(self, f, v, limit=1): return [] if "fake" in v.lower() else [{"x": 1}]
|
|
259
|
+
r = run_audit({"input": "summary?", "response": "Per **Fake Report.pdf**, x happened.",
|
|
260
|
+
"context.retrieved": "c", "scores": {}}, KB(), _cfg(gt_context_path="context.retrieved"))
|
|
261
|
+
assert r.has_fabrication is True
|
|
262
|
+
# a clean case does not trip the gate
|
|
263
|
+
r2 = run_audit({"input": "outlook?", "response": "Cautious.", "context.retrieved": "cautious given rates",
|
|
264
|
+
"scores": {"Groundedness": {"score": 0.9, "target": 0.7}}}, KB(), _cfg(gt_context_path="context.retrieved"))
|
|
265
|
+
assert r2.has_fabrication is False
|
|
@@ -51,6 +51,7 @@ def test_configured_graph_prefers_graphdb():
|
|
|
51
51
|
s = Settings()
|
|
52
52
|
s.graphdb.base_url = "http://gdb"
|
|
53
53
|
s.graphdb.repository = "repo"
|
|
54
|
+
s.graphdb.sparql_query = "SELECT ?s WHERE { ?s ?p ?o {filter_clause} }"
|
|
54
55
|
cfg, name = _configured_graph(s)
|
|
55
56
|
assert cfg is s.graphdb and name == s.graphdb.provider
|
|
56
57
|
|
|
@@ -58,6 +59,7 @@ def test_configured_graph_prefers_graphdb():
|
|
|
58
59
|
def test_configured_graph_falls_back_to_neptune():
|
|
59
60
|
s = Settings()
|
|
60
61
|
s.neptune.endpoint_default = "cluster.example.neptune.amazonaws.com"
|
|
62
|
+
s.neptune.sparql_query = "SELECT ?s WHERE { ?s ?p ?o {filter_clause} }"
|
|
61
63
|
cfg, name = _configured_graph(s)
|
|
62
64
|
assert cfg is s.neptune and name == "neptune"
|
|
63
65
|
|
|
@@ -67,17 +69,27 @@ def test_configured_graph_none_when_unset():
|
|
|
67
69
|
assert cfg is None and name == ""
|
|
68
70
|
|
|
69
71
|
|
|
72
|
+
def test_configured_graph_ignores_env_only_endpoint(monkeypatch):
|
|
73
|
+
# Regression (#18): neptune.endpoint resolves from the shared NEPTUNE_ENDPOINT env var,
|
|
74
|
+
# so a project with NO graph query (no graph block declared) must NOT be treated as
|
|
75
|
+
# graph-configured just because that env var is set for another project.
|
|
76
|
+
monkeypatch.setenv("NEPTUNE_ENDPOINT", "https://someone-elses-cluster.example:8182")
|
|
77
|
+
cfg, name = _configured_graph(Settings()) # no sparql_query declared
|
|
78
|
+
assert cfg is None and name == ""
|
|
79
|
+
|
|
80
|
+
|
|
70
81
|
def test_profile_graph_reports_neptune_not_missing(monkeypatch):
|
|
71
82
|
from ingestion_validation import profiler
|
|
72
83
|
s = Settings()
|
|
73
84
|
s.neptune.endpoint_default = "cluster.example.neptune.amazonaws.com"
|
|
85
|
+
s.neptune.sparql_query = "SELECT ?s WHERE { ?s ?p ?o {filter_clause} }"
|
|
74
86
|
|
|
75
87
|
class _FakeGraph:
|
|
76
88
|
def reachable(self):
|
|
77
89
|
return False
|
|
78
90
|
monkeypatch.setattr(profiler, "get_adapter", lambda *a, **k: _FakeGraph())
|
|
79
91
|
prof = profiler.profile_graph(s)
|
|
80
|
-
# It must not claim "no graph configured" - it now sees the neptune block.
|
|
92
|
+
# It must not claim "no graph configured" - it now sees the neptune block (with a query).
|
|
81
93
|
assert prof["provider"] == "neptune"
|
|
82
94
|
assert not any("No graph endpoint" in n for n in prof["notes"])
|
|
83
95
|
|
|
@@ -172,7 +172,7 @@ def test_profile_storage_no_bucket_is_neutral():
|
|
|
172
172
|
def test_profile_graph_collects_predicates(monkeypatch):
|
|
173
173
|
rows = [{"p": "http://ex/eTag"}, {"p": "http://ex/name"}]
|
|
174
174
|
_patch(monkeypatch, FakeGraphAdapter(rows=rows, reachable=True))
|
|
175
|
-
s = Settings(graphdb=GraphDBConfig(base_url="http://g", repository="repo"))
|
|
175
|
+
s = Settings(graphdb=GraphDBConfig(base_url="http://g", repository="repo", sparql_query="SELECT ?s WHERE { ?s ?p ?o {filter_clause} }"))
|
|
176
176
|
p = profiler.profile_graph(s)
|
|
177
177
|
assert p["reachable"] is True
|
|
178
178
|
assert "http://ex/eTag" in p["predicates"]
|
|
@@ -190,7 +190,7 @@ def test_profile_graph_predicate_coverage_suggests_required(monkeypatch):
|
|
|
190
190
|
# can be computed. eTag 10/10, name 9/10 -> required; rare 1/10 -> optional.
|
|
191
191
|
rows = [{"p": "http://ex/eTag", "c": "10"}, {"p": "http://ex/name", "c": "9"}, {"p": "http://ex/rare", "c": "1"}]
|
|
192
192
|
_patch(monkeypatch, FakeGraphAdapter(rows=rows, reachable=True))
|
|
193
|
-
s = Settings(graphdb=GraphDBConfig(base_url="http://g", repository="repo"))
|
|
193
|
+
s = Settings(graphdb=GraphDBConfig(base_url="http://g", repository="repo", sparql_query="SELECT ?s WHERE { ?s ?p ?o {filter_clause} }"))
|
|
194
194
|
p = profiler.profile_graph(s)
|
|
195
195
|
assert p["subjects"] == 10
|
|
196
196
|
assert len(p["coverage"]) == 3
|
|
@@ -265,8 +265,9 @@ def test_scale_guard_trims_passed_docs(tmp_path):
|
|
|
265
265
|
r.add_step(StepResult(
|
|
266
266
|
"Redis Chunks", status, "x",
|
|
267
267
|
checks=[{"label": "Chunks exist", "passed": status is StepStatus.PASSED, "detail": "9 chunks, verbose"}],
|
|
268
|
-
details={"chunk_view": {"count":
|
|
269
|
-
"items": [{"key": "k", "length": 11, "preview": "p", "fields": {}}
|
|
268
|
+
details={"chunk_view": {"count": 15, "total_chars": 100, "avg_chars": 11,
|
|
269
|
+
"items": [{"key": f"k{j}", "length": 11, "preview": "p", "fields": {}}
|
|
270
|
+
for j in range(15)]}}, # >_CHUNK_ITEMS_KEEP -> trimmed at scale
|
|
270
271
|
))
|
|
271
272
|
r.add_step(StepResult(
|
|
272
273
|
"Neptune Metadata", StepStatus.PASSED, "graph",
|
|
@@ -685,3 +686,26 @@ def test_recommendations_section_only_with_fixable_issues():
|
|
|
685
686
|
# clean run -> nothing rendered (follows "only when issues exist")
|
|
686
687
|
clean_agg = report_mod._aggregate([case(i, clean=True) for i in range(10)])
|
|
687
688
|
assert report_mod._recommendations_section(clean_agg) == ""
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
def test_chunk_previews_kept_per_document_not_blanket_at_scale():
|
|
692
|
+
# A small doc's chunk previews are cheap and are what you drill into; only large docs
|
|
693
|
+
# are trimmed at scale - previously the whole corpus was blanked, emptying 1-chunk docs.
|
|
694
|
+
def case(name, n_chunks):
|
|
695
|
+
r = PipelineResult(document_id=name, file_name=f"{name}.pdf")
|
|
696
|
+
items = [{"key": f"c{j}", "length": 10, "preview": "text", "fields": {}} for j in range(n_chunks)]
|
|
697
|
+
r.add_step(StepResult("Redis Chunks", StepStatus.PASSED, "ok",
|
|
698
|
+
checks=[{"label": "Chunks exist", "passed": True}],
|
|
699
|
+
details={"chunk_view": {"count": n_chunks, "total_chars": 10 * n_chunks,
|
|
700
|
+
"avg_chars": 10, "items": items}}))
|
|
701
|
+
r.finalize()
|
|
702
|
+
return {"name": name, "result": r}
|
|
703
|
+
cases = [case("small", 2)] + [case(f"big{i}", 20) for i in range(250)] # > embed_detail_cap
|
|
704
|
+
html = open(generate_batch_dashboard(cases, __import__("tempfile").mktemp(suffix=".html"),
|
|
705
|
+
embed_detail_cap=200), encoding="utf-8").read()
|
|
706
|
+
m = re.search(r"const REPORT = (\{.*?\});", html, re.S)
|
|
707
|
+
assert m is not None
|
|
708
|
+
payload = json.loads(m.group(1))
|
|
709
|
+
by = {c["name"]: c for c in payload["cases"]}
|
|
710
|
+
assert by["small"]["chunks"]["items"] # 2-chunk doc keeps its previews
|
|
711
|
+
assert by["big0"]["chunks"]["items"] == [] # 20-chunk doc is trimmed
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/baseline.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/chunk_coherence.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/config/__init__.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/config_lint.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/content_inspect.py
RENAMED
|
File without changes
|
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/corpus_health.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/diagnostics.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/embedding_drift.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/eval_interop.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/init_wizard.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/live_dashboard.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/mcp_server.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/models/__init__.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/notifications.py
RENAMED
|
File without changes
|
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/provenance.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/providers/graph.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/providers/source.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/report/analysis.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/report/export.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/report/shell.py
RENAMED
|
File without changes
|
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/trend_tracker.py
RENAMED
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/utils/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/ingestion_validation/validators/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_discovery_parallel.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_retrieval_assertions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_universal_concerns.py
RENAMED
|
File without changes
|
|
File without changes
|
{compass_kb_validation-2.6.0 → compass_kb_validation-2.6.1}/tests/test_vectorstore_filters.py
RENAMED
|
File without changes
|