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
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
"""Protected grading and stage access for actual integrated RAG execution.
|
|
2
|
+
|
|
3
|
+
The configured factory registers one explicit domain policy. Custom evaluators,
|
|
4
|
+
review protocols and report shapes can instead register IntegratedDriver with
|
|
5
|
+
LifecycleBackend. Neither path changes the neutral orchestration contracts.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from collections import Counter, defaultdict
|
|
10
|
+
import json
|
|
11
|
+
import math
|
|
12
|
+
|
|
13
|
+
from .assessment_contracts import Assessment, EvidenceView, _thaw
|
|
14
|
+
from .integrated_rag import (
|
|
15
|
+
INTEGRATED_SCHEMA, INTEGRATED_STAGE_SCHEMA, INTEGRATED_STAGES, IntegratedDriver,
|
|
16
|
+
build_context, validate_answer,
|
|
17
|
+
)
|
|
18
|
+
from .integration_contracts import require_digest, value_digest
|
|
19
|
+
from .lifecycle import LifecycleGradingRef, LifecycleJournal, RunPolicy, _selection
|
|
20
|
+
from .lifecycle_workflow import LifecycleBackend, _comparison_require
|
|
21
|
+
from .pipeline import _score
|
|
22
|
+
from .pipeline_workflow import _CASE_SCHEMA, _validate_case
|
|
23
|
+
from .stage_contracts import (
|
|
24
|
+
STAGE_EVIDENCE_CAPABILITY, StageContractError, StageEvidence, StageSelector,
|
|
25
|
+
)
|
|
26
|
+
from .workflow_contracts import (
|
|
27
|
+
Criterion, Dataset, DatasetDefinition, EvaluatorDefinition, MetricSpec,
|
|
28
|
+
PayloadSchema, SuiteDefinition, WorkflowContractError, contract_digest,
|
|
29
|
+
)
|
|
30
|
+
from .workflow_registry import WorkflowRegistry
|
|
31
|
+
|
|
32
|
+
_REFERENCE = "sphynx.rag.integrated.references.v1"
|
|
33
|
+
_REPORT = "sphynx.rag.integrated.report.v1"
|
|
34
|
+
_EVALUATOR = "sphynx.rag.integrated.evaluator.v1"
|
|
35
|
+
_REDUCER = "sphynx.rag.integrated.equal-case-trial-mean.v1"
|
|
36
|
+
_COMPARISON = "sphynx.rag.integrated.paired-delta.v1"
|
|
37
|
+
_PREFIX = "sphynx.rag.integrated."
|
|
38
|
+
_NUMERIC = ("execution_completed", "routing_correct", "retained_pool_ndcg_at_5",
|
|
39
|
+
"retained_pool_recall_at_5", "context_count")
|
|
40
|
+
_CRITERIA = tuple(_PREFIX + name for name in (*_NUMERIC, "answer_semantic_quality"))
|
|
41
|
+
_RANKING_POPULATION = {
|
|
42
|
+
"boundary": "N17_retained_stage_pool",
|
|
43
|
+
"denominator": "retained_inherited_chunk_pool",
|
|
44
|
+
"source_truth_rule": "native_complete_source_span_inheritance.v1",
|
|
45
|
+
"duplicate_credit": "overlapping_or_duplicate_inherited_chunks_receive_separate_native_credit",
|
|
46
|
+
"interpretation": "conditional_stage_pool_diagnostic_not_fixed_source_evidence_recall",
|
|
47
|
+
}
|
|
48
|
+
_RANKING_LIMITS = ["ranking_diagnostics_condition_on_retained_inherited_chunk_pool",
|
|
49
|
+
"overlapping_or_duplicate_chunks_receive_separate_native_credit",
|
|
50
|
+
"not_end_to_end_source_evidence_recall"]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _metric_population(name):
|
|
54
|
+
return {"selection": "first_success_or_last_failed_per_case_trial", "missing": "excluded_with_coverage",
|
|
55
|
+
**(_RANKING_POPULATION if name.startswith("retained_pool_") else {})}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _require(value, message):
|
|
59
|
+
if not value:
|
|
60
|
+
raise WorkflowContractError(message)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _validate_reference(value):
|
|
64
|
+
_require(type(value) is dict and set(value) == {"source_sha256", "source_version", "task"},
|
|
65
|
+
"integrated reference fields differ")
|
|
66
|
+
_require(type(value["task"]) is dict and type(value["task"].get("should_call_rag")) is bool,
|
|
67
|
+
"integrated source reference is incomplete")
|
|
68
|
+
_require(all(type(value[key]) is str and value[key] for key in ("source_sha256", "source_version")),
|
|
69
|
+
"integrated reference revision is incomplete")
|
|
70
|
+
require_digest(value["source_sha256"], "reference source sha256")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _validate_stage(value):
|
|
74
|
+
required = {"schema_version", "run_id", "case_id", "trial", "attempt", "stage_id", "occurrence",
|
|
75
|
+
"operation", "input_digest", "input", "output", "output_digest", "status", "implementation"}
|
|
76
|
+
_require(type(value) is dict and required <= set(value)
|
|
77
|
+
and set(value) <= required | {"parent_elapsed_seconds", "error_type"},
|
|
78
|
+
"integrated stage fields differ")
|
|
79
|
+
_require(value["schema_version"] == INTEGRATED_STAGE_SCHEMA and value["stage_id"] in INTEGRATED_STAGES
|
|
80
|
+
and type(value["occurrence"]) is int and value["occurrence"] == 1
|
|
81
|
+
and value["status"] in {"started", "completed", "failed"},
|
|
82
|
+
"integrated stage identity/status differs")
|
|
83
|
+
_require(all(type(value[key]) is str and value[key] for key in ("run_id", "case_id", "operation"))
|
|
84
|
+
and all(type(value[key]) is int and value[key] > 0 for key in ("trial", "attempt"))
|
|
85
|
+
and type(value["input"]) is dict and type(value["implementation"]) is dict,
|
|
86
|
+
"integrated stage identity/payload types differ")
|
|
87
|
+
_require(value["input_digest"] == value_digest(value["input"]), "integrated stage input digest differs")
|
|
88
|
+
if value["status"] == "completed":
|
|
89
|
+
_require(value["output_digest"] == value_digest(value["output"]), "integrated stage output digest differs")
|
|
90
|
+
else:
|
|
91
|
+
_require(value["output"] is None and value["output_digest"] is None, "uncompleted stage has an output")
|
|
92
|
+
if "parent_elapsed_seconds" in value:
|
|
93
|
+
n = value["parent_elapsed_seconds"]
|
|
94
|
+
_require(type(n) in (float, int) and math.isfinite(n) and n >= 0, "stage wall observation differs")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _validate_report(value):
|
|
98
|
+
_require(type(value) is dict and value.get("schema_version") == _REPORT
|
|
99
|
+
and set(value) == {"schema_version", "run_id", "grading_id", "candidate", "scope", "metrics",
|
|
100
|
+
"counts", "selection", "assessment_rows", "trust_tier", "limitations"},
|
|
101
|
+
"integrated report fields differ")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _evaluate(context):
|
|
105
|
+
"""Deterministic source-bound diagnostics; no inferred answer-quality label."""
|
|
106
|
+
output = _thaw(context.outputs)
|
|
107
|
+
reference = _thaw(context.references)
|
|
108
|
+
_require(reference["task"]["task_id"] == context.case.case_id, "reference belongs to another case")
|
|
109
|
+
fields = dict(evaluator_id=_EVALUATOR, case_id=context.case.case_id,
|
|
110
|
+
run_id=context.run_id, grading_id=context.grading_id,
|
|
111
|
+
trial=context.metadata["trial"], attempt=context.metadata["attempt"],
|
|
112
|
+
evidence_ids=tuple(e.evidence_id for e in context.evidence))
|
|
113
|
+
def assessment(name, kind, value=None, availability="available", reason=None):
|
|
114
|
+
return Assessment(_PREFIX + name, kind=kind, value=value, availability=availability, reason=reason, **fields)
|
|
115
|
+
failure = context.metadata["candidate_failure"]
|
|
116
|
+
rows = [assessment("execution_completed", "assertion", failure is None)]
|
|
117
|
+
observed = output.get("routing_decision")
|
|
118
|
+
rows.append(assessment("routing_correct", "assertion", observed == reference["task"]["should_call_rag"])
|
|
119
|
+
if type(observed) is bool else assessment("routing_correct", "assertion", availability="missing",
|
|
120
|
+
reason="router_output_not_retained"))
|
|
121
|
+
retrieval = output.get("retrieval")
|
|
122
|
+
score = None
|
|
123
|
+
if retrieval is not None:
|
|
124
|
+
score, _ = _score(reference["task"], retrieval["response"], retrieval["request"])
|
|
125
|
+
for name in ("ndcg_at_5", "recall_at_5"):
|
|
126
|
+
value = None if score is None else score["stage_metrics"]["N17"][name]
|
|
127
|
+
rows.append(assessment("retained_pool_" + name, "score", value) if value is not None else
|
|
128
|
+
assessment("retained_pool_" + name, "score", availability="undefined" if score is not None else "missing",
|
|
129
|
+
reason="native_metric_population_undefined" if score is not None else
|
|
130
|
+
"source_labels_unavailable" if retrieval is not None else "retrieval_not_observed"))
|
|
131
|
+
context_output = output.get("context")
|
|
132
|
+
rows.append(assessment("context_count", "score", len(context_output["rows"])) if context_output is not None else
|
|
133
|
+
assessment("context_count", "score", availability="missing", reason="context_not_observed"))
|
|
134
|
+
rows.append(assessment("answer_semantic_quality", "label", availability="missing",
|
|
135
|
+
reason="evidence_bound_semantic_review_not_provided"))
|
|
136
|
+
return tuple(rows)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _planned(record):
|
|
140
|
+
definition = record["run"]["definition"]
|
|
141
|
+
return tuple((case["case_id"], trial) for case in definition["cases"]
|
|
142
|
+
for trial in range(1, definition["policy"]["trials"] + 1))
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _assessment_index(record):
|
|
146
|
+
result = {}
|
|
147
|
+
for row in record["rows"]:
|
|
148
|
+
if row["failure"] is not None:
|
|
149
|
+
continue
|
|
150
|
+
for assessment in row["output"]["assessments"]:
|
|
151
|
+
key = (row["case_id"], row["trial"], assessment["criterion_id"])
|
|
152
|
+
_require(key not in result, "duplicate selected integrated assessment")
|
|
153
|
+
result[key] = assessment
|
|
154
|
+
return result
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _missing_reasons(record):
|
|
158
|
+
"""Index each lane once; absent pairs must not rescan the whole cohort."""
|
|
159
|
+
selected, grading = _selection(record["run"]), {}
|
|
160
|
+
for row in record["rows"]:
|
|
161
|
+
key = (row["case_id"], row["trial"])
|
|
162
|
+
state = grading.setdefault(key, {"successful": False, "last_failure": None})
|
|
163
|
+
state["successful"] |= row["failure"] is None
|
|
164
|
+
state["last_failure"] = row["failure"]
|
|
165
|
+
result = {}
|
|
166
|
+
for key in _planned(record):
|
|
167
|
+
state = grading.get(key)
|
|
168
|
+
if key not in selected:
|
|
169
|
+
result[key] = "candidate_not_started"
|
|
170
|
+
elif state is None:
|
|
171
|
+
result[key] = "grading_not_started_or_unavailable"
|
|
172
|
+
elif not state["successful"]:
|
|
173
|
+
result[key] = "grading_failed:" + state["last_failure"]
|
|
174
|
+
else:
|
|
175
|
+
result[key] = "criterion_not_assessed"
|
|
176
|
+
return result
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _reduce(record):
|
|
180
|
+
"""Mean trials within each case, then equal weight to eligible cases."""
|
|
181
|
+
values, coverage = defaultdict(lambda: defaultdict(list)), defaultdict(Counter)
|
|
182
|
+
planned, index = _planned(record), _assessment_index(record)
|
|
183
|
+
for case, trial in planned:
|
|
184
|
+
for name in _CRITERIA:
|
|
185
|
+
assessment = index.get((case, trial, name))
|
|
186
|
+
availability = "ungraded" if assessment is None else assessment["availability"]
|
|
187
|
+
coverage[name][availability] += 1
|
|
188
|
+
if assessment is not None and availability == "available" and assessment["kind"] in {"assertion", "score"}:
|
|
189
|
+
values[name][case].append(float(assessment["value"]))
|
|
190
|
+
metrics = {}
|
|
191
|
+
for name in _NUMERIC:
|
|
192
|
+
identifier = _PREFIX + name
|
|
193
|
+
case_values = [sum(v) / len(v) for v in values[identifier].values()]
|
|
194
|
+
metrics[identifier] = {"value": sum(case_values) / len(case_values) if case_values else None,
|
|
195
|
+
"eligible_cases": len(case_values), "planned_trials": len(planned),
|
|
196
|
+
"ungraded_trials": coverage[identifier]["ungraded"], "coverage": dict(coverage[identifier]),
|
|
197
|
+
"population": _metric_population(name)}
|
|
198
|
+
return {"policy_id": _REDUCER, "metrics": metrics,
|
|
199
|
+
"coverage": {key: dict(value) for key, value in coverage.items()}}
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _project(record):
|
|
203
|
+
run, grading = record["run"], record["definition"]
|
|
204
|
+
selected = _selection(run)
|
|
205
|
+
rows = [a for row in record["rows"] if row["failure"] is None for a in row["output"]["assessments"]]
|
|
206
|
+
planned = len(run["definition"]["cases"]) * run["definition"]["policy"]["trials"]
|
|
207
|
+
return {"schema_version": _REPORT, "run_id": grading["run_id"], "grading_id": grading["grading_id"],
|
|
208
|
+
"candidate": run["definition"]["candidate_identity"], "scope": run["definition"]["identity"]["scope"],
|
|
209
|
+
"metrics": record.get("analysis", {}).get("metrics", {}),
|
|
210
|
+
"counts": {"candidate_attempts": len(run["attempts"]),
|
|
211
|
+
"failed_candidate_attempts": sum(a["failure"] is not None for a in run["attempts"]),
|
|
212
|
+
"grading_attempts": len(record["rows"]),
|
|
213
|
+
"failed_grading_attempts": sum(a["failure"] is not None for a in record["rows"]),
|
|
214
|
+
"planned_trials": planned, "selected_trials": len(selected),
|
|
215
|
+
"graded_trials": len({(r["case_id"], r["trial"]) for r in record["rows"] if r["failure"] is None})},
|
|
216
|
+
"selection": [{"case_id": case, "trial": trial, "attempt": row["attempt"], "failure": row["failure"]}
|
|
217
|
+
for (case, trial), row in sorted(selected.items())],
|
|
218
|
+
"assessment_rows": rows, "trust_tier": "local_unverified",
|
|
219
|
+
"limitations": ["caller_declared_revision_not_code_attestation", "semantic_review_unavailable",
|
|
220
|
+
"source_span_represented_documents", "local_stage_wall_times_not_service_latency", *_RANKING_LIMITS]}
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _compare(baseline, candidate):
|
|
224
|
+
left, right = (record["run"]["definition"] for record in (baseline, candidate))
|
|
225
|
+
_require(left["candidate_identity"]["context_policy"] == right["candidate_identity"]["context_policy"],
|
|
226
|
+
"integrated context policies differ")
|
|
227
|
+
planned = _planned(baseline)
|
|
228
|
+
_require(planned == _planned(candidate), "integrated planned comparison cohort differs")
|
|
229
|
+
a, b, pairs, metrics = _assessment_index(baseline), _assessment_index(candidate), [], {}
|
|
230
|
+
baseline_absent, candidate_absent = _missing_reasons(baseline), _missing_reasons(candidate)
|
|
231
|
+
for name in _NUMERIC:
|
|
232
|
+
criterion = _PREFIX + name
|
|
233
|
+
case_deltas = defaultdict(list)
|
|
234
|
+
eligible = excluded = 0
|
|
235
|
+
baseline_ungraded = candidate_ungraded = 0
|
|
236
|
+
for case, trial in planned:
|
|
237
|
+
key = (case, trial, criterion)
|
|
238
|
+
x, y = a.get(key), b.get(key)
|
|
239
|
+
baseline_ungraded += x is None
|
|
240
|
+
candidate_ungraded += y is None
|
|
241
|
+
valid = x is not None and y is not None and x["availability"] == y["availability"] == "available"
|
|
242
|
+
delta = float(y["value"]) - float(x["value"]) if valid else None
|
|
243
|
+
pairs.append({"case_id": key[0], "trial": key[1], "criterion_id": criterion,
|
|
244
|
+
"baseline": None if x is None else x["value"], "candidate": None if y is None else y["value"],
|
|
245
|
+
"delta": delta, "availability": "available" if valid else "unavailable",
|
|
246
|
+
"baseline_availability": "ungraded" if x is None else x["availability"],
|
|
247
|
+
"candidate_availability": "ungraded" if y is None else y["availability"],
|
|
248
|
+
"baseline_reason": baseline_absent[(case, trial)] if x is None else x["reason"],
|
|
249
|
+
"candidate_reason": candidate_absent[(case, trial)] if y is None else y["reason"]})
|
|
250
|
+
if valid:
|
|
251
|
+
eligible += 1
|
|
252
|
+
case_deltas[key[0]].append(delta)
|
|
253
|
+
else:
|
|
254
|
+
excluded += 1
|
|
255
|
+
means = [sum(v) / len(v) for v in case_deltas.values()]
|
|
256
|
+
metrics[criterion] = {"candidate_minus_baseline": sum(means) / len(means) if means else None,
|
|
257
|
+
"planned_pairs": len(planned), "eligible_pairs": eligible, "excluded_pairs": excluded,
|
|
258
|
+
"baseline_ungraded_trials": baseline_ungraded, "candidate_ungraded_trials": candidate_ungraded,
|
|
259
|
+
"eligible_cases": len(means), "population": _metric_population(name)}
|
|
260
|
+
return {"policy_id": _COMPARISON, "baseline_run_id": left["run_id"], "candidate_run_id": right["run_id"],
|
|
261
|
+
"baseline_revision": left["candidate_identity"]["revision"],
|
|
262
|
+
"candidate_revision": right["candidate_identity"]["revision"], "metrics": metrics, "pairs": pairs,
|
|
263
|
+
"verdict": None, "reason": "no_quality_gate_or_statistical_significance_policy_selected",
|
|
264
|
+
"limitations": list(_RANKING_LIMITS)}
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _bound_context_evaluator(registry):
|
|
268
|
+
"""Opt-in adapter: keep the native criterion while binding its stage input."""
|
|
269
|
+
from dataclasses import replace
|
|
270
|
+
from .evaluator_bindings import (
|
|
271
|
+
EvaluatorBinding, InputRequirement, _dispatch_binding, _schema_identity,
|
|
272
|
+
)
|
|
273
|
+
evaluator_id = "sphynx.rag.integrated.context-count-stage.v1"
|
|
274
|
+
criterion_id = _PREFIX + "context_count"
|
|
275
|
+
schema = registry.get_schema(INTEGRATED_STAGE_SCHEMA)
|
|
276
|
+
|
|
277
|
+
def count_stage(context):
|
|
278
|
+
stage = context.outputs
|
|
279
|
+
available = stage.get("status") == "completed"
|
|
280
|
+
return (Assessment(criterion_id, evaluator_id, context.case.case_id, "score",
|
|
281
|
+
"available" if available else "missing",
|
|
282
|
+
len(stage["output"]["rows"]) if available else None,
|
|
283
|
+
reason=None if available else "context_not_observed",
|
|
284
|
+
evidence_ids=tuple(item.evidence_id for item in context.evidence),
|
|
285
|
+
run_id=context.run_id, grading_id=context.grading_id,
|
|
286
|
+
trial=context.metadata["trial"], attempt=context.metadata["attempt"]),)
|
|
287
|
+
|
|
288
|
+
definition = EvaluatorDefinition(evaluator_id, "v1", evaluator_id, (criterion_id,),
|
|
289
|
+
metric_ids=(criterion_id,))
|
|
290
|
+
registry.register_evaluator(definition, count_stage)
|
|
291
|
+
binding = EvaluatorBinding.for_evaluator("sphynx.integrated.context-count-binding.v1", "v1",
|
|
292
|
+
definition, target="stage", stage_id="context", stage_schema=_schema_identity(schema),
|
|
293
|
+
requirements=(InputRequirement.for_schema("outputs", schema, fields=("status",), optional=True),))
|
|
294
|
+
|
|
295
|
+
def evaluate(context):
|
|
296
|
+
# IntegratedBackend._run verified these terminal snapshots against the
|
|
297
|
+
# retained artifact bytes before this grading context was constructed.
|
|
298
|
+
selector = binding.selector(context)
|
|
299
|
+
raw = context.outputs.get("stages", {}).get("context")
|
|
300
|
+
if raw is None:
|
|
301
|
+
evidence = EvidenceView(context.run_id + ":unobserved:" + contract_digest(selector.to_dict()),
|
|
302
|
+
None, "application/json", "stage.event", "verified_integrated_grading", "candidate_permitted",
|
|
303
|
+
INTEGRATED_STAGE_SCHEMA, selector.case_id, selector.stage_id, "unavailable",
|
|
304
|
+
{"run_id": context.run_id, "trial": selector.trial, "attempt": selector.attempt})
|
|
305
|
+
stage = StageEvidence.unavailable(selector, evidence, reason="context_not_observed")
|
|
306
|
+
else:
|
|
307
|
+
value = _thaw(raw); artifact = value.pop("artifact")
|
|
308
|
+
_require((value["run_id"], value["case_id"], value["trial"], value["attempt"],
|
|
309
|
+
value["stage_id"], value["occurrence"]) ==
|
|
310
|
+
(context.run_id, selector.case_id, selector.trial, selector.attempt,
|
|
311
|
+
selector.stage_id, selector.occurrence), "context stage grading selection differs")
|
|
312
|
+
matching = [item for item in context.evidence
|
|
313
|
+
if item.evidence_id == context.run_id + ":" + artifact["path"]
|
|
314
|
+
and item.sha256 == artifact["sha256"]]
|
|
315
|
+
_require(len(matching) == 1, "context stage lacks its verified retained artifact")
|
|
316
|
+
evidence = replace(matching[0], schema_version=INTEGRATED_STAGE_SCHEMA,
|
|
317
|
+
step_id=selector.stage_id, metadata={**_thaw(matching[0].metadata), "run_id": context.run_id})
|
|
318
|
+
stage = StageEvidence.projected(selector, evidence, value, schema=schema)
|
|
319
|
+
bound = _dispatch_binding(registry, binding, context, stage=stage)
|
|
320
|
+
allowed = {item.evidence_id for item in context.evidence}
|
|
321
|
+
# The primary native evaluator composes the child. Its new implementation
|
|
322
|
+
# identity and metadata bind that child; stable native criterion IDs remain.
|
|
323
|
+
mapped = tuple(replace(row, evaluator_id=_EVALUATOR,
|
|
324
|
+
evidence_ids=tuple(key for key in row.evidence_ids if key in allowed)) for row in bound)
|
|
325
|
+
return tuple(row for row in _evaluate(context) if row.criterion_id != criterion_id) + mapped
|
|
326
|
+
|
|
327
|
+
primary = EvaluatorDefinition(_EVALUATOR, "v1", _EVALUATOR + ".context-binding.v1", _CRITERIA,
|
|
328
|
+
metric_ids=tuple(_PREFIX + name for name in _NUMERIC),
|
|
329
|
+
configuration={"stage_binding": binding.to_dict(), "composition": "native-criterion-stage-adapter.v1"})
|
|
330
|
+
return primary, evaluate
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class IntegratedBackend(LifecycleBackend):
|
|
334
|
+
"""One configured local system boundary with protected native references.
|
|
335
|
+
|
|
336
|
+
``authorize_references(case_id, access)`` must return True before source
|
|
337
|
+
labels can be loaded for grading. It grants no candidate access. The default
|
|
338
|
+
evaluator reports structural/routing/retrieval diagnostics; answer semantic
|
|
339
|
+
quality remains missing. For different criteria or bound reviews, register
|
|
340
|
+
the driver with the general LifecycleBackend and explicit domain callbacks.
|
|
341
|
+
"""
|
|
342
|
+
def __init__(self, registry: WorkflowRegistry, driver: IntegratedDriver, *, authorize_references,
|
|
343
|
+
reference_access=None, run_policy=None, grading_policy=None, suite_id="rag.integrated.v1",
|
|
344
|
+
bind_context_evaluator=False):
|
|
345
|
+
_require(isinstance(driver, IntegratedDriver) and callable(authorize_references),
|
|
346
|
+
"integrated backend needs driver and explicit reference authorization")
|
|
347
|
+
_require(type(bind_context_evaluator) is bool, "bind_context_evaluator must be boolean")
|
|
348
|
+
source = driver.pipeline.source
|
|
349
|
+
schema = registry.register_schema(PayloadSchema(_CASE_SCHEMA, "v1", "sphynx.pipeline.case-validator.v1", _validate_case))
|
|
350
|
+
reference = registry.register_schema(PayloadSchema(_REFERENCE, "v1", "sphynx.integrated.reference-validator.v1", _validate_reference))
|
|
351
|
+
registry.register_schema(PayloadSchema(INTEGRATED_STAGE_SCHEMA, "v1", "sphynx.integrated.stage-record-validator.v1", _validate_stage))
|
|
352
|
+
registry.register_schema(PayloadSchema(_REPORT, "v1", "sphynx.integrated.report-validator.v1", _validate_report))
|
|
353
|
+
definition = DatasetDefinition(source.dataset_id, source.version, suite_id + ".provider", _CASE_SCHEMA, _REFERENCE,
|
|
354
|
+
selection={"case_ids": list(source.case_ids), "order": "native_dataset_order"},
|
|
355
|
+
identity={"source_sha256": source.sha256, "reference_revision": source.version,
|
|
356
|
+
"reference_rule": "native_complete_source_span_inheritance.v1"})
|
|
357
|
+
def load_reference(case_id):
|
|
358
|
+
_, tasks = driver.pipeline._loaded()
|
|
359
|
+
task = next((task for task in tasks if task["task_id"] == case_id), None)
|
|
360
|
+
_require(task is not None, "reference case is outside the selected cohort")
|
|
361
|
+
return {"source_sha256": source.sha256, "source_version": source.version, "task": task}
|
|
362
|
+
registry.register_provider(Dataset(definition, schema, lambda selection: driver.cases(),
|
|
363
|
+
reference_schema=reference, reference_loader=load_reference, authorize_references=authorize_references))
|
|
364
|
+
for identifier in _CRITERIA:
|
|
365
|
+
registry.register_criterion(Criterion(identifier, "v1", identifier.rsplit(".", 1)[-1]))
|
|
366
|
+
registry.register_policy(_REDUCER, version="v1", implementation_id=_REDUCER, kind="aggregation", callback=_reduce,
|
|
367
|
+
metadata={"population": "first_success_or_last_failed_per_case_trial; available_values_only",
|
|
368
|
+
"weights": "mean_trials_within_case_then_equal_case_mean"})
|
|
369
|
+
registry.register_policy(_COMPARISON, version="v1", implementation_id=_COMPARISON, kind="comparison", callback=_compare,
|
|
370
|
+
metadata={"population": "same_case_trial_available_pairs", "quality_gate": None})
|
|
371
|
+
for name in _NUMERIC:
|
|
372
|
+
registry.register_metric(MetricSpec(_PREFIX + name, "v1", "count" if name == "context_count" else "ratio",
|
|
373
|
+
"descriptive" if name == "context_count" else "higher", _REDUCER, _COMPARISON,
|
|
374
|
+
population=_metric_population(name)))
|
|
375
|
+
if bind_context_evaluator:
|
|
376
|
+
evaluator, callback = _bound_context_evaluator(registry)
|
|
377
|
+
registry.register_evaluator(evaluator, callback)
|
|
378
|
+
else:
|
|
379
|
+
registry.register_evaluator(EvaluatorDefinition(_EVALUATOR, "v1", _EVALUATOR, _CRITERIA,
|
|
380
|
+
metric_ids=tuple(_PREFIX + name for name in _NUMERIC)), _evaluate)
|
|
381
|
+
registry.register_projection(_REPORT, _project, version="v1", implementation_id="sphynx.integrated.projection.v1")
|
|
382
|
+
suite = SuiteDefinition(suite_id, "v1", "sphynx.integrated." + suite_id, "Integrated retrieval, context and answer",
|
|
383
|
+
configuration={"boundary": "sphynx.rag.integrated.v1", "pipeline": driver.pipeline.describe(driver.pipeline.suite_id).to_dict(),
|
|
384
|
+
"context_policy": {"max_bytes": driver.max_context_bytes,
|
|
385
|
+
"selection": "whole_chunks_in_final_rank_order_utf8_bytes.v1"}},
|
|
386
|
+
criterion_ids=_CRITERIA, evaluator_ids=(_EVALUATOR,), metric_ids=tuple(_PREFIX + name for name in _NUMERIC),
|
|
387
|
+
required_capabilities=(STAGE_EVIDENCE_CAPABILITY,), datasets=(definition,),
|
|
388
|
+
metadata={"candidate_source_bytes_verified": False, "semantic_review": "not_provided"})
|
|
389
|
+
def admit(plan, cases):
|
|
390
|
+
admitted = driver.admit(plan.candidate)
|
|
391
|
+
_require(tuple(c.case_id for c in cases) == source.case_ids, "integrated selected case order differs")
|
|
392
|
+
return {"artifact_bytes_verified": admitted.artifact_bytes_verified, "candidate_source_bytes_verified": False,
|
|
393
|
+
"fixed": {"boundary": "sphynx.rag.integrated.v1", "source": source.to_dict(),
|
|
394
|
+
"context_policy": _thaw(suite.configuration["context_policy"])},
|
|
395
|
+
"candidate": {"identity": driver.candidate_identity(plan.candidate),
|
|
396
|
+
"pipeline_admission": admitted.to_dict()}}
|
|
397
|
+
super().__init__(registry, suite, driver=driver, evaluator_id=_EVALUATOR, projection_schema_id=_REPORT,
|
|
398
|
+
comparison_policy_id=_COMPARISON, run_policy=run_policy or RunPolicy(reducer_id=_REDUCER),
|
|
399
|
+
grading_policy=grading_policy, reference_access=reference_access, admission_verifier=admit,
|
|
400
|
+
scopes=("system",), capabilities=(STAGE_EVIDENCE_CAPABILITY, "sphynx.rag.integrated.v1"),
|
|
401
|
+
include_emitted_evidence=bind_context_evaluator)
|
|
402
|
+
registry.register_backend(self)
|
|
403
|
+
registry.register_suite(suite)
|
|
404
|
+
|
|
405
|
+
@staticmethod
|
|
406
|
+
def _comparison_conditions(baseline, candidate):
|
|
407
|
+
LifecycleBackend._comparison_conditions(baseline, candidate)
|
|
408
|
+
left, right = (record["run"]["definition"] for record in (baseline, candidate))
|
|
409
|
+
_comparison_require(left["candidate_identity"]["context_policy"] == right["candidate_identity"]["context_policy"],
|
|
410
|
+
"integrated context policies differ")
|
|
411
|
+
_comparison_require(_planned(baseline) == _planned(candidate), "integrated planned comparison cohort differs")
|
|
412
|
+
|
|
413
|
+
def project_comparison(self, sources, native):
|
|
414
|
+
from ._comparison_adapters import _integrated_view
|
|
415
|
+
return _integrated_view(sources, native, {item.metric_id: item for item in self.registry.list_metrics()})
|
|
416
|
+
|
|
417
|
+
def _run(self, ref):
|
|
418
|
+
record = super()._run(ref)
|
|
419
|
+
_require(record["definition"]["identity"]["scope"] == "system"
|
|
420
|
+
and record["definition"]["identity"]["mode"] == "local", "integrated saved scope/mode differs")
|
|
421
|
+
cases = {case["case_id"]: case for case in record["definition"]["cases"]}
|
|
422
|
+
identity = record["definition"]["candidate_identity"]
|
|
423
|
+
journal = LifecycleJournal(ref.path, ref.definition_sha256)
|
|
424
|
+
emitted = {e["data"]["binding"]["path"]: e["data"] for e in record["events"] if e["event"] == "artifact"}
|
|
425
|
+
for attempt in record["attempts"]:
|
|
426
|
+
output = attempt["outputs"]
|
|
427
|
+
if not output:
|
|
428
|
+
_require(attempt["failure"] is not None, "successful integrated attempt has no output")
|
|
429
|
+
continue
|
|
430
|
+
_require(output.get("schema_version") == INTEGRATED_SCHEMA
|
|
431
|
+
and (output["case_id"], output["trial"], output["attempt"]) ==
|
|
432
|
+
(attempt["case_id"], attempt["trial"], attempt["attempt"])
|
|
433
|
+
and output["candidate_revision"] == identity["revision"]
|
|
434
|
+
and output["input_digest"] == contract_digest(cases[attempt["case_id"]])
|
|
435
|
+
and output["candidate_identity_digest"] == value_digest(identity), "integrated output binding differs")
|
|
436
|
+
terminals, order = {}, []
|
|
437
|
+
for index, event in enumerate(output["events"]):
|
|
438
|
+
_require(event["sequence"] == index and event["stage_id"] in INTEGRATED_STAGES
|
|
439
|
+
and event["occurrence"] == 1 and event["phase"] in {"started", "completed", "failed"},
|
|
440
|
+
"integrated event sequence differs")
|
|
441
|
+
if event["phase"] == "started":
|
|
442
|
+
order.append(event["stage_id"])
|
|
443
|
+
binding = event["artifact"]
|
|
444
|
+
native = emitted.get(binding["path"])
|
|
445
|
+
_require(native is not None and native["binding"] == binding and
|
|
446
|
+
binding["role"] == "integrated." + event["stage_id"] + "." + event["phase"] and
|
|
447
|
+
(native["case_id"], native["trial"], native["attempt"]) ==
|
|
448
|
+
(attempt["case_id"], attempt["trial"], attempt["attempt"]), "stage event is outside its attempt")
|
|
449
|
+
if native["truncated"]:
|
|
450
|
+
continue
|
|
451
|
+
value = json.loads(journal.read_artifact(binding)); _validate_stage(value)
|
|
452
|
+
_require((value["run_id"], value["case_id"], value["trial"], value["attempt"], value["stage_id"], value["occurrence"], value["status"]) ==
|
|
453
|
+
(ref.run_id, attempt["case_id"], attempt["trial"], attempt["attempt"], event["stage_id"], event["occurrence"], event["phase"]),
|
|
454
|
+
"stage event selector binding differs")
|
|
455
|
+
if event["phase"] != "started":
|
|
456
|
+
_require(event["stage_id"] not in terminals, "integrated stage has duplicate terminal events")
|
|
457
|
+
terminals[event["stage_id"]] = event["phase"]
|
|
458
|
+
_require(output["stages"].get(event["stage_id"]) == {**value, "artifact": binding}, "stage snapshot differs from retained bytes")
|
|
459
|
+
_require(order == list(INTEGRATED_STAGES[:len(order)]) and set(output["stages"]) == set(terminals),
|
|
460
|
+
"integrated stages are not the retained execution prefix")
|
|
461
|
+
if attempt["failure"] is None:
|
|
462
|
+
expected = ["router"] if output.get("routing_decision") is False else list(INTEGRATED_STAGES)
|
|
463
|
+
_require(list(terminals) == expected and set(terminals.values()) == {"completed"},
|
|
464
|
+
"successful integrated execution lacks required stages")
|
|
465
|
+
retrieval = output.get("retrieval")
|
|
466
|
+
if retrieval is not None:
|
|
467
|
+
request = retrieval["request"]
|
|
468
|
+
body = dict(request); digest = body.pop("input_digest")
|
|
469
|
+
_require(value_digest(body) == digest and request["case_id"] == attempt["case_id"]
|
|
470
|
+
and request["query"] == output["rewritten_query"]
|
|
471
|
+
and request["documents"] == cases[attempt["case_id"]]["inputs"]["documents"],
|
|
472
|
+
"retained retrieval request/source binding differs")
|
|
473
|
+
from .pipeline import validate_pipeline_response
|
|
474
|
+
validate_pipeline_response(retrieval["response"], request)
|
|
475
|
+
for kind, value in retrieval["response"]["stages"].items():
|
|
476
|
+
_require(output["stages"][kind]["output"] == value, "retrieval response differs from stage artifact")
|
|
477
|
+
if output.get("context") is not None:
|
|
478
|
+
expected = build_context(retrieval["response"], request["documents"], identity["context_policy"]["max_bytes"])
|
|
479
|
+
_require(output["context"] == expected and output["stages"]["context"]["output"] == expected,
|
|
480
|
+
"integrated context differs from retained retrieval")
|
|
481
|
+
if output.get("answer") is not None:
|
|
482
|
+
generated = output["stages"]["generator"]
|
|
483
|
+
_require(generated["input"]["contexts"] == output["context"]["rows"]
|
|
484
|
+
and generated["input"]["query"] == output["rewritten_query"], "generator handoff differs")
|
|
485
|
+
validate_answer(generated["output"], output["context"])
|
|
486
|
+
_require(all(generated["output"].get(key, [] if key == "citations" else None) == output[key]
|
|
487
|
+
for key in ("answer", "citations", "abstained", "token_counts")), "answer differs from generation artifact")
|
|
488
|
+
return record
|
|
489
|
+
|
|
490
|
+
def _references(self, run_record):
|
|
491
|
+
references = super()._references(run_record)
|
|
492
|
+
source = self.driver.pipeline.source
|
|
493
|
+
for case, reference in references.items():
|
|
494
|
+
_require(reference["source_sha256"] == source.sha256 and reference["source_version"] == source.version
|
|
495
|
+
and reference["task"]["task_id"] == case, "integrated reference revision/case differs")
|
|
496
|
+
return references
|
|
497
|
+
|
|
498
|
+
def stage_evidence(self, native_ref, selector):
|
|
499
|
+
if not isinstance(selector, StageSelector) or selector.stage_id not in INTEGRATED_STAGES or selector.occurrence != 1:
|
|
500
|
+
raise StageContractError("integrated stage selection requires a supported exact selector")
|
|
501
|
+
run_ref = native_ref.run if isinstance(native_ref, LifecycleGradingRef) else native_ref
|
|
502
|
+
record = self._run(run_ref)
|
|
503
|
+
if isinstance(native_ref, LifecycleGradingRef):
|
|
504
|
+
self._grading(native_ref)
|
|
505
|
+
starts = {(e["data"]["case_id"], e["data"]["trial"], e["data"]["attempt"])
|
|
506
|
+
for e in record["events"] if e["event"] == "candidate_started"}
|
|
507
|
+
if (selector.case_id, selector.trial, selector.attempt) not in starts:
|
|
508
|
+
raise StageContractError("stage selector is outside the run's attempted cohort")
|
|
509
|
+
journal, result = LifecycleJournal(run_ref.path, run_ref.definition_sha256), []
|
|
510
|
+
for event in record["events"]:
|
|
511
|
+
data = event["data"]
|
|
512
|
+
if event["event"] != "artifact" or (data["case_id"], data["trial"], data["attempt"]) != (selector.case_id, selector.trial, selector.attempt):
|
|
513
|
+
continue
|
|
514
|
+
binding = data["binding"]
|
|
515
|
+
if not binding["role"].startswith("integrated." + selector.stage_id + "."):
|
|
516
|
+
continue
|
|
517
|
+
evidence = EvidenceView(run_ref.run_id + ":" + binding["path"], binding["sha256"], "application/json",
|
|
518
|
+
"stage.event", "parent_retained_integrated_stage", "candidate_permitted", INTEGRATED_STAGE_SCHEMA,
|
|
519
|
+
selector.case_id, selector.stage_id, "unavailable" if data["truncated"] else "available",
|
|
520
|
+
{"artifact_path": binding["path"], "journal_sequence": event["sequence"], "role": binding["role"],
|
|
521
|
+
"timing_authority": "parent_observed_local_stage_wall", "trial": selector.trial, "attempt": selector.attempt})
|
|
522
|
+
if data["truncated"]:
|
|
523
|
+
result.append(StageEvidence.unavailable(selector, evidence, reason="lifecycle_output_limit_truncated_stage_record"))
|
|
524
|
+
else:
|
|
525
|
+
value = json.loads(journal.read_artifact(binding))
|
|
526
|
+
_require((value["run_id"], value["case_id"], value["trial"], value["attempt"], value["stage_id"], value["occurrence"]) ==
|
|
527
|
+
(run_ref.run_id, selector.case_id, selector.trial, selector.attempt, selector.stage_id, selector.occurrence)
|
|
528
|
+
and binding["role"] == "integrated." + selector.stage_id + "." + value["status"],
|
|
529
|
+
"stage selector binding differs")
|
|
530
|
+
result.append(StageEvidence.projected(selector, evidence, value, schema=self.registry.get_schema(INTEGRATED_STAGE_SCHEMA)))
|
|
531
|
+
if result:
|
|
532
|
+
return tuple(result)
|
|
533
|
+
evidence = EvidenceView(run_ref.run_id + ":unobserved:" + contract_digest(selector.to_dict()), None,
|
|
534
|
+
"application/json", "stage.event", "parent_retained_integrated_stage", "candidate_permitted",
|
|
535
|
+
INTEGRATED_STAGE_SCHEMA, selector.case_id, selector.stage_id, "unavailable")
|
|
536
|
+
return (StageEvidence.unavailable(selector, evidence, reason="stage_not_observed_or_skipped"),)
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
def build_integrated_registry(driver: IntegratedDriver, *, authorize_references, reference_access=None,
|
|
540
|
+
run_policy=None, grading_policy=None, suite_id="rag.integrated.v1",
|
|
541
|
+
bind_context_evaluator=False) -> WorkflowRegistry:
|
|
542
|
+
"""Register configured local system execution; load no assets or references.
|
|
543
|
+
|
|
544
|
+
The default reducer is explicit equal-case mean of available trial means.
|
|
545
|
+
Plan policies can omit aggregation; per-case assessments remain available.
|
|
546
|
+
No quality gate, semantic review or authenticated revision is implied.
|
|
547
|
+
"""
|
|
548
|
+
registry = WorkflowRegistry(legacy_ids=(driver.pipeline.source.dataset_id,))
|
|
549
|
+
IntegratedBackend(registry, driver, authorize_references=authorize_references, reference_access=reference_access,
|
|
550
|
+
run_policy=run_policy, grading_policy=grading_policy, suite_id=suite_id,
|
|
551
|
+
bind_context_evaluator=bind_context_evaluator)
|
|
552
|
+
return registry
|