Repository navigation
fix(OMN-19654): the delegate-skill claim store lives under the runtime's declared state root, not ~/.omninode - #2917
Merged
Conversation
…e's declared state root, not ~/.omninode On the onex-lab k3s lane the deployed node_delegate_skill_orchestrator runs with readOnlyRootFilesystem and HOME=/. With no projection binding overlay on the pod, the OMN-18887 claim port fell back to a SQLite file derived from Path.home(), so every bus delivery tried to create /.omninode and terminalized OSError [Errno 30] Read-only file system. No delegation completed on the lane. The fallback claim store now resolves from ONEX_STATE_DIR, then ONEX_STATE_ROOT (both declared by the runtime manifests over a writable volume), through a new omnimarket.config.state_root resolver that raises a named OnexStateRootUnconfiguredError when neither is set. Resolution is deferred to the first claim, which only a bus delivery makes, so the bus-less CLI that builds the same handler and never claims is unaffected.
✅ Architectural Review — PASSEDErrors: 0 What this checks
No architectural violations found. Static architectural lint — no model inference (OMN-14176). |
onexbot-occ-writer Bot
added a commit
to OmniNode-ai/onex_change_control
that referenced
this pull request
Sep 25, 2026
…nimarket#2917 The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited. Ticket: OMN-16859 (AC3b) Onex-Workflow: OCC Receipt Runner Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/36177065633
✅ Hostile Reviewer — PASSEDBlocking findings (critical/error): 0 Gate semantics
Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8524) |
jonahgabriel
enabled auto-merge (squash)
September 25, 2026 19:14
…ore once The deferred sqlite store was resolved without synchronization, so the first claims on a fresh port, arriving together from in-flight records, each built their own adapter. Resolution now happens under a lock with a double check, and the missing-resolver case raises instead of relying on an assert. New test: eight concurrent first claims of one delivery resolve the store once and exactly one wins (RED 8 resolutions, GREEN 1).
onexbot-occ-writer Bot
added a commit
to OmniNode-ai/onex_change_control
that referenced
this pull request
Sep 25, 2026
…nimarket#2917 The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited. Ticket: OMN-16859 (AC3b) Onex-Workflow: OCC Receipt Runner Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/36195123053
jonahgabriel
pushed a commit
to OmniNode-ai/onex_change_control
that referenced
this pull request
Sep 25, 2026
…imarket#2917 (#11329) * evidence(OMN-19654): author OCC companion for OmniNode-ai/omnimarket#2917 OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 8718cdd3ffe4da07d89250e69a9ee07df4f207d4. * evidence(OMN-19654): self-bind OCC#11329 + rebind contract_sha256 * evidence(OMN-16859): executed test_passes receipts for OmniNode-ai/omnimarket#2917 The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited. Ticket: OMN-16859 (AC3b) Onex-Workflow: OCC Receipt Runner Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/36177065633 * evidence(OMN-16859): executed test_passes receipts for OmniNode-ai/omnimarket#2917 The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited. Ticket: OMN-16859 (AC3b) Onex-Workflow: OCC Receipt Runner Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/36195123053 --------- Co-authored-by: omnimarket-bot <bot@omninode.ai> Co-authored-by: onexbot-occ-writer[bot] <307849072+onexbot-occ-writer[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This pull request resolves defect OMN-19654, which gates OMN-18307 AC4. The defect caused the deployed node_delegate_skill_orchestrator on the onex-lab k3s lane (host .201, namespace onex-dev) to terminalize every bus delegation with OSError [Errno 30] Read-only file system: '/.omninode' (ONEX_CORE_095_HANDLER_EXECUTION_ERROR). Correlation IDs 73d3d9b9-9f2e-418a-8309-de304d892b27 and 406dbd74-6c5b-4ed4-bd90-22ab30dc5a94 are associated with the failure in pod omninode-runtime-effects.
Root cause
The OMN-18887 claim port (ports/port_delegation_claim.py, resolve_delegation_claim_store) falls back to SqliteDatabaseAdapter(default_claim_db_path()) when no projection binding overlay is set. The default_claim_db_path is derived from default_evidence_db_path(), which resolves to Path.home()/.omninode/delegation/delegation.sqlite (projection/sqlite_database.py:37-39). Because SqliteDatabaseAdapter._connect creates the parent directory, a read-only root filesystem with HOME=/ results in EROFS on every delivery.
Change
A new module src/omnimarket/config/state_root.py introduces resolve_onex_state_root(purpose=...), which reads ONEX_STATE_DIR and then ONEX_STATE_ROOT. It raises OnexStateRootUnconfiguredError naming both keys if neither is set, with no home, cwd, or temp fallback. The default_claim_db_path now returns /delegation/delegation_claims.sqlite. DelegationClaimPort gains a keyword resolve_database factory, ensuring the sqlite fallback is resolved at the first claim rather than at handler construction. This allows the bus-less CLI, which builds the same handler but never claims, to operate without a state root. The attested-write type check was moved into _require_attested_write and continues to run on both paths. The Postgres path, used when the binding overlay is set, remains unchanged. No manifest change is required for onex-lab, as the onex-dev runtime base already declares ONEX_STATE_DIR and ONEX_STATE_ROOT over the /app/data emptyDir, and the prod runtime ConfigMap declares ONEX_STATE_ROOT.
Every writer with the same default
Other writers using the same Path.home()/.omninode default were not changed in this PR because they hold user data (evidence rows, minted tenant identity, BYOK credentials) on the bus-less CLI path, and moving them would relocate existing user data. These include projection/sqlite_database.py:37 default_evidence_db_path (with callers at nodes/node_delegate_skill_orchestrator/ports/evidence_db_resolution.py:101, local_deployment/tenant_identity.py:239, inference/local_byok_credential_adapter.py, projection/sqlite_metering_reader.py, and cli/cli_local.py) and omniclaude src/omniclaude/delegation/sqlite_adapter.py:25. Read-only overlay lookups that do not write include routing/delegation_backend_resolution.py:70, adapters/llm/bifrost/config_loader_bifrost_delegation.py:59, adapters/adk/adapter_adk_invoke.py:73, and delegation/swe_discriminator/model_client.py:43.
Tests
The test file tests/unit/nodes/node_delegate_skill_orchestrator/test_claim_store_state_root_omn19654.py contains 6 cases selected by -k omninode_readonly_rootfs. These cases verify that claims land under ONEX_STATE_DIR with an unwritable HOME, that ONEX_STATE_ROOT is used when ONEX_STATE_DIR is unset, that ONEX_STATE_DIR takes precedence, that unset or blank state roots refuse at claim with OnexStateRootUnconfiguredError while construction succeeds, and that a second port instance loses a redelivered claim. Before the fix, all 6 cases failed (5 with PermissionError creating /.omninode and 1 on the missing module). After the fix, 6 cases passed. The entire tests/unit/nodes/node_delegate_skill_orchestrator directory shows 257 passed and 3 skipped. Golden chain, structured terminal truth, claims migration, and evidence-db resolution tests show 74 passed. ruff, mypy --strict, and pre-commit checks are clean.
Lab readback
A pre-PR probe was run on the onex-lab lane (.201 k3s, namespace onex-dev, pod omninode-runtime-effects, image onex-lab/omninode-runtime:20260925T175853Z-a6afd007, omnimarket 0.4.219) as a separate python process via kubectl exec, without changing the running consumer or image. The negative control using the installed unfixed port reproduced the lane defect with OSError errno=30 (EROFS) at '/.omninode'. Candidate modules loaded from this branch's source in the same pod with ONEX_STATE_DIR=/tmp/omn19654-probe resulted in the first claim winning true, redelivery winning false, and the db file being created under the state root, with /.omninode not existing. When ONEX_STATE_DIR was removed, the candidate resolved ONEX_STATE_ROOT=/app/data/.onex_state and wrote there; the probe file was subsequently removed and /app/data was restored to its prior listing.
Runtime-affecting
Yes. This change alters the deployed delegate-skill orchestrator's claim store location.
Tickets
OMN-19654 is the primary ticket, serving as the gate for OMN-18307 AC4. An end-to-end delegation completing on the onex-lab lane is not yet proven; OMN-19654 AC1 and OMN-18307 AC4 will be read back after this merge and the lab lane is rebuilt via the deploy agent. A follow-up issue, not included in this PR, notes that while the node contract declares delegate_skill_command_claims in the application Postgres database (db_io, omninode_internal schema) and the table exists in the lab omnidash_analytics database, no runtime pod sets the projection binding overlay, causing deployed claims to use the per-pod sqlite fallback rather than the contract-declared Postgres table.
Body drafted by
onex delegaterun 65609ce9-ff36-46a7-ba21-015b30d2b073 (Qwen3.8-27B, receipt status success) and checked against the facts above by the authoring lane (omn19654-rofs-fix-83).Evidence-Ticket: OMN-19654
Evidence-Source: OCC#11329