@camstack/addon-pipeline 1.2.139 → 1.2.140

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 (37) hide show
  1. package/dist/audio-analyzer/index.js +2 -2
  2. package/dist/audio-analyzer/index.mjs +2 -2
  3. package/dist/detection-pipeline/index.js +5 -5
  4. package/dist/detection-pipeline/index.mjs +4 -4
  5. package/dist/{dist-WUZH-lAM.js → dist-3bEUjzHN.js} +279 -1
  6. package/dist/{dist-CTmOaCwF.mjs → dist-B25xMJDp.mjs} +268 -2
  7. package/dist/{event-loop-stall-monitor-CoM21UjL.js → event-loop-stall-monitor-BQeD-JuB.js} +1 -1
  8. package/dist/{event-loop-stall-monitor-BMtR9qZR.mjs → event-loop-stall-monitor-CrWg3jrh.mjs} +1 -1
  9. package/dist/{lazy-sharp-1WF7ZnxZ.js → lazy-sharp-buaVXzJ6.js} +1 -1
  10. package/dist/motion-wasm/index.js +2 -2
  11. package/dist/motion-wasm/index.mjs +1 -1
  12. package/dist/{node-CQcgxO8l.mjs → node-CFEV-qgx.mjs} +1 -1
  13. package/dist/{node-BAo2ivVu.js → node-Cn9gEOs4.js} +1 -1
  14. package/dist/pipeline-runner/index.js +98 -14
  15. package/dist/pipeline-runner/index.mjs +97 -13
  16. package/dist/{process-memory-BPEKERfe.mjs → process-memory-B4SGuNSB.mjs} +1 -1
  17. package/dist/{process-memory-BZvkQCLP.js → process-memory-D7R-j96w.js} +1 -1
  18. package/dist/recorder/index.js +3 -2
  19. package/dist/recorder/index.mjs +3 -2
  20. package/dist/{segment-demux-js-CubhFNwb.mjs → segment-demux-js-CwNYlHRC.mjs} +1 -1
  21. package/dist/{segment-demux-js-B1L1pfoc.js → segment-demux-js-J1AdcHSK.js} +1 -1
  22. package/dist/session-decode/decode-worker-child.js +2 -2
  23. package/dist/session-decode/decode-worker-child.mjs +1 -1
  24. package/dist/stream-broker/_stub.js +2 -2
  25. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DJ4k5ZBb.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-O4QuB94V.mjs} +3 -3
  26. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D4-thZGg.mjs +26 -0
  27. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DPpl_mtg.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-bjYJYwAq.mjs} +1 -1
  28. package/dist/stream-broker/demux-worker-child.js +1 -1
  29. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  30. package/dist/stream-broker/{hostInit-oy-XDnw6.mjs → hostInit-DXcoBCs4.mjs} +3 -3
  31. package/dist/stream-broker/index.js +3 -3
  32. package/dist/stream-broker/index.mjs +3 -3
  33. package/dist/stream-broker/remoteEntry.js +1 -1
  34. package/dist/{worker-protocol-C-0LYdSt.js → worker-protocol-CxvZ6FP4.js} +1 -1
  35. package/dist/{worker-protocol-DsuI4ifI.mjs → worker-protocol-DYOG2ris.mjs} +1 -1
  36. package/package.json +4 -1
  37. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-xdmO8wYp.mjs +0 -26
@@ -9662,6 +9662,112 @@ var DecoderSessionConfigSchema = object({
9662
9662
  */
9663
9663
  debug: boolean().optional()
9664
9664
  });
9665
+ /**
9666
+ * Distinct (device, family, variant) counters one instance will hold.
9667
+ *
9668
+ * A large fleet x the handful of families any single addon reports, with
9669
+ * slack. At ~200 B per counter this is a ~100 KB ceiling on a process that
9670
+ * already declares an RSS budget in the gigabytes.
9671
+ */
9672
+ var MAX_KEYS = 1024;
9673
+ /**
9674
+ * Where reasons past {@link MAX_REASONS_PER_KEY} go.
9675
+ *
9676
+ * They are FOLDED, never dropped: `attempts - succeeded` must always equal the
9677
+ * sum of the reason counts, or the ratio stops adding up.
9678
+ */
9679
+ var OVERFLOW_REASON = "other";
9680
+ /** `deviceId` + `family` + optional `variant`, flattened into the map key. */
9681
+ function counterKey(deviceId, family, variant) {
9682
+ return variant === void 0 ? `${deviceId}${family}` : `${deviceId}${family}${variant}`;
9683
+ }
9684
+ /**
9685
+ * A bounded set of per-camera, cumulative failure counters.
9686
+ *
9687
+ * One instance per contributing subsystem. `note` is O(1) and allocation-free
9688
+ * on the steady path; `snapshot` reads without mutating anything.
9689
+ */
9690
+ var FailureCounters = class {
9691
+ maxKeys;
9692
+ maxReasons;
9693
+ counters = /* @__PURE__ */ new Map();
9694
+ refused = 0;
9695
+ constructor(maxKeys = MAX_KEYS, maxReasons = 16) {
9696
+ this.maxKeys = maxKeys;
9697
+ this.maxReasons = maxReasons;
9698
+ }
9699
+ /**
9700
+ * Counters refused because {@link MAX_KEYS} was already held.
9701
+ *
9702
+ * Cumulative for the life of the instance: a bound that bit is a fact about
9703
+ * the deployment, and a surface that hid it would under-report a fleet
9704
+ * precisely when the fleet got large enough to matter.
9705
+ */
9706
+ get keysRefused() {
9707
+ return this.refused;
9708
+ }
9709
+ /** Counters currently held. */
9710
+ get size() {
9711
+ return this.counters.size;
9712
+ }
9713
+ /**
9714
+ * Fold one observation in.
9715
+ *
9716
+ * A non-positive or non-integer `deviceId` is REFUSED rather than bucketed:
9717
+ * see the module docblock — an entry that cannot name its camera is worse
9718
+ * than no entry.
9719
+ */
9720
+ note(observation, nowMs) {
9721
+ if (!Number.isInteger(observation.deviceId) || observation.deviceId <= 0) return;
9722
+ const key = counterKey(observation.deviceId, observation.family, observation.variant);
9723
+ let counter = this.counters.get(key);
9724
+ if (counter === void 0) {
9725
+ if (this.counters.size >= this.maxKeys) {
9726
+ this.refused += 1;
9727
+ return;
9728
+ }
9729
+ counter = {
9730
+ deviceId: observation.deviceId,
9731
+ family: observation.family,
9732
+ variant: observation.variant,
9733
+ sinceMs: nowMs,
9734
+ attempts: 0,
9735
+ succeeded: 0,
9736
+ reasons: /* @__PURE__ */ new Map()
9737
+ };
9738
+ this.counters.set(key, counter);
9739
+ }
9740
+ counter.attempts += 1;
9741
+ if (observation.reason === void 0) {
9742
+ counter.succeeded += 1;
9743
+ return;
9744
+ }
9745
+ const reason = counter.reasons.has(observation.reason) || counter.reasons.size < this.maxReasons ? observation.reason : OVERFLOW_REASON;
9746
+ counter.reasons.set(reason, (counter.reasons.get(reason) ?? 0) + 1);
9747
+ }
9748
+ /** Read every counter. Never mutates — see the module docblock. */
9749
+ snapshot(nowMs) {
9750
+ const out = [];
9751
+ for (const counter of this.counters.values()) out.push({
9752
+ deviceId: counter.deviceId,
9753
+ family: counter.family,
9754
+ ...counter.variant !== void 0 ? { variant: counter.variant } : {},
9755
+ sinceMs: counter.sinceMs,
9756
+ atMs: nowMs,
9757
+ attempts: counter.attempts,
9758
+ succeeded: counter.succeeded,
9759
+ reasons: [...counter.reasons.entries()].map(([reason, count]) => ({
9760
+ reason,
9761
+ count
9762
+ })).toSorted((a, b) => b.count - a.count)
9763
+ });
9764
+ return out;
9765
+ }
9766
+ /** Drop everything (host disposal). */
9767
+ clear() {
9768
+ this.counters.clear();
9769
+ }
9770
+ };
9665
9771
  var MODEL_FORMATS = [
9666
9772
  "onnx",
9667
9773
  "coreml",
@@ -15030,6 +15136,133 @@ method(LogEntrySchema, _void(), { kind: "mutation" }), method(object({
15030
15136
  limit: number().optional(),
15031
15137
  tags: record(string(), string()).optional()
15032
15138
  }), array(LogEntrySchema).readonly());
15139
+ /**
15140
+ * `failure-contribution` — the capability an addon reports its OWN losses
15141
+ * through, per camera, with the denominator attached. It stores nothing.
15142
+ *
15143
+ * ## The twin of `load-contribution`, and why it is a twin and not a field
15144
+ *
15145
+ * `load-contribution` answers *what did this camera COST*. This answers *what
15146
+ * did this camera LOSE*. The reporting discipline is identical and deliberately
15147
+ * copied: the contributor reports what it already knows, hub-main adds only
15148
+ * `addonId`, nothing needs global knowledge, and there is no central list for
15149
+ * somebody to forget to edit.
15150
+ *
15151
+ * They are not merged, because their invariants are opposites:
15152
+ *
15153
+ * - a `load-contribution` measurement is **absent, never zero** — a zero would
15154
+ * claim a camera cost nothing, which is a measurement nobody made;
15155
+ * - a `failure-contribution` zero is the **most valuable value on the
15156
+ * surface** — `attempts: 400, succeeded: 400` is the proof a fix landed,
15157
+ * and it is exactly what an absent entry cannot say.
15158
+ *
15159
+ * Putting a loss counter on a cost entry would also break the reconciliation
15160
+ * that gives `load-contribution` its point: contributions are subtracted from
15161
+ * `metrics.node-processes-snapshot` to find processes nobody claims. A failure
15162
+ * has no process.
15163
+ *
15164
+ * ## Why not a log line, since the counters already exist
15165
+ *
15166
+ * Several of these paths already counted themselves — `CaptureScheduler`'s
15167
+ * per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
15168
+ * ends in a log line, and a log line is the thing the operator asked to stop
15169
+ * needing: *"possiamo armare questi errori intanto? Così al prossimo giro
15170
+ * ricontrolliamo tutti questi punti"*. Reading them meant grepping Loki and
15171
+ * hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
15172
+ * media blackout were both diagnosed. The counters stay; this is where they can
15173
+ * be READ.
15174
+ *
15175
+ * ## The rate is served with its denominator or not at all
15176
+ *
15177
+ * Every entry carries `attempts` and `succeeded`. A miss count alone is
15178
+ * unreadable: on 2026-08-28 the enrichment-crop miss count read as "35x worse
15179
+ * than yesterday" and was **flat across twelve hours** once divided by the
15180
+ * successes on the same path. A surface that publishes only the numerator
15181
+ * reproduces that mistake on every read.
15182
+ *
15183
+ * ## Shape
15184
+ *
15185
+ * Copied from `load-contribution.cap.ts` (`mode: 'collection'`,
15186
+ * `internal: true`, `mount: { kind: 'skip' }`): no tRPC route of its own and no
15187
+ * generated hooks, while `addons.listCapabilityProviders` still enumerates it
15188
+ * and the hub's `CapabilityRegistry` still holds an RPC proxy per provider — so
15189
+ * a forked runner's entries reach hub-main over transport that already exists.
15190
+ * No new UDS message, no second registry (D3). The operator reads the assembled
15191
+ * result through `system.getFailureContributions`.
15192
+ */
15193
+ var FailureReasonCountSchema = object({
15194
+ /**
15195
+ * Why the attempt did not land, in the contributor's own vocabulary —
15196
+ * `worker-lease-gone`, `queue-overflow`, `timeout`, `empty-read`. The same
15197
+ * strings that already appear in this repo's logs and, where one exists, the
15198
+ * same string the per-track `previewMissReason` records (D276): a second
15199
+ * vocabulary for the same loss would make the row and the counter
15200
+ * un-joinable.
15201
+ */
15202
+ reason: string(),
15203
+ count: number().int().nonnegative()
15204
+ });
15205
+ var FailureContributionSchema = object({
15206
+ /**
15207
+ * The failing path — `enrichment-crop`, `inference`, `plate-ocr`,
15208
+ * `person-over-vehicle`. Free text, for the reason `load-contribution` keeps
15209
+ * `unit` free: the families are owned by different addons and a shared enum
15210
+ * is a central list that rots invisibly.
15211
+ */
15212
+ family: string(),
15213
+ /**
15214
+ * The NUMERIC device id — the same value every log line carries as
15215
+ * `tags.deviceId`. Never nullable and never absent: a contributor that
15216
+ * cannot name the camera must not emit the entry, because a fleet total
15217
+ * cannot answer the only question anybody asks of this surface.
15218
+ */
15219
+ deviceId: number().int().positive(),
15220
+ /**
15221
+ * A second dimension inside the family: the model / step id for an inference
15222
+ * timeout, so "which camera AND which model" is one read. Absent when the
15223
+ * family has a single variant.
15224
+ */
15225
+ variant: string().optional(),
15226
+ /**
15227
+ * Epoch ms this counter started — the INCARNATION MARKER. A consumer
15228
+ * differencing two reads must drop the interval when it changes, because the
15229
+ * counter restarted from zero in a respawned runner. Same discipline as
15230
+ * `LoadContribution.startedAtMs`.
15231
+ */
15232
+ sinceMs: number(),
15233
+ /** Epoch ms it was read. `atMs - sinceMs` is the interval this covers. */
15234
+ atMs: number(),
15235
+ /**
15236
+ * THE DENOMINATOR — every attempt on this path for this camera in the
15237
+ * window. A failure count published without it is the mistake this schema
15238
+ * exists to make impossible.
15239
+ */
15240
+ attempts: number().int().nonnegative(),
15241
+ /** Attempts that landed. `attempts - succeeded` is the loss. */
15242
+ succeeded: number().int().nonnegative(),
15243
+ /** The loss, partitioned. Sums to `attempts - succeeded`. */
15244
+ reasons: array(FailureReasonCountSchema).readonly()
15245
+ });
15246
+ var failureContributionCapability = {
15247
+ name: "failure-contribution",
15248
+ scope: "system",
15249
+ mode: "collection",
15250
+ internal: true,
15251
+ methods: {
15252
+ /**
15253
+ * This addon's per-camera failure counters, read live from bounded in-RAM
15254
+ * state it already keeps. Inert: no persistence, no sampling, no timer.
15255
+ *
15256
+ * READING NEVER RESETS. The counters are CUMULATIVE since `sinceMs`, and a
15257
+ * consumer that wants a rate differences two reads. A draining read would
15258
+ * make two operators with the page open each destroy half of the other's
15259
+ * numbers, and `load-contribution` already settled the same question the
15260
+ * same way for `cpuSeconds`.
15261
+ */
15262
+ list: method(_void(), array(FailureContributionSchema).readonly()) },
15263
+ /** In-process only — enumerated through `addons.listCapabilityProviders`. */
15264
+ mount: { kind: "skip" }
15265
+ };
15033
15266
  var LoadContributionSchema = object({
15034
15267
  role: _enum([
15035
15268
  "decode",
@@ -20083,6 +20316,20 @@ var TrackSchema = object({
20083
20316
  * `=== true` and render nothing otherwise — never infer "no rider".
20084
20317
  */
20085
20318
  hasRider: boolean().optional(),
20319
+ /**
20320
+ * WHY this track ended without a NATIVE best-shot tile
20321
+ * ([D276](../decisions/adr-0276-a-stand-in-tile-is-provisional-and-a-close-says-why.md)) —
20322
+ * a composed token line (`no-key-frame capture=keyframe:native-missx4`,
20323
+ * `derive-returned-null tile=standin`, …) written at close and CLEARED by
20324
+ * the late-keyFrame upgrade when a native tile lands after all. The
20325
+ * operator-facing answer to "perché manca l'immagine?" on a track whose
20326
+ * tile is a face/plate stand-in, a raster crop, or an icon.
20327
+ *
20328
+ * **Absent ≠ "missed silently"**: a row written before the column, a hub
20329
+ * that predates the field, and every track whose tile landed native all
20330
+ * omit it. Render nothing when absent.
20331
+ */
20332
+ previewMissReason: string().optional(),
20086
20333
  ...TrackFlagFields,
20087
20334
  ...TrackRetrainFields
20088
20335
  });
@@ -29779,6 +30026,13 @@ var LoggingSettingsPatchSchema = object({
29779
30026
  * anyone but its owner.
29780
30027
  */
29781
30028
  var ReportedLoadContributionSchema = LoadContributionSchema.extend({ addonId: string() });
30029
+ /**
30030
+ * One per-camera failure counter, plus WHO reported it.
30031
+ *
30032
+ * Same rule as {@link ReportedLoadContributionSchema}: `addonId` is stamped by
30033
+ * the hub as it enumerates providers, never by the contributor.
30034
+ */
30035
+ var ReportedFailureContributionSchema = FailureContributionSchema.extend({ addonId: string() });
29782
30036
  var GetLoggingSettingsInputSchema = object({
29783
30037
  scopeNodeId: string().optional(),
29784
30038
  /**
@@ -29837,7 +30091,7 @@ method(_void(), FeatureManifestSchema), method(_void(), HealthStatusSchema), met
29837
30091
  }), method(_void(), SiteLocationStatusSchema, {
29838
30092
  kind: "mutation",
29839
30093
  auth: "admin"
29840
- }), method(_void(), RequestCensusStatusSchema, { auth: "admin" }), method(_void(), array(ReportedLoadContributionSchema).readonly(), { auth: "admin" }), method(GetLoggingSettingsInputSchema, LoggingSettingsStateSchema, { auth: "admin" }), method(SetLoggingSettingsInputSchema, LoggingSettingsStateSchema, {
30094
+ }), method(_void(), RequestCensusStatusSchema, { auth: "admin" }), method(_void(), array(ReportedLoadContributionSchema).readonly(), { auth: "admin" }), method(_void(), array(ReportedFailureContributionSchema).readonly(), { auth: "admin" }), method(GetLoggingSettingsInputSchema, LoggingSettingsStateSchema, { auth: "admin" }), method(SetLoggingSettingsInputSchema, LoggingSettingsStateSchema, {
29841
30095
  kind: "mutation",
29842
30096
  auth: "admin"
29843
30097
  });
@@ -32578,6 +32832,12 @@ Object.freeze({
32578
32832
  addonId: null,
32579
32833
  access: "create"
32580
32834
  },
32835
+ "failureContribution.list": {
32836
+ capName: "failure-contribution",
32837
+ capScope: "system",
32838
+ addonId: null,
32839
+ access: "view"
32840
+ },
32581
32841
  "fanControl.setDirection": {
32582
32842
  capName: "fan-control",
32583
32843
  capScope: "device",
@@ -35884,6 +36144,12 @@ Object.freeze({
35884
36144
  addonId: null,
35885
36145
  access: "create"
35886
36146
  },
36147
+ "system.getFailureContributions": {
36148
+ capName: "system",
36149
+ capScope: "system",
36150
+ addonId: null,
36151
+ access: "view"
36152
+ },
35887
36153
  "system.getLoadContributions": {
35888
36154
  capName: "system",
35889
36155
  capScope: "system",
@@ -39871,4 +40137,4 @@ function enumerateInferenceDevices(hw) {
39871
40137
  return out;
39872
40138
  }
39873
40139
  //#endregion
39874
- export { loadContributionCapability as $, string as $t, audioAnalysisCapability as A, BaseAddon as At, defineCustomActions as B, parseJsonUnknown as Bt, RATE_CONTROL_RELAXED as C, errMsg as Ct, RingBuffer as D, invocationFromEncodeProfile as Dt, RecordingConfigSchema as E, buildFfmpegArgs as Et, createHwAccelCache as F, hydrateSchema as Ft, egressTranscodeSharingKey as G, array as Gt, deriveDetailCropRect as H, selectAssignedProfileSlots as Ht, createLogChannelsProvider as I, isEvent as It, evaluateSensorEdge as J, lazy as Jt, egressTransportFromRequest as K, boolean as Kt, customAction as L, makeProfileBrokerId as Lt, audioKindId as M, DeviceFeature as Mt, batteryCapability as N, DeviceType as Nt, YAMNET_TO_MACRO as O, isSoftwareDecode as Ot, cameraStreamsCapability as P, createEvent as Pt, isFirstLevelMacroClass as Q, record as Qt, declareLogChannel as R, makeSourceBrokerId as Rt, PoolMemoryWatchdog as S, webrtcSessionCapability as St, RECORDING_EXPORT_MAX_READ_BYTES as T, Fmp4BoxSplitter as Tt, deriveRecordingMode as U, sleep as Ut, deriveBatteryPresence as V, parseProfileBrokerId as Vt, detectionPipelineCapability as W, _enum as Wt, hfModelUrl as X, number as Xt, evaluateZoneRules as Y, literal as Yt, inferModelProvider as Z, object as Zt, ExportRecordSchema as _, resolveRecordingProfiles as _t, COCO_80_LABELS as a, parseProcStatus as at, NativeLeaseSettingsSchema as b, streamBrokerCapability as bt, DEFAULT_CLUSTER_STEP_MODELS as c, pickDetailCropConvention as ct, DEFAULT_EVENTS_BAND_BUFFER_SEC as d, pipelineRunnerCapability as dt, union as en, logChannelsCapability as et, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as f, recordingCapability as ft, EncodeProfileSchema as g, resolvePoolMemoryPolicy as gt, EVENT_PAD_MS as h, resolveEgressDecodeHwAccel as ht, BatteryStatusSchema as i, overlayClusterStepSettings as it, audioAnalyzerCapability as j, CAM_PROFILE_ORDER as jt, addonWidgetsSourceCapability as k, BOOT_RECOVERY_BACKOFF_MS as kt, DEFAULT_CLUSTER_STEP_SETTINGS as l, pickNativeLeaseOverride as lt, DEVICE_BACKEND_TO_FORMAT as m, resolveClusterStepModelId as mt, AUDIO_BACKEND_CHOICES as n, maskUrlCredentials as nt, COCO_TO_MACRO as o, pickClusterStepModels as ot, DEFAULT_NATIVE_LEASE_SETTINGS as p, recordingExportCapability as pt, enumerateInferenceDevices as q, discriminatedUnion as qt, AUDIO_MACRO_LABELS as r, motionDetectionCapability as rt, DEFAULT_AUDIO_ANALYZER_CONFIG as s, pickClusterStepSettings as st, APPLE_SA_TO_MACRO as t, EventCategory as tn, mapAudioLabelToMacro as tt, DEFAULT_DETAIL_CROP_CONVENTION as u, pipelineExecutorCapability as ut, HF_BASE_URL as v, runtimeDevices as vt, RATE_CONTROL_TIGHT as w, AUDIO_PRESETS as wt, OpsLogEntrySchema as x, supportedRuntimes as xt, NativeLeaseAdmissionSchema as y, storageEvictableCapability as yt, defaultDeviceFor as z, nodePin as zt };
40140
+ export { inferModelProvider as $, object as $t, addonWidgetsSourceCapability as A, isSoftwareDecode as At, defaultDeviceFor as B, makeSourceBrokerId as Bt, PoolMemoryWatchdog as C, supportedRuntimes as Ct, RecordingConfigSchema as D, Fmp4BoxSplitter as Dt, RECORDING_EXPORT_MAX_READ_BYTES as E, AUDIO_PRESETS as Et, cameraStreamsCapability as F, DeviceType as Ft, detectionPipelineCapability as G, sleep as Gt, deriveBatteryPresence as H, parseJsonUnknown as Ht, createHwAccelCache as I, createEvent as It, enumerateInferenceDevices as J, boolean as Jt, egressTranscodeSharingKey as K, _enum as Kt, createLogChannelsProvider as L, hydrateSchema as Lt, audioAnalyzerCapability as M, BaseAddon as Mt, audioKindId as N, CAM_PROFILE_ORDER as Nt, RingBuffer as O, buildFfmpegArgs as Ot, batteryCapability as P, DeviceFeature as Pt, hfModelUrl as Q, number as Qt, customAction as R, isEvent as Rt, OpsLogEntrySchema as S, streamBrokerCapability as St, RATE_CONTROL_TIGHT as T, errMsg as Tt, deriveDetailCropRect as U, parseProfileBrokerId as Ut, defineCustomActions as V, nodePin as Vt, deriveRecordingMode as W, selectAssignedProfileSlots as Wt, evaluateZoneRules as X, lazy as Xt, evaluateSensorEdge as Y, discriminatedUnion as Yt, failureContributionCapability as Z, literal as Zt, ExportRecordSchema as _, resolveEgressDecodeHwAccel as _t, COCO_80_LABELS as a, motionDetectionCapability as at, NativeLeaseAdmissionSchema as b, runtimeDevices as bt, DEFAULT_CLUSTER_STEP_MODELS as c, pickClusterStepModels as ct, DEFAULT_EVENTS_BAND_BUFFER_SEC as d, pickNativeLeaseOverride as dt, record as en, isFirstLevelMacroClass as et, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as f, pipelineExecutorCapability as ft, EncodeProfileSchema as g, resolveClusterStepModelId as gt, EVENT_PAD_MS as h, recordingExportCapability as ht, BatteryStatusSchema as i, maskUrlCredentials as it, audioAnalysisCapability as j, BOOT_RECOVERY_BACKOFF_MS as jt, YAMNET_TO_MACRO as k, invocationFromEncodeProfile as kt, DEFAULT_CLUSTER_STEP_SETTINGS as l, pickClusterStepSettings as lt, DEVICE_BACKEND_TO_FORMAT as m, recordingCapability as mt, AUDIO_BACKEND_CHOICES as n, union as nn, logChannelsCapability as nt, COCO_TO_MACRO as o, overlayClusterStepSettings as ot, DEFAULT_NATIVE_LEASE_SETTINGS as p, pipelineRunnerCapability as pt, egressTransportFromRequest as q, array as qt, AUDIO_MACRO_LABELS as r, EventCategory as rn, mapAudioLabelToMacro as rt, DEFAULT_AUDIO_ANALYZER_CONFIG as s, parseProcStatus as st, APPLE_SA_TO_MACRO as t, string as tn, loadContributionCapability as tt, DEFAULT_DETAIL_CROP_CONVENTION as u, pickDetailCropConvention as ut, FailureCounters as v, resolvePoolMemoryPolicy as vt, RATE_CONTROL_RELAXED as w, webrtcSessionCapability as wt, NativeLeaseSettingsSchema as x, storageEvictableCapability as xt, HF_BASE_URL as y, resolveRecordingProfiles as yt, declareLogChannel as z, makeProfileBrokerId as zt };
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-WUZH-lAM.js");
1
+ const require_dist = require("./dist-3bEUjzHN.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  let node_perf_hooks = require("node:perf_hooks");
4
4
  //#region src/detection-pipeline/registry/model-catalogs.ts
@@ -1,4 +1,4 @@
1
- import { M as audioKindId, X as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-CTmOaCwF.mjs";
1
+ import { N as audioKindId, Q as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-B25xMJDp.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { PerformanceObserver } from "node:perf_hooks";
4
4
  //#region src/detection-pipeline/registry/model-catalogs.ts
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-WUZH-lAM.js");
1
+ const require_dist = require("./dist-3bEUjzHN.js");
2
2
  let node_path = require("node:path");
3
3
  node_path = require_dist.__toESM(node_path);
4
4
  let node_url = require("node:url");
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-WUZH-lAM.js");
6
- const require_lazy_sharp = require("../lazy-sharp-1WF7ZnxZ.js");
5
+ const require_dist = require("../dist-3bEUjzHN.js");
6
+ const require_lazy_sharp = require("../lazy-sharp-buaVXzJ6.js");
7
7
  let node_fs = require("node:fs");
8
8
  let node_path = require("node:path");
9
9
  //#region src/motion-wasm/wasm-motion-detector.ts
@@ -1,4 +1,4 @@
1
- import { At as BaseAddon, Ft as hydrateSchema, Nt as DeviceType, Y as evaluateZoneRules, rt as motionDetectionCapability } from "../dist-CTmOaCwF.mjs";
1
+ import { Ft as DeviceType, Lt as hydrateSchema, Mt as BaseAddon, X as evaluateZoneRules, at as motionDetectionCapability } from "../dist-B25xMJDp.mjs";
2
2
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
@@ -1,4 +1,4 @@
1
- import { Ct as errMsg, Et as buildFfmpegArgs, Ot as isSoftwareDecode, Tt as Fmp4BoxSplitter } from "./dist-CTmOaCwF.mjs";
1
+ import { At as isSoftwareDecode, Dt as Fmp4BoxSplitter, Ot as buildFfmpegArgs, Tt as errMsg } from "./dist-B25xMJDp.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import "node:fs";
4
4
  import "node:path";
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-WUZH-lAM.js");
1
+ const require_dist = require("./dist-3bEUjzHN.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  let node_fs = require("node:fs");
4
4
  node_fs = require_dist.__toESM(node_fs, 1);
@@ -2,12 +2,12 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-WUZH-lAM.js");
6
- const require_node = require("../node-BAo2ivVu.js");
7
- const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-CoM21UjL.js");
8
- const require_worker_protocol = require("../worker-protocol-C-0LYdSt.js");
5
+ const require_dist = require("../dist-3bEUjzHN.js");
6
+ const require_node = require("../node-Cn9gEOs4.js");
7
+ const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-BQeD-JuB.js");
8
+ const require_worker_protocol = require("../worker-protocol-CxvZ6FP4.js");
9
9
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
10
- const require_lazy_sharp = require("../lazy-sharp-1WF7ZnxZ.js");
10
+ const require_lazy_sharp = require("../lazy-sharp-buaVXzJ6.js");
11
11
  const require_restream_intent = require("../restream-intent-Cv9x3jmu.js");
12
12
  const require_remote_restream = require("../remote-restream-CO36Sr30.js");
13
13
  let node_child_process = require("node:child_process");
@@ -3652,6 +3652,74 @@ function packageZoneUnion(polygons) {
3652
3652
  };
3653
3653
  }
3654
3654
  //#endregion
3655
+ //#region src/pipeline-runner/failure-report.ts
3656
+ /**
3657
+ * What `pipeline-runner` reports through `failure-contribution` — the inference
3658
+ * deadline, per camera, with the frames that made it as the denominator.
3659
+ *
3660
+ * ## The number that was never divided
3661
+ *
3662
+ * ~120 `inference timed out — permit released, result discarded` lines in six
3663
+ * hours across seven cameras, on 2026-08-28, never investigated. The line has
3664
+ * carried `tags: { deviceId }` for a while, so the count per camera was always
3665
+ * available; what was not available was the number to divide it by. 120
3666
+ * timeouts out of 120 000 admitted frames and 120 out of 1 200 are opposite
3667
+ * findings and produce identical log volume.
3668
+ *
3669
+ * So the counter takes BOTH outcomes of the same await, from the same place in
3670
+ * `awaitInferenceBounded`. A success counted anywhere else would eventually
3671
+ * drift from the failure and turn the ratio into fiction.
3672
+ *
3673
+ * ## Why there is no `variant` yet
3674
+ *
3675
+ * `failure-contribution` has a `variant` slot exactly so "which camera AND
3676
+ * which model" is one read, and the operator asked for it. The runner cannot
3677
+ * fill it honestly: `awaitInferenceBounded` wraps
3678
+ * `config.processFrame(deviceId, frameInput, executorHandle)`, which runs the
3679
+ * camera's WHOLE pipeline graph behind one deadline. Nothing at this seam knows
3680
+ * which step was still running when the 20 s expired — `CameraRegistration`
3681
+ * carries fps and mode, not models.
3682
+ *
3683
+ * Naming the step means the executor attributing the deadline to the step that
3684
+ * held it, and reporting THAT. Emitting a `variant` the runner guessed (the
3685
+ * camera's configured graph id, say) would be worse than leaving it absent: it
3686
+ * would look like an attribution and be a label. Absent, never invented — the
3687
+ * same rule `load-contribution` states for a measurement nobody made.
3688
+ */
3689
+ /** One bounded inference deadline per admitted detection frame. */
3690
+ var FAMILY_INFERENCE = "inference";
3691
+ /** The call did not return inside `inferenceTimeoutMs`. */
3692
+ var REASON_INFERENCE_TIMEOUT = "timeout";
3693
+ /**
3694
+ * The runner's `failure-contribution` counters.
3695
+ *
3696
+ * One instance per runner process, read (never drained) by the provider.
3697
+ */
3698
+ var RunnerFailureReport = class {
3699
+ now;
3700
+ counters;
3701
+ constructor(now = Date.now, counters = new require_dist.FailureCounters()) {
3702
+ this.now = now;
3703
+ this.counters = counters;
3704
+ }
3705
+ /** One bounded inference call. `reason` absent = it returned in time. */
3706
+ noteInference(deviceId, reason) {
3707
+ this.counters.note({
3708
+ deviceId,
3709
+ family: FAMILY_INFERENCE,
3710
+ ...reason !== void 0 ? { reason } : {}
3711
+ }, this.now());
3712
+ }
3713
+ /** The `failure-contribution` provider's payload. Reads, never resets. */
3714
+ list() {
3715
+ return this.counters.snapshot(this.now());
3716
+ }
3717
+ /** Addon disposal. */
3718
+ clear() {
3719
+ this.counters.clear();
3720
+ }
3721
+ };
3722
+ //#endregion
3655
3723
  //#region src/pipeline-runner/frame-governor.ts
3656
3724
  var FrameGovernor = class {
3657
3725
  config;
@@ -4716,6 +4784,7 @@ var PipelineRunner = class {
4716
4784
  if (outcome === TIMED_OUT) {
4717
4785
  release();
4718
4786
  this.inflightTimeouts += 1;
4787
+ this.config.noteInferenceOutcome?.(deviceId, REASON_INFERENCE_TIMEOUT);
4719
4788
  this.logger?.warn("inference timed out — permit released, result discarded", {
4720
4789
  tags: { deviceId },
4721
4790
  meta: {
@@ -4738,7 +4807,7 @@ var PipelineRunner = class {
4738
4807
  });
4739
4808
  };
4740
4809
  inflight.then(() => noteSettled("resolved"), () => noteSettled("rejected"));
4741
- }
4810
+ } else this.config.noteInferenceOutcome?.(deviceId);
4742
4811
  return outcome;
4743
4812
  } finally {
4744
4813
  if (timer !== null) clearTimeout(timer);
@@ -5269,6 +5338,13 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
5269
5338
  */
5270
5339
  costRegistry = new require_node.ChildCostRegistry();
5271
5340
  /**
5341
+ * Per-camera inference-deadline counters reported through
5342
+ * `failure-contribution`. Bounded, cumulative, and read (never drained) by
5343
+ * the provider. Constructed eagerly: created on the first timeout it would
5344
+ * have no denominator for everything that already succeeded.
5345
+ */
5346
+ failureReport = new RunnerFailureReport();
5347
+ /**
5272
5348
  * Per-runner (per-node) decode-worker SPAWN-CONCURRENCY GATE (P5). A single
5273
5349
  * counting semaphore every session-decode fork (detection + motion, all
5274
5350
  * cameras on this node) passes through, sized to
@@ -5519,7 +5595,8 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
5519
5595
  logger: this.ctx.logger,
5520
5596
  onOccupancyRecheck: (deviceId, frames) => {
5521
5597
  this.enqueueOccupancyBurst(deviceId, frames);
5522
- }
5598
+ },
5599
+ noteInferenceOutcome: (deviceId, reason) => this.failureReport.noteInference(deviceId, reason)
5523
5600
  });
5524
5601
  this.spawnGate = new Semaphore(Math.max(1, this.config.maxConcurrentDecodeSpawns));
5525
5602
  this.liveWorkers = new LiveDecodeWorkerAdmission({
@@ -5567,13 +5644,20 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
5567
5644
  });
5568
5645
  this.metricsSnapshotTimer = setInterval(() => this.emitMetricsSnapshot(), METRICS_SNAPSHOT_INTERVAL_MS);
5569
5646
  return {
5570
- providers: [{
5571
- capability: require_dist.pipelineRunnerCapability,
5572
- provider: this
5573
- }, {
5574
- capability: require_dist.loadContributionCapability,
5575
- provider: { list: () => this.costRegistry.contributions() }
5576
- }],
5647
+ providers: [
5648
+ {
5649
+ capability: require_dist.pipelineRunnerCapability,
5650
+ provider: this
5651
+ },
5652
+ {
5653
+ capability: require_dist.loadContributionCapability,
5654
+ provider: { list: () => this.costRegistry.contributions() }
5655
+ },
5656
+ {
5657
+ capability: require_dist.failureContributionCapability,
5658
+ provider: { list: () => this.failureReport.list() }
5659
+ }
5660
+ ],
5577
5661
  customActions: pipelineRunnerBenchActions,
5578
5662
  actionHandlers: {
5579
5663
  cacheBenchFrame: async (input) => this.cacheBenchFrame(input),