ADR-015: Fix fabricated llm-infra-core dependency - #10
Merged
Conversation
The `infra` repo publishes flat, separately-named crates and has never had an aggregator crate, so `llm-infra-core` failed workspace resolution outright. The adapter implements metrics, logging, caching, rate limiting and retry itself; its only real coupling to infra is four `From` impls converting Observatory config types to infra config types. Declare just the three crates those need -- infra-cache, infra-errors, infra-rate-limit -- pinned to a rev, and rewrite the impls against the real APIs. `From<ObservatoryLogLevel> for LogLevel` is dropped: infra has no logging crate, so the target type does not exist under any name. Also adds the `rand` dependency that RetryAdapter's jitter already used but was never declared -- a second break in the same file that was masked by the resolution failure. Implements the observatory portion of agentics-enforcement/plans/adr/ADR-015
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.
Implements the observatory portion of
agentics-enforcement/plans/adr/ADR-015(step 4).What was wrong
Cargo.toml:110andcrates/adapters/Cargo.toml:33declaredllm-infra-core. That crate does not exist and never has. Theinfrarepo (github.com/LLM-Dev-Ops/infra) publishes flat, separately-named crates —infra-config,infra-otel,infra-errors,infra-cache,infra-retry,infra-rate-limit, and 13 more — with no aggregator crate, so the eightfeatures = [...]on that line were an invented facade rather than a misspelling. This blocked the entire Rust workspace at dependency resolution.Verified on
mainbefore changing anything:What the code actually used
The whole
upstream/infra.rsadapter (1049 lines) turns out to be self-contained:MetricsAdapter,LoggingAdapter,CacheAdapter,RateLimitAdapterandRetryAdaptereach implement their behaviour from scratch overHashMap,std::time::Instant,tokio::time::sleepand thetracingcrate. None of them stores or calls an infra type.Of the 30 symbols in the
use llm_infra_core::{...}block, 13 do not exist anywhere in the real infra repo under any name (CacheStats,ConfigValue,Environment,ErrorKind,Timer,RetryResult,SpanContext,TraceId,TracingConfig,LogContext,LogLevel,Logger,StructuredLogger), and most of the rest appeared only in the import itself.The only genuine coupling is four
Fromimpls converting Observatory config types into infra config types. So this declares exactly the three crates those need, rather than all six the ADR lists forgovernance-dashboard— declaringinfra-configandinfra-otelwould add git dependencies that nothing references.Changes
Cargo.toml:110— one fabricatedllm-infra-coreentry replaced withinfra-cache,infra-errors,infra-rate-limit, git-pinned torev = "a8bc89c190f63b139812f30a54e21a25b8f70e81".infrahas no tags; that rev is currentmain(confirmed againstgit ls-remote).crates/adapters/Cargo.toml:33— the cascadingllm-infra-core.workspace = truereplaced with the same three.crates/adapters/src/upstream/infra.rs— import block narrowed to what is used, and theFromimpls rewritten against the real APIs:CacheConfig:new()/with_max_entries/with_default_ttl/with_stats→with_max_size/with_ttl/with_metrics.RetryConfig(frominfra-errors):with_initial_delay→with_base_delay,with_max_attemptsnow takesusize,with_jitternow takesbool.RateLimitConfig: the real type modelsrequests_per_second, notmax_requests+ window, so the conversion divides by the window.From<ObservatoryLogLevel> for LogLeveldeleted — infra has no logging crate, so the target type does not exist under any name.LoggingAdapteralready routed throughtracingdirectly, so no behaviour changed.crates/adapters/Cargo.toml— addedrand = "0.8"(matchingcrates/collectorandcrates/storage).RetryAdapter::executealready calledrand::random::<f64>()for jitter but the dependency was never declared; this was a second break in the same file, masked behind the resolution failure.Two judgment calls worth a reviewer's eye, both noted in comments in the source:
RateLimitConfig::newis fallible (Result<_, RateLimitError>) butFromis not, so the fields are set directly and validation is bypassed. A zero-length window yields an infinite rate rather than an error.TryFromwould be more correct but changes the public API.backoff_multiplierhas no counterpart ininfra_errors::RetryConfig, which selects aRetryStrategyenum variant instead of taking a numeric multiplier. The field stays on the Observatory type (its own retry loop still uses it) but does not map across.Build output
The
llm-infra-coreresolution failure is gone — the pinned infra crates resolve. Resolution then proceeds far enough to hit a pre-existing, unrelated conflict:This is not caused by this PR. Confirmed by deleting the
llm-infra-coredeclaration outright onmain— with no infra dependency of any kind in the graph,cargo generate-lockfileproduces the identical error. It was simply masked before, becausellm-infra-corefailed resolution first. None ofinfra-cache,infra-errorsorinfra-rate-limitdepends onsqlxorsqlite(their deps areasync-trait,thiserror,serde,tokio,parking_lot,dashmap,chrono,uuid,rand).Root cause: this repo pins
sqlx = "0.8"(Cargo.toml:58) whilellm-cost-opsonbranch = "main"pinssqlx = "0.7"with thesqlitefeature; the two pulllibsqlite3-sys0.28 and 0.26, and cargo allows only one package claiminglinks = "sqlite3".Because
cargo build --workspacecannot complete until that is resolved, the four rewrittenFromimpls were compiled against the real crates in isolation instead — same three git dependencies at the same pinned rev, same impl bodies:Clean, no warnings.
Left undone
cargo build --workspacestill does not pass, and the test suite was never reached, because of thelibsqlite3-sysconflict above. That needs a human decision and is outside ADR-015's scope — the options are to pinllm-cost-opsto a rev usingsqlx 0.8, upgradecost-opsupstream, dropsqlitefrom its feature list (nothing in observatory asks for it), or downgrade this repo'ssqlxto 0.7. I did not want to pick one unilaterally; each changes either a shared upstream repo or this repo's storage layer.Cargo.toml:99-106(schema-registry-core,llm-config-core,llm-latency-lens-core,llm-cost-ops,llm-sentinel-core) still usebranch = "main"rather than a pinnedrev. ADR-015's decision 4 wants rev/tag pins fleet-wide, but their names are correct, so they are out of scope here.