@camstack/addon-pipeline 1.2.293 → 1.2.295

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 (39) hide show
  1. package/THIRD_PARTY_MODELS.md +233 -0
  2. package/dist/audio-analyzer/index.js +2 -2
  3. package/dist/audio-analyzer/index.mjs +2 -2
  4. package/dist/{default-detection-model-DCQlW9fx.mjs → default-detection-model-CAUBVbgK.mjs} +53 -19
  5. package/dist/{default-detection-model-DTKHLLcC.js → default-detection-model-wNEISVA9.js} +58 -18
  6. package/dist/detection-pipeline/index.js +286 -458
  7. package/dist/detection-pipeline/index.mjs +286 -458
  8. package/dist/{dist-Ce8s7XqV.js → dist-BsVcf5wO.js} +1321 -833
  9. package/dist/{dist-C0Fr4hM5.mjs → dist-CuxSNLKW.mjs} +1316 -834
  10. package/dist/motion-wasm/index.js +1 -1
  11. package/dist/motion-wasm/index.mjs +1 -1
  12. package/dist/{node-Xm7amG2e.mjs → node-Cqb1QiXk.mjs} +1 -1
  13. package/dist/{node-DpOrymbW.js → node-UFk6I2f6.js} +1 -1
  14. package/dist/pipeline-runner/index.js +266 -72
  15. package/dist/pipeline-runner/index.mjs +266 -72
  16. package/dist/{process-memory-CBRjuhyg.js → process-memory-CJV29sPf.js} +1 -1
  17. package/dist/{process-memory-BN5qYGsD.mjs → process-memory-D0Nvs9rr.mjs} +1 -1
  18. package/dist/recorder/index.js +12 -2
  19. package/dist/recorder/index.mjs +12 -2
  20. package/dist/{segment-demux-js-BhMlS_Ow.js → segment-demux-js-DGwmf5hu.js} +1 -1
  21. package/dist/{segment-demux-js-Bhwpj5Wl.mjs → segment-demux-js-DIDWw1iE.mjs} +1 -1
  22. package/dist/stream-broker/_stub.js +2 -2
  23. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DKd7oYba.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-B7nBFqva.mjs} +2 -2
  24. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CCIyBvRa.mjs +26 -0
  25. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DoyA71_q.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DeD_UFdb.mjs} +1 -1
  26. package/dist/stream-broker/demux-worker-child.js +1 -1
  27. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  28. package/dist/stream-broker/{hostInit-CCMIHjff.mjs → hostInit-BKlb3qac.mjs} +2 -2
  29. package/dist/stream-broker/index.js +3 -3
  30. package/dist/stream-broker/index.mjs +3 -3
  31. package/dist/stream-broker/remoteEntry.js +1 -1
  32. package/package.json +3 -2
  33. package/python/postprocessors/__init__.py +2 -0
  34. package/python/postprocessors/ssd.py +73 -17
  35. package/python/postprocessors/test_ssd.py +205 -0
  36. package/python/postprocessors/test_yunet.py +292 -0
  37. package/python/postprocessors/testdata/ssdlite_mobiledet_outputs.json +1 -0
  38. package/python/postprocessors/yunet.py +275 -0
  39. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-6IHzlLJ_.mjs +0 -26
@@ -1,6 +1,6 @@
1
- import { $t as errMsg, An as literal, At as pickDetailCropConvention, C as FailureCounters, D as NativeLeaseAdmissionSchema, Dn as boolean, E as MOTION_CLOSE_AFTER_MS, En as array, Fn as string, Ln as EventCategory, Mn as object, Nt as pipelineRunnerCapability, O as NativeLeaseSettingsSchema, Tn as _enum, _ as DEFAULT_NATIVE_LEASE_SETTINGS, _t as loadContributionCapability, bn as nodePin, fn as createEvent, ft as failureContributionCapability, jn as number, jt as pickNativeLeaseOverride, kn as lazy, m as DEFAULT_DETAIL_CROP_CONVENTION, mn as defineCustomActions, on as BaseAddon, pn as customAction, tt as deriveDetailCropRect, v as DEVICE_BACKEND_TO_FORMAT } from "../dist-C0Fr4hM5.mjs";
2
- import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-Xm7amG2e.mjs";
3
- import { a as localFrameRegistry, d as getStepDefinition, i as rootObjectGate, o as resolveFrameViewGeometry, r as macroGateVerdict } from "../default-detection-model-DCQlW9fx.mjs";
1
+ import { An as lazy, D as MOTION_CLOSE_AFTER_MS, Dn as array, En as _enum, In as string, Mn as number, Mt as pickNativeLeaseOverride, Nn as object, O as NativeLeaseAdmissionSchema, On as boolean, Pt as pipelineRunnerCapability, Rn as EventCategory, en as errMsg, h as DEFAULT_DETAIL_CROP_CONVENTION, hn as defineCustomActions, i as BackgroundRunRegistry, jn as literal, jt as pickDetailCropConvention, k as NativeLeaseSettingsSchema, mn as customAction, nt as deriveDetailCropRect, pn as createEvent, pt as failureContributionCapability, sn as BaseAddon, v as DEFAULT_NATIVE_LEASE_SETTINGS, vt as loadContributionCapability, w as FailureCounters, xn as nodePin, y as DEVICE_BACKEND_TO_FORMAT } from "../dist-CuxSNLKW.mjs";
2
+ import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-Cqb1QiXk.mjs";
3
+ import { a as localFrameRegistry, d as getStepDefinition, i as rootObjectGate, o as resolveFrameViewGeometry, p as RETIRED_MODEL_IDS, r as macroGateVerdict } from "../default-detection-model-CAUBVbgK.mjs";
4
4
  import { t as isWorkerReply } from "../worker-protocol-C_W-P_g-.mjs";
5
5
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
6
6
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
@@ -1017,6 +1017,68 @@ var ParkedFrameStore = class {
1017
1017
  }
1018
1018
  }
1019
1019
  };
1020
+ /**
1021
+ * The key prefix the hub parks a face's SOURCE frame under (D644). The hub
1022
+ * owns the key; the runner reads only this prefix, to keep those parcels in
1023
+ * their own budget. Mirrors `FACE_SOURCE_PARK_PREFIX` in addon-post-analysis
1024
+ * (`runtime/face-source-park-port.ts`) — both specs pin the literal.
1025
+ */
1026
+ var FACE_SOURCE_PARCEL_PREFIX = "face-src:";
1027
+ /** Is this key a face source parcel? */
1028
+ function isFaceSourceParcelKey(trackId) {
1029
+ return trackId.startsWith(FACE_SOURCE_PARCEL_PREFIX);
1030
+ }
1031
+ /**
1032
+ * Track parcels and face source parcels in TWO stores with two budgets (D644).
1033
+ *
1034
+ * A face source parcel is a full native frame parked on every held best face.
1035
+ * In the shared store its eviction took the GLOBALLY oldest parcel — a
1036
+ * track's `keyFrame` or `thumbnail` — so a busy face scene could cost a track
1037
+ * its best frame (D58: media a later pass depends on must land). Here a face
1038
+ * parcel can only ever evict another face parcel.
1039
+ */
1040
+ var PartitionedParkedFrameStore = class {
1041
+ track;
1042
+ faceSource;
1043
+ constructor(options = {}) {
1044
+ this.track = new ParkedFrameStore(options.track);
1045
+ this.faceSource = new ParkedFrameStore({
1046
+ budgetBytes: 16 * 1024 * 1024,
1047
+ perDeviceMax: 4,
1048
+ ...options.faceSource
1049
+ });
1050
+ }
1051
+ storeFor(trackId) {
1052
+ return isFaceSourceParcelKey(trackId) ? this.faceSource : this.track;
1053
+ }
1054
+ get size() {
1055
+ return this.track.size + this.faceSource.size;
1056
+ }
1057
+ get bytes() {
1058
+ return this.track.bytes + this.faceSource.bytes;
1059
+ }
1060
+ park(deviceId, trackId, kind, frame) {
1061
+ return this.storeFor(trackId).park(deviceId, trackId, kind, frame);
1062
+ }
1063
+ get(deviceId, trackId, kind) {
1064
+ return this.storeFor(trackId).get(deviceId, trackId, kind);
1065
+ }
1066
+ release(deviceId, trackId) {
1067
+ return this.storeFor(trackId).release(deviceId, trackId);
1068
+ }
1069
+ statsByDevice(deviceId) {
1070
+ const a = this.track.statsByDevice(deviceId);
1071
+ const b = this.faceSource.statsByDevice(deviceId);
1072
+ return {
1073
+ parcels: a.parcels + b.parcels,
1074
+ bytes: a.bytes + b.bytes
1075
+ };
1076
+ }
1077
+ clear() {
1078
+ this.track.clear();
1079
+ this.faceSource.clear();
1080
+ }
1081
+ };
1020
1082
  /** {@link RETAINED_FRAME_BUDGET_MB} in bytes. */
1021
1083
  var RETAINED_FRAME_BUDGET_BYTES = (() => {
1022
1084
  const raw = Number(process.env["CAMSTACK_SESSION_RETAIN_MB"]);
@@ -2166,28 +2228,17 @@ function onboardRootDetections(slot, frame, gate) {
2166
2228
  //#endregion
2167
2229
  //#region src/pipeline-runner/bench-step-schema.ts
2168
2230
  /**
2169
- * Shared bench-facing schemas: the minimal recursive step tree and the
2170
- * engine choice. Extracted from `bench-actions.ts` so the capacity-ramp
2171
- * schemas (`capacity/capacity-schemas.ts`) can reuse them without a
2172
- * bench-actions ↔ capacity-schemas import cycle.
2173
- *
2174
- * Local mirror of pipeline-executor's shapes ON PURPOSE (not a cap-package
2175
- * coupling): the shape is fixed by the runtime contract
2176
- * (runtime + backend + format + optional device / addonId + modelId +
2177
- * enabled + children).
2178
- */
2179
- var BenchEngineChoiceSchema = object({
2180
- runtime: _enum(["node", "python"]),
2181
- backend: string(),
2182
- format: _enum([
2183
- "onnx",
2184
- "coreml",
2185
- "openvino",
2186
- "tflite",
2187
- "pt"
2188
- ]),
2189
- device: string().optional()
2190
- });
2231
+ * Shared bench-facing schemas: the minimal recursive step tree. Extracted from
2232
+ * `bench-actions.ts` so the capacity-ramp schemas (`capacity/capacity-schemas.ts`)
2233
+ * can reuse it without a bench-actions ↔ capacity-schemas import cycle.
2234
+ *
2235
+ * Local mirror of pipeline-executor's step shape ON PURPOSE (not a cap-package
2236
+ * coupling): addonId + modelId + enabled + children.
2237
+ *
2238
+ * There is no engine choice here any more (D646). A bench names the pool it
2239
+ * measures by `deviceKey`; the engine override it used to carry was honoured by
2240
+ * swapping the executor's shared engine state under live cameras.
2241
+ */
2191
2242
  var BenchStepSchema = lazy(() => object({
2192
2243
  addonId: string(),
2193
2244
  modelId: string(),
@@ -2223,7 +2274,6 @@ var RunCapacityRampInputSchema = object({
2223
2274
  sessionId: string(),
2224
2275
  nodeId: string().optional(),
2225
2276
  deviceKey: string().optional(),
2226
- engine: BenchEngineChoiceSchema.optional(),
2227
2277
  slo: CapacitySloSchema.optional(),
2228
2278
  allowActiveCameras: boolean().optional(),
2229
2279
  drainTimeoutSec: number().min(1).max(300).optional()
@@ -2411,16 +2461,15 @@ var CacheBenchFrameResultSchema = object({
2411
2461
  });
2412
2462
  var ReleaseBenchFrameInputSchema = object({ frameId: string() });
2413
2463
  var ReleaseBenchFrameResultSchema = object({ released: boolean() });
2414
- var RunSyntheticBenchInputSchema = object({
2464
+ var StartSyntheticBenchInputSchema = object({
2415
2465
  frameId: string(),
2416
2466
  steps: array(BenchStepSchema).min(1),
2417
2467
  parallel: number().int().min(1).max(32),
2418
2468
  iterations: number().int().min(1).max(1e4),
2419
2469
  warmup: number().int().min(0).max(100).optional(),
2420
- sessionId: string().optional(),
2470
+ sessionId: string().min(1),
2421
2471
  simulatePipeline: boolean().optional(),
2422
2472
  nodeId: string().optional(),
2423
- engine: BenchEngineChoiceSchema.optional(),
2424
2473
  deviceKey: string().optional(),
2425
2474
  plane: _enum(["full", "frame"]).optional()
2426
2475
  });
@@ -2430,7 +2479,16 @@ var TimingSplitSchema = object({
2430
2479
  p95: number(),
2431
2480
  p99: number()
2432
2481
  });
2433
- var RunSyntheticBenchResultSchema = object({
2482
+ var BenchPoolSchema = object({
2483
+ nodeId: string(),
2484
+ deviceKey: string().nullable(),
2485
+ runtime: string().nullable(),
2486
+ numWorkers: number().nullable(),
2487
+ concurrency: number().nullable(),
2488
+ batchMode: string().nullable(),
2489
+ maxBatchSize: number().nullable()
2490
+ });
2491
+ var SyntheticBenchResultSchema = object({
2434
2492
  runs: number(),
2435
2493
  wallSec: number(),
2436
2494
  fps: number(),
@@ -2442,23 +2500,52 @@ var RunSyntheticBenchResultSchema = object({
2442
2500
  predictMs: number(),
2443
2501
  batchSizeMean: number(),
2444
2502
  batchSizeMax: number(),
2445
- engine: object({
2446
- runtime: string(),
2447
- backend: string(),
2448
- device: string().optional()
2449
- }).optional(),
2450
- tuning: object({
2451
- batchMode: string(),
2452
- windowMs: number(),
2453
- maxBatchSize: number(),
2454
- concurrency: number()
2455
- }).optional(),
2456
- path: string().optional()
2503
+ pool: BenchPoolSchema,
2504
+ path: string()
2505
+ });
2506
+ /** `startSyntheticBench` answers at once; the run continues in the background. */
2507
+ var StartSyntheticBenchAcceptedSchema = object({
2508
+ accepted: literal(true),
2509
+ sessionId: string()
2457
2510
  });
2511
+ var SyntheticBenchKeySchema = object({ sessionId: string() });
2512
+ var SyntheticBenchStatusSchema = object({
2513
+ sessionId: string(),
2514
+ state: _enum([
2515
+ "running",
2516
+ "done",
2517
+ "failed",
2518
+ "aborted"
2519
+ ]),
2520
+ startedAtMs: number(),
2521
+ finishedAtMs: number().nullable(),
2522
+ progress: object({
2523
+ runs: number(),
2524
+ totalRuns: number()
2525
+ }).nullable(),
2526
+ result: SyntheticBenchResultSchema.nullable(),
2527
+ error: string().nullable()
2528
+ }).nullable();
2458
2529
  var pipelineRunnerBenchActions = defineCustomActions({
2459
2530
  cacheBenchFrame: customAction(CacheBenchFrameInputSchema, CacheBenchFrameResultSchema, { kind: "mutation" }),
2460
2531
  releaseBenchFrame: customAction(ReleaseBenchFrameInputSchema, ReleaseBenchFrameResultSchema, { kind: "mutation" }),
2461
- runSyntheticBench: customAction(RunSyntheticBenchInputSchema, RunSyntheticBenchResultSchema, { kind: "mutation" }),
2532
+ /**
2533
+ * START a synthetic bench and return at once (D646). Up to 32 parallel ×
2534
+ * 10 000 iterations does not fit the UDS addon-call plane's 60 s request
2535
+ * timeout, and a synchronous call was abandoned by its caller while it kept
2536
+ * loading the node. Poll `getSyntheticBenchStatus {sessionId}`; stop early
2537
+ * with `abortSyntheticBench {sessionId}`. One bench per runner at a time —
2538
+ * the measurement owns the pool.
2539
+ */
2540
+ startSyntheticBench: customAction(StartSyntheticBenchInputSchema, StartSyntheticBenchAcceptedSchema, {
2541
+ kind: "mutation",
2542
+ auth: "admin"
2543
+ }),
2544
+ getSyntheticBenchStatus: customAction(SyntheticBenchKeySchema, SyntheticBenchStatusSchema),
2545
+ abortSyntheticBench: customAction(SyntheticBenchKeySchema, object({ aborted: boolean() }), {
2546
+ kind: "mutation",
2547
+ auth: "admin"
2548
+ }),
2462
2549
  /**
2463
2550
  * OPEN-loop capacity ramp (spec `2026-08-02-capacity-test-design.md` §4):
2464
2551
  * paced N×`fpsPerCamera` single-frame `runPipeline` calls with raw RGB —
@@ -2523,12 +2610,24 @@ function buildBenchRunPipelineInput(req) {
2523
2610
  return {
2524
2611
  steps: [...req.steps],
2525
2612
  frame: req.frame,
2526
- ...req.engine ? { engine: req.engine } : {},
2527
2613
  ...req.deviceKey ? { deviceKey: req.deviceKey } : {},
2528
2614
  ...req.plane ? { plane: req.plane } : {}
2529
2615
  };
2530
2616
  }
2531
2617
  /**
2618
+ * The tuning query for the pool a bench MEASURED (D646). It asked the node
2619
+ * default of whatever node answered first, so an NPU run was recorded beside
2620
+ * the onnx pool's `concurrency: 4`. Absent `deviceKey`, never
2621
+ * present-and-undefined, for the same `.loose()` reason as
2622
+ * {@link buildBenchRunPipelineInput}.
2623
+ */
2624
+ function buildBenchTuningQuery(target) {
2625
+ return {
2626
+ nodeId: target.nodeId,
2627
+ input: target.deviceKey ? { deviceKey: target.deviceKey } : {}
2628
+ };
2629
+ }
2630
+ /**
2532
2631
  * How long a box stays "seen".
2533
2632
  *
2534
2633
  * Sized on the gate's own clock, not on a guess: `maxDeferralMs` defaults to
@@ -3290,7 +3389,14 @@ function toDetailResult(detection, stepId, crop) {
3290
3389
  ...label.modelId !== void 0 ? { labelModelId: label.modelId } : {}
3291
3390
  } : {},
3292
3391
  ...detection.faceAlignedCrop !== void 0 ? { alignedCropJpeg: detection.faceAlignedCrop } : {},
3293
- ...detection.nativeFaceShortSidePx !== void 0 ? { nativeFaceShortSidePx: detection.nativeFaceShortSidePx } : {}
3392
+ ...detection.nativeFaceShortSidePx !== void 0 ? { nativeFaceShortSidePx: detection.nativeFaceShortSidePx } : {},
3393
+ ...detection.landmarks !== void 0 ? { landmarks: detection.landmarks.map((p) => mapPointToFrameSpace(p, crop)) } : {}
3394
+ };
3395
+ }
3396
+ function mapPointToFrameSpace(point, crop) {
3397
+ return {
3398
+ x: crop.frameSpace.x + point.x * (crop.frameSpace.w / crop.width),
3399
+ y: crop.frameSpace.y + point.y * (crop.frameSpace.h / crop.height)
3294
3400
  };
3295
3401
  }
3296
3402
  /**
@@ -6597,6 +6703,7 @@ var PipelineRunner = class {
6597
6703
  //#endregion
6598
6704
  //#region src/pipeline-runner/stateless-step.ts
6599
6705
  function modelServability(step, modelId, format) {
6706
+ if (RETIRED_MODEL_IDS[step.id]?.includes(modelId) === true) return { kind: "retired" };
6600
6707
  const entry = step.models.find((m) => m.id === modelId);
6601
6708
  if (entry === void 0) return { kind: "custom-model" };
6602
6709
  if (entry.formats[format] !== void 0) return { kind: "catalog-build" };
@@ -6641,6 +6748,7 @@ async function runStatelessStep(deps, input) {
6641
6748
  const format = await deps.executionFormat();
6642
6749
  if (format === null) return refuse(deps, input, "model-not-servable", "this node could not report the engine format it would dispatch on, so the model pin cannot be verified — running anyway would risk a silent format substitution");
6643
6750
  const servability = modelServability(definition, input.modelId, format);
6751
+ if (servability.kind === "retired") return refuse(deps, input, "model-not-servable", `model "${input.modelId}" was retired from the ${definition.id} catalog — this node would have substituted the step default`);
6644
6752
  if (servability.kind === "no-build") return refuse(deps, input, "model-not-servable", `model "${input.modelId}" has no ${format} build (catalog ships: ${servability.availableFormats.join(", ") || "none"}) — this node would have substituted the ${format} default`);
6645
6753
  let decodeError = null;
6646
6754
  const crop = await cutFromFullFrame(input.frameJpeg, {
@@ -7496,6 +7604,26 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
7496
7604
  benchFrameCache = /* @__PURE__ */ new Map();
7497
7605
  benchFrameSweeper = null;
7498
7606
  /**
7607
+ * Synthetic benches, start-then-poll (D646). One at a time on this runner —
7608
+ * the measurement owns the pool — and the last few finished ones kept for a
7609
+ * late poll. In RAM: a bench belongs to this process.
7610
+ */
7611
+ syntheticBenches = new BackgroundRunRegistry({
7612
+ maxConcurrent: 1,
7613
+ keepFinished: 5,
7614
+ onSettled: (status) => {
7615
+ const line = { meta: {
7616
+ sessionId: status.runId,
7617
+ state: status.state,
7618
+ error: status.error,
7619
+ runs: status.result?.runs ?? null,
7620
+ fps: status.result?.fps ?? null
7621
+ } };
7622
+ if (status.state === "failed") this.ctx.logger.warn("synthetic bench failed", line);
7623
+ else this.ctx.logger.info("synthetic bench finished", line);
7624
+ }
7625
+ });
7626
+ /**
7499
7627
  * In-flight + recent capacity-ramp runs, keyed by sessionId. The ramp is
7500
7628
  * fire-and-poll (a full run outlives the UDS addon-call 60s timeout), so
7501
7629
  * completed results are kept here for `getCapacityRampStatus` to collect;
@@ -7574,7 +7702,11 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
7574
7702
  nodeId: this.nodeId,
7575
7703
  continuousRetain: isContinuousRetainEnabled()
7576
7704
  });
7577
- this.parkedFrames = new ParkedFrameStore({ onEvict: (eviction) => this.noteParkedEviction(eviction.deviceId, eviction.cause) });
7705
+ const onEvict = (eviction) => this.noteParkedEviction(eviction.deviceId, eviction.cause);
7706
+ this.parkedFrames = new PartitionedParkedFrameStore({
7707
+ track: { onEvict },
7708
+ faceSource: { onEvict }
7709
+ });
7578
7710
  this.runner = new PipelineRunner({
7579
7711
  maxQueueDepth: this.config.maxQueueDepth,
7580
7712
  maxConcurrentInferences: this.config.maxConcurrentInferences,
@@ -7692,7 +7824,9 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
7692
7824
  actionHandlers: {
7693
7825
  cacheBenchFrame: async (input) => this.cacheBenchFrame(input),
7694
7826
  releaseBenchFrame: async (input) => this.releaseBenchFrame(input),
7695
- runSyntheticBench: async (input) => this.runSyntheticBench(input),
7827
+ startSyntheticBench: async (input) => this.startSyntheticBench(input),
7828
+ getSyntheticBenchStatus: async (input) => this.getSyntheticBenchStatus(input.sessionId),
7829
+ abortSyntheticBench: async (input) => ({ aborted: this.syntheticBenches.abort(input.sessionId) }),
7696
7830
  runCapacityRamp: async (input) => this.runCapacityRampAction(input),
7697
7831
  getCapacityRampStatus: async (input) => this.getCapacityRampStatusAction(input),
7698
7832
  listCapacityRamps: async () => this.listCapacityRampsAction(),
@@ -7714,6 +7848,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
7714
7848
  this.benchFrameSweeper = null;
7715
7849
  }
7716
7850
  this.benchFrameCache.clear();
7851
+ this.syntheticBenches.abortAll();
7717
7852
  for (const entry of this.capacityRuns.values()) entry.abortFlag.aborted = true;
7718
7853
  this.capacityRuns.clear();
7719
7854
  if (this.unsubMotionEvents) {
@@ -7793,7 +7928,34 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
7793
7928
  const now = Date.now();
7794
7929
  for (const [id, entry] of this.benchFrameCache) if (entry.expiresAt < now) this.benchFrameCache.delete(id);
7795
7930
  }
7796
- async runSyntheticBench(input) {
7931
+ /**
7932
+ * Validate the cheap preconditions synchronously (so a bad frame id is a
7933
+ * refusal the caller sees at once), then run the bench in the background
7934
+ * and answer with the receipt (D646).
7935
+ */
7936
+ startSyntheticBench(input) {
7937
+ if (!this.ctx.api) throw new Error("startSyntheticBench: ctx.api unavailable");
7938
+ if (!this.benchFrameCache.has(input.frameId)) throw new Error(`startSyntheticBench: frameId ${input.frameId} not cached (call cacheBenchFrame first)`);
7939
+ this.syntheticBenches.start(input.sessionId, (run) => this.runSyntheticBench(input, run));
7940
+ return {
7941
+ accepted: true,
7942
+ sessionId: input.sessionId
7943
+ };
7944
+ }
7945
+ getSyntheticBenchStatus(sessionId) {
7946
+ const status = this.syntheticBenches.status(sessionId);
7947
+ if (status === null) return null;
7948
+ return {
7949
+ sessionId: status.runId,
7950
+ state: status.state,
7951
+ startedAtMs: status.startedAtMs,
7952
+ finishedAtMs: status.finishedAtMs,
7953
+ progress: status.progress,
7954
+ result: status.result,
7955
+ error: status.error
7956
+ };
7957
+ }
7958
+ async runSyntheticBench(input, run) {
7797
7959
  const ctx = this.ctx;
7798
7960
  const api = ctx.api;
7799
7961
  if (!api) throw new Error("runSyntheticBench: ctx.api unavailable");
@@ -7843,8 +8005,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
7843
8005
  }, pin)).frameId;
7844
8006
  await api.pipelineExecutor.runPipeline.mutate({ ...buildBenchRunPipelineInput({
7845
8007
  steps: stepsToRun,
7846
- frame: sharedFrame,
7847
- ...input.engine ? { engine: input.engine } : {}
8008
+ frame: sharedFrame
7848
8009
  }) }, pin);
7849
8010
  const warmupCount = input.warmup ?? 1;
7850
8011
  for (let w = 0; w < warmupCount; w++) await api.pipelineExecutor.inferCached.mutate({
@@ -7858,11 +8019,12 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
7858
8019
  const batchSizes = [];
7859
8020
  const detCounts = [];
7860
8021
  let _n = 0;
7861
- const sessionId = input.sessionId ?? `synth-${Date.now().toString(36)}`;
8022
+ const sessionId = input.sessionId;
7862
8023
  const totalRuns = input.parallel * input.iterations;
7863
8024
  const wallStart = performance.now();
7864
8025
  const worker = async () => {
7865
8026
  for (let i = 0; i < input.iterations; i++) {
8027
+ if (run.signal.aborted) break;
7866
8028
  const t0 = performance.now();
7867
8029
  const result = await api.pipelineExecutor.inferCached.mutate({
7868
8030
  stepId: rootStep.addonId,
@@ -7882,6 +8044,10 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
7882
8044
  batchSizes.push(bs);
7883
8045
  detCounts.push(dets);
7884
8046
  const n = ++_n;
8047
+ run.report({
8048
+ runs: n,
8049
+ totalRuns
8050
+ });
7885
8051
  if (n <= 20) ctx.logger.info("bench call trace (cached)", { meta: {
7886
8052
  n,
7887
8053
  wallMs: Math.round(wallMs),
@@ -7934,7 +8100,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
7934
8100
  await Promise.all(Array.from({ length: input.parallel }, () => worker()));
7935
8101
  const wallSec = (performance.now() - wallStart) / 1e3;
7936
8102
  await api.pipelineExecutor.uncacheFrame.mutate({ frameId: poolFrameId }, pin).catch(() => {});
7937
- return this.buildBenchResult(wallTimings, inferTimings, preprocessTimings, predictTimings, batchSizes, detCounts, wallSec, "cached");
8103
+ return this.buildBenchResult(wallTimings, inferTimings, preprocessTimings, predictTimings, batchSizes, detCounts, wallSec, "cached", { nodeId: benchNode });
7938
8104
  }
7939
8105
  ctx.logger.info("synthetic bench: using full runPipeline path", { meta: {
7940
8106
  steps: enabledSteps.length,
@@ -7948,7 +8114,6 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
7948
8114
  const result = await api.pipelineExecutor.runPipeline.mutate({ ...buildBenchRunPipelineInput({
7949
8115
  steps: stepsToRun,
7950
8116
  frame: sharedFrame,
7951
- ...input.engine ? { engine: input.engine } : {},
7952
8117
  ...input.deviceKey ? { deviceKey: input.deviceKey } : {},
7953
8118
  ...input.plane ? { plane: input.plane } : {}
7954
8119
  }) }, pin);
@@ -7976,11 +8141,12 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
7976
8141
  const predictTimings = [];
7977
8142
  const batchSizes = [];
7978
8143
  const detCounts = [];
7979
- const sessionId = input.sessionId ?? `synth-${Date.now().toString(36)}`;
8144
+ const sessionId = input.sessionId;
7980
8145
  const totalRuns = input.parallel * input.iterations;
7981
8146
  const wallStart = performance.now();
7982
8147
  const worker = async () => {
7983
8148
  for (let i = 0; i < input.iterations; i++) {
8149
+ if (run.signal.aborted) break;
7984
8150
  const { wallMs, result } = await callOnce();
7985
8151
  wallTimings.push(wallMs);
7986
8152
  serverWallTimings.push(result.debug?.wallMs ?? 0);
@@ -7990,6 +8156,10 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
7990
8156
  batchSizes.push(result.debug?.batchSize ?? 1);
7991
8157
  detCounts.push(result.detections?.length ?? 0);
7992
8158
  const n = wallTimings.length;
8159
+ run.report({
8160
+ runs: n,
8161
+ totalRuns
8162
+ });
7993
8163
  if (n % Math.max(1, input.parallel) === 0 && ctx.eventBus) {
7994
8164
  const elapsed = (performance.now() - wallStart) / 1e3;
7995
8165
  const fps = elapsed > 0 ? n / elapsed : 0;
@@ -8030,9 +8200,12 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
8030
8200
  };
8031
8201
  await Promise.all(Array.from({ length: input.parallel }, () => worker()));
8032
8202
  const wallSec = (performance.now() - wallStart) / 1e3;
8033
- return this.buildBenchResult(wallTimings, inferTimings, preprocessTimings, predictTimings, batchSizes, detCounts, wallSec, "pipeline");
8203
+ return this.buildBenchResult(wallTimings, inferTimings, preprocessTimings, predictTimings, batchSizes, detCounts, wallSec, "pipeline", {
8204
+ nodeId: benchNode,
8205
+ ...input.deviceKey ? { deviceKey: input.deviceKey } : {}
8206
+ });
8034
8207
  }
8035
- async buildBenchResult(wallTimings, inferTimings, preprocessTimings, predictTimings, batchSizes, detCounts, wallSec, path) {
8208
+ async buildBenchResult(wallTimings, inferTimings, preprocessTimings, predictTimings, batchSizes, detCounts, wallSec, path, target) {
8036
8209
  const meanOfArr = (xs) => xs.length > 0 ? xs.reduce((s, v) => s + v, 0) / xs.length : 0;
8037
8210
  this.ctx.logger.info("synthetic bench summary", { meta: {
8038
8211
  runs: wallTimings.length,
@@ -8068,24 +8241,47 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
8068
8241
  batchSizeMean: Math.round(meanOf(batchSizes) * 100) / 100,
8069
8242
  batchSizeMax: batchSizes.length > 0 ? Math.max(...batchSizes) : 0,
8070
8243
  path,
8071
- ...await this.getEngineAndTuning()
8244
+ pool: await this.readBenchPool(target)
8072
8245
  };
8073
8246
  }
8074
- async getEngineAndTuning() {
8247
+ /**
8248
+ * The pool a bench measured, and its provisioning — asked of the node it
8249
+ * was pinned to, for the device pool it named (D646). It used to ask the
8250
+ * node DEFAULT of whichever node answered, so an NPU bench was recorded
8251
+ * beside the onnx pool's tuning. A failed read is `null` fields and a line,
8252
+ * never a default (D393).
8253
+ */
8254
+ async readBenchPool(target) {
8255
+ const unknown = {
8256
+ nodeId: target.nodeId,
8257
+ deviceKey: target.deviceKey ?? null,
8258
+ runtime: null,
8259
+ numWorkers: null,
8260
+ concurrency: null,
8261
+ batchMode: null,
8262
+ maxBatchSize: null
8263
+ };
8264
+ const api = this.ctx.api;
8265
+ if (!api) return unknown;
8266
+ const query = buildBenchTuningQuery(target);
8075
8267
  try {
8076
- const api = this.ctx.api;
8077
- if (!api) return {};
8078
- const [eng, tuning] = await Promise.all([api.pipelineExecutor.getSelectedEngine.query(), api.pipelineExecutor.getEffectiveTuning.query()]);
8268
+ const tuning = await api.pipelineExecutor.getEffectiveTuning.query({ ...query.input }, nodePin(query.nodeId));
8079
8269
  return {
8080
- engine: eng ? {
8081
- runtime: eng.runtime,
8082
- backend: eng.backend,
8083
- device: eng.device
8084
- } : void 0,
8085
- tuning: tuning ?? void 0
8270
+ nodeId: target.nodeId,
8271
+ deviceKey: tuning.deviceKey,
8272
+ runtime: tuning.runtime,
8273
+ numWorkers: tuning.numWorkers,
8274
+ concurrency: tuning.concurrency,
8275
+ batchMode: tuning.batchMode,
8276
+ maxBatchSize: tuning.maxBatchSize
8086
8277
  };
8087
- } catch {
8088
- return {};
8278
+ } catch (err) {
8279
+ this.ctx.logger.warn("synthetic bench: pool tuning read failed — reported as unknown", { meta: {
8280
+ nodeId: target.nodeId,
8281
+ deviceKey: target.deviceKey ?? null,
8282
+ error: errMsg(err)
8283
+ } });
8284
+ return unknown;
8089
8285
  }
8090
8286
  }
8091
8287
  /**
@@ -8208,7 +8404,6 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
8208
8404
  settleSec,
8209
8405
  measureSec,
8210
8406
  deviceKey: input.deviceKey ?? null,
8211
- engine: input.engine ?? null,
8212
8407
  contaminatedByActiveCameras,
8213
8408
  steps: stepsToRun.map((s) => `${s.addonId}/${s.modelId}${s.enabled ? "" : "[off]"}`)
8214
8409
  } });
@@ -8225,8 +8420,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
8225
8420
  },
8226
8421
  plane: "frame",
8227
8422
  sessionId,
8228
- ...input.deviceKey ? { deviceKey: input.deviceKey } : {},
8229
- ...input.engine ? { engine: input.engine } : {}
8423
+ ...input.deviceKey ? { deviceKey: input.deviceKey } : {}
8230
8424
  }, pin);
8231
8425
  if (result.debug?.engine !== void 0) engineLabel = result.debug.engine;
8232
8426
  if (result.shed === true) return {
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-Ce8s7XqV.js");
2
+ const require_dist = require("./dist-BsVcf5wO.js");
3
3
  let node_fs = require("node:fs");
4
4
  node_fs = require_chunk.__toESM(node_fs);
5
5
  let node_child_process = require("node:child_process");
@@ -1,4 +1,4 @@
1
- import { Dt as parseProcStatus } from "./dist-C0Fr4hM5.mjs";
1
+ import { Ot as parseProcStatus } from "./dist-CuxSNLKW.mjs";
2
2
  import * as fs from "node:fs";
3
3
  import { execFile } from "node:child_process";
4
4
  //#region src/shared/node-topology-platform.ts
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-Ce8s7XqV.js");
7
- const require_node = require("../node-DpOrymbW.js");
6
+ const require_dist = require("../dist-BsVcf5wO.js");
7
+ const require_node = require("../node-UFk6I2f6.js");
8
8
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
9
9
  const require_restream_intent = require("../restream-intent-7uDNqMKs.js");
10
10
  const require_retire_root_keys = require("../retire-root-keys-Csb8z2f3.js");
@@ -5576,6 +5576,16 @@ Object.freeze({
5576
5576
  "priority": 3
5577
5577
  } } },
5578
5578
  "getHistory": { "filter": { "limit": 100 } },
5579
+ "previewStateSummary": { "rule": { "__nested__": {
5580
+ "enabled": true,
5581
+ "conditions": {},
5582
+ "media": { "attach": "best" },
5583
+ "throttle": {
5584
+ "cooldownSec": 60,
5585
+ "scope": "rule-device"
5586
+ },
5587
+ "priority": 3
5588
+ } } },
5579
5589
  "testRule": {
5580
5590
  "rule": { "__nested__": {
5581
5591
  "enabled": true,
@@ -1,5 +1,5 @@
1
- import { $t as errMsg, B as VISIT_MERGE_GAP_MS, Bt as resolveCreateExportSubject, Cn as selectAssignedProfileSlots, Ct as migrateLegacyDeviceSignalConfig, Dn as boolean, En as array, F as RECORDING_SOURCE_CAMSTACK_ADDON, Fn as string, Ft as recordingArchiveCapability, Ht as resolveLocationMode, I as RecordingConfigSchema, It as recordingCapability, J as clipExportFailure, K as batteryCapability, Kt as storageEvictableCapability, L as RecordingSignalStatusSchema, Ln as EventCategory, Lt as recordingExportCapability, Mn as object, N as RECORDING_EXPORT_MAX_READ_BYTES, Nn as preprocess, P as RECORDING_SOURCE_CAMSTACK, Pn as record, Rt as recordingSignalCapability, S as ExportRecordSchema, St as mayWriteToLocation, Tn as _enum, Wt as resolveRecordingProfiles, Y as clipExportFailureOf, Yt as stripRetiredBandPreBufferSec, Zt as videoclipsCapability, _t as loadContributionCapability, a as CLIP_BROKER_PACED_RATES, b as EVENT_PAD_MS, bn as nodePin, dt as exportSubjectOf, et as deriveBatteryPresence, gn as hydrateSchema, gt as isFirstLevelMacroClass, h as DEFAULT_EVENTS_BAND_BUFFER_SEC, i as BatteryStatusSchema, jn as number, k as OpsLogEntrySchema, ln as DeviceFeature, lt as evictionPolicyForMode, mn as defineCustomActions, nt as deriveRecordingMode, on as BaseAddon, pn as customAction, pt as gbToBytes, qt as storageOccupancyCapability, st as evaluateSensorEdge, un as DeviceType, ut as evictionPolicyOfLocation, wn as sleep$1, wt as modeMayWrite, xt as mayReadLocation, y as EVENT_OWNER_TYPES, z as VIDEOCLIPS_MAX_OFFER_BYTES } from "../dist-C0Fr4hM5.mjs";
2
- import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-Xm7amG2e.mjs";
1
+ import { A as OpsLogEntrySchema, B as VIDEOCLIPS_MAX_OFFER_BYTES, C as ExportRecordSchema, Ct as mayWriteToLocation, Dn as array, En as _enum, F as RECORDING_SOURCE_CAMSTACK, Fn as record, Gt as resolveRecordingProfiles, I as RECORDING_SOURCE_CAMSTACK_ADDON, In as string, It as recordingArchiveCapability, Jt as storageOccupancyCapability, L as RecordingConfigSchema, Lt as recordingCapability, Mn as number, Nn as object, On as boolean, P as RECORDING_EXPORT_MAX_READ_BYTES, Pn as preprocess, Qt as videoclipsCapability, R as RecordingSignalStatusSchema, Rn as EventCategory, Rt as recordingExportCapability, St as mayReadLocation, Tn as sleep$1, Tt as modeMayWrite, Ut as resolveLocationMode, V as VISIT_MERGE_GAP_MS, Vt as resolveCreateExportSubject, X as clipExportFailureOf, Xt as stripRetiredBandPreBufferSec, Y as clipExportFailure, _n as hydrateSchema, _t as isFirstLevelMacroClass, a as BatteryStatusSchema, b as EVENT_OWNER_TYPES, ct as evaluateSensorEdge, dn as DeviceType, dt as evictionPolicyOfLocation, en as errMsg, ft as exportSubjectOf, g as DEFAULT_EVENTS_BAND_BUFFER_SEC, hn as defineCustomActions, mn as customAction, mt as gbToBytes, o as CLIP_BROKER_PACED_RATES, q as batteryCapability, qt as storageEvictableCapability, rt as deriveRecordingMode, sn as BaseAddon, tt as deriveBatteryPresence, un as DeviceFeature, ut as evictionPolicyForMode, vt as loadContributionCapability, wn as selectAssignedProfileSlots, wt as migrateLegacyDeviceSignalConfig, x as EVENT_PAD_MS, xn as nodePin, zt as recordingSignalCapability } from "../dist-CuxSNLKW.mjs";
2
+ import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-Cqb1QiXk.mjs";
3
3
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
4
4
  import { d as PREBUFFER_MAX_MS, l as withRecordingIntent, r as RECORDING_PRE_ROLL_REQUEST_MS } from "../restream-intent-DyGmLAU9.mjs";
5
5
  import { n as RowMapStore, t as retireRootKeys } from "../retire-root-keys-DZvlso2l.mjs";
@@ -5569,6 +5569,16 @@ Object.freeze({
5569
5569
  "priority": 3
5570
5570
  } } },
5571
5571
  "getHistory": { "filter": { "limit": 100 } },
5572
+ "previewStateSummary": { "rule": { "__nested__": {
5573
+ "enabled": true,
5574
+ "conditions": {},
5575
+ "media": { "attach": "best" },
5576
+ "throttle": {
5577
+ "cooldownSec": 60,
5578
+ "scope": "rule-device"
5579
+ },
5580
+ "priority": 3
5581
+ } } },
5572
5582
  "testRule": {
5573
5583
  "rule": { "__nested__": {
5574
5584
  "enabled": true,
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-Ce8s7XqV.js");
2
+ const require_dist = require("./dist-BsVcf5wO.js");
3
3
  let node_child_process = require("node:child_process");
4
4
  //#region src/stream-broker/recorded/avcc-annexb.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import { r as __toESM, t as __commonJSMin } from "./chunk-DnnnRqeS.mjs";
2
- import { $t as errMsg } from "./dist-C0Fr4hM5.mjs";
2
+ import { en as errMsg } from "./dist-CuxSNLKW.mjs";
3
3
  import { spawn } from "node:child_process";
4
4
  //#region src/stream-broker/recorded/avcc-annexb.ts
5
5
  /**
@@ -1,7 +1,7 @@
1
- import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, p as c, r as l, s as u, t as d, u as f } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DoyA71_q.mjs";
1
+ import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, p as c, r as l, s as u, t as d, u as f } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DeD_UFdb.mjs";
2
2
  import { a as p, i as m, n as h, o as g, r as _, t as v } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.js-C9j-2lBe.mjs";
3
3
  import { n as y, r as b, t as x } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-XO0-Pyu6.mjs";
4
- import { t as S } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-6IHzlLJ_.mjs";
4
+ import { t as S } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CCIyBvRa.mjs";
5
5
  import { n as C, t as w } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-BO7TIbJV.mjs";
6
6
  //#region ../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
7
7
  var T = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) === t).join(" ").trim(), E = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), D = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), O = (e) => {