@dx-do/cli 5.2.49 → 6.0.1

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,693 @@
1
+ ---
2
+ id: tas-cookbook
3
+ title: TAS cookbook — operations reference and recipe catalog
4
+ applies_to: tas
5
+ tags: [reference, recipes, authoring]
6
+ related: [tas-quickstart, gotchas, discovery-flow, run-query-vs-run-partial]
7
+ ---
8
+
9
+ # TAS cookbook
10
+
11
+ Full operation reference for TAS (`/tas/graph/query`) authoring, plus a
12
+ recipe catalog. Use after `tas-quickstart.md` when you need the breadth of
13
+ ops or a concrete pattern to start from. The schema's `.describe()`
14
+ metadata is the canonical wire spec — this cookbook organizes it by
15
+ purpose.
16
+
17
+ ## TAS at a glance
18
+
19
+ A TAS query returns a graph (`vertices` + `edges`) shaped by a single
20
+ recursive **filter tree**. Every filter node is `{ "op": "<NAME>", ... }` —
21
+ a discriminated union on `op`. Most ops can wrap an `input` filter
22
+ (recursive composition); leaf ops (`ALL`, `LAYER`, `LUCENE`, `VARIABLE`)
23
+ do not.
24
+
25
+ ```mermaid
26
+ flowchart LR
27
+ envelope["TasQuery envelope { filter, projection, limit, variables, ... }"] --> root["root filter (composite)"]
28
+ root --> leaves["leaves: ALL / ATTRIBUTE / LAYER / VERTEX / LUCENE / VARIABLE"]
29
+ root --> composers["composers: AND / OR / NOT"]
30
+ root --> shapers["shapers / collectors: TRAVERSE / TAKE_VERTICES / TAKE_EDGES / FOLLOW_PATH / COLLECT_*"]
31
+ composers --> root
32
+ shapers --> root
33
+ ```
34
+
35
+ ## Top-level envelope
36
+
37
+ Common fields:
38
+
39
+ | Field | Type | Purpose |
40
+ |-------|------|---------|
41
+ | `filter` | TasFilter | Root filter tree (required in practice) |
42
+ | `limit` | number | Cap returned vertices |
43
+ | `offset` | number | Pagination offset |
44
+ | `projection` | `"DETAILED" \| "BRIEF" \| "NO_TYPE"` | Vertex/edge attribute breadth |
45
+ | `projectionFilter` | `{ attributes: string[], attributeValueAsFields?: ... }` | Project specific attributes only |
46
+ | `order` | `[{ name, comparator, caseInsensitive, desc }]` | Sort order |
47
+ | `variables` | `[{ name, input: filter }]` | Named sub-filters reusable via `{op: "VARIABLE", name}` |
48
+ | `universe` | TasFilter | Restrict the working set before `filter` |
49
+ | `postFilter` | TasFilter | Filter applied after `filter` |
50
+ | `stateFilter` | VertexStateFilter | Restrict by vertex state |
51
+ | `includeStatus` | boolean | Adds a `states[]` array to the response (does NOT filter topology — see [Status section](#status--includestatus-and-the-states-response-array)). |
52
+ | `includeServices` | boolean | Adds service-attribution metadata to each vertex |
53
+ | `authorizationView` | string | Apply an auth view restriction |
54
+
55
+ `projection` only changes attribute breadth (`DETAILED` is the default for
56
+ "give me everything"). Use `projectionFilter.attributes[]` to project a
57
+ specific subset.
58
+
59
+ ## Leaf filters
60
+
61
+ ### `ALL`
62
+ Match every vertex. Use with a small `limit` for sampling.
63
+
64
+ ```json
65
+ { "op": "ALL" }
66
+ ```
67
+
68
+ ### `ATTRIBUTE`
69
+ The workhorse — match by one or more attribute expressions. The list of
70
+ expressions is AND-ed.
71
+
72
+ ```json
73
+ {
74
+ "op": "ATTRIBUTE",
75
+ "expressions": [
76
+ { "name": "type", "values": ["HOST"], "operator": "IN" }
77
+ ]
78
+ }
79
+ ```
80
+
81
+ `AttributeExpression` fields:
82
+
83
+ | Field | Notes |
84
+ |-------|-------|
85
+ | `name` | Attribute name (e.g. `type`, `name`, `hostname`, `k8s_namespace`) |
86
+ | `pointer` | JSON pointer for nested attribute lookup |
87
+ | `values` | Comparison values (regex pattern strings for `MATCHES`) |
88
+ | `operator` | `IN \| NOT_IN \| MATCHES \| NOT_MATCHES \| GE \| GT \| LE \| LT` |
89
+ | `comparator` | `LEXICAL \| NUMBER \| DATETIME` (default LEXICAL) |
90
+ | `caseInsensitive` | for MATCHES |
91
+ | `layer` | Optional: scope expression to a layer |
92
+
93
+ There is no `TYPE` or `ID` filter op — type is just an attribute named `type`,
94
+ and id selection is done via the `VERTEX` op (below).
95
+
96
+ ### `LAYER`
97
+ Restrict to a layer (`externalId` first segment, by convention).
98
+
99
+ ```json
100
+ { "op": "LAYER", "value": "ATC" }
101
+ ```
102
+
103
+ Or multiple layers:
104
+
105
+ ```json
106
+ { "op": "LAYER", "values": ["ATC", "INFRASTRUCTURE", "APM_INFRASTRUCTURE"] }
107
+ ```
108
+
109
+ Discover real layer names via `corpus_get("queries", "50-discover-custom-layers")`,
110
+ or by inspecting `externalId` prefixes on an `ALL` query.
111
+
112
+ ### `VERTEX`
113
+ Select by id or external id.
114
+
115
+ ```json
116
+ { "op": "VERTEX", "vertexId": [12345, 67890] }
117
+ ```
118
+
119
+ ```json
120
+ { "op": "VERTEX", "externalId": ["ATC:tx:checkout"] }
121
+ ```
122
+
123
+ ### `LUCENE`
124
+ Lucene-style query string (only on tenants with Lucene indexing — see
125
+ gotchas).
126
+
127
+ ```json
128
+ { "op": "LUCENE", "query": "name:Kubernetes*" }
129
+ ```
130
+
131
+ ### `VARIABLE`
132
+ Reference a named sub-filter declared in the top-level `variables[]` array.
133
+
134
+ ```json
135
+ { "op": "VARIABLE", "name": "k8s_hosts" }
136
+ ```
137
+
138
+ ### `SERVICE`
139
+ Restrict to vertices participating in a named service (or services).
140
+
141
+ ```json
142
+ {
143
+ "op": "SERVICE",
144
+ "values": ["payments-api"],
145
+ "includeServiceHierarchy": true
146
+ }
147
+ ```
148
+
149
+ ## Composition
150
+
151
+ ### `AND` / `OR`
152
+
153
+ ```json
154
+ { "op": "AND", "input": [filterA, filterB, ...] }
155
+ ```
156
+
157
+ ```json
158
+ { "op": "OR", "input": [filterA, filterB, ...] }
159
+ ```
160
+
161
+ ### `NOT`
162
+
163
+ ```json
164
+ { "op": "NOT", "input": filterA }
165
+ ```
166
+
167
+ `AND`/`OR` take an **array** in `input`; `NOT` takes a **single** filter.
168
+ Empty `AND`/`OR` arrays are rejected — see `gotchas.md`.
169
+
170
+ ### Variable reuse (`variables[]` + `VARIABLE`)
171
+
172
+ Declare named sub-filters at the top level, then reference them in the main
173
+ filter tree. Useful when the same vertex set is reused as a starting point.
174
+
175
+ ```json
176
+ {
177
+ "variables": [
178
+ { "name": "k8s_hosts", "input": { "op": "ATTRIBUTE", "expressions": [ ... ] } }
179
+ ],
180
+ "filter": {
181
+ "op": "TRAVERSE",
182
+ "input": { "op": "VARIABLE", "name": "k8s_hosts" },
183
+ "traverse": [{ "direction": "ANY", "repeat": 1 }]
184
+ },
185
+ ...
186
+ }
187
+ ```
188
+
189
+ There is no `ASSIGN` / `USE` op — the top-level `variables[]` array is the
190
+ mechanism.
191
+
192
+ ## Graph shaping
193
+
194
+ These wrap a base filter (`input`) and reshape its result.
195
+
196
+ ### `TRAVERSE`
197
+ Walk the graph from a starting set. Each `Traverse` step has `direction`,
198
+ `repeat` (max hops), and optional `vertexFilter` / `edgeFilter` / `next`
199
+ (nested traversal).
200
+
201
+ ```json
202
+ {
203
+ "op": "TRAVERSE",
204
+ "input": { "op": "ATTRIBUTE", "expressions": [...] },
205
+ "traverse": [{ "direction": "ANY", "repeat": 2 }],
206
+ "includeInput": true
207
+ }
208
+ ```
209
+
210
+ `direction`: `FORWARD | BACKWARD | ANY`. `includeInput: true` keeps the
211
+ starting vertices in the result; without it you only get the traversal
212
+ targets.
213
+
214
+ Multi-step (chained) traversal:
215
+
216
+ ```json
217
+ {
218
+ "op": "TRAVERSE",
219
+ "input": { "op": "ATTRIBUTE", "expressions": [...] },
220
+ "traverse": [
221
+ { "direction": "FORWARD", "repeat": 1,
222
+ "next": [{ "direction": "BACKWARD", "repeat": 2 }] }
223
+ ]
224
+ }
225
+ ```
226
+
227
+ ### `TAKE_VERTICES` / `TAKE_EDGES` / `TAKE_FLOWS`
228
+ Restrict the result to only vertices, only edges, or only flow records:
229
+
230
+ ```json
231
+ { "op": "TAKE_EDGES", "input": { "op": "TRAVERSE", ... } }
232
+ ```
233
+
234
+ Common pattern: traverse then `TAKE_EDGES` to get just the edges between two
235
+ sets of vertices.
236
+
237
+ ### `FOLLOW_PATH`
238
+ Directional path-following with hop limits and flow filtering. Useful for
239
+ "upstream / downstream" queries.
240
+
241
+ ```json
242
+ {
243
+ "op": "FOLLOW_PATH",
244
+ "input": filter,
245
+ "type": "DOWN",
246
+ "downHops": 3,
247
+ "followToLayers": ["INFRASTRUCTURE"]
248
+ }
249
+ ```
250
+
251
+ `type`: `UP | DOWN | BOTH | UP_THEN_DOWN | DOWN_THEN_UP | FULL | COVERAGE`.
252
+
253
+ ### `STATUS`
254
+ Restrict the input set by current vertex state (alerts, metrics, etc.).
255
+
256
+ ```json
257
+ {
258
+ "op": "STATUS",
259
+ "input": filter,
260
+ "statusFilter": { "op": "ALERT", ... }
261
+ }
262
+ ```
263
+
264
+ You can also use the top-level `stateFilter` field for the same effect.
265
+
266
+ > ⚠️ The `statusFilter`'s `STATE` leaf op (filtering by numeric status code) is
267
+ > currently a server-side no-op — `state[]` is silently ignored. Use the two-query
268
+ > client-side filter pattern in `cookbooks/gotchas` instead. The other state-filter
269
+ > ops (`ALERT`, `METRIC`, `VERTEX_ID`, `NAMESPACE`, `MANAGEMENT_MODULE`) work
270
+ > as expected.
271
+
272
+ ### `ADD_FLOWS` / `ADD_WIRES` / `ADD_WIRE_CONTEXT` / `ADD_TRANSITIONING_EDGES`
273
+ Augment the result with related flow/wire/transitioning-edge information
274
+ without changing the base vertex set.
275
+
276
+ - `ADD_FLOWS` — adds flow records (`direction: FORWARD | BACKWARD | ANY`).
277
+ - `ADD_WIRES` — adds wire connection records.
278
+ - `ADD_WIRE_CONTEXT` — adds wire context records with service context.
279
+ - `ADD_TRANSITIONING_EDGES` — adds edges whose endpoints are currently
280
+ transitioning state.
281
+
282
+ All four wrap an `input` filter and return the original vertex/edge result
283
+ enriched with the additional domain records.
284
+
285
+ ### `COVERAGE`
286
+ Compute coverage information over the input set. Use `COVERAGE` with TAS-level
287
+ alert/health context filters.
288
+
289
+ ### `JOIN`
290
+ Join two filter results. `type`: `INNER | LEFT | RIGHT | NOT`. Use sparingly —
291
+ most TAS queries are tree-shaped, not join-shaped.
292
+
293
+ ```json
294
+ { "op": "JOIN", "input": filterA, "rightInput": filterB, "type": "INNER" }
295
+ ```
296
+
297
+ ### `LEGACY`
298
+ Escape hatch for server-side legacy filter syntax. Use only when a modern
299
+ equivalent does not exist — the string is executed as an internal legacy query.
300
+
301
+ ```json
302
+ { "op": "LEGACY", "query": "..." }
303
+ ```
304
+
305
+ ### `PROJECT`
306
+ Return a pre-computed projection result by name. Rarely needed outside
307
+ server-generated queries.
308
+
309
+ ```json
310
+ { "op": "PROJECT", "name": "some-projection" }
311
+ ```
312
+
313
+ ## Collectors
314
+
315
+ Specialized filters that return aggregated information about the input set
316
+ rather than the vertices/edges themselves. Each result is keyed by `id` in the
317
+ `analytics[]` array of the `TasGraph` response.
318
+
319
+ | Op | Key field(s) | What it returns |
320
+ |----|--------------|----------------|
321
+ | `COLLECT_ATTRIBUTES` | `attributeName` (single string) | Distinct values of one attribute across the matched vertex set, with per-value count and (optionally) the vertex IDs that carry each value. Stack multiple instances inside an `AND` to collect several attributes in one round-trip. |
322
+ | `COLLECT_ATTRIBUTE_NAMES` | — | Distinct attribute names present on the matched vertex set. |
323
+ | `COLLECT_VERTEX_ID` | — | List of vertex IDs in the result set. |
324
+ | `COLLECT_COUNTS` | — | Vertex + edge counts (with optional per-type breakdown). |
325
+ | `COLLECT_GROUPING_INFO` | `grouping: [{name, layer}, ...]` | Hierarchical grouping breakdown along one or more grouping dimensions, with per-group counts and alert stats. |
326
+ | `COLLECT_CARD_INFO` | `tier`, `attributeName` | Card-shaped summary for one APM tier, grouped by a single attribute. |
327
+ | `COLLECT_EXPERIENCE_ATTRIBUTES` | `attributeName`, `selector` | Same shape as `COLLECT_ATTRIBUTES`, restricted to APM experience or business-transaction vertices. |
328
+
329
+ **Field-name landmine:** `COLLECT_ATTRIBUTES` is `attributeName` (singular). The `grouping[]` array shape lives on `COLLECT_GROUPING_INFO` — these are distinct ops with distinct payload shapes. Using `groupings`/`grouping` on `COLLECT_ATTRIBUTES` returns HTTP 500.
330
+
331
+ Collectors wrap an `input` filter. The `id` field on each collector maps to a
332
+ key in `TasGraph.analytics[]` — use multiple collectors inside an `AND` to
333
+ collect several summaries in a single round-trip.
334
+
335
+ ```json
336
+ {
337
+ "op": "AND",
338
+ "input": [
339
+ { "op": "ALL" },
340
+ { "op": "COLLECT_COUNTS", "id": "counts", "input": { "op": "ALL" } },
341
+ { "op": "COLLECT_ATTRIBUTE_NAMES", "id": "attrNames", "input": { "op": "ALL" } }
342
+ ]
343
+ }
344
+ ```
345
+
346
+ The schema's `.describe()` metadata documents the per-collector field details
347
+ (see `tas/response.ts` schemas via the package's `.d.ts`).
348
+
349
+ ## Status — `includeStatus` and the `states[]` response array
350
+
351
+ Setting `includeStatus: true` at the envelope level adds a `states[]`
352
+ array to the response alongside `vertices[]` / `edges[]`. **This is
353
+ purely additive** — the toggle does NOT filter the topology; it just
354
+ attaches state information for the vertices already in the result.
355
+
356
+ To filter topology BY state, use the `STATUS` op (or top-level
357
+ `stateFilter`) — those narrow the vertex set; `includeStatus` controls
358
+ whether the state rows are also serialized in the response. Most
359
+ callers want both: filter via `STATUS`, then `includeStatus: true` to
360
+ inspect the state alongside the matched topology.
361
+
362
+ ### `states[]` shape
363
+
364
+ Each entry is a per-`(vertex, alert OR metric)` row, so a single
365
+ vertex can have multiple state rows:
366
+
367
+ ```ts
368
+ type VertexStateResponseItem = {
369
+ vertexId: number;
370
+ alertId?: number; // populated for alert-driven state rows
371
+ metricId?: number; // populated for metric-driven state rows
372
+ stateExternalId?: {
373
+ vertexId: number;
374
+ alert?: string; // e.g. "sa://sa_status" — see rolled-up alert below
375
+ metric?: string;
376
+ };
377
+ status: number; // numeric severity — see mapping below
378
+ data?: {
379
+ alarm?: { total, critical, major, minor, information };
380
+ services?: Record<string, unknown>;
381
+ stateUpdated?: boolean;
382
+ };
383
+ startTime: number; // epoch ms when this state began
384
+ endTime: number; // epoch ms when it ended; far-future ⇒ ongoing
385
+ };
386
+ ```
387
+
388
+ ### Numeric `status` mapping
389
+
390
+ Per-tenant DXO2 convention (verified empirically — used by both
391
+ `states[].status` and `STATUS.statusFilter`'s `STATE` op `state[]`):
392
+
393
+ | `status` | Label |
394
+ |---|---|
395
+ | 0 | UNKNOWN |
396
+ | 1 | OK |
397
+ | 2 | MINOR |
398
+ | 3 | MAJOR |
399
+ | 4 | CRITICAL |
400
+
401
+ (See `cookbooks/gotchas` for the caveat that the canonical schema
402
+ under-documents this — and that the `STATE` filter op itself is
403
+ currently a server-side no-op until that's fixed.)
404
+
405
+ ### The rolled-up `sa://sa_status` alert
406
+
407
+ Every vertex carries a synthetic aggregate alert with
408
+ `stateExternalId.alert === "sa://sa_status"`. Its `status` is the
409
+ **worst severity across all of that vertex's individual alerts and
410
+ metrics** — i.e. the value the platform UI shows on the status badge.
411
+ Per-individual-alert and per-individual-metric rows can disagree with
412
+ this rollup (a vertex can have one CRITICAL alert and OK metrics; the
413
+ rollup is CRITICAL).
414
+
415
+ The rollup row's `data.alarm` block summarizes per-tier counts:
416
+ `{ total, critical, major, minor, information }`. Useful for
417
+ "how many alarms of each tier does this vertex carry" without
418
+ reading every per-alert row.
419
+
420
+ ### Reading state for a specific vertex
421
+
422
+ Match `states[].vertexId` against the vertex's `id`. Filter to the
423
+ rolled-up severity by also checking
424
+ `stateExternalId.alert === "sa://sa_status"`. Per-source severity is
425
+ the inverse — exclude that alert id and look at the per-alert /
426
+ per-metric rows.
427
+
428
+ ### Worked example: "what's the rolled-up status of these vertices?"
429
+
430
+ ```json
431
+ {
432
+ "filter": { "op": "VERTEX", "externalId": ["<your-id-1>", "<your-id-2>"] },
433
+ "includeStatus": true,
434
+ "limit": 50,
435
+ "projection": "DETAILED"
436
+ }
437
+ ```
438
+
439
+ Response (sketch):
440
+
441
+ ```json
442
+ {
443
+ "vertices": [{ "id": 5435, "externalId": "<your-id-1>", "attributes": { ... } }],
444
+ "states": [{
445
+ "vertexId": 5435,
446
+ "alertId": 774,
447
+ "stateExternalId": { "vertexId": 5435, "alert": "sa://sa_status" },
448
+ "status": 3,
449
+ "data": { "alarm": { "total": 1, "critical": 0, "major": 1, "minor": 0, "information": 0 } },
450
+ "startTime": 1768820848440,
451
+ "endTime": 1782097233000
452
+ }]
453
+ }
454
+ ```
455
+
456
+ `status: 3` ⇒ MAJOR; `data.alarm.major: 1` confirms the underlying
457
+ alarm count.
458
+
459
+ ### Common patterns
460
+
461
+ - **"Show me everything currently CRITICAL"** — the filter-server-side
462
+ path via `STATE` op is a no-op today. Use the two-query pattern
463
+ documented in `cookbooks/gotchas`: pull candidates with
464
+ `includeStatus: true`, client-filter to vertices whose rollup row
465
+ has `status === 4`, then issue a second query (e.g. TRAVERSE from
466
+ those externalIds) for downstream context.
467
+ - **"What alarms does this vertex have right now?"** — issue a
468
+ `VERTEX(externalId=[...])` filter with `includeStatus: true` and
469
+ read every `states[]` row whose `vertexId` matches; skip the
470
+ `sa://sa_status` row to enumerate per-source alerts.
471
+ - **"How long has this been bad?"** — `(endTime - startTime)` for the
472
+ most recent rollup row (or per-source row if you want the specific
473
+ alert's duration). A far-future `endTime` (e.g. `7505567987654`)
474
+ means the state is ongoing.
475
+
476
+ ## Recipe catalog
477
+
478
+ Each recipe describes a goal in plain English and gives the minimum filter
479
+ shape. Each links to a worked example shipped in the corpus —
480
+ `corpus_get("queries", "<id>")` returns the full payload + per-op
481
+ descriptions.
482
+
483
+ ### "Give me a sample of vertices to learn what's there"
484
+ `corpus_get("queries", "01-discover-vertices")`
485
+
486
+ ```json
487
+ { "filter": { "op": "ALL" }, "limit": 20, "projection": "DETAILED" }
488
+ ```
489
+
490
+ ### "Find vertices of type X (or several types)"
491
+ `corpus_get("queries", "02-discover-services")`
492
+
493
+ ```json
494
+ {
495
+ "filter": {
496
+ "op": "ATTRIBUTE",
497
+ "expressions": [
498
+ { "name": "type", "values": ["HOST", "AGENT"], "operator": "IN" }
499
+ ]
500
+ },
501
+ "limit": 100, "projection": "DETAILED"
502
+ }
503
+ ```
504
+
505
+ ### "Find vertices whose attribute matches a regex"
506
+ `corpus_get("queries", "10-filter-attribute-matches")`
507
+
508
+ ```json
509
+ {
510
+ "filter": {
511
+ "op": "ATTRIBUTE",
512
+ "expressions": [
513
+ { "name": "name", "values": [".*tixchange.*"],
514
+ "operator": "MATCHES", "caseInsensitive": true }
515
+ ]
516
+ },
517
+ "limit": 50, "projection": "DETAILED"
518
+ }
519
+ ```
520
+
521
+ ### "Find vertices in a specific layer"
522
+ `corpus_get("queries", "13-filter-layer")`
523
+
524
+ ```json
525
+ { "filter": { "op": "LAYER", "value": "ATC" }, "limit": 50, "projection": "DETAILED" }
526
+ ```
527
+
528
+ ### "Find vertices in any layer except a known set" (find unknown layers)
529
+ `corpus_get("queries", "50-discover-custom-layers")`
530
+
531
+ ```json
532
+ {
533
+ "filter": {
534
+ "op": "NOT",
535
+ "input": { "op": "LAYER",
536
+ "values": ["ATC", "INFRASTRUCTURE", "APM_INFRASTRUCTURE"] }
537
+ },
538
+ "limit": 200, "projection": "DETAILED"
539
+ }
540
+ ```
541
+
542
+ ### "Multi-condition AND (type AND name pattern)"
543
+ `corpus_get("queries", "11-filter-and-compose")`
544
+
545
+ ```json
546
+ {
547
+ "filter": {
548
+ "op": "AND",
549
+ "input": [
550
+ { "op": "ATTRIBUTE", "expressions": [{ "name": "type",
551
+ "values": ["BUSINESSTRANSACTION"], "operator": "IN" }] },
552
+ { "op": "ATTRIBUTE", "expressions": [{ "name": "name",
553
+ "values": ["/checkout.shtml", "/signon.shtml"], "operator": "IN" }] }
554
+ ]
555
+ },
556
+ "limit": 20, "projection": "DETAILED"
557
+ }
558
+ ```
559
+
560
+ ### "OR with a NOT (type X OR (type Y but not name matching ...))"
561
+ `corpus_get("queries", "12-filter-or-not")`
562
+
563
+ ```json
564
+ {
565
+ "filter": {
566
+ "op": "OR",
567
+ "input": [
568
+ { "op": "ATTRIBUTE", "expressions": [{ "name": "type",
569
+ "values": ["k8s_POD"], "operator": "IN" }] },
570
+ { "op": "AND", "input": [
571
+ { "op": "ATTRIBUTE", "expressions": [{ "name": "type",
572
+ "values": ["AGENT"], "operator": "IN" }] },
573
+ { "op": "NOT", "input": { "op": "ATTRIBUTE", "expressions": [
574
+ { "name": "name", "values": [".*Logstash.*"],
575
+ "operator": "MATCHES", "caseInsensitive": true } ] } }
576
+ ] }
577
+ ]
578
+ },
579
+ "limit": 50, "projection": "DETAILED"
580
+ }
581
+ ```
582
+
583
+ ### "N-hop neighborhood from a starting set"
584
+ `corpus_get("queries", "14-filter-traverse")`
585
+
586
+ ```json
587
+ {
588
+ "filter": {
589
+ "op": "TRAVERSE",
590
+ "input": { "op": "ATTRIBUTE", "expressions": [{ "name": "type",
591
+ "values": ["k8s_CLUSTER"], "operator": "IN" }] },
592
+ "traverse": [{ "direction": "ANY", "repeat": 2 }],
593
+ "includeInput": true
594
+ },
595
+ "limit": 100, "projection": "DETAILED"
596
+ }
597
+ ```
598
+
599
+ ### "Just the edges between a starting set and its neighborhood"
600
+ `corpus_get("queries", "15-filter-take-vertices-edges")`
601
+
602
+ ```json
603
+ {
604
+ "filter": {
605
+ "op": "TAKE_EDGES",
606
+ "input": {
607
+ "op": "TRAVERSE",
608
+ "input": { "op": "ATTRIBUTE", "expressions": [{ "name": "type",
609
+ "values": ["k8s_CLUSTER"], "operator": "IN" }] },
610
+ "traverse": [{ "direction": "ANY", "repeat": 2 }],
611
+ "includeInput": true
612
+ }
613
+ },
614
+ "limit": 100, "projection": "DETAILED"
615
+ }
616
+ ```
617
+
618
+ ### "Project only the attributes I care about"
619
+ `corpus_get("queries", "16-filter-projection")`
620
+
621
+ ```json
622
+ {
623
+ "filter": { "op": "ATTRIBUTE", "expressions": [
624
+ { "name": "type", "values": ["k8s_POD"], "operator": "IN" } ] },
625
+ "limit": 30,
626
+ "projectionFilter": {
627
+ "attributes": ["name", "type", "hostname", "k8s_namespace", "k8s_status"]
628
+ }
629
+ }
630
+ ```
631
+
632
+ ### "Reuse the same starting set in two places"
633
+ `corpus_get("queries", "18-filter-variable-reuse")`
634
+
635
+ ```json
636
+ {
637
+ "variables": [
638
+ { "name": "k8s_hosts", "input": { "op": "ATTRIBUTE", "expressions": [
639
+ { "name": "type", "values": ["HOST"], "operator": "IN" } ] } }
640
+ ],
641
+ "filter": {
642
+ "op": "TRAVERSE",
643
+ "input": { "op": "VARIABLE", "name": "k8s_hosts" },
644
+ "traverse": [{ "direction": "ANY", "repeat": 1 }],
645
+ "includeInput": true
646
+ },
647
+ "limit": 50, "projection": "DETAILED"
648
+ }
649
+ ```
650
+
651
+ ### "Sort results and include status info"
652
+ `corpus_get("queries", "19-filter-order-statefilter")`
653
+
654
+ ```json
655
+ {
656
+ "filter": { "op": "ATTRIBUTE", "expressions": [
657
+ { "name": "type", "values": ["AGENT"], "operator": "IN" } ] },
658
+ "order": [{ "name": "name", "desc": false, "caseInsensitive": true }],
659
+ "includeStatus": true,
660
+ "limit": 20, "projection": "DETAILED"
661
+ }
662
+ ```
663
+
664
+ Response carries `states[]` alongside `vertices[]`. To read the
665
+ rolled-up severity per vertex, find each vertex's `states[]` row
666
+ where `stateExternalId.alert === "sa://sa_status"` and read
667
+ `status` (0=UNKNOWN, 1=OK, 2=MINOR, 3=MAJOR, 4=CRITICAL). See the
668
+ Status section above for the full shape and common patterns.
669
+
670
+ ### "Free-text Lucene query (where supported)"
671
+ `corpus_get("queries", "17-filter-lucene")` — may return HTTP 400 on tenants
672
+ without Lucene indexing.
673
+
674
+ ```json
675
+ { "filter": { "op": "LUCENE", "query": "name:Kubernetes*" },
676
+ "limit": 20, "projection": "DETAILED" }
677
+ ```
678
+
679
+ ## Authoring tips
680
+
681
+ - Start broad (`ALL` with small `limit`) to discover vocabulary, then
682
+ progressively narrow with `ATTRIBUTE` and `LAYER`.
683
+ - For "find X and its dependencies", build it as `TRAVERSE` over a base
684
+ `ATTRIBUTE` filter.
685
+ - For "find edges between X and Y", build `TRAVERSE` then wrap in `TAKE_EDGES`.
686
+ - When the same set is reused (e.g. base set and its neighborhood), declare
687
+ it in `variables[]` and reference via `{op: "VARIABLE", name}`.
688
+ - Default `projection: "DETAILED"` if you do not yet know which attributes
689
+ you need; switch to `projectionFilter.attributes[]` once you do.
690
+ - Verify sub-trees with `run_partial_query` (see `run-query-vs-run-partial.md`)
691
+ rather than authoring throwaway test queries.
692
+ - See `gotchas.md` for the common `expressions` (array, not `expression`),
693
+ `input` (not `filters`), and layer-name pitfalls.