omnilane 0.42.8 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +189 -1
- package/README.ja.md +180 -20
- package/README.ko.md +179 -20
- package/README.md +282 -61
- package/README.zh-CN.md +178 -19
- package/README.zh-TW.md +168 -41
- package/VERSION +1 -1
- package/bin/omnilane +29 -0
- package/completions/_omnilane +1 -1
- package/completions/omnilane.bash +1 -1
- package/completions/omnilane.fish +2 -0
- package/docs/native-executor.md +59 -0
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/scripts/dispatch.sh +54 -4
- package/scripts/doctor.sh +7 -1
- package/scripts/lib/aa_lanes.py +135 -0
- package/scripts/lib/aa_policy.py +154 -1
- package/scripts/lib/build_overlay.py +45 -18
- package/scripts/lib/caller_identity.py +78 -14
- package/scripts/lib/cli_provenance.py +82 -0
- package/scripts/lib/native.py +107 -2
- package/scripts/lib/native_context.py +145 -0
- package/scripts/lib/overlay_health.py +24 -2
- package/scripts/lib/probe.py +2 -0
- package/scripts/lib/probe_sweep.py +176 -0
- package/scripts/lib/resign.py +475 -0
- package/scripts/release-audit.sh +31 -0
- package/skills/omnilane/SKILL.md +375 -464
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Add eligible_lanes to a refused AA decision.
|
|
3
|
+
|
|
4
|
+
A refusal that only says no leaves a model caller guessing. This reads the
|
|
5
|
+
decision on stdin and appends the lanes whose chain still holds a target at or
|
|
6
|
+
below the caller's effective ceiling, by registry score alone: no CLI is probed
|
|
7
|
+
and nothing is dispatched. Output is one JSON line, the decision plus the list.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import json
|
|
13
|
+
import shlex
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
18
|
+
import aa_policy # noqa: E402
|
|
19
|
+
import caller_identity # noqa: E402
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def lanes(paths: list[Path]) -> dict[str, list[list[str]]]:
|
|
23
|
+
"""Lane -> chain segments; the first file naming a lane wins, as in dispatch."""
|
|
24
|
+
table: dict[str, list[list[str]]] = {}
|
|
25
|
+
for path in paths:
|
|
26
|
+
try:
|
|
27
|
+
text = path.read_text(encoding="utf-8")
|
|
28
|
+
except OSError:
|
|
29
|
+
continue
|
|
30
|
+
for line in text.splitlines():
|
|
31
|
+
line = line.split("#", 1)[0]
|
|
32
|
+
if not line.strip() or line[0] in " \t" or ":" not in line:
|
|
33
|
+
continue
|
|
34
|
+
name, chain = line.split(":", 1)
|
|
35
|
+
name = name.strip()
|
|
36
|
+
if not name or name in table or not chain.strip():
|
|
37
|
+
continue
|
|
38
|
+
segments = []
|
|
39
|
+
for segment in chain.split("|"):
|
|
40
|
+
try:
|
|
41
|
+
fields = shlex.split(segment)
|
|
42
|
+
except ValueError:
|
|
43
|
+
fields = []
|
|
44
|
+
if fields:
|
|
45
|
+
segments.append(fields)
|
|
46
|
+
table[name] = segments
|
|
47
|
+
return table
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def eligible(registry: dict, table: dict[str, list[list[str]]], ceiling: int) -> list[dict]:
|
|
51
|
+
found = []
|
|
52
|
+
for lane, segments in table.items():
|
|
53
|
+
for fields in segments:
|
|
54
|
+
vendor = fields[0]
|
|
55
|
+
if vendor in ("off", "vote") or len(fields) < 2:
|
|
56
|
+
continue
|
|
57
|
+
effort = fields[2] if len(fields) > 2 and fields[2] != "-" else None
|
|
58
|
+
row, _ = caller_identity.resolve(registry, vendor, fields[1], effort)
|
|
59
|
+
if row is None or row["score"] > ceiling:
|
|
60
|
+
continue
|
|
61
|
+
found.append({
|
|
62
|
+
"lane": lane,
|
|
63
|
+
"target": row["id"],
|
|
64
|
+
"score": row["score"],
|
|
65
|
+
"transport_verified": row["transport_mapping"].get("runtime_verified") is True,
|
|
66
|
+
})
|
|
67
|
+
break
|
|
68
|
+
return found
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def lane_requirement(registry: dict, segments: list[list[str]], caller: dict | None) -> dict | None:
|
|
72
|
+
"""The cheapest target in one lane, and the caller effort that would reach it."""
|
|
73
|
+
rows = []
|
|
74
|
+
for fields in segments:
|
|
75
|
+
if fields[0] in ("off", "vote") or len(fields) < 2:
|
|
76
|
+
continue
|
|
77
|
+
effort = fields[2] if len(fields) > 2 and fields[2] != "-" else None
|
|
78
|
+
row, _ = caller_identity.resolve(registry, fields[0], fields[1], effort)
|
|
79
|
+
if row is not None:
|
|
80
|
+
rows.append(row)
|
|
81
|
+
if not rows:
|
|
82
|
+
return None
|
|
83
|
+
cheapest = min(rows, key=lambda row: (row["score"], row["id"]))
|
|
84
|
+
required = None
|
|
85
|
+
if isinstance(caller, dict):
|
|
86
|
+
reaching = sorted((row for row in registry["scored_configs"]
|
|
87
|
+
if row["vendor"] == caller.get("vendor") and row["model"] == caller.get("model")
|
|
88
|
+
and row["score"] >= cheapest["score"]),
|
|
89
|
+
key=lambda row: (row["score"], row["id"]))
|
|
90
|
+
if reaching:
|
|
91
|
+
required = reaching[0]["effort"] or "none"
|
|
92
|
+
return {"target": cheapest["id"], "score": cheapest["score"], "required_caller_effort": required}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def main(argv: list[str] | None = None) -> int:
|
|
96
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
97
|
+
parser.add_argument("--registry", required=True)
|
|
98
|
+
parser.add_argument("--routing", action="append", default=[], type=Path,
|
|
99
|
+
help="routing file, highest precedence first; may repeat")
|
|
100
|
+
parser.add_argument("--lane", help="the lane that was refused")
|
|
101
|
+
args = parser.parse_args(argv)
|
|
102
|
+
raw = sys.stdin.read()
|
|
103
|
+
try:
|
|
104
|
+
decision = json.loads(raw)
|
|
105
|
+
ceiling = decision.get("effective_ceiling")
|
|
106
|
+
if decision.get("allowed") is False and type(ceiling) is int:
|
|
107
|
+
registry, _ = aa_policy.load_registry(args.registry)
|
|
108
|
+
table = lanes(args.routing)
|
|
109
|
+
decision["eligible_lanes"] = eligible(registry, table, ceiling)
|
|
110
|
+
if args.lane in table and decision.get("code") == "target-above-effective-ceiling":
|
|
111
|
+
# The decision describes the last candidate tried; the lane may hold a cheaper one.
|
|
112
|
+
need = lane_requirement(registry, table[args.lane], decision.get("caller"))
|
|
113
|
+
if need is not None:
|
|
114
|
+
decision["lane_requirement"] = dict(need, lane=args.lane)
|
|
115
|
+
if decision.get("inherited_ceiling") == decision.get("caller_score"):
|
|
116
|
+
decision["required_caller_effort"] = need["required_caller_effort"]
|
|
117
|
+
effort = need["required_caller_effort"]
|
|
118
|
+
held = (" The harness recorded no effort, so this caller is held to its "
|
|
119
|
+
"model's floor." if decision.get("caller_degraded") else "")
|
|
120
|
+
decision["reason"] = (
|
|
121
|
+
f"lane {args.lane}'s cheapest target {need['target']} scores "
|
|
122
|
+
f"{need['score']}, above this caller's ceiling of {ceiling}.{held} "
|
|
123
|
+
+ (f"Relaunch the calling session at effort {effort} or higher, or have "
|
|
124
|
+
"a human operator dispatch it." if effort else
|
|
125
|
+
"No effort of the caller's model reaches it; a stronger caller model "
|
|
126
|
+
"or a human operator has to dispatch it."))
|
|
127
|
+
sys.stdout.write(json.dumps(decision, ensure_ascii=False, separators=(",", ":")) + "\n")
|
|
128
|
+
except (ValueError, OSError, aa_policy.PolicyError, KeyError, TypeError):
|
|
129
|
+
# Guidance is best effort; the refusal itself must always get through.
|
|
130
|
+
sys.stdout.write(raw if raw.endswith("\n") else raw + "\n")
|
|
131
|
+
return 0
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
if __name__ == "__main__":
|
|
135
|
+
raise SystemExit(main())
|
package/scripts/lib/aa_policy.py
CHANGED
|
@@ -239,7 +239,13 @@ def load_caller(path: str | Path, registry: dict[str, Any],
|
|
|
239
239
|
_check(value.get("snapshot_id") == registry["snapshot"]["id"],
|
|
240
240
|
"caller-context snapshot does not match frozen registry")
|
|
241
241
|
_check(value.get("kind") == "model", "unsupported caller-context kind")
|
|
242
|
+
# effort_unverified marks a caller degraded to its model's lowest-scored row
|
|
243
|
+
# because the launching harness recorded no effort; it may only be true.
|
|
244
|
+
unverified = value.pop("effort_unverified", None)
|
|
245
|
+
_check(unverified is None or unverified is True, "invalid caller-context effort_unverified")
|
|
242
246
|
_exact_fields(value, {"schema_version", "snapshot_id", "kind", "caller", "inherited_ceiling"})
|
|
247
|
+
if unverified:
|
|
248
|
+
value["effort_unverified"] = True
|
|
243
249
|
value["caller"] = _identity(value["caller"], "caller")
|
|
244
250
|
ceiling = value["inherited_ceiling"]
|
|
245
251
|
_check(type(ceiling) is int and 0 <= ceiling <= 100,
|
|
@@ -345,10 +351,15 @@ def decide(registry: dict[str, Any], registry_sha256: str, *,
|
|
|
345
351
|
"file it prints as --caller-context, which dispatch does itself when the "
|
|
346
352
|
"launching CLI names its model and effort; a human operator passes "
|
|
347
353
|
"--operator-asserted-human"),
|
|
354
|
+
failed_gate="caller-identity",
|
|
355
|
+
reason="no caller identity reached the gate",
|
|
356
|
+
next_command="omnilane whoami",
|
|
348
357
|
)
|
|
349
358
|
return base
|
|
350
359
|
base["caller_context_sha256"] = caller_sha256
|
|
351
360
|
caller_identity = caller["caller"]
|
|
361
|
+
degraded = caller.get("effort_unverified") is True
|
|
362
|
+
base["caller_degraded"] = degraded
|
|
352
363
|
caller_rows = _matching_rows(registry, caller_identity)
|
|
353
364
|
if len(caller_rows) != 1:
|
|
354
365
|
detail = _unknown_reason(registry, caller_identity)
|
|
@@ -356,9 +367,24 @@ def decide(registry: dict[str, Any], registry_sha256: str, *,
|
|
|
356
367
|
code="unknown-caller-config" if not caller_rows else "ambiguous-caller-config",
|
|
357
368
|
message=detail or "caller exact vendor/model/effort/reasoning/fallback is not uniquely scored",
|
|
358
369
|
caller=caller_identity,
|
|
370
|
+
failed_gate="caller-identity",
|
|
371
|
+
reason="the caller context names a configuration the frozen registry does not score exactly once",
|
|
372
|
+
next_command="omnilane whoami",
|
|
359
373
|
)
|
|
360
374
|
return base
|
|
361
375
|
caller_row = caller_rows[0]
|
|
376
|
+
model_rows = [row for row in registry["scored_configs"]
|
|
377
|
+
if row["vendor"] == caller_row["vendor"] and row["model"] == caller_row["model"]]
|
|
378
|
+
if degraded and caller_row["score"] != min(row["score"] for row in model_rows):
|
|
379
|
+
base.update(
|
|
380
|
+
code="invalid-degraded-caller",
|
|
381
|
+
message="an effort-unverified caller must name its model's lowest-scored row",
|
|
382
|
+
caller=caller_identity,
|
|
383
|
+
failed_gate="caller-identity",
|
|
384
|
+
reason="effort_unverified was set on a row above the model's floor",
|
|
385
|
+
next_command="omnilane whoami",
|
|
386
|
+
)
|
|
387
|
+
return base
|
|
362
388
|
effective = min(caller_row["score"], caller["inherited_ceiling"])
|
|
363
389
|
base.update(
|
|
364
390
|
caller=caller_identity,
|
|
@@ -370,7 +396,14 @@ def decide(registry: dict[str, Any], registry_sha256: str, *,
|
|
|
370
396
|
registry, vendor, model, effort, target_config
|
|
371
397
|
)
|
|
372
398
|
if target_row is None:
|
|
373
|
-
base.update(
|
|
399
|
+
base.update(
|
|
400
|
+
code=mapping_code,
|
|
401
|
+
message="target runtime cannot be mapped to one verified exact AA configuration",
|
|
402
|
+
failed_gate="target-transport",
|
|
403
|
+
reason=("the caller is identified; this host's transport overlay does not currently "
|
|
404
|
+
f"verify {vendor} {model} at effort {effort}"),
|
|
405
|
+
next_command="omnilane resign --check",
|
|
406
|
+
**detail)
|
|
374
407
|
return base
|
|
375
408
|
target_score = target_row["score"]
|
|
376
409
|
target_identity = _row_identity(target_row)
|
|
@@ -381,9 +414,30 @@ def decide(registry: dict[str, Any], registry_sha256: str, *,
|
|
|
381
414
|
target_estimated=target_row["estimated"],
|
|
382
415
|
)
|
|
383
416
|
if target_score > effective:
|
|
417
|
+
reaching = sorted((row for row in model_rows if row["score"] >= target_score),
|
|
418
|
+
key=lambda row: (row["score"], row["id"]))
|
|
419
|
+
required = reaching[0]["effort"] or "none" if reaching else None
|
|
420
|
+
if caller["inherited_ceiling"] < caller_row["score"]:
|
|
421
|
+
reason = ("this worker inherited a ceiling below the target; only the session that "
|
|
422
|
+
"dispatched it, or a human operator, can reach this target")
|
|
423
|
+
required = None
|
|
424
|
+
elif required is None:
|
|
425
|
+
reason = (f"no scored effort of {caller_row['model']} reaches {target_score}; a "
|
|
426
|
+
"stronger caller model or a human operator has to dispatch this target")
|
|
427
|
+
elif degraded:
|
|
428
|
+
reason = (f"the launching harness recorded no effort, so the caller was held to "
|
|
429
|
+
f"{caller_row['model']}'s floor of {effective}; relaunch the session with an "
|
|
430
|
+
f"explicit effort of {required} or higher")
|
|
431
|
+
else:
|
|
432
|
+
reason = (f"relaunch the calling session at effort {required} or higher, or have a "
|
|
433
|
+
"human operator dispatch this target")
|
|
384
434
|
base.update(
|
|
385
435
|
code="target-above-effective-ceiling",
|
|
386
436
|
message=f"target score {target_score} exceeds effective caller ceiling {effective}",
|
|
437
|
+
failed_gate="downward-ceiling",
|
|
438
|
+
reason=reason,
|
|
439
|
+
required_caller_effort=required,
|
|
440
|
+
next_command="omnilane list",
|
|
387
441
|
)
|
|
388
442
|
return base
|
|
389
443
|
child_context = {
|
|
@@ -402,6 +456,105 @@ def decide(registry: dict[str, Any], registry_sha256: str, *,
|
|
|
402
456
|
return base
|
|
403
457
|
|
|
404
458
|
|
|
459
|
+
def decide_inherited(registry: dict[str, Any], registry_sha256: str, *,
|
|
460
|
+
caller: dict[str, Any] | None, caller_sha256: str | None,
|
|
461
|
+
operator_asserted_human: bool = False,
|
|
462
|
+
host_asserted: dict[str, str] | None = None) -> dict[str, Any]:
|
|
463
|
+
"""A native worker that inherits the caller's own model and effort unchanged.
|
|
464
|
+
|
|
465
|
+
It runs what the caller runs, so it scores what the caller scores and cannot
|
|
466
|
+
be an upward dispatch, whether or not the caller's effort is known. There is
|
|
467
|
+
no external CLI, so no transport mapping is involved. It is nobody's lane
|
|
468
|
+
target: the decision names no target configuration and must not be reported
|
|
469
|
+
as satisfying one.
|
|
470
|
+
|
|
471
|
+
None of that rests on knowing who the caller is, so a caller whose identity
|
|
472
|
+
cannot be read still gets an inherited worker, on the host's word for its
|
|
473
|
+
vendor and model. That decision is marked unverified, carries no ceiling and
|
|
474
|
+
publishes no child context: a worker that tried to dispatch would have no
|
|
475
|
+
identity to dispatch with.
|
|
476
|
+
"""
|
|
477
|
+
base: dict[str, Any] = {
|
|
478
|
+
"schema_version": 1,
|
|
479
|
+
"snapshot_id": registry["snapshot"]["id"],
|
|
480
|
+
"registry_sha256": registry_sha256,
|
|
481
|
+
"allowed": False,
|
|
482
|
+
"code": "deny",
|
|
483
|
+
"message": "AA policy denied dispatch",
|
|
484
|
+
"caller_kind": "operator-asserted-human" if operator_asserted_human else "model",
|
|
485
|
+
"target_request": {"vendor": None, "model": None, "effort": None, "inherit": True},
|
|
486
|
+
"target_config_id": None,
|
|
487
|
+
"caller_score": None,
|
|
488
|
+
"inherited_ceiling": None,
|
|
489
|
+
"effective_ceiling": None,
|
|
490
|
+
"target_score": None,
|
|
491
|
+
"target_estimated": None,
|
|
492
|
+
"child_context": None,
|
|
493
|
+
"evidence_limit": ("the host asserts that a sub-agent spawned without a model override "
|
|
494
|
+
"inherits the caller's runtime; omnilane cannot observe it"),
|
|
495
|
+
}
|
|
496
|
+
if operator_asserted_human:
|
|
497
|
+
base.update(code="inherit-requires-model-caller",
|
|
498
|
+
message="only a model running inside a harness has a runtime to inherit",
|
|
499
|
+
failed_gate="caller-identity",
|
|
500
|
+
reason="a human operator has no sub-agent tool; dispatch a lane instead",
|
|
501
|
+
next_command="omnilane list")
|
|
502
|
+
return base
|
|
503
|
+
if caller is None and host_asserted is not None:
|
|
504
|
+
base.update(allowed=True, code="native-inherited-unverified-caller",
|
|
505
|
+
message="the worker inherits the caller's own runtime, so it cannot score above it; "
|
|
506
|
+
"the caller's vendor and model are the host's statement, not a verified identity",
|
|
507
|
+
caller_kind="model-unverified", caller_identity_verified=False,
|
|
508
|
+
caller_identity_source="host-asserted",
|
|
509
|
+
target={"inherit": True, "vendor": host_asserted["vendor"],
|
|
510
|
+
"model": host_asserted["model"]})
|
|
511
|
+
return base
|
|
512
|
+
if caller is None:
|
|
513
|
+
base.update(code="missing-caller-context",
|
|
514
|
+
message="no caller identity: an inherited worker still has to know whose runtime it inherits",
|
|
515
|
+
failed_gate="caller-identity",
|
|
516
|
+
reason="no caller identity reached the gate and the capability file names no current_model",
|
|
517
|
+
next_command="omnilane whoami # if that cannot read this harness: omnilane "
|
|
518
|
+
"native-context --vendor VENDOR --model MODEL --inherits-caller-runtime")
|
|
519
|
+
return base
|
|
520
|
+
base["caller_context_sha256"] = caller_sha256
|
|
521
|
+
base["caller_identity_verified"] = True
|
|
522
|
+
base["caller_identity_source"] = "caller-context"
|
|
523
|
+
identity = caller["caller"]
|
|
524
|
+
degraded = caller.get("effort_unverified") is True
|
|
525
|
+
rows = _matching_rows(registry, identity)
|
|
526
|
+
if len(rows) != 1:
|
|
527
|
+
base.update(code="unknown-caller-config" if not rows else "ambiguous-caller-config",
|
|
528
|
+
message=_unknown_reason(registry, identity)
|
|
529
|
+
or "caller exact vendor/model/effort/reasoning/fallback is not uniquely scored",
|
|
530
|
+
caller=identity, failed_gate="caller-identity",
|
|
531
|
+
reason="the caller context names a configuration the frozen registry does not score exactly once",
|
|
532
|
+
next_command="omnilane whoami")
|
|
533
|
+
return base
|
|
534
|
+
row = rows[0]
|
|
535
|
+
floor = min(r["score"] for r in registry["scored_configs"]
|
|
536
|
+
if r["vendor"] == row["vendor"] and r["model"] == row["model"])
|
|
537
|
+
if degraded and row["score"] != floor:
|
|
538
|
+
base.update(code="invalid-degraded-caller",
|
|
539
|
+
message="an effort-unverified caller must name its model's lowest-scored row",
|
|
540
|
+
caller=identity, failed_gate="caller-identity",
|
|
541
|
+
reason="effort_unverified was set on a row above the model's floor",
|
|
542
|
+
next_command="omnilane whoami")
|
|
543
|
+
return base
|
|
544
|
+
effective = min(row["score"], caller["inherited_ceiling"])
|
|
545
|
+
child = {"schema_version": 1, "snapshot_id": registry["snapshot"]["id"], "kind": "model",
|
|
546
|
+
"caller": identity, "inherited_ceiling": effective}
|
|
547
|
+
if degraded:
|
|
548
|
+
child["effort_unverified"] = True
|
|
549
|
+
base.update(allowed=True, code="native-inherited-allowed",
|
|
550
|
+
message="the worker inherits the caller's own runtime, so it cannot score above it",
|
|
551
|
+
caller=identity, caller_degraded=degraded, caller_score=row["score"],
|
|
552
|
+
inherited_ceiling=caller["inherited_ceiling"], effective_ceiling=effective,
|
|
553
|
+
target={"inherit": True, "vendor": row["vendor"], "model": row["model"]},
|
|
554
|
+
child_context=child)
|
|
555
|
+
return base
|
|
556
|
+
|
|
557
|
+
|
|
405
558
|
def _normalized_effort(value: str) -> str | None:
|
|
406
559
|
return None if value in ("", "-") else value
|
|
407
560
|
|
|
@@ -6,6 +6,8 @@ corresponds to a probe run under the selected evidence root whose raw
|
|
|
6
6
|
stdout/stderr is hashed into the manifest, so the overlay's evidence[] anchors
|
|
7
7
|
the whole set.
|
|
8
8
|
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
9
11
|
import argparse
|
|
10
12
|
import hashlib
|
|
11
13
|
import json
|
|
@@ -14,9 +16,13 @@ import shutil
|
|
|
14
16
|
import socket
|
|
15
17
|
from collections import Counter
|
|
16
18
|
from datetime import datetime, timezone
|
|
19
|
+
import sys
|
|
17
20
|
from pathlib import Path
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
23
|
+
import cli_provenance # noqa: E402
|
|
24
|
+
|
|
25
|
+
REPO = Path(os.environ.get("OMNILANE_REPO") or Path(__file__).resolve().parents[2])
|
|
20
26
|
HOME = Path.home()
|
|
21
27
|
SWEEP_ID = os.environ.get("OMNILANE_TRANSPORT_SWEEP_ID", "overlay-reprobe-20260909")
|
|
22
28
|
DEFAULT_ROOT = HOME / ".omnilane" / "transport-evidence" / SWEEP_ID
|
|
@@ -98,19 +104,21 @@ def cli_path(name: str) -> Path:
|
|
|
98
104
|
return Path(found).resolve()
|
|
99
105
|
|
|
100
106
|
|
|
107
|
+
RUNNERS = {"grok": "run-grok.sh", "codex": "run-codex.sh", "claude": "run-claude.sh",
|
|
108
|
+
"gemini": "run-gemini.sh"}
|
|
109
|
+
CLI_NAMES = {"grok": "grok", "codex": "codex", "claude": "claude", "gemini": "agy"}
|
|
110
|
+
|
|
111
|
+
|
|
101
112
|
def core_evidence() -> list[tuple[Path, str]]:
|
|
102
113
|
"""Resolved when a build runs, not at import: a host missing one CLI can
|
|
103
114
|
still load this module to read PROVEN."""
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
(cli_path("agy"), "gemini"),
|
|
112
|
-
(REPO / "scripts/runners/run-gemini.sh", "gemini"),
|
|
113
|
-
]
|
|
115
|
+
anchors = []
|
|
116
|
+
for vendor in ("grok", "codex", "claude", "gemini"):
|
|
117
|
+
if shutil.which(CLI_NAMES[vendor]) is None:
|
|
118
|
+
continue # not installed here: main() signs nothing for it
|
|
119
|
+
anchors += [(cli_path(CLI_NAMES[vendor]), vendor),
|
|
120
|
+
(REPO / "scripts/runners" / RUNNERS[vendor], vendor)]
|
|
121
|
+
return anchors
|
|
114
122
|
|
|
115
123
|
|
|
116
124
|
def sha256(path: Path) -> str:
|
|
@@ -129,6 +137,12 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
129
137
|
default=DEFAULT_ROOT,
|
|
130
138
|
help=f"probe sweep root (default: {DEFAULT_ROOT})",
|
|
131
139
|
)
|
|
140
|
+
parser.add_argument(
|
|
141
|
+
"--source",
|
|
142
|
+
default=os.environ.get("OMNILANE_TRANSPORT_SOURCE")
|
|
143
|
+
or f"{socket.gethostname()} / build_overlay {datetime.now(timezone.utc).date().isoformat()}",
|
|
144
|
+
help="free-text provenance recorded in the overlay",
|
|
145
|
+
)
|
|
132
146
|
args = parser.parse_args(argv)
|
|
133
147
|
root = args.root.expanduser()
|
|
134
148
|
|
|
@@ -144,7 +158,11 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
144
158
|
if path.exists():
|
|
145
159
|
entry[suffix] = {"path": str(path), "sha256": sha256(path)}
|
|
146
160
|
if "json" not in entry:
|
|
147
|
-
|
|
161
|
+
# A vendor nobody is logged in to was never probed; that is a gap in this
|
|
162
|
+
# host's overlay, not a reason to refuse to sign the vendors that were.
|
|
163
|
+
unproven.append({"config_id": cid, "verdict_reason": "not probed on this host",
|
|
164
|
+
"observed_model": None, "probed_at": None})
|
|
165
|
+
continue
|
|
148
166
|
descriptor_path = Path(entry["json"]["path"])
|
|
149
167
|
descriptor = json.loads(descriptor_path.read_text())
|
|
150
168
|
if not isinstance(descriptor, dict):
|
|
@@ -169,11 +187,18 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
169
187
|
manifest_path = root / "probe-manifest.json"
|
|
170
188
|
manifest_path.write_text(json.dumps(manifest, indent=2, sort_keys=True) + "\n")
|
|
171
189
|
|
|
190
|
+
anchors = core_evidence()
|
|
191
|
+
anchored = {vendor for _, vendor in anchors}
|
|
172
192
|
mappings = []
|
|
173
193
|
for cid, (selector, runtime_model, _) in sorted(PROVEN.items()):
|
|
174
194
|
if cid not in manifest["probe_runs"]:
|
|
175
195
|
continue
|
|
176
196
|
row = ROWS[cid]
|
|
197
|
+
if row["vendor"] not in anchored:
|
|
198
|
+
# Evidence with no executable to pin it to verifies nothing.
|
|
199
|
+
unproven.append({"config_id": cid, "verdict_reason": "vendor CLI is not installed",
|
|
200
|
+
"observed_model": None, "probed_at": None})
|
|
201
|
+
continue
|
|
177
202
|
mapping = {
|
|
178
203
|
"config_id": cid,
|
|
179
204
|
"identity": {key: row[key] for key in IDENTITY_FIELDS},
|
|
@@ -187,18 +212,20 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
187
212
|
mapping["cli_flag"] = "--reasoning-effort"
|
|
188
213
|
mappings.append(mapping)
|
|
189
214
|
|
|
190
|
-
evidence = [
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
215
|
+
evidence = []
|
|
216
|
+
for path, vendor in anchors:
|
|
217
|
+
anchor = {"path": str(path), "sha256": sha256(path), "vendor": vendor}
|
|
218
|
+
if path.name != RUNNERS[vendor]:
|
|
219
|
+
# The signer an unattended re-sign is later held to; see cli_provenance.
|
|
220
|
+
anchor["codesign"] = cli_provenance.facts(path)
|
|
221
|
+
evidence.append(anchor)
|
|
194
222
|
evidence.append({"path": str(manifest_path), "sha256": sha256(manifest_path)})
|
|
195
223
|
|
|
196
224
|
overlay = {
|
|
197
225
|
"schema_version": 1,
|
|
198
226
|
"snapshot_id": REGISTRY["snapshot"]["id"],
|
|
199
227
|
"host": socket.gethostname(),
|
|
200
|
-
"source":
|
|
201
|
-
"gemini selectors re-probed 2026-09-09 after agy 1.1.27 -> 1.1.28"),
|
|
228
|
+
"source": args.source,
|
|
202
229
|
"evidence": evidence,
|
|
203
230
|
"mappings": mappings,
|
|
204
231
|
"unproven": unproven,
|
|
@@ -40,6 +40,8 @@ Selector = tuple[str, Optional[str], Optional[str]]
|
|
|
40
40
|
Lookup = Callable[[int], Optional[tuple[int, list[str]]]]
|
|
41
41
|
EnvironmentLookup = Callable[[int], dict[str, str]]
|
|
42
42
|
UUID_PATTERN = re.compile(r"[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}\Z")
|
|
43
|
+
CODEX_TOOL_HOSTS = frozenset(("codex-code-mode-host",))
|
|
44
|
+
SHELLS = frozenset(("zsh", "bash", "sh", "dash", "fish"))
|
|
43
45
|
TURN_END_EVENTS = frozenset(("task_complete", "turn_complete", "turn_aborted"))
|
|
44
46
|
CODEX_SANDBOX_REFUSAL = (
|
|
45
47
|
"Codex sandbox (CODEX_SANDBOX=seatbelt) blocked process inspection; omnilane also "
|
|
@@ -58,7 +60,9 @@ def _vendor(executable: str) -> str | None:
|
|
|
58
60
|
name = path.name
|
|
59
61
|
if name == "claude" or (path.parent.name == "versions" and path.parent.parent.name == "claude"):
|
|
60
62
|
return "claude"
|
|
61
|
-
|
|
63
|
+
# codex-profile-switch launches the desktop app-server as `codex-modified`; its sibling
|
|
64
|
+
# `codex-code-mode-host` is a tool host, not the CLI, so the match stays exact.
|
|
65
|
+
if name in ("codex", "codex-modified"):
|
|
62
66
|
return "codex"
|
|
63
67
|
if name == "grok" or (name.startswith("grok-") and path.parent.name == "downloads"):
|
|
64
68
|
return "grok"
|
|
@@ -184,6 +188,17 @@ def resolve(registry: dict, vendor: str, model: str | None,
|
|
|
184
188
|
return None, f"no scored configuration for {vendor} {model} at effort {effort}"
|
|
185
189
|
|
|
186
190
|
|
|
191
|
+
def floor_row(registry: dict, vendor: str, model: str | None) -> dict | None:
|
|
192
|
+
"""The lowest-scored row of a known model, for a caller whose effort is unrecorded.
|
|
193
|
+
|
|
194
|
+
Whatever effort actually ran scores at least this much, so the floor can only
|
|
195
|
+
narrow what the caller may dispatch; it never widens it.
|
|
196
|
+
"""
|
|
197
|
+
rows = [row for row in registry["scored_configs"]
|
|
198
|
+
if row["vendor"] == vendor and row["model"] == model]
|
|
199
|
+
return min(rows, key=lambda row: (row["score"], row["id"])) if rows else None
|
|
200
|
+
|
|
201
|
+
|
|
187
202
|
def _thread_environment(entries: list[bytes]) -> dict[str, str]:
|
|
188
203
|
values = [entry.partition(b"=")[2] for entry in entries
|
|
189
204
|
if entry.partition(b"=")[0] == b"CODEX_THREAD_ID"]
|
|
@@ -279,7 +294,7 @@ def _launcher(pid: int, lookup: Lookup) -> tuple[int, Selector, int | None] | No
|
|
|
279
294
|
Nearest wins: a codex worker started by a Claude session is a codex caller.
|
|
280
295
|
"""
|
|
281
296
|
seen: set[int] = set()
|
|
282
|
-
|
|
297
|
+
below: list[tuple[int, list[str]]] = []
|
|
283
298
|
for _ in range(MAX_DEPTH):
|
|
284
299
|
if pid <= 0 or pid in seen:
|
|
285
300
|
return None
|
|
@@ -290,12 +305,25 @@ def _launcher(pid: int, lookup: Lookup) -> tuple[int, Selector, int | None] | No
|
|
|
290
305
|
ppid, argv = entry
|
|
291
306
|
selector = read_selector(argv)
|
|
292
307
|
if selector is not None:
|
|
293
|
-
return pid, selector,
|
|
294
|
-
|
|
308
|
+
return pid, selector, _thread_anchor(below)
|
|
309
|
+
below.append((pid, argv))
|
|
295
310
|
pid = ppid
|
|
296
311
|
return None
|
|
297
312
|
|
|
298
313
|
|
|
314
|
+
def _thread_anchor(below: list[tuple[int, list[str]]]) -> int | None:
|
|
315
|
+
"""The process whose initial environment codex wrote for this conversation.
|
|
316
|
+
|
|
317
|
+
That is codex's direct child, unless codex runs commands through its own tool
|
|
318
|
+
host: one host serves every conversation of an app-server, so it carries no
|
|
319
|
+
thread id and the process it starts for the command does.
|
|
320
|
+
"""
|
|
321
|
+
for pid, argv in reversed(below):
|
|
322
|
+
if not (argv and Path(argv[0]).name in CODEX_TOOL_HOSTS):
|
|
323
|
+
return pid
|
|
324
|
+
return None
|
|
325
|
+
|
|
326
|
+
|
|
299
327
|
def find_launcher(pid: int, lookup: Lookup = _process) -> tuple[int, Selector] | None:
|
|
300
328
|
try:
|
|
301
329
|
found = _launcher(pid, lookup)
|
|
@@ -400,11 +428,20 @@ def _rollout_selector(thread: str,
|
|
|
400
428
|
event, context_turn, event_turn = ended
|
|
401
429
|
raise ValueError(f"latest turn_context turn {context_turn} has already ended "
|
|
402
430
|
f"({event}, turn {event_turn})" + _rollout_age_hint(last_timestamp, now))
|
|
403
|
-
for key
|
|
431
|
+
for key in ("turn_id", "model"):
|
|
432
|
+
value = latest[key]
|
|
404
433
|
if not isinstance(value, str) or not value.strip():
|
|
405
434
|
detail = " (turn unknown)" if key == "turn_id" else ""
|
|
406
435
|
raise ValueError(f"latest turn_context {key} must be a non-empty string{detail}")
|
|
407
|
-
|
|
436
|
+
effort = latest["effort"]
|
|
437
|
+
source = f"thread {thread}, turn {latest['turn_id']}"
|
|
438
|
+
if effort is None:
|
|
439
|
+
# Heartbeat automations wake a thread without recording an effort. The
|
|
440
|
+
# model is still known, so the caller degrades instead of going blind.
|
|
441
|
+
return ("codex", latest["model"], None), source + ", turn_context records no effort"
|
|
442
|
+
if not isinstance(effort, str) or not effort.strip():
|
|
443
|
+
raise ValueError("latest turn_context effort must be a non-empty string")
|
|
444
|
+
return ("codex", latest["model"], effort), source
|
|
408
445
|
|
|
409
446
|
|
|
410
447
|
def read_caller(pid: int, lookup: Lookup = _process,
|
|
@@ -442,7 +479,17 @@ def read_caller(pid: int, lookup: Lookup = _process,
|
|
|
442
479
|
detail = f"errno {error.errno}" if isinstance(error, OSError) else "invalid environment block"
|
|
443
480
|
raise ValueError(f"cannot read codex direct child initial environment ({detail})") from None
|
|
444
481
|
if not inherited or not UUID_PATTERN.fullmatch(inherited):
|
|
445
|
-
|
|
482
|
+
entry = lookup(child)
|
|
483
|
+
name = Path(entry[1][0]).name if entry and entry[1] else "unknown"
|
|
484
|
+
hint = ""
|
|
485
|
+
if name.lstrip("-") in SHELLS:
|
|
486
|
+
# codex starts `zsh -lc '<command>'`; the shell sets the thread id and, for one
|
|
487
|
+
# simple command, execs into it, so that command is the direct child. With
|
|
488
|
+
# `;`, `&&`, `|` or a subshell the shell stays, and its own start had no id.
|
|
489
|
+
hint = ("; run the omnilane command as the only command of the tool call, "
|
|
490
|
+
"with no `;`, `&&`, `|` or subshell around it")
|
|
491
|
+
raise ValueError(f"codex direct child CODEX_THREAD_ID is missing or not a UUID "
|
|
492
|
+
f"(read from pid {child}, {name}){hint}")
|
|
446
493
|
if inherited != thread:
|
|
447
494
|
raise ValueError("CODEX_THREAD_ID mismatch between current process and codex direct child")
|
|
448
495
|
selector, source = _rollout_selector(thread, current_environment, now)
|
|
@@ -461,18 +508,25 @@ def load_registry(path: str | Path) -> tuple[dict, str]:
|
|
|
461
508
|
os.environ.update(saved)
|
|
462
509
|
|
|
463
510
|
|
|
464
|
-
def write_context(row: dict, registry: dict, home: Path) -> Path:
|
|
511
|
+
def write_context(row: dict, registry: dict, home: Path, effort_unverified: bool = False) -> Path:
|
|
465
512
|
"""One file per identity: every session launched the same way is the same caller."""
|
|
466
513
|
directory = Path(home) / "caller-context"
|
|
467
514
|
directory.mkdir(parents=True, exist_ok=True)
|
|
468
|
-
|
|
469
|
-
|
|
515
|
+
stem = row["id"].replace("/", "--")
|
|
516
|
+
if effort_unverified:
|
|
517
|
+
# Not the same caller as one that really launched at the floor effort.
|
|
518
|
+
stem = f"{row['vendor']}--{row['model'].replace('.', '-')}--effort-unverified"
|
|
519
|
+
path = directory / (stem + ".json")
|
|
520
|
+
value = {
|
|
470
521
|
"schema_version": 1,
|
|
471
522
|
"snapshot_id": registry["snapshot"]["id"],
|
|
472
523
|
"kind": "model",
|
|
473
524
|
"caller": {key: row[key] for key in aa_policy.IDENTITY_FIELDS},
|
|
474
525
|
"inherited_ceiling": row["score"],
|
|
475
|
-
}
|
|
526
|
+
}
|
|
527
|
+
if effort_unverified:
|
|
528
|
+
value["effort_unverified"] = True
|
|
529
|
+
text = json.dumps(value, indent=2, sort_keys=True) + "\n"
|
|
476
530
|
try:
|
|
477
531
|
if path.read_text() == text:
|
|
478
532
|
return path
|
|
@@ -505,14 +559,24 @@ def main(argv: list[str] | None = None, environment: Mapping[str, str] = os.envi
|
|
|
505
559
|
print(f"omnilane: cannot read the caller identity: {error}", file=sys.stderr)
|
|
506
560
|
return 3
|
|
507
561
|
row, reason = resolve(registry, vendor, model, effort)
|
|
562
|
+
degraded = False
|
|
563
|
+
if row is None and vendor == "codex" and model and effort is None:
|
|
564
|
+
row = floor_row(registry, vendor, model)
|
|
565
|
+
degraded = row is not None
|
|
508
566
|
if row is None:
|
|
509
567
|
print(f"omnilane: cannot read the caller identity from pid {pid}: {reason}", file=sys.stderr)
|
|
510
568
|
return 3
|
|
511
569
|
home = Path(os.environ.get("OMNILANE_HOME") or Path.home() / ".omnilane")
|
|
512
|
-
path = write_context(row, registry, home)
|
|
570
|
+
path = write_context(row, registry, home, effort_unverified=degraded)
|
|
513
571
|
provenance = f", {source}" if source else ""
|
|
514
|
-
|
|
515
|
-
|
|
572
|
+
if degraded:
|
|
573
|
+
print(f"omnilane: caller is {vendor}/{model} at an unrecorded effort; degraded to its "
|
|
574
|
+
f"lowest-scored row {row['id']} (ceiling {row['score']}), read from pid {pid}"
|
|
575
|
+
f"{provenance}. Lanes above that ceiling need a session launched with an "
|
|
576
|
+
f"explicit effort.", file=sys.stderr)
|
|
577
|
+
else:
|
|
578
|
+
print(f"omnilane: caller is {row['id']} (score {row['score']}), read from pid {pid}"
|
|
579
|
+
f"{provenance}", file=sys.stderr)
|
|
516
580
|
print(path)
|
|
517
581
|
return 0
|
|
518
582
|
|