Skip to content

Conversation

@luandro
Copy link
Contributor

@luandro luandro commented Feb 11, 2026

Codex generated this pull request, but encountered an unexpected error after generation. This is a placeholder PR message.


Codex Task

Greptile Overview

Greptile Summary

This PR implements content repository management infrastructure for the API server, enabling content-mutating jobs (notion:fetch, notion:fetch-all, notion:translate) to commit and push changes to a dedicated git branch.

Key Changes

  • New content-repo.ts module: Implements git repository lifecycle management with lock-based serialization, cancellation support, and secure credential handling via GIT_ASKPASS
  • Lock acquisition improvements: Properly distinguishes EEXIST (retry) from other filesystem errors (fail fast), honors shouldAbort callback during lock wait to enable prompt cancellation
  • Job executor integration: Content-mutating jobs now execute within the content repo workflow with proper path resolution using PROJECT_ROOT constant
  • Comprehensive test coverage: New content-repo.test.ts validates lock retry, error handling, cancellation, and concurrent initialization scenarios
  • Docker configuration: Updates workflow to use communityfirst/comapeo-docs-api image name, adds publish mode logic for graceful credential handling
  • Infrastructure: Adds git to Dockerfile, documents required env vars in .env.example
  • Error resilience: generateBlocks.ts now catches page processing errors to prevent batch failures

Review Notes

The implementation addresses the P1 and P2 issues documented in PR_129_REVIEW_FINDINGS.md:

  • ✅ Lock retry now only retries on EEXIST, fails fast on other errors
  • ✅ Cancellation is checked during lock acquisition loop via shouldAbort callback
  • ✅ Script path resolution uses explicit PROJECT_ROOT instead of runtime process.cwd()
  • ✅ Test coverage includes lock contention, cancellation, and error scenarios

The code quality is strong with proper separation of concerns, comprehensive error handling, and good test coverage.

Confidence Score: 4/5

  • This PR is safe to merge with low risk - the implementation properly handles lock contention, cancellation, and error scenarios
  • Score reflects solid implementation quality with comprehensive test coverage for critical paths (lock acquisition, cancellation, error handling). The main risk areas (git credential handling, concurrent job execution, path resolution) are properly addressed. Confidence is 4/5 rather than 5/5 because this is new infrastructure that introduces git operations and filesystem locking - production validation would provide full confidence
  • No files require special attention - all critical components have corresponding test coverage

Important Files Changed

Filename Overview
scripts/api-server/content-repo.ts Adds comprehensive git repository management with lock acquisition, cancellation support, and proper error handling for EEXIST vs other errors
scripts/api-server/job-executor.ts Integrates content repo workflow for mutating jobs, adds PROJECT_ROOT for stable path resolution, properly passes cancellation callbacks
scripts/api-server/content-repo.test.ts Comprehensive test coverage for lock retry, fast-fail on non-EEXIST errors, cancellation during lock wait, and concurrent initialization
.github/workflows/docker-publish.yml Changes image name to communityfirst/comapeo-docs-api and adds publish mode logic to handle missing credentials gracefully
Dockerfile Adds git package dependency required for content repository operations
scripts/notion-fetch/generateBlocks.ts Adds error handling wrapper around processSinglePage to prevent uncaught exceptions from crashing batch processing

Sequence Diagram

sequenceDiagram
    participant Client
    participant JobExecutor
    participant ContentRepo
    participant LockMgr as Lock Manager
    participant Git
    participant Remote as GitHub Remote

    Client->>JobExecutor: executeJob(notion:fetch)
    JobExecutor->>JobExecutor: isContentMutatingJob() → true
    JobExecutor->>ContentRepo: runContentTask(taskName, requestId, taskRunner, {shouldAbort})
    
    ContentRepo->>LockMgr: acquireRepoLock(lockPath, shouldAbort)
    
    loop Lock Acquisition
        LockMgr->>LockMgr: assertNotAborted(shouldAbort)
        LockMgr->>LockMgr: open(lockPath, "wx")
        alt Lock Available
            LockMgr-->>ContentRepo: {release: fn}
        else EEXIST (Lock Held)
            LockMgr->>LockMgr: sleep(200ms)
        else Other Error
            LockMgr-->>ContentRepo: throw ContentRepoError
        end
    end
    
    ContentRepo->>ContentRepo: initializeContentRepo()
    ContentRepo->>Git: config user.name/email
    ContentRepo->>Git: remote set-url origin
    
    ContentRepo->>ContentRepo: assertNotAborted()
    ContentRepo->>Git: fetch origin content
    ContentRepo->>Git: checkout -B content origin/content
    ContentRepo->>Git: reset --hard origin/content
    ContentRepo->>Git: clean -fd
    
    ContentRepo->>ContentRepo: assertNotAborted()
    ContentRepo->>JobExecutor: taskRunner(workdir)
    JobExecutor->>JobExecutor: spawn(bun, script, {cwd: workdir})
    JobExecutor-->>ContentRepo: output
    
    ContentRepo->>ContentRepo: assertNotAborted()
    ContentRepo->>Git: status --porcelain
    
    alt Changes Detected
        ContentRepo->>Git: add -A
        ContentRepo->>Git: commit -m "content-bot: ..."
        ContentRepo->>ContentRepo: assertNotAborted()
        ContentRepo->>Git: push origin content
        ContentRepo->>Git: rev-parse HEAD
        Git-->>ContentRepo: commitSha
        ContentRepo-->>JobExecutor: {output, noOp: false, commitSha}
    else No Changes
        ContentRepo-->>JobExecutor: {output, noOp: true}
    end
    
    ContentRepo->>LockMgr: lock.release()
    LockMgr->>LockMgr: close(lockFile)
    LockMgr->>LockMgr: rm(lockPath)
    
    JobExecutor-->>Client: Job completed
Loading

@github-actions
Copy link
Contributor

github-actions bot commented Feb 11, 2026

🚀 Preview Deployment

Your documentation preview is ready!

Preview URL: https://pr-129.comapeo-docs.pages.dev

🔄 Content: Regenerated 5 pages from Notion (script changes detected)

💡 Tip: Add label fetch-all-pages to test with full content, or fetch-10-pages for broader coverage.

This preview will update automatically when you push new commits to this PR.


Built with commit c98437d

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6d4039f6f9

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@luandro
Copy link
Contributor Author

luandro commented Feb 12, 2026

@codex @greptile review

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

6 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

// Register the process so it can be killed on cancellation
jobTracker.registerProcess(jobId, {
kill: () => childProcess?.kill("SIGTERM"),
});

P1 Badge Honor cancellation before running content sync steps

For content-mutating jobs, process cancellation is only wired once runJobProcess registers the child process, but that runner is invoked inside runContentTask after lock wait/fetch/reset work; if a user cancels during that pre-spawn window (for example while queued behind another mutating job), cancelJob marks the job failed yet execution can still continue and eventually push content changes. This makes cancellation non-authoritative and can produce commits after an explicit cancel request.

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

7 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

luandro and others added 4 commits February 11, 2026 22:03
The lock acquisition must happen AFTER directory creation to avoid
30-minute timeout when dirname(WORKDIR) doesn't exist. This regression
was introduced when serialization logic was added in commit 13ab1e7.

The acquireRepoLock() call would fail with ENOENT and retry as if it
were lock contention, rather than immediately failing or succeeding.

Fixes the order to:
1. initializeContentRepo() - creates dirname(workdir) with mkdir -p
2. acquireRepoLock() - creates lock file in now-existing directory
@luandro luandro force-pushed the codex/update-docker-api-for-repo-management branch from 3dae2c4 to 75b9cf3 Compare February 12, 2026 01:06
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

7 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

Replace boolean `initialized` flag with promise-based lock to prevent
concurrent initialization race conditions in git config operations.

- Use `initPromise` to ensure single initialization across concurrent calls
- Reset promise on failure to allow retry after transient errors
- Addresses code review feedback on lines 203-259

Reviewed-by: OpenAI Codex
* fix(api-server): address pr review race and path issues

* fix(ci): align docker publish workflow with validation and tests

* fix(ci): use version tags for docker publish actions

* fix(api-server): address pr 133 review regressions

* fix(ci-validation): restore docker action pinning policy checks

* fix(content-repo): reintroduce safe init singleton

* fix(ci): disable docker push when registry secrets are unavailable

* test(ci): cover docker publish secret-gating behavior
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

12 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

13 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

…po locking (#135)

* test(api-server): add focused content-repo lock and init race coverage

* docs(api-server): document content-repo envs for docker runtime

* feat(test-docker): add docker-compose fetch-all smoke script
@socket-security
Copy link

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedyaml@​2.8.29910010083100

View full report

@luandro luandro merged commit 2eb8bee into feat/notion-api-service Feb 12, 2026
5 checks passed
@luandro luandro deleted the codex/update-docker-api-for-repo-management branch February 12, 2026 13:43
@github-actions
Copy link
Contributor

🧹 Preview Deployment Cleanup

The preview deployment for this PR has been cleaned up.

Preview URL was: https://pr-129.comapeo-docs.pages.dev


Note: Cloudflare Pages deployments follow automatic retention policies. Old previews are cleaned up automatically.

luandro added a commit that referenced this pull request Feb 13, 2026
* fix(notion-fetch): isolate per-page failures in batch processing

* fix(api-server): defer content repo init and relax health readiness

* fix(api-server): serialize init and honor pre-spawn cancellation

* fix(content-repo): initialize repo before acquiring lock

The lock acquisition must happen AFTER directory creation to avoid
30-minute timeout when dirname(WORKDIR) doesn't exist. This regression
was introduced when serialization logic was added in commit 13ab1e7.

The acquireRepoLock() call would fail with ENOENT and retry as if it
were lock contention, rather than immediately failing or succeeding.

Fixes the order to:
1. initializeContentRepo() - creates dirname(workdir) with mkdir -p
2. acquireRepoLock() - creates lock file in now-existing directory

* fix(content-repo): prevent initialization race condition

Replace boolean `initialized` flag with promise-based lock to prevent
concurrent initialization race conditions in git config operations.

- Use `initPromise` to ensure single initialization across concurrent calls
- Reset promise on failure to allow retry after transient errors
- Addresses code review feedback on lines 203-259

Reviewed-by: OpenAI Codex

* Codex-generated pull request (#133)

* fix(api-server): address pr review race and path issues

* fix(ci): align docker publish workflow with validation and tests

* fix(ci): use version tags for docker publish actions

* fix(api-server): address pr 133 review regressions

* fix(ci-validation): restore docker action pinning policy checks

* fix(content-repo): reintroduce safe init singleton

* fix(ci): disable docker push when registry secrets are unavailable

* test(ci): cover docker publish secret-gating behavior

* doc: review findings

* fix(api-server): harden content repo lock and script path handling (#134)

* test(api-server): complete PR 129 reliability coverage for content repo locking (#135)

* test(api-server): add focused content-repo lock and init race coverage

* docs(api-server): document content-repo envs for docker runtime

* feat(test-docker): add docker-compose fetch-all smoke script
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