Skip to content

refactor: rename 'upstream sync' to 'remote sync' / 'Sync from Remote'#33

Merged
damienriehl merged 3 commits intomainfrom
fix/rename-upstream-to-remote
Apr 6, 2026
Merged

refactor: rename 'upstream sync' to 'remote sync' / 'Sync from Remote'#33
damienriehl merged 3 commits intomainfrom
fix/rename-upstream-to-remote

Conversation

@JohnRDOrazio
Copy link
Copy Markdown
Member

@JohnRDOrazio JohnRDOrazio commented Apr 5, 2026

Summary

  • Rename all "upstream sync" terminology to "remote sync" throughout the backend
  • File renames: upstream_sync.pyremote_sync.py across routes, models, schemas, and services
  • Route paths: /upstream-sync/remote-sync
  • Class/type names: UpstreamSync*RemoteSync*
  • Field names: upstream_commit_sharemote_commit_sha
  • API docs tag: "Sync from Remote"
  • Alembic migration to rename database table and columns

Closes #31

Related

Test plan

  • alembic upgrade head succeeds (table/column rename)
  • alembic downgrade -1 succeeds (revert)
  • All remote sync endpoints respond at /remote-sync paths
  • API docs show "Sync from Remote" tag

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor
    • Sync terminology updated from "Upstream" to "Remote" across all APIs
    • Endpoint paths changed from /upstream-sync/* to /remote-sync/*
    • JSON field names updated (e.g., upstream_commit_sharemote_commit_sha)

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 5, 2026

Warning

Rate limit exceeded

@damienriehl has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 38 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 5 minutes and 38 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d730ddad-5fa1-403c-93ca-563e75c9ca4e

📥 Commits

Reviewing files that changed from the base of the PR and between 8e45412 and d04800a.

📒 Files selected for processing (10)
  • alembic/versions/r1s2t3u4v5w6_rename_upstream_to_remote_sync.py
  • ontokit/api/routes/__init__.py
  • ontokit/api/routes/pull_requests.py
  • ontokit/api/routes/remote_sync.py
  • ontokit/models/__init__.py
  • ontokit/models/remote_sync.py
  • ontokit/schemas/remote_sync.py
  • ontokit/services/pull_request_service.py
  • ontokit/services/remote_sync_service.py
  • ontokit/worker.py
📝 Walkthrough

Walkthrough

This PR systematically renames terminology throughout the codebase from "upstream sync" to "remote sync" across database schema, ORM models, API schemas, routes, services, and background workers, including database migration, model/schema class renames, API endpoint path updates, and background task name changes.

Changes

Cohort / File(s) Summary
Database Migration
alembic/versions/r1s2t3u4v5w6_rename_upstream_to_remote_sync.py
New migration renames table upstream_sync_configs to remote_sync_configs, column upstream_commit_sha to remote_commit_sha in both configs and sync_events, and updates related index names. Includes both upgrade and downgrade operations.
ORM Models & Schemas
ontokit/models/__init__.py, ontokit/models/remote_sync.py, ontokit/schemas/remote_sync.py
Renames ORM class UpstreamSyncConfig to RemoteSyncConfig with updated __tablename__, column upstream_commit_sha to remote_commit_sha, and foreign key references. Updates Pydantic schemas similarly: UpstreamSyncConfig* classes to RemoteSyncConfig* with matching field renames. Updates module exports to source from new remote_sync module.
API Routes
ontokit/api/routes/__init__.py, ontokit/api/routes/remote_sync.py, ontokit/api/routes/pull_requests.py
Updates route registration from upstream_sync to remote_sync with tag change. Renames endpoint paths from /upstream-sync to /remote-sync, function names get_upstream_sync_config() to get_remote_sync_config(), etc. Updates webhook-triggered sync lookup to query RemoteSyncConfig and enqueue run_remote_check_task.
Service Layer
ontokit/services/remote_sync_service.py, ontokit/services/pull_request_service.py
Renames UpstreamSyncService to RemoteSyncService and factory function get_upstream_sync_service() to get_remote_sync_service() with updated return types and error messages. Updates helper method name in pull_request_service from _sync_upstream_config_for_webhooks() to _sync_remote_config_for_webhooks() with model swap from UpstreamSyncConfig to RemoteSyncConfig.
Background Worker
ontokit/worker.py
Renames background task function from run_upstream_check_task() to run_remote_check_task(), Redis pub/sub channel from upstream_sync:updates to remote_sync:updates, and event notification type strings from upstream_check_* to remote_check_*. Updates model imports and all internal references to use RemoteSyncConfig.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related issues

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • damienriehl

Poem

🐰 From upstream we hop to remote skies,
Renaming paths where the sync-daemon flies,
Tables and tasks all rebranded with care,
No forks in the garden, just repos we share! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main refactoring change: renaming 'upstream sync' to 'remote sync' terminology throughout the codebase.
Linked Issues check ✅ Passed All coding requirements from issue #31 are met: routes renamed, URL paths updated, schemas/models/services renamed (UpstreamSync* → RemoteSync*), database migration added, API tag updated.
Out of Scope Changes check ✅ Passed All changes are directly related to the refactoring scope: terminology updates, file renames, route paths, schemas, models, services, and database migration. No unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/rename-upstream-to-remote

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
ontokit/worker.py (1)

689-697: ⚠️ Potential issue | 🟠 Major

Route terminal setup errors through the failure path.

Lines 689-697 and 722-733 return a {"status": "failed"} payload instead of raising. That bypasses the except block, so no remote_check_failed pubsub event is emitted, and ontokit/services/remote_sync_service.py will still surface the job as completed because it only marks raised jobs as failed.

Also applies to: 722-733

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ontokit/worker.py` around lines 689 - 697, The current early-return paths
that return {"status": "failed", ...} (e.g., when config is falsy or project is
not found in the block using config, project_result and project) must instead
raise an exception so the outer except can catch it and emit the
remote_check_failed pubsub event; replace those returns with a specific
exception (or RuntimeError) raised with the same error message, and apply the
same change to the analogous checks in the later block (the 722-733 section) so
ontokit/services/remote_sync_service.py will treat the job as failed and publish
the failure event.
ontokit/services/remote_sync_service.py (2)

157-171: ⚠️ Potential issue | 🟠 Major

Only persist checking after the job is queued.

Lines 158-163 commit the state flip before verifying the queue is available. If queue acquisition or enqueueing fails, this path exits before the job is None fallback and the config stays stuck in checking.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ontokit/services/remote_sync_service.py` around lines 157 - 171, Currently
the code sets config.status="checking" and commits before acquiring the queue
and enqueueing the job, which can leave config stuck if get_arq_pool() or
pool.enqueue_job(...) fails; change the flow in the method that enqueues
run_remote_check_task so that you first attempt to acquire the pool
(get_arq_pool()) and enqueue the job (pool.enqueue_job(str(project_id))), and
only after a successful enqueue (job is not None) set config.status="checking"
and call await self.db.commit(); additionally, catch exceptions from
get_arq_pool() and enqueue_job and in those error paths set
config.status="error", populate config.error_message, and commit via await
self.db.commit() before raising the HTTPException so the DB never remains in a
stale "checking" state.

93-105: ⚠️ Potential issue | 🟠 Major

Reject partial updates when no remote-sync config exists.

Lines 95-99 build a new RemoteSyncConfig from RemoteSyncConfigUpdate. If the request only includes partial fields, the write falls through to the non-null repo_owner, repo_name, and file_path columns and fails as a DB integrity error instead of a clean 4xx.

Suggested guard
         if config is None:
             # Create new config — require full payload
             if isinstance(data, RemoteSyncConfigUpdate):
-                # Treat partial update on non-existent config as create with defaults
-                config = RemoteSyncConfig(project_id=project_id)
-                for field, value in data.model_dump(exclude_unset=True).items():
-                    setattr(config, field, value)
+                raise HTTPException(
+                    status_code=status.HTTP_400_BAD_REQUEST,
+                    detail="Remote sync is not configured; send a full create payload first",
+                )
             else:
                 config = RemoteSyncConfig(
                     project_id=project_id,
                     **data.model_dump(),
                 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ontokit/services/remote_sync_service.py` around lines 93 - 105, When creating
a new RemoteSyncConfig from an update payload in remote_sync_service.py (the
branch that checks isinstance(data, RemoteSyncConfigUpdate)), validate that all
required fields (e.g., repo_owner, repo_name, file_path) are present in
data.model_dump(exclude_unset=True); if any are missing, raise a 4xx-style error
(e.g., HTTPException/ValueError) instead of constructing a partial
RemoteSyncConfig and writing to the DB. Update the logic around
RemoteSyncConfig(project_id=project_id) to check the dumped keys first and only
populate defaults when all required fields exist; otherwise return a clear
client error indicating the missing required fields.
ontokit/api/routes/pull_requests.py (1)

681-686: ⚠️ Potential issue | 🟠 Major

Don't leave webhook-triggered syncs stuck in checking.

Lines 682-686 commit sync_config.status = "checking" before the background job is safely queued. If queue acquisition or enqueueing fails, the webhook can error out after persisting that state, which leaves the config stuck in checking and blocks later manual checks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ontokit/api/routes/pull_requests.py` around lines 681 - 686, The code sets
sync_config.status = "checking" and commits before acquiring the ARQ pool and
enqueueing the background task, which can leave the config stuck if enqueueing
fails; change the flow so you only persist the "checking" status after
successfully obtaining get_arq_pool() and awaiting
pool.enqueue_job("run_remote_check_task", str(project_id)), or alternatively
wrap the pool acquisition/enqueue in a try/except and on failure reset
sync_config.status (or rollback) and commit that change; reference
sync_config.status, get_arq_pool(), pool.enqueue_job, and service.db.commit to
locate and update the logic.
🧹 Nitpick comments (3)
ontokit/schemas/remote_sync.py (2)

66-67: Use Pydantic v2 model_config instead of class Config.

The class Config syntax is Pydantic v1 style. For Pydantic v2 compliance, use model_config = ConfigDict(from_attributes=True).

♻️ Proposed fix
 from pydantic import BaseModel, Field
+from pydantic import ConfigDict
-    class Config:
-        from_attributes = True
+    model_config = ConfigDict(from_attributes=True)

Based on learnings: "Use Pydantic v2 for request/response validation with strict validation and computed fields".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ontokit/schemas/remote_sync.py` around lines 66 - 67, Replace the Pydantic v1
"class Config" usage with a Pydantic v2 model configuration: remove the inner
class Config and add a module-level or model-level attribute model_config =
ConfigDict(from_attributes=True); also import ConfigDict from pydantic at the
top of the file so the model uses Pydantic v2 settings. Target the model that
currently defines "class Config" (the Config inner class) and replace it with
"model_config" and the ConfigDict import.

83-84: Same Pydantic v2 migration needed here.

Apply the same model_config = ConfigDict(from_attributes=True) pattern to SyncEventResponse.

♻️ Proposed fix
-    class Config:
-        from_attributes = True
+    model_config = ConfigDict(from_attributes=True)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ontokit/schemas/remote_sync.py` around lines 83 - 84, Replace the old
Pydantic v1 style inner class Config in SyncEventResponse with a v2 config by
adding model_config = ConfigDict(from_attributes=True) on the SyncEventResponse
class and import ConfigDict from pydantic; remove or replace the nested class
Config declaration so SyncEventResponse uses model_config =
ConfigDict(from_attributes=True).
ontokit/api/routes/remote_sync.py (1)

40-41: Consider using Depends() for service injection.

The current pattern calls get_remote_sync_service(db) directly within each handler. Per coding guidelines, services should be injected via FastAPI's Depends() for consistency and testability.

♻️ Proposed approach

Create a dependency that composes the DB session:

from ontokit.services.remote_sync_service import RemoteSyncService, get_remote_sync_service

# Dependency that yields the service
def get_service(db: Annotated[AsyncSession, Depends(get_db)]) -> RemoteSyncService:
    return get_remote_sync_service(db)

Then inject in handlers:

 async def get_remote_sync_config(
     project_id: UUID,
-    db: Annotated[AsyncSession, Depends(get_db)],
+    service: Annotated[RemoteSyncService, Depends(get_service)],
     user: RequiredUser,
 ) -> RemoteSyncConfigResponse | None:
-    service = get_remote_sync_service(db)
     return await service.get_config(project_id, user)

As per coding guidelines: "Use dependency injection via FastAPI's Depends() for service access".

Also applies to: 59-60, 76-77, 96-97, 111-112, 126-127

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ontokit/api/routes/remote_sync.py` around lines 40 - 41, Create a FastAPI
dependency that composes the DB session and returns the service instead of
calling get_remote_sync_service(db) directly: add a function (e.g., get_service)
that takes db: Annotated[AsyncSession, Depends(get_db)] and returns
get_remote_sync_service(db) (type RemoteSyncService). Then update each route
handler to accept service: RemoteSyncService = Depends(get_service) and call
methods on that injected service (e.g., service.get_config, service.get_state,
service.sync, service.start_sync, etc.) in place of direct
get_remote_sync_service(db) calls; apply the same change to the other handlers
mentioned (lines ~59-60, 76-77, 96-97, 111-112, 126-127).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@ontokit/api/routes/pull_requests.py`:
- Around line 681-686: The code sets sync_config.status = "checking" and commits
before acquiring the ARQ pool and enqueueing the background task, which can
leave the config stuck if enqueueing fails; change the flow so you only persist
the "checking" status after successfully obtaining get_arq_pool() and awaiting
pool.enqueue_job("run_remote_check_task", str(project_id)), or alternatively
wrap the pool acquisition/enqueue in a try/except and on failure reset
sync_config.status (or rollback) and commit that change; reference
sync_config.status, get_arq_pool(), pool.enqueue_job, and service.db.commit to
locate and update the logic.

In `@ontokit/services/remote_sync_service.py`:
- Around line 157-171: Currently the code sets config.status="checking" and
commits before acquiring the queue and enqueueing the job, which can leave
config stuck if get_arq_pool() or pool.enqueue_job(...) fails; change the flow
in the method that enqueues run_remote_check_task so that you first attempt to
acquire the pool (get_arq_pool()) and enqueue the job
(pool.enqueue_job(str(project_id))), and only after a successful enqueue (job is
not None) set config.status="checking" and call await self.db.commit();
additionally, catch exceptions from get_arq_pool() and enqueue_job and in those
error paths set config.status="error", populate config.error_message, and commit
via await self.db.commit() before raising the HTTPException so the DB never
remains in a stale "checking" state.
- Around line 93-105: When creating a new RemoteSyncConfig from an update
payload in remote_sync_service.py (the branch that checks isinstance(data,
RemoteSyncConfigUpdate)), validate that all required fields (e.g., repo_owner,
repo_name, file_path) are present in data.model_dump(exclude_unset=True); if any
are missing, raise a 4xx-style error (e.g., HTTPException/ValueError) instead of
constructing a partial RemoteSyncConfig and writing to the DB. Update the logic
around RemoteSyncConfig(project_id=project_id) to check the dumped keys first
and only populate defaults when all required fields exist; otherwise return a
clear client error indicating the missing required fields.

In `@ontokit/worker.py`:
- Around line 689-697: The current early-return paths that return {"status":
"failed", ...} (e.g., when config is falsy or project is not found in the block
using config, project_result and project) must instead raise an exception so the
outer except can catch it and emit the remote_check_failed pubsub event; replace
those returns with a specific exception (or RuntimeError) raised with the same
error message, and apply the same change to the analogous checks in the later
block (the 722-733 section) so ontokit/services/remote_sync_service.py will
treat the job as failed and publish the failure event.

---

Nitpick comments:
In `@ontokit/api/routes/remote_sync.py`:
- Around line 40-41: Create a FastAPI dependency that composes the DB session
and returns the service instead of calling get_remote_sync_service(db) directly:
add a function (e.g., get_service) that takes db: Annotated[AsyncSession,
Depends(get_db)] and returns get_remote_sync_service(db) (type
RemoteSyncService). Then update each route handler to accept service:
RemoteSyncService = Depends(get_service) and call methods on that injected
service (e.g., service.get_config, service.get_state, service.sync,
service.start_sync, etc.) in place of direct get_remote_sync_service(db) calls;
apply the same change to the other handlers mentioned (lines ~59-60, 76-77,
96-97, 111-112, 126-127).

In `@ontokit/schemas/remote_sync.py`:
- Around line 66-67: Replace the Pydantic v1 "class Config" usage with a
Pydantic v2 model configuration: remove the inner class Config and add a
module-level or model-level attribute model_config =
ConfigDict(from_attributes=True); also import ConfigDict from pydantic at the
top of the file so the model uses Pydantic v2 settings. Target the model that
currently defines "class Config" (the Config inner class) and replace it with
"model_config" and the ConfigDict import.
- Around line 83-84: Replace the old Pydantic v1 style inner class Config in
SyncEventResponse with a v2 config by adding model_config =
ConfigDict(from_attributes=True) on the SyncEventResponse class and import
ConfigDict from pydantic; remove or replace the nested class Config declaration
so SyncEventResponse uses model_config = ConfigDict(from_attributes=True).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a2af34a3-5fee-4de1-a8e9-90563e7062fc

📥 Commits

Reviewing files that changed from the base of the PR and between b8e0bab and 8e45412.

📒 Files selected for processing (10)
  • alembic/versions/r1s2t3u4v5w6_rename_upstream_to_remote_sync.py
  • ontokit/api/routes/__init__.py
  • ontokit/api/routes/pull_requests.py
  • ontokit/api/routes/remote_sync.py
  • ontokit/models/__init__.py
  • ontokit/models/remote_sync.py
  • ontokit/schemas/remote_sync.py
  • ontokit/services/pull_request_service.py
  • ontokit/services/remote_sync_service.py
  • ontokit/worker.py

Copy link
Copy Markdown
Contributor

@damienriehl damienriehl left a comment

Choose a reason for hiding this comment

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

Clean mechanical rename with a well-structured Alembic migration. Table, column, and index renames in correct order with proper downgrade path.

JohnRDOrazio and others added 3 commits April 6, 2026 09:56
Closes #31

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Renames upstream_sync_configs → remote_sync_configs,
upstream_commit_sha → remote_commit_sha on both tables,
and updates the associated index.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@damienriehl damienriehl force-pushed the fix/rename-upstream-to-remote branch from 8e45412 to d04800a Compare April 6, 2026 14:56
@damienriehl damienriehl merged commit 1a14032 into main Apr 6, 2026
16 checks passed
@damienriehl damienriehl deleted the fix/rename-upstream-to-remote branch April 6, 2026 15:00
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.

Rename 'upstream sync' to 'remote sync' / 'Sync from Remote'

2 participants