@camstack/types 1.2.170 → 1.2.172

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/addon.js CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_event_category = require("./event-category-BVo6ta6_.js");
3
- const require_sleep = require("./sleep-IjLtwkO5.js");
3
+ const require_sleep = require("./sleep-Bo9cUOXp.js");
4
4
  const require_err_msg = require("./err-msg-COpsHMw2.js");
5
5
  //#region src/generated/cap-input-defaults.ts
6
6
  /**
@@ -149,6 +149,8 @@ var CAP_INPUT_DEFAULTS = Object.freeze({
149
149
  "pipelineEnabled": true,
150
150
  "zones": [],
151
151
  "onboardMotionDrivesAnalyzer": true,
152
+ "preRollInferenceEnabled": true,
153
+ "preRollInferenceFrames": 12,
152
154
  "occupancyRecheckEnabled": true,
153
155
  "occupancyRecheckSec": 300,
154
156
  "occupancyRecheckFrames": 4,
package/dist/addon.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as EventCategory } from "./event-category-CnLqLOKs.mjs";
2
- import { D as adminUiCapability, E as DeviceType, G as scopeKey, H as ReadinessTimeoutError, M as expandCapMethods, R as nodePin, S as DEVICE_CHILDREN_BATCH_MAX, V as ReadinessRegistry, _t as DATAPLANE_SECRET_HEADER, a as asJsonObject, b as deviceOpsCapability, bt as BaseAddon, d as BOOT_RECOVERY_BACKOFF_MS, f as DEVICE_SCOPED_CAPS, h as createEventBusSliceSource, m as createDeviceProxy, p as isDeviceScopedCap, s as asString, t as sleep, u as parseJsonUnknown, wt as emitReadiness, x as viewerUiCapability, xt as normalizeAddonInitResult, yt as DisposerChain, z as readNodePin } from "./sleep-uGNYCvYp.mjs";
2
+ import { D as adminUiCapability, E as DeviceType, G as scopeKey, H as ReadinessTimeoutError, M as expandCapMethods, R as nodePin, S as DEVICE_CHILDREN_BATCH_MAX, V as ReadinessRegistry, _t as DATAPLANE_SECRET_HEADER, a as asJsonObject, b as deviceOpsCapability, bt as BaseAddon, d as BOOT_RECOVERY_BACKOFF_MS, f as DEVICE_SCOPED_CAPS, h as createEventBusSliceSource, m as createDeviceProxy, p as isDeviceScopedCap, s as asString, t as sleep, u as parseJsonUnknown, wt as emitReadiness, x as viewerUiCapability, xt as normalizeAddonInitResult, yt as DisposerChain, z as readNodePin } from "./sleep-DMghvp8F.mjs";
3
3
  import { t as errMsg } from "./err-msg-IQTHeDzc.mjs";
4
4
  //#region src/generated/cap-input-defaults.ts
5
5
  /**
@@ -148,6 +148,8 @@ var CAP_INPUT_DEFAULTS = Object.freeze({
148
148
  "pipelineEnabled": true,
149
149
  "zones": [],
150
150
  "onboardMotionDrivesAnalyzer": true,
151
+ "preRollInferenceEnabled": true,
152
+ "preRollInferenceFrames": 12,
151
153
  "occupancyRecheckEnabled": true,
152
154
  "occupancyRecheckSec": 300,
153
155
  "occupancyRecheckFrames": 4,
@@ -2818,6 +2818,58 @@ export declare const pipelineAnalyticsCapability: {
2818
2818
  trackClass: z.ZodNullable<z.ZodString>;
2819
2819
  trackLabel: z.ZodNullable<z.ZodString>;
2820
2820
  }, z.core.$strip>>>, "query">;
2821
+ /**
2822
+ * Birth decisions — one row per resolved confirmation-gate verdict (D409).
2823
+ *
2824
+ * The READ half of a measurement, and only that: it gates nothing and no
2825
+ * runtime path consults it. It exists because the two questions the
2826
+ * operator's "traccia partita in ritardo" marks raised are both multi-day
2827
+ * and `logs.query` holds under an hour of fleet traffic —
2828
+ * • how often is a birth DECIDED on a frame the subject was not observed
2829
+ * in (`decidedOnCoastedFrame`), and did D379's carried pixels make it a
2830
+ * real observation anyway (`decidedByBirthEvidence`);
2831
+ * • how long after the camera's motion onset does a track's `firstSeen`
2832
+ * land (`birthLatencyMs` — read its error bars in
2833
+ * `BirthDecisionRecordSchema` before quoting it).
2834
+ *
2835
+ * Newest-first, capped by `limit` (default
2836
+ * {@link BIRTH_DECISION_DEFAULT_LIMIT}), optionally scoped to one camera,
2837
+ * one verdict, or a `since`. The table is bounded by row count, not age —
2838
+ * see {@link MAX_BIRTH_DECISION_RECORDS}.
2839
+ */
2840
+ readonly listBirthDecisions: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
2841
+ deviceId: z.ZodOptional<z.ZodNumber>;
2842
+ since: z.ZodOptional<z.ZodNumber>;
2843
+ verdict: z.ZodOptional<z.ZodEnum<{
2844
+ confirmed: "confirmed";
2845
+ suppressed: "suppressed";
2846
+ "exhausted-fallback": "exhausted-fallback";
2847
+ }>>;
2848
+ limit: z.ZodOptional<z.ZodNumber>;
2849
+ }, z.core.$strip>, z.ZodReadonly<z.ZodArray<z.ZodObject<{
2850
+ id: z.ZodString;
2851
+ at: z.ZodNumber;
2852
+ deviceId: z.ZodNumber;
2853
+ sourceTrackId: z.ZodString;
2854
+ className: z.ZodString;
2855
+ verdict: z.ZodEnum<{
2856
+ confirmed: "confirmed";
2857
+ suppressed: "suppressed";
2858
+ "exhausted-fallback": "exhausted-fallback";
2859
+ }>;
2860
+ reason: z.ZodNullable<z.ZodString>;
2861
+ attempts: z.ZodNumber;
2862
+ deferredForMs: z.ZodNumber;
2863
+ decidedOnCoastedFrame: z.ZodBoolean;
2864
+ birthEvidenceAvailable: z.ZodBoolean;
2865
+ decidedByBirthEvidence: z.ZodBoolean;
2866
+ bestScore: z.ZodNullable<z.ZodNumber>;
2867
+ appliedMinConfidence: z.ZodNullable<z.ZodNumber>;
2868
+ firstSeen: z.ZodNullable<z.ZodNumber>;
2869
+ motionOnsetAt: z.ZodNullable<z.ZodNumber>;
2870
+ birthLatencyMs: z.ZodNullable<z.ZodNumber>;
2871
+ birthIndexInBurst: z.ZodNullable<z.ZodNumber>;
2872
+ }, z.core.$strip>>>, "query">;
2821
2873
  /**
2822
2874
  * Durable event-store footprint for the management UI: event rows
2823
2875
  * (motion + object + audio) counted per camera + total, plus the
@@ -256,6 +256,8 @@ declare const RunnerCameraConfigSchema: z.ZodObject<{
256
256
  color: z.ZodDefault<z.ZodString>;
257
257
  }, z.core.$strip>>>>;
258
258
  onboardMotionDrivesAnalyzer: z.ZodDefault<z.ZodBoolean>;
259
+ preRollInferenceEnabled: z.ZodDefault<z.ZodBoolean>;
260
+ preRollInferenceFrames: z.ZodDefault<z.ZodNumber>;
259
261
  occupancyRecheckEnabled: z.ZodDefault<z.ZodBoolean>;
260
262
  occupancyRecheckSec: z.ZodDefault<z.ZodNumber>;
261
263
  occupancyRecheckFrames: z.ZodDefault<z.ZodNumber>;
@@ -516,6 +518,8 @@ export declare const pipelineRunnerCapability: {
516
518
  color: z.ZodDefault<z.ZodString>;
517
519
  }, z.core.$strip>>>>;
518
520
  onboardMotionDrivesAnalyzer: z.ZodDefault<z.ZodBoolean>;
521
+ preRollInferenceEnabled: z.ZodDefault<z.ZodBoolean>;
522
+ preRollInferenceFrames: z.ZodDefault<z.ZodNumber>;
519
523
  occupancyRecheckEnabled: z.ZodDefault<z.ZodBoolean>;
520
524
  occupancyRecheckSec: z.ZodDefault<z.ZodNumber>;
521
525
  occupancyRecheckFrames: z.ZodDefault<z.ZodNumber>;
@@ -5208,6 +5208,13 @@ export type AppRouter = TrpcCoreRouter<{
5208
5208
  output: z.infer<typeof pipelineAnalyticsCapability.methods.listArchivedDebugNotes.output>;
5209
5209
  meta: object;
5210
5210
  }>;
5211
+ listBirthDecisions: TRPCQueryProcedure<{
5212
+ input: {
5213
+ [x: string]: unknown;
5214
+ } & z.input<typeof pipelineAnalyticsCapability.methods.listBirthDecisions.input>;
5215
+ output: z.infer<typeof pipelineAnalyticsCapability.methods.listBirthDecisions.output>;
5216
+ meta: object;
5217
+ }>;
5211
5218
  getEventStoreFootprint: TRPCQueryProcedure<{
5212
5219
  input: {
5213
5220
  [x: string]: unknown;
@@ -6,7 +6,7 @@
6
6
  * scope+access check inside `protectedProcedure` (see
7
7
  * `server/backend/src/api/trpc/trpc.middleware.ts`).
8
8
  *
9
- * Coverage: 1023 method paths across 129 capabilities.
9
+ * Coverage: 1024 method paths across 129 capabilities.
10
10
  */
11
11
  import type { CapabilityMethodAccess } from '../capabilities/capability-definition.js';
12
12
  export interface MethodAccessRecord {
@@ -6,7 +6,7 @@
6
6
  * system-scope cap that takes a deviceId was previously never device-filtered
7
7
  * — see the generator header).
8
8
  *
9
- * Coverage: 368 methods carry a device reference, of which
9
+ * Coverage: 369 methods carry a device reference, of which
10
10
  * 134 are on SYSTEM-scope caps.
11
11
  *
12
12
  * Top-level fields, number arrays, and one-level arrays of objects carrying
package/dist/index.d.ts CHANGED
@@ -40,6 +40,7 @@ export type { HydratedFieldEntry } from './interfaces/config-ui.js';
40
40
  export { collectHydratedFieldEntries, collectHydratedFieldValues, hydrateSchema, resolveHydratedFieldValue, WELL_KNOWN_TAB_MAP, WELL_KNOWN_TABS, } from './interfaces/config-ui.js';
41
41
  export { collectSecretConfigKeys, isSecretConfigField, REDACTED_SECRET, schemaDeclaresAnyField, } from './interfaces/config-ui-secrets.js';
42
42
  export type * from './interfaces/context.js';
43
+ export * from './interfaces/birth-decision-ledger.js';
43
44
  export * from './interfaces/debug-note-archive.js';
44
45
  export type * from './interfaces/decoder.js';
45
46
  export type * from './interfaces/detection-addon.js';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_event_category = require("./event-category-BVo6ta6_.js");
3
- const require_sleep = require("./sleep-IjLtwkO5.js");
3
+ const require_sleep = require("./sleep-Bo9cUOXp.js");
4
4
  const require_canonical_hash = require("./canonical-hash-DNV8S5ET.js");
5
5
  const require_enums = require("./enums.js");
6
6
  const require_err_msg = require("./err-msg-COpsHMw2.js");
@@ -1257,6 +1257,230 @@ function walkField(field, out) {
1257
1257
  }
1258
1258
  }
1259
1259
  //#endregion
1260
+ //#region src/interfaces/birth-decision-ledger.ts
1261
+ /**
1262
+ * Birth-decision ledger — one durable row per track-birth VERDICT (D409).
1263
+ *
1264
+ * ── Why this exists ────────────────────────────────────────────────────────
1265
+ * On 2026-09-08 the operator marked eleven tracks for review and five of them
1266
+ * said "traccia partita in ritardo" — the track appears to begin long after the
1267
+ * subject entered the scene. Two causes were proposed and NEITHER was measured:
1268
+ *
1269
+ * - the confirmation gate's deferral (`maxDeferralMs`, 2 s). This is now
1270
+ * DISPROVEN as a cause of a late TIMELINE: a track's `firstSeen` and its
1271
+ * first position are the CANDIDATE's first frame, not the confirmation's.
1272
+ * Verified on `d035f251` (device 3829): first position == `firstSeen`, with
1273
+ * confirmation 2 163 ms later.
1274
+ * - the detector simply not firing until the subject is well into the scene.
1275
+ * Unmeasured, and the reason this table exists.
1276
+ *
1277
+ * A second, real defect is also unquantified. The deferred-birth re-offer in
1278
+ * `index.ts` takes the track from `result.tracked` with NO `matchedThisFrame`
1279
+ * check, so a birth can be CONFIRMED on a frame the subject was never observed
1280
+ * in. D379's carried birth evidence means some of those confirmations rest on a
1281
+ * real observation of the birth instant anyway — and how often is exactly what
1282
+ * nobody knows. {@link BirthDecisionRecord.decidedOnCoastedFrame} and
1283
+ * {@link BirthDecisionRecord.decidedByBirthEvidence} are the two columns that
1284
+ * answer it together.
1285
+ *
1286
+ * ── Why a TABLE and not a log line ─────────────────────────────────────────
1287
+ * `logs.query` is an in-memory ring. Measured on the live hub on 2026-09-08 it
1288
+ * held 40 000 entries covering 38 minutes — the whole ring is under an hour of
1289
+ * fleet traffic. Every question this data is for ("how often, on camera 617,
1290
+ * over the week the operator complained about") outlives that ring by two
1291
+ * orders of magnitude, and a previous investigation in this repo was blocked
1292
+ * for precisely this reason. The gate ALREADY writes a log line per decision
1293
+ * (`confirmation gate: birth confirmed/suppressed/undecided`); adding a
1294
+ * fourteenth field to it would answer nothing a day later.
1295
+ *
1296
+ * This is a MEASUREMENT table. It changes no behaviour, gates nothing, and
1297
+ * nothing reads it on the frame path.
1298
+ */
1299
+ /**
1300
+ * How many birth decisions the cluster keeps, across every camera.
1301
+ *
1302
+ * Sized off a MEASURED rate, not a guess. Fleet-wide on the live hub,
1303
+ * 2026-09-08 20:16 local, over the 38 minutes the log ring covered: 17 `track
1304
+ * started` + 14 `birth suppressed — track record retracted` = 31 decided
1305
+ * births, i.e. ~49/hour, ~1 200/day. Call a busy daytime hour five times that
1306
+ * and the fleet writes ~6 000 rows/day.
1307
+ *
1308
+ * 30 000 rows is therefore ~25 days at the measured rate and ~5 days at five
1309
+ * times it — comfortably past "a few days of traffic", which is the bar the
1310
+ * operator's week-long complaint sets. At ~200 bytes a row the ceiling is
1311
+ * ~6 MB, against a `tracks` table measured at 4.6 MB for a single 501-row page.
1312
+ *
1313
+ * A COUNT and not an age, for the same reason as the debug-note archive: the
1314
+ * denominator of a miss rate is only meaningful over whatever window the table
1315
+ * actually holds, and a quiet fleet should keep more of it, not less. Trimmed
1316
+ * oldest-first on append.
1317
+ */
1318
+ var MAX_BIRTH_DECISION_RECORDS = 3e4;
1319
+ /** Default page size for `listBirthDecisions` when the caller omits one. */
1320
+ var BIRTH_DECISION_DEFAULT_LIMIT = 500;
1321
+ /**
1322
+ * How stale a motion onset may be and still be offered as the birth-latency
1323
+ * proxy. Beyond this the row records `null`, never a large number.
1324
+ *
1325
+ * 60 s is one order of magnitude above the latency being measured (the
1326
+ * complaint is "seconds late") and one below the duration of a busy scene's
1327
+ * continuous motion burst, where the onset is minutes old and says nothing
1328
+ * about THIS subject. See {@link BirthDecisionRecord.birthLatencyMs} for the
1329
+ * full error bars.
1330
+ */
1331
+ var MAX_BIRTH_LATENCY_PROXY_MS = 6e4;
1332
+ /**
1333
+ * What the gate decided about a birth, from the CALLER's point of view.
1334
+ *
1335
+ * Deliberately not `ConfirmationVerdict`: `undecided` is not a birth decision
1336
+ * at all — it is a deferral, and the row is written when the deferral ENDS.
1337
+ * The third member is the one the gate's own type cannot express, because
1338
+ * exhaustion is a property of how long the caller waited.
1339
+ */
1340
+ var BirthDecisionVerdictSchema = zod.z.enum([
1341
+ "confirmed",
1342
+ "suppressed",
1343
+ "exhausted-fallback"
1344
+ ]);
1345
+ /** One birth decision, as it is kept. */
1346
+ var BirthDecisionRecordSchema = zod.z.object({
1347
+ id: zod.z.string(),
1348
+ /** Epoch ms the VERDICT was taken (not the birth instant — see `firstSeen`). */
1349
+ at: zod.z.number().int(),
1350
+ /** The camera. Required: every question here is asked per-camera. */
1351
+ deviceId: zod.z.number().int(),
1352
+ /**
1353
+ * The track the decision was about. PROVENANCE, not ownership — a suppressed
1354
+ * birth has no track at all, and a confirmed one is expected to age out long
1355
+ * before this row does. Named `sourceTrackId` so the retention model's
1356
+ * ownership derivation (`collection-classification.ts`, which keys on a
1357
+ * column literally called `trackId`) cannot reach it.
1358
+ */
1359
+ sourceTrackId: zod.z.string(),
1360
+ /** The candidate's claimed class. The miss rate is asked per class too. */
1361
+ className: zod.z.string(),
1362
+ verdict: BirthDecisionVerdictSchema,
1363
+ /**
1364
+ * The gate's own `ConfirmationReason` (`confirmed`, `suppressed`,
1365
+ * `native-pass`, `no-crop`, `timeout`, `carried-inconclusive`, …), or `null`
1366
+ * when the gate is DISABLED and every birth is waved through. `null` is not
1367
+ * "unknown": it says the gate took no measurement because it was off, which
1368
+ * is a different population and must never be averaged in with the rest.
1369
+ */
1370
+ reason: zod.z.string().nullable(),
1371
+ /** Deferral attempts this birth used. 0 = decided on its first look. */
1372
+ attempts: zod.z.number().int(),
1373
+ /** Ms from the FIRST undecided attempt to this verdict. 0 = never deferred. */
1374
+ deferredForMs: zod.z.number().int(),
1375
+ /**
1376
+ * THE COLUMN THE RE-OFFER DEFECT IS COUNTED IN.
1377
+ *
1378
+ * `true` when the frame the verdict was taken on carried no matched
1379
+ * detection for this track — the tracker was coasting a frozen box and the
1380
+ * subject was not observed. The deferred-birth re-offer pulls the candidate
1381
+ * straight out of `result.tracked` without checking, so this is reachable
1382
+ * today; the question is the RATE, per camera, and whether refusing those
1383
+ * frames would have cost real tracks (cross-read against `verdict` and
1384
+ * `decidedByBirthEvidence`).
1385
+ */
1386
+ decidedOnCoastedFrame: zod.z.boolean(),
1387
+ /** Were D379 birth-instant pixels in hand when this candidate was submitted? */
1388
+ birthEvidenceAvailable: zod.z.boolean(),
1389
+ /**
1390
+ * Did those pixels DECIDE it (`cropSource === 'carried'`)? Available and
1391
+ * deciding are different: the carried crop is confirm-only, so a candidate
1392
+ * can hold evidence, be found inconclusive on it, and be decided by a native
1393
+ * crop of a later instant. A coasted decision backed by carried evidence is
1394
+ * a real observation of the birth instant; one without it is not.
1395
+ */
1396
+ decidedByBirthEvidence: zod.z.boolean(),
1397
+ /** Best class-compatible crop score, or `null` when nothing compatible was
1398
+ * found — deliberately not 0, which would be a measurement that never was. */
1399
+ bestScore: zod.z.number().nullable(),
1400
+ /** The bar this candidate actually faced (the phantom-cell hook may raise it). */
1401
+ appliedMinConfidence: zod.z.number().nullable(),
1402
+ /**
1403
+ * The track's own `firstSeen` — the candidate's first frame, which is where
1404
+ * the timeline starts. `null` for a suppressed birth, which has no track.
1405
+ */
1406
+ firstSeen: zod.z.number().int().nullable(),
1407
+ /**
1408
+ * The device's most recent motion RISING EDGE at the moment of the decision,
1409
+ * or `null` when there is none, it is older than
1410
+ * {@link MAX_BIRTH_LATENCY_PROXY_MS}, or this runner never saw one.
1411
+ */
1412
+ motionOnsetAt: zod.z.number().int().nullable(),
1413
+ /**
1414
+ * `firstSeen − motionOnsetAt` — THE OPERATOR'S COMPLAINT, IN MILLISECONDS,
1415
+ * AND THE WEAKEST NUMBER IN THIS ROW. Read the error bars before quoting it.
1416
+ *
1417
+ * **Why motion onset and not something else.** Two other proxies were
1418
+ * considered and rejected:
1419
+ * - *the recording/pipeline session start*: for a camera on
1420
+ * `detectionMode: 'always'` the session opens at process start, hours
1421
+ * before any subject. It measures nothing.
1422
+ * - *the first detection on the device in this burst*: CIRCULAR. A track's
1423
+ * `firstSeen` IS the first detection of that object, so for the track that
1424
+ * OPENS a burst — the only one the operator is complaining about — the two
1425
+ * are the same instant and the latency is 0 by construction.
1426
+ * Motion onset is the only in-process signal produced by a DIFFERENT
1427
+ * mechanism from the object detector, so it is the only one that can precede
1428
+ * it. It is also already maintained per-device at frame rate on this very
1429
+ * node (`handleMotionAnalysis` / `handleOnboardMotion`), which is what makes
1430
+ * it free — and, decisively, the frame path and the motion path are gated to
1431
+ * the SAME designated post-processing node, so the mirror is never empty for
1432
+ * a camera whose births land here.
1433
+ *
1434
+ * **Error bars, all of them.**
1435
+ * 1. *Motion has no class.* A burst opened by rain, a headlight sweeping a
1436
+ * wall or a branch, and only later joined by the person, OVERSTATES the
1437
+ * latency without bound. Mitigated, never removed, by
1438
+ * {@link BirthDecisionRecord.birthIndexInBurst}: only index 0 is a
1439
+ * candidate for "this burst is this subject", and even then it is a
1440
+ * candidate, not a fact.
1441
+ * 2. *The sign is not guaranteed.* The analyzer needs a pixel-count and
1442
+ * intensity threshold. A subject entering slowly at the far edge of the
1443
+ * frame can clear the detector's confidence floor BEFORE it clears the
1444
+ * motion floor, making this negative. Negatives are stored as-is and
1445
+ * never clamped — clamping would fabricate the distribution's left tail,
1446
+ * which is the half that says the proxy is unreliable.
1447
+ * 3. *Onboard motion carries firmware latency of unknown, per-model offset*
1448
+ * (hundreds of ms), plus camera-vs-hub clock skew on top. Numbers are
1449
+ * therefore comparable WITHIN a camera and not across cameras of
1450
+ * different motion sources. The motion source is deliberately not copied
1451
+ * here — it belongs to the addon that owns the device (D224) and this is
1452
+ * a write on the frame path — so group by `deviceId`, which is how the
1453
+ * question is always asked anyway.
1454
+ * 4. *Continuous motion.* On a busy scene the burst never closes and the
1455
+ * onset is minutes old. Bounded by {@link MAX_BIRTH_LATENCY_PROXY_MS};
1456
+ * past it this is `null`.
1457
+ * 5. *No motion signal at all* — analyzer off, onboard-only camera not
1458
+ * reporting, or nothing since boot: `null`. Which is the truth about a
1459
+ * camera nobody has a reference instant for.
1460
+ *
1461
+ * So this is a per-camera DISTRIBUTION over index-0 births, and it is honest
1462
+ * as such. It is not a per-track fact and must never be shown as one.
1463
+ */
1464
+ birthLatencyMs: zod.z.number().int().nullable(),
1465
+ /**
1466
+ * How many births this device has already decided since that motion onset.
1467
+ * 0 = the first, i.e. the only index at which the burst plausibly belongs to
1468
+ * this subject. `null` when there is no usable onset.
1469
+ */
1470
+ birthIndexInBurst: zod.z.number().int().nullable()
1471
+ });
1472
+ /** Query input for `listBirthDecisions` — newest first, one camera or all. */
1473
+ var BirthDecisionQueryInputSchema = zod.z.object({
1474
+ /** Restrict to a single camera; omit for every row. */
1475
+ deviceId: zod.z.number().int().optional(),
1476
+ /** Only decisions at or after this epoch ms. */
1477
+ since: zod.z.number().int().optional(),
1478
+ /** Restrict to one verdict — the miss rate is read one population at a time. */
1479
+ verdict: BirthDecisionVerdictSchema.optional(),
1480
+ /** Max rows returned, newest-first. */
1481
+ limit: zod.z.number().int().min(1).max(5e3).optional()
1482
+ });
1483
+ //#endregion
1260
1484
  //#region src/interfaces/debug-note-archive.ts
1261
1485
  /**
1262
1486
  * Debug-note archive — the durable corpus of what operators asked to be
@@ -20294,6 +20518,26 @@ var pipelineAnalyticsCapability = {
20294
20518
  */
20295
20519
  listArchivedDebugNotes: require_sleep.method(ArchivedDebugNoteQueryInputSchema, zod.z.array(ArchivedDebugNoteSchema).readonly(), { kind: "query" }),
20296
20520
  /**
20521
+ * Birth decisions — one row per resolved confirmation-gate verdict (D409).
20522
+ *
20523
+ * The READ half of a measurement, and only that: it gates nothing and no
20524
+ * runtime path consults it. It exists because the two questions the
20525
+ * operator's "traccia partita in ritardo" marks raised are both multi-day
20526
+ * and `logs.query` holds under an hour of fleet traffic —
20527
+ * • how often is a birth DECIDED on a frame the subject was not observed
20528
+ * in (`decidedOnCoastedFrame`), and did D379's carried pixels make it a
20529
+ * real observation anyway (`decidedByBirthEvidence`);
20530
+ * • how long after the camera's motion onset does a track's `firstSeen`
20531
+ * land (`birthLatencyMs` — read its error bars in
20532
+ * `BirthDecisionRecordSchema` before quoting it).
20533
+ *
20534
+ * Newest-first, capped by `limit` (default
20535
+ * {@link BIRTH_DECISION_DEFAULT_LIMIT}), optionally scoped to one camera,
20536
+ * one verdict, or a `since`. The table is bounded by row count, not age —
20537
+ * see {@link MAX_BIRTH_DECISION_RECORDS}.
20538
+ */
20539
+ listBirthDecisions: require_sleep.method(BirthDecisionQueryInputSchema, zod.z.array(BirthDecisionRecordSchema).readonly(), { kind: "query" }),
20540
+ /**
20297
20541
  * Durable event-store footprint for the management UI: event rows
20298
20542
  * (motion + object + audio) counted per camera + total, plus the
20299
20543
  * event-owned media bytes on disk per camera + total. Stat/count-based,
@@ -21080,6 +21324,22 @@ var occupancyRecheckFramesField = {
21080
21324
  step: 1
21081
21325
  };
21082
21326
  /**
21327
+ * Frames one PRE-ROLL catch-up burst may send to inference at session open.
21328
+ *
21329
+ * The default of 12 over a ~4 s retained window is one frame per ~333 ms of
21330
+ * footage, and costs ~480 ms of ONE inference permit at the 40 ms/frame this
21331
+ * fleet measures — one-shot, and only ever taken while a permit would still be
21332
+ * spare for live. `0` turns the burst off entirely (the history is still
21333
+ * decoded, because that is how the dial reaches a decodable GOP, and is then
21334
+ * discarded — the pre-D411 behaviour).
21335
+ */
21336
+ var preRollInferenceFramesField = {
21337
+ min: 0,
21338
+ max: 30,
21339
+ default: 12,
21340
+ step: 1
21341
+ };
21342
+ /**
21083
21343
  * Source enum for motion signals fed to the runner. Extensible — add
21084
21344
  * new variants here when new motion-trigger paths are wired in
21085
21345
  * (`wasm-cross-camera`, `event-bus-relay`, etc.). The runner uses
@@ -21320,6 +21580,31 @@ var RunnerCameraConfigSchema = zod.z.object({
21320
21580
  * to every occupancy rule until something moved in front of it. The churn is
21321
21581
  * now paid on the interval instead — see `occupancyRecheckSecField`.
21322
21582
  */
21583
+ /**
21584
+ * Infer the session's PRE-ROLL — the retained history the restreamer replays
21585
+ * at session open — instead of decoding it and throwing it away.
21586
+ *
21587
+ * DEFAULT `true`, and the default is the argument. This is not a new
21588
+ * capability being offered cautiously: the pre-roll is ALREADY requested,
21589
+ * already served, already decoded and already paid for on every on-motion
21590
+ * detection session that asks for history. What shipped was a last-moment
21591
+ * discard — `FrameSlot`'s throttle compares wall clocks, and ~4 s of media
21592
+ * arriving inside a few hundred ms of wall clock looks to it like one frame's
21593
+ * worth. Device 617, 2026-09-08: a re-run of the SAME model over the stored
21594
+ * recording scored the subject `vehicle 0.5669` — above the 0.50 floor —
21595
+ * 1.68 s BEFORE the live track was born, on a frame that was in the pre-roll,
21596
+ * was decoded, and was freed.
21597
+ *
21598
+ * Shipping that as opt-in would ship the bug: an operator cannot discover a
21599
+ * setting whose absence looks exactly like a camera that noticed the cyclist
21600
+ * late. What makes ON safe is not a switch but the BOUND —
21601
+ * `preRollInferenceFrames`, a wall-clock ceiling, and a lane that never takes
21602
+ * the last inference permit — so the switch exists for the camera where the
21603
+ * history is worthless (a doorbell whose subject is always already at the
21604
+ * door), not as a hedge against the feature.
21605
+ */
21606
+ preRollInferenceEnabled: zod.z.boolean().default(true),
21607
+ preRollInferenceFrames: zod.z.number().min(preRollInferenceFramesField.min).max(preRollInferenceFramesField.max).default(preRollInferenceFramesField.default),
21323
21608
  occupancyRecheckEnabled: zod.z.boolean().default(true),
21324
21609
  occupancyRecheckSec: zod.z.number().min(occupancyRecheckSecField.min).max(occupancyRecheckSecField.max).default(occupancyRecheckSecField.default),
21325
21610
  occupancyRecheckFrames: zod.z.number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default),
@@ -21474,6 +21759,29 @@ var RunnerCameraDeviceUIFields = [
21474
21759
  includes: "onboard"
21475
21760
  }
21476
21761
  },
21762
+ {
21763
+ key: "preRollInferenceEnabled",
21764
+ type: "boolean",
21765
+ style: "checkbox",
21766
+ label: "Detect in the pre-roll",
21767
+ description: "Run detection over the few seconds of footage the camera had already buffered when motion fired, so a subject that was in view before the trigger is found at the moment it appeared rather than seconds later. The burst is bounded and never delays live detection.",
21768
+ default: true
21769
+ },
21770
+ {
21771
+ key: "preRollInferenceFrames",
21772
+ type: "slider",
21773
+ label: "Pre-roll frames",
21774
+ description: "How many frames of buffered history may be detected on, per session. Higher samples the history more densely; 0 disables the pass.",
21775
+ min: preRollInferenceFramesField.min,
21776
+ max: preRollInferenceFramesField.max,
21777
+ step: preRollInferenceFramesField.step,
21778
+ default: preRollInferenceFramesField.default,
21779
+ showValue: true,
21780
+ showWhen: {
21781
+ field: "preRollInferenceEnabled",
21782
+ equals: true
21783
+ }
21784
+ },
21477
21785
  {
21478
21786
  key: "occupancyRecheckEnabled",
21479
21787
  type: "boolean",
@@ -44686,6 +44994,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
44686
44994
  addonId: null,
44687
44995
  access: "view"
44688
44996
  },
44997
+ "pipelineAnalytics.listBirthDecisions": {
44998
+ capName: "pipeline-analytics",
44999
+ capScope: "device",
45000
+ addonId: null,
45001
+ access: "view"
45002
+ },
44689
45003
  "pipelineAnalytics.listEventKinds": {
44690
45004
  capName: "pipeline-analytics",
44691
45005
  capScope: "device",
@@ -48747,6 +49061,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
48747
49061
  form: "single",
48748
49062
  optional: true
48749
49063
  }],
49064
+ "pipelineAnalytics.listBirthDecisions": [{
49065
+ name: "deviceId",
49066
+ form: "single",
49067
+ optional: true
49068
+ }],
48750
49069
  "pipelineAnalytics.listEventKinds": [{
48751
49070
  name: "deviceId",
48752
49071
  form: "single",
@@ -54815,6 +55134,7 @@ exports.BACKEND_TO_FORMAT = BACKEND_TO_FORMAT;
54815
55134
  exports.BASE_LIVE_EGRESS_PROFILE = BASE_LIVE_EGRESS_PROFILE;
54816
55135
  exports.BATTERY_DEVICE_PROFILE = BATTERY_DEVICE_PROFILE;
54817
55136
  exports.BATTERY_UNREACHABLE_AFTER_MS = BATTERY_UNREACHABLE_AFTER_MS;
55137
+ exports.BIRTH_DECISION_DEFAULT_LIMIT = BIRTH_DECISION_DEFAULT_LIMIT;
54818
55138
  exports.BOOT_RECOVERY_BACKOFF_MS = require_sleep.BOOT_RECOVERY_BACKOFF_MS;
54819
55139
  exports.BacklightModeSchema = BacklightModeSchema;
54820
55140
  exports.BackupDestinationInfoSchema = BackupDestinationInfoSchema;
@@ -54828,6 +55148,9 @@ exports.BaseDevice = BaseDevice;
54828
55148
  exports.BaseDeviceProvider = BaseDeviceProvider;
54829
55149
  exports.BatteryStatusSchema = BatteryStatusSchema;
54830
55150
  exports.BinaryStatusSchema = BinaryStatusSchema;
55151
+ exports.BirthDecisionQueryInputSchema = BirthDecisionQueryInputSchema;
55152
+ exports.BirthDecisionRecordSchema = BirthDecisionRecordSchema;
55153
+ exports.BirthDecisionVerdictSchema = BirthDecisionVerdictSchema;
54831
55154
  exports.BoundingBoxSchema = BoundingBoxSchema;
54832
55155
  exports.BrightnessStatusSchema = BrightnessStatusSchema;
54833
55156
  exports.BrokerAddInputSchema = AddInputSchema;
@@ -55204,6 +55527,8 @@ exports.LoginMethodContributionSchema = LoginMethodContributionSchema;
55204
55527
  exports.LoginStageEnum = LoginStageEnum;
55205
55528
  exports.MACRO_LABELS = MACRO_LABELS;
55206
55529
  exports.MAX_ARCHIVED_DEBUG_NOTES = MAX_ARCHIVED_DEBUG_NOTES;
55530
+ exports.MAX_BIRTH_DECISION_RECORDS = MAX_BIRTH_DECISION_RECORDS;
55531
+ exports.MAX_BIRTH_LATENCY_PROXY_MS = MAX_BIRTH_LATENCY_PROXY_MS;
55207
55532
  exports.MAX_CLIP_EVENT_IDS = MAX_CLIP_EVENT_IDS;
55208
55533
  exports.MAX_CLIP_LABELS = MAX_CLIP_LABELS;
55209
55534
  exports.MAX_CONDITION_DEPTH = MAX_CONDITION_DEPTH;