feat(console): add typed logs ledger and maintenance UI - #1176
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThis PR adds a feature-gated local Logs console with validated APIs, live SSE recovery, request inspection, payload and artifact views, audited maintenance actions, CLI logging projections, documentation, and real-console QA coverage. ChangesLocal logging foundations
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Operator
participant LogsLedger
participant LogsApiClient
participant EventSource
participant RequestInspector
Operator->>LogsLedger: Open /logs
LogsLedger->>LogsApiClient: Load request and audit pages
LogsLedger->>EventSource: Subscribe to replay streams
EventSource-->>LogsLedger: Deliver events or replay gaps
LogsLedger->>LogsApiClient: Hydrate missing data
Operator->>RequestInspector: Select a request
RequestInspector->>LogsApiClient: Load request details and artifacts
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
|
This pull request is currently a draft. Reviews will not take place until the PR is marked as ready for review. |
647184e to
c5123a3
Compare
c5123a3 to
0c73c0a
Compare
0c73c0a to
6d2750f
Compare
928a1fe to
baac27d
Compare
baac27d to
ede9ae9
Compare
ede9ae9 to
7bf275a
Compare
i386
left a comment
There was a problem hiding this comment.
Reviewed the PR head and posted three actionable inline findings: one request-amplification issue in live ledger recovery, one export-download race, and one E2E cleanup false-positive. Focused logs tests, lint, typecheck, build, shell validation, and diff checks passed; the full UI suite has one unrelated DataMode localStorage failure in this checkout, while the PR's Linux quality jobs are green and the wider build matrix is still running.
7bf275a to
a5634d9
Compare
60efc23 to
c9078ba
Compare
c9078ba to
a04274b
Compare
There was a problem hiding this comment.
Actionable comments posted: 9
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (27)
crates/mesh-llm-ui/src/features/logs/lib/log-grid.ts-29-39 (1)
29-39: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReject or type unsupported column counts.
The class map supports only two through four columns. For example,
trailingRowSpanClass(6, 5, 5, 'xl')calculates span5and returnsundefined. The final cell does not fill the row. Constraincolumnsto supported values, or add mappings for every accepted value. Add a regression test for the selected behavior.Proposed fix
- if (columns < 2 || index < 0 || index >= count) return undefined + if (columns < 2 || columns > 4 || index < 0 || index >= count) return undefined🤖 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-ui/src/features/logs/lib/log-grid.ts` around lines 29 - 39, Constrain trailingRowSpanClass to the supported two-to-four column range, rejecting unsupported values before span calculation so inputs such as six columns cannot produce an unmapped span. Add a regression test covering the selected rejection behavior and retain the existing valid-column span mapping.crates/mesh-llm-ui/src/features/logs/lib/log-fixtures.test.ts-115-125 (1)
115-125: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winMake the clock-dependent tests deterministic.
Use
vi.useFakeTimers()andvi.setSystemTime()for these assertions. For fixture initialization, set the fake clock before evaluating the fixture module or inject a reference time.
crates/mesh-llm-ui/src/features/logs/lib/log-fixtures.test.ts#L115-L125: Remove host-clock dependence from fixture timestamp assertions.crates/mesh-llm-ui/src/features/logs/lib/log-search.test.ts#L47-L70: Pass a fixednowMsto query and range helpers.crates/mesh-llm-ui/src/features/logs/lib/log-search.test.ts#L227-L243: Freeze the clock before testing relative-time labels.As per coding guidelines, “Keep tests deterministic; avoid relying on real timers unless using fake timers.”
🤖 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-ui/src/features/logs/lib/log-fixtures.test.ts` around lines 115 - 125, The clock-dependent tests must be deterministic: in crates/mesh-llm-ui/src/features/logs/lib/log-fixtures.test.ts:115-125, use vi.useFakeTimers() and vi.setSystemTime() before fixture evaluation or inject a fixed reference time, then remove Date.now() dependence; in crates/mesh-llm-ui/src/features/logs/lib/log-search.test.ts:47-70, pass a fixed nowMs to the query and range helpers; and in crates/mesh-llm-ui/src/features/logs/lib/log-search.test.ts:227-243, freeze the clock before asserting relative-time labels.Source: Coding guidelines
crates/mesh-llm-ui/src/features/logs/lib/log-search.ts-27-45 (1)
27-45: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse elapsed durations for relative time presets.
setDate()andsetHours()use local calendar time. A24hor7drange can become 23 or 25 hours across a daylight-saving transition. CalculatefromfromnowMs - durationMsso the REST scope always matches the selected duration.Proposed fix
- const now = new Date(nowMs) - const from = new Date(now.getTime()) - - switch (preset) { - case '1h': - from.setHours(from.getHours() - 1) - break - case '6h': - from.setHours(from.getHours() - 6) - break - case '24h': - from.setDate(from.getDate() - 1) - break - case '7d': - from.setDate(from.getDate() - 7) - break - } - - return { from: from.toISOString(), to: now.toISOString() } + const durationMs = + preset === '1h' ? 3_600_000 : + preset === '6h' ? 6 * 3_600_000 : + preset === '24h' ? 24 * 3_600_000 : + 7 * 24 * 3_600_000 + + return { + from: new Date(nowMs - durationMs).toISOString(), + to: new Date(nowMs).toISOString() + }🤖 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-ui/src/features/logs/lib/log-search.ts` around lines 27 - 45, Update the relative-time calculation around `now` and `from` to subtract fixed millisecond durations from `nowMs` for each preset instead of using `setHours()` or `setDate()`. Preserve the existing `from`/`to` ISO-string return shape while ensuring `1h`, `6h`, `24h`, and `7d` always represent exact elapsed durations across daylight-saving transitions.crates/mesh-llm-ui/src/features/logs/lib/use-advancing-chart-clock.ts-8-16 (1)
8-16: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winRefresh the clock when updates are re-enabled.
At Line 9, the hook returns the old
currentvalue until the next minute boundary afterenabledchanges fromfalsetotrue. A finite chart range can exclude requests created during that delay. SetcurrentfromDate.now()before scheduling the aligned timeout. Add a fake-timer regression test for this transition.Proposed fix
useEffect(() => { if (!enabled) return + setCurrent(Date.now()) let interval: number | undefinedBased on learnings, “Keep tests deterministic; avoid relying on real timers unless using fake timers.”
🤖 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-ui/src/features/logs/lib/use-advancing-chart-clock.ts` around lines 8 - 16, Update the enabled branch of the use-advancing-chart-clock hook to call setCurrent(Date.now()) immediately before calculating or scheduling the aligned timeout, so re-enabling refreshes the clock without waiting for the next boundary. Add a deterministic fake-timer regression test covering the false-to-true enabled transition and verifying the current time updates immediately.Source: Learnings
scripts/qa-logging-console-e2e.sh-46-46 (1)
46-46: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReserve ports for all harness listeners.
--base-port 65534and--base-port 65535pass validation. The derivedCONSOLE_PORTorBIND_PORTthen exceeds65535. LimitBASE_PORTto65533.Proposed fix
-[[ "$BASE_PORT" =~ ^[0-9]+$ && "$BASE_PORT" -gt 1024 ]] || { echo "error: invalid --base-port" >&2; exit 2; } +[[ "$BASE_PORT" =~ ^[0-9]+$ && "$BASE_PORT" -gt 1024 && "$BASE_PORT" -le 65533 ]] || { + echo "error: invalid --base-port" >&2 + exit 2 +}🤖 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-console-e2e.sh` at line 46, Update the BASE_PORT validation in the script’s argument-checking condition to reject values above 65533 while preserving the existing numeric and minimum-port checks, ensuring derived CONSOLE_PORT and BIND_PORT values remain within the valid port range.crates/mesh-llm-cli/src/parser/logging_help.rs-51-57 (1)
51-57: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winMake the home-directory assertion portable.
Line 54 panics when
HOMEis unset. An emptyHOMEvalue also makeshelp.contains(&home)match every string. ReadHOMEandUSERPROFILEconditionally, and compare only a non-empty absolute expanded path.The PR objective requires cross-platform path redaction, so this test must not depend on one Unix environment variable.
Proposed fix
- let home = std::env::var("HOME").expect("HOME should be available"); - - assert!(!help.contains(&home)); + for variable in ["HOME", "USERPROFILE"] { + if let Ok(home) = std::env::var(variable) { + let home_path = std::path::Path::new(&home); + if !home.is_empty() && home_path.is_absolute() { + let expanded = home_path.join(".mesh-llm/logging"); + let expanded = expanded.to_string_lossy(); + assert!(!help.contains(expanded.as_ref())); + } + } + }🤖 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-cli/src/parser/logging_help.rs` around lines 51 - 57, Update the test logging_help_does_not_expand_the_private_home_directory to conditionally read HOME and USERPROFILE, filter out missing or empty values, and assert only against non-empty absolute expanded paths so it remains portable across platforms.crates/mesh-llm-host-runtime/src/runtime/local/native_runtime_events/tests.rs-114-114 (1)
114-114: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winSerialize every test that mutates the output sink.
The test at
native_runtime_events/tests.rs:246also callsset_output_sinkand usesOutputSinkResetGuard, but it is not annotated with#[serial_test::serial]. Add the attribute to that test.🤖 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/runtime/local/native_runtime_events/tests.rs` at line 114, Add #[serial_test::serial] to the test around set_output_sink and OutputSinkResetGuard in native_runtime_events/tests.rs, matching the existing annotation pattern and serializing all tests that mutate the output sink.Justfile-17-21 (1)
17-21: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winRestrict
qa-logging-console-e2eto Unix hosts.Windows is a supported platform, but this recipe requires a Bash script and the Unix binary path
./target/debug/mesh-llm. Add[unix]before the recipe or provide Windows-specific commands.🤖 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 `@Justfile` around lines 17 - 21, Restrict the qa-logging-console-e2e recipe to Unix hosts by adding the Justfile [unix] attribute before it, since its Bash harness and ./target/debug/mesh-llm path are Unix-specific.crates/mesh-llm-tui/src/output/logging_projection/privacy.rs-424-479 (1)
424-479: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winFix the test portability and the doubled backslashes.
Two problems in these tests:
- Lines 425 and 467 call
std::env::var("HOME").expect(...).HOMEis not set on Windows, so both tests panic there instead of failing on a real privacy regression. Skip the home-path case when the variable is absent, or readUSERPROFILEas a fallback.- Line 470 uses
r"startup failed opening C:\\Users\\operator\\config.toml". The string is raw, so the doubled backslashes are literal. The test therefore asserts onC:\\Users\\..., not theC:\Users\...form used at line 410. Use a single backslash.💚 Proposed fix
- r"startup failed opening C:\\Users\\operator\\config.toml".to_owned(), + r"startup failed opening C:\Users\operator\config.toml".to_owned(),🤖 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-tui/src/output/logging_projection/privacy.rs` around lines 424 - 479, Make both privacy tests portable by replacing the mandatory HOME lookups with an optional HOME value or a USERPROFILE fallback, and only include the home-path case when a value is available. In preserves_fatal_context_while_selectively_redacting_credentials_and_paths, change the raw Windows path case to use single literal backslashes, matching the path form used in redacts_the_operator_logging_privacy_corpus.crates/mesh-llm-ui/src/features/logs/components/LogMaintenanceReceiptDiagnostics.tsx-6-6 (1)
6-6: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAlign the partial-cascade condition with retry eligibility.
Line 6 treats a receipt as partial when
state === 'partial'orartifactDeletion.failed > 0.hasRetryableArtifactWorkinLogMaintenanceReceiptEligibility.ts(line 4) requires both conditions. Acompletedreceipt that reports failed artifact files therefore shows "Partial cascade: … could not be removed", but no retry control appears. The operator sees a failure with no available action.Either use the same predicate here, or state explicitly in the message that no retry is available for a completed receipt.
Also applies to: 25-31
🤖 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-ui/src/features/logs/components/LogMaintenanceReceiptDiagnostics.tsx` at line 6, Align the partial-cascade predicate in LogMaintenanceReceiptDiagnostics with hasRetryableArtifactWork from LogMaintenanceReceiptEligibility, requiring both a partial receipt state and failed artifact deletions before showing the retry-related diagnostic. Preserve the existing message for receipts that satisfy this retryable condition.crates/mesh-llm-ui/src/features/logs/components/LogRoutingAttemptsTimeline.test.tsx-63-69 (1)
63-69: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winMake the duration assertion locale-independent.
durationMs.toLocaleString()has no locale override, and the test setup does not pin one. Underde_DE.UTF-8,1,000 msrenders as1.000 ms; use an explicit locale or a separator-tolerant matcher.🤖 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-ui/src/features/logs/components/LogRoutingAttemptsTimeline.test.tsx` around lines 63 - 69, Update the duration assertion in the LogRoutingAttemptsTimeline test to avoid assuming a locale-specific thousands separator. Use an explicit locale when formatting the expected value or a matcher that accepts both comma and period separators, while preserving validation of the 1,000 ms duration.crates/mesh-llm-ui/src/features/logs/components/LogRequestOverviewDerivations.ts-26-38 (1)
26-38: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winGuard
formatDurationMsagainstNaN.
NaNpasses every comparison asfalse, so execution reaches line 32.Math.floor(NaN / 60_000)returnsNaN, and the function returns the string"NaNm NaNs".NaNreaches this function whenDate.parsefails on a retained timestamp, which happens informatRequestDurationat line 42 and inattemptDurationMsat line 80. Both results render directly in the Overview panel and the routing-attempt list. Treat a non-finite value as unrecorded.🐛 Proposed fix
export function formatDurationMs(durationMs: number | undefined): string { - if (durationMs === undefined || durationMs < 0) return 'Not recorded' + if (durationMs === undefined || !Number.isFinite(durationMs) || durationMs < 0) return 'Not recorded' if (durationMs < 1_000) return `${durationMs} ms`🤖 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-ui/src/features/logs/components/LogRequestOverviewDerivations.ts` around lines 26 - 38, Update formatDurationMs to treat any non-finite duration, including NaN, as unrecorded alongside undefined and negative values. Use a finite-number guard before the existing formatting branches so invalid Date.parse-derived values return “Not recorded” and valid durations retain their current formatting.crates/mesh-llm-ui/src/features/logs/components/LogRequestDeleteControl.tsx-129-140 (1)
129-140: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReplace the hard-coded
log-delete-reasonid with a generated id.The
idis static. If twoLogRequestDeleteControlinstances mount at the same time, for example one control in a ledger row and one control in the inspector footer, the document contains duplicate ids. ThehtmlForassociation then resolves to the first match, and screen readers andgetByLabelTextqueries target the wrong input. UseuseIdasLogPayloadPane.tsxdoes.♿ Proposed fix using `useId`
-import { useRef, useState } from 'react' +import { useId, useRef, useState } from 'react'const [pending, setPending] = useState(false) const triggerRef = useRef<HTMLButtonElement | null>(null) + const reasonId = useId()<label className="grid gap-1.5 text-[length:var(--density-type-caption)] text-fg-dim" - htmlFor="log-delete-reason" + htmlFor={reasonId} > <span className="type-label text-fg-faint">Required audit reason</span> <Input - id="log-delete-reason" + id={reasonId} onChange={(event) => setReason(event.currentTarget.value)}🤖 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-ui/src/features/logs/components/LogRequestDeleteControl.tsx` around lines 129 - 140, Update LogRequestDeleteControl to generate the reason input identifier with React’s useId, following the existing pattern in LogPayloadPane.tsx, and reuse that generated value for both the input id and label htmlFor instead of the hard-coded “log-delete-reason”.crates/mesh-llm-ui/e2e/logs/real-console.spec.ts-58-67 (1)
58-67: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winDo not assert inside the
expect.pollcallback.
expect(response.ok()).toBeTruthy()on line 61 throws when the ledger returns a transient non-OK response. An exception inside the poll callback fails the test immediately; it does not trigger another poll attempt. Return a sentinel instead and let the outer matcher retry.🐛 Proposed fix
await expect .poll(async () => { const response = await page.request.get('/api/logs/requests?limit=10') - expect(response.ok()).toBeTruthy() + if (!response.ok()) return undefined const body = (await response.json()) as LogPage🤖 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-ui/e2e/logs/real-console.spec.ts` around lines 58 - 67, Update the polling callback in the real-console request-log test to remove the inner expect assertion on response.ok(). Return a falsy sentinel when the response is non-OK so the outer toBeTruthy matcher retries, while preserving the existing JSON parsing and request-ID matching for successful responses.crates/mesh-llm-ui/src/components/ui/chart.tsx-129-138 (1)
129-138: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winInclude the index in the tooltip item key.
dataKeycomes frompayload[0], so it is the same for every rendered item. If two payload entries share the samename, or both names are undefined, the keys collide and React logs a duplicate-key warning and can reuse the wrong node. Add the index.🐛 Proposed fix
- key={`chart-item-${String(itemName ?? '')}-${String(dataKey ?? '')}`} + key={`chart-item-${index}-${String(itemName ?? '')}`}🤖 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-ui/src/components/ui/chart.tsx` around lines 129 - 138, Update the tooltip item key in the payload map to include the existing index alongside itemName and dataKey, ensuring entries with duplicate or undefined names receive unique React keys.crates/mesh-llm-ui/src/components/ui/data-table-pagination.tsx-39-41 (1)
39-41: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win"Page 0 of 1" appears when the table is empty.
When
pageCountis 0, the first expression renders0andMath.max(pageCount, 1)renders1. The label reads "Page 0 of 1", which contradicts itself. Render both values from the same empty check.🐛 Proposed fix
<span className="type-caption text-fg-faint"> - Page {pageCount === 0 ? 0 : pageIndex + 1} of {Math.max(pageCount, 1)} + Page {pageCount === 0 ? 0 : pageIndex + 1} of {pageCount} </span>🤖 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-ui/src/components/ui/data-table-pagination.tsx` around lines 39 - 41, Update the pagination label in the data table component so the empty-table case uses consistent values for both the current page and total pages, avoiding “Page 0 of 1.” Reuse the existing pageCount empty check in the Page display and preserve the current one-based pagination values when pages exist.crates/mesh-llm-ui/e2e/logs/log-workflows.spec.ts-94-97 (1)
94-97: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
artifactDeletionreportsremovedequal tofailed.For
completedthe helper returns{ removed: 0, failed: 0 }, and forpartialit returns{ removed: 1, failed: 1 }. A completed cleanup that removes nothing is an unusual fixture, and it can hide a rendering bug in the receipt counters. Setremovedfrom the planned artifact count instead.♻️ Suggested fixture change
function artifactDeletion(state: 'previewed' | 'completed' | 'partial') { const failed = state === 'partial' ? 1 : 0 - return { removed: failed, failed, ...(failed > 0 ? { failureClass: 'unsafe_path' } : {}) } + const removed = state === 'previewed' ? 0 : 2 - failed + return { removed, failed, ...(failed > 0 ? { failureClass: 'unsafe_path' } : {}) } }🤖 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-ui/e2e/logs/log-workflows.spec.ts` around lines 94 - 97, Update artifactDeletion so removed reflects the planned artifact count for each cleanup state rather than the failed count; keep failed derived from the partial state and retain failureClass only when failures occur.crates/mesh-llm-ui/e2e/configuration/schema-controls.spec.ts-313-333 (1)
313-333: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
auditSettingdiscards the category and label metadata it computes.
auditSettingcallssetting(...)withcategory_id: 'logs-audit'andcategory_label: 'Security Audit', then replacespresentationwith onlycontrol_hint.settingplaceslabel,help,category_id, andcategory_labelinsidepresentation, so all of that metadata is dropped. Thelabelandhelpoptions therefore have no effect on the fixture payload, and the "Security Audit" category is never sent.If the intent is to exercise the fallback presentation path, keep the fixture minimal and remove the unused inputs. If the intent is to send category metadata, keep the
presentationobject fromsetting.♻️ Option A: keep the fixture explicit about what it sends
function auditSetting( canonicalPath: string, options: { - label: string - help: string value_schema: JsonRecord control_hint?: string apply_mode?: string restart_scope?: string } ) { const entry = setting(canonicalPath, { ...options, + label: canonicalPath, + help: canonicalPath, category_id: 'logs-audit', category_label: 'Security Audit' }) return { ...entry, presentation: options.control_hint ? { control_hint: options.control_hint } : undefined } }🤖 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-ui/e2e/configuration/schema-controls.spec.ts` around lines 313 - 333, Update auditSetting to preserve the presentation object returned by setting, including label, help, category_id, and category_label, while adding control_hint without discarding existing metadata. If the fixture is intentionally meant to test the fallback presentation path instead, remove the unused label, help, and category inputs and keep the minimal payload explicit.crates/mesh-llm-ui/src/components/ui/data-table-column-header.tsx-32-45 (1)
32-45: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winExpose the current sort state to assistive technology
The sort icons are
aria-hidden, andDataTabledoes not setaria-sorton<TableHead>. Extend the trigger's accessible name with the current sort state.🤖 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-ui/src/components/ui/data-table-column-header.tsx` around lines 32 - 45, Update the sort trigger in the data-table column header to include the current sort state in its accessible name, using the existing column.getIsSorted() value to distinguish ascending, descending, and unsorted states while preserving the visual icon behavior.crates/mesh-llm-ui/e2e/logs/real-console.spec.ts-2-6 (1)
2-6: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winSeed live data mode in the real-console test.
The harness runs
target/debug/mesh-llm, and debug UI bundles default toharness. Setmesh-llm-ui-preview:data-mode:v2tolivebefore/logsloads so the certification uses real DTOs.🤖 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-ui/e2e/logs/real-console.spec.ts` around lines 2 - 6, Update the real-console test setup before the /logs page loads to seed local storage key mesh-llm-ui-preview:data-mode:v2 with the value live. Ensure this initialization is applied in the harness-driven setup used by the real-console test so the certification consumes live DTOs instead of the default harness mode.crates/mesh-llm-ui/src/components/ui/data-table.test.tsx-34-36 (1)
34-36: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winReplace the real-time waits with fake timers.
These assertions depend on a 100 ms wall-clock delay. Slow or loaded CI workers can make these tests flaky. Use Vitest fake timers and restore real timers after each test.
Based on learnings: “Keep tests deterministic; avoid relying on real timers unless using fake timers.”
Also applies to: 60-62
🤖 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-ui/src/components/ui/data-table.test.tsx` around lines 34 - 36, Replace the real-time setTimeout waits in the affected render-stability assertions with Vitest fake-timer advancement, and configure fake timers for the tests while restoring real timers after each test. Preserve the existing settled-render expectations in both locations.Source: Learnings
crates/mesh-llm-ui/src/features/configuration/components/DefaultsTab.tsx-222-228 (1)
222-228: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winMake the dynamic-validation label reachable.
For schema-derived settings,
dynamic_validation_onlyalways reaches Line 226 before Line 227.crates/mesh-llm-ui/src/features/configuration/api/config-adapter.tsLines 647-649 assignrestart-requiredto every setting that is notdynamic_applywith no restart scope. Therefore,Validated on savenever renders.Place the dynamic-validation check before the mutability check if it is the intended status. If restart is also required, render a label that reports both states. Add regression coverage for
dynamic_validation_only.🤖 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-ui/src/features/configuration/components/DefaultsTab.tsx` around lines 222 - 228, Update applyModeLabel so the dynamic_validation_only case is evaluated before the mutability === 'restart-required' fallback, making “Validated on save” reachable for schema-derived settings. If both validation and restart are required, return a label that communicates both states, and add regression coverage for dynamic_validation_only.crates/mesh-llm-ui/src/components/ui/data-table.tsx-147-153 (1)
147-153: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse the visible leaf-column count for the empty-state span.
When columns are hidden, use
Math.max(table.getVisibleLeafColumns().length, 1)instead ofcolumns.length. Add a regression test for an empty table after hiding a column.🤖 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-ui/src/components/ui/data-table.tsx` around lines 147 - 153, Update the empty-state TableCell in the data table rendering to set colSpan from Math.max(table.getVisibleLeafColumns().length, 1) instead of columns.length, preserving at least one visible span when all columns are hidden. Add a regression test covering an empty table after hiding a column.crates/mesh-llm-ui/src/features/logs/api/client.ts-219-232 (1)
219-232: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winCompare
outcomeby equality, not by substring.Line 228 uses
item.outcome.includes(query.outcome).outcomeis a single enum value, not a list. A partial value such ascanceloredmatches unrelated rows. Every other filter on lines 223-229 uses equality. Use equality here so harness filtering matches the live endpoint contract.🐛 Proposed fix
- if (query.outcome && !item.outcome.includes(query.outcome)) return false + if (query.outcome && item.outcome !== query.outcome) return false🤖 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-ui/src/features/logs/api/client.ts` around lines 219 - 232, Update filterHarnessRequests to compare item.outcome and query.outcome with equality rather than substring matching, preserving the existing optional-filter behavior and aligning outcome filtering with the live endpoint contract.crates/mesh-llm-ui/src/features/logs/api/client.ts-321-332 (1)
321-332: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winHarness mode does not cover the whole logs read surface.
LogsApiClientshort-circuits harness mode forlistRequests,getRequest,listRequestEvents,listRequestArtifacts, andlistAudits, but two read paths still reach the network in harness mode. The shared root cause is a missing harness branch on those paths.
crates/mesh-llm-ui/src/features/logs/api/client.ts#L321-L332: the harness branch requiresquery.requestId. Add a harness result forlistProxywhenrequestIdis absent, so the method never callsthis.#fetchin harness mode.crates/mesh-llm-ui/src/features/logs/api/use-log-artifact-content-query.ts#L12-L21:getArtifactaccepts nomodeparameter, so the hook issues a live request even thoughdataMode.modeis part of the query key. Add amodeparameter with a harness branch togetArtifact, or dropmodefrom the key.🤖 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-ui/src/features/logs/api/client.ts` around lines 321 - 332, Update LogsApiClient.listProxy in crates/mesh-llm-ui/src/features/logs/api/client.ts (lines 321-332) so harness mode returns generated or otherwise appropriate local results even when query.requestId is absent, and never reaches this.#fetch. Update getArtifact in crates/mesh-llm-ui/src/features/logs/api/use-log-artifact-content-query.ts (lines 12-21) to accept the query’s mode and provide a harness branch, or remove mode from the query key; ensure harness-mode artifact reads do not issue live requests.crates/mesh-llm-ui/src/features/logs/api/use-logs-audit-query.ts-30-38 (1)
30-38: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winTruncated results are reported as complete when the last page has no
nextCursor.Line 34 breaks out of the inner loop once
items.lengthreachesAUDIT_MAX_RECORDS. The remaining entries inresult.value.itemsare discarded. Line 38 then returns{ items, nextCursor: undefined }with noincompleteflag if the server sent nonextCursor. The caller reads a truncated window as a complete one. Setincompletewhen the cap stopped consumption.🐛 Proposed fix
for (const entry of result.value.items) { if (entryIds.has(entry.entryId)) continue entryIds.add(entry.entryId) items.push(entry) if (items.length === AUDIT_MAX_RECORDS) break } + const capped = items.length === AUDIT_MAX_RECORDS cursor = result.value.nextCursor - if (cursor === undefined) return { state: 'supported', value: { items, nextCursor: undefined } } + if (cursor === undefined) { + return capped + ? { state: 'supported', value: { items, nextCursor: undefined, incomplete: true } } + : { state: 'supported', value: { items, nextCursor: undefined } } + }🤖 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-ui/src/features/logs/api/use-logs-audit-query.ts` around lines 30 - 38, Track whether the loop in the audit query pagination flow stopped because items.length reached AUDIT_MAX_RECORDS, and mark the returned result as incomplete when that cap truncates result.value.items. Preserve the existing nextCursor handling, but ensure the no-nextCursor return from the cursor loop includes the incomplete state whenever entries were discarded due to the limit.crates/mesh-llm-ui/src/features/logs/api/schemas.ts-766-784 (1)
766-784: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winValidate the audit gap sequence ordering like the replay gap.
Line 768 rejects a replay gap where
toSequence < fromSequence.parseAuditGapon lines 782-784 forwards the wire value with no equivalent check, so an inverted audit gap reachesuseLogsLiveRecovery. Both gap kinds carry the samefromSequence/toSequencecontract. Apply the same check.🐛 Proposed fix
export function parseAuditGap(input: unknown) { - return parseAuditGapWire(input) + const gap = parseAuditGapWire(input) + if (gap.toSequence < gap.fromSequence) throw new LogsDtoError() + return gap }🤖 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-ui/src/features/logs/api/schemas.ts` around lines 766 - 784, Update parseAuditGap to validate that toSequence is not less than fromSequence, matching the ordering check in parseReplayGap; throw LogsDtoError for inverted audit gaps before returning the parsed wire value.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4cf4ec40-a34f-410e-bf64-eeb0fbac71eb
⛔ Files ignored due to path filters (7)
crates/mesh-llm-ui/package-lock.jsonis excluded by!**/package-lock.jsoncrates/mesh-llm-ui/pnpm-lock.yamlis excluded by!**/pnpm-lock.yamllogs-banner-mobile.pngis excluded by!**/*.pnglogs-desktop.pngis excluded by!**/*.pnglogs-history-mobile.pngis excluded by!**/*.pnglogs-populated-desktop.pngis excluded by!**/*.pnglogs-populated-mobile.pngis excluded by!**/*.png
📒 Files selected for processing (186)
Justfilecrates/mesh-llm-cli/src/parser.rscrates/mesh-llm-cli/src/parser/logging_help.rscrates/mesh-llm-console-server/src/lib.rscrates/mesh-llm-host-runtime/src/api/server.rscrates/mesh-llm-host-runtime/src/api/tests/ui_routes.rscrates/mesh-llm-host-runtime/src/logging/raw_mesh_lifecycle/tests.rscrates/mesh-llm-host-runtime/src/runtime/local/native_runtime_events/tests.rscrates/mesh-llm-tui/src/output/EVENTS.mdcrates/mesh-llm-tui/src/output/dashboard.rscrates/mesh-llm-tui/src/output/formatting.rscrates/mesh-llm-tui/src/output/logging_projection.rscrates/mesh-llm-tui/src/output/logging_projection/privacy.rscrates/mesh-llm-tui/src/output/mod.rscrates/mesh-llm-tui/src/output/state.rscrates/mesh-llm-tui/src/output/tests/logging_projection.rscrates/mesh-llm-tui/src/output/tests/mod.rscrates/mesh-llm-ui/e2e/a11y/logs-a11y.spec.tscrates/mesh-llm-ui/e2e/configuration/schema-controls.spec.tscrates/mesh-llm-ui/e2e/logs/log-workflows.spec.tscrates/mesh-llm-ui/e2e/logs/real-console.spec.tscrates/mesh-llm-ui/e2e/logs/request-inspector-capability.spec.tscrates/mesh-llm-ui/e2e/logs/request-inspector-fixtures.tscrates/mesh-llm-ui/e2e/logs/request-inspector-helpers.tscrates/mesh-llm-ui/e2e/logs/request-inspector-overview.spec.tscrates/mesh-llm-ui/e2e/logs/request-inspector-payloads.spec.tscrates/mesh-llm-ui/e2e/logs/request-inspector-routes.tscrates/mesh-llm-ui/e2e/logs/request-inspector-test.tscrates/mesh-llm-ui/e2e/logs/request-inspector.spec.tscrates/mesh-llm-ui/package.jsoncrates/mesh-llm-ui/playwright.config.tscrates/mesh-llm-ui/src/app/layout/RootLayout.test.tsxcrates/mesh-llm-ui/src/app/layout/RootLayout.tsxcrates/mesh-llm-ui/src/app/router/router.test.tsxcrates/mesh-llm-ui/src/app/router/router.tsxcrates/mesh-llm-ui/src/components/ui/CopyInstructionRow.test.tsxcrates/mesh-llm-ui/src/components/ui/CopyInstructionRow.tsxcrates/mesh-llm-ui/src/components/ui/DropdownMenu.tsxcrates/mesh-llm-ui/src/components/ui/FilterPopover.tsxcrates/mesh-llm-ui/src/components/ui/StatusBadge.tsxcrates/mesh-llm-ui/src/components/ui/chart.tsxcrates/mesh-llm-ui/src/components/ui/collapsible.tsxcrates/mesh-llm-ui/src/components/ui/data-table-column-header.tsxcrates/mesh-llm-ui/src/components/ui/data-table-pagination.tsxcrates/mesh-llm-ui/src/components/ui/data-table-view-options.tsxcrates/mesh-llm-ui/src/components/ui/data-table.test.tsxcrates/mesh-llm-ui/src/components/ui/data-table.tsxcrates/mesh-llm-ui/src/components/ui/scroll-area.tsxcrates/mesh-llm-ui/src/features/app-tabs/data.tscrates/mesh-llm-ui/src/features/app-tabs/types.tscrates/mesh-llm-ui/src/features/chat/pages/ChatPage.tsxcrates/mesh-llm-ui/src/features/configuration/api/config-adapter.test.tscrates/mesh-llm-ui/src/features/configuration/api/config-adapter.tscrates/mesh-llm-ui/src/features/configuration/api/runtime-settings.tscrates/mesh-llm-ui/src/features/configuration/components/DefaultsTab.test.tsxcrates/mesh-llm-ui/src/features/configuration/components/DefaultsTab.tsxcrates/mesh-llm-ui/src/features/configuration/components/configuration-tab-ids.test.tscrates/mesh-llm-ui/src/features/configuration/components/configuration-tab-ids.tscrates/mesh-llm-ui/src/features/configuration/pages/ConfigurationPage.tsxcrates/mesh-llm-ui/src/features/configuration/pages/ConfigurationRoutePage.test.tsxcrates/mesh-llm-ui/src/features/configuration/pages/ConfigurationRoutePage.tsxcrates/mesh-llm-ui/src/features/logs/api/client.test.tscrates/mesh-llm-ui/src/features/logs/api/client.tscrates/mesh-llm-ui/src/features/logs/api/ids.tscrates/mesh-llm-ui/src/features/logs/api/schemas.test.tscrates/mesh-llm-ui/src/features/logs/api/schemas.tscrates/mesh-llm-ui/src/features/logs/api/sse.tscrates/mesh-llm-ui/src/features/logs/api/use-log-artifact-content-query.test.tsxcrates/mesh-llm-ui/src/features/logs/api/use-log-artifact-content-query.tscrates/mesh-llm-ui/src/features/logs/api/use-log-request-details-query.test.tscrates/mesh-llm-ui/src/features/logs/api/use-log-request-details-query.tscrates/mesh-llm-ui/src/features/logs/api/use-logs-audit-query.test.tsxcrates/mesh-llm-ui/src/features/logs/api/use-logs-audit-query.tscrates/mesh-llm-ui/src/features/logs/api/use-logs-ledger-query.test.tscrates/mesh-llm-ui/src/features/logs/api/use-logs-ledger-query.tscrates/mesh-llm-ui/src/features/logs/api/use-logs-live-recovery.test.tsxcrates/mesh-llm-ui/src/features/logs/api/use-logs-live-recovery.tscrates/mesh-llm-ui/src/features/logs/components/CopyRequestIdButton.tsxcrates/mesh-llm-ui/src/features/logs/components/JsonPayloadView.test.tsxcrates/mesh-llm-ui/src/features/logs/components/JsonPayloadView.tsxcrates/mesh-llm-ui/src/features/logs/components/LogArtifactDownloadControl.tsxcrates/mesh-llm-ui/src/features/logs/components/LogArtifactMetadata.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogArtifactMetadata.tsxcrates/mesh-llm-ui/src/features/logs/components/LogArtifactStateBadges.tsxcrates/mesh-llm-ui/src/features/logs/components/LogCleanupDialog.tsxcrates/mesh-llm-ui/src/features/logs/components/LogCleanupScope.tscrates/mesh-llm-ui/src/features/logs/components/LogDiagnosticArtifactList.tsxcrates/mesh-llm-ui/src/features/logs/components/LogEventInspector.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogEventInspector.tsxcrates/mesh-llm-ui/src/features/logs/components/LogEventLedgerColumns.tsxcrates/mesh-llm-ui/src/features/logs/components/LogMaintenanceReceiptDiagnostics.tsxcrates/mesh-llm-ui/src/features/logs/components/LogMaintenanceReceiptEligibility.tscrates/mesh-llm-ui/src/features/logs/components/LogOperations.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogOperations.tsxcrates/mesh-llm-ui/src/features/logs/components/LogPayloadContent.tsxcrates/mesh-llm-ui/src/features/logs/components/LogPayloadPane.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestDeleteControl.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestDetails.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestDetails.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestDetailsDiagnosticsQueries.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestDetailsOverviewQueries.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestDiagnosticSummary.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestDiagnostics.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestDiagnostics.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestEvidenceTimeline.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestEvidenceTimeline.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestInspectorFooter.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestInspectorFooter.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestInspectorHeader.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestOverview.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestOverview.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestOverviewDerivations.tscrates/mesh-llm-ui/src/features/logs/components/LogRequestOverviewEvidence.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestOverviewMetadata.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestOverviewOrdering.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestOverviewPanel.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestPayloads.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestPayloads.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRequestTimeline.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRoutingAttemptsTimeline.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogRoutingAttemptsTimeline.tsxcrates/mesh-llm-ui/src/features/logs/components/LogStreamTimeline.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogStreamTimeline.tsxcrates/mesh-llm-ui/src/features/logs/components/LogsEventLedger.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogsLedger.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogsLedger.tsxcrates/mesh-llm-ui/src/features/logs/components/LogsLedgerFilterPersistence.test.tsxcrates/mesh-llm-ui/src/features/logs/components/LogsLedgerInspectorCapability.test.tsxcrates/mesh-llm-ui/src/features/logs/components/RequestsOverTimeChart.test.tsxcrates/mesh-llm-ui/src/features/logs/components/RequestsOverTimeChart.tsxcrates/mesh-llm-ui/src/features/logs/lib/log-audit-fixtures.test.tscrates/mesh-llm-ui/src/features/logs/lib/log-event-ledger.test.tscrates/mesh-llm-ui/src/features/logs/lib/log-event-ledger.tscrates/mesh-llm-ui/src/features/logs/lib/log-fixtures.test.tscrates/mesh-llm-ui/src/features/logs/lib/log-fixtures.tscrates/mesh-llm-ui/src/features/logs/lib/log-fixtures/artifacts.tscrates/mesh-llm-ui/src/features/logs/lib/log-fixtures/audits.tscrates/mesh-llm-ui/src/features/logs/lib/log-fixtures/lifecycle-events.tscrates/mesh-llm-ui/src/features/logs/lib/log-fixtures/proxy-attempts.tscrates/mesh-llm-ui/src/features/logs/lib/log-fixtures/requests.tscrates/mesh-llm-ui/src/features/logs/lib/log-fixtures/support.tscrates/mesh-llm-ui/src/features/logs/lib/log-grid.test.tscrates/mesh-llm-ui/src/features/logs/lib/log-grid.tscrates/mesh-llm-ui/src/features/logs/lib/log-inspector.tscrates/mesh-llm-ui/src/features/logs/lib/log-instant.test.tscrates/mesh-llm-ui/src/features/logs/lib/log-instant.tscrates/mesh-llm-ui/src/features/logs/lib/log-kpis.test.tscrates/mesh-llm-ui/src/features/logs/lib/log-kpis.tscrates/mesh-llm-ui/src/features/logs/lib/log-payload-content.test.tscrates/mesh-llm-ui/src/features/logs/lib/log-payload-content.tscrates/mesh-llm-ui/src/features/logs/lib/log-request-details.test.tscrates/mesh-llm-ui/src/features/logs/lib/log-request-details.tscrates/mesh-llm-ui/src/features/logs/lib/log-search.test.tscrates/mesh-llm-ui/src/features/logs/lib/log-search.tscrates/mesh-llm-ui/src/features/logs/lib/log-timeline.test.tscrates/mesh-llm-ui/src/features/logs/lib/log-timeline.tscrates/mesh-llm-ui/src/features/logs/lib/log-token-usage.tscrates/mesh-llm-ui/src/features/logs/lib/log-volume.test.tscrates/mesh-llm-ui/src/features/logs/lib/log-volume.tscrates/mesh-llm-ui/src/features/logs/lib/use-advancing-chart-clock.tscrates/mesh-llm-ui/src/features/logs/pages/LogMaintenanceInvalidation.test.tsxcrates/mesh-llm-ui/src/features/logs/pages/LogRequestDetailsPage.test.tsxcrates/mesh-llm-ui/src/features/logs/pages/LogRequestDetailsPage.tsxcrates/mesh-llm-ui/src/features/logs/pages/LogsFeatureGate.tsxcrates/mesh-llm-ui/src/features/logs/pages/LogsLedgerPage.tsxcrates/mesh-llm-ui/src/features/reserves/components/ReservesSurface.tsxcrates/mesh-llm-ui/src/features/reserves/pages/ReservesPage.test.tsxcrates/mesh-llm-ui/src/features/shell/components/TopNav.test.tsxcrates/mesh-llm-ui/src/features/shell/components/TopNav.tsxcrates/mesh-llm-ui/src/lib/env.tscrates/mesh-llm-ui/src/lib/feature-flags/definitions.tscrates/mesh-llm-ui/src/lib/i18n/index.tsxcrates/mesh-llm-ui/src/styles/globals.csscrates/mesh-llm/src/lib.rsdocs/CLI.mddocs/LOGGING.mddocs/README.mddocs/USAGE.mddocs/design/DESIGN.mddocs/design/TESTING.mddocs/plugins/telemetry.mdlogs-desktop-snapshot.mdlogs-populated-desktop.mdlogs-populated-mobile.mdscripts/qa-logging-console-e2e.shwebsite/src/docs/pages/CLI.md
e6e582f to
78e15be
Compare
Summary
Third and final PR in the logging stack, based on #1175. This layer delivers the operator-facing logs console, request inspector, maintenance workflows, and privacy-safe output projections.
System logs ledger
Request Inspector
Maintenance and recovery
/logsand request-inspector route serving from the embedded console.Configuration and terminal output
[logging.audit]settings in configuration schema/UI and CLI help. Because this feature is unreleased, there is no deprecated top-level[audit]compatibility layer.Quality coverage
Screenshots
Captured from the final branch with deterministic test-harness data. The image assets are hosted separately and are not part of the commit.
Request log
Request Inspector — overview
Request Inspector — redacted payload
Request Inspector — stream and routing timeline
Request Inspector — failed request diagnostics
Validation
cargo check -p mesh-llm, and workspace formatting passed locally.Stack
Guardrails
This PR is the UI, configuration presentation, and terminal-projection layer. It does not change mesh/protobuf schemas, ALPN labels, the native ABI, or add an OTLP log API. The screenshots are hosted separately and are not committed to this branch.
Summary by CodeRabbit
/logsdeep links now correctly load the console.