Skip to content

controller: port replan.rs::push_config_to_agent to typed-stage-split pipeline - #334

Merged
zzylol merged 1 commit into
mainfrom
mvp/port-replan-push-config-to-typed
May 8, 2026
Merged

zzylol merged 1 commit into
mainfrom
mvp/port-replan-push-config-to-typed

Conversation

@zzylol

@zzylol zzylol commented May 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Ports the OpAMP-push side of the agent-config emit to the typed L5
stage-split pipeline so reconnecting (plan-pinned) agents receive
the same routed YAML as fresh-connect agents — finishes the
OpAMP-on-connect side of the typed emit after #329 ported the
bootstrap GET path.

Why

Replanner::push_config_to_agent (and the agent-config push in
replan_metric) called the legacy generate_agent_config emitter,
which produces a single-pipeline DDSketch YAML with no gorillas3
archive write, no OTTL routing processor, and no
metrics/warm_passthrough pipeline. Agents that connected via the
OpAMP on_connect callback (the post-#333 reconnection path) got
that legacy YAML — so freshness-probe routing reached
fresh-connect agents (criterion ⑥ on #46) but NOT plan-pinned
reconnecting agents.

Closes the gap on issue #46, criterion ⑥.

What changed

  • replan.rs: new private helpers try_emit_typed_edge_yaml(metric)
    / try_emit_typed_edge_yaml_for_workload(&wl) that mirror
    main::emit_bootstrap_typed's flow (bind_workload_typed
    split_typed_three_stage → pick Edge → apply demo plumbing →
    emit_for_runtime).
  • push_config_to_agent and replan_metric's agent-config push
    branch on planner::stage_split::typed_stage_split_enabled()
    typed emit on, legacy fallback on emit failure or when the gate
    is off.
  • New builder Replanner::with_workload_registry(Arc<WorkloadRegistry>)
    so the typed path can extend its edge config with the same
    archive-tier metrics the bootstrap GET path applies. main()
    wires it during replanner construction.
  • config/mod.rs: extracted extend_edge_with_demo_plumbing from
    the inline body of emit_bootstrap_typed. Both bootstrap and
    replan now apply the SAME freshness-probe + workload-registry
    archive extension. main::emit_bootstrap_typed collapses to a
    one-line call.

Gate behaviour

USE_TYPED_STAGE_SPLIT path
unset / 0 legacygenerate_agent_config (single-pipeline DDSketch). Backwards-compat.
1 / true / yes typed — bind → stage-split → Edge → demo-plumbing → emit_for_runtime(AsapOtel, …). On error, falls back to the legacy emitter so the push never silently drops.

Same gate / same matrix as handle_plan (#329's PR) and
handle_bootstrap_agent_config.

Runtime default

OpAMP on_connect doesn't surface the agent's X-Agent-Runtime
header today, so the typed emit defaults to
AgentRuntime::AsapOtel — matches the bootstrap default for
unspecified clients. If a future commit threads runtime info
through OpAMP, swap the default for a per-agent lookup.

Test plan

  • cargo test --release replan::tests:: — 7/7 pass, including
    the two new tests:
    • typed_replan_emit_includes_freshness_probe_routing
      asserts the typed YAML contains gorillas3, routing,
      metrics/warm_passthrough, and references the freshness probe.
    • legacy_path_omits_typed_processors_when_gate_off — pins
      the gate semantics so a regression always-on'ing the typed path
      surfaces here.
  • cargo build --release
  • Demo verification on the OpAMP-on-connect path (out of scope
    for this PR — requires a full demo run).

Pre-existing failing tests in controller/src/main.rs::api_tests
(agent_receives_config_on_connect_via_workload_registry,
replan_pushes_only_to_registered_agent) fail on origin/main too
— unrelated WebSocket protobuf decode race.

🤖 Generated with Claude Code

… pipeline

`Replanner::push_config_to_agent` (and the agent-config push in
`replan_metric`) called the legacy `generate_agent_config` emitter,
which produces a single-pipeline DDSketch YAML with no `gorillas3`
archive write, no OTTL `routing` processor, and no
`metrics/warm_passthrough` pipeline. Agents that connected via the
OpAMP `on_connect` callback (the post-#333 reconnection path) got
that legacy YAML — so freshness-probe routing reached fresh-connect
agents (criterion ⑥ on issue #46) but NOT plan-pinned reconnecting
agents.

Mirror `main::emit_bootstrap_typed`'s flow on the OpAMP push path:
`bind_workload_typed` → `split_typed_three_stage` → pick the Edge
stage → extend with freshness-probe + workload-registry archive
metrics → `emit_for_runtime`. Gate it behind the existing
`USE_TYPED_STAGE_SPLIT` env var so the legacy single-pipeline
fallback still runs when the gate is off, matching `handle_plan` /
`handle_bootstrap_agent_config`. On any typed-emit error the push
falls back to the legacy emitter so it never silently drops.

The bootstrap-scope demo plumbing (freshness probes +
workload-registry archive metrics) is lifted out of
`emit_bootstrap_typed` into a shared `config::extend_edge_with_demo_plumbing`
helper; both bootstrap and replan now apply the SAME extension. The
runtime defaults to `AgentRuntime::AsapOtel` since OpAMP `on_connect`
doesn't surface the agent's runtime header today (matches the
bootstrap default for legacy clients).

Adds two unit tests in `replan::tests`:
- `typed_replan_emit_includes_freshness_probe_routing` —
  asserts the typed path emits `gorillas3`, `routing`,
  `metrics/warm_passthrough`, and references `http_freshness_probe_warm`.
- `legacy_path_omits_typed_processors_when_gate_off` — pins the
  gate semantics so a regression that always-on'd the typed path
  would surface here.

Together with PR #329 (bootstrap GET path) this finishes the
OpAMP-on-connect side of the typed emit so reconnecting agents now
receive the same routed YAML as fresh-connect agents.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@zzylol
zzylol merged commit 589d177 into main May 8, 2026
zzylol added a commit that referenced this pull request May 8, 2026
Activates the typed-stage-split path for every compose invocation that
includes base.yml, so the demo (and any ad-hoc `docker compose up
controller` against base alone) routes through the typed pipeline:
bootstrap GET (#329), OpAMP-on-connect replan (#334), and per-metric
5-sketch family routing (#339 + #340 + the in-flight stitching PR).

The mvp-multi-stage.yml overlay already sets the same default; this
just promotes the gate to the base layer so it is on without the
overlay.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@zzylol
zzylol deleted the mvp/port-replan-push-config-to-typed branch May 9, 2026 18:00
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