sable-sphynx 0.7.0.dev0__py3-none-any.whl
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.
- sable_sphynx-0.7.0.dev0.dist-info/METADATA +152 -0
- sable_sphynx-0.7.0.dev0.dist-info/RECORD +174 -0
- sable_sphynx-0.7.0.dev0.dist-info/WHEEL +5 -0
- sable_sphynx-0.7.0.dev0.dist-info/top_level.txt +1 -0
- sphynx/__init__.py +469 -0
- sphynx/__init__.pyi +376 -0
- sphynx/_analytical_client.py +77 -0
- sphynx/_analytical_values.py +252 -0
- sphynx/_audit_client.py +173 -0
- sphynx/_comparison_adapters.py +113 -0
- sphynx/_componentized_full_rag.py +34 -0
- sphynx/_composed_pipeline.py +109 -0
- sphynx/_full_rag_grading.py +218 -0
- sphynx/_full_rag_trace.py +221 -0
- sphynx/_local_eval.py +268 -0
- sphynx/_pipeline_core.py +243 -0
- sphynx/_pr_client.py +237 -0
- sphynx/_rag_diagnostics_calibration.py +285 -0
- sphynx/_rag_diagnostics_catalog.py +39 -0
- sphynx/_rag_diagnostics_common.py +26 -0
- sphynx/_rag_diagnostics_contracts.py +186 -0
- sphynx/_rag_diagnostics_engine.py +243 -0
- sphynx/_rag_diagnostics_importers.py +242 -0
- sphynx/_rag_diagnostics_ranking.py +81 -0
- sphynx/_rag_diagnostics_semantic.py +325 -0
- sphynx/_rag_ranking.py +149 -0
- sphynx/_speech_benchmark_scoring.py +140 -0
- sphynx/_speech_benchmark_sources.py +275 -0
- sphynx/_speech_complete_scoring.py +218 -0
- sphynx/_speech_complete_source.py +118 -0
- sphynx/_speech_kido.py +294 -0
- sphynx/_speech_scoring.py +77 -0
- sphynx/_track_capture.py +213 -0
- sphynx/analytical_views.py +515 -0
- sphynx/assessment_contracts.py +378 -0
- sphynx/assessment_selection.py +57 -0
- sphynx/audit_access.py +245 -0
- sphynx/audit_contracts.py +204 -0
- sphynx/audit_requests.py +180 -0
- sphynx/authoring.py +188 -0
- sphynx/benchmarks.py +568 -0
- sphynx/candidates.py +62 -0
- sphynx/catalog.py +272 -0
- sphynx/chunking.py +372 -0
- sphynx/clickhouse_reader.py +169 -0
- sphynx/client.py +486 -0
- sphynx/comparison_core.py +149 -0
- sphynx/comparison_views.py +223 -0
- sphynx/components.py +1661 -0
- sphynx/contracts.py +514 -0
- sphynx/customer_rerank.py +299 -0
- sphynx/customer_retrieval.py +146 -0
- sphynx/data/benchmark-releases.v1.json +164 -0
- sphynx/data/public-benchmark-release.v1.json +354 -0
- sphynx/data/rag-diagnostics-synthetic.v1.json +6982 -0
- sphynx/data/rag-paper-references.v1.json +176 -0
- sphynx/data/rag-paper-schemas.v1.json +1069 -0
- sphynx/data/rag-rerank-v1.json +507 -0
- sphynx/dataset_catalog_data.py +1214 -0
- sphynx/dataset_readiness.py +138 -0
- sphynx/dataset_v3.py +999 -0
- sphynx/demo.py +130 -0
- sphynx/demo_candidates/__init__.py +1 -0
- sphynx/demo_candidates/dense.py +11 -0
- sphynx/demo_candidates/lexical.py +21 -0
- sphynx/diagnostics.py +207 -0
- sphynx/documentation.py +737 -0
- sphynx/documentation_candidate.py +939 -0
- sphynx/evals.py +538 -0
- sphynx/evaluation_protocols.py +124 -0
- sphynx/evaluator_bindings.py +370 -0
- sphynx/evidence.py +352 -0
- sphynx/execution_capabilities.py +109 -0
- sphynx/fast_search.py +285 -0
- sphynx/full_rag.py +341 -0
- sphynx/hosted/__init__.py +18 -0
- sphynx/hosted/benchmark_intake.py +218 -0
- sphynx/hosted/contracts.py +361 -0
- sphynx/hosted/model_admission.py +130 -0
- sphynx/hosted/model_artifacts.py +298 -0
- sphynx/hosted/model_contracts.py +63 -0
- sphynx/hosted/model_gcs.py +181 -0
- sphynx/hosted/model_history.py +84 -0
- sphynx/hosted/model_session.py +233 -0
- sphynx/hosted/public_suite.py +74 -0
- sphynx/hosted/registry.py +97 -0
- sphynx/hosted/revisions.py +126 -0
- sphynx/hosted/sandbox.py +105 -0
- sphynx/hosted/submission.py +287 -0
- sphynx/hosted_workflow.py +451 -0
- sphynx/http_transport.py +86 -0
- sphynx/integrated_rag.py +352 -0
- sphynx/integrated_workflow.py +552 -0
- sphynx/integration_contracts.py +474 -0
- sphynx/invocation.py +791 -0
- sphynx/invocation_candidates.py +392 -0
- sphynx/invocation_catalog_data.py +40 -0
- sphynx/learned_catalog_data.py +30 -0
- sphynx/learned_rerank.py +267 -0
- sphynx/legacy_full_rag.py +67 -0
- sphynx/lifecycle.py +885 -0
- sphynx/lifecycle_workflow.py +490 -0
- sphynx/metric_views.py +474 -0
- sphynx/metrics.py +282 -0
- sphynx/model_adapters.py +438 -0
- sphynx/model_catalog_data.py +30 -0
- sphynx/official_benchmarks.py +385 -0
- sphynx/packs.py +258 -0
- sphynx/pipeline.py +313 -0
- sphynx/pipeline_workflow.py +551 -0
- sphynx/pr_evaluations.py +560 -0
- sphynx/progress.py +89 -0
- sphynx/public_bundle.py +173 -0
- sphynx/public_eval.py +62 -0
- sphynx/public_rerank.py +355 -0
- sphynx/py.typed +0 -0
- sphynx/pytest_plugin.py +62 -0
- sphynx/question_robustness.py +437 -0
- sphynx/rag.py +329 -0
- sphynx/rag_diagnostics.py +309 -0
- sphynx/rag_papers/__init__.py +29 -0
- sphynx/rag_papers/__main__.py +45 -0
- sphynx/rag_papers/candidates.py +19 -0
- sphynx/rag_papers/contracts.py +282 -0
- sphynx/rag_papers/datasets.py +291 -0
- sphynx/rag_papers/experiments.py +116 -0
- sphynx/rag_papers/judges.py +308 -0
- sphynx/rag_papers/registry.py +33 -0
- sphynx/rag_papers/runner.py +176 -0
- sphynx/rag_papers/sable.py +135 -0
- sphynx/rag_papers/schemas.py +12 -0
- sphynx/rag_papers/scoring.py +249 -0
- sphynx/rag_papers/semantic.py +288 -0
- sphynx/rag_papers/trec.py +80 -0
- sphynx/recorded_scores.py +352 -0
- sphynx/records.py +124 -0
- sphynx/reflex_traces.py +193 -0
- sphynx/report_rendering.py +71 -0
- sphynx/rerank_family_contracts.py +150 -0
- sphynx/rerank_workflow.py +424 -0
- sphynx/research_candidate.py +190 -0
- sphynx/results.py +852 -0
- sphynx/retrieval.py +750 -0
- sphynx/retrieval_candidates.py +295 -0
- sphynx/retrieval_catalog_data.py +19 -0
- sphynx/retrieval_recordings.py +125 -0
- sphynx/reviewer_audit.py +266 -0
- sphynx/routing_policies.py +375 -0
- sphynx/runner.py +544 -0
- sphynx/sable_rerank.py +489 -0
- sphynx/score_reliability.py +393 -0
- sphynx/speech_benchmarks.py +204 -0
- sphynx/speech_campaigns.py +378 -0
- sphynx/speech_complete.py +236 -0
- sphynx/speech_contracts.py +225 -0
- sphynx/speech_evidence.py +429 -0
- sphynx/speech_listening.py +115 -0
- sphynx/speech_multilingual.py +71 -0
- sphynx/speech_tts.py +479 -0
- sphynx/sql/001_sync_v1.sql +30 -0
- sphynx/stage_contracts.py +199 -0
- sphynx/statistical_catalog_data.py +53 -0
- sphynx/statistical_rerank.py +232 -0
- sphynx/sync.py +797 -0
- sphynx/workbench.py +378 -0
- sphynx/workbench_catalog_data.py +13 -0
- sphynx/workbench_tracks.py +78 -0
- sphynx/workflow_async.py +197 -0
- sphynx/workflow_contracts.py +594 -0
- sphynx/workflow_decisions.py +211 -0
- sphynx/workflow_defaults.py +16 -0
- sphynx/workflow_extensions.py +212 -0
- sphynx/workflow_registry.py +513 -0
- sphynx/workflows.py +792 -0
sphynx/sable_rerank.py
ADDED
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
"""Owner-held Sable reranker development packs.
|
|
2
|
+
|
|
3
|
+
The dataset path is supplied by the owner at runtime. Neither passages nor
|
|
4
|
+
reference labels are installed in the wheel. Local execution is untrusted:
|
|
5
|
+
the candidate process can read files available to its OS identity, so genuinely
|
|
6
|
+
blind holdouts require a separate platform runner.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import hashlib
|
|
12
|
+
import json
|
|
13
|
+
from dataclasses import dataclass, replace
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any, Mapping
|
|
16
|
+
|
|
17
|
+
from .contracts import INTERFACE_VERSION, SABLE_RERANK_DEV_PACK_ID, CandidateSpec, ContractError, build_candidate_request, canonical_json
|
|
18
|
+
from .evidence import RunRef, read_capture_artifact, read_capture_manifest, read_run_manifest, verify_run
|
|
19
|
+
from .metrics import METRIC_RELEASE, aggregate_case_metrics, grade_case
|
|
20
|
+
from .packs import ExecutionPolicy, PackDescriptor
|
|
21
|
+
from .rag import RagRerankPack, validate_dataset_v2
|
|
22
|
+
from .runner import ENV_POLICY_ID, MAX_STREAM_BYTES, _case_snapshot, _parse_response, _run_with_cases
|
|
23
|
+
|
|
24
|
+
SABLE_PACK_ID = SABLE_RERANK_DEV_PACK_ID
|
|
25
|
+
_SCHEMA = "sphynx.sable.rerank.private.v1"
|
|
26
|
+
_ORIGINS = frozenset({"reconstructed_development", "exact_pre_rerank"})
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True)
|
|
30
|
+
class PrivatePack:
|
|
31
|
+
pack: RagRerankPack
|
|
32
|
+
origin: str
|
|
33
|
+
label_status: str
|
|
34
|
+
source_revision: str
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def dataset_digest(self) -> str:
|
|
38
|
+
return self.pack.dataset_digest
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass(frozen=True)
|
|
42
|
+
class PrivateEvaluation:
|
|
43
|
+
run_id: str
|
|
44
|
+
pack_id: str
|
|
45
|
+
dataset_digest: str
|
|
46
|
+
origin: str
|
|
47
|
+
label_status: str
|
|
48
|
+
candidate: Mapping[str, str]
|
|
49
|
+
execution_policy: Mapping[str, Any]
|
|
50
|
+
runner: Mapping[str, str]
|
|
51
|
+
status: str
|
|
52
|
+
cases: tuple[Mapping[str, Any], ...]
|
|
53
|
+
metrics: Mapping[str, Mapping[str, Any]]
|
|
54
|
+
|
|
55
|
+
def to_dict(self) -> dict[str, Any]:
|
|
56
|
+
return {
|
|
57
|
+
"schema_version": "sphynx.sable.rerank.evaluation.v1",
|
|
58
|
+
"run_id": self.run_id,
|
|
59
|
+
"pack_id": self.pack_id,
|
|
60
|
+
"dataset_digest": self.dataset_digest,
|
|
61
|
+
"origin": self.origin,
|
|
62
|
+
"label_status": self.label_status,
|
|
63
|
+
"trust_tier": "local_unverified",
|
|
64
|
+
"candidate": dict(self.candidate),
|
|
65
|
+
"execution_policy": dict(self.execution_policy),
|
|
66
|
+
"runner": dict(self.runner),
|
|
67
|
+
"status": self.status,
|
|
68
|
+
"cases": [dict(case) for case in self.cases],
|
|
69
|
+
"metrics": {key: dict(value) for key, value in self.metrics.items()},
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
def to_json(self) -> str:
|
|
73
|
+
return canonical_json(self.to_dict())
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def load_private_pack(dataset_path: str | Path, *, expected_sha256: str | None = None) -> PrivatePack:
|
|
77
|
+
"""Validate an external dataset and bind its complete bytes to a release.
|
|
78
|
+
|
|
79
|
+
``expected_sha256`` is useful when loading a separately approved release;
|
|
80
|
+
a changed label or passage byte then fails before candidate execution.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
path = Path(dataset_path).expanduser().resolve(strict=True)
|
|
84
|
+
payload = path.read_bytes()
|
|
85
|
+
digest = hashlib.sha256(payload).hexdigest()
|
|
86
|
+
if expected_sha256 is not None and expected_sha256.removeprefix("sha256:") != digest:
|
|
87
|
+
raise ContractError("private pack bytes differ from expected SHA-256")
|
|
88
|
+
try:
|
|
89
|
+
value = json.loads(payload)
|
|
90
|
+
except (UnicodeError, json.JSONDecodeError) as exc:
|
|
91
|
+
raise ContractError("private pack must be UTF-8 JSON") from exc
|
|
92
|
+
if not isinstance(value, dict):
|
|
93
|
+
raise ContractError("private pack must be a JSON object")
|
|
94
|
+
meta = value.get("sphynx_private_pack")
|
|
95
|
+
if not isinstance(meta, dict) or meta.get("schema_version") != _SCHEMA:
|
|
96
|
+
raise ContractError("private pack metadata/schema is missing")
|
|
97
|
+
if meta.get("pack_id") != SABLE_PACK_ID or meta.get("visibility") != "private":
|
|
98
|
+
raise ContractError("private Sable pack identity or visibility is invalid")
|
|
99
|
+
origin = meta.get("origin")
|
|
100
|
+
label_status = meta.get("label_status")
|
|
101
|
+
if origin not in _ORIGINS or label_status not in {"provisional", "human_adjudicated"}:
|
|
102
|
+
raise ContractError("private pack origin or label status is invalid")
|
|
103
|
+
if origin == "reconstructed_development" and label_status != "provisional":
|
|
104
|
+
raise ContractError("reconstructed pools cannot claim adjudicated benchmark labels")
|
|
105
|
+
if label_status == "human_adjudicated" and meta.get("privacy_review") != "approved":
|
|
106
|
+
raise ContractError("adjudicated private pack requires approved privacy review")
|
|
107
|
+
source_revision = meta.get("source_revision")
|
|
108
|
+
if not isinstance(source_revision, str) or not source_revision.strip():
|
|
109
|
+
raise ContractError("private pack needs source_revision")
|
|
110
|
+
cases, provisional_refs, threshold = validate_dataset_v2(value)
|
|
111
|
+
for case, reference in zip(cases, provisional_refs):
|
|
112
|
+
has_required_group = any(group.required for group in reference.evidence_groups)
|
|
113
|
+
has_relevant_passage = any(item.relevance_grade >= threshold for item in reference.candidates)
|
|
114
|
+
if has_required_group and not has_relevant_passage:
|
|
115
|
+
raise ContractError(f"{case.case_id}: answerable reranker pool has no relevant passage; track retrieval coverage separately")
|
|
116
|
+
if not has_required_group and has_relevant_passage:
|
|
117
|
+
raise ContractError(f"{case.case_id}: unsupported reranker pool contains a relevant passage")
|
|
118
|
+
if label_status == "human_adjudicated":
|
|
119
|
+
for task in value["tasks"]:
|
|
120
|
+
if not all(isinstance(item.get("adjudication"), dict) for item in task["candidates"]):
|
|
121
|
+
raise ContractError("human_adjudicated status requires every candidate adjudication")
|
|
122
|
+
references = tuple(replace(ref, label_authority=label_status) for ref in provisional_refs)
|
|
123
|
+
descriptor = PackDescriptor(
|
|
124
|
+
pack_id=SABLE_PACK_ID,
|
|
125
|
+
pack_release="v1." + digest,
|
|
126
|
+
title="Owner-held Sable passage reranking development pack",
|
|
127
|
+
track="rag_rerank",
|
|
128
|
+
interface_version=INTERFACE_VERSION,
|
|
129
|
+
case_schema_version=value["schema_version"],
|
|
130
|
+
request_schema_version="sphynx.rag.rerank.request.v1",
|
|
131
|
+
response_schema_version="sphynx.rag.rerank.response.v1",
|
|
132
|
+
status="runnable",
|
|
133
|
+
description="Owner-held Sable data; local runs are development results only.",
|
|
134
|
+
execution_policy=ExecutionPolicy("v1", 1, 30.0, "local-unbounded.v1"),
|
|
135
|
+
case_count=len(cases),
|
|
136
|
+
metric_release=METRIC_RELEASE,
|
|
137
|
+
)
|
|
138
|
+
pack = RagRerankPack(descriptor, cases, references, METRIC_RELEASE, "sha256:" + digest, threshold)
|
|
139
|
+
return PrivatePack(pack, origin, label_status, source_revision)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def run_private_rerank(
|
|
143
|
+
candidate: CandidateSpec, dataset_path: str | Path, output_dir: str | Path,
|
|
144
|
+
*, expected_sha256: str | None = None,
|
|
145
|
+
) -> RunRef:
|
|
146
|
+
"""Run a candidate on the complete frozen pool without sending labels."""
|
|
147
|
+
|
|
148
|
+
private = load_private_pack(dataset_path, expected_sha256=expected_sha256)
|
|
149
|
+
return _run_with_cases(candidate, private.pack.descriptor, private.pack.cases, output_dir)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def grade_private_rerank(
|
|
153
|
+
run_ref: RunRef | str | Path, dataset_path: str | Path,
|
|
154
|
+
*, expected_sha256: str | None = None,
|
|
155
|
+
) -> PrivateEvaluation:
|
|
156
|
+
"""Replay verified raw captures against a matching owner-held dataset."""
|
|
157
|
+
|
|
158
|
+
private = load_private_pack(dataset_path, expected_sha256=expected_sha256)
|
|
159
|
+
pack = private.pack
|
|
160
|
+
run_path = (run_ref.path if isinstance(run_ref, RunRef) else Path(run_ref)).expanduser().resolve()
|
|
161
|
+
manifest = read_run_manifest(run_path)
|
|
162
|
+
ref = RunRef(manifest["run_id"], run_path, manifest["pack_id"])
|
|
163
|
+
verify_run(ref)
|
|
164
|
+
if manifest.get("pack_id") != SABLE_PACK_ID or manifest.get("pack_release") != pack.descriptor.pack_release:
|
|
165
|
+
raise ContractError("run and private pack release differ")
|
|
166
|
+
if manifest.get("case_count") != len(pack.cases) or manifest.get("capture_count") != len(pack.cases):
|
|
167
|
+
raise ContractError("run does not cover every private pack case exactly once")
|
|
168
|
+
policy = pack.descriptor.execution_policy
|
|
169
|
+
expected_policy = {
|
|
170
|
+
"policy_version": policy.policy_version, "trials": policy.trials,
|
|
171
|
+
"per_case_timeout_seconds": policy.per_case_timeout_seconds,
|
|
172
|
+
"resource_policy_id": policy.resource_policy_id,
|
|
173
|
+
"environment_policy_id": ENV_POLICY_ID,
|
|
174
|
+
"stdout_stderr_retention_limit_bytes_each": MAX_STREAM_BYTES,
|
|
175
|
+
}
|
|
176
|
+
if manifest.get("execution_policy") != expected_policy:
|
|
177
|
+
raise ContractError("run execution policy differs from private pack")
|
|
178
|
+
candidate_identity = manifest.get("candidate")
|
|
179
|
+
if not isinstance(candidate_identity, dict) or candidate_identity.get("interface_version") != INTERFACE_VERSION:
|
|
180
|
+
raise ContractError("run candidate interface differs from private pack")
|
|
181
|
+
runner_identity = manifest.get("runner")
|
|
182
|
+
if not isinstance(runner_identity, dict) or runner_identity.get("release") != "v1" or runner_identity.get("clock_domain") != "python.monotonic_ns.process_local":
|
|
183
|
+
raise ContractError("run runner identity is unsupported")
|
|
184
|
+
expected_cases = [
|
|
185
|
+
{
|
|
186
|
+
"dataset_id": case.dataset_id, "dataset_version": case.dataset_version,
|
|
187
|
+
"case_id": case.case_id, "query_id": case.query_id, "pool_digest": case.pool_digest,
|
|
188
|
+
"split": case.split, "split_group_id": case.split_group_id, "cluster_id": case.cluster_id,
|
|
189
|
+
"suite_type": case.suite_type, "versions": case.versions.to_dict(),
|
|
190
|
+
}
|
|
191
|
+
for case in pack.cases
|
|
192
|
+
]
|
|
193
|
+
if manifest.get("cases") != expected_cases or manifest.get("track") != "rag_rerank" or manifest.get("trust_tier") != "local_unverified" or manifest.get("provenance") != "runner_observed":
|
|
194
|
+
raise ContractError("run pool, cohort, order, or trust identity differs from private pack")
|
|
195
|
+
ids = manifest.get("capture_ids")
|
|
196
|
+
if not isinstance(ids, list) or len(ids) != len(pack.cases):
|
|
197
|
+
raise ContractError("run capture order is invalid")
|
|
198
|
+
results = []
|
|
199
|
+
case_rows: list[Mapping[str, Any]] = []
|
|
200
|
+
for case, capture_id in zip(pack.cases, ids):
|
|
201
|
+
capture = read_capture_manifest(ref, capture_id)
|
|
202
|
+
identity = capture.get("identity", {})
|
|
203
|
+
if not isinstance(identity, dict) or any((
|
|
204
|
+
identity.get("case_id") != case.case_id,
|
|
205
|
+
identity.get("pool_digest") != case.pool_digest,
|
|
206
|
+
identity.get("trial_index") != 1,
|
|
207
|
+
identity.get("run_id") != ref.run_id,
|
|
208
|
+
)):
|
|
209
|
+
raise ContractError(f"capture {capture_id} does not match private case")
|
|
210
|
+
request = build_candidate_request(case, SABLE_PACK_ID)
|
|
211
|
+
if read_capture_artifact(ref, capture_id, "candidate_request") != (request.to_json() + "\n").encode("utf-8"):
|
|
212
|
+
raise ContractError(f"candidate request differs from private case {case.case_id}")
|
|
213
|
+
if read_capture_artifact(ref, capture_id, "case_snapshot") != (canonical_json(_case_snapshot(case)) + "\n").encode("utf-8"):
|
|
214
|
+
raise ContractError(f"case snapshot differs from private case {case.case_id}")
|
|
215
|
+
status = capture.get("status")
|
|
216
|
+
ranked = None
|
|
217
|
+
if status == "success":
|
|
218
|
+
ranked, error_code, _ = _parse_response(read_capture_artifact(ref, capture_id, "candidate_stdout"), request)
|
|
219
|
+
if error_code or ranked is None or capture.get("ranked_candidate_ids") != list(ranked):
|
|
220
|
+
raise ContractError(f"saved ranking differs from raw response for {case.case_id}")
|
|
221
|
+
elif capture.get("ranked_candidate_ids") is not None:
|
|
222
|
+
raise ContractError(f"failed capture has a ranking for {case.case_id}")
|
|
223
|
+
timing = capture.get("timing")
|
|
224
|
+
latency_ns = timing.get("candidate_latency_ns") if isinstance(timing, dict) else None
|
|
225
|
+
if latency_ns is not None and (type(latency_ns) is not int or latency_ns < 0):
|
|
226
|
+
raise ContractError(f"invalid timing for {case.case_id}")
|
|
227
|
+
result = grade_case(
|
|
228
|
+
case, pack.reference_for(case.case_id), ranked,
|
|
229
|
+
latency_ns / 1_000_000 if latency_ns is not None else None,
|
|
230
|
+
terminal_status="ok" if status == "success" else str(status),
|
|
231
|
+
relevance_threshold=pack.relevance_threshold, pack=pack,
|
|
232
|
+
)
|
|
233
|
+
results.append(result)
|
|
234
|
+
case_rows.append({
|
|
235
|
+
"case_id": case.case_id, "pool_digest": case.pool_digest,
|
|
236
|
+
"status": status, "values": dict(result.values),
|
|
237
|
+
"undefined_reasons": dict(result.undefined_reasons),
|
|
238
|
+
})
|
|
239
|
+
metrics = {name: value.to_dict() for name, value in aggregate_case_metrics(results, pack=pack).items()}
|
|
240
|
+
return PrivateEvaluation(
|
|
241
|
+
ref.run_id, SABLE_PACK_ID, private.dataset_digest, private.origin,
|
|
242
|
+
private.label_status, manifest["candidate"], expected_policy, runner_identity,
|
|
243
|
+
"completed" if all(row["status"] == "success" for row in case_rows) else "incomplete",
|
|
244
|
+
tuple(case_rows), metrics,
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def compare_private_rerank(a: PrivateEvaluation, b: PrivateEvaluation) -> dict[str, Any]:
|
|
249
|
+
"""Compare two fully matched frozen-pool runs with paired case deltas."""
|
|
250
|
+
|
|
251
|
+
if a.pack_id != b.pack_id or a.dataset_digest != b.dataset_digest:
|
|
252
|
+
raise ContractError("private reranker comparisons require the exact same pack bytes")
|
|
253
|
+
if [row["pool_digest"] for row in a.cases] != [row["pool_digest"] for row in b.cases]:
|
|
254
|
+
raise ContractError("private reranker comparisons require identical ordered pools")
|
|
255
|
+
if a.execution_policy != b.execution_policy or a.runner != b.runner:
|
|
256
|
+
raise ContractError("private reranker comparisons require matching runner and execution policy")
|
|
257
|
+
metrics: dict[str, Any] = {}
|
|
258
|
+
for metric_id in a.metrics:
|
|
259
|
+
av, bv = a.metrics[metric_id], b.metrics[metric_id]
|
|
260
|
+
pairs = [
|
|
261
|
+
{"case_id": left["case_id"], "a": left["values"][metric_id], "b": right["values"][metric_id],
|
|
262
|
+
"delta_b_minus_a": right["values"][metric_id] - left["values"][metric_id]}
|
|
263
|
+
for left, right in zip(a.cases, b.cases)
|
|
264
|
+
if left["values"][metric_id] is not None and right["values"][metric_id] is not None
|
|
265
|
+
]
|
|
266
|
+
metrics[metric_id] = {
|
|
267
|
+
"a": av["value"], "b": bv["value"],
|
|
268
|
+
"delta_b_minus_a": bv["value"] - av["value"] if av["value"] is not None and bv["value"] is not None else None,
|
|
269
|
+
"paired_cases": pairs,
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
"pack_id": a.pack_id, "dataset_digest": a.dataset_digest,
|
|
273
|
+
"origin": a.origin, "trust_tier": "local_unverified", "metrics": metrics,
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def build_cherry_development_dataset(pool_path: str | Path, labels_path: str | Path) -> dict[str, Any]:
|
|
278
|
+
"""Adapt the existing reconstructed Cherry study without bundling its data.
|
|
279
|
+
|
|
280
|
+
The result is a development dataset only. The study did not capture the
|
|
281
|
+
actual production Pinecone pool, contextualized passages, or rewritten
|
|
282
|
+
query, and its labels have not been Sphynx-adjudicated.
|
|
283
|
+
"""
|
|
284
|
+
|
|
285
|
+
pool_bytes = Path(pool_path).read_bytes()
|
|
286
|
+
label_bytes = Path(labels_path).read_bytes()
|
|
287
|
+
pool = json.loads(pool_bytes)
|
|
288
|
+
labels = json.loads(label_bytes)
|
|
289
|
+
if pool.get("schema_version") != "cherry-pre-rerank-dense-pools.v1":
|
|
290
|
+
raise ContractError("unsupported Cherry frozen-pool source schema")
|
|
291
|
+
if pool.get("status") != "frozen_before_reranker_scoring":
|
|
292
|
+
raise ContractError("Cherry pool was not frozen before reranker scoring")
|
|
293
|
+
if labels.get("schema_version") != "cherry-reranker-labels.v1":
|
|
294
|
+
raise ContractError("unsupported Cherry label source schema")
|
|
295
|
+
frozen_body = {key: value for key, value in pool.items() if key not in {"runtime", "pool_sha256"}}
|
|
296
|
+
expected_pool_sha = hashlib.sha256(canonical_json(frozen_body).encode("utf-8")).hexdigest()
|
|
297
|
+
if pool.get("pool_sha256") != expected_pool_sha or labels.get("pool_sha256") != expected_pool_sha:
|
|
298
|
+
raise ContractError("Cherry pool and labels do not share the frozen source digest")
|
|
299
|
+
queries = pool.get("queries")
|
|
300
|
+
label_queries = labels.get("queries")
|
|
301
|
+
if not isinstance(queries, list) or not isinstance(label_queries, dict) or len(queries) != len(label_queries):
|
|
302
|
+
raise ContractError("Cherry questions and labels disagree")
|
|
303
|
+
source_sha = hashlib.sha256(pool_bytes).hexdigest()
|
|
304
|
+
label_sha = hashlib.sha256(label_bytes).hexdigest()
|
|
305
|
+
tasks: list[dict[str, Any]] = []
|
|
306
|
+
for index, item in enumerate(queries):
|
|
307
|
+
case_id = item["task_id"]
|
|
308
|
+
if case_id not in label_queries or item.get("candidate_count") != len(item.get("candidates", [])):
|
|
309
|
+
raise ContractError(f"Cherry pool or labels missing for {case_id}")
|
|
310
|
+
qrels = label_queries[case_id].get("relevance")
|
|
311
|
+
if not isinstance(qrels, dict):
|
|
312
|
+
raise ContractError(f"Cherry qrels missing for {case_id}")
|
|
313
|
+
candidates_raw = item["candidates"]
|
|
314
|
+
candidate_ids = {candidate["candidate_id"] for candidate in candidates_raw}
|
|
315
|
+
if len(candidate_ids) != len(candidates_raw) or not set(qrels) <= candidate_ids:
|
|
316
|
+
raise ContractError(f"Cherry qrels do not match frozen pool for {case_id}")
|
|
317
|
+
answerable = any(int(value.get("grade", 0)) >= 2 for value in qrels.values())
|
|
318
|
+
group_id = f"evidence:{index:02d}"
|
|
319
|
+
acceptable = [candidate["candidate_id"] for candidate in candidates_raw
|
|
320
|
+
if int(qrels.get(candidate["candidate_id"], {}).get("grade", 0)) >= 2]
|
|
321
|
+
candidates = []
|
|
322
|
+
for rank, candidate in enumerate(candidates_raw, start=1):
|
|
323
|
+
label = qrels.get(candidate["candidate_id"], {})
|
|
324
|
+
source_id = str(candidate["source_id"])
|
|
325
|
+
chunk_index = int(candidate["chunk_index"])
|
|
326
|
+
candidates.append({
|
|
327
|
+
"candidate_id": candidate["candidate_id"],
|
|
328
|
+
"document_id": "source:" + source_id,
|
|
329
|
+
"source_id": source_id,
|
|
330
|
+
"chunk_id": f"{source_id}:chunk:{chunk_index}",
|
|
331
|
+
"url": f"urn:sable:cherry:{source_id}:{chunk_index}",
|
|
332
|
+
"input": candidate["input"],
|
|
333
|
+
"dense_rank": rank,
|
|
334
|
+
"dense_score": candidate["first_stage_score"],
|
|
335
|
+
"relevance_grade": int(label.get("grade", 0)),
|
|
336
|
+
"evidence_group_ids": [group_id] if candidate["candidate_id"] in acceptable else [],
|
|
337
|
+
"known_hard_negative": bool(label.get("hard_negative", False)),
|
|
338
|
+
})
|
|
339
|
+
task = {
|
|
340
|
+
"task_id": case_id, "query_id": case_id, "cluster_id": case_id,
|
|
341
|
+
"split_group_id": case_id, "domain": "cherry", "query": item["query"],
|
|
342
|
+
"answerability": "answerable" if answerable else "unsupported",
|
|
343
|
+
"business_severity": "medium",
|
|
344
|
+
"query_categories": ["straightforward_factual" if answerable else "unsupported_not_in_kb"],
|
|
345
|
+
"customer": "cherry", "split": "dev", "suite_type": "customer_acceptance",
|
|
346
|
+
"versions": {
|
|
347
|
+
"corpus": "cherry-reconstruction:" + str(pool["source_corpus_sha256"]),
|
|
348
|
+
"index": "snowflake-local:" + source_sha,
|
|
349
|
+
"chunking": "public-api-chunks",
|
|
350
|
+
"embedding": "snowflake-arctic-m-v2:" + str(pool["first_stage"]["revision"]),
|
|
351
|
+
},
|
|
352
|
+
"candidates": candidates,
|
|
353
|
+
"evidence_groups": [{
|
|
354
|
+
"evidence_group_id": group_id,
|
|
355
|
+
"description": "Answer-bearing passages with Cherry study relevance grade at least two",
|
|
356
|
+
"required": True,
|
|
357
|
+
"acceptable_candidate_ids": acceptable,
|
|
358
|
+
}] if answerable else [],
|
|
359
|
+
}
|
|
360
|
+
if not answerable:
|
|
361
|
+
task["expected_unsupported_behavior"] = "abstain"
|
|
362
|
+
tasks.append(task)
|
|
363
|
+
dataset = {
|
|
364
|
+
"schema_version": "rag-evals.dataset.v2",
|
|
365
|
+
"dataset_id": "sable.cherry.reconstructed.v1",
|
|
366
|
+
"version": "v1",
|
|
367
|
+
"default_relevance_threshold": 2,
|
|
368
|
+
"sphynx_private_pack": {
|
|
369
|
+
"schema_version": _SCHEMA, "pack_id": SABLE_PACK_ID,
|
|
370
|
+
"visibility": "private", "origin": "reconstructed_development",
|
|
371
|
+
"label_status": "provisional",
|
|
372
|
+
"source_revision": str(pool["first_stage"]["fast_search_source_revision"]),
|
|
373
|
+
"source_pool_sha256": source_sha, "source_label_sha256": label_sha,
|
|
374
|
+
},
|
|
375
|
+
"tasks": tasks,
|
|
376
|
+
}
|
|
377
|
+
validate_dataset_v2(dataset)
|
|
378
|
+
return dataset
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def build_exact_sable_dataset(
|
|
382
|
+
records: list[Mapping[str, Any]], *, dataset_id: str, dataset_version: str,
|
|
383
|
+
source_revision: str, label_status: str = "provisional",
|
|
384
|
+
privacy_review: str = "pending",
|
|
385
|
+
) -> dict[str, Any]:
|
|
386
|
+
"""Build a private pack from reviewed Fast Search pre-rerank exports.
|
|
387
|
+
|
|
388
|
+
Every record must provide ``case_id``, ``snapshot`` (the opt-in capture),
|
|
389
|
+
``versions`` (corpus/index/chunking/embedding), ``answerability``, and a
|
|
390
|
+
complete ``labels`` mapping keyed by vector ID. Label groups and cohort
|
|
391
|
+
fields are owner-supplied; no relevance is inferred from model output.
|
|
392
|
+
"""
|
|
393
|
+
|
|
394
|
+
if not records or label_status not in {"provisional", "human_adjudicated"}:
|
|
395
|
+
raise ContractError("exact Sable dataset needs records and valid label status")
|
|
396
|
+
if label_status == "human_adjudicated" and privacy_review != "approved":
|
|
397
|
+
raise ContractError("adjudicated dataset requires approved privacy review")
|
|
398
|
+
tasks = []
|
|
399
|
+
snapshots = []
|
|
400
|
+
for record in records:
|
|
401
|
+
if not isinstance(record, Mapping):
|
|
402
|
+
raise ContractError("each exact Sable case must be an object")
|
|
403
|
+
case_id = record.get("case_id")
|
|
404
|
+
snapshot = record.get("snapshot")
|
|
405
|
+
labels = record.get("labels")
|
|
406
|
+
versions = record.get("versions")
|
|
407
|
+
if not isinstance(snapshot, Mapping) or snapshot.get("schema_version") != "sphynx.fast-search.pre-rerank.v1":
|
|
408
|
+
raise ContractError(f"{case_id}: invalid Fast Search capture schema")
|
|
409
|
+
if snapshot.get("boundary") != "after_pinecone_before_reranker":
|
|
410
|
+
raise ContractError(f"{case_id}: capture is not at the exact pre-rerank boundary")
|
|
411
|
+
pool = snapshot.get("candidates")
|
|
412
|
+
if not isinstance(pool, list) or not pool or snapshot.get("candidate_count") != len(pool):
|
|
413
|
+
raise ContractError(f"{case_id}: capture has no complete candidate pool")
|
|
414
|
+
if not isinstance(labels, Mapping) or set(labels) != {item.get("candidate_id") for item in pool}:
|
|
415
|
+
raise ContractError(f"{case_id}: every captured vector needs exactly one label")
|
|
416
|
+
if not isinstance(versions, Mapping) or set(versions) != {"corpus", "index", "chunking", "embedding"}:
|
|
417
|
+
raise ContractError(f"{case_id}: explicit corpus/index/chunking/embedding versions required")
|
|
418
|
+
candidates = []
|
|
419
|
+
for rank, item in enumerate(pool, 1):
|
|
420
|
+
if not isinstance(item, Mapping) or item.get("dense_rank") != rank:
|
|
421
|
+
raise ContractError(f"{case_id}: captured dense rank/order is invalid")
|
|
422
|
+
candidate_id = item["candidate_id"]
|
|
423
|
+
label = labels[candidate_id]
|
|
424
|
+
if not isinstance(label, Mapping) or "relevance_grade" not in label or "evidence_group_ids" not in label:
|
|
425
|
+
raise ContractError(f"{case_id}: incomplete label for {candidate_id}")
|
|
426
|
+
candidate = {
|
|
427
|
+
"candidate_id": candidate_id,
|
|
428
|
+
"document_id": item["document_id"],
|
|
429
|
+
"source_id": item["source_id"],
|
|
430
|
+
"chunk_id": candidate_id,
|
|
431
|
+
"url": item.get("url") or f"urn:fast-search:{candidate_id}",
|
|
432
|
+
"input": item["reranker_input"],
|
|
433
|
+
"dense_rank": rank,
|
|
434
|
+
"dense_score": item["dense_score"],
|
|
435
|
+
"relevance_grade": label["relevance_grade"],
|
|
436
|
+
"evidence_group_ids": label["evidence_group_ids"],
|
|
437
|
+
"known_hard_negative": bool(label.get("known_hard_negative", False)),
|
|
438
|
+
"raw_text": item.get("raw_text"),
|
|
439
|
+
"source_url": item.get("url"),
|
|
440
|
+
"title": item.get("title"),
|
|
441
|
+
"section_path": item.get("section_path"),
|
|
442
|
+
"pipeline_id": item.get("pipeline_id"),
|
|
443
|
+
}
|
|
444
|
+
if "adjudication" in label:
|
|
445
|
+
candidate["adjudication"] = label["adjudication"]
|
|
446
|
+
candidates.append(candidate)
|
|
447
|
+
split = record.get("split", "dev")
|
|
448
|
+
task = {
|
|
449
|
+
"task_id": case_id, "query_id": case_id,
|
|
450
|
+
"cluster_id": record.get("cluster_id", case_id),
|
|
451
|
+
"split_group_id": record.get("split_group_id", case_id),
|
|
452
|
+
"domain": record.get("domain", "sable"),
|
|
453
|
+
"query": snapshot["query"],
|
|
454
|
+
"answerability": record.get("answerability"),
|
|
455
|
+
"business_severity": record.get("business_severity", "medium"),
|
|
456
|
+
"query_categories": record.get("query_categories", ["straightforward_factual"]),
|
|
457
|
+
"customer": snapshot["org"],
|
|
458
|
+
"split": split,
|
|
459
|
+
"suite_type": record.get("suite_type", "untouched_holdout" if split == "holdout" else "customer_acceptance"),
|
|
460
|
+
"versions": dict(versions),
|
|
461
|
+
"candidates": candidates,
|
|
462
|
+
"evidence_groups": record.get("evidence_groups", []),
|
|
463
|
+
"capture_scope": {
|
|
464
|
+
"org": snapshot["org"], "kbs": snapshot["kbs"],
|
|
465
|
+
"filters": snapshot["filters"],
|
|
466
|
+
"requested_top_k": snapshot["requested_top_k"],
|
|
467
|
+
"retrieval_depth": snapshot["retrieval_depth"],
|
|
468
|
+
},
|
|
469
|
+
}
|
|
470
|
+
if task["answerability"] == "unsupported":
|
|
471
|
+
task["expected_unsupported_behavior"] = "abstain"
|
|
472
|
+
tasks.append(task)
|
|
473
|
+
snapshots.append(snapshot)
|
|
474
|
+
dataset = {
|
|
475
|
+
"schema_version": "rag-evals.dataset.v2",
|
|
476
|
+
"dataset_id": dataset_id,
|
|
477
|
+
"version": dataset_version,
|
|
478
|
+
"default_relevance_threshold": 2,
|
|
479
|
+
"sphynx_private_pack": {
|
|
480
|
+
"schema_version": _SCHEMA, "pack_id": SABLE_PACK_ID,
|
|
481
|
+
"visibility": "private", "origin": "exact_pre_rerank",
|
|
482
|
+
"label_status": label_status, "privacy_review": privacy_review,
|
|
483
|
+
"source_revision": source_revision,
|
|
484
|
+
"capture_sha256": hashlib.sha256(canonical_json(snapshots).encode("utf-8")).hexdigest(),
|
|
485
|
+
},
|
|
486
|
+
"tasks": tasks,
|
|
487
|
+
}
|
|
488
|
+
validate_dataset_v2(dataset)
|
|
489
|
+
return dataset
|