quantum-reasoning-skill 1.0.0 → 1.1.0
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.
- package/LICENSE +21 -21
- package/README.md +86 -133
- package/SKILL.md +146 -146
- package/VERSION +1 -1
- package/index.js +207 -1
- package/package.json +41 -1
- package/.github/ISSUE_TEMPLATE/benchmark-result.yml +0 -81
- package/.github/ISSUE_TEMPLATE/bug-report.yml +0 -38
- package/.github/ISSUE_TEMPLATE/feature-request.yml +0 -31
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -15
- package/.github/workflows/npm-publish.yml +0 -32
- package/.github/workflows/publish-release.yml +0 -79
- package/.github/workflows/validate-skill.yml +0 -154
- package/CHANGELOG.md +0 -51
- package/CITATION.cff +0 -17
- package/CONTRIBUTING.md +0 -88
- package/SECURITY.md +0 -17
- package/benchmark/README.md +0 -134
- package/benchmark/cases.jsonl +0 -6
- package/benchmark/evaluate.py +0 -257
- package/benchmark/schemas/case.schema.json +0 -20
- package/benchmark/schemas/comparison.schema.json +0 -64
- package/benchmark/schemas/metadata.schema.json +0 -53
- package/benchmark/schemas/result.schema.json +0 -25
- package/benchmark/validate_submission.py +0 -114
- package/docs/COMPATIBILITY.md +0 -44
- package/docs/MEASUREMENT.md +0 -131
- package/examples/host-integration.md +0 -57
- package/examples/usage.md +0 -31
- package/reference/branch_controller.py +0 -256
- package/tests/test_benchmark.py +0 -120
- package/tests/test_reference.py +0 -128
- package/tests/test_submission_validation.py +0 -78
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
"""Reference branch-control logic for the Quantum Reasoning Skill.
|
|
2
|
-
|
|
3
|
-
This module is intentionally provider-agnostic. It does not generate hidden reasoning
|
|
4
|
-
or call an LLM. It only manages branch telemetry and makes deterministic decisions
|
|
5
|
-
from explicit, externally supplied measurements.
|
|
6
|
-
|
|
7
|
-
The thresholds below are reference defaults, not scientifically validated constants.
|
|
8
|
-
They are meant to be calibrated with benchmark evidence.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from __future__ import annotations
|
|
12
|
-
|
|
13
|
-
from dataclasses import dataclass, replace
|
|
14
|
-
from enum import Enum
|
|
15
|
-
from math import log2
|
|
16
|
-
from typing import Iterable, Sequence
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class BranchState(str, Enum):
|
|
20
|
-
ACTIVE = "active"
|
|
21
|
-
DORMANT = "dormant"
|
|
22
|
-
REJECTED = "rejected"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@dataclass(frozen=True)
|
|
26
|
-
class BranchMetrics:
|
|
27
|
-
evidence: float
|
|
28
|
-
verification: float
|
|
29
|
-
independence: float
|
|
30
|
-
information_gain: float
|
|
31
|
-
contradiction: float
|
|
32
|
-
unresolved_assumptions: float
|
|
33
|
-
normalized_cost: float
|
|
34
|
-
shared_assumption_ratio: float = 0.0
|
|
35
|
-
semantic_similarity_to_leader: float = 0.0
|
|
36
|
-
|
|
37
|
-
def validate(self) -> None:
|
|
38
|
-
for name, value in self.__dict__.items():
|
|
39
|
-
if not 0.0 <= value <= 1.0:
|
|
40
|
-
raise ValueError(f"{name} must be in [0, 1], got {value!r}")
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@dataclass(frozen=True)
|
|
44
|
-
class Branch:
|
|
45
|
-
branch_id: str
|
|
46
|
-
metrics: BranchMetrics
|
|
47
|
-
state: BranchState = BranchState.ACTIVE
|
|
48
|
-
previous_metrics: BranchMetrics | None = None
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@dataclass(frozen=True)
|
|
52
|
-
class Thresholds:
|
|
53
|
-
collapse_score: float = 0.78
|
|
54
|
-
collapse_verification: float = 0.75
|
|
55
|
-
collapse_max_contradiction: float = 0.15
|
|
56
|
-
collapse_margin: float = 0.12
|
|
57
|
-
unresolved_near_leader_margin: float = 0.10
|
|
58
|
-
reject_contradiction: float = 0.85
|
|
59
|
-
dormant_score: float = 0.35
|
|
60
|
-
revive_evidence_delta: float = 0.15
|
|
61
|
-
revive_verification_delta: float = 0.25
|
|
62
|
-
revive_contradiction_drop: float = 0.20
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
DEFAULT_THRESHOLDS = Thresholds()
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
WEIGHTS = {
|
|
69
|
-
"evidence": 0.25,
|
|
70
|
-
"verification": 0.25,
|
|
71
|
-
"independence": 0.15,
|
|
72
|
-
"information_gain": 0.10,
|
|
73
|
-
"contradiction": -0.15,
|
|
74
|
-
"unresolved_assumptions": -0.05,
|
|
75
|
-
"normalized_cost": -0.05,
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def _clamp01(value: float) -> float:
|
|
80
|
-
return max(0.0, min(1.0, value))
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def effective_independence(metrics: BranchMetrics) -> float:
|
|
84
|
-
"""Penalize correlated branches and near-duplicates.
|
|
85
|
-
|
|
86
|
-
The effective independence is the declared independence reduced by the strongest
|
|
87
|
-
observed correlation signal: shared assumptions or semantic similarity.
|
|
88
|
-
"""
|
|
89
|
-
metrics.validate()
|
|
90
|
-
correlation = max(
|
|
91
|
-
metrics.shared_assumption_ratio,
|
|
92
|
-
metrics.semantic_similarity_to_leader,
|
|
93
|
-
)
|
|
94
|
-
return _clamp01(metrics.independence * (1.0 - correlation))
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def branch_score(metrics: BranchMetrics) -> float:
|
|
98
|
-
"""Return a deterministic support score in [0, 1]."""
|
|
99
|
-
metrics.validate()
|
|
100
|
-
values = {
|
|
101
|
-
"evidence": metrics.evidence,
|
|
102
|
-
"verification": metrics.verification,
|
|
103
|
-
"independence": effective_independence(metrics),
|
|
104
|
-
"information_gain": metrics.information_gain,
|
|
105
|
-
"contradiction": metrics.contradiction,
|
|
106
|
-
"unresolved_assumptions": metrics.unresolved_assumptions,
|
|
107
|
-
"normalized_cost": metrics.normalized_cost,
|
|
108
|
-
}
|
|
109
|
-
raw = 0.15 + sum(WEIGHTS[name] * value for name, value in values.items())
|
|
110
|
-
return _clamp01(raw)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def rank_branches(branches: Iterable[Branch]) -> list[Branch]:
|
|
114
|
-
return sorted(
|
|
115
|
-
(branch for branch in branches if branch.state != BranchState.REJECTED),
|
|
116
|
-
key=lambda branch: branch_score(branch.metrics),
|
|
117
|
-
reverse=True,
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def classify_branch(
|
|
122
|
-
branch: Branch,
|
|
123
|
-
thresholds: Thresholds = DEFAULT_THRESHOLDS,
|
|
124
|
-
) -> Branch:
|
|
125
|
-
"""Move an active branch to dormant/rejected when evidence warrants it."""
|
|
126
|
-
score = branch_score(branch.metrics)
|
|
127
|
-
if branch.metrics.contradiction >= thresholds.reject_contradiction:
|
|
128
|
-
return replace(branch, state=BranchState.REJECTED)
|
|
129
|
-
if score < thresholds.dormant_score:
|
|
130
|
-
return replace(branch, state=BranchState.DORMANT)
|
|
131
|
-
return replace(branch, state=BranchState.ACTIVE)
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def should_revive(
|
|
135
|
-
branch: Branch,
|
|
136
|
-
thresholds: Thresholds = DEFAULT_THRESHOLDS,
|
|
137
|
-
) -> bool:
|
|
138
|
-
"""Return True when new evidence materially improves a dormant branch."""
|
|
139
|
-
if branch.state != BranchState.DORMANT or branch.previous_metrics is None:
|
|
140
|
-
return False
|
|
141
|
-
current = branch.metrics
|
|
142
|
-
previous = branch.previous_metrics
|
|
143
|
-
current.validate()
|
|
144
|
-
previous.validate()
|
|
145
|
-
return any(
|
|
146
|
-
(
|
|
147
|
-
current.evidence - previous.evidence >= thresholds.revive_evidence_delta,
|
|
148
|
-
current.verification - previous.verification
|
|
149
|
-
>= thresholds.revive_verification_delta,
|
|
150
|
-
previous.contradiction - current.contradiction
|
|
151
|
-
>= thresholds.revive_contradiction_drop,
|
|
152
|
-
)
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
def update_branch_state(
|
|
157
|
-
branch: Branch,
|
|
158
|
-
thresholds: Thresholds = DEFAULT_THRESHOLDS,
|
|
159
|
-
) -> Branch:
|
|
160
|
-
if should_revive(branch, thresholds):
|
|
161
|
-
return replace(branch, state=BranchState.ACTIVE)
|
|
162
|
-
return classify_branch(branch, thresholds)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
def normalized_entropy(probabilities: Sequence[float]) -> float:
|
|
166
|
-
"""Normalized Shannon entropy in [0, 1]."""
|
|
167
|
-
if not probabilities:
|
|
168
|
-
return 0.0
|
|
169
|
-
if any(value < 0 for value in probabilities):
|
|
170
|
-
raise ValueError("probabilities cannot contain negative values")
|
|
171
|
-
total = sum(probabilities)
|
|
172
|
-
if total <= 0:
|
|
173
|
-
return 0.0
|
|
174
|
-
normalized = [value / total for value in probabilities if value > 0]
|
|
175
|
-
if len(normalized) <= 1:
|
|
176
|
-
return 0.0
|
|
177
|
-
entropy = -sum(value * log2(value) for value in normalized)
|
|
178
|
-
return _clamp01(entropy / log2(len(normalized)))
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
def uncertainty_from_branches(branches: Sequence[Branch]) -> float:
|
|
182
|
-
"""Estimate uncertainty from the score distribution of surviving branches."""
|
|
183
|
-
surviving = [
|
|
184
|
-
branch_score(branch.metrics)
|
|
185
|
-
for branch in branches
|
|
186
|
-
if branch.state != BranchState.REJECTED
|
|
187
|
-
]
|
|
188
|
-
return normalized_entropy(surviving)
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def recommended_width(uncertainty: float) -> tuple[int, int]:
|
|
192
|
-
"""Return a reference branch-count range for the next search step."""
|
|
193
|
-
if not 0.0 <= uncertainty <= 1.0:
|
|
194
|
-
raise ValueError("uncertainty must be in [0, 1]")
|
|
195
|
-
if uncertainty < 0.25:
|
|
196
|
-
return (2, 3)
|
|
197
|
-
if uncertainty < 0.55:
|
|
198
|
-
return (4, 6)
|
|
199
|
-
return (6, 10)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
def collapse_decision(
|
|
203
|
-
branches: Sequence[Branch],
|
|
204
|
-
thresholds: Thresholds = DEFAULT_THRESHOLDS,
|
|
205
|
-
) -> tuple[bool, str, Branch | None]:
|
|
206
|
-
"""Determine whether the search can collapse to a single branch.
|
|
207
|
-
|
|
208
|
-
Returns ``(can_collapse, reason, leader)``. Collapse is blocked when a strong,
|
|
209
|
-
unresolved alternative remains close enough to the leader to matter.
|
|
210
|
-
"""
|
|
211
|
-
ranked = rank_branches(branches)
|
|
212
|
-
if not ranked:
|
|
213
|
-
return (False, "no surviving branch", None)
|
|
214
|
-
|
|
215
|
-
leader = ranked[0]
|
|
216
|
-
leader_score = branch_score(leader.metrics)
|
|
217
|
-
if leader_score < thresholds.collapse_score:
|
|
218
|
-
return (False, "leader score below collapse threshold", leader)
|
|
219
|
-
if leader.metrics.verification < thresholds.collapse_verification:
|
|
220
|
-
return (False, "leader verification below collapse threshold", leader)
|
|
221
|
-
if leader.metrics.contradiction > thresholds.collapse_max_contradiction:
|
|
222
|
-
return (False, "leader contradiction remains too high", leader)
|
|
223
|
-
|
|
224
|
-
if len(ranked) > 1:
|
|
225
|
-
runner_up = ranked[1]
|
|
226
|
-
runner_score = branch_score(runner_up.metrics)
|
|
227
|
-
if leader_score - runner_score < thresholds.collapse_margin:
|
|
228
|
-
return (False, "leader margin is too small", leader)
|
|
229
|
-
if (
|
|
230
|
-
runner_up.metrics.information_gain >= 0.60
|
|
231
|
-
and leader_score - runner_score
|
|
232
|
-
<= thresholds.unresolved_near_leader_margin
|
|
233
|
-
):
|
|
234
|
-
return (False, "high-information alternative remains unresolved", leader)
|
|
235
|
-
|
|
236
|
-
return (True, "collapse criteria satisfied", leader)
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
def diversity_ratio(
|
|
240
|
-
pairwise_similarities: Sequence[float],
|
|
241
|
-
duplicate_threshold: float = 0.85,
|
|
242
|
-
) -> float:
|
|
243
|
-
"""Fraction of pairwise comparisons that are materially distinct.
|
|
244
|
-
|
|
245
|
-
Similarity values must be in [0, 1]. A pair at or above the duplicate threshold
|
|
246
|
-
is treated as correlated/redundant for this diagnostic.
|
|
247
|
-
"""
|
|
248
|
-
if not pairwise_similarities:
|
|
249
|
-
return 1.0
|
|
250
|
-
if not 0.0 <= duplicate_threshold <= 1.0:
|
|
251
|
-
raise ValueError("duplicate_threshold must be in [0, 1]")
|
|
252
|
-
for value in pairwise_similarities:
|
|
253
|
-
if not 0.0 <= value <= 1.0:
|
|
254
|
-
raise ValueError("similarity values must be in [0, 1]")
|
|
255
|
-
distinct = sum(value < duplicate_threshold for value in pairwise_similarities)
|
|
256
|
-
return distinct / len(pairwise_similarities)
|
package/tests/test_benchmark.py
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import importlib.util
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
import unittest
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
ROOT = Path(__file__).resolve().parents[1]
|
|
9
|
-
SPEC = importlib.util.spec_from_file_location(
|
|
10
|
-
"benchmark_evaluate", ROOT / "benchmark" / "evaluate.py"
|
|
11
|
-
)
|
|
12
|
-
assert SPEC and SPEC.loader
|
|
13
|
-
evaluate = importlib.util.module_from_spec(SPEC)
|
|
14
|
-
SPEC.loader.exec_module(evaluate)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
CASES = [
|
|
18
|
-
{
|
|
19
|
-
"id": "c1",
|
|
20
|
-
"domain": "math",
|
|
21
|
-
"prompt": "1+1?",
|
|
22
|
-
"accepted_answers": ["2"],
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
"id": "c2",
|
|
26
|
-
"domain": "logic",
|
|
27
|
-
"prompt": "yes?",
|
|
28
|
-
"accepted_answers": ["yes"],
|
|
29
|
-
},
|
|
30
|
-
]
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class BenchmarkTests(unittest.TestCase):
|
|
34
|
-
def test_summary_computes_accuracy_and_telemetry(self):
|
|
35
|
-
results = [
|
|
36
|
-
{
|
|
37
|
-
"case_id": "c1",
|
|
38
|
-
"answer": "2",
|
|
39
|
-
"tokens": 100,
|
|
40
|
-
"tool_calls": 1,
|
|
41
|
-
"latency_ms": 50,
|
|
42
|
-
"branches_total": 4,
|
|
43
|
-
"branches_distinct": 3,
|
|
44
|
-
"revived_branches": 1,
|
|
45
|
-
"recovered_errors": 1,
|
|
46
|
-
"contradictions_found": 2,
|
|
47
|
-
"contradictions_resolved": 2,
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
"case_id": "c2",
|
|
51
|
-
"answer": "no",
|
|
52
|
-
"tokens": 200,
|
|
53
|
-
"tool_calls": 3,
|
|
54
|
-
"latency_ms": 150,
|
|
55
|
-
"branches_total": 2,
|
|
56
|
-
"branches_distinct": 1,
|
|
57
|
-
"revived_branches": 0,
|
|
58
|
-
"recovered_errors": 0,
|
|
59
|
-
"contradictions_found": 1,
|
|
60
|
-
"contradictions_resolved": 0,
|
|
61
|
-
},
|
|
62
|
-
]
|
|
63
|
-
summary = evaluate.summarize(CASES, results)
|
|
64
|
-
self.assertEqual(summary["accuracy"], 0.5)
|
|
65
|
-
self.assertEqual(summary["mean_tokens"], 150.0)
|
|
66
|
-
self.assertEqual(summary["mean_tool_calls"], 2.0)
|
|
67
|
-
self.assertEqual(summary["mean_latency_ms"], 100.0)
|
|
68
|
-
self.assertEqual(summary["branch_diversity_ratio"], 4 / 6)
|
|
69
|
-
self.assertEqual(summary["contradiction_resolution_rate"], 2 / 3)
|
|
70
|
-
|
|
71
|
-
def test_compare_reports_cost_and_accuracy_changes(self):
|
|
72
|
-
baseline = {
|
|
73
|
-
"accuracy": 0.5,
|
|
74
|
-
"mean_tokens": 100.0,
|
|
75
|
-
"mean_tool_calls": 1.0,
|
|
76
|
-
"mean_latency_ms": 100.0,
|
|
77
|
-
"branch_diversity_ratio": 0.4,
|
|
78
|
-
"contradiction_resolution_rate": 0.5,
|
|
79
|
-
}
|
|
80
|
-
skill = {
|
|
81
|
-
"accuracy": 0.75,
|
|
82
|
-
"mean_tokens": 150.0,
|
|
83
|
-
"mean_tool_calls": 2.0,
|
|
84
|
-
"mean_latency_ms": 120.0,
|
|
85
|
-
"branch_diversity_ratio": 0.7,
|
|
86
|
-
"contradiction_resolution_rate": 0.8,
|
|
87
|
-
}
|
|
88
|
-
delta = evaluate.compare(baseline, skill)
|
|
89
|
-
self.assertEqual(delta["accuracy_delta"], 0.25)
|
|
90
|
-
self.assertEqual(delta["tokens_percent_change"], 50.0)
|
|
91
|
-
self.assertEqual(delta["tool_calls_percent_change"], 100.0)
|
|
92
|
-
self.assertEqual(delta["latency_percent_change"], 20.0)
|
|
93
|
-
self.assertAlmostEqual(delta["branch_diversity_delta"], 0.3)
|
|
94
|
-
self.assertAlmostEqual(delta["contradiction_resolution_delta"], 0.3)
|
|
95
|
-
|
|
96
|
-
def test_missing_result_fields_fail(self):
|
|
97
|
-
with self.assertRaises(ValueError):
|
|
98
|
-
evaluate.summarize(
|
|
99
|
-
CASES,
|
|
100
|
-
[{"case_id": "c1", "answer": "2", "tokens": 1}],
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
def test_unknown_case_id_fails(self):
|
|
104
|
-
with self.assertRaises(ValueError):
|
|
105
|
-
evaluate.summarize(
|
|
106
|
-
CASES,
|
|
107
|
-
[
|
|
108
|
-
{
|
|
109
|
-
"case_id": "missing",
|
|
110
|
-
"answer": "2",
|
|
111
|
-
"tokens": 1,
|
|
112
|
-
"tool_calls": 0,
|
|
113
|
-
"latency_ms": 1,
|
|
114
|
-
}
|
|
115
|
-
],
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if __name__ == "__main__":
|
|
120
|
-
unittest.main()
|
package/tests/test_reference.py
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import importlib.util
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
import sys
|
|
6
|
-
import unittest
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
ROOT = Path(__file__).resolve().parents[1]
|
|
10
|
-
SPEC = importlib.util.spec_from_file_location(
|
|
11
|
-
"branch_controller", ROOT / "reference" / "branch_controller.py"
|
|
12
|
-
)
|
|
13
|
-
assert SPEC and SPEC.loader
|
|
14
|
-
bc = importlib.util.module_from_spec(SPEC)
|
|
15
|
-
sys.modules[SPEC.name] = bc
|
|
16
|
-
SPEC.loader.exec_module(bc)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class BranchControllerTests(unittest.TestCase):
|
|
20
|
-
def metrics(self, **overrides):
|
|
21
|
-
values = {
|
|
22
|
-
"evidence": 0.8,
|
|
23
|
-
"verification": 0.8,
|
|
24
|
-
"independence": 0.9,
|
|
25
|
-
"information_gain": 0.6,
|
|
26
|
-
"contradiction": 0.1,
|
|
27
|
-
"unresolved_assumptions": 0.1,
|
|
28
|
-
"normalized_cost": 0.2,
|
|
29
|
-
"shared_assumption_ratio": 0.0,
|
|
30
|
-
"semantic_similarity_to_leader": 0.0,
|
|
31
|
-
}
|
|
32
|
-
values.update(overrides)
|
|
33
|
-
return bc.BranchMetrics(**values)
|
|
34
|
-
|
|
35
|
-
def test_score_penalizes_shared_assumptions(self):
|
|
36
|
-
independent = self.metrics(shared_assumption_ratio=0.0)
|
|
37
|
-
correlated = self.metrics(shared_assumption_ratio=0.8)
|
|
38
|
-
self.assertGreater(bc.branch_score(independent), bc.branch_score(correlated))
|
|
39
|
-
|
|
40
|
-
def test_high_contradiction_rejects_branch(self):
|
|
41
|
-
branch = bc.Branch("bad", self.metrics(contradiction=0.95))
|
|
42
|
-
updated = bc.classify_branch(branch)
|
|
43
|
-
self.assertEqual(updated.state, bc.BranchState.REJECTED)
|
|
44
|
-
|
|
45
|
-
def test_material_evidence_change_revives_dormant_branch(self):
|
|
46
|
-
previous = self.metrics(evidence=0.30, verification=0.35, contradiction=0.50)
|
|
47
|
-
current = self.metrics(evidence=0.50, verification=0.35, contradiction=0.50)
|
|
48
|
-
branch = bc.Branch(
|
|
49
|
-
"revive",
|
|
50
|
-
current,
|
|
51
|
-
state=bc.BranchState.DORMANT,
|
|
52
|
-
previous_metrics=previous,
|
|
53
|
-
)
|
|
54
|
-
self.assertTrue(bc.should_revive(branch))
|
|
55
|
-
self.assertEqual(bc.update_branch_state(branch).state, bc.BranchState.ACTIVE)
|
|
56
|
-
|
|
57
|
-
def test_collapse_requires_clear_verified_leader(self):
|
|
58
|
-
leader = bc.Branch(
|
|
59
|
-
"leader",
|
|
60
|
-
self.metrics(
|
|
61
|
-
evidence=1.0,
|
|
62
|
-
verification=1.0,
|
|
63
|
-
independence=1.0,
|
|
64
|
-
information_gain=0.8,
|
|
65
|
-
contradiction=0.0,
|
|
66
|
-
unresolved_assumptions=0.0,
|
|
67
|
-
normalized_cost=0.0,
|
|
68
|
-
),
|
|
69
|
-
)
|
|
70
|
-
weak = bc.Branch(
|
|
71
|
-
"weak",
|
|
72
|
-
self.metrics(
|
|
73
|
-
evidence=0.35,
|
|
74
|
-
verification=0.30,
|
|
75
|
-
independence=0.5,
|
|
76
|
-
information_gain=0.2,
|
|
77
|
-
contradiction=0.4,
|
|
78
|
-
unresolved_assumptions=0.5,
|
|
79
|
-
normalized_cost=0.4,
|
|
80
|
-
),
|
|
81
|
-
)
|
|
82
|
-
can_collapse, reason, selected = bc.collapse_decision([leader, weak])
|
|
83
|
-
self.assertTrue(can_collapse, reason)
|
|
84
|
-
self.assertEqual(selected.branch_id, "leader")
|
|
85
|
-
|
|
86
|
-
def test_close_competitor_blocks_collapse(self):
|
|
87
|
-
first = bc.Branch(
|
|
88
|
-
"a",
|
|
89
|
-
self.metrics(
|
|
90
|
-
evidence=1.0,
|
|
91
|
-
verification=1.0,
|
|
92
|
-
independence=1.0,
|
|
93
|
-
contradiction=0.0,
|
|
94
|
-
unresolved_assumptions=0.0,
|
|
95
|
-
normalized_cost=0.0,
|
|
96
|
-
),
|
|
97
|
-
)
|
|
98
|
-
second = bc.Branch(
|
|
99
|
-
"b",
|
|
100
|
-
self.metrics(
|
|
101
|
-
evidence=0.95,
|
|
102
|
-
verification=0.95,
|
|
103
|
-
independence=1.0,
|
|
104
|
-
contradiction=0.0,
|
|
105
|
-
unresolved_assumptions=0.0,
|
|
106
|
-
normalized_cost=0.0,
|
|
107
|
-
),
|
|
108
|
-
)
|
|
109
|
-
can_collapse, reason, _ = bc.collapse_decision([first, second])
|
|
110
|
-
self.assertFalse(can_collapse)
|
|
111
|
-
self.assertIn("margin", reason)
|
|
112
|
-
|
|
113
|
-
def test_uncertainty_controls_width(self):
|
|
114
|
-
self.assertEqual(bc.recommended_width(0.10), (2, 3))
|
|
115
|
-
self.assertEqual(bc.recommended_width(0.40), (4, 6))
|
|
116
|
-
self.assertEqual(bc.recommended_width(0.90), (6, 10))
|
|
117
|
-
|
|
118
|
-
def test_diversity_ratio_detects_duplicates(self):
|
|
119
|
-
ratio = bc.diversity_ratio([0.2, 0.9, 0.4, 0.95], duplicate_threshold=0.85)
|
|
120
|
-
self.assertEqual(ratio, 0.5)
|
|
121
|
-
|
|
122
|
-
def test_invalid_metric_fails_fast(self):
|
|
123
|
-
with self.assertRaises(ValueError):
|
|
124
|
-
bc.branch_score(self.metrics(evidence=1.2))
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if __name__ == "__main__":
|
|
128
|
-
unittest.main()
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
import importlib.util, json, sys, tempfile, unittest
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
|
|
5
|
-
ROOT = Path(__file__).resolve().parents[1]
|
|
6
|
-
for name, path in (
|
|
7
|
-
("evaluate", ROOT / "benchmark" / "evaluate.py"),
|
|
8
|
-
("validate_submission", ROOT / "benchmark" / "validate_submission.py"),
|
|
9
|
-
):
|
|
10
|
-
spec = importlib.util.spec_from_file_location(name, path)
|
|
11
|
-
module = importlib.util.module_from_spec(spec)
|
|
12
|
-
sys.modules[name] = module
|
|
13
|
-
assert spec.loader is not None
|
|
14
|
-
spec.loader.exec_module(module)
|
|
15
|
-
|
|
16
|
-
evaluate = sys.modules["evaluate"]
|
|
17
|
-
validator = sys.modules["validate_submission"]
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class SubmissionValidationTests(unittest.TestCase):
|
|
21
|
-
def make_bundle(self, root: Path) -> Path:
|
|
22
|
-
bundle = root / "provider-model-2026-09-07"
|
|
23
|
-
bundle.mkdir()
|
|
24
|
-
cases = [{"id": "c1", "domain": "math", "prompt": "1+1?", "accepted_answers": ["2"]}]
|
|
25
|
-
baseline = [{"case_id": "c1", "answer": "2", "tokens": 10, "tool_calls": 0, "latency_ms": 100}]
|
|
26
|
-
skill = [{"case_id": "c1", "answer": "2", "tokens": 12, "tool_calls": 0, "latency_ms": 110}]
|
|
27
|
-
(bundle / "cases.jsonl").write_text(json.dumps(cases[0]) + "\n", encoding="utf-8")
|
|
28
|
-
(bundle / "baseline.jsonl").write_text(json.dumps(baseline[0]) + "\n", encoding="utf-8")
|
|
29
|
-
(bundle / "skill.jsonl").write_text(json.dumps(skill[0]) + "\n", encoding="utf-8")
|
|
30
|
-
meta = {
|
|
31
|
-
"provider": "example",
|
|
32
|
-
"model": "model",
|
|
33
|
-
"run_date": "2026-09-07",
|
|
34
|
-
"skill_version": "0.3.0",
|
|
35
|
-
"repetitions_per_case": 1,
|
|
36
|
-
"failures_recorded": True,
|
|
37
|
-
"baseline": {"instruction_config": "baseline", "sampling": {}, "tool_availability": [], "context_limit": 1000, "output_limit": 100},
|
|
38
|
-
"skill": {"instruction_config": "SKILL.md", "sampling": {}, "tool_availability": [], "context_limit": 1000, "output_limit": 100},
|
|
39
|
-
}
|
|
40
|
-
(bundle / "metadata.json").write_text(json.dumps(meta), encoding="utf-8")
|
|
41
|
-
payload = {"skill": evaluate.summarize(cases, skill), "baseline": evaluate.summarize(cases, baseline)}
|
|
42
|
-
payload["comparison"] = evaluate.compare(payload["baseline"], payload["skill"])
|
|
43
|
-
(bundle / "comparison.json").write_text(json.dumps(payload, sort_keys=True), encoding="utf-8")
|
|
44
|
-
(bundle / "README.md").write_text("Reproducible test bundle.\n", encoding="utf-8")
|
|
45
|
-
return bundle
|
|
46
|
-
|
|
47
|
-
def test_valid_bundle(self):
|
|
48
|
-
with tempfile.TemporaryDirectory() as tmp:
|
|
49
|
-
validator.validate_bundle(self.make_bundle(Path(tmp)))
|
|
50
|
-
|
|
51
|
-
def test_missing_artifact_fails(self):
|
|
52
|
-
with tempfile.TemporaryDirectory() as tmp:
|
|
53
|
-
bundle = self.make_bundle(Path(tmp))
|
|
54
|
-
(bundle / "README.md").unlink()
|
|
55
|
-
with self.assertRaises(ValueError):
|
|
56
|
-
validator.validate_bundle(bundle)
|
|
57
|
-
|
|
58
|
-
def test_tampered_comparison_fails(self):
|
|
59
|
-
with tempfile.TemporaryDirectory() as tmp:
|
|
60
|
-
bundle = self.make_bundle(Path(tmp))
|
|
61
|
-
payload = json.loads((bundle / "comparison.json").read_text())
|
|
62
|
-
payload["comparison"]["accuracy_delta"] = 99
|
|
63
|
-
(bundle / "comparison.json").write_text(json.dumps(payload), encoding="utf-8")
|
|
64
|
-
with self.assertRaises(ValueError):
|
|
65
|
-
validator.validate_bundle(bundle)
|
|
66
|
-
|
|
67
|
-
def test_unrecorded_failures_flag_fails(self):
|
|
68
|
-
with tempfile.TemporaryDirectory() as tmp:
|
|
69
|
-
bundle = self.make_bundle(Path(tmp))
|
|
70
|
-
meta = json.loads((bundle / "metadata.json").read_text())
|
|
71
|
-
meta["failures_recorded"] = False
|
|
72
|
-
(bundle / "metadata.json").write_text(json.dumps(meta), encoding="utf-8")
|
|
73
|
-
with self.assertRaises(ValueError):
|
|
74
|
-
validator.validate_bundle(bundle)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if __name__ == "__main__":
|
|
78
|
-
unittest.main()
|