…N string lists
ADP strictly decodes local configuration before connecting to the Agent's
configuration stream, so a value the Agent accepts but ADP rejects aborts
startup. Integers written with a base prefix (`0x10`) failed to decode, a
leading-zero integer (`010`) silently read as decimal instead of octal, and a
string-list value holding a JSON list read as a single element.
Add a `go-strconv` crate porting Go's `strconv.ParseBool`, `ParseInt(s, 0, 64)`,
and `ParseFloat(s, 64)` (including hexadecimal floats), and use it for every
string-to-scalar coercion. Read string lists as the Agent's `cast` fork does:
a JSON list of strings first, else split on whitespace.
Refs #2753
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
ADP decodes its local file and environment strictly before it connects to the Datadog Agent's configuration stream, so any value the Agent accepts but ADP rejects stops ADP from starting at all, and any value ADP reads differently is wrong until the stream replaces it (or for good, when it's consumed before the stream connects, like
agent_ipc.grpc_max_message_size). TodayDD_DOGSTATSD_PORT=0x10aborts the boot,010silently reads as 10 where the Agent reads 8, andDD_APM_OBFUSCATION_ELASTICSEARCH_KEEP_VALUES='["a","b"]'becomes one bogus element. This makes ADP read numeric strings and string lists exactly as the Agent does, by porting Go'sstrconvgrammars into a sharedlib/go-strconvcrate (alongsidelib/go-duration), including hexadecimal floats.Refs #2753.
flowchart LR S["string value<br/>(env var, quoted YAML, stream string)"] --> T{leaf type} T -->|integer| I["trimZeroDecimal →<br/>go_strconv::parse_int<br/>(0x / 0o / 0b / 0-octal / _)"] T -->|number| F["go_strconv::parse_float<br/>(decimal, hex, _)"] T -->|boolean| B[go_strconv::parse_bool] T -->|"string list<br/>(no env_parser)"| L{"JSON list<br/>of strings?"} L -->|yes| J[that list] L -->|no| W[split on whitespace]Out of scope, left to the related compatibility decisions: malformed inputs the Agent keeps as raw strings with a warning while ADP rejects them (bool words like
on,1.342177295e+08for an integer, non-JSON maps/lists), covered by #2755 and #2756. Surrounding whitespace on a number stays trimmed (the Agent rejects it), andNaN/Infstay rejected since JSON can't carry them.The corpus-replay expectations for
depth-env-hex,int-string-base-prefix(theDD_DOGSTATSD_PORTboot entry), anddepth-env-json-list(keep_values) should flip once that harness lands; it isn't onmainyet, so they aren't updated here.Test plan
go-strconvunit tests; every expected value was produced by Go 1.27'sstrconvgo-strconvagainst Go on 200k random number-like strings (400k int/float checks, 0 mismatches); the harness isn't committedcast_de,env_decode, andlist_decases for base-prefixed integers, hex floats, and JSON-list stringsenv_readertest covering the recorded corpus inputs plus010→ 8 and a hex floatevery_scalar_leaf_accepts_the_agent_castable_form_of_its_typenow writes every integer leaf in hexadecimalloaded.rstest drives real environment variables throughLoadedConfiguration::loadand connected startup (run)🤖 Generated with Claude Code