vmware-debug 1.11.4__tar.gz → 1.12.1__tar.gz
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.
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/.claude-plugin/plugin.json +1 -1
- vmware_debug-1.12.1/.clawhubignore +19 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/.mcp.json +1 -1
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/PKG-INFO +2 -2
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/RELEASE_NOTES.md +44 -0
- vmware_debug-1.12.1/openclaw.plugin.json +24 -0
- vmware_debug-1.12.1/package.json +20 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/pyproject.toml +2 -2
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/server.json +2 -2
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/skills/vmware-debug/SKILL.md +1 -1
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/skills/vmware-debug/references/capabilities.md +7 -1
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/skills/vmware-debug/references/routing.md +5 -2
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/skills/vmware-debug/references/setup-guide.md +2 -2
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_classification_against_vsphere_vocabulary.py +7 -0
- vmware_debug-1.12.1/tests/eval/regression/test_real_alert_titles_classify.py +153 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/uv.lock +5 -5
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/__init__.py +1 -1
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/cli.py +5 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/mcp_server/server.py +4 -2
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/timeline.py +31 -1
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/rules/evidence_sources.yaml +62 -2
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/.gitignore +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/README-CN.md +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/README.md +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/SECURITY.md +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/docs/plans/2026-08-28-investigation-layer-design.md +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/skills/vmware-debug/references/agent-guardrails.md +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/skills/vmware-debug/references/cli-reference.md +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/skills/vmware-debug/references/event-envelope.md +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/__init__.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/conftest.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/__init__.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/__init__.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/_family.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/_scores.json +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/_scoring.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/_skill.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/conftest.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/test_entity_reachability.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/test_error_actionability.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/test_tool_description_quality.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/test_tool_manifest_budget.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/__init__.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/_vsphere_event_vocabulary.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_audit_isolation.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_capability_grader.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_case_id_non_ascii.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_case_plan_max_steps.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_debug_regressions.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_environment_resolver_isolation.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_every_tool_parameter_is_documented.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_evidence_payload_contract.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_host_lifecycle_classification.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_investigation_metrics.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_result_envelope.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_skill_name_aliases.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_spike_resolution.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_tool_annotations.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_case_conclusion.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_case_evidence.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_case_grading.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_case_hypotheses.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_case_ids.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_case_ledger_concurrency.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_case_plan.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_case_readiness.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_case_store.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_case_timeline_close.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_case_tools.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_knowledge.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_safe_error_passthrough.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/test_timeline.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/envelope.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/mcp/__init__.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/mcp/tools.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/mcp_server/__init__.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/__init__.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/__init__.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/api.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/conclusion.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/evidence.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/grading.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/hypotheses.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/ids.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/knowledge.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/model.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/payloads.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/plan.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/readiness.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/sources.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/store.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/cases/timeline.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/ops/skill_names.py +0 -0
- {vmware_debug-1.11.4 → vmware_debug-1.12.1}/vmware_debug/rules/grading_rules.yaml +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
|
|
3
3
|
"name": "vmware-debug",
|
|
4
4
|
"displayName": "VMware Debug",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.12.1",
|
|
6
6
|
"description": "VMware incident timeline, root-cause routing, local case ledger; no vSphere access. 14 MCP tools.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Wei Zhou",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# What `clawhub package publish` uploads from this folder.
|
|
2
|
+
#
|
|
3
|
+
# The CLI does not read .gitignore — only this file. Without it, publishing from
|
|
4
|
+
# the repo root uploads everything on disk: .venv/, dist/, and any untracked
|
|
5
|
+
# credential file (mcp-publisher leaves .mcpregistry_*_token here). So this is an
|
|
6
|
+
# allowlist: ignore every top-level entry, then re-include only the plugin.
|
|
7
|
+
/*
|
|
8
|
+
!/openclaw.plugin.json
|
|
9
|
+
!/package.json
|
|
10
|
+
!/.claude-plugin/
|
|
11
|
+
!/.mcp.json
|
|
12
|
+
!/skills/
|
|
13
|
+
!/README.md
|
|
14
|
+
!/LICENSE
|
|
15
|
+
|
|
16
|
+
# Never ship these even inside an allowed directory.
|
|
17
|
+
.DS_Store
|
|
18
|
+
__pycache__/
|
|
19
|
+
*.pyc
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: vmware-debug
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.12.1
|
|
4
4
|
Summary: VMware diagnostic brain — offline incident triage, log/event correlation, and root-cause routing across the VMware skill family
|
|
5
5
|
Project-URL: Homepage, https://github.com/vmware-skills/VMware-Debug
|
|
6
6
|
Project-URL: Repository, https://github.com/vmware-skills/VMware-Debug
|
|
@@ -18,7 +18,7 @@ Requires-Dist: mcp[cli]<2.0,>=1.10
|
|
|
18
18
|
Requires-Dist: pyyaml<7.0,>=6.0
|
|
19
19
|
Requires-Dist: rich<15.0,>=13.0
|
|
20
20
|
Requires-Dist: typer<1.0,>=0.12
|
|
21
|
-
Requires-Dist: vmware-policy<2.0,>=1.
|
|
21
|
+
Requires-Dist: vmware-policy<2.0,>=1.15.0
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
23
|
|
|
24
24
|
<!-- mcp-name: io.github.vmware-skills/vmware-debug -->
|
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
## v1.12.1 — every CLI command declares what it reaches
|
|
2
|
+
|
|
3
|
+
Across the family, CLI reads never wrote `~/.vmware/audit.db`; they now do (`@audited`, under the
|
|
4
|
+
MCP tool's name). To keep that from regressing, every CLI command must declare `@guarded` (a write),
|
|
5
|
+
`@audited` (reaches a remote system) or `@cli_local` (reaches nothing remote), and a family gate fails
|
|
6
|
+
any command that declares none.
|
|
7
|
+
|
|
8
|
+
This skill's 4 CLI commands reach nothing remote; each is marked `@cli_local` with its reason.
|
|
9
|
+
Their behaviour does not change.
|
|
10
|
+
|
|
11
|
+
Requires `vmware-policy>=1.15.0`.
|
|
12
|
+
|
|
13
|
+
## v1.12.0 — real alert titles get a category
|
|
14
|
+
|
|
15
|
+
Eight alerts read off a lab vCenter 8.0.3 and Aria 8.18.7 were passed through `triage`, and six
|
|
16
|
+
came back `uncategorized`; the top hypothesis was "uncategorized" itself. Five of them were not odd
|
|
17
|
+
spellings of subsystems the taxonomy already had — they were subsystems it had no category for:
|
|
18
|
+
|
|
19
|
+
* **`hardware`** (tpm, attestation, ipmi, sensor, bmc) — "Host TPM attestation alarm". The catalogue
|
|
20
|
+
already routed `hardware`, but the classifier could never emit it. Its plan now asks vmware-monitor
|
|
21
|
+
for the host sensors and the CIM Server state that supplies them (new `host_hardware` class).
|
|
22
|
+
* **`licensing`** (license) — "License will soon expire", "Expired vCenter Server license". Routes to
|
|
23
|
+
vmware-monitor `license_status` (which asset holds which key). An Aria alert about a vCenter license
|
|
24
|
+
is built from vCenter's data, so it is not counted as a second source: licensing stays at Candidate.
|
|
25
|
+
* **`data_collection`** (adapter instance, not receiving data, collector group, cloud proxy) — "Objects
|
|
26
|
+
are not receiving data from adapter instance". Routes to Aria's adapters, collector groups, node
|
|
27
|
+
health and resources, plus vmware-monitor for whether the source vCenter is reachable. Not a bare
|
|
28
|
+
"collector": vCenter's own services are named that way ("ESXi Dump Collector service") and stay
|
|
29
|
+
under `platform`.
|
|
30
|
+
* **`auth`** now reads "password" — "Root user password expired".
|
|
31
|
+
|
|
32
|
+
Seven of the eight now classify. "Group population health is degraded" stays uncategorized on purpose:
|
|
33
|
+
it is a roll-up of member health and names no subsystem. Against all 427 vSphere event types the
|
|
34
|
+
taxonomy now reads 140 (was 124): 14 licensing and 2 password events, and no type changed its first
|
|
35
|
+
category. The keyword table is at 100, the cap its padding test allows — the next category will have
|
|
36
|
+
to argue for moving it.
|
|
37
|
+
|
|
38
|
+
**`case_readiness` recognises vmware-aiops.** It used to land in `unrecognised_skills` although routing
|
|
39
|
+
sent power_lifecycle cases to it. A new `vm_operations` class lists `vm_list_snapshots` only. AIops's
|
|
40
|
+
cluster summary and investigation bundles call vmware-monitor's code and would have counted monitor's
|
|
41
|
+
data as a second source; `vm_task_status` needs a task id a plan does not have, and called with a VM
|
|
42
|
+
name it answers "gone" with no error. With monitor and aiops, power_lifecycle now reaches Probable;
|
|
43
|
+
data_collection reaches Probable with monitor and aria.
|
|
44
|
+
|
|
1
45
|
## v1.11.4 — concurrent writers stop losing case entries
|
|
2
46
|
|
|
3
47
|
Two agents on one case — a supported setup, since `OPS_HOME` can point at a shared folder — lost
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "vmware-debug",
|
|
3
|
+
"name": "VMware Debug",
|
|
4
|
+
"description": "VMware incident timeline, root-cause routing, local case ledger; no vSphere access. 14 MCP tools.",
|
|
5
|
+
"skills": [
|
|
6
|
+
"./skills"
|
|
7
|
+
],
|
|
8
|
+
"mcpServers": {
|
|
9
|
+
"vmware-debug": {
|
|
10
|
+
"transport": "stdio",
|
|
11
|
+
"command": "uvx",
|
|
12
|
+
"args": [
|
|
13
|
+
"--from",
|
|
14
|
+
"vmware-debug==1.12.1",
|
|
15
|
+
"vmware-debug-mcp"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"configSchema": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"additionalProperties": false,
|
|
22
|
+
"properties": {}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zw008/vmware-debug",
|
|
3
|
+
"version": "1.12.1",
|
|
4
|
+
"description": "VMware incident timeline, root-cause routing, local case ledger; no vSphere access. 14 MCP tools.",
|
|
5
|
+
"private": true,
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/vmware-skills/VMware-Debug",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/vmware-skills/VMware-Debug.git"
|
|
11
|
+
},
|
|
12
|
+
"openclaw": {
|
|
13
|
+
"compat": {
|
|
14
|
+
"pluginApi": ">=2026.3.24-beta.2"
|
|
15
|
+
},
|
|
16
|
+
"build": {
|
|
17
|
+
"openclawVersion": "2026.3.24-beta.2"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "vmware-debug"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.12.1"
|
|
8
8
|
description = "VMware diagnostic brain — offline incident triage, log/event correlation, and root-cause routing across the VMware skill family"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -21,7 +21,7 @@ dependencies = [
|
|
|
21
21
|
"typer>=0.12,<1.0",
|
|
22
22
|
"rich>=13.0,<15.0",
|
|
23
23
|
"mcp[cli]>=1.10,<2.0",
|
|
24
|
-
"vmware-policy>=1.
|
|
24
|
+
"vmware-policy>=1.15.0,<2.0",
|
|
25
25
|
# Imported directly by ops/cases/grading.py for the rules file. It has
|
|
26
26
|
# always arrived transitively via vmware-policy; a package should
|
|
27
27
|
# declare what it imports rather than rely on a dependency's dependency.
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"url": "https://github.com/vmware-skills/VMware-Debug",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "1.
|
|
10
|
+
"version": "1.12.1",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "pypi",
|
|
14
14
|
"identifier": "vmware-debug",
|
|
15
|
-
"version": "1.
|
|
15
|
+
"version": "1.12.1",
|
|
16
16
|
"runtimeHint": "uvx",
|
|
17
17
|
"packageArguments": [
|
|
18
18
|
{
|
|
@@ -31,9 +31,15 @@ fixed in-process constant, so `total` is a real count and `limit` is `null`.
|
|
|
31
31
|
## Symptom categories
|
|
32
32
|
|
|
33
33
|
`storage`, `network`, `compute`, `ha_drs`, `host_lifecycle`, `power_lifecycle`,
|
|
34
|
-
`auth`, `platform`.
|
|
34
|
+
`auth`, `platform`, `hardware`, `licensing`, `data_collection`.
|
|
35
35
|
See `references/routing.md` for keyword signatures and the skill each routes to.
|
|
36
36
|
|
|
37
|
+
`hardware`, `licensing` and `data_collection` were added after real alert titles
|
|
38
|
+
("Host TPM attestation alarm", "License will soon expire", "Objects are not
|
|
39
|
+
receiving data from adapter instance") matched no category at all. A roll-up
|
|
40
|
+
such as "Group population health is degraded" is deliberately left
|
|
41
|
+
uncategorized: it names no subsystem, and the cause is in one of its members.
|
|
42
|
+
|
|
37
43
|
`host_lifecycle` is a host changing its own availability state — maintenance
|
|
38
44
|
mode, shutdown, reboot, standby, connection loss, sync failure.
|
|
39
45
|
`power_lifecycle` is the VM-level equivalent. They are separate because they are
|
|
@@ -11,9 +11,12 @@ Keep this in sync with `_CATEGORY_SIGNATURES` in `vmware_debug/ops/timeline.py`
|
|
|
11
11
|
| **compute** | cpu ready, memory, balloon, swap, contention, numa | vmware-aria (metrics + anomalies) | pilot (rightsizing) |
|
|
12
12
|
| **ha_drs** | ha, high availability, drs, failover, admission control, isolation | vmware-monitor, vmware-aiops (cluster) | pilot |
|
|
13
13
|
| **host_lifecycle** | maintenance mode, shut down of, host reboot, standby mode, lost connection to, cannot synchronize, not responding | vmware-monitor (host/cluster state), vmware-harden (drift — a host that left service on cue was told to), vmware-log-insight (vpxd/hostd) | pilot |
|
|
14
|
-
| **power_lifecycle** | power on/off, failed to start, boot, vmx, ovf, clone, snapshot | vmware-aiops (
|
|
15
|
-
| **auth** | login, authentication, denied, 401, 403, token, certificate, tls | config/.env, target cert + time sync | config fix |
|
|
14
|
+
| **power_lifecycle** | power on/off, failed to start, boot, vmx, ovf, clone, snapshot | vmware-aiops (snapshot tree), vmware-monitor | aiops |
|
|
15
|
+
| **auth** | login, authentication, denied, 401, 403, token, certificate, tls, password | config/.env, target cert + time sync | config fix |
|
|
16
16
|
| **platform** | vpxd, hostd, service restart, crash, 503, not responding, disconnected | vmware-monitor (connection/service), vmware-log-insight (vpxd/hostd) | pilot |
|
|
17
|
+
| **hardware** | tpm, attestation, ipmi, sensor, bmc | vmware-monitor (host sensors and the CIM Server that supplies them, host logs for ipmi/cim), the server's BMC | site / vendor |
|
|
18
|
+
| **licensing** | license | vmware-monitor (license_status — which asset holds which key); an Aria alert on "Unlicensed Group" is Aria's own license | license portal |
|
|
19
|
+
| **data_collection** | adapter instance, not receiving data, collector group, cloud proxy | vmware-aria (adapters, collector groups, node health, objects that stopped reporting), vmware-monitor (is the source vCenter reachable) | aria admin |
|
|
17
20
|
|
|
18
21
|
## Remediation handoff (advisor → executor)
|
|
19
22
|
|
|
@@ -6,7 +6,7 @@ is a pure, offline correlation engine. There is no `config.yaml` and no `.env`.
|
|
|
6
6
|
## Install
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
|
-
uv tool install vmware-debug==1.
|
|
9
|
+
uv tool install vmware-debug==1.12.1
|
|
10
10
|
vmware-debug categories # verify it runs
|
|
11
11
|
```
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ vmware-debug categories # verify it runs
|
|
|
15
15
|
```json
|
|
16
16
|
{
|
|
17
17
|
"command": "uvx",
|
|
18
|
-
"args": ["--from", "vmware-debug==1.
|
|
18
|
+
"args": ["--from", "vmware-debug==1.12.1", "vmware-debug-mcp"]
|
|
19
19
|
}
|
|
20
20
|
```
|
|
21
21
|
|
|
@@ -50,6 +50,13 @@ So the change this file guards is not a bigger vocabulary. It is:
|
|
|
50
50
|
know" and to go find that subsystem's read tools. For ``VmPoweredOnEvent``
|
|
51
51
|
that is a wasted round trip after a false premise.
|
|
52
52
|
|
|
53
|
+
**Re-measured 2026-09-15: reads 140, misses 287.** The 16 newly read types are
|
|
54
|
+
the exception the paragraph above does not cover — 14 are licensing events
|
|
55
|
+
(``LicenseExpiredEvent`` and its family) and 2 are password events, and licensing
|
|
56
|
+
*was* a subsystem the taxonomy lacked. The category was added because real lab
|
|
57
|
+
alert titles needed it (``test_real_alert_titles_classify``), not to move this
|
|
58
|
+
number; the claim about the rest of the residue still holds.
|
|
59
|
+
|
|
53
60
|
The numbers below are recorded, not required. If someone later raises coverage by
|
|
54
61
|
padding ``_CATEGORY_SIGNATURES``, ``test_the_taxonomy_was_not_quietly_padded``
|
|
55
62
|
fails and says so, because a coverage figure that goes up without an explanation
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Alert titles from a real estate, and what the taxonomy made of them.
|
|
2
|
+
|
|
3
|
+
On 2026-09-14 eight alerts were read off the lab vCenter 8.0.3 and Aria 8.18.7
|
|
4
|
+
and passed through ``triage``. Six came back ``uncategorized`` and the top
|
|
5
|
+
hypothesis was "uncategorized" itself. Unlike the residue measured in
|
|
6
|
+
``test_classification_against_vsphere_vocabulary`` — events whose subsystem the
|
|
7
|
+
taxonomy already had, spelled differently — these named subsystems it had no
|
|
8
|
+
category for at all:
|
|
9
|
+
|
|
10
|
+
Root user password expired credential lifecycle; auth read only
|
|
11
|
+
login/token/certificate words
|
|
12
|
+
License will soon expire licensing — no category
|
|
13
|
+
Expired vCenter Server license licensing — no category
|
|
14
|
+
Host TPM attestation alarm hardware — routed in the catalogue,
|
|
15
|
+
but the classifier could never emit it
|
|
16
|
+
Objects are not receiving data the monitoring pipeline itself — no
|
|
17
|
+
from adapter instance category
|
|
18
|
+
|
|
19
|
+
So the change is new categories with their own routing, not more synonyms for
|
|
20
|
+
the old ones. One title stays unread on purpose, and is pinned below.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import pytest
|
|
26
|
+
|
|
27
|
+
from vmware_debug.envelope import normalize_event
|
|
28
|
+
from vmware_debug.ops.cases.readiness import readiness
|
|
29
|
+
from vmware_debug.ops.cases.sources import load_catalogue
|
|
30
|
+
from vmware_debug.ops.timeline import classification_coverage, classify_symptom
|
|
31
|
+
|
|
32
|
+
#: (alert title, source, the category it has to land in first)
|
|
33
|
+
LAB_ALERTS = (
|
|
34
|
+
("Root user password expired", "monitor", "auth"),
|
|
35
|
+
("License will soon expire", "aria", "licensing"),
|
|
36
|
+
("Expired vCenter Server license", "monitor", "licensing"),
|
|
37
|
+
("Host TPM attestation alarm", "monitor", "hardware"),
|
|
38
|
+
("Objects are not receiving data from adapter instance", "aria", "data_collection"),
|
|
39
|
+
("vCenter appliance health service is down", "aria", "platform"),
|
|
40
|
+
("Host connection and power state", "monitor", "host_lifecycle"),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
#: A roll-up of its members' health. It names no subsystem: whatever is wrong is
|
|
44
|
+
#: wrong with one of the members, and any category given to the title would be
|
|
45
|
+
#: a guess dressed as a routing decision.
|
|
46
|
+
ROLLUP_ALERT = "Group population health is degraded"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _event(title: str, source: str) -> object:
|
|
50
|
+
return normalize_event(
|
|
51
|
+
{"ts": "2026-09-14T08:00:00Z", "source": source, "severity": "warning", "text": title}
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@pytest.mark.parametrize(("title", "source", "category"), LAB_ALERTS)
|
|
56
|
+
def test_each_lab_alert_lands_in_its_category_first(title, source, category):
|
|
57
|
+
event = _event(title, source)
|
|
58
|
+
found = classify_symptom(event.text, event.entity, event.fields)
|
|
59
|
+
assert found and found[0] == category, f"{title!r} -> {found}"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_the_population_rollup_stays_unread():
|
|
63
|
+
"""Pinned so a later keyword does not quietly start routing it somewhere."""
|
|
64
|
+
assert classify_symptom(ROLLUP_ALERT) == []
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_the_lab_stream_is_now_mostly_readable():
|
|
68
|
+
events = [_event(t, s) for t, s, _c in LAB_ALERTS] + [_event(ROLLUP_ALERT, "aria")]
|
|
69
|
+
coverage = classification_coverage(events)
|
|
70
|
+
assert coverage["uncategorized"] == 1
|
|
71
|
+
assert coverage["unmatched_samples"] == [ROLLUP_ALERT]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@pytest.mark.parametrize(
|
|
75
|
+
("text", "category"),
|
|
76
|
+
[
|
|
77
|
+
# Each contains a word the new categories added, and was already about
|
|
78
|
+
# something else. A bare "collector" took the first two from platform.
|
|
79
|
+
("The ESXi Dump Collector service is not running on vcsa01", "platform"),
|
|
80
|
+
("vCenter Server Syslog Collector service stopped", "platform"),
|
|
81
|
+
("vSAN license expired for datastore vsan-01", "storage"),
|
|
82
|
+
("Password for user root@192.168.60.10 denied: authentication failed", "auth"),
|
|
83
|
+
],
|
|
84
|
+
)
|
|
85
|
+
def test_a_new_category_does_not_steal_an_existing_match(text, category):
|
|
86
|
+
assert classify_symptom(text)[0] == category, classify_symptom(text)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class TestReadiness:
|
|
90
|
+
def test_aiops_is_a_recognised_skill(self):
|
|
91
|
+
"""It used to land in unrecognised_skills while routing pointed
|
|
92
|
+
power_lifecycle cases at it."""
|
|
93
|
+
out = readiness(["vmware-monitor", "vmware-aiops"])
|
|
94
|
+
assert out["unrecognised_skills"] == []
|
|
95
|
+
|
|
96
|
+
def test_aiops_lifts_power_lifecycle_to_probable(self):
|
|
97
|
+
without = readiness(["vmware-monitor"])["categories"]["power_lifecycle"]
|
|
98
|
+
with_aiops = readiness(["vmware-monitor", "vmware-aiops"])["categories"]["power_lifecycle"]
|
|
99
|
+
assert without["ceiling"] == "candidate"
|
|
100
|
+
assert with_aiops["ceiling"] == "probable"
|
|
101
|
+
assert with_aiops["independent_sources"] == ["vmware-aiops", "vmware-monitor"]
|
|
102
|
+
|
|
103
|
+
def test_aiops_classes_name_only_reads_aiops_does_itself(self):
|
|
104
|
+
"""AIops's cluster summary and investigation bundles call vmware-monitor's
|
|
105
|
+
code. Listed under aiops they would be monitor's data counted as a second
|
|
106
|
+
source — a Probable bought with one source under two names."""
|
|
107
|
+
delegated = {
|
|
108
|
+
"cluster_health_summary",
|
|
109
|
+
"cross_vcenter_attention",
|
|
110
|
+
"vm_investigation_bundle",
|
|
111
|
+
"host_investigation_bundle",
|
|
112
|
+
"datastore_investigation_bundle",
|
|
113
|
+
}
|
|
114
|
+
for name, spec in load_catalogue()["classes"].items():
|
|
115
|
+
if spec.get("skill") == "vmware-aiops":
|
|
116
|
+
tools = {e["tool"] for e in spec["tools"]}
|
|
117
|
+
assert not tools & delegated, f"{name} lists delegated tools {tools & delegated}"
|
|
118
|
+
|
|
119
|
+
def test_task_status_is_not_offered_as_evidence(self):
|
|
120
|
+
"""It takes a task id; a plan has VM names. Called with a name it answers
|
|
121
|
+
"gone" and no error, which the grader would count as a second source."""
|
|
122
|
+
tools = {
|
|
123
|
+
e["tool"]
|
|
124
|
+
for spec in load_catalogue()["classes"].values()
|
|
125
|
+
if spec.get("skill") == "vmware-aiops"
|
|
126
|
+
for e in spec["tools"]
|
|
127
|
+
}
|
|
128
|
+
assert "vm_task_status" not in tools
|
|
129
|
+
|
|
130
|
+
def test_collection_reaches_probable_with_monitor_and_aria(self):
|
|
131
|
+
"""Aria's collector state and vCenter's own reachability are two observations."""
|
|
132
|
+
out = readiness(["vmware-monitor", "vmware-aria"])["categories"]["data_collection"]
|
|
133
|
+
assert out["ceiling"] == "probable"
|
|
134
|
+
|
|
135
|
+
def test_licensing_does_not_count_an_aria_alert_as_a_second_source(self):
|
|
136
|
+
"""An Aria alert about a vCenter license is built from vCenter's data, so
|
|
137
|
+
monitor plus aria would be one source counted twice."""
|
|
138
|
+
out = readiness(["vmware-monitor", "vmware-aria"])["categories"]["licensing"]
|
|
139
|
+
assert out["ceiling"] == "candidate"
|
|
140
|
+
|
|
141
|
+
def test_one_skill_alone_is_still_one_source(self):
|
|
142
|
+
out = readiness(["vmware-aria"])["categories"]["data_collection"]
|
|
143
|
+
assert out["ceiling"] == "candidate"
|
|
144
|
+
|
|
145
|
+
def test_a_hardware_plan_can_ask_for_the_sensors(self):
|
|
146
|
+
routed = load_catalogue()["routing"]["hardware"]["supporting"]
|
|
147
|
+
tools = {e["tool"] for c in routed for e in load_catalogue()["classes"][c]["tools"]}
|
|
148
|
+
assert {"get_host_sensors", "get_host_services"} <= tools
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@pytest.fixture(autouse=True)
|
|
152
|
+
def _isolated_home(tmp_path, monkeypatch):
|
|
153
|
+
monkeypatch.setenv("OPS_HOME", str(tmp_path / "vmware"))
|
|
@@ -1293,7 +1293,7 @@ wheels = [
|
|
|
1293
1293
|
|
|
1294
1294
|
[[package]]
|
|
1295
1295
|
name = "vmware-debug"
|
|
1296
|
-
version = "1.
|
|
1296
|
+
version = "1.12.1"
|
|
1297
1297
|
source = { editable = "." }
|
|
1298
1298
|
dependencies = [
|
|
1299
1299
|
{ name = "mcp", extra = ["cli"] },
|
|
@@ -1316,7 +1316,7 @@ requires-dist = [
|
|
|
1316
1316
|
{ name = "pyyaml", specifier = ">=6.0,<7.0" },
|
|
1317
1317
|
{ name = "rich", specifier = ">=13.0,<15.0" },
|
|
1318
1318
|
{ name = "typer", specifier = ">=0.12,<1.0" },
|
|
1319
|
-
{ name = "vmware-policy", specifier = ">=1.
|
|
1319
|
+
{ name = "vmware-policy", specifier = ">=1.15.0,<2.0" },
|
|
1320
1320
|
]
|
|
1321
1321
|
|
|
1322
1322
|
[package.metadata.requires-dev]
|
|
@@ -1328,14 +1328,14 @@ dev = [
|
|
|
1328
1328
|
|
|
1329
1329
|
[[package]]
|
|
1330
1330
|
name = "vmware-policy"
|
|
1331
|
-
version = "1.
|
|
1331
|
+
version = "1.15.0"
|
|
1332
1332
|
source = { registry = "https://pypi.org/simple" }
|
|
1333
1333
|
dependencies = [
|
|
1334
1334
|
{ name = "pyyaml" },
|
|
1335
1335
|
{ name = "rich" },
|
|
1336
1336
|
{ name = "typer" },
|
|
1337
1337
|
]
|
|
1338
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
1338
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ac/0c/c7b6c9e2e82b5c8d40b0721bfc9a6428bdd9fd41d8c1c6ec492b94f183f8/vmware_policy-1.15.0.tar.gz", hash = "sha256:48e1850c434dd3f34401b1e3785c073d72b451af904cc2f8c7d3bde772309e8a", size = 181525, upload-time = "2026-09-15T05:43:38.307Z" }
|
|
1339
1339
|
wheels = [
|
|
1340
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1340
|
+
{ url = "https://files.pythonhosted.org/packages/37/26/088f02325e51109cfe8e433d861c28f75f22ce26bb375944d365c46f85c4/vmware_policy-1.15.0-py3-none-any.whl", hash = "sha256:2f5a7b0e57fc084ea9083e67fb6e3c27059e6bd9c75b3eabfed58d6ee4366db4", size = 69524, upload-time = "2026-09-15T05:43:36.606Z" },
|
|
1341
1341
|
]
|
|
@@ -20,6 +20,7 @@ from rich.table import Table
|
|
|
20
20
|
|
|
21
21
|
from vmware_debug import __version__
|
|
22
22
|
from vmware_debug.mcp.tools import incident_timeline, list_symptom_categories
|
|
23
|
+
from vmware_policy import cli_local
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
def _harden_console_encoding() -> None:
|
|
@@ -53,12 +54,14 @@ console = Console()
|
|
|
53
54
|
|
|
54
55
|
|
|
55
56
|
@app.command()
|
|
57
|
+
@cli_local("prints the installed version")
|
|
56
58
|
def version() -> None:
|
|
57
59
|
"""Print the installed version."""
|
|
58
60
|
console.print(f"vmware-debug {__version__}")
|
|
59
61
|
|
|
60
62
|
|
|
61
63
|
@app.command()
|
|
64
|
+
@cli_local("prints the built-in symptom catalogue; contacts nothing")
|
|
62
65
|
def categories() -> None:
|
|
63
66
|
"""List the symptom categories debug recognises and what to check for each."""
|
|
64
67
|
table = Table(title="vmware-debug symptom categories")
|
|
@@ -71,6 +74,7 @@ def categories() -> None:
|
|
|
71
74
|
|
|
72
75
|
|
|
73
76
|
@app.command()
|
|
77
|
+
@cli_local("correlates events read from a file or stdin; contacts nothing")
|
|
74
78
|
def triage(
|
|
75
79
|
events_file: Optional[Path] = typer.Option(
|
|
76
80
|
None, "--events", "-e", help="JSON file of event envelopes; reads stdin if omitted."
|
|
@@ -99,6 +103,7 @@ def triage(
|
|
|
99
103
|
|
|
100
104
|
|
|
101
105
|
@app.command()
|
|
106
|
+
@cli_local("starts the MCP server; its tools audit themselves")
|
|
102
107
|
def mcp() -> None:
|
|
103
108
|
"""Start the stdio MCP server (no network access; proxy-safe)."""
|
|
104
109
|
from vmware_debug.mcp_server.server import main as _main
|
|
@@ -588,7 +588,8 @@ def build_server() -> FastMCP:
|
|
|
588
588
|
whether it is
|
|
589
589
|
available, through which tools, and if not, `how_to_supply`. Per
|
|
590
590
|
symptom category (storage, network, compute, ha_drs, configuration,
|
|
591
|
-
accelerator, kubernetes, hardware
|
|
591
|
+
accelerator, kubernetes, hardware, host_lifecycle, power_lifecycle,
|
|
592
|
+
auth, platform, licensing, data_collection): a `ceiling` and the
|
|
592
593
|
`independent_sources` behind it. There is deliberately no single score —
|
|
593
594
|
"readiness 78%" cannot be acted on, "storage reaches Probable, hardware
|
|
594
595
|
reaches Candidate" can.
|
|
@@ -648,7 +649,8 @@ def build_server() -> FastMCP:
|
|
|
648
649
|
category: Force the symptom class instead of inferring it. Exactly
|
|
649
650
|
one of: storage, network, compute, ha_drs, configuration,
|
|
650
651
|
accelerator, kubernetes, hardware, host_lifecycle,
|
|
651
|
-
power_lifecycle, auth, platform
|
|
652
|
+
power_lifecycle, auth, platform, licensing,
|
|
653
|
+
data_collection. Omit to infer, then read
|
|
652
654
|
`category_signals` for the word that decided it.
|
|
653
655
|
available_skills: Narrow to the skills actually installed, in either
|
|
654
656
|
spelling ("monitor" or "vmware-monitor"). Omit to assume all of
|
|
@@ -79,7 +79,7 @@ _CATEGORY_SIGNATURES: tuple[tuple[str, tuple[str, ...], str], ...] = (
|
|
|
79
79
|
(
|
|
80
80
|
"auth",
|
|
81
81
|
("login", "authentication", "permission", "denied", "unauthorized",
|
|
82
|
-
"401", "403", "token", "certificate", "tls"),
|
|
82
|
+
"401", "403", "token", "certificate", "tls", "password"),
|
|
83
83
|
"check the service account + credentials in config/.env; verify the "
|
|
84
84
|
"target's certificate/time sync",
|
|
85
85
|
),
|
|
@@ -90,6 +90,36 @@ _CATEGORY_SIGNATURES: tuple[tuple[str, tuple[str, ...], str], ...] = (
|
|
|
90
90
|
"vmware-monitor (host connection state + service health) + "
|
|
91
91
|
"vmware-log-insight (vpxd/hostd logs around the first error)",
|
|
92
92
|
),
|
|
93
|
+
# The three below are subsystems, not synonyms. Real alert titles from a lab
|
|
94
|
+
# estate ("Host TPM attestation alarm", "License will soon expire", "Objects
|
|
95
|
+
# are not receiving data from adapter instance") matched nothing because no
|
|
96
|
+
# category covered them at all — see test_real_alert_titles_classify.
|
|
97
|
+
(
|
|
98
|
+
"hardware",
|
|
99
|
+
("tpm", "attestation", "ipmi", "sensor", "bmc"),
|
|
100
|
+
"vmware-monitor (get_host_sensors; host_log_scan for ipmi/cim errors — "
|
|
101
|
+
"no sensor data usually means no IPMI device or a stopped CIM service) + "
|
|
102
|
+
"the server's own BMC (iDRAC/iLO/XCC). A TPM attestation alarm is most "
|
|
103
|
+
"often a firmware setting (TPM 2.0 / TIS mode) rather than a failing part",
|
|
104
|
+
),
|
|
105
|
+
(
|
|
106
|
+
"licensing",
|
|
107
|
+
("license",),
|
|
108
|
+
"vmware-monitor (license_status: per-asset assignments show whether the "
|
|
109
|
+
"alarmed asset still holds the expiring key, or the alarm is stale) + "
|
|
110
|
+
"vmware-aria (an alert on 'Unlicensed Group' is Aria's own license, not "
|
|
111
|
+
"vCenter's)",
|
|
112
|
+
),
|
|
113
|
+
(
|
|
114
|
+
"data_collection",
|
|
115
|
+
# Not a bare "collector": vCenter's own services are named that way
|
|
116
|
+
# ("ESXi Dump Collector service is not running") and belong to platform.
|
|
117
|
+
("adapter instance", "not receiving data", "collector group", "cloud proxy"),
|
|
118
|
+
"vmware-aria (list_adapters for when each adapter last collected, "
|
|
119
|
+
"list_collector_groups, get_aria_health; list_resources to find the "
|
|
120
|
+
"objects that stopped reporting) + vmware-monitor (whether the source "
|
|
121
|
+
"vCenter itself is reachable)",
|
|
122
|
+
),
|
|
93
123
|
)
|
|
94
124
|
|
|
95
125
|
|
|
@@ -109,6 +109,52 @@ classes:
|
|
|
109
109
|
- {tool: list_tkc_clusters, gives: "workload clusters and their phase"}
|
|
110
110
|
- {tool: list_namespace_storage_usage, gives: "namespace storage pressure"}
|
|
111
111
|
|
|
112
|
+
# Same skill as virtualization_state, so never a second source for a monitor
|
|
113
|
+
# case. Separate only so a licensing plan asks for license_status and not
|
|
114
|
+
# for seven unrelated tools.
|
|
115
|
+
license_state:
|
|
116
|
+
label: License inventory and which asset holds which license
|
|
117
|
+
skill: vmware-monitor
|
|
118
|
+
decisive: false
|
|
119
|
+
tools:
|
|
120
|
+
- {tool: license_status, gives: "license expiry, and the license assigned to each vCenter and host"}
|
|
121
|
+
- {tool: get_alarms, gives: "whether the license alarm is active, and whether its condition still holds"}
|
|
122
|
+
|
|
123
|
+
collection_pipeline:
|
|
124
|
+
label: Aria's own collection pipeline (adapters, collectors, node health)
|
|
125
|
+
skill: vmware-aria
|
|
126
|
+
decisive: false
|
|
127
|
+
tools:
|
|
128
|
+
- {tool: list_adapters, gives: "each adapter instance and when it last collected"}
|
|
129
|
+
- {tool: list_collector_groups, gives: "collector groups and their members"}
|
|
130
|
+
- {tool: get_aria_health, gives: "Aria node and service health"}
|
|
131
|
+
- {tool: list_resources, gives: "objects under the adapter, to find the ones that stopped reporting"}
|
|
132
|
+
|
|
133
|
+
# Same skill as virtualization_state, so never a second source. Separate so
|
|
134
|
+
# a hardware plan asks for the sensors and the CIM Server state that supplies
|
|
135
|
+
# them, which is what its suggested_check tells the reader to look at.
|
|
136
|
+
host_hardware:
|
|
137
|
+
label: Host hardware sensors and the CIM Server that supplies them
|
|
138
|
+
skill: vmware-monitor
|
|
139
|
+
decisive: false
|
|
140
|
+
tools:
|
|
141
|
+
- {tool: get_host_sensors, gives: "sensor readings per host, and hosts reporting none with their CIM Server state"}
|
|
142
|
+
- {tool: get_host_services, gives: "whether sfcbd-watchdog (CIM Server) is running on the host"}
|
|
143
|
+
|
|
144
|
+
# Only reads vmware-aiops performs itself. Its cluster_health_summary,
|
|
145
|
+
# cross_vcenter_attention and *_investigation_bundle tools call
|
|
146
|
+
# vmware-monitor's code; listed here they would be monitor's data counted as
|
|
147
|
+
# a second, independent source.
|
|
148
|
+
# vm_task_status is left out on purpose: it takes a task id, a plan only has
|
|
149
|
+
# VM names, and called with a name it answers "gone" with no error — a reply
|
|
150
|
+
# that would count as a second source while saying nothing.
|
|
151
|
+
vm_operations:
|
|
152
|
+
label: VM snapshot tree
|
|
153
|
+
skill: vmware-aiops
|
|
154
|
+
decisive: false
|
|
155
|
+
tools:
|
|
156
|
+
- {tool: vm_list_snapshots, gives: "the VM's snapshot tree"}
|
|
157
|
+
|
|
112
158
|
# ── The two that do not exist ──────────────────────────────────────────
|
|
113
159
|
# Both are decisive: either one can take a conclusion to Confirmed. Neither
|
|
114
160
|
# has a tool. Listing them empty is what lets case_readiness report an honest
|
|
@@ -169,7 +215,7 @@ routing:
|
|
|
169
215
|
supporting: [kubernetes, virtualization_state, logs]
|
|
170
216
|
decisive: [knowledge]
|
|
171
217
|
hardware:
|
|
172
|
-
supporting: [virtualization_state, logs]
|
|
218
|
+
supporting: [host_hardware, virtualization_state, logs]
|
|
173
219
|
decisive: [hardware]
|
|
174
220
|
|
|
175
221
|
# The three below complete the set that ops/timeline.py's keyword classifier
|
|
@@ -188,7 +234,7 @@ routing:
|
|
|
188
234
|
decisive: [knowledge]
|
|
189
235
|
|
|
190
236
|
power_lifecycle:
|
|
191
|
-
supporting: [virtualization_state, logs]
|
|
237
|
+
supporting: [virtualization_state, logs, vm_operations]
|
|
192
238
|
decisive: [knowledge]
|
|
193
239
|
|
|
194
240
|
auth:
|
|
@@ -198,3 +244,17 @@ routing:
|
|
|
198
244
|
platform:
|
|
199
245
|
supporting: [virtualization_state, logs, metrics_and_anomalies]
|
|
200
246
|
decisive: [knowledge]
|
|
247
|
+
|
|
248
|
+
# Licensing has one source here. An Aria alert about a vCenter license is
|
|
249
|
+
# built from vCenter's own data, so counting it would be one source twice —
|
|
250
|
+
# the same double-count vm_operations refuses for AIops's bundles.
|
|
251
|
+
licensing:
|
|
252
|
+
supporting: [license_state]
|
|
253
|
+
decisive: [knowledge]
|
|
254
|
+
|
|
255
|
+
# Two observations: Aria's own collector state, and whether the vCenter it
|
|
256
|
+
# collects from is reachable.
|
|
257
|
+
|
|
258
|
+
data_collection:
|
|
259
|
+
supporting: [collection_pipeline, virtualization_state]
|
|
260
|
+
decisive: [knowledge]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_debug-1.11.4 → vmware_debug-1.12.1}/docs/plans/2026-08-28-investigation-layer-design.md
RENAMED
|
File without changes
|
{vmware_debug-1.11.4 → vmware_debug-1.12.1}/skills/vmware-debug/references/agent-guardrails.md
RENAMED
|
File without changes
|
|
File without changes
|
{vmware_debug-1.11.4 → vmware_debug-1.12.1}/skills/vmware-debug/references/event-envelope.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/test_entity_reachability.py
RENAMED
|
File without changes
|
{vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/test_error_actionability.py
RENAMED
|
File without changes
|
{vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/test_tool_description_quality.py
RENAMED
|
File without changes
|
{vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/capability/test_tool_manifest_budget.py
RENAMED
|
File without changes
|
|
File without changes
|
{vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/_vsphere_event_vocabulary.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_case_plan_max_steps.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_evidence_payload_contract.py
RENAMED
|
File without changes
|
|
File without changes
|
{vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_investigation_metrics.py
RENAMED
|
File without changes
|
|
File without changes
|
{vmware_debug-1.11.4 → vmware_debug-1.12.1}/tests/eval/regression/test_skill_name_aliases.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|