Skip to content

fix(edge): pin cold-ship/control-channel decoupling + e2e-validate cold path - #500

Merged
zzylol merged 1 commit into
mainfrom
fix/edge-cold-ship-decouple
Jun 14, 2026
Merged

zzylol merged 1 commit into
mainfrom
fix/edge-cold-ship-decouple

Conversation

@zzylol

@zzylol zzylol commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Context

The cold-archive ship from the edge feeds the cold-fallback evaluation (Fig 7 cold arm). The concern: under static config (cold.enabled: true, control_channel.enabled: false) cold fragments never ship, so MinIO/archive stays empty. PR #373 fixed the QUERY-side routing; this is the EDGE-side follow-up.

Investigation result (honest)

The edge cold-fragment shipper is already decoupled from the control channel. Cold ingest (ingest.go), cold flush+ship (flush.go flushAll/flushShardWarmCold), and ship-worker startup (processor.go Start) are all gated solely on cold.enabled; the control channel (startControlPlane) is an independent path that only applies precompute.PrecomputeConfigSet updates to sketch aggregators. A grep for any conjunction of {ctrl/ControlChannel/control} with {cold/ship/frag} in non-test Go returns nothing. There was no control-channel gate to remove. The static config deploy/mvp-multinode/configs/asap/asap-otel-agent-asapedge.yaml (cold on, ship_endpoint set, control_channel disabled) ships cold under exactly this code.

Change (minimal, defensive — no behavior change)

  • TestColdShipsWithControlChannelDisabled pins the invariant: drives the processor through its real lifecycle (StartConsumeMetricsflushAll → async ship) with cold.enabled: true + control_channel.enabled: false, asserts ctrlChan == nil, and verifies gzipped ASAPFRG1 fragments reach the HTTP sink and decode back to the ingested series. A regression that re-couples shipping to the control channel fails it.
  • A load-bearing INVARIANT comment at p.shipWorker.start() in Start().

E2E validated LIVE on this machine

Against the runnable gorilla-merger (built go build ./cmd/gorilla-merger), using the same asap-gorilla-go encoder the edge uses:

  1. POST /ingest/gorilla200 (30-sample XOR fragment)
  2. pending L1 block built on flush
  3. queryable via Thanos StoreAPI — gRPC Series returns the series, all 30/30 samples decoded back
  4. compaction → shipped L2 block
  5. live object-store PUT to a local MinIO bucket — shipper uploaded blocks uploaded=1; block chunks/index/meta.json verified in-bucket (numSamples: 30, thanos.labels: {cluster, merger, tier})

Details: datasets_eval/cold-path-e2e-validation.md.

Still docker/compose-gated (NOT claimed)

The cross-service compose stack as one unit (edge collector + data-plane + thanos-query/store-gateway read leg) and the full Fig 7 cold-arm latency/recall numbers.

Tests

  • asapedgeprocessor go test ./... — PASS (incl. the new test)
  • gorilla-merger go test ./internal/... — PASS

🤖 Generated with Claude Code

…ld path

The edge cold-fragment shipper is gated SOLELY on cold.enabled and is already
independent of the control channel (which only carries coordinated-sampling
PrecomputeConfigSet updates) — so a static-config edge with cold.enabled: true
and control_channel.enabled: false DOES ship its cold tier. Investigation across
processor.go / cold_fragment_shipper.go / cold_spool.go / flush.go / ingest.go
found no control-channel gate on shipping; there was nothing to remove.

This change pins that decoupling so it can't regress, and validates the cold
path end to end against the runnable gorilla-merger:

- Add TestColdShipsWithControlChannelDisabled: drives the processor through its
  real lifecycle (Start -> ConsumeMetrics -> flushAll -> async ship) with
  cold.enabled + control_channel.enabled=false, asserts ctrlChan==nil, and
  verifies gzipped ASAPFRG1 fragments reach the HTTP sink and decode back to the
  ingested series. A regression that re-couples shipping to the control channel
  fails it.
- Add a load-bearing INVARIANT comment at p.shipWorker.start() in Start().

E2E validated live on this machine (see datasets_eval/cold-path-e2e-validation.md):
edge-encoder ASAPFRG1 fragments -> gzip POST /ingest/gorilla (200) -> pending L1
block -> queryable via Thanos StoreAPI (30/30 samples round-trip) -> compaction
to L2 -> live object-store PUT to a local MinIO bucket (uploaded=1; block
chunks+index+meta.json verified in-bucket). Remaining docker/compose-gated: the
cross-service stack (edge collector + data-plane + thanos-query/store-gateway
read leg) and the full Fig 7 cold-arm latency/recall numbers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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