Skip to content

feat(tracing): boot journey + process device for out-of-request calls - #116

Merged
ngjunsiang merged 2 commits into
mainfrom
feat/boot-journey
Oct 21, 2026
Merged

ngjunsiang merged 2 commits into
mainfrom
feat/boot-journey

Conversation

@ngjunsiang

Copy link
Copy Markdown
Contributor

Fixes #114 (all four decisions settled in the issue, user-ruled 2026-10-21, recommendations accepted).

What

Every SDK call is a user request — human or agent — so calls outside any request context (startup vault fetches, background threads) now correlate instead of landing as anonymous single-span traces:

  • Boot journey: one uid-journey-… per process boot, lazily minted on first out-of-request use and fixed for the process's lifetime (format matches generate_category_uid("journey") — replicated, not imported).
  • Journey name: rides along as X-Journey-Name (campus#952 adoption) when the app calls set_process_journey(name="campus.api.boot"); auto-minted journeys are unnamed until then.
  • Process device: X-Campus-Device defaults to RAILWAY_DEPLOYMENT_ID, so boot spans attribute to the deploy that produced them.

Strict MVP scope (ruled): in-request calls never inherit the boot journey — a journeyed request forwards its own (precedence pinned by test), a journey-less request stays unjourneyed since the trace waterfall already correlates the chain. The process device only gap-fills when a request stashed no device of its own.

Opt-out, both forms (ruled): CAMPUS_PROCESS_JOURNEY=off (also false/0/no) for pytest/CI with zero code; disable_process_journey() for embedded hosts. A non-off env value pins an explicit id. set_process_journey() re-enables after either; set_process_device() overrides the env default.

Zero server-side changes: the campus journeys middleware already adopts header-minted journeys, and #952 (merged) adopts the name.

Testing

  • TestProcessJourney (15 tests): mint-once per boot, explicit id/name, env off + disable API + re-enable, env-pinned id, device from Railway env + override, strict-MVP in-request non-inheritance, journeyed-request precedence, device gap-fill vs stashed-device-wins, id-format lockstep.
  • Full suite: 313 passed. A _reset_process_journey() test hook keeps the module state isolated between tests.

JS added 2 commits October 21, 2026 11:27
Every SDK call is a user request — human or agent (ruling,
campus-api-python#114) — so calls outside any request context
(startup, background threads) now carry:

- X-Journey-ID: one uid-journey-… per process boot, lazily minted on
  first use, fixed for the process's lifetime (format matches
  campus.common.utils.uid.generate_category_uid without importing the
  server package).
- X-Journey-Name: only when the app names the journey
  (set_process_journey(name=...)), riding the campus#952 adoption.
- X-Campus-Device: the process device, defaulting to
  RAILWAY_DEPLOYMENT_ID, so boot spans attribute to the deploy that
  produced them.

Strict MVP scope (ruled): in-request calls never inherit the boot
journey — a journeyed request forwards its own, a journey-less request
stays unjourneyed (the trace waterfall already correlates it) — and
the process device only fills the gap when the request stashed none.

Opt-out, both ruled in: CAMPUS_PROCESS_JOURNEY=off (also
false/0/no; a non-off value pins an explicit id) for pytest/CI, and
disable_process_journey() in code; set_process_journey() re-enables
and set_process_device() overrides.

Fixes #114.
The in_request flag broke type narrowing: pyright could not connect
the bool to flask being non-None inside the request branch. Branch on
flask None-ness directly and return from each path.
@ngjunsiang
ngjunsiang merged commit 14ef22c into main Oct 21, 2026
5 checks passed
@ngjunsiang
ngjunsiang deleted the feat/boot-journey branch October 21, 2026 03:32
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.

tracing: process (boot) journey for out-of-request SDK calls, with opt-out

1 participant