Skip to content

enhancement(agent-data-plane): let the binary declare its own identity - #2346

Open
jszwedko wants to merge 8 commits into
jszwedko/fail-on-placeholder-build-metadatafrom
jszwedko/binary-owned-app-identity
Open

enhancement(agent-data-plane): let the binary declare its own identity#2346
jszwedko wants to merge 8 commits into
jszwedko/fail-on-placeholder-build-metadatafrom
jszwedko/binary-owned-app-identity

Conversation

@jszwedko

@jszwedko jszwedko commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #2345. Base is jszwedko/fail-on-placeholder-build-metadata; review that one first. The diff shown here is only this step.

Human Summary

Move static metadata or inferable metadata (version) into ADP to remove the need to set some of the APP_ variables. This, I think, will remove one source of bugs resulting from inconsistent setting as was seen in #2343 and enable easier local development (don't need to remember to set the variables). Instead, we only set the metadata that is only known at build time (like 🥁 the build time).

AI Summary

saluki-metadata bakes the application's name and version into a shared library at compile time — something it fundamentally cannot do per-binary, since one compiled copy is shared by every binary in the workspace. The only lever scoped to a single build command is the process environment, which is why every build entry point has had to independently remember the same four values. That's thirteen places, and the drift it produces is what the last two PRs were cleaning up. This removes the cause rather than the symptoms.

The fix is to split the eight fields by what they actually describe:

Per-binary — moves to the binary Per-build — stays in the build script
full_name, short_name, identifier, version git_hash, build_time, dev_build, target_arch

ADP declares the left column once, in main.rs:

pub const APP_DETAILS: AppDetails = saluki_metadata::declare_app_details!(
    full_name  = "Agent Data Plane",
    short_name = "data-plane",
    identifier = "adp",
);

The version comes from Cargo — env! inside the macro expands in the calling crate, so it picks up ADP's version, and CARGO_PKG_VERSION_{MAJOR,MINOR,PATCH} replaces the hand-rolled version splitting in the build script. The right column is genuinely shared (one build has one git hash regardless of how many binaries it produces), so it stays put — as does the release-metadata guard from #2345, narrowed to the fields it still covers. target_arch has to stay there regardless: TARGET is only set for build scripts.

Registration happens as the first statement of main. The details are a compile-time constant with no relationship to configuration, so they're registered before anything else rather than being routed through the config-driven bootstrap phase — which also means the window where config loading and logging translation run is already covered. The get_app_details() signature is unchanged, so every existing call site is untouched, including saluki-app and the version command.

Net effect: APP_FULL_NAME, APP_SHORT_NAME, APP_IDENTIFIER, and APP_VERSION stop being build inputs entirely and disappear from the Makefile, Dockerfile.agent-data-plane, .gitlab/build.yml, both Windows scripts, the AIX script, and both antithesis Dockerfiles. This also makes the value fixes in #2343 and the metadata completion in #2345 moot by deletion — those lines no longer exist to drift.

Also included

run_inner's Action::Version arm was unreachable — version returns early, before configuration is loaded, so that reporting the version never depends on usable config. The dead arm quietly implied the opposite, so it now asserts the invariant instead: removing the early return fails loudly rather than silently turning version into a config-requiring command.

Behavior changes

  • A bare cargo build now produces a correctly identified binary. This was the original motivation, and it's per-binary rather than the workspace-wide .cargo/config.toml default we ruled out earlier.
  • Windows version strings are fixed. Non-tag Windows builds embedded v12345-abc1234 (a pipeline slug) as the version; they now report the real version, matching every other platform. No other platform's version string changes — the container and tarball paths already used the Cargo version.
  • ADP_APP_VERSION survives in the Makefile, but only because release artifacts are named after it.

Test plan

  • cargo build with no environment at all reports Agent Data Plane / data-plane / adp / 1.6.0 — previously unknown
  • make build-adp reports the same, plus a real git hash
  • agent-data-plane version still prints v1.6.0-<sha>; the leading v is display-only and unaffected
  • cargo clippy --workspace --all-targets clean; 1235 tests pass across saluki-metadata, saluki-app, saluki-components, datadog-agent-commons, and agent-data-plane
  • Confirmed no dangling references to the four removed variables anywhere in the repo
  • New tests/version_cli.rs asserts the built binary reports its real identity — verified it actually catches a regression by moving the registration below the version early-return, which compiles fine and fails the test
  • Container, Windows, and AIX builds are unexercised locally — worth a pipeline run before this leaves draft

Follow-up, not in this PR

Library unit tests observe the unregistered fallback, because there's no main() to register. That's true today as well (the build script yields unknown under cargo test), so nothing regresses — endpoints.rs asserts 0-0-0-unknown.agent against itself either way. What changes is that it becomes fixable: identity can now be injected at runtime. Doing it properly needs an idempotent helper, since a OnceLock is shared across parallel tests in one binary.

saluki-metadata baked the application's name and version into a shared library at compile
time, which it fundamentally can't do per-binary: one compiled copy is shared by every
binary in the workspace. The only lever scoped to a single build command was the process
environment, so every build entry point had to independently remember the same four
values. Thirteen places, and the drift they produced has been the subject of the last two
PRs.

Split the eight fields by what they actually describe. Name and version identify a
specific application, so ADP now declares them with `declare_app_details!` and registers
them during bootstrap; the version comes from Cargo. Git hash, build time, dev build, and
target arch describe the build rather than the application, so they stay exactly where
they were, in saluki-metadata's build script.

Ordering is enforced structurally rather than by convention: AppBootstrapper takes the
details and registers them before initializing any subsystem, so the one library consumer
that runs during bootstrap (the logging subagent prefix) can't observe an unregistered
application. ADP's own call sites use the constant directly, which covers `version`
running before bootstrap.

Net effect: APP_FULL_NAME, APP_SHORT_NAME, APP_IDENTIFIER, and APP_VERSION stop being
build inputs and disappear from the Makefile, both Dockerfiles, GitLab CI, both Windows
scripts, and the AIX script. A bare `cargo build` now produces a correctly identified
binary, which is what prompted this in the first place.
@dd-octo-sts dd-octo-sts Bot added area/core Core functionality, event model, etc. area/ci CI/CD, automated testing, etc. area/observability Internal observability of ADP and Saluki. area/docs Reference documentation. area/test All things testing: unit/integration, correctness, SMP regression, etc. labels Aug 14, 2026
@pr-commenter

pr-commenter Bot commented Aug 14, 2026

Copy link
Copy Markdown

Binary Size Analysis (Agent Data Plane)

Baseline: 0f47357 · Comparison: 3cabab8 · diff
Analysis Configuration: stripped binaries · Pass/Fail Threshold: +5%
Sizes: 41.27 MiB (baseline) vs 41.27 MiB (comparison)
Size Change: +6.75 KiB (+0.02%)

✅ Binary size difference within threshold

Changes by Module
Module File Size Symbols
tonic +23.44 KiB 30
http_body_util -20.06 KiB 34
anon.9025c6fd4a0a51cad91457cfe87a71e4.13.llvm.18245512350128999780 +17.18 KiB 1
anon.6c8cc82583d787f2710e1f8f86e78987.13.llvm.13314861055718887123 -17.17 KiB 1
agent_data_plane_config::shared::_ -12.38 KiB 16
anon.1d8517c8059ad43009e1259e7daa13a7.669.llvm.15455447979520375041 +11.93 KiB 1
anon.eaa35ebdc5998855717b6f667ad22404.791.llvm.3148331925466594304 -11.93 KiB 1
agent_data_plane_config::domains::dogstatsd +10.43 KiB 13
anon.9025c6fd4a0a51cad91457cfe87a71e4.188.llvm.18245512350128999780 +9.81 KiB 1
anon.6c8cc82583d787f2710e1f8f86e78987.188.llvm.13314861055718887123 -9.81 KiB 1
anon.9025c6fd4a0a51cad91457cfe87a71e4.17.llvm.18245512350128999780 +9.16 KiB 1
anon.6c8cc82583d787f2710e1f8f86e78987.17.llvm.13314861055718887123 -9.16 KiB 1
anon.1d8517c8059ad43009e1259e7daa13a7.6.llvm.15455447979520375041 +8.50 KiB 1
anon.b4c2f64c550c4589f85f6dbb07966708.4.llvm.712483885966489896 -8.49 KiB 1
tracing_subscriber +7.15 KiB 27
anon.1d8517c8059ad43009e1259e7daa13a7.12.llvm.15455447979520375041 +6.94 KiB 1
anon.b4c2f64c550c4589f85f6dbb07966708.27.llvm.712483885966489896 -6.93 KiB 1
anon.b4c2f64c550c4589f85f6dbb07966708.239.llvm.712483885966489896 -6.18 KiB 1
anon.1d8517c8059ad43009e1259e7daa13a7.617.llvm.15455447979520375041 +6.09 KiB 1
tracing_appender -6.00 KiB 3
Detailed Symbol Changes
    FILE SIZE        VM SIZE    
 --------------  -------------- 
  [NEW] +17.2Ki  [NEW]     +76    anon.9025c6fd4a0a51cad91457cfe87a71e4.13.llvm.18245512350128999780
  [NEW] +14.7Ki  [NEW] +14.6Ki    agent_data_plane::state::metrics::rules::get_compat_remappings::h988e27bcdad70c35
  +105% +12.0Ki  +106% +12.0Ki    agent_data_plane::state::metrics::rules::get_datadog_agent_remappings::h4cb0b5de28120f9b
  [NEW] +11.9Ki  [NEW]     +81    anon.1d8517c8059ad43009e1259e7daa13a7.669.llvm.15455447979520375041
  [NEW] +9.81Ki  [NEW]     +79    anon.9025c6fd4a0a51cad91457cfe87a71e4.188.llvm.18245512350128999780
  [NEW] +9.16Ki  [NEW]     +91    anon.9025c6fd4a0a51cad91457cfe87a71e4.17.llvm.18245512350128999780
  [NEW] +8.50Ki  [NEW]     +81    anon.1d8517c8059ad43009e1259e7daa13a7.6.llvm.15455447979520375041
 +11e2% +7.58Ki +13e2% +7.58Ki    serde_core::ser::SerializeMap::serialize_entry::h728aad161ebf36c2
  +0.1% +6.42Ki  +0.2% +7.57Ki    [6933 Others]
  [NEW] +6.94Ki  [NEW]     +77    anon.1d8517c8059ad43009e1259e7daa13a7.12.llvm.15455447979520375041
  [NEW] +6.09Ki  [NEW]     +79    anon.1d8517c8059ad43009e1259e7daa13a7.617.llvm.15455447979520375041
  [DEL] -6.18Ki  [DEL]     -79    anon.b4c2f64c550c4589f85f6dbb07966708.239.llvm.712483885966489896
 -96.1% -6.54Ki -98.7% -6.57Ki    _<serde_json::ser::Compound<W,F> as serde_core::ser::SerializeStruct>::serialize_field::hdd4aaf394e2ce237
  [DEL] -6.93Ki  [DEL]     -77    anon.b4c2f64c550c4589f85f6dbb07966708.27.llvm.712483885966489896
  [DEL] -8.49Ki  [DEL]     -81    anon.b4c2f64c550c4589f85f6dbb07966708.4.llvm.712483885966489896
  [DEL] -9.16Ki  [DEL]     -91    anon.6c8cc82583d787f2710e1f8f86e78987.17.llvm.13314861055718887123
  [DEL] -9.81Ki  [DEL]     -79    anon.6c8cc82583d787f2710e1f8f86e78987.188.llvm.13314861055718887123
  [DEL] -11.9Ki  [DEL]     -81    anon.eaa35ebdc5998855717b6f667ad22404.791.llvm.3148331925466594304
  [DEL] -12.6Ki  [DEL] -12.5Ki    agent_data_plane::state::metrics::rules::dogstatsd::get_dogstatsd_remappings::h069d38e10ec08aa6
  [DEL] -14.8Ki  [DEL] -14.7Ki    agent_data_plane::state::metrics::rules::compat::get_compat_remappings::h8f85ea9596b4bcb8
  [DEL] -17.2Ki  [DEL]     -76    anon.6c8cc82583d787f2710e1f8f86e78987.13.llvm.13314861055718887123
  +0.0% +6.75Ki  +0.0% +8.06Ki    TOTAL

Comment thread ci/tooling/build-adp-aix.sh Outdated
Comment thread ci/tooling/windows-build-adp.ps1 Outdated
Comment thread ci/tooling/windows-integration-tests.ps1 Outdated
Comment thread docs/agent-data-plane/releasing.md Outdated
Comment thread Makefile Outdated
handle_version_command's signature change wasn't buying anything: APP_DETAILS is a crate
const, so the function can just read it. The actual requirement is only that it not use
get_app_details(), since it can run before bootstrap registers.
`version` returns early, before configuration is loaded, so that reporting the version
never depends on there being usable config. That made run_inner's Version arm dead code
which quietly implied the opposite. Assert the invariant instead, so removing the early
return fails loudly rather than silently turning `version` into a config-requiring
command.
…mments

Drop the comments narrating which values moved out of the build tooling, and restore the
build metadata description in the release docs. The comments described the change rather
than the current state, which isn't useful to a later reader.
@pr-commenter

pr-commenter Bot commented Aug 14, 2026

Copy link
Copy Markdown

Regression Detector (Agent Data Plane)

Run ID: 13061cc6-e347-42a8-b66e-b4a26ad27b34
Baseline: 0f47357a · Comparison: 3cabab83 · diff

Optimization Goals: ✅ No significant changes detected

Fine details of change detection per experiment (5)

Experiments configured erratic: true are tagged (ignored) and skipped when determining which experiments regressed or improved. Experiments which are detected as erratic at runtime are tagged (erratic) to flag that the run's sample dispersion was high, but their regression / improvement signal still counts.

experiment goal Δ mean % links
quality_gates_rss_dsd_heavy memory ⚪ +0.04 metrics profiles logs
quality_gates_rss_dsd_low memory ⚪ -0.36 metrics profiles logs
quality_gates_rss_idle memory ⚪ -0.40 metrics profiles logs
quality_gates_rss_dsd_medium memory ⚪ -0.48 metrics profiles logs
quality_gates_rss_dsd_ultraheavy memory ⚪ -0.99 metrics profiles logs
Bounds Checks: ✅ Passed (5)
experiment check replicates observed links
quality_gates_rss_dsd_heavy memory_usage 10/10 ✅ 228 MiB ≤ 250 MiB metrics profiles logs
quality_gates_rss_dsd_low memory_usage 10/10 ✅ 51.2 MiB ≤ 60 MiB metrics profiles logs
quality_gates_rss_dsd_medium memory_usage 10/10 ✅ 90.1 MiB ≤ 100 MiB metrics profiles logs
quality_gates_rss_dsd_ultraheavy memory_usage 10/10 ✅ 384 MiB ≤ 420 MiB metrics profiles logs
quality_gates_rss_idle memory_usage 10/10 ✅ 31.7 MiB ≤ 40 MiB metrics profiles logs
Explanation

A change is flagged as a regression when |Δ mean %| > 5.00% in the regressing direction for its optimization goal AND SMP marks the experiment as a regression (is_regression: true). Improvements use the matching criteria for the improving direction. Experiments configured erratic: true (tagged (ignored)) are skipped outright; experiments detected as erratic at runtime (tagged (erratic)) still count, since that flag describes sample dispersion rather than directional certainty. The Δ mean % cell is colored accordingly: 🟢 = improvement, 🔴 = regression, ⚪ = neutral. Reduction in CPU or memory is an improvement; reduction in ingress throughput is a regression. Experiments tagged (no analysis) show ⚠️ n/a: SMP ran them but produced no analysis, usually because a replicate failed and exhausted its retries. Check the SMP report for that experiment's replicate failures.

…tstrap

Application details are a compile-time constant with no relationship to configuration, so
routing them through AppBootstrapper coupled them to the config-driven bootstrap phase for
no reason: from_configuration took an argument unrelated to configuration, and `version`
needed a special case to read the constant directly because it runs beforehand.

Registering at the top of main is both simpler and strictly earlier, which also closes the
window where config loading and logging translation ran with the details unregistered.
saluki-app and the version command revert to their original shapes.
@dd-octo-sts dd-octo-sts Bot removed the area/observability Internal observability of ADP and Saluki. label Aug 14, 2026
Action::Dogstatsd(cmd) => handle_dogstatsd_command(local_config, cmd).await,
Action::Version(v) => handle_version_command(v.json).await,
// Handled before bootstrap, so that reporting the version never depends on there being usable configuration.
Action::Version(_) => unreachable!("version is handled before bootstrap"),

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is an unrelated change, but 🤖 noticed it while I was in the area.

@jszwedko
jszwedko marked this pull request as ready for review August 14, 2026 22:48
@jszwedko
jszwedko requested review from a team as code owners August 14, 2026 22:48
Registering the application's details is a one-line call at the top of main, and forgetting
it degrades silently to reporting an unknown application. No other test in the workspace
can catch that: library unit tests have no main, so they legitimately observe the same
unregistered fallback.

Exercise the real binary instead. Verified by moving the registration below the version
early-return, which the compiler accepts and this test rejects. Parsing the output as JSON
also pins the version command to running before logging is initialized, since log output on
stdout would otherwise break it.

@datadog-official datadog-official Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Datadog Autotest: PASS

More details

ADP registers its identity before every repository consumer can read it, including CLI version reporting, logging, endpoints, and IPC registration. The remaining metadata stays compile-time populated, and all repository build entry points were updated consistently with the removed identity variables.

Was this helpful? React 👍 or 👎

Open Bits AI session

🤖 Datadog Autotest · Commit 8956d37 · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8956d37fbe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/saluki-metadata/build.rs Outdated
Vale flags the bare keyword as a misspelling, and the surrounding code already refers to
it in backticks.
…ally

The check only ran when some build metadata had already been supplied, so declaring a
release build while supplying none of it skipped the check entirely and shipped
placeholders -- reachable through a direct Docker build, since the Dockerfile defaults
both arguments to empty.

That gate was based on a mistaken premise: that tag-pipeline test and lint jobs supply no
metadata. They run through the Makefile, which exports it for every recipe, so they carry
real values and satisfy the check like any other build.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ci CI/CD, automated testing, etc. area/core Core functionality, event model, etc. area/docs Reference documentation. area/test All things testing: unit/integration, correctness, SMP regression, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant