Skip to content

Plan: integrate request correlation across HTTP, tasks, and outbound provider calls (4.1.3) - #280

Draft
leynos wants to merge 6 commits into
mainfrom
4-1-3-integrate-request-correlation.md
Draft

Plan: integrate request correlation across HTTP, tasks, and outbound provider calls (4.1.3)#280
leynos wants to merge 6 commits into
mainfrom
4-1-3-integrate-request-correlation.md

Conversation

@leynos

@leynos leynos commented Aug 23, 2026

Copy link
Copy Markdown
Owner

Summary

Adds the execution plan for roadmap item 4.1.3, integrating request
correlation across the Falcon HTTP boundary, Celery tasks, and outbound
OpenAI-compatible provider calls.

This PR contains no production code — only the plan and its index entry.

What the plan covers

Ten milestones: pin falcon-correlate; build an episodic-owned correlation
seam with sanitization and runtime configuration; wire
CorrelationIDMiddlewareASGI ahead of the authorization middleware; split
episodic/observability.py below the 400-line limit; bootstrap logging and
carry the identifier into log lines; configure Celery propagation; correlate
outbound provider calls; two behavioural-test milestones; and documentation
with a new ADR 018.

Design review

The first draft was stress-tested by a six-lens review panel — structure,
alternatives, scaling and observability, contracts, failure modes, and
long-term viability. It falsified four load-bearing premises. Each was verified
by probing the runtime rather than by reading documentation, and each changed
the plan.

make check-architecture cannot enforce the boundary the draft relied on.
Hecate's include_external_packages defaults to false and [tool.hecate]
does not set it, so the gate sees zero third-party imports and would pass a
domain module importing httpx directly. Constraint C2 is reworded as a review
obligation and a new import-graph test replaces the imagined gate.

Not every log call funnels through the logging helpers. 29 of 48 call sites
bypass them — including _log_authorization_denial, the roadmap's own headline
example, which logs at DEBUG through a direct logger.log call. The draft's
marquee transcript did not correspond to any message the codebase emits; it is
replaced with the real one, and the plan now schedules the edits instead of
claiming coverage it did not have.

import falcon_correlate registers the Celery signal handlers globally, at
import time
, and pulls Celery in at ~87 ms. configure_celery_correlation(app)
ignores its argument entirely, so the draft's negative control — "delete the
call and the test must fail" — was unfalsifiable. It is now signal
disconnection.

episodic/observability.py is 399 lines against a blocking 400-line Pylint
limit
, so the planned edit would have failed make lint on the first run. A
new milestone splits it first, including the ~20 Skylos entry-point rules that
must be renamed in lockstep.

Two fixes that looked right were tested and rejected: importing a
falcon_correlate submodule does not avoid the Celery side effect, because
Python executes the package __init__ first; and hypothesis.event() cannot
enforce class coverage, because it only feeds the statistics report and a
module-level counter is unsafe under pytest-xdist.

Security findings folded in

Verified against Granian: a 60,000-byte correlation header is accepted,
stored, and echoed in full, and the payload abc method=GET path=/admin principal_id=root round-trips intact — audit-trail forgery in a last-wins
logfmt parser, since the identifier is appended last. Sanitization is now
unconditional at the seam rather than dependent on an optional upstream
validator.

Risk R2 is rewritten. Granian does populate scope["client"], so the
draft's stated hazard was largely theoretical. The real one is that Traefik on
DOKS gives operators no stable range to trust — pod IPs change on every
reschedule — while relaying the header verbatim, so the path of least
resistance trusts every pod in the cluster. The plan now ships a Traefik
middleware that overwrites the header at the edge.

Notes for the reviewer

  • One deviation needs sign-off. Decision D10 adds a correlate_client
    helper beyond the roadmap's literal "falcon-correlate transport support",
    because every existing adapter fixture injects a client and the transport
    approach structurally cannot reach those. Flagged as a reviewer gate before
    EP-M5.
  • falcon-correlate is pinned at v0.1.0, which upstream cut in response
    to the draft. It resolves to caea7a6a — the exact commit every finding here
    was probed against — so nothing needed re-verifying. Risk R1 drops from
    medium/certain to low/low; what survives is that the package is still absent
    from PyPI, single-author, and alpha-status. Because a Git tag is mutable where
    a commit is not, EP-M0 asks the implementer to confirm the locked revision in
    uv.lock, so a moved tag surfaces as a reviewable lockfile change.
  • Two upstream issues are identified for filing rather than local shimming.
  • make markdownlint (which runs the spelling gate) passes with 0 issues.

References

🤖 Generated with Claude Code

Summary by Sourcery

Define the implementation plan for end-to-end request correlation across Episodic’s HTTP, worker, logging, and provider boundaries.

Enhancements:

  • Add a comprehensive execution plan for propagating sanitized request correlation identifiers across HTTP requests, Celery tasks, logs, and outbound provider calls.
  • Document design decisions, security risks, verification obligations, implementation milestones, and operational limitations for the correlation rollout.

Documentation:

  • Index the new request-correlation execution plan in the documentation contents.

leynos and others added 4 commits August 23, 2026 03:26
Add docs/execplans/4-1-3-integrate-request-correlation.md, the execution plan
for roadmap item 4.1.3, covering Falcon ASGI middleware wiring, runtime
configuration, Celery propagation, and outbound provider-call correlation.

The plan records several findings established by probing the runtime rather
than by reading documentation:

- falcon-correlate has no tags or releases and is absent from PyPI, so the
  dependency must be pinned to a commit SHA.
- femtologging's log_context fields never reach records emitted through
  get_logger, so ContextualLogFilter is unusable; the plan decorates messages
  inside the existing logging helpers instead.
- Celery's before_task_publish does not fire in eager mode, and eager tasks
  inherit the caller's context, so a naive eager-mode test would pass against
  an unwired application. The verification plan splits the Celery obligations
  to avoid that vacuity.
- An rpc:// result backend silently disables publish-time propagation.
- Falcon's req.remote_addr is the peer address and falls back to 127.0.0.1
  when the ASGI scope omits the client, which makes trusting loopback a real
  hazard.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rename the axiom identifiers from AX-n to AXIOM-n so the typos spelling gate
stops reading "AX" as a misspelling of "AXE", remove the leading spaces from
inside code spans that tripped MD038, and rewrap three over-length lines.

make markdownlint now reports 0 issues.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add the execplan to docs/contents.md alongside the other phase-4 API plans so
the documentation index stays complete.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A design-review panel stress-tested the draft and falsified four of its
load-bearing premises. Each was verified by probing the runtime, and each
changed the plan:

- make check-architecture cannot enforce the boundary the plan claimed it
  enforced. Hecate's include_external_packages defaults to false, so it sees
  zero third-party imports. Constraint C2 is reworded and INV-9 pins the
  import graph instead.
- Not every log call funnels through the episodic/logging.py helpers: 29 of 48
  call sites bypass them, including the authorization denial the roadmap names,
  which logs at DEBUG through a direct logger.log call. The draft's marquee
  transcript was fabricated; it is replaced with the message the code emits.
- import falcon_correlate registers the Celery signal handlers globally at
  import time, so configure_celery_correlation(app) is declarative and INV-4a's
  negative control was unfalsifiable. It is now signal disconnection.
- episodic/observability.py is 399 lines against a blocking 400-line Pylint
  limit, so the planned edit would have failed make lint. EP-M3a now splits it.

Two proposed fixes that looked correct were tested and rejected: importing a
falcon_correlate submodule does not avoid the Celery side effect, because
Python runs the package __init__ first; and hypothesis.event() cannot enforce
class coverage, so INV-1 now uses @example anchors.

Also added: unconditional identifier sanitization after verifying that a
60,000-byte header and a logfmt-injection payload both round-trip today; a
logging bootstrap, without which the whole milestone emits no bytes in the
container; a bounded correlation-source counter; an rpc:// hard error;
prefork context-leak and import-cost obligations; and an explicit client
factory signature after the draft's **kwargs: object failed ty with 18 errors.

Risk R2 is rewritten: Granian does populate scope["client"], so the draft
aimed at a non-hazard, while the real one is that Traefik pod IPs give
operators no stable range to trust and relay the header verbatim.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Warning

Your free Security trial is over. An organization admin can activate billing to continue.

@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Warning

Your free Security trial is over. An organization admin can activate billing to continue.


Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a detailed execution plan document for roadmap item 4.1.3 (request correlation across HTTP, Celery, and outbound provider calls) and indexes it in the docs contents, with no production code changes.

Sequence diagram for planned HTTP request correlation

sequenceDiagram
    participant Client
    participant Traefik
    participant Falcon
    participant Authorization
    participant Celery
    participant Provider

    Client->>Traefik: HTTP request
    Traefik->>Traefik: Overwrite X-Correlation-ID
    Traefik->>Falcon: Forward request
    Falcon->>Falcon: CorrelationIDMiddlewareASGI.process_request
    Falcon->>Authorization: AuthorizationMiddleware.process_request
    Authorization-->>Falcon: Allow or deny
    Falcon->>Celery: Publish task with correlation_id
    Falcon->>Provider: HTTP request with X-Correlation-ID
    Falcon-->>Client: Response with X-Correlation-ID
Loading

Sequence diagram for planned Celery correlation propagation

sequenceDiagram
    participant HTTP as HTTP Service
    participant Celery as Celery Publish Signal
    participant Worker
    participant Task

    HTTP->>Celery: before_task_publish
    Celery->>Celery: propagate_correlation_id_to_celery
    Celery-->>Worker: Message with correlation_id
    Worker->>Worker: task_prerun restores correlation_id
    Worker->>Task: Execute task
    Task-->>Worker: task_postrun clears correlation_id
Loading

Sequence diagram for planned outbound provider correlation

sequenceDiagram
    participant Request as Request Context
    participant Adapter as OpenAICompatibleLLMAdapter
    participant Client as httpx AsyncClient
    participant Provider as OpenAI-Compatible Provider

    Request->>Adapter: LLM operation
    Adapter->>Client: Build correlated client
    Client->>Provider: HTTP request with X-Correlation-ID
    Provider-->>Client: Provider response
    Client-->>Adapter: Response
Loading

File-Level Changes

Change Details Files
Index the new request-correlation execution plan in the documentation contents so it appears alongside other exec plans.
  • Add a bullet linking to execplans/4-1-3-integrate-request-correlation.md under the execution plans section
  • Provide a short description for the plan entry (request correlation propagation plan)
docs/contents.md
Introduce a comprehensive execution plan document for integrating request correlation across Falcon HTTP, Celery workers, and outbound OpenAI-compatible provider calls, including constraints, risks, milestones, and verification strategy.
  • Define purpose, scope, and desired behaviour for request correlation identifiers across HTTP, tasks, and provider calls
  • Capture design-review outcomes and surprises that changed the plan’s assumptions
  • List constraints, tolerances, risks, and axioms governing correlation behaviour and security
  • Lay out a multi-milestone implementation plan (EP-M0–EP-M7) covering dependency pinning, middleware seam, logging, Celery propagation, provider correlation, behavioural tests, and documentation
  • Specify verification plan with concrete test obligations and artefacts (INV-1 through INV-10) and residual gaps
  • Document decision log (D1–D12) explaining key design choices, security posture, and coupling to falcon-correlate
  • Provide progress checklist, conformance basis to roadmap/design docs/ADRs, and operational notes for implementation and recovery
docs/execplans/4-1-3-integrate-request-correlation.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

Upstream cut v0.1.0, resolving to caea7a6ac804f851f7226ccf9acb3d256cc2d5d4 —
the same commit every empirical finding in the plan was probed against, so no
finding needs re-verifying. Verified that the tag installs and reports version
0.1.0.

Decision D1 now pins the tag unconditionally, matching the df12-python-lints
tag pin rather than the femtologging and tei-rapporteur commit pins, and states
the rule: prefer a tag whenever upstream offers one.

Risk R1 drops from medium/certain to low/low. What survives is narrower and
worth keeping: the package is still absent from PyPI, has a single author, is
alpha-status, and carries the trust decision in R2 plus the private-attribute
coupling in R6. A Git tag is also mutable where a commit is not, so EP-M0 now
asks the implementer to confirm the locked revision in uv.lock is caea7a6a; a
moved tag then surfaces as a reviewable lockfile change rather than a silent
behaviour swap.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

…eview

Cross-reference the eight issues filed against femtologging, falcon-correlate,
and episodic from the discoveries that produced them, so an implementer reading
a Surprises entry can see whether the underlying defect is being fixed at
source.

Also replaces EP-M0's "file two upstream issues" pre-step: both are now filed
(falcon-correlate#158 and #159), and neither blocks this plan.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
codescene-access[bot]

This comment was marked as outdated.

@codescene-access codescene-access Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No quality gates enabled for this code.

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.

1 participant