Skip to content

fix(ingestion): stop absolute app.* imports resolving to graph in prod - #3780

Merged
PetrefiedThunder merged 3 commits into
mainfrom
claude/ingestion-absolute-app-imports
Nov 4, 2026
Merged

PetrefiedThunder merged 3 commits into
mainfrom
claude/ingestion-absolute-app-imports

Conversation

@PetrefiedThunder

@PetrefiedThunder PetrefiedThunder commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

This is the same class of bug as the CSV/EDI 500 fixed in #3774. In the consolidated server, the top-level app package is services/graph/app. So any from app.X import ... inside ingestion either fails or quietly loads graph's module instead. Unit tests put services/ingestion first on the path, so they never see it.

I checked each one inside the production image after import server.main:

Import Resolves to in prod Effect
stripe_billing/rate_limiting.py: app.config services/graph/app/config.py Graph's Settings has no redis_url, so the Stripe webhook rate limiter always falls back to per-worker memory, even with Redis healthy. Log: 'Settings' object has no attribute 'redis_url'
audit_export_log.py: app.chain_verification_job ModuleNotFoundError The verification fallback silently skips in-memory job results
labels/gs1_128.py: app.gs1_identifiers ModuleNotFoundError The module can't be imported in prod (it has no runtime caller yet)

Change

  • All three imports are now relative.

  • New test_no_absolute_app_imports.py parses services/ingestion/app and fails on any absolute app import or import_module("app...."). It allows the two that open work already removes:

    Delete those entries when that work lands.

Verification

Runtime. Production image built from this branch, with Postgres 17 and Redis 7.

  • Before (main): a signed-looking request to POST /api/v1/billing/webhooks logs Redis unavailable for stripe webhook rate limiting, using in-memory fallback ... 'Settings' object has no attribute 'redis_url'.
  • After: the same request logs no fallback warning, and Redis holds stripe_webhook:rate:<ip>. Inside the server, labels.gs1_128 and audit_export_log import, and the audit fallback runs.

Tests

  • The guard passes on this branch and fails against main's code.
  • gs1, Stripe, audit-export, rate-limit and Redis-retry suites: 647 passed, 6 skipped (the skips need a migrated Postgres).

🤖 Generated with Claude Code


Note

Medium Risk
Touches Stripe webhook rate limiting and audit fallback paths in production; behavior change is intentional (correct module resolution) but affects billing and observability under the monolith.

Overview
Fixes production mis-resolution of from app.* inside ingestion when the consolidated server loads multiple services that each expose a top-level app package (graph's app wins on sys.path).

Three imports are switched to relative paths: audit verification fallback now pulls chain_verification_job from .chain_verification_job instead of failing with ModuleNotFoundError; GS1-128 labels import gs1_identifiers via ..gs1_identifiers; Stripe webhook rate limiting loads ingestion config via ..config so redis_url is read correctly and Redis-backed limits work instead of always falling back to per-worker memory.

Adds test_no_absolute_app_imports.py, which AST-scans services/ingestion/app and fails on new absolute app / import_module("app...") usage, with a small allowlist for fixes landing in other PRs.

Reviewed by Cursor Bugbot for commit 75f874b. Bugbot is set up for automated code reviews on this repo. Configure here.

In the consolidated server every service dir is on sys.path and the
top-level ``app`` package is services/graph/app. Three ingestion modules
still imported their siblings as ``app.X``:

- stripe_billing/rate_limiting: ``app.config`` loaded graph's Settings,
  which has no redis_url, so the Stripe webhook rate limiter always fell
  back to per-worker memory ("'Settings' object has no attribute
  'redis_url'") even with Redis healthy.
- audit_export_log: ``app.chain_verification_job`` raised
  ModuleNotFoundError inside the verification fallback.
- labels/gs1_128: ``app.gs1_identifiers`` made the module unimportable
  (no runtime caller yet).

All three are now relative. A new AST guard test fails on any absolute
``app`` import or ``import_module("app....")`` in services/ingestion/app.
It allows the two that open work already removes (#3774 and
fix/csv-edi-ingest-monolith-imports); those entries should be deleted when
that work lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
regengine Ready Ready Preview Nov 2, 2026 11:09am UTC

Request Review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-31T09:41:40.935955Z
We couldn’t complete this review. Comment @codex review to try again.
b3c0587 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@cursor

cursor Bot commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: cb6bbc7a-5804-48ee-b2b0-6d68181a1334)

@coderabbitai

coderabbitai Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between e2c0073 and 75f874b.

Files selected for processing: 1
  • services/ingestion/app/labels/gs1_128.py

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 5 remain after this review.

Walkthrough

Three ingestion modules now use package-relative imports instead of absolute app imports. A new test scans Python files under the ingestion app for absolute app imports, with two exemptions for pending fixes. It reports matching file paths, line numbers, and modules.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: Minimal · up to 75f87

No actionable merge-blocking risk remains in the reviewed scope.

Architecture risk: Low · up to 75f87

The change affects 1 system.

Changed systems: services/ingestion

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — services/ingestion (service) was modified; 4 changed files map to changed impact.

Before / after behavior

  • observed — Modified behavior in services/ingestion/app/audit_export_log.py: _get_verification_fallback now imports the verification job store and lock from .chain_verification_job instead of app.chain_verification_job.
  • observed — Modified behavior in services/ingestion/app/stripe_billing/rate_limiting.py: _get_redis now imports get_settings from ..config rather than app.config.
  • observed — Modified behavior in services/ingestion/tests/test_no_absolute_app_imports.py: Added a module docstring describing the absolute-import problem in the consolidated server and why ingestion unit tests may not expose it.
  • observed — Modified behavior in services/ingestion/tests/test_no_absolute_app_imports.py: Added AST and path imports, the ingestion app directory path, and two (file, module) exemptions for pending fixes.
Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: preventing absolute app.* imports from resolving to the graph package in production.
Description check Passed The description explains the root cause, affected modules, code changes, test coverage, and runtime verification. It omits the template headings for Type of Change, Checklist, and Related Issues, but …
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description explains the root cause, affected modules, code changes, test coverage, and runtime verification. It omits the template headings for Type of Change, Checklist, and Related Issues, but it provides the critical implementation and validation details.

Full details: Docstring Coverage

Explanation

Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 4 functions across 4 files.

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

PR Blocker Checklist

Head SHA: 75f874b7f51a13478cce5afd401b747acbe2a83d

Status: Ready

  • All review threads resolved
  • No reviews requesting changes
  • No blocked review engines

…lute-app-imports

Signed-off-by: Christopher Sellers <1@christophersellers.com>
…lute-app-imports

Signed-off-by: Christopher Sellers <1@christophersellers.com>

@PetrefiedThunder PetrefiedThunder left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REVIEW: PASS pi 75f874b

Checked: the three absolute app.* imports (audit_export_log -> .chain_verification_job, labels/gs1_128 -> ..gs1_identifiers, stripe_billing/rate_limiting -> ..config) resolve to the same ingestion modules relatively, so the consolidated server can no longer pick up graph's app.config. The new AST guard catches from app..., import app... and import_module("app...").

Local (box, py3.12, requirements.lock): 701 passed, 6 skipped (guard + audit-export, stripe, rate-limit, sandbox and settings suites). CI: everything relevant is green; only Engine Review Pass is red, which is expected before this review.

Non-blocking: PENDING_ELSEWHERE lists edi_ingestion/routes.py / app.edi_ingestion.rejection_log. #3782 also removes that import, so drop the entry once either PR lands.

@PetrefiedThunder
PetrefiedThunder enabled auto-merge (squash) November 3, 2026 07:15
@PetrefiedThunder
PetrefiedThunder merged commit 8677d25 into main Nov 4, 2026
95 of 96 checks passed
@PetrefiedThunder
PetrefiedThunder deleted the claude/ingestion-absolute-app-imports branch November 4, 2026 07:44
PetrefiedThunder pushed a commit that referenced this pull request Nov 4, 2026
Brings in #3780 (relative imports in three ingestion modules plus the
test_no_absolute_app_imports guard), #3793, #3794, #3807 and #3809. Both
conflicts (stripe_billing/rate_limiting.py, webhook_compat.py) were the same
relative-import change made on both sides; main's wording kept. The new
guard test, the WI-02 bare-import guard, the route snapshot test and the
repository gates pass on the merged tree.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GyhDYGPjbfDzVjRUqkvz4B
PetrefiedThunder pushed a commit that referenced this pull request Nov 5, 2026
Brings in #3780 (relative imports in three ingestion modules plus the
test_no_absolute_app_imports guard), #3793, #3794, #3807 and #3809. Both
conflicts (stripe_billing/rate_limiting.py, webhook_compat.py) were the same
relative-import change made on both sides; main's wording kept. The new
guard test, the WI-02 bare-import guard, the route snapshot test and the
repository gates pass on the merged tree.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GyhDYGPjbfDzVjRUqkvz4B

This branch was successfully deployed

1 active deployment
Preview — 75f874b7 Deployed Nov 2, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant