@camstack/addon-post-analysis 1.2.307 → 1.2.308
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/{clip-model-registry-C67UM_q_.js → clip-model-registry-BqrTKyUe.js} +346 -267
- package/dist/{clip-model-registry-C9Aw4qkh.mjs → clip-model-registry-FGOIz3PZ.mjs} +346 -267
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/_stub.js +1 -1
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-QE0Juzwb.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-61DKRi3y.mjs} +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-C-9GoNIB.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-DzNrV8y8.mjs → hostInit-BeNsqz7j.mjs} +1 -1
- package/dist/pipeline-analytics/index.js +625 -251
- package/dist/pipeline-analytics/index.mjs +625 -251
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-MwQBD526.mjs +0 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, $n as ruleDeviceCompatCapQueries, $t as TimelapseRuleInputSchema, A as EMBEDDING_REQUIREMENTS_FAILED, An as isDetectionMacroClass, Ar as ZodObject, At as NcTemplateVarDescriptorSchema, B as ListTrackRelationsInputSchema, Bn as memoizePinnedFfmpeg, Br as record, Bt as SCENE_DEFAULT_ANCHOR_THRESHOLD, C as DEFAULT_EVENT_COLOR, Cn as encodeVectorBase64, Cr as customAction, Ct as NcSnoozeInputSchema, D as DeclaredDevices, Dn as gifDeriveSpeed, Dr as nodePin, Dt as NcTaxonomySchema, E as DETECTION_PIPELINE_CAP_NAME, En as failureContributionCapability, Er as isDeviceScopedCap, Et as NcSystemEventKindSchema, F as EXPORT_DENSE_MAX_RANGES, Fn as isSystemDelivery, Fr as literal, Ft as RECORDING_SOURCE_CAMSTACK_ADDON, G as MAX_BIRTH_LATENCY_PROXY_MS, Gn as plateGalleryCapability, Gr as unknown, Gt as SCENE_DIVERGED, H as LockStateSchema, Hn as occupancyScope, Hr as string, Ht as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, I as FIRST_LEVEL_MACRO_CLASSES, In as isSystemEventSummaryRule, Ir as looseObject, It as RebuildObjectEmbeddingsRefusalSchema, J as MOTION_CLOSE_AFTER_MS, Jn as readTimelapseGeneratedAt, Jt as SetTrackPurityInputSchema, K as MAX_TRACK_PURITIES, Kn as readDeviceStateFrom, Kr as EventCategory, Kt as SCENE_RESET_RECAPTURES, L as FULL_IMAGE_BBOX, Ln as isVectorIndexDimConflict, Lr as number, Lt as RetrainStatusSchema, M as EVENT_DENSITY_BATCH_MAX, Mn as isKnownTemplateVar, Mr as array, Mt as OpsLogEntrySchema, N as EVENT_KIND_BY_CAP, Nn as isMediaOwnerType, Nr as boolean, O as DetectionSourceSchema, On as gifFromMp4Args, Ot as NcTemplatePreviewInputSchema, P as EVENT_OWNER_TYPES, Pn as isScheduleActive, Pr as discriminatedUnion, Pt as RECORDING_EXPORT_MAX_READ_BYTES, Q as NC_AUDIO_CONFIRM_HITS_DEFAULT, Qn as ruleBelongsToAlarm$1, Qt as TRACK_RELATIONS_DEFAULT_LIMIT, R as FailureCounters, Rn as kebabToCamel, Rr as object, Rt as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, S as CoverStateSchema, Sr as createEvent, St as NcScheduleSchema, T as DETECTION_MACRO_CLASSES, Tn as faceGalleryCapability, Tr as hydrateSchema, Tt as NcSnoozeSuppressedSchema, U as MAX_ARCHIVED_DEBUG_NOTES, Ur as tuple, Ut as SCENE_DEFAULT_QUIET_SECONDS, V as ListTrackRelationsResultSchema, Vn as notificationRulesCapability, Vr as strictObject, Vt as SCENE_DEFAULT_CHECK_INTERVAL_SEC, W as MAX_BIRTH_DECISION_RECORDS, Wn as pipelineAnalyticsCapability, Wr as union, Wt as SCENE_DEFAULT_UNCOVERED_POLICY, X as MotionTriggeredBySchema, Xn as resolveLocationMode, Xt as SetTrackRelationInputSchema, Y as MediaFileKindEnum, Yn as resolveClipSearchMinScore, Yt as SetTrackPurityResultSchema, Z as NC_ALARM_SYSTEM_EVENT_KINDS, Zt as TIMELAPSE_DENSE_FLOOR_SEC, _ as BaseDevice, _n as describeSystemEventFamilyProblem, _r as isSourceCap, _t as NcRuleInputSchema, a as CLIP_EMBEDDING_STEP_ID, an as TrackSideSchema, ar as subKindsOf, at as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, b as ClearTrackRelationInputSchema, bn as embeddingRefusalOf, br as BaseAddon, bt as NcRuleTargetSchema, c as resolveClusterModelPin, cn as alarmPanelCapability, cr as systemEventFilterApplies, ct as NC_SNOOZE_MAX_MINUTES, d as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, dn as audioModeOf, dr as templateVarsFor, dt as NC_TAXONOMY, en as TimelapseRulePatchSchema, er as ruleKindOf, et as NC_CLIP_POST_ROLL_DEFAULT_SEC, f as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, fn as buildEventKindDescriptor, fr as vectorDimFromBase64, ft as NC_TEMPLATE_VARS, g as BIRTH_DECISION_DEFAULT_LIMIT, gn as describeSystemEventDeliveryProblem, gr as evaluateSensorEdge, gt as NcConditionsSchema, h as ArchivedDebugNoteSchema, hn as deriveRecordingMode, hr as canonicalHash, ht as NcConditionDescriptorSchema, in as TrackRelationSchema, ir as storageOccupancyCapability, it as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, j as EMBEDDING_REQUIREMENTS_UNAVAILABLE, jn as isEventOwnerType, jr as _enum, jt as OPS_LOG_DEFAULT_LIMIT, k as EMBEDDING_MODEL_FAILED, kn as isAudioClassName, kr as sleep$1, kt as NcTemplatePreviewSchema, l as APPEARANCE_BIN_COUNT, ln as assertTimelapseCadences, lr as systemEventSummaryScheduleOf, lt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, m as AlarmArmModeSchema, mn as cosineSimilarity$1, mr as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, mt as NcAlarmSettingsPatchSchema, nn as TrackPuritySchema, nr as sensorRaisedOf, nt as NC_CLIP_RETENTION_MAX_SEC, o as FACE_EMBEDDING_STEP_ID, on as TrackSourceSchema, or as systemEventDeliveryProblems, ot as NC_DEFAULT_SNOOZE_MINUTES, p as AUDIO_MACRO_LABELS, pn as consumableLowPercentOf, pr as zoneAnalyticsCapability, pt as NcAlarmConfigSchema, q as MAX_TRACK_RELATIONS, qn as readMotionTriggeredBy, qt as SceneMonitorSchema, rn as TrackRelationKindSchema, rr as servedTemplateVars, rt as NC_CONDITION_CATALOG, s as readClusterModelPinStrict, sn as addonWidgetsSourceCapability, sr as systemEventFamilyProblems, st as NC_SENSOR_TRANSITION_KINDS, t as BUILTIN_CLIP_MODELS, tn as TimelapseRuleSchema, tr as sceneMonitorCapability, tt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, u as APPEARANCE_BLOCKS, un as audioMetricsCapability, ur as templateCarriesSummary, ut as NC_TANK_SYSTEM_EVENT_KINDS, v as BirthDecisionRecordSchema, vr as DeviceType, vt as NcRulePatchSchema, w as DEFAULT_TIMELAPSE_PREVIEW_TEXT, wn as evictionPolicyOfLocation, wr as defineCustomActions, wt as NcSnoozeSchema, x as ClearTrackRelationResultSchema, xr as CamProfileSchema, xt as NcRuleUpdateInputSchema, y as COCO_TO_MACRO, yr as errMsg, yt as NcRuleSchema, z as LabelAttributionSchema, zn as mayWriteToLocation, zr as partialRecord, zt as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS } from "../clip-model-registry-
|
|
1
|
+
import { $ as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, $n as ruleDeviceCompatCapQueries, $t as TimelapseRuleInputSchema, A as EMBEDDING_REQUIREMENTS_FAILED, An as isDetectionMacroClass, Ar as ZodObject, At as NcTemplateVarDescriptorSchema, B as ListTrackRelationsInputSchema, Bn as memoizePinnedFfmpeg, Br as record, Bt as SCENE_DEFAULT_ANCHOR_THRESHOLD, C as DEFAULT_EVENT_COLOR, Cn as encodeVectorBase64, Cr as customAction, Ct as NcSnoozeInputSchema, D as DeclaredDevices, Dn as gifDeriveSpeed, Dr as nodePin, Dt as NcTaxonomySchema, E as DETECTION_PIPELINE_CAP_NAME, En as failureContributionCapability, Er as isDeviceScopedCap, Et as NcSystemEventKindSchema, F as EXPORT_DENSE_MAX_RANGES, Fn as isSystemDelivery, Fr as literal, Ft as RECORDING_SOURCE_CAMSTACK_ADDON, G as MAX_BIRTH_LATENCY_PROXY_MS, Gn as plateGalleryCapability, Gr as unknown, Gt as SCENE_DIVERGED, H as LockStateSchema, Hn as occupancyScope, Hr as string, Ht as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, I as FIRST_LEVEL_MACRO_CLASSES, In as isSystemEventSummaryRule, Ir as looseObject, It as RebuildObjectEmbeddingsRefusalSchema, J as MOTION_CLOSE_AFTER_MS, Jn as readTimelapseGeneratedAt, Jt as SetTrackPurityInputSchema, K as MAX_TRACK_PURITIES, Kn as readDeviceStateFrom, Kr as EventCategory, Kt as SCENE_RESET_RECAPTURES, L as FULL_IMAGE_BBOX, Ln as isVectorIndexDimConflict, Lr as number, Lt as RetrainStatusSchema, M as EVENT_DENSITY_BATCH_MAX, Mn as isKnownTemplateVar, Mr as array, Mt as OpsLogEntrySchema, N as EVENT_KIND_BY_CAP, Nn as isMediaOwnerType, Nr as boolean, O as DetectionSourceSchema, On as gifFromMp4Args, Ot as NcTemplatePreviewInputSchema, P as EVENT_OWNER_TYPES, Pn as isScheduleActive, Pr as discriminatedUnion, Pt as RECORDING_EXPORT_MAX_READ_BYTES, Q as NC_AUDIO_CONFIRM_HITS_DEFAULT, Qn as ruleBelongsToAlarm$1, Qt as TRACK_RELATIONS_DEFAULT_LIMIT, R as FailureCounters, Rn as kebabToCamel, Rr as object, Rt as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, S as CoverStateSchema, Sr as createEvent, St as NcScheduleSchema, T as DETECTION_MACRO_CLASSES, Tn as faceGalleryCapability, Tr as hydrateSchema, Tt as NcSnoozeSuppressedSchema, U as MAX_ARCHIVED_DEBUG_NOTES, Ur as tuple, Ut as SCENE_DEFAULT_QUIET_SECONDS, V as ListTrackRelationsResultSchema, Vn as notificationRulesCapability, Vr as strictObject, Vt as SCENE_DEFAULT_CHECK_INTERVAL_SEC, W as MAX_BIRTH_DECISION_RECORDS, Wn as pipelineAnalyticsCapability, Wr as union, Wt as SCENE_DEFAULT_UNCOVERED_POLICY, X as MotionTriggeredBySchema, Xn as resolveLocationMode, Xt as SetTrackRelationInputSchema, Y as MediaFileKindEnum, Yn as resolveClipSearchMinScore, Yt as SetTrackPurityResultSchema, Z as NC_ALARM_SYSTEM_EVENT_KINDS, Zt as TIMELAPSE_DENSE_FLOOR_SEC, _ as BaseDevice, _n as describeSystemEventFamilyProblem, _r as isSourceCap, _t as NcRuleInputSchema, a as CLIP_EMBEDDING_STEP_ID, an as TrackSideSchema, ar as subKindsOf, at as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, b as ClearTrackRelationInputSchema, bn as embeddingRefusalOf, br as BaseAddon, bt as NcRuleTargetSchema, c as resolveClusterModelPin, cn as alarmPanelCapability, cr as systemEventFilterApplies, ct as NC_SNOOZE_MAX_MINUTES, d as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, dn as audioModeOf, dr as templateVarsFor, dt as NC_TAXONOMY, en as TimelapseRulePatchSchema, er as ruleKindOf, et as NC_CLIP_POST_ROLL_DEFAULT_SEC, f as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, fn as buildEventKindDescriptor, fr as vectorDimFromBase64, ft as NC_TEMPLATE_VARS, g as BIRTH_DECISION_DEFAULT_LIMIT, gn as describeSystemEventDeliveryProblem, gr as evaluateSensorEdge, gt as NcConditionsSchema, h as ArchivedDebugNoteSchema, hn as deriveRecordingMode, hr as canonicalHash, ht as NcConditionDescriptorSchema, in as TrackRelationSchema, ir as storageOccupancyCapability, it as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, j as EMBEDDING_REQUIREMENTS_UNAVAILABLE, jn as isEventOwnerType, jr as _enum, jt as OPS_LOG_DEFAULT_LIMIT, k as EMBEDDING_MODEL_FAILED, kn as isAudioClassName, kr as sleep$1, kt as NcTemplatePreviewSchema, l as APPEARANCE_BIN_COUNT, ln as assertTimelapseCadences, lr as systemEventSummaryScheduleOf, lt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, m as AlarmArmModeSchema, mn as cosineSimilarity$1, mr as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, mt as NcAlarmSettingsPatchSchema, nn as TrackPuritySchema, nr as sensorRaisedOf, nt as NC_CLIP_RETENTION_MAX_SEC, o as FACE_EMBEDDING_STEP_ID, on as TrackSourceSchema, or as systemEventDeliveryProblems, ot as NC_DEFAULT_SNOOZE_MINUTES, p as AUDIO_MACRO_LABELS, pn as consumableLowPercentOf, pr as zoneAnalyticsCapability, pt as NcAlarmConfigSchema, q as MAX_TRACK_RELATIONS, qn as readMotionTriggeredBy, qt as SceneMonitorSchema, rn as TrackRelationKindSchema, rr as servedTemplateVars, rt as NC_CONDITION_CATALOG, s as readClusterModelPinStrict, sn as addonWidgetsSourceCapability, sr as systemEventFamilyProblems, st as NC_SENSOR_TRANSITION_KINDS, t as BUILTIN_CLIP_MODELS, tn as TimelapseRuleSchema, tr as sceneMonitorCapability, tt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, u as APPEARANCE_BLOCKS, un as audioMetricsCapability, ur as templateCarriesSummary, ut as NC_TANK_SYSTEM_EVENT_KINDS, v as BirthDecisionRecordSchema, vr as DeviceType, vt as NcRulePatchSchema, w as DEFAULT_TIMELAPSE_PREVIEW_TEXT, wn as evictionPolicyOfLocation, wr as defineCustomActions, wt as NcSnoozeSchema, x as ClearTrackRelationResultSchema, xr as CamProfileSchema, xt as NcRuleUpdateInputSchema, y as COCO_TO_MACRO, yr as errMsg, yt as NcRuleSchema, z as LabelAttributionSchema, zn as mayWriteToLocation, zr as partialRecord, zt as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS } from "../clip-model-registry-FGOIz3PZ.mjs";
|
|
2
2
|
import { t as __exportAll } from "../embedding-encoder/index.mjs";
|
|
3
3
|
import * as fs$1 from "node:fs";
|
|
4
4
|
import { createWriteStream, promises } from "node:fs";
|
|
@@ -42578,6 +42578,280 @@ function parseDebugDeviceIds(url) {
|
|
|
42578
42578
|
return out;
|
|
42579
42579
|
}
|
|
42580
42580
|
//#endregion
|
|
42581
|
+
//#region src/pipeline-analytics/store/tracking-tape-index-store.ts
|
|
42582
|
+
/**
|
|
42583
|
+
* @durable class=ledger owner=pipeline-analytics
|
|
42584
|
+
* write="one row per PROMOTED tracking-tape window (`debug.tape.promote`);
|
|
42585
|
+
* updated when the operator marks it reviewed or releases its pins;
|
|
42586
|
+
* deleted together with its file by `debug.tape.delete`."
|
|
42587
|
+
* retention="NOT an age clock and NOT track retention — a promoted window is
|
|
42588
|
+
* history being labelled (D681). Bounded by the promotion budget
|
|
42589
|
+
* (MAX_PROMOTED_TAPES = 60, 1 GiB): a promotion beyond it is REFUSED,
|
|
42590
|
+
* never satisfied by evicting another row."
|
|
42591
|
+
*/
|
|
42592
|
+
var TRACKING_TAPES_COLLECTION = "pipeline-analytics:tracking-tapes";
|
|
42593
|
+
var TRACKING_TAPES_COLUMNS = [
|
|
42594
|
+
{
|
|
42595
|
+
name: "id",
|
|
42596
|
+
type: "TEXT",
|
|
42597
|
+
primaryKey: true,
|
|
42598
|
+
notNull: true
|
|
42599
|
+
},
|
|
42600
|
+
{
|
|
42601
|
+
name: "deviceId",
|
|
42602
|
+
type: "INTEGER",
|
|
42603
|
+
notNull: true
|
|
42604
|
+
},
|
|
42605
|
+
{
|
|
42606
|
+
name: "scenario",
|
|
42607
|
+
type: "TEXT",
|
|
42608
|
+
notNull: true
|
|
42609
|
+
},
|
|
42610
|
+
{
|
|
42611
|
+
name: "note",
|
|
42612
|
+
type: "TEXT"
|
|
42613
|
+
},
|
|
42614
|
+
{
|
|
42615
|
+
name: "lighting",
|
|
42616
|
+
type: "TEXT",
|
|
42617
|
+
notNull: true
|
|
42618
|
+
},
|
|
42619
|
+
{
|
|
42620
|
+
name: "fromMs",
|
|
42621
|
+
type: "INTEGER",
|
|
42622
|
+
notNull: true
|
|
42623
|
+
},
|
|
42624
|
+
{
|
|
42625
|
+
name: "toMs",
|
|
42626
|
+
type: "INTEGER",
|
|
42627
|
+
notNull: true
|
|
42628
|
+
},
|
|
42629
|
+
{
|
|
42630
|
+
name: "state",
|
|
42631
|
+
type: "TEXT",
|
|
42632
|
+
notNull: true
|
|
42633
|
+
},
|
|
42634
|
+
{
|
|
42635
|
+
name: "frames",
|
|
42636
|
+
type: "INTEGER",
|
|
42637
|
+
notNull: true
|
|
42638
|
+
},
|
|
42639
|
+
{
|
|
42640
|
+
name: "skips",
|
|
42641
|
+
type: "INTEGER",
|
|
42642
|
+
notNull: true
|
|
42643
|
+
},
|
|
42644
|
+
{
|
|
42645
|
+
name: "gaps",
|
|
42646
|
+
type: "INTEGER",
|
|
42647
|
+
notNull: true
|
|
42648
|
+
},
|
|
42649
|
+
{
|
|
42650
|
+
name: "bytes",
|
|
42651
|
+
type: "INTEGER",
|
|
42652
|
+
notNull: true
|
|
42653
|
+
},
|
|
42654
|
+
{
|
|
42655
|
+
name: "reviewed",
|
|
42656
|
+
type: "BOOLEAN",
|
|
42657
|
+
notNull: true
|
|
42658
|
+
},
|
|
42659
|
+
{
|
|
42660
|
+
name: "trackIds",
|
|
42661
|
+
type: "TEXT",
|
|
42662
|
+
notNull: true
|
|
42663
|
+
},
|
|
42664
|
+
{
|
|
42665
|
+
name: "createdAt",
|
|
42666
|
+
type: "INTEGER",
|
|
42667
|
+
notNull: true
|
|
42668
|
+
},
|
|
42669
|
+
{
|
|
42670
|
+
name: "releasedAt",
|
|
42671
|
+
type: "INTEGER"
|
|
42672
|
+
},
|
|
42673
|
+
{
|
|
42674
|
+
name: "pinsSettled",
|
|
42675
|
+
type: "BOOLEAN",
|
|
42676
|
+
notNull: true
|
|
42677
|
+
}
|
|
42678
|
+
];
|
|
42679
|
+
var TrackingTapeRowSchema = object({
|
|
42680
|
+
id: string(),
|
|
42681
|
+
deviceId: number().int(),
|
|
42682
|
+
scenario: string(),
|
|
42683
|
+
note: string().nullable(),
|
|
42684
|
+
lighting: TapeLightingSchema,
|
|
42685
|
+
fromMs: number().int(),
|
|
42686
|
+
toMs: number().int(),
|
|
42687
|
+
state: _enum(["complete", "incomplete"]),
|
|
42688
|
+
frames: number().int(),
|
|
42689
|
+
skips: number().int(),
|
|
42690
|
+
gaps: number().int(),
|
|
42691
|
+
bytes: number().int(),
|
|
42692
|
+
reviewed: boolean(),
|
|
42693
|
+
trackIds: array(string()),
|
|
42694
|
+
createdAt: number().int(),
|
|
42695
|
+
releasedAt: number().int().nullable(),
|
|
42696
|
+
pinsSettled: boolean()
|
|
42697
|
+
});
|
|
42698
|
+
var TrackIdsSchema = array(string());
|
|
42699
|
+
/**
|
|
42700
|
+
* True when the SQLite settings backend would hand `text` back DECODED: it
|
|
42701
|
+
* parses any TEXT that starts with `[` or `{` and is valid JSON
|
|
42702
|
+
* (`decodeColumnValue` decodes by content, not by declared type). Free text
|
|
42703
|
+
* like that cannot round-trip through a TEXT column (follow-up 617, review M2).
|
|
42704
|
+
*/
|
|
42705
|
+
function decodesAsJson(text) {
|
|
42706
|
+
if (!(text.startsWith("[") || text.startsWith("{"))) return false;
|
|
42707
|
+
try {
|
|
42708
|
+
JSON.parse(text);
|
|
42709
|
+
return true;
|
|
42710
|
+
} catch {
|
|
42711
|
+
return false;
|
|
42712
|
+
}
|
|
42713
|
+
}
|
|
42714
|
+
/**
|
|
42715
|
+
* Free text (`scenario`, `note`) as the column hands it back: a value the
|
|
42716
|
+
* backend decoded is re-encoded, so a row written before `debug.tape.promote`
|
|
42717
|
+
* refused such text never vanishes (its whitespace may differ). Anything else
|
|
42718
|
+
* goes to the schema as it came.
|
|
42719
|
+
*/
|
|
42720
|
+
function freeText(raw) {
|
|
42721
|
+
return raw !== null && typeof raw === "object" ? JSON.stringify(raw) : raw;
|
|
42722
|
+
}
|
|
42723
|
+
/**
|
|
42724
|
+
* `trackIds` as the column hands it back. The SQLite backend decodes a TEXT
|
|
42725
|
+
* that starts with `[` on read (`decodeColumnValue`), so the store sees the
|
|
42726
|
+
* ARRAY it wrote; a string is parsed here only for a backend (or an old row)
|
|
42727
|
+
* that hands the text back as written. `JSON.parse(String(array))` threw on the
|
|
42728
|
+
* decoded array and every promoted row was skipped as malformed (follow-up 617).
|
|
42729
|
+
* `null` = unreadable, absent included (the column is NOT NULL, so absence is
|
|
42730
|
+
* corruption) — the row is reported, never repaired.
|
|
42731
|
+
*/
|
|
42732
|
+
function decodeTrackIds(raw) {
|
|
42733
|
+
if (raw === void 0 || raw === null) return null;
|
|
42734
|
+
if (typeof raw !== "string") return raw;
|
|
42735
|
+
try {
|
|
42736
|
+
return JSON.parse(raw);
|
|
42737
|
+
} catch {
|
|
42738
|
+
return null;
|
|
42739
|
+
}
|
|
42740
|
+
}
|
|
42741
|
+
var TrackingTapeIndexStore = class {
|
|
42742
|
+
store;
|
|
42743
|
+
logger;
|
|
42744
|
+
constructor(deps) {
|
|
42745
|
+
this.store = deps.store;
|
|
42746
|
+
this.logger = deps.logger;
|
|
42747
|
+
}
|
|
42748
|
+
static async declare(store) {
|
|
42749
|
+
await store.declareCollection.mutate({
|
|
42750
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42751
|
+
columns: [...TRACKING_TAPES_COLUMNS],
|
|
42752
|
+
indexes: [{
|
|
42753
|
+
name: "idx_trackingtapes_device_created",
|
|
42754
|
+
columns: ["deviceId", "createdAt"]
|
|
42755
|
+
}]
|
|
42756
|
+
});
|
|
42757
|
+
}
|
|
42758
|
+
async insert(row) {
|
|
42759
|
+
const { id, trackIds, ...rest } = TrackingTapeRowSchema.parse(row);
|
|
42760
|
+
await this.store.insert.mutate({
|
|
42761
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42762
|
+
record: {
|
|
42763
|
+
id,
|
|
42764
|
+
data: {
|
|
42765
|
+
...rest,
|
|
42766
|
+
trackIds: JSON.stringify(trackIds)
|
|
42767
|
+
}
|
|
42768
|
+
}
|
|
42769
|
+
});
|
|
42770
|
+
}
|
|
42771
|
+
async get(id) {
|
|
42772
|
+
const first = (await this.store.query.query({
|
|
42773
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42774
|
+
filter: {
|
|
42775
|
+
where: { id },
|
|
42776
|
+
limit: 1
|
|
42777
|
+
}
|
|
42778
|
+
}))[0];
|
|
42779
|
+
return first === void 0 ? null : this.parse(first.id, first.data);
|
|
42780
|
+
}
|
|
42781
|
+
async list(deviceId) {
|
|
42782
|
+
const rows = await this.store.query.query({
|
|
42783
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42784
|
+
filter: {
|
|
42785
|
+
...deviceId !== void 0 ? { where: { deviceId } } : {},
|
|
42786
|
+
orderBy: {
|
|
42787
|
+
field: "createdAt",
|
|
42788
|
+
direction: "desc"
|
|
42789
|
+
},
|
|
42790
|
+
limit: 1e3
|
|
42791
|
+
}
|
|
42792
|
+
});
|
|
42793
|
+
const out = [];
|
|
42794
|
+
for (const r of rows) {
|
|
42795
|
+
const parsed = this.parse(r.id, r.data);
|
|
42796
|
+
if (parsed !== null) out.push(parsed);
|
|
42797
|
+
}
|
|
42798
|
+
return out;
|
|
42799
|
+
}
|
|
42800
|
+
async setReviewed(id, reviewed) {
|
|
42801
|
+
await this.store.update.mutate({
|
|
42802
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42803
|
+
id,
|
|
42804
|
+
data: { reviewed }
|
|
42805
|
+
});
|
|
42806
|
+
}
|
|
42807
|
+
/** Release AND unsettle in one row write: the unpins the release implies
|
|
42808
|
+
* are owed from this moment, whether or not the caller lives to make them. */
|
|
42809
|
+
async setReleased(id, atMs) {
|
|
42810
|
+
await this.store.update.mutate({
|
|
42811
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42812
|
+
id,
|
|
42813
|
+
data: {
|
|
42814
|
+
releasedAt: atMs,
|
|
42815
|
+
pinsSettled: false
|
|
42816
|
+
}
|
|
42817
|
+
});
|
|
42818
|
+
}
|
|
42819
|
+
async setPinsSettled(id, settled) {
|
|
42820
|
+
await this.store.update.mutate({
|
|
42821
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42822
|
+
id,
|
|
42823
|
+
data: { pinsSettled: settled }
|
|
42824
|
+
});
|
|
42825
|
+
}
|
|
42826
|
+
async remove(id) {
|
|
42827
|
+
await this.store.delete.mutate({
|
|
42828
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42829
|
+
key: id
|
|
42830
|
+
});
|
|
42831
|
+
}
|
|
42832
|
+
parse(id, data) {
|
|
42833
|
+
const ids = TrackIdsSchema.safeParse(decodeTrackIds(data["trackIds"]));
|
|
42834
|
+
const parsed = TrackingTapeRowSchema.safeParse({
|
|
42835
|
+
id,
|
|
42836
|
+
...data,
|
|
42837
|
+
scenario: freeText(data["scenario"]),
|
|
42838
|
+
note: freeText(data["note"] ?? null),
|
|
42839
|
+
releasedAt: data["releasedAt"] ?? null,
|
|
42840
|
+
trackIds: ids.success ? ids.data : null
|
|
42841
|
+
});
|
|
42842
|
+
if (parsed.success) return parsed.data;
|
|
42843
|
+
this.logger.warn("tracking tape index: skipped a malformed row", {
|
|
42844
|
+
meta: {
|
|
42845
|
+
id,
|
|
42846
|
+
issues: parsed.error.issues.map((i) => i.path.join(".")),
|
|
42847
|
+
trackIdsType: typeof data["trackIds"]
|
|
42848
|
+
},
|
|
42849
|
+
...typeof data["deviceId"] === "number" ? { tags: { deviceId: data["deviceId"] } } : {}
|
|
42850
|
+
});
|
|
42851
|
+
return null;
|
|
42852
|
+
}
|
|
42853
|
+
};
|
|
42854
|
+
//#endregion
|
|
42581
42855
|
//#region src/pipeline-analytics/debug/tape-actions.ts
|
|
42582
42856
|
/**
|
|
42583
42857
|
* `debug.tape.*` — the tracking-tape surface (D681, spec §3.3). Admin,
|
|
@@ -42608,12 +42882,19 @@ var TapeStatusRowSchema = object({
|
|
|
42608
42882
|
var TapeStatusInputSchema = object({ deviceIds: array(number().int()).optional() });
|
|
42609
42883
|
var TapeStatusOutputSchema = object({ cameras: array(TapeStatusRowSchema).readonly() });
|
|
42610
42884
|
var TapeLightingInputSchema = _enum(["day", "ir"]);
|
|
42885
|
+
/**
|
|
42886
|
+
* Free text the settings store would hand back decoded is refused by name
|
|
42887
|
+
* (follow-up 617, review M2): whole JSON array/object text in a TEXT column
|
|
42888
|
+
* comes back as an array or object, and the index could not read the row.
|
|
42889
|
+
*/
|
|
42890
|
+
var NOT_JSON_TEXT = "must not be JSON array/object text — the settings store would hand it back decoded";
|
|
42891
|
+
var notJsonText = (s) => !decodesAsJson(s);
|
|
42611
42892
|
var PromoteInputSchema = object({
|
|
42612
42893
|
deviceId: number().int().positive(),
|
|
42613
42894
|
fromMs: number().int(),
|
|
42614
42895
|
toMs: number().int(),
|
|
42615
|
-
scenario: string(),
|
|
42616
|
-
note: string().max(500).optional(),
|
|
42896
|
+
scenario: string().refine(notJsonText, { message: NOT_JSON_TEXT }),
|
|
42897
|
+
note: string().max(500).refine(notJsonText, { message: NOT_JSON_TEXT }).optional(),
|
|
42617
42898
|
lighting: TapeLightingInputSchema.optional()
|
|
42618
42899
|
});
|
|
42619
42900
|
var PromoteOutputSchema = discriminatedUnion("ok", [object({
|
|
@@ -51074,6 +51355,17 @@ function pairRiders(detections) {
|
|
|
51074
51355
|
* (D438) no frame did, and a newcomer on the stale prediction took the id.
|
|
51075
51356
|
*/
|
|
51076
51357
|
var MAX_PREDICTION_MS = 1e3;
|
|
51358
|
+
/**
|
|
51359
|
+
* A frame more than `maxMissedMs` behind the latest is a CLOCK STEP only as
|
|
51360
|
+
* the K-th such frame in a row, each in order with the one before (follow-up
|
|
51361
|
+
* 617, fix round 3; D49: a read that would destroy work needs another to
|
|
51362
|
+
* agree). A step ends every track on the camera; one stray timestamp — a
|
|
51363
|
+
* backlog spike 4.5 s late — or two runner clocks delivering interleaved
|
|
51364
|
+
* (a camera migrating between runners) must not. Three is the least that a
|
|
51365
|
+
* single late frame plus an interleaved partner cannot reach by chance; the
|
|
51366
|
+
* cost of a real step is K−1 dropped frames (~260 ms at 7.7 fps).
|
|
51367
|
+
*/
|
|
51368
|
+
var CLOCK_STEP_CONFIRM_FRAMES = 3;
|
|
51077
51369
|
/** Confident boxes kept on a tracklet's path (the old tracker's bound). */
|
|
51078
51370
|
var MAX_PATH_LENGTH = 300;
|
|
51079
51371
|
/** Swap test: crossed pairs cheaper than this over the chosen pairs are doubt. */
|
|
@@ -51879,6 +52171,35 @@ function linkReach(from, gapMs) {
|
|
|
51879
52171
|
return diag * Math.min(LINK_REACH_MAX_DIAGONALS, Math.max(LINK_REACH_MIN_DIAGONALS, LINK_REACH_DIAGONALS_PER_SEC * gapMs / 1e3));
|
|
51880
52172
|
}
|
|
51881
52173
|
var arcKey = (from, to) => `${from}\u0000${to}`;
|
|
52174
|
+
/**
|
|
52175
|
+
* The rejections that mean "geometry or appearance said no to a plausible
|
|
52176
|
+
* continuation" of a confirmed predecessor — a track the operator sees break
|
|
52177
|
+
* (follow-up 617, F5). Every one of them is past `hardRejection`, so the
|
|
52178
|
+
* predecessor is confirmed. NOT here (fix round 1): `unconfirmed`;
|
|
52179
|
+
* `has-successor` (continued elsewhere); `concurrent` and `identity-conflict`
|
|
52180
|
+
* (two subjects — the normal case, and the most frequent); `dropped` (an
|
|
52181
|
+
* operator delete or a refused chain).
|
|
52182
|
+
*/
|
|
52183
|
+
var BREAK_REJECTIONS = new Set([
|
|
52184
|
+
"reach",
|
|
52185
|
+
"area",
|
|
52186
|
+
"appearance",
|
|
52187
|
+
"contested",
|
|
52188
|
+
"cost"
|
|
52189
|
+
]);
|
|
52190
|
+
/** The confirmed predecessors whose link a decision rejected as a break (F5). */
|
|
52191
|
+
function confirmedPredecessorRejections(candidates) {
|
|
52192
|
+
const out = [];
|
|
52193
|
+
for (const c of candidates ?? []) {
|
|
52194
|
+
if (c.rejected === void 0 || !BREAK_REJECTIONS.has(c.rejected)) continue;
|
|
52195
|
+
out.push({
|
|
52196
|
+
from: c.from,
|
|
52197
|
+
rejected: c.rejected,
|
|
52198
|
+
gapMs: c.gapMs
|
|
52199
|
+
});
|
|
52200
|
+
}
|
|
52201
|
+
return out;
|
|
52202
|
+
}
|
|
51882
52203
|
function arcFacts(a) {
|
|
51883
52204
|
return {
|
|
51884
52205
|
from: a.from.id,
|
|
@@ -51956,6 +52277,26 @@ var DeferredLinker = class {
|
|
|
51956
52277
|
if (seen === void 0) this.names.set(p.id, new Set([p.identity]));
|
|
51957
52278
|
else seen.add(p.identity);
|
|
51958
52279
|
}
|
|
52280
|
+
/**
|
|
52281
|
+
* A clock step (follow-up 617, fix round 2): every piece still undecided is
|
|
52282
|
+
* decided `new`, so nothing that existed before the step can be absorbed
|
|
52283
|
+
* across it — whatever was ready was committed just before. The facade
|
|
52284
|
+
* rebases its clock past `LINK_MAX_GAP_MS`, so no later piece can continue
|
|
52285
|
+
* one of these either. An extra id, never a mix-up.
|
|
52286
|
+
*/
|
|
52287
|
+
closeUndecided(now, pieces) {
|
|
52288
|
+
for (const p of pieces) this.accept(p, now);
|
|
52289
|
+
for (const p of this.pieces.values()) {
|
|
52290
|
+
if (this.outcomes.has(p.id)) continue;
|
|
52291
|
+
this.decide(p.id, "new");
|
|
52292
|
+
this.observer?.({
|
|
52293
|
+
t: now,
|
|
52294
|
+
kind: "new",
|
|
52295
|
+
to: p.id,
|
|
52296
|
+
reason: "clock-step"
|
|
52297
|
+
});
|
|
52298
|
+
}
|
|
52299
|
+
}
|
|
51959
52300
|
isTailFinal(id, now, isLive) {
|
|
51960
52301
|
const root = this.rootOf(id);
|
|
51961
52302
|
if (this.pieces.has(root) && !this.outcomes.has(root)) return false;
|
|
@@ -52706,7 +53047,15 @@ var Tracklet = class {
|
|
|
52706
53047
|
h: this.assocBox.h
|
|
52707
53048
|
};
|
|
52708
53049
|
}
|
|
53050
|
+
/**
|
|
53051
|
+
* A confident sighting. One OLDER than the last (`t < lastSeenAt` — ~1 % of
|
|
53052
|
+
* frames reach the tracker out of capture order, up to 1.2 s back) is
|
|
53053
|
+
* `stale`: it changes nothing. A rewound tracklet would be measured from a
|
|
53054
|
+
* box its subject left a second ago, and L2 refused a link by reach on
|
|
53055
|
+
* exactly that (follow-up 617, F1). The caller reports it.
|
|
53056
|
+
*/
|
|
52709
53057
|
observeConfident(det, t, faceBearing) {
|
|
53058
|
+
if (t < this.lastSeenAt) return "stale";
|
|
52710
53059
|
const dt = t - this.lastSeenAt;
|
|
52711
53060
|
if (dt > 0) {
|
|
52712
53061
|
const from = centreOf(this.lastBox);
|
|
@@ -52718,6 +53067,7 @@ var Tracklet = class {
|
|
|
52718
53067
|
this.emitIntervalMs = dt;
|
|
52719
53068
|
}
|
|
52720
53069
|
this.recordConfident(det, t, faceBearing);
|
|
53070
|
+
return "recorded";
|
|
52721
53071
|
}
|
|
52722
53072
|
observeLowScore(box, t) {
|
|
52723
53073
|
this.assocBox = box;
|
|
@@ -52819,6 +53169,15 @@ var TrackletTracker = class {
|
|
|
52819
53169
|
demoteSilent(t) {
|
|
52820
53170
|
for (const tr of this.live.values()) if (tr.mode === "active" && t - tr.lastSeenAt > MAX_PREDICTION_MS) tr.mode = "coasting";
|
|
52821
53171
|
}
|
|
53172
|
+
/** Ends every live tracklet at its own last sighting (a clock step); the ids it ended. */
|
|
53173
|
+
endAll(reason) {
|
|
53174
|
+
const ended = [];
|
|
53175
|
+
for (const tr of [...this.live.values()]) {
|
|
53176
|
+
ended.push(tr.id);
|
|
53177
|
+
this.finish(tr, tr.lastSeenAt, reason);
|
|
53178
|
+
}
|
|
53179
|
+
return ended;
|
|
53180
|
+
}
|
|
52822
53181
|
/** Silence: end what the coast budget no longer covers. */
|
|
52823
53182
|
expire(now) {
|
|
52824
53183
|
for (const tr of [...this.live.values()]) if (now - tr.lastSeenAt > this.config.maxMissedMs) this.finish(tr, tr.lastSeenAt, "missed");
|
|
@@ -52909,12 +53268,12 @@ var TrackletTracker = class {
|
|
|
52909
53268
|
const d = frame.detections[pair.detection];
|
|
52910
53269
|
if (tr === void 0 || d === void 0) return;
|
|
52911
53270
|
frame.used.add(pair.detection);
|
|
53271
|
+
if (tr.observeConfident(d, frame.t, frame.ctx.faceBearing?.has(d.bbox) === true) === "stale") return;
|
|
52912
53272
|
tr.mode = "active";
|
|
52913
53273
|
if (d.class !== tr.klass) this.refuse({
|
|
52914
53274
|
reason: "cross-class-absorbed",
|
|
52915
53275
|
against: tr
|
|
52916
53276
|
}, d);
|
|
52917
|
-
tr.observeConfident(d, frame.t, frame.ctx.faceBearing?.has(d.bbox) === true);
|
|
52918
53277
|
if (pair.contested) {
|
|
52919
53278
|
tr.contestedHits += 1;
|
|
52920
53279
|
tr.contestedSince ??= frame.t;
|
|
@@ -53103,27 +53462,151 @@ var TrackerV2 = class {
|
|
|
53103
53462
|
l1;
|
|
53104
53463
|
l2;
|
|
53105
53464
|
pending = [];
|
|
53465
|
+
/**
|
|
53466
|
+
* Internal time = the caller's frame time + `offset`. Zero until a clock
|
|
53467
|
+
* step; each step moves it so the internal clock never goes back and
|
|
53468
|
+
* resumes past `LINK_MAX_GAP_MS` of silence (fix round 2, C1). L1, L2, their
|
|
53469
|
+
* facts and prunes run on internal time; fusions and `frameClock()` are
|
|
53470
|
+
* handed back in the caller's clock.
|
|
53471
|
+
*/
|
|
53472
|
+
offset = 0;
|
|
53106
53473
|
lastT = 0;
|
|
53474
|
+
/** The latest FRAME time taken (internal) — never the sweep's extrapolated `now`. */
|
|
53475
|
+
lastFrameT = Number.NEGATIVE_INFINITY;
|
|
53476
|
+
observers;
|
|
53477
|
+
/** Caller times of the consecutive frames past the stale bound so far — the
|
|
53478
|
+
* run a clock step needs `CLOCK_STEP_CONFIRM_FRAMES` of (fix round 3). */
|
|
53479
|
+
stepRun = [];
|
|
53107
53480
|
constructor(config, deps) {
|
|
53108
53481
|
this.config = config;
|
|
53109
|
-
this.
|
|
53482
|
+
this.observers = deps.observers ?? {};
|
|
53483
|
+
const out = this.observers;
|
|
53484
|
+
const internal = {
|
|
53485
|
+
...out.refusal !== void 0 ? { refusal: out.refusal } : {},
|
|
53486
|
+
ended: (f) => out.ended?.({
|
|
53487
|
+
...f,
|
|
53488
|
+
at: f.at - this.offset
|
|
53489
|
+
}),
|
|
53490
|
+
split: (f) => out.split?.({
|
|
53491
|
+
...f,
|
|
53492
|
+
t: f.t - this.offset
|
|
53493
|
+
})
|
|
53494
|
+
};
|
|
53495
|
+
this.l1 = new TrackletTracker(config, deps.mintTrackId, internal);
|
|
53110
53496
|
this.l2 = new DeferredLinker({
|
|
53111
53497
|
maxMissedMs: config.maxMissedMs,
|
|
53112
53498
|
appearanceResolvesAmbiguity: config.appearanceResolvesAmbiguity
|
|
53113
|
-
},
|
|
53499
|
+
}, (f) => out.link?.({
|
|
53500
|
+
...f,
|
|
53501
|
+
t: f.t - this.offset
|
|
53502
|
+
}));
|
|
53114
53503
|
}
|
|
53115
|
-
update(detections,
|
|
53504
|
+
update(detections, frameT, ctx) {
|
|
53505
|
+
const order = this.classifyFrame(frameT);
|
|
53506
|
+
if (order === "out-of-order") return this.drop(frameT, detections.length);
|
|
53507
|
+
let t = frameT + this.offset;
|
|
53508
|
+
if (order === "clock-step") t = this.clockStep(frameT, this.lastFrameT - t);
|
|
53509
|
+
this.stepRun = [];
|
|
53510
|
+
this.lastFrameT = t;
|
|
53116
53511
|
this.lastT = Math.max(this.lastT, t);
|
|
53117
53512
|
const step = this.l1.step(detections, t, ctx);
|
|
53118
53513
|
this.link(this.lastT);
|
|
53119
53514
|
return step.emissions.map((e) => this.emit(e, t));
|
|
53120
53515
|
}
|
|
53121
53516
|
/**
|
|
53517
|
+
* A frame stamped before the latest one already taken (follow-up 617, F1;
|
|
53518
|
+
* ~1 % of frames, up to 1.2 s back). It is decided ONCE, for the whole
|
|
53519
|
+
* frame (fix round 1, H1): matched against the tracklets' NEWEST boxes, a
|
|
53520
|
+
* stale box can land on another subject — a walker's old box on the walker
|
|
53521
|
+
* behind — and be emitted under that id. So nothing binds, spawns, splits or
|
|
53522
|
+
* is demoted on it; the confirmed tracklets are emitted as on a frame that
|
|
53523
|
+
* matched nothing (no sighting), and one fact says the frame was dropped.
|
|
53524
|
+
*/
|
|
53525
|
+
/**
|
|
53526
|
+
* How `update` will take a frame at `frameT` — without taking it. The
|
|
53527
|
+
* processor asks first (fix round 3, MEDIUM-2), so a dropped frame never
|
|
53528
|
+
* reaches the stationary gate, the zones or the event path.
|
|
53529
|
+
* - `in-order`: not behind the latest frame taken;
|
|
53530
|
+
* - `out-of-order`: behind it — within `maxMissedMs` (disorder, ≤ 1.2 s
|
|
53531
|
+
* measured), or further back but not yet the `CLOCK_STEP_CONFIRM_FRAMES`-th
|
|
53532
|
+
* such frame in a row;
|
|
53533
|
+
* - `clock-step`: the K-th consecutive frame past the bound, each in order
|
|
53534
|
+
* with the one before (within `maxMissedMs`).
|
|
53535
|
+
*/
|
|
53536
|
+
classifyFrame(frameT) {
|
|
53537
|
+
const behindMs = this.lastFrameT - (frameT + this.offset);
|
|
53538
|
+
if (!(behindMs > 0)) return "in-order";
|
|
53539
|
+
if (behindMs <= this.config.maxMissedMs) return "out-of-order";
|
|
53540
|
+
return this.runLength(frameT) >= CLOCK_STEP_CONFIRM_FRAMES ? "clock-step" : "out-of-order";
|
|
53541
|
+
}
|
|
53542
|
+
/** The past-bound run this frame would make, itself included. */
|
|
53543
|
+
runLength(frameT) {
|
|
53544
|
+
const prev = this.stepRun.at(-1);
|
|
53545
|
+
return (prev !== void 0 && frameT >= prev && frameT - prev <= this.config.maxMissedMs ? this.stepRun.length : 0) + 1;
|
|
53546
|
+
}
|
|
53547
|
+
/**
|
|
53548
|
+
* Drops a frame `classifyFrame` called `out-of-order`. A frame past the
|
|
53549
|
+
* bound extends (or restarts) the run a clock step needs; any other breaks
|
|
53550
|
+
* it. One fact per frame.
|
|
53551
|
+
*/
|
|
53552
|
+
drop(frameT, detections) {
|
|
53553
|
+
const behindMs = this.lastFrameT - (frameT + this.offset);
|
|
53554
|
+
let pendingClockStep = 0;
|
|
53555
|
+
if (behindMs > this.config.maxMissedMs) {
|
|
53556
|
+
pendingClockStep = this.runLength(frameT);
|
|
53557
|
+
this.stepRun = pendingClockStep === 1 ? [frameT] : [...this.stepRun, frameT];
|
|
53558
|
+
} else this.stepRun = [];
|
|
53559
|
+
this.observers.outOfOrder?.({
|
|
53560
|
+
t: frameT,
|
|
53561
|
+
lastFrameT: this.frameClock(),
|
|
53562
|
+
behindMs,
|
|
53563
|
+
detections,
|
|
53564
|
+
pendingClockStep
|
|
53565
|
+
});
|
|
53566
|
+
return this.l1.liveTracklets().filter((tr) => tr.confirmed).map((tracklet) => this.emit({
|
|
53567
|
+
tracklet,
|
|
53568
|
+
detection: void 0,
|
|
53569
|
+
matched: false
|
|
53570
|
+
}, this.lastFrameT));
|
|
53571
|
+
}
|
|
53572
|
+
/**
|
|
53573
|
+
* The frame clock stepped back further than `maxMissedMs` (fix round 2, C1):
|
|
53574
|
+
* not disorder — an NTP correction, or a camera moved to a runner whose clock
|
|
53575
|
+
* is behind. An unbounded gate dropped every frame until the new clock passed
|
|
53576
|
+
* the old high mark (60 s back: 461 frames, a new subject never tracked, the
|
|
53577
|
+
* departed one coasting on). Instead: commit what L2 has decided, end every
|
|
53578
|
+
* live tracklet at its own last sighting, decide every piece still undecided
|
|
53579
|
+
* `new` (no fusion crosses the step), and resume the internal clock past
|
|
53580
|
+
* `LINK_MAX_GAP_MS` of silence, so nothing later can continue anything
|
|
53581
|
+
* earlier. Returns the frame's internal time.
|
|
53582
|
+
*/
|
|
53583
|
+
clockStep(frameT, behindMs) {
|
|
53584
|
+
const lastFrameT = this.frameClock();
|
|
53585
|
+
this.link(this.lastT);
|
|
53586
|
+
const ended = this.l1.endAll("clock-step");
|
|
53587
|
+
this.l2.closeUndecided(this.lastT, this.pieces());
|
|
53588
|
+
const resumeAt = Math.max(this.lastT, this.lastFrameT) + LINK_MAX_GAP_MS + 1;
|
|
53589
|
+
this.offset = resumeAt - frameT;
|
|
53590
|
+
this.lastT = resumeAt;
|
|
53591
|
+
this.observers.clockStep?.({
|
|
53592
|
+
t: frameT,
|
|
53593
|
+
lastFrameT,
|
|
53594
|
+
behindMs,
|
|
53595
|
+
ended
|
|
53596
|
+
});
|
|
53597
|
+
return resumeAt;
|
|
53598
|
+
}
|
|
53599
|
+
/** The latest frame time taken, in the caller's clock (rebased by a clock step). */
|
|
53600
|
+
frameClock() {
|
|
53601
|
+
return this.lastFrameT - this.offset;
|
|
53602
|
+
}
|
|
53603
|
+
/**
|
|
53122
53604
|
* The close sweep's entry on a camera whose frames stopped (D438): end the
|
|
53123
53605
|
* tracklets the coast budget no longer covers, THEN run L2 (review C2).
|
|
53124
53606
|
* `now` is FRAME time (the processor converts wall clock, Task 11).
|
|
53125
53607
|
*/
|
|
53126
|
-
advance(
|
|
53608
|
+
advance(frameNow) {
|
|
53609
|
+
const now = frameNow + this.offset;
|
|
53127
53610
|
this.lastT = Math.max(this.lastT, now);
|
|
53128
53611
|
this.l1.expire(now);
|
|
53129
53612
|
this.link(now);
|
|
@@ -53139,6 +53622,7 @@ var TrackerV2 = class {
|
|
|
53139
53622
|
markSuppressed(id) {
|
|
53140
53623
|
this.l1.markSuppressed(id);
|
|
53141
53624
|
}
|
|
53625
|
+
/** In the caller's clock (translated when each was committed, LOW-5). */
|
|
53142
53626
|
drainFusions() {
|
|
53143
53627
|
const out = this.pending;
|
|
53144
53628
|
this.pending = [];
|
|
@@ -53151,8 +53635,8 @@ var TrackerV2 = class {
|
|
|
53151
53635
|
isLive(id) {
|
|
53152
53636
|
return this.l2.membersOf(this.l2.rootOf(id)).some((m) => this.isLiveTracklet(m));
|
|
53153
53637
|
}
|
|
53154
|
-
isTailFinal(id,
|
|
53155
|
-
return this.l2.isTailFinal(id,
|
|
53638
|
+
isTailFinal(id, frameNow) {
|
|
53639
|
+
return this.l2.isTailFinal(id, frameNow + this.offset, (m) => this.isLiveTracklet(m));
|
|
53156
53640
|
}
|
|
53157
53641
|
/**
|
|
53158
53642
|
* Ends every live member of the chain. `stationary` (round 4): the
|
|
@@ -53168,9 +53652,15 @@ var TrackerV2 = class {
|
|
|
53168
53652
|
const tr = this.l1.get(id);
|
|
53169
53653
|
return tr !== void 0 && tr.endedAt === null;
|
|
53170
53654
|
}
|
|
53655
|
+
pieces() {
|
|
53656
|
+
return [...this.l1.liveTracklets(), ...this.l1.endedTracklets()].map(toPiece);
|
|
53657
|
+
}
|
|
53171
53658
|
link(now) {
|
|
53172
|
-
const
|
|
53173
|
-
|
|
53659
|
+
const offset = this.offset;
|
|
53660
|
+
for (const f of this.l2.step(now, this.pieces())) this.pending.push({
|
|
53661
|
+
...f,
|
|
53662
|
+
t: f.t - offset
|
|
53663
|
+
});
|
|
53174
53664
|
this.l1.prune(now);
|
|
53175
53665
|
this.l2.prune(now);
|
|
53176
53666
|
}
|
|
@@ -53233,7 +53723,8 @@ var NO_ENDS = {
|
|
|
53233
53723
|
missed: 0,
|
|
53234
53724
|
ambiguous: 0,
|
|
53235
53725
|
dropped: 0,
|
|
53236
|
-
stationary: 0
|
|
53726
|
+
stationary: 0,
|
|
53727
|
+
"clock-step": 0
|
|
53237
53728
|
};
|
|
53238
53729
|
function emptyStats() {
|
|
53239
53730
|
return {
|
|
@@ -53246,16 +53737,28 @@ function emptyStats() {
|
|
|
53246
53737
|
linksRefused: 0,
|
|
53247
53738
|
linksNew: 0,
|
|
53248
53739
|
linksDisagreed: 0,
|
|
53249
|
-
lowScoreHolds: 0
|
|
53740
|
+
lowScoreHolds: 0,
|
|
53741
|
+
outOfOrderFrames: 0,
|
|
53742
|
+
clockSteps: 0
|
|
53250
53743
|
};
|
|
53251
53744
|
}
|
|
53252
53745
|
/** Nothing happened in the window: no tracklet ended, no split, no L2
|
|
53253
53746
|
* decision, no low-score hold (review LOW-N1 — what the sweep stays quiet about). */
|
|
53254
53747
|
function isIdleTrackerStats(stats) {
|
|
53255
|
-
return [stats.tracklets.confirmed, stats.tracklets.unconfirmed].flatMap((c) => Object.values(c)).every((n) => n === 0) && stats.splits === 0 && stats.linksCommitted === 0 && stats.linksRefused === 0 && stats.linksNew === 0 && stats.linksDisagreed === 0 && stats.lowScoreHolds === 0;
|
|
53748
|
+
return [stats.tracklets.confirmed, stats.tracklets.unconfirmed].flatMap((c) => Object.values(c)).every((n) => n === 0) && stats.splits === 0 && stats.linksCommitted === 0 && stats.linksRefused === 0 && stats.linksNew === 0 && stats.linksDisagreed === 0 && stats.lowScoreHolds === 0 && stats.outOfOrderFrames === 0 && stats.clockSteps === 0;
|
|
53256
53749
|
}
|
|
53257
53750
|
/** Shared empty — a fold is rare and every other frame would allocate. */
|
|
53258
53751
|
var EMPTY_RIDER_FOLDS = [];
|
|
53752
|
+
/** The tape observation of a dropped frame: no gate verdict, nothing bound. */
|
|
53753
|
+
var DROPPED_FRAME_OBSERVATION = {
|
|
53754
|
+
gate: {
|
|
53755
|
+
strong: [],
|
|
53756
|
+
weak: [],
|
|
53757
|
+
confirmed: [],
|
|
53758
|
+
woken: []
|
|
53759
|
+
},
|
|
53760
|
+
live: []
|
|
53761
|
+
};
|
|
53259
53762
|
/** Mapping from StateAnalyzer's `ObjectState.state` values to the
|
|
53260
53763
|
* canonical TrackState enum used on tracks + events. */
|
|
53261
53764
|
function mapObjectStateToTrackState(s) {
|
|
@@ -53434,6 +53937,14 @@ var FrameProcessor = class {
|
|
|
53434
53937
|
else if (f.kind === "new") this.stats.linksNew += 1;
|
|
53435
53938
|
else if (f.kind === "disagreed") this.stats.linksDisagreed += 1;
|
|
53436
53939
|
this.trackerObservers.link?.(f);
|
|
53940
|
+
},
|
|
53941
|
+
outOfOrder: (f) => {
|
|
53942
|
+
this.stats.outOfOrderFrames += 1;
|
|
53943
|
+
this.trackerObservers.outOfOrder?.(f);
|
|
53944
|
+
},
|
|
53945
|
+
clockStep: (f) => {
|
|
53946
|
+
this.stats.clockSteps += 1;
|
|
53947
|
+
this.trackerObservers.clockStep?.(f);
|
|
53437
53948
|
}
|
|
53438
53949
|
}
|
|
53439
53950
|
});
|
|
@@ -53717,6 +54228,37 @@ var FrameProcessor = class {
|
|
|
53717
54228
|
* Zero is the expected reading; a rising one means two people stand close
|
|
53718
54229
|
* together on this camera, which is worth knowing per-camera rather than
|
|
53719
54230
|
* per-fleet. */
|
|
54231
|
+
/**
|
|
54232
|
+
* A frame `classifyFrame` called out of order: the tracker records the drop
|
|
54233
|
+
* (and any clock-step run it extends) and nothing else reads the frame. The
|
|
54234
|
+
* per-frame side tables a reader asks for afterwards are emptied, so it never
|
|
54235
|
+
* re-reads the previous frame's.
|
|
54236
|
+
*/
|
|
54237
|
+
droppedFrame(input) {
|
|
54238
|
+
this.tracker.drop(input.timestamp, input.frame.detections.length);
|
|
54239
|
+
this.lastZoneOverlaps = /* @__PURE__ */ new Map();
|
|
54240
|
+
this.lastZoneRejections = /* @__PURE__ */ new Map();
|
|
54241
|
+
this.lastLabelWriteRefusals = [];
|
|
54242
|
+
const fusions = this.tracker.drainFusions();
|
|
54243
|
+
this.applyFusions(fusions);
|
|
54244
|
+
return {
|
|
54245
|
+
deviceId: this.deviceId,
|
|
54246
|
+
timestamp: input.timestamp,
|
|
54247
|
+
frameWidth: input.frame.width,
|
|
54248
|
+
frameHeight: input.frame.height,
|
|
54249
|
+
tracked: [],
|
|
54250
|
+
objectEvents: [],
|
|
54251
|
+
appearanceEvents: [],
|
|
54252
|
+
rawTrackedDetections: [],
|
|
54253
|
+
stationaryConfirmed: [],
|
|
54254
|
+
stationaryWoken: [],
|
|
54255
|
+
stationaryContinued: 0,
|
|
54256
|
+
riderFolds: [],
|
|
54257
|
+
...input.observe === true ? { observation: DROPPED_FRAME_OBSERVATION } : {},
|
|
54258
|
+
fusions,
|
|
54259
|
+
droppedOutOfOrder: true
|
|
54260
|
+
};
|
|
54261
|
+
}
|
|
53720
54262
|
facesRefusedOutsideParent() {
|
|
53721
54263
|
return this.faceOutsideParentCount;
|
|
53722
54264
|
}
|
|
@@ -53739,6 +54281,7 @@ var FrameProcessor = class {
|
|
|
53739
54281
|
}
|
|
53740
54282
|
process(input) {
|
|
53741
54283
|
const { timestamp, frame } = input;
|
|
54284
|
+
if (this.tracker.classifyFrame(timestamp) === "out-of-order") return this.droppedFrame(input);
|
|
53742
54285
|
this.lastFrameT = timestamp;
|
|
53743
54286
|
this.lastFrameWallAt = this.wallClock();
|
|
53744
54287
|
const frameWidth = frame.width;
|
|
@@ -56490,239 +57033,6 @@ async function promoteTapeWindow(deps, input, signal) {
|
|
|
56490
57033
|
};
|
|
56491
57034
|
}
|
|
56492
57035
|
//#endregion
|
|
56493
|
-
//#region src/pipeline-analytics/store/tracking-tape-index-store.ts
|
|
56494
|
-
/**
|
|
56495
|
-
* @durable class=ledger owner=pipeline-analytics
|
|
56496
|
-
* write="one row per PROMOTED tracking-tape window (`debug.tape.promote`);
|
|
56497
|
-
* updated when the operator marks it reviewed or releases its pins;
|
|
56498
|
-
* deleted together with its file by `debug.tape.delete`."
|
|
56499
|
-
* retention="NOT an age clock and NOT track retention — a promoted window is
|
|
56500
|
-
* history being labelled (D681). Bounded by the promotion budget
|
|
56501
|
-
* (MAX_PROMOTED_TAPES = 60, 1 GiB): a promotion beyond it is REFUSED,
|
|
56502
|
-
* never satisfied by evicting another row."
|
|
56503
|
-
*/
|
|
56504
|
-
var TRACKING_TAPES_COLLECTION = "pipeline-analytics:tracking-tapes";
|
|
56505
|
-
var TRACKING_TAPES_COLUMNS = [
|
|
56506
|
-
{
|
|
56507
|
-
name: "id",
|
|
56508
|
-
type: "TEXT",
|
|
56509
|
-
primaryKey: true,
|
|
56510
|
-
notNull: true
|
|
56511
|
-
},
|
|
56512
|
-
{
|
|
56513
|
-
name: "deviceId",
|
|
56514
|
-
type: "INTEGER",
|
|
56515
|
-
notNull: true
|
|
56516
|
-
},
|
|
56517
|
-
{
|
|
56518
|
-
name: "scenario",
|
|
56519
|
-
type: "TEXT",
|
|
56520
|
-
notNull: true
|
|
56521
|
-
},
|
|
56522
|
-
{
|
|
56523
|
-
name: "note",
|
|
56524
|
-
type: "TEXT"
|
|
56525
|
-
},
|
|
56526
|
-
{
|
|
56527
|
-
name: "lighting",
|
|
56528
|
-
type: "TEXT",
|
|
56529
|
-
notNull: true
|
|
56530
|
-
},
|
|
56531
|
-
{
|
|
56532
|
-
name: "fromMs",
|
|
56533
|
-
type: "INTEGER",
|
|
56534
|
-
notNull: true
|
|
56535
|
-
},
|
|
56536
|
-
{
|
|
56537
|
-
name: "toMs",
|
|
56538
|
-
type: "INTEGER",
|
|
56539
|
-
notNull: true
|
|
56540
|
-
},
|
|
56541
|
-
{
|
|
56542
|
-
name: "state",
|
|
56543
|
-
type: "TEXT",
|
|
56544
|
-
notNull: true
|
|
56545
|
-
},
|
|
56546
|
-
{
|
|
56547
|
-
name: "frames",
|
|
56548
|
-
type: "INTEGER",
|
|
56549
|
-
notNull: true
|
|
56550
|
-
},
|
|
56551
|
-
{
|
|
56552
|
-
name: "skips",
|
|
56553
|
-
type: "INTEGER",
|
|
56554
|
-
notNull: true
|
|
56555
|
-
},
|
|
56556
|
-
{
|
|
56557
|
-
name: "gaps",
|
|
56558
|
-
type: "INTEGER",
|
|
56559
|
-
notNull: true
|
|
56560
|
-
},
|
|
56561
|
-
{
|
|
56562
|
-
name: "bytes",
|
|
56563
|
-
type: "INTEGER",
|
|
56564
|
-
notNull: true
|
|
56565
|
-
},
|
|
56566
|
-
{
|
|
56567
|
-
name: "reviewed",
|
|
56568
|
-
type: "BOOLEAN",
|
|
56569
|
-
notNull: true
|
|
56570
|
-
},
|
|
56571
|
-
{
|
|
56572
|
-
name: "trackIds",
|
|
56573
|
-
type: "TEXT",
|
|
56574
|
-
notNull: true
|
|
56575
|
-
},
|
|
56576
|
-
{
|
|
56577
|
-
name: "createdAt",
|
|
56578
|
-
type: "INTEGER",
|
|
56579
|
-
notNull: true
|
|
56580
|
-
},
|
|
56581
|
-
{
|
|
56582
|
-
name: "releasedAt",
|
|
56583
|
-
type: "INTEGER"
|
|
56584
|
-
},
|
|
56585
|
-
{
|
|
56586
|
-
name: "pinsSettled",
|
|
56587
|
-
type: "BOOLEAN",
|
|
56588
|
-
notNull: true
|
|
56589
|
-
}
|
|
56590
|
-
];
|
|
56591
|
-
var TrackingTapeRowSchema = object({
|
|
56592
|
-
id: string(),
|
|
56593
|
-
deviceId: number().int(),
|
|
56594
|
-
scenario: string(),
|
|
56595
|
-
note: string().nullable(),
|
|
56596
|
-
lighting: TapeLightingSchema,
|
|
56597
|
-
fromMs: number().int(),
|
|
56598
|
-
toMs: number().int(),
|
|
56599
|
-
state: _enum(["complete", "incomplete"]),
|
|
56600
|
-
frames: number().int(),
|
|
56601
|
-
skips: number().int(),
|
|
56602
|
-
gaps: number().int(),
|
|
56603
|
-
bytes: number().int(),
|
|
56604
|
-
reviewed: boolean(),
|
|
56605
|
-
trackIds: array(string()),
|
|
56606
|
-
createdAt: number().int(),
|
|
56607
|
-
releasedAt: number().int().nullable(),
|
|
56608
|
-
pinsSettled: boolean()
|
|
56609
|
-
});
|
|
56610
|
-
var TrackIdsSchema = array(string());
|
|
56611
|
-
var TrackingTapeIndexStore = class {
|
|
56612
|
-
store;
|
|
56613
|
-
logger;
|
|
56614
|
-
constructor(deps) {
|
|
56615
|
-
this.store = deps.store;
|
|
56616
|
-
this.logger = deps.logger;
|
|
56617
|
-
}
|
|
56618
|
-
static async declare(store) {
|
|
56619
|
-
await store.declareCollection.mutate({
|
|
56620
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56621
|
-
columns: [...TRACKING_TAPES_COLUMNS],
|
|
56622
|
-
indexes: [{
|
|
56623
|
-
name: "idx_trackingtapes_device_created",
|
|
56624
|
-
columns: ["deviceId", "createdAt"]
|
|
56625
|
-
}]
|
|
56626
|
-
});
|
|
56627
|
-
}
|
|
56628
|
-
async insert(row) {
|
|
56629
|
-
const { id, trackIds, ...rest } = TrackingTapeRowSchema.parse(row);
|
|
56630
|
-
await this.store.insert.mutate({
|
|
56631
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56632
|
-
record: {
|
|
56633
|
-
id,
|
|
56634
|
-
data: {
|
|
56635
|
-
...rest,
|
|
56636
|
-
trackIds: JSON.stringify(trackIds)
|
|
56637
|
-
}
|
|
56638
|
-
}
|
|
56639
|
-
});
|
|
56640
|
-
}
|
|
56641
|
-
async get(id) {
|
|
56642
|
-
const first = (await this.store.query.query({
|
|
56643
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56644
|
-
filter: {
|
|
56645
|
-
where: { id },
|
|
56646
|
-
limit: 1
|
|
56647
|
-
}
|
|
56648
|
-
}))[0];
|
|
56649
|
-
return first === void 0 ? null : this.parse(first.id, first.data);
|
|
56650
|
-
}
|
|
56651
|
-
async list(deviceId) {
|
|
56652
|
-
const rows = await this.store.query.query({
|
|
56653
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56654
|
-
filter: {
|
|
56655
|
-
...deviceId !== void 0 ? { where: { deviceId } } : {},
|
|
56656
|
-
orderBy: {
|
|
56657
|
-
field: "createdAt",
|
|
56658
|
-
direction: "desc"
|
|
56659
|
-
},
|
|
56660
|
-
limit: 1e3
|
|
56661
|
-
}
|
|
56662
|
-
});
|
|
56663
|
-
const out = [];
|
|
56664
|
-
for (const r of rows) {
|
|
56665
|
-
const parsed = this.parse(r.id, r.data);
|
|
56666
|
-
if (parsed !== null) out.push(parsed);
|
|
56667
|
-
}
|
|
56668
|
-
return out;
|
|
56669
|
-
}
|
|
56670
|
-
async setReviewed(id, reviewed) {
|
|
56671
|
-
await this.store.update.mutate({
|
|
56672
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56673
|
-
id,
|
|
56674
|
-
data: { reviewed }
|
|
56675
|
-
});
|
|
56676
|
-
}
|
|
56677
|
-
/** Release AND unsettle in one row write: the unpins the release implies
|
|
56678
|
-
* are owed from this moment, whether or not the caller lives to make them. */
|
|
56679
|
-
async setReleased(id, atMs) {
|
|
56680
|
-
await this.store.update.mutate({
|
|
56681
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56682
|
-
id,
|
|
56683
|
-
data: {
|
|
56684
|
-
releasedAt: atMs,
|
|
56685
|
-
pinsSettled: false
|
|
56686
|
-
}
|
|
56687
|
-
});
|
|
56688
|
-
}
|
|
56689
|
-
async setPinsSettled(id, settled) {
|
|
56690
|
-
await this.store.update.mutate({
|
|
56691
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56692
|
-
id,
|
|
56693
|
-
data: { pinsSettled: settled }
|
|
56694
|
-
});
|
|
56695
|
-
}
|
|
56696
|
-
async remove(id) {
|
|
56697
|
-
await this.store.delete.mutate({
|
|
56698
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56699
|
-
key: id
|
|
56700
|
-
});
|
|
56701
|
-
}
|
|
56702
|
-
parse(id, data) {
|
|
56703
|
-
let trackIds = [];
|
|
56704
|
-
try {
|
|
56705
|
-
trackIds = JSON.parse(String(data["trackIds"] ?? "[]"));
|
|
56706
|
-
} catch {
|
|
56707
|
-
trackIds = null;
|
|
56708
|
-
}
|
|
56709
|
-
const ids = TrackIdsSchema.safeParse(trackIds);
|
|
56710
|
-
const parsed = TrackingTapeRowSchema.safeParse({
|
|
56711
|
-
id,
|
|
56712
|
-
...data,
|
|
56713
|
-
note: data["note"] ?? null,
|
|
56714
|
-
releasedAt: data["releasedAt"] ?? null,
|
|
56715
|
-
trackIds: ids.success ? ids.data : null
|
|
56716
|
-
});
|
|
56717
|
-
if (parsed.success) return parsed.data;
|
|
56718
|
-
this.logger.warn("tracking tape index: skipped a malformed row", {
|
|
56719
|
-
meta: { id },
|
|
56720
|
-
...typeof data["deviceId"] === "number" ? { tags: { deviceId: data["deviceId"] } } : {}
|
|
56721
|
-
});
|
|
56722
|
-
return null;
|
|
56723
|
-
}
|
|
56724
|
-
};
|
|
56725
|
-
//#endregion
|
|
56726
57036
|
//#region src/pipeline-analytics/tracking-bench/recorder/tape-status.ts
|
|
56727
57037
|
/** The one node that may hold tapes: sqlite and bulk state are hub-only, and
|
|
56728
57038
|
* an agent persists nothing (spec §3.1). */
|
|
@@ -97602,6 +97912,12 @@ var TRACKER_FACT_LOG_SAMPLE_EVERY = 10;
|
|
|
97602
97912
|
* positive spawns (review M1: ~1 750 `new` decisions per camera per hour) —
|
|
97603
97913
|
* are sampled harder; the per-minute summary carries their exact counts. */
|
|
97604
97914
|
var TRACKER_PIECE_LOG_SAMPLE_EVERY = 50;
|
|
97915
|
+
/** Out-of-order frames (follow-up 617, F1: ~1 % of frames) log the first N,
|
|
97916
|
+
* then one in this many — every line carries the count; the per-minute
|
|
97917
|
+
* summary carries the exact `outOfOrderFrames`. */
|
|
97918
|
+
var TRACKER_OUT_OF_ORDER_LOG_SAMPLE_EVERY = 50;
|
|
97919
|
+
/** Clock-step WARNs past the first ten (fix round 3, MEDIUM-1). */
|
|
97920
|
+
var TRACKER_CLOCK_STEP_LOG_SAMPLE_EVERY = 50;
|
|
97605
97921
|
/** First N, then one in `every` — the refusal stream's cadence (D391). */
|
|
97606
97922
|
function sampledTrackerFact(count, every = TRACKER_FACT_LOG_SAMPLE_EVERY) {
|
|
97607
97923
|
return count <= TRACKER_FACT_LOG_ALWAYS_FIRST || count % every === 0;
|
|
@@ -102249,9 +102565,11 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
102249
102565
|
let splitCount = 0;
|
|
102250
102566
|
let ignoredCount = 0;
|
|
102251
102567
|
let newCount = 0;
|
|
102568
|
+
let outOfOrderCount = 0;
|
|
102569
|
+
let clockStepCount = 0;
|
|
102252
102570
|
const endedCounts = /* @__PURE__ */ new Map();
|
|
102253
102571
|
const logLink = (f) => {
|
|
102254
|
-
const
|
|
102572
|
+
const decision = {
|
|
102255
102573
|
source,
|
|
102256
102574
|
t: f.t,
|
|
102257
102575
|
kind: f.kind,
|
|
@@ -102260,7 +102578,10 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
102260
102578
|
cost: f.cost,
|
|
102261
102579
|
gapMs: f.gapMs,
|
|
102262
102580
|
reason: f.reason,
|
|
102263
|
-
recognition: f.recognition
|
|
102581
|
+
recognition: f.recognition
|
|
102582
|
+
};
|
|
102583
|
+
const meta = {
|
|
102584
|
+
...decision,
|
|
102264
102585
|
candidates: f.candidates
|
|
102265
102586
|
};
|
|
102266
102587
|
switch (f.kind) {
|
|
@@ -102298,7 +102619,14 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
102298
102619
|
meta
|
|
102299
102620
|
});
|
|
102300
102621
|
return;
|
|
102301
|
-
case "new":
|
|
102622
|
+
case "new": {
|
|
102623
|
+
if (f.reason === "clock-step") {
|
|
102624
|
+
trackerLog.debug("tracker: piece decided new — closed by a frame clock step", {
|
|
102625
|
+
tags: { deviceId },
|
|
102626
|
+
meta
|
|
102627
|
+
});
|
|
102628
|
+
return;
|
|
102629
|
+
}
|
|
102302
102630
|
if (f.reason === "unconfirmed") {
|
|
102303
102631
|
trackerLog.debug("tracker: piece decided new — never confirmed", {
|
|
102304
102632
|
tags: { deviceId },
|
|
@@ -102306,6 +102634,17 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
102306
102634
|
});
|
|
102307
102635
|
return;
|
|
102308
102636
|
}
|
|
102637
|
+
const rejectedPredecessors = confirmedPredecessorRejections(f.candidates);
|
|
102638
|
+
if (rejectedPredecessors.length > 0) {
|
|
102639
|
+
trackerLog.info("tracker: piece decided new — a confirmed predecessor was rejected", {
|
|
102640
|
+
tags: { deviceId },
|
|
102641
|
+
meta: {
|
|
102642
|
+
...decision,
|
|
102643
|
+
rejectedPredecessors
|
|
102644
|
+
}
|
|
102645
|
+
});
|
|
102646
|
+
return;
|
|
102647
|
+
}
|
|
102309
102648
|
newCount += 1;
|
|
102310
102649
|
if (!sampledTrackerFact(newCount, TRACKER_PIECE_LOG_SAMPLE_EVERY)) return;
|
|
102311
102650
|
trackerLog.info("tracker: piece decided new — no predecessor", {
|
|
@@ -102316,6 +102655,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
102316
102655
|
}
|
|
102317
102656
|
});
|
|
102318
102657
|
return;
|
|
102658
|
+
}
|
|
102319
102659
|
}
|
|
102320
102660
|
};
|
|
102321
102661
|
p.setTrackerObservers({
|
|
@@ -102336,6 +102676,39 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
102336
102676
|
});
|
|
102337
102677
|
},
|
|
102338
102678
|
link: logLink,
|
|
102679
|
+
clockStep: (f) => {
|
|
102680
|
+
clockStepCount += 1;
|
|
102681
|
+
if (!sampledTrackerFact(clockStepCount, TRACKER_CLOCK_STEP_LOG_SAMPLE_EVERY)) return;
|
|
102682
|
+
trackerLog.warn("tracker: frame clock stepped back — tracklets ended, clock rebased", {
|
|
102683
|
+
tags: { deviceId },
|
|
102684
|
+
meta: {
|
|
102685
|
+
source,
|
|
102686
|
+
t: f.t,
|
|
102687
|
+
lastFrameT: f.lastFrameT,
|
|
102688
|
+
behindMs: f.behindMs,
|
|
102689
|
+
ended: f.ended,
|
|
102690
|
+
clockStepCount,
|
|
102691
|
+
sampledEvery: TRACKER_CLOCK_STEP_LOG_SAMPLE_EVERY
|
|
102692
|
+
}
|
|
102693
|
+
});
|
|
102694
|
+
},
|
|
102695
|
+
outOfOrder: (f) => {
|
|
102696
|
+
outOfOrderCount += 1;
|
|
102697
|
+
if (!sampledTrackerFact(outOfOrderCount, TRACKER_OUT_OF_ORDER_LOG_SAMPLE_EVERY)) return;
|
|
102698
|
+
trackerLog.info("tracker: out-of-order frame dropped — older than the latest frame", {
|
|
102699
|
+
tags: { deviceId },
|
|
102700
|
+
meta: {
|
|
102701
|
+
source,
|
|
102702
|
+
t: f.t,
|
|
102703
|
+
lastFrameT: f.lastFrameT,
|
|
102704
|
+
behindMs: f.behindMs,
|
|
102705
|
+
detections: f.detections,
|
|
102706
|
+
pendingClockStep: f.pendingClockStep,
|
|
102707
|
+
outOfOrderCount,
|
|
102708
|
+
sampledEvery: TRACKER_OUT_OF_ORDER_LOG_SAMPLE_EVERY
|
|
102709
|
+
}
|
|
102710
|
+
});
|
|
102711
|
+
},
|
|
102339
102712
|
ended: (f) => {
|
|
102340
102713
|
const k = `${f.reason}:${String(f.confirmed)}`;
|
|
102341
102714
|
const n = (endedCounts.get(k) ?? 0) + 1;
|
|
@@ -102477,6 +102850,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
102477
102850
|
});
|
|
102478
102851
|
});
|
|
102479
102852
|
this.reportTrackerSummary(deviceId, key, processor, "frame");
|
|
102853
|
+
if (result.droppedOutOfOrder === true) return;
|
|
102480
102854
|
for (const r of processor.getLastLabelWriteRefusals()) {
|
|
102481
102855
|
const message = r.reason.kind === "macro-class" ? "label tier collapse refused" : "label write refused";
|
|
102482
102856
|
this.ctx.logger.info(message, {
|