Skip to content

feat(tracing): trace scheduled Runtime processing (#1243) - #1245

Draft
guozhihao-224 wants to merge 1 commit into
oceanbase:masterfrom
guozhihao-224:feat/scheduled-processing-tracing
Draft

feat(tracing): trace scheduled Runtime processing (#1243)#1245
guozhihao-224 wants to merge 1 commit into
oceanbase:masterfrom
guozhihao-224:feat/scheduled-processing-tracing

Conversation

@guozhihao-224

Copy link
Copy Markdown

Which issue or RFC does this PR close?

Closes #1243.

Rationale for this change

Scheduled Source-window processing and Experience incubation previously reported outcomes only through logs (background.operation.completed), with no trace root. RFC 0046 requires background work to start its own trace when tracing is enabled. This PR adds one trace root per scoped scheduled activation so operators can see when a scheduled run ran, which outcome it produced, and where latency or failure occurred.

What changes are included in this PR?

  • Add a minimal OTel-free tracing protocol (Tracer/Span in src/powercontext/tracing.py) injected into the built-in Runtime; Runtime code stays independent of any OpenTelemetry implementation.
  • Add a DomainTracer adapter in src/powercontext/server/tracing.py that maps the protocol onto ServerTracing (start_root_span opens a fresh trace; start_span joins the current context).
  • Emit scheduled.process_source_window / scheduled.incubate_experience_candidates root spans from the scheduled processors, with memory.flush / experience.incubation boundary spans underneath. Outcomes are success/noop/failure/cancelled, matching the existing logs. Scheduled roots never inherit an HTTP or MCP context and never record scope IDs or content.
  • Wire the tracer through open_builtin_runtime and create_server_app.
  • Update the HTTP flush_memory span tree (the memory.flush boundary span also appears under powercontext flush_memory), the e2e parent-chain assertion, and the Phoenix docs (EN/ZH).
  • Add unit tests covering all four outcomes, root isolation, and the no-scope/content data policy, plus an e2e scheduled-activation test.

Are there any user-facing changes?

Observability-only: when tracing is enabled, scheduled activations now emit spans. No breaking API or persisted-format changes; tracing remains optional, and scheduler/Runtime behavior is unchanged when tracing is off.

How was this change tested?

  • pytest tests/builtin/runtime/test_scheduler.py → 12 passed
  • pytest tests/e2e/test_observability.py → 3 passed
  • Full unit suite → 451 passed, 1 skipped; e2e suite → 31 passed, 6 skipped
  • ruff check / ruff format --check / ty check → all pass
  • Exported span tree (PR requirement):
scheduled.process_source_window  {operation.name=process_source_window,
  unit=background, outcome=success, source_count=1}
  └── memory.flush                 {outcome=success, source_count=1}

- Updated documentation to reflect the addition of a new `memory.flush` span in the tracing output.
- Implemented minimal OpenTelemetry-free tracing hooks in `tracing.py` for domain code.
- Added tracing for scheduled source window processing and experience incubation, capturing success, failure, and cancellation outcomes.
- Introduced a `DomainTracer` to adapt server tracing for domain-specific spans.
- Enhanced tests to verify the correct tracing behavior for scheduled operations and memory flush events.
@CLAassistant

CLAassistant commented Aug 16, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds scheduled-processing trace roots to the built-in Runtime (per RFC 0046 / issue #1243) by introducing a minimal tracing protocol for domain code and adapting the server’s OpenTelemetry tracing to that protocol. The goal is to make scheduled Source-window processing and Experience incubation observable in traces without leaking scope/content data and without coupling Runtime code to OTel.

Changes:

  • Introduce an OpenTelemetry-free Tracer/Span protocol for domain code and inject it into the built-in Runtime.
  • Add scheduled trace roots (scheduled.process_source_window, scheduled.incubate_experience_candidates) and boundary spans (memory.flush, experience.incubation) with outcome attributes.
  • Update tests and Phoenix tracing docs to reflect the new span tree (including memory.flush under HTTP operations and scheduled activations).

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/e2e/test_observability.py Extends e2e assertions for the new memory.flush boundary span and adds an e2e scheduled-activation trace-root test.
tests/builtin/runtime/test_scheduler.py Adds unit tests asserting scheduled trace roots and outcome attributes (noop/success/failure/cancelled) plus data-policy checks.
src/powercontext/tracing.py Introduces the minimal domain tracing protocol (Tracer/Span) to decouple Runtime from OTel.
src/powercontext/server/tracing.py Adds DomainTracer adapter bridging the protocol to ServerTracing and implements root-span creation for scheduled work.
src/powercontext/server/factory.py Wires DomainTracer into Runtime construction in the server app lifespan.
src/powercontext/builtin/runtime/composition.py Extends open_builtin_runtime to accept and pass through the injected domain tracer.
src/powercontext/builtin/runtime/application.py Emits scheduled root spans and adds memory.flush / experience.incubation boundary spans with outcomes and bounded attributes.
docs/zh/docs/how-to/trace-with-phoenix.md Updates the Phoenix trace walkthrough to include memory.flush and scheduled trace roots.
docs/en/docs/how-to/trace-with-phoenix.md Updates the Phoenix trace walkthrough to include memory.flush and scheduled trace roots.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +147 to +167
def start_span(self, name: str, *, attributes: dict[str, object]) -> _ActiveSpan:
span_attributes = dict(attributes)
request_id = current_request_id()
# note(guozhihao-224): only child spans join a request; scheduled roots are fresh traces with no request id.
if request_id is not None:
span_attributes["powercontext.request.id"] = request_id
return self._tracing.start_span(
name,
kind=SpanKind.INTERNAL,
attributes=span_attributes,
context=None,
)

def start_root_span(self, name: str, *, attributes: dict[str, object]) -> _ActiveSpan:
# note(guozhihao-224): fresh empty context keeps scheduled activations as independent trace roots.
return self._tracing.start_span(
name,
kind=SpanKind.INTERNAL,
attributes=dict(attributes),
context=Context(),
)
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.

feat: trace scheduled Runtime processing

3 participants