Skip to content

feat(logging): expose audited local log APIs and runtime telemetry - #1175

Merged
ndizazzo merged 1 commit into
logging-foundation-v3from
logging-api-v3
Aug 12, 2026
Merged

feat(logging): expose audited local log APIs and runtime telemetry#1175
ndizazzo merged 1 commit into
logging-foundation-v3from
logging-api-v3

Conversation

@ndizazzo

@ndizazzo ndizazzo commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

Second PR in the logging stack, based on #1174. This layer connects the logging foundation to runtime boundaries and exposes audited, trusted-local operator APIs.

Request and runtime instrumentation

  • Adds a typed OpenAI frontend lifecycle observer with canonical request IDs and exactly one terminal outcome for success, rejection, backend failure, timeout, stream error, cancellation, and disconnect/drop.
  • Bridges frontend events into the durable logging service without double-owning raw mesh ingress requests.
  • Records bounded routing attempts, stream progress, completion tokens, and operational outcomes across local, remote, plugin, pipeline, and Mixture-of-Agents paths.
  • Instruments management API, raw mesh, QUIC/tunnel, discovery, model/runtime, Skippy, command/auth, and node-revocation operations.
  • Preserves typed HTTP/transport outcomes so 4xx, 5xx, cancellation, and write/disconnect failures are classified correctly.

Trusted-local logs API

  • Adds paginated endpoints for request summaries, lifecycle events, artifacts, proxy attempts, and audit entries.
  • Adds a versioned SSE stream with bounded filters, cursors, replay windows, explicit replay-gap recovery, and audited local access.
  • Adds bounded export with artifact-content controls and stable DTO/error contracts.
  • Extends runtime status with logging capabilities and health information used by the console.

Maintenance and delivery

  • Adds preview/run scoped cleanup and per-request delete operations with idempotent, durable receipts.
  • Preserves typed not-found/conflict outcomes and safely replays completed cleanup receipts even when artifact capture is disabled.
  • Adds webhook delivery, retries, scheduling, receipts, and dead-letter retention.
  • Adds bounded logging-health metrics without introducing an OTLP log-record exporter.

Reliability and compatibility

  • Advances SSE replay cursors through eviction gaps so clients cannot loop on the same missing range.
  • Parses audit stream selection independently of query-parameter ordering and rejects duplicate selectors.
  • Validates node-revocation inputs before persistence and emits success audit records only after durable state changes.
  • Keeps the management/SSE surface local and additive; mesh protocol compatibility is unchanged.

Validation

  • PR Quality Checks — passed.
  • PR Builds — passed, including the repaired macOS unit-test lane.
  • PR Website Checks — passed.
  • Host logging tests: 262 passed.
  • Logs API route tests: 28 passed.
  • Log-store tests: 96 passed.
  • Focused transport/OpenAI lifecycle tests, formatting, and warnings-denied Clippy passed locally.

Stack

Guardrails

The management endpoints and SSE stream are trusted-local operator surfaces, not mesh protocols. This PR does not change protobuf/gossip schemas, ALPN labels, the native ABI, or add an OTLP log-record API. It intentionally contains no console implementation; the typed UI is isolated in #1176.

Summary by CodeRabbit

  • New Features
    • Added a trusted-local Logging API for viewing requests, events, artifacts, proxies, and audits.
    • Added live log streaming with replay, filtering, pagination, exports, cleanup, deletion, and webhook retry controls.
    • Added diagnostics and logging health details to status responses.
    • Added request ID propagation and structured token usage reporting.
    • Added privacy-safe operational auditing across commands, runtime, mesh, and model lifecycle events.
  • Bug Fixes
    • Improved validation, redaction, persistence reliability, retention, and recovery for logging operations.
  • Documentation
    • Added Local Logging API documentation and telemetry privacy guidance.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3e9b5713-d8d3-43a5-9112-824fe67a0957

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds a complete local logging and audit platform. It introduces durable SQLite storage (mesh-llm-log-store), a runtime logging service, replay bus, cleanup and webhook delivery workers (mesh-llm-host-runtime), a trusted-local Logging API, and operational audit events across CLI, mesh, and runtime code paths. It also adds lifecycle observability to the OpenAI ingress/transport path and openai-frontend, updates shared lifecycle event schemas with token usage and status codes, adds documentation and a QA certification harness, and fixes an unrelated tool-evidence repair gate in mesh-mixture-of-agents.

Changes

Local Logging Platform (Core)

Layer / File(s) Summary
Async logging foundation lifecycle
mesh-llm-host-runtime/src/lib.rs, .../sdk/embedded_logging.rs, Cargo.toml
Logging foundation initialization becomes async with serialized replacement, retirement, and CLI-only init/shutdown APIs.
Replay bus and metrics
.../logging/bus.rs, .../logging/metrics.rs, .../logging/mod.rs
ReplayBus gains independent lifecycle/audit replay history and broadcast fan-out; a fail-open LoggingMetrics sink is added.
Retention cleanup worker
.../logging/cleanup.rs, .../logging/cleanup/tests.rs
Adds a cancellable, TTL/row-cap cleanup worker with startup catch-up and audit reporting.
Terminal outcomes and lifecycle ownership
.../logging/lifecycle.rs, .../logging/management_lifecycle.rs, .../logging/operator_audit.rs, .../logging/output_projection.rs, .../logging/openai_lifecycle.rs, .../logging/raw_mesh_lifecycle.rs*
Adds status/usage-bearing terminal outcomes, management/OpenAI/raw-mesh lifecycle ownership adapters, and operator audit writes.
Registry, metadata, persistence, redaction
.../logging/registry.rs, .../logging/request_metadata.rs, .../logging/persistence.rs, .../logging/policy.rs*
Adds bounded active-request snapshots, privacy-safe metadata classification, and JSON-aware artifact redaction.
Runtime state, query facade, service pipeline
.../logging/runtime_state*, .../logging/service*
Adds LoggingRuntimeState, LoggingQueryFacade, worker orchestration, and a typed persistence pipeline with terminal priority lane.
Webhook delivery
.../logging/webhook_delivery*, .../logging/webhook_scheduler.rs
Adds a bounded async webhook delivery worker and scheduler with retry, dead-lettering, and manual retry.

Local Logging API

Layer / File(s) Summary
Access control and managed headers
api/access.rs, api/http.rs, api/management_lifecycle.rs, api/server.rs, api/status.rs
Marks /api/logs trusted-local-only, adds bounded response-head handling with scoped request IDs, and status payload logging fields.
Diagnostics and route wiring
api/routes/diagnostics.rs, api/routes/mod.rs, api/routes/mcp.rs, api/routes/plugins.rs, api/routes/runtime.rs
Adds /api/diagnostics and dispatches /api/logs paths.
Logs route dispatch, DTOs, parsing
api/routes/logs/mod.rs, dto.rs, error.rs, parse.rs
Adds request/event/artifact/proxy/audit DTOs and validated parsers.
Logs SSE replay streaming
api/routes/logs/events/*
Adds lifecycle/audit SSE framing, cursor-based replay, and the streaming adapter.
Mutation routes
api/routes/logs/cleanup.rs, delete.rs, export.rs, maintenance_control.rs, webhook_retry.rs
Adds cleanup preview/run, delete-one, export, and webhook retry endpoints.
API tests
api/tests/logs_api_routes*, api/tests/management_http.rs
Adds route-level and lifecycle test coverage.

Operational Audit Events

Layer / File(s) Summary
CLI command and auth audit
mesh-llm-commands/src/*, mesh-llm/src/*
Adds command dispatch audit boundary, auth command events, and revocation validation ordering fix.
Mesh audit events
mesh-llm-host-runtime/src/mesh/*
Adds MeshOperationalEvent recording for connection and gossip lifecycle.
Runtime audit events
mesh-llm-host-runtime/src/runtime/*, inference/skippy/mod.rs
Adds discovery, config, model, local-serving, and native Skippy operational events, plus survey telemetry integration.

OpenAI Lifecycle Observability

Layer / File(s) Summary
Request parsing and lifecycle context
network/openai/request_parse.rs, parse_failure.rs
Adds canonical RequestId propagation and lifecycle context on parse failures.
Response relay and usage
network/openai/response/*
Threads route observation through response handling and replaces completion tokens with full TokenUsage.
MoA and transport dispatch outcomes
network/openai/moa_gateway/*, network/openai/transport.rs, ingress.rs
Adds structured dispatch outcome types replacing booleans/optionals.
Tunnel prefetch
network/tunnel.rs
Adds bounded header prefetching and lifecycle suppression.
openai-frontend lifecycle observer
openai-frontend/src/lifecycle.rs, router/stream_lifecycle.rs
Adds a metadata-only lifecycle observer contract and UUID request IDs.
skippy-server wiring
skippy-server/src/embedded.rs, lib.rs
Adds lifecycle-observer-aware startup functions.

Log Store Engine (mesh-llm-log-store)

Layer / File(s) Summary
Schema and store core
migrations.rs, store.rs, error.rs, lib.rs, timestamps.rs
Defines V1-V3 schema, transactional migrations, and poisoning recovery.
Artifacts and cursors
artifact_repository.rs, artifacts.rs, capture.rs, cursor.rs
Adds artifact pointer repository and cascade deletion.
Typed query API
query/*
Adds request/event/artifact/proxy query types and keyset pagination.
Maintenance and retention
maintenance*, repositories/cleanup.rs
Adds delete-one/cleanup execution with cooperative cancellation.
Acceptance tests
api_acceptance_tests/*
Adds end-to-end acceptance coverage.

Other

Layer / File(s) Summary
mesh-mixture-of-agents fix
crates/mesh-mixture-of-agents/src/lib.rs
Removes the keyword gate on tool-result evidence repair.
Documentation and QA scripts
website/*, docs/plugins/telemetry.md, scripts/qa-*, scripts/tests/*
Adds Logging API docs and a QA recovery certification harness.

Estimated code review effort: 5 (Critical) | ~240 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant OpenAiIngress
  participant OpenAiLifecycleLoggingAdapter
  participant LoggingService
  participant LogStore
  participant ReplayBus

  Client->>OpenAiIngress: HTTP request
  OpenAiIngress->>OpenAiLifecycleLoggingAdapter: claim lifecycle ownership
  OpenAiLifecycleLoggingAdapter->>LoggingService: register admitted event
  OpenAiIngress->>OpenAiIngress: route and dispatch request
  OpenAiIngress->>OpenAiLifecycleLoggingAdapter: record terminal outcome (status, usage)
  OpenAiLifecycleLoggingAdapter->>LoggingService: enqueue terminal lifecycle event
  LoggingService->>ReplayBus: push replay record
  LoggingService->>LogStore: persist summary and lifecycle event
  ReplayBus-->>Client: SSE replay/live event (via Logging API stream)
Loading
sequenceDiagram
  participant Client
  participant LogsApi
  participant LoggingQueryFacade
  participant LogStore
  participant ArtifactFileStore

  Client->>LogsApi: POST /api/logs/requests/{id}/delete
  LogsApi->>LoggingQueryFacade: prepare_delete_request
  LoggingQueryFacade->>LogStore: persist immutable receipt and targets
  LogsApi->>LoggingQueryFacade: execute_prepared_delete_request
  LoggingQueryFacade->>ArtifactFileStore: delete artifact files (cancellable)
  ArtifactFileStore-->>LoggingQueryFacade: deletion progress
  LoggingQueryFacade->>LogStore: complete receipt, cascade delete rows
  LogsApi-->>Client: completed or pending (202) receipt
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.07% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: audited local logging APIs and runtime telemetry.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch logging-api-v3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

This pull request is currently a draft. Reviews will not take place until the PR is marked as ready for review.

@ndizazzo
ndizazzo force-pushed the logging-api-v3 branch 3 times, most recently from 0f7702b to 327be35 Compare August 11, 2026 22:10
@ndizazzo
ndizazzo force-pushed the logging-api-v3 branch 2 times, most recently from a69f411 to fe69495 Compare August 12, 2026 05:19
@ndizazzo
ndizazzo marked this pull request as ready for review August 12, 2026 07:07
@github-actions
github-actions Bot requested a review from i386 August 12, 2026 07:07

@coderabbitai coderabbitai 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.

Actionable comments posted: 18

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/mesh-llm-events/src/logging/presentation.rs (1)

67-76: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Include terminal status in failed and rejected summaries.

Failed and Rejected now carry status_code, but these branches discard it. presentation_local_summary() therefore omits the terminal HTTP status for failed and rejected requests, unlike completed attempts and requests. Use append_status for both branches.

Proposed fix
-            LifecycleEvent::Failed { .. } => "request failed".to_string(),
-            LifecycleEvent::Rejected { .. } => "request rejected".to_string(),
+            LifecycleEvent::Failed { status_code, .. } => {
+                append_status("request failed".to_string(), status_code)
+            }
+            LifecycleEvent::Rejected { status_code, .. } => {
+                append_status("request rejected".to_string(), status_code)
+            }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-events/src/logging/presentation.rs` around lines 67 - 76,
Update the LifecycleEvent::Failed and LifecycleEvent::Rejected branches in
presentation_local_summary() to extract their status_code and pass the
corresponding summary through append_status, preserving the existing “request
failed” and “request rejected” messages while including the terminal HTTP
status.
🟡 Minor comments (20)
scripts/qa-logging-recovery.sh-391-394 (1)

391-394: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not suppress rejected-request transport failures.

The trailing || true makes submit_rejected_request return success after a curl failure. The later request-list timeout then reports PREREQ, which can hide a failed logging path.

Return failure when curl cannot contact the node. Also verify that the response represents the expected rejected request before using it as lifecycle evidence.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/qa-logging-recovery.sh` around lines 391 - 394, The curl invocation
in submit_rejected_request must propagate transport failures instead of masking
them with || true. Remove the unconditional success fallback, then validate the
returned response matches the expected rejected request before treating it as
lifecycle evidence; only proceed to the request-list timeout check after both
conditions succeed.
scripts/qa-logging-recovery.sh-600-604 (1)

600-604: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate the typed unavailable error body.

This check accepts any HTTP 503 response. It does not verify the documented typed logging-unavailable response. A proxy or unrelated server failure can therefore pass the certification.

Parse the response envelope and require the expected unavailable error code before recording logging_fail_open as PASS.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/qa-logging-recovery.sh` around lines 600 - 604, Update the
logging_fail_open validation around the curl request and record_result call to
parse fail-open-logs.json and require the documented typed logging-unavailable
error code in the response envelope, not merely HTTP status 503. Record PASS
only when both the status and expected error code match; otherwise preserve the
existing FAIL path and diagnostic status.
scripts/qa-control-plane-mixed-version.sh-1182-1187 (1)

1182-1187: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate every canonical model reference before sorting.

An inventory such as [{"metadata": {}}] passes this check. Its reference list is [None], and sorted([None]) succeeds. The harness then reports a valid typed inventory without a canonical model reference.

Require each entry to be an object with a non-empty string canonical_model_ref and a metadata object before comparing the ordered references.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/qa-control-plane-mixed-version.sh` around lines 1182 - 1187, Update
the inventory validation after the list check to require every entry to be an
object with a non-empty string canonical_model_ref and a metadata dictionary
before building refs or sorting. Then compare the validated references for
ordering, preserving the existing failure behavior for invalid or unsorted
inventories.
crates/mesh-llm-host-runtime/src/api/routes/logs/parse.rs-473-481 (1)

473-481: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The path-shape heuristic redacts legitimate operator reasons.

The path_shaped test is broader than a path check:

  • value.as_bytes().get(1) == Some(&b':') matches any reason whose second byte is a colon. A reason such as a: cleanup after incident becomes [REDACTED].
  • value.contains('\\') matches any reason containing a backslash anywhere.

When the heuristic fires, the entire reason is replaced. The audit entry then records no operator intent at all, and maintenance_reason stores [REDACTED] as the maintenance reason. The caller receives no signal that the text was discarded.

Narrow the drive-letter check to a single ASCII alphabetic first byte followed by : and a separator, and apply apply_redaction instead of whole-value replacement for the backslash case.

🔧 Proposed narrowing
-    let path_shaped = value.starts_with('/')
-        || value.starts_with("~/")
-        || value.as_bytes().get(1) == Some(&b':')
-        || value.contains('\\');
+    let bytes = value.as_bytes();
+    let windows_drive = bytes.first().is_some_and(u8::is_ascii_alphabetic)
+        && bytes.get(1) == Some(&b':')
+        && matches!(bytes.get(2), Some(b'\\') | Some(b'/'));
+    let path_shaped = value.starts_with('/') || value.starts_with("~/") || windows_drive;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-host-runtime/src/api/routes/logs/parse.rs` around lines 473 -
481, Refine the path_shaped logic around the value sanitization expression:
require the drive-letter form to have an ASCII alphabetic first byte, a colon,
and a path separator, and handle backslash-containing values through
crate::logging::policy::apply_redaction rather than replacing the entire reason.
Preserve whole-value redaction only for clearly identified path-shaped inputs
such as absolute or home-relative paths, while retaining operator text and
maintenance_reason content whenever possible.
crates/mesh-llm-host-runtime/src/api/routes/diagnostics.rs-10-22 (1)

10-22: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

/api/diagnostics returns 404 when the request carries a query string.

crates/mesh-llm-host-runtime/src/api/routes/mod.rs matches this route on path_only but passes the full path. GET /api/diagnostics?foo=1 therefore reaches handle, fails the exact equality at Line 18, and returns 404. The split-readiness branch uses starts_with, so it does not have this behavior.

🐛 Proposed fix
-    if path == "/api/diagnostics" {
+    if path.split('?').next() == Some("/api/diagnostics") {
         return handle_general_diagnostics(stream, state).await;
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-host-runtime/src/api/routes/diagnostics.rs` around lines 10 -
22, Update handle in the diagnostics route so the general diagnostics comparison
uses the query-free path, matching the path_only value used by routes::mod.
Preserve the existing split-readiness routing and 404 behavior for unrelated
paths, while allowing /api/diagnostics requests with query strings to reach
handle_general_diagnostics.
crates/mesh-llm-host-runtime/src/api/routes/logs/delete.rs-144-158 (1)

144-158: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Build the shared deadline from the injected time caps, not the constant.

Line 150 uses DELETE_TIME_CAP while the surrounding code honors prepare_time_cap and execution_time_cap. The injected caps therefore control only the Tokio timeouts, and the cooperative store cancellation still runs on the fixed two-second budget. That makes the parameters misleading and weakens the test at Lines 317-394.

🐛 Proposed fix
-    let control = MaintenanceDeadline::new(DELETE_TIME_CAP);
+    let control = MaintenanceDeadline::new(prepare_time_cap.max(execution_time_cap));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-host-runtime/src/api/routes/logs/delete.rs` around lines 144
- 158, Update the maintenance deadline initialization in the delete handler to
use the injected prepare_time_cap and execution_time_cap values instead of the
fixed DELETE_TIME_CAP constant. Ensure MaintenanceDeadline enforces the same
configured caps used by timeout_maintenance, while preserving the existing
prepare and execution flow.
crates/mesh-llm-host-runtime/src/api/routes/logs/events/session.rs-338-362 (1)

338-362: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Replace the expect on the lifecycle gap frame with the Err handling used on the audit path.

recovery_cursor is an opaque cursor supplied by the durable query layer, and this function does not bound its length. If frame() rejects the result against MAX_FRAME_BYTES, this expect panics inside the spawned producer task.

The audit path already degrades gracefully for the same condition. See Line 230 (if let Ok(frame) = gap) and Line 277.

🛡️ Proposed fix
-        .filter_map(|channel| {
-            let requested = subscription.cursor.sequence(*channel);
-            let channel_evicted_through = evicted_through.sequence(*channel);
-            (requested < channel_evicted_through).then(|| {
-                let gap = GapData::new(
-                    *channel,
-                    requested.saturating_add(1),
-                    channel_evicted_through,
-                    recovery_cursor.clone(),
-                );
-                gap_frame(cursor_from_replay(latest), &gap)
-                    .expect("bounded replay-gap data fits the SSE frame cap")
-            })
-        })
+        .filter_map(|channel| {
+            let requested = subscription.cursor.sequence(*channel);
+            let channel_evicted_through = evicted_through.sequence(*channel);
+            if requested >= channel_evicted_through {
+                return None;
+            }
+            let gap = GapData::new(
+                *channel,
+                requested.saturating_add(1),
+                channel_evicted_through,
+                recovery_cursor.clone(),
+            );
+            gap_frame(cursor_from_replay(latest), &gap).ok()
+        })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-host-runtime/src/api/routes/logs/events/session.rs` around
lines 338 - 362, Update gap_frames to handle a failed gap_frame conversion
without panicking: replace the expect with Err-aware filtering so oversized
lifecycle gap frames are skipped, matching the audit path’s graceful handling
around the referenced gap processing. Preserve successful frame collection and
the existing gap construction behavior.
crates/mesh-llm-host-runtime/src/logging/metrics.rs-171-180 (1)

171-180: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Release the read guard before you call the sink.

Line 175 shadows the guard binding with the cloned Option<Arc<...>>. Shadowing does not drop the guard. The read lock stays held until the end of record, so sink.record(metric) runs while the lock is held. A sink that blocks then blocks set_sink, and a sink that calls record again can deadlock against a waiting writer.

Bind the guard to a separate name and drop it before the call.

🔒 Proposed fix to release the guard
     pub(crate) fn record(&self, metric: LoggingMetric) {
-        let Ok(sink) = self.sink.try_read() else {
+        let Ok(guard) = self.sink.try_read() else {
             return;
         };
-        let sink = sink.clone();
+        let sink = guard.clone();
+        drop(guard);
         let Some(sink) = sink else {
             return;
         };
         let _ = catch_unwind(AssertUnwindSafe(|| sink.record(metric)));
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-host-runtime/src/logging/metrics.rs` around lines 171 - 180,
Update LoggingMetricRecorder::record to bind the try_read guard separately from
the cloned sink, then explicitly release the guard before invoking
sink.record(metric). Preserve the existing early returns and panic handling
while ensuring the sink call occurs without the read lock held.
crates/mesh-llm-log-store/src/api_acceptance_tests/cursor_pagination.rs-11-12 (1)

11-12: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Correct the comment about unique timestamps.

The comment states that unique sequential timestamps cause gaps, and that a cursor at T3 skips T4. That does not match the keyset implementation. The pagination predicate is a strict tuple comparison (occurred_at, artifact_id) < (?, ?) against the last returned row, so it never skips a row, whether or not timestamps repeat. The duplicate timestamps in this test exercise the tiebreak path; they are not required for correctness.

Reword the comment so it does not document a constraint that the implementation does not have.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-log-store/src/api_acceptance_tests/cursor_pagination.rs`
around lines 11 - 12, Reword the comments in the cursor pagination test to
remove the claim that unique sequential timestamps cause gaps or that a cursor
at T3 skips T4. State that duplicate timestamps are included to exercise the
artifact_id tiebreak path, while pagination remains correct with unique
timestamps.
crates/mesh-llm-log-store/src/api_acceptance_tests/cursor_pagination.rs-215-228 (1)

215-228: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The ordering assertion does not test ordering.

Line 222 copies all_ids, line 223 sorts the copy descending, and line 224 asserts on sorted[0]. The sort discards the order that pagination produced. The assertion then only states that same-ts-0004 is the lexicographic maximum of the five inserted IDs, which holds for any page order. The comment on line 221 states that DESC ordering is verified, but it is not.

Assert on all_ids directly.

💚 Proposed fix
-    // Verify ordering: DESC on (created_at, request_id), so highest ID first.
-    let mut sorted = all_ids.clone();
-    sorted.sort_unstable_by(|a, b| b.cmp(a));
-    assert_eq!(
-        sorted[0], "same-ts-0004",
-        "DESC order means highest ID first"
-    );
+    // Verify ordering: DESC on (created_at, request_id), so highest ID first.
+    let expected: Vec<String> = (0..5u32)
+        .rev()
+        .map(|i| format!("same-ts-{i:04}"))
+        .collect();
+    assert_eq!(
+        all_ids, expected,
+        "pages must arrive in DESC (created_at, request_id) order"
+    );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-log-store/src/api_acceptance_tests/cursor_pagination.rs`
around lines 215 - 228, Remove the copied-and-sorted validation around all_ids
and assert directly on the pagination result, such as checking all_ids[0] is
"same-ts-0004". Keep the existing count assertion and DESC ordering comment,
ensuring the test verifies the order returned by pagination rather than
reordering it first.
crates/mesh-llm-log-store/src/api_acceptance_tests/mod.rs-35-40 (1)

35-40: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

TestClock stops being monotonic after 60 calls.

now formats n % 60 into the seconds field. Call 60 returns the same string as call 0, and every later call returns a timestamp earlier than the preceding ones. Durable ordering, keyset cursors, and terminal-at comparisons all key on this string. Any acceptance test in this module tree that issues more than 60 clock reads gets silently inverted ordering rather than a failure.

Widen the formatted range so the clock stays monotonic.

💚 Proposed fix
 impl ClockTrait for TestClock {
     fn now(&self) -> String {
         let n = self.instant.fetch_add(1, Ordering::Relaxed);
-        format!("2025-01-01T00:00:{:02}Z", n % 60)
+        format!(
+            "2025-01-01T{:02}:{:02}:{:02}Z",
+            (n / 3600) % 24,
+            (n / 60) % 60,
+            n % 60
+        )
     }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-log-store/src/api_acceptance_tests/mod.rs` around lines 35 -
40, Update TestClock::now to format the incrementing instant without wrapping at
60, using a sufficiently wide seconds field so successive calls remain
lexicographically monotonic beyond 60 reads while preserving the existing
timestamp format.
crates/mesh-llm-log-store/src/capture.rs-226-237 (1)

226-237: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

MaintenanceExecutionCancelled misrepresents a disabled capture facade.

A disabled capture facade is not a cancelled or timed-out operation. The API layer maps MaintenanceExecutionCancelled to a cancellation/deadline outcome, so an operator sees a timeout instead of "artifact capture unavailable". crates/mesh-llm-log-store/src/maintenance/metadata_delete.rs already uses LogStoreError::ArtifactDeletionUnavailable for the same "no trusted artifact owner" condition. Use that variant here and in delete_request_cascade, prepare_delete_request, and execute_prepared_delete_request.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-log-store/src/capture.rs` around lines 226 - 237, Replace the
disabled-facade error returned by execute_cleanup with
LogStoreError::ArtifactDeletionUnavailable instead of
MaintenanceExecutionCancelled. Apply the same variant consistently in
delete_request_cascade, prepare_delete_request, and
execute_prepared_delete_request when no available capture store exists,
preserving cancellation handling for actual cancelled or timed-out operations.
crates/mesh-llm-host-runtime/src/network/openai/response/stream_translation.rs-147-157 (1)

147-157: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The two stream adapters end a failed stream differently.

For the normalized path, Lines 147-148 write the chunked terminator 0\r\n\r\n and shut the socket down before the !done_seen check at Line 149. The client receives a well-formed, complete-looking chunked response that simply lacks data: [DONE].

For the translated path, the !done_seen check at Line 252 returns before any terminator is written. The client sees a truncated chunked body.

Both cases represent the same failure class, so a client cannot use the framing to detect it consistently. Choose one convention for both adapters.

Also applies to: 252-259

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@crates/mesh-llm-host-runtime/src/network/openai/response/stream_translation.rs`
around lines 147 - 157, Make the normalized and translated stream adapters use
the same failure framing when !done_seen. Align the end-of-stream handling
around the relevant adapter completion logic so both paths either write the
chunked terminator and shut down before returning the incomplete-stream error,
or both return before doing so; preserve the existing stream_error and
successful completion behavior.
crates/mesh-llm-host-runtime/src/network/openai/response/routing.rs-228-245 (1)

228-245: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

The test does not cover what its name states.

Three problems:

  1. _route is unused. Both loop iterations run the identical tokio::io::duplex forwarding, so the remote path is never exercised. route_remote_attempt forwards through forward_peer_request, not forward_buffered_request.
  2. No request-ID logic runs. forward_buffered_request is a write_all wrapper, so the assertion only proves that write_all copies bytes.
  3. The remote path applies prepare_peer_forwarded_request before writing, which can change the bytes. The test claims byte preservation for that path without exercising it.

Either drop the loop and rename the test to describe the local wrapper, or assert on prepare_peer_forwarded_request output for the remote claim.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-host-runtime/src/network/openai/response/routing.rs` around
lines 228 - 245, The test
local_and_remote_forwarding_preserve_the_canonical_request_id_bytes does not
exercise either route-specific request-ID behavior. Remove the unused route loop
and rename the test to describe only forward_buffered_request, or replace the
remote iteration with an assertion against prepare_peer_forwarded_request output
before forwarding so the remote byte transformation is actually covered.
crates/mesh-llm-host-runtime/src/network/openai/response/pipeline.rs-158-163 (1)

158-163: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

A failed shutdown is reported as a dropped response.

Both paths write the complete body first and then call shutdown. If only shutdown fails, the client already received the full response. Returning Dropped records a delivered response as a dropped one, which corrupts the terminal outcome for that request.

A client that closes its read side immediately after reading makes this path reachable.

Treat a shutdown error as a completed response.

🐛 Proposed fix for the streaming path
-    if client_stream.write_all(b"0\r\n\r\n").await.is_err()
-        || client_stream.shutdown().await.is_err()
-    {
+    if client_stream.write_all(b"0\r\n\r\n").await.is_err() {
         return PipelineProxyResult::Dropped;
     }
+    let _ = client_stream.shutdown().await;
     completed_pipeline_response(status, usage_parser.usage)
🐛 Proposed fix for the non-streaming path
             if client_stream.write_all(header.as_bytes()).await.is_err()
                 || client_stream.write_all(&resp_bytes).await.is_err()
-                || client_stream.shutdown().await.is_err()
             {
                 PipelineProxyResult::Dropped
             } else {
+                let _ = client_stream.shutdown().await;
                 completed_pipeline_response(status, usage)
             }

Also applies to: 234-241

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-host-runtime/src/network/openai/response/pipeline.rs` around
lines 158 - 163, Update the response-finalization logic in both streaming and
non-streaming paths around client_stream.write_all and client_stream.shutdown:
return Dropped only when writing the complete body fails, and ignore shutdown
errors so a fully written response proceeds to
completed_pipeline_response(status, usage_parser.usage).
crates/mesh-llm-host-runtime/src/network/openai/transport.rs-99-138 (1)

99-138: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Three independent terminal-outcome mappers classify the same HTTP status differently. The file now contains three functions that each convert a result into a TerminalOutcome, and none of them share a status-classification rule. A single upstream status therefore lands in different buckets depending on which path terminalizes the request, so audit and telemetry consumers cannot reconcile them. Extract one status-to-TerminalOutcome classifier and call it from all three.

  • crates/mesh-llm-host-runtime/src/network/openai/transport.rs#L99-L138: RouteDispatchOutcome::terminal_outcome treats only 200..=299 as success, so a Responded(302) becomes FailedWithStatus.
  • crates/mesh-llm-host-runtime/src/network/openai/transport.rs#L831-L872: terminal_outcome_for_mesh_route_result treats (200..400) as success at Lines 838 and 841, so a delivered 302 becomes CompletedWithStatus. proxy_result_metadata at Line 733 uses the same 200..400 range.
  • crates/mesh-llm-host-runtime/src/network/openai/transport.rs#L874-L888: terminal_outcome_for_mesh_request_failure ignores the status it just sent. ModelUnavailable sends HTTP 429 at Lines 581-587 but maps to Failed, whereas the dispatch mapper maps every 4xx to RejectedWithStatus.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-host-runtime/src/network/openai/transport.rs` around lines 99
- 138, Extract a shared HTTP status-to-TerminalOutcome classifier and use it
from RouteDispatchOutcome::terminal_outcome,
terminal_outcome_for_mesh_route_result, and
terminal_outcome_for_mesh_request_failure so identical statuses receive
identical classifications. Apply one consistent success range, preserve 4xx as
RejectedWithStatus, classify other statuses as FailedWithStatus, and ensure
failure paths use their actual HTTP status, including ModelUnavailable’s 429.
Update proxy_result_metadata to use the same status range. Affected sites:
crates/mesh-llm-host-runtime/src/network/openai/transport.rs:99-138, 831-872,
and 874-888 all require routing through the shared classifier.
crates/mesh-llm-host-runtime/src/network/openai/ingress.rs-611-618 (1)

611-618: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Record the route selection before the admission response is written.

check_activity_admission writes the observed 503 and returns Err(outcome). Only after that does this branch call route_selected_with_metadata. The lifecycle therefore records the response observation before RouteSelected.

Move the metadata call above the admission check so the event order matches the request order.

♻️ Proposed fix
+    route_observer.route_selected_with_metadata(Some(model_name), Some("plugin"), Some("admission"));
     match check_activity_admission(
         tcp_stream,
         &ctx.node.activity_policy_guard,
         crate::runtime::IngressType::PluginDispatch,
         route_observer,
     )
     .await
     {
         Ok(stream) => tcp_stream = stream,
-        Err(outcome) => {
-            route_observer.route_selected_with_metadata(
-                Some(model_name),
-                Some("plugin"),
-                Some("admission"),
-            );
-            return outcome;
-        }
+        Err(outcome) => return outcome,
     }

Note that this also records the selection on the allowed path. If that is not wanted, keep the call inside the Err arm but move it before check_activity_admission using an early admission probe.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-host-runtime/src/network/openai/ingress.rs` around lines 611
- 618, Move the route_selected_with_metadata call associated with admission from
the Err(outcome) handling to before check_activity_admission, ensuring
RouteSelected is recorded before any admission response is written. Preserve the
existing model_name, "plugin", and "admission" metadata, and retain the
allowed-path behavior described by the review.
crates/mesh-llm-host-runtime/src/logging/persistence.rs-339-345 (1)

339-345: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve severity when the audit record also carries a detail.

insert_audit_entry has no severity parameter, so severity reaches storage only inside detail_json. The else branch at Line 341 is the only place that writes it.

When a record carries both a detail and a severity, the if branch runs and the severity is discarded. Operator filtering on audit severity then returns inconsistent results, because whether severity is present depends on whether an unrelated detail field was set.

Merge the severity into the detail object instead of choosing between them.

🐛 Proposed fix to merge severity into the detail
-        let detail_json = if let Some(detail_json) = record.detail_json() {
-            Some(apply_redaction(&sanitize_paths_in_text(detail_json)).0)
-        } else {
-            record
-                .severity()
-                .map(|severity| serde_json::json!({ "severity": severity.as_str() }).to_string())
-        };
+        let severity = record.severity().map(|severity| severity.as_str());
+        let detail_json = match (record.detail_json(), severity) {
+            (Some(detail_json), severity) => {
+                let sanitized = apply_redaction(&sanitize_paths_in_text(detail_json)).0;
+                Some(match (severity, serde_json::from_str::<serde_json::Value>(&sanitized)) {
+                    (Some(severity), Ok(serde_json::Value::Object(mut fields))) => {
+                        fields
+                            .entry("severity")
+                            .or_insert_with(|| serde_json::Value::String(severity.to_string()));
+                        serde_json::Value::Object(fields).to_string()
+                    }
+                    _ => sanitized,
+                })
+            }
+            (None, Some(severity)) => {
+                Some(serde_json::json!({ "severity": severity }).to_string())
+            }
+            (None, None) => None,
+        };

The or_insert_with call keeps an explicit severity already present in the detail. Add a test that builds a record with both fields and asserts the persisted detail contains the severity.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-host-runtime/src/logging/persistence.rs` around lines 339 -
345, Update the detail_json construction in insert_audit_entry so records
containing both detail_json and severity preserve both values. Parse the
sanitized detail as a JSON object, insert severity only when that key is absent,
and serialize the merged object; retain the existing severity-only fallback for
records without detail. Add a test covering both fields and asserting the
persisted detail includes severity.
crates/mesh-llm-host-runtime/src/logging/service.rs-1693-1705 (1)

1693-1705: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Recover from a poisoned delivery mutex in the status read.

persistence_worker_state panics when the delivery mutex is poisoned. LoggingRuntimeState::status calls this method on the trusted-local status path, so one earlier panic under the delivery lock converts every later status read into a panic. Logging status must stay fail-open. Recover the guard like the other health reads in this feature.

🛡️ Proposed fix
     pub(crate) fn persistence_worker_state(&self) -> PersistenceWorkerState {
-        let delivery = self.delivery.lock().expect("delivery mutex poisoned");
+        let delivery = self
+            .delivery
+            .lock()
+            .unwrap_or_else(std::sync::PoisonError::into_inner);
         match &*delivery {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-host-runtime/src/logging/service.rs` around lines 1693 -
1705, Update LoggingRuntimeState::persistence_worker_state to recover from a
poisoned delivery mutex instead of calling expect, following the guard-recovery
pattern used by the other health reads. Preserve the existing
DeliveryMode-to-PersistenceWorkerState mapping and ensure status reads remain
fail-open.
crates/mesh-llm-host-runtime/src/logging/service/artifact_persistence.rs-116-151 (1)

116-151: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

Check the size bound before validating JSON content.

Line 123 calls validated_media_kind(media_kind, Some(content)) before the size check at Line 124. When the declared essence is JSON, validated_media_kind parses the whole slice with serde_json::from_slice. An oversized body is therefore fully parsed on the ingress thread and then discarded as metadata-only. The size guard exists to keep large bodies off the request path, and this parse costs more than the copy the guard avoids.

Compute the oversize decision first, then skip content validation for the metadata-only record.

⚡ Proposed fix
-        let media_kind = validated_media_kind(media_kind, Some(content));
-        let (content, memory_permit) = if content.len() > self.config.artifact_command_max_bytes {
+        let oversized = content.len() > self.config.artifact_command_max_bytes;
+        // A metadata-only record stores no bytes, so content validation would
+        // parse a large body only to discard it.
+        let media_kind = validated_media_kind(media_kind, (!oversized).then_some(content));
+        let (content, memory_permit) = if oversized {
             (
                 ArtifactCaptureContent::Unavailable(
                     ArtifactUnavailableReason::CaptureContentLimitExceeded,
                 ),
                 None,
             )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/mesh-llm-host-runtime/src/logging/service/artifact_persistence.rs`
around lines 116 - 151, Update enqueue_openai_artifact_body to determine whether
content exceeds artifact_command_max_bytes before calling validated_media_kind.
For oversized content, skip JSON/content validation and produce the existing
metadata-only record; retain validated_media_kind for content within the size
limit and preserve the current capture and memory-budget behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2e0ecb96-a5ea-41de-9aac-261c56f56e62

📥 Commits

Reviewing files that changed from the base of the PR and between 76d7ca8 and d25681e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (191)
  • crates/mesh-llm-commands/Cargo.toml
  • crates/mesh-llm-commands/src/auth.rs
  • crates/mesh-llm-commands/src/auth/tests.rs
  • crates/mesh-llm-commands/src/lib.rs
  • crates/mesh-llm-commands/src/operational_logging.rs
  • crates/mesh-llm-events/src/logging/envelope.rs
  • crates/mesh-llm-events/src/logging/events.rs
  • crates/mesh-llm-events/src/logging/presentation.rs
  • crates/mesh-llm-events/src/logging/tests.rs
  • crates/mesh-llm-host-runtime/Cargo.toml
  • crates/mesh-llm-host-runtime/src/api/access.rs
  • crates/mesh-llm-host-runtime/src/api/http.rs
  • crates/mesh-llm-host-runtime/src/api/management_lifecycle.rs
  • crates/mesh-llm-host-runtime/src/api/mod.rs
  • crates/mesh-llm-host-runtime/src/api/routes/diagnostics.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/cleanup.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/delete.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/dto.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/error.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/events/mod.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/events/protocol.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/events/query.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/events/session.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/events/session/tests.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/events/stream.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/export.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/maintenance_control.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/mod.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/parse.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/tests.rs
  • crates/mesh-llm-host-runtime/src/api/routes/logs/webhook_retry.rs
  • crates/mesh-llm-host-runtime/src/api/routes/mcp.rs
  • crates/mesh-llm-host-runtime/src/api/routes/mod.rs
  • crates/mesh-llm-host-runtime/src/api/routes/plugins.rs
  • crates/mesh-llm-host-runtime/src/api/routes/runtime.rs
  • crates/mesh-llm-host-runtime/src/api/server.rs
  • crates/mesh-llm-host-runtime/src/api/status.rs
  • crates/mesh-llm-host-runtime/src/api/tests/logs_api_routes.rs
  • crates/mesh-llm-host-runtime/src/api/tests/logs_api_routes/access_and_mutation.rs
  • crates/mesh-llm-host-runtime/src/api/tests/logs_api_routes/event_stream.rs
  • crates/mesh-llm-host-runtime/src/api/tests/logs_api_routes/read_and_export.rs
  • crates/mesh-llm-host-runtime/src/api/tests/logs_api_routes/read_and_export/export.rs
  • crates/mesh-llm-host-runtime/src/api/tests/management_http.rs
  • crates/mesh-llm-host-runtime/src/api/tests/mod.rs
  • crates/mesh-llm-host-runtime/src/inference/skippy/mod.rs
  • crates/mesh-llm-host-runtime/src/lib.rs
  • crates/mesh-llm-host-runtime/src/logging/bus.rs
  • crates/mesh-llm-host-runtime/src/logging/cleanup.rs
  • crates/mesh-llm-host-runtime/src/logging/cleanup/tests.rs
  • crates/mesh-llm-host-runtime/src/logging/lifecycle.rs
  • crates/mesh-llm-host-runtime/src/logging/management_lifecycle.rs
  • crates/mesh-llm-host-runtime/src/logging/metrics.rs
  • crates/mesh-llm-host-runtime/src/logging/mod.rs
  • crates/mesh-llm-host-runtime/src/logging/openai_lifecycle.rs
  • crates/mesh-llm-host-runtime/src/logging/operator_audit.rs
  • crates/mesh-llm-host-runtime/src/logging/output_projection.rs
  • crates/mesh-llm-host-runtime/src/logging/persistence.rs
  • crates/mesh-llm-host-runtime/src/logging/policy.rs
  • crates/mesh-llm-host-runtime/src/logging/policy/artifact_redaction.rs
  • crates/mesh-llm-host-runtime/src/logging/raw_mesh_lifecycle.rs
  • crates/mesh-llm-host-runtime/src/logging/raw_mesh_lifecycle/tests.rs
  • crates/mesh-llm-host-runtime/src/logging/registry.rs
  • crates/mesh-llm-host-runtime/src/logging/request_metadata.rs
  • crates/mesh-llm-host-runtime/src/logging/runtime_state.rs
  • crates/mesh-llm-host-runtime/src/logging/runtime_state/query_facade.rs
  • crates/mesh-llm-host-runtime/src/logging/runtime_state/tests.rs
  • crates/mesh-llm-host-runtime/src/logging/runtime_state/workers.rs
  • crates/mesh-llm-host-runtime/src/logging/service.rs
  • crates/mesh-llm-host-runtime/src/logging/service/artifact_persistence.rs
  • crates/mesh-llm-host-runtime/src/logging/service/operational_audit.rs
  • crates/mesh-llm-host-runtime/src/logging/service_tests.rs
  • crates/mesh-llm-host-runtime/src/logging/service_tests/configuration.rs
  • crates/mesh-llm-host-runtime/src/logging/service_tests/delivery_shutdown.rs
  • crates/mesh-llm-host-runtime/src/logging/service_tests/lifecycle_registry.rs
  • crates/mesh-llm-host-runtime/src/logging/webhook_delivery.rs
  • crates/mesh-llm-host-runtime/src/logging/webhook_delivery/tests.rs
  • crates/mesh-llm-host-runtime/src/logging/webhook_scheduler.rs
  • crates/mesh-llm-host-runtime/src/mesh/connections.rs
  • crates/mesh-llm-host-runtime/src/mesh/gossip.rs
  • crates/mesh-llm-host-runtime/src/mesh/mod.rs
  • crates/mesh-llm-host-runtime/src/mesh/operational_logging.rs
  • crates/mesh-llm-host-runtime/src/network/openai/ingress.rs
  • crates/mesh-llm-host-runtime/src/network/openai/ingress_tests/durable_artifacts.rs
  • crates/mesh-llm-host-runtime/src/network/openai/moa_gateway/mod.rs
  • crates/mesh-llm-host-runtime/src/network/openai/moa_gateway/progress.rs
  • crates/mesh-llm-host-runtime/src/network/openai/moa_gateway/streaming.rs
  • crates/mesh-llm-host-runtime/src/network/openai/mod.rs
  • crates/mesh-llm-host-runtime/src/network/openai/parse_failure.rs
  • crates/mesh-llm-host-runtime/src/network/openai/request_parse.rs
  • crates/mesh-llm-host-runtime/src/network/openai/response.rs
  • crates/mesh-llm-host-runtime/src/network/openai/response/common.rs
  • crates/mesh-llm-host-runtime/src/network/openai/response/dispatch.rs
  • crates/mesh-llm-host-runtime/src/network/openai/response/external_endpoint.rs
  • crates/mesh-llm-host-runtime/src/network/openai/response/json_adaptation.rs
  • crates/mesh-llm-host-runtime/src/network/openai/response/pipeline.rs
  • crates/mesh-llm-host-runtime/src/network/openai/response/relay.rs
  • crates/mesh-llm-host-runtime/src/network/openai/response/routing.rs
  • crates/mesh-llm-host-runtime/src/network/openai/response/send.rs
  • crates/mesh-llm-host-runtime/src/network/openai/response/stream_translation.rs
  • crates/mesh-llm-host-runtime/src/network/openai/transport.rs
  • crates/mesh-llm-host-runtime/src/network/openai/transport_tests.rs
  • crates/mesh-llm-host-runtime/src/network/openai/transport_tests/durable_artifacts.rs
  • crates/mesh-llm-host-runtime/src/network/openai/transport_tests/lifecycle.rs
  • crates/mesh-llm-host-runtime/src/network/openai/transport_tests/routing.rs
  • crates/mesh-llm-host-runtime/src/network/tunnel.rs
  • crates/mesh-llm-host-runtime/src/runtime/auto_join.rs
  • crates/mesh-llm-host-runtime/src/runtime/config_state.rs
  • crates/mesh-llm-host-runtime/src/runtime/control_loop.rs
  • crates/mesh-llm-host-runtime/src/runtime/discovery.rs
  • crates/mesh-llm-host-runtime/src/runtime/local.rs
  • crates/mesh-llm-host-runtime/src/runtime/local/native_runtime_events.rs
  • crates/mesh-llm-host-runtime/src/runtime/local/native_runtime_events/tests.rs
  • crates/mesh-llm-host-runtime/src/runtime/mod.rs
  • crates/mesh-llm-host-runtime/src/runtime/model_lifecycle.rs
  • crates/mesh-llm-host-runtime/src/runtime/model_lifecycle/load.rs
  • crates/mesh-llm-host-runtime/src/runtime/model_lifecycle/unload.rs
  • crates/mesh-llm-host-runtime/src/runtime/operational_logging.rs
  • crates/mesh-llm-host-runtime/src/runtime/operational_logging/tests.rs
  • crates/mesh-llm-host-runtime/src/runtime/run_auto.rs
  • crates/mesh-llm-host-runtime/src/runtime/startup_handles.rs
  • crates/mesh-llm-host-runtime/src/runtime/survey.rs
  • crates/mesh-llm-host-runtime/src/runtime/survey/logging_metrics.rs
  • crates/mesh-llm-host-runtime/src/runtime/tests/logging.rs
  • crates/mesh-llm-host-runtime/src/runtime/tests/mod.rs
  • crates/mesh-llm-host-runtime/src/runtime_data/api_views.rs
  • crates/mesh-llm-host-runtime/src/runtime_data/mod.rs
  • crates/mesh-llm-host-runtime/src/sdk/embedded_logging.rs
  • crates/mesh-llm-log-store/src/api_acceptance_tests/cursor_pagination.rs
  • crates/mesh-llm-log-store/src/api_acceptance_tests/mod.rs
  • crates/mesh-llm-log-store/src/api_acceptance_tests/retention_cleanup.rs
  • crates/mesh-llm-log-store/src/api_acceptance_tests/retention_policy.rs
  • crates/mesh-llm-log-store/src/api_acceptance_tests/schema_lifecycle.rs
  • crates/mesh-llm-log-store/src/api_acceptance_tests/summary_audit.rs
  • crates/mesh-llm-log-store/src/api_acceptance_tests/summary_events.rs
  • crates/mesh-llm-log-store/src/api_acceptance_tests/webhook.rs
  • crates/mesh-llm-log-store/src/artifact_repository.rs
  • crates/mesh-llm-log-store/src/artifact_unavailable_tests.rs
  • crates/mesh-llm-log-store/src/artifacts.rs
  • crates/mesh-llm-log-store/src/artifacts_tests.rs
  • crates/mesh-llm-log-store/src/capture.rs
  • crates/mesh-llm-log-store/src/cursor.rs
  • crates/mesh-llm-log-store/src/error.rs
  • crates/mesh-llm-log-store/src/lib.rs
  • crates/mesh-llm-log-store/src/maintenance.rs
  • crates/mesh-llm-log-store/src/maintenance/execution.rs
  • crates/mesh-llm-log-store/src/maintenance/metadata_delete.rs
  • crates/mesh-llm-log-store/src/maintenance/scope_filters.rs
  • crates/mesh-llm-log-store/src/maintenance/tests.rs
  • crates/mesh-llm-log-store/src/maintenance/tests/cleanup.rs
  • crates/mesh-llm-log-store/src/maintenance/tests/delete_one.rs
  • crates/mesh-llm-log-store/src/migrations.rs
  • crates/mesh-llm-log-store/src/query/mod.rs
  • crates/mesh-llm-log-store/src/query/related.rs
  • crates/mesh-llm-log-store/src/query/requests.rs
  • crates/mesh-llm-log-store/src/query_pagination_tests.rs
  • crates/mesh-llm-log-store/src/query_tests.rs
  • crates/mesh-llm-log-store/src/repositories.rs
  • crates/mesh-llm-log-store/src/repositories/cleanup.rs
  • crates/mesh-llm-log-store/src/store.rs
  • crates/mesh-llm-log-store/src/tests/cursor_pagination.rs
  • crates/mesh-llm-log-store/src/tests/mod.rs
  • crates/mesh-llm-log-store/src/tests/retention_cleanup.rs
  • crates/mesh-llm-log-store/src/tests/store_setup.rs
  • crates/mesh-llm-log-store/src/tests/summary_records.rs
  • crates/mesh-llm-log-store/src/timestamps.rs
  • crates/mesh-llm/Cargo.toml
  • crates/mesh-llm/src/commands/mod.rs
  • crates/mesh-llm/src/lib.rs
  • crates/mesh-mixture-of-agents/src/lib.rs
  • crates/openai-frontend/Cargo.toml
  • crates/openai-frontend/README.md
  • crates/openai-frontend/src/backend.rs
  • crates/openai-frontend/src/lib.rs
  • crates/openai-frontend/src/lifecycle.rs
  • crates/openai-frontend/src/responses.rs
  • crates/openai-frontend/src/router.rs
  • crates/openai-frontend/src/router/stream_lifecycle.rs
  • crates/openai-frontend/src/router_tests.rs
  • crates/openai-frontend/tests/benchy_contract.rs
  • crates/openai-frontend/tests/lifecycle_observer.rs
  • crates/skippy-server/src/embedded.rs
  • crates/skippy-server/src/lib.rs
  • docs/plugins/telemetry.md
  • scripts/qa-control-plane-mixed-version.sh
  • scripts/qa-logging-recovery.sh
  • scripts/tests/test_logging_api_docs.py
  • scripts/tests/test_logging_module_boundaries.py
  • scripts/tests/test_qa_logging_recovery.py
  • website/src/_data/docs.js
  • website/src/docs/pages/api-reference.md
  • website/src/docs/pages/logging-api.md

Comment thread crates/mesh-llm-commands/src/auth.rs
Comment thread crates/mesh-llm-host-runtime/src/api/routes/diagnostics.rs
Comment thread crates/mesh-llm-host-runtime/src/api/routes/logs/cleanup.rs
Comment thread crates/mesh-llm-host-runtime/src/api/routes/logs/export.rs
Comment thread crates/mesh-llm-host-runtime/src/runtime/local/native_runtime_events/tests.rs Outdated
Comment thread crates/mesh-llm-log-store/src/artifact_repository.rs
Comment thread crates/mesh-llm-log-store/src/maintenance/execution.rs Outdated
Comment thread crates/mesh-llm/src/lib.rs
Comment thread scripts/qa-logging-recovery.sh
@ndizazzo
ndizazzo merged commit e0d0468 into main Aug 12, 2026
48 checks passed
@ndizazzo
ndizazzo deleted the logging-api-v3 branch August 12, 2026 17:41
michaelneale added a commit that referenced this pull request Aug 13, 2026
…#1291)

The ingress rewrite in #1175 collapsed MoaInterceptResult::Degraded into
NotMoa while wiring route observers through the MoA intercept. The gateway
still rewrote model=mesh to the real served model, but routing kept using
the stale decision.effective_model ("mesh") and 404'd every single-node
model=mesh request. Released 0.75.0 is unaffected.

Restore the Degraded { stream, model } variant, route with the rewritten
model, and pin the contract with a regression test that fails loudly if
Degraded is ever folded into NotMoa again.

Repro: mesh-llm serve with one model, POST /v1/chat/completions with
model="mesh" -> 404 before, 200 after.
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