Skip to content

ADR-015: Fix fabricated llm-infra-core dependency - #10

Merged
nicholas-ruest merged 1 commit into
mainfrom
adr-015/fix-package-naming
Jul 27, 2026
Merged

ADR-015: Fix fabricated llm-infra-core dependency#10
nicholas-ruest merged 1 commit into
mainfrom
adr-015/fix-package-naming

Conversation

@nicholas-ruest

Copy link
Copy Markdown
Member

Implements the observatory portion of agentics-enforcement/plans/adr/ADR-015 (step 4).

What was wrong

Cargo.toml:110 and crates/adapters/Cargo.toml:33 declared llm-infra-core. That crate does not exist and never has. The infra repo (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 eight features = [...] on that line were an invented facade rather than a misspelling. This blocked the entire Rust workspace at dependency resolution.

Verified on main before changing anything:

error: no matching package named `llm-infra-core` found
location searched: Git repository https://github.com/LLM-Dev-Ops/infra.git?branch=main
required by package `llm-observatory-adapters v0.1.1 (crates/adapters)`

What the code actually used

The whole upstream/infra.rs adapter (1049 lines) turns out to be self-contained: MetricsAdapter, LoggingAdapter, CacheAdapter, RateLimitAdapter and RetryAdapter each implement their behaviour from scratch over HashMap, std::time::Instant, tokio::time::sleep and the tracing crate. 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 From impls converting Observatory config types into infra config types. So this declares exactly the three crates those need, rather than all six the ADR lists for governance-dashboard — declaring infra-config and infra-otel would add git dependencies that nothing references.

Changes

  • Cargo.toml:110 — one fabricated llm-infra-core entry replaced with infra-cache, infra-errors, infra-rate-limit, git-pinned to rev = "a8bc89c190f63b139812f30a54e21a25b8f70e81". infra has no tags; that rev is current main (confirmed against git ls-remote).
  • crates/adapters/Cargo.toml:33 — the cascading llm-infra-core.workspace = true replaced with the same three.
  • crates/adapters/src/upstream/infra.rs — import block narrowed to what is used, and the From impls rewritten against the real APIs:
    • CacheConfig: new()/with_max_entries/with_default_ttl/with_statswith_max_size/with_ttl/with_metrics.
    • RetryConfig (from infra-errors): with_initial_delaywith_base_delay, with_max_attempts now takes usize, with_jitter now takes bool.
    • RateLimitConfig: the real type models requests_per_second, not max_requests + window, so the conversion divides by the window.
    • From<ObservatoryLogLevel> for LogLevel deleted — infra has no logging crate, so the target type does not exist under any name. LoggingAdapter already routed through tracing directly, so no behaviour changed.
  • crates/adapters/Cargo.toml — added rand = "0.8" (matching crates/collector and crates/storage). RetryAdapter::execute already called rand::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::new is fallible (Result<_, RateLimitError>) but From is not, so the fields are set directly and validation is bypassed. A zero-length window yields an infinite rate rather than an error. TryFrom would be more correct but changes the public API.
  • backoff_multiplier has no counterpart in infra_errors::RetryConfig, which selects a RetryStrategy enum 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-core resolution failure is gone — the pinned infra crates resolve. Resolution then proceeds far enough to hit a pre-existing, unrelated conflict:

error: failed to select a version for `libsqlite3-sys`.
    ... required by package `sqlx-sqlite v0.8.0`
    ... which satisfies dependency `sqlx-sqlite = "=0.8.0"` of package `sqlx v0.8.0`
    ... which satisfies dependency `sqlx = "^0.8"` of package `llm-observatory-storage v0.1.1 (crates/storage)`
versions that meet the requirements `^0.28.0` are: 0.28.0

package `libsqlite3-sys` links to the native library `sqlite3`, but it conflicts with a previous package which links to `sqlite3` as well:
package `libsqlite3-sys v0.26.0`
    ... which satisfies dependency `libsqlite3-sys = "^0.26.0"` of package `sqlx-sqlite v0.7.0`
    ... which satisfies dependency `sqlx-sqlite = "=0.7.0"` of package `sqlx v0.7.0`
    ... which satisfies dependency `sqlx = "^0.7"` of package `llm-cost-ops v0.1.1 (github.com/LLM-Dev-Ops/cost-ops?branch=main#aef76ae9)`

This is not caused by this PR. Confirmed by deleting the llm-infra-core declaration outright on main — with no infra dependency of any kind in the graph, cargo generate-lockfile produces the identical error. It was simply masked before, because llm-infra-core failed resolution first. None of infra-cache, infra-errors or infra-rate-limit depends on sqlx or sqlite (their deps are async-trait, thiserror, serde, tokio, parking_lot, dashmap, chrono, uuid, rand).

Root cause: this repo pins sqlx = "0.8" (Cargo.toml:58) while llm-cost-ops on branch = "main" pins sqlx = "0.7" with the sqlite feature; the two pull libsqlite3-sys 0.28 and 0.26, and cargo allows only one package claiming links = "sqlite3".

Because cargo build --workspace cannot complete until that is resolved, the four rewritten From impls were compiled against the real crates in isolation instead — same three git dependencies at the same pinned rev, same impl bodies:

   Compiling infra-errors v0.1.0 (https://github.com/LLM-Dev-Ops/infra.git?rev=a8bc89c1...)
   Compiling infra-rate-limit v0.1.0 (https://github.com/LLM-Dev-Ops/infra.git?rev=a8bc89c1...)
   Compiling infra-cache v0.1.0 (https://github.com/LLM-Dev-Ops/infra.git?rev=a8bc89c1...)
   Compiling infracheck v0.1.0
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 45s

Clean, no warnings.

Left undone

  • cargo build --workspace still does not pass, and the test suite was never reached, because of the libsqlite3-sys conflict above. That needs a human decision and is outside ADR-015's scope — the options are to pin llm-cost-ops to a rev using sqlx 0.8, upgrade cost-ops upstream, drop sqlite from its feature list (nothing in observatory asks for it), or downgrade this repo's sqlx to 0.7. I did not want to pick one unilaterally; each changes either a shared upstream repo or this repo's storage layer.
  • The other upstream git dependencies at Cargo.toml:99-106 (schema-registry-core, llm-config-core, llm-latency-lens-core, llm-cost-ops, llm-sentinel-core) still use branch = "main" rather than a pinned rev. ADR-015's decision 4 wants rev/tag pins fleet-wide, but their names are correct, so they are out of scope here.

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
@nicholas-ruest
nicholas-ruest merged commit 020f903 into main Jul 27, 2026
3 of 7 checks passed
@nicholas-ruest
nicholas-ruest deleted the adr-015/fix-package-naming branch July 27, 2026 20:26
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