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.
Files changed (174) hide show
  1. sable_sphynx-0.7.0.dev0.dist-info/METADATA +152 -0
  2. sable_sphynx-0.7.0.dev0.dist-info/RECORD +174 -0
  3. sable_sphynx-0.7.0.dev0.dist-info/WHEEL +5 -0
  4. sable_sphynx-0.7.0.dev0.dist-info/top_level.txt +1 -0
  5. sphynx/__init__.py +469 -0
  6. sphynx/__init__.pyi +376 -0
  7. sphynx/_analytical_client.py +77 -0
  8. sphynx/_analytical_values.py +252 -0
  9. sphynx/_audit_client.py +173 -0
  10. sphynx/_comparison_adapters.py +113 -0
  11. sphynx/_componentized_full_rag.py +34 -0
  12. sphynx/_composed_pipeline.py +109 -0
  13. sphynx/_full_rag_grading.py +218 -0
  14. sphynx/_full_rag_trace.py +221 -0
  15. sphynx/_local_eval.py +268 -0
  16. sphynx/_pipeline_core.py +243 -0
  17. sphynx/_pr_client.py +237 -0
  18. sphynx/_rag_diagnostics_calibration.py +285 -0
  19. sphynx/_rag_diagnostics_catalog.py +39 -0
  20. sphynx/_rag_diagnostics_common.py +26 -0
  21. sphynx/_rag_diagnostics_contracts.py +186 -0
  22. sphynx/_rag_diagnostics_engine.py +243 -0
  23. sphynx/_rag_diagnostics_importers.py +242 -0
  24. sphynx/_rag_diagnostics_ranking.py +81 -0
  25. sphynx/_rag_diagnostics_semantic.py +325 -0
  26. sphynx/_rag_ranking.py +149 -0
  27. sphynx/_speech_benchmark_scoring.py +140 -0
  28. sphynx/_speech_benchmark_sources.py +275 -0
  29. sphynx/_speech_complete_scoring.py +218 -0
  30. sphynx/_speech_complete_source.py +118 -0
  31. sphynx/_speech_kido.py +294 -0
  32. sphynx/_speech_scoring.py +77 -0
  33. sphynx/_track_capture.py +213 -0
  34. sphynx/analytical_views.py +515 -0
  35. sphynx/assessment_contracts.py +378 -0
  36. sphynx/assessment_selection.py +57 -0
  37. sphynx/audit_access.py +245 -0
  38. sphynx/audit_contracts.py +204 -0
  39. sphynx/audit_requests.py +180 -0
  40. sphynx/authoring.py +188 -0
  41. sphynx/benchmarks.py +568 -0
  42. sphynx/candidates.py +62 -0
  43. sphynx/catalog.py +272 -0
  44. sphynx/chunking.py +372 -0
  45. sphynx/clickhouse_reader.py +169 -0
  46. sphynx/client.py +486 -0
  47. sphynx/comparison_core.py +149 -0
  48. sphynx/comparison_views.py +223 -0
  49. sphynx/components.py +1661 -0
  50. sphynx/contracts.py +514 -0
  51. sphynx/customer_rerank.py +299 -0
  52. sphynx/customer_retrieval.py +146 -0
  53. sphynx/data/benchmark-releases.v1.json +164 -0
  54. sphynx/data/public-benchmark-release.v1.json +354 -0
  55. sphynx/data/rag-diagnostics-synthetic.v1.json +6982 -0
  56. sphynx/data/rag-paper-references.v1.json +176 -0
  57. sphynx/data/rag-paper-schemas.v1.json +1069 -0
  58. sphynx/data/rag-rerank-v1.json +507 -0
  59. sphynx/dataset_catalog_data.py +1214 -0
  60. sphynx/dataset_readiness.py +138 -0
  61. sphynx/dataset_v3.py +999 -0
  62. sphynx/demo.py +130 -0
  63. sphynx/demo_candidates/__init__.py +1 -0
  64. sphynx/demo_candidates/dense.py +11 -0
  65. sphynx/demo_candidates/lexical.py +21 -0
  66. sphynx/diagnostics.py +207 -0
  67. sphynx/documentation.py +737 -0
  68. sphynx/documentation_candidate.py +939 -0
  69. sphynx/evals.py +538 -0
  70. sphynx/evaluation_protocols.py +124 -0
  71. sphynx/evaluator_bindings.py +370 -0
  72. sphynx/evidence.py +352 -0
  73. sphynx/execution_capabilities.py +109 -0
  74. sphynx/fast_search.py +285 -0
  75. sphynx/full_rag.py +341 -0
  76. sphynx/hosted/__init__.py +18 -0
  77. sphynx/hosted/benchmark_intake.py +218 -0
  78. sphynx/hosted/contracts.py +361 -0
  79. sphynx/hosted/model_admission.py +130 -0
  80. sphynx/hosted/model_artifacts.py +298 -0
  81. sphynx/hosted/model_contracts.py +63 -0
  82. sphynx/hosted/model_gcs.py +181 -0
  83. sphynx/hosted/model_history.py +84 -0
  84. sphynx/hosted/model_session.py +233 -0
  85. sphynx/hosted/public_suite.py +74 -0
  86. sphynx/hosted/registry.py +97 -0
  87. sphynx/hosted/revisions.py +126 -0
  88. sphynx/hosted/sandbox.py +105 -0
  89. sphynx/hosted/submission.py +287 -0
  90. sphynx/hosted_workflow.py +451 -0
  91. sphynx/http_transport.py +86 -0
  92. sphynx/integrated_rag.py +352 -0
  93. sphynx/integrated_workflow.py +552 -0
  94. sphynx/integration_contracts.py +474 -0
  95. sphynx/invocation.py +791 -0
  96. sphynx/invocation_candidates.py +392 -0
  97. sphynx/invocation_catalog_data.py +40 -0
  98. sphynx/learned_catalog_data.py +30 -0
  99. sphynx/learned_rerank.py +267 -0
  100. sphynx/legacy_full_rag.py +67 -0
  101. sphynx/lifecycle.py +885 -0
  102. sphynx/lifecycle_workflow.py +490 -0
  103. sphynx/metric_views.py +474 -0
  104. sphynx/metrics.py +282 -0
  105. sphynx/model_adapters.py +438 -0
  106. sphynx/model_catalog_data.py +30 -0
  107. sphynx/official_benchmarks.py +385 -0
  108. sphynx/packs.py +258 -0
  109. sphynx/pipeline.py +313 -0
  110. sphynx/pipeline_workflow.py +551 -0
  111. sphynx/pr_evaluations.py +560 -0
  112. sphynx/progress.py +89 -0
  113. sphynx/public_bundle.py +173 -0
  114. sphynx/public_eval.py +62 -0
  115. sphynx/public_rerank.py +355 -0
  116. sphynx/py.typed +0 -0
  117. sphynx/pytest_plugin.py +62 -0
  118. sphynx/question_robustness.py +437 -0
  119. sphynx/rag.py +329 -0
  120. sphynx/rag_diagnostics.py +309 -0
  121. sphynx/rag_papers/__init__.py +29 -0
  122. sphynx/rag_papers/__main__.py +45 -0
  123. sphynx/rag_papers/candidates.py +19 -0
  124. sphynx/rag_papers/contracts.py +282 -0
  125. sphynx/rag_papers/datasets.py +291 -0
  126. sphynx/rag_papers/experiments.py +116 -0
  127. sphynx/rag_papers/judges.py +308 -0
  128. sphynx/rag_papers/registry.py +33 -0
  129. sphynx/rag_papers/runner.py +176 -0
  130. sphynx/rag_papers/sable.py +135 -0
  131. sphynx/rag_papers/schemas.py +12 -0
  132. sphynx/rag_papers/scoring.py +249 -0
  133. sphynx/rag_papers/semantic.py +288 -0
  134. sphynx/rag_papers/trec.py +80 -0
  135. sphynx/recorded_scores.py +352 -0
  136. sphynx/records.py +124 -0
  137. sphynx/reflex_traces.py +193 -0
  138. sphynx/report_rendering.py +71 -0
  139. sphynx/rerank_family_contracts.py +150 -0
  140. sphynx/rerank_workflow.py +424 -0
  141. sphynx/research_candidate.py +190 -0
  142. sphynx/results.py +852 -0
  143. sphynx/retrieval.py +750 -0
  144. sphynx/retrieval_candidates.py +295 -0
  145. sphynx/retrieval_catalog_data.py +19 -0
  146. sphynx/retrieval_recordings.py +125 -0
  147. sphynx/reviewer_audit.py +266 -0
  148. sphynx/routing_policies.py +375 -0
  149. sphynx/runner.py +544 -0
  150. sphynx/sable_rerank.py +489 -0
  151. sphynx/score_reliability.py +393 -0
  152. sphynx/speech_benchmarks.py +204 -0
  153. sphynx/speech_campaigns.py +378 -0
  154. sphynx/speech_complete.py +236 -0
  155. sphynx/speech_contracts.py +225 -0
  156. sphynx/speech_evidence.py +429 -0
  157. sphynx/speech_listening.py +115 -0
  158. sphynx/speech_multilingual.py +71 -0
  159. sphynx/speech_tts.py +479 -0
  160. sphynx/sql/001_sync_v1.sql +30 -0
  161. sphynx/stage_contracts.py +199 -0
  162. sphynx/statistical_catalog_data.py +53 -0
  163. sphynx/statistical_rerank.py +232 -0
  164. sphynx/sync.py +797 -0
  165. sphynx/workbench.py +378 -0
  166. sphynx/workbench_catalog_data.py +13 -0
  167. sphynx/workbench_tracks.py +78 -0
  168. sphynx/workflow_async.py +197 -0
  169. sphynx/workflow_contracts.py +594 -0
  170. sphynx/workflow_decisions.py +211 -0
  171. sphynx/workflow_defaults.py +16 -0
  172. sphynx/workflow_extensions.py +212 -0
  173. sphynx/workflow_registry.py +513 -0
  174. sphynx/workflows.py +792 -0
@@ -0,0 +1,138 @@
1
+ """Small source-readiness summaries with explicit identity and provenance.
2
+
3
+ These utilities describe supplied rows and pinned bytes. They do not establish
4
+ review authority, independent labels, holdout quality, or benchmark capability.
5
+ Summaries omit raw question text, labels, identifiers, and local source paths.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import hashlib
10
+ from collections.abc import Iterable, Mapping
11
+ from pathlib import Path
12
+ import re
13
+ from typing import Any
14
+
15
+ from .contracts import ContractError, canonical_json
16
+
17
+ _SHA256 = re.compile(r"sha256:[0-9a-f]{64}\Z")
18
+
19
+
20
+ def _text(value: Any, field: str) -> str:
21
+ if type(value) is not str or not value.strip() or "\x00" in value:
22
+ raise ContractError(f"{field} must be nonempty text")
23
+ try:
24
+ value.encode("utf-8", errors="strict")
25
+ except UnicodeEncodeError:
26
+ raise ContractError(f"{field} must contain valid Unicode") from None
27
+ return value
28
+
29
+
30
+ def _rows(values: Iterable[Any], field: str) -> list[Any]:
31
+ if isinstance(values, (str, bytes, Mapping)):
32
+ raise ContractError(f"{field} must be an iterable of rows")
33
+ try:
34
+ return list(values)
35
+ except TypeError:
36
+ raise ContractError(f"{field} must be an iterable of rows") from None
37
+
38
+
39
+ def overlap_summary(left: Iterable[str], right: Iterable[str]) -> dict[str, Any]:
40
+ """Count exact unique identities; hash their sorted unique intersection.
41
+
42
+ Row counts retain duplicates. Overlap, union, and the overlap digest use
43
+ sets, so duplicate rows and ordering do not change their identity meaning.
44
+ IDs are compared exactly, without question-text or case normalization.
45
+ """
46
+ left_rows = _rows(left, "left identities")
47
+ right_rows = _rows(right, "right identities")
48
+ left_ids = {_text(value, "left identity") for value in left_rows}
49
+ right_ids = {_text(value, "right identity") for value in right_rows}
50
+ overlap = left_ids & right_ids
51
+ digest = hashlib.sha256(canonical_json(sorted(overlap)).encode("utf-8")).hexdigest()
52
+ return {
53
+ "left_rows": len(left_rows), "right_rows": len(right_rows),
54
+ "left_unique": len(left_ids), "right_unique": len(right_ids),
55
+ "union_unique": len(left_ids | right_ids), "overlap_unique": len(overlap),
56
+ "left_only_unique": len(left_ids - right_ids), "right_only_unique": len(right_ids - left_ids),
57
+ "overlap_digest": "sha256:" + digest,
58
+ }
59
+
60
+
61
+ def routing_provenance_summary(questions: Iterable[Mapping[str, Any]],
62
+ labels: Iterable[Mapping[str, Any]]) -> dict[str, Any]:
63
+ """Join unique question IDs and summarize supplied routing provenance.
64
+
65
+ Repeated questions are extra rows after the first occurrence of a company
66
+ and user-turn pair. Normalization collapses whitespace and applies casefold;
67
+ it does not remove punctuation, infer paraphrases, or match text across companies.
68
+ Family identity is supplied label metadata, not inferred from repeated text.
69
+ Incomplete or empty family metadata remains unknown.
70
+ """
71
+ question_rows = _rows(questions, "questions")
72
+ label_rows = _rows(labels, "labels")
73
+ question_by_id: dict[str, Mapping[str, Any]] = {}
74
+ repeated_keys: set[tuple[str, str]] = set()
75
+ for row in question_rows:
76
+ if not isinstance(row, Mapping):
77
+ raise ContractError("question rows must be objects")
78
+ question_id = _text(row.get("question_id"), "question ID")
79
+ if question_id in question_by_id:
80
+ raise ContractError("question IDs must be unique")
81
+ company = _text(row.get("company_id"), "company ID")
82
+ turn = _text(row.get("user_turn"), "user turn")
83
+ question_by_id[question_id] = row
84
+ repeated_keys.add((" ".join(company.casefold().split()), " ".join(turn.casefold().split())))
85
+
86
+ label_by_id: dict[str, Mapping[str, Any]] = {}
87
+ for row in label_rows:
88
+ if not isinstance(row, Mapping):
89
+ raise ContractError("label rows must be objects")
90
+ question_id = _text(row.get("question_id"), "label question ID")
91
+ if question_id in label_by_id:
92
+ raise ContractError("label question IDs must be unique")
93
+ if question_id not in question_by_id:
94
+ raise ContractError("label question IDs do not match question IDs")
95
+ if "company_id" in row and row["company_id"] != question_by_id[question_id]["company_id"]:
96
+ raise ContractError("label company identity differs from its question")
97
+ label_by_id[question_id] = row
98
+ if set(label_by_id) != set(question_by_id):
99
+ raise ContractError("labels must match questions one to one")
100
+
101
+ missing_families = 0
102
+ families: set[tuple[str, str]] = set()
103
+ for question_id, row in label_by_id.items():
104
+ family = row.get("family_id")
105
+ if family is None or (type(family) is str and not family.strip()):
106
+ missing_families += 1
107
+ continue
108
+ family = _text(family, "family ID")
109
+ families.add((question_by_id[question_id]["company_id"], family))
110
+ known_families = bool(question_rows) and missing_families == 0
111
+ return {
112
+ "question_rows": len(question_rows), "label_rows": len(label_rows),
113
+ "question_unique": len(question_by_id),
114
+ "repeated_question_rows": len(question_rows) - len(repeated_keys),
115
+ "repeated_question_status": "known",
116
+ "family_status": "known" if known_families else "unknown",
117
+ "family_count": len(families) if known_families else None,
118
+ "missing_family_rows": missing_families,
119
+ }
120
+
121
+
122
+ def verify_source_file(path: str | Path, expected_sha256: str | None = None) -> dict[str, Any]:
123
+ """Verify actual file bytes against an explicit lowercase SHA-256 pin.
124
+
125
+ Missing or malformed pins fail before reading. The calculated digest is
126
+ compared with the caller's pin; it is never adopted as a new authority.
127
+ Return byte metadata only, without exposing the source path or content.
128
+ """
129
+ if type(expected_sha256) is not str or not _SHA256.fullmatch(expected_sha256):
130
+ raise ContractError("source verification requires an explicit lowercase sha256 pin")
131
+ try:
132
+ raw = Path(path).read_bytes()
133
+ except (OSError, TypeError, ValueError):
134
+ raise ContractError("source file could not be read") from None
135
+ actual = "sha256:" + hashlib.sha256(raw).hexdigest()
136
+ if actual != expected_sha256:
137
+ raise ContractError("source bytes differ from the supplied SHA-256 pin")
138
+ return {"sha256": actual, "size_bytes": len(raw)}