omnilane 0.42.4 → 0.42.6
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +97 -1
- package/README.ja.md +48 -0
- package/README.ko.md +48 -0
- package/README.md +79 -0
- package/README.zh-CN.md +69 -0
- package/README.zh-TW.md +69 -0
- package/VERSION +1 -1
- package/docs/release-notes-0.42.5.md +99 -0
- package/package.json +2 -2
- package/plugin.json +1 -1
- package/scripts/doctor.sh +26 -0
- package/scripts/lib/aa_policy.py +38 -2
- package/scripts/lib/build_overlay.py +214 -0
- package/scripts/lib/overlay_health.py +97 -0
- package/scripts/lib/probe.py +408 -0
- package/skills/omnilane/SKILL.md +83 -1
- package/docs/release-notes-0.42.4.md +0 -47
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnilane",
|
|
3
|
-
"version": "0.42.
|
|
3
|
+
"version": "0.42.6",
|
|
4
4
|
"description": "One routing table, every harness — classify subtasks into lanes and delegate each lane through a compatible caller-owned native agent or vendor CLI.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"omnilane": "bin/omnilane"
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"docs/model-capabilities-2026-09.md",
|
|
30
30
|
"docs/native-executor.md",
|
|
31
31
|
"docs/completion-wakeup.md",
|
|
32
|
-
"docs/release-notes-0.42.
|
|
32
|
+
"docs/release-notes-0.42.5.md",
|
|
33
33
|
"hooks/",
|
|
34
34
|
"skills/",
|
|
35
35
|
".claude-plugin/",
|
package/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://antigravity.google/schemas/v1/plugin.json",
|
|
3
3
|
"name": "omnilane",
|
|
4
|
-
"version": "0.42.
|
|
4
|
+
"version": "0.42.6",
|
|
5
5
|
"description": "One routing table, every harness: classify subtasks into lanes and delegate through compatible caller-owned native agents or vendor CLIs with exact-AA downward policy and supervised jobs."
|
|
6
6
|
}
|
package/scripts/doctor.sh
CHANGED
|
@@ -33,6 +33,7 @@ REPO="${OMNILANE_DOCTOR_REPO:-$SCRIPT_ROOT}"
|
|
|
33
33
|
OMNILANE_HOME="${OMNILANE_HOME:-$HOME/.omnilane}"
|
|
34
34
|
PROBE_SCRIPT="${OMNILANE_PROVIDER_PROBE_SCRIPT:-$REPO/scripts/provider-probe.sh}"
|
|
35
35
|
GOAL_LOOP="${OMNILANE_DOCTOR_GOAL_LOOP:-$REPO/scripts/lib/goal-loop.sh}"
|
|
36
|
+
OVERLAY_HEALTH="${OMNILANE_DOCTOR_OVERLAY_HEALTH:-$REPO/scripts/lib/overlay_health.py}"
|
|
36
37
|
# shellcheck disable=SC1091
|
|
37
38
|
source "$SCRIPT_ROOT/scripts/lib/live-protocol.sh"
|
|
38
39
|
PASS_COUNT=0
|
|
@@ -409,6 +410,31 @@ else
|
|
|
409
410
|
report PASS live-unavailable "none"
|
|
410
411
|
fi
|
|
411
412
|
|
|
413
|
+
# live-capable above answers "does this CLI support a live session", which stays
|
|
414
|
+
# true while the AA gate refuses every dispatch. Nothing else loads the overlay,
|
|
415
|
+
# so one drifted evidence hash used to go unreported by an all-green doctor.
|
|
416
|
+
overlay_path="$(
|
|
417
|
+
set +u
|
|
418
|
+
[[ -f "$OMNILANE_HOME/local.sh" ]] && . "$OMNILANE_HOME/local.sh" 2>/dev/null
|
|
419
|
+
printf '%s' "${OMNILANE_AA_TRANSPORT_OVERLAY:-}"
|
|
420
|
+
)"
|
|
421
|
+
if [[ -z "$overlay_path" ]]; then
|
|
422
|
+
report PASS transport-overlay "no overlay configured; every runtime mapping stays unverified"
|
|
423
|
+
elif ! command -v python3 >/dev/null 2>&1; then
|
|
424
|
+
report WARN transport-overlay "python3 is absent; cannot load the AA transport overlay"
|
|
425
|
+
elif [[ ! -r "$OVERLAY_HEALTH" ]]; then
|
|
426
|
+
report WARN transport-overlay "$OVERLAY_HEALTH is missing"
|
|
427
|
+
else
|
|
428
|
+
overlay_line="$(OMNILANE_AA_TRANSPORT_OVERLAY="$overlay_path" \
|
|
429
|
+
python3 "$OVERLAY_HEALTH" "$REPO" 2>&1)"
|
|
430
|
+
overlay_level="${overlay_line%% *}"
|
|
431
|
+
overlay_message="${overlay_line#* }"
|
|
432
|
+
case "$overlay_level" in
|
|
433
|
+
PASS|WARN|FAIL) report "$overlay_level" transport-overlay "$overlay_message" ;;
|
|
434
|
+
*) report WARN transport-overlay "unreadable overlay health output: $overlay_line" ;;
|
|
435
|
+
esac
|
|
436
|
+
fi
|
|
437
|
+
|
|
412
438
|
if [[ -n "$PROBE_VENDOR" ]]; then
|
|
413
439
|
if [[ ! -x "$PROBE_SCRIPT" ]]; then
|
|
414
440
|
report FAIL provider-probe "probe runner is unavailable"
|
package/scripts/lib/aa_policy.py
CHANGED
|
@@ -28,6 +28,11 @@ MAX_BYTES = 1_048_576
|
|
|
28
28
|
APPROVED_REGISTRY_SHA256 = "0782c87de123c02738c3ff60e4bc3c1cc10d110113e872b8f8627212861cdaab"
|
|
29
29
|
|
|
30
30
|
IDENTITY_FIELDS = ("vendor", "model", "effort", "reasoning", "fallback")
|
|
31
|
+
TRANSPORT_EVIDENCE_VENDORS = frozenset(("codex", "claude", "grok", "gemini"))
|
|
32
|
+
# How strongly a mapping's probe identified the responder. Reported, never
|
|
33
|
+
# enforced: dispatch turns on runtime_verified alone, as it did before the field
|
|
34
|
+
# existed, so a weaker tier can never refuse a lane that used to run.
|
|
35
|
+
TRANSPORT_EVIDENCE_TIERS = frozenset(("billed-model", "client-echo", "selector-only"))
|
|
31
36
|
IDENTIFIER = re.compile(r"[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}\Z")
|
|
32
37
|
|
|
33
38
|
|
|
@@ -147,15 +152,37 @@ def apply_transport_overlay(registry: dict[str, Any]) -> None:
|
|
|
147
152
|
_check(overlay.get("schema_version") == 1, "unsupported transport overlay")
|
|
148
153
|
_check(overlay.get("snapshot_id") == registry["snapshot"]["id"], "transport overlay snapshot mismatch")
|
|
149
154
|
_check(overlay.get("host") == socket.gethostname(), "transport overlay host mismatch")
|
|
155
|
+
stale_vendors: set[str] = set()
|
|
150
156
|
for evidence in overlay.get("evidence", []):
|
|
151
|
-
|
|
157
|
+
_check(isinstance(evidence, dict), "invalid transport evidence")
|
|
158
|
+
vendor = evidence.get("vendor")
|
|
159
|
+
_check(
|
|
160
|
+
"vendor" not in evidence
|
|
161
|
+
or type(vendor) is str and vendor in TRANSPORT_EVIDENCE_VENDORS,
|
|
162
|
+
"invalid transport evidence vendor",
|
|
163
|
+
)
|
|
164
|
+
evidence_path = evidence["path"]
|
|
165
|
+
evidence_sha256 = evidence["sha256"]
|
|
166
|
+
_check(type(evidence_path) is str, "invalid transport evidence path")
|
|
167
|
+
_check(type(evidence_sha256) is str, "invalid transport evidence digest")
|
|
168
|
+
try:
|
|
169
|
+
fd = os.open(evidence_path, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)
|
|
170
|
+
except FileNotFoundError:
|
|
171
|
+
if vendor is None:
|
|
172
|
+
raise
|
|
173
|
+
stale_vendors.add(vendor)
|
|
174
|
+
continue
|
|
152
175
|
with os.fdopen(fd, "rb") as stream:
|
|
153
176
|
_check(stat.S_ISREG(os.fstat(stream.fileno()).st_mode), "invalid transport evidence file")
|
|
154
177
|
digest_file = hashlib.sha256()
|
|
155
178
|
for block in iter(lambda: stream.read(1024 * 1024), b""):
|
|
156
179
|
digest_file.update(block)
|
|
157
|
-
|
|
180
|
+
if digest_file.hexdigest() != evidence_sha256:
|
|
181
|
+
if vendor is None:
|
|
182
|
+
_check(False, "transport contract evidence changed")
|
|
183
|
+
stale_vendors.add(vendor)
|
|
158
184
|
_check(bool(overlay.get("evidence")), "transport overlay requires local evidence")
|
|
185
|
+
tiers: dict[str, str] = {}
|
|
159
186
|
for mapping in overlay.get("mappings", []):
|
|
160
187
|
rows = [row for row in registry["scored_configs"] if row["id"] == mapping.get("config_id")]
|
|
161
188
|
_check(len(rows) == 1, "unknown overlay config")
|
|
@@ -175,6 +202,11 @@ def apply_transport_overlay(registry: dict[str, Any]) -> None:
|
|
|
175
202
|
_check(mapping["runtime_model"].endswith("-" + row["effort"]), "encoded effort does not match exact tuple")
|
|
176
203
|
else:
|
|
177
204
|
_check(mapping.get("runtime_model") == row["model"], "overlay model mismatch")
|
|
205
|
+
tier = mapping.get("evidence_tier", "selector-only")
|
|
206
|
+
_check(tier in TRANSPORT_EVIDENCE_TIERS, "unknown transport evidence tier")
|
|
207
|
+
if row["vendor"] in stale_vendors:
|
|
208
|
+
continue
|
|
209
|
+
tiers[row["id"]] = tier
|
|
178
210
|
row["transport_mapping"].update(
|
|
179
211
|
status="verified", runtime_verified=True,
|
|
180
212
|
runtime_model=mapping["runtime_model"], runtime_effort=mapping["runtime_effort"],
|
|
@@ -183,6 +215,8 @@ def apply_transport_overlay(registry: dict[str, Any]) -> None:
|
|
|
183
215
|
verification="request-selector-contract", upstream_identity_verified=False,
|
|
184
216
|
overlay_sha256=digest, overlay_host=overlay["host"],
|
|
185
217
|
)
|
|
218
|
+
registry["_stale_transport_vendors"] = sorted(stale_vendors)
|
|
219
|
+
registry["_transport_evidence_tiers"] = tiers
|
|
186
220
|
|
|
187
221
|
|
|
188
222
|
def load_registry(path: str | Path, expected_sha256: str | None = None) -> tuple[dict[str, Any], str]:
|
|
@@ -233,6 +267,8 @@ def _runtime_target(registry: dict[str, Any], vendor: str, model: str,
|
|
|
233
267
|
exact_id = [row for row in registry["scored_configs"] if row["id"] == target_config] if target_config else registry["scored_configs"]
|
|
234
268
|
if target_config and not exact_id:
|
|
235
269
|
return None, "unknown-target-config", {"target_config": target_config}
|
|
270
|
+
if vendor in registry.get("_stale_transport_vendors", []):
|
|
271
|
+
return None, "unknown-target-runtime", {"vendor": vendor, "model": model, "effort": effort}
|
|
236
272
|
vendor_rows = [row for row in exact_id if row["vendor"] == vendor]
|
|
237
273
|
candidates: list[dict[str, Any]] = []
|
|
238
274
|
unresolved: list[str] = []
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Build the merged omnilane AA transport overlay from verified probe evidence.
|
|
3
|
+
|
|
4
|
+
Only (config_id, selector) pairs listed in PROVEN are written. Every entry here
|
|
5
|
+
corresponds to a probe run under the selected evidence root whose raw
|
|
6
|
+
stdout/stderr is hashed into the manifest, so the overlay's evidence[] anchors
|
|
7
|
+
the whole set.
|
|
8
|
+
"""
|
|
9
|
+
import argparse
|
|
10
|
+
import hashlib
|
|
11
|
+
import json
|
|
12
|
+
import os
|
|
13
|
+
import shutil
|
|
14
|
+
import socket
|
|
15
|
+
from collections import Counter
|
|
16
|
+
from datetime import datetime, timezone
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
REPO = Path(os.environ.get("OMNILANE_REPO", "/Users/vincentw/dev/omnilane"))
|
|
20
|
+
HOME = Path.home()
|
|
21
|
+
SWEEP_ID = os.environ.get("OMNILANE_TRANSPORT_SWEEP_ID", "overlay-reprobe-20260909")
|
|
22
|
+
DEFAULT_ROOT = HOME / ".omnilane" / "transport-evidence" / SWEEP_ID
|
|
23
|
+
REGISTRY = json.loads((REPO / "config/aa-model-policy.json").read_text())
|
|
24
|
+
ROWS = {r["id"]: r for r in REGISTRY["scored_configs"]}
|
|
25
|
+
IDENTITY_FIELDS = ("vendor", "model", "effort", "reasoning", "fallback")
|
|
26
|
+
|
|
27
|
+
# config_id -> (selector_type, runtime_model, probe evidence basename)
|
|
28
|
+
PROVEN: dict[str, tuple[str, str, str]] = {}
|
|
29
|
+
|
|
30
|
+
for model, slug in [("gpt-6-astra", "gpt-6-astra"), ("gpt-5.6-sol", "gpt-5_6-sol"),
|
|
31
|
+
("gpt-5.6-luna", "gpt-5_6-luna"), ("gpt-5.6-terra", "gpt-5_6-terra")]:
|
|
32
|
+
base = model.replace(".", "-").replace("gpt-", "gpt-")
|
|
33
|
+
for effort in ["max", "xhigh", "high", "medium", "low"]:
|
|
34
|
+
cid = f"codex/{model.replace('.', '-')}" + ("" if effort == "max" else f"-{effort}")
|
|
35
|
+
ev = f"cx-avail-{model.replace('.', '_')}" if effort == "high" else f"cx-{model.replace('.', '_')}-{effort}"
|
|
36
|
+
PROVEN[cid] = ("model_and_effort", model, ev)
|
|
37
|
+
|
|
38
|
+
for effort in ["xhigh", "medium"]:
|
|
39
|
+
PROVEN[f"codex/gpt-5-4-mini" + ("" if effort == "xhigh" else f"-{effort}")] = (
|
|
40
|
+
"model_and_effort", "gpt-5.4-mini", f"cx-gpt-5_4-mini-{effort}")
|
|
41
|
+
|
|
42
|
+
PROVEN["grok/grok-4-6"] = ("cli_reasoning_effort", "grok-4.6", "gk-grok-4_6-high")
|
|
43
|
+
for effort in ["xhigh", "medium", "low"]:
|
|
44
|
+
PROVEN[f"grok/grok-4-6-{effort}"] = ("cli_reasoning_effort", "grok-4.6", f"gk-grok-4_6-{effort}")
|
|
45
|
+
PROVEN["grok/grok-4-5"] = ("cli_reasoning_effort", "grok-4.5", "gk-grok-4_5-high")
|
|
46
|
+
|
|
47
|
+
for cid, rid, ev in [
|
|
48
|
+
("gemini/gemini-3-8-flash", "gemini-3.8-flash-high", "agy-gemini-3_8-flash-high"),
|
|
49
|
+
("gemini/gemini-3-8-flash-medium", "gemini-3.8-flash-medium", "agy-gemini-3_8-flash-medium"),
|
|
50
|
+
("gemini/gemini-3-8-flash-low", "gemini-3.8-flash-low", "agy-gemini-3_8-flash-low"),
|
|
51
|
+
("gemini/gemini-3-7-flash", "gemini-3.7-flash-high", "agy-gemini-3_7-flash-high"),
|
|
52
|
+
("gemini/gemini-3-7-flash-medium", "gemini-3.7-flash-medium", "agy-gemini-3_7-flash-medium"),
|
|
53
|
+
("gemini/gemini-3-7-flash-low", "gemini-3.7-flash-low", "agy-gemini-3_7-flash-low"),
|
|
54
|
+
("gemini/gemini-3-6-flash", "gemini-3.6-flash-high", "agy-gemini-3_6-flash-high"),
|
|
55
|
+
]:
|
|
56
|
+
PROVEN[cid] = ("model_id_encoded_effort", rid, ev)
|
|
57
|
+
|
|
58
|
+
for effort in ["max", "xhigh", "high", "medium", "low"]:
|
|
59
|
+
cid = "claude/claude-opus-5" + ("" if effort == "max" else f"-{effort}")
|
|
60
|
+
PROVEN[cid] = ("model_and_effort", "claude-opus-5", f"cl-claude-opus-5-{effort}")
|
|
61
|
+
# gpt-6-astra rejects effort "none" upstream ("Unsupported value: 'none' is not
|
|
62
|
+
# supported with the 'gpt-6-astra' model"), so it has no non-reasoning selector.
|
|
63
|
+
for model in ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-5.4-mini"]:
|
|
64
|
+
PROVEN[f"codex/{model.replace('.', '-')}-non-reasoning"] = (
|
|
65
|
+
"model_and_effort", model, f"cx-{model.replace('.', '_')}-none")
|
|
66
|
+
|
|
67
|
+
# Default (no --effort) Haiku 4.5 spent 124 thinking tokens, so the selector
|
|
68
|
+
# lands on the reasoning row rather than its non-reasoning sibling.
|
|
69
|
+
PROVEN["claude/claude-4-5-haiku-reasoning"] = (
|
|
70
|
+
"model_and_effort", "claude-haiku-4-5", "cl-rmode-claude-haiku-4-5-noeffort")
|
|
71
|
+
|
|
72
|
+
for cid, model in [("claude/claude-sonnet-5", "claude-sonnet-5"),
|
|
73
|
+
("claude/claude-opus-4-8", "claude-opus-4-8"),
|
|
74
|
+
("claude/claude-opus-4-7", "claude-opus-4-7"),
|
|
75
|
+
("claude/claude-opus-4-6-adaptive", "claude-opus-4-6"),
|
|
76
|
+
("claude/claude-sonnet-4-6-adaptive", "claude-sonnet-4-6")]:
|
|
77
|
+
PROVEN[cid] = ("model_and_effort", model, f"cl-{model}-max")
|
|
78
|
+
|
|
79
|
+
# Fable is listed so its failures reach unproven[] rather than vanishing. Its
|
|
80
|
+
# probes were refused for quota on 2026-09-07 and again on 2026-09-09; the
|
|
81
|
+
# verdict decides whether these rows become mappings or stay visible failures.
|
|
82
|
+
for effort in ["max", "xhigh", "high", "medium", "low"]:
|
|
83
|
+
cid = "claude/claude-fable-5-1" + ("" if effort == "max" else f"-{effort}")
|
|
84
|
+
PROVEN[cid] = ("model_and_effort", "claude-fable-5-1", f"cl-claude-fable-5-1-{effort}")
|
|
85
|
+
PROVEN["claude/claude-fable-5"] = (
|
|
86
|
+
"model_and_effort", "claude-fable-5", "cl-claude-fable-5-max")
|
|
87
|
+
|
|
88
|
+
def cli_path(name: str) -> Path:
|
|
89
|
+
"""Anchor the executable the runners resolve, not a version pinned here.
|
|
90
|
+
|
|
91
|
+
The runners invoke bare names, so a pinned path can name a binary that has
|
|
92
|
+
not run since the last self-update; the overlay must hash what answers.
|
|
93
|
+
aa_policy opens evidence with O_NOFOLLOW, so this resolves past the symlink.
|
|
94
|
+
"""
|
|
95
|
+
found = shutil.which(name)
|
|
96
|
+
if not found:
|
|
97
|
+
raise SystemExit(f"cannot resolve the {name} CLI to anchor its evidence")
|
|
98
|
+
return Path(found).resolve()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def core_evidence() -> list[tuple[Path, str]]:
|
|
102
|
+
"""Resolved when a build runs, not at import: a host missing one CLI can
|
|
103
|
+
still load this module to read PROVEN."""
|
|
104
|
+
return [
|
|
105
|
+
(cli_path("grok"), "grok"),
|
|
106
|
+
(REPO / "scripts/runners/run-grok.sh", "grok"),
|
|
107
|
+
(cli_path("codex"), "codex"),
|
|
108
|
+
(REPO / "scripts/runners/run-codex.sh", "codex"),
|
|
109
|
+
(cli_path("claude"), "claude"),
|
|
110
|
+
(REPO / "scripts/runners/run-claude.sh", "claude"),
|
|
111
|
+
(cli_path("agy"), "gemini"),
|
|
112
|
+
(REPO / "scripts/runners/run-gemini.sh", "gemini"),
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def sha256(path: Path) -> str:
|
|
117
|
+
digest = hashlib.sha256()
|
|
118
|
+
with open(path, "rb") as stream:
|
|
119
|
+
for block in iter(lambda: stream.read(1 << 20), b""):
|
|
120
|
+
digest.update(block)
|
|
121
|
+
return digest.hexdigest()
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def main(argv: list[str] | None = None) -> None:
|
|
125
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
126
|
+
parser.add_argument(
|
|
127
|
+
"--root",
|
|
128
|
+
type=Path,
|
|
129
|
+
default=DEFAULT_ROOT,
|
|
130
|
+
help=f"probe sweep root (default: {DEFAULT_ROOT})",
|
|
131
|
+
)
|
|
132
|
+
args = parser.parse_args(argv)
|
|
133
|
+
root = args.root.expanduser()
|
|
134
|
+
|
|
135
|
+
manifest = {"probe_runs": {}}
|
|
136
|
+
unproven = []
|
|
137
|
+
# Evidence written before 0.42.6 carries no tier; it proved the selector and
|
|
138
|
+
# nothing about who answered, which is exactly what selector-only records.
|
|
139
|
+
tiers: dict[str, str] = {}
|
|
140
|
+
for cid, (_, _, ev) in sorted(PROVEN.items()):
|
|
141
|
+
entry = {}
|
|
142
|
+
for suffix in ("json", "stdout", "stderr", "rollout", "cli_log"):
|
|
143
|
+
path = root / "evidence" / f"{ev}.{suffix}"
|
|
144
|
+
if path.exists():
|
|
145
|
+
entry[suffix] = {"path": str(path), "sha256": sha256(path)}
|
|
146
|
+
if "json" not in entry:
|
|
147
|
+
raise SystemExit(f"missing probe evidence for {cid}: {ev}")
|
|
148
|
+
descriptor_path = Path(entry["json"]["path"])
|
|
149
|
+
descriptor = json.loads(descriptor_path.read_text())
|
|
150
|
+
if not isinstance(descriptor, dict):
|
|
151
|
+
raise SystemExit(f"invalid probe descriptor for {cid}: {ev}")
|
|
152
|
+
if "verdict" not in descriptor:
|
|
153
|
+
print(f"warning: legacy evidence (verdict=unknown): {cid}: {ev}")
|
|
154
|
+
elif descriptor["verdict"] != "pass":
|
|
155
|
+
unproven.append({
|
|
156
|
+
"config_id": cid,
|
|
157
|
+
"verdict_reason": descriptor.get("verdict_reason") or f"verdict: {descriptor['verdict']}",
|
|
158
|
+
"observed_model": descriptor.get("observed_model"),
|
|
159
|
+
"probed_at": descriptor.get("probed_at") or datetime.fromtimestamp(
|
|
160
|
+
descriptor_path.stat().st_mtime, timezone.utc).isoformat(),
|
|
161
|
+
})
|
|
162
|
+
# Visibility only: failed evidence must not enter the signed manifest.
|
|
163
|
+
continue
|
|
164
|
+
tier = descriptor.get("evidence_tier", "selector-only")
|
|
165
|
+
if tier not in ("billed-model", "client-echo", "selector-only"):
|
|
166
|
+
raise SystemExit(f"unknown evidence tier for {cid}: {tier}")
|
|
167
|
+
tiers[cid] = tier
|
|
168
|
+
manifest["probe_runs"][cid] = entry
|
|
169
|
+
manifest_path = root / "probe-manifest.json"
|
|
170
|
+
manifest_path.write_text(json.dumps(manifest, indent=2, sort_keys=True) + "\n")
|
|
171
|
+
|
|
172
|
+
mappings = []
|
|
173
|
+
for cid, (selector, runtime_model, _) in sorted(PROVEN.items()):
|
|
174
|
+
if cid not in manifest["probe_runs"]:
|
|
175
|
+
continue
|
|
176
|
+
row = ROWS[cid]
|
|
177
|
+
mapping = {
|
|
178
|
+
"config_id": cid,
|
|
179
|
+
"identity": {key: row[key] for key in IDENTITY_FIELDS},
|
|
180
|
+
"runtime_model": runtime_model,
|
|
181
|
+
"runtime_effort": row["effort"],
|
|
182
|
+
"selector_type": selector,
|
|
183
|
+
"verification": "request-selector-contract",
|
|
184
|
+
"evidence_tier": tiers.get(cid, "selector-only"),
|
|
185
|
+
}
|
|
186
|
+
if selector == "cli_reasoning_effort":
|
|
187
|
+
mapping["cli_flag"] = "--reasoning-effort"
|
|
188
|
+
mappings.append(mapping)
|
|
189
|
+
|
|
190
|
+
evidence = [
|
|
191
|
+
{"path": str(path), "sha256": sha256(path), "vendor": vendor}
|
|
192
|
+
for path, vendor in core_evidence()
|
|
193
|
+
]
|
|
194
|
+
evidence.append({"path": str(manifest_path), "sha256": sha256(manifest_path)})
|
|
195
|
+
|
|
196
|
+
overlay = {
|
|
197
|
+
"schema_version": 1,
|
|
198
|
+
"snapshot_id": REGISTRY["snapshot"]["id"],
|
|
199
|
+
"host": socket.gethostname(),
|
|
200
|
+
"source": ("claude-code / MacStudio / operator-directed full sweep 2026-09-07; "
|
|
201
|
+
"gemini selectors re-probed 2026-09-09 after agy 1.1.27 -> 1.1.28"),
|
|
202
|
+
"evidence": evidence,
|
|
203
|
+
"mappings": mappings,
|
|
204
|
+
"unproven": unproven,
|
|
205
|
+
}
|
|
206
|
+
out = root / "transport-contracts.local.json"
|
|
207
|
+
out.write_text(json.dumps(overlay, indent=2, ensure_ascii=False) + "\n")
|
|
208
|
+
spread = Counter(m["evidence_tier"] for m in mappings)
|
|
209
|
+
print(f"wrote {out} with {len(mappings)} mappings and {len(evidence)} evidence anchors")
|
|
210
|
+
print(" evidence tiers: " + ", ".join(f"{tier} {count}" for tier, count in sorted(spread.items())))
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
if __name__ == "__main__":
|
|
214
|
+
main()
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Report whether the configured AA transport overlay still loads.
|
|
3
|
+
|
|
4
|
+
Prints one `LEVEL<TAB>message` line for `omnilane doctor`. Always exits 0; the
|
|
5
|
+
caller decides how to grade the level. Nothing here contacts a provider.
|
|
6
|
+
|
|
7
|
+
Exists because no other doctor check observes the AA gate: every vendor CLI can
|
|
8
|
+
be reachable and every lane resolvable while `load_registry` refuses the whole
|
|
9
|
+
registry over one drifted evidence hash.
|
|
10
|
+
"""
|
|
11
|
+
import hashlib
|
|
12
|
+
import os
|
|
13
|
+
import sys
|
|
14
|
+
from collections import Counter
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
REPO = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(__file__).resolve().parents[1]
|
|
18
|
+
sys.path.insert(0, str(REPO / "scripts" / "lib"))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def emit(level: str, message: str) -> None:
|
|
22
|
+
print(f"{level}\t{message}")
|
|
23
|
+
raise SystemExit(0)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def digest(path: Path) -> str:
|
|
27
|
+
value = hashlib.sha256()
|
|
28
|
+
with open(path, "rb") as stream:
|
|
29
|
+
for block in iter(lambda: stream.read(1024 * 1024), b""):
|
|
30
|
+
value.update(block)
|
|
31
|
+
return value.hexdigest()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def offenders(overlay_path: Path) -> list[str]:
|
|
35
|
+
"""Name the evidence entries that no longer match, for an actionable report."""
|
|
36
|
+
import json
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
overlay = json.loads(overlay_path.read_text())
|
|
40
|
+
except (OSError, ValueError):
|
|
41
|
+
return []
|
|
42
|
+
found = []
|
|
43
|
+
for entry in overlay.get("evidence", []):
|
|
44
|
+
path = Path(entry.get("path", ""))
|
|
45
|
+
tag = entry.get("vendor") or "untagged"
|
|
46
|
+
if not path.exists():
|
|
47
|
+
found.append(f"{tag}:missing {path}")
|
|
48
|
+
elif digest(path) != entry.get("sha256"):
|
|
49
|
+
found.append(f"{tag}:hash drift {path}")
|
|
50
|
+
return found
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def main() -> None:
|
|
54
|
+
overlay_path = os.environ.get("OMNILANE_AA_TRANSPORT_OVERLAY", "")
|
|
55
|
+
if not overlay_path:
|
|
56
|
+
emit("PASS", "no overlay configured; every runtime mapping stays unverified")
|
|
57
|
+
if not Path(overlay_path).exists():
|
|
58
|
+
emit("FAIL", f"configured overlay is missing: {overlay_path}")
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
import aa_policy
|
|
62
|
+
except ImportError as error:
|
|
63
|
+
emit("WARN", f"cannot import aa_policy: {error}")
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
registry, _ = aa_policy.load_registry(str(REPO / "config" / "aa-model-policy.json"))
|
|
67
|
+
except Exception as error: # PolicyError, OSError, and anything else fails the gate
|
|
68
|
+
detail = "; ".join(offenders(Path(overlay_path))) or str(error)
|
|
69
|
+
emit("FAIL", f"overlay rejected, every dispatch is refused: {error} ({detail})")
|
|
70
|
+
|
|
71
|
+
tiers = registry.get("_transport_evidence_tiers", {})
|
|
72
|
+
verified = Counter()
|
|
73
|
+
for row in registry["scored_configs"]:
|
|
74
|
+
if row["transport_mapping"].get("runtime_verified") is True:
|
|
75
|
+
verified[row["vendor"], tiers.get(row["id"], "selector-only")] += 1
|
|
76
|
+
summary = ", ".join(f"{vendor} {count} {tier}"
|
|
77
|
+
for (vendor, tier), count in sorted(verified.items())) or "none"
|
|
78
|
+
|
|
79
|
+
import json
|
|
80
|
+
|
|
81
|
+
overlay = json.loads(Path(overlay_path).read_text())
|
|
82
|
+
unproven = overlay.get("unproven", [])
|
|
83
|
+
extra = f"; {len(unproven)} config(s) recorded unproven" if unproven else ""
|
|
84
|
+
weak = sorted({vendor for (vendor, tier) in verified if tier == "selector-only"})
|
|
85
|
+
if weak:
|
|
86
|
+
extra += (f"; {', '.join(weak)} prove only the request selector, re-probe to "
|
|
87
|
+
"record who answered")
|
|
88
|
+
|
|
89
|
+
stale = registry.get("_stale_transport_vendors", [])
|
|
90
|
+
if stale:
|
|
91
|
+
detail = "; ".join(o for o in offenders(Path(overlay_path))) or "unknown cause"
|
|
92
|
+
emit("WARN", f"stale vendor(s) {', '.join(stale)} degraded to unverified "
|
|
93
|
+
f"({detail}); still verified: {summary}{extra}")
|
|
94
|
+
emit("PASS", f"verified mappings: {summary}{extra}")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
main()
|