Metadata
Origin
Review of PR #264
What to build
Three small polishings of src/docverse/handlers/webhooks/github.py:
_lowercase_headers (currently lines 119-129) accepts headers: object and guards .items() with hasattr. FastAPI's request.headers is always a starlette.datastructures.Headers instance, so the guard is dead code and the parameter type is too loose.
- The dispatch path (lines 90-97) calls
factory.get_github_webhook_secret() and factory.create_push_event_processor() in sequence inside one try / except GitHubAppNotConfiguredError. Both can raise the same error from the Factory — collapse to a single accessor so there is one raise site.
_handle_push (lines 56-60) logs delivery_id=event.delivery_id while the surrounding handler binds github_delivery_id via context.rebind_logger (lines 110-112). Two field names for the same value hurts greppability.
Approach sketch
- Type
_lowercase_headers parameter as Mapping[str, str] (vendor-neutral; starlette.datastructures.Headers satisfies it). Drop if hasattr(headers, "items"). The body becomes one comprehension.
- Add a Factory accessor (e.g.
create_webhook_dispatch()) that returns (secret: str, processor: PushEventProcessor) and raises GitHubAppNotConfiguredError once. The handler's try block then wraps a single call.
- Drop
delivery_id=event.delivery_id from the info call. The bound github_delivery_id already shows up in the log record.
Acceptance criteria
Metadata
tickets/DM-54689-github-webhookOrigin
Review of PR #264
What to build
Three small polishings of
src/docverse/handlers/webhooks/github.py:_lowercase_headers(currently lines 119-129) acceptsheaders: objectand guards.items()withhasattr. FastAPI'srequest.headersis always astarlette.datastructures.Headersinstance, so the guard is dead code and the parameter type is too loose.factory.get_github_webhook_secret()andfactory.create_push_event_processor()in sequence inside onetry/except GitHubAppNotConfiguredError. Both can raise the same error from the Factory — collapse to a single accessor so there is one raise site._handle_push(lines 56-60) logsdelivery_id=event.delivery_idwhile the surrounding handler bindsgithub_delivery_idviacontext.rebind_logger(lines 110-112). Two field names for the same value hurts greppability.Approach sketch
_lowercase_headersparameter asMapping[str, str](vendor-neutral;starlette.datastructures.Headerssatisfies it). Dropif hasattr(headers, "items"). The body becomes one comprehension.create_webhook_dispatch()) that returns(secret: str, processor: PushEventProcessor)and raisesGitHubAppNotConfiguredErroronce. The handler'stryblock then wraps a single call.delivery_id=event.delivery_idfrom theinfocall. The boundgithub_delivery_idalready shows up in the log record.Acceptance criteria
_lowercase_headersparameter isMapping[str, str]; nohasattrguard;nox -s typingclean.GitHubAppNotConfiguredErrorfrom a single Factory call site (not two adjacent calls).Processed push webhooklog line emitsgithub_delivery_idonly (no duplicatedelivery_idkey).