Issue description
GitHub and GitLab push webhooks enqueue jobs using an unsupported execution mode.
Both handlers create jobs with:
{
"mode": "incremental",
"trigger": "webhook"
}
However, the server job executor does not recognize incremental. It only has explicit behavior for sync, full_resync, initial_index, and
index_only.
The job still completes successfully, but documentation regeneration is skipped and the repository’s synchronization baseline is advanced.
Exact failure path
1. Webhook handlers enqueue incremental
GitHub creates the job at:
- packages/server/src/repowise/server/routers/webhooks.py:119
- Mode assignment: packages/server/src/repowise/server/routers/webhooks.py:124
GitLab has the same behavior:
- packages/server/src/repowise/server/routers/webhooks.py:177
- Mode assignment: packages/server/src/repowise/server/routers/webhooks.py:182
Both handler docstrings describe these as “sync” jobs, making the configuration inconsistent with the documented intent.
2. The executor does not recognize the mode
The executor reads the job mode here:
- packages/server/src/repowise/server/job_executor.py:343
It only derives flags for:
is_full_resync = mode == "full_resync"
is_initial_index = mode == "initial_index"
is_index_only = mode == "index_only"
incremental matches none of these conditions.
3. Full documentation generation is disabled
The main pipeline generates documentation only for full resync and initial-index jobs:
generate_docs = (
(is_full_resync or is_initial_index)
and llm_client is not None
and bool(config.get("generate_docs", True))
)
Therefore, a webhook job calls run_pipeline() with generate_docs=False.
The repository is re-ingested and its analysis data may be updated, but no documentation pages are generated.
4. Incremental regeneration is also skipped
The executor has a separate incremental page-regeneration phase, but it runs only for sync:
- packages/server/src/repowise/server/job_executor.py:401
- packages/server/src/repowise/server/job_executor.py:406
if mode == "sync" and llm_client is not None:
incremental_pages = await _incremental_page_regen(...)
Because the webhook mode is incremental, this condition is false.
The webhook job therefore skips both possible documentation-generation paths.
5. The job still reports success and advances the baseline
After re-indexing, the job is marked completed, even though no documentation was regenerated.
The executor then calls _stamp_last_sync_commit() for every non-initial-index mode:
- packages/server/src/repowise/server/job_executor.py:482
- packages/server/src/repowise/server/job_executor.py:497
This updates state.json with the current HEAD.
The polling fallback subsequently sees HEAD == last_sync_commit and concludes that the repository is synchronized, so it does not enqueue a
corrective sync job.
Resulting behavior
Push webhook
→ "incremental" job created
→ repository re-indexed
→ documentation regeneration skipped
→ job marked completed
→ last_sync_commit advanced
→ polling fallback sees repository as current
→ stale documentation remains indefinitely
Expected behavior
A default-branch push webhook should perform the same incremental documentation refresh as a polling-triggered sync job:
- Re-index the repository.
- Determine which pages are affected by the pushed commits.
- Regenerate those pages when an LLM provider is configured.
- Persist the updated pages and search indexes.
- Advance last_sync_commit only after the intended sync path succeeds.
Proposed implementation direction
Use the executor’s canonical sync mode in both webhook handlers:
{
"mode": "sync",
"trigger": "webhook",
"before": "...",
"after": "..."
}
For backward compatibility, the executor could also normalize existing incremental jobs to sync:
if mode == "incremental":
mode = "sync"
It would also be useful to validate modes explicitly so future unknown values fail visibly instead of silently running with partial behavior.
Test gap
Current webhook tests verify only request acceptance and authentication:
- tests/unit/server/test_webhooks.py:15
- tests/unit/server/test_webhooks.py:87
They do not:
- Seed a matching repository.
- Inspect the generated job configuration.
- Verify the linked webhook event’s job ID.
- Execute the generated job.
- Assert that incremental page regeneration occurs.
- Verify synchronization-state behavior.
Issue description
GitHub and GitLab push webhooks enqueue jobs using an unsupported execution mode.
Both handlers create jobs with:
{
"mode": "incremental",
"trigger": "webhook"
}
However, the server job executor does not recognize incremental. It only has explicit behavior for sync, full_resync, initial_index, and
index_only.
The job still completes successfully, but documentation regeneration is skipped and the repository’s synchronization baseline is advanced.
Exact failure path
1. Webhook handlers enqueue incremental
GitHub creates the job at:
GitLab has the same behavior:
Both handler docstrings describe these as “sync” jobs, making the configuration inconsistent with the documented intent.
2. The executor does not recognize the mode
The executor reads the job mode here:
It only derives flags for:
is_full_resync = mode == "full_resync"
is_initial_index = mode == "initial_index"
is_index_only = mode == "index_only"
incremental matches none of these conditions.
3. Full documentation generation is disabled
The main pipeline generates documentation only for full resync and initial-index jobs:
generate_docs = (
(is_full_resync or is_initial_index)
and llm_client is not None
and bool(config.get("generate_docs", True))
)
Therefore, a webhook job calls run_pipeline() with generate_docs=False.
The repository is re-ingested and its analysis data may be updated, but no documentation pages are generated.
4. Incremental regeneration is also skipped
The executor has a separate incremental page-regeneration phase, but it runs only for sync:
if mode == "sync" and llm_client is not None:
incremental_pages = await _incremental_page_regen(...)
Because the webhook mode is incremental, this condition is false.
The webhook job therefore skips both possible documentation-generation paths.
5. The job still reports success and advances the baseline
After re-indexing, the job is marked completed, even though no documentation was regenerated.
The executor then calls _stamp_last_sync_commit() for every non-initial-index mode:
This updates state.json with the current HEAD.
The polling fallback subsequently sees HEAD == last_sync_commit and concludes that the repository is synchronized, so it does not enqueue a
corrective sync job.
Resulting behavior
Push webhook
→ "incremental" job created
→ repository re-indexed
→ documentation regeneration skipped
→ job marked completed
→ last_sync_commit advanced
→ polling fallback sees repository as current
→ stale documentation remains indefinitely
Expected behavior
A default-branch push webhook should perform the same incremental documentation refresh as a polling-triggered sync job:
Proposed implementation direction
Use the executor’s canonical sync mode in both webhook handlers:
{
"mode": "sync",
"trigger": "webhook",
"before": "...",
"after": "..."
}
For backward compatibility, the executor could also normalize existing incremental jobs to sync:
if mode == "incremental":
mode = "sync"
It would also be useful to validate modes explicitly so future unknown values fail visibly instead of silently running with partial behavior.
Test gap
Current webhook tests verify only request acceptance and authentication:
They do not: