diff --git a/rust/contracts/rust-core-api.md b/rust/contracts/rust-core-api.md index 9a25720f..ba7bf46b 100644 --- a/rust/contracts/rust-core-api.md +++ b/rust/contracts/rust-core-api.md @@ -3626,7 +3626,10 @@ parser diagnostics; hosts localize codes for presentation. With `deduplicate:true`, adjacent facts with equal event ID, fields, channel, level, message and op merge within a batch into `log.repeated`; structural hashing is followed by equality comparison. Results then correspond to retained records, - and the repeated record uses the last omitted event sequence. `previousEvent` + and the repeated record uses the last omitted event sequence. Every failed header + or event result carries `index`, the zero-based position of the rejected item in + its input list, so hosts can name the rejected event without relying on result + order; successful results have no `index`. `previousEvent` carries the prior batch’s last input for bounded cross-batch comparison; it is validated again and never emitted by itself. With `validateCatalog:true`, every ordinary event must exist in `catalog::EVENTS`; @@ -5854,10 +5857,8 @@ row, and existing type/state/sequence/message/error fields remain unchanged. Hosts decode and forward optional structured identity independently of the event kind, once before event-specific handling; this also covers VCS, build, toolchain and backend sessions. Core owns these session lifecycle states and protocol -initialization. macOS owns only `lsp.session.stage_changed` (DEBUG; closed -requested|resolving|registered|stopping|cancelled) and `lsp.cache.cleaned` (DEBUG; -removed entry count), emitted at the source rather than inferred from v1 text. -Host ready/terminated callbacks retain v1 buffer lines without duplicate v2 facts. +initialization; hosts add no launch-stage or cache-maintenance events of their +own. Host ready/terminated callbacks retain v1 buffer lines without duplicate v2 facts. Stderr is framed by LF, removes a trailing CR, ignores empty lines, flushes the last partial line at EOF, and keeps at most 4096 bytes per line while discarding the remainder through LF. `truncated:true` marks the reader limit. Catalog text @@ -5947,8 +5948,9 @@ accepts `{pluginId,operation,outcome,stage?,durationMs,operationId?}` with no ot keys and returns `data:{result:{}}` once the fact is queued, or `data:{error:{code:-32064,reason}}`. `outcome` is `finished|failed`; `stage` is required for `failed` and forbidden for `finished`. `durationMs` is monotonic -milliseconds up to 2^53-1. `operationId` follows the SDK `operationId` grammar -(1-128 bytes of ASCII letters, digits and `._:/-$`). The fact becomes +milliseconds up to 2^53-1. `operationId` is 1-128 bytes of ASCII letters, digits +and `._:/-`: the SDK `operationId` grammar without `$`, because the record also +uses it as its `op`, whose grammar has no `$`. The fact becomes `plugins.operation.finished` or `plugins.operation.failed` on `plugins/{plugin}/host`, the same events and channel an SDK-backed plugin writes, with fields `plugin`, `operation`, `duration_ms` and, for failures, `code`. @@ -5978,13 +5980,42 @@ a code has one meaning across every contribution with that lifecycle: An unknown operation, a stage the lifecycle cannot reach, an unknown key, an explicit `null` for an optional key, an invalid operation ID or an out-of-range duration all return -32064. Whoever executes the attempt records it. The host -records debug adapter starts and build commands itself. A debug adapter start -uses the debug session ID as `operationId`, so it correlates with that session's -own debug records. It stays at `launch` until the adapter is reachable: a stdio -process once it runs, a language server hosted adapter once its socket connects. -A failure before then is `launch`, or `timeout` when the hosted adapter's -discovery deadline fires. `exit` applies only to an adapter that was reached. -Core refusing the debug session is a host outcome and is not recorded. +records debug adapter starts and build commands itself. + +A debug adapter start uses the debug session ID as `operationId`, so it +correlates with that session's own debug records. It runs from launch +resolution until the adapter answers `initialize`. The adapter is reached once a +stdio process runs, or once a language server hosted adapter's socket connects. +The start records exactly one result: + +- `resolve` when the adapter's settings, launch plan, program or state + directories cannot be resolved; +- `launch` when the adapter is not reached; +- `timeout` when the hosted adapter's discovery deadline, the `initialize` + window or a write deadline runs out; +- `exit` when a reached adapter's process or stream ends, or a stdio adapter + stops reading its input, before it answers `initialize`; +- `initialize` for any other failure of a reached adapter before then, a refused + `initialize` included; +- `finished` when the adapter answers `initialize`. + +A start the user stops records nothing, and neither does Core refusing the debug +session, which is a host outcome. + +A build command source run uses the `op` of the action that loads the build +model or its dependencies as `operationId`. It ends at: + +- `plan` when the host cannot prepare the plan or its output file, or the plan + is not a command; +- `resolve` when the build tool cannot be found; +- `launch` when the command's process does not start; +- `exit` when the command fails, which also covers output that then does not + decode; +- `decode` when a successful command's output is not a valid document; +- `timeout` when a deadline runs out at any stage. + +A load that the project's close cancels records nothing. Requests to a +provider-backed build system are the plugin's own to log. A declarative language server is resolved by the host and supervised by Core. The host records failures before launch, including servers that launch as @@ -6038,32 +6069,45 @@ and `plugins/v1/fixtures/backend/plugin-logging.json`. Explicit upstream LSP mes types retain their severity through separate catalog events; unclassified stderr is DEBUG and actual lifecycle failure is ERROR. -macOS PR3 passes `CoreLogRecord` directly to the injected `LogSink`. Every -MacLogStore drain, flush and finish calls `diagnostics.drainCoreEvents` once, -retaining source `ts`/`op` and allocating session `seq`. Only the application -writer installs the Core log waker; its callback schedules the same 100 ms -one-shot drain that host events use, so Core and plugin facts recorded without -host activity reach disk and live subscribers without an idle poller or second -writer. Finishing the session removes the waker before the final drain. -MacLogStore sends `diagnostics.configureCoreEvents` only when the -detailed-diagnostics state or its channel roots change. `channelCategory` maps -lsp to language, vcs to git and plugin-host processes to plugins. The selected diagnostic category drives -`lsp.setDetailedDiagnostics` for active sessions, newly registered sessions and -a one-shot 15-minute expiry. A failed desired state, including a failed -`configureCoreEvents`, is reported once with -`app.logging.diagnostics_failed`; changing desired state permits another attempt. -Language-server evidence has no in-memory v1 buffer on macOS; the log window reads -only v2 session files. +The desktop host (Viva/Go, `desktop/internal/logstore` in Lithe-IDEA) encodes +the facts it drains together with its own events, in one +`diagnostics.encodeLogBatch` with `validateCatalog: true`. Every drain, flush and +close calls `diagnostics.drainCoreEvents` once, keeps each fact's `ts`, `op` and +channel, and allocates the session `seq`. Core keeps one log waker per process, +so only the application's writer installs it. Its callback only wakes the +writer, which runs the same 100 ms coalesced drain that host events use. Core +and plugin facts recorded without host activity therefore reach disk and live +subscribers without an idle poller or a second writer. Closing the writer +removes the waker before the final drain. + +The writer sends `diagnostics.configureCoreEvents` only when the +detailed-diagnostics state changes. A failed `configureCoreEvents` is reported +once with `app.logging.diagnostics_failed`, and is retried only after the +desired state changes again. The same state drives `lsp.setDetailedDiagnostics` +for every active plugin session the host started, for sessions started while it +is on, and for its one-shot 15-minute expiry. Sessions refusing the switch are +reported with the same event once per choice, however many refuse; a session +that ended meanwhile is not a failure. `channelCategory` maps lsp to +language, vcs to git and plugin-host processes to plugins. + +Lifecycle facts that Core attaches to runtime events (`event`, `catalogLevel`, +`fields`) are forwarded to the writer once, before the host branches on the +event type. This includes the exit event and the last events read while a +session stops. The log window reads only v2 session files and the writer's +live batches. There is no in-memory v1 buffer. `diagnostics.resolveLogChannel` additionally returns optional `pluginFilesPath` -for a `plugins//host` channel using Core's `plugin_files_path` rule. macOS -creates that directory under its current session with mode 0700 and descriptor -relative no-follow traversal, and supplies `request.logDirectory` before local -language/provider/backend launch. Missing log storage omits it; Core rejects a -launch that actually uses `${logDir}`. Remote processes cannot write the macOS -log directory, so remote requests omit it and reject `${logDir}` rather than -writing into remote package/state directories. Package installation validation -uses an uncreated placeholder only to validate expansion, never to launch. +for a `plugins//host` channel using Core's `plugin_files_path` rule. The +desktop host creates that directory under its current session with mode 0700, +checking each path segment and refusing `.`, `..` and existing symbolic links or +special files. It supplies the directory as `request.logDirectory` before a +local language server or plugin backend launch. When the directory is +unavailable, the host records `app.background.operation_failed` and omits it. +Core then rejects a launch that actually uses `${logDir}`. Remote processes +cannot write the host's log directory, so remote requests omit it and reject +`${logDir}` rather than writing into remote package or state directories. +Package installation validation uses an uncreated placeholder only to validate +expansion, never to launch. Core directory traversal and scratch cleanup reuse PR1's `app.search.directory_skipped`, `app.workspace.directory_skipped` and diff --git a/rust/crates/diagnostics/src/catalog.rs b/rust/crates/diagnostics/src/catalog.rs index 3e7fa696..6774912f 100644 --- a/rust/crates/diagnostics/src/catalog.rs +++ b/rust/crates/diagnostics/src/catalog.rs @@ -262,12 +262,11 @@ mod tests { let fields = BTreeMap::from([("failure_code".into(), json!("request_failed"))]); assert!(validate_fields("remote.upload.abort_failed", &fields).is_ok()); let fields = BTreeMap::from([ - ("plugin".into(), json!("io.example")), - ("language".into(), json!("toml")), + ("operation".into(), json!("fixture")), ("error".into(), json!("failed")), ]); assert_eq!( - validate_fields("plugins.grammar.load_failed", &fields) + validate_fields("app.background.operation_failed", &fields) .unwrap_err() .code, CatalogErrorCode::MissingField diff --git a/rust/crates/diagnostics/src/catalog_generated.rs b/rust/crates/diagnostics/src/catalog_generated.rs index 66082260..b4819533 100644 --- a/rust/crates/diagnostics/src/catalog_generated.rs +++ b/rust/crates/diagnostics/src/catalog_generated.rs @@ -13,19 +13,20 @@ pub static EVENTS: &[EventMetadata] = &[ message: "User action {action} performed", fields: &[ FieldMetadata { name: "action", field_type: FieldType::Token, required: true, description: "Stable id of the user action that started the work, never a localized menu or button title", reason: None }, - FieldMetadata { name: "surface", field_type: FieldType::Token, required: true, description: "UI surface that invoked the action: menu, shortcut, palette, toolbar, button, context_menu, notification or plugin", reason: None }, + FieldMetadata { name: "surface", field_type: FieldType::Token, required: true, description: "UI surface that invoked the action: menu, shortcut, palette, toolbar, button, context_menu, notification, plugin or drag_drop", reason: None }, ], span: None, rate: 600, owner: "LitheModuleAPI", }, EventMetadata { - id: "app.action_search.failed", + id: "app.background.operation_failed", channel: "app", - level: LogLevel::Error, - message: "Action catalog search failed", + level: LogLevel::Warn, + message: "Background operation {operation} failed", fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Core command failure while matching the current action catalog; excludes query text and action content", reason: None }, + FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Error raised by the background work; the window degrades instead of notifying the user", reason: None }, + FieldMetadata { name: "operation", field_type: FieldType::Token, required: true, description: "Source-owned category of work the window runs on its own, such as project_tree_watch or memory_sample", reason: None }, ], span: None, rate: 60, @@ -44,19 +45,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "lithe-core", }, - EventMetadata { - id: "app.core.fallback_selected", - channel: "app", - level: LogLevel::Warn, - message: "Core request used a fallback", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Core request or catalog decoding operation that selected a fallback", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "app.core.request.failed", channel: "app/core", @@ -114,67 +102,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 600, owner: "lithe-core", }, - EventMetadata { - id: "app.credentials.cleanup_failed", - channel: "app", - level: LogLevel::Warn, - message: "Obsolete credential removal failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "app.credentials.write_failed", - channel: "app", - level: LogLevel::Error, - message: "Credential update failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure that prevented completing the requested operation", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "app.demo.failed", - channel: "app", - level: LogLevel::Warn, - message: "Problems demo {stage} failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "File operation error raised while creating or removing the Problems demo files", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Problems demo step that failed, e.g. creation or cleanup", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "app.diagnostics.cleanup_failed", - channel: "app", - level: LogLevel::Warn, - message: "Diagnostic staging cleanup failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "app.diagnostics.crash_skipped", - channel: "app", - level: LogLevel::Warn, - message: "Crash report collection skipped evidence", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Native failure reading the DiagnosticReports directory or an eligible application crash report", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "app.diagnostics.export_failed", channel: "app", @@ -188,57 +115,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "Lithe", }, - EventMetadata { - id: "app.font.missing", - channel: "app", - level: LogLevel::Warn, - message: "Bundled font {font} missing", - fields: &[ - FieldMetadata { name: "font", field_type: FieldType::Token, required: true, description: "Filename of the missing bundled font, e.g. Inter-Regular.otf", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "app.font.registration_failed", - channel: "app", - level: LogLevel::Warn, - message: "Bundled font {font} registration failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "CoreText error returned when registering this bundled font", reason: None }, - FieldMetadata { name: "font", field_type: FieldType::Token, required: true, description: "Filename of the font passed to CoreText for registration", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "app.history.operation_failed", - channel: "app", - level: LogLevel::Warn, - message: "Local history operation failed", - fields: &[ - FieldMetadata { name: "count", field_type: FieldType::Int, required: false, description: "Number of failed snapshots in this batch; absent for a single history operation", reason: None }, - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "History action that failed, such as record, relocate or restore", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheLocalHistoryModule", - }, - EventMetadata { - id: "app.history.restore_failed", - channel: "app", - level: LogLevel::Error, - message: "Local history restore failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure that prevented completing the requested operation", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheLocalHistoryModule", - }, EventMetadata { id: "app.ide.broker_failed", channel: "app", @@ -265,19 +141,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "lithe-core", }, - EventMetadata { - id: "app.ide.request_failed", - channel: "app", - level: LogLevel::Error, - message: "IDE capability request failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "IDE request phase that failed, such as response encoding or dispatch", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "app.indexing.rollback_failed", channel: "app", @@ -316,33 +179,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "Lithe", }, - EventMetadata { - id: "app.module.transition_failed", - channel: "app", - level: LogLevel::Warn, - message: "Module transition failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - FieldMetadata { name: "module", field_type: FieldType::Token, required: true, description: "Module identifier whose lifecycle transition failed", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Lifecycle action that failed, such as shutdown, sleep or idle", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheApplicationKernel", - }, - EventMetadata { - id: "app.native.operation_failed", - channel: "app", - level: LogLevel::Error, - message: "Native {stage} operation failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Original native error from the failed request, preserving stable domain and code", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Native user request that could not finish, such as relaunch, agent-preserve, or background-selection", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "app.notification.operation_failed", channel: "app", @@ -369,33 +205,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "Lithe", }, - EventMetadata { - id: "app.process.journal_failed", - channel: "app", - level: LogLevel::Warn, - message: "Process lifecycle journal write failed at {stage}", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Persistence error raised while saving managed process identities", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Lifecycle journal write stage, e.g. process-exit or startup-descendants", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "app.process.watch_failed", - channel: "app", - level: LogLevel::Warn, - message: "Retained process watch failed at {stage}", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "POSIX error from creating, registering or reading the retained process watcher", reason: None }, - FieldMetadata { name: "pid", field_type: FieldType::Int, required: false, description: "Retained process PID being registered; absent for watcher-wide failures", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Retained process watcher step, e.g. create, register or read", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "app.search.directory_skipped", channel: "app", @@ -480,51 +289,41 @@ pub static EVENTS: &[EventMetadata] = &[ owner: "Lithe", }, EventMetadata { - id: "app.storage.cleanup_failed", - channel: "app", - level: LogLevel::Warn, - message: "Core storage cleanup failed", - fields: &[ - FieldMetadata { name: "count", field_type: FieldType::Int, required: true, description: "Number of failed storage removals summarized by this cleanup operation", reason: None }, - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "First filesystem failure category observed while removing owned temporary or history files", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Storage cleanup owner, e.g. snapshot-rollback or history-pruning", reason: None }, - ], - span: None, - rate: 60, - owner: "lithe-core", - }, - EventMetadata { - id: "app.storage.maintenance_failed", + id: "app.startup.leftovers_resolved", channel: "app", - level: LogLevel::Warn, - message: "Native storage {stage} failed", + level: LogLevel::Info, + message: "Leftover processes from the previous session resolved", fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Native filesystem error preserving its stable domain and code at the handling boundary", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Native storage operation that failed, such as file-close, staging-remove, or permissions", reason: None }, + FieldMetadata { name: "decided_by", field_type: FieldType::Token, required: true, description: "What decided the leftovers: policy when the process lifecycle plan settled them without asking, dialog when the user answered the start-up question", reason: None }, + FieldMetadata { name: "ended", field_type: FieldType::Int, required: true, description: "Number of leftover processes the client ended", reason: None }, + FieldMetadata { name: "kept", field_type: FieldType::Int, required: true, description: "Number of leftover processes the client kept running and stopped tracking", reason: None }, ], span: None, rate: 60, owner: "Lithe", }, EventMetadata { - id: "app.window.session_missing", + id: "app.storage.cleanup_failed", channel: "app", level: LogLevel::Warn, - message: "Project window {window} session missing", + message: "Core storage cleanup failed", fields: &[ - FieldMetadata { name: "window", field_type: FieldType::Id, required: true, description: "Internal project window UUID whose corresponding session could not be found", reason: None }, + FieldMetadata { name: "count", field_type: FieldType::Int, required: true, description: "Number of failed storage removals summarized by this cleanup operation", reason: None }, + FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "First filesystem failure category observed while removing owned temporary or history files", reason: None }, + FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Storage cleanup owner, e.g. snapshot-rollback or history-pruning", reason: None }, ], span: None, rate: 60, - owner: "Lithe", + owner: "lithe-core", }, EventMetadata { - id: "app.workbench.registration_failed", + id: "app.storage.maintenance_failed", channel: "app", level: LogLevel::Warn, - message: "Workbench UI registration failed", + message: "Host storage {stage} failed", fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Validation error raised when registering workbench UI contributions", reason: None }, + FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Filesystem error at the host's handling boundary, preserving its stable domain and code", reason: None }, + FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Host storage operation that failed, such as plugin_install_cleanup: a downloaded or staged plugin package the install could not remove", reason: None }, ], span: None, rate: 60, @@ -543,31 +342,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "lithe-core", }, - EventMetadata { - id: "app.workspace.file_operation_failed", - channel: "app", - level: LogLevel::Error, - message: "Workspace file operation failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Workspace file action that failed, such as move, copy or create", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheWorkspaceModule", - }, - EventMetadata { - id: "app.workspace.rollback_failed", - channel: "app", - level: LogLevel::Warn, - message: "Workspace preference rollback failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheWorkspaceModule", - }, EventMetadata { id: "app.workspace.scratch_cleanup_failed", channel: "app", @@ -580,20 +354,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "lithe-core", }, - EventMetadata { - id: "debug.inspection.fallback_selected", - channel: "debug", - level: LogLevel::Warn, - message: "Debug inspection used a fallback", - fields: &[ - FieldMetadata { name: "count", field_type: FieldType::Int, required: false, description: "Number of field requests that failed in this bounded snapshot; absent for memory layout decoding", reason: None }, - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Debug inspection step that failed, variable-fields or memory-layout", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheDebugModule", - }, EventMetadata { id: "debug.operation.cancelled", channel: "debug/{adapter}", @@ -632,19 +392,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 120, owner: "lithe-core", }, - EventMetadata { - id: "debug.session.cleanup_failed", - channel: "debug", - level: LogLevel::Warn, - message: "Debug session cleanup failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Debug cleanup phase that failed, breakpoints or disconnect", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheDebugModule", - }, EventMetadata { id: "debug.session.failed", channel: "debug/{adapter}", @@ -695,43 +442,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 120, owner: "lithe-core", }, - EventMetadata { - id: "debug.shortcut.decision_failed", - channel: "debug", - level: LogLevel::Error, - message: "Debug shortcut state decision failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Core failure while choosing whether the requested debug shortcut should start or continue", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "debug.transport.failed", - channel: "debug", - level: LogLevel::Error, - message: "Debug adapter transport failed", - fields: &[ - FieldMetadata { name: "exit_code", field_type: FieldType::Int, required: false, description: "Native adapter process exit status when available; absent for startup, timeout and receive failures", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Native failure stage, process-start, initialization-timeout, transport-exit or transport-receive", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheDebugModule", - }, - EventMetadata { - id: "editor.document.header_failed", - channel: "editor", - level: LogLevel::Warn, - message: "Document header inspection failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "editor.document.open_failed", channel: "editor", @@ -745,19 +455,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "Lithe", }, - EventMetadata { - id: "editor.document.recovery_failed", - channel: "editor", - level: LogLevel::Warn, - message: "Document {document} save state recovery failed", - fields: &[ - FieldMetadata { name: "document", field_type: FieldType::Id, required: true, description: "Internal document UUID whose save lifecycle state could not be recovered", reason: None }, - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Error raised while recovering the document lifecycle state after a failed save", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "editor.document.save_failed", channel: "editor", @@ -773,31 +470,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "Lithe", }, - EventMetadata { - id: "editor.document.save_superseded", - channel: "editor", - level: LogLevel::Debug, - message: "Document {document} revision {revision} save superseded", - fields: &[ - FieldMetadata { name: "document", field_type: FieldType::Id, required: true, description: "Internal document UUID whose save result was superseded", reason: None }, - FieldMetadata { name: "revision", field_type: FieldType::Int, required: true, description: "Native document lifecycle revision at the post-write supersession check", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "editor.document.staging_cleanup_failed", - channel: "editor", - level: LogLevel::Warn, - message: "Document staging cleanup failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Filesystem error raised while deleting the temporary document staging file", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "editor.document.watch_failed", channel: "editor", @@ -811,84 +483,15 @@ pub static EVENTS: &[EventMetadata] = &[ owner: "Lithe", }, EventMetadata { - id: "editor.icon.fallback_selected", + id: "editor.recovery.applied", channel: "editor", - level: LogLevel::Debug, - message: "File icon content inspection failed", + level: LogLevel::Info, + message: "Unsaved draft restored into its document", fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "File icon inspection kind, e.g. generic", reason: None }, + FieldMetadata { name: "conflict", field_type: FieldType::Bool, required: true, description: "Whether the file changed on disk since the draft was written, so the draft opens as a conflict against the disk version", reason: None }, ], span: None, - rate: 30, - owner: "Lithe", - }, - EventMetadata { - id: "editor.preview.update_failed", - channel: "editor", - level: LogLevel::Debug, - message: "Preview {stage} update failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Native WebKit or filesystem failure while applying the preview update", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Preview update stage, such as markdown-javascript or download-replace", reason: None }, - ], - span: None, - rate: 30, - owner: "Lithe", - }, - EventMetadata { - id: "editor.settings_import.failed", - channel: "editor", - level: LogLevel::Error, - message: "Editor settings import failed at {stage}", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Import or native I/O error classification; source paths, configuration contents and provider prose are omitted", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Import workflow boundary that failed: source-read, scan, apply, or undo", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "editor.settings_import.warnings_shown", - channel: "editor", - level: LogLevel::Warn, - message: "Editor settings import has unsupported source settings", - fields: &[ - FieldMetadata { name: "source_count", field_type: FieldType::Int, required: true, description: "Number of discovered sources with warnings shown in this scan", reason: None }, - FieldMetadata { name: "warning_count", field_type: FieldType::Int, required: true, description: "Total number of source warnings shown in this scan", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "editor.shortcuts.update_failed", - channel: "editor", - level: LogLevel::Error, - message: "Keyboard shortcut update failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "editor.sync.edit_received", - channel: "editor", - level: LogLevel::Debug, - message: "Document {document} received {change_count} edits during freeze", - fields: &[ - FieldMetadata { name: "base_revision", field_type: FieldType::Int, required: true, description: "Native revision on which the incoming browser edit batch was based", reason: None }, - FieldMetadata { name: "change_count", field_type: FieldType::Int, required: true, description: "Number of ordered edits in the incoming browser batch", reason: None }, - FieldMetadata { name: "document", field_type: FieldType::Id, required: true, description: "Internal document UUID that received browser edits while synchronization was frozen", reason: None }, - FieldMetadata { name: "inserted_utf16_length", field_type: FieldType::Int, required: true, description: "Total UTF-16 code units inserted by the incoming edit batch", reason: None }, - FieldMetadata { name: "native_revision", field_type: FieldType::Int, required: true, description: "Current native revision when the edit batch arrived", reason: None }, - FieldMetadata { name: "replaced_utf16_length", field_type: FieldType::Int, required: true, description: "Total UTF-16 code units replaced by the incoming edit batch", reason: None }, - ], - span: None, - rate: 60, + rate: 60, owner: "Lithe", }, EventMetadata { @@ -963,44 +566,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "Lithe", }, - EventMetadata { - id: "editor.sync.unlock_failed", - channel: "editor", - level: LogLevel::Debug, - message: "Document {document} synchronization unlock failed", - fields: &[ - FieldMetadata { name: "document", field_type: FieldType::Id, required: true, description: "Internal document UUID whose browser synchronization lock could not be released", reason: None }, - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Browser bridge error returned while releasing the synchronization lock", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "editor.sync.unlock_finished", - channel: "editor", - level: LogLevel::Debug, - message: "Document {document} synchronization unlocked", - fields: &[ - FieldMetadata { name: "document", field_type: FieldType::Id, required: true, description: "Internal document UUID whose browser synchronization lock was released", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "editor.syntax.configuration_failed", - channel: "editor", - level: LogLevel::Warn, - message: "Syntax {kind} configuration load failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Read or decode error raised while loading the syntax configuration", reason: None }, - FieldMetadata { name: "kind", field_type: FieldType::Token, required: true, description: "Syntax configuration being loaded, e.g. highlighting or colors", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "editor.text.classification_failed", channel: "editor", @@ -1013,46 +578,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "Lithe", }, - EventMetadata { - id: "editor.workspace_edit.rollback_failed", - channel: "editor", - level: LogLevel::Warn, - message: "Workspace edit rollback failed", - fields: &[ - FieldMetadata { name: "count", field_type: FieldType::Int, required: true, description: "Number of closed-file rollback writes that failed", reason: None }, - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "lsp.cache.cleaned", - channel: "lsp/{server}", - level: LogLevel::Debug, - message: "Language server {server} cache cleaned", - fields: &[ - FieldMetadata { name: "removed", field_type: FieldType::Int, required: true, description: "Number of workspace cache entries removed by the host cache cleaner.", reason: None }, - FieldMetadata { name: "server", field_type: FieldType::Id, required: true, description: "Core-resolved language provider routing segment whose workspace cache was pruned.", reason: None }, - ], - span: None, - rate: 60, - owner: "LanguageToolingSessionManager", - }, - EventMetadata { - id: "lsp.host.operation_failed", - channel: "lsp/{server}", - level: LogLevel::Warn, - message: "Language host operation failed at {stage}", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Native or stable runtime error that caused the host operation fallback", reason: None }, - FieldMetadata { name: "server", field_type: FieldType::Id, required: true, description: "Core-resolved language server identity owning this host operation", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Host operation step that failed, such as entrypoint-warmup or language-import", reason: None }, - ], - span: None, - rate: 120, - owner: "LitheLanguageIntelligenceModule", - }, EventMetadata { id: "lsp.message.detail.logged", channel: "lsp/{server}", @@ -1229,21 +754,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 120, owner: "lithe-core", }, - EventMetadata { - id: "lsp.session.degradation_received", - channel: "lsp/{server}", - level: LogLevel::Warn, - message: "Language server {server} operation degraded", - fields: &[ - FieldMetadata { name: "exit_code", field_type: FieldType::Int, required: false, description: "Native language server process exit status when supplied by the runtime.", reason: None }, - FieldMetadata { name: "failure_code", field_type: FieldType::Token, required: true, description: "Stable failure classification supplied by the owning runtime or host boundary.", reason: None }, - FieldMetadata { name: "server", field_type: FieldType::Id, required: true, description: "Language provider identity owned by the registered session.", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Actual source stage, such as discovery, configuration, documentSync or processStart.", reason: None }, - ], - span: None, - rate: 60, - owner: "LanguageToolingSessionManager", - }, EventMetadata { id: "lsp.session.failed", channel: "lsp/{server}", @@ -1258,34 +768,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "lithe-core", }, - EventMetadata { - id: "lsp.session.issue_failed", - channel: "lsp/{server}", - level: LogLevel::Error, - message: "Language server {server} operation failed", - fields: &[ - FieldMetadata { name: "exit_code", field_type: FieldType::Int, required: false, description: "Native language server process exit status when supplied by the runtime.", reason: None }, - FieldMetadata { name: "failure_code", field_type: FieldType::Token, required: true, description: "Stable failure classification supplied by the owning runtime or host boundary.", reason: None }, - FieldMetadata { name: "server", field_type: FieldType::Id, required: true, description: "Language provider identity owned by the registered session.", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Actual source stage, such as discovery, configuration, documentSync or processStart.", reason: None }, - ], - span: None, - rate: 60, - owner: "LanguageToolingSessionManager", - }, - EventMetadata { - id: "lsp.session.stage_changed", - channel: "lsp/{server}", - level: LogLevel::Debug, - message: "Language server {server} host stage changed to {stage}", - fields: &[ - FieldMetadata { name: "server", field_type: FieldType::Id, required: true, description: "Core-resolved language provider routing segment shared with engine session events.", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Closed host orchestration stage: requested, resolving, registered, stopping, or cancelled.", reason: None }, - ], - span: None, - rate: 60, - owner: "LanguageToolingSessionManager", - }, EventMetadata { id: "lsp.session.updated", channel: "lsp/{server}", @@ -1351,164 +833,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 120, owner: "lithe-core", }, - EventMetadata { - id: "perf.app.sampled", - channel: "perf", - level: LogLevel::Debug, - message: "Application performance sampled at {phase}", - fields: &[ - FieldMetadata { name: "duration", field_type: FieldType::Duration, required: false, description: "Elapsed time for the measured application phase in milliseconds, when applicable", reason: None }, - FieldMetadata { name: "phase", field_type: FieldType::Token, required: true, description: "Performance baseline phase associated with this sample, e.g. ready or stable", reason: None }, - FieldMetadata { name: "rss", field_type: FieldType::Bytes, required: false, description: "Application resident memory sampled from the native process monitor, in bytes", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "perf.app.signpost_measured", - channel: "perf", - level: LogLevel::Debug, - message: "Native signpost measured", - fields: &[ - FieldMetadata { name: "duration", field_type: FieldType::Duration, required: true, description: "Monotonic duration of the native signpost operation.", reason: None }, - FieldMetadata { name: "name", field_type: FieldType::Token, required: true, description: "Controlled native signpost name for the measured operation.", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe.Monitoring", - }, - EventMetadata { - id: "perf.editor.open_measured", - channel: "perf", - level: LogLevel::Debug, - message: "Editor opening measured", - fields: &[ - FieldMetadata { name: "attach", field_type: FieldType::Duration, required: false, description: "Monaco opening attach elapsed monotonic time in milliseconds.", reason: None }, - FieldMetadata { name: "first_frame", field_type: FieldType::Duration, required: false, description: "Monaco opening first_frame elapsed monotonic time in milliseconds.", reason: None }, - FieldMetadata { name: "frames", field_type: FieldType::Int, required: false, description: "Monaco opening frames count reported by the editor measurement.", reason: None }, - FieldMetadata { name: "lines", field_type: FieldType::Int, required: false, description: "Monaco opening lines count reported by the editor measurement.", reason: None }, - FieldMetadata { name: "max_frame_gap", field_type: FieldType::Duration, required: false, description: "Monaco opening max_frame_gap elapsed monotonic time in milliseconds.", reason: None }, - FieldMetadata { name: "model", field_type: FieldType::Duration, required: false, description: "Monaco opening model elapsed monotonic time in milliseconds.", reason: None }, - FieldMetadata { name: "reused", field_type: FieldType::Bool, required: false, description: "Whether opening reused the existing Monaco document model.", reason: None }, - FieldMetadata { name: "settled", field_type: FieldType::Duration, required: false, description: "Monaco opening settled elapsed monotonic time in milliseconds.", reason: None }, - FieldMetadata { name: "utf16_length", field_type: FieldType::Int, required: false, description: "Monaco opening utf16_length count reported by the editor measurement.", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "perf.editor.semantic_measured", - channel: "perf", - level: LogLevel::Debug, - message: "Editor semantic update measured with {tokens} tokens", - fields: &[ - FieldMetadata { name: "revision", field_type: FieldType::Int, required: false, description: "Document revision associated with the semantic token update, when supplied", reason: None }, - FieldMetadata { name: "tokens", field_type: FieldType::Int, required: true, description: "Number of semantic tokens delivered to the editor for this update", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "perf.git.cache_hit", - channel: "perf", - level: LogLevel::Debug, - message: "Git {operation} history cache hit", - fields: &[ - FieldMetadata { name: "duration", field_type: FieldType::Duration, required: true, description: "Elapsed history cache lookup time in milliseconds", reason: None }, - FieldMetadata { name: "operation", field_type: FieldType::Token, required: true, description: "Git service operation served from the history cache, e.g. history", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheGitModule", - }, - EventMetadata { - id: "perf.git.command_finished", - channel: "perf", - level: LogLevel::Debug, - message: "Git {operation} command measured", - fields: &[ - FieldMetadata { name: "duration", field_type: FieldType::Duration, required: true, description: "Elapsed Git command workflow time in milliseconds", reason: None }, - FieldMetadata { name: "operation", field_type: FieldType::Token, required: true, description: "Git service operation that issued the measured command", reason: None }, - FieldMetadata { name: "succeeded", field_type: FieldType::Bool, required: true, description: "Whether the Git command result reported success", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheGitModule", - }, - EventMetadata { - id: "perf.git.read_finished", - channel: "perf", - level: LogLevel::Debug, - message: "Git {operation} read measured", - fields: &[ - FieldMetadata { name: "duration", field_type: FieldType::Duration, required: true, description: "Elapsed Git service read time in milliseconds", reason: None }, - FieldMetadata { name: "operation", field_type: FieldType::Token, required: true, description: "Git service read operation being measured, e.g. history", reason: None }, - FieldMetadata { name: "succeeded", field_type: FieldType::Bool, required: true, description: "Whether the Git service read returned a result", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheGitModule", - }, - EventMetadata { - id: "perf.git.worktree_inspected", - channel: "perf", - level: LogLevel::Debug, - message: "Git worktree inspection measured", - fields: &[ - FieldMetadata { name: "duration", field_type: FieldType::Duration, required: true, description: "Elapsed time for this worktree inspection phase, in milliseconds", reason: None }, - FieldMetadata { name: "phase", field_type: FieldType::Token, required: true, description: "Worktree inspection phase supplied by the Git service", reason: None }, - FieldMetadata { name: "worktree", field_type: FieldType::Path, required: true, description: "Worktree root path from the Git snapshot, redacted by Core before persistence.", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheGitModule", - }, - EventMetadata { - id: "perf.settings.latency_measured", - channel: "perf", - level: LogLevel::Debug, - message: "Settings latency measured", - fields: &[ - FieldMetadata { name: "category", field_type: FieldType::Token, required: true, description: "Native settings latency category value; timestamps use monotonic nanoseconds.", reason: None }, - FieldMetadata { name: "event_id", field_type: FieldType::Int, required: true, description: "Native settings latency event_id value; timestamps use monotonic nanoseconds.", reason: None }, - FieldMetadata { name: "input_ns", field_type: FieldType::Int, required: true, description: "Native settings latency input_ns value; timestamps use monotonic nanoseconds.", reason: None }, - FieldMetadata { name: "phase", field_type: FieldType::Token, required: true, description: "Native settings latency phase value; timestamps use monotonic nanoseconds.", reason: None }, - FieldMetadata { name: "received_ns", field_type: FieldType::Int, required: true, description: "Native settings latency received_ns value; timestamps use monotonic nanoseconds.", reason: None }, - FieldMetadata { name: "selected_ns", field_type: FieldType::Int, required: true, description: "Native settings latency selected_ns value; timestamps use monotonic nanoseconds.", reason: None }, - FieldMetadata { name: "time_ns", field_type: FieldType::Int, required: true, description: "Native settings latency time_ns value; timestamps use monotonic nanoseconds.", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe.Monitoring", - }, - EventMetadata { - id: "plugins.backend.activation_failed", - channel: "plugins/{plugin}/host", - level: LogLevel::Warn, - message: "Plugin {plugin} backend activation failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Error returned while activating the installed plugin backend", reason: None }, - FieldMetadata { name: "plugin", field_type: FieldType::Id, required: true, description: "Validated installed plugin id whose backend activation failed", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "plugins.catalog.rejected", - channel: "plugins", - level: LogLevel::Warn, - message: "Plugin catalog startup rejected", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Validation error that rejected the global plugin module graph, without a single owning plugin", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "plugins.diagnostics.rejected", channel: "plugins/{plugin}/host", @@ -1522,86 +846,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 1, owner: "lithe-core", }, - EventMetadata { - id: "plugins.editor.action_failed", - channel: "plugins/{plugin}/host", - level: LogLevel::Warn, - message: "Plugin {plugin} editor action failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Error returned while executing the selected plugin editor action", reason: None }, - FieldMetadata { name: "plugin", field_type: FieldType::Id, required: true, description: "Validated plugin id that contributed the invoked editor action", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "plugins.editor.actions_failed", - channel: "plugins/{plugin}/host", - level: LogLevel::Warn, - message: "Plugin {plugin} editor actions failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Error returned while loading available editor actions from this plugin", reason: None }, - FieldMetadata { name: "plugin", field_type: FieldType::Id, required: true, description: "Validated plugin id whose editor actions could not be queried", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "plugins.editor.provider_failed", - channel: "plugins/{plugin}/host", - level: LogLevel::Warn, - message: "Plugin {plugin} editor provider failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Error returned while calling the provider function or validating its result", reason: None }, - FieldMetadata { name: "plugin", field_type: FieldType::Id, required: true, description: "Validated plugin id whose editor language-feature provider function failed or answered invalidly", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "plugins.editor.refresh_failed", - channel: "plugins", - level: LogLevel::Warn, - message: "Plugin editor actions refresh failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Error returned while refreshing the plugin editor action registrations", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "plugins.grammar.load_failed", - channel: "plugins/{plugin}/host", - level: LogLevel::Warn, - message: "Plugin {plugin} grammar failed in editor", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: false, description: "Editor grammar loading error, when the browser supplied structured failure details", reason: None }, - FieldMetadata { name: "language", field_type: FieldType::Version, required: false, description: "Language id reported by the editor, omitted only when longer than 64 bytes", reason: None }, - FieldMetadata { name: "plugin", field_type: FieldType::Id, required: true, description: "Validated plugin id that contributed the grammar rejected by the editor", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "plugins.grammar.rejected", - channel: "plugins/{plugin}/host", - level: LogLevel::Warn, - message: "Plugin {plugin} grammar rejected: {reason}", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: false, description: "Grammar file read or decode error; absent for path and file-kind rejections", reason: None }, - FieldMetadata { name: "language", field_type: FieldType::Version, required: false, description: "Language id from the rejected plugin grammar declaration", reason: None }, - FieldMetadata { name: "plugin", field_type: FieldType::Id, required: true, description: "Validated plugin id that owns the rejected grammar declaration", reason: None }, - FieldMetadata { name: "reason", field_type: FieldType::Token, required: true, description: "Grammar rejection category, e.g. outside-package, not-regular-file or invalid-grammar", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "plugins.host.message.detail.logged", channel: "plugins/{plugin}/host", @@ -1765,21 +1009,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 120, owner: "lithe-core", }, - EventMetadata { - id: "plugins.host.request_failed", - channel: "plugins/{plugin}/host", - level: LogLevel::Error, - message: "Plugin host request {method} failed with {code}", - fields: &[ - FieldMetadata { name: "code", field_type: FieldType::Token, required: true, description: "Stable plugin.host.* failure code the backend received, independent of the native error's wording", reason: None }, - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Native host service error or stable host request failure code", reason: None }, - FieldMetadata { name: "method", field_type: FieldType::Token, required: true, description: "Host method or plugin function the request named, e.g. lithe/host/languageServer/notify; never its params", reason: None }, - FieldMetadata { name: "plugin", field_type: FieldType::Id, required: true, description: "Validated plugin identity that owns this failed host request", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "plugins.host.response.skipped", channel: "plugins/{plugin}/host", @@ -1872,71 +1101,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 120, owner: "lithe-core", }, - EventMetadata { - id: "plugins.lifecycle.failed", - channel: "plugins", - level: LogLevel::Error, - message: "Module activation failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Error raised while starting the registered eager modules", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "plugins.lifecycle.started", - channel: "plugins", - level: LogLevel::Info, - message: "Eager modules started", - fields: &[ - - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "plugins.migration.finished", - channel: "plugins/{plugin}/host", - level: LogLevel::Info, - message: "Plugin {plugin} migrated {profiles} database profiles and {passwords} credentials", - fields: &[ - FieldMetadata { name: "passwords", field_type: FieldType::Int, required: true, description: "Number of legacy passwords successfully transferred to the plugin credential store", reason: None }, - FieldMetadata { name: "plugin", field_type: FieldType::Id, required: true, description: "Validated database plugin id that received the migrated state", reason: None }, - FieldMetadata { name: "profiles", field_type: FieldType::Int, required: true, description: "Number of legacy database connection profiles migrated into the plugin state", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "plugins.migration.password_failed", - channel: "plugins/{plugin}/host", - level: LogLevel::Warn, - message: "Plugin {plugin} credential migration failed for connection {connection}", - fields: &[ - FieldMetadata { name: "connection", field_type: FieldType::Id, required: true, description: "Legacy database connection id whose password could not be transferred", reason: None }, - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Credential store error raised when transferring this connection password; never the secret", reason: None }, - FieldMetadata { name: "plugin", field_type: FieldType::Id, required: true, description: "Validated database plugin id receiving the migrated credentials", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "plugins.migration.state_failed", - channel: "plugins/{plugin}/host", - level: LogLevel::Warn, - message: "Plugin {plugin} state migration failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Filesystem or encoding error raised while writing the migrated plugin state", reason: None }, - FieldMetadata { name: "plugin", field_type: FieldType::Id, required: true, description: "Validated database plugin id receiving the migrated connection state", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "plugins.operation.failed", channel: "plugins/{plugin}/host", @@ -1998,56 +1162,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 600, owner: "lithe-core", }, - EventMetadata { - id: "plugins.resources.maintenance_failed", - channel: "plugins", - level: LogLevel::Warn, - message: "Plugin resource {stage} failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Native failure while maintaining host-owned plugin download, staging, or state resources", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Owned plugin resource operation that failed, such as staging-remove, rollback, or archive-close", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "plugins.scan.failed", - channel: "plugins", - level: LogLevel::Warn, - message: "Live plugin scan failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Error returned by the live installed-plugin scan", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "plugins.startup.rejected", - channel: "plugins/{plugin}/host", - level: LogLevel::Warn, - message: "Plugin {plugin} startup rejected", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Manifest, UI binding or resource validation error that rejected this plugin at startup", reason: None }, - FieldMetadata { name: "plugin", field_type: FieldType::Id, required: true, description: "Validated installed plugin id whose startup acceptance checks failed", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "remote.build.cleanup_failed", - channel: "remote", - level: LogLevel::Warn, - message: "Remote build output cleanup failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Filesystem error raised while removing remote build output staging", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "remote.client.operation_failed", channel: "remote", @@ -2061,30 +1175,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "lithe-core", }, - EventMetadata { - id: "remote.connections.save_failed", - channel: "remote", - level: LogLevel::Warn, - message: "Remote connection metadata save failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "remote.directory.watch_failed", - channel: "remote", - level: LogLevel::Warn, - message: "Remote directory watch ended", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Error that ended the remote workspace directory observation stream", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "remote.forward.accept_failed", channel: "remote", @@ -2111,19 +1201,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 12, owner: "lithe-core", }, - EventMetadata { - id: "remote.plugins.cleanup_failed", - channel: "remote", - level: LogLevel::Warn, - message: "Remote plugin {stage} cleanup failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Filesystem error raised while deleting remote plugin deployment staging", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Remote plugin deployment cleanup target, e.g. snapshot or extraction", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "remote.process.cleanup_failed", channel: "remote", @@ -2187,68 +1264,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "lithe-core", }, - EventMetadata { - id: "remote.workspace.write_failed", - channel: "remote", - level: LogLevel::Error, - message: "Remote workspace write failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "run.build.scratch_cleanup_failed", - channel: "run", - level: LogLevel::Warn, - message: "Build dependency {stage} cleanup failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Filesystem error raised while deleting a build scratch file", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Build scratch cleanup target, e.g. provider-output or abandoned-scratch", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "run.configuration.operation_failed", - channel: "run", - level: LogLevel::Warn, - message: "Execution configuration operation failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Execution configuration phase that failed, load, plan, fingerprint or save", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheExecutionModule", - }, - EventMetadata { - id: "run.configuration.write_failed", - channel: "run", - level: LogLevel::Error, - message: "Execution configuration write failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure that prevented completing the requested operation", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheExecutionModule", - }, - EventMetadata { - id: "run.preparation.failed", - channel: "run", - level: LogLevel::Error, - message: "Execution preparation failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure that prevented completing the requested operation", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheExecutionModule", - }, EventMetadata { id: "run.process.execution.failed", channel: "run", @@ -2294,19 +1309,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 600, owner: "Lithe", }, - EventMetadata { - id: "run.process.io_failed", - channel: "run", - level: LogLevel::Warn, - message: "Process pipe {stage} failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "FileHandle error from releasing a process pipe or writing standard input", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Native pipe operation that failed: close, stdin-write, stdout-drain, stream-drain, or capture-drain", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "terminal.input.failed", channel: "terminal", @@ -2321,24 +1323,13 @@ pub static EVENTS: &[EventMetadata] = &[ owner: "LitheTerminalModule", }, EventMetadata { - id: "terminal.renderer.fallback_selected", - channel: "terminal", - level: LogLevel::Warn, - message: "Terminal renderer fallback selected", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Metal renderer activation error that caused the terminal to select Core Graphics", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "terminal.shell.discovery_failed", + id: "terminal.session.start_failed", channel: "terminal", level: LogLevel::Warn, - message: "Registered login shell discovery failed", + message: "Terminal session failed to start", fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Filesystem error raised while reading the registered login shell list", reason: None }, + FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Error raised while starting the terminal session, preserving stable domain and code", reason: None }, + FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Terminal start step that failed, e.g. spawn or attach", reason: None }, ], span: None, rate: 60, @@ -2369,70 +1360,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "Lithe", }, - EventMetadata { - id: "update.download.interrupted", - channel: "update", - level: LogLevel::Warn, - message: "Update download interrupted with resume data retained", - fields: &[ - FieldMetadata { name: "http_status", field_type: FieldType::Int, required: false, description: "Actual upstream HTTP status when the download failed with httpStatus.", reason: None }, - FieldMetadata { name: "reason", field_type: FieldType::Token, required: true, description: "Existing UpdateDownloadFailure case: timedOut, connectionFailed, tlsOrProxyFailure, httpStatus or invalidResponse; unclassified when no upstream cause exists.", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "update.relay.start_failed", - channel: "update", - level: LogLevel::Warn, - message: "Update download relay unavailable", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Socket or listener setup error that prevented starting the local update download relay", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "update.rollback.cleanup_failed", - channel: "update", - level: LogLevel::Warn, - message: "Stable rollback {stage} cleanup failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Filesystem or disk-image cleanup error raised while preparing a stable rollback", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Rollback cleanup target, e.g. leftover, disk-image or staging", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "update.rollback.preparation_failed", - channel: "update", - level: LogLevel::Warn, - message: "Stable rollback preparation failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Download, verification or staging error that prevented preparing the stable rollback package", reason: None }, - FieldMetadata { name: "exit_code", field_type: FieldType::Int, required: false, description: "Native installer tool exit status observed at the rollback boundary.", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: false, description: "Controlled installer tool basename that failed during package preparation.", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, - EventMetadata { - id: "update.source.probe_failed", - channel: "update", - level: LogLevel::Error, - message: "Update source probe failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Native transport or decoding error while checking the configured update source", reason: None }, - ], - span: None, - rate: 60, - owner: "Lithe", - }, EventMetadata { id: "vcs.authentication.response_failed", channel: "vcs/git", @@ -2545,30 +1472,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "lithe-core", }, - EventMetadata { - id: "vcs.history_action_capabilities.failed", - channel: "vcs", - level: LogLevel::Warn, - message: "Git history action eligibility could not be read", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Stable failure category for the history action eligibility request", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheGitModule", - }, - EventMetadata { - id: "vcs.history_date_query.failed", - channel: "vcs", - level: LogLevel::Error, - message: "Git history date filter failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Stable failure category for the shared date filter", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheGitModule", - }, EventMetadata { id: "vcs.host.cleanup_failed", channel: "vcs/git", @@ -2745,6 +1648,20 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 120, owner: "lithe-core", }, + EventMetadata { + id: "vcs.provider.skipped", + channel: "vcs", + level: LogLevel::Warn, + message: "Version control provider {plugin} skipped for {vcs}", + fields: &[ + FieldMetadata { name: "plugin", field_type: FieldType::Id, required: true, description: "Validated id of the plugin whose provider for this version control system was not used", reason: None }, + FieldMetadata { name: "selected", field_type: FieldType::Id, required: true, description: "Validated id of the plugin whose provider was selected instead", reason: None }, + FieldMetadata { name: "vcs", field_type: FieldType::Token, required: true, description: "Version control system both plugins provide", reason: None }, + ], + span: None, + rate: 60, + owner: "Lithe", + }, EventMetadata { id: "vcs.response.skipped", channel: "vcs/{provider}", @@ -2798,19 +1715,6 @@ pub static EVENTS: &[EventMetadata] = &[ rate: 60, owner: "lithe-core", }, - EventMetadata { - id: "vcs.shelf.operation_failed", - channel: "vcs", - level: LogLevel::Error, - message: "Saved changes operation failed", - fields: &[ - FieldMetadata { name: "error", field_type: FieldType::Error, required: true, description: "Underlying failure at this operation boundary, preserving stable domain and code", reason: None }, - FieldMetadata { name: "stage", field_type: FieldType::Token, required: true, description: "Saved changes action that failed, load, save or delete", reason: None }, - ], - span: None, - rate: 60, - owner: "LitheGitModule", - }, EventMetadata { id: "vcs.shutdown.timed_out", channel: "vcs/{provider}", diff --git a/rust/crates/diagnostics/src/core_events.rs b/rust/crates/diagnostics/src/core_events.rs index 43ad911c..537acbbf 100644 --- a/rust/crates/diagnostics/src/core_events.rs +++ b/rust/crates/diagnostics/src/core_events.rs @@ -456,7 +456,7 @@ mod tests { #[test] fn queue_rejects_non_core_owner_and_invalid_fields() { assert_eq!( - prepare("app.font.missing", BTreeMap::new(), None) + prepare("app.action.performed", BTreeMap::new(), None) .unwrap_err() .code, -32059 diff --git a/rust/crates/diagnostics/src/record.rs b/rust/crates/diagnostics/src/record.rs index 85c66460..bda93ed7 100644 --- a/rust/crates/diagnostics/src/record.rs +++ b/rust/crates/diagnostics/src/record.rs @@ -515,6 +515,11 @@ pub struct EncodedLogResult { /// Stable item-specific failure, absent on success. #[serde(skip_serializing_if = "Option::is_none")] pub error: Option, + /// Zero-based position of the rejected item in its input list, present only with + /// `error`. Deduplication makes results correspond to retained records rather than + /// inputs, so this is how a host names the event it must report as rejected. + #[serde(skip_serializing_if = "Option::is_none")] + pub index: Option, } /// Owned batch output with one entry per input item. #[derive(Debug, Serialize)] @@ -535,7 +540,13 @@ pub fn encode_log_batch(request: EncodeLogBatchRequest) -> EncodeLogBatchRespons let headers = request .headers .iter() - .map(|header| batch_result(encode_header(header), Some(header.channel.clone()))) + .enumerate() + .map(|(index, header)| { + indexed( + batch_result(encode_header(header), Some(header.channel.clone())), + index, + ) + }) .collect(); let mut results = Vec::new(); let mut previous: Option<(u64, StructuredLogEvent, Option)> = @@ -550,7 +561,7 @@ pub fn encode_log_batch(request: EncodeLogBatchRequest) -> EncodeLogBatchRespons }); let mut repeated = 0; let mut last: Option = None; - for value in request.events { + for (index, value) in request.events.into_iter().enumerate() { let prepared = (|| { let mut event: StructuredLogEvent = serde_json::from_value(value.clone()) .map_err(|_| LogError::new(-32051, "Invalid structured event shape"))?; @@ -582,13 +593,16 @@ pub fn encode_log_batch(request: EncodeLogBatchRequest) -> EncodeLogBatchRespons continue; } flush_repeated(&mut results, &previous, &last, &mut repeated); - results.push(batch_result(encode_record(event.clone()), channel.clone())); + results.push(indexed( + batch_result(encode_record(event.clone()), channel.clone()), + index, + )); previous = Some((hash, event, channel)); } Err(error) => { flush_repeated(&mut results, &previous, &last, &mut repeated); previous = None; - results.push(batch_result(Err(error), None)); + results.push(indexed(batch_result(Err(error), None), index)); } } } @@ -640,15 +654,25 @@ fn batch_result(result: Result, channel: Option) -> En line: Some(line), error: None, channel, + index: None, }, Err(error) => EncodedLogResult { line: None, error: Some(error), channel: None, + index: None, }, } } +/// Names the input a failed result rejects; successful results stay unindexed. +fn indexed(mut result: EncodedLogResult, index: usize) -> EncodedLogResult { + if result.error.is_some() { + result.index = Some(index); + } + result +} + /// Checks one structured event against the catalog, fills its catalog level, /// and returns the channel it belongs on. `input` supplies the channel for the /// `log.dropped` and `log.repeated` system events. @@ -799,24 +823,6 @@ mod tests { .unwrap() } - #[test] - fn browser_grammar_failure_accepts_cpp_and_missing_long_language_identity() { - for language in [Some("c++"), None] { - let mut fields = serde_json::json!({"plugin":"io.example.grammar"}); - if let Some(language) = language { - fields["language"] = language.into(); - } - let input = serde_json::json!({"events":[{"ts":"2026-11-03T00:00:00Z","level":"WARN","seq":1, - "event":"plugins.grammar.load_failed","msg":"","fields":fields}],"validateCatalog":true}); - let result = encode_log_batch(serde_json::from_value(input).unwrap()); - assert!( - result.results[0].line.is_some(), - "{language:?}: {:?}", - result.results[0].error - ); - } - } - #[test] fn structured_credential_keys_are_redacted_and_reserved_keys_rejected() { let mut event = dropped_event("2026-11-03T08:00:00Z", 1, 2); @@ -1066,10 +1072,39 @@ mod tests { } } + #[test] + fn rejected_results_name_their_input_after_deduplication() { + let started = json!({"ts":"2026-11-03T08:00:00Z", "level":"INFO", "seq":1, + "event":"app.session.started", "msg":""}); + let mut repeated = started.clone(); + repeated["seq"] = json!(2); + let unknown = json!({"ts":"2026-11-03T08:00:00Z", "level":"INFO", "seq":3, + "event":"app.unknown.never_declared", "msg":""}); + let wrong_level = json!({"ts":"2026-11-03T08:00:00Z", "level":"WARN", "seq":4, + "event":"app.session.started", "msg":""}); + let batch = encode_log_batch(EncodeLogBatchRequest { + previous_event: None, + deduplicate: true, + validate_catalog: true, + headers: vec![], + events: vec![started, repeated, unknown, wrong_level], + }); + let rejected: Vec<_> = batch + .results + .iter() + .filter_map(|result| Some((result.index?, result.error.as_ref()?.code))) + .collect(); + assert_eq!(rejected, vec![(2, -32053), (3, -32057)]); + assert!(batch + .results + .iter() + .all(|result| result.error.is_some() == result.index.is_some())); + } + #[test] fn catalog_batch_deduplicates_equal_fields_without_merging_operations() { - let event = json!({"ts":"2026-11-03T08:00:00Z", "level":"WARN", "seq":1, - "event":"app.font.missing", "msg":"ignored", "fields":{"font":"fixture"}, "op":"first"}); + let event = json!({"ts":"2026-11-03T08:00:00Z", "level":"INFO", "seq":1, + "event":"app.action.performed", "msg":"ignored", "fields":{"action":"fixture","surface":"menu"}, "op":"first"}); let mut second = event.clone(); second["seq"] = json!(2); let mut third = event.clone(); @@ -1093,13 +1128,13 @@ mod tests { .unwrap() .contains("op=second")); let next = encode_log_batch(EncodeLogBatchRequest { - previous_event: Some(json!({"ts":"2026-11-03T08:00:00Z", "level":"WARN", "seq":3, - "event":"app.font.missing", "msg":"ignored", "fields":{"font":"fixture"}, "op":"second"})), + previous_event: Some(json!({"ts":"2026-11-03T08:00:00Z", "level":"INFO", "seq":3, + "event":"app.action.performed", "msg":"ignored", "fields":{"action":"fixture","surface":"menu"}, "op":"second"})), deduplicate: true, validate_catalog: true, headers: vec![], - events: vec![json!({"ts":"2026-11-03T08:00:01Z", "level":"WARN", "seq":4, - "event":"app.font.missing", "msg":"ignored", "fields":{"font":"fixture"}, "op":"second"})], + events: vec![json!({"ts":"2026-11-03T08:00:01Z", "level":"INFO", "seq":4, + "event":"app.action.performed", "msg":"ignored", "fields":{"action":"fixture","surface":"menu"}, "op":"second"})], }); assert_eq!(next.results.len(), 1); assert!(next.results[0] diff --git a/rust/fixtures/diagnostics/logging-v2.json b/rust/fixtures/diagnostics/logging-v2.json index 77d27e69..9994a13d 100644 --- a/rust/fixtures/diagnostics/logging-v2.json +++ b/rust/fixtures/diagnostics/logging-v2.json @@ -941,16 +941,17 @@ "name": "catalog message and channel", "input": { "ts": "2026-11-03T08:00:00Z", - "level": "WARN", + "level": "INFO", "seq": 1, - "event": "app.font.missing", + "event": "app.action.performed", "msg": "untrusted message", "fields": { - "font": "FixtureFont" + "action": "fixture.action", + "surface": "menu" } }, "channel": "app", - "contains": "Bundled font FixtureFont missing" + "contains": "User action fixture.action performed" }, { "name": "unknown event", @@ -961,7 +962,8 @@ "event": "unknown.event", "msg": "untrusted message", "fields": { - "font": "FixtureFont" + "action": "fixture.action", + "surface": "menu" } }, "code": -32053 @@ -970,9 +972,9 @@ "name": "missing field", "input": { "ts": "2026-11-03T08:00:00Z", - "level": "WARN", + "level": "INFO", "seq": 1, - "event": "app.font.missing", + "event": "app.action.performed", "msg": "untrusted message", "fields": {} }, @@ -982,12 +984,13 @@ "name": "invalid field", "input": { "ts": "2026-11-03T08:00:00Z", - "level": "WARN", + "level": "INFO", "seq": 1, - "event": "app.font.missing", + "event": "app.action.performed", "msg": "untrusted message", "fields": { - "font": "has spaces" + "action": "has spaces", + "surface": "menu" } }, "code": -32055 @@ -996,13 +999,14 @@ "name": "unknown field", "input": { "ts": "2026-11-03T08:00:00Z", - "level": "WARN", + "level": "INFO", "seq": 1, - "event": "app.font.missing", + "event": "app.action.performed", "msg": "untrusted message", "fields": { - "font": "FixtureFont", - "extra": true + "extra": true, + "action": "fixture.action", + "surface": "menu" } }, "code": -32056 @@ -1011,12 +1015,13 @@ "name": "level mismatch", "input": { "ts": "2026-11-03T08:00:00Z", - "level": "INFO", + "level": "WARN", "seq": 1, - "event": "app.font.missing", + "event": "app.action.performed", "msg": "untrusted message", "fields": { - "font": "FixtureFont" + "action": "fixture.action", + "surface": "menu" } }, "code": -32057 diff --git a/rust/logging/README.md b/rust/logging/README.md index dcefb806..533ab3e5 100644 --- a/rust/logging/README.md +++ b/rust/logging/README.md @@ -1,6 +1,6 @@ # 结构化日志 v2 事件目录 -`rust/logging/events/.json` 是事件声明的唯一来源。macOS 使用生成的类型化事件,经 `MacLogStore` 写入 v2 会话文件;Windows 仍使用 v1。日志消息是供诊断使用的英文事实,**不走 i18n**;界面上的错误、提示和操作名称仍然走共享 i18n。 +`rust/logging/events/.json` 是事件声明的唯一来源。Core 用生成的 `rust/crates/diagnostics/src/catalog_generated.rs` 校验每一条事实。桌面端(Viva/Go,写入器在 Lithe-IDEA 的 `desktop/internal/logstore`)按事件 ID 和磁盘键传字段,由 Core 编码后写入 v2 会话文件,不写 v1 日志。日志消息是供诊断使用的英文事实,**不走 i18n**;界面上的错误、提示和操作名称仍然走共享 i18n。 本文规定声明语法、通道、字段编码与隐私边界、级别与 span、执行轨迹事件、Core 事件队列、引擎宿主接入、辅助 crate、生成器和用法门禁。什么必须记录、怎样设计一条日志和审查清单见 `.agents/skills/develop-lithe/references/logging.md`;决策原因见 `.agents/notes/implemented/architecture/2026-11-03-structured-logging-channels.md`。 @@ -16,7 +16,7 @@ - 通道由固定根和可选段组成,只接受三种形状:单独的根;非插件根加固定段或动态段;插件宿主 `plugins/{plugin}/host`。固定段也是目录声明的一部分。 - 动态段只能来自插件、provider、server 或内部连接等已校验的 ID,格式为 `^[a-z0-9][a-z0-9._-]{0,63}$`,同时拒绝末尾点号和 Windows 设备名(如 `con`、`nul.txt`、`com1`)。禁止使用显示名称、任意目录、用户输入和命令行。占位符必须引用本事件必填的 `id` 字段。 - 活动文件名为 `.log`,轮转文件名为 `~1.log`。`~` 不在通道字符集中,因此 `vcs/git.1` 不会与 `vcs/git` 的轮转文件冲突。`_overflow` 使用同样的文件头和轮转规则。 -- Swift 的 `LogSegment` 校验失败时返回 `nil`,不得对未知输入强制解包。 +- 宿主记录目录事件时不传通道,由 Core 按目录模板和本事件的 `id` 字段推出。`id` 不合法时 Core 拒绝整条事件;桌面写入器统计拒绝次数,并在日志窗口显示最近几种拒绝原因,不得改写成别的通道再写。 - 引擎按角色使用事件族:`lsp.*` 使用 `lsp/{server}`,`vcs.*` 的引擎事件使用 `vcs/{provider}`,`plugins.host.*` 使用 `plugins/{plugin}/host`。Core 依据显式 role 和目录身份字段选择事件,目录模板仍是通道的唯一来源,任何输入都不能改写普通事件的通道。非法段改用稳定的 SHA-256 前缀身份,不丢弃日志,也不影响插件启动。 - 引擎宿主的段通过 `diagnostics.resolveEngineLogSubject` 取得,与会话启动共用 `SessionLogIdentity::new`。宿主不得实现另一份哈希或身份规则。 @@ -26,24 +26,24 @@ `description` 去除首尾空白后至少 16 个字符,说明该字段在本事件里的含义、来源或单位,并尽量给出典型值。生成器拒绝按类型填写的通用短语(例如 `Validated internal identifier`、`Structured failure`、`Count or numeric result`),也不提供按类型的默认描述。span 自动字段的说明绑定具体操作 ID 和终态。 -| 类型 | Swift 参数 | Core 编码与边界 | +| 类型 | 宿主传入的磁盘键与 JSON 值 | Core 编码与边界 | | --- | --- | --- | -| `int` | `Int64` | 有符号整数 | -| `bool` | `Bool` | 布尔值 | -| `duration` | `Duration` | 非负整数毫秒,磁盘键为 `_ms`;声明名不得自带 `_ms` | -| `bytes` | `UInt64` | 无符号字节数 | -| `id` | `LogSegment` | 校验后的不透明 ID,可用作通道段 | -| `token` | `String` | ≤64 字节的受控短词,字符为 ASCII 字母数字和 `._:/-$`,例如命令名、阶段或结果枚举 | -| `version` | `String` | ≤64 字节的组件版本,字符为 ASCII 字母数字和 `._+-` | -| `path` | `URL` | 落盘前改写为工作区相对路径或 ``;无法归属的绝对路径不得直接落盘;上限 4096 字节 | -| `error` | `any Error` | 展开为 ``、`_code`、`_domain`,字段名通常就是 `error`;消息脱敏并限长至 1 KiB,code 可以是整数或稳定 token | -| `text` | `String` | 只用于无法结构化的上游诊断(stderr 行、LSP logMessage)和经 Core 集中格式化函数脱敏的外部进程 argv;脱敏、去除控制字符、限长至 1 KiB | +| `int` | ``,整数 | 有符号整数 | +| `bool` | ``,布尔值 | 布尔值 | +| `duration` | `_ms`,非负整数毫秒 | 非负整数毫秒;声明名不得自带 `_ms` | +| `bytes` | ``,非负整数 | 无符号字节数 | +| `id` | ``,字符串 | 校验后的不透明 ID,可用作通道段 | +| `token` | ``,字符串 | ≤64 字节的受控短词,字符为 ASCII 字母数字和 `._:/-$`,例如命令名、阶段或结果枚举 | +| `version` | ``,字符串 | ≤64 字节的组件版本,字符为 ASCII 字母数字和 `._+-` | +| `path` | ``,绝对路径字符串 | 落盘前改写为工作区相对路径或 ``;无法归属的绝对路径不得直接落盘;上限 4096 字节 | +| `error` | ``、`_code`、`_domain` 三个键,桌面端由 `core.LogErrorFields` 生成 | 字段名通常就是 `error`;消息脱敏并限长至 1 KiB,code 可以是整数或稳定 token | +| `text` | ``,字符串 | 只用于无法结构化的上游诊断(stderr 行、LSP logMessage)和经 Core 集中格式化函数脱敏的外部进程 argv;脱敏、去除控制字符、限长至 1 KiB | 源码、编辑缓冲区、文件内容、提交说明正文、环境变量值、进程的 stdout 与 stdin、凭据、终端历史和协议正文没有对应类型,不得塞进 `text`、`error`、token、路径字段或消息模板。外部进程的 argv 只经过 `rust/crates/git/src/command_trace.rs` 的 `format_arguments`,stderr 只保留脱敏后的末尾几行(第五节)。迁移旧日志时拆开拼接消息,只保留结构化的时间、计数、受控结果词和错误类别。`text` 的理由不能写成“方便调试”。 -Swift 的事件值是**未经脱敏的内存输入**,不能自行序列化落盘。Core 先对 `error`、`text` 输入脱敏、删除控制字符、按 UTF-8 字符边界截断到 1024 字节,再由 `catalog::validate_fields(id, fields)` 校验磁盘键展开后的类型、必填、未知字段、长度和错误组件完整性;这一步校验形状,不代替隐私脱敏。macOS 的跨边界适配器连接 Core 的脱敏、格式化和写入路径,不得另写 Swift 格式化或隐私策略。 +宿主的字段值是**未经脱敏的内存输入**,不能自行序列化落盘。Core 先对 `error`、`text` 输入脱敏、删除控制字符、按 UTF-8 字符边界截断到 1024 字节,再由 `catalog::validate_fields(id, fields)` 校验磁盘键展开后的类型、必填、未知字段、长度和错误组件完整性;这一步校验形状,不代替隐私脱敏。桌面写入器把每一批事件交给 Core 的 `diagnostics.encodeLogBatch`(`validateCatalog: true`)编码,只追加 Core 返回的行,不得另写 Go 格式化或隐私策略。 -可选身份字段超长时只省略该字段,不省略整条事件。例如 `plugins.grammar.load_failed` 的语言字段是可选 `version`,允许 `c++` 等合法语言 ID;语言 ID 超长时省略语言字段,插件失败事件照常记录。 +可选身份字段超长时只省略该字段,不省略整条事件。例如 `lsp.process.started` 的 `runtime_version` 是可选 `version`;运行时上报的版本超过 64 字节时省略该字段,进程启动事件照常记录。 ## 四、级别、span 与 rate @@ -52,9 +52,9 @@ Swift 的事件值是**未经脱敏的内存输入**,不能自行序列化落 - `warn`:可恢复失败、功能降级、上游警告,以及 Core 执行轨迹的失败。 - `error`:宿主确认用户请求最终失败。不允许使用 `warning` 别名。 -目录中的 `span: { "failureLevel": "error" }` 把基事件展开为 `.started`、`.finished`、`.failed`。started 固定为 debug,生成的 `begin` 总会发出它,由写入端在入队前按级别和详细诊断通道过滤,因此正式版开启详细诊断后也能看到。finished 使用声明的 `level`,failed 使用 `failureLevel`;两种终态自动增加逻辑字段 `duration`(磁盘键 `duration_ms`),failed 还自动增加结构化 `error`。不得声明与这些自动字段冲突的键。 +目录中的 `span: { "failureLevel": "error" }` 把基事件展开为 `.started`、`.finished`、`.failed`。started 固定为 debug,记录方总是发出它,由写入端在入队前按级别和详细诊断通道过滤,因此正式版开启详细诊断后也能看到。finished 使用声明的 `level`,failed 使用 `failureLevel`;两种终态自动增加逻辑字段 `duration`(磁盘键 `duration_ms`),failed 还自动增加结构化 `error`。不得声明与这些自动字段冲突的键。 -生成的 span 由一个调用方值拥有;`finish`、`fail` 是 mutating,第一次终态生效,后续调用被忽略。不要复制 span 来产生多份生命周期。`LogSpanClock` 可注入单调时间,默认使用 `ContinuousClock`,不使用墙钟差值。`operationID` 独立于普通字段,传给持久化层成为 `op`,不得重新声明成目录字段。必填上下文在 begin 时提供,`exit_code`、`outcome` 等可选结果在终态时提供。 +一个 span 由一个调用方拥有,第一次终态生效,后续终态被忽略;不要复制 span 来产生多份生命周期。持续时间取单调时钟的差值,不使用墙钟差值。op 独立于普通字段,交给写入器成为 `op`,不得重新声明成目录字段。必填上下文在 started 时提供,`exit_code`、`outcome` 等可选结果在终态时提供。桌面端目前没有生成的 span 辅助类型,记录 span 事件的方式见日志参考页。 `rate` 声明每个事件、每个通道每分钟的条数上限,取值 1 到 60000,默认 60。执行轨迹(Git 命令、Core 请求、用户操作)为 600,LSP 为 120,辅助 crate 的转发 accept 与 bridge 失败为 12。rate 目前只是目录元数据,写入器还不执行它;以后执行时在发送侧合并高频记录,用有界状态维护丢弃计数,不通过绕过日志系统补写。 @@ -68,43 +68,43 @@ Swift 的事件值是**未经脱敏的内存输入**,不能自行序列化落 | `app.core.request.finished` / `.traced` / `.failed` | `app/core` | info / debug / warn | `method`、`source`,可选 `operation`、`trigger`、`path`、`remote`,`duration`;finished 与 traced 可带 `cancelled`,failed 带 `error`(domain 为 `core`) | | `vcs.git.command.finished` / `.traced` / `.failed` | `vcs/git` | info / debug / warn | `command`、`arguments`、`source`,可选 `repository`、`remote`、`exit_code`、`stderr`,`duration`;finished 与 traced 可带 `cancelled`,failed 可带 `error` | -- `app.action.performed` 由 `UserActionTrace` 在最外层用户入口记录,owner 为 `LitheModuleAPI`。`action` 是稳定的操作 id,`surface` 是 `UserActionSurface` 的取值。它的 op 绑定到 `UserActionContext.current`,桥接层据此给 Core 请求附上 `origin`。 +- `app.action.performed` 在最外层用户入口记录,owner 为 `LitheModuleAPI`。`action` 是稳定的操作 id,不是本地化标题;`surface` 只取目录列出的封闭取值。桌面端由工作台的 `performed`(其他窗口或 goroutine 用 `performedIn`)记录,同时为这次操作新建 op;之后这次操作的记录都用这个 op,它发出的 Core 请求带 `origin { source, trigger, operation }`,Core 的请求轨迹和 Git 轨迹因此与宿主记录共用一个 op。 - Core 请求轨迹在 `rust/crates/core/src/runtime/dispatcher.rs` 的请求分发处记录,实现在 `rust/crates/core/src/runtime/request_trace.rs`。用户来源的成功或取消记 finished,后台或未知来源的成功或取消记 traced,失败记 failed。`request_trace::is_hot` 列出的按键、每帧、轮询和监听批次方法,以及全部 `diagnostics.*` 和 `core.ping`,不记录。 - Git 进程轨迹在 `rust/crates/git/src/command_trace.rs` 的执行点记录,本地与远程工作区都经过这里。可见命令指经 `execute_git` 执行、作为 invocation 返回给宿主并显示在 Git 控制台的命令;内部读取指 Core 经 `capture_git` 执行、自己解析输出的命令。来源为用户的可见命令,成功或取消记 finished;其余成功或取消记 traced,包括用户操作中的内部读取;失败记 failed。退出码表示“回答”的情形(`exit_is_answer`),以及来源不是用户的内部读取的非零退出,不算失败;后者由调用方判断含义,调用方返回错误时由请求轨迹记录失败。 - `arguments` 由 `format_arguments` 生成:提交说明值换成 ``,`-c` 中凭据和个人身份键的值换成 ``,URL 用户信息和共享脱敏规则覆盖的内容被改写,超过 1 KiB 时在末尾截断并以 `…` 标记。 - `stderr` 只在失败或非零退出时出现:取进程最后 16 KiB 输出中最后 8 个非空行,逐行脱敏后用 ` | ` 连接,超过 1 KiB 时丢弃最早的内容并以 `…` 标记。 -- Core 轨迹的失败固定为 WARN,因为 Core 不知道宿主会重试、降级还是放弃。宿主提示的事实都在同一 op 的 Core 失败轨迹里时,提示用 `LogRecordReference(channel:event:op:)` 引用它,宿主不再记录;宿主只为降级、放弃、重试耗尽、残留等 Core 不掌握的事实记录自己的终态。 +- Core 轨迹的失败固定为 WARN,因为 Core 不知道宿主会重试、降级还是放弃。宿主提示的事实都在同一 op 的 Core 失败轨迹里时,提示带上这个 op(桌面端的提示和通知历史提供“查看日志”,打开日志窗口并只显示这个 op 的记录),宿主不再重复记录;宿主只为降级、放弃、重试耗尽、残留等 Core 不掌握的事实记录自己的终态。 ## 六、Core 事件队列与宿主写入 - Rust 侧没有请求事件流可用的事实(执行轨迹、析构、后台清理、辅助 crate 失败)进入 `lithe-diagnostics`(`rust/crates/diagnostics`)`core_events` 的进程级有界队列,最多 256 条。`record` 校验 owner、规范化并脱敏字段后入队,不做文件 I/O。队列满时新事实只计入丢弃数;同一批次里事件、通道、字段和 op 都相同的事实只保留一条,其余计入丢弃数。 - DEBUG 事实在入队前过滤:宿主通过 `diagnostics.configureCoreEvents { debug, roots }` 告诉 Core 详细诊断是否开启、开启哪些通道根,`roots` 省略表示全部根,默认关闭。未开启的 DEBUG 事实直接返回成功,不入队、不计入丢弃数。构造字段前先调用 `core_events::accepts(level, root)`,被拒绝的事实只花一次分支判断。 -- `MacLogStore` 在详细诊断状态变化时调用 `configureCoreEvents`,只在开关或通道根集合变化时发送;调用失败时记录一次 `app.logging.diagnostics_failed`。 -- 写入器在每次写入批次、flush 和退出时排空一次。没有其他宿主活动时,由 Core 的唤醒回调安排排空:drain 之后的第一条事实或第一次丢弃计数触发一次回调,同一个 drain 周期内的后续变化合并。只有组合根创建的应用写入器调用 `MacLogStore.observeCoreFacts()` 安装回调,回调复用宿主事件已有的 100 毫秒单次排空调度;`finishSession` 先移除回调,再做最后一次排空。回调不得重入 Core。不得为 Core 队列增加空闲轮询或独立写入器。 -- 排空得到的 `CoreLogRecord` 原样交给统一的 `LogSink`:保留 `ts` 和 `op`,由写入器分配 `seq`,继续以 `validateCatalog: true` 写入。 +- 桌面写入器(`desktop/internal/logstore` 的 `Store`)在详细诊断状态变化时调用 `configureCoreEvents`,只在开关变化时发送;调用失败时记录一次 `app.logging.diagnostics_failed`,直到想要的状态再次变化前不重试。 +- 写入器在每次写入批次、flush 和退出时排空一次。没有其他宿主活动时,由 Core 的唤醒回调安排排空:drain 之后的第一条事实或第一次丢弃计数触发一次回调,同一个 drain 周期内的后续变化合并。Core 每个进程只有一个唤醒回调,所以只有 `cmd/lithe` 创建的应用写入器调用 `Store.ObserveCoreFacts()` 安装它;回调只唤醒写入器,复用宿主事件已有的 100 毫秒合并排空;`Close` 先移除回调,再做最后一次排空。回调不得重入 Core。不得为 Core 队列增加空闲轮询或独立写入器。 +- 排空得到的 Core 事实与宿主事件进入同一批编码:保留 `ts`、`op` 和 Core 给出的通道,由写入器分配 `seq`,以 `validateCatalog: true` 写入。排空本身失败只计入写入失败数。 ## 七、引擎宿主 - 启动者显式声明 role、真实 `pluginId` 和 VCS `logSubject`;宿主不解析 providerID。 -- stderr 读取器限制每行 4 KiB、每秒 200 行,之后再走 `text` 的 1 KiB 脱敏规范化。与 v1 相比唯一的兼容变化是从任意 trim 的读取块改为逐行文本:保留行内空格,移除 LF 和末尾 CR,并应用已声明的长度上限和限流。 +- Core 的 stderr 读取器(`rust/crates/lsp-engine/src/logging.rs`)限制每行 4 KiB、每秒 200 行,之后再走 `text` 的 1 KiB 脱敏规范化。与 v1 相比唯一的兼容变化是从任意 trim 的读取块改为逐行文本:保留行内空格,移除 LF 和末尾 CR,并应用已声明的长度上限和限流。 - 上游明确给出的严重度通过独立的目录事件保留:`window/logMessage` 和 `window/showMessage` 的 type 1/2/3/4 分别为 ERROR/WARN/INFO/DEBUG,未知类型为 DEBUG。未分类的 stderr 是 DEBUG 排障证据,流名称不表示警告;实际的进程或协议失败由 `*.session.failed` 记录 ERROR,正常关闭仍是生命周期状态。 - 插件自身使用独立协商的 `litheLogging` 0 和 `lithe/log`,由 Core 把四种受控事实映射到插件目录事件,不能再用 stderr 或任意自由消息代替。协议字段、op、限额和 fixture 以 [插件契约](../../shared/plugins/contract/v1/README.md#structured-plugin-diagnostics) 为准。 - 声明式贡献没有插件进程,不能发 `lithe/log`。实际执行它的一方通过 `diagnostics.recordPluginOperation` 代记每次尝试的一条终态,事件和通道与 SDK 插件相同:`plugins.operation.finished` 或 `plugins.operation.failed`,写入 `plugins/{plugin}/host`。平台层只上报观察到的阶段和耗时,级别和 `host.*` 失败类别只由 Core 按阶段决定;取消、停止和过期结果不记录。宿主当前代记下表四种贡献,唯一来源是 `rust/crates/diagnostics/src/plugin_operations.rs` 的 `CONTRIBUTIONS`;输入、阶段到类别的对应和 -32064 见 [Rust Core API](../contracts/rust-core-api.md#engine-logging-v2-handoff-pr3)。 | operation | 声明来源 | 记录方 | 可能的失败阶段 | | --- | --- | --- | --- | - | `languageServer/start` | `languageServers[]` | macOS 宿主记启动前的失败;进入启动后用 `lsp.startServer.startupOperation` 交给 Core,Core 记录唯一结果 | resolve、launch、exit、initialize、timeout | - | `debugAdapter/start` | `debugAdapters[]` | macOS 宿主;op 为调试会话 ID,Core 拒绝建会话不记录 | resolve、launch、exit、initialize、timeout | - | `lithe/build/model` | `buildSystems[]` 的命令式模型 | macOS 宿主;计划由插件后端提供时由 SDK 记录 | plan、resolve、launch、timeout、exit、decode | - | `lithe/build/dependencies` | `buildSystems[]` 的命令式依赖树 | macOS 宿主;计划由插件后端提供时由 SDK 记录 | plan、resolve、launch、timeout、exit、decode | + | `languageServer/start` | `languageServers[]` | 桌面宿主记启动前的失败;进入启动后用 `lsp.startServer.startupOperation` 交给 Core,Core 记录唯一结果 | resolve、launch、exit、initialize、timeout | + | `debugAdapter/start` | `debugAdapters[]` | 桌面宿主;op 为调试会话 ID,用户停止和 Core 拒绝建会话不记录 | resolve、launch、exit、initialize、timeout | + | `lithe/build/model` | `buildSystems[]` 的命令式模型 | 桌面宿主,op 为加载模型的操作;计划由插件后端提供时由 SDK 记录 | plan、resolve、launch、timeout、exit、decode | + | `lithe/build/dependencies` | `buildSystems[]` 的命令式依赖树 | 桌面宿主,op 为加载依赖的操作;计划由插件后端提供时由 SDK 记录 | plan、resolve、launch、timeout、exit、decode | - 新增一种声明式贡献时,在同一次改动里给 `CONTRIBUTIONS` 加一行,在执行方开始和结束一次 attempt,并更新本表;不新增事件、通道或错误码。 -- 上游 trace 默认关闭。宿主通过 `lsp.setDetailedDiagnostics` 对活动会话和新会话显式开启,15 分钟后单次到期关闭。详细诊断类别与通道根的对应为 `lsp` → language、`vcs` → git、`plugins` → plugins。 + 新增一种声明式贡献时,在同一次改动里给 `CONTRIBUTIONS` 加一行,在执行方开始和结束一次 attempt,并更新本表;不新增事件、通道或错误码。Core 拒绝或无法入队一条代记结果时,桌面宿主记 `app.background.operation_failed`(`operation` 为 `plugin_operation_record`),不重试。 +- 上游 trace 默认关闭。宿主通过 `lsp.setDetailedDiagnostics` 对活动会话和新会话显式开启,15 分钟后单次到期关闭。桌面端由写入器的详细诊断开关驱动:开关变化时通知插件后端的 runner,runner 把当前值发给它启动的每个活动会话,之后启动的会话也会收到;同一次选择只记录一次拒绝(`app.logging.diagnostics_failed`)。详细诊断类别与通道根的对应为 `lsp` → language、`vcs` → git、`plugins` → plugins。 - 详细诊断只接纳 `$/logTrace.message` 摘要;`verbose` 可能包含原始 RPC 载荷和文档源码,禁止进入 v2 `text`。凭据脱敏和 1 KiB 限长不代表源码可以落盘。`initialized` 之前收到的开关只保存目标状态,Core 在 `initialized` 之后发送通知。 -- v1 的 detail、message、level 保持兼容原文;v2 字段通过独立的 `EngineLogInput` 传递,禁止从 detail 反解。原始通知 JSON、`projectCount=N` 和 navigation 格式不变。macOS 日志窗口统一读取 v2 会话文件和写入器的实时批次,不写 v1 文件。 -- Core 的生命周期事实挂在原有 `type: stateChanged` 运行时事件上,复用 `prepare_catalog_event` 校验,不额外增加 v1 日志行。Swift 在事件分支之前转发任何携带 `coreLog` 的事件一次,语言服务、VCS、构建、工具链和后端都适用。`*.session.updated` 的 state 指 Core 会话生命周期,owner 是 `lithe-core`,宿主不再重复发同一状态事实。 -- 宿主在实际调用点发 `lsp.session.stage_changed`,阶段闭集为 requested、resolving、registered、stopping、cancelled;缓存清理成功发 `lsp.cache.cleaned(removed)`,它与 Core 配置键清理的 `configuration.cleaned` 是不同事实。两者为 DEBUG,因为它们解释内部启动编排和缓存维护,不需要常态落盘。ready 和 terminated 由 Core 的 `protocol.initialized` 和 `session.updated` 表达。阶段、缓存、degradation 和 issue 事件统一使用 Core 计算的段;manager 按 providerID 缓存成功或失败结果,最多 128 项,满时清空;失败只跳过对应的宿主 v2 事件,不改变原有行为。 -- 本地启动前,`MacLogStore` 用 Core 的 `plugin_files_path` 创建当前会话的 `sessions//plugins//files/`,目录权限 0700,用相对描述符和 no-follow 遍历防止符号链接越界。该目录只属于当前日志会话,不注册为跨工作树可复用的构建资源,不写 bundle 或安装目录。存储不可用时不传 `logDirectory`,使用 `${logDir}` 的模板按现有 `invalidRequest` 失败。远程进程不能写本机日志目录,因此同样不传 `logDirectory` 并拒绝该变量。安装验证只用未创建的占位目录校验展开,不启动进程也不写入。 +- v1 的 detail、message、level 保持兼容原文;v2 字段通过独立的 `EngineLogInput` 传递,禁止从 detail 反解。原始通知 JSON、`projectCount=N` 和 navigation 格式不变。桌面日志窗口只读取 v2 会话文件和写入器的实时批次,没有 v1 文件。 +- Core 的生命周期事实挂在原有运行时事件上(`type: stateChanged`、`log`、退出事件等),以 `event`、`catalogLevel`、`fields` 三个键给出,复用 `prepare_catalog_event` 校验,不额外增加 v1 日志行。没通过 Core 自身目录校验的事实不带 `event`。桌面端的 `pluginbackend.Runner` 在按事件类型分支之前,把同时带 `event` 和 `catalogLevel` 的事件转发给写入器一次,包括停止会话时等到的最后一批事件;数字按原文保留,不经浮点舍入。语言服务、VCS、构建、工具链和后端都适用。这些事实不属于任何用户操作,不带 op。`*.session.updated` 的 state 指 Core 会话生命周期,owner 是 `lithe-core`,宿主不再重复发同一状态事实。 +- 语言服务的启动、ready 和 terminated 全部由 Core 的 `*.process.started`、`protocol.initialized` 和 `session.updated` 表达,宿主不另发启动阶段或缓存维护事件。 +- 本地启动前,桌面写入器的 `Store.PluginFilesDirectory` 用 `diagnostics.resolveLogChannel` 返回的 `pluginFilesPath` 创建当前会话的 `sessions//plugins//files/`,目录权限 0700;创建前逐段检查路径,拒绝 `.`、`..` 和已存在的符号链接或特殊文件,防止越界。语言服务器和插件后端的 `${logDir}` 都用这个目录;创建失败时记 `app.background.operation_failed`(`operation` 为 `plugin_log_directory`),进程照常启动但不带 `logDirectory`。该目录只属于当前日志会话,不注册为跨工作树可复用的构建资源,不写 bundle 或安装目录。存储不可用时不传 `logDirectory`,使用 `${logDir}` 的模板按现有 `invalidRequest` 失败。远程进程不能写本机日志目录,因此同样不传 `logDirectory` 并拒绝该变量。安装验证只用未创建的占位目录校验展开,不启动进程也不写入。 ## 八、辅助 crate @@ -122,7 +122,7 @@ Swift 的事件值是**未经脱敏的内存输入**,不能自行序列化落 1. 先调查真实调用,选择根和 owner;没有实际来源不新增事件。 2. 在对应 JSON 中声明稳定 ID、通道模板、英文事实、级别和字段;成对操作优先使用 span。检查隐私和动态段来源。 3. 运行生成器,核对 Rust 字段表;不得手改生成文件。 -4. 接入时使用类型化事件。不再有调用点的事件从目录删除并重新生成。 +4. Core 内使用生成表里的事件;桌面端按事件 ID 和磁盘键调用写入器,并运行 Lithe-IDEA 的 `TestEveryLoggedEventIsAcceptedByTheKernel`(`desktop/internal/core`),它用正在链接的 Core 检查每个调用点。不再有调用点的事件从目录删除并重新生成;删除前在 Lithe-IDEA 的 `desktop/` 里搜索事件 ID,确认桌面端也没有调用点。 5. 运行下列检查。生成结果稳定排序、使用 LF,不读取运行时 JSON。 ```sh @@ -130,42 +130,42 @@ node scripts/logging/generate-log-events.mjs node scripts/logging/generate-log-events.mjs --check ``` -`--check` 只读比较,不修复漂移,有缺失或差异即以非零状态退出。生成器先完成全部目录校验和输出规划,再写第一个文件。它只输出 `rust/crates/diagnostics/src/catalog_generated.rs`;桌面客户端的类型化事件、生成器测试和第十二节的用法门禁尚未恢复,由 [Lithe-IDEA#1802](https://github.com/1lck/Lithe-IDEA/issues/1802) 跟踪。 +`--check` 只读比较,不修复漂移,有缺失或差异即以非零状态退出。生成器先完成全部目录校验和输出规划,再写第一个文件。它只输出 `rust/crates/diagnostics/src/catalog_generated.rs`。桌面客户端的类型化事件、生成器测试和第十二节的用法门禁尚未恢复,由 [Lithe-IDEA#1802](https://github.com/1lck/Lithe-IDEA/issues/1802) 跟踪;在那之前,第 4 步的调用点测试在提交前发现事件 ID、级别和字段的漂移,但不检查绕过日志和丢弃失败的写法。 ## 十一、API 示例 -Swift 的用户入口用 `UserActionTrace` 包装;生成事件的初始化参数按字段名排序: +桌面端(Lithe-IDEA 的 `desktop/internal/workbench`)在用户入口记录操作,之后这次操作的记录和 Core 请求都带同一个 op: -```swift -// 菜单项:记录 app.action.performed,并把操作上下文交给后续的 Core 请求 -UserActionTrace.run("open-project", surface: .menu, sink: UserActionTrace.applicationSink) { - model.openProject() -} +```go +// 菜单项:记录 app.action.performed,并为这次操作新建 op +a.performed("output.copyAll", surfaceContextMenu) -// SwiftUI 按钮:包装回调,surface 默认为 .button -Button(action: UserActionTrace.action("workspace.remote.test") { model.testConnection() }) { - Text("Test") -} +// 窗口线程上的失败:用户没有得到想要的结果,记 ERROR +a.operationFailed("editor_open_in_browser", err) -// 宿主自己的事实:在同一 op 下记录,并取得可以交给界面提示的引用 -let scope = LogScope(sink: sink, operationID: operationID) -let reference = scope.emitReferenced(AppLoggingDiagnosticsFailed(error: failure)) +// 后台 goroutine:从 ctx 取得操作的 op,不读窗口线程的状态 +a.background(p, timeout, func(ctx context.Context) func(*App) { + if err := work(ctx); err != nil { + a.backgroundFailedIn(ctx, "output_style", err) // 降级或附带结果失败,记 WARN + } + return nil +}) ``` Rust 通过静态 `EVENTS`(按 ID 排序)和二分查找的 `event_by_id` 暴露元数据,不分配运行时目录缓存。生成表通过路径子模块载入:Rust 的 `include!` 不能接受仓库注释门禁要求的首行 `//!`,子模块能满足该门禁,不需要豁免或放宽检查。 ## 十二、用法门禁 -本节描述的 `scripts/logging/verify-log-usage.mjs` 目前不在仓库中,恢复由 [Lithe-IDEA#1802](https://github.com/1lck/Lithe-IDEA/issues/1802) 跟踪;恢复前不要把它列进检查步骤。 +用法门禁 `scripts/logging/verify-log-usage.mjs` 目前不在仓库中。它原先扫描的 Swift 客户端已经删除,恢复时改为覆盖 Viva 桌面端的 Go 生产代码,由 [Lithe-IDEA#1802](https://github.com/1lck/Lithe-IDEA/issues/1802) 跟踪;恢复前不要把它列进检查步骤。下面是恢复后必须保持的规则,Go 的具体写法清单由 #1802 定义。 -`scripts/logging/verify-log-usage.mjs` 扫描 `macos/Sources`、`rust/crates/core/src`、`rust/crates/git-host/src`、`rust/crates/ide-host/src` 和 `rust/crates/remote/src`。排除 `rust/crates/remote/src/server/`、`rust/crates/remote/src/bin/` 和 `rust/crates/ide-host/src/bin/`:它们在远端主机或独立进程中运行,stderr 由宿主进程处理,以后单独迁移。 +门禁扫描 `rust/crates/core/src`、`rust/crates/git-host/src`、`rust/crates/ide-host/src`、`rust/crates/remote/src` 和桌面端的 Go 生产代码。排除 `rust/crates/remote/src/server/`、`rust/crates/remote/src/bin/` 和 `rust/crates/ide-host/src/bin/`:它们在远端主机或独立进程中运行,stderr 由宿主进程处理,以后单独迁移。 -门禁只扫描生产代码:词法上遮蔽注释和字符串内容,排除 `Tests/`、`tests/`、`tests.rs`、文件名以 `_tests.rs` 结尾的 Rust 文件,以及明确标注 `#[cfg(test)]` 或 `#[cfg(all(test, …))]` 的项。它只检查列出的直接写法,不跨文件追踪别名或动态调用。规则分两类: +门禁只扫描生产代码:词法上遮蔽注释和字符串内容,排除测试目录、`tests.rs`、文件名以 `_tests.rs` 或 `_test.go` 结尾的文件,以及明确标注 `#[cfg(test)]` 或 `#[cfg(all(test, …))]` 的项。它只检查列出的直接写法,不跨文件追踪别名或动态调用。规则分两类: -- **绕过日志**:Swift 的 `NSLog`、stderr 写入、`os_log`、导入 `os.log` 后的 `Logger`、`.record(level:)`、`print`/`debugPrint`;Rust 的 `eprintln!`、`println!`、`dbg!`。这些写法不经过目录和脱敏,只能改成生成事件;确属机器协议的永久例外写进 `scripts/logging/log-usage-allowlist.json`,给出具体的协议或架构理由和精确计数。 -- **丢弃失败**:Swift 语句级 `try?`(含 `_ = try?`)、块体只有 `return`/`break`/`continue` 的 `catch`;Rust 语句级 `.ok();` 和 `let _ = …;`。失败要么处理并记录事件,要么在同一行或上一行写 `// log-exempt: <原因>`。原因至少 3 个非空白字符,必须属于日志参考页的四类封闭例外;空原因本身报错。标记只对这四条规则生效,不能豁免绕过日志的写法,这类规则也不能进 allowlist。 +- **绕过日志**:Rust 的 `eprintln!`、`println!`、`dbg!`,以及 Go 里不经过写入器的标准错误输出和标准库日志。这些写法不经过目录和脱敏,只能改成目录事件;确属机器协议的永久例外写进 `scripts/logging/log-usage-allowlist.json`,给出具体的协议或架构理由和精确计数。 +- **丢弃失败**:Rust 语句级 `.ok();` 和 `let _ = …;`,以及 Go 里丢弃的错误返回值。失败要么处理并记录事件,要么在同一行或上一行写 `// log-exempt: <原因>`。原因至少 3 个非空白字符,必须属于日志参考页的四类封闭例外;空原因本身报错。标记只对丢弃失败的规则生效,不能豁免绕过日志的写法,这类规则也不能进 allowlist。 -门禁没有存量额度,任何违规都直接失败。allowlist 的计数必须等于实际出现次数,少于或多于实际都失败,防止空出来的名额被新写法占用。当前 allowlist 为空。迁移机器读取的性能标记时同步修改它的消费者,不能直接删除测试依赖的协议输出。 +门禁没有存量额度,任何违规都直接失败。allowlist 的计数必须等于实际出现次数,少于或多于实际都失败,防止空出来的名额被新写法占用。迁移机器读取的性能标记时同步修改它的消费者,不能直接删除测试依赖的协议输出。 ## 十三、CI、工作树与发行包 diff --git a/rust/logging/events/app.json b/rust/logging/events/app.json index b9efe717..842db5c1 100644 --- a/rust/logging/events/app.json +++ b/rust/logging/events/app.json @@ -2,91 +2,6 @@ "version": 1, "root": "app", "events": [ - { - "id": "app.core.fallback_selected", - "channel": "app", - "level": "warn", - "message": "Core request used a fallback", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Core request or catalog decoding operation that selected a fallback" - }, - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "app.credentials.cleanup_failed", - "channel": "app", - "level": "warn", - "message": "Obsolete credential removal failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "app.credentials.write_failed", - "channel": "app", - "level": "error", - "message": "Credential update failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Underlying failure that prevented completing the requested operation" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "app.demo.failed", - "channel": "app", - "level": "warn", - "message": "Problems demo {stage} failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Problems demo step that failed, e.g. creation or cleanup" - }, - "error": { - "type": "error", - "required": true, - "description": "File operation error raised while creating or removing the Problems demo files" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "app.diagnostics.cleanup_failed", - "channel": "app", - "level": "warn", - "message": "Diagnostic staging cleanup failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "app.diagnostics.export_failed", "channel": "app", @@ -107,101 +22,6 @@ "rate": 60, "owner": "Lithe" }, - { - "id": "app.font.missing", - "channel": "app", - "level": "warn", - "message": "Bundled font {font} missing", - "fields": { - "font": { - "type": "token", - "required": true, - "description": "Filename of the missing bundled font, e.g. Inter-Regular.otf" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "app.font.registration_failed", - "channel": "app", - "level": "warn", - "message": "Bundled font {font} registration failed", - "fields": { - "font": { - "type": "token", - "required": true, - "description": "Filename of the font passed to CoreText for registration" - }, - "error": { - "type": "error", - "required": true, - "description": "CoreText error returned when registering this bundled font" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "app.history.operation_failed", - "channel": "app", - "level": "warn", - "message": "Local history operation failed", - "fields": { - "count": { - "type": "int", - "required": false, - "description": "Number of failed snapshots in this batch; absent for a single history operation" - }, - "stage": { - "type": "token", - "required": true, - "description": "History action that failed, such as record, relocate or restore" - }, - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "LitheLocalHistoryModule" - }, - { - "id": "app.history.restore_failed", - "channel": "app", - "level": "error", - "message": "Local history restore failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Underlying failure that prevented completing the requested operation" - } - }, - "rate": 60, - "owner": "LitheLocalHistoryModule" - }, - { - "id": "app.ide.request_failed", - "channel": "app", - "level": "error", - "message": "IDE capability request failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "IDE request phase that failed, such as response encoding or dispatch" - }, - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "app.logging.redirect_failed", "channel": "app", @@ -222,76 +42,6 @@ "rate": 60, "owner": "Lithe" }, - { - "id": "app.module.transition_failed", - "channel": "app", - "level": "warn", - "message": "Module transition failed", - "fields": { - "module": { - "type": "token", - "required": true, - "description": "Module identifier whose lifecycle transition failed" - }, - "stage": { - "type": "token", - "required": true, - "description": "Lifecycle action that failed, such as shutdown, sleep or idle" - }, - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "LitheApplicationKernel" - }, - { - "id": "app.process.journal_failed", - "channel": "app", - "level": "warn", - "message": "Process lifecycle journal write failed at {stage}", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Lifecycle journal write stage, e.g. process-exit or startup-descendants" - }, - "error": { - "type": "error", - "required": true, - "description": "Persistence error raised while saving managed process identities" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "app.process.watch_failed", - "channel": "app", - "level": "warn", - "message": "Retained process watch failed at {stage}", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Retained process watcher step, e.g. create, register or read" - }, - "pid": { - "type": "int", - "required": false, - "description": "Retained process PID being registered; absent for watcher-wide failures" - }, - "error": { - "type": "error", - "required": true, - "description": "POSIX error from creating, registering or reading the retained process watcher" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "app.search.directory_skipped", "channel": "app", @@ -341,6 +91,31 @@ "rate": 60, "owner": "Lithe" }, + { + "id": "app.startup.leftovers_resolved", + "channel": "app", + "level": "info", + "message": "Leftover processes from the previous session resolved", + "fields": { + "decided_by": { + "type": "token", + "required": true, + "description": "What decided the leftovers: policy when the process lifecycle plan settled them without asking, dialog when the user answered the start-up question" + }, + "ended": { + "type": "int", + "required": true, + "description": "Number of leftover processes the client ended" + }, + "kept": { + "type": "int", + "required": true, + "description": "Number of leftover processes the client kept running and stopped tracking" + } + }, + "rate": 60, + "owner": "Lithe" + }, { "id": "app.shell.environment", "channel": "app", @@ -369,36 +144,6 @@ "failureLevel": "warn" } }, - { - "id": "app.window.session_missing", - "channel": "app", - "level": "warn", - "message": "Project window {window} session missing", - "fields": { - "window": { - "type": "id", - "required": true, - "description": "Internal project window UUID whose corresponding session could not be found" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "app.workbench.registration_failed", - "channel": "app", - "level": "warn", - "message": "Workbench UI registration failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Validation error raised when registering workbench UI contributions" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "app.workspace.directory_skipped", "channel": "app", @@ -419,41 +164,6 @@ "rate": 60, "owner": "lithe-core" }, - { - "id": "app.workspace.file_operation_failed", - "channel": "app", - "level": "error", - "message": "Workspace file operation failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Workspace file action that failed, such as move, copy or create" - }, - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "LitheWorkspaceModule" - }, - { - "id": "app.workspace.rollback_failed", - "channel": "app", - "level": "warn", - "message": "Workspace preference rollback failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "LitheWorkspaceModule" - }, { "id": "app.workspace.scratch_cleanup_failed", "channel": "app", @@ -484,21 +194,6 @@ "rate": 60, "owner": "Lithe" }, - { - "id": "app.action_search.failed", - "channel": "app", - "level": "error", - "message": "Action catalog search failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Core command failure while matching the current action catalog; excludes query text and action content" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "app.cache.write_failed", "channel": "app", @@ -564,56 +259,21 @@ "rate": 60, "owner": "lithe-core" }, - { - "id": "app.native.operation_failed", - "channel": "app", - "level": "error", - "message": "Native {stage} operation failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Native user request that could not finish, such as relaunch, agent-preserve, or background-selection" - }, - "error": { - "type": "error", - "required": true, - "description": "Original native error from the failed request, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "app.storage.maintenance_failed", "channel": "app", "level": "warn", - "message": "Native storage {stage} failed", + "message": "Host storage {stage} failed", "fields": { "stage": { "type": "token", "required": true, - "description": "Native storage operation that failed, such as file-close, staging-remove, or permissions" + "description": "Host storage operation that failed, such as plugin_install_cleanup: a downloaded or staged plugin package the install could not remove" }, "error": { "type": "error", "required": true, - "description": "Native filesystem error preserving its stable domain and code at the handling boundary" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "app.diagnostics.crash_skipped", - "channel": "app", - "level": "warn", - "message": "Crash report collection skipped evidence", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Native failure reading the DiagnosticReports directory or an eligible application crash report" + "description": "Filesystem error at the host's handling boundary, preserving its stable domain and code" } }, "rate": 60, @@ -863,11 +523,31 @@ "surface": { "type": "token", "required": true, - "description": "UI surface that invoked the action: menu, shortcut, palette, toolbar, button, context_menu, notification or plugin" + "description": "UI surface that invoked the action: menu, shortcut, palette, toolbar, button, context_menu, notification, plugin or drag_drop" } }, "rate": 600, "owner": "LitheModuleAPI" + }, + { + "id": "app.background.operation_failed", + "channel": "app", + "level": "warn", + "message": "Background operation {operation} failed", + "fields": { + "operation": { + "type": "token", + "required": true, + "description": "Source-owned category of work the window runs on its own, such as project_tree_watch or memory_sample" + }, + "error": { + "type": "error", + "required": true, + "description": "Error raised by the background work; the window degrades instead of notifying the user" + } + }, + "rate": 60, + "owner": "Lithe" } ] } diff --git a/rust/logging/events/debug.json b/rust/logging/events/debug.json index be45697c..bd835bd9 100644 --- a/rust/logging/events/debug.json +++ b/rust/logging/events/debug.json @@ -2,66 +2,6 @@ "version": 1, "root": "debug", "events": [ - { - "id": "debug.inspection.fallback_selected", - "channel": "debug", - "level": "warn", - "message": "Debug inspection used a fallback", - "fields": { - "count": { - "type": "int", - "required": false, - "description": "Number of field requests that failed in this bounded snapshot; absent for memory layout decoding" - }, - "stage": { - "type": "token", - "required": true, - "description": "Debug inspection step that failed, variable-fields or memory-layout" - }, - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "LitheDebugModule" - }, - { - "id": "debug.session.cleanup_failed", - "channel": "debug", - "level": "warn", - "message": "Debug session cleanup failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Debug cleanup phase that failed, breakpoints or disconnect" - }, - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "LitheDebugModule" - }, - { - "id": "debug.shortcut.decision_failed", - "channel": "debug", - "level": "error", - "message": "Debug shortcut state decision failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Core failure while choosing whether the requested debug shortcut should start or continue" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "debug.process.started", "channel": "debug/{adapter}", @@ -186,26 +126,6 @@ }, "rate": 120, "owner": "lithe-core" - }, - { - "id": "debug.transport.failed", - "channel": "debug", - "level": "error", - "message": "Debug adapter transport failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Native failure stage, process-start, initialization-timeout, transport-exit or transport-receive" - }, - "exit_code": { - "type": "int", - "required": false, - "description": "Native adapter process exit status when available; absent for startup, timeout and receive failures" - } - }, - "rate": 60, - "owner": "LitheDebugModule" } ] } diff --git a/rust/logging/events/editor.json b/rust/logging/events/editor.json index b86a26c4..d749e392 100644 --- a/rust/logging/events/editor.json +++ b/rust/logging/events/editor.json @@ -2,61 +2,6 @@ "version": 1, "root": "editor", "events": [ - { - "id": "editor.settings_import.failed", - "channel": "editor", - "level": "error", - "message": "Editor settings import failed at {stage}", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Import workflow boundary that failed: source-read, scan, apply, or undo" - }, - "error": { - "type": "error", - "required": true, - "description": "Import or native I/O error classification; source paths, configuration contents and provider prose are omitted" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "editor.settings_import.warnings_shown", - "channel": "editor", - "level": "warn", - "message": "Editor settings import has unsupported source settings", - "fields": { - "source_count": { - "type": "int", - "required": true, - "description": "Number of discovered sources with warnings shown in this scan" - }, - "warning_count": { - "type": "int", - "required": true, - "description": "Total number of source warnings shown in this scan" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "editor.document.header_failed", - "channel": "editor", - "level": "warn", - "message": "Document header inspection failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "editor.document.open_failed", "channel": "editor", @@ -77,26 +22,6 @@ "rate": 60, "owner": "Lithe" }, - { - "id": "editor.document.recovery_failed", - "channel": "editor", - "level": "warn", - "message": "Document {document} save state recovery failed", - "fields": { - "document": { - "type": "id", - "required": true, - "description": "Internal document UUID whose save lifecycle state could not be recovered" - }, - "error": { - "type": "error", - "required": true, - "description": "Error raised while recovering the document lifecycle state after a failed save" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "editor.document.save_failed", "channel": "editor", @@ -127,41 +52,6 @@ "rate": 60, "owner": "Lithe" }, - { - "id": "editor.document.save_superseded", - "channel": "editor", - "level": "debug", - "message": "Document {document} revision {revision} save superseded", - "fields": { - "document": { - "type": "id", - "required": true, - "description": "Internal document UUID whose save result was superseded" - }, - "revision": { - "type": "int", - "required": true, - "description": "Native document lifecycle revision at the post-write supersession check" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "editor.document.staging_cleanup_failed", - "channel": "editor", - "level": "warn", - "message": "Document staging cleanup failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Filesystem error raised while deleting the temporary document staging file" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "editor.document.watch_failed", "channel": "editor", @@ -178,95 +68,15 @@ "owner": "Lithe" }, { - "id": "editor.icon.fallback_selected", - "channel": "editor", - "level": "debug", - "message": "File icon content inspection failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "File icon inspection kind, e.g. generic" - }, - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 30, - "owner": "Lithe" - }, - { - "id": "editor.preview.update_failed", - "channel": "editor", - "level": "debug", - "message": "Preview {stage} update failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Preview update stage, such as markdown-javascript or download-replace" - }, - "error": { - "type": "error", - "required": true, - "description": "Native WebKit or filesystem failure while applying the preview update" - } - }, - "rate": 30, - "owner": "Lithe" - }, - { - "id": "editor.shortcuts.update_failed", - "channel": "editor", - "level": "error", - "message": "Keyboard shortcut update failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "editor.sync.edit_received", + "id": "editor.recovery.applied", "channel": "editor", - "level": "debug", - "message": "Document {document} received {change_count} edits during freeze", + "level": "info", + "message": "Unsaved draft restored into its document", "fields": { - "document": { - "type": "id", - "required": true, - "description": "Internal document UUID that received browser edits while synchronization was frozen" - }, - "base_revision": { - "type": "int", - "required": true, - "description": "Native revision on which the incoming browser edit batch was based" - }, - "native_revision": { - "type": "int", - "required": true, - "description": "Current native revision when the edit batch arrived" - }, - "change_count": { - "type": "int", - "required": true, - "description": "Number of ordered edits in the incoming browser batch" - }, - "inserted_utf16_length": { - "type": "int", - "required": true, - "description": "Total UTF-16 code units inserted by the incoming edit batch" - }, - "replaced_utf16_length": { - "type": "int", + "conflict": { + "type": "bool", "required": true, - "description": "Total UTF-16 code units replaced by the incoming edit batch" + "description": "Whether the file changed on disk since the draft was written, so the draft opens as a conflict against the disk version" } }, "rate": 60, @@ -345,61 +155,6 @@ "failureLevel": "error" } }, - { - "id": "editor.sync.unlock_failed", - "channel": "editor", - "level": "debug", - "message": "Document {document} synchronization unlock failed", - "fields": { - "document": { - "type": "id", - "required": true, - "description": "Internal document UUID whose browser synchronization lock could not be released" - }, - "error": { - "type": "error", - "required": true, - "description": "Browser bridge error returned while releasing the synchronization lock" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "editor.sync.unlock_finished", - "channel": "editor", - "level": "debug", - "message": "Document {document} synchronization unlocked", - "fields": { - "document": { - "type": "id", - "required": true, - "description": "Internal document UUID whose browser synchronization lock was released" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "editor.syntax.configuration_failed", - "channel": "editor", - "level": "warn", - "message": "Syntax {kind} configuration load failed", - "fields": { - "kind": { - "type": "token", - "required": true, - "description": "Syntax configuration being loaded, e.g. highlighting or colors" - }, - "error": { - "type": "error", - "required": true, - "description": "Read or decode error raised while loading the syntax configuration" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "editor.text.classification_failed", "channel": "editor", @@ -408,26 +163,6 @@ "fields": {}, "rate": 60, "owner": "Lithe" - }, - { - "id": "editor.workspace_edit.rollback_failed", - "channel": "editor", - "level": "warn", - "message": "Workspace edit rollback failed", - "fields": { - "count": { - "type": "int", - "required": true, - "description": "Number of closed-file rollback writes that failed" - }, - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "Lithe" } ] } diff --git a/rust/logging/events/lsp.json b/rust/logging/events/lsp.json index a0502ea5..2df4c2a3 100644 --- a/rust/logging/events/lsp.json +++ b/rust/logging/events/lsp.json @@ -2,31 +2,6 @@ "version": 1, "root": "lsp", "events": [ - { - "id": "lsp.host.operation_failed", - "channel": "lsp/{server}", - "level": "warn", - "message": "Language host operation failed at {stage}", - "fields": { - "server": { - "type": "id", - "required": true, - "description": "Core-resolved language server identity owning this host operation" - }, - "stage": { - "type": "token", - "required": true, - "description": "Host operation step that failed, such as entrypoint-warmup or language-import" - }, - "error": { - "type": "error", - "required": true, - "description": "Native or stable runtime error that caused the host operation fallback" - } - }, - "rate": 120, - "owner": "LitheLanguageIntelligenceModule" - }, { "id": "lsp.message.logged", "channel": "lsp/{server}", @@ -255,102 +230,6 @@ } } }, - { - "id": "lsp.session.issue_failed", - "channel": "lsp/{server}", - "level": "error", - "owner": "LanguageToolingSessionManager", - "message": "Language server {server} operation failed", - "fields": { - "server": { - "type": "id", - "required": true, - "description": "Language provider identity owned by the registered session." - }, - "stage": { - "type": "token", - "required": true, - "description": "Actual source stage, such as discovery, configuration, documentSync or processStart." - }, - "failure_code": { - "type": "token", - "required": true, - "description": "Stable failure classification supplied by the owning runtime or host boundary." - }, - "exit_code": { - "type": "int", - "required": false, - "description": "Native language server process exit status when supplied by the runtime." - } - } - }, - { - "id": "lsp.session.degradation_received", - "channel": "lsp/{server}", - "level": "warn", - "owner": "LanguageToolingSessionManager", - "message": "Language server {server} operation degraded", - "fields": { - "server": { - "type": "id", - "required": true, - "description": "Language provider identity owned by the registered session." - }, - "stage": { - "type": "token", - "required": true, - "description": "Actual source stage, such as discovery, configuration, documentSync or processStart." - }, - "failure_code": { - "type": "token", - "required": true, - "description": "Stable failure classification supplied by the owning runtime or host boundary." - }, - "exit_code": { - "type": "int", - "required": false, - "description": "Native language server process exit status when supplied by the runtime." - } - } - }, - { - "id": "lsp.session.stage_changed", - "channel": "lsp/{server}", - "level": "debug", - "owner": "LanguageToolingSessionManager", - "message": "Language server {server} host stage changed to {stage}", - "fields": { - "server": { - "type": "id", - "required": true, - "description": "Core-resolved language provider routing segment shared with engine session events." - }, - "stage": { - "type": "token", - "required": true, - "description": "Closed host orchestration stage: requested, resolving, registered, stopping, or cancelled." - } - } - }, - { - "id": "lsp.cache.cleaned", - "channel": "lsp/{server}", - "level": "debug", - "owner": "LanguageToolingSessionManager", - "message": "Language server {server} cache cleaned", - "fields": { - "server": { - "type": "id", - "required": true, - "description": "Core-resolved language provider routing segment whose workspace cache was pruned." - }, - "removed": { - "type": "int", - "required": true, - "description": "Number of workspace cache entries removed by the host cache cleaner." - } - } - }, { "id": "lsp.process.cleanup_failed", "channel": "lsp/{server}", diff --git a/rust/logging/events/perf.json b/rust/logging/events/perf.json index 83b9af31..b92194b3 100644 --- a/rust/logging/events/perf.json +++ b/rust/logging/events/perf.json @@ -1,264 +1,5 @@ { "version": 1, "root": "perf", - "events": [ - { - "id": "perf.app.sampled", - "channel": "perf", - "level": "debug", - "message": "Application performance sampled at {phase}", - "fields": { - "rss": { - "type": "bytes", - "required": false, - "description": "Application resident memory sampled from the native process monitor, in bytes" - }, - "phase": { - "type": "token", - "required": true, - "description": "Performance baseline phase associated with this sample, e.g. ready or stable" - }, - "duration": { - "type": "duration", - "required": false, - "description": "Elapsed time for the measured application phase in milliseconds, when applicable" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "perf.editor.open_measured", - "channel": "perf", - "level": "debug", - "message": "Editor opening measured", - "fields": { - "model": { - "type": "duration", - "required": false, - "description": "Monaco opening model elapsed monotonic time in milliseconds." - }, - "attach": { - "type": "duration", - "required": false, - "description": "Monaco opening attach elapsed monotonic time in milliseconds." - }, - "settled": { - "type": "duration", - "required": false, - "description": "Monaco opening settled elapsed monotonic time in milliseconds." - }, - "first_frame": { - "type": "duration", - "required": false, - "description": "Monaco opening first_frame elapsed monotonic time in milliseconds." - }, - "max_frame_gap": { - "type": "duration", - "required": false, - "description": "Monaco opening max_frame_gap elapsed monotonic time in milliseconds." - }, - "frames": { - "type": "int", - "required": false, - "description": "Monaco opening frames count reported by the editor measurement." - }, - "lines": { - "type": "int", - "required": false, - "description": "Monaco opening lines count reported by the editor measurement." - }, - "utf16_length": { - "type": "int", - "required": false, - "description": "Monaco opening utf16_length count reported by the editor measurement." - }, - "reused": { - "type": "bool", - "required": false, - "description": "Whether opening reused the existing Monaco document model." - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "perf.editor.semantic_measured", - "channel": "perf", - "level": "debug", - "message": "Editor semantic update measured with {tokens} tokens", - "fields": { - "tokens": { - "type": "int", - "required": true, - "description": "Number of semantic tokens delivered to the editor for this update" - }, - "revision": { - "type": "int", - "required": false, - "description": "Document revision associated with the semantic token update, when supplied" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "perf.git.cache_hit", - "channel": "perf", - "level": "debug", - "message": "Git {operation} history cache hit", - "fields": { - "operation": { - "type": "token", - "required": true, - "description": "Git service operation served from the history cache, e.g. history" - }, - "duration": { - "type": "duration", - "required": true, - "description": "Elapsed history cache lookup time in milliseconds" - } - }, - "rate": 60, - "owner": "LitheGitModule" - }, - { - "id": "perf.git.command_finished", - "channel": "perf", - "level": "debug", - "message": "Git {operation} command measured", - "fields": { - "operation": { - "type": "token", - "required": true, - "description": "Git service operation that issued the measured command" - }, - "duration": { - "type": "duration", - "required": true, - "description": "Elapsed Git command workflow time in milliseconds" - }, - "succeeded": { - "type": "bool", - "required": true, - "description": "Whether the Git command result reported success" - } - }, - "rate": 60, - "owner": "LitheGitModule" - }, - { - "id": "perf.git.read_finished", - "channel": "perf", - "level": "debug", - "message": "Git {operation} read measured", - "fields": { - "operation": { - "type": "token", - "required": true, - "description": "Git service read operation being measured, e.g. history" - }, - "duration": { - "type": "duration", - "required": true, - "description": "Elapsed Git service read time in milliseconds" - }, - "succeeded": { - "type": "bool", - "required": true, - "description": "Whether the Git service read returned a result" - } - }, - "rate": 60, - "owner": "LitheGitModule" - }, - { - "id": "perf.git.worktree_inspected", - "channel": "perf", - "level": "debug", - "message": "Git worktree inspection measured", - "fields": { - "phase": { - "type": "token", - "required": true, - "description": "Worktree inspection phase supplied by the Git service" - }, - "duration": { - "type": "duration", - "required": true, - "description": "Elapsed time for this worktree inspection phase, in milliseconds" - }, - "worktree": { - "type": "path", - "required": true, - "description": "Worktree root path from the Git snapshot, redacted by Core before persistence." - } - }, - "rate": 60, - "owner": "LitheGitModule" - }, - { - "id": "perf.app.signpost_measured", - "channel": "perf", - "level": "debug", - "message": "Native signpost measured", - "owner": "Lithe.Monitoring", - "fields": { - "name": { - "type": "token", - "required": true, - "description": "Controlled native signpost name for the measured operation." - }, - "duration": { - "type": "duration", - "required": true, - "description": "Monotonic duration of the native signpost operation." - } - } - }, - { - "id": "perf.settings.latency_measured", - "channel": "perf", - "level": "debug", - "message": "Settings latency measured", - "owner": "Lithe.Monitoring", - "fields": { - "phase": { - "type": "token", - "required": true, - "description": "Native settings latency phase value; timestamps use monotonic nanoseconds." - }, - "category": { - "type": "token", - "required": true, - "description": "Native settings latency category value; timestamps use monotonic nanoseconds." - }, - "event_id": { - "type": "int", - "required": true, - "description": "Native settings latency event_id value; timestamps use monotonic nanoseconds." - }, - "time_ns": { - "type": "int", - "required": true, - "description": "Native settings latency time_ns value; timestamps use monotonic nanoseconds." - }, - "input_ns": { - "type": "int", - "required": true, - "description": "Native settings latency input_ns value; timestamps use monotonic nanoseconds." - }, - "received_ns": { - "type": "int", - "required": true, - "description": "Native settings latency received_ns value; timestamps use monotonic nanoseconds." - }, - "selected_ns": { - "type": "int", - "required": true, - "description": "Native settings latency selected_ns value; timestamps use monotonic nanoseconds." - } - } - } - ] + "events": [] } diff --git a/rust/logging/events/plugins.json b/rust/logging/events/plugins.json index c4c9a6fc..883625c2 100644 --- a/rust/logging/events/plugins.json +++ b/rust/logging/events/plugins.json @@ -2,320 +2,6 @@ "version": 1, "root": "plugins", "events": [ - { - "id": "plugins.backend.activation_failed", - "channel": "plugins/{plugin}/host", - "level": "warn", - "message": "Plugin {plugin} backend activation failed", - "fields": { - "plugin": { - "type": "id", - "required": true, - "description": "Validated installed plugin id whose backend activation failed" - }, - "error": { - "type": "error", - "required": true, - "description": "Error returned while activating the installed plugin backend" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.catalog.rejected", - "channel": "plugins", - "level": "warn", - "message": "Plugin catalog startup rejected", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Validation error that rejected the global plugin module graph, without a single owning plugin" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.editor.action_failed", - "channel": "plugins/{plugin}/host", - "level": "warn", - "message": "Plugin {plugin} editor action failed", - "fields": { - "plugin": { - "type": "id", - "required": true, - "description": "Validated plugin id that contributed the invoked editor action" - }, - "error": { - "type": "error", - "required": true, - "description": "Error returned while executing the selected plugin editor action" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.editor.actions_failed", - "channel": "plugins/{plugin}/host", - "level": "warn", - "message": "Plugin {plugin} editor actions failed", - "fields": { - "plugin": { - "type": "id", - "required": true, - "description": "Validated plugin id whose editor actions could not be queried" - }, - "error": { - "type": "error", - "required": true, - "description": "Error returned while loading available editor actions from this plugin" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.editor.provider_failed", - "channel": "plugins/{plugin}/host", - "level": "warn", - "message": "Plugin {plugin} editor provider failed", - "fields": { - "plugin": { - "type": "id", - "required": true, - "description": "Validated plugin id whose editor language-feature provider function failed or answered invalidly" - }, - "error": { - "type": "error", - "required": true, - "description": "Error returned while calling the provider function or validating its result" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.editor.refresh_failed", - "channel": "plugins", - "level": "warn", - "message": "Plugin editor actions refresh failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Error returned while refreshing the plugin editor action registrations" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.grammar.load_failed", - "channel": "plugins/{plugin}/host", - "level": "warn", - "message": "Plugin {plugin} grammar failed in editor", - "fields": { - "plugin": { - "type": "id", - "required": true, - "description": "Validated plugin id that contributed the grammar rejected by the editor" - }, - "language": { - "type": "version", - "required": false, - "description": "Language id reported by the editor, omitted only when longer than 64 bytes" - }, - "error": { - "type": "error", - "required": false, - "description": "Editor grammar loading error, when the browser supplied structured failure details" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.grammar.rejected", - "channel": "plugins/{plugin}/host", - "level": "warn", - "message": "Plugin {plugin} grammar rejected: {reason}", - "fields": { - "plugin": { - "type": "id", - "required": true, - "description": "Validated plugin id that owns the rejected grammar declaration" - }, - "language": { - "type": "version", - "required": false, - "description": "Language id from the rejected plugin grammar declaration" - }, - "reason": { - "type": "token", - "required": true, - "description": "Grammar rejection category, e.g. outside-package, not-regular-file or invalid-grammar" - }, - "error": { - "type": "error", - "required": false, - "description": "Grammar file read or decode error; absent for path and file-kind rejections" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.lifecycle.failed", - "channel": "plugins", - "level": "error", - "message": "Module activation failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Error raised while starting the registered eager modules" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.lifecycle.started", - "channel": "plugins", - "level": "info", - "message": "Eager modules started", - "fields": {}, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.migration.finished", - "channel": "plugins/{plugin}/host", - "level": "info", - "message": "Plugin {plugin} migrated {profiles} database profiles and {passwords} credentials", - "fields": { - "plugin": { - "type": "id", - "required": true, - "description": "Validated database plugin id that received the migrated state" - }, - "profiles": { - "type": "int", - "required": true, - "description": "Number of legacy database connection profiles migrated into the plugin state" - }, - "passwords": { - "type": "int", - "required": true, - "description": "Number of legacy passwords successfully transferred to the plugin credential store" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.migration.password_failed", - "channel": "plugins/{plugin}/host", - "level": "warn", - "message": "Plugin {plugin} credential migration failed for connection {connection}", - "fields": { - "plugin": { - "type": "id", - "required": true, - "description": "Validated database plugin id receiving the migrated credentials" - }, - "connection": { - "type": "id", - "required": true, - "description": "Legacy database connection id whose password could not be transferred" - }, - "error": { - "type": "error", - "required": true, - "description": "Credential store error raised when transferring this connection password; never the secret" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.migration.state_failed", - "channel": "plugins/{plugin}/host", - "level": "warn", - "message": "Plugin {plugin} state migration failed", - "fields": { - "plugin": { - "type": "id", - "required": true, - "description": "Validated database plugin id receiving the migrated connection state" - }, - "error": { - "type": "error", - "required": true, - "description": "Filesystem or encoding error raised while writing the migrated plugin state" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.resources.maintenance_failed", - "channel": "plugins", - "level": "warn", - "message": "Plugin resource {stage} failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Owned plugin resource operation that failed, such as staging-remove, rollback, or archive-close" - }, - "error": { - "type": "error", - "required": true, - "description": "Native failure while maintaining host-owned plugin download, staging, or state resources" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.scan.failed", - "channel": "plugins", - "level": "warn", - "message": "Live plugin scan failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Error returned by the live installed-plugin scan" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "plugins.startup.rejected", - "channel": "plugins/{plugin}/host", - "level": "warn", - "message": "Plugin {plugin} startup rejected", - "fields": { - "plugin": { - "type": "id", - "required": true, - "description": "Validated installed plugin id whose startup acceptance checks failed" - }, - "error": { - "type": "error", - "required": true, - "description": "Manifest, UI binding or resource validation error that rejected this plugin at startup" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "plugins.host.stderr.received", "channel": "plugins/{plugin}/host", @@ -525,36 +211,6 @@ "rate": 120, "owner": "lithe-core" }, - { - "id": "plugins.host.request_failed", - "channel": "plugins/{plugin}/host", - "level": "error", - "message": "Plugin host request {method} failed with {code}", - "fields": { - "plugin": { - "type": "id", - "required": true, - "description": "Validated plugin identity that owns this failed host request" - }, - "method": { - "type": "token", - "required": true, - "description": "Host method or plugin function the request named, e.g. lithe/host/languageServer/notify; never its params" - }, - "code": { - "type": "token", - "required": true, - "description": "Stable plugin.host.* failure code the backend received, independent of the native error's wording" - }, - "error": { - "type": "error", - "required": true, - "description": "Native host service error or stable host request failure code" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "plugins.host.session.updated", "channel": "plugins/{plugin}/host", diff --git a/rust/logging/events/remote.json b/rust/logging/events/remote.json index 260c4a89..4f5ca0b8 100644 --- a/rust/logging/events/remote.json +++ b/rust/logging/events/remote.json @@ -2,71 +2,6 @@ "version": 1, "root": "remote", "events": [ - { - "id": "remote.build.cleanup_failed", - "channel": "remote", - "level": "warn", - "message": "Remote build output cleanup failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Filesystem error raised while removing remote build output staging" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "remote.connections.save_failed", - "channel": "remote", - "level": "warn", - "message": "Remote connection metadata save failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "remote.directory.watch_failed", - "channel": "remote", - "level": "warn", - "message": "Remote directory watch ended", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Error that ended the remote workspace directory observation stream" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "remote.plugins.cleanup_failed", - "channel": "remote", - "level": "warn", - "message": "Remote plugin {stage} cleanup failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Remote plugin deployment cleanup target, e.g. snapshot or extraction" - }, - "error": { - "type": "error", - "required": true, - "description": "Filesystem error raised while deleting remote plugin deployment staging" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "remote.process.cleanup_failed", "channel": "remote", @@ -157,21 +92,6 @@ "rate": 60, "owner": "lithe-core" }, - { - "id": "remote.workspace.write_failed", - "channel": "remote", - "level": "error", - "message": "Remote workspace write failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "Lithe" - }, { "id": "remote.forward.accept_failed", "channel": "remote", diff --git a/rust/logging/events/run.json b/rust/logging/events/run.json index 901b49be..9b05636d 100644 --- a/rust/logging/events/run.json +++ b/rust/logging/events/run.json @@ -2,76 +2,6 @@ "version": 1, "root": "run", "events": [ - { - "id": "run.build.scratch_cleanup_failed", - "channel": "run", - "level": "warn", - "message": "Build dependency {stage} cleanup failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Build scratch cleanup target, e.g. provider-output or abandoned-scratch" - }, - "error": { - "type": "error", - "required": true, - "description": "Filesystem error raised while deleting a build scratch file" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "run.configuration.operation_failed", - "channel": "run", - "level": "warn", - "message": "Execution configuration operation failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Execution configuration phase that failed, load, plan, fingerprint or save" - }, - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "LitheExecutionModule" - }, - { - "id": "run.configuration.write_failed", - "channel": "run", - "level": "error", - "message": "Execution configuration write failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Underlying failure that prevented completing the requested operation" - } - }, - "rate": 60, - "owner": "LitheExecutionModule" - }, - { - "id": "run.preparation.failed", - "channel": "run", - "level": "error", - "message": "Execution preparation failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Underlying failure that prevented completing the requested operation" - } - }, - "rate": 60, - "owner": "LitheExecutionModule" - }, { "id": "run.process.execution", "channel": "run", @@ -99,26 +29,6 @@ "span": { "failureLevel": "error" } - }, - { - "id": "run.process.io_failed", - "channel": "run", - "level": "warn", - "message": "Process pipe {stage} failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Native pipe operation that failed: close, stdin-write, stdout-drain, stream-drain, or capture-drain" - }, - "error": { - "type": "error", - "required": true, - "description": "FileHandle error from releasing a process pipe or writing standard input" - } - }, - "rate": 60, - "owner": "Lithe" } ] } diff --git a/rust/logging/events/terminal.json b/rust/logging/events/terminal.json index a9d70cef..2b229231 100644 --- a/rust/logging/events/terminal.json +++ b/rust/logging/events/terminal.json @@ -23,30 +23,20 @@ "owner": "LitheTerminalModule" }, { - "id": "terminal.renderer.fallback_selected", + "id": "terminal.session.start_failed", "channel": "terminal", "level": "warn", - "message": "Terminal renderer fallback selected", + "message": "Terminal session failed to start", "fields": { - "error": { - "type": "error", + "stage": { + "type": "token", "required": true, - "description": "Metal renderer activation error that caused the terminal to select Core Graphics" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "terminal.shell.discovery_failed", - "channel": "terminal", - "level": "warn", - "message": "Registered login shell discovery failed", - "fields": { + "description": "Terminal start step that failed, e.g. spawn or attach" + }, "error": { "type": "error", "required": true, - "description": "Filesystem error raised while reading the registered login shell list" + "description": "Error raised while starting the terminal session, preserving stable domain and code" } }, "rate": 60, diff --git a/rust/logging/events/update.json b/rust/logging/events/update.json index 43edc5a3..98f310aa 100644 --- a/rust/logging/events/update.json +++ b/rust/logging/events/update.json @@ -36,101 +36,6 @@ }, "rate": 60, "owner": "Lithe" - }, - { - "id": "update.download.interrupted", - "channel": "update", - "level": "warn", - "message": "Update download interrupted with resume data retained", - "fields": { - "reason": { - "type": "token", - "required": true, - "description": "Existing UpdateDownloadFailure case: timedOut, connectionFailed, tlsOrProxyFailure, httpStatus or invalidResponse; unclassified when no upstream cause exists." - }, - "http_status": { - "type": "int", - "required": false, - "description": "Actual upstream HTTP status when the download failed with httpStatus." - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "update.relay.start_failed", - "channel": "update", - "level": "warn", - "message": "Update download relay unavailable", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Socket or listener setup error that prevented starting the local update download relay" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "update.rollback.cleanup_failed", - "channel": "update", - "level": "warn", - "message": "Stable rollback {stage} cleanup failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Rollback cleanup target, e.g. leftover, disk-image or staging" - }, - "error": { - "type": "error", - "required": true, - "description": "Filesystem or disk-image cleanup error raised while preparing a stable rollback" - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "update.rollback.preparation_failed", - "channel": "update", - "level": "warn", - "message": "Stable rollback preparation failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Download, verification or staging error that prevented preparing the stable rollback package" - }, - "stage": { - "type": "token", - "required": false, - "description": "Controlled installer tool basename that failed during package preparation." - }, - "exit_code": { - "type": "int", - "required": false, - "description": "Native installer tool exit status observed at the rollback boundary." - } - }, - "rate": 60, - "owner": "Lithe" - }, - { - "id": "update.source.probe_failed", - "channel": "update", - "level": "error", - "message": "Update source probe failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Native transport or decoding error while checking the configured update source" - } - }, - "rate": 60, - "owner": "Lithe" } ] } diff --git a/rust/logging/events/vcs.json b/rust/logging/events/vcs.json index 5bf2d659..ac4e2ca4 100644 --- a/rust/logging/events/vcs.json +++ b/rust/logging/events/vcs.json @@ -22,41 +22,6 @@ "rate": 60, "owner": "Lithe" }, - { - "id": "vcs.history_date_query.failed", - "channel": "vcs", - "level": "error", - "message": "Git history date filter failed", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Stable failure category for the shared date filter" - } - }, - "rate": 60, - "owner": "LitheGitModule" - }, - { - "id": "vcs.shelf.operation_failed", - "channel": "vcs", - "level": "error", - "message": "Saved changes operation failed", - "fields": { - "stage": { - "type": "token", - "required": true, - "description": "Saved changes action that failed, load, save or delete" - }, - "error": { - "type": "error", - "required": true, - "description": "Underlying failure at this operation boundary, preserving stable domain and code" - } - }, - "rate": 60, - "owner": "LitheGitModule" - }, { "id": "vcs.stderr.received", "channel": "vcs/{provider}", @@ -576,21 +541,6 @@ "rate": 600, "owner": "lithe-core" }, - { - "id": "vcs.history_action_capabilities.failed", - "channel": "vcs", - "level": "warn", - "message": "Git history action eligibility could not be read", - "fields": { - "error": { - "type": "error", - "required": true, - "description": "Stable failure category for the history action eligibility request" - } - }, - "rate": 60, - "owner": "LitheGitModule" - }, { "id": "vcs.message.error.logged", "channel": "vcs/{provider}", @@ -770,6 +720,31 @@ "description": "Stable Core lifecycle failure category, such as serverExited or transportFailed, without protocol or process contents" } } + }, + { + "id": "vcs.provider.skipped", + "channel": "vcs", + "level": "warn", + "message": "Version control provider {plugin} skipped for {vcs}", + "fields": { + "plugin": { + "type": "id", + "required": true, + "description": "Validated id of the plugin whose provider for this version control system was not used" + }, + "vcs": { + "type": "token", + "required": true, + "description": "Version control system both plugins provide" + }, + "selected": { + "type": "id", + "required": true, + "description": "Validated id of the plugin whose provider was selected instead" + } + }, + "rate": 60, + "owner": "Lithe" } ] }