@camstack/types 1.2.358 → 1.2.360

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.
@@ -80,6 +80,43 @@ declare const BulkRecordSchema: z.ZodObject<{
80
80
  id: z.ZodOptional<z.ZodString>;
81
81
  data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
82
82
  }, z.core.$strip>;
83
+ /**
84
+ * One write inside a {@link settingsStoreCapability.methods.transact} call.
85
+ * Only the three that a "replace this set, bump that revision" write needs.
86
+ */
87
+ declare const TransactOpSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
88
+ op: z.ZodLiteral<"deleteWhere">;
89
+ collection: z.ZodString;
90
+ filter: z.ZodObject<{
91
+ where: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
92
+ whereIn: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodUnknown>>>;
93
+ whereBetween: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodTuple<[z.ZodUnknown, z.ZodUnknown], null>>>;
94
+ whereNot: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
95
+ whereNotIn: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodUnknown>>>;
96
+ }, z.core.$strip>;
97
+ }, z.core.$strip>, z.ZodObject<{
98
+ op: z.ZodLiteral<"insertMany">;
99
+ collection: z.ZodString;
100
+ records: z.ZodReadonly<z.ZodArray<z.ZodObject<{
101
+ id: z.ZodOptional<z.ZodString>;
102
+ data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
103
+ }, z.core.$strip>>>;
104
+ }, z.core.$strip>, z.ZodObject<{
105
+ op: z.ZodLiteral<"update">;
106
+ collection: z.ZodString;
107
+ id: z.ZodString;
108
+ data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
109
+ }, z.core.$strip>], "op">;
110
+ /**
111
+ * The precondition of a transaction: the row `key` of `collection` must hold
112
+ * `equals` in `column`, read INSIDE the transaction.
113
+ */
114
+ declare const TransactGuardSchema: z.ZodObject<{
115
+ collection: z.ZodString;
116
+ key: z.ZodString;
117
+ column: z.ZodString;
118
+ equals: z.ZodUnknown;
119
+ }, z.core.$strip>;
83
120
  /**
84
121
  * Column declaration for a structured (SQL-backed) collection.
85
122
  *
@@ -302,6 +339,60 @@ export declare const settingsStoreCapability: {
302
339
  }, z.core.$strip>, z.ZodObject<{
303
340
  inserted: z.ZodNumber;
304
341
  }, z.core.$strip>, "mutation">;
342
+ /**
343
+ * Several writes, ONE transaction, behind an optional precondition.
344
+ *
345
+ * The multi-collection twin of {@link insertMany}: a write that has to move
346
+ * a set of rows in one collection AND a revision in another cannot be
347
+ * expressed as separate calls without a window in which a reader (or a
348
+ * crash) sees half of it. The retrain annotation save replaces a frame's
349
+ * rows, its dismissed set and its revision this way.
350
+ *
351
+ * `guard`, when given, is read inside the transaction: if the row is
352
+ * missing or its column differs from `equals`, NOTHING is written and the
353
+ * answer is `{ applied: false, current }` with what was found — the
354
+ * compare-and-set a revisioned write needs, with no second reader able to
355
+ * slip between the check and the writes.
356
+ *
357
+ * **All or nothing**, like {@link insertMany}: a throw in any op rolls the
358
+ * whole call back. Ops run in the order given (delete before insert to
359
+ * replace a set). `namespace` applies to every collection named.
360
+ */
361
+ readonly transact: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
362
+ namespace: z.ZodOptional<z.ZodString>;
363
+ guard: z.ZodOptional<z.ZodObject<{
364
+ collection: z.ZodString;
365
+ key: z.ZodString;
366
+ column: z.ZodString;
367
+ equals: z.ZodUnknown;
368
+ }, z.core.$strip>>;
369
+ ops: z.ZodReadonly<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
370
+ op: z.ZodLiteral<"deleteWhere">;
371
+ collection: z.ZodString;
372
+ filter: z.ZodObject<{
373
+ where: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
374
+ whereIn: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodUnknown>>>;
375
+ whereBetween: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodTuple<[z.ZodUnknown, z.ZodUnknown], null>>>;
376
+ whereNot: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
377
+ whereNotIn: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodUnknown>>>;
378
+ }, z.core.$strip>;
379
+ }, z.core.$strip>, z.ZodObject<{
380
+ op: z.ZodLiteral<"insertMany">;
381
+ collection: z.ZodString;
382
+ records: z.ZodReadonly<z.ZodArray<z.ZodObject<{
383
+ id: z.ZodOptional<z.ZodString>;
384
+ data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
385
+ }, z.core.$strip>>>;
386
+ }, z.core.$strip>, z.ZodObject<{
387
+ op: z.ZodLiteral<"update">;
388
+ collection: z.ZodString;
389
+ id: z.ZodString;
390
+ data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
391
+ }, z.core.$strip>], "op">>>;
392
+ }, z.core.$strip>, z.ZodObject<{
393
+ applied: z.ZodBoolean;
394
+ current: z.ZodOptional<z.ZodUnknown>;
395
+ }, z.core.$strip>, "mutation">;
305
396
  /** Update an existing record by ID. */
306
397
  readonly update: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
307
398
  namespace: z.ZodOptional<z.ZodString>;
@@ -513,7 +604,7 @@ export type ISettingsStoreProvider = InferProvider<typeof settingsStoreCapabilit
513
604
  * Methods are accessed as `client.get.query(input)`, `client.set.mutate(input)`, etc.
514
605
  */
515
606
  export type SettingsStoreClient = import('../generated/addon-api.js').AddonApi['settingsStore'];
516
- export { AggregateFieldSchema, AggregateResultSchema, BulkRecordSchema, CollectionColumnSchema, CollectionIndexSchema, MutationFilterSchema, QueryFilterSchema, SettingsRecordSchema, };
607
+ export { AggregateFieldSchema, AggregateResultSchema, BulkRecordSchema, CollectionColumnSchema, CollectionIndexSchema, MutationFilterSchema, QueryFilterSchema, SettingsRecordSchema, TransactGuardSchema, TransactOpSchema, };
517
608
  export type BulkRecord = z.infer<typeof BulkRecordSchema>;
518
609
  export type AggregateField = z.infer<typeof AggregateFieldSchema>;
519
610
  export type AggregateResult = z.infer<typeof AggregateResultSchema>;
package/dist/client.d.ts CHANGED
@@ -14,4 +14,4 @@
14
14
  * value this entry does not export — a missing name here is `undefined` at
15
15
  * runtime, not a build error.
16
16
  */
17
- export { APPLE_SA_TO_MACRO, AUDIO_MACRO_LABELS, AlarmArmModeSchema, CLIP_BROKER_PACED_RATES, COCO_TO_MACRO, CamProfileSchema, DEFAULT_TIMELAPSE_PREVIEW_TEXT, DeviceType, EVENTFUL_CAP_NAMES, EVENT_KIND_BY_CAP, EVENT_TAXONOMY, MACRO_LABELS, NC_ALARM_DELAY_MAX_SEC, NC_ALARM_SENSORS_MAX, NC_ALARM_SYSTEM_EVENT_KINDS, NC_ALARM_TRIGGERED_MAX_SEC, NC_BATTERY_CONSUMABLE_SYSTEM_EVENT_KINDS, NC_CAMERA_SCOPE_CAP_NAME, NC_CONSUMABLE_LOW_PERCENT_DEFAULT, NC_CONSUMABLE_LOW_PERCENT_MAX, NC_GROUPING_DEFAULT_SEC, NC_GROUPING_MAX_SEC, NC_GROUPING_MIN_SEC, NC_RULE_EDITOR_SECTION_ORDER, NC_RULE_KIND_SPECS, NC_SENSOR_TRANSITION_UNSUPPORTED_REASON, NC_SYSTEM_EVENT_FAMILY_FILTERS, NC_SYSTEM_EVENT_KIND_GROUP_SPECS, NC_SYSTEM_EVENT_SUMMARY_FAMILIES, NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS, NC_TEMPLATE_VARS, NcAlarmConfigSchema, NcAlarmSensorsSchema, NcAlarmSettingsPatchSchema, NcHistoryEntrySchema, NcRuleLastRunsSchema, NodeDirectorySchema, RECORDING_EXPORT_MAX_READ_BYTES, SystemMirror, TIMELAPSE_DENSE_FLOOR_SEC, TimelapseRuleSchema, YAMNET_TO_MACRO, alarmDeviceBlocksArming, alarmDeviceSecureOnArm, alarmPatchLanded, conditionVisibleForKind, createSystemProxy, droppedConditionsForKind, isHeldBackTemplateVar, isSystemRuleKind, kindsForDiscriminator, knownValues, nodePickerItems, packagePickerItems, pickerForCondition, pickerForRuleClasses, resolveModeDelays, ruleDeviceCompatCapNames, ruleEditorSectionsForKind, ruleGroupingApplies, ruleKindOf, ruleKindSpec, ruleSeedForSection, sensorTransitionNeverFires, sensorTransitionOffered, stateLabel, systemEventDeliveryProblems, systemEventFilterAppliesToAnyKind, systemEventKindsOfFamily, systemFamilyOfKind, templateCarriesSummary, templateVarDeliveryApplies, templateVarKindApplies, templateVarSystemEventApplies, } from './index.js';
17
+ export { APPLE_SA_TO_MACRO, AUDIO_MACRO_LABELS, AlarmArmModeSchema, CLIP_BROKER_PACED_RATES, COCO_TO_MACRO, CamProfileSchema, DEFAULT_TIMELAPSE_PREVIEW_TEXT, DeviceType, EVENTFUL_CAP_NAMES, EVENT_KIND_BY_CAP, EVENT_TAXONOMY, MACRO_LABELS, NC_ALARM_DELAY_MAX_SEC, NC_ALARM_SENSORS_MAX, NC_ALARM_SYSTEM_EVENT_KINDS, NC_ALARM_TRIGGERED_MAX_SEC, NC_BATTERY_CONSUMABLE_SYSTEM_EVENT_KINDS, NC_CAMERA_SCOPE_CAP_NAME, NC_CONSUMABLE_LOW_PERCENT_DEFAULT, NC_CONSUMABLE_LOW_PERCENT_MAX, NC_GROUPING_DEFAULT_SEC, NC_GROUPING_MAX_SEC, NC_GROUPING_MIN_SEC, NC_RULE_EDITOR_SECTION_ORDER, NC_RULE_KIND_SPECS, NC_SENSOR_TRANSITION_UNSUPPORTED_REASON, NC_SYSTEM_EVENT_FAMILY_FILTERS, NC_SYSTEM_EVENT_KIND_GROUP_SPECS, NC_SYSTEM_EVENT_SUMMARY_FAMILIES, NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS, NC_TEMPLATE_VARS, NcAlarmConfigSchema, NcAlarmSensorsSchema, NcAlarmSettingsPatchSchema, NcHistoryEntrySchema, NcRuleLastRunsSchema, NodeDirectorySchema, RECORDING_EXPORT_MAX_READ_BYTES, RETRAIN_REVIEW_ADJUSTED_IOU, RETRAIN_REVIEW_MATCH_IOU, RETRAIN_REVIEW_STATUSES, RETRAIN_REVISION_CONFLICT, SystemMirror, TIMELAPSE_DENSE_FLOOR_SEC, TimelapseRuleSchema, YAMNET_TO_MACRO, alarmDeviceBlocksArming, alarmDeviceSecureOnArm, alarmPatchLanded, classifyRetrainReview, conditionVisibleForKind, createSystemProxy, droppedConditionsForKind, isHeldBackTemplateVar, isSystemRuleKind, kindsForDiscriminator, knownValues, nodePickerItems, packagePickerItems, pickerForCondition, pickerForRuleClasses, parseRetrainRevisionConflict, resolveModeDelays, retrainBoxIou, retrainRevisionConflictMessage, ruleDeviceCompatCapNames, ruleEditorSectionsForKind, ruleGroupingApplies, ruleKindOf, ruleKindSpec, ruleSeedForSection, sensorTransitionNeverFires, sensorTransitionOffered, stateLabel, summarizeReview, systemEventDeliveryProblems, systemEventFilterAppliesToAnyKind, systemEventKindsOfFamily, systemFamilyOfKind, templateCarriesSummary, templateVarDeliveryApplies, templateVarKindApplies, templateVarSystemEventApplies, } from './index.js';
package/dist/client.js CHANGED
@@ -100,6 +100,213 @@ var PeerBytesTicketSchema = zod.z.object({
100
100
  declaredBytes: zod.z.number().int().nonnegative().nullable()
101
101
  });
102
102
  //#endregion
103
+ //#region src/retrain-review.ts
104
+ /** Every status, in the order a summary lists them. */
105
+ var RETRAIN_REVIEW_STATUSES = [
106
+ "unchanged",
107
+ "adjusted",
108
+ "reclassified",
109
+ "added",
110
+ "removed",
111
+ "model-error"
112
+ ];
113
+ /**
114
+ * Two boxes overlapping at least this much are the same subject when a legacy
115
+ * row (no origin) is matched against a proposal. Deliberately loose: a legacy
116
+ * row is judged on evidence that is no longer exact.
117
+ */
118
+ var RETRAIN_REVIEW_MATCH_IOU = .5;
119
+ /**
120
+ * A kept box overlapping its origin at least this much is `unchanged`; below it
121
+ * the rectangle was moved or resized on purpose (`adjusted`). Not 1.0: the
122
+ * canvas rounds, and a box dragged by one pixel and dragged back is not an edit.
123
+ */
124
+ var RETRAIN_REVIEW_ADJUSTED_IOU = .95;
125
+ /** Two boxes this close on every edge are the same rectangle (an exact match). */
126
+ var EXACT_EDGE_EPSILON = 1e-6;
127
+ var optLabel = (label) => label !== void 0 ? { label } : {};
128
+ /** Intersection over union of two normalised rectangles. */
129
+ function retrainBoxIou(a, b) {
130
+ const inter = Math.max(0, Math.min(a.x + a.w, b.x + b.w) - Math.max(a.x, b.x)) * Math.max(0, Math.min(a.y + a.h, b.y + b.h) - Math.max(a.y, b.y));
131
+ const union = a.w * a.h + b.w * b.h - inter;
132
+ return union > 0 ? inter / union : 0;
133
+ }
134
+ function sameRect(a, b) {
135
+ return Math.abs(a.x - b.x) <= EXACT_EDGE_EPSILON && Math.abs(a.y - b.y) <= EXACT_EDGE_EPSILON && Math.abs(a.w - b.w) <= EXACT_EDGE_EPSILON && Math.abs(a.h - b.h) <= EXACT_EDGE_EPSILON;
136
+ }
137
+ function labelField(value) {
138
+ return value?.trim() ?? "";
139
+ }
140
+ /** Kept box versus its baseline: class/label first, then geometry. */
141
+ function compareKept(saved, baseline, adjustedIou) {
142
+ const iou = retrainBoxIou(saved.bbox, baseline.bbox);
143
+ if (saved.macroClass !== baseline.macroClass || labelField(saved.label) !== labelField(baseline.label)) return {
144
+ status: "reclassified",
145
+ iou
146
+ };
147
+ return {
148
+ status: iou < adjustedIou ? "adjusted" : "unchanged",
149
+ iou
150
+ };
151
+ }
152
+ /**
153
+ * Pair legacy rows with proposals: exact rectangles first, then by descending
154
+ * overlap, one proposal per row. Greedy on a sorted list so the result does not
155
+ * depend on the order the rows were listed in.
156
+ */
157
+ function pairLegacy(saved, legacyIndexes, origins, matchIou) {
158
+ const candidates = [];
159
+ for (const savedIndex of legacyIndexes) {
160
+ const box = saved[savedIndex];
161
+ if (box === void 0) continue;
162
+ origins.forEach((origin, originIndex) => {
163
+ const exact = sameRect(box.bbox, origin.bbox);
164
+ const iou = exact ? 1 : retrainBoxIou(box.bbox, origin.bbox);
165
+ if (exact || iou >= matchIou) candidates.push({
166
+ savedIndex,
167
+ originIndex,
168
+ iou,
169
+ exact
170
+ });
171
+ });
172
+ }
173
+ candidates.sort((a, b) => Number(b.exact) - Number(a.exact) || b.iou - a.iou);
174
+ const pairs = /* @__PURE__ */ new Map();
175
+ const takenOrigins = /* @__PURE__ */ new Set();
176
+ for (const c of candidates) {
177
+ if (pairs.has(c.savedIndex) || takenOrigins.has(c.originIndex)) continue;
178
+ pairs.set(c.savedIndex, c.originIndex);
179
+ takenOrigins.add(c.originIndex);
180
+ }
181
+ return pairs;
182
+ }
183
+ /**
184
+ * Classify what the operator did on ONE frame.
185
+ *
186
+ * @param saved the frame's saved boxes.
187
+ * @param origins the proposals known now (the pipeline's boxes, re-derived) —
188
+ * consulted ONLY for rows that carry no origin snapshot.
189
+ * @param dismissed the proposals the operator deleted, with their snapshots.
190
+ */
191
+ function classifyRetrainReview(saved, origins, dismissed, opts = {}) {
192
+ const matchIou = opts.matchIou ?? .5;
193
+ const adjustedIou = opts.adjustedIou ?? .95;
194
+ const claimedRefs = /* @__PURE__ */ new Set();
195
+ const boxes = [];
196
+ const legacyIndexes = [];
197
+ saved.forEach((box, index) => {
198
+ if (box.origin === null) legacyIndexes.push(index);
199
+ else claimedRefs.add(box.origin.ref);
200
+ });
201
+ for (const entry of dismissed) claimedRefs.add(entry.ref);
202
+ const legacyPairs = pairLegacy(saved, legacyIndexes, origins, matchIou);
203
+ for (const originIndex of legacyPairs.values()) {
204
+ const origin = origins[originIndex];
205
+ if (origin !== void 0) claimedRefs.add(origin.ref);
206
+ }
207
+ saved.forEach((box, index) => {
208
+ const exactBaseline = box.origin;
209
+ const pairedOrigin = exactBaseline === null ? origins[legacyPairs.get(index) ?? -1] : void 0;
210
+ const baseline = exactBaseline ?? pairedOrigin ?? null;
211
+ const approximate = exactBaseline === null;
212
+ if (box.kind === "model_error") {
213
+ boxes.push({
214
+ ref: box.id,
215
+ savedId: box.id,
216
+ status: "model-error",
217
+ approximate: false,
218
+ macroClass: box.macroClass,
219
+ ...optLabel(box.label),
220
+ ...baseline !== null ? {
221
+ origin: baseline,
222
+ iou: retrainBoxIou(box.bbox, baseline.bbox)
223
+ } : {}
224
+ });
225
+ return;
226
+ }
227
+ if (baseline === null || baseline.source === "operator") {
228
+ boxes.push({
229
+ ref: box.id,
230
+ savedId: box.id,
231
+ status: "added",
232
+ approximate: approximate && baseline === null,
233
+ macroClass: box.macroClass,
234
+ ...optLabel(box.label),
235
+ ...baseline !== null ? { origin: baseline } : {}
236
+ });
237
+ return;
238
+ }
239
+ const verdict = compareKept(box, baseline, adjustedIou);
240
+ boxes.push({
241
+ ref: box.id,
242
+ savedId: box.id,
243
+ status: verdict.status,
244
+ approximate,
245
+ macroClass: box.macroClass,
246
+ ...optLabel(box.label),
247
+ origin: baseline,
248
+ iou: verdict.iou
249
+ });
250
+ });
251
+ for (const entry of dismissed) boxes.push({
252
+ ref: entry.ref,
253
+ status: "removed",
254
+ approximate: false,
255
+ macroClass: entry.snapshot.macroClass,
256
+ ...optLabel(entry.snapshot.label),
257
+ origin: entry.snapshot
258
+ });
259
+ if (opts.inferRemoved === true) for (const origin of origins) {
260
+ if (claimedRefs.has(origin.ref)) continue;
261
+ boxes.push({
262
+ ref: origin.ref,
263
+ status: "removed",
264
+ approximate: true,
265
+ macroClass: origin.macroClass,
266
+ ...optLabel(origin.label),
267
+ origin
268
+ });
269
+ }
270
+ return {
271
+ boxes,
272
+ approximate: boxes.some((b) => b.approximate)
273
+ };
274
+ }
275
+ /** Counts per status, plus the totals a list row shows. */
276
+ function summarizeReview(review) {
277
+ const counts = {
278
+ unchanged: 0,
279
+ adjusted: 0,
280
+ reclassified: 0,
281
+ added: 0,
282
+ removed: 0,
283
+ "model-error": 0
284
+ };
285
+ for (const box of review.boxes) counts[box.status] += 1;
286
+ return {
287
+ counts,
288
+ total: review.boxes.length,
289
+ changed: review.boxes.length - counts.unchanged,
290
+ approximate: review.approximate
291
+ };
292
+ }
293
+ /** The prefix of the error a stale `expectedRevision` save is refused with. */
294
+ var RETRAIN_REVISION_CONFLICT = "retrain-revision-conflict";
295
+ /** The message a refused save carries — `parseRetrainRevisionConflict` reads it back. */
296
+ function retrainRevisionConflictMessage(frameId, conflict) {
297
+ return `${RETRAIN_REVISION_CONFLICT}: frame ${frameId} moved on — it is at revision ${String(conflict.currentRevision)}, the save expected ${String(conflict.expectedRevision)} (current=${String(conflict.currentRevision)} expected=${String(conflict.expectedRevision)})`;
298
+ }
299
+ /** The conflict an error message names, or `null` when it is some other error. */
300
+ function parseRetrainRevisionConflict(message) {
301
+ if (!message.includes("retrain-revision-conflict")) return null;
302
+ const match = /current=(\d+) expected=(\d+)/.exec(message);
303
+ if (match?.[1] === void 0 || match[2] === void 0) return null;
304
+ return {
305
+ currentRevision: Number(match[1]),
306
+ expectedRevision: Number(match[2])
307
+ };
308
+ }
309
+ //#endregion
103
310
  //#region src/capabilities/schemas/streaming-shared.ts
104
311
  /** Shared Zod schemas used across streaming capabilities. */
105
312
  var CamProfileSchema = zod.z.enum([
@@ -5770,6 +5977,7 @@ function createDeviceProxy(api, binding, opts) {
5770
5977
  proposeRetrainAnnotations: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "proposeRetrainAnnotations", "mutation", input),
5771
5978
  listRetrainAnnotations: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRetrainAnnotations", "query", input),
5772
5979
  saveRetrainAnnotations: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "saveRetrainAnnotations", "mutation", input),
5980
+ backfillRetrainOrigins: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "backfillRetrainOrigins", "mutation", input),
5773
5981
  completeRetrainTrack: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "completeRetrainTrack", "mutation", input),
5774
5982
  restageRetrainTrack: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "restageRetrainTrack", "mutation", input),
5775
5983
  getRetrainExportUrl: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getRetrainExportUrl", "query", input),
@@ -7577,6 +7785,7 @@ function createSystemProxy(api) {
7577
7785
  upsert: (input) => dispatch("settingsStore", "upsert", "mutation", input),
7578
7786
  insert: (input) => dispatch("settingsStore", "insert", "mutation", input),
7579
7787
  insertMany: (input) => dispatch("settingsStore", "insertMany", "mutation", input),
7788
+ transact: (input) => dispatch("settingsStore", "transact", "mutation", input),
7580
7789
  update: (input) => dispatch("settingsStore", "update", "mutation", input),
7581
7790
  delete: (input) => dispatch("settingsStore", "delete", "mutation", input),
7582
7791
  deleteWhere: (input) => dispatch("settingsStore", "deleteWhere", "mutation", input),
@@ -10642,6 +10851,10 @@ exports.NcHistoryEntrySchema = NcHistoryEntrySchema;
10642
10851
  exports.NcRuleLastRunsSchema = NcRuleLastRunsSchema;
10643
10852
  exports.NodeDirectorySchema = NodeDirectorySchema;
10644
10853
  exports.RECORDING_EXPORT_MAX_READ_BYTES = RECORDING_EXPORT_MAX_READ_BYTES;
10854
+ exports.RETRAIN_REVIEW_ADJUSTED_IOU = RETRAIN_REVIEW_ADJUSTED_IOU;
10855
+ exports.RETRAIN_REVIEW_MATCH_IOU = RETRAIN_REVIEW_MATCH_IOU;
10856
+ exports.RETRAIN_REVIEW_STATUSES = RETRAIN_REVIEW_STATUSES;
10857
+ exports.RETRAIN_REVISION_CONFLICT = RETRAIN_REVISION_CONFLICT;
10645
10858
  exports.SystemMirror = SystemMirror;
10646
10859
  exports.TIMELAPSE_DENSE_FLOOR_SEC = TIMELAPSE_DENSE_FLOOR_SEC;
10647
10860
  exports.TimelapseRuleSchema = TimelapseRuleSchema;
@@ -10649,6 +10862,7 @@ exports.YAMNET_TO_MACRO = YAMNET_TO_MACRO;
10649
10862
  exports.alarmDeviceBlocksArming = alarmDeviceBlocksArming;
10650
10863
  exports.alarmDeviceSecureOnArm = alarmDeviceSecureOnArm;
10651
10864
  exports.alarmPatchLanded = alarmPatchLanded;
10865
+ exports.classifyRetrainReview = classifyRetrainReview;
10652
10866
  exports.conditionVisibleForKind = conditionVisibleForKind;
10653
10867
  exports.createSystemProxy = createSystemProxy;
10654
10868
  exports.droppedConditionsForKind = droppedConditionsForKind;
@@ -10658,9 +10872,12 @@ exports.kindsForDiscriminator = kindsForDiscriminator;
10658
10872
  exports.knownValues = knownValues;
10659
10873
  exports.nodePickerItems = nodePickerItems;
10660
10874
  exports.packagePickerItems = packagePickerItems;
10875
+ exports.parseRetrainRevisionConflict = parseRetrainRevisionConflict;
10661
10876
  exports.pickerForCondition = pickerForCondition;
10662
10877
  exports.pickerForRuleClasses = pickerForRuleClasses;
10663
10878
  exports.resolveModeDelays = resolveModeDelays;
10879
+ exports.retrainBoxIou = retrainBoxIou;
10880
+ exports.retrainRevisionConflictMessage = retrainRevisionConflictMessage;
10664
10881
  exports.ruleDeviceCompatCapNames = ruleDeviceCompatCapNames;
10665
10882
  exports.ruleEditorSectionsForKind = ruleEditorSectionsForKind;
10666
10883
  exports.ruleGroupingApplies = ruleGroupingApplies;
@@ -10670,6 +10887,7 @@ exports.ruleSeedForSection = ruleSeedForSection;
10670
10887
  exports.sensorTransitionNeverFires = sensorTransitionNeverFires;
10671
10888
  exports.sensorTransitionOffered = sensorTransitionOffered;
10672
10889
  exports.stateLabel = stateLabel;
10890
+ exports.summarizeReview = summarizeReview;
10673
10891
  exports.systemEventDeliveryProblems = systemEventDeliveryProblems;
10674
10892
  exports.systemEventFilterAppliesToAnyKind = systemEventFilterAppliesToAnyKind;
10675
10893
  exports.systemEventKindsOfFamily = systemEventKindsOfFamily;
package/dist/client.mjs CHANGED
@@ -99,6 +99,213 @@ var PeerBytesTicketSchema = z.object({
99
99
  declaredBytes: z.number().int().nonnegative().nullable()
100
100
  });
101
101
  //#endregion
102
+ //#region src/retrain-review.ts
103
+ /** Every status, in the order a summary lists them. */
104
+ var RETRAIN_REVIEW_STATUSES = [
105
+ "unchanged",
106
+ "adjusted",
107
+ "reclassified",
108
+ "added",
109
+ "removed",
110
+ "model-error"
111
+ ];
112
+ /**
113
+ * Two boxes overlapping at least this much are the same subject when a legacy
114
+ * row (no origin) is matched against a proposal. Deliberately loose: a legacy
115
+ * row is judged on evidence that is no longer exact.
116
+ */
117
+ var RETRAIN_REVIEW_MATCH_IOU = .5;
118
+ /**
119
+ * A kept box overlapping its origin at least this much is `unchanged`; below it
120
+ * the rectangle was moved or resized on purpose (`adjusted`). Not 1.0: the
121
+ * canvas rounds, and a box dragged by one pixel and dragged back is not an edit.
122
+ */
123
+ var RETRAIN_REVIEW_ADJUSTED_IOU = .95;
124
+ /** Two boxes this close on every edge are the same rectangle (an exact match). */
125
+ var EXACT_EDGE_EPSILON = 1e-6;
126
+ var optLabel = (label) => label !== void 0 ? { label } : {};
127
+ /** Intersection over union of two normalised rectangles. */
128
+ function retrainBoxIou(a, b) {
129
+ const inter = Math.max(0, Math.min(a.x + a.w, b.x + b.w) - Math.max(a.x, b.x)) * Math.max(0, Math.min(a.y + a.h, b.y + b.h) - Math.max(a.y, b.y));
130
+ const union = a.w * a.h + b.w * b.h - inter;
131
+ return union > 0 ? inter / union : 0;
132
+ }
133
+ function sameRect(a, b) {
134
+ return Math.abs(a.x - b.x) <= EXACT_EDGE_EPSILON && Math.abs(a.y - b.y) <= EXACT_EDGE_EPSILON && Math.abs(a.w - b.w) <= EXACT_EDGE_EPSILON && Math.abs(a.h - b.h) <= EXACT_EDGE_EPSILON;
135
+ }
136
+ function labelField(value) {
137
+ return value?.trim() ?? "";
138
+ }
139
+ /** Kept box versus its baseline: class/label first, then geometry. */
140
+ function compareKept(saved, baseline, adjustedIou) {
141
+ const iou = retrainBoxIou(saved.bbox, baseline.bbox);
142
+ if (saved.macroClass !== baseline.macroClass || labelField(saved.label) !== labelField(baseline.label)) return {
143
+ status: "reclassified",
144
+ iou
145
+ };
146
+ return {
147
+ status: iou < adjustedIou ? "adjusted" : "unchanged",
148
+ iou
149
+ };
150
+ }
151
+ /**
152
+ * Pair legacy rows with proposals: exact rectangles first, then by descending
153
+ * overlap, one proposal per row. Greedy on a sorted list so the result does not
154
+ * depend on the order the rows were listed in.
155
+ */
156
+ function pairLegacy(saved, legacyIndexes, origins, matchIou) {
157
+ const candidates = [];
158
+ for (const savedIndex of legacyIndexes) {
159
+ const box = saved[savedIndex];
160
+ if (box === void 0) continue;
161
+ origins.forEach((origin, originIndex) => {
162
+ const exact = sameRect(box.bbox, origin.bbox);
163
+ const iou = exact ? 1 : retrainBoxIou(box.bbox, origin.bbox);
164
+ if (exact || iou >= matchIou) candidates.push({
165
+ savedIndex,
166
+ originIndex,
167
+ iou,
168
+ exact
169
+ });
170
+ });
171
+ }
172
+ candidates.sort((a, b) => Number(b.exact) - Number(a.exact) || b.iou - a.iou);
173
+ const pairs = /* @__PURE__ */ new Map();
174
+ const takenOrigins = /* @__PURE__ */ new Set();
175
+ for (const c of candidates) {
176
+ if (pairs.has(c.savedIndex) || takenOrigins.has(c.originIndex)) continue;
177
+ pairs.set(c.savedIndex, c.originIndex);
178
+ takenOrigins.add(c.originIndex);
179
+ }
180
+ return pairs;
181
+ }
182
+ /**
183
+ * Classify what the operator did on ONE frame.
184
+ *
185
+ * @param saved the frame's saved boxes.
186
+ * @param origins the proposals known now (the pipeline's boxes, re-derived) —
187
+ * consulted ONLY for rows that carry no origin snapshot.
188
+ * @param dismissed the proposals the operator deleted, with their snapshots.
189
+ */
190
+ function classifyRetrainReview(saved, origins, dismissed, opts = {}) {
191
+ const matchIou = opts.matchIou ?? .5;
192
+ const adjustedIou = opts.adjustedIou ?? .95;
193
+ const claimedRefs = /* @__PURE__ */ new Set();
194
+ const boxes = [];
195
+ const legacyIndexes = [];
196
+ saved.forEach((box, index) => {
197
+ if (box.origin === null) legacyIndexes.push(index);
198
+ else claimedRefs.add(box.origin.ref);
199
+ });
200
+ for (const entry of dismissed) claimedRefs.add(entry.ref);
201
+ const legacyPairs = pairLegacy(saved, legacyIndexes, origins, matchIou);
202
+ for (const originIndex of legacyPairs.values()) {
203
+ const origin = origins[originIndex];
204
+ if (origin !== void 0) claimedRefs.add(origin.ref);
205
+ }
206
+ saved.forEach((box, index) => {
207
+ const exactBaseline = box.origin;
208
+ const pairedOrigin = exactBaseline === null ? origins[legacyPairs.get(index) ?? -1] : void 0;
209
+ const baseline = exactBaseline ?? pairedOrigin ?? null;
210
+ const approximate = exactBaseline === null;
211
+ if (box.kind === "model_error") {
212
+ boxes.push({
213
+ ref: box.id,
214
+ savedId: box.id,
215
+ status: "model-error",
216
+ approximate: false,
217
+ macroClass: box.macroClass,
218
+ ...optLabel(box.label),
219
+ ...baseline !== null ? {
220
+ origin: baseline,
221
+ iou: retrainBoxIou(box.bbox, baseline.bbox)
222
+ } : {}
223
+ });
224
+ return;
225
+ }
226
+ if (baseline === null || baseline.source === "operator") {
227
+ boxes.push({
228
+ ref: box.id,
229
+ savedId: box.id,
230
+ status: "added",
231
+ approximate: approximate && baseline === null,
232
+ macroClass: box.macroClass,
233
+ ...optLabel(box.label),
234
+ ...baseline !== null ? { origin: baseline } : {}
235
+ });
236
+ return;
237
+ }
238
+ const verdict = compareKept(box, baseline, adjustedIou);
239
+ boxes.push({
240
+ ref: box.id,
241
+ savedId: box.id,
242
+ status: verdict.status,
243
+ approximate,
244
+ macroClass: box.macroClass,
245
+ ...optLabel(box.label),
246
+ origin: baseline,
247
+ iou: verdict.iou
248
+ });
249
+ });
250
+ for (const entry of dismissed) boxes.push({
251
+ ref: entry.ref,
252
+ status: "removed",
253
+ approximate: false,
254
+ macroClass: entry.snapshot.macroClass,
255
+ ...optLabel(entry.snapshot.label),
256
+ origin: entry.snapshot
257
+ });
258
+ if (opts.inferRemoved === true) for (const origin of origins) {
259
+ if (claimedRefs.has(origin.ref)) continue;
260
+ boxes.push({
261
+ ref: origin.ref,
262
+ status: "removed",
263
+ approximate: true,
264
+ macroClass: origin.macroClass,
265
+ ...optLabel(origin.label),
266
+ origin
267
+ });
268
+ }
269
+ return {
270
+ boxes,
271
+ approximate: boxes.some((b) => b.approximate)
272
+ };
273
+ }
274
+ /** Counts per status, plus the totals a list row shows. */
275
+ function summarizeReview(review) {
276
+ const counts = {
277
+ unchanged: 0,
278
+ adjusted: 0,
279
+ reclassified: 0,
280
+ added: 0,
281
+ removed: 0,
282
+ "model-error": 0
283
+ };
284
+ for (const box of review.boxes) counts[box.status] += 1;
285
+ return {
286
+ counts,
287
+ total: review.boxes.length,
288
+ changed: review.boxes.length - counts.unchanged,
289
+ approximate: review.approximate
290
+ };
291
+ }
292
+ /** The prefix of the error a stale `expectedRevision` save is refused with. */
293
+ var RETRAIN_REVISION_CONFLICT = "retrain-revision-conflict";
294
+ /** The message a refused save carries — `parseRetrainRevisionConflict` reads it back. */
295
+ function retrainRevisionConflictMessage(frameId, conflict) {
296
+ return `${RETRAIN_REVISION_CONFLICT}: frame ${frameId} moved on — it is at revision ${String(conflict.currentRevision)}, the save expected ${String(conflict.expectedRevision)} (current=${String(conflict.currentRevision)} expected=${String(conflict.expectedRevision)})`;
297
+ }
298
+ /** The conflict an error message names, or `null` when it is some other error. */
299
+ function parseRetrainRevisionConflict(message) {
300
+ if (!message.includes("retrain-revision-conflict")) return null;
301
+ const match = /current=(\d+) expected=(\d+)/.exec(message);
302
+ if (match?.[1] === void 0 || match[2] === void 0) return null;
303
+ return {
304
+ currentRevision: Number(match[1]),
305
+ expectedRevision: Number(match[2])
306
+ };
307
+ }
308
+ //#endregion
102
309
  //#region src/capabilities/schemas/streaming-shared.ts
103
310
  /** Shared Zod schemas used across streaming capabilities. */
104
311
  var CamProfileSchema = z.enum([
@@ -5769,6 +5976,7 @@ function createDeviceProxy(api, binding, opts) {
5769
5976
  proposeRetrainAnnotations: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "proposeRetrainAnnotations", "mutation", input),
5770
5977
  listRetrainAnnotations: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRetrainAnnotations", "query", input),
5771
5978
  saveRetrainAnnotations: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "saveRetrainAnnotations", "mutation", input),
5979
+ backfillRetrainOrigins: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "backfillRetrainOrigins", "mutation", input),
5772
5980
  completeRetrainTrack: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "completeRetrainTrack", "mutation", input),
5773
5981
  restageRetrainTrack: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "restageRetrainTrack", "mutation", input),
5774
5982
  getRetrainExportUrl: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getRetrainExportUrl", "query", input),
@@ -7576,6 +7784,7 @@ function createSystemProxy(api) {
7576
7784
  upsert: (input) => dispatch("settingsStore", "upsert", "mutation", input),
7577
7785
  insert: (input) => dispatch("settingsStore", "insert", "mutation", input),
7578
7786
  insertMany: (input) => dispatch("settingsStore", "insertMany", "mutation", input),
7787
+ transact: (input) => dispatch("settingsStore", "transact", "mutation", input),
7579
7788
  update: (input) => dispatch("settingsStore", "update", "mutation", input),
7580
7789
  delete: (input) => dispatch("settingsStore", "delete", "mutation", input),
7581
7790
  deleteWhere: (input) => dispatch("settingsStore", "deleteWhere", "mutation", input),
@@ -10603,4 +10812,4 @@ var TimelapseRuleSchema = TimelapseRuleInputSchema.extend({
10603
10812
  updatedAt: z.number()
10604
10813
  });
10605
10814
  //#endregion
10606
- export { APPLE_SA_TO_MACRO, AUDIO_MACRO_LABELS, AlarmArmModeSchema, CLIP_BROKER_PACED_RATES, COCO_TO_MACRO, CamProfileSchema, DEFAULT_TIMELAPSE_PREVIEW_TEXT, DeviceType, EVENTFUL_CAP_NAMES, EVENT_KIND_BY_CAP, EVENT_TAXONOMY, MACRO_LABELS, NC_ALARM_DELAY_MAX_SEC, NC_ALARM_SENSORS_MAX, NC_ALARM_SYSTEM_EVENT_KINDS, NC_ALARM_TRIGGERED_MAX_SEC, NC_BATTERY_CONSUMABLE_SYSTEM_EVENT_KINDS, NC_CAMERA_SCOPE_CAP_NAME, NC_CONSUMABLE_LOW_PERCENT_DEFAULT, NC_CONSUMABLE_LOW_PERCENT_MAX, NC_GROUPING_DEFAULT_SEC, NC_GROUPING_MAX_SEC, NC_GROUPING_MIN_SEC, NC_RULE_EDITOR_SECTION_ORDER, NC_RULE_KIND_SPECS, NC_SENSOR_TRANSITION_UNSUPPORTED_REASON, NC_SYSTEM_EVENT_FAMILY_FILTERS, NC_SYSTEM_EVENT_KIND_GROUP_SPECS, NC_SYSTEM_EVENT_SUMMARY_FAMILIES, NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS, NC_TEMPLATE_VARS, NcAlarmConfigSchema, NcAlarmSensorsSchema, NcAlarmSettingsPatchSchema, NcHistoryEntrySchema, NcRuleLastRunsSchema, NodeDirectorySchema, RECORDING_EXPORT_MAX_READ_BYTES, SystemMirror, TIMELAPSE_DENSE_FLOOR_SEC, TimelapseRuleSchema, YAMNET_TO_MACRO, alarmDeviceBlocksArming, alarmDeviceSecureOnArm, alarmPatchLanded, conditionVisibleForKind, createSystemProxy, droppedConditionsForKind, isHeldBackTemplateVar, isSystemRuleKind, kindsForDiscriminator, knownValues, nodePickerItems, packagePickerItems, pickerForCondition, pickerForRuleClasses, resolveModeDelays, ruleDeviceCompatCapNames, ruleEditorSectionsForKind, ruleGroupingApplies, ruleKindOf, ruleKindSpec, ruleSeedForSection, sensorTransitionNeverFires, sensorTransitionOffered, stateLabel, systemEventDeliveryProblems, systemEventFilterAppliesToAnyKind, systemEventKindsOfFamily, systemFamilyOfKind, templateCarriesSummary, templateVarDeliveryApplies, templateVarKindApplies, templateVarSystemEventApplies };
10815
+ export { APPLE_SA_TO_MACRO, AUDIO_MACRO_LABELS, AlarmArmModeSchema, CLIP_BROKER_PACED_RATES, COCO_TO_MACRO, CamProfileSchema, DEFAULT_TIMELAPSE_PREVIEW_TEXT, DeviceType, EVENTFUL_CAP_NAMES, EVENT_KIND_BY_CAP, EVENT_TAXONOMY, MACRO_LABELS, NC_ALARM_DELAY_MAX_SEC, NC_ALARM_SENSORS_MAX, NC_ALARM_SYSTEM_EVENT_KINDS, NC_ALARM_TRIGGERED_MAX_SEC, NC_BATTERY_CONSUMABLE_SYSTEM_EVENT_KINDS, NC_CAMERA_SCOPE_CAP_NAME, NC_CONSUMABLE_LOW_PERCENT_DEFAULT, NC_CONSUMABLE_LOW_PERCENT_MAX, NC_GROUPING_DEFAULT_SEC, NC_GROUPING_MAX_SEC, NC_GROUPING_MIN_SEC, NC_RULE_EDITOR_SECTION_ORDER, NC_RULE_KIND_SPECS, NC_SENSOR_TRANSITION_UNSUPPORTED_REASON, NC_SYSTEM_EVENT_FAMILY_FILTERS, NC_SYSTEM_EVENT_KIND_GROUP_SPECS, NC_SYSTEM_EVENT_SUMMARY_FAMILIES, NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS, NC_TEMPLATE_VARS, NcAlarmConfigSchema, NcAlarmSensorsSchema, NcAlarmSettingsPatchSchema, NcHistoryEntrySchema, NcRuleLastRunsSchema, NodeDirectorySchema, RECORDING_EXPORT_MAX_READ_BYTES, RETRAIN_REVIEW_ADJUSTED_IOU, RETRAIN_REVIEW_MATCH_IOU, RETRAIN_REVIEW_STATUSES, RETRAIN_REVISION_CONFLICT, SystemMirror, TIMELAPSE_DENSE_FLOOR_SEC, TimelapseRuleSchema, YAMNET_TO_MACRO, alarmDeviceBlocksArming, alarmDeviceSecureOnArm, alarmPatchLanded, classifyRetrainReview, conditionVisibleForKind, createSystemProxy, droppedConditionsForKind, isHeldBackTemplateVar, isSystemRuleKind, kindsForDiscriminator, knownValues, nodePickerItems, packagePickerItems, parseRetrainRevisionConflict, pickerForCondition, pickerForRuleClasses, resolveModeDelays, retrainBoxIou, retrainRevisionConflictMessage, ruleDeviceCompatCapNames, ruleEditorSectionsForKind, ruleGroupingApplies, ruleKindOf, ruleKindSpec, ruleSeedForSection, sensorTransitionNeverFires, sensorTransitionOffered, stateLabel, summarizeReview, systemEventDeliveryProblems, systemEventFilterAppliesToAnyKind, systemEventKindsOfFamily, systemFamilyOfKind, templateCarriesSummary, templateVarDeliveryApplies, templateVarKindApplies, templateVarSystemEventApplies };
@@ -1885,6 +1885,13 @@ export type AppRouter = TrpcCoreRouter<{
1885
1885
  output: z.infer<typeof dataStoreProviderCapability.methods.insertMany.output>;
1886
1886
  meta: object;
1887
1887
  }>;
1888
+ transact: TRPCMutationProcedure<{
1889
+ input: {
1890
+ [x: string]: unknown;
1891
+ } & z.input<typeof dataStoreProviderCapability.methods.transact.input>;
1892
+ output: z.infer<typeof dataStoreProviderCapability.methods.transact.output>;
1893
+ meta: object;
1894
+ }>;
1888
1895
  update: TRPCMutationProcedure<{
1889
1896
  input: {
1890
1897
  [x: string]: unknown;
@@ -6136,6 +6143,13 @@ export type AppRouter = TrpcCoreRouter<{
6136
6143
  output: z.infer<typeof pipelineAnalyticsCapability.methods.saveRetrainAnnotations.output>;
6137
6144
  meta: object;
6138
6145
  }>;
6146
+ backfillRetrainOrigins: TRPCMutationProcedure<{
6147
+ input: {
6148
+ [x: string]: unknown;
6149
+ } & z.input<typeof pipelineAnalyticsCapability.methods.backfillRetrainOrigins.input>;
6150
+ output: z.infer<typeof pipelineAnalyticsCapability.methods.backfillRetrainOrigins.output>;
6151
+ meta: object;
6152
+ }>;
6139
6153
  completeRetrainTrack: TRPCMutationProcedure<{
6140
6154
  input: {
6141
6155
  [x: string]: unknown;
@@ -8153,6 +8167,13 @@ export type AppRouter = TrpcCoreRouter<{
8153
8167
  output: z.infer<typeof settingsStoreCapability.methods.insertMany.output>;
8154
8168
  meta: object;
8155
8169
  }>;
8170
+ transact: TRPCMutationProcedure<{
8171
+ input: {
8172
+ [x: string]: unknown;
8173
+ } & z.input<typeof settingsStoreCapability.methods.transact.input>;
8174
+ output: z.infer<typeof settingsStoreCapability.methods.transact.output>;
8175
+ meta: object;
8176
+ }>;
8156
8177
  update: TRPCMutationProcedure<{
8157
8178
  input: {
8158
8179
  [x: string]: unknown;