@dx-do/cli 5.2.49 → 5.2.50

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 (185) hide show
  1. package/README.md +24 -6
  2. package/dist-node/01-discover-vertices.tas-pwngv2fz.md +31 -0
  3. package/dist-node/01-discover-vertices.tas.data-store-svjfrm1f.json5 +29 -0
  4. package/dist-node/01-discover-vertices.tas.data-store-tmd-w650nfzt.json +4 -0
  5. package/dist-node/02-discover-services.tas-867m0m88.md +30 -0
  6. package/dist-node/02-discover-services.tas.data-store-jz0gx5vn.json5 +40 -0
  7. package/dist-node/02-discover-services.tas.data-store-tmd-eq264m6y.json +4 -0
  8. package/dist-node/03-discover-sources.nassql-4tgp9jvv.md +34 -0
  9. package/dist-node/03-discover-sources.nassql.data-store-by6sqk23.json5 +63 -0
  10. package/dist-node/03-discover-sources.nassql.data-store-tmd-n3gy57wm.json +4 -0
  11. package/dist-node/04-discover-metadata-columns.nassql-vhzb0mrq.md +26 -0
  12. package/dist-node/04-discover-metadata-columns.nassql.data-store-c9zr7p0q.json5 +35 -0
  13. package/dist-node/04-discover-metadata-columns.nassql.data-store-tmd-4ygrjvty.json +4 -0
  14. package/dist-node/10-filter-attribute-matches.tas-tafqmtw1.md +33 -0
  15. package/dist-node/10-filter-attribute-matches.tas.data-store-tmd-m2sendv0.json +4 -0
  16. package/dist-node/10-filter-attribute-matches.tas.data-store-whdc6vbc.json5 +35 -0
  17. package/dist-node/11-filter-and-compose.tas-m8856738.md +29 -0
  18. package/dist-node/11-filter-and-compose.tas.data-store-dh5meyk8.json5 +56 -0
  19. package/dist-node/11-filter-and-compose.tas.data-store-tmd-mfn8a16f.json +4 -0
  20. package/dist-node/12-filter-or-not.tas-21zab96s.md +35 -0
  21. package/dist-node/12-filter-or-not.tas.data-store-7vjr4fnd.json5 +83 -0
  22. package/dist-node/12-filter-or-not.tas.data-store-tmd-am9smwe5.json +4 -0
  23. package/dist-node/13-filter-layer.tas-r1ff5anv.md +29 -0
  24. package/dist-node/13-filter-layer.tas.data-store-5mneyz77.json5 +30 -0
  25. package/dist-node/13-filter-layer.tas.data-store-tmd-9qmhyfzr.json +4 -0
  26. package/dist-node/14-filter-traverse.tas-da9jene0.md +38 -0
  27. package/dist-node/14-filter-traverse.tas.data-store-p0vxtfvj.json5 +63 -0
  28. package/dist-node/14-filter-traverse.tas.data-store-tmd-5hepg5wf.json +4 -0
  29. package/dist-node/15-filter-take-vertices-edges.tas-m160qc7z.md +35 -0
  30. package/dist-node/15-filter-take-vertices-edges.tas.data-store-drmcme43.json5 +46 -0
  31. package/dist-node/15-filter-take-vertices-edges.tas.data-store-tmd-8fewsp5s.json +4 -0
  32. package/dist-node/16-filter-projection.tas-dh39mcx8.md +31 -0
  33. package/dist-node/16-filter-projection.tas.data-store-tmd-3r8anggx.json +4 -0
  34. package/dist-node/16-filter-projection.tas.data-store-xjbdry1x.json5 +36 -0
  35. package/dist-node/17-filter-lucene.tas-gyvtzwaa.md +29 -0
  36. package/dist-node/17-filter-lucene.tas.data-store-1knw6srt.json5 +39 -0
  37. package/dist-node/17-filter-lucene.tas.data-store-tmd-5cf3tygg.json +5 -0
  38. package/dist-node/18-filter-variable-reuse.tas-89fq0y6x.md +46 -0
  39. package/dist-node/18-filter-variable-reuse.tas.data-store-by35113t.json5 +55 -0
  40. package/dist-node/18-filter-variable-reuse.tas.data-store-tmd-ak7aprgk.json +4 -0
  41. package/dist-node/19-filter-order-statefilter.tas-hm3z71qj.md +36 -0
  42. package/dist-node/19-filter-order-statefilter.tas.data-store-ra9hj1rz.json5 +51 -0
  43. package/dist-node/19-filter-order-statefilter.tas.data-store-tmd-wqer9xy2.json +4 -0
  44. package/dist-node/20-nassql-from-metadata-basic.nassql-szr2xax1.md +28 -0
  45. package/dist-node/20-nassql-from-metadata-basic.nassql.data-store-tmd-c7drxs1m.json +4 -0
  46. package/dist-node/20-nassql-from-metadata-basic.nassql.data-store-zdf1gp1v.json5 +42 -0
  47. package/dist-node/21-nassql-from-metadata-regex.nassql-78jnsn3e.md +30 -0
  48. package/dist-node/21-nassql-from-metadata-regex.nassql.data-store-ckzsv7h1.json5 +53 -0
  49. package/dist-node/21-nassql-from-metadata-regex.nassql.data-store-tmd-zgr6r9my.json +4 -0
  50. package/dist-node/22-nassql-from-topology.nassql-a71qw9r0.md +42 -0
  51. package/dist-node/22-nassql-from-topology.nassql.data-store-81m23nge.json5 +58 -0
  52. package/dist-node/22-nassql-from-topology.nassql.data-store-tmd-vhpjy6c7.json +4 -0
  53. package/dist-node/23-nassql-join-topology-metadata.nassql-hywxhcg2.md +35 -0
  54. package/dist-node/23-nassql-join-topology-metadata.nassql.data-store-da7q90n2.json5 +76 -0
  55. package/dist-node/23-nassql-join-topology-metadata.nassql.data-store-tmd-rr8wt9qa.json +4 -0
  56. package/dist-node/24-nassql-from-data-window-mean.nassql-q6qsgdxw.md +33 -0
  57. package/dist-node/24-nassql-from-data-window-mean.nassql.data-store-j7xmg7fc.json5 +81 -0
  58. package/dist-node/24-nassql-from-data-window-mean.nassql.data-store-tmd-qgzz2f7v.json +4 -0
  59. package/dist-node/25-nassql-group-order-top.nassql-awgnwn3r.md +30 -0
  60. package/dist-node/25-nassql-group-order-top.nassql.data-store-cmrn300b.json5 +48 -0
  61. package/dist-node/25-nassql-group-order-top.nassql.data-store-tmd-7xpqeh7c.json +4 -0
  62. package/dist-node/26-nassql-filter-predicate.nassql-2t27h5ev.md +41 -0
  63. package/dist-node/26-nassql-filter-predicate.nassql.data-store-k2rgp609.json5 +59 -0
  64. package/dist-node/26-nassql-filter-predicate.nassql.data-store-tmd-m4dddgwm.json +4 -0
  65. package/dist-node/27-nassql-distinct-keep.nassql-6z55dvk3.md +24 -0
  66. package/dist-node/27-nassql-distinct-keep.nassql.data-store-mrx00ys5.json5 +52 -0
  67. package/dist-node/27-nassql-distinct-keep.nassql.data-store-tmd-0p9hy42g.json +4 -0
  68. package/dist-node/28-nassql-format-time.nassql-6wraqgdk.md +30 -0
  69. package/dist-node/28-nassql-format-time.nassql.data-store-tmd-bbbqhz1x.json +4 -0
  70. package/dist-node/28-nassql-format-time.nassql.data-store-tvy8y2cs.json5 +59 -0
  71. package/dist-node/29-nassql-describe-log.nassql-t9vnxeb0.md +31 -0
  72. package/dist-node/29-nassql-describe-log.nassql.data-store-tmd-q4mtczy8.json +4 -0
  73. package/dist-node/29-nassql-describe-log.nassql.data-store-x16y4crx.json5 +51 -0
  74. package/dist-node/30-nassql-map-string.nassql-f2tdknzs.md +30 -0
  75. package/dist-node/30-nassql-map-string.nassql.data-store-t8ahcabn.json5 +53 -0
  76. package/dist-node/30-nassql-map-string.nassql.data-store-tmd-a6xq0bdx.json +4 -0
  77. package/dist-node/31-nassql-join-data-sum.nassql-p16y3xk6.md +26 -0
  78. package/dist-node/31-nassql-join-data-sum.nassql.data-store-dje7wm6v.json5 +64 -0
  79. package/dist-node/31-nassql-join-data-sum.nassql.data-store-tmd-c1pyx1qw.json +4 -0
  80. package/dist-node/32-nassql-bottom-aggregation.nassql-hpgfn77p.md +26 -0
  81. package/dist-node/32-nassql-bottom-aggregation.nassql.data-store-tmd-p0ssj1vc.json +4 -0
  82. package/dist-node/32-nassql-bottom-aggregation.nassql.data-store-v9580caa.json5 +43 -0
  83. package/dist-node/33-nassql-cross-domain-pipeline.nassql-fm0ynphf.md +45 -0
  84. package/dist-node/33-nassql-cross-domain-pipeline.nassql.data-store-tmd-18881drs.json +4 -0
  85. package/dist-node/33-nassql-cross-domain-pipeline.nassql.data-store-vqs9hkx4.json5 +79 -0
  86. package/dist-node/3rdpartylicenses-hx59bakt.txt +885 -0
  87. package/dist-node/50-discover-custom-layers.tas-2hvvpkzw.md +66 -0
  88. package/dist-node/50-discover-custom-layers.tas.data-store-h85zgna9.json5 +36 -0
  89. package/dist-node/50-discover-custom-layers.tas.data-store-tmd-hagn9eak.json +4 -0
  90. package/dist-node/51-collect-counts-everything.tas-nz0ksgdc.md +46 -0
  91. package/dist-node/51-collect-counts-everything.tas.data-store-eypcjah8.json5 +48 -0
  92. package/dist-node/51-collect-counts-everything.tas.data-store-tmd-4pcj94s9.json +4 -0
  93. package/dist-node/52-collect-counts-bulk.tas-eerw4z8s.md +54 -0
  94. package/dist-node/52-collect-counts-bulk.tas.data-store-scedtw1m.json5 +65 -0
  95. package/dist-node/52-collect-counts-bulk.tas.data-store-tmd-csyzj189.json +4 -0
  96. package/dist-node/53-collect-attributes-by-type.tas-cw0285hx.md +71 -0
  97. package/dist-node/53-collect-attributes-by-type.tas.data-store-fvjge4yr.json5 +65 -0
  98. package/dist-node/53-collect-attributes-by-type.tas.data-store-tmd-274qrd8f.json +4 -0
  99. package/dist-node/README-ghxecaz0.md +84 -0
  100. package/dist-node/SKILL-1xn7r9nt.md +104 -0
  101. package/dist-node/agent-25q752kd.md +55 -0
  102. package/dist-node/agent_connection_and_status-0dq7zkpc.md +62 -0
  103. package/dist-node/agent_source_collector-6s06n3rs.md +40 -0
  104. package/dist-node/agentic-mcp-rycd2gh8.md +140 -0
  105. package/dist-node/application-dfva8tz0.md +48 -0
  106. package/dist-node/application-m0q2vaxj.md +74 -0
  107. package/dist-node/attribute_resource_metric_name-pxrceab5.md +56 -0
  108. package/dist-node/browseragent-snippet.template-9megjp8a.html +12 -0
  109. package/dist-node/bulkvertexpatch-1a4qy5vb.md +78 -0
  110. package/dist-node/bundle.pbd-38r15kyd.template +13 -0
  111. package/dist-node/bundle.profile-1wpzpt3d.template +2 -0
  112. package/dist-node/business_transaction-mbqz5ex9.md +61 -0
  113. package/dist-node/chunk-4I3HBO6U-2ebgf7kh.js +127 -0
  114. package/dist-node/chunk-4PMCLJMS-0mqvr4m4.js +1 -0
  115. package/dist-node/chunk-5VSFINOX-ewzpx7wh.js +5 -0
  116. package/dist-node/chunk-72HYG3XZ-kf7hy4vs.js +3625 -0
  117. package/dist-node/chunk-JRM4BLOM-rg32z8w4.js +1 -0
  118. package/dist-node/chunk-Q2JA73UH-akkb8bh3.js +14 -0
  119. package/dist-node/chunk-RNMHSXZF-pdwasrg7.js +1358 -0
  120. package/dist-node/chunk-VV2FJEMA-3rvtkmga.js +321 -0
  121. package/dist-node/chunk-YVD3UK5I-9pxr1jka.js +695 -0
  122. package/dist-node/configuration-1vczsdex.md +104 -0
  123. package/dist-node/dashboards-x0xddksy.md +17 -0
  124. package/dist-node/database_or_inferred-8vqf5gyr.md +75 -0
  125. package/dist-node/default-licensing-config-0p879qpb.template +122 -0
  126. package/dist-node/dependency-3b0neg5x.md +40 -0
  127. package/dist-node/description.md-qwc2bj9r.template +30 -0
  128. package/dist-node/discovery-flow-fw79kbx4.md +116 -0
  129. package/dist-node/dxi_service-13prnpd5.md +59 -0
  130. package/dist-node/entity-relationships-cevz61kj.md +142 -0
  131. package/dist-node/gotchas-8ab64kcd.md +389 -0
  132. package/dist-node/host-es6fxtgx.md +46 -0
  133. package/dist-node/host-j3qqrm5f.md +55 -0
  134. package/dist-node/index-104hyb1m.html +13 -0
  135. package/dist-node/index-7fp2dfas.json +178 -0
  136. package/dist-node/index-g3hh5wez.json +403 -0
  137. package/dist-node/index-mbzg9rhc.json +270 -0
  138. package/dist-node/index-qffdhwgm.json +2479 -0
  139. package/dist-node/inferred-w998vfq1.md +41 -0
  140. package/dist-node/installInstructions.md-k9ghf3dr.template +21 -0
  141. package/dist-node/inventorize-xc9h9bjr.md +34 -0
  142. package/dist-node/investigation-planning-6kcm01h9.md +149 -0
  143. package/dist-node/investigator-flow-jc2s0n46.md +186 -0
  144. package/dist-node/k8s_deployment_and_namespace-69c29152.md +88 -0
  145. package/dist-node/k8s_pod_and_container-9h4v6cmj.md +64 -0
  146. package/dist-node/main-SGLYO5YX-ht69eb0y.js +13 -0
  147. package/dist-node/main.js +397415 -0
  148. package/dist-node/marketplace-srdmzxkj.json +15 -0
  149. package/dist-node/metric-source-names-6cbczyks.md +75 -0
  150. package/dist-node/metrics-grounding-2h4kkbe3.md +130 -0
  151. package/dist-node/mm-cookbook-23jpw721.md +231 -0
  152. package/dist-node/mm-quickstart-x2adfc16.md +106 -0
  153. package/dist-node/nassql-cookbook-n8kc0mff.md +812 -0
  154. package/dist-node/nassql-quickstart-090e0yex.md +149 -0
  155. package/dist-node/plugin-c3bavxvf.json +18 -0
  156. package/dist-node/polyfills-A7ZF72EO-mp884a0b.js +2 -0
  157. package/dist-node/prerendered-routes-523d8gat.json +3 -0
  158. package/dist-node/primeicons-4GST5W3O-jac3wxrf.woff2 +0 -0
  159. package/dist-node/primeicons-DHQU4SEP-760n99pp.svg +345 -0
  160. package/dist-node/primeicons-GEFHGEHP-rc4kaa3b.ttf +0 -0
  161. package/dist-node/primeicons-P53SE5CV-4saz3d5j.woff +0 -0
  162. package/dist-node/primeicons-RSSEDYLY-4d4vbd67.eot +0 -0
  163. package/dist-node/query-vs-analysis-separation-sag1ezcq.md +97 -0
  164. package/dist-node/run-query-vs-run-partial-6138pc94.md +80 -0
  165. package/dist-node/service-5pz5nhzf.md +133 -0
  166. package/dist-node/service-hierarchies-87a4ynpj.md +178 -0
  167. package/dist-node/service-k4f5mkbq.md +51 -0
  168. package/dist-node/servlet_or_frontend-1kjcb7ar.md +76 -0
  169. package/dist-node/src-apm-mfnsq6vw.svg +4 -0
  170. package/dist-node/src-axa-nn28yqmj.svg +4 -0
  171. package/dist-node/src-dxim-fv7ne4qa.svg +4 -0
  172. package/dist-node/styles-23VUPSCU-9ehggc1f.css +1 -0
  173. package/dist-node/tas-cookbook-0y4826rp.md +693 -0
  174. package/dist-node/tas-quickstart-wgcvwffc.md +138 -0
  175. package/dist-node/time-format-0595g01j.md +41 -0
  176. package/dist-node/toggles.pbd-9wscbmng.template +2 -0
  177. package/dist-node/type-host-agbhmn6v.svg +6 -0
  178. package/dist-node/type-metric-p9b90bpx.svg +4 -0
  179. package/dist-node/type-service-k7f1x71k.svg +4 -0
  180. package/dist-node/ui-0b5grqrg.md +113 -0
  181. package/dist-node/universe-b9nhf325.md +47 -0
  182. package/dist-node/universe-fzpwzvxr.md +91 -0
  183. package/dist-node/universes-and-scopes-1cb9pfk7.md +105 -0
  184. package/dist-node/vertex_entity_node-mm3yp9d0.md +31 -0
  185. package/package.json +1 -1
@@ -0,0 +1,66 @@
1
+ # 50-discover-custom-layers (TAS)
2
+
3
+ ## Purpose
4
+
5
+ Find all vertices whose layer is **not** one of the built-in DataStore layers. This surfaces custom integration layers that third-party or internal connectors may use when writing their entities to the topology graph.
6
+
7
+ ## Query Construction
8
+
9
+ Wraps a `LAYER` filter (using the multi-value `values` array) in a `NOT` filter:
10
+
11
+ ```
12
+ NOT(
13
+ LAYER(values: ["ATC", "UIM", "APM_INFRASTRUCTURE", "INFRASTRUCTURE",
14
+ "SA", "ACN", "CONNECTOR_METADATA", "ACN_CONFIGURATION"])
15
+ )
16
+ ```
17
+
18
+ The `LAYER` filter with `values` performs an OR match across all listed layer names. `NOT` inverts this, selecting every vertex whose layer is absent from the list. The result set therefore contains only vertices on unknown/custom layers.
19
+
20
+ The exclusion list is the union of:
21
+ - **Java API constants** (`TasConstants`): `ATC`, `APM_INFRASTRUCTURE`, `SA`, `ACN`
22
+ - **`Layer` class static instances**: `ATC`, `UIM`, `APM_INFRASTRUCTURE`, `INFRASTRUCTURE`
23
+ - **Conditional but server-recognized** (appear when the tenant uses connectors that publish to them): `CONNECTOR_METADATA`, `ACN_CONFIGURATION`
24
+
25
+ ## API Surface Exercised
26
+
27
+ - **Filter**: `NOT` — inverts any inner filter result
28
+ - **Filter**: `LAYER` with `values` (array) — multi-layer OR match
29
+ - Together these form the idiomatic "exclude known layers" pattern; there is no native `NOT_LAYER` op
30
+
31
+ ## Expected Output
32
+
33
+ Up to 200 vertices with `DETAILED` projection. For each vertex inspect:
34
+ - `externalId` — the first colon-delimited segment is the custom layer name
35
+ - `attributes.type` — the vertex type registered by the integration
36
+
37
+ If the tenant has no custom integrations, the result will be empty (0 vertices).
38
+
39
+ A typical result on a tenant with one or two integrations might look like:
40
+
41
+ | Layer | Vertex count | Sample externalId prefix |
42
+ |---|---|---|
43
+ | `CUSTOM` | tens | `CUSTOM:LOGANALYTICS\|…` |
44
+ | `INFRASTRUCTURE_UIM` | tens | `INFRASTRUCTURE_UIM:OpenAccess_…` |
45
+ | `NETWORK_SPECTRUM` | tens | `NETWORK_SPECTRUM:<entity-id>` |
46
+
47
+ To enumerate distinct custom layer names from any result file:
48
+
49
+ ```bash
50
+ python3 -c "
51
+ import json
52
+ with open('packages/.tmp/output/datastore-driver/<dir>/<TENANT>_50-discover-custom-layers.tas.data-store.result.json') as f:
53
+ data = json.load(f)
54
+ layers = sorted({v.get('externalId','').split(':')[0] for v in data['vertices']})
55
+ print('Custom layers found:', layers)
56
+ "
57
+ ```
58
+
59
+ ## What the Results Tell You
60
+
61
+ Any layer name that appears here was written by an integration that is not part of the core DataStore product. Common examples include:
62
+ - Cloud-provider collectors (e.g., `AWS`, `AZURE`, `GCP` specific namespaces)
63
+ - Custom on-premise connectors
64
+ - Partner integrations that declare their own namespace
65
+
66
+ Once you know the custom layer names, you can query them directly with a targeted `LAYER` filter (see query 13 for the pattern).
@@ -0,0 +1,36 @@
1
+ /*
2
+ * Find vertices in CUSTOM (non-standard) topology layers — i.e.
3
+ * anything written by integrations that aren't part of the core
4
+ * DataStore product. Pattern: NOT(LAYER(values: <known layers>))
5
+ * — invert the filter against the known-standard set.
6
+ *
7
+ * The exclusion list combines:
8
+ * - Java API constants (TasConstants): ATC, APM_INFRASTRUCTURE,
9
+ * SA, ACN
10
+ * - `Layer` class static instances: ATC, UIM, APM_INFRASTRUCTURE,
11
+ * INFRASTRUCTURE
12
+ * - Conditional but server-recognized (appear when the tenant
13
+ * uses connectors that publish to them): CONNECTOR_METADATA,
14
+ * ACN_CONFIGURATION
15
+ *
16
+ * Result-set on a tenant with integrations: typically tens of
17
+ * vertices across a handful of partner-defined layers
18
+ * (NETWORK_SPECTRUM, INFRASTRUCTURE_UIM, CUSTOM, etc.). Empty on
19
+ * tenants without integrations.
20
+ */
21
+ {
22
+ /*
23
+ * NOT-wrapping a LAYER-with-values is the idiomatic "anything
24
+ * NOT in this layer set" pattern. There is no native `NOT_LAYER`
25
+ * op; this is the canonical replacement.
26
+ */
27
+ "filter": {
28
+ "op": "NOT",
29
+ "input": {
30
+ "op": "LAYER",
31
+ "values": ["ATC", "UIM", "APM_INFRASTRUCTURE", "INFRASTRUCTURE", "SA", "ACN", "CONNECTOR_METADATA", "ACN_CONFIGURATION"]
32
+ }
33
+ },
34
+ "limit": 200,
35
+ "projection": "DETAILED"
36
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "description": "Find vertices on non-standard layers — any layer not in the known built-in set. Useful for discovering custom integration layers.",
3
+ "tags": ["tas", "filter", "layer", "discovery"]
4
+ }
@@ -0,0 +1,46 @@
1
+ # 51-collect-counts-everything (TAS)
2
+
3
+ ## Purpose
4
+
5
+ Answer "how many vertices does this tenant have?" in a single round trip without paying the wire cost of the actual vertex set. The right thing to run before deciding whether to dump a tenant's full topology to a UI / agent / file — small tenants might be 1k vertices, big ones can hit 500k.
6
+
7
+ > **MCP shortcut:** the same answer is one call away via `discovery_entity_count`. Use the shortcut when you just need the number; come back here when you want to see the underlying TAS pattern (so you can adapt it — same shape with `ALL` swapped for any vertex-shaped filter gives a count for that subset).
8
+
9
+ ## Query Construction
10
+
11
+ The query composes three ops, outside-in:
12
+
13
+ 1. `EMPTY` — pass-through wrapper that forces the final result vertex set to be empty.
14
+ 2. `COLLECT_COUNTS` — analytic op that records its input's vertex count under a named `id` and emits it on `result.analytics[]`. Otherwise pass-through.
15
+ 3. `ALL` — every vertex in the tenant.
16
+
17
+ The inner pipeline counts everything; the outer `EMPTY` drops the vertex set so only the analytic crosses the wire. Response is under 200 bytes regardless of tenant size.
18
+
19
+ ## API Surface Exercised
20
+
21
+ - **EMPTY**: drop the final vertex set; keep analytics. Useful any time you only want aggregate metadata, not the vertices themselves.
22
+ - **COLLECT_COUNTS**: cheap pass-through analytic. Records `{ id, vertexCount }` on `result.analytics[]`. The `id` is your read-key — use a stable string you can match against when multiple analytics are emitted.
23
+ - **ALL**: matches every vertex in the tenant.
24
+
25
+ ## Expected Output
26
+
27
+ ```json
28
+ {
29
+ "vertices": [],
30
+ "edges": [],
31
+ "analytics": [
32
+ { "t": "COLLECT_COUNTS", "id": "EVERYTHING", "vertexCount": 1718 }
33
+ ],
34
+ "totalVertices": 0,
35
+ "totalEdges": 0,
36
+ "nextOffset": -1
37
+ }
38
+ ```
39
+
40
+ `vertices` and `edges` are empty by design (the EMPTY wrapper). The analytic carries the count.
41
+
42
+ ## What the Results Tell You
43
+
44
+ `vertexCount` is the total live vertex count in the tenant at query time. Tenants under ~5k vertices can usually be loaded whole into a graph visualizer; bigger tenants need scoping (by service, by type, by neighborhood traversal) before a full-topology load is worth attempting.
45
+
46
+ This pattern generalizes — replace `ALL` with any vertex-shaped filter and you get a count for that subset. See `52-collect-counts-bulk` for the bulk-fan-in extension that gets multiple counts in a single query.
@@ -0,0 +1,48 @@
1
+ /*
2
+ * Pre-flight tenant-size probe — answer "how many vertices does
3
+ * this tenant have?" in one cheap analytic-only round trip. No
4
+ * vertices on the wire, just a single number.
5
+ *
6
+ * Pattern: EMPTY > COLLECT_COUNTS > ALL.
7
+ * - ALL produces every vertex.
8
+ * - COLLECT_COUNTS records the count as an analytic (it's a
9
+ * pass-through op, so vertices flow through unchanged).
10
+ * - EMPTY drops the vertex set on the way out so the response
11
+ * is just `{ analytics: [{ t: "COLLECT_COUNTS", id, vertexCount }] }`.
12
+ *
13
+ * Response is < 200 bytes regardless of tenant size — 100 vertices
14
+ * or 500,000. Use this BEFORE deciding whether to dump the whole
15
+ * topology to a UI / agent / file.
16
+ */
17
+ {
18
+ "filter": {
19
+ /*
20
+ * EMPTY — pass-through "force-empty-output" wrapper. The inner
21
+ * filter still runs (and any analytics inside still emit), but
22
+ * the final vertex set returned to the client is empty.
23
+ */
24
+ "op": "EMPTY",
25
+ "input": {
26
+ /*
27
+ * COLLECT_COUNTS — analytic pass-through. Records
28
+ * `vertexCount` for whatever its `input` produces, keyed by
29
+ * the unique `id`. Read it back from `result.analytics[]`.
30
+ */
31
+ "op": "COLLECT_COUNTS",
32
+ "id": "EVERYTHING",
33
+ "input": {
34
+ /*
35
+ * ALL — every vertex in the tenant. Pair with
36
+ * COLLECT_COUNTS to get the total tenant size.
37
+ */
38
+ "op": "ALL"
39
+ }
40
+ }
41
+ },
42
+ /*
43
+ * `limit: 1` is symbolic here — EMPTY drops the vertex set
44
+ * regardless. Some servers reject `limit: 0`, so 1 is the
45
+ * conventional placeholder for "I don't want any vertices".
46
+ */
47
+ "limit": 1
48
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "description": "Pre-flight tenant-size probe — total vertex count via EMPTY > COLLECT_COUNTS > ALL, single small round trip",
3
+ "tags": ["tas", "analytics", "collect-counts", "discovery"]
4
+ }
@@ -0,0 +1,54 @@
1
+ # 52-collect-counts-bulk (TAS)
2
+
3
+ ## Purpose
4
+
5
+ Get N vertex counts (per type, per service, per layer — whatever the axis) in a single round trip instead of N parallel queries. The pattern that makes "count per service" UIs feasible on tenants with hundreds of services without a request storm.
6
+
7
+ > **MCP shortcut for the per-service case:** `discovery_service_counts` returns `{services: [{id, name, count, childServiceNames}]}` in one call — it composes this exact `OR(COLLECT_COUNTS(SERVICE([name])))` query over the OI service catalog (and batches by 200 names so it scales past the multi-thousand-service tenants). Reach for the shortcut for the per-service axis; reach for the underlying pattern (this query) when you want counts on a different axis (per-type, per-layer, per-traversal-result, …).
8
+
9
+ ## Query Construction
10
+
11
+ Three ops, nested:
12
+
13
+ 1. `EMPTY` — drop the final vertex set; keep the analytics.
14
+ 2. `OR` — compose multiple branches under one filter tree. Each branch produces a vertex set; OR returns their union. (The union is discarded by EMPTY — we don't actually want it.)
15
+ 3. Each branch is a `COLLECT_COUNTS` analytic with a unique `id`, wrapping whatever vertex-shaped filter defines its slice.
16
+
17
+ The example uses three branches:
18
+ - `count:host` — vertices with `type = HOST`
19
+ - `count:agent` — vertices with `type = AGENT`
20
+ - `count:all` — every vertex (`ALL`)
21
+
22
+ The inner filter for each branch can be anything — `SERVICE`, `LAYER`, `LUCENE`, `ATTRIBUTE`, `TRAVERSE`, even another nested composition. Each branch's analytic is independent.
23
+
24
+ ## API Surface Exercised
25
+
26
+ - **EMPTY**: as in `51-collect-counts-everything` — discard the vertex set, keep analytics.
27
+ - **OR**: composes multiple sub-filters under one tree. Each branch runs in parallel inside the server, sharing the same query-plan context.
28
+ - **COLLECT_COUNTS** with unique `id` per branch: each one emits an independent analytic entry.
29
+
30
+ ## Expected Output
31
+
32
+ ```json
33
+ {
34
+ "vertices": [],
35
+ "edges": [],
36
+ "analytics": [
37
+ { "t": "COLLECT_COUNTS", "id": "count:host", "vertexCount": 32 },
38
+ { "t": "COLLECT_COUNTS", "id": "count:agent", "vertexCount": 96 },
39
+ { "t": "COLLECT_COUNTS", "id": "count:all", "vertexCount": 1718 }
40
+ ]
41
+ }
42
+ ```
43
+
44
+ Read the per-branch counts back by matching on `id`. Order isn't guaranteed — always look up by id, don't rely on positional indexing.
45
+
46
+ ## What the Results Tell You
47
+
48
+ How big each slice is, before you commit to fetching its vertices. Concretely:
49
+
50
+ - A "service picker" UI can render `Service Foo · 175 entities` rows for hundreds of services on the strength of one query — no need to issue one query per service.
51
+ - A "topology summary" tool can answer "how is this tenant composed?" with one query: count by type, count by layer, count by source-product.
52
+ - A scoping decision (e.g. "should I load this neighborhood or just sample it?") can call this once with the proposed filter to know the size before committing.
53
+
54
+ The fan-in trick is the load-bearing pattern — without it, count-per-X UIs default to N parallel queries, which scales poorly with N. The unique-id-per-branch contract is non-negotiable; reusing an id silently collapses the analytics.
@@ -0,0 +1,65 @@
1
+ /*
2
+ * Bulk count probe — multiple `COLLECT_COUNTS` analytics in a
3
+ * SINGLE round trip via `OR` composition. Each branch contributes
4
+ * its own analytic to `result.analytics[]`, keyed by a unique `id`.
5
+ *
6
+ * Use this any time you'd otherwise loop over N filters running
7
+ * one COLLECT_COUNTS each. Counts per type, per layer, per service,
8
+ * per attribute value — all collapse into one query. The inner
9
+ * `OR` produces a UNION of vertex sets but the outer `EMPTY`
10
+ * discards that — only the analytics matter.
11
+ *
12
+ * The example below counts HOSTs, AGENTs, and the total tenant
13
+ * vertices in one query. Swap the inner ATTRIBUTE filters for
14
+ * SERVICE / LAYER / LUCENE / TRAVERSE / etc. to count along any
15
+ * axis you care about.
16
+ */
17
+ {
18
+ "filter": {
19
+ /*
20
+ * EMPTY drops the unioned vertex set. The analytics survive.
21
+ */
22
+ "op": "EMPTY",
23
+ "input": {
24
+ /*
25
+ * OR composes multiple branches — each branch runs its own
26
+ * COLLECT_COUNTS over a distinct vertex slice and emits its
27
+ * own analytic. The OR's vertex output is the union of
28
+ * branch outputs, but EMPTY makes that irrelevant.
29
+ *
30
+ * Important: each COLLECT_COUNTS needs a UNIQUE `id`. Use
31
+ * something stable you can match against when reading the
32
+ * analytics back (e.g. `count:host`, `svc:42`, `layer:apm`).
33
+ */
34
+ "op": "OR",
35
+ "input": [
36
+ {
37
+ "op": "COLLECT_COUNTS",
38
+ "id": "count:host",
39
+ "input": {
40
+ "op": "ATTRIBUTE",
41
+ "expressions": [
42
+ { "name": "type", "operator": "IN", "values": ["HOST"] }
43
+ ]
44
+ }
45
+ },
46
+ {
47
+ "op": "COLLECT_COUNTS",
48
+ "id": "count:agent",
49
+ "input": {
50
+ "op": "ATTRIBUTE",
51
+ "expressions": [
52
+ { "name": "type", "operator": "IN", "values": ["AGENT"] }
53
+ ]
54
+ }
55
+ },
56
+ {
57
+ "op": "COLLECT_COUNTS",
58
+ "id": "count:all",
59
+ "input": { "op": "ALL" }
60
+ }
61
+ ]
62
+ }
63
+ },
64
+ "limit": 1
65
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "description": "Bulk count probe — multiple COLLECT_COUNTS via OR composition, one round trip per N counts",
3
+ "tags": ["tas", "analytics", "collect-counts", "or-composition", "discovery"]
4
+ }
@@ -0,0 +1,71 @@
1
+ # 53-collect-attributes-by-type (TAS)
2
+
3
+ ## Purpose
4
+
5
+ Bucket every vertex in the tenant by its `type` attribute and get the per-value count in one query — a complete "what kinds of entities are here, and how many of each?" histogram. Companion to `COLLECT_COUNTS`:
6
+
7
+ - `COLLECT_COUNTS` — "how many?"
8
+ - `COLLECT_ATTRIBUTES` — "how many of each value?"
9
+
10
+ Run this on a new tenant to get the type breakdown without iterating per-type queries.
11
+
12
+ ## Query Construction
13
+
14
+ Two ops:
15
+
16
+ 1. `EMPTY` — drop the actual vertex set; keep the analytic.
17
+ 2. `COLLECT_ATTRIBUTES` — for each vertex in `input`, record its value of `attributeName` and tally how many vertices share each distinct value.
18
+
19
+ `attributeName: "type"` makes this a type histogram. Swap for any attribute key — `"agent"` for an agent-name histogram, `"layer"` for a layer histogram, `"hostname"` for a hostname histogram, etc.
20
+
21
+ `input: { op: "ALL" }` runs the histogram over every vertex. Replace with a more specific filter (`SERVICE`, `LAYER`, `ATTRIBUTE`, `TRAVERSE`) to scope the histogram to a population.
22
+
23
+ ## API Surface Exercised
24
+
25
+ - **EMPTY**: drop the vertex set; keep analytics. As in `51` and `52`.
26
+ - **COLLECT_ATTRIBUTES**: analytic op. Required: `id`, `attributeName`. Optional knobs:
27
+ - `layer` — restrict collection to one layer
28
+ - `includeIds: true` — also return `vertexIds[]` per bucket (handy when you want to drill into one without re-querying)
29
+ - `caseInsensitive: true` — dedupe value strings case-insensitively
30
+ - `skipBackends: true` — exclude backend-type vertices
31
+
32
+ ## Expected Output
33
+
34
+ ```json
35
+ {
36
+ "vertices": [],
37
+ "edges": [],
38
+ "analytics": [
39
+ {
40
+ "t": "COLLECT_ATTRIBUTES",
41
+ "id": "type-histogram",
42
+ "values": [
43
+ {
44
+ "attribValue": "k8s_CONTAINER",
45
+ "occurances": 257,
46
+ "alerts": 0,
47
+ "cautionAlerts": 0,
48
+ "dangerAlerts": 0,
49
+ "vertexIds": null
50
+ },
51
+ { "attribValue": "k8s_POD", "occurances": 192, "alerts": 0, "cautionAlerts": 0, "dangerAlerts": 0, "vertexIds": null },
52
+ { "attribValue": "GENERICFRONTEND","occurances": 144, "alerts": 0, "cautionAlerts": 0, "dangerAlerts": 0, "vertexIds": null }
53
+ ]
54
+ }
55
+ ]
56
+ }
57
+ ```
58
+
59
+ Note the canonical wire fields are `attribValue` (not `attributeValue`) and `occurances` (not `occurrences`) — both typos are baked into the Java model. Match the wire form exactly.
60
+
61
+ Each value entry also carries `alerts` / `cautionAlerts` / `dangerAlerts` (per-bucket alert counts inherited from `TasGroupingAlertStatistics`) and a `vertexIds` field that's `null` unless `includeIds: true` is set on the COLLECT_ATTRIBUTES op. The alert counts are usually `0` on tenants without a configured alarm pipeline.
62
+
63
+ ## What the Results Tell You
64
+
65
+ A complete profile of what's in the tenant, by entity kind. Concretely:
66
+
67
+ - A "what's deployed?" inspection picks out the dominant types (k8s heavy? agent heavy? business-transaction heavy?) without needing to know the type vocabulary up front.
68
+ - An adapter that styles a graph by type can pre-allocate per-type style rules from this histogram, sized to actual cardinality.
69
+ - Anomaly detection: comparing the histogram across time reveals onboarded / offboarded entity classes — a tenant that grew a `MYSQL_DB` bucket overnight just connected a database collector.
70
+
71
+ The pattern generalizes. Same shape with `attributeName: "agent"` gives you a load distribution across agents. With `attributeName: "SourceProduct"` (and a population that has it), you get a per-product entity census.
@@ -0,0 +1,65 @@
1
+ /*
2
+ * Histogram-by-attribute — `COLLECT_ATTRIBUTES` over a population
3
+ * groups vertices by a chosen attribute and returns the per-value
4
+ * occurrence count. Companion to COLLECT_COUNTS:
5
+ *
6
+ * COLLECT_COUNTS — "how many?"
7
+ * COLLECT_ATTRIBUTES — "how many of each value?"
8
+ *
9
+ * Output entry shape (under `result.analytics[]`):
10
+ *
11
+ * {
12
+ * t: "COLLECT_ATTRIBUTES",
13
+ * id, layer?,
14
+ * values: [
15
+ * { attribValue, occurances, vertexIds? },
16
+ * ...
17
+ * ]
18
+ * }
19
+ *
20
+ * Note the canonical wire field is `attribValue` (not
21
+ * `attributeValue`) and `occurances` (not `occurrences`) — both
22
+ * are typos baked into the Java model. Match exactly.
23
+ *
24
+ * The example below buckets every vertex in the tenant by its
25
+ * `type` attribute, returning a complete type histogram in a
26
+ * single query — useful as a "what's in this tenant?" probe.
27
+ */
28
+ {
29
+ "filter": {
30
+ /*
31
+ * EMPTY drops the actual vertex set so the response is just
32
+ * the histogram. Drop EMPTY if you want both the vertices
33
+ * AND the histogram in one shot — analytics flow through
34
+ * regardless of whether vertices reach the client.
35
+ */
36
+ "op": "EMPTY",
37
+ "input": {
38
+ /*
39
+ * COLLECT_ATTRIBUTES — analytic pass-through. For each
40
+ * vertex in `input`, record its value of `attributeName`
41
+ * and tally how many vertices share it.
42
+ */
43
+ "op": "COLLECT_ATTRIBUTES",
44
+ "id": "type-histogram",
45
+ /*
46
+ * `attributeName` selects which attribute's values to
47
+ * collect. "type" gives a type histogram; "agent" gives an
48
+ * agent-name histogram; any attribute key works.
49
+ */
50
+ "attributeName": "type",
51
+ /*
52
+ * Optional knobs (omitted here):
53
+ * - `layer`: restrict collection to one layer
54
+ * - `includeIds: true`: also return `vertexIds[]` per value
55
+ * (use when you want to drill into a specific bucket
56
+ * without re-querying)
57
+ * - `caseInsensitive: true`: dedupe values case-insensitively
58
+ */
59
+ "input": {
60
+ "op": "ALL"
61
+ }
62
+ }
63
+ },
64
+ "limit": 1
65
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "description": "Type histogram via COLLECT_ATTRIBUTES — group every tenant vertex by its `type` attribute, get per-value counts in one query",
3
+ "tags": ["tas", "analytics", "collect-attributes", "discovery", "histogram"]
4
+ }
@@ -0,0 +1,84 @@
1
+ # investigate (Claude Code plugin)
2
+
3
+ The `investigate@dx-do` plugin — for asking a DXO2 tenant investigative questions in natural language ("are there any hosts with high CPU right now?", "which services depend on host X?", "where's the noise coming from?") and having Claude carry the conversation through scope-clarification → discovery → query authoring → UI / analyzer handoff.
4
+
5
+ Lives under [`@dx-do/claude`](../README.md) — the umbrella package that hosts all dx-do Claude Code plugins.
6
+
7
+ ## What you get
8
+
9
+ - **`dx-do-query` MCP server** — auto-wired at plugin enable time. 21 tools across 4 modules (discovery, corpus, datastore, ui — see `dx-do help agentic-mcp`). Corpus tools surface 5 entities, 14 cookbooks, and 29 worked-example queries shipped via `@dx-do/corpus`.
10
+ - **`investigator` skill** — auto-loaded summary that reaches into the corpus for the right cookbook / entity / example before authoring a query. Teaches the decision tree, schema landmines, handoff phrasing.
11
+
12
+ (Sibling skills planned in this same plugin: `analyzer` for thresholding/anomaly work on a saved query's data, `organizer` for curating the user's saved-query catalog.)
13
+
14
+ ## Prerequisites
15
+
16
+ 1. **A `dx-do` binary the plugin can find.** The plugin's MCP server entry resolves `${DXDO_BIN:-dx-do}` — so either:
17
+ - Set `DXDO_BIN=/path/to/your/dx-do` in your shell environment (point it at `packages/cli/dist-bun/dx-do` from a source checkout if you don't want a global install), OR
18
+ - Put `dx-do` on `$PATH` the conventional way: `sudo cp packages/cli/dist-bun/dx-do /usr/local/bin/dx-do && sudo chown $USER /usr/local/bin/dx-do` (the chown is required on macOS Sequoia or AMFI SIGKILLs the binary), OR
19
+ - npm-installed: `npx @dx-do/cli` works once `@dx-do/cli` is published.
20
+
21
+ `DXDO_BIN` is the lowest-friction option for source-checkout devs — no `sudo`, no `/usr/local/bin/` mutation, and the binary always points at whatever you most recently rebuilt under `packages/cli/dist-bun/`.
22
+ 2. **A tenant config** at `~/.dxdo/<alias>.dxo2.config.json`. Default plugin invocation uses `default`; override with `DXDO_CONFIG_ALIAS=<your-alias>` in your shell environment before launching Claude Code.
23
+
24
+ > **About the experimental gate.** `dx-do agentic mcp` (and `dx-do ui start`) are currently marked experimental. The plugin's `plugin.json` already sets `DXDO_ENABLE_EXPERIMENTAL_COMMANDS=true` in the MCP-server spawn env, so users do **not** need to do anything special — Claude Code spawns the subprocess with the gate open. The same env var is needed if you ever invoke `dx-do agentic extract-claude-marketplace` from the shell yourself; see the install section below.
25
+
26
+ ## Install — for users with the `dx-do` binary
27
+
28
+ The marketplace + this plugin are embedded in every `dx-do` binary. Extract once (the env var opens the experimental gate so the command runs):
29
+
30
+ ```sh
31
+ DXDO_ENABLE_EXPERIMENTAL_COMMANDS=true \
32
+ dx-do agentic extract-claude-marketplace base-directory=~/
33
+ ```
34
+
35
+ Then in a Claude Code session:
36
+
37
+ ```
38
+ /plugin marketplace add ~/dx-do-claude-marketplace
39
+ /plugin install investigate@dx-do
40
+ /reload-plugins
41
+ ```
42
+
43
+ The extract command prints the exact slash-command sequence so you can copy-paste it into Claude Code. Plugin management is interactive-only — there is no shell `claude plugin install`.
44
+
45
+ ## Install — source-checkout dev
46
+
47
+ ```
48
+ /plugin marketplace add /Users/$USER/github/dx-do-mono/packages/claude
49
+ /plugin install investigate@dx-do
50
+ /reload-plugins
51
+ ```
52
+
53
+ (`packages/claude/` already has `.claude-plugin/marketplace.json` + per-plugin subdirs — same layout extract produces.)
54
+
55
+ ## Verify
56
+
57
+ After install, in a fresh Claude Code session:
58
+
59
+ ```
60
+ "What entities can you ground me in for the bound tenant?"
61
+ ```
62
+
63
+ Expected: Claude invokes the `investigator` skill (visible in the skill list), calls `corpus_sections` + `corpus_list('entities')`, and surfaces the universe / service / dxi_service / host / agent entries.
64
+
65
+ If Claude doesn't reach for the skill automatically, the description trigger isn't strong enough — file a follow-up.
66
+
67
+ ## What's in here
68
+
69
+ ```
70
+ .claude-plugin/
71
+ plugin.json ← plugin manifest (mcpServers + metadata)
72
+ skills/
73
+ investigator/
74
+ SKILL.md ← the auto-loaded investigator skill
75
+ ```
76
+
77
+ The skill points at content in `@dx-do/corpus` for the rich grounding (cookbooks, entities, queries). The MCP server `dx-do-query` (from `@dx-do/ui`) is the agent's tool surface.
78
+
79
+ ## Related
80
+
81
+ - [`@dx-do/claude` README](../README.md) — why one package, many plugins.
82
+ - `dx-do help agentic-mcp` — full tool surface + module flags.
83
+ - `@dx-do/corpus` — `cookbooks/`, `entities/`, `queries/` content the skill references.
84
+ - `~/.claude/plans/` (this Mac) — milestone plan.