algo-cli-runtime 0.14.0__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.
- algo_cli/__init__.py +3 -0
- algo_cli/__main__.py +7 -0
- algo_cli/_internal/__init__.py +12 -0
- algo_cli/_internal/policy_chain.py +259 -0
- algo_cli/action_registry.py +1047 -0
- algo_cli/agent_blocks.py +550 -0
- algo_cli/agent_pipeline.py +1457 -0
- algo_cli/agent_threads.py +308 -0
- algo_cli/animations.py +316 -0
- algo_cli/cache_admission.py +209 -0
- algo_cli/capability_mask.py +66 -0
- algo_cli/chat_protocol.py +116 -0
- algo_cli/chatgpt_auth.py +510 -0
- algo_cli/chatgpt_client.py +657 -0
- algo_cli/code_rag.py +479 -0
- algo_cli/config.py +651 -0
- algo_cli/context_budget.py +679 -0
- algo_cli/credential_helpers.py +315 -0
- algo_cli/deliberation.py +29 -0
- algo_cli/display.py +1470 -0
- algo_cli/evals/__init__.py +21 -0
- algo_cli/evals/algorithm_effectiveness.py +560 -0
- algo_cli/evals/competitive_harness_rating.py +702 -0
- algo_cli/evals/cot_quality.py +220 -0
- algo_cli/evals/harness_retrieval_benchmark.py +401 -0
- algo_cli/evals/performance_regression.py +136 -0
- algo_cli/evals/scorecard_grading.py +308 -0
- algo_cli/evals/session_distribution.py +84 -0
- algo_cli/execution_guardrails.py +806 -0
- algo_cli/extensions_manifest.py +84 -0
- algo_cli/git_evidence.py +227 -0
- algo_cli/google_workspace.py +407 -0
- algo_cli/google_workspace_auth.py +523 -0
- algo_cli/harness.py +2587 -0
- algo_cli/identity.py +557 -0
- algo_cli/index_compute_lab.py +228 -0
- algo_cli/inference_harness.py +70 -0
- algo_cli/intelligence/__init__.py +1103 -0
- algo_cli/intelligence/acrobat_config.py +307 -0
- algo_cli/intelligence/acrobat_manifests.py +338 -0
- algo_cli/intelligence/acrobat_models.py +195 -0
- algo_cli/intelligence/acrobat_pipeline.py +295 -0
- algo_cli/intelligence/acrobat_runtime.py +302 -0
- algo_cli/intelligence/acrobat_security.py +261 -0
- algo_cli/intelligence/acrobat_workflows.py +226 -0
- algo_cli/intelligence/actionability.py +165 -0
- algo_cli/intelligence/adversarial_audit.py +136 -0
- algo_cli/intelligence/agent_arena.py +92 -0
- algo_cli/intelligence/agent_benchmark.py +236 -0
- algo_cli/intelligence/agent_runtime.py +171 -0
- algo_cli/intelligence/agents_as_tools.py +70 -0
- algo_cli/intelligence/artifact_binding.py +80 -0
- algo_cli/intelligence/autonomous_engineer.py +1976 -0
- algo_cli/intelligence/backpressure.py +99 -0
- algo_cli/intelligence/bloom_filter.py +186 -0
- algo_cli/intelligence/bonferroni.py +66 -0
- algo_cli/intelligence/boundary_compaction.py +98 -0
- algo_cli/intelligence/catalog_verifier.py +172 -0
- algo_cli/intelligence/cavecrew.py +118 -0
- algo_cli/intelligence/changelog.py +176 -0
- algo_cli/intelligence/checkpoint_resume.py +92 -0
- algo_cli/intelligence/circuit_breaker.py +88 -0
- algo_cli/intelligence/clarification_gate.py +101 -0
- algo_cli/intelligence/code_graph.py +180 -0
- algo_cli/intelligence/coderank.py +97 -0
- algo_cli/intelligence/consistent_hash.py +150 -0
- algo_cli/intelligence/consortium_synthesis.py +139 -0
- algo_cli/intelligence/construction/__init__.py +241 -0
- algo_cli/intelligence/construction/common.py +273 -0
- algo_cli/intelligence/construction/documents.py +496 -0
- algo_cli/intelligence/construction/labor_units.py +1395 -0
- algo_cli/intelligence/construction/payments.py +470 -0
- algo_cli/intelligence/construction/risk.py +784 -0
- algo_cli/intelligence/content_extractor.py +132 -0
- algo_cli/intelligence/context_adaptive.py +102 -0
- algo_cli/intelligence/context_ops.py +95 -0
- algo_cli/intelligence/count_min.py +145 -0
- algo_cli/intelligence/cow_state.py +103 -0
- algo_cli/intelligence/critic_loop.py +119 -0
- algo_cli/intelligence/cross_source.py +113 -0
- algo_cli/intelligence/daemon_mode.py +99 -0
- algo_cli/intelligence/dag_orchestration.py +151 -0
- algo_cli/intelligence/deep_research.py +155 -0
- algo_cli/intelligence/degenerate_detector.py +78 -0
- algo_cli/intelligence/delta_report.py +92 -0
- algo_cli/intelligence/discovery_event_log.py +92 -0
- algo_cli/intelligence/document_ingest.py +298 -0
- algo_cli/intelligence/dual_layer_validate.py +151 -0
- algo_cli/intelligence/echo_fidelity.py +73 -0
- algo_cli/intelligence/ema_tuning.py +104 -0
- algo_cli/intelligence/event_log.py +92 -0
- algo_cli/intelligence/evidence_graph.py +114 -0
- algo_cli/intelligence/extension_host.py +162 -0
- algo_cli/intelligence/extension_manifest.py +115 -0
- algo_cli/intelligence/falsification_suite.py +178 -0
- algo_cli/intelligence/finance/__init__.py +169 -0
- algo_cli/intelligence/finance/anomalies.py +135 -0
- algo_cli/intelligence/finance/ap_ar.py +351 -0
- algo_cli/intelligence/finance/cash.py +162 -0
- algo_cli/intelligence/finance/close.py +332 -0
- algo_cli/intelligence/finance/common.py +244 -0
- algo_cli/intelligence/finance/construction.py +135 -0
- algo_cli/intelligence/finance/controls.py +172 -0
- algo_cli/intelligence/finance/evidence.py +119 -0
- algo_cli/intelligence/finance/exceptions.py +157 -0
- algo_cli/intelligence/finance/reconciliations.py +254 -0
- algo_cli/intelligence/finance/revenue.py +109 -0
- algo_cli/intelligence/finance/tax.py +74 -0
- algo_cli/intelligence/finance/workpapers.py +111 -0
- algo_cli/intelligence/finding_record.py +120 -0
- algo_cli/intelligence/flow_dag.py +267 -0
- algo_cli/intelligence/gatherer.py +223 -0
- algo_cli/intelligence/golden_master.py +98 -0
- algo_cli/intelligence/graph_rag.py +195 -0
- algo_cli/intelligence/group_chat.py +143 -0
- algo_cli/intelligence/hash_dedup.py +145 -0
- algo_cli/intelligence/hyperloglog.py +128 -0
- algo_cli/intelligence/incremental_index.py +316 -0
- algo_cli/intelligence/index_store.py +16 -0
- algo_cli/intelligence/iteration_plan.py +133 -0
- algo_cli/intelligence/kernel_plugins.py +167 -0
- algo_cli/intelligence/lesson_catalog.py +135 -0
- algo_cli/intelligence/llm_fallback.py +169 -0
- algo_cli/intelligence/log2_histogram.py +267 -0
- algo_cli/intelligence/lsp_integration.py +147 -0
- algo_cli/intelligence/memory_evolution.py +117 -0
- algo_cli/intelligence/minhash_lsh.py +182 -0
- algo_cli/intelligence/multi_model_score.py +174 -0
- algo_cli/intelligence/multi_tier_grade.py +211 -0
- algo_cli/intelligence/negative_controls.py +113 -0
- algo_cli/intelligence/numeric_clamp.py +63 -0
- algo_cli/intelligence/occ_editor.py +66 -0
- algo_cli/intelligence/output_normalize.py +112 -0
- algo_cli/intelligence/parallel_delegation.py +98 -0
- algo_cli/intelligence/parallel_fanout.py +104 -0
- algo_cli/intelligence/permission_modes.py +105 -0
- algo_cli/intelligence/pre_push_gate.py +68 -0
- algo_cli/intelligence/prefetch.py +171 -0
- algo_cli/intelligence/process_framework.py +217 -0
- algo_cli/intelligence/project_graph.py +387 -0
- algo_cli/intelligence/query_expansion.py +146 -0
- algo_cli/intelligence/ralph_loop.py +117 -0
- algo_cli/intelligence/rate_limiter.py +153 -0
- algo_cli/intelligence/refactor_transaction.py +94 -0
- algo_cli/intelligence/research_workspace.py +108 -0
- algo_cli/intelligence/retraction_ledger.py +72 -0
- algo_cli/intelligence/saga_pattern.py +88 -0
- algo_cli/intelligence/session_fork.py +100 -0
- algo_cli/intelligence/shadow_editor.py +67 -0
- algo_cli/intelligence/shell_session.py +213 -0
- algo_cli/intelligence/source_registry.py +143 -0
- algo_cli/intelligence/spawn_scales.py +99 -0
- algo_cli/intelligence/stat_stability.py +104 -0
- algo_cli/intelligence/structural_validator.py +148 -0
- algo_cli/intelligence/subagent_spawner.py +111 -0
- algo_cli/intelligence/symmetric_verify.py +70 -0
- algo_cli/intelligence/task_classifier.py +129 -0
- algo_cli/intelligence/team_execution.py +122 -0
- algo_cli/intelligence/tiered_access.py +121 -0
- algo_cli/intelligence/utility_registry.py +159 -0
- algo_cli/intuition_engine.py +560 -0
- algo_cli/intuition_injector.py +82 -0
- algo_cli/kernels/__init__.py +5 -0
- algo_cli/kernels/manifest.py +763 -0
- algo_cli/main.py +3903 -0
- algo_cli/memory_candidates.py +541 -0
- algo_cli/memory_echo_veil.py +394 -0
- algo_cli/memory_runtime.py +112 -0
- algo_cli/model_info.py +548 -0
- algo_cli/model_profile.py +160 -0
- algo_cli/model_routing.py +74 -0
- algo_cli/oneshot.py +331 -0
- algo_cli/perf_telemetry.py +389 -0
- algo_cli/plugins.py +245 -0
- algo_cli/private_event_store.py +654 -0
- algo_cli/quantization/__init__.py +24 -0
- algo_cli/quantization/lloyd_max.py +98 -0
- algo_cli/quantization/turbo_quant.py +308 -0
- algo_cli/reasoning/__init__.py +46 -0
- algo_cli/reasoning/combinatorial.py +356 -0
- algo_cli/reasoning/graph_of_thought.py +297 -0
- algo_cli/reasoning/mcts.py +220 -0
- algo_cli/reasoning/neuro_symbolic.py +250 -0
- algo_cli/reasoning/react.py +246 -0
- algo_cli/reasoning/reflexion.py +225 -0
- algo_cli/reasoning/tree_of_thought.py +241 -0
- algo_cli/reasoning_bridge.py +150 -0
- algo_cli/reconciliation.py +284 -0
- algo_cli/reflex.py +385 -0
- algo_cli/resources/docs/ALGO.md +13958 -0
- algo_cli/resources/docs/algo-cli-algorithm-evidence-contract.md +60 -0
- algo_cli/resources/docs/algo-cli-execution-verification-contract.md +59 -0
- algo_cli/resources/docs/algo-cli-memory-lifecycle-contract.md +72 -0
- algo_cli/resources/docs/harness-extension-cleanup-recommendation.md +41 -0
- algo_cli/resources/docs/index-compute-lab-integration.md +32 -0
- algo_cli/resources/docs/inference-harness-loop-blueprint-2026-06.md +55 -0
- algo_cli/resources/docs/main-split-map.md +35 -0
- algo_cli/resources/docs/privacy-and-context.md +48 -0
- algo_cli/resources/docs/reflex-loop-v0.2.md +354 -0
- algo_cli/resources/skills/README.md +26 -0
- algo_cli/resources/skills/algo-cli.md +59 -0
- algo_cli/resources/skills/edit-file-precision.md +49 -0
- algo_cli/resources/skills/harness-search-first.md +47 -0
- algo_cli/resources/skills/memory-recall-ritual.md +51 -0
- algo_cli/resources/skills/qol-algorithms.md +224 -0
- algo_cli/resources/skills/smart-error-recovery.md +56 -0
- algo_cli/resources/skills/tool-selection-cheatsheet.md +65 -0
- algo_cli/retrieval_algorithms.py +127 -0
- algo_cli/runtime_qos.py +236 -0
- algo_cli/runtime_services.py +320 -0
- algo_cli/session_commands.py +95 -0
- algo_cli/session_mode.py +113 -0
- algo_cli/skills.py +430 -0
- algo_cli/slash_dispatch.py +1265 -0
- algo_cli/small_context.py +206 -0
- algo_cli/spawn_budget.py +89 -0
- algo_cli/task_ledger.py +84 -0
- algo_cli/task_router.py +197 -0
- algo_cli/tool_context.py +94 -0
- algo_cli/tool_contract.py +99 -0
- algo_cli/tool_policy.py +357 -0
- algo_cli/tool_runtime.py +647 -0
- algo_cli/tools.py +3056 -0
- algo_cli/url_scheme.py +174 -0
- algo_cli/verify.py +154 -0
- algo_cli/version_manifest.py +178 -0
- algo_cli/vision_screenshot_verify.py +76 -0
- algo_cli/workspace_resolver.py +68 -0
- algo_cli/x_account.py +209 -0
- algo_cli/xai_auth.py +374 -0
- algo_cli/xai_client.py +600 -0
- algo_cli_runtime-0.14.0.dist-info/METADATA +369 -0
- algo_cli_runtime-0.14.0.dist-info/RECORD +237 -0
- algo_cli_runtime-0.14.0.dist-info/WHEEL +4 -0
- algo_cli_runtime-0.14.0.dist-info/entry_points.txt +3 -0
- algo_cli_runtime-0.14.0.dist-info/licenses/LICENSE +21 -0
- ollama_cli/__init__.py +67 -0
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
"""Strict, evidence-gated comparative ratings for local agent harnesses.
|
|
2
|
+
|
|
3
|
+
The source matrix is preserved as evidence, but reported overall values are
|
|
4
|
+
never trusted. Rankings always use the equal-weight arithmetic mean of the
|
|
5
|
+
five declared axes. A separate ten-gate rubric prevents a corrected ranking
|
|
6
|
+
from being misrepresented as proof that a project is the comparative leader.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import math
|
|
12
|
+
from collections.abc import Iterable, Mapping, Sequence
|
|
13
|
+
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
SCHEMA_VERSION = 1
|
|
18
|
+
SOURCE_DATE = "2026-07-10"
|
|
19
|
+
SUBJECT_PROJECT = "Algo CLI"
|
|
20
|
+
AXES = (
|
|
21
|
+
"architecture",
|
|
22
|
+
"code_quality",
|
|
23
|
+
"test_coverage",
|
|
24
|
+
"security_safety",
|
|
25
|
+
"local_first_fit",
|
|
26
|
+
)
|
|
27
|
+
AXIS_LABELS = {
|
|
28
|
+
"architecture": "Architecture",
|
|
29
|
+
"code_quality": "Code quality",
|
|
30
|
+
"test_coverage": "Test coverage",
|
|
31
|
+
"security_safety": "Security/safety",
|
|
32
|
+
"local_first_fit": "Local-first fit",
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# These are the scores in the attached 2026-07-10 review. Do not adjust them
|
|
36
|
+
# in order to change the result; new scores require a new, reproducible review.
|
|
37
|
+
ATTACHED_2026_07_10_ROWS: tuple[dict[str, Any], ...] = (
|
|
38
|
+
{
|
|
39
|
+
"project": "OpenAgentd",
|
|
40
|
+
"axes": {
|
|
41
|
+
"architecture": 9,
|
|
42
|
+
"code_quality": 9,
|
|
43
|
+
"test_coverage": 7,
|
|
44
|
+
"security_safety": 8,
|
|
45
|
+
"local_first_fit": 7,
|
|
46
|
+
},
|
|
47
|
+
"reported_overall": 8.8,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"project": "QodeX",
|
|
51
|
+
"axes": {
|
|
52
|
+
"architecture": 8,
|
|
53
|
+
"code_quality": 8,
|
|
54
|
+
"test_coverage": 8,
|
|
55
|
+
"security_safety": 9,
|
|
56
|
+
"local_first_fit": 9,
|
|
57
|
+
},
|
|
58
|
+
"reported_overall": 8.4,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"project": SUBJECT_PROJECT,
|
|
62
|
+
"axes": {
|
|
63
|
+
"architecture": 8,
|
|
64
|
+
"code_quality": 8,
|
|
65
|
+
"test_coverage": 9,
|
|
66
|
+
"security_safety": 7,
|
|
67
|
+
"local_first_fit": 9,
|
|
68
|
+
},
|
|
69
|
+
"reported_overall": 8.2,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"project": "EvoAgentX",
|
|
73
|
+
"axes": {
|
|
74
|
+
"architecture": 7,
|
|
75
|
+
"code_quality": 7,
|
|
76
|
+
"test_coverage": 5,
|
|
77
|
+
"security_safety": 6,
|
|
78
|
+
"local_first_fit": 7,
|
|
79
|
+
},
|
|
80
|
+
"reported_overall": 6.4,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"project": "AgentEvolver",
|
|
84
|
+
"axes": {
|
|
85
|
+
"architecture": 6,
|
|
86
|
+
"code_quality": 5,
|
|
87
|
+
"test_coverage": 2,
|
|
88
|
+
"security_safety": 4,
|
|
89
|
+
"local_first_fit": 5,
|
|
90
|
+
},
|
|
91
|
+
"reported_overall": 4.4,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"project": "GenericAgent",
|
|
95
|
+
"axes": {
|
|
96
|
+
"architecture": 5,
|
|
97
|
+
"code_quality": 4,
|
|
98
|
+
"test_coverage": 1,
|
|
99
|
+
"security_safety": 4,
|
|
100
|
+
"local_first_fit": 6,
|
|
101
|
+
},
|
|
102
|
+
"reported_overall": 4.0,
|
|
103
|
+
},
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
LEADER_GATE_NAMES = (
|
|
107
|
+
"architecture dominance",
|
|
108
|
+
"code quality dominance",
|
|
109
|
+
"test coverage dominance",
|
|
110
|
+
"security/safety dominance",
|
|
111
|
+
"local-first fit dominance",
|
|
112
|
+
"reproducible comparative benchmark",
|
|
113
|
+
"production algorithm effectiveness",
|
|
114
|
+
"cross-harness protocol parity",
|
|
115
|
+
"clean landed release",
|
|
116
|
+
"complete competitor evidence",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _safe_text(value: Any) -> str:
|
|
121
|
+
try:
|
|
122
|
+
return "" if value is None else str(value)
|
|
123
|
+
except Exception:
|
|
124
|
+
return f"<{type(value).__name__}>"
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _json_safe(
|
|
128
|
+
value: Any,
|
|
129
|
+
*,
|
|
130
|
+
depth: int = 0,
|
|
131
|
+
seen: set[int] | None = None,
|
|
132
|
+
) -> Any:
|
|
133
|
+
if value is None or isinstance(value, (str, bool, int)):
|
|
134
|
+
return value
|
|
135
|
+
if isinstance(value, float):
|
|
136
|
+
return value if math.isfinite(value) else None
|
|
137
|
+
if depth >= 8:
|
|
138
|
+
return _safe_text(value)
|
|
139
|
+
identities = seen if seen is not None else set()
|
|
140
|
+
identity = id(value)
|
|
141
|
+
if identity in identities:
|
|
142
|
+
return "<recursive>"
|
|
143
|
+
if isinstance(value, Mapping):
|
|
144
|
+
identities.add(identity)
|
|
145
|
+
try:
|
|
146
|
+
return {
|
|
147
|
+
_safe_text(key): _json_safe(item, depth=depth + 1, seen=identities)
|
|
148
|
+
for key, item in value.items()
|
|
149
|
+
}
|
|
150
|
+
finally:
|
|
151
|
+
identities.discard(identity)
|
|
152
|
+
if isinstance(value, (list, tuple)):
|
|
153
|
+
identities.add(identity)
|
|
154
|
+
try:
|
|
155
|
+
return [_json_safe(item, depth=depth + 1, seen=identities) for item in value]
|
|
156
|
+
finally:
|
|
157
|
+
identities.discard(identity)
|
|
158
|
+
if isinstance(value, (set, frozenset)):
|
|
159
|
+
identities.add(identity)
|
|
160
|
+
try:
|
|
161
|
+
safe_items = [_json_safe(item, depth=depth + 1, seen=identities) for item in value]
|
|
162
|
+
return sorted(safe_items, key=_safe_text)
|
|
163
|
+
finally:
|
|
164
|
+
identities.discard(identity)
|
|
165
|
+
return _safe_text(value)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _decimal_score(value: Any) -> Decimal | None:
|
|
169
|
+
if isinstance(value, bool):
|
|
170
|
+
return None
|
|
171
|
+
try:
|
|
172
|
+
score = Decimal(str(value))
|
|
173
|
+
except (InvalidOperation, ValueError, TypeError):
|
|
174
|
+
return None
|
|
175
|
+
if not score.is_finite() or not Decimal("0") <= score <= Decimal("10"):
|
|
176
|
+
return None
|
|
177
|
+
return score
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _one_decimal(value: Decimal) -> Decimal:
|
|
181
|
+
return value.quantize(Decimal("0.1"), rounding=ROUND_HALF_UP)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _materialize_rows(rows: Iterable[Mapping[str, Any]] | None) -> tuple[list[Any], str | None]:
|
|
185
|
+
if rows is None or isinstance(rows, (str, bytes, Mapping)):
|
|
186
|
+
return [], "rows must be an iterable of rating mappings"
|
|
187
|
+
try:
|
|
188
|
+
return list(rows), None
|
|
189
|
+
except Exception as exc:
|
|
190
|
+
return [], f"could not read rating rows: {_safe_text(exc)}"
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def recompute_comparative_rating(
|
|
194
|
+
rows: Iterable[Mapping[str, Any]] | None = ATTACHED_2026_07_10_ROWS,
|
|
195
|
+
) -> dict[str, Any]:
|
|
196
|
+
"""Validate five-axis rows and rank only by their recomputed mean.
|
|
197
|
+
|
|
198
|
+
A bad reported overall is explicitly rejected, but an otherwise valid row
|
|
199
|
+
remains in the corrected ranking. Malformed rows make the comparison
|
|
200
|
+
incomplete and are excluded rather than receiving invented defaults.
|
|
201
|
+
"""
|
|
202
|
+
raw_rows, collection_error = _materialize_rows(rows)
|
|
203
|
+
schema_errors = [collection_error] if collection_error else []
|
|
204
|
+
arithmetic_errors: list[str] = []
|
|
205
|
+
normalized: list[dict[str, Any]] = []
|
|
206
|
+
seen_projects: set[str] = set()
|
|
207
|
+
|
|
208
|
+
for position, raw in enumerate(raw_rows, start=1):
|
|
209
|
+
if not isinstance(raw, Mapping):
|
|
210
|
+
schema_errors.append(f"row {position} is not a mapping")
|
|
211
|
+
continue
|
|
212
|
+
|
|
213
|
+
project = _safe_text(raw.get("project")).strip()
|
|
214
|
+
if not project:
|
|
215
|
+
schema_errors.append(f"row {position} is missing project")
|
|
216
|
+
continue
|
|
217
|
+
project_key = project.casefold()
|
|
218
|
+
if project_key in seen_projects:
|
|
219
|
+
schema_errors.append(f"duplicate project row: {project!r}")
|
|
220
|
+
continue
|
|
221
|
+
seen_projects.add(project_key)
|
|
222
|
+
|
|
223
|
+
raw_axes = raw.get("axes")
|
|
224
|
+
if not isinstance(raw_axes, Mapping):
|
|
225
|
+
schema_errors.append(f"project {project!r} axes must be a mapping")
|
|
226
|
+
continue
|
|
227
|
+
supplied_axes = {_safe_text(key) for key in raw_axes}
|
|
228
|
+
expected_axes = set(AXES)
|
|
229
|
+
if supplied_axes != expected_axes:
|
|
230
|
+
missing = sorted(expected_axes - supplied_axes)
|
|
231
|
+
extra = sorted(supplied_axes - expected_axes)
|
|
232
|
+
schema_errors.append(
|
|
233
|
+
f"project {project!r} must provide exactly five axes; "
|
|
234
|
+
f"missing={missing}, extra={extra}"
|
|
235
|
+
)
|
|
236
|
+
continue
|
|
237
|
+
|
|
238
|
+
decimal_axes: dict[str, Decimal] = {}
|
|
239
|
+
invalid_axes: list[str] = []
|
|
240
|
+
for axis in AXES:
|
|
241
|
+
score = _decimal_score(raw_axes.get(axis))
|
|
242
|
+
if score is None:
|
|
243
|
+
invalid_axes.append(axis)
|
|
244
|
+
else:
|
|
245
|
+
decimal_axes[axis] = score
|
|
246
|
+
if invalid_axes:
|
|
247
|
+
schema_errors.append(
|
|
248
|
+
f"project {project!r} has invalid 0..10 scores for axes {invalid_axes}"
|
|
249
|
+
)
|
|
250
|
+
continue
|
|
251
|
+
|
|
252
|
+
reported = _decimal_score(raw.get("reported_overall"))
|
|
253
|
+
if reported is None:
|
|
254
|
+
schema_errors.append(
|
|
255
|
+
f"project {project!r} reported_overall must be a finite 0..10 number"
|
|
256
|
+
)
|
|
257
|
+
continue
|
|
258
|
+
|
|
259
|
+
computed = _one_decimal(sum(decimal_axes.values(), Decimal("0")) / Decimal(len(AXES)))
|
|
260
|
+
reported_matches = reported == computed
|
|
261
|
+
if not reported_matches:
|
|
262
|
+
arithmetic_errors.append(
|
|
263
|
+
f"project {project!r} reported overall {float(reported):.1f} "
|
|
264
|
+
f"does not equal the five-axis mean {float(computed):.1f}"
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
normalized.append(
|
|
268
|
+
{
|
|
269
|
+
"project": project,
|
|
270
|
+
"axes": {axis: float(decimal_axes[axis]) for axis in AXES},
|
|
271
|
+
"weights": {axis: 0.2 for axis in AXES},
|
|
272
|
+
"reported_overall": float(reported),
|
|
273
|
+
"reported_overall_valid": reported_matches,
|
|
274
|
+
"accepted_reported_overall": float(reported) if reported_matches else None,
|
|
275
|
+
"computed_overall": float(computed),
|
|
276
|
+
"ranking_overall": float(computed),
|
|
277
|
+
}
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
normalized.sort(key=lambda row: (-float(row["computed_overall"]), str(row["project"]).casefold()))
|
|
281
|
+
previous_score: float | None = None
|
|
282
|
+
previous_rank = 0
|
|
283
|
+
for position, row in enumerate(normalized, start=1):
|
|
284
|
+
ranking_score = float(row["computed_overall"])
|
|
285
|
+
rank = previous_rank if previous_score == ranking_score else position
|
|
286
|
+
row["rank"] = rank
|
|
287
|
+
previous_score = ranking_score
|
|
288
|
+
previous_rank = rank
|
|
289
|
+
|
|
290
|
+
strict_leader = bool(
|
|
291
|
+
normalized
|
|
292
|
+
and (len(normalized) == 1 or normalized[0]["computed_overall"] > normalized[1]["computed_overall"])
|
|
293
|
+
)
|
|
294
|
+
return {
|
|
295
|
+
"schema_version": SCHEMA_VERSION,
|
|
296
|
+
"source_date": SOURCE_DATE,
|
|
297
|
+
"axes": list(AXES),
|
|
298
|
+
"axis_labels": dict(AXIS_LABELS),
|
|
299
|
+
"weighting": "equal arithmetic mean (20% per axis)",
|
|
300
|
+
"row_count_received": len(raw_rows),
|
|
301
|
+
"row_count_ranked": len(normalized),
|
|
302
|
+
"complete": not schema_errors and bool(normalized),
|
|
303
|
+
"reported_arithmetic_valid": not arithmetic_errors,
|
|
304
|
+
"status": "blocked" if schema_errors else ("corrected" if arithmetic_errors else "valid"),
|
|
305
|
+
"ranking_basis": "computed_overall; reported_overall is never used for ranking",
|
|
306
|
+
"strict_leader": normalized[0]["project"] if strict_leader else None,
|
|
307
|
+
"ranking": normalized,
|
|
308
|
+
"arithmetic_errors": arithmetic_errors,
|
|
309
|
+
"schema_errors": schema_errors,
|
|
310
|
+
"validation_errors": [*schema_errors, *arithmetic_errors],
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def _project_names(rating: Mapping[str, Any]) -> list[str]:
|
|
315
|
+
ranking = rating.get("ranking")
|
|
316
|
+
if not isinstance(ranking, list):
|
|
317
|
+
return []
|
|
318
|
+
return [
|
|
319
|
+
str(row.get("project"))
|
|
320
|
+
for row in ranking
|
|
321
|
+
if isinstance(row, Mapping) and str(row.get("project") or "").strip()
|
|
322
|
+
]
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def _mapping_evidence(evidence: Mapping[str, Any], key: str) -> Mapping[str, Any] | None:
|
|
326
|
+
value = evidence.get(key)
|
|
327
|
+
return value if isinstance(value, Mapping) else None
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def _nonempty_text(value: Any) -> bool:
|
|
331
|
+
return isinstance(value, str) and bool(value.strip())
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def _string_set(value: Any) -> set[str] | None:
|
|
335
|
+
if isinstance(value, (str, bytes)) or not isinstance(value, Sequence):
|
|
336
|
+
return None
|
|
337
|
+
strings = {item.strip() for item in value if isinstance(item, str) and item.strip()}
|
|
338
|
+
return strings if len(strings) == len(value) else None
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def _evidence_gate(
|
|
342
|
+
name: str,
|
|
343
|
+
data: Mapping[str, Any] | None,
|
|
344
|
+
*,
|
|
345
|
+
required_fields: tuple[str, ...],
|
|
346
|
+
valid: bool | None = None,
|
|
347
|
+
reason: str = "",
|
|
348
|
+
) -> dict[str, Any]:
|
|
349
|
+
if data is None:
|
|
350
|
+
status = "unavailable"
|
|
351
|
+
gate_reason = "required structured evidence was not supplied"
|
|
352
|
+
else:
|
|
353
|
+
missing = [field for field in required_fields if field not in data]
|
|
354
|
+
if missing:
|
|
355
|
+
status = "error"
|
|
356
|
+
gate_reason = f"evidence is missing required fields: {missing}"
|
|
357
|
+
elif data.get("status") != "pass":
|
|
358
|
+
status = "fail"
|
|
359
|
+
gate_reason = reason or "evidence status is not pass"
|
|
360
|
+
elif valid is False:
|
|
361
|
+
status = "fail"
|
|
362
|
+
gate_reason = reason or "evidence failed its acceptance criteria"
|
|
363
|
+
elif valid is None:
|
|
364
|
+
status = "error"
|
|
365
|
+
gate_reason = reason or "evidence could not be validated"
|
|
366
|
+
else:
|
|
367
|
+
status = "pass"
|
|
368
|
+
gate_reason = ""
|
|
369
|
+
return {
|
|
370
|
+
"name": name,
|
|
371
|
+
"status": status,
|
|
372
|
+
"critical": True,
|
|
373
|
+
"points": 1.0 if status == "pass" else 0.0,
|
|
374
|
+
"max_points": 1.0,
|
|
375
|
+
"reason": gate_reason,
|
|
376
|
+
"evidence": _json_safe(data) if data is not None else {},
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def _axis_gates(
|
|
381
|
+
rating: Mapping[str, Any],
|
|
382
|
+
subject: str,
|
|
383
|
+
*,
|
|
384
|
+
competitor_evidence_ready: bool,
|
|
385
|
+
) -> list[dict[str, Any]]:
|
|
386
|
+
ranking = rating.get("ranking")
|
|
387
|
+
rows = [row for row in ranking if isinstance(row, Mapping)] if isinstance(ranking, list) else []
|
|
388
|
+
subject_row = next((row for row in rows if row.get("project") == subject), None)
|
|
389
|
+
gates: list[dict[str, Any]] = []
|
|
390
|
+
for axis in AXES:
|
|
391
|
+
name = f"{AXIS_LABELS[axis].lower()} dominance"
|
|
392
|
+
if not competitor_evidence_ready:
|
|
393
|
+
status = "unavailable"
|
|
394
|
+
reason = "complete revision-pinned competitor evidence is required before axis comparison"
|
|
395
|
+
metrics: dict[str, Any] = {}
|
|
396
|
+
elif subject_row is None or not isinstance(subject_row.get("axes"), Mapping):
|
|
397
|
+
status = "error"
|
|
398
|
+
reason = f"subject {subject!r} is absent from the corrected rating"
|
|
399
|
+
metrics = {}
|
|
400
|
+
else:
|
|
401
|
+
subject_score = float(subject_row["axes"][axis])
|
|
402
|
+
competitors = [
|
|
403
|
+
(str(row["project"]), float(row["axes"][axis]))
|
|
404
|
+
for row in rows
|
|
405
|
+
if row.get("project") != subject and isinstance(row.get("axes"), Mapping)
|
|
406
|
+
]
|
|
407
|
+
if not competitors:
|
|
408
|
+
status = "error"
|
|
409
|
+
reason = "at least one competitor is required"
|
|
410
|
+
metrics = {"subject_score": subject_score}
|
|
411
|
+
else:
|
|
412
|
+
best_score = max(score for _project, score in competitors)
|
|
413
|
+
leaders = sorted(project for project, score in competitors if score == best_score)
|
|
414
|
+
status = "pass" if subject_score > best_score else "fail"
|
|
415
|
+
reason = (
|
|
416
|
+
""
|
|
417
|
+
if status == "pass"
|
|
418
|
+
else "subject must strictly exceed the best competitor; ties do not establish leadership"
|
|
419
|
+
)
|
|
420
|
+
metrics = {
|
|
421
|
+
"subject": subject,
|
|
422
|
+
"subject_score": subject_score,
|
|
423
|
+
"best_competitor_score": best_score,
|
|
424
|
+
"best_competitors": leaders,
|
|
425
|
+
"strictly_greater": subject_score > best_score,
|
|
426
|
+
}
|
|
427
|
+
gates.append(
|
|
428
|
+
{
|
|
429
|
+
"name": name,
|
|
430
|
+
"axis": axis,
|
|
431
|
+
"status": status,
|
|
432
|
+
"critical": True,
|
|
433
|
+
"points": 1.0 if status == "pass" else 0.0,
|
|
434
|
+
"max_points": 1.0,
|
|
435
|
+
"reason": reason,
|
|
436
|
+
"evidence": metrics,
|
|
437
|
+
}
|
|
438
|
+
)
|
|
439
|
+
return gates
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def evaluate_comparative_leader(
|
|
443
|
+
rating: Mapping[str, Any],
|
|
444
|
+
*,
|
|
445
|
+
subject: str = SUBJECT_PROJECT,
|
|
446
|
+
evidence: Mapping[str, Any] | None = None,
|
|
447
|
+
worktree_clean: bool | None = None,
|
|
448
|
+
competitor_evidence_complete: bool | None = None,
|
|
449
|
+
) -> dict[str, Any]:
|
|
450
|
+
"""Apply the ten critical gates required for a comparative-leader claim.
|
|
451
|
+
|
|
452
|
+
Evidence is deliberately separate from axis scores: it can validate a
|
|
453
|
+
claim, but it cannot add points to an axis. Unknown flags fail closed.
|
|
454
|
+
"""
|
|
455
|
+
supplied = evidence if isinstance(evidence, Mapping) else {}
|
|
456
|
+
projects = _project_names(rating)
|
|
457
|
+
project_set = set(projects)
|
|
458
|
+
competitor_set = project_set - {subject}
|
|
459
|
+
|
|
460
|
+
competitor_data = _mapping_evidence(supplied, "competitors")
|
|
461
|
+
competitor_projects = _string_set(competitor_data.get("projects")) if competitor_data else None
|
|
462
|
+
revisions = competitor_data.get("revisions") if competitor_data else None
|
|
463
|
+
artifact_refs = competitor_data.get("artifact_refs") if competitor_data else None
|
|
464
|
+
competitors_valid = bool(
|
|
465
|
+
competitor_data
|
|
466
|
+
and competitor_projects == competitor_set
|
|
467
|
+
and isinstance(revisions, Mapping)
|
|
468
|
+
and competitor_set <= {str(key) for key in revisions}
|
|
469
|
+
and all(_nonempty_text(revisions.get(project)) for project in competitor_set)
|
|
470
|
+
and isinstance(artifact_refs, Mapping)
|
|
471
|
+
and competitor_set <= {str(key) for key in artifact_refs}
|
|
472
|
+
and all(_nonempty_text(artifact_refs.get(project)) for project in competitor_set)
|
|
473
|
+
and _nonempty_text(competitor_data.get("observed_at"))
|
|
474
|
+
)
|
|
475
|
+
if competitor_evidence_complete is not True:
|
|
476
|
+
competitors_valid = False
|
|
477
|
+
competitor_gate = _evidence_gate(
|
|
478
|
+
"complete competitor evidence",
|
|
479
|
+
competitor_data,
|
|
480
|
+
required_fields=("status", "projects", "revisions", "artifact_refs", "observed_at"),
|
|
481
|
+
valid=(competitors_valid if competitor_evidence_complete is not None else None),
|
|
482
|
+
reason=(
|
|
483
|
+
"competitor evidence is explicitly incomplete"
|
|
484
|
+
if competitor_evidence_complete is False
|
|
485
|
+
else "evidence must cover every competitor with a pinned revision and artifact"
|
|
486
|
+
),
|
|
487
|
+
)
|
|
488
|
+
competitor_ready = competitor_gate["status"] == "pass"
|
|
489
|
+
|
|
490
|
+
benchmark_data = _mapping_evidence(supplied, "benchmark")
|
|
491
|
+
benchmark_projects = _string_set(benchmark_data.get("projects")) if benchmark_data else None
|
|
492
|
+
runs_per_project = benchmark_data.get("runs_per_project") if benchmark_data else None
|
|
493
|
+
benchmark_valid = bool(
|
|
494
|
+
benchmark_data
|
|
495
|
+
and _nonempty_text(benchmark_data.get("protocol"))
|
|
496
|
+
and _nonempty_text(benchmark_data.get("artifact_digest"))
|
|
497
|
+
and benchmark_projects == project_set
|
|
498
|
+
and isinstance(runs_per_project, int)
|
|
499
|
+
and not isinstance(runs_per_project, bool)
|
|
500
|
+
and runs_per_project >= 3
|
|
501
|
+
)
|
|
502
|
+
benchmark_gate = _evidence_gate(
|
|
503
|
+
"reproducible comparative benchmark",
|
|
504
|
+
benchmark_data,
|
|
505
|
+
required_fields=(
|
|
506
|
+
"status",
|
|
507
|
+
"protocol",
|
|
508
|
+
"artifact_digest",
|
|
509
|
+
"projects",
|
|
510
|
+
"runs_per_project",
|
|
511
|
+
),
|
|
512
|
+
valid=benchmark_valid,
|
|
513
|
+
reason="benchmark must cover every project with at least three runs per project",
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
algorithm_data = _mapping_evidence(supplied, "algorithms")
|
|
517
|
+
required_checks = algorithm_data.get("required_checks") if algorithm_data else None
|
|
518
|
+
passed_checks = algorithm_data.get("passed_checks") if algorithm_data else None
|
|
519
|
+
algorithms = _string_set(algorithm_data.get("algorithm_ids")) if algorithm_data else None
|
|
520
|
+
receipts = algorithm_data.get("production_receipts") if algorithm_data else None
|
|
521
|
+
algorithm_valid = bool(
|
|
522
|
+
algorithm_data
|
|
523
|
+
and _nonempty_text(algorithm_data.get("probe"))
|
|
524
|
+
and _nonempty_text(algorithm_data.get("artifact_digest"))
|
|
525
|
+
and isinstance(required_checks, int)
|
|
526
|
+
and not isinstance(required_checks, bool)
|
|
527
|
+
and required_checks > 0
|
|
528
|
+
and passed_checks == required_checks
|
|
529
|
+
and algorithms
|
|
530
|
+
and isinstance(receipts, Mapping)
|
|
531
|
+
and algorithms <= {str(key) for key in receipts}
|
|
532
|
+
and all(_nonempty_text(receipts.get(algorithm)) for algorithm in algorithms)
|
|
533
|
+
)
|
|
534
|
+
algorithm_gate = _evidence_gate(
|
|
535
|
+
"production algorithm effectiveness",
|
|
536
|
+
algorithm_data,
|
|
537
|
+
required_fields=(
|
|
538
|
+
"status",
|
|
539
|
+
"probe",
|
|
540
|
+
"artifact_digest",
|
|
541
|
+
"required_checks",
|
|
542
|
+
"passed_checks",
|
|
543
|
+
"algorithm_ids",
|
|
544
|
+
"production_receipts",
|
|
545
|
+
),
|
|
546
|
+
valid=algorithm_valid,
|
|
547
|
+
reason="every required algorithm check needs a production-path receipt",
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
protocol_data = _mapping_evidence(supplied, "protocol_parity")
|
|
551
|
+
protocol_projects = _string_set(protocol_data.get("projects")) if protocol_data else None
|
|
552
|
+
raw_results = protocol_data.get("raw_results") if protocol_data else None
|
|
553
|
+
protocol_valid = bool(
|
|
554
|
+
protocol_data
|
|
555
|
+
and _nonempty_text(protocol_data.get("protocol"))
|
|
556
|
+
and _nonempty_text(protocol_data.get("artifact_digest"))
|
|
557
|
+
and protocol_projects == project_set
|
|
558
|
+
and protocol_data.get("same_workload") is True
|
|
559
|
+
and protocol_data.get("same_hardware") is True
|
|
560
|
+
and protocol_data.get("same_model") is True
|
|
561
|
+
and isinstance(raw_results, Mapping)
|
|
562
|
+
and project_set <= {str(key) for key in raw_results}
|
|
563
|
+
and all(_nonempty_text(raw_results.get(project)) for project in project_set)
|
|
564
|
+
)
|
|
565
|
+
protocol_gate = _evidence_gate(
|
|
566
|
+
"cross-harness protocol parity",
|
|
567
|
+
protocol_data,
|
|
568
|
+
required_fields=(
|
|
569
|
+
"status",
|
|
570
|
+
"protocol",
|
|
571
|
+
"artifact_digest",
|
|
572
|
+
"projects",
|
|
573
|
+
"same_workload",
|
|
574
|
+
"same_hardware",
|
|
575
|
+
"same_model",
|
|
576
|
+
"raw_results",
|
|
577
|
+
),
|
|
578
|
+
valid=protocol_valid,
|
|
579
|
+
reason="all projects must run the same workload, hardware, and model with raw artifacts",
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
release_data = _mapping_evidence(supplied, "release")
|
|
583
|
+
release_valid = bool(
|
|
584
|
+
release_data
|
|
585
|
+
and worktree_clean is True
|
|
586
|
+
and _nonempty_text(release_data.get("commit"))
|
|
587
|
+
and len(str(release_data.get("commit")).strip()) >= 7
|
|
588
|
+
and _nonempty_text(release_data.get("verification_artifact"))
|
|
589
|
+
)
|
|
590
|
+
release_gate = _evidence_gate(
|
|
591
|
+
"clean landed release",
|
|
592
|
+
release_data,
|
|
593
|
+
required_fields=("status", "commit", "verification_artifact"),
|
|
594
|
+
valid=(release_valid if worktree_clean is not None else None),
|
|
595
|
+
reason=(
|
|
596
|
+
"the worktree is dirty; working-tree results cannot establish released leadership"
|
|
597
|
+
if worktree_clean is False
|
|
598
|
+
else "a clean worktree, landed commit, and verification artifact are required"
|
|
599
|
+
),
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
gates = [
|
|
603
|
+
*_axis_gates(rating, subject, competitor_evidence_ready=competitor_ready),
|
|
604
|
+
benchmark_gate,
|
|
605
|
+
algorithm_gate,
|
|
606
|
+
protocol_gate,
|
|
607
|
+
release_gate,
|
|
608
|
+
competitor_gate,
|
|
609
|
+
]
|
|
610
|
+
score = float(sum(float(gate["points"]) for gate in gates))
|
|
611
|
+
ranking = rating.get("ranking")
|
|
612
|
+
subject_row = next(
|
|
613
|
+
(
|
|
614
|
+
row
|
|
615
|
+
for row in ranking
|
|
616
|
+
if isinstance(row, Mapping) and row.get("project") == subject
|
|
617
|
+
),
|
|
618
|
+
None,
|
|
619
|
+
) if isinstance(ranking, list) else None
|
|
620
|
+
corrected_rank = subject_row.get("rank") if isinstance(subject_row, Mapping) else None
|
|
621
|
+
strict_leader = rating.get("strict_leader") == subject
|
|
622
|
+
all_gates_pass = len(gates) == 10 and all(gate["status"] == "pass" for gate in gates)
|
|
623
|
+
claim_allowed = bool(
|
|
624
|
+
rating.get("complete")
|
|
625
|
+
and strict_leader
|
|
626
|
+
and corrected_rank == 1
|
|
627
|
+
and all_gates_pass
|
|
628
|
+
and worktree_clean is True
|
|
629
|
+
and competitor_evidence_complete is True
|
|
630
|
+
)
|
|
631
|
+
blocking_reasons = [
|
|
632
|
+
f"{gate['name']}: {gate['reason'] or gate['status']}"
|
|
633
|
+
for gate in gates
|
|
634
|
+
if gate["status"] != "pass"
|
|
635
|
+
]
|
|
636
|
+
if corrected_rank != 1:
|
|
637
|
+
blocking_reasons.insert(0, f"corrected comparative rank is {corrected_rank!r}, not 1")
|
|
638
|
+
if not strict_leader:
|
|
639
|
+
blocking_reasons.insert(0, "subject is not the unique corrected-rating leader")
|
|
640
|
+
if not rating.get("complete"):
|
|
641
|
+
blocking_reasons.insert(0, "rating rows are incomplete or malformed")
|
|
642
|
+
|
|
643
|
+
return {
|
|
644
|
+
"schema_version": SCHEMA_VERSION,
|
|
645
|
+
"subject": subject,
|
|
646
|
+
"status": "leader" if claim_allowed else "blocked",
|
|
647
|
+
"claim_allowed": claim_allowed,
|
|
648
|
+
"score": score,
|
|
649
|
+
"max_score": 10.0,
|
|
650
|
+
"gate_count": len(gates),
|
|
651
|
+
"all_gates_critical": True,
|
|
652
|
+
"corrected_rank": corrected_rank,
|
|
653
|
+
"strict_corrected_leader": strict_leader,
|
|
654
|
+
"worktree_clean": worktree_clean,
|
|
655
|
+
"competitor_evidence_complete": competitor_evidence_complete,
|
|
656
|
+
"evidence_policy": (
|
|
657
|
+
"Every gate must pass. Unknown evidence, a dirty worktree, a tie, or a non-leading "
|
|
658
|
+
"corrected rank blocks a leader claim. Evidence never changes an axis score."
|
|
659
|
+
),
|
|
660
|
+
"gates": gates,
|
|
661
|
+
"blocking_reasons": blocking_reasons,
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
def build_competitive_harness_report(
|
|
666
|
+
rows: Iterable[Mapping[str, Any]] | None = ATTACHED_2026_07_10_ROWS,
|
|
667
|
+
*,
|
|
668
|
+
subject: str = SUBJECT_PROJECT,
|
|
669
|
+
evidence: Mapping[str, Any] | None = None,
|
|
670
|
+
worktree_clean: bool | None = None,
|
|
671
|
+
competitor_evidence_complete: bool | None = None,
|
|
672
|
+
) -> dict[str, Any]:
|
|
673
|
+
"""Return the corrected rating and fail-closed leader rubric as JSON data."""
|
|
674
|
+
rating = recompute_comparative_rating(rows)
|
|
675
|
+
leader = evaluate_comparative_leader(
|
|
676
|
+
rating,
|
|
677
|
+
subject=subject,
|
|
678
|
+
evidence=evidence,
|
|
679
|
+
worktree_clean=worktree_clean,
|
|
680
|
+
competitor_evidence_complete=competitor_evidence_complete,
|
|
681
|
+
)
|
|
682
|
+
return {
|
|
683
|
+
"schema_version": SCHEMA_VERSION,
|
|
684
|
+
"report": "competitive-harness-rating",
|
|
685
|
+
"source_date": SOURCE_DATE,
|
|
686
|
+
"rating": rating,
|
|
687
|
+
"leader_rubric": leader,
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
__all__ = [
|
|
692
|
+
"ATTACHED_2026_07_10_ROWS",
|
|
693
|
+
"AXES",
|
|
694
|
+
"AXIS_LABELS",
|
|
695
|
+
"LEADER_GATE_NAMES",
|
|
696
|
+
"SCHEMA_VERSION",
|
|
697
|
+
"SOURCE_DATE",
|
|
698
|
+
"SUBJECT_PROJECT",
|
|
699
|
+
"build_competitive_harness_report",
|
|
700
|
+
"evaluate_comparative_leader",
|
|
701
|
+
"recompute_comparative_rating",
|
|
702
|
+
]
|