@camstack/addon-post-analysis 1.2.104 → 1.2.107
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/{dist-IZLiqXRa.mjs → dist-Dv2LOr1d.mjs} +283 -10
- package/dist/{dist-KXhjlCmh.js → dist-wQmgHP6h.js} +300 -9
- package/dist/embedding-encoder/index.js +89 -131
- package/dist/embedding-encoder/index.mjs +89 -131
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-D8fRo8aP.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-Ds7UUptm.mjs} +3 -3
- package/dist/pipeline-analytics/{hostInit-7agPxY0d.mjs → hostInit-B30POcEN.mjs} +3 -3
- package/dist/pipeline-analytics/index.js +5212 -1068
- package/dist/pipeline-analytics/index.mjs +5202 -1060
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +8 -1
|
@@ -7790,7 +7790,7 @@ var RecordingBandSchema = object({
|
|
|
7790
7790
|
* visit is derived, not a second copy of the files.
|
|
7791
7791
|
*/
|
|
7792
7792
|
var VISIT_MERGE_GAP_MS = {
|
|
7793
|
-
preBufferSec:
|
|
7793
|
+
preBufferSec: 15,
|
|
7794
7794
|
postBufferSec: 30
|
|
7795
7795
|
}.postBufferSec * 1e3;
|
|
7796
7796
|
/**
|
|
@@ -17208,7 +17208,7 @@ var TrackEnvelopeSchema = object({
|
|
|
17208
17208
|
* `snapshots[]` references — megabytes across a page of tracks. `slim`
|
|
17209
17209
|
* keeps every scalar the list surfaces actually render (ids, class(es),
|
|
17210
17210
|
* label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
|
|
17211
|
-
* zonesVisited, bestEventId, envelope, hasFace, hasRider) and returns `positions` /
|
|
17211
|
+
* zonesVisited, bestEventId, envelope, hasFace, hasEmbeddedFace, hasRider) and returns `positions` /
|
|
17212
17212
|
* `snapshots` as EMPTY arrays — detail views re-fetch the full row via
|
|
17213
17213
|
* `getTrack`. Mirrors the event-store `projection` convention
|
|
17214
17214
|
* (`getObjectEvents` et al.).
|
|
@@ -17503,6 +17503,35 @@ var TrackSchema = object({
|
|
|
17503
17503
|
*/
|
|
17504
17504
|
hasFace: boolean().optional(),
|
|
17505
17505
|
/**
|
|
17506
|
+
* This track has a face row IN THE GALLERY: a crop **and** an embedding — a
|
|
17507
|
+
* face an operator could ASSIGN to an identity.
|
|
17508
|
+
*
|
|
17509
|
+
* The STRICT twin of {@link hasFace}, and the pair only earns its keep
|
|
17510
|
+
* because the two disagree. `hasFace` is stamped at the TOP of the face
|
|
17511
|
+
* branch, before every gate, and means no more than "a face detector produced
|
|
17512
|
+
* a face detail". This one is stamped at the single moment the gallery row
|
|
17513
|
+
* LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
|
|
17514
|
+
* past the embedding-magnitude verdict, the `minFacePx` detection gate, the
|
|
17515
|
+
* candidate gate, the imageless-track drop (no crop was ever captured) and
|
|
17516
|
+
* the crop-store drop. Everything between the detector and that insert can
|
|
17517
|
+
* legitimately refuse the face, so a flag written any earlier promises the
|
|
17518
|
+
* operator something to assign and delivers nothing.
|
|
17519
|
+
*
|
|
17520
|
+
* **Independent of recognition.** A face collected but never auto-matched is
|
|
17521
|
+
* still assignable — it is in fact the face an operator most wants to reach —
|
|
17522
|
+
* so this is NOT gated on `recognizedIdentityId`. Recognition lands in
|
|
17523
|
+
* `subLabel`; this says only that the raw material exists.
|
|
17524
|
+
*
|
|
17525
|
+
* **Set once, never cleared.** A track that produced a gallery row produced
|
|
17526
|
+
* one; deleting the row later is the gallery's business, not this flag's.
|
|
17527
|
+
*
|
|
17528
|
+
* **Absent ≠ false**, the same rule as {@link hasFace}: every row written
|
|
17529
|
+
* before the column omits it, and so does every server that predates the
|
|
17530
|
+
* field. A consumer must test `=== true` and render nothing otherwise —
|
|
17531
|
+
* never infer "no assignable face".
|
|
17532
|
+
*/
|
|
17533
|
+
hasEmbeddedFace: boolean().optional(),
|
|
17534
|
+
/**
|
|
17506
17535
|
* This subject CONTAINS a folded rider — a person the rider-pairing step
|
|
17507
17536
|
* ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
|
|
17508
17537
|
* so the passage is tracked once and as a VEHICLE.
|
|
@@ -19299,6 +19328,26 @@ var DetailResultSchema = object({
|
|
|
19299
19328
|
* the consuming gate treats as accept — never as reject.
|
|
19300
19329
|
*/
|
|
19301
19330
|
embeddingMagnitude: number().optional(),
|
|
19331
|
+
/**
|
|
19332
|
+
* Model that produced `embedding` — the SAME contract `labelModelId` has for
|
|
19333
|
+
* `label`, and for the same reason: the producing node is the only side that
|
|
19334
|
+
* knows which model actually ran, and re-deriving it downstream is exactly
|
|
19335
|
+
* the inference this model exists to forbid.
|
|
19336
|
+
*
|
|
19337
|
+
* Additive and optional, so a runner that predates it degrades to
|
|
19338
|
+
* "unmeasurable" rather than to a wrong answer — the consumer falls back to
|
|
19339
|
+
* its previous assumption instead of refusing.
|
|
19340
|
+
*
|
|
19341
|
+
* Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
|
|
19342
|
+
* to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
|
|
19343
|
+
* with nothing on the wire it took the id from the GALLERY, so the gate
|
|
19344
|
+
* compared the gallery against itself and could never fire. That turned the
|
|
19345
|
+
* one guard protecting the face feature space into a tautology, and it is
|
|
19346
|
+
* why swapping `face-embedding`'s model would NOT have stranded the enrolled
|
|
19347
|
+
* gallery as the catalog comment predicts — it would have scored the new
|
|
19348
|
+
* model's vectors against the old model's samples in one cosine space.
|
|
19349
|
+
*/
|
|
19350
|
+
embeddingModelId: string().optional(),
|
|
19302
19351
|
label: string().optional(),
|
|
19303
19352
|
/**
|
|
19304
19353
|
* The tier `label` occupies, copied VERBATIM from the producing step's
|
|
@@ -20174,6 +20223,12 @@ var CameraStatusSchema = object({
|
|
|
20174
20223
|
/** Unix timestamp (ms) when this snapshot was composed server-side. */
|
|
20175
20224
|
fetchedAt: number()
|
|
20176
20225
|
});
|
|
20226
|
+
var InferenceDeviceExclusionReasonSchema = _enum([
|
|
20227
|
+
"disabled",
|
|
20228
|
+
"unavailable",
|
|
20229
|
+
"cannot-host-camera-root",
|
|
20230
|
+
"accelerator-preferred"
|
|
20231
|
+
]);
|
|
20177
20232
|
var NodeInferenceDeviceSchema = object({
|
|
20178
20233
|
/** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
|
|
20179
20234
|
key: string(),
|
|
@@ -20204,7 +20259,17 @@ var NodeInferenceDeviceSchema = object({
|
|
|
20204
20259
|
* available per format; this is the stored selection that becomes the
|
|
20205
20260
|
* default for EVERY camera landing on this accelerator.
|
|
20206
20261
|
*/
|
|
20207
|
-
steps: record(string(), DeviceStepConfigSchema).optional()
|
|
20262
|
+
steps: record(string(), DeviceStepConfigSchema).optional(),
|
|
20263
|
+
/**
|
|
20264
|
+
* `null` when the device IS a camera-root candidate on this node; otherwise
|
|
20265
|
+
* the reason the dispatcher drops it. Computed by the SAME
|
|
20266
|
+
* `resolveInferenceDeviceEligibility` the dispatcher runs, so this view can
|
|
20267
|
+
* never disagree with the election — deriving it in the UI from
|
|
20268
|
+
* `enabled`/`available` would silently miss `cannot-host-camera-root` (needs
|
|
20269
|
+
* the node's model catalog) and `accelerator-preferred` (needs the node-wide
|
|
20270
|
+
* "an accelerator is serving" predicate).
|
|
20271
|
+
*/
|
|
20272
|
+
exclusion: InferenceDeviceExclusionReasonSchema.nullable()
|
|
20208
20273
|
});
|
|
20209
20274
|
var NodeInferenceDevicesSchema = object({
|
|
20210
20275
|
nodeId: string(),
|
|
@@ -25125,7 +25190,12 @@ var ListResultSchema = object({
|
|
|
25125
25190
|
probedAt: number()
|
|
25126
25191
|
});
|
|
25127
25192
|
var PreferredSchema = LocalInterfaceSchema.nullable();
|
|
25128
|
-
|
|
25193
|
+
/**
|
|
25194
|
+
* Candidate base URL for the SDK to race on connect. Order matters —
|
|
25195
|
+
* the SDK should attempt these top-to-bottom with a short per-candidate
|
|
25196
|
+
* timeout (e.g. 1500ms) and cache the winner for the session.
|
|
25197
|
+
*/
|
|
25198
|
+
var ConnectionEndpointSchema = object({
|
|
25129
25199
|
/** Operator-facing label (e.g. "LAN — en0", "Public tunnel"). */
|
|
25130
25200
|
label: string(),
|
|
25131
25201
|
/** Fully-formed base URL with scheme + host + port. */
|
|
@@ -25168,7 +25238,42 @@ var GetConnectionEndpointsResultSchema = object({ endpoints: array(object({
|
|
|
25168
25238
|
* ordering between polls.
|
|
25169
25239
|
*/
|
|
25170
25240
|
priority: number()
|
|
25171
|
-
})
|
|
25241
|
+
});
|
|
25242
|
+
/**
|
|
25243
|
+
* Where the advertised local port came from. Ordered most → least
|
|
25244
|
+
* authoritative, and the whole point of returning it: a client must be able to
|
|
25245
|
+
* tell a FACT about the hub's socket from an echo of its own guess.
|
|
25246
|
+
*/
|
|
25247
|
+
var LocalPortSourceEnum = _enum([
|
|
25248
|
+
"server-config",
|
|
25249
|
+
"server-env",
|
|
25250
|
+
"caller-hint",
|
|
25251
|
+
"default"
|
|
25252
|
+
]);
|
|
25253
|
+
/** The port every LAN/loopback `baseUrl` in the same result was built with. */
|
|
25254
|
+
var AdvertisedLocalPortSchema = object({
|
|
25255
|
+
port: number().int().min(1).max(65535),
|
|
25256
|
+
source: LocalPortSourceEnum
|
|
25257
|
+
});
|
|
25258
|
+
var GetConnectionEndpointsResultSchema = object({
|
|
25259
|
+
endpoints: array(ConnectionEndpointSchema).readonly(),
|
|
25260
|
+
/**
|
|
25261
|
+
* The port the hub built the LAN/loopback URLs with, and where that number
|
|
25262
|
+
* came from.
|
|
25263
|
+
*
|
|
25264
|
+
* Returned rather than merely applied, because "the URL is right" and "the
|
|
25265
|
+
* client can KNOW the URL is right" are different properties. A client that
|
|
25266
|
+
* only sees a corrected URL cannot distinguish a hub that fixed the port from
|
|
25267
|
+
* a hub that echoed the port the client sent, so it cannot decide whether to
|
|
25268
|
+
* race the candidate or discard it. With `source` it can: anything but
|
|
25269
|
+
* `caller-hint` is the hub's own socket.
|
|
25270
|
+
*
|
|
25271
|
+
* Absent on hubs predating this field — a client that finds it missing is
|
|
25272
|
+
* talking to an echoing hub and must degrade exactly as it does for
|
|
25273
|
+
* `caller-hint`.
|
|
25274
|
+
*/
|
|
25275
|
+
localPort: AdvertisedLocalPortSchema
|
|
25276
|
+
});
|
|
25172
25277
|
/**
|
|
25173
25278
|
* The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
|
|
25174
25279
|
* AUTO (resolved from the candidate ranking at send time); `resolved` reports
|
|
@@ -25189,8 +25294,13 @@ var AllowedAddressesSchema = object({
|
|
|
25189
25294
|
*/
|
|
25190
25295
|
addresses: array(string()).readonly() });
|
|
25191
25296
|
method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
|
|
25192
|
-
/**
|
|
25193
|
-
|
|
25297
|
+
/**
|
|
25298
|
+
* LEGACY HINT — do not send from new code. Kept optional so clients
|
|
25299
|
+
* written against the echoing contract keep working; the hub uses it
|
|
25300
|
+
* only when it cannot read its own port, and says so via
|
|
25301
|
+
* `localPort.source === 'caller-hint'`.
|
|
25302
|
+
*/
|
|
25303
|
+
port: number().int().min(1).max(65535).optional(),
|
|
25194
25304
|
/** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
|
|
25195
25305
|
* candidate. Default `true`. */
|
|
25196
25306
|
includeLoopback: boolean().optional(),
|
|
@@ -38885,6 +38995,140 @@ function readTimelapseGeneratedAt(rule, deviceId) {
|
|
|
38885
38995
|
if (map !== void 0) return map[String(deviceId)] ?? 0;
|
|
38886
38996
|
return rule.lastGeneratedAt ?? 0;
|
|
38887
38997
|
}
|
|
38998
|
+
/**
|
|
38999
|
+
* A model choice has a SCOPE, and a scope change has a workflow.
|
|
39000
|
+
*
|
|
39001
|
+
* ## The two scopes
|
|
39002
|
+
*
|
|
39003
|
+
* Almost every pipeline step's model is a **node** question: which build runs
|
|
39004
|
+
* fastest on THIS accelerator. Two nodes may legitimately answer differently —
|
|
39005
|
+
* a Coral runs the tflite SSD, a Mac runs the coreml YOLO — because the answers
|
|
39006
|
+
* are compared against nothing. They produce boxes, and a box is a box.
|
|
39007
|
+
*
|
|
39008
|
+
* Two steps are not like that. `face-embedding` and `clip-embedding` produce
|
|
39009
|
+
* **vectors that land in ONE shared index** (`identity_samples`,
|
|
39010
|
+
* `vec_object_clip`) and are ranked against each other by cosine similarity.
|
|
39011
|
+
* Cosine similarity between two encoders is not a weak signal, it is a
|
|
39012
|
+
* meaningless number — and nothing inside a vector can tell you it happened.
|
|
39013
|
+
* So for those two steps the model is a **cluster** question with exactly one
|
|
39014
|
+
* answer, stored in exactly one row.
|
|
39015
|
+
*
|
|
39016
|
+
* That is the same argument [D52](../../../../docs/decisions/adr-0052.md) makes
|
|
39017
|
+
* for the crop convention (`detail-crop.ts`), one level up: the crop decides
|
|
39018
|
+
* WHAT pixels the encoder sees, this decides WHICH encoder sees them. Both are
|
|
39019
|
+
* cluster-wide for the same reason and neither may become per-node.
|
|
39020
|
+
*
|
|
39021
|
+
* ## Why the registry lives here and not in the step catalog
|
|
39022
|
+
*
|
|
39023
|
+
* The scope itself is declared on the step, in
|
|
39024
|
+
* `detection-pipeline/registry/step-definitions.ts` (`StepDefinition.modelScope`)
|
|
39025
|
+
* — that is where a new step declares what kind of choice its model is. But the
|
|
39026
|
+
* catalog lives inside `addon-pipeline`, and three packages that must NOT
|
|
39027
|
+
* import an addon need to know the set: the orchestrator (which renders and
|
|
39028
|
+
* stores the row), post-analysis (which pins the row for a re-embed pass) and
|
|
39029
|
+
* admin-ui (which mirrors it). So the set is mirrored here, and
|
|
39030
|
+
* `scripts/check-cluster-model-scope.ts` fails the build when the two disagree.
|
|
39031
|
+
* A hand-copied key that stops matching is exactly how a setting silently stops
|
|
39032
|
+
* arriving while both sides still look correct.
|
|
39033
|
+
*
|
|
39034
|
+
* ## The defaults ARE today's behaviour
|
|
39035
|
+
*
|
|
39036
|
+
* {@link DEFAULT_CLUSTER_STEP_MODELS} reproduces the catalog `defaultModelId`
|
|
39037
|
+
* of both steps. Declaring the scope therefore changes nothing on the day it
|
|
39038
|
+
* ships: the cluster row starts out saying what every node was already doing.
|
|
39039
|
+
* Changing it is legitimate — that is what the knob is for — but it invalidates
|
|
39040
|
+
* the stored vectors of that surface, and must be followed by a re-embed pass
|
|
39041
|
+
* (`face-reembed-pass.ts`, `embedding-rebuild.ts`).
|
|
39042
|
+
*/
|
|
39043
|
+
/**
|
|
39044
|
+
* The cluster-scoped steps. Mirrored from the catalog's `modelScope: 'cluster'`
|
|
39045
|
+
* declarations and guarded by `scripts/check-cluster-model-scope.ts`.
|
|
39046
|
+
*/
|
|
39047
|
+
var CLUSTER_MODEL_SCOPED_STEPS = [{
|
|
39048
|
+
stepId: "face-embedding",
|
|
39049
|
+
label: "Face recognition model",
|
|
39050
|
+
defaultModelId: "arcface-r100",
|
|
39051
|
+
indexName: "the enrolled face gallery",
|
|
39052
|
+
options: [
|
|
39053
|
+
{
|
|
39054
|
+
id: "arcface-r100",
|
|
39055
|
+
label: "ArcFace (ResNet34)"
|
|
39056
|
+
},
|
|
39057
|
+
{
|
|
39058
|
+
id: "auraface-r100",
|
|
39059
|
+
label: "AuraFace R100"
|
|
39060
|
+
},
|
|
39061
|
+
{
|
|
39062
|
+
id: "inception-resnet-v1",
|
|
39063
|
+
label: "Inception ResNet V1"
|
|
39064
|
+
}
|
|
39065
|
+
]
|
|
39066
|
+
}, {
|
|
39067
|
+
stepId: "clip-embedding",
|
|
39068
|
+
label: "Semantic search model",
|
|
39069
|
+
defaultModelId: "mobileclip-s1",
|
|
39070
|
+
indexName: "the object semantic-search index",
|
|
39071
|
+
options: [{
|
|
39072
|
+
id: "mobileclip-s1",
|
|
39073
|
+
label: "MobileCLIP S1"
|
|
39074
|
+
}, {
|
|
39075
|
+
id: "mobileclip-s2",
|
|
39076
|
+
label: "MobileCLIP S2"
|
|
39077
|
+
}]
|
|
39078
|
+
}];
|
|
39079
|
+
/**
|
|
39080
|
+
* The settings key holding one step's cluster model choice.
|
|
39081
|
+
*
|
|
39082
|
+
* Step-qualified so the keys stay unique across the addon's whole schema, which
|
|
39083
|
+
* is what lets {@link pickClusterStepModels} walk every section instead of
|
|
39084
|
+
* trusting the section id.
|
|
39085
|
+
*/
|
|
39086
|
+
function clusterModelSettingKey(stepId) {
|
|
39087
|
+
return `clusterModel:${stepId}`;
|
|
39088
|
+
}
|
|
39089
|
+
/** The cluster row when nobody has configured one — today's catalog defaults. */
|
|
39090
|
+
var DEFAULT_CLUSTER_STEP_MODELS = Object.freeze(Object.fromEntries(CLUSTER_MODEL_SCOPED_STEPS.map((s) => [s.stepId, s.defaultModelId])));
|
|
39091
|
+
/** A stored choice is a non-empty model id, or it is not a choice. */
|
|
39092
|
+
var ChosenModelIdSchema = string().min(1);
|
|
39093
|
+
/**
|
|
39094
|
+
* Narrow a FLAT settings record to the cluster row.
|
|
39095
|
+
*
|
|
39096
|
+
* Per-FIELD fallback, deliberately (same rule as `readDetailCropConvention`): a
|
|
39097
|
+
* junk face model must not also discard a valid clip model. An absent, empty or
|
|
39098
|
+
* non-string value resolves to the step's catalog default — the historical
|
|
39099
|
+
* behaviour — never to a blank id, because a blank id downstream becomes
|
|
39100
|
+
* "substitute the format default", which is precisely the substitution this
|
|
39101
|
+
* scope exists to forbid.
|
|
39102
|
+
*/
|
|
39103
|
+
function readClusterStepModels(config) {
|
|
39104
|
+
const out = {};
|
|
39105
|
+
for (const step of CLUSTER_MODEL_SCOPED_STEPS) {
|
|
39106
|
+
const parsed = ChosenModelIdSchema.safeParse(config[clusterModelSettingKey(step.stepId)]);
|
|
39107
|
+
out[step.stepId] = parsed.success ? parsed.data : step.defaultModelId;
|
|
39108
|
+
}
|
|
39109
|
+
return out;
|
|
39110
|
+
}
|
|
39111
|
+
function isHydratedField$2(entry) {
|
|
39112
|
+
return typeof entry === "object" && entry !== null && "key" in entry;
|
|
39113
|
+
}
|
|
39114
|
+
/**
|
|
39115
|
+
* Extract the cluster row from an `addon-settings.getGlobalSettings` payload.
|
|
39116
|
+
*
|
|
39117
|
+
* Walks EVERY section rather than looking inside {@link CLUSTER_MODEL_SECTION_ID}
|
|
39118
|
+
* alone: the keys are unique across the addon's schema, and a section rename
|
|
39119
|
+
* must not silently revert the whole cluster to the defaults. A `null` payload
|
|
39120
|
+
* (addon mid-boot) is the defaults.
|
|
39121
|
+
*/
|
|
39122
|
+
function pickClusterStepModels(view) {
|
|
39123
|
+
if (view === null) return DEFAULT_CLUSTER_STEP_MODELS;
|
|
39124
|
+
const flat = {};
|
|
39125
|
+
const wanted = new Set(CLUSTER_MODEL_SCOPED_STEPS.map((s) => clusterModelSettingKey(s.stepId)));
|
|
39126
|
+
for (const section of view.sections) for (const entry of section.fields) {
|
|
39127
|
+
if (!isHydratedField$2(entry) || typeof entry.key !== "string") continue;
|
|
39128
|
+
if (wanted.has(entry.key)) flat[entry.key] = entry.value;
|
|
39129
|
+
}
|
|
39130
|
+
return readClusterStepModels(flat);
|
|
39131
|
+
}
|
|
38888
39132
|
object({
|
|
38889
39133
|
/**
|
|
38890
39134
|
* Fraction of the box's own size added on EACH side before cutting.
|
|
@@ -38905,10 +39149,39 @@ object({
|
|
|
38905
39149
|
*/
|
|
38906
39150
|
square: boolean()
|
|
38907
39151
|
});
|
|
38908
|
-
|
|
39152
|
+
/**
|
|
39153
|
+
* The convention in force when nobody has configured one — byte-for-byte the
|
|
39154
|
+
* behaviour of the pre-unification LIVE path (`DETAIL_CROP_PADDING_RATIO`).
|
|
39155
|
+
*/
|
|
39156
|
+
var DEFAULT_DETAIL_CROP_CONVENTION = {
|
|
38909
39157
|
paddingRatio: .15,
|
|
38910
39158
|
square: false
|
|
38911
|
-
}
|
|
39159
|
+
};
|
|
39160
|
+
/**
|
|
39161
|
+
* The normalised box that means "the image IS the subject".
|
|
39162
|
+
*
|
|
39163
|
+
* Used when the stored pixels are ALREADY the model's input — the 112×112
|
|
39164
|
+
* aligned face template a gallery sample carries. There is no rectangle left to
|
|
39165
|
+
* choose, and the convention must not choose one: re-detecting and re-aligning
|
|
39166
|
+
* over a template applies a SECOND warp, passes every gate, and produces a
|
|
39167
|
+
* plausible useless vector (session 2026-08-20 §3).
|
|
39168
|
+
*
|
|
39169
|
+
* Sending it as the whole frame with this box is exact rather than merely
|
|
39170
|
+
* convenient, and the reason is a property of {@link deriveDetailCropRect}, not
|
|
39171
|
+
* a coincidence: padding a full-frame box can only push OUTSIDE the frame, and
|
|
39172
|
+
* both edge modes bring it straight back — unsquared truncates, squared cannot
|
|
39173
|
+
* exceed the frame's short side and then slides inside. So for a SQUARE image
|
|
39174
|
+
* the derivation is the identity under every convention value, and an operator
|
|
39175
|
+
* changing the crop margin cannot silently re-cut an enrolled template.
|
|
39176
|
+
* `face-reembed-pass.spec.ts` asserts that identity against the real function.
|
|
39177
|
+
*/
|
|
39178
|
+
var FULL_IMAGE_BBOX = Object.freeze({
|
|
39179
|
+
x: 0,
|
|
39180
|
+
y: 0,
|
|
39181
|
+
w: 1,
|
|
39182
|
+
h: 1
|
|
39183
|
+
});
|
|
39184
|
+
DEFAULT_DETAIL_CROP_CONVENTION.paddingRatio;
|
|
38912
39185
|
/**
|
|
38913
39186
|
* WHICH delivered frames the decode worker retains a native copy of.
|
|
38914
39187
|
*
|
|
@@ -39364,4 +39637,4 @@ function vectorDimFromBase64(encoded) {
|
|
|
39364
39637
|
return Math.floor(Buffer.from(encoded, "base64").byteLength / 4);
|
|
39365
39638
|
}
|
|
39366
39639
|
//#endregion
|
|
39367
|
-
export {
|
|
39640
|
+
export { deriveRecordingMode as $, PoolMemoryWatchdog as A, array as At, TimelapseRulePatchSchema as B, EventCategory as Bt, NcScheduleSchema as C, DeviceType as Ct, NcSystemEventKindSchema as D, nodePin as Dt, NcSnoozeSuppressedSchema as E, isDeviceScopedCap as Et, SCENE_DEFAULT_UNCOVERED_POLICY as F, object as Ft, alarmPanelCapability as G, TrackSourceSchema as H, SCENE_DIVERGED as I, partialRecord as It, audioModeOf as J, assertTimelapseCadences as K, SceneMonitorSchema as L, record as Lt, RetrainStatusSchema as M, discriminatedUnion as Mt, SCENE_CONFIRM_DEFAULT_TIMEOUT_MS as N, literal as Nt, NcTaxonomySchema as O, sleep as Ot, SCENE_DEFAULT_ANCHOR_THRESHOLD as P, number as Pt, defineCustomActions as Q, TIMELAPSE_DENSE_FLOOR_SEC as R, string as Rt, NcRuleTargetSchema as S, BaseAddon as St, NcSnoozeSchema as T, hydrateSchema as Tt, VISIT_MERGE_GAP_MS as U, TimelapseRuleSchema as V, addonWidgetsSourceCapability as W, cosineSimilarity as X, buildEventKindDescriptor as Y, customAction as Z, NC_TAXONOMY as _, systemEventFilterApplies as _t, DETECTION_MACRO_CLASSES as a, isScheduleActive as at, NcRulePatchSchema as b, zoneAnalyticsCapability as bt, EVENT_KIND_BY_CAP as c, parseProcStatus as ct, LabelAttributionSchema as d, plateGalleryCapability as dt, embeddingEncoderCapability as et, MACRO_LABELS as f, readDeviceStateFrom as ft, NC_SNOOZE_MAX_MINUTES as g, subKindsOf as gt, NC_DEFAULT_SNOOZE_MINUTES as h, sceneMonitorCapability as ht, DEFAULT_TIMELAPSE_PREVIEW_TEXT as i, isDetectionMacroClass as it, RECORDING_EXPORT_MAX_READ_BYTES as j, boolean as jt, OpsLogEntrySchema as k, _enum as kt, EVENT_PAD_MS as l, pickClusterStepModels as lt, NC_CONDITION_CATALOG as m, resolvePoolMemoryPolicy as mt, CLUSTER_MODEL_SCOPED_STEPS as n, faceGalleryCapability as nt, DETECTION_PIPELINE_CAP_NAME as o, kebabToCamel as ot, NC_ALARM_SYSTEM_EVENT_KINDS as p, readTimelapseGeneratedAt as pt, audioMetricsCapability as q, DEFAULT_EVENT_COLOR as r, hfModelUrl as rt, DeclaredDevices as s, notificationRulesCapability as st, BaseDevice as t, encodeVectorBase64 as tt, FULL_IMAGE_BBOX as u, pipelineAnalyticsCapability as ut, NcConditionDescriptorSchema as v, vectorDimFromBase64 as vt, NcSnoozeInputSchema as w, createEvent as wt, NcRuleSchema as x, errMsg as xt, NcRuleInputSchema as y, videoclipsCapability as yt, TimelapseRuleInputSchema as z, unknown as zt };
|