Skip to content

fix(OMN-15749): deploy-agent docker fixture absorbs daemon/registry timeouts - #2826

Merged
jonahgabriel merged 1 commit into
devfrom
jonah/omn-15749-deploy-agent-docker-fixture-timeout-resilience
Aug 21, 2026
Merged

jonahgabriel merged 1 commit into
devfrom
jonah/omn-15749-deploy-agent-docker-fixture-timeout-resilience

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Aug 21, 2026 •

Copy link
Copy Markdown
Collaborator

Ticket

OMN-15749 — CI: OMN-15181 deploy-agent digest-verification fixture tests time out on real docker create/docker rm -f under runner contention.

Problem

scripts/deploy-agent/tests/unit/test_executor_digest_verification_image_id_omn15181.py builds a real, disposable busybox container to pin actual docker inspect semantics. All four of its docker calls already passed check=False — the author's intent was that a non-zero exit is the fixture's business to interpret, not an automatic test failure. But subprocess.run raises TimeoutExpired regardless of check=, so the one failure mode the fixture could not absorb is the one that actually fires on the shared self-hosted fleet: docker daemon and registry contention.

Three separate PRs have been red on this, none of them related in content:

  • infra#2790, job 96427221459 (2026-08-20T12:54:17Z) — subprocess.TimeoutExpired: Command ['docker', 'pull', 'busybox:latest'] timed out after 90 seconds, erroring both tests in the class at fixture setup. This is the live signature that motivated the fix.
  • infra#2684, job 93142435731 — docker rm -f ... timed out after 30 seconds at teardown, erroring an otherwise-passing test.
  • infra#2685, job 93142579498 — docker create --name ... busybox:latest timed out after 30 seconds, erroring both tests at setup.

Deploy Agent Tests (OMN-15378) / deploy-agent-tests is a required merge gate, so each occurrence blocks a PR on a condition that says nothing about the code under test.

Fix

Route all four docker calls through a _docker() helper that collapses a timeout to None, putting the timeout back under the fixture's control:

  • docker pull is a best-effort warm-up. A timeout no longer errors both tests — the image is usually already cached on the runner, and docker create is the real gate.
  • docker create timing out, or failing because busybox never became available locally, skips. That is an environment condition, not a statement about docker inspect semantics, and the class is already @requires_docker-gated on exactly that kind of condition. Any other non-zero exit still raises AssertionError, so a genuine docker semantic is not swallowed.
  • docker rm -f timing out at teardown no longer errors a passing test. The container name is uuid-unique, so a leaked container cannot collide with a later run.

Create/remove budgets raised 30s → 90s/60s per the ticket's option 1, same rationale as OMN-8535 (deploy-agent build timeout 300s → 900s) and OMN-7871.

This is the same reasoning as the already-merged OMN-16317 fix (infra#2819, commit 0289995d7), which applied it to the sibling test_bare_sha256_is_an_invalid_pull_reference negative test in this same module. That fix covered one call site; this one closes the remaining live-network docker calls in the file.

dod_evidence

Branch behaviour proven directly. All five fixture paths were driven with a stubbed subprocess.run (throwaway probe, not committed):

Scenario Result
docker pull times out, create OK fixture yields — pull timeout is no longer fatal
docker create times out Skipped, not an error
docker create fails "No such image" Skipped, not an error
docker create fails "conflict: name already in use" AssertionError — real errors still surface
happy path yields; calls are pull/90s, create/90s, rm/60s

The fourth row is the important one: the gate is not weakened, only the environment-conditional paths are.

Local verification:

  • uv run --project scripts/deploy-agent --extra dev pytest scripts/deploy-agent/tests -q → 198 passed, 8 skipped (the 8 skips are the @requires_docker classes; this Mac has no docker daemon).
  • mypy on the changed file: 11 errors before, 11 after — no new error introduced. All 11 pre-date this change and are outside CI's mypy scope (ci.yml runs mypy src/omnibase_infra).
  • uv run ruff format / ruff check on scripts/deploy-agent/: clean.
  • pre-commit run --all-files: 92 hooks, 0 failures.
  • Pre-push governed impacted-test selector: 1685 passed, 6 skipped in 272s.

CI acceptance signal: on the self-hosted runners docker is reachable, so Deploy Agent Tests must report 203 passed — the same count as a healthy pre-change run. A drop to 201 passed, 2 skipped would mean the fixture is wrongly skipping on a healthy runner and this PR should not merge.

Context

Found while diagnosing two "recurring CI failure clusters" across open omnibase_infra PRs. The other cluster (Kafka Schema Handshake) is entirely environmental — runner-fleet git fetch failures downstream of the OMN-16284 burst incident — and needs no code change; that analysis is recorded on OMN-16284 and OMN-16030. This fixture defect was the only genuine mechanical root fix in either cluster.

Evidence-Source: OCC#6819
Evidence-Ticket: OMN-15749

…ry timeouts

Every docker call in the OMN-15181 real_container fixture already passed
check=False, so a non-zero exit was the fixture's business to interpret.
But subprocess.run raises TimeoutExpired regardless of check=, so the one
failure mode the fixture could not absorb was the one that actually fires
on the shared self-hosted fleet: docker daemon and registry contention.

Route all four docker calls through a _docker() helper that collapses a
timeout to None, putting it back under the fixture's control:

- docker pull is a best-effort warm-up; a timeout no longer errors both
  tests (the image is usually already cached and docker create is the
  real gate).
- docker create timing out, or failing because busybox never became
  available locally, skips -- that is an environment condition, not a
  statement about docker inspect semantics. Any OTHER non-zero exit
  still raises, so a genuine docker semantic is not swallowed.
- docker rm -f timing out at teardown no longer errors a passing test;
  the container name is uuid-unique so a leaked container cannot collide.

Create/remove budgets raised 30s -> 90s/60s per the ticket's option 1,
same rationale as OMN-8535 and OMN-7871.

Same reasoning as the merged OMN-16317 fix (#2819), which applied it to
the sibling bare-sha256 negative test in this directory; this closes the
remaining live-network docker calls in the module.

Refs: OMN-15749
@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your current included review allowance is based on your included PR review attempts over the past 7 days.

Next review available in: 37 minutes

Limit details: You’ve used the included review currently available. Your 117 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d2e6e23f-2d53-4a84-af40-f3410147c3d4

📥 Commits

Reviewing files that changed from the base of the PR and between 2444b99 and cc972ae.

📒 Files selected for processing (1)
  • scripts/deploy-agent/tests/unit/test_executor_digest_verification_image_id_omn15181.py

Comment @coderabbitai help to get the list of available commands.

@onexbot-occ-writer

Copy link
Copy Markdown
Contributor

OCC autobind did not mint a companion for this PR: no changed-file candidate could be proven RED against the merge base, and emitting a PR-existence probe instead would be non-falsifiable evidence (OMN-15247). Hand-authored evidence is required.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Hostile Reviewer — PASSED

Blocking findings (critical): 0
Total findings: 0
Models succeeded: qwen3-review,qwen3-review-b


Gate semantics (pilot phase)

Verdict Meaning Blocks merge?
passed No critical findings No
blocked CRITICAL findings found Yes
degraded All models unavailable (infra) No (pilot)

Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8468/OMN-8524)

jonahgabriel added a commit to OmniNode-ai/onex_change_control that referenced this pull request Aug 21, 2026
#6819)

* evidence(OMN-15749): OCC companion for OmniNode-ai/omnibase_infra#2826

Hand-authored because OCC autobind formally DECLINED this PR. onexbot-occ-writer
commented on omnibase_infra#2826 at 2026-08-21T04:48:24Z with marker
`occ-autobind-no-red-derivable:2826`: "no changed-file candidate could be proven
RED against the merge base, and emitting a PR-existence probe instead would be
non-falsifiable evidence (OMN-15247). Hand-authored evidence is required."
That satisfies the pr-landing-ceremony §1.3 precondition for hand-authoring.

The probe is content-bound, not a PR-existence check, so it clears the
evidence-admissibility gate on all three axes:

- EXECUTED — `gh api` is on the allowlist; bare `gh pr view` is not.
- FALSIFIABLE — verified GREEN at head cc972ae1a and RED at merge-base
  2444b99f1, where the fixture still calls subprocess.run directly and
  _PULL_TIMEOUT_SECONDS does not exist. Both directions run before the
  receipt was written; the receipt records the real exit status.
- OUTSIDE ITS OWN DIFF — it reads omnibase_infra, which this OCC PR does
  not author.

Uses the OMN-15411 Rule E pipe-safe shape (capture into "$body", then pipe to
grep) with the ?ref= URL single-quoted, and `grep -qF --` because the needle
would otherwise be parsed as an option.

Refs: OMN-15749, omnibase_infra#2826, OMN-15247 (admissibility), OMN-13888
(per-entry hash), OMN-15411 (pipe-safe probe shape)

* evidence(OMN-15749): add the OCC self-bind entry for PR #6819

occ-preflight failed post-recovery with reason=pr_ticket_mismatch:

    no PASS receipt for one or more tickets binds to PR #6819
    or one of its commit SHAs: OMN-15749

The product-PR receipt was found and its hashes verified clean
(missing_or_nonpass_receipts and stale_receipt_bindings were both empty) --
the gap was purely binding. That receipt carries pr_number 2826, the
omnibase_infra PR, so nothing bound OMN-15749 to this OCC PR itself, which
is what the eligibility checker resolves against.

Every other OCC companion carries such an entry (occ-self-bind-pr-6805,
-6809, -6810, -6811); I omitted it because the worked example I copied from,
OCC#6814, appends to a contract whose self-bind another PR had already
landed. A companion that CREATES its contract needs its own.

Adds occ-self-bind-pr-6819 following the established convention, with the
probe run live and the real stdout recorded. Also updates the product-PR
receipt's contract_sha256, which necessarily moved when the file gained an
entry -- both contract_entry_sha256 values are unchanged, per OMN-13888.

Refs: OMN-15749, omnibase_infra#2826, OMN-13888
@jonahgabriel
jonahgabriel merged commit f06fa07 into dev Aug 21, 2026
210 of 230 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-15749-deploy-agent-docker-fixture-timeout-resilience branch August 21, 2026 09:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant