Skip to content

test(rekognition): fix intermittent full-suite CI failure on the off-loop read test (remediates #1205) - #1208

Closed
groupthinking wants to merge 3 commits into
mainfrom
claude/determined-maxwell-u91xgx
Closed

test(rekognition): fix intermittent full-suite CI failure on the off-loop read test (remediates #1205)#1208
groupthinking wants to merge 3 commits into
mainfrom
claude/determined-maxwell-u91xgx

Conversation

@groupthinking

Copy link
Copy Markdown
Owner

Canonical issue

Closes #1204 (remediates the failing test CI gate on #1205)

This branch is a superset of #1205 (perf/rekognition-offloop): the same two Rekognition off-loop commits plus one test-only fix. It exists because the automation is constrained to develop on claude/determined-maxwell-u91xgx and may not push to #1205's head branch. A maintainer should either merge this in place of #1205, or apply the single-file fix below to #1205's branch and close whichever becomes redundant — the two must not both land.

Outcome

The Rekognition provider's local-image read is asserted to run off the event loop by a deterministic thread-id check. That assertion was flaky in the full CI suite (_read_file_bytes was never called) while passing in isolation and in the single-file run. This makes the assertion robust so the test gate is green, with no change to production behaviour.

Scope

  • Included: tests/unit/test_aws_rekognition_provider.pytest_local_image_read_runs_off_the_event_loop_thread now patches the running method's own __globals__ instead of a separately re-imported module alias.
  • Explicitly excluded: no change to aws_rekognition.py or any production code; the off-loop property assertion itself is unchanged.

Root cause

The test re-imported the provider module inside the test body and patched that alias, then invoked _prepare_image_input on a provider built from the module-level import. Under EventRelay's documented dual-import hazard (src.youtube_extension vs youtube_extension resolve to two distinct module objects with independent dicts), the alias can differ from the dict backing the running coroutine's bare _read_file_bytes lookup. The patch then silently no-ops, the real read runs, and the recorder never fires — exactly the observed assert 'thread_id' in {}.

The fix derives the patch target from the provider actually under test — type(provider)._prepare_image_input.__globals__. A function's __globals__ is frozen to its defining module at def-time and is precisely the dict the name lookup uses, so the patch is identical to that dict by construction and immune to import-path / module-identity mismatch.

Risk

  • Risk level: low
  • Failure mode: none in production — test-only change; the strengthened assertion still fails loudly if the read regresses onto the loop thread.
  • Rollback: revert this single commit.

Verification

Tied to head 2997873:

Production evidence

Not applicable — test-only change. The underlying perf change's production import path is documented in #1205.

Agent handoff

  • One canonical issue is linked
  • No competing PR implements the same issue — perf(cloud-ai): run AWS Rekognition boto3 calls off the event loop #1205 is the sibling; see note above, they must be de-duplicated by a human.
  • Acceptance criteria are satisfied
  • Required checks pass on the current head — pending CI
  • Human decision is requested only for the merge itself (protected main)

Generated by Claude Code

groupthinking and others added 3 commits August 1, 2026 17:54
boto3 is a synchronous SDK. Every Rekognition call in AWSRekognition was
issued directly inside an `async def`, so each one blocked the event loop
for a full network round-trip. `_wait_for_job_completion` is the worst
case: it polls every 5s for up to 600s, so a single video analysis could
stall the loop up to 120 times.

All 14 boto3 calls now dispatch via `await asyncio.to_thread(...)`, and
the local-image read in `_prepare_image_input` goes through a new
module-level `_read_file_bytes` helper on the same path.

- 89 pre-existing tests pass with zero edits
- 6 new heartbeat tests (`TestRekognitionDoesNotBlockEventLoop`); 5 of the
  6 discriminate, proven by reverting both dimensions simultaneously
  (5 targeted failures / 90 passed)
- ruff: exact parity with origin/main (8 pre-existing findings, 0 added)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…elapsed ticks

The heartbeat form of this one test failed on CI. Unlike the four boto3 tests,
which drive a controllable 0.12s mock, the local file read is a few
microseconds of real work, so "did the loop tick while it ran" is a
load-sensitive proxy rather than a property.

Assert the property directly instead: record `threading.get_ident()` inside
`_read_file_bytes` and require it to differ from the thread running the event
loop. That is exactly what "dispatched off the loop" means, needs no sleeps,
and cannot flake under runner contention.

- 95 tests pass (89 pre-existing, unmodified, + 6 new)
- Non-vacuity: calling `_read_file_bytes` directly instead of via
  `asyncio.to_thread` yields exactly 1 targeted failure / 94 passed
- Suite runtime for the file drops to 0.85s (the 0.12s sleep is gone)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…mported alias

The off-loop assertion for the local image read failed intermittently in the
full CI suite ("_read_file_bytes was never called") while passing in isolation
and in the single-file run.

Root cause: the test re-imported the provider module inside the test body and
patched that alias, then called `_prepare_image_input` on a provider built from
the module-level import. Under EventRelay's dual-import hazard
(`src.youtube_extension` vs `youtube_extension` resolve to two distinct module
objects with independent dicts), the alias can differ from the dict backing the
running coroutine's bare `_read_file_bytes` lookup — so the patch silently
no-ops, the real read runs, and the recorder never fires.

Fix: derive the patch target from the provider we actually call
(`type(provider)._prepare_image_input.__globals__`). A function's `__globals__`
is frozen to its defining module at def-time and is exactly the dict the
name lookup uses, making the patch identical to that dict by construction and
immune to import-path / module-identity mismatch. The off-loop property
assertion is unchanged.
@vercel

vercel Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v0-uvai Ready Ready Preview, v0 Aug 1, 2026 11:22pm

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • [‘architecture-gap’, ‘bug’, ‘ci-cd’, ‘ci/cd’, ‘copilot-rabbit’, ‘documentation’, ‘duplicate’, ‘enhancement’, ‘frontend’, ‘github_actions’, ‘good first issue’, ‘help wanted’, ‘high-priority’, ‘invalid’, ‘javascript’, ‘ml-model’, ‘needs-triage’, ‘pipeline-critical’, ‘placeholder-code’, ‘priority:high’, ‘python’, ‘python:uv’, ‘question’, ‘styling’, ‘tests’, ‘v0’]

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e28b20d7-7639-4f5d-a2b0-a330fc6e5022

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 2997873.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

None

@github-actions github-actions Bot added the python label Aug 1, 2026
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

Agent Completion Truth Gate: BLOCKED

Reasons: invalid_payload

Machine-readable verdict
{
  "details": {
    "invalid_fields": [
      "policy.agent_login",
      "policy.run_id"
    ]
  },
  "reasons": [
    "invalid_payload"
  ],
  "verdict": "blocked"
}

Workflow evidence

Copy link
Copy Markdown
Owner Author

Remediation status (head 2997873)

Fixed — the one real failure. The test gate on #1205 was red solely on TestRekognitionDoesNotBlockEventLoop::test_local_image_read_runs_off_the_event_loop_thread (_read_file_bytes was never called). Root cause: the test patched a re-imported module alias that, under EventRelay's src.youtube_extension vs youtube_extension dual-import, can differ from the dict backing the running coroutine's bare _read_file_bytes lookup — the patch then no-ops. This branch patches the running method's own __globals__ (derived from the provider under test), which is the exact dict the lookup uses. Verified locally: full file 95/95; reproduced the module-identity mismatch and confirmed the new form records the off-loop thread with bytes intact. Production code is untouched.

Not fixed — pre-existing systemic gates, unrelated to this one-file test diff. Explaining rather than papering over:

Merge posture: base main is protected and this PR carries no automerge label, so per policy the merge itself is a human decision — I have not auto-merged. Terminal state: awaiting maintainer sign-off, with the sibling #1205 to be de-duplicated (merge one, drop the other; they must not both land).


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Update: the test CI gate is now green on head 2997873 (run) — the fix is confirmed on CI, not just locally. The only remaining reds are the two pre-existing systemic gates noted above (gitleaks uv.lock false positive; agent-completion trust-payload), neither caused by this diff. Ready for maintainer sign-off / de-duplication against #1205.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Contained as a duplicate repair. Its proven __globals__ patching approach is already present on canonical PR #1205 at exact head af04aedb59d5b46871c46ab945536faa58c97d91, using patch.dict for automatic restoration. Exact-head CI is green and CodeRabbit independently verified the repair. Closing this PR unmerged; branch claude/determined-maxwell-u91xgx and commit 299787303706ebe77ac470c07ef03bad3b9e3213 are preserved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(cloud-ai): AWS Rekognition blocks the event loop on 14 synchronous boto3 calls

2 participants