Skip to content

feat(asap-precompute-rs): otap codec (Phase 5 step B) - #256

Merged
zzylol merged 1 commit into
mainfrom
feat/otap-codec-phase5b
May 5, 2026
Merged

zzylol merged 1 commit into
mainfrom
feat/otap-codec-phase5b

Conversation

@zzylol

@zzylol zzylol commented May 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase B of the OTAP-Rust integration (per
docs/design-asap-otap-rust-integration.md §11):
the Layer-4 codec for the Arrow-native edge agent. Pure data-shape
translation between arrow::RecordBatch and the host-neutral
Observation / SketchEnvelope types — no Tokio tasks, no timers,
no control-channel inbox.

The codec lives at asap-precompute-rs/src/otap/, gated behind a
non-default otap Cargo feature so that the existing crate consumers
(sketchcollector, sketchtelegraf, the future sketchvector) don't
have to compile Apache Arrow when they don't need it.

New files

  • asap-precompute-rs/src/otap/mod.rs — module entry, public surface,
    schema documentation.
  • asap-precompute-rs/src/otap/schema.rs — well-known column /
    attribute names (Strategy-B carrier keys per
    edge-framework §7.2).
  • asap-precompute-rs/src/otap/decode.rsdecode_batch(&RecordBatch) -> Result<Vec<Observation>, OtapDecodeError>. One observation per
    row; routes envelope rows (non-null _asap_envelope cell) through
    KindEnvelope, scalar rows through KindFloat. Resolves columns
    once per batch then walks rows by index (the design-doc §4
    throughput win).
  • asap-precompute-rs/src/otap/encode.rsencode_batch(&[SketchEnvelope]) -> Result<RecordBatch, OtapEncodeError>. Strategy-B carrier:
    payload as Binary column, metadata as typed columns, labels as
    the sorted union of all envelope label keys.
  • asap-precompute-rs/src/otap/plugin.rsStubPlugin<P: Precompute>,
    the minimal "plugin compiles" shell that threads decode → observe →
    tick → encode. Comments mark the seams Phase C will fill in
    (NodeControlMsg::Wakeup, control-channel task, lifecycle drain).
  • asap-precompute-rs/tests/otap_codec.rs — integration tests:
    decode→encode round trip, encode→decode round trip, per-sketch-type
    smoke (DDSketch / KLL / HLL / CountSketch / CountMinSketch
    envelopes round-trip with payload intact), scalar-row decode
    asymmetry pin.

Verification

All four verification commands are green:

$ cargo test --release -p asap-precompute-rs --features otap
test result: ok. 57 passed; 0 failed [unit tests, lib + otap]
test result: ok. 11 passed; 0 failed [tests/api_surface.rs]
test result: ok. 7 passed; 0 failed [tests/cross_language_parity.rs]
test result: ok. 4 passed; 0 failed [tests/otap_codec.rs]
test result: ok. 27 passed; 0 failed [tests/runtime.rs]

$ cargo test --release -p asap-precompute-rs
test result: ok. 43 passed; 0 failed [unit tests, lib]
test result: ok. 11 passed; 0 failed
test result: ok. 7 passed; 0 failed
test result: ok. 27 passed; 0 failed
(0 results in tests/otap_codec.rs because the file is `#![cfg(feature = "otap")]`)

$ cargo clippy --release -p asap-precompute-rs --features otap --all-targets -- -D warnings
Finished `release` profile [optimized] target(s) in 0.70s

$ RUSTDOCFLAGS="-D warnings" cargo doc --no-deps -p asap-precompute-rs --features otap
Finished `dev` profile [unoptimized + debuginfo] target(s)

The 14 new otap::* unit tests plus the 4 new integration tests all
pass. No-feature build still passes the existing 88 tests; nothing in
otap leaked into the default build.

Deliberately deferred (Phase C / D)

Per docs/design-asap-otap-rust-integration.md §11, the following
are out of scope for Phase B and intentionally NOT in this PR:

  • Tokio interval timer / Wakeup-driven flush ticker (Phase C).
  • Control-channel poll task / NodeControlMsg::Config handling (Phase C).
  • otap-patch/plugins/asap_sketches/ directory and the real OTAP
    local::Processor<OtapPdata> impl (Phase C).
  • linkme distributed-slice registration in otap-patch/all/mod.rs
    (Phase D).
  • build_sketchotap.sh build pipeline (Phase D).
  • The full OtapArrowRecords shape with sibling resource / scope /
    per-row attribute child batches joined by integer ids — Phase B
    uses a flat per-row RecordBatch carrying the Strategy-B keys as
    ordinary columns. The Phase-C plugin shell is the layer that runs
    OTAP's native attribute join and projects an OtapArrowRecords
    down to the codec's flat shape.

StubPlugin exists solely to satisfy the §11 exit criterion ("plugin
compiles"); Phase C replaces it with a real OTAP plugin.

Schema decision (v1)

The codec discovers a flat per-row RecordBatch with well-known
columns by name (per design doc §4: "v1: pin to OTel-Arrow's
well-known schema"). Columns:

Column Arrow type Required Meaning
time_unix_nano UInt64 or Timestamp(Nanosecond) optional observation timestamp
metric Utf8 optional metric name
value Float64 optional scalar value (KindFloat)
_asap_envelope Binary optional envelope payload (KindEnvelope)
_asap_sketch_type Utf8 optional "DDSketch" / "KLLSketch" / …
_asap_agg_id UInt64 optional controller plan join key
_asap_schema_version UInt32 optional envelope schema version
_asap_window_start_ms UInt64 optional window inclusive lower bound
_asap_window_end_ms UInt64 optional window exclusive upper bound
_asap_encoding Utf8 optional "PROTO_FULL" / "PROTO_DELTA" / "MSGPACK"
any other Utf8 column Utf8 per-row label key

The Strategy-B keys are byte-identical to the table in
edge-framework §7.2;
schema.rs::tests::well_known_keys_match_edge_framework_doc pins
that contract.

Test plan

  • cargo test --release -p asap-precompute-rs --features otap — green.
  • cargo test --release -p asap-precompute-rs — still green; nothing in otap leaked into default build.
  • cargo clippy --release -p asap-precompute-rs --features otap --all-targets -- -D warnings — clean.
  • cargo doc --no-deps -p asap-precompute-rs --features otap — no broken intra-doc links.
  • decode-then-encode round trip preserves payload bytes per row.
  • encode-then-decode round trip preserves envelope bytes.
  • schema-mismatch error paths return OtapDecodeError with informative variants (not panics).
  • all five sketch types (DDSketch / KLL / HLL / CountSketch / CountMinSketch) round-trip with payload intact.

🤖 Generated with Claude Code

Adds the Layer-4 OTAP-Rust codec at `asap-precompute-rs/src/otap/`,
gated behind the non-default `otap` Cargo feature. Mirrors the
two-layer split pinned by `docs/design-asap-otap-rust-integration.md`
§2 and the Phase-4 Telegraf codec (PR #234) in shape: pure data-shape
translation between `arrow::RecordBatch` and the host-neutral
`Observation` / `SketchEnvelope` types, no Tokio tasks, no timers,
no control-channel inbox. Lifecycle (Wakeup-driven flush, control
channel, linkme registration) is Phase C and explicitly deferred.

The Strategy-B carrier keys (_asap_envelope, _asap_sketch_type, etc.)
are defined as constants matching edge-framework §7.2's table
byte-for-byte so cross-platform interop holds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@zzylol
zzylol merged commit 52f0a6a into main May 5, 2026
@zzylol
zzylol deleted the feat/otap-codec-phase5b 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