@objectstack/observability 17.1.0 → 17.3.0

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,485 @@
1
1
  # @objectstack/observability
2
2
 
3
+ ## 17.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 37e82eb: Surface a licensed `max_nodes` oversell to operators as telemetry
8
+
9
+ `os serve` already warned loudly at boot when `OS_CLUSTER_REPLICAS` declared more
10
+ nodes than the licence gate admits, but that warning existed only in one
11
+ process's startup output: an operator who scaled past their cap three weeks ago
12
+ had no way to ask the question today, and no way to alert on it. The same
13
+ advisory verdict is now also published through the deployment's configured
14
+ metrics backend, so it reaches the place operators already look.
15
+
16
+ Three names join `SEMCONV` in `@objectstack/observability`, emitted once per boot
17
+ by `os serve` when a remote cluster driver is configured, each labelled with the
18
+ gate's own verdict vocabulary (`admitted` / `capped` / `refused`):
19
+
20
+ - `cluster_declared_nodes` (gauge) — the replica count the operator **declared**;
21
+ - `cluster_admitted_nodes` (gauge) — how many of them the licence **admits**;
22
+ - `cluster_node_cap_verdicts_total` (counter) — one increment per process boot
23
+ that consulted the gate, so an alert stays writable after a one-shot gauge has
24
+ aged out of a push-based backend.
25
+
26
+ **Visibility only — the cap remains advisory and nothing is refused.** The gate is
27
+ consulted once per process at boot, every replica computes the same verdict, and
28
+ none can know whether it is one of the admitted ones, so all of them still join.
29
+ The names say so on purpose: this process has no cluster membership view at all,
30
+ so a series called `cluster_nodes` or `cluster_active_nodes` would be a false
31
+ statement dressed as telemetry. Nothing here counts peers, and no accept/reject
32
+ behaviour changed.
33
+
34
+ Absence is meaningful rather than an instrumentation gap: a single-node
35
+ deployment never consults the gate and emits nothing, and an emission also needs
36
+ a metrics backend configured via `OS_OBS_EXPORTER`.
37
+
38
+ ### Patch Changes
39
+
40
+ - e7191ce: fix(build): give each `exports` condition its own `types` target in the 28 dual-build packages (#13112)
41
+
42
+ **Published-surface change, zero runtime change.** No emitted byte moves; what
43
+ moves is which declaration file a resolver READS. Maintainer ruling 2026-08-29
44
+ (decision batch #3, verbatim 「同意」) chose declaring the files over deleting
45
+ them.
46
+
47
+ ## What was wrong
48
+
49
+ These 28 packages are `"type": "module"` and dual-built, and each spelled one
50
+ `types` condition as a **sibling** of `import`/`require`:
51
+
52
+ ```json
53
+ "exports": { ".": {
54
+ "types": "./dist/index.d.ts", "import": "./dist/index.js", "require": "./dist/index.cjs"
55
+ } }
56
+ ```
57
+
58
+ A sibling `types` answers for **both** conditions, so a CommonJS consumer was
59
+ handed `dist/index.d.ts` — an ES-module declaration, because the package is
60
+ `"type": "module"` — for an entry point it reaches with `require`. Measured with
61
+ `tsc --traceResolution` on a `"type": "commonjs"` fixture at `moduleResolution:
62
+ node16`:
63
+
64
+ ```
65
+ error TS1479: The current file is a CommonJS module whose imports will produce
66
+ 'require' calls; however, the referenced file is an ECMAScript module and cannot
67
+ be imported with 'require'.
68
+ ```
69
+
70
+ The JavaScript at `dist/index.cjs` loads perfectly (`check:dual-build-cjs-loads`
71
+ has asserted that for months). It is the **types** that told the consumer the
72
+ supported `require` entry point could not be required. The `dist/index.d.cts`
73
+ twin tsup emits beside it — 36 files, 5,517,701 B on this build — was named by
74
+ no condition at all and shipped in every tarball unreachable.
75
+
76
+ ## What changed
77
+
78
+ Each condition now names its own declaration, the shape TypeScript documents:
79
+
80
+ ```json
81
+ "exports": { ".": {
82
+ "import": { "types": "./dist/index.d.ts", "default": "./dist/index.js" },
83
+ "require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" }
84
+ } }
85
+ ```
86
+
87
+ 33 entry points across 27 packages, subpaths included. The root `types` field is
88
+ untouched, so `node10` resolvers are unaffected; the `import` condition resolves
89
+ exactly what it resolved before, measured as an unchanged control in the same
90
+ run.
91
+
92
+ ## `@objectstack/core` is deliberately NOT changed
93
+
94
+ Splitting a declaration in two makes TypeScript compare it nominally, and
95
+ `ObjectKernel` carries a `private plugins` member that reaches every plugin
96
+ through `PluginContext.getKernel()`. With core split, whole-repo `pnpm build`
97
+ fails in `@objectstack/verify` with 5 × TS2345 ("Types have separate
98
+ declarations of a private property 'plugins'"); with core held back and the
99
+ other 27 split, 71/71 tasks pass. So core keeps the sibling-`types` shape and
100
+ its two `.d.cts` files (220,854 B) stay unreachable, declared as such in
101
+ `check:dual-build-cjs-loads`. Splitting it needs a decision about core's public
102
+ types, not about an exports map.
103
+
104
+ ## For consumers
105
+
106
+ - **ESM consumers: nothing changes.** Same declaration file, byte for byte.
107
+ - **CJS consumers under `node16`/`nodenext`: TS1479 goes away** and the
108
+ declarations they get are the ones built for CommonJS.
109
+ - **`node10` / `moduleResolution: node` consumers: nothing changes** — they never
110
+ read `exports`.
111
+ - Nothing is removed: every path that resolved before still resolves.
112
+
113
+ Packages that are CJS-first (`require` → `./dist/index.js`, no `"type": "module"`)
114
+ were already correct and are untouched — their `dist/index.d.ts` really is the
115
+ CommonJS declaration. Their ESM mirror (an unreachable `.d.mts` under the
116
+ `import` condition) is a separate, larger population and is filed separately per
117
+ the ruling, not fixed here.
118
+
119
+ `check:dual-build-cjs-loads` grew a fourth invariant (TYPED) that reds on the old
120
+ shape, so the drift cannot return silently.
121
+ - Updated dependencies [809d417]
122
+ - Updated dependencies [387e231]
123
+ - Updated dependencies [f794e4e]
124
+ - Updated dependencies [cae2169]
125
+ - Updated dependencies [b812a54]
126
+ - Updated dependencies [2d4fa75]
127
+ - Updated dependencies [0e4e51b]
128
+ - Updated dependencies [e84bbf6]
129
+ - Updated dependencies [effae80]
130
+ - Updated dependencies [d62f990]
131
+ - Updated dependencies [c45d8e6]
132
+ - Updated dependencies [2e3e8c7]
133
+ - Updated dependencies [e621291]
134
+ - Updated dependencies [40a93b5]
135
+ - Updated dependencies [d5b330d]
136
+ - Updated dependencies [dda969c]
137
+ - Updated dependencies [1f45690]
138
+ - Updated dependencies [277948f]
139
+ - Updated dependencies [8bdd955]
140
+ - Updated dependencies [f3bbbef]
141
+ - Updated dependencies [4f24e9d]
142
+ - Updated dependencies [474242f]
143
+ - Updated dependencies [63cd487]
144
+ - Updated dependencies [bd4aa4e]
145
+ - Updated dependencies [803eaab]
146
+ - Updated dependencies [f8e8f03]
147
+ - Updated dependencies [eae824e]
148
+ - Updated dependencies [f6fa22c]
149
+ - Updated dependencies [8a483b3]
150
+ - Updated dependencies [97bcd99]
151
+ - Updated dependencies [df59de0]
152
+ - Updated dependencies [96e25a8]
153
+ - Updated dependencies [f75a38a]
154
+ - Updated dependencies [7a25e7d]
155
+ - Updated dependencies [1fa05a6]
156
+ - Updated dependencies [c85a265]
157
+ - Updated dependencies [dcb10a5]
158
+ - Updated dependencies [773a999]
159
+ - Updated dependencies [35dffea]
160
+ - Updated dependencies [776a098]
161
+ - Updated dependencies [5060877]
162
+ - Updated dependencies [4f6325d]
163
+ - Updated dependencies [52954c0]
164
+ - Updated dependencies [2aa8456]
165
+ - Updated dependencies [93809a3]
166
+ - Updated dependencies [7c0d0c3]
167
+ - Updated dependencies [daae7aa]
168
+ - Updated dependencies [8dc22d6]
169
+ - Updated dependencies [279431e]
170
+ - Updated dependencies [948dd6b]
171
+ - Updated dependencies [3b4c56c]
172
+ - Updated dependencies [ae8edd2]
173
+ - Updated dependencies [e25403c]
174
+ - Updated dependencies [64baa68]
175
+ - Updated dependencies [9fa70d7]
176
+ - Updated dependencies [09db64a]
177
+ - Updated dependencies [92916e7]
178
+ - Updated dependencies [a84f3ea]
179
+ - Updated dependencies [f2eaae8]
180
+ - Updated dependencies [c09451b]
181
+ - Updated dependencies [ba64877]
182
+ - Updated dependencies [7345308]
183
+ - Updated dependencies [79b6a22]
184
+ - Updated dependencies [30d96ab]
185
+ - Updated dependencies [f658793]
186
+ - Updated dependencies [c95ad19]
187
+ - Updated dependencies [e58ea8b]
188
+ - Updated dependencies [4a17645]
189
+ - Updated dependencies [3795c5f]
190
+ - Updated dependencies [8ab926b]
191
+ - Updated dependencies [7317cf2]
192
+ - Updated dependencies [e25e839]
193
+ - Updated dependencies [5997207]
194
+ - Updated dependencies [8b13cc8]
195
+ - Updated dependencies [4a4a35d]
196
+ - Updated dependencies [86e765a]
197
+ - Updated dependencies [1d7e76a]
198
+ - Updated dependencies [53dc739]
199
+ - Updated dependencies [fd289be]
200
+ - Updated dependencies [03bf7b1]
201
+ - Updated dependencies [f90e820]
202
+ - Updated dependencies [18d816a]
203
+ - Updated dependencies [e8bd715]
204
+ - Updated dependencies [b91c351]
205
+ - Updated dependencies [a28a3c0]
206
+ - Updated dependencies [daeaaf9]
207
+ - Updated dependencies [c459da6]
208
+ - Updated dependencies [e914733]
209
+ - Updated dependencies [f887e52]
210
+ - Updated dependencies [881f8d8]
211
+ - Updated dependencies [3bfa1e6]
212
+ - Updated dependencies [901355c]
213
+ - Updated dependencies [34ce8e7]
214
+ - Updated dependencies [33681ea]
215
+ - Updated dependencies [4635f3e]
216
+ - Updated dependencies [ee3595c]
217
+ - Updated dependencies [b2eab95]
218
+ - Updated dependencies [93940d4]
219
+ - Updated dependencies [3a04b01]
220
+ - Updated dependencies [45b9051]
221
+ - Updated dependencies [b9e9227]
222
+ - Updated dependencies [d395692]
223
+ - Updated dependencies [5894d30]
224
+ - Updated dependencies [a3765f6]
225
+ - Updated dependencies [e22158f]
226
+ - Updated dependencies [7404925]
227
+ - Updated dependencies [0c2334f]
228
+ - Updated dependencies [778c59f]
229
+ - Updated dependencies [d2619fd]
230
+ - Updated dependencies [6acb11a]
231
+ - Updated dependencies [33c5fd3]
232
+ - Updated dependencies [20b0fdb]
233
+ - Updated dependencies [905019b]
234
+ - Updated dependencies [a286411]
235
+ - Updated dependencies [98c0d33]
236
+ - Updated dependencies [368a82e]
237
+ - Updated dependencies [a3d5724]
238
+ - Updated dependencies [93ea19b]
239
+ - Updated dependencies [9ee2dcf]
240
+ - Updated dependencies [8cb96ec]
241
+ - Updated dependencies [8f10a79]
242
+ - Updated dependencies [6269a55]
243
+ - Updated dependencies [0fb8760]
244
+ - Updated dependencies [e5ce2ed]
245
+ - Updated dependencies [be21955]
246
+ - Updated dependencies [bc56e18]
247
+ - Updated dependencies [be21955]
248
+ - Updated dependencies [a9ee989]
249
+ - Updated dependencies [4d0d944]
250
+ - Updated dependencies [15d58db]
251
+ - Updated dependencies [d63b014]
252
+ - Updated dependencies [9abe4e4]
253
+ - Updated dependencies [2cc7122]
254
+ - Updated dependencies [50d6c92]
255
+ - Updated dependencies [9e0ba21]
256
+ - Updated dependencies [311433f]
257
+ - Updated dependencies [3e5ad08]
258
+ - Updated dependencies [9abe4e4]
259
+ - Updated dependencies [b7131f3]
260
+ - Updated dependencies [e5812fa]
261
+ - Updated dependencies [7085f90]
262
+ - Updated dependencies [dee4dd4]
263
+ - Updated dependencies [ce7e497]
264
+ - Updated dependencies [51ecb2f]
265
+ - Updated dependencies [9086761]
266
+ - Updated dependencies [42a117b]
267
+ - Updated dependencies [1401ae7]
268
+ - Updated dependencies [4297fe7]
269
+ - Updated dependencies [e398863]
270
+ - Updated dependencies [d16df74]
271
+ - Updated dependencies [f11fc61]
272
+ - Updated dependencies [e808890]
273
+ - Updated dependencies [8f79379]
274
+ - Updated dependencies [e6ca40e]
275
+ - Updated dependencies [0c77ea4]
276
+ - Updated dependencies [52954c0]
277
+ - Updated dependencies [89eb997]
278
+ - Updated dependencies [aa5994e]
279
+ - Updated dependencies [be93457]
280
+ - Updated dependencies [a65db76]
281
+ - Updated dependencies [15eb2c9]
282
+ - Updated dependencies [5691b07]
283
+ - Updated dependencies [2a6122b]
284
+ - Updated dependencies [225e769]
285
+ - Updated dependencies [8af88dd]
286
+ - Updated dependencies [fb5fbb8]
287
+ - Updated dependencies [d7b3963]
288
+ - Updated dependencies [b72db01]
289
+ - Updated dependencies [dce5cd4]
290
+ - Updated dependencies [177ebdc]
291
+ - Updated dependencies [8d237b4]
292
+ - Updated dependencies [2d2e6f0]
293
+ - Updated dependencies [2d8dd8d]
294
+ - Updated dependencies [22d573e]
295
+ - Updated dependencies [b5a2398]
296
+ - Updated dependencies [348860c]
297
+ - Updated dependencies [5383fa6]
298
+ - Updated dependencies [5b3ff63]
299
+ - Updated dependencies [1a6a19c]
300
+ - Updated dependencies [527e050]
301
+ - Updated dependencies [dd33bf9]
302
+ - Updated dependencies [4cb2a90]
303
+ - Updated dependencies [74a7804]
304
+ - Updated dependencies [53d3689]
305
+ - Updated dependencies [b3a63d3]
306
+ - Updated dependencies [033a34c]
307
+ - Updated dependencies [4d25d22]
308
+ - Updated dependencies [1ffee51]
309
+ - Updated dependencies [5ae4303]
310
+ - Updated dependencies [ece4dad]
311
+ - Updated dependencies [e9b377e]
312
+ - Updated dependencies [146f448]
313
+ - Updated dependencies [735f5c7]
314
+ - Updated dependencies [a7e18de]
315
+ - Updated dependencies [366f895]
316
+ - Updated dependencies [dc75ba8]
317
+ - Updated dependencies [cce0aa9]
318
+ - Updated dependencies [e764507]
319
+ - Updated dependencies [cff17af]
320
+ - Updated dependencies [39404f3]
321
+ - Updated dependencies [ca1965f]
322
+ - Updated dependencies [8619f95]
323
+ - Updated dependencies [b706af9]
324
+ - Updated dependencies [fc9ba76]
325
+ - Updated dependencies [0f94cc7]
326
+ - Updated dependencies [a11c1a5]
327
+ - Updated dependencies [71f9cd1]
328
+ - Updated dependencies [ee17d86]
329
+ - Updated dependencies [cdbd920]
330
+ - Updated dependencies [18c432e]
331
+ - Updated dependencies [3c418c4]
332
+ - Updated dependencies [fa8715a]
333
+ - Updated dependencies [a933ed7]
334
+ - Updated dependencies [b3ca463]
335
+ - Updated dependencies [a933ed7]
336
+ - Updated dependencies [0d4a6a8]
337
+ - Updated dependencies [518d5e5]
338
+ - Updated dependencies [6643ba1]
339
+ - Updated dependencies [eeba2ef]
340
+ - Updated dependencies [ec4c4d2]
341
+ - Updated dependencies [424f73c]
342
+ - Updated dependencies [cccbe51]
343
+ - Updated dependencies [a8d6b1d]
344
+ - Updated dependencies [e4a7695]
345
+ - Updated dependencies [87075b1]
346
+ - Updated dependencies [fc58a99]
347
+ - Updated dependencies [14cfc00]
348
+ - Updated dependencies [1c6f7b4]
349
+ - Updated dependencies [e854a53]
350
+ - Updated dependencies [dfebfc8]
351
+ - Updated dependencies [d028b37]
352
+ - Updated dependencies [122ef38]
353
+ - Updated dependencies [4a37870]
354
+ - Updated dependencies [428f9b2]
355
+ - Updated dependencies [aa7ff56]
356
+ - Updated dependencies [c41b42e]
357
+ - Updated dependencies [c4db311]
358
+ - Updated dependencies [750fff5]
359
+ - Updated dependencies [c19035e]
360
+ - Updated dependencies [ececf7a]
361
+ - Updated dependencies [d173125]
362
+ - Updated dependencies [8eeca27]
363
+ - Updated dependencies [8425c17]
364
+ - Updated dependencies [a5ef1d8]
365
+ - Updated dependencies [772d5de]
366
+ - Updated dependencies [ce80ec2]
367
+ - Updated dependencies [b372318]
368
+ - Updated dependencies [97a2263]
369
+ - Updated dependencies [29d0676]
370
+ - Updated dependencies [0169d49]
371
+ - Updated dependencies [6bd3231]
372
+ - Updated dependencies [d2b5ba8]
373
+ - Updated dependencies [b799ac5]
374
+ - Updated dependencies [8f74307]
375
+ - Updated dependencies [d23dc08]
376
+ - Updated dependencies [644ad50]
377
+ - Updated dependencies [0da7cd2]
378
+ - Updated dependencies [28a5c3e]
379
+ - Updated dependencies [4bc18e5]
380
+ - @objectstack/spec@17.3.0
381
+
382
+ ## 17.2.0
383
+
384
+ ### Minor Changes
385
+
386
+ - 914c413: fix(observability): **BREAKING** — `http_request_errors_total` is retired (ADR-0049 enforce-or-remove, #9834)
387
+
388
+ **⛔ If you have a Grafana panel, an alert rule or a recording rule keyed on
389
+ `http_request_errors_total`, it will read a FLAT ZERO after this upgrade.** That
390
+ zero is the removal, not a healthy server, and it is the one way this change can
391
+ hurt you — nothing throws, nothing warns, the series simply stops receiving
392
+ samples. Rewrite the query before you deploy.
393
+
394
+ Maintainer ruling 2026-08-20: **RETIRE**. The name was declared in `SEMCONV` as
395
+ part of a stable namespace *"so hosts can wire alerts/dashboards against it"*,
396
+ but the only emitter was `@objectstack/runtime`'s `instrumentRouteHandler`,
397
+ applied only by the dispatcher's own route Proxy — so the series never saw
398
+ auth's `getRawApp()` mount, the REST data API via `RouteManager`, or any other
399
+ inbound surface. Its two siblings in the same HTTP family moved to the
400
+ `IHttpServer.afterResponse` transport seam (`http_requests_total`, #9650/#9835;
401
+ `http_request_duration_ms`, #9834/#10004) and this one could not follow:
402
+ `HttpResponseObservation` carries `{method, routePattern, status, elapsedMs}`
403
+ and **no throw signal of any kind**, so every transport-side shape would have
404
+ counted a *different* population rather than the same one more widely.
405
+
406
+ Migration (FROM → TO):
407
+
408
+ | Wrote | Write instead |
409
+ |---|---|
410
+ | `rate(http_request_errors_total[5m])` in a panel or alert | `rate(http_requests_total{status=~"5.."}[5m])` — emitted by the transport, so it covers every inbound surface instead of the dispatcher's routes only |
411
+ | `sum by (route) (http_request_errors_total)` | `sum by (route) (http_requests_total{status=~"5.."})` |
412
+ | `SEMCONV.httpRequestErrorsTotal` / `RUNTIME_METRICS.httpRequestErrorsTotal` in host code | Delete the read. Both members are gone; `tsc` reports the missing property at the read site. |
413
+
414
+ One-line fix: replace the metric name with `http_requests_total{status=~"5.."}`.
415
+
416
+ <!-- adr-0087: registered http-request-errors-total-retired -->
417
+
418
+ **The replacement is wider, not merely different.** The retired counter was
419
+ divergent from a 5xx rate in *both* directions, measured: the dispatcher answers
420
+ its own errors through `errorResponseBase`, which sets a status and does **not**
421
+ re-throw — so the counter **missed** those — while its `catch` incremented
422
+ unconditionally, so a **thrown 4xx WAS counted** as an error. And
423
+ `http_requests_total` already carries a `status` label, so a status-class error
424
+ counter was fully derivable from data the transport already publishes. Prove the
425
+ new query wider rather than merely non-empty: make an auth route or a REST
426
+ data-API route answer 5xx and confirm it moves, where the retired counter would
427
+ not have moved at all.
428
+
429
+ **If what you were actually alerting on was "a handler threw rather than
430
+ returning an error envelope"** — the one signal this counter uniquely carried —
431
+ that is the `errorReporter`, not a metric. Wire an `ErrorReporter` adapter
432
+ (Sentry / Datadog / your own); it still fires on every 5xx throw and is
433
+ untouched by this change.
434
+
435
+ What is NOT removed: `http_requests_total`, `http_request_duration_ms`,
436
+ request-id propagation, the 5xx error reporter, and the
437
+ `res.__obsRecordedError` side channel that carries a swallowed error to it. The
438
+ dispatcher still instruments every route it mounts; it just no longer publishes
439
+ a fourth series whose name promised more coverage than it had.
440
+
441
+ ### Patch Changes
442
+
443
+ - Updated dependencies [6936d07]
444
+ - Updated dependencies [59eb04d]
445
+ - Updated dependencies [9f05b7d]
446
+ - Updated dependencies [7d2d112]
447
+ - Updated dependencies [5fa0d72]
448
+ - Updated dependencies [02b3b07]
449
+ - Updated dependencies [914c413]
450
+ - Updated dependencies [55809a0]
451
+ - Updated dependencies [52db1d1]
452
+ - Updated dependencies [5649efb]
453
+ - Updated dependencies [2306a76]
454
+ - Updated dependencies [e5ea701]
455
+ - Updated dependencies [a40dcc1]
456
+ - Updated dependencies [def0d3e]
457
+ - Updated dependencies [8d0bb79]
458
+ - Updated dependencies [5acb58d]
459
+ - Updated dependencies [2e3cf95]
460
+ - Updated dependencies [4c93387]
461
+ - Updated dependencies [a037f7c]
462
+ - Updated dependencies [3ee8ddf]
463
+ - Updated dependencies [16cef97]
464
+ - Updated dependencies [a79bd35]
465
+ - Updated dependencies [6ceaa4b]
466
+ - Updated dependencies [15ea214]
467
+ - Updated dependencies [de19489]
468
+ - Updated dependencies [c684d00]
469
+ - Updated dependencies [923c424]
470
+ - Updated dependencies [1ec36b7]
471
+ - Updated dependencies [5f2e54c]
472
+ - Updated dependencies [189373b]
473
+ - Updated dependencies [35ad101]
474
+ - Updated dependencies [ceb33a9]
475
+ - Updated dependencies [73d9795]
476
+ - Updated dependencies [8012960]
477
+ - Updated dependencies [f34f56b]
478
+ - Updated dependencies [f399618]
479
+ - Updated dependencies [75e9301]
480
+ - Updated dependencies [2810695]
481
+ - @objectstack/spec@17.2.0
482
+
3
483
  ## 17.1.0
4
484
 
5
485
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -76,15 +76,20 @@ var SEMCONV = {
76
76
  * body parse included — not the handler's share of it.
77
77
  */
78
78
  httpRequestDurationMs: "http_request_duration_ms",
79
- /**
80
- * Counter, labels: `method`, `route`. Incremented when an in-flight
81
- * handler throws after the response is sent. Emitted by
82
- * `@objectstack/runtime`'s `instrumentRouteHandler`, and NOT movable to
83
- * the seam above as-is: the observation carries a status but no throw
84
- * signal, so a transport-side emitter would count a different population
85
- * (#9834 records the fork).
86
- */
87
- httpRequestErrorsTotal: "http_request_errors_total",
79
+ // ⛔ RETIRED — `http_request_errors_total` was removed in
80
+ // `@objectstack/observability` 17.2.0 (#9834, ADR-0049 enforce-or-remove).
81
+ // Do not re-add the name. It was DECLARED here as a stable server-wide
82
+ // signal and EMITTED only from `@objectstack/runtime`'s per-route wrapper,
83
+ // on a THROWN handler so it never saw auth's `getRawApp()` mount, the
84
+ // REST data API, or any error a handler answered politely through
85
+ // `errorResponseBase` (which sets a status and does not re-throw). No
86
+ // transport-side emitter could preserve that population either: the
87
+ // `IHttpServer.afterResponse` observation carries `{method, routePattern,
88
+ // status, elapsedMs}` and no throw signal at all.
89
+ // ⇒ Read the 5xx rate from `http_requests_total{status=~"5.."}` instead.
90
+ // The transport emits that family through the seam, so it covers every
91
+ // inbound surface (#9650 / #9835 / #10004) and carries the status label
92
+ // this counter only stood in for. Maintainer ruling 2026-08-20.
88
93
  // ── Storage — emitted by `@objectstack/service-storage` adapters ──
89
94
  /** Counter, labels: `adapter` (`local`|`s3`|…), `op` (`get`|`put`|`delete`|`head`), `result` (`ok`|`error`). */
90
95
  storageOperationsTotal: "storage_operations_total",
@@ -143,12 +148,63 @@ var SEMCONV = {
143
148
  /** Histogram (ms). */
144
149
  registryLookupDurationMs: "registry_lookup_duration_ms",
145
150
  /** Counter, labels: `source` (`r2`|`http`|`local`), `result` (`hit`|`miss`|`error`). */
146
- registrySourceFetchesTotal: "registry_source_fetches_total"
151
+ registrySourceFetchesTotal: "registry_source_fetches_total",
152
+ // ── Cluster licensing — emitted by `@objectstack/cli`'s `os serve` at boot ──
153
+ //
154
+ // ⚠️ Every name in this group is a reading of what the operator DECLARED
155
+ // and what the licence gate SAID about that declaration. **None of them is
156
+ // a membership reading**, and none may be renamed into one. At the moment
157
+ // `os serve` consults the multi-node gate, the process has no cluster
158
+ // membership view at all: `nodeId` is generated randomly per process, there
159
+ // is no join/leave registry, and the only count in existence is
160
+ // `OS_CLUSTER_REPLICAS` — an operator-declared desired count that is
161
+ // identical in every replica. A series called `cluster_nodes` or
162
+ // `cluster_active_nodes` fed from here would be a false statement dressed
163
+ // as telemetry, so the honesty lives in the NAMES: `declared` is what the
164
+ // operator wrote, `admitted` is what the gate says fits the licence.
165
+ //
166
+ // The cap these describe is ADVISORY and is not enforced: no replica can
167
+ // act on the verdict alone to refuse itself, so a `capped` verdict means
168
+ // every declared replica still joins. Read a `capped` series as "this
169
+ // deployment is configured beyond what it paid for", never as "replicas
170
+ // were turned away".
171
+ //
172
+ // ⚠️ Absence is meaningful and is NOT an instrumentation gap: the gate is
173
+ // consulted only when `OS_CLUSTER_DRIVER` names a remote driver, so a
174
+ // single-node deployment emits nothing here at all. An emission also needs
175
+ // a configured metrics backend (`OS_OBS_EXPORTER`); with none, the boot log
176
+ // line remains the only reading.
177
+ /**
178
+ * Gauge, labels: `verdict` (`admitted`|`capped`|`refused`). The replica
179
+ * count the operator DECLARED via `OS_CLUSTER_REPLICAS` — not a count of
180
+ * anything observed. Absent when nothing was declared; deliberately never
181
+ * emitted as `0`, which would read as a declaration of zero replicas.
182
+ */
183
+ clusterDeclaredNodes: "cluster_declared_nodes",
184
+ /**
185
+ * Gauge, labels: `verdict` (`admitted`|`capped`|`refused`). How many of the
186
+ * declared nodes the licence gate admits. Absent when the gate imposes no
187
+ * count cap at all — emitting a number there would invent a limit that was
188
+ * never expressed.
189
+ */
190
+ clusterAdmittedNodes: "cluster_admitted_nodes",
191
+ /**
192
+ * Counter, labels: `verdict` (`admitted`|`capped`|`refused`). One
193
+ * increment per PROCESS BOOT that consulted the gate — a boot-event count,
194
+ * never a node count. It exists because the two gauges above are written
195
+ * once per boot and a push-based exporter lets a one-shot gauge age out of
196
+ * the backend; `increase(cluster_node_cap_verdicts_total{verdict="capped"}[1h]) > 0`
197
+ * stays alertable after the gauges have gone stale.
198
+ */
199
+ clusterNodeCapVerdictsTotal: "cluster_node_cap_verdicts_total"
147
200
  };
148
201
  var RUNTIME_METRICS = {
149
202
  httpRequestsTotal: SEMCONV.httpRequestsTotal,
150
- httpRequestDurationMs: SEMCONV.httpRequestDurationMs,
151
- httpRequestErrorsTotal: SEMCONV.httpRequestErrorsTotal
203
+ httpRequestDurationMs: SEMCONV.httpRequestDurationMs
204
+ // `httpRequestErrorsTotal` retired with its SEMCONV declaration above
205
+ // (#9834). The alias is not a compatibility window of its own: there is no
206
+ // emitter left to read, so keeping the name here would hand callers a
207
+ // string nothing ever writes.
152
208
  };
153
209
 
154
210
  // src/http-transport-metrics.ts