omnilane 0.41.1 → 0.42.1
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 +4 -4
- package/.claude-plugin/plugin.json +2 -2
- package/CHANGELOG.md +25 -1
- package/README.ja.md +21 -2
- package/README.ko.md +21 -2
- package/README.md +83 -16
- package/README.zh-CN.md +21 -2
- package/README.zh-TW.md +63 -11
- package/VERSION +1 -1
- package/config/aa-model-policy.json +3046 -0
- package/docs/completion-wakeup.md +126 -0
- package/docs/native-executor.md +264 -0
- package/docs/release-notes-0.42.1.md +32 -0
- package/hooks/routing-instruction.md +101 -40
- package/package.json +6 -2
- package/plugin.json +2 -2
- package/scripts/completion-wakeup.py +390 -0
- package/scripts/dispatch.sh +240 -18
- package/scripts/jobs.sh +58 -15
- package/scripts/lib/aa_policy.py +473 -0
- package/scripts/lib/aa_retry.py +77 -0
- package/scripts/lib/common.sh +59 -0
- package/scripts/lib/job-worker.sh +2 -0
- package/scripts/lib/native.py +507 -0
- package/scripts/runners/run-grok.sh +4 -0
- package/scripts/runners/run-vote.sh +3 -0
- package/skills/omnilane/SKILL.md +120 -31
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Frozen exact-AA downward-delegation decision engine.
|
|
3
|
+
|
|
4
|
+
This module is intentionally provider-free. It validates one explicit caller
|
|
5
|
+
assertion against the frozen registry, resolves only runtime-verified target
|
|
6
|
+
mappings, and emits a structured allow/deny decision. The JSON context is
|
|
7
|
+
cooperative workflow metadata, not operating-system authentication.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import hashlib
|
|
14
|
+
import json
|
|
15
|
+
import os
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
import re
|
|
18
|
+
import stat
|
|
19
|
+
import tempfile
|
|
20
|
+
import socket
|
|
21
|
+
import sys
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
MAX_BYTES = 1_048_576
|
|
26
|
+
# Approval anchor for the frozen AA v4.2 2026-09-07 source bytes. Updating this
|
|
27
|
+
# constant is a governance change, never a caller argument/environment override.
|
|
28
|
+
APPROVED_REGISTRY_SHA256 = "0782c87de123c02738c3ff60e4bc3c1cc10d110113e872b8f8627212861cdaab"
|
|
29
|
+
|
|
30
|
+
IDENTITY_FIELDS = ("vendor", "model", "effort", "reasoning", "fallback")
|
|
31
|
+
IDENTIFIER = re.compile(r"[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}\Z")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class PolicyError(ValueError):
|
|
35
|
+
"""A public, non-sensitive policy validation error."""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _check(condition: bool, message: str) -> None:
|
|
39
|
+
if not condition:
|
|
40
|
+
raise PolicyError(message)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _unique_object(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
|
|
44
|
+
result: dict[str, Any] = {}
|
|
45
|
+
for key, value in pairs:
|
|
46
|
+
_check(key not in result, "duplicate JSON key")
|
|
47
|
+
result[key] = value
|
|
48
|
+
return result
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _read_bytes(path: str | Path) -> bytes:
|
|
52
|
+
fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)
|
|
53
|
+
with os.fdopen(fd, "rb") as stream:
|
|
54
|
+
info = os.fstat(stream.fileno())
|
|
55
|
+
_check(stat.S_ISREG(info.st_mode), "policy input must be a regular file")
|
|
56
|
+
_check(info.st_size <= MAX_BYTES, "policy input is too large")
|
|
57
|
+
data = stream.read(MAX_BYTES + 1)
|
|
58
|
+
_check(len(data) <= MAX_BYTES, "policy input is too large")
|
|
59
|
+
return data
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _read_json(path: str | Path) -> tuple[dict[str, Any], str]:
|
|
63
|
+
data = _read_bytes(path)
|
|
64
|
+
try:
|
|
65
|
+
value = json.loads(
|
|
66
|
+
data.decode("utf-8"),
|
|
67
|
+
object_pairs_hook=_unique_object,
|
|
68
|
+
parse_constant=lambda _: (_ for _ in ()).throw(PolicyError("invalid JSON number")),
|
|
69
|
+
)
|
|
70
|
+
except (UnicodeError, json.JSONDecodeError) as error:
|
|
71
|
+
raise PolicyError("invalid JSON input") from error
|
|
72
|
+
_check(isinstance(value, dict), "policy input must be a JSON object")
|
|
73
|
+
return value, hashlib.sha256(data).hexdigest()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _exact_fields(value: dict[str, Any], required: set[str]) -> None:
|
|
77
|
+
_check(set(value) == required, "missing or unknown caller-context fields")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _identity(value: Any, label: str) -> dict[str, Any]:
|
|
81
|
+
_check(isinstance(value, dict), f"{label} must be a JSON object")
|
|
82
|
+
_exact_fields(value, set(IDENTITY_FIELDS))
|
|
83
|
+
for key in ("vendor", "model", "reasoning"):
|
|
84
|
+
field = value[key]
|
|
85
|
+
_check(isinstance(field, str) and bool(IDENTIFIER.fullmatch(field)),
|
|
86
|
+
f"invalid {label}.{key}")
|
|
87
|
+
for key in ("effort", "fallback"):
|
|
88
|
+
field = value[key]
|
|
89
|
+
_check(field is None or (isinstance(field, str) and bool(IDENTIFIER.fullmatch(field))),
|
|
90
|
+
f"invalid {label}.{key}")
|
|
91
|
+
return {key: value[key] for key in IDENTITY_FIELDS}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _validate_registry(value: dict[str, Any]) -> dict[str, Any]:
|
|
95
|
+
required = {
|
|
96
|
+
"schema_version", "snapshot", "policy", "scored_configs",
|
|
97
|
+
"unknown_configs", "reference_configs", "aliases", "coverage",
|
|
98
|
+
}
|
|
99
|
+
_check(required <= set(value) <= required | {"schema_notes"},
|
|
100
|
+
"unsupported AA registry schema")
|
|
101
|
+
_check(type(value["schema_version"]) is int and value["schema_version"] == 1,
|
|
102
|
+
"unsupported AA registry version")
|
|
103
|
+
snapshot = value["snapshot"]
|
|
104
|
+
_check(isinstance(snapshot, dict), "invalid AA registry snapshot")
|
|
105
|
+
for key in ("id", "benchmark_version", "as_of", "frozen"):
|
|
106
|
+
_check(key in snapshot, "incomplete AA registry snapshot")
|
|
107
|
+
_check(snapshot["benchmark_version"] == "4.2"
|
|
108
|
+
and snapshot["as_of"] == "2026-09-07"
|
|
109
|
+
and snapshot["frozen"] is True,
|
|
110
|
+
"AA registry is not frozen v4.2 dated 2026-09-07")
|
|
111
|
+
policy = value["policy"]
|
|
112
|
+
_check(isinstance(policy, dict)
|
|
113
|
+
and policy.get("decision") == "target_score <= min(caller_score, inherited_ceiling)"
|
|
114
|
+
and policy.get("same_score_allowed") is True
|
|
115
|
+
and policy.get("unknown") == "deny"
|
|
116
|
+
and policy.get("transport_mapping_requires_runtime_verification") is True,
|
|
117
|
+
"AA registry policy contract mismatch")
|
|
118
|
+
rows = value["scored_configs"]
|
|
119
|
+
_check(isinstance(rows, list) and rows, "AA registry has no scored configurations")
|
|
120
|
+
seen: set[str] = set()
|
|
121
|
+
for row in rows:
|
|
122
|
+
_check(isinstance(row, dict), "invalid AA scored configuration")
|
|
123
|
+
for key in (*IDENTITY_FIELDS, "id", "score", "estimated", "benchmark_version",
|
|
124
|
+
"as_of", "transport_mapping"):
|
|
125
|
+
_check(key in row, "incomplete AA scored configuration")
|
|
126
|
+
_check(isinstance(row["id"], str) and row["id"] not in seen,
|
|
127
|
+
"duplicate AA scored configuration")
|
|
128
|
+
seen.add(row["id"])
|
|
129
|
+
_identity({key: row[key] for key in IDENTITY_FIELDS}, "registry identity")
|
|
130
|
+
_check(type(row["score"]) is int and 0 <= row["score"] <= 100,
|
|
131
|
+
"invalid AA score")
|
|
132
|
+
_check(type(row["estimated"]) is bool, "invalid AA estimated flag")
|
|
133
|
+
_check(row["benchmark_version"] == "4.2" and row["as_of"] == "2026-09-07",
|
|
134
|
+
"mixed AA registry snapshot")
|
|
135
|
+
_check(isinstance(row["transport_mapping"], dict), "invalid transport mapping")
|
|
136
|
+
return value
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def apply_transport_overlay(registry: dict[str, Any]) -> None:
|
|
140
|
+
"""Host-local request selector proof, independent of frozen AA scores."""
|
|
141
|
+
path = os.environ.get("OMNILANE_AA_TRANSPORT_OVERLAY")
|
|
142
|
+
if not path:
|
|
143
|
+
return
|
|
144
|
+
overlay, digest = _read_json(path)
|
|
145
|
+
expected = os.environ.get("OMNILANE_AA_OVERLAY_SHA256")
|
|
146
|
+
_check(not expected or expected == digest, "transport overlay changed after initial decision")
|
|
147
|
+
_check(overlay.get("schema_version") == 1, "unsupported transport overlay")
|
|
148
|
+
_check(overlay.get("snapshot_id") == registry["snapshot"]["id"], "transport overlay snapshot mismatch")
|
|
149
|
+
_check(overlay.get("host") == socket.gethostname(), "transport overlay host mismatch")
|
|
150
|
+
for evidence in overlay.get("evidence", []):
|
|
151
|
+
fd = os.open(evidence["path"], os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)
|
|
152
|
+
with os.fdopen(fd, "rb") as stream:
|
|
153
|
+
_check(stat.S_ISREG(os.fstat(stream.fileno()).st_mode), "invalid transport evidence file")
|
|
154
|
+
digest_file = hashlib.sha256()
|
|
155
|
+
for block in iter(lambda: stream.read(1024 * 1024), b""):
|
|
156
|
+
digest_file.update(block)
|
|
157
|
+
_check(digest_file.hexdigest() == evidence["sha256"], "transport contract evidence changed")
|
|
158
|
+
_check(bool(overlay.get("evidence")), "transport overlay requires local evidence")
|
|
159
|
+
for mapping in overlay.get("mappings", []):
|
|
160
|
+
rows = [row for row in registry["scored_configs"] if row["id"] == mapping.get("config_id")]
|
|
161
|
+
_check(len(rows) == 1, "unknown overlay config")
|
|
162
|
+
row = rows[0]
|
|
163
|
+
_check(mapping.get("identity") == _row_identity(row), "overlay exact identity mismatch")
|
|
164
|
+
_check(mapping.get("verification") == "request-selector-contract", "unsupported overlay verification")
|
|
165
|
+
_check(mapping.get("runtime_effort") == row["effort"], "overlay effort mismatch")
|
|
166
|
+
selector_type = mapping.get("selector_type", "model_and_effort")
|
|
167
|
+
_check(selector_type in ("model_and_effort", "model_id_encoded_effort"), "unknown selector type")
|
|
168
|
+
if selector_type == "model_id_encoded_effort":
|
|
169
|
+
_check(row["vendor"] == "gemini", "unsupported encoded-effort vendor")
|
|
170
|
+
_check(mapping.get("runtime_model") in row["transport_mapping"].get("candidate_model_ids", []), "unproven encoded model selector")
|
|
171
|
+
_check(mapping["runtime_model"].endswith("-" + row["effort"]), "encoded effort does not match exact tuple")
|
|
172
|
+
else:
|
|
173
|
+
_check(mapping.get("runtime_model") == row["model"], "overlay model mismatch")
|
|
174
|
+
row["transport_mapping"].update(
|
|
175
|
+
status="verified", runtime_verified=True,
|
|
176
|
+
runtime_model=mapping["runtime_model"], runtime_effort=mapping["runtime_effort"],
|
|
177
|
+
selector_type=selector_type,
|
|
178
|
+
verification="request-selector-contract", upstream_identity_verified=False,
|
|
179
|
+
overlay_sha256=digest, overlay_host=overlay["host"],
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def load_registry(path: str | Path, expected_sha256: str | None = None) -> tuple[dict[str, Any], str]:
|
|
184
|
+
value, digest = _read_json(path)
|
|
185
|
+
_check(digest == APPROVED_REGISTRY_SHA256, "unapproved AA registry; use the approved frozen snapshot byte-for-byte")
|
|
186
|
+
if expected_sha256:
|
|
187
|
+
_check(digest == expected_sha256, "AA registry changed after initial decision")
|
|
188
|
+
registry = _validate_registry(value)
|
|
189
|
+
apply_transport_overlay(registry)
|
|
190
|
+
return registry, digest
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def load_caller(path: str | Path, registry: dict[str, Any],
|
|
194
|
+
expected_sha256: str | None = None) -> tuple[dict[str, Any], str]:
|
|
195
|
+
value, digest = _read_json(path)
|
|
196
|
+
if expected_sha256:
|
|
197
|
+
_check(digest == expected_sha256, "caller context changed after initial decision")
|
|
198
|
+
_check(type(value.get("schema_version")) is int and value["schema_version"] == 1,
|
|
199
|
+
"unsupported caller-context version")
|
|
200
|
+
_check(value.get("snapshot_id") == registry["snapshot"]["id"],
|
|
201
|
+
"caller-context snapshot does not match frozen registry")
|
|
202
|
+
_check(value.get("kind") == "model", "unsupported caller-context kind")
|
|
203
|
+
_exact_fields(value, {"schema_version", "snapshot_id", "kind", "caller", "inherited_ceiling"})
|
|
204
|
+
value["caller"] = _identity(value["caller"], "caller")
|
|
205
|
+
ceiling = value["inherited_ceiling"]
|
|
206
|
+
_check(type(ceiling) is int and 0 <= ceiling <= 100,
|
|
207
|
+
"invalid inherited caller ceiling")
|
|
208
|
+
return value, digest
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _row_identity(row: dict[str, Any]) -> dict[str, Any]:
|
|
212
|
+
return {key: row[key] for key in IDENTITY_FIELDS}
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _matching_rows(registry: dict[str, Any], identity: dict[str, Any]) -> list[dict[str, Any]]:
|
|
216
|
+
return [row for row in registry["scored_configs"] if _row_identity(row) == identity]
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _unknown_reason(registry: dict[str, Any], identity: dict[str, Any]) -> str | None:
|
|
220
|
+
for row in registry["unknown_configs"]:
|
|
221
|
+
if all(row.get(key) == identity[key] for key in IDENTITY_FIELDS):
|
|
222
|
+
return row.get("reason")
|
|
223
|
+
return None
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _runtime_target(registry: dict[str, Any], vendor: str, model: str,
|
|
227
|
+
effort: str | None, target_config: str | None) -> tuple[dict[str, Any] | None, str, dict[str, Any]]:
|
|
228
|
+
exact_id = [row for row in registry["scored_configs"] if row["id"] == target_config] if target_config else registry["scored_configs"]
|
|
229
|
+
if target_config and not exact_id:
|
|
230
|
+
return None, "unknown-target-config", {"target_config": target_config}
|
|
231
|
+
vendor_rows = [row for row in exact_id if row["vendor"] == vendor]
|
|
232
|
+
candidates: list[dict[str, Any]] = []
|
|
233
|
+
unresolved: list[str] = []
|
|
234
|
+
for row in vendor_rows:
|
|
235
|
+
mapping = row["transport_mapping"]
|
|
236
|
+
model_ids = mapping.get("candidate_model_ids", [])
|
|
237
|
+
runtime_model = mapping.get("runtime_model")
|
|
238
|
+
runtime_effort = mapping.get("runtime_effort", row["effort"])
|
|
239
|
+
model_match = model == runtime_model if runtime_model is not None else model in model_ids
|
|
240
|
+
encoded_effort = mapping.get("selector_type") == "model_id_encoded_effort"
|
|
241
|
+
if not model_match:
|
|
242
|
+
continue
|
|
243
|
+
if encoded_effort and effort not in (None, runtime_effort):
|
|
244
|
+
return None, "encoded-effort-conflict", {"model": model, "effort": effort, "encoded_effort": runtime_effort}
|
|
245
|
+
if not encoded_effort and effort != runtime_effort:
|
|
246
|
+
continue
|
|
247
|
+
if mapping.get("runtime_verified") is True and mapping.get("status") in ("verified", "resolved"):
|
|
248
|
+
candidates.append(row)
|
|
249
|
+
else:
|
|
250
|
+
unresolved.append(row["id"])
|
|
251
|
+
if vendor == "grok" and candidates:
|
|
252
|
+
# The checked-in Grok runner accepts EFFORT for interface parity but
|
|
253
|
+
# discards it. A scored reasoning/effort row therefore cannot be
|
|
254
|
+
# proven by that runtime surface.
|
|
255
|
+
return None, "runtime-effort-discarded", {"vendor": vendor, "model": model, "effort": effort}
|
|
256
|
+
if len(candidates) == 1:
|
|
257
|
+
return candidates[0], "runtime-mapping-verified", {}
|
|
258
|
+
if len(candidates) > 1:
|
|
259
|
+
return None, "ambiguous-runtime-mapping", {"candidate_config_ids": [row["id"] for row in candidates]}
|
|
260
|
+
if unresolved:
|
|
261
|
+
return None, "runtime-mapping-unverified", {"candidate_config_ids": unresolved}
|
|
262
|
+
return None, "unknown-target-runtime", {"vendor": vendor, "model": model, "effort": effort}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def decide(registry: dict[str, Any], registry_sha256: str, *,
|
|
266
|
+
vendor: str, model: str, effort: str | None,
|
|
267
|
+
caller: dict[str, Any] | None, caller_sha256: str | None,
|
|
268
|
+
operator_asserted_human: bool = False,
|
|
269
|
+
target_config: str | None = None) -> dict[str, Any]:
|
|
270
|
+
base: dict[str, Any] = {
|
|
271
|
+
"schema_version": 1,
|
|
272
|
+
"snapshot_id": registry["snapshot"]["id"],
|
|
273
|
+
"registry_sha256": registry_sha256,
|
|
274
|
+
"allowed": False,
|
|
275
|
+
"code": "deny",
|
|
276
|
+
"message": "AA policy denied dispatch",
|
|
277
|
+
"caller_kind": "operator-asserted-human" if operator_asserted_human else "model",
|
|
278
|
+
"target_request": {"vendor": vendor, "model": model, "effort": effort},
|
|
279
|
+
"target_config_id": target_config,
|
|
280
|
+
"caller_score": None,
|
|
281
|
+
"inherited_ceiling": None,
|
|
282
|
+
"effective_ceiling": None,
|
|
283
|
+
"target_score": None,
|
|
284
|
+
"target_estimated": None,
|
|
285
|
+
"child_context": None,
|
|
286
|
+
"evidence_limit": "workflow metadata and selected model arguments do not prove actual provider identity",
|
|
287
|
+
}
|
|
288
|
+
if operator_asserted_human:
|
|
289
|
+
base.update(
|
|
290
|
+
allowed=True,
|
|
291
|
+
code="operator-asserted-human-exemption",
|
|
292
|
+
message="explicit operator assertion bypassed model-level AA ceiling",
|
|
293
|
+
evidence_limit="operator assertion is cooperative metadata, not authentication or provider-identity proof",
|
|
294
|
+
)
|
|
295
|
+
return base
|
|
296
|
+
if caller is None:
|
|
297
|
+
base.update(
|
|
298
|
+
code="missing-caller-context",
|
|
299
|
+
message="provide --caller-context FILE or explicitly assert --operator-asserted-human",
|
|
300
|
+
)
|
|
301
|
+
return base
|
|
302
|
+
base["caller_context_sha256"] = caller_sha256
|
|
303
|
+
caller_identity = caller["caller"]
|
|
304
|
+
caller_rows = _matching_rows(registry, caller_identity)
|
|
305
|
+
if len(caller_rows) != 1:
|
|
306
|
+
detail = _unknown_reason(registry, caller_identity)
|
|
307
|
+
base.update(
|
|
308
|
+
code="unknown-caller-config" if not caller_rows else "ambiguous-caller-config",
|
|
309
|
+
message=detail or "caller exact vendor/model/effort/reasoning/fallback is not uniquely scored",
|
|
310
|
+
caller=caller_identity,
|
|
311
|
+
)
|
|
312
|
+
return base
|
|
313
|
+
caller_row = caller_rows[0]
|
|
314
|
+
effective = min(caller_row["score"], caller["inherited_ceiling"])
|
|
315
|
+
base.update(
|
|
316
|
+
caller=caller_identity,
|
|
317
|
+
caller_score=caller_row["score"],
|
|
318
|
+
inherited_ceiling=caller["inherited_ceiling"],
|
|
319
|
+
effective_ceiling=effective,
|
|
320
|
+
)
|
|
321
|
+
target_row, mapping_code, detail = _runtime_target(
|
|
322
|
+
registry, vendor, model, effort, target_config
|
|
323
|
+
)
|
|
324
|
+
if target_row is None:
|
|
325
|
+
base.update(code=mapping_code, message="target runtime cannot be mapped to one verified exact AA configuration", **detail)
|
|
326
|
+
return base
|
|
327
|
+
target_score = target_row["score"]
|
|
328
|
+
target_identity = _row_identity(target_row)
|
|
329
|
+
base.update(
|
|
330
|
+
target_config_id=target_row["id"],
|
|
331
|
+
target=target_identity,
|
|
332
|
+
target_score=target_score,
|
|
333
|
+
target_estimated=target_row["estimated"],
|
|
334
|
+
)
|
|
335
|
+
if target_score > effective:
|
|
336
|
+
base.update(
|
|
337
|
+
code="target-above-effective-ceiling",
|
|
338
|
+
message=f"target score {target_score} exceeds effective caller ceiling {effective}",
|
|
339
|
+
)
|
|
340
|
+
return base
|
|
341
|
+
child_context = {
|
|
342
|
+
"schema_version": 1,
|
|
343
|
+
"snapshot_id": registry["snapshot"]["id"],
|
|
344
|
+
"kind": "model",
|
|
345
|
+
"caller": target_identity,
|
|
346
|
+
"inherited_ceiling": effective,
|
|
347
|
+
}
|
|
348
|
+
base.update(
|
|
349
|
+
allowed=True,
|
|
350
|
+
code="same-score-allowed" if target_score == effective else "downward-allowed",
|
|
351
|
+
message="target exact AA score is at or below effective caller ceiling",
|
|
352
|
+
child_context=child_context,
|
|
353
|
+
)
|
|
354
|
+
return base
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def _normalized_effort(value: str) -> str | None:
|
|
358
|
+
return None if value in ("", "-") else value
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def _json_line(value: dict[str, Any]) -> str:
|
|
362
|
+
return json.dumps(value, ensure_ascii=False, separators=(",", ":")) + "\n"
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def atomic_bytes(path: Path, content: bytes) -> None:
|
|
366
|
+
"""Publish private metadata without exposing a partial file."""
|
|
367
|
+
fd, name = tempfile.mkstemp(prefix=".aa-", dir=path.parent)
|
|
368
|
+
try:
|
|
369
|
+
with os.fdopen(fd, "wb") as stream:
|
|
370
|
+
stream.write(content)
|
|
371
|
+
stream.flush()
|
|
372
|
+
os.fsync(stream.fileno())
|
|
373
|
+
os.replace(name, path)
|
|
374
|
+
finally:
|
|
375
|
+
if os.path.exists(name):
|
|
376
|
+
os.unlink(name)
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def atomic_json(path: Path, value: dict[str, Any]) -> None:
|
|
380
|
+
atomic_bytes(path, _json_line(value).encode("utf-8"))
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def publish_context(directory: str | Path, registry: dict[str, Any],
|
|
384
|
+
caller: dict[str, Any] | None, decision: dict[str, Any],
|
|
385
|
+
registry_source: str | Path | None = None) -> dict[str, Any]:
|
|
386
|
+
"""Keep immutable-by-convention authorizer and a distinct narrowed child identity.
|
|
387
|
+
|
|
388
|
+
This is lineage metadata, not authentication. The frozen registry content is
|
|
389
|
+
copied so later retries cannot silently select a different score snapshot.
|
|
390
|
+
"""
|
|
391
|
+
root = Path(directory)
|
|
392
|
+
_check(root.is_dir() and not root.is_symlink(), "invalid context publication directory")
|
|
393
|
+
_check(decision.get("allowed") is True, "cannot publish a denied decision")
|
|
394
|
+
source = Path(registry_source) if registry_source else Path(__file__).resolve().parents[2] / "config/aa-model-policy.json"
|
|
395
|
+
source_bytes = _read_bytes(source)
|
|
396
|
+
_check(hashlib.sha256(source_bytes).hexdigest() == APPROVED_REGISTRY_SHA256, "unapproved AA registry snapshot publication")
|
|
397
|
+
atomic_bytes(root / "aa-registry.json", source_bytes)
|
|
398
|
+
registry_sha = hashlib.sha256((root / "aa-registry.json").read_bytes()).hexdigest()
|
|
399
|
+
if caller is not None:
|
|
400
|
+
atomic_json(root / "aa-authorizer.json", caller)
|
|
401
|
+
child = decision.get("child_context")
|
|
402
|
+
if child is not None:
|
|
403
|
+
atomic_json(root / "aa-child-context.json", child)
|
|
404
|
+
lineage = {
|
|
405
|
+
"schema_version": 1,
|
|
406
|
+
"registry_sha256": registry_sha,
|
|
407
|
+
"authorizer_sha256": hashlib.sha256((root / "aa-authorizer.json").read_bytes()).hexdigest() if caller else None,
|
|
408
|
+
"operator_asserted_human": decision["caller_kind"] == "operator-asserted-human",
|
|
409
|
+
"target_config_id": decision["target_config_id"],
|
|
410
|
+
"target_request": decision["target_request"],
|
|
411
|
+
"effective_ceiling": decision["effective_ceiling"],
|
|
412
|
+
"child_context": child,
|
|
413
|
+
}
|
|
414
|
+
overlay_path = os.environ.get("OMNILANE_AA_TRANSPORT_OVERLAY")
|
|
415
|
+
if overlay_path:
|
|
416
|
+
overlay, _ = _read_json(overlay_path)
|
|
417
|
+
atomic_json(root / "aa-transport-overlay.json", overlay)
|
|
418
|
+
lineage["transport_overlay_sha256"] = hashlib.sha256((root / "aa-transport-overlay.json").read_bytes()).hexdigest()
|
|
419
|
+
atomic_json(root / "aa-lineage.json", lineage)
|
|
420
|
+
atomic_json(root / "aa-decision.json", decision)
|
|
421
|
+
return lineage
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def main(argv: list[str] | None = None) -> int:
|
|
425
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
426
|
+
parser.add_argument("--registry", required=True)
|
|
427
|
+
parser.add_argument("--expected-registry-sha256")
|
|
428
|
+
source = parser.add_mutually_exclusive_group()
|
|
429
|
+
source.add_argument("--caller-context")
|
|
430
|
+
source.add_argument("--operator-asserted-human", action="store_true")
|
|
431
|
+
parser.add_argument("--expected-caller-sha256")
|
|
432
|
+
parser.add_argument("--vendor", required=True)
|
|
433
|
+
parser.add_argument("--model", required=True)
|
|
434
|
+
parser.add_argument("--effort", required=True)
|
|
435
|
+
parser.add_argument("--target-config")
|
|
436
|
+
parser.add_argument("--publish-dir")
|
|
437
|
+
args = parser.parse_args(argv)
|
|
438
|
+
try:
|
|
439
|
+
registry, registry_sha = load_registry(args.registry, args.expected_registry_sha256)
|
|
440
|
+
caller = None
|
|
441
|
+
caller_sha = None
|
|
442
|
+
if args.caller_context:
|
|
443
|
+
caller, caller_sha = load_caller(
|
|
444
|
+
args.caller_context, registry, args.expected_caller_sha256
|
|
445
|
+
)
|
|
446
|
+
result = decide(
|
|
447
|
+
registry,
|
|
448
|
+
registry_sha,
|
|
449
|
+
vendor=args.vendor,
|
|
450
|
+
model=args.model,
|
|
451
|
+
effort=_normalized_effort(args.effort),
|
|
452
|
+
caller=caller,
|
|
453
|
+
caller_sha256=caller_sha,
|
|
454
|
+
operator_asserted_human=args.operator_asserted_human,
|
|
455
|
+
target_config=args.target_config,
|
|
456
|
+
)
|
|
457
|
+
if args.publish_dir and result["allowed"]:
|
|
458
|
+
publish_context(args.publish_dir, registry, caller, result, args.registry)
|
|
459
|
+
print(_json_line(result), end="")
|
|
460
|
+
return 0 if result["allowed"] else 3
|
|
461
|
+
except (PolicyError, OSError, RecursionError, TypeError, KeyError) as error:
|
|
462
|
+
message = str(error) if isinstance(error, PolicyError) else "invalid or inaccessible AA policy input"
|
|
463
|
+
print(_json_line({
|
|
464
|
+
"schema_version": 1,
|
|
465
|
+
"allowed": False,
|
|
466
|
+
"code": "invalid-policy-input",
|
|
467
|
+
"message": message,
|
|
468
|
+
}), end="")
|
|
469
|
+
return 2
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
if __name__ == "__main__":
|
|
473
|
+
sys.exit(main())
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Reconstruct only a validated job-owned authorizer; never borrow retry shell identity."""
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import sys
|
|
7
|
+
import aa_policy
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def retry_args(directory):
|
|
11
|
+
root = Path(directory)
|
|
12
|
+
os.environ.pop("OMNILANE_AA_TRANSPORT_OVERLAY", None)
|
|
13
|
+
os.environ.pop("OMNILANE_AA_OVERLAY_SHA256", None)
|
|
14
|
+
lineage, _ = aa_policy._read_json(root / "aa-lineage.json")
|
|
15
|
+
aa_policy._check(lineage.get("schema_version") == 1, "unsupported retry lineage")
|
|
16
|
+
registry_path = root / "aa-registry.json"
|
|
17
|
+
registry, _ = aa_policy.load_registry(registry_path, lineage["registry_sha256"])
|
|
18
|
+
result = ["--aa-policy", str(registry_path)]
|
|
19
|
+
original = None
|
|
20
|
+
original_limit = 100
|
|
21
|
+
if lineage.get("operator_asserted_human") is not True:
|
|
22
|
+
context = root / "aa-authorizer.json"
|
|
23
|
+
aa_policy._check(isinstance(lineage.get("authorizer_sha256"), str), "missing retry authorizer hash")
|
|
24
|
+
original, _ = aa_policy.load_caller(context, registry, lineage["authorizer_sha256"])
|
|
25
|
+
rows = aa_policy._matching_rows(registry, original["caller"])
|
|
26
|
+
aa_policy._check(len(rows) == 1, "unknown original retry authorizer")
|
|
27
|
+
original_limit = min(rows[0]["score"], original["inherited_ceiling"])
|
|
28
|
+
current_path = os.environ.get("OMNILANE_AA_CALLER_CONTEXT")
|
|
29
|
+
current_human = os.environ.get("OMNILANE_AA_OPERATOR_ASSERTED_HUMAN") == "1"
|
|
30
|
+
aa_policy._check(bool(current_path) != current_human, "retry requires one current caller context or explicit current human assertion")
|
|
31
|
+
if current_path:
|
|
32
|
+
current, _ = aa_policy.load_caller(current_path, registry)
|
|
33
|
+
rows = aa_policy._matching_rows(registry, current["caller"])
|
|
34
|
+
aa_policy._check(len(rows) == 1, "unknown current retry caller")
|
|
35
|
+
narrowed = dict(current)
|
|
36
|
+
narrowed["inherited_ceiling"] = min(original_limit, current["inherited_ceiling"], rows[0]["score"])
|
|
37
|
+
digest = aa_policy.hashlib.sha256(aa_policy._json_line(narrowed).encode()).hexdigest()
|
|
38
|
+
context = root / ("aa-retry-authorizer-" + digest + ".json")
|
|
39
|
+
aa_policy.atomic_json(context, narrowed)
|
|
40
|
+
result += ["--caller-context", str(context)]
|
|
41
|
+
elif original is not None:
|
|
42
|
+
result += ["--caller-context", str(root / "aa-authorizer.json")]
|
|
43
|
+
else:
|
|
44
|
+
result += ["--operator-asserted-human"]
|
|
45
|
+
if lineage.get("transport_overlay_sha256"):
|
|
46
|
+
overlay = root / "aa-transport-overlay.json"
|
|
47
|
+
_, digest = aa_policy._read_json(overlay)
|
|
48
|
+
aa_policy._check(digest == lineage["transport_overlay_sha256"], "retry transport overlay changed")
|
|
49
|
+
result += ["--transport-overlay", str(overlay)]
|
|
50
|
+
config = lineage.get("target_config_id")
|
|
51
|
+
if config:
|
|
52
|
+
aa_policy._check(isinstance(config, str) and aa_policy.IDENTIFIER.fullmatch(config), "invalid retry target config")
|
|
53
|
+
result += ["--target-config", config]
|
|
54
|
+
return result
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def metadata_fields(directory):
|
|
58
|
+
value, _ = aa_policy._read_json(Path(directory) / "meta.json")
|
|
59
|
+
keys = ("lane", "vendor", "model", "effort", "timeout", "job_timeout", "mode", "workdir")
|
|
60
|
+
aa_policy._check(value.get("mode") in ("advise", "work"), "invalid retry mode")
|
|
61
|
+
aa_policy._check(type(value.get("timeout")) is int and value["timeout"] > 0, "invalid retry timeout")
|
|
62
|
+
aa_policy._check(value.get("job_timeout") is None or (type(value["job_timeout"]) is int and value["job_timeout"] > 0), "invalid retry job timeout")
|
|
63
|
+
result = []
|
|
64
|
+
for key in keys:
|
|
65
|
+
field = value[key]
|
|
66
|
+
text = "null" if field is None else str(field)
|
|
67
|
+
aa_policy._check("\n" not in text and "\r" not in text and "\x00" not in text, "invalid retry metadata value")
|
|
68
|
+
result.append(text)
|
|
69
|
+
return result
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
if __name__ == "__main__":
|
|
73
|
+
try:
|
|
74
|
+
print("\n".join(metadata_fields(sys.argv[2]) if sys.argv[1] == "--metadata" else retry_args(sys.argv[1])))
|
|
75
|
+
except (aa_policy.PolicyError, OSError, KeyError, TypeError):
|
|
76
|
+
print("omnilane: retry requires intact AA lineage; current caller is missing or original authorizer/registry is changed", file=sys.stderr)
|
|
77
|
+
sys.exit(3)
|
package/scripts/lib/common.sh
CHANGED
|
@@ -82,6 +82,65 @@ file_sha256() {
|
|
|
82
82
|
fi
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
# Re-run the same provider-free AA decision immediately before a runner or one
|
|
86
|
+
# of its internal constituents/retries. Inputs are cooperative workflow
|
|
87
|
+
# metadata; hashes detect mutation after dispatch but do not authenticate the
|
|
88
|
+
# operator or prove the provider's actual model identity.
|
|
89
|
+
aa_policy_gate() {
|
|
90
|
+
local vendor="$1" model="$2" effort="$3" target_config="${4:-${OMNILANE_AA_TARGET_CONFIG:-}}"
|
|
91
|
+
local policy_file="${OMNILANE_AA_POLICY_FILE:-$OMNILANE_REPO/config/aa-model-policy.json}" output rc=0
|
|
92
|
+
local authorizer="${OMNILANE_AA_AUTHORIZER_CONTEXT-${OMNILANE_AA_CALLER_CONTEXT:-}}"
|
|
93
|
+
local authorizer_sha="${OMNILANE_AA_AUTHORIZER_SHA256-${OMNILANE_AA_CALLER_SHA256:-}}"
|
|
94
|
+
local args=()
|
|
95
|
+
if [[ "$vendor" == "vote" && "${OMNILANE_AA_VOTE_PREFLIGHT:-0}" == "1" ]]; then
|
|
96
|
+
return 0
|
|
97
|
+
fi
|
|
98
|
+
[[ -n "$policy_file" ]] || {
|
|
99
|
+
echo 'omnilane: AA policy metadata missing before provider invocation' >&2
|
|
100
|
+
return 3
|
|
101
|
+
}
|
|
102
|
+
args=(--registry "$policy_file" --vendor "$vendor" --model "$model" --effort "$effort")
|
|
103
|
+
[[ -z "${OMNILANE_AA_REGISTRY_SHA256:-}" ]] ||
|
|
104
|
+
args+=(--expected-registry-sha256 "$OMNILANE_AA_REGISTRY_SHA256")
|
|
105
|
+
[[ -z "$target_config" ]] || args+=(--target-config "$target_config")
|
|
106
|
+
if [[ "${OMNILANE_AA_AUTHORIZER_HUMAN-${OMNILANE_AA_OPERATOR_ASSERTED_HUMAN:-0}}" == "1" ]]; then
|
|
107
|
+
args+=(--operator-asserted-human)
|
|
108
|
+
elif [[ -n "$authorizer" ]]; then
|
|
109
|
+
args+=(--caller-context "$authorizer")
|
|
110
|
+
[[ -z "$authorizer_sha" ]] ||
|
|
111
|
+
args+=(--expected-caller-sha256 "$authorizer_sha")
|
|
112
|
+
fi
|
|
113
|
+
output="$(python3 "$OMNILANE_REPO/scripts/lib/aa_policy.py" "${args[@]}")" || rc=$?
|
|
114
|
+
if [[ "$rc" -ne 0 ]]; then
|
|
115
|
+
printf '%s\n' "$output" >&2
|
|
116
|
+
return "$rc"
|
|
117
|
+
fi
|
|
118
|
+
if [[ -n "${OMNILANE_AA_CONTEXT_DIR:-}" ]]; then
|
|
119
|
+
local child_path
|
|
120
|
+
child_path="$(python3 - "$OMNILANE_REPO" "$OMNILANE_AA_CONTEXT_DIR" "$output" <<'AA_CHILD'
|
|
121
|
+
import hashlib, json, sys
|
|
122
|
+
from pathlib import Path
|
|
123
|
+
sys.path.insert(0, str(Path(sys.argv[1]) / "scripts/lib"))
|
|
124
|
+
import aa_policy
|
|
125
|
+
decision = json.loads(sys.argv[3])
|
|
126
|
+
child = decision.get("child_context")
|
|
127
|
+
if child is not None:
|
|
128
|
+
name = "aa-child-" + hashlib.sha256(aa_policy._json_line(child).encode()).hexdigest() + ".json"
|
|
129
|
+
path = Path(sys.argv[2]) / name
|
|
130
|
+
aa_policy.atomic_json(path, child)
|
|
131
|
+
print(path)
|
|
132
|
+
AA_CHILD
|
|
133
|
+
)" || return $?
|
|
134
|
+
export OMNILANE_AA_CALLER_CONTEXT="$child_path"
|
|
135
|
+
export OMNILANE_AA_CALLER_SHA256=""
|
|
136
|
+
if [[ -n "$child_path" ]]; then
|
|
137
|
+
OMNILANE_AA_CALLER_SHA256="$(file_sha256 "$child_path")"
|
|
138
|
+
export OMNILANE_AA_CALLER_SHA256
|
|
139
|
+
fi
|
|
140
|
+
fi
|
|
141
|
+
return 0
|
|
142
|
+
}
|
|
143
|
+
|
|
85
144
|
resolve_timeout_cmd() {
|
|
86
145
|
if command -v timeout &>/dev/null; then echo "timeout";
|
|
87
146
|
elif command -v gtimeout &>/dev/null; then echo "gtimeout";
|
|
@@ -43,6 +43,7 @@ emit_mode_notice() {
|
|
|
43
43
|
|
|
44
44
|
run_single_shot() {
|
|
45
45
|
local notice="$1" rc
|
|
46
|
+
aa_policy_gate "$VENDOR" "$MODEL" "$EFFORT" || return $?
|
|
46
47
|
set +e
|
|
47
48
|
(
|
|
48
49
|
unset OMNILANE_INBOX
|
|
@@ -310,6 +311,7 @@ fi
|
|
|
310
311
|
|
|
311
312
|
write_current_pid_file "$HOLDER_PID_FILE"
|
|
312
313
|
export OMNILANE_INBOX="$RUNNER_INBOX_FIFO"
|
|
314
|
+
aa_policy_gate "$VENDOR" "$MODEL" "$EFFORT" || exit $?
|
|
313
315
|
"$RUNNER" "$MODE" "$WORKDIR" "$MODEL" "$EFFORT" "$PROMPT_FILE" "$OUTPUT_FILE" 6<&- 7>&- &
|
|
314
316
|
runner_pid=$!
|
|
315
317
|
|