@aristanetworks/eos-mcp-server 0.8.0-beta → 0.8.1-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +4 -30
  3. package/dist/cli.d.ts +1 -4
  4. package/dist/cli.js +4 -63
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config/diagnostics.d.ts +10 -5
  7. package/dist/config/diagnostics.js +3 -2
  8. package/dist/config/diagnostics.js.map +1 -1
  9. package/dist/config/loadConfig.js +1 -5
  10. package/dist/config/loadConfig.js.map +1 -1
  11. package/dist/config/schema.d.ts +28 -14
  12. package/dist/diagnostics/concurrency.d.ts +7 -11
  13. package/dist/diagnostics/concurrency.js +38 -80
  14. package/dist/diagnostics/concurrency.js.map +1 -1
  15. package/dist/diagnostics/eapiRunner.js +7 -1
  16. package/dist/diagnostics/eapiRunner.js.map +1 -1
  17. package/dist/diagnostics/executor.d.ts +1 -2
  18. package/dist/diagnostics/executor.js +2 -3
  19. package/dist/diagnostics/executor.js.map +1 -1
  20. package/dist/diagnostics/types.d.ts +3 -4
  21. package/dist/eapi/client.js +5 -4
  22. package/dist/eapi/client.js.map +1 -1
  23. package/dist/eapi/types.d.ts +3 -0
  24. package/dist/eapi/types.js.map +1 -1
  25. package/dist/index.js +0 -10
  26. package/dist/index.js.map +1 -1
  27. package/dist/mcp/createServer.js +2 -19
  28. package/dist/mcp/createServer.js.map +1 -1
  29. package/dist/mcp/tools/ping.d.ts +0 -7
  30. package/dist/mcp/tools/ping.js +13 -26
  31. package/dist/mcp/tools/ping.js.map +1 -1
  32. package/dist/serverInfo/buildServerInfo.js +2 -1
  33. package/dist/serverInfo/buildServerInfo.js.map +1 -1
  34. package/dist/serverInfo/types.d.ts +1 -0
  35. package/docs/CHECKPOINT.md +3 -6
  36. package/docs/CODE_WALKTHROUGH.md +6 -11
  37. package/docs/DESIGN.md +3 -3
  38. package/docs/DIAGNOSTICS.md +18 -69
  39. package/docs/IMPLEMENTATION_PLAN.md +2 -2
  40. package/docs/adr/0002-fail-closed-diagnostic-reservations.md +2 -0
  41. package/docs/adr/0003-durable-diagnostic-ledger.md +2 -0
  42. package/docs/adr/0004-offline-operator-attested-release.md +2 -0
  43. package/docs/adr/0005-multi-destination-ping.md +1 -1
  44. package/docs/adr/0006-in-memory-timed-diagnostic-capacity.md +21 -0
  45. package/docs/research/eos-diagnostic-lifecycle.md +2 -0
  46. package/package.json +1 -1
  47. package/dist/commands/inspectDiagnostics.d.ts +0 -3
  48. package/dist/commands/inspectDiagnostics.js +0 -35
  49. package/dist/commands/inspectDiagnostics.js.map +0 -1
  50. package/dist/commands/releaseDiagnostics.d.ts +0 -9
  51. package/dist/commands/releaseDiagnostics.js +0 -87
  52. package/dist/commands/releaseDiagnostics.js.map +0 -1
  53. package/dist/diagnostics/journal.d.ts +0 -14
  54. package/dist/diagnostics/journal.js +0 -317
  55. package/dist/diagnostics/journal.js.map +0 -1
  56. package/dist/diagnostics/journalTypes.d.ts +0 -8
  57. package/dist/diagnostics/journalTypes.js +0 -2
  58. package/dist/diagnostics/journalTypes.js.map +0 -1
  59. package/dist/diagnostics/releaseEvidence.d.ts +0 -502
  60. package/dist/diagnostics/releaseEvidence.js +0 -115
  61. package/dist/diagnostics/releaseEvidence.js.map +0 -1
  62. package/dist/diagnostics/reservationSchema.d.ts +0 -49
  63. package/dist/diagnostics/reservationSchema.js +0 -18
  64. package/dist/diagnostics/reservationSchema.js.map +0 -1
  65. package/dist/diagnostics/statePath.d.ts +0 -4
  66. package/dist/diagnostics/statePath.js +0 -25
  67. package/dist/diagnostics/statePath.js.map +0 -1
  68. package/dist/utils/privateFile.d.ts +0 -3
  69. package/dist/utils/privateFile.js +0 -7
  70. package/dist/utils/privateFile.js.map +0 -1
  71. package/docs/examples/diagnostic-release-evidence.template.json +0 -26
@@ -39,7 +39,8 @@ export function buildServerInfo(context, diagnosticCapacity) {
39
39
  ping_reply_timeout_ms: context.config.diagnostics.pingReplyTimeoutMs,
40
40
  command_timeout_ms: context.config.diagnostics.commandTimeoutMs,
41
41
  http_timeout_ms: context.config.diagnostics.httpTimeoutMs,
42
- overall_operation_timeout_ms: context.config.diagnostics.overallOperationTimeoutMs
42
+ overall_operation_timeout_ms: context.config.diagnostics.overallOperationTimeoutMs,
43
+ native_request_timeout: context.config.diagnostics.nativeRequestTimeout
43
44
  }
44
45
  },
45
46
  diagnostics: {
@@ -1 +1 @@
1
- {"version":3,"file":"buildServerInfo.js","sourceRoot":"","sources":["../../src/serverInfo/buildServerInfo.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"buildServerInfo.js","sourceRoot":"","sources":["../../src/serverInfo/buildServerInfo.ts"],"names":[],"mappings":"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"}
@@ -46,6 +46,7 @@ export interface ServerInfo {
46
46
  command_timeout_ms: number;
47
47
  http_timeout_ms: number;
48
48
  overall_operation_timeout_ms: number;
49
+ native_request_timeout: boolean;
49
50
  };
50
51
  };
51
52
  diagnostics: {
@@ -23,8 +23,6 @@ The server is a test-backed, read-only MCP service for Arista EOS eAPI. The prod
23
23
  - `validate-inventory`
24
24
  - `print-server-info`
25
25
  - `probe`
26
- - `inspect-diagnostics` (read-only persisted state and audit, no device access)
27
- - `release-diagnostics` (offline operator attestation, explicit scope and atomic audit)
28
26
 
29
27
  ## Safety and operational controls
30
28
 
@@ -35,10 +33,9 @@ The server is a test-backed, read-only MCP service for Arista EOS eAPI. The prod
35
33
  - HTTPS with certificate validation by default and optional custom CA support.
36
34
  - Validated show commands and bounded logging/running-configuration queries.
37
35
  - Read-operation concurrency, target, response-size, and timeout controls.
38
- - Configurable diagnostic budgets, durable ledger-scoped admission, independent timeouts, and indefinite fail-closed reservations after uncertain remote completion.
39
- - Write-ahead SQLite reservations, exact wire-ID persistence/correlation, exclusive crash-released ownership, restoration of unfinished work as uncertain, and fail-closed storage errors.
36
+ - Configurable diagnostic budgets, in-memory per-server admission, independent timeouts, and uncertain reservations held for the command budget after unknown remote completion (ADR 0006).
40
37
  - JSON-RPC version/ID and result/error exclusivity validation precedes output interpretation or read-only fallback; unrelated acknowledgements cannot free diagnostic capacity.
41
- - Live sanitized capacity/reservation visibility in server info; `diagnostic_capacity_uncertain` prevents new or queued work when all capacity is uncertain. Persistence and offline inspection are implemented. Offline operator-attested release is implemented, not an EOS completion proof. A qualified native remote kill/deadline mechanism remains unimplemented; installed EOS requestTimeout is not an end-to-end termination guarantee.
38
+ - Live sanitized capacity/reservation visibility in server info, including when each uncertain slot frees. A qualified native remote kill/deadline mechanism remains unimplemented; installed EOS requestTimeout is not an end-to-end termination guarantee.
42
39
  - No retries or shell/SSH fallback for ping. Non-configuring diagnostics are not passive reads; traceroute and capture are not implemented.
43
40
  - Sanitized result envelopes with stable machine-readable errors.
44
41
 
@@ -53,4 +50,4 @@ The server is a test-backed, read-only MCP service for Arista EOS eAPI. The prod
53
50
 
54
51
  Run `npm test`, `npm run typecheck`, `npm run lint`, and `npm run build` after changes. Optional integration tests require the configured cEOS environment. Ping's module and MCP stdio integration suites are qualified on cEOS 4.34.3M; see [DIAGNOSTICS.md](DIAGNOSTICS.md).
55
52
 
56
- Latest refactor verification: **362 tests across 40 files passed** with `INTEGRATION=1`, plus typecheck, static policy, build, and whitespace checks. Independent read-only review found no findings. Synthetic ledgers written by pre-refactor commit `0e208ec` retained compatible audit checksums, inspection, committed retries, legacy RPC identities, and remaining capacity. No real EOS reservations were operator-released in these checks.
53
+ Latest verification (in-memory capacity, ADR 0006): unit suite, typecheck, static policy and build pass; `INTEGRATION=1` was run against the cEOS lab, including a second server pinging the same inventory while the first held an uncertain slot.
@@ -20,8 +20,6 @@ Execution starts at `src/index.ts`. It parses CLI args, loads config, then dispa
20
20
  - `validate-inventory`: validate inventory and print the result.
21
21
  - `print-server-info`: print sanitized server metadata.
22
22
  - `probe`: run the same probe logic as the MCP probe tool.
23
- - `inspect-diagnostics`: read existing reservations and release audit without device access, ownership takeover, or reset.
24
- - `release-diagnostics`: offline, exact-scope operator release with explicit fencing attestation and atomic audit; no device calls or MCP exposure.
25
23
 
26
24
  CLI parsing lives in `src/cli.ts`. The app name and version are read from `package.json` at runtime via `src/core/version.ts`. Shared error handling lives in `src/core/errors.ts`, which defines `AppError` and the stable machine-readable error codes used across the CLI and MCP layers.
27
25
 
@@ -53,7 +51,7 @@ eAPI protocol and transport are split:
53
51
 
54
52
  - `src/eapi/client.ts`: builds JSON-RPC `runCmds` requests using the connection's `eapiVersion` (`"latest"` by default, `1` when pinned in config), handles HTTP errors, invalid JSON, protocol version/response-ID correlation, exclusive result/error envelopes, JSON-RPC errors, and unexpected result counts. Supports opt-in enable mode (`{ enable: true }`) for privileged commands by prepending `enable` to the wire commands and stripping the extra result entry transparently. Per-request timeout and caller cancellation are combined with `AbortSignal`.
55
53
  - `src/eapi/transport.ts`: production HTTPS transport and test-friendly fetch transport. The production transport enforces `maxResponseSizeBytes` while chunks are received, before buffering an oversized device response.
56
- - `src/eapi/client.ts` also exposes single-execution text commands for active diagnostics, without JSON fallback retries, using the pre-journaled request identity supplied by the diagnostic execution context.
54
+ - `src/eapi/client.ts` also exposes single-execution text commands for active diagnostics, without JSON fallback retries, using the reserved request identity supplied by the diagnostic execution context.
57
55
  - `src/eapi/types.ts`: shared eAPI types, the low-level `EosCommandRunner` interface used by `EapiDeviceReader`, `EapiCommandOptions`, and helpers for validating/drilling into eAPI JSON-RPC response payloads.
58
56
 
59
57
  ## Read Tool Services
@@ -77,17 +75,15 @@ Shared type-narrowing utilities (`isObject`, `readString`, `readBoolean`, `readN
77
75
  ## Diagnostic Execution
78
76
 
79
77
  - `src/diagnostics/executor.ts`: typed diagnostic orchestration, inventory opt-in and probe-budget checks, existing result envelopes, and cancellation. One executor is created per server instance.
80
- - `src/diagnostics/concurrency.ts`: admission shared by concurrent calls, with queueing separated from durable reservation creation, completion, and uncertainty transitions. Shutdown, storage failure, and exhausted uncertainty share queued-work rejection. Unknown completion never expires; cancelled waiters are removed.
78
+ - `src/diagnostics/concurrency.ts`: in-memory admission shared by concurrent calls in one server process. Unknown completion holds a slot for `commandTimeoutMs`, then a timer frees it; a late confirmed response frees it sooner. Shutdown rejects queued work; cancelled waiters are removed.
81
79
  - `src/diagnostics/eapiRunner.ts`: connection resolution followed by one text eAPI attempt in enable mode. Separate error paths distinguish local rejection before dispatch from uncertain RPC, transport, or malformed-result failures after dispatch; there is no mutable dispatch flag or retry.
82
80
  - `src/diagnostics/executionError.ts`: typed `AppError` classification (`not_dispatched`, `completed`, or `unknown`). Only explicitly settled errors permit capacity reuse; ordinary errors remain uncertain.
83
81
  - `src/diagnostics/ping.ts`: literal-address/VRF/source/count validation, finite ping command construction, and loss/RTT interpretation. A no-reply finding is not an execution failure.
84
82
  - `src/diagnostics/types.ts`: request, prepared intent, observation, and finding types discriminated by diagnostic kind, plus the `DiagnosticDeviceRunner` seam. Only ping is implemented; capture sessions are not pre-modeled.
85
83
 
86
- Diagnostic execution reuses read-operation orchestration with independent settings and global admission. Unknown completion retains capacity indefinitely; HTTP abort and elapsed budgets are not remote kill signals. Each server-info call reads `DiagnosticExecutor.getCapacity()` afresh; the standalone CLI reports no live snapshot.
84
+ Diagnostic execution reuses read-operation orchestration with independent settings and global admission. Unknown completion holds capacity for the command budget; HTTP abort is not a remote kill signal. Each server-info call reads `DiagnosticExecutor.getCapacity()` afresh; the standalone CLI reports no live snapshot.
87
85
 
88
- `journal.ts` provides private SQLite persistence and an exclusive ownership lock; `statePath.ts` supplies canonical inventory identity/default storage. Entries survive crashes, and commit failure blocks dispatch or reuse. The journal is injected through `journalTypes.ts`, so pure executor tests can remain in memory. Native SQLite loads only when production diagnostic permissions or ledger administration require it.
89
-
90
- `releaseEvidence.ts` validates attestation scope/consistency and uses shared JSON SHA-256 hashing for evidence and audit checksums; it does not verify external fencing. `reservationSchema.ts` validates and normalizes both unresolved records and audit snapshots, including absent legacy RPC IDs. The refactor preserves serialized records, checksum computation, and schema versions. Schema-1 migration, audit insertion, and selected deletions share the release transaction; ordinary server migration preserves occupied capacity. See [DIAGNOSTICS.md](DIAGNOSTICS.md).
86
+ Capacity lives in memory per server process, so several servers can run against one inventory. See [DIAGNOSTICS.md](DIAGNOSTICS.md) and [ADR 0006](adr/0006-in-memory-timed-diagnostic-capacity.md).
91
87
 
92
88
  ## MCP Layer
93
89
 
@@ -126,11 +122,10 @@ Tests mirror the source layout:
126
122
  - Inventory and target behavior: `inventory.test.ts`, `targetResolution.test.ts`
127
123
  - eAPI and connection behavior: `eapiClient.test.ts`, `eosDeviceReader.test.ts`, `startupValidation.test.ts`, `responseSize.test.ts`
128
124
  - Read services and orchestration: `probeDevices.test.ts`, `runShow.test.ts`, `loggingQuery.test.ts`, `showLogging.test.ts`, `getFacts.test.ts`, `getRunningConfig.test.ts`, `readExecution.test.ts`
129
- - Diagnostics: `ping.test.ts`, `diagnosticConfig.test.ts`, `diagnostics.test.ts`, `diagnosticEapi.test.ts`, `diagnosticReservations.test.ts` (delayed-start/cancellation regressions and visibility)
130
- - Diagnostic persistence: `diagnosticJournal.test.ts` (including child-process crash/lock recovery), `diagnosticPersistence.test.ts` (write-ahead failures and queued-admission failure without invalidating completed work), `eapiCorrelation.test.ts`, `inspectDiagnostics.test.ts` (read-only CLI and concurrent-release snapshot consistency)
125
+ - Diagnostics: `ping.test.ts`, `diagnosticConfig.test.ts`, `diagnostics.test.ts`, `diagnosticEapi.test.ts`, `diagnosticReservations.test.ts` (timed release, cancellation, late responses and visibility)
126
+ - Response correlation: `eapiCorrelation.test.ts`
131
127
  - Server info and errors: `buildServerInfo.test.ts`, `errors.test.ts`, `errorTaxonomy.test.ts`
132
128
  - MCP adapters and stdio: `readToolsMcp.test.ts`, `probeDevicesTool.test.ts`, `listInventoryTool.test.ts`, `mcpStdioSmoke.test.ts`
133
129
  - Package/static policy: `packagePolicy.test.ts`, `packageSmoke.test.ts`
134
130
  - Optional cEOS integration (requires a configured lab): `integration.test.ts`, `pingIntegration.test.ts`, `pingMcpIntegration.test.ts`
135
- - Offline attested release and CLI: `diagnosticRelease.test.ts`, `releaseDiagnosticsCli.test.ts` (synthetic evidence only; no live EOS releases)
136
131
  - Shared test helpers: `test/helpers.ts`
package/docs/DESIGN.md CHANGED
@@ -52,15 +52,15 @@ Read requests have configured per-device timeout, optional overall timeout, devi
52
52
 
53
53
  ### Active diagnostic controls
54
54
 
55
- `eos_ping` uses independent `diagnostics` settings with finite defaults: count 3/max 10, aggregate probes 100 (hosts × destinations × count), 16 destinations per call, server-wide device concurrency 5, reply timeout 1000 ms, command budget 30000 ms, HTTP timeout 35000 ms, and overall timeout 60000 ms. All are configurable; target and response-size limits are shared with reads. Config validation requires consistent counts, execution budgets, and HTTP timeouts.
55
+ `eos_ping` uses independent `diagnostics` settings with finite defaults: count 3/max 10, aggregate probes 100 (hosts × destinations × count), 16 destinations per call, per-server device concurrency 5, reply timeout 1000 ms, command budget 30000 ms, HTTP timeout 35000 ms, and overall timeout 60000 ms. All are configurable; target and response-size limits are shared with reads. Config validation requires consistent counts, execution budgets, and HTTP timeouts.
56
56
 
57
- A ping request names one or more destinations and sends exactly one text-mode eAPI request per host and destination, without automatic retries. Those executions run concurrently under the shared admission controller, each with its own reservation, and return one result per host and destination. Fixed count, one-second interval, fixed size 64, and reply timeout bound device work; the command budget is not a native remote kill timer. HTTP abort is not proof of remote completion. Unknown completion retains its global admission slot indefinitely; elapsed time is never completion evidence. When all capacity is uncertain, new and queued work fail closed with `diagnostic_capacity_uncertain`. Server info exposes current sanitized capacity and reservation state. Production commits reservations before dispatch to a private SQLite ledger and commits confirmed removal before reusing capacity. Unfinished entries restore as uncertain across restarts; only one server may own a ledger. Invalid, mismatched, or missing companion state fails closed. `inspect-diagnostics` provides read-only offline inspection without ownership takeover or device access. Ledger location is configurable as `diagnostics.stateFile`, otherwise derived from the canonical inventory path under the user's state directory. Offline operator-attested release requires independent fencing evidence covering running, accepted queued and replayable work, exact IDs, explicit confirmation and exclusive ownership. Schema-2 audit and deletions commit atomically; inspection is read-only, and neither a reset nor a release is exposed through MCP. Authority is the OS-authorized operator, not automated validation of fencing truth. A qualified native remote deadline remains unresolved; timeout-shaped RPC errors are not assumed to confirm process exit. Cancellation stops scheduling and aborts HTTP requests; overall timeout remains a request-level failure without partial results. See [DIAGNOSTICS.md](DIAGNOSTICS.md) for the full lifecycle assumptions and limits.
57
+ A ping request names one or more destinations and sends exactly one text-mode eAPI request per host and destination, without automatic retries. Those executions run concurrently under the shared admission controller, each with its own reservation, and return one result per host and destination. Fixed count, one-second interval, fixed size 64, and reply timeout bound device work; by default each request also carries EOS `requestTimeout` set to the command budget (`diagnostics.nativeRequestTimeout`), which interrupts execution on the device but does not cover time queued before execution. HTTP abort is not proof of remote completion. Unknown completion holds its admission slot for the command budget, then frees it; a late confirmed response frees it sooner. Capacity is held in memory per server process, so several servers can use one inventory at once ([ADR 0006](adr/0006-in-memory-timed-diagnostic-capacity.md)). Server info exposes current sanitized capacity and reservation state. A qualified native remote deadline remains unresolved; timeout-shaped RPC errors are not assumed to confirm process exit. Cancellation stops scheduling and aborts HTTP requests; overall timeout remains a request-level failure without partial results. See [DIAGNOSTICS.md](DIAGNOSTICS.md) for the full lifecycle assumptions and limits.
58
58
 
59
59
  Only unicast literal destinations are supported; DNS, scoped/link-local IPv6, multicast, unspecified, and limited broadcast addresses are rejected. Optional VRF/source selection must not fall back. Directed-broadcast detection is not guaranteed from an address alone.
60
60
 
61
61
  ## Result and error model
62
62
 
63
- Every eAPI response must identify JSON-RPC 2.0, match its request ID exactly, and contain exactly one result/error member before interpretation. Missing or mismatched identity is `eapi_response_uncorrelated`, not completion evidence. Diagnostic wire IDs are journaled before dispatch and survive uncertain restarts; legacy records without wire IDs are not retroactively correlated. Correlation IDs do not provide an EOS job lookup, cancellation, or idempotency facility.
63
+ Every eAPI response must identify JSON-RPC 2.0, match its request ID exactly, and contain exactly one result/error member before interpretation. Missing or mismatched identity is `eapi_response_uncorrelated`, not completion evidence. Each diagnostic execution's reservation ID is its wire ID. Correlation IDs do not provide an EOS job lookup, cancellation, or idempotency facility.
64
64
 
65
65
  Device-facing tools return target metadata, resolved devices, summary counts, and per-device results. Request-level failures and known device failures use `AppError` machine-readable codes. Supported read tools expose raw eAPI payloads only through an explicit `include_raw` option. Ping separates successful execution from a reachability finding and returns normalized loss/RTT measurements; original EOS text is opt-in. Unrecognized output is an explicit device failure, never an invented finding.
66
66
 
@@ -63,6 +63,7 @@ diagnostics:
63
63
  commandTimeoutMs: 30000
64
64
  httpTimeoutMs: 35000
65
65
  overallOperationTimeoutMs: 60000
66
+ nativeRequestTimeout: true
66
67
  ```
67
68
 
68
69
  | Setting | Meaning |
@@ -71,13 +72,14 @@ diagnostics:
71
72
  | `maxPingCount` | Maximum probes per device and destination |
72
73
  | `maxProbesPerRequest` | Maximum resolved host count × destination count × requested probes |
73
74
  | `maxDestinationsPerRequest` | Maximum destinations in one `eos_ping` call |
74
- | `deviceConcurrency` | Ledger-scoped diagnostic capacity, shared by active and uncertain executions across calls and preserved across server restarts |
75
+ | `deviceConcurrency` | Diagnostic capacity of one server process, shared by its active and uncertain executions across calls |
75
76
  | `pingReplyTimeoutMs` | EOS per-reply timeout; a positive multiple of 1000 ms |
76
77
  | `commandTimeoutMs` | Conservative device execution budget; see lifecycle below |
77
78
  | `httpTimeoutMs` | Per-device diagnostic eAPI HTTP timeout, separate from `readTimeoutMs` |
78
79
  | `overallOperationTimeoutMs` | Whole diagnostic call deadline, including waiting for global capacity |
80
+ | `nativeRequestTimeout` | Send EOS `runCmds.requestTimeout` set to `commandTimeoutMs`, so the device interrupts a ping that outlives its budget; set `false` for an EOS version that rejects the field |
79
81
 
80
- Optional `diagnostics.stateFile` selects the durable SQLite ledger; relative paths resolve beside the settings file. Otherwise, the server uses `$XDG_STATE_HOME/eos-mcp-server/<inventory-identity>/diagnostics.sqlite`, falling back to `~/.local/state` when `XDG_STATE_HOME` is absent or not absolute. The identity hashes the inventory's canonical filesystem path, so symlink aliases share the default ledger. Keep the inventory identity and ledger location stable across restarts. Changing/copying inventory paths or selecting another state file does not migrate prior reservations and must not be used to bypass them.
82
+ Diagnostic capacity is held in memory by each server process; nothing is written to disk. Several MCP servers (for example two chat sessions) can run against the same inventory at once, each with its own `deviceConcurrency`. The former `diagnostics.stateFile` setting is rejected with guidance; delete it. Ledger files left under `$XDG_STATE_HOME/eos-mcp-server/` (or `~/.local/state/eos-mcp-server/`) by earlier versions are no longer read and can be deleted. See [ADR 0006](adr/0006-in-memory-timed-diagnostic-capacity.md).
81
83
 
82
84
  Existing `maxReadTargets` (default 50) and `maxResponseSizeBytes` (default 1,048,576) also apply. Diagnostic concurrency and timeouts are independent of the corresponding read settings. Effective diagnostic settings are reported by `eos_get_server_info` under `limits.diagnostics`.
83
85
 
@@ -91,84 +93,33 @@ The HTTP timeout must exceed the command budget by at least 1000 ms. Individual
91
93
 
92
94
  ## Execution and lifecycle
93
95
 
94
- Each host/destination execution is one text-mode eAPI request containing `enable` followed by the generated ping command. The exact wire request ID is committed as `rpc_request_id` before dispatch. All eAPI responses, including read-tool responses, must use JSON-RPC 2.0, match the exact request ID, and contain exactly one `result` or `error` member. Missing/stale identity fails with `eapi_response_uncorrelated`; contradictory envelopes fail with `eapi_payload_invalid`. Neither is completion evidence, and an unrelated response is never exposed as the requested diagnostic's raw output. There are **no automatic ping retries**, including no JSON-to-text retry. Read-only auto fallback also requires a correlated error and uses a new ID for its subsequent request. Existing `eos_run_show` validation remains show-only.
96
+ Each host/destination execution is one text-mode eAPI request containing `enable` followed by the generated ping command. The reservation ID is used as the exact wire request ID. All eAPI responses, including read-tool responses, must use JSON-RPC 2.0, match the exact request ID, and contain exactly one `result` or `error` member. Missing/stale identity fails with `eapi_response_uncorrelated`; contradictory envelopes fail with `eapi_payload_invalid`. Neither is completion evidence, and an unrelated response is never exposed as the requested diagnostic's raw output. There are **no automatic ping retries**, including no JSON-to-text retry. Read-only auto fallback also requires a correlated error and uses a new ID for its subsequent request. Existing `eos_run_show` validation remains show-only.
95
97
 
96
- On cEOS 4.34.3M, ping's `timeout` maps to a per-reply wait, not a whole-process deadline. The tool combines finite `repeat`, explicit one-second `interval`, and finite reply timeout; the conservative execution formula above must fit `commandTimeoutMs`. This budget is **not** a remote wall-clock kill timer. It assumes normal EOS command scheduling, not a stalled operating system or an indefinitely queued eAPI command. No remote process termination guarantee is made.
98
+ On cEOS 4.34.3M, ping's `timeout` maps to a per-reply wait, not a whole-process deadline. The tool combines finite `repeat`, explicit one-second `interval`, and finite reply timeout; the conservative execution formula above must fit `commandTimeoutMs`. This budget is **not** a remote wall-clock kill timer. It assumes normal EOS command scheduling, not a stalled operating system or an indefinitely queued eAPI command. No remote process termination guarantee is made. The same budget is how long an uncertain slot is held (below).
97
99
 
98
- One admission controller is shared by all diagnostic calls using the server's ledger. The reservation is durably committed **before** the device runner can dispatch. Confirmed synchronous completion or a locally established rejection before dispatch releases capacity only after the removal commits. Unknown completion after transport loss, HTTP timeout, invalid eAPI payload (including correlated results with missing or non-text output), cancellation, or a post-dispatch RPC error becomes **uncertain and never expires automatically**. RPC interruption errors are not process-reaped certificates; even failed commands may conservatively retain capacity. Neither elapsed time nor HTTP abort proves that earlier work stopped or cannot start later. A late confirmed response can release its reservation only while the original owner still has the ledger open; there is no reset exposed through MCP.
99
-
100
- The ledger uses Node's built-in SQLite (Node 24+, potentially marked experimental by the runtime), FULL synchronous commits, and a separate SQLite ownership database. Only one server may own a ledger; another owner fails with `diagnostic_state_in_use`. OS locking releases ownership when a process crashes, without PID-age guessing or deleting a stale lock. All unfinished records, including records persisted as active before a crash, reopen as uncertain. Corrupt, incompatible, inventory-mismatched, or half-missing state is rejected rather than initialized as fresh capacity. A full SQLite integrity check runs before restored capacity is accepted and during offline inspection; malformed indexes must not hide occupied reservations. State write failure blocks further diagnostics with `diagnostic_state_write_failed`; an abort listener does not throw if writing uncertainty fails, because the earlier committed record still preserves the reservation.
100
+ One admission controller is shared by all diagnostic calls in a server process. A slot is reserved **before** the device runner can dispatch. Confirmed synchronous completion or a locally established rejection before dispatch frees it immediately. Unknown completion after transport loss, HTTP timeout, invalid eAPI payload (including correlated results with missing or non-text output), cancellation, or a post-dispatch RPC error becomes **uncertain**: the slot stays held for `commandTimeoutMs` from that moment, then frees itself. A late confirmed response frees it sooner. RPC interruption errors are not treated as proof of completion. Restarting the server forgets uncertain slots; under normal scheduling the original command has finished within `commandTimeoutMs` of dispatch anyway. If EOS ever queued a request for longer than that, replacement work could overlap it; [ADR 0006](adr/0006-in-memory-timed-diagnostic-capacity.md) accepts that bounded risk for ping.
101
101
 
102
102
  A request fans out into one execution per resolved host and destination. Executions run concurrently, up to `deviceConcurrency`, through the same admission controller as every other call; each takes and releases its own reservation exactly as a single ping does. Executions are scheduled host by host, in destination order. Queued executions wait for capacity inside the same overall deadline, so size multi-destination requests so that roughly `ceil(executions / available capacity)` successive waves of pings fit within `overallOperationTimeoutMs`; uncertain reservations reduce available capacity. The device can also limit overlap: on cEOS 4.34.3M, eAPI executed at most three commands concurrently per device, and further delivered requests waited on the device while holding their server reservations. A single-host request therefore gains at most that device's eAPI concurrency, even when more server capacity is free.
103
103
 
104
- The overall deadline or MCP cancellation stops scheduling new executions, removes capacity waiters, and aborts in-flight HTTP work. Every in-flight execution of a cancelled multi-destination request becomes uncertain, so one cancellation can hold up to `deviceConcurrency` slots; queued executions are never dispatched. An overall timeout is a request-level `operation_timeout`, not a partial-results response. Already completed findings are not returned on that path. Do not blindly retry an interrupted diagnostic.
104
+ The overall deadline or MCP cancellation stops scheduling new executions, removes capacity waiters, and aborts in-flight HTTP work. Every in-flight execution of a cancelled multi-destination request becomes uncertain, so one cancellation can hold up to `deviceConcurrency` slots for up to `commandTimeoutMs`; queued executions of that request are never dispatched. An overall timeout is a request-level `operation_timeout`, not a partial-results response. Already completed findings are not returned on that path. Do not blindly retry an interrupted diagnostic.
105
105
 
106
106
  ## Uncertain execution and capacity visibility
107
107
 
108
- `eos_get_server_info` returns a fresh `diagnostics.capacity` snapshot with:
108
+ `eos_get_server_info` returns a fresh `diagnostics.capacity` snapshot for that server process with:
109
109
 
110
- - `scope: "state-file"` for the production durable ledger, `limit`, and `available_count`. A deliberately in-memory executor reports `server-instance`; production can use that mode only when no inventory host has diagnostic permission.
110
+ - `limit` and `available_count`.
111
111
  - `active_count`, `uncertain_count`, and `queued_count`.
112
- - `reservations`: ID, inventory hostname, diagnostic kind, state, reservation timestamp, and (when uncertain) uncertainty timestamp and machine-readable reason code. New reservations also carry `rpc_request_id`, matching the journaled reservation ID and the actual wire ID. Legacy records without this field remain uncorrelated; no wire identity is invented for them. Destinations, endpoints, credentials, and original EOS output are not included.
113
- - `storage_error_code` when journal I/O has failed; new work is blocked even if the numeric limit would otherwise leave space.
112
+ - `reservations`: ID (also the wire RPC ID), inventory hostname, diagnostic kind, state, reservation timestamp, and (when uncertain) uncertainty timestamp, `releases_at`, and machine-readable reason code. Destinations, endpoints, credentials, and original EOS output are not included.
114
113
 
115
- When every slot is uncertain, new requests fail immediately with `diagnostic_capacity_uncertain`. The MCP result has `isError: true` and structured `error_code`/`message`. Work already waiting for capacity is also rejected instead of waiting indefinitely; if uncertainty arises during group execution, those failures use the existing per-device envelope. If some healthy capacity remains, it can still execute diagnostics without freeing uncertain slots.
114
+ Uncertain slots count against `deviceConcurrency` like active ones. New work queues behind them and is dispatched when a slot frees, within the overall deadline; if the deadline expires first the call fails with `operation_timeout`. If some capacity remains, diagnostics keep running without waiting for uncertain slots.
116
115
 
117
116
  The standalone `print-server-info` CLI has no live executor and reports `diagnostics.capacity: null`, not fabricated available capacity. Inspect the running MCP server for actual reservation state.
118
117
 
119
- ### Offline inspection and operator recovery
120
-
121
- ```bash
122
- eos-mcp-server inspect-diagnostics --config eos-mcp-server.yml --json
123
- # Or derive the default ledger from the same inventory identity:
124
- eos-mcp-server inspect-diagnostics --inventory inventory.yml --json
125
- ```
126
-
127
- Inspection opens existing state read-only, including while another server owns it; it does not resolve credentials, contact devices, take over ownership, create a missing ledger, or clear records. Integrity, schema, reservations, and audit are read in one transaction, so a concurrent commit cannot mix before/after release states. A competing writer may fail closed while this short read snapshot is held; inspect current state before retrying an administrative release. Inspection reports recorded state, not proof that remote work completed.
128
-
129
- **Operational constraints:** use a persistent local filesystem that honors SQLite locking and sync, private owner-controlled state files (POSIX mode 0600), and an owner-controlled directory not writable by group/others. Network filesystems and ephemeral/container storage are not qualified durability mechanisms. Preserve the ledger, its `.lock.sqlite` ownership file, and any SQLite recovery files together. Do not delete, replace, copy, rotate, roll back, or change the ledger path to clear reservations. Loss of both ledger files cannot be distinguished locally from first initialization. Before upgrading from the earlier in-memory implementation, unresolved old executions require independent reconciliation; they cannot be recovered from a journal that did not yet exist.
130
-
131
- Restarting with the same ledger retains uncertainty. Recovery is now available only as an **offline, audited Operator Release** backed by a **Fencing Attestation**. There is no MCP reset, release-all operation, native completion-token lookup, or automatic timeout-based release. Stopping the MCP process establishes local ownership transfer, not remote termination.
132
-
133
- #### Operator release workflow
134
-
135
- 1. Stop the server owning this ledger and prevent diagnostic resubmission. The release command refuses a live ledger owner; it does not stop one.
136
- 2. Run `inspect-diagnostics --json` and retain the `inventory_identity`, exact selected reservation IDs, immutable host/admission timestamps, and recorded RPC IDs. Establish the original physical device and execution epoch from independent evidence/history, not just today's inventory mapping.
137
- 3. Independently verify that the fence terminates running work, invalidates **accepted queued** work, and prevents later dispatch/replay. A timeout, empty process list, quiet counters, or repeated observations are insufficient.
138
- 4. Prepare a private JSON attestation from [the deliberately invalid template](examples/diagnostic-release-evidence.template.json). Replace every placeholder with actual evidence. Change each assertion to true only after verification. Do not put credentials, raw packet contents, or EOS output in the file; use evidence references instead.
139
- 5. Release only the exact covered IDs, then inspect the audit:
140
-
141
- ```bash
142
- # Prepare with private permissions; the template cannot authorize a release as-is.
143
- umask 077
144
- cp docs/examples/diagnostic-release-evidence.template.json ./evidence.json
145
- # Human: complete the attestation from independently verified fencing evidence.
146
- chmod 600 ./evidence.json
147
-
148
- eos-mcp-server release-diagnostics --config eos-mcp-server.yml \
149
- --reservation-id '<exact-id>' --evidence-file ./evidence.json \
150
- --confirm-fenced --json
151
- # Repeat --reservation-id only for other IDs covered by the same attestation.
152
- eos-mcp-server inspect-diagnostics --config eos-mcp-server.yml --json
153
- ```
154
-
155
- `--confirm-fenced`, an evidence file, and explicit unique IDs are mandatory. Evidence is private, owner-controlled UTF-8 JSON with unique keys, at most 65536 bytes and 100 explicitly covered reservations. There is no wildcard selection. The command performs no credential resolution, device call, URI fetch, fencing action, or network retry. A state-only config with an explicit `diagnostics.stateFile` can be used if the original inventory is unavailable; the attestation still must match the ledger's stored inventory identity. If config declares an inventory path, its canonical identity must also match.
156
-
157
- The attestation requires `evidence_version: 1`, a new UUID `attestation_id`, the exact `inventory_identity`, an accountable `verified_by`, a past UTC `verified_at`, a reason, and four literal-true assertions: `independent_evidence_verified`, `running_work_terminated`, `accepted_queued_work_cannot_execute`, and `replay_prevented`. Each covered reservation must match its exact ID, host and `reserved_at`, and its exact `rpc_request_id` (explicit JSON null for legacy records without one). It must also identify the physical device, fenced execution epoch, fencing time, and independent evidence reference. Fencing must follow reservation admission and precede verification. The selected CLI IDs and evidence scope must match exactly.
158
-
159
- #### Audit and authority
160
-
161
- The release audit and every selected deletion commit in **one FULL-synchronous SQLite transaction** under exclusive ledger ownership. A failed batch rolls back earlier deletions and its audit; unselected reservations remain held. The append-only-through-the-application audit records original reservation snapshots, the complete attestation, its canonical SHA-256 digest, an audit-content checksum, server recording time, and actual local OS username/UID. `verified_by` is a claimed accountable person, not authenticated identity; the OS account is collected independently. Local operators must be trusted and protected by OS access controls. This is not a cryptographic human-presence check, and an untrusted agent with the ledger owner's filesystem privileges is outside that protection.
162
-
163
- `inspect-diagnostics --json` exposes `release_audit` to local operators; MCP server info does not expose the evidence or audit. Checksums detect accidental inconsistency, not deliberate tampering by the trusted filesystem owner. The program validates consistency and explicit authority; it **cannot establish the truth of external fencing evidence**. Releasing on false attestation can violate remote concurrency safety.
164
-
165
- If CLI completion is lost, inspect the audit first. Repeating the exact committed attestation returns its original release ID with `already_committed: true` and makes no additional changes. Reusing an attestation UUID for changed evidence is rejected. This local administrative idempotency does not make EOS ping requests idempotent; never retry a ping just because its RPC ID is known.
166
-
167
- Ledger schema 1 upgrades atomically to schema 2, preserving unresolved reservations and adding release history. Read-only inspection of schema 1 does not migrate it. A rejected release also rolls back any migration. Schema-2 ledgers with missing or invalid audit history fail closed, and older schema-1-only binaries must not be used to bypass the audit.
168
-
169
118
  ### Native EOS timeout qualification
170
119
 
171
- The installed cEOS implementation exposes a `runCmds.requestTimeout` execution-stage interruption timer. It was accepted in a bounded read request, and a later loopback experiment observed an interruption response after 273 ms with a 250 ms native timer (RPC code 1001 / error 408). No ping process appeared in the subsequent samples. This single normal-load result does not qualify a dispatch-relative or process-exit deadline, nor establish the public support contract. The product does not enable it or treat timeout-shaped RPC errors as completion. No durable token-bound status/cancel method was qualified. See [the primary-source investigation](research/eos-diagnostic-lifecycle.md) for evidence, citations, and limits.
120
+ The installed cEOS implementation exposes a `runCmds.requestTimeout` execution-stage interruption timer. It was accepted in a bounded read request, and a later loopback experiment observed an interruption response after 273 ms with a 250 ms native timer (RPC code 1001 / error 408). No ping process appeared in the subsequent samples. This single normal-load result does not qualify a dispatch-relative or process-exit deadline, nor establish the public support contract.
121
+
122
+ Ping requests now send `requestTimeout` equal to `commandTimeoutMs` (in seconds) by default, so EOS also stops a command that outlives its budget. Re-checked on the cEOS 4.34.3M lab: a 4-probe loopback ping with a 30 s timeout completed normally in about 3.1 s; with 0.25 s EOS returned RPC 1001 / error 408 after 264 ms and no ping process remained on the device. The timer starts only when EOS begins executing the command, so it does not cover time a request spends queued before that. A timeout-shaped RPC error is still treated as unknown completion and holds the slot like any other uncertain execution. Other EOS versions and physical platforms have not been checked; if one rejects the field, every ping fails with an RPC error, and `diagnostics.nativeRequestTimeout: false` turns it off. No durable token-bound status/cancel method was qualified. See [the primary-source investigation](research/eos-diagnostic-lifecycle.md) for evidence, citations, and limits.
172
123
 
173
124
  ## Results
174
125
 
@@ -187,7 +138,7 @@ Execution `status: "success"` means ping executed and its output was understood.
187
138
 
188
139
  Each diagnostic kind supplies a `DiagnosticDefinition`: `prepare` validates the whole request before dispatch and returns the echoed request plus the executions every resolved host performs, `probeCount` prices one execution against the aggregate budget, and `interpret` turns observed output into a finding. The executor runs every prepared execution on every host and knows nothing kind-specific. Ping's definition, validation, compilation, and interpretation live in `src/diagnostics/ping.ts`; it prepares one execution per destination. Multiple destinations are therefore a property of ping's definition, not of the executor.
189
140
 
190
- Admission queueing is separate from reservation creation and state transitions; shutdown, storage failure, and uncertain-capacity exhaustion share queue rejection. A queued admission failure does not invalidate an earlier command whose completion was already committed. The eAPI adapter separates connection validation from dispatch/error handling instead of maintaining a dispatch flag. `DiagnosticExecutionError` carries a typed `not_dispatched`, `completed`, or `unknown` classification; ordinary errors and malformed acknowledgements remain uncertain. Capacity is reusable only after the corresponding durable removal succeeds.
141
+ Admission queueing is separate from reservation state transitions; shutdown rejects queued work with `diagnostic_server_stopping`. The eAPI adapter separates connection validation from dispatch/error handling instead of maintaining a dispatch flag. `DiagnosticExecutionError` carries a typed `not_dispatched`, `completed`, or `unknown` classification; ordinary errors and malformed acknowledgements remain uncertain.
191
142
 
192
143
  The request, observation, and finding types are discriminated by `kind`; only `ping` is implemented. Add other real operations at this seam without exposing arbitrary command strings. A destination-based operation such as traceroute can reuse multi-destination fan-out by preparing one execution per destination, although its much longer execution bound makes large requests hard to fit in the overall deadline. Packet capture needs a separate decision about transport, privilege, visibility, asynchronous lifetime, artifacts, and sensitive data; no capture-session abstractions are fabricated now.
193
144
 
@@ -198,15 +149,13 @@ Validated against the repository's cEOS 4.34.3M lab over HTTPS eAPI:
198
149
  - IPv4/IPv6 loopback, explicit source and default VRF, and measured RTTs.
199
150
  - Explicit one-second pacing, finite repeat count, and reply-timeout behavior.
200
151
  - Group fan-out and 100% packet loss in the MGMT VRF.
201
- - Multi-destination fan-out: six 10-packet pings from one host to its BGP peers completed in 18.6 s (about 56 s when issued as serial calls). A ledger sampler observed five simultaneous active reservations, and direct concurrent eAPI requests confirmed the device ran at most three commands at once.
152
+ - Multi-destination fan-out: six 10-packet pings from one host to its BGP peers completed in 18.6 s (about 56 s when issued as serial calls). A capacity sampler observed five simultaneous active reservations, and direct concurrent eAPI requests confirmed the device ran at most three commands at once.
202
153
  - Invalid VRF and unavailable source fail without fallback.
203
154
  - Overall HTTP cancellation can leave a short-lived device ping; observed processes exited after their finite probe sequence.
204
155
  - MCP stdio execution loads configured defaults and returns real measurements.
205
156
 
206
157
  Older EOS versions and physical platforms have not been qualified for this new tool; the existing read-path minimum does not establish ping compatibility.
207
158
 
208
- The refactor was also checked against synthetic ledgers and release audits written by the pre-refactor code (`0e208ec`): inspection, checksum validation, exact committed retries, legacy absent RPC IDs, and remaining reservations stayed compatible. Audit snapshots use the shared reservation codec, and evidence/audit digests share the same JSON SHA-256 implementation; the serialized formats and schema versions are unchanged.
209
-
210
159
  ```bash
211
160
  npm test
212
161
  npm run typecheck
@@ -215,4 +164,4 @@ npm run build
215
164
  INTEGRATION=1 npm test
216
165
  ```
217
166
 
218
- Integration tests use the isolated `clab/testlab.clab.yaml` lab (admin/admin and lab-only TLS override). The read-path suite now defaults to that topology's unprefixed node names; `EOS_MCP_TEST_PREFIX=clab-testlab-` supports older prefixed deployments. All 13 read-path checks have been run alongside the ping suites, including the EOS code-1003 unconverted-command JSON-to-text read fallback; active ping still never retries. Optional `EOS_PING_TEST_HOST`, `EOS_PING_TEST_HOST_2`, and `EOS_PING_TEST_SILENT_HOST` override its device/silent-destination addresses. Unit tests additionally cover partial loss, input injection, mapped-address restrictions, fail-closed policy, invalid settings, concurrent calls, multi-destination ordering, concurrent destination dispatch, per-destination failure isolation, whole-request destination validation, multi-destination cancellation, uncertain reservations, cancellation, response-size enforcement, write-ahead ordering, blocked dispatch on storage failure, failed completion commits, private permissions, ownership exclusion, malformed/missing ledgers, actual child-process crash recovery, and offline non-mutating inspection. Operator-release tests use synthetic ledger records and synthetic attestations only: they cover exact scope, legacy null IDs, rejected/malformed evidence, private bounded file input, competing ownership, identity/timestamp mismatches, schema migration/rollback, partial deletion rollback, audit integrity and idempotent retry. They do not claim any real EOS execution was fenced or release live test reservations. Additional protocol regressions cover missing/stale IDs, invalid versions, contradictory result/error envelopes, no retry on an uncorrelated read error, persisted wire-ID ordering, and reservation survival across restart after an unrelated acknowledgement. The delayed-backend regression models a request timing out at 35 seconds and starting remotely after the former 65-second expiry: replacement work is now rejected, so modeled active execution stays within the configured ceiling. This is a deterministic fault model, not a claim to have reproduced live EOS queue overload. Live MCP integration also checks timeout-to-uncertain visibility and the structured capacity error before and after restarting with the same ledger.
167
+ Integration tests use the isolated `clab/testlab.clab.yaml` lab (admin/admin and lab-only TLS override). The read-path suite now defaults to that topology's unprefixed node names; `EOS_MCP_TEST_PREFIX=clab-testlab-` supports older prefixed deployments. All 13 read-path checks have been run alongside the ping suites, including the EOS code-1003 unconverted-command JSON-to-text read fallback; active ping still never retries. Optional `EOS_PING_TEST_HOST`, `EOS_PING_TEST_HOST_2`, and `EOS_PING_TEST_SILENT_HOST` override its device/silent-destination addresses. Unit tests additionally cover partial loss, input injection, mapped-address restrictions, fail-closed policy, invalid settings, concurrent calls, multi-destination ordering, concurrent destination dispatch, per-destination failure isolation, whole-request destination validation, multi-destination cancellation, uncertain reservations and their timed release, early release on a late confirmed response, cancellation, and response-size enforcement. Additional protocol regressions cover missing/stale IDs, invalid versions, contradictory result/error envelopes, and no retry on an uncorrelated read error. Live MCP integration checks timeout-to-uncertain visibility and runs a second server against the same inventory while the first holds an uncertain slot.
@@ -12,8 +12,8 @@ The server is a permanent read-only MCP service. Scope includes inventory inspec
12
12
  - Inventory-authoritative host/group target resolution.
13
13
  - HTTPS eAPI client with TLS validation, custom CA support, credential validation, request cancellation, and response-size limits.
14
14
  - Eight MCP tools: server info, inventory, probe, ping, show, logging, facts, and running configuration.
15
- - Typed diagnostic execution with inherited opt-in, configurable budgets/timeouts, global admission, no retries, indefinite uncertain-execution reservations, and live sanitized capacity visibility. Write-ahead durable reservations, crash-safe ownership and offline inspection are implemented. Offline operator-attested release, atomic audit and schema migration are implemented. Machine-verified remote completion/deadline qualification remains follow-up work.
16
- - Local `validate-inventory`, `print-server-info`, `probe`, read-only `inspect-diagnostics`, and offline attested `release-diagnostics` commands.
15
+ - Typed diagnostic execution with inherited opt-in, configurable budgets/timeouts, in-memory per-server admission, no retries, uncertain-execution reservations held for the command budget, and live sanitized capacity visibility. Machine-verified remote completion/deadline qualification remains follow-up work.
16
+ - Local `validate-inventory`, `print-server-info`, and `probe` commands.
17
17
  - Bounded concurrency, target counts, command counts, logging messages, device responses, and aggregate tool responses.
18
18
  - Unit, MCP stdio smoke, package-policy, and optional cEOS integration coverage.
19
19
 
@@ -1,5 +1,7 @@
1
1
  # Retain uncertain diagnostic capacity instead of expiring it
2
2
 
3
+ **Status: superseded by [ADR 0006](0006-in-memory-timed-diagnostic-capacity.md).** Uncertain capacity now frees itself after the execution budget.
4
+
3
5
  Persistence follow-up: [ADR 0003](0003-durable-diagnostic-ledger.md) extends this first slice with a durable ledger; the safety-over-availability decision below remains in force.
4
6
 
5
7
  A finite probe count and reply timeout do not establish when an already-delivered eAPI request will start. Releasing a reservation after a guessed command/HTTP window can therefore admit replacement work while the original command can still execute. Prefer safety over availability: retain unknown-completion reservations without automatic expiry, releasing them only after confirmed completion or definitive rejection before execution. When all capacity is uncertain, reject new and queued diagnostics with `diagnostic_capacity_uncertain`; expose sanitized live reservation metadata through server info rather than suggesting automatic retries or a larger cooldown.
@@ -1,5 +1,7 @@
1
1
  # Preserve diagnostic reservations across restart in a private SQLite ledger
2
2
 
3
+ **Status: superseded by [ADR 0006](0006-in-memory-timed-diagnostic-capacity.md).** The ledger and its ownership lock were removed.
4
+
3
5
  Operator recovery follow-up: [ADR 0004](0004-offline-operator-attested-release.md) adds offline attested release and schema-2 audit; the persistence guarantees below remain in force.
4
6
 
5
7
  In-memory fail-closed reservations are insufficient when an MCP process restarts while EOS work may still run or start later. Production diagnostic execution therefore uses Node's built-in SQLite on private persistent local storage: commit a reservation before dispatch, commit confirmed removal before capacity reuse, and restore unfinished records as uncertain. A separate SQLite ownership database holds an exclusive OS-managed lock for the server lifetime, so process crashes release ownership without guessing from PID or lock age. Prefer one active server per ledger over independent processes silently allocating fresh capacity. Existing state is validated and bound to the canonical inventory identity; corruption, missing companion files, incompatible schemas, and write failures block work rather than recreate empty capacity.
@@ -1,5 +1,7 @@
1
1
  # Allow offline operator-attested release with atomic audit
2
2
 
3
+ **Status: superseded by [ADR 0006](0006-in-memory-timed-diagnostic-capacity.md).** `release-diagnostics` and `inspect-diagnostics` were removed.
4
+
3
5
  EOS completion remains unprovable from silence or an interruption error, but permanently retaining uncertain capacity leaves no operational recovery path. The user explicitly authorized offline operator authority grounded in independently verified fencing of running, accepted queued and replayable work. Permit only exact reservation IDs, matching immutable execution identities, a private bounded attestation file and explicit confirmation, under exclusive ledger ownership. This is not automatic proof of EOS completion, a fencing action, a wildcard clear, or an MCP tool.
4
6
 
5
7
  Commit original reservation snapshots, the attestation, content checksums, recording time and actual OS account in the same FULL-synchronous SQLite transaction as every selected deletion. Keep the claimed verifier distinct from OS identity; neither a field label nor an explicit flag proves human presence. The trusted filesystem owner/OS access policy is the authority, and hashes detect accidental inconsistency rather than malicious owner forgery. Exact committed retries return the prior event without further mutation; changed reuse is rejected. Upgrade schema 1 transactionally to schema 2 so older binaries fail closed rather than ignore operator audit. Read-only inspection does not migrate state. False human evidence can violate remote concurrency safety; the program cannot certify external fencing truth.
@@ -4,6 +4,6 @@ Testing several destinations from the same target, such as every BGP peer of a s
4
4
 
5
5
  Make this a breaking change rather than adding a second tool or an optional alias: one interface serves a single ping (a one-element array) and a sweep, and responses always contain one result per host and destination, each naming its destination. The removed `destination` field is rejected with guidance instead of being silently accepted. `summary` counts host/destination executions; `resolved_devices` still lists hosts.
6
6
 
7
- Keep the safety model of ADRs 0001 to 0004 unchanged. Every execution is admitted, journaled, released, or retained as uncertain exactly like a single ping, under the existing shared `deviceConcurrency`. The whole request is validated before any dispatch, the aggregate probe budget counts hosts × destinations × count, and `maxDestinationsPerRequest` bounds request size. The cost is that one cancelled or timed-out request can now leave up to `deviceConcurrency` uncertain reservations from a single host target, as group targets already could. Large requests must fit the overall deadline in successive waves of available capacity. No up-front feasibility rejection or per-request concurrency cap is added: a conservative bound would reject deliberately short deadlines that existing integration tests and operators use, and a per-request cap would diverge from existing group fan-out.
7
+ Keep the safety model of ADRs 0001 to 0004 unchanged ([ADR 0006](0006-in-memory-timed-diagnostic-capacity.md) later replaced the reservation model of 0002 to 0004). Every execution is admitted, journaled, released, or retained as uncertain exactly like a single ping, under the existing shared `deviceConcurrency`. The whole request is validated before any dispatch, the aggregate probe budget counts hosts × destinations × count, and `maxDestinationsPerRequest` bounds request size. The cost is that one cancelled or timed-out request can now leave up to `deviceConcurrency` uncertain reservations from a single host target, as group targets already could. Large requests must fit the overall deadline in successive waves of available capacity. No up-front feasibility rejection or per-request concurrency cap is added: a conservative bound would reject deliberately short deadlines that existing integration tests and operators use, and a per-request cap would diverge from existing group fan-out.
8
8
 
9
9
  Fan-out across destinations belongs to ping's `DiagnosticDefinition`, which prepares one execution per destination. The executor only runs prepared executions on resolved hosts, so a future destination-based diagnostic can reuse the pattern, and diagnostics without destinations such as packet capture are not forced into it.
@@ -0,0 +1,21 @@
1
+ # Replace the durable diagnostic ledger with in-memory, time-bounded capacity
2
+
3
+ Supersedes [ADR 0002](0002-fail-closed-diagnostic-reservations.md), [ADR 0003](0003-durable-diagnostic-ledger.md) and [ADR 0004](0004-offline-operator-attested-release.md). [ADR 0001](0001-non-configuring-diagnostics.md) and [ADR 0005](0005-multi-destination-ping.md) stay in force.
4
+
5
+ ADRs 0002 to 0004 held an execution's slot forever when its completion was unknown, because a delivered eAPI request might in principle sit in an EOS queue and start later. Holding slots forever then required a durable SQLite ledger so restarts could not reset them, an exclusive ownership lock so a second process could not allocate fresh capacity, and an offline operator attestation and audit workflow to recover stuck slots. The exclusive lock was taken at server start whenever any host allowed diagnostics, so only one MCP server per inventory could run. A second chat session, or the desktop app alongside a Code session, failed to start at all, losing every read-only tool as well as `eos_ping`.
6
+
7
+ That machinery guarded a failure mode the project never observed: the lifecycle investigation reports that no delayed-queue fault was reproduced. Being wrong about it costs little. A ping execution is capped at `maxPingCount` 64-byte probes at one-second pacing, changes no configuration, and cEOS ran at most three eAPI commands concurrently per device regardless of server capacity. Against that, the design cost every user concurrent sessions, could permanently remove capacity after one timeout, and required a human attestation to recover.
8
+
9
+ Capacity is now per server process and in memory. A confirmed completion or a rejection established before dispatch frees its slot at once. An execution whose completion is unknown (transport loss, HTTP timeout, malformed or uncorrelated response, cancellation, or a post-dispatch RPC error) keeps its slot as **uncertain** for `commandTimeoutMs`, the configured worst-case execution budget, measured from the moment it became uncertain. The slot then frees itself; a late confirmed response frees it sooner. Uncertain slots count against `deviceConcurrency` like active ones, so new work queues behind them within the overall deadline instead of failing with a dedicated error.
10
+
11
+ Accepted consequences:
12
+
13
+ - `deviceConcurrency` limits one server process, not an inventory. N concurrent sessions can run up to N × `deviceConcurrency` pings. The per-request limits (`maxPingCount`, `maxProbesPerRequest`, `maxDestinationsPerRequest`) and the device's own eAPI concurrency still bound load.
14
+ - A restart forgets uncertain slots. Under normal EOS scheduling the original command has finished within `commandTimeoutMs` of dispatch anyway.
15
+ - If EOS did queue a request for longer than the hold, replacement work could overlap it. This is the risk ADR 0002 refused; it is now accepted as bounded and low-impact for ping.
16
+
17
+ Removed: the SQLite ledger and its ownership lock, `diagnostics.stateFile`, the `inspect-diagnostics` and `release-diagnostics` commands, fencing attestations and release audit, the `diagnostic_capacity_uncertain` and `diagnostic_state_*` error codes, and the `scope`, `storage_error_code` and `rpc_request_id` fields of the capacity snapshot (`reservation_id` is the wire RPC ID). Existing ledger files under `$XDG_STATE_HOME/eos-mcp-server/` are no longer read and can be deleted. JSON-RPC response correlation, write-ahead classification of dispatch state, and the no-automatic-retry rule are unchanged.
18
+
19
+ Ping requests also send EOS's native `runCmds.requestTimeout`, set to `commandTimeoutMs`, so the device interrupts a command that outlives the same budget the server holds an uncertain slot for. It is on by default and can be disabled with `diagnostics.nativeRequestTimeout: false` for an EOS version that rejects the field. It covers execution only, not time queued before execution, and its timeout error is still treated as unknown completion.
20
+
21
+ Revisit this if a diagnostic with real side effects or long remote lifetimes is added, such as packet capture. That operation should get its own lifecycle decision rather than inheriting ping's.
@@ -1,5 +1,7 @@
1
1
  # EOS HTTPS eAPI diagnostic lifecycle
2
2
 
3
+ > Historical investigation. [ADR 0006](../adr/0006-in-memory-timed-diagnostic-capacity.md) later chose to hold uncertain capacity for the command budget instead of indefinitely, accepting the unreproduced delayed-queue risk described here.
4
+
3
5
  ## Conclusion
4
6
 
5
7
  **No dispatch-relative deadline, durable execution-token lifecycle, or definitive cancellation guarantee was qualified for ping.** However, EOS **does expose a native `runCmds.requestTimeout`**: saying eAPI has only a client-side timeout would be incorrect. Its installed implementation is an execution-stage interruption timer, not a verified admission-to-process-exit bound. Losing HTTP completion evidence must therefore remain an uncertain reservation, not become free capacity after a cooldown.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aristanetworks/eos-mcp-server",
3
- "version": "0.8.0-beta",
3
+ "version": "0.8.1-beta",
4
4
  "description": "MCP server for Arista EOS eAPI",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -1,3 +0,0 @@
1
- import type { ResolvedServerConfig } from "../config/schema.js";
2
- /** Offline/read-only: no credentials, device calls, ownership takeover, or capacity reset. */
3
- export declare function runInspectDiagnostics(config: ResolvedServerConfig, asJson: boolean): Promise<number>;
@@ -1,35 +0,0 @@
1
- import path from "node:path";
2
- import { toErrorCode, toErrorMessage } from "../core/errors.js";
3
- import { resolveDiagnosticStateFile } from "../diagnostics/statePath.js";
4
- import { prettyJson } from "../utils/json.js";
5
- /** Offline/read-only: no credentials, device calls, ownership takeover, or capacity reset. */
6
- export async function runInspectDiagnostics(config, asJson) {
7
- try {
8
- const file = resolveDiagnosticStateFile(config);
9
- const { inspectDiagnosticJournal } = await import("../diagnostics/journal.js");
10
- const state = inspectDiagnosticJournal(file);
11
- const output = { state_file: path.basename(file), schema_version: state.schema_version, inventory_identity: state.inventory_identity,
12
- unresolved_count: state.reservations.length, reservations: state.reservations, release_audit: state.release_audit };
13
- if (asJson) {
14
- console.log(prettyJson(output));
15
- }
16
- else {
17
- console.log(`Diagnostic ledger: ${output.state_file}`);
18
- console.log(`Inventory identity: ${output.inventory_identity}`);
19
- console.log(`Unresolved reservations: ${output.unresolved_count}`);
20
- for (const reservation of output.reservations) {
21
- console.log(`- ${reservation.reservation_id}: ${reservation.inventory_hostname} recorded ${reservation.state}${reservation.reason_code === undefined ? "" : ` (${reservation.reason_code})`}; RPC ID: ${reservation.rpc_request_id ?? "(not recorded)"}`);
22
- }
23
- console.log(`Operator release audit records: ${output.release_audit.length} (use --json for evidence and OS identity)`);
24
- console.log("Recorded state is not proof of remote completion. No reservation was cleared.");
25
- }
26
- return 0;
27
- }
28
- catch (error) {
29
- if (!asJson)
30
- throw error;
31
- console.log(prettyJson({ error_code: toErrorCode(error, "diagnostic_state_invalid"), message: toErrorMessage(error) }));
32
- return 1;
33
- }
34
- }
35
- //# sourceMappingURL=inspectDiagnostics.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"inspectDiagnostics.js","sourceRoot":"","sources":["../../src/commands/inspectDiagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,8FAA8F;AAC9F,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,MAA4B,EAAE,MAAe;IACvF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,0BAA0B,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,EAAE,wBAAwB,EAAE,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;QAC/E,MAAM,KAAK,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,cAAc,EAAE,KAAK,CAAC,cAAc,EAAE,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;YAClI,gBAAgB,EAAE,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC;QACtH,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,sBAAsB,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACvD,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC;YAChE,OAAO,CAAC,GAAG,CAAC,4BAA4B,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;YACnE,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;gBAC9C,OAAO,CAAC,GAAG,CAAC,KAAK,WAAW,CAAC,cAAc,KAAK,WAAW,CAAC,kBAAkB,aAAa,WAAW,CAAC,KAAK,GAAG,WAAW,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,WAAW,GAAG,aAAa,WAAW,CAAC,cAAc,IAAI,gBAAgB,EAAE,CAAC,CAAC;YAC5P,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,mCAAmC,MAAM,CAAC,aAAa,CAAC,MAAM,4CAA4C,CAAC,CAAC;YACxH,OAAO,CAAC,GAAG,CAAC,+EAA+E,CAAC,CAAC;QAC/F,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,MAAM;YAAE,MAAM,KAAK,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC,KAAK,EAAE,0BAA0B,CAAC,EAAE,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QACxH,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
@@ -1,9 +0,0 @@
1
- import type { ResolvedServerConfig } from "../config/schema.js";
2
- export interface ReleaseDiagnosticsOptions {
3
- reservationIds?: string[];
4
- evidenceFile?: string;
5
- confirmFenced?: boolean;
6
- json?: boolean;
7
- }
8
- /** Offline operator authority: no credentials, device calls, evidence fetching, or MCP reset. */
9
- export declare function runReleaseDiagnostics(config: ResolvedServerConfig, options: ReleaseDiagnosticsOptions): Promise<number>;