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,130 @@
1
+ """Trusted, generation-pinned admission metadata for the first CPU model.
2
+
3
+ Only an operator can supply this record. Its digest detects changed bytes; a
4
+ candidate declaration and a readiness message do not establish model use. The
5
+ actual probe is performed separately before the operator publishes admission.
6
+ No ML packages, candidate code or network clients are loaded by this module.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+ import hashlib
12
+ import json
13
+ from pathlib import Path
14
+ import re
15
+
16
+ from ..contracts import ContractError, canonical_json
17
+ from .contracts import HostedError
18
+ from .model_artifacts import MODEL_REF, model_artifact_inventory
19
+ from .model_contracts import MODEL_RUNTIME_PROFILE, MODEL_SUITE, MODEL_BASELINE
20
+ from .model_gcs import ModelObjectReceipt, ModelRegistration
21
+ from .model_session import SESSION_POLICY, TIMING_POLICY
22
+
23
+ ADMISSION_SCHEMA = "sphynx.hosted.model-runtime-admission.v1"
24
+ TRUSTED_BUCKET = "sphynx-hosted-pilot-510311"
25
+ ALLOWED_REPOSITORIES = (1360688838, 1396941909)
26
+ IMAGE_PREFIX = "us-central1-docker.pkg.dev/sphynx-510311/sphynx-hosted/minilm-cpu@sha256:"
27
+ MAX_ADMISSION_BYTES = 262_144
28
+ _FIELDS = {"schema_version", "model_ref", "manifest_digest", "runtime_profile", "image_digest",
29
+ "dependency_lock", "model_assets", "resource_policy", "timing_policy", "probe",
30
+ "allowed_repositories", "team_id", "admission_digest"}
31
+
32
+
33
+ def _require(condition, code="invalid_model_admission"):
34
+ if not condition:
35
+ raise HostedError(code, "operator model runtime admission is missing, invalid or outside its scope")
36
+
37
+
38
+ def admission_digest(record):
39
+ """Hash the full canonical operator record except the hash field itself."""
40
+ _require(type(record) is dict)
41
+ try:
42
+ raw = canonical_json({k: v for k, v in record.items() if k != "admission_digest"})
43
+ except (ContractError, RecursionError):
44
+ raise HostedError("invalid_model_admission", "operator model admission must be finite bounded JSON") from None
45
+ return "sha256:" + hashlib.sha256(raw.encode("utf-8")).hexdigest()
46
+
47
+
48
+ def validate_model_runtime(record, *, trusted_bucket=TRUSTED_BUCKET):
49
+ """Validate and detach metadata; no receipt bytes or model use are inferred."""
50
+ _require(type(record) is dict and set(record) == _FIELDS)
51
+ try:
52
+ raw = canonical_json(record)
53
+ _require(len(raw.encode("utf-8")) <= MAX_ADMISSION_BYTES)
54
+ except (ContractError, RecursionError):
55
+ raise HostedError("invalid_model_admission", "operator model admission must be finite bounded JSON") from None
56
+ _require(record["schema_version"] == ADMISSION_SCHEMA and record["model_ref"] == MODEL_REF
57
+ and record["runtime_profile"] == MODEL_RUNTIME_PROFILE and record["team_id"] == "sable")
58
+ _require(trusted_bucket == TRUSTED_BUCKET)
59
+ inventory = model_artifact_inventory()
60
+ pin = inventory["manifest.json"]["digest"]
61
+ _require(record["manifest_digest"] == pin, "unapproved_model_manifest")
62
+ registration = ModelRegistration.from_dict(record["model_assets"], trusted_bucket=trusted_bucket,
63
+ approved_manifest_pins={MODEL_REF: pin})
64
+ _require(registration.manifest_digest == pin)
65
+ image = record["image_digest"]
66
+ _require(type(image) is str and re.fullmatch(re.escape(IMAGE_PREFIX) + "[0-9a-f]{64}", image),
67
+ "invalid_model_runtime_identity")
68
+ # Canonical equality preserves JSON types (True is not the CPU count 1).
69
+ _require(canonical_json(record["resource_policy"]) == canonical_json(SESSION_POLICY)
70
+ and canonical_json(record["timing_policy"]) == canonical_json(TIMING_POLICY),
71
+ "invalid_model_runtime_policy")
72
+ repos = record["allowed_repositories"]
73
+ _require(type(repos) is list and all(type(item) is int for item in repos)
74
+ and repos == list(ALLOWED_REPOSITORIES), "model_runtime_not_authorized")
75
+ lock = ModelObjectReceipt.from_dict(record["dependency_lock"])
76
+ probe = ModelObjectReceipt.from_dict(record["probe"])
77
+ _require(lock.bucket == trusted_bucket and lock.size_bytes <= 2 * 1024 * 1024
78
+ and re.fullmatch(r"prepared/runtimes/minilm-cpu/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/[A-Za-z0-9_./-]+", lock.object_name),
79
+ "invalid_model_dependency_lock")
80
+ image_sha = image.rsplit(":", 1)[1]
81
+ _require(probe.bucket == trusted_bucket and probe.size_bytes <= 2 * 1024 * 1024
82
+ and re.fullmatch(r"captures/model-probes/" + image_sha + r"/[0-9a-f]{64}/probe\.json", probe.object_name),
83
+ "invalid_model_probe_receipt")
84
+ _require(type(record["admission_digest"]) is str and re.fullmatch(r"sha256:[0-9a-f]{64}", record["admission_digest"])
85
+ and record["admission_digest"] == admission_digest(record), "model_admission_digest_mismatch")
86
+ return json.loads(raw)
87
+
88
+
89
+ def require_model_authorization(record, *, team_id, base_repository_id, head_repository_id,
90
+ suite, baseline, trusted_bucket=TRUSTED_BUCKET):
91
+ admitted = validate_model_runtime(record, trusted_bucket=trusted_bucket)
92
+ _require(team_id == admitted["team_id"] and type(base_repository_id) is int
93
+ and type(head_repository_id) is int and base_repository_id in admitted["allowed_repositories"]
94
+ and head_repository_id in admitted["allowed_repositories"], "model_runtime_not_authorized")
95
+ _require(suite == MODEL_SUITE, "model_suite_not_supported")
96
+ _require(baseline == MODEL_BASELINE, "model_baseline_not_supported")
97
+ return admitted
98
+
99
+
100
+ @dataclass(frozen=True)
101
+ class ModelRuntimeAdmission:
102
+ """Immutable operator record; callers receive detached JSON dictionaries."""
103
+ record_json: str
104
+
105
+ @classmethod
106
+ def from_dict(cls, record, *, trusted_bucket=TRUSTED_BUCKET):
107
+ return cls(canonical_json(validate_model_runtime(record, trusted_bucket=trusted_bucket)))
108
+
109
+ def to_dict(self):
110
+ return json.loads(self.record_json)
111
+
112
+
113
+ def load_model_runtime(path, *, trusted_bucket=TRUSTED_BUCKET):
114
+ try:
115
+ with Path(path).open("rb") as stream:
116
+ raw = stream.read(MAX_ADMISSION_BYTES + 1)
117
+ _require(0 < len(raw) <= MAX_ADMISSION_BYTES)
118
+ def unique(pairs):
119
+ value = {}
120
+ for key, item in pairs:
121
+ _require(key not in value)
122
+ value[key] = item
123
+ return value
124
+ record = json.loads(raw, object_pairs_hook=unique,
125
+ parse_constant=lambda _: (_ for _ in ()).throw(ValueError()))
126
+ return ModelRuntimeAdmission.from_dict(record, trusted_bucket=trusted_bucket)
127
+ except HostedError:
128
+ raise
129
+ except (OSError, ValueError, TypeError, RecursionError):
130
+ raise HostedError("invalid_model_admission", "operator model admission could not be loaded") from None
@@ -0,0 +1,298 @@
1
+ """Trusted offline MiniLM artifact intake; never imports an ML backend.
2
+
3
+ Only one operator-reviewed, safetensors-only closure is admitted. A candidate
4
+ cannot choose a URL, redirect, local path, replacement revision or digest pin.
5
+ Artifact availability is separate from runtime admission and inference proof.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass
10
+ import hashlib
11
+ import json
12
+ import math
13
+ from pathlib import Path
14
+ import re
15
+ import shutil
16
+ import stat
17
+ import struct
18
+ from types import MappingProxyType
19
+
20
+ from ..contracts import canonical_json
21
+ from ..integration_contracts import value_digest
22
+ from .contracts import HostedError
23
+
24
+ SCHEMA = "sphynx.hosted.model-artifact.v1"
25
+ MODEL_ID = "minilm-l6-v2"
26
+ CHECKPOINT = "cross-encoder/ms-marco-MiniLM-L-6-v2"
27
+ PUBLISHER_CHECKPOINT = "cross-encoder/ms-marco-MiniLM-L6-v2"
28
+ REVISION = "233902d25c440f23af6f7d6e94d2946bac0bee0a"
29
+ MODEL_REF = MODEL_ID + "@" + REVISION
30
+ SNAPSHOT_LOCATOR = "snapshot/" + REVISION
31
+ REGISTERED_MODEL_LOCATORS = MappingProxyType({MODEL_REF: SNAPSHOT_LOCATOR})
32
+ REVIEWED_FILES = MappingProxyType({
33
+ "config.json": (794, "380e02c93f431831be65d99a4e7e5f67c133985bf2e77d9d4eba46847190bacc"),
34
+ "model.safetensors": (90870598, "821d1aa69520101d6e0737f78a042ae25b19e5cb9160701909d10434f4aeb0ae"),
35
+ "README.md": (3673, "7c0ec39941d0d1d766ccde671f592971d82fe45b7eea550a80d1ea864ebc3baa"),
36
+ "special_tokens_map.json": (132, "3c3507f36dff57bce437223db3b3081d1e2b52ec3e56ee55438193ecb2c94dd6"),
37
+ "tokenizer.json": (711396, "d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"),
38
+ "tokenizer_config.json": (1330, "a5c2e5a7b1a29a0702cd28c08a399b5ecc110c263009d17f7e3b415f25905fd8"),
39
+ "vocab.txt": (231508, "07eced375cec144d27c900241f3e339478dec958f92fddbc551f295c992038a3"),
40
+ })
41
+ MAX_FILE_BYTES = 128 * 1024 * 1024
42
+ MAX_JSON_BYTES = 2 * 1024 * 1024
43
+ MAX_HEADER_BYTES = 64 * 1024
44
+ MODEL_CARD_URL = "https://huggingface.co/" + PUBLISHER_CHECKPOINT + "/blob/" + REVISION + "/README.md"
45
+ NOTICE = ("# MiniLM model artifact notice\n\n"
46
+ "Model: cross-encoder/ms-marco-MiniLM-L6-v2.\n"
47
+ "Pinned revision: " + REVISION + ".\n"
48
+ "The historical SDK alias is cross-encoder/ms-marco-MiniLM-L-6-v2.\n"
49
+ "The publisher model card declares Apache-2.0; the unmodified card is retained in README.md.\n"
50
+ "Publisher card: " + MODEL_CARD_URL + "\n"
51
+ "License text: https://www.apache.org/licenses/LICENSE-2.0\n\n"
52
+ "This is the seven-file CPU safetensors inference closure, not a complete repository mirror.\n"
53
+ "The snapshot contains no standalone LICENSE file. No redistribution approval or human review\n"
54
+ "receipt is asserted here. Model weights and code licensing are separate from dataset rights.\n"
55
+ "All scores are raw ranking utilities, not calibrated probabilities.\n").encode("utf-8")
56
+
57
+
58
+ def _require(condition, code="invalid_model_artifact"):
59
+ if not condition:
60
+ raise HostedError(code, "model artifact identity or local closure is invalid")
61
+
62
+
63
+ def _encoded(value):
64
+ return (canonical_json(value) + "\n").encode("utf-8")
65
+
66
+
67
+ def _digest(raw):
68
+ return "sha256:" + hashlib.sha256(raw).hexdigest()
69
+
70
+
71
+ def _json(raw):
72
+ _require(type(raw) is bytes and 0 < len(raw) <= MAX_JSON_BYTES)
73
+ def unique(pairs):
74
+ result = {}
75
+ for key, value in pairs:
76
+ _require(key not in result, "duplicate_model_field")
77
+ result[key] = value
78
+ return result
79
+ try:
80
+ return json.loads(raw, object_pairs_hook=unique,
81
+ parse_constant=lambda _: (_ for _ in ()).throw(ValueError()))
82
+ except (ValueError, UnicodeError, RecursionError):
83
+ raise HostedError("invalid_model_artifact", "model metadata JSON is invalid") from None
84
+
85
+
86
+ def _alias(path):
87
+ info = path.lstat()
88
+ return path.is_symlink() or bool(getattr(info, "st_file_attributes", 0) & 0x400)
89
+
90
+
91
+ def _root(directory):
92
+ path = Path(directory).absolute()
93
+ _require(path.is_dir() and not _alias(path), "invalid_model_path")
94
+ return path.resolve()
95
+
96
+
97
+ def _inventory(root, allowed_directories=()):
98
+ files = {}
99
+ pending = [root]
100
+ while pending:
101
+ for path in pending.pop().iterdir():
102
+ _require(not _alias(path), "invalid_model_path")
103
+ mode = path.lstat().st_mode
104
+ if stat.S_ISDIR(mode):
105
+ _require(path.relative_to(root).as_posix() in allowed_directories, "model_closure_mismatch")
106
+ pending.append(path)
107
+ else:
108
+ _require(stat.S_ISREG(mode), "invalid_model_path")
109
+ files[path.relative_to(root).as_posix()] = path
110
+ return files
111
+
112
+
113
+ def _file_hash(path):
114
+ h = hashlib.sha256()
115
+ with path.open("rb") as stream:
116
+ for block in iter(lambda: stream.read(1024 * 1024), b""):
117
+ h.update(block)
118
+ return "sha256:" + h.hexdigest()
119
+
120
+
121
+ def _validate_header(path):
122
+ """Read only the safe serialization header; no tensors are allocated."""
123
+ size = path.stat().st_size
124
+ with path.open("rb") as stream:
125
+ prefix = stream.read(8)
126
+ _require(len(prefix) == 8, "invalid_model_weights")
127
+ length = struct.unpack("<Q", prefix)[0]
128
+ _require(0 < length <= MAX_HEADER_BYTES and 8 + length < size, "invalid_model_weights")
129
+ header = _json(stream.read(length))
130
+ _require(type(header) is dict and header.get("__metadata__") == {"format": "pt"}, "invalid_model_weights")
131
+ tensors = {name: value for name, value in header.items() if name != "__metadata__"}
132
+ _require(len(tensors) == 106, "invalid_model_weights")
133
+ segments, dtypes = [], set()
134
+ for name, tensor in tensors.items():
135
+ _require(type(name) is str and bool(name) and type(tensor) is dict
136
+ and set(tensor) == {"dtype", "shape", "data_offsets"}, "invalid_model_weights")
137
+ dtype, shape, offsets = tensor["dtype"], tensor["shape"], tensor["data_offsets"]
138
+ _require(dtype in ("F32", "I64") and type(shape) is list and len(shape) <= 4
139
+ and all(type(n) is int and 0 < n <= 1000000 for n in shape), "invalid_model_weights")
140
+ _require(type(offsets) is list and len(offsets) == 2
141
+ and all(type(n) is int and 0 <= n <= MAX_FILE_BYTES for n in offsets), "invalid_model_weights")
142
+ start, end = offsets
143
+ _require(end > start and end - start == math.prod(shape) * (4 if dtype == "F32" else 8), "invalid_model_weights")
144
+ segments.append((start, end)); dtypes.add(dtype)
145
+ _require(dtypes == {"F32", "I64"}, "invalid_model_weights")
146
+ cursor = 0
147
+ for start, end in sorted(segments):
148
+ _require(start == cursor, "invalid_model_weights")
149
+ cursor = end
150
+ _require(cursor == size - 8 - length, "invalid_model_weights")
151
+ return {"serialization": "safetensors", "tensor_count": 106, "dtypes": ["F32", "I64"],
152
+ "tensor_execution": False}
153
+
154
+
155
+ def verify_minilm_snapshot(snapshot_dir):
156
+ """Check the operator-reviewed seven files and metadata without loading ML."""
157
+ root = _root(snapshot_dir)
158
+ actual = _inventory(root)
159
+ _require(set(actual) == set(REVIEWED_FILES), "model_closure_mismatch")
160
+ hashes = {}
161
+ for name, (expected_size, expected_sha) in REVIEWED_FILES.items():
162
+ path = actual[name]
163
+ _require(type(expected_size) is int and 0 < expected_size <= MAX_FILE_BYTES)
164
+ _require(path.stat().st_size == expected_size, "model_file_size_mismatch")
165
+ digest = _file_hash(path)
166
+ _require(digest == "sha256:" + expected_sha, "model_file_digest_mismatch")
167
+ hashes[name] = digest
168
+ config = _json(actual["config.json"].read_bytes())
169
+ tokenizer = _json(actual["tokenizer_config.json"].read_bytes())
170
+ _require(type(config) is dict and type(tokenizer) is dict
171
+ and "auto_map" not in config and "auto_map" not in tokenizer, "unsupported_model_code")
172
+ expected = {"architectures": ["BertForSequenceClassification"], "model_type": "bert", "hidden_size": 384,
173
+ "num_hidden_layers": 6, "num_attention_heads": 12, "max_position_embeddings": 512,
174
+ "vocab_size": 30522, "sbert_ce_default_activation_function": "torch.nn.modules.linear.Identity"}
175
+ _require(all(config.get(k) == v for k, v in expected.items()), "unsupported_model_architecture")
176
+ _require(tokenizer.get("model_max_length") == 512 and tokenizer.get("tokenizer_class") == "BertTokenizer",
177
+ "unsupported_model_tokenizer")
178
+ serialization = _validate_header(actual["model.safetensors"])
179
+ return {"snapshot_files": hashes, "snapshot_digest": value_digest(hashes), "serialization": serialization}
180
+
181
+
182
+ def _manifest():
183
+ hashes = {name: "sha256:" + pair[1] for name, pair in REVIEWED_FILES.items()}
184
+ return {"schema_version": SCHEMA, "model_ref": MODEL_REF, "model_id": MODEL_ID,
185
+ "checkpoint": CHECKPOINT, "publisher_checkpoint": PUBLISHER_CHECKPOINT, "revision": REVISION,
186
+ "tokenizer_revision": REVISION, "snapshot_digest": value_digest(hashes), "snapshot_locator": SNAPSHOT_LOCATOR,
187
+ "files": {name: {"size_bytes": size, "digest": "sha256:" + digest} for name, (size, digest) in REVIEWED_FILES.items()},
188
+ "notice": {"locator": "MODEL_NOTICE.md", "size_bytes": len(NOTICE), "digest": _digest(NOTICE)},
189
+ "serialization": {"format": "safetensors", "tensor_count": 106, "dtypes": ["F32", "I64"], "trust_remote_code": False},
190
+ "scoring_parameters": {"maximum_tokens": 512, "batch_size": 16, "activation": "identity",
191
+ "query_prefix": "", "truncation": "longest_first", "seed": 0, "device": "cpu", "torch_threads": 1},
192
+ "license_provenance": {"declared_license": "Apache-2.0", "declaration_file": "README.md",
193
+ "model_card_url": MODEL_CARD_URL, "standalone_license_in_snapshot": False,
194
+ "redistribution_approval_receipt": None},
195
+ "runtime_requirements": {"python": "3.12", "backend": "sentence_transformers.CrossEncoder",
196
+ "suggested_profile": "python-minilm-cpu.v1", "torch_wheel": "cpu-only",
197
+ "suggested_memory_bytes": 2147483648, "network": "none", "weights_mount": "read-only",
198
+ "immutable_runtime_digest": None, "dependency_lock_digest": None,
199
+ "required_gates": ["hashed_linux_cpu_dependency_lock", "immutable_runtime_image",
200
+ "sandbox_backend_compatibility", "bounded_cold_start_and_peak_rss", "case_and_watchdog_timeout_budget"]},
201
+ "verification_scope": {"source_file_hashes": True, "safetensors_header": True,
202
+ "backend_imported": False, "model_executed": False, "hosted_execution_admitted": False}}
203
+
204
+
205
+ def model_artifact_inventory():
206
+ """Return the exact reviewed nine-file inventory for an operator registry."""
207
+ manifest = _encoded(_manifest())
208
+ inventory = {SNAPSHOT_LOCATOR + "/" + name: {"digest": "sha256:" + sha, "size_bytes": size}
209
+ for name, (size, sha) in REVIEWED_FILES.items()}
210
+ inventory["manifest.json"] = {"digest": _digest(manifest), "size_bytes": len(manifest)}
211
+ inventory["MODEL_NOTICE.md"] = {"digest": _digest(NOTICE), "size_bytes": len(NOTICE)}
212
+ return inventory
213
+
214
+
215
+ @dataclass(frozen=True)
216
+ class ModelArtifactExport:
217
+ directory: Path
218
+ manifest_sha256: str
219
+ model_ref: str
220
+ snapshot_digest: str
221
+
222
+
223
+ @dataclass(frozen=True)
224
+ class VerifiedModelArtifact:
225
+ directory: Path
226
+ snapshot_path: Path
227
+ manifest_sha256: str
228
+ manifest_json: str
229
+
230
+ @property
231
+ def manifest(self):
232
+ return json.loads(self.manifest_json)
233
+
234
+ @property
235
+ def model_ref(self):
236
+ return self.manifest["model_ref"]
237
+
238
+ @property
239
+ def snapshot_digest(self):
240
+ return self.manifest["snapshot_digest"]
241
+
242
+ def reverify(self):
243
+ """Call before execution or use an independently protected read-only mount."""
244
+ return load_model_artifact(self.directory, expected_manifest_sha256=self.manifest_sha256,
245
+ registered_asset_locators=REGISTERED_MODEL_LOCATORS)
246
+
247
+
248
+ def export_minilm_artifact(snapshot_dir, output_dir):
249
+ """Copy only a verified existing snapshot into a fresh deterministic package.
250
+
251
+ No network, model downloads, backend imports, cloud writes or inference occur.
252
+ A failed export can leave an incomplete fresh directory; it is never admitted.
253
+ """
254
+ identity = verify_minilm_snapshot(snapshot_dir)
255
+ source = _root(snapshot_dir)
256
+ output = Path(output_dir).absolute()
257
+ _require(not output.exists(), "model_export_exists")
258
+ output.mkdir(parents=True, exist_ok=False)
259
+ target = output / SNAPSHOT_LOCATOR
260
+ target.mkdir(parents=True)
261
+ for name in REVIEWED_FILES:
262
+ shutil.copyfile(source / name, target / name)
263
+ # Recheck the copies, so edits between source validation and copying fail.
264
+ _require(verify_minilm_snapshot(target) == identity, "model_copy_identity_mismatch")
265
+ (output / "MODEL_NOTICE.md").write_bytes(NOTICE)
266
+ raw = _encoded(_manifest())
267
+ (output / "manifest.json").write_bytes(raw)
268
+ loaded = load_model_artifact(output, expected_manifest_sha256=_digest(raw),
269
+ registered_asset_locators=REGISTERED_MODEL_LOCATORS)
270
+ return ModelArtifactExport(output, loaded.manifest_sha256, loaded.model_ref, loaded.snapshot_digest)
271
+
272
+
273
+ def load_model_artifact(bundle_dir, *, expected_manifest_sha256, registered_asset_locators):
274
+ """Verify a staged, operator-registered package against an independent pin.
275
+
276
+ A hosted caller must first verify generation-pinned GCS receipts. This loader
277
+ performs no URL resolution and cannot derive authority from a candidate's pin.
278
+ """
279
+ _require(type(expected_manifest_sha256) is str
280
+ and re.fullmatch(r"sha256:[0-9a-f]{64}", expected_manifest_sha256), "invalid_model_manifest_pin")
281
+ _require(isinstance(registered_asset_locators, (dict, MappingProxyType))
282
+ and dict(registered_asset_locators) == dict(REGISTERED_MODEL_LOCATORS), "unregistered_model_locator")
283
+ root = _root(bundle_dir)
284
+ inventory = _inventory(root, {"snapshot", SNAPSHOT_LOCATOR})
285
+ expected = {"manifest.json", "MODEL_NOTICE.md"} | {SNAPSHOT_LOCATOR + "/" + name for name in REVIEWED_FILES}
286
+ _require(set(inventory) == expected, "model_closure_mismatch")
287
+ path = inventory["manifest.json"]
288
+ _require(0 < path.stat().st_size <= MAX_JSON_BYTES)
289
+ raw = path.read_bytes()
290
+ _require(_digest(raw) == expected_manifest_sha256, "model_manifest_digest_mismatch")
291
+ parsed = _json(raw)
292
+ _require(_encoded(parsed) == _encoded(_manifest()), "model_manifest_identity_mismatch")
293
+ _require(inventory["MODEL_NOTICE.md"].stat().st_size == len(NOTICE), "model_notice_mismatch")
294
+ _require(inventory["MODEL_NOTICE.md"].read_bytes() == NOTICE, "model_notice_mismatch")
295
+ snapshot_path = root / SNAPSHOT_LOCATOR
296
+ identity = verify_minilm_snapshot(snapshot_path)
297
+ _require(identity["snapshot_digest"] == parsed["snapshot_digest"], "model_snapshot_digest_mismatch")
298
+ return VerifiedModelArtifact(root, snapshot_path, expected_manifest_sha256, canonical_json(parsed))
@@ -0,0 +1,63 @@
1
+ """Additive configuration for one operator-admitted, offline CPU model runtime.
2
+
3
+ Configuration describes an approach; it does not prove that submitted code used
4
+ the declared model. Parsing never imports ML libraries or retrieves artifacts.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from dataclasses import dataclass
9
+ from typing import Any, Mapping
10
+
11
+ from .contracts import CandidateConfig, HostedError, _parse_candidate_config, fields
12
+ from .model_artifacts import MODEL_REF
13
+
14
+ MODEL_CONFIG_SCHEMA = "sphynx.candidate.repository.v2"
15
+ MODEL_SUBMISSION_SCHEMA = "sphynx.hosted.prepared-submission.v3"
16
+ MODEL_RUNTIME_PROFILE = "python-minilm-cpu.v1"
17
+ MODEL_TRANSPORT = "jsonl-session.v1"
18
+ MODEL_SUITE = "rag.rerank.public.v1"
19
+ MODEL_BASELINE = "supplied-score:v1"
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class RegisteredModelCandidateConfig(CandidateConfig):
24
+ """The legacy source contract with a separately admitted session runtime."""
25
+
26
+ def to_dict(self) -> dict[str, Any]:
27
+ value = super().to_dict()
28
+ value["schema_version"] = MODEL_CONFIG_SCHEMA
29
+ value["runtime"] = {"profile": MODEL_RUNTIME_PROFILE, "python": "3.12",
30
+ "transport": MODEL_TRANSPORT}
31
+ value["model"] = {"kind": "registered", "ref": MODEL_REF}
32
+ return value
33
+
34
+
35
+ def parse_model_configuration(raw: Mapping[str, Any]) -> RegisteredModelCandidateConfig:
36
+ fields(raw, {"schema_version", "candidate", "build", "runtime", "model"} |
37
+ ({"method"} if "method" in raw else set()), "model configuration")
38
+ if raw["schema_version"] != MODEL_CONFIG_SCHEMA:
39
+ raise HostedError("unsupported_configuration_version", "expected model repository v2")
40
+ runtime = fields(raw["runtime"], {"profile", "python", "transport"}, "model runtime")
41
+ if dict(runtime) != {"profile": MODEL_RUNTIME_PROFILE, "python": "3.12", "transport": MODEL_TRANSPORT}:
42
+ raise HostedError("unsupported_runtime", "model candidates require the admitted CPU session profile")
43
+ model = fields(raw["model"], {"kind", "ref"}, "registered model")
44
+ if dict(model) != {"kind": "registered", "ref": MODEL_REF}:
45
+ raise HostedError("unapproved_model_manifest", "model candidates require the registered MiniLM revision")
46
+ build = fields(raw["build"], {"commands", "dependencies"}, "model build")
47
+ if type(build["commands"]) is not list or build["commands"]:
48
+ raise HostedError("model_build_not_supported", "model candidates must use the prebuilt runtime without build commands")
49
+ if type(build["dependencies"]) is not list or build["dependencies"]:
50
+ raise HostedError("dependencies_not_supported", "model candidates must use the operator-frozen offline dependencies")
51
+ # Reuse all existing source/argv/interface/method checks without admitting a
52
+ # model through the legacy parser or a family.v1 method.
53
+ legacy = dict(raw)
54
+ legacy.update(schema_version="sphynx.candidate.repository.v1",
55
+ runtime={"profile": "python-cpu.v1", "python": "3.12"}, model={"kind": "none"})
56
+ parsed = _parse_candidate_config(legacy)
57
+ values = dict(vars(parsed))
58
+ values.update(runtime_profile=MODEL_RUNTIME_PROFILE, model_kind="registered")
59
+ return RegisteredModelCandidateConfig(**values)
60
+
61
+
62
+ def is_model_configuration(config) -> bool:
63
+ return isinstance(config, RegisteredModelCandidateConfig)