controller: port handle_bootstrap_agent_config to typed-stage-split path - #329
Merged
Merged
Conversation
Phase 3.3 (#94) worked around the bootstrap-vs-replan-push divergence by adding a driver-side POST to /api/v1/plan after stack-up. This is the deep fix: handle_bootstrap_agent_config now mirrors handle_plan's typed L5 pipeline under USE_TYPED_STAGE_SPLIT=1 — bind_workload_typed → split_typed_three_stage → emit_for_runtime, dispatched by the X-Agent-Runtime header (defaults to Sketchcollector for legacy agents). Pinned-plan lookup via X-Agent-ID + the replanner's agent_to_metric mapping avoids drift between bootstrap and the first OpAMP push. A fresh agent fetching its initial config now sees the Phase 3.2.5 gorillas3 archive emit + warm-passthrough routing processor and the Phase ε.1.5 per-runtime dispatch without requiring the demo driver's explicit POST. The driver POSTs stay as a safety belt (they still exercise the typed-backend JSON push that the bootstrap GET doesn't fire). Backwards-compat: when USE_TYPED_STAGE_SPLIT is unset or the typed path can't resolve a workload (empty registry, unsupported topology) the handler falls back to the legacy generate_agent_config emit. Bootstrap never returns a 500 just because the typed path hit a gap. Tests: - bootstrap_legacy_path_when_env_unset — env unset → legacy ddsketch: - bootstrap_typed_path_when_env_set — env set + workload → typed ddsketchprocessor: - bootstrap_typed_path_sketchotap_runtime_dispatch — X-Agent-Runtime: sketchotap → otel_dataflow/v1 DAG YAML - bootstrap_typed_path_sketchtelegraf_runtime_dispatch → Telegraf TOML - bootstrap_typed_path_falls_back_to_legacy_when_no_workload — typed gate on but empty registry → legacy fallback (no 500) cargo test --release: 558 passed, 10 pre-existing failures unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 7, 2026
zzylol
added a commit
that referenced
this pull request
May 8, 2026
…rt + archive-tier accuracy ground truth (#332) This is the Option-B-as-sole-path validation re-run. With PR #329 (controller bootstrap GET → typed-stage-split) merged, the driver's post-stack-up `POST /api/v1/plan` workaround (PR #328) is redundant for the bootstrap path. Default it OFF so we can verify the bootstrap GET actually carries the load; operators can keep the safety belt by setting `ENABLE_OPTION_A_DRIVER_POST=1`. Three coupled fixes also land here so the demo's verdict matrix returns to all-green: 1. Backend container was crashing immediately on startup because `deploy/docker-compose/base.yml` passed `--ingest-port=9090` to a binary (`precompute_engine`, the deployed Dockerfile.backend target) that has no such flag — clap exited with `unexpected argument` and every subsequent Connection refused / failed POST from the controller cascaded from there. Drop the invalid flag and the redundant `19090:9090` host publish (Prometheus remote-write was deleted in ASAPQuery-backend PR #100; OTLP-only ingest goes over 4317 intra-docker). 2. `accuracy_reduce.py` is ported off the deleted `/var/asap/cold/raw/` JSONL tee onto the archive-engine-via-header path: `--cell-dir` re-issues each replay PromQL with `X-ASAP-Engine: thanos_archive` (Step 2.3 / PR #97) for ground truth. The driver's accuracy phase is rewritten to drop the `docker cp cold-truth/` step that was failing silently and skipping the entire reduce. The legacy JSONL path is kept behind `--use-jsonl` / `--use-jsonl-truth`. 3. STATUS detection in `capture_emitted_configs()` recognises the bootstrap-time typed marker (`[USE_TYPED_STAGE_SPLIT] emitted bootstrap config from typed path`) so a successful Option-B bootstrap renders as `live-bootstrap` even when the Option-A POST is gated off and `pushing typed` never fires. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
zzylol
added a commit
that referenced
this pull request
May 8, 2026
… pipeline (#334) `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>
4 tasks
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
handle_bootstrap_agent_config(the static/api/v1/collector-config/agentURL each fresh agent fetches at boot) off the legacygenerate_agent_configpath and onto the typed L5 emit pipeline thathandle_planalready uses — gated onUSE_TYPED_STAGE_SPLIT=1.X-Agent-Runtimeheader per Phase ε.1.5 (Sketchcollector/Sketchotap/Sketchtelegraf, defaults toSketchcollector); also honours an optionalX-Agent-IDheader so a previously-pinned agent gets the same workload its replanner mapping records — bootstrap and the first OpAMP push converge.generate_agent_configemit. Bootstrap never returns 500 just because the typed path hit a gap.Why this matters
Without this fix, a fresh agent connecting at startup misses Phase 3.2.5's
gorillas3archive emit + warm-passthrough routing processor and the Phase ε.1.5 per-runtime dispatch — those only arrive oncehandle_planis later invoked. Phase 3.3 (#94) worked around this by having the demo driver POST/api/v1/planafter stack-up; the driver POSTs stay as a safety belt (they exercise the typed-backend JSON push that the bootstrap GET doesn't fire), but the typed pipeline now runs at fetch time too.Test plan
cargo test --release -p controller— 558 passing, 10 pre-existing failures unchangedbootstrap_legacy_path_when_env_unset— env unset → legacyddsketch:blockbootstrap_typed_path_when_env_set— env set + registered workload → typedddsketchprocessor:(proves Phase 3.2.5'semit_edge_yamlis on the path)bootstrap_typed_path_sketchotap_runtime_dispatch—X-Agent-Runtime: sketchotap→otel_dataflow/v1DAG YAMLbootstrap_typed_path_sketchtelegraf_runtime_dispatch→ Telegraf TOMLbootstrap_typed_path_falls_back_to_legacy_when_no_workload— typed gate on + empty registry → legacy fallback (no 500)Files changed
controller/src/main.rs— handler rewrite + newemit_bootstrap_typedhelper + 5 unit tests + test-router wiringdocs/control-plane-design.md— new "Bootstrap and plan-push converge on the same emit pipeline" subsectiondocs/system-overview.md— new "Bootstrap fetch surface" entry under §6 Push surfacesdeploy/scripts/run_mvp_demo.sh— comment now describes the driver POST as a safety belt rather than a load-bearing step🤖 Generated with Claude Code