Repository navigation
fix(OMN-20299): onex delegate derives a caller lane when no rule names one, so no CLI run writes a null caller_lane - #4427
Conversation
…s one, so no CLI run writes a null caller_lane
…12145) * evidence(OMN-20299): author OCC companion for OmniNode-ai/omnibase_infra#4427 OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 400cf2512d86654719956b0b1109f3ca0ab03346. * evidence(OMN-20299): self-bind OCC#12145 + rebind contract_sha256 --------- Co-authored-by: omnimarket-bot <bot@omninode.ai>
There was a problem hiding this comment.
Hostile Reviewer — adversarial findings (OMN-17492)
Models succeeded: qwen3-review, gpt-oss-review
Models failed: none
New finding threads: 0
Deduped (already posted on this PR): 0
Below quorum (one model only, reported not threaded): 12
Nit-level findings suppressed: 0
The model is the FINDER, never the gate: merge is gated only by the
deterministic Hostile Review Thread Gate, which blocks while
hostile-reviewer threads are unresolved. Resolve each thread after
addressing (or rejecting, with a reply) its finding.
Below quorum: 12 finding(s) raised by one model only (OMN-18479)
These are reported and NOT dropped, but they get no thread and do not block: a single model's finding no other model reproduced is not evidence enough to stop a merge. Read them; act on them if they are right.
- [MAJOR]
src/omnibase_infra/cli/delegate_caller.py, _fallback_lane(qwen3-review) — session fallback emits raw UUID without slug sanitization | The session branch of _fallback_lane returns f"session:{session}" directly, bypassing slug. The session value is read from the CLAUDE_CODE - [MAJOR]
src/omnibase_infra/cli/delegate_caller.py, _derived and _fallback_lane launchd branch(qwen3-review) — Truncation to _LANE_MAX can produce a token that fails the lane regex | _derived and the launchd branch both apply [:_LANE_MAX] after joining. If the truncation point falls on a colon or a hyphen, the - [MAJOR]
CLI payload generation (not shown in diff) needs modification(gpt-oss-review) — Derived caller lane never added to payload metadata | Integration tests now assert that the metadata map contains a "caller_lane" key, but the CLI code that builds the payload does not insert this fie - [MAJOR]
src/omnibase_infra/cli/model_delegate_caller.py(gpt-oss-review) — Inconsistent optional type for ModelDelegateCaller.lane | The field lane is typed as Optional[str] with a default of None, yet documentation and resolver guarantee a non‑null value. This mismatch can - [MINOR]
src/omnibase_infra/cli/delegate_caller.py, _fallback_lane(qwen3-review) — XPC_SERVICE_NAME is attacker-controllable in a CI or container context | The launchd fallback reads XPC_SERVICE_NAME from the process environment. In a GitHub Actions runner, a Docker container, or an - [MINOR]
src/omnibase_infra/cli/delegate_caller.py, _fallback_lane GHA branch(qwen3-review) — GITHUB_REPOSITORY rsplit takes the last path segment, not the repo name | The GHA branch extracts the repository name via environ.get("GITHUB_REPOSITORY", "").strip().rsplit("/", 1)[-1]. GITHUB_REPOSI - [MINOR]
tests/unit/cli/test_cli_delegate_caller_never_null.py(qwen3-review) — No test exercises the _LANE_MAX truncation boundary | The test suite parametrizes host values including 'a' * 300, which triggers truncation in the unattributed branch. However, no test feeds a launch - [MINOR]
tests/integration/cli/test_delegate_ticket_cli_omn19514.py(qwen3-review) — Integration tests assert exact metadata key set, coupling to implementation detail | The integration tests now assert set(metadata) == {DELEGATE_TICKET_METADATA_KEY, "caller_lane"}. This hard-codes th - [MINOR]
src/omnibase_infra/cli/delegate_caller.py, resolve_delegate_caller(qwen3-review) — socket.gethostname() called at resolution time is not injectable in all call sites | resolve_delegate_caller accepts a host parameter that defaults to None, in which case socket.gethostname() is calle - [MINOR]
src/omnibase_infra/cli/delegate_caller.py:line where socket.gethostname() is used(gpt-oss-review) — Hostname leakage through caller_lane metadata | The fallback lane includes the machine hostname obtained via socket.gethostname(). When the caller_lane is added to request metadata, the internal host - [MINOR]
src/omnibase_infra/cli/delegate_caller.py: within _fallback_lane host resolution(gpt-oss-review) — Uncaught OSError from socket.gethostname() | socket.gethostname() can raise OSError on some platforms (e.g., when the hostname cannot be determined). The resolver does not handle this exception, causi - [MINOR]
tests/unit/cli/test_cli_delegate_caller_identity.py(gpt-oss-review) — Non‑deterministic host fallback in tests without explicit host argument | Tests that invoke resolve_delegate_caller without providing the host argument rely on the default socket.gethostname(), which
✅ Hostile Reviewer — REVIEWEDCritical findings: 0
Semantics (OMN-17492 — the model finds, thread resolution gates)
Powered by omniintelligence.review_pairing.cli_review — multi-model adversarial review: qwen3-review (Qwen3.8-27B), gpt-oss-review (gpt-oss-120b) (OMN-8468/OMN-8524/OMN-17492) |
…tadata The stand-in request model now declares a metadata field to accept the caller_lane payload. This prevents extra_forbidden errors when the delegate always includes caller metadata. The model still omits requested_timeout_seconds to preserve existing test coverage. Local integration and unit test suites pass with this change.
There was a problem hiding this comment.
Hostile Reviewer — adversarial findings (OMN-17492)
Models succeeded: qwen3-review, gpt-oss-review
Models failed: none
New finding threads: 0
Deduped (already posted on this PR): 0
Below quorum (one model only, reported not threaded): 14
Nit-level findings suppressed: 0
The model is the FINDER, never the gate: merge is gated only by the
deterministic Hostile Review Thread Gate, which blocks while
hostile-reviewer threads are unresolved. Resolve each thread after
addressing (or rejecting, with a reply) its finding.
Below quorum: 14 finding(s) raised by one model only (OMN-18479)
These are reported and NOT dropped, but they get no thread and do not block: a single model's finding no other model reproduced is not evidence enough to stop a merge. Read them; act on them if they are right.
- [MAJOR]
src/omnibase_infra/cli/delegate_caller.py(qwen3-review) — Session fallback bypasses UUID validation and slug sanitization | The session fallback path in _fallback_lane returns f"session:{session}" without applying _slug or truncating to _LANE_MAX. The sessio - [MAJOR]
src/omnibase_infra/cli/delegate_caller.py(qwen3-review) — Unsanitized environment variables in derived lane tokens | The GITHUB_WORKFLOW and GITHUB_REPOSITORY values are passed through _slug, which is correct. However, the XPC_SERVICE_NAME value is used dire - [MAJOR]
src/omnibase_infra/cli/delegate_caller.py(qwen3-review) — Truncation to _LANE_MAX may produce invalid lane tokens | The _derived function truncates the joined string to _LANE_MAX characters. If the truncation point falls in the middle of a slugified part, th - [MAJOR]
tests/unit/cli/test_cli_delegate_caller_never_null.py(qwen3-review) — Missing test for session fallback with non-UUID session values | The test suite verifies that CLAUDE_CODE_SESSION_ID with a valid UUID produces a session lane, but does not test what happens when the - [MAJOR]
src/omnibase_infra/cli/delegate_caller.py:71-78(gpt-oss-review) — Unsanitized session ID used in lane token | The fallback logic inserts the raw CLAUDE_CODE_SESSION_ID value into the lane token ("session:{session}") without applying the slug sanitization used for ot - [MAJOR]
src/omnibase_infra/cli/delegate_caller.py:73-78(gpt-oss-review) — Uncaught exception from socket.gethostname() | Whenhostis not provided,resolve_delegate_callercallssocket.gethostname()to obtain the fallback host name.socket.gethostname()can raise `O - [MINOR]
src/omnibase_infra/cli/delegate_caller.py(qwen3-review) — socket.gethostname() called on every resolve when host is None | When host is None, resolve_delegate_caller calls socket.gethostname() unconditionally in the fallback path. This is a system call that - [MINOR]
src/omnibase_infra/cli/delegate_caller.py(qwen3-review) — GITHUB_REPOSITORY rsplit produces 'unknown' for empty repository | When GITHUB_REPOSITORY is empty or unset, repository becomes an empty string, and the code uses repository or "unknown". This is corr - [MINOR]
tests/unit/cli/test_cli_delegate_caller_never_null.py(qwen3-review) — No test for _slug edge cases with leading/trailing dots and underscores | The slug function strips leading and trailing '-', '.', and '' characters. The test suite does not verify that a value like - [MINOR]
src/omnibase_infra/cli/delegate_caller.py(qwen3-review) — lane_source string is not machine-parseable | The lane_source values are human-readable strings like "fallback env XPC_SERVICE_NAME" or "fallback host". These are used in the ModelDelegateCaller model - [MINOR]
tests/unit/cli/test_cli_delegate_caller_never_null.py(qwen3-review) — No test for launchd label that exceeds _LANE_MAX | The _LANE_MAX constant is 128, and the launchd path truncates to this limit. No test verifies that a launchd label longer than 128 characters is corr - [MINOR]
src/omnibase_infra/cli/model_delegate_caller.py:13-20(gpt-oss-review) — ModelDelegateCaller lane field remains Optional despite non‑null guarantee | The resolver now guaranteeslaneis neverNone, but the Pydantic model still declareslane: str | None. This type mis - [MINOR]
src/omnibase_infra/cli/delegate_caller.py:30-78(gpt-oss-review) — Additional regex and slug processing on every caller resolution | The new fallback logic introduces three compiled regular expressions and multiple string transformations for each call to `resolve_del - [MINOR]
src/omnibase_infra/cli/delegate_caller.py:56-64(gpt-oss-review) — Missing test for overly long launchd label truncation | The fallback for launchd jobs truncates the lane token to_LANE_MAXcharacters, but the test suite does not verify behavior when the label exc
There was a problem hiding this comment.
Hostile Reviewer — adversarial findings (OMN-17492)
Models succeeded: qwen3-review, gpt-oss-review
Models failed: none
New finding threads: 2
Deduped (already posted on this PR): 0
Below quorum (one model only, reported not threaded): 9
Nit-level findings suppressed: 0
The model is the FINDER, never the gate: merge is gated only by the
deterministic Hostile Review Thread Gate, which blocks while
hostile-reviewer threads are unresolved. Resolve each thread after
addressing (or rejecting, with a reply) its finding.
Below quorum: 9 finding(s) raised by one model only (OMN-18479)
These are reported and NOT dropped, but they get no thread and do not block: a single model's finding no other model reproduced is not evidence enough to stop a merge. Read them; act on them if they are right.
- [MAJOR]
src/omnibase_infra/cli/delegate_caller.py(qwen3-review) — Session fallback bypasses UUID validation and slugification | The session fallback path in_fallback_lanereturnsf"session:{session}"without passing the session value through_slugor validati - [MAJOR]
src/omnibase_infra/cli/delegate_caller.py(qwen3-review) — Launchd label fallback bypasses slugification and length bound | The launchd fallback path returnsf"launchd:{label}"[:_LANE_MAX]without passing the label through_slug. The `_LAUNCHD_LABEL_PATTE - [MAJOR]
src/omnibase_infra/cli/delegate_caller.py(gpt-oss-review) — Uncaught exception from socket.gethostname in fallback lane generation | The fallback lane logic callssocket.gethostname()whenhostis not supplied. If the system call fails (e.g., due to DNS mi - [MAJOR]
src/omnibase_infra/cli/model_delegate_caller.py(gpt-oss-review) — ModelDelegateCaller lane field remains optional despite resolver guarantee |ModelDelegateCaller.laneis typed asstr | Noneand defaults toNone, yetresolve_delegate_callernow always return - [MAJOR]
tests/unit/cli/test_cli_delegate_caller_never_null.py(gpt-oss-review) — Missing test for hostname‑fallback error handling | The new fallback path relies onsocket.gethostname(), but the test suite does not simulate a failure of this call. Absence of such a test leaves t - [MINOR]
src/omnibase_infra/cli/delegate_caller.py(qwen3-review) — Host name is attacker-controllable via socket.gethostname() | Whenhostis not explicitly provided,socket.gethostname()is used to construct theunattributed:<host>lane. On multi-tenant or con - [MINOR]
tests/unit/cli/test_cli_delegate_caller_never_null.py(qwen3-review) — Test for host fallback does not validate lane token format | The testtest_caller_lane_host_fallback_is_always_a_lane_tokenparametrizes host values including""," ","host with spaces!", ` - [MINOR]
tests/unit/cli/test_cli_delegate_caller_never_null.py(qwen3-review) — No test for the case where GITHUB_ACTIONS is true but GITHUB_WORKFLOW is empty | The GHA fallback requires bothGITHUB_ACTIONSto be"true"andGITHUB_WORKFLOWto be non-empty. If `GITHUB_ACTION - [MINOR]
src/omnibase_infra/cli/delegate_caller.py(gpt-oss-review) — Non‑deterministic lane token due to host‑dependent fallback | When no explicit lane is provided, the resolver derives a lane from the machine hostname. Hostnames differ across environments, causing th
Findings demoted from threads (anchor rejected)
-
[MINOR] hostile-reviewer (qwen3-review)
GitHub Actions repository extraction uses rsplit which may produce unexpected results | The GHA fallback extracts the repository name via
environ.get("GITHUB_REPOSITORY", "").strip().rsplit("/", 1)[-1]. IfGITHUB_REPOSITORYis set to a value without a slash (e.g., just"omnibase_infra"), the result is the entire string, which is correct. However, if the value is empty or contains multiple slashes, the behavior is correct but the code does not explicitly handle the case whereGITHUB_REPOSITORYis unsResolve this thread when addressed — the
Hostile Review Thread Gateblocks while hostile-reviewer threads are unresolved (OMN-17492). -
[MINOR] hostile-reviewer (gpt-oss-review)
Potential lane token collision from length truncation | The fallback lane strings are truncated to
_LANE_MAXcharacters after concatenation. Truncation can cut off part of the identifier, producing identical tokens for distinct inputs (e.g., long hostnames or GitHub repo names), which may lead to misattribution in the ledger. | Evidence: Both_derivedand the launchd fallback use[:_LANE_MAX]on the full token string. | Fix: Apply truncation to each component before joining, or hash the excess portionResolve this thread when addressed — the
Hostile Review Thread Gateblocks while hostile-reviewer threads are unresolved (OMN-17492).
OMN-20299: onex delegate never sends a run with no caller lane
On the .201 dev lane (compose project
omnibase-infra,delegation_events, read-only), 651 of 699 rows in the 24 hours to 2026-10-01T12:24Z had a nullcaller_lane. The largest groups all came throughonex delegate: the worktree-prune classifier and triage (launchd jobs), the spread and liveness probes, CI-red classifiers, and Claude Code sessions that have a session id but no lane variable (this orchestrator's own session, 946b3f5f, among them). The resolver from OMN-19860 ended in "otherwise none", so each of those runs attributed to nobody.OMN-20288 makes each internal caller pass
--caller-lane. This PR is the resolver side, so that a caller that forgets is still named and the projection's nullcaller_lanemeans "did not come through this CLI".What changes
cli/delegate_caller.py: after--caller-lane, the lane variables and the registered worktree, the lane is derived, most explicit first:launchd:<label>fromXPC_SERVICE_NAMEwhen it holds a launchd job label (Terminal and app sessions carry0or anapplication.name there and are ignored);gha:<repo>:<workflow>under GitHub Actions;session:<uuid>from the Claude Code session;unattributed:<host>.Each derived name has a kind prefix no ledger lane uses, so it never counts as a lane's own delegation in the OMN-20299 share. The stderr
caller:line names the rule (fallback env XPC_SERVICE_NAME,fallback session,fallback host). The model docstring now says the resolver never leaves the lane None.Tests
tests/unit/cli/test_cli_delegate_caller_never_null.py(16 cases). It was committed first, RED (16 failed on the parent commit), then the fix (all pass).test_cli_delegate_caller_identity.pyand four intests/integration/cli/test_delegate_ticket_cli_omn19514.pyasserted the old "no lane" shape and now assert the derived lane. The ticket key assertions are unchanged.pytest tests/unit/cli tests/integration/cli/test_delegate_ticket_cli_omn19514.py -k "caller or ticket": 85 passed. ruff format and check clean,mypy --strictclean on the changed modules, pre-commit over the branch range clean.Lab proof (rule 24), .201 dev lane, compose project
omnibase-infraThis branch's
srcplaced ahead of the dispatch venv's install (omnibase_infra=0.38.62@shadowedin the identity line),onex delegate "... (OMN-20299 lab proof, caller fallback ...)" --task-type summarization --ticket OMN-20299 --bus kafka --lane dev --locus deployed-lane, no lane flag and no lane variable:fdffa5ba-0edb-4d18-aca9-29f4a0c24134, session setlane=session:946b3f5f-... (fallback session)caller_lane=session:946b3f5f-1b49-45bf-bb3d-a15f6158685f, local-heavy-reasoning on .2012c50482d-07d2-4c13-bdcc-0bdb3d7d124c, session set8df71f78-473f-4e82-b290-679a863c9168, session unsetlane=unattributed:stickybeatz-studio.local (fallback host)caller_lane=unattributed:stickybeatz-studio.local, session emptyThe released consumer accepted the metadata; no omnimarket change is needed.
Runtime-affecting: no. The CLI runs on the caller's host, not in a lane container.
Ticket: OMN-20299
Evidence-Ticket: OMN-20299
Evidence-Source: OCC#12145
Lab pool readback (OMN-18893)