@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
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_clip_model_registry = require("../clip-model-registry-
|
|
5
|
+
const require_clip_model_registry = require("../clip-model-registry-BqrTKyUe.js");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
node_fs = require_clip_model_registry.__toESM(node_fs, 1);
|
|
8
8
|
let node_path = require("node:path");
|
|
@@ -42620,6 +42620,280 @@ function parseDebugDeviceIds(url) {
|
|
|
42620
42620
|
return out;
|
|
42621
42621
|
}
|
|
42622
42622
|
//#endregion
|
|
42623
|
+
//#region src/pipeline-analytics/store/tracking-tape-index-store.ts
|
|
42624
|
+
/**
|
|
42625
|
+
* @durable class=ledger owner=pipeline-analytics
|
|
42626
|
+
* write="one row per PROMOTED tracking-tape window (`debug.tape.promote`);
|
|
42627
|
+
* updated when the operator marks it reviewed or releases its pins;
|
|
42628
|
+
* deleted together with its file by `debug.tape.delete`."
|
|
42629
|
+
* retention="NOT an age clock and NOT track retention — a promoted window is
|
|
42630
|
+
* history being labelled (D681). Bounded by the promotion budget
|
|
42631
|
+
* (MAX_PROMOTED_TAPES = 60, 1 GiB): a promotion beyond it is REFUSED,
|
|
42632
|
+
* never satisfied by evicting another row."
|
|
42633
|
+
*/
|
|
42634
|
+
var TRACKING_TAPES_COLLECTION = "pipeline-analytics:tracking-tapes";
|
|
42635
|
+
var TRACKING_TAPES_COLUMNS = [
|
|
42636
|
+
{
|
|
42637
|
+
name: "id",
|
|
42638
|
+
type: "TEXT",
|
|
42639
|
+
primaryKey: true,
|
|
42640
|
+
notNull: true
|
|
42641
|
+
},
|
|
42642
|
+
{
|
|
42643
|
+
name: "deviceId",
|
|
42644
|
+
type: "INTEGER",
|
|
42645
|
+
notNull: true
|
|
42646
|
+
},
|
|
42647
|
+
{
|
|
42648
|
+
name: "scenario",
|
|
42649
|
+
type: "TEXT",
|
|
42650
|
+
notNull: true
|
|
42651
|
+
},
|
|
42652
|
+
{
|
|
42653
|
+
name: "note",
|
|
42654
|
+
type: "TEXT"
|
|
42655
|
+
},
|
|
42656
|
+
{
|
|
42657
|
+
name: "lighting",
|
|
42658
|
+
type: "TEXT",
|
|
42659
|
+
notNull: true
|
|
42660
|
+
},
|
|
42661
|
+
{
|
|
42662
|
+
name: "fromMs",
|
|
42663
|
+
type: "INTEGER",
|
|
42664
|
+
notNull: true
|
|
42665
|
+
},
|
|
42666
|
+
{
|
|
42667
|
+
name: "toMs",
|
|
42668
|
+
type: "INTEGER",
|
|
42669
|
+
notNull: true
|
|
42670
|
+
},
|
|
42671
|
+
{
|
|
42672
|
+
name: "state",
|
|
42673
|
+
type: "TEXT",
|
|
42674
|
+
notNull: true
|
|
42675
|
+
},
|
|
42676
|
+
{
|
|
42677
|
+
name: "frames",
|
|
42678
|
+
type: "INTEGER",
|
|
42679
|
+
notNull: true
|
|
42680
|
+
},
|
|
42681
|
+
{
|
|
42682
|
+
name: "skips",
|
|
42683
|
+
type: "INTEGER",
|
|
42684
|
+
notNull: true
|
|
42685
|
+
},
|
|
42686
|
+
{
|
|
42687
|
+
name: "gaps",
|
|
42688
|
+
type: "INTEGER",
|
|
42689
|
+
notNull: true
|
|
42690
|
+
},
|
|
42691
|
+
{
|
|
42692
|
+
name: "bytes",
|
|
42693
|
+
type: "INTEGER",
|
|
42694
|
+
notNull: true
|
|
42695
|
+
},
|
|
42696
|
+
{
|
|
42697
|
+
name: "reviewed",
|
|
42698
|
+
type: "BOOLEAN",
|
|
42699
|
+
notNull: true
|
|
42700
|
+
},
|
|
42701
|
+
{
|
|
42702
|
+
name: "trackIds",
|
|
42703
|
+
type: "TEXT",
|
|
42704
|
+
notNull: true
|
|
42705
|
+
},
|
|
42706
|
+
{
|
|
42707
|
+
name: "createdAt",
|
|
42708
|
+
type: "INTEGER",
|
|
42709
|
+
notNull: true
|
|
42710
|
+
},
|
|
42711
|
+
{
|
|
42712
|
+
name: "releasedAt",
|
|
42713
|
+
type: "INTEGER"
|
|
42714
|
+
},
|
|
42715
|
+
{
|
|
42716
|
+
name: "pinsSettled",
|
|
42717
|
+
type: "BOOLEAN",
|
|
42718
|
+
notNull: true
|
|
42719
|
+
}
|
|
42720
|
+
];
|
|
42721
|
+
var TrackingTapeRowSchema = require_clip_model_registry.object({
|
|
42722
|
+
id: require_clip_model_registry.string(),
|
|
42723
|
+
deviceId: require_clip_model_registry.number().int(),
|
|
42724
|
+
scenario: require_clip_model_registry.string(),
|
|
42725
|
+
note: require_clip_model_registry.string().nullable(),
|
|
42726
|
+
lighting: TapeLightingSchema,
|
|
42727
|
+
fromMs: require_clip_model_registry.number().int(),
|
|
42728
|
+
toMs: require_clip_model_registry.number().int(),
|
|
42729
|
+
state: require_clip_model_registry._enum(["complete", "incomplete"]),
|
|
42730
|
+
frames: require_clip_model_registry.number().int(),
|
|
42731
|
+
skips: require_clip_model_registry.number().int(),
|
|
42732
|
+
gaps: require_clip_model_registry.number().int(),
|
|
42733
|
+
bytes: require_clip_model_registry.number().int(),
|
|
42734
|
+
reviewed: require_clip_model_registry.boolean(),
|
|
42735
|
+
trackIds: require_clip_model_registry.array(require_clip_model_registry.string()),
|
|
42736
|
+
createdAt: require_clip_model_registry.number().int(),
|
|
42737
|
+
releasedAt: require_clip_model_registry.number().int().nullable(),
|
|
42738
|
+
pinsSettled: require_clip_model_registry.boolean()
|
|
42739
|
+
});
|
|
42740
|
+
var TrackIdsSchema = require_clip_model_registry.array(require_clip_model_registry.string());
|
|
42741
|
+
/**
|
|
42742
|
+
* True when the SQLite settings backend would hand `text` back DECODED: it
|
|
42743
|
+
* parses any TEXT that starts with `[` or `{` and is valid JSON
|
|
42744
|
+
* (`decodeColumnValue` decodes by content, not by declared type). Free text
|
|
42745
|
+
* like that cannot round-trip through a TEXT column (follow-up 617, review M2).
|
|
42746
|
+
*/
|
|
42747
|
+
function decodesAsJson(text) {
|
|
42748
|
+
if (!(text.startsWith("[") || text.startsWith("{"))) return false;
|
|
42749
|
+
try {
|
|
42750
|
+
JSON.parse(text);
|
|
42751
|
+
return true;
|
|
42752
|
+
} catch {
|
|
42753
|
+
return false;
|
|
42754
|
+
}
|
|
42755
|
+
}
|
|
42756
|
+
/**
|
|
42757
|
+
* Free text (`scenario`, `note`) as the column hands it back: a value the
|
|
42758
|
+
* backend decoded is re-encoded, so a row written before `debug.tape.promote`
|
|
42759
|
+
* refused such text never vanishes (its whitespace may differ). Anything else
|
|
42760
|
+
* goes to the schema as it came.
|
|
42761
|
+
*/
|
|
42762
|
+
function freeText(raw) {
|
|
42763
|
+
return raw !== null && typeof raw === "object" ? JSON.stringify(raw) : raw;
|
|
42764
|
+
}
|
|
42765
|
+
/**
|
|
42766
|
+
* `trackIds` as the column hands it back. The SQLite backend decodes a TEXT
|
|
42767
|
+
* that starts with `[` on read (`decodeColumnValue`), so the store sees the
|
|
42768
|
+
* ARRAY it wrote; a string is parsed here only for a backend (or an old row)
|
|
42769
|
+
* that hands the text back as written. `JSON.parse(String(array))` threw on the
|
|
42770
|
+
* decoded array and every promoted row was skipped as malformed (follow-up 617).
|
|
42771
|
+
* `null` = unreadable, absent included (the column is NOT NULL, so absence is
|
|
42772
|
+
* corruption) — the row is reported, never repaired.
|
|
42773
|
+
*/
|
|
42774
|
+
function decodeTrackIds(raw) {
|
|
42775
|
+
if (raw === void 0 || raw === null) return null;
|
|
42776
|
+
if (typeof raw !== "string") return raw;
|
|
42777
|
+
try {
|
|
42778
|
+
return JSON.parse(raw);
|
|
42779
|
+
} catch {
|
|
42780
|
+
return null;
|
|
42781
|
+
}
|
|
42782
|
+
}
|
|
42783
|
+
var TrackingTapeIndexStore = class {
|
|
42784
|
+
store;
|
|
42785
|
+
logger;
|
|
42786
|
+
constructor(deps) {
|
|
42787
|
+
this.store = deps.store;
|
|
42788
|
+
this.logger = deps.logger;
|
|
42789
|
+
}
|
|
42790
|
+
static async declare(store) {
|
|
42791
|
+
await store.declareCollection.mutate({
|
|
42792
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42793
|
+
columns: [...TRACKING_TAPES_COLUMNS],
|
|
42794
|
+
indexes: [{
|
|
42795
|
+
name: "idx_trackingtapes_device_created",
|
|
42796
|
+
columns: ["deviceId", "createdAt"]
|
|
42797
|
+
}]
|
|
42798
|
+
});
|
|
42799
|
+
}
|
|
42800
|
+
async insert(row) {
|
|
42801
|
+
const { id, trackIds, ...rest } = TrackingTapeRowSchema.parse(row);
|
|
42802
|
+
await this.store.insert.mutate({
|
|
42803
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42804
|
+
record: {
|
|
42805
|
+
id,
|
|
42806
|
+
data: {
|
|
42807
|
+
...rest,
|
|
42808
|
+
trackIds: JSON.stringify(trackIds)
|
|
42809
|
+
}
|
|
42810
|
+
}
|
|
42811
|
+
});
|
|
42812
|
+
}
|
|
42813
|
+
async get(id) {
|
|
42814
|
+
const first = (await this.store.query.query({
|
|
42815
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42816
|
+
filter: {
|
|
42817
|
+
where: { id },
|
|
42818
|
+
limit: 1
|
|
42819
|
+
}
|
|
42820
|
+
}))[0];
|
|
42821
|
+
return first === void 0 ? null : this.parse(first.id, first.data);
|
|
42822
|
+
}
|
|
42823
|
+
async list(deviceId) {
|
|
42824
|
+
const rows = await this.store.query.query({
|
|
42825
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42826
|
+
filter: {
|
|
42827
|
+
...deviceId !== void 0 ? { where: { deviceId } } : {},
|
|
42828
|
+
orderBy: {
|
|
42829
|
+
field: "createdAt",
|
|
42830
|
+
direction: "desc"
|
|
42831
|
+
},
|
|
42832
|
+
limit: 1e3
|
|
42833
|
+
}
|
|
42834
|
+
});
|
|
42835
|
+
const out = [];
|
|
42836
|
+
for (const r of rows) {
|
|
42837
|
+
const parsed = this.parse(r.id, r.data);
|
|
42838
|
+
if (parsed !== null) out.push(parsed);
|
|
42839
|
+
}
|
|
42840
|
+
return out;
|
|
42841
|
+
}
|
|
42842
|
+
async setReviewed(id, reviewed) {
|
|
42843
|
+
await this.store.update.mutate({
|
|
42844
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42845
|
+
id,
|
|
42846
|
+
data: { reviewed }
|
|
42847
|
+
});
|
|
42848
|
+
}
|
|
42849
|
+
/** Release AND unsettle in one row write: the unpins the release implies
|
|
42850
|
+
* are owed from this moment, whether or not the caller lives to make them. */
|
|
42851
|
+
async setReleased(id, atMs) {
|
|
42852
|
+
await this.store.update.mutate({
|
|
42853
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42854
|
+
id,
|
|
42855
|
+
data: {
|
|
42856
|
+
releasedAt: atMs,
|
|
42857
|
+
pinsSettled: false
|
|
42858
|
+
}
|
|
42859
|
+
});
|
|
42860
|
+
}
|
|
42861
|
+
async setPinsSettled(id, settled) {
|
|
42862
|
+
await this.store.update.mutate({
|
|
42863
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42864
|
+
id,
|
|
42865
|
+
data: { pinsSettled: settled }
|
|
42866
|
+
});
|
|
42867
|
+
}
|
|
42868
|
+
async remove(id) {
|
|
42869
|
+
await this.store.delete.mutate({
|
|
42870
|
+
collection: TRACKING_TAPES_COLLECTION,
|
|
42871
|
+
key: id
|
|
42872
|
+
});
|
|
42873
|
+
}
|
|
42874
|
+
parse(id, data) {
|
|
42875
|
+
const ids = TrackIdsSchema.safeParse(decodeTrackIds(data["trackIds"]));
|
|
42876
|
+
const parsed = TrackingTapeRowSchema.safeParse({
|
|
42877
|
+
id,
|
|
42878
|
+
...data,
|
|
42879
|
+
scenario: freeText(data["scenario"]),
|
|
42880
|
+
note: freeText(data["note"] ?? null),
|
|
42881
|
+
releasedAt: data["releasedAt"] ?? null,
|
|
42882
|
+
trackIds: ids.success ? ids.data : null
|
|
42883
|
+
});
|
|
42884
|
+
if (parsed.success) return parsed.data;
|
|
42885
|
+
this.logger.warn("tracking tape index: skipped a malformed row", {
|
|
42886
|
+
meta: {
|
|
42887
|
+
id,
|
|
42888
|
+
issues: parsed.error.issues.map((i) => i.path.join(".")),
|
|
42889
|
+
trackIdsType: typeof data["trackIds"]
|
|
42890
|
+
},
|
|
42891
|
+
...typeof data["deviceId"] === "number" ? { tags: { deviceId: data["deviceId"] } } : {}
|
|
42892
|
+
});
|
|
42893
|
+
return null;
|
|
42894
|
+
}
|
|
42895
|
+
};
|
|
42896
|
+
//#endregion
|
|
42623
42897
|
//#region src/pipeline-analytics/debug/tape-actions.ts
|
|
42624
42898
|
/**
|
|
42625
42899
|
* `debug.tape.*` — the tracking-tape surface (D681, spec §3.3). Admin,
|
|
@@ -42650,12 +42924,19 @@ var TapeStatusRowSchema = require_clip_model_registry.object({
|
|
|
42650
42924
|
var TapeStatusInputSchema = require_clip_model_registry.object({ deviceIds: require_clip_model_registry.array(require_clip_model_registry.number().int()).optional() });
|
|
42651
42925
|
var TapeStatusOutputSchema = require_clip_model_registry.object({ cameras: require_clip_model_registry.array(TapeStatusRowSchema).readonly() });
|
|
42652
42926
|
var TapeLightingInputSchema = require_clip_model_registry._enum(["day", "ir"]);
|
|
42927
|
+
/**
|
|
42928
|
+
* Free text the settings store would hand back decoded is refused by name
|
|
42929
|
+
* (follow-up 617, review M2): whole JSON array/object text in a TEXT column
|
|
42930
|
+
* comes back as an array or object, and the index could not read the row.
|
|
42931
|
+
*/
|
|
42932
|
+
var NOT_JSON_TEXT = "must not be JSON array/object text — the settings store would hand it back decoded";
|
|
42933
|
+
var notJsonText = (s) => !decodesAsJson(s);
|
|
42653
42934
|
var PromoteInputSchema = require_clip_model_registry.object({
|
|
42654
42935
|
deviceId: require_clip_model_registry.number().int().positive(),
|
|
42655
42936
|
fromMs: require_clip_model_registry.number().int(),
|
|
42656
42937
|
toMs: require_clip_model_registry.number().int(),
|
|
42657
|
-
scenario: require_clip_model_registry.string(),
|
|
42658
|
-
note: require_clip_model_registry.string().max(500).optional(),
|
|
42938
|
+
scenario: require_clip_model_registry.string().refine(notJsonText, { message: NOT_JSON_TEXT }),
|
|
42939
|
+
note: require_clip_model_registry.string().max(500).refine(notJsonText, { message: NOT_JSON_TEXT }).optional(),
|
|
42659
42940
|
lighting: TapeLightingInputSchema.optional()
|
|
42660
42941
|
});
|
|
42661
42942
|
var PromoteOutputSchema = require_clip_model_registry.discriminatedUnion("ok", [require_clip_model_registry.object({
|
|
@@ -51118,6 +51399,17 @@ function pairRiders(detections) {
|
|
|
51118
51399
|
* (D438) no frame did, and a newcomer on the stale prediction took the id.
|
|
51119
51400
|
*/
|
|
51120
51401
|
var MAX_PREDICTION_MS = 1e3;
|
|
51402
|
+
/**
|
|
51403
|
+
* A frame more than `maxMissedMs` behind the latest is a CLOCK STEP only as
|
|
51404
|
+
* the K-th such frame in a row, each in order with the one before (follow-up
|
|
51405
|
+
* 617, fix round 3; D49: a read that would destroy work needs another to
|
|
51406
|
+
* agree). A step ends every track on the camera; one stray timestamp — a
|
|
51407
|
+
* backlog spike 4.5 s late — or two runner clocks delivering interleaved
|
|
51408
|
+
* (a camera migrating between runners) must not. Three is the least that a
|
|
51409
|
+
* single late frame plus an interleaved partner cannot reach by chance; the
|
|
51410
|
+
* cost of a real step is K−1 dropped frames (~260 ms at 7.7 fps).
|
|
51411
|
+
*/
|
|
51412
|
+
var CLOCK_STEP_CONFIRM_FRAMES = 3;
|
|
51121
51413
|
/** Confident boxes kept on a tracklet's path (the old tracker's bound). */
|
|
51122
51414
|
var MAX_PATH_LENGTH = 300;
|
|
51123
51415
|
/** Swap test: crossed pairs cheaper than this over the chosen pairs are doubt. */
|
|
@@ -51923,6 +52215,35 @@ function linkReach(from, gapMs) {
|
|
|
51923
52215
|
return diag * Math.min(LINK_REACH_MAX_DIAGONALS, Math.max(LINK_REACH_MIN_DIAGONALS, LINK_REACH_DIAGONALS_PER_SEC * gapMs / 1e3));
|
|
51924
52216
|
}
|
|
51925
52217
|
var arcKey = (from, to) => `${from}\u0000${to}`;
|
|
52218
|
+
/**
|
|
52219
|
+
* The rejections that mean "geometry or appearance said no to a plausible
|
|
52220
|
+
* continuation" of a confirmed predecessor — a track the operator sees break
|
|
52221
|
+
* (follow-up 617, F5). Every one of them is past `hardRejection`, so the
|
|
52222
|
+
* predecessor is confirmed. NOT here (fix round 1): `unconfirmed`;
|
|
52223
|
+
* `has-successor` (continued elsewhere); `concurrent` and `identity-conflict`
|
|
52224
|
+
* (two subjects — the normal case, and the most frequent); `dropped` (an
|
|
52225
|
+
* operator delete or a refused chain).
|
|
52226
|
+
*/
|
|
52227
|
+
var BREAK_REJECTIONS = new Set([
|
|
52228
|
+
"reach",
|
|
52229
|
+
"area",
|
|
52230
|
+
"appearance",
|
|
52231
|
+
"contested",
|
|
52232
|
+
"cost"
|
|
52233
|
+
]);
|
|
52234
|
+
/** The confirmed predecessors whose link a decision rejected as a break (F5). */
|
|
52235
|
+
function confirmedPredecessorRejections(candidates) {
|
|
52236
|
+
const out = [];
|
|
52237
|
+
for (const c of candidates ?? []) {
|
|
52238
|
+
if (c.rejected === void 0 || !BREAK_REJECTIONS.has(c.rejected)) continue;
|
|
52239
|
+
out.push({
|
|
52240
|
+
from: c.from,
|
|
52241
|
+
rejected: c.rejected,
|
|
52242
|
+
gapMs: c.gapMs
|
|
52243
|
+
});
|
|
52244
|
+
}
|
|
52245
|
+
return out;
|
|
52246
|
+
}
|
|
51926
52247
|
function arcFacts(a) {
|
|
51927
52248
|
return {
|
|
51928
52249
|
from: a.from.id,
|
|
@@ -52000,6 +52321,26 @@ var DeferredLinker = class {
|
|
|
52000
52321
|
if (seen === void 0) this.names.set(p.id, new Set([p.identity]));
|
|
52001
52322
|
else seen.add(p.identity);
|
|
52002
52323
|
}
|
|
52324
|
+
/**
|
|
52325
|
+
* A clock step (follow-up 617, fix round 2): every piece still undecided is
|
|
52326
|
+
* decided `new`, so nothing that existed before the step can be absorbed
|
|
52327
|
+
* across it — whatever was ready was committed just before. The facade
|
|
52328
|
+
* rebases its clock past `LINK_MAX_GAP_MS`, so no later piece can continue
|
|
52329
|
+
* one of these either. An extra id, never a mix-up.
|
|
52330
|
+
*/
|
|
52331
|
+
closeUndecided(now, pieces) {
|
|
52332
|
+
for (const p of pieces) this.accept(p, now);
|
|
52333
|
+
for (const p of this.pieces.values()) {
|
|
52334
|
+
if (this.outcomes.has(p.id)) continue;
|
|
52335
|
+
this.decide(p.id, "new");
|
|
52336
|
+
this.observer?.({
|
|
52337
|
+
t: now,
|
|
52338
|
+
kind: "new",
|
|
52339
|
+
to: p.id,
|
|
52340
|
+
reason: "clock-step"
|
|
52341
|
+
});
|
|
52342
|
+
}
|
|
52343
|
+
}
|
|
52003
52344
|
isTailFinal(id, now, isLive) {
|
|
52004
52345
|
const root = this.rootOf(id);
|
|
52005
52346
|
if (this.pieces.has(root) && !this.outcomes.has(root)) return false;
|
|
@@ -52750,7 +53091,15 @@ var Tracklet = class {
|
|
|
52750
53091
|
h: this.assocBox.h
|
|
52751
53092
|
};
|
|
52752
53093
|
}
|
|
53094
|
+
/**
|
|
53095
|
+
* A confident sighting. One OLDER than the last (`t < lastSeenAt` — ~1 % of
|
|
53096
|
+
* frames reach the tracker out of capture order, up to 1.2 s back) is
|
|
53097
|
+
* `stale`: it changes nothing. A rewound tracklet would be measured from a
|
|
53098
|
+
* box its subject left a second ago, and L2 refused a link by reach on
|
|
53099
|
+
* exactly that (follow-up 617, F1). The caller reports it.
|
|
53100
|
+
*/
|
|
52753
53101
|
observeConfident(det, t, faceBearing) {
|
|
53102
|
+
if (t < this.lastSeenAt) return "stale";
|
|
52754
53103
|
const dt = t - this.lastSeenAt;
|
|
52755
53104
|
if (dt > 0) {
|
|
52756
53105
|
const from = centreOf(this.lastBox);
|
|
@@ -52762,6 +53111,7 @@ var Tracklet = class {
|
|
|
52762
53111
|
this.emitIntervalMs = dt;
|
|
52763
53112
|
}
|
|
52764
53113
|
this.recordConfident(det, t, faceBearing);
|
|
53114
|
+
return "recorded";
|
|
52765
53115
|
}
|
|
52766
53116
|
observeLowScore(box, t) {
|
|
52767
53117
|
this.assocBox = box;
|
|
@@ -52863,6 +53213,15 @@ var TrackletTracker = class {
|
|
|
52863
53213
|
demoteSilent(t) {
|
|
52864
53214
|
for (const tr of this.live.values()) if (tr.mode === "active" && t - tr.lastSeenAt > MAX_PREDICTION_MS) tr.mode = "coasting";
|
|
52865
53215
|
}
|
|
53216
|
+
/** Ends every live tracklet at its own last sighting (a clock step); the ids it ended. */
|
|
53217
|
+
endAll(reason) {
|
|
53218
|
+
const ended = [];
|
|
53219
|
+
for (const tr of [...this.live.values()]) {
|
|
53220
|
+
ended.push(tr.id);
|
|
53221
|
+
this.finish(tr, tr.lastSeenAt, reason);
|
|
53222
|
+
}
|
|
53223
|
+
return ended;
|
|
53224
|
+
}
|
|
52866
53225
|
/** Silence: end what the coast budget no longer covers. */
|
|
52867
53226
|
expire(now) {
|
|
52868
53227
|
for (const tr of [...this.live.values()]) if (now - tr.lastSeenAt > this.config.maxMissedMs) this.finish(tr, tr.lastSeenAt, "missed");
|
|
@@ -52953,12 +53312,12 @@ var TrackletTracker = class {
|
|
|
52953
53312
|
const d = frame.detections[pair.detection];
|
|
52954
53313
|
if (tr === void 0 || d === void 0) return;
|
|
52955
53314
|
frame.used.add(pair.detection);
|
|
53315
|
+
if (tr.observeConfident(d, frame.t, frame.ctx.faceBearing?.has(d.bbox) === true) === "stale") return;
|
|
52956
53316
|
tr.mode = "active";
|
|
52957
53317
|
if (d.class !== tr.klass) this.refuse({
|
|
52958
53318
|
reason: "cross-class-absorbed",
|
|
52959
53319
|
against: tr
|
|
52960
53320
|
}, d);
|
|
52961
|
-
tr.observeConfident(d, frame.t, frame.ctx.faceBearing?.has(d.bbox) === true);
|
|
52962
53321
|
if (pair.contested) {
|
|
52963
53322
|
tr.contestedHits += 1;
|
|
52964
53323
|
tr.contestedSince ??= frame.t;
|
|
@@ -53147,27 +53506,151 @@ var TrackerV2 = class {
|
|
|
53147
53506
|
l1;
|
|
53148
53507
|
l2;
|
|
53149
53508
|
pending = [];
|
|
53509
|
+
/**
|
|
53510
|
+
* Internal time = the caller's frame time + `offset`. Zero until a clock
|
|
53511
|
+
* step; each step moves it so the internal clock never goes back and
|
|
53512
|
+
* resumes past `LINK_MAX_GAP_MS` of silence (fix round 2, C1). L1, L2, their
|
|
53513
|
+
* facts and prunes run on internal time; fusions and `frameClock()` are
|
|
53514
|
+
* handed back in the caller's clock.
|
|
53515
|
+
*/
|
|
53516
|
+
offset = 0;
|
|
53150
53517
|
lastT = 0;
|
|
53518
|
+
/** The latest FRAME time taken (internal) — never the sweep's extrapolated `now`. */
|
|
53519
|
+
lastFrameT = Number.NEGATIVE_INFINITY;
|
|
53520
|
+
observers;
|
|
53521
|
+
/** Caller times of the consecutive frames past the stale bound so far — the
|
|
53522
|
+
* run a clock step needs `CLOCK_STEP_CONFIRM_FRAMES` of (fix round 3). */
|
|
53523
|
+
stepRun = [];
|
|
53151
53524
|
constructor(config, deps) {
|
|
53152
53525
|
this.config = config;
|
|
53153
|
-
this.
|
|
53526
|
+
this.observers = deps.observers ?? {};
|
|
53527
|
+
const out = this.observers;
|
|
53528
|
+
const internal = {
|
|
53529
|
+
...out.refusal !== void 0 ? { refusal: out.refusal } : {},
|
|
53530
|
+
ended: (f) => out.ended?.({
|
|
53531
|
+
...f,
|
|
53532
|
+
at: f.at - this.offset
|
|
53533
|
+
}),
|
|
53534
|
+
split: (f) => out.split?.({
|
|
53535
|
+
...f,
|
|
53536
|
+
t: f.t - this.offset
|
|
53537
|
+
})
|
|
53538
|
+
};
|
|
53539
|
+
this.l1 = new TrackletTracker(config, deps.mintTrackId, internal);
|
|
53154
53540
|
this.l2 = new DeferredLinker({
|
|
53155
53541
|
maxMissedMs: config.maxMissedMs,
|
|
53156
53542
|
appearanceResolvesAmbiguity: config.appearanceResolvesAmbiguity
|
|
53157
|
-
},
|
|
53543
|
+
}, (f) => out.link?.({
|
|
53544
|
+
...f,
|
|
53545
|
+
t: f.t - this.offset
|
|
53546
|
+
}));
|
|
53158
53547
|
}
|
|
53159
|
-
update(detections,
|
|
53548
|
+
update(detections, frameT, ctx) {
|
|
53549
|
+
const order = this.classifyFrame(frameT);
|
|
53550
|
+
if (order === "out-of-order") return this.drop(frameT, detections.length);
|
|
53551
|
+
let t = frameT + this.offset;
|
|
53552
|
+
if (order === "clock-step") t = this.clockStep(frameT, this.lastFrameT - t);
|
|
53553
|
+
this.stepRun = [];
|
|
53554
|
+
this.lastFrameT = t;
|
|
53160
53555
|
this.lastT = Math.max(this.lastT, t);
|
|
53161
53556
|
const step = this.l1.step(detections, t, ctx);
|
|
53162
53557
|
this.link(this.lastT);
|
|
53163
53558
|
return step.emissions.map((e) => this.emit(e, t));
|
|
53164
53559
|
}
|
|
53165
53560
|
/**
|
|
53561
|
+
* A frame stamped before the latest one already taken (follow-up 617, F1;
|
|
53562
|
+
* ~1 % of frames, up to 1.2 s back). It is decided ONCE, for the whole
|
|
53563
|
+
* frame (fix round 1, H1): matched against the tracklets' NEWEST boxes, a
|
|
53564
|
+
* stale box can land on another subject — a walker's old box on the walker
|
|
53565
|
+
* behind — and be emitted under that id. So nothing binds, spawns, splits or
|
|
53566
|
+
* is demoted on it; the confirmed tracklets are emitted as on a frame that
|
|
53567
|
+
* matched nothing (no sighting), and one fact says the frame was dropped.
|
|
53568
|
+
*/
|
|
53569
|
+
/**
|
|
53570
|
+
* How `update` will take a frame at `frameT` — without taking it. The
|
|
53571
|
+
* processor asks first (fix round 3, MEDIUM-2), so a dropped frame never
|
|
53572
|
+
* reaches the stationary gate, the zones or the event path.
|
|
53573
|
+
* - `in-order`: not behind the latest frame taken;
|
|
53574
|
+
* - `out-of-order`: behind it — within `maxMissedMs` (disorder, ≤ 1.2 s
|
|
53575
|
+
* measured), or further back but not yet the `CLOCK_STEP_CONFIRM_FRAMES`-th
|
|
53576
|
+
* such frame in a row;
|
|
53577
|
+
* - `clock-step`: the K-th consecutive frame past the bound, each in order
|
|
53578
|
+
* with the one before (within `maxMissedMs`).
|
|
53579
|
+
*/
|
|
53580
|
+
classifyFrame(frameT) {
|
|
53581
|
+
const behindMs = this.lastFrameT - (frameT + this.offset);
|
|
53582
|
+
if (!(behindMs > 0)) return "in-order";
|
|
53583
|
+
if (behindMs <= this.config.maxMissedMs) return "out-of-order";
|
|
53584
|
+
return this.runLength(frameT) >= CLOCK_STEP_CONFIRM_FRAMES ? "clock-step" : "out-of-order";
|
|
53585
|
+
}
|
|
53586
|
+
/** The past-bound run this frame would make, itself included. */
|
|
53587
|
+
runLength(frameT) {
|
|
53588
|
+
const prev = this.stepRun.at(-1);
|
|
53589
|
+
return (prev !== void 0 && frameT >= prev && frameT - prev <= this.config.maxMissedMs ? this.stepRun.length : 0) + 1;
|
|
53590
|
+
}
|
|
53591
|
+
/**
|
|
53592
|
+
* Drops a frame `classifyFrame` called `out-of-order`. A frame past the
|
|
53593
|
+
* bound extends (or restarts) the run a clock step needs; any other breaks
|
|
53594
|
+
* it. One fact per frame.
|
|
53595
|
+
*/
|
|
53596
|
+
drop(frameT, detections) {
|
|
53597
|
+
const behindMs = this.lastFrameT - (frameT + this.offset);
|
|
53598
|
+
let pendingClockStep = 0;
|
|
53599
|
+
if (behindMs > this.config.maxMissedMs) {
|
|
53600
|
+
pendingClockStep = this.runLength(frameT);
|
|
53601
|
+
this.stepRun = pendingClockStep === 1 ? [frameT] : [...this.stepRun, frameT];
|
|
53602
|
+
} else this.stepRun = [];
|
|
53603
|
+
this.observers.outOfOrder?.({
|
|
53604
|
+
t: frameT,
|
|
53605
|
+
lastFrameT: this.frameClock(),
|
|
53606
|
+
behindMs,
|
|
53607
|
+
detections,
|
|
53608
|
+
pendingClockStep
|
|
53609
|
+
});
|
|
53610
|
+
return this.l1.liveTracklets().filter((tr) => tr.confirmed).map((tracklet) => this.emit({
|
|
53611
|
+
tracklet,
|
|
53612
|
+
detection: void 0,
|
|
53613
|
+
matched: false
|
|
53614
|
+
}, this.lastFrameT));
|
|
53615
|
+
}
|
|
53616
|
+
/**
|
|
53617
|
+
* The frame clock stepped back further than `maxMissedMs` (fix round 2, C1):
|
|
53618
|
+
* not disorder — an NTP correction, or a camera moved to a runner whose clock
|
|
53619
|
+
* is behind. An unbounded gate dropped every frame until the new clock passed
|
|
53620
|
+
* the old high mark (60 s back: 461 frames, a new subject never tracked, the
|
|
53621
|
+
* departed one coasting on). Instead: commit what L2 has decided, end every
|
|
53622
|
+
* live tracklet at its own last sighting, decide every piece still undecided
|
|
53623
|
+
* `new` (no fusion crosses the step), and resume the internal clock past
|
|
53624
|
+
* `LINK_MAX_GAP_MS` of silence, so nothing later can continue anything
|
|
53625
|
+
* earlier. Returns the frame's internal time.
|
|
53626
|
+
*/
|
|
53627
|
+
clockStep(frameT, behindMs) {
|
|
53628
|
+
const lastFrameT = this.frameClock();
|
|
53629
|
+
this.link(this.lastT);
|
|
53630
|
+
const ended = this.l1.endAll("clock-step");
|
|
53631
|
+
this.l2.closeUndecided(this.lastT, this.pieces());
|
|
53632
|
+
const resumeAt = Math.max(this.lastT, this.lastFrameT) + LINK_MAX_GAP_MS + 1;
|
|
53633
|
+
this.offset = resumeAt - frameT;
|
|
53634
|
+
this.lastT = resumeAt;
|
|
53635
|
+
this.observers.clockStep?.({
|
|
53636
|
+
t: frameT,
|
|
53637
|
+
lastFrameT,
|
|
53638
|
+
behindMs,
|
|
53639
|
+
ended
|
|
53640
|
+
});
|
|
53641
|
+
return resumeAt;
|
|
53642
|
+
}
|
|
53643
|
+
/** The latest frame time taken, in the caller's clock (rebased by a clock step). */
|
|
53644
|
+
frameClock() {
|
|
53645
|
+
return this.lastFrameT - this.offset;
|
|
53646
|
+
}
|
|
53647
|
+
/**
|
|
53166
53648
|
* The close sweep's entry on a camera whose frames stopped (D438): end the
|
|
53167
53649
|
* tracklets the coast budget no longer covers, THEN run L2 (review C2).
|
|
53168
53650
|
* `now` is FRAME time (the processor converts wall clock, Task 11).
|
|
53169
53651
|
*/
|
|
53170
|
-
advance(
|
|
53652
|
+
advance(frameNow) {
|
|
53653
|
+
const now = frameNow + this.offset;
|
|
53171
53654
|
this.lastT = Math.max(this.lastT, now);
|
|
53172
53655
|
this.l1.expire(now);
|
|
53173
53656
|
this.link(now);
|
|
@@ -53183,6 +53666,7 @@ var TrackerV2 = class {
|
|
|
53183
53666
|
markSuppressed(id) {
|
|
53184
53667
|
this.l1.markSuppressed(id);
|
|
53185
53668
|
}
|
|
53669
|
+
/** In the caller's clock (translated when each was committed, LOW-5). */
|
|
53186
53670
|
drainFusions() {
|
|
53187
53671
|
const out = this.pending;
|
|
53188
53672
|
this.pending = [];
|
|
@@ -53195,8 +53679,8 @@ var TrackerV2 = class {
|
|
|
53195
53679
|
isLive(id) {
|
|
53196
53680
|
return this.l2.membersOf(this.l2.rootOf(id)).some((m) => this.isLiveTracklet(m));
|
|
53197
53681
|
}
|
|
53198
|
-
isTailFinal(id,
|
|
53199
|
-
return this.l2.isTailFinal(id,
|
|
53682
|
+
isTailFinal(id, frameNow) {
|
|
53683
|
+
return this.l2.isTailFinal(id, frameNow + this.offset, (m) => this.isLiveTracklet(m));
|
|
53200
53684
|
}
|
|
53201
53685
|
/**
|
|
53202
53686
|
* Ends every live member of the chain. `stationary` (round 4): the
|
|
@@ -53212,9 +53696,15 @@ var TrackerV2 = class {
|
|
|
53212
53696
|
const tr = this.l1.get(id);
|
|
53213
53697
|
return tr !== void 0 && tr.endedAt === null;
|
|
53214
53698
|
}
|
|
53699
|
+
pieces() {
|
|
53700
|
+
return [...this.l1.liveTracklets(), ...this.l1.endedTracklets()].map(toPiece);
|
|
53701
|
+
}
|
|
53215
53702
|
link(now) {
|
|
53216
|
-
const
|
|
53217
|
-
|
|
53703
|
+
const offset = this.offset;
|
|
53704
|
+
for (const f of this.l2.step(now, this.pieces())) this.pending.push({
|
|
53705
|
+
...f,
|
|
53706
|
+
t: f.t - offset
|
|
53707
|
+
});
|
|
53218
53708
|
this.l1.prune(now);
|
|
53219
53709
|
this.l2.prune(now);
|
|
53220
53710
|
}
|
|
@@ -53277,7 +53767,8 @@ var NO_ENDS = {
|
|
|
53277
53767
|
missed: 0,
|
|
53278
53768
|
ambiguous: 0,
|
|
53279
53769
|
dropped: 0,
|
|
53280
|
-
stationary: 0
|
|
53770
|
+
stationary: 0,
|
|
53771
|
+
"clock-step": 0
|
|
53281
53772
|
};
|
|
53282
53773
|
function emptyStats() {
|
|
53283
53774
|
return {
|
|
@@ -53290,16 +53781,28 @@ function emptyStats() {
|
|
|
53290
53781
|
linksRefused: 0,
|
|
53291
53782
|
linksNew: 0,
|
|
53292
53783
|
linksDisagreed: 0,
|
|
53293
|
-
lowScoreHolds: 0
|
|
53784
|
+
lowScoreHolds: 0,
|
|
53785
|
+
outOfOrderFrames: 0,
|
|
53786
|
+
clockSteps: 0
|
|
53294
53787
|
};
|
|
53295
53788
|
}
|
|
53296
53789
|
/** Nothing happened in the window: no tracklet ended, no split, no L2
|
|
53297
53790
|
* decision, no low-score hold (review LOW-N1 — what the sweep stays quiet about). */
|
|
53298
53791
|
function isIdleTrackerStats(stats) {
|
|
53299
|
-
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;
|
|
53792
|
+
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;
|
|
53300
53793
|
}
|
|
53301
53794
|
/** Shared empty — a fold is rare and every other frame would allocate. */
|
|
53302
53795
|
var EMPTY_RIDER_FOLDS = [];
|
|
53796
|
+
/** The tape observation of a dropped frame: no gate verdict, nothing bound. */
|
|
53797
|
+
var DROPPED_FRAME_OBSERVATION = {
|
|
53798
|
+
gate: {
|
|
53799
|
+
strong: [],
|
|
53800
|
+
weak: [],
|
|
53801
|
+
confirmed: [],
|
|
53802
|
+
woken: []
|
|
53803
|
+
},
|
|
53804
|
+
live: []
|
|
53805
|
+
};
|
|
53303
53806
|
/** Mapping from StateAnalyzer's `ObjectState.state` values to the
|
|
53304
53807
|
* canonical TrackState enum used on tracks + events. */
|
|
53305
53808
|
function mapObjectStateToTrackState(s) {
|
|
@@ -53478,6 +53981,14 @@ var FrameProcessor = class {
|
|
|
53478
53981
|
else if (f.kind === "new") this.stats.linksNew += 1;
|
|
53479
53982
|
else if (f.kind === "disagreed") this.stats.linksDisagreed += 1;
|
|
53480
53983
|
this.trackerObservers.link?.(f);
|
|
53984
|
+
},
|
|
53985
|
+
outOfOrder: (f) => {
|
|
53986
|
+
this.stats.outOfOrderFrames += 1;
|
|
53987
|
+
this.trackerObservers.outOfOrder?.(f);
|
|
53988
|
+
},
|
|
53989
|
+
clockStep: (f) => {
|
|
53990
|
+
this.stats.clockSteps += 1;
|
|
53991
|
+
this.trackerObservers.clockStep?.(f);
|
|
53481
53992
|
}
|
|
53482
53993
|
}
|
|
53483
53994
|
});
|
|
@@ -53761,6 +54272,37 @@ var FrameProcessor = class {
|
|
|
53761
54272
|
* Zero is the expected reading; a rising one means two people stand close
|
|
53762
54273
|
* together on this camera, which is worth knowing per-camera rather than
|
|
53763
54274
|
* per-fleet. */
|
|
54275
|
+
/**
|
|
54276
|
+
* A frame `classifyFrame` called out of order: the tracker records the drop
|
|
54277
|
+
* (and any clock-step run it extends) and nothing else reads the frame. The
|
|
54278
|
+
* per-frame side tables a reader asks for afterwards are emptied, so it never
|
|
54279
|
+
* re-reads the previous frame's.
|
|
54280
|
+
*/
|
|
54281
|
+
droppedFrame(input) {
|
|
54282
|
+
this.tracker.drop(input.timestamp, input.frame.detections.length);
|
|
54283
|
+
this.lastZoneOverlaps = /* @__PURE__ */ new Map();
|
|
54284
|
+
this.lastZoneRejections = /* @__PURE__ */ new Map();
|
|
54285
|
+
this.lastLabelWriteRefusals = [];
|
|
54286
|
+
const fusions = this.tracker.drainFusions();
|
|
54287
|
+
this.applyFusions(fusions);
|
|
54288
|
+
return {
|
|
54289
|
+
deviceId: this.deviceId,
|
|
54290
|
+
timestamp: input.timestamp,
|
|
54291
|
+
frameWidth: input.frame.width,
|
|
54292
|
+
frameHeight: input.frame.height,
|
|
54293
|
+
tracked: [],
|
|
54294
|
+
objectEvents: [],
|
|
54295
|
+
appearanceEvents: [],
|
|
54296
|
+
rawTrackedDetections: [],
|
|
54297
|
+
stationaryConfirmed: [],
|
|
54298
|
+
stationaryWoken: [],
|
|
54299
|
+
stationaryContinued: 0,
|
|
54300
|
+
riderFolds: [],
|
|
54301
|
+
...input.observe === true ? { observation: DROPPED_FRAME_OBSERVATION } : {},
|
|
54302
|
+
fusions,
|
|
54303
|
+
droppedOutOfOrder: true
|
|
54304
|
+
};
|
|
54305
|
+
}
|
|
53764
54306
|
facesRefusedOutsideParent() {
|
|
53765
54307
|
return this.faceOutsideParentCount;
|
|
53766
54308
|
}
|
|
@@ -53783,6 +54325,7 @@ var FrameProcessor = class {
|
|
|
53783
54325
|
}
|
|
53784
54326
|
process(input) {
|
|
53785
54327
|
const { timestamp, frame } = input;
|
|
54328
|
+
if (this.tracker.classifyFrame(timestamp) === "out-of-order") return this.droppedFrame(input);
|
|
53786
54329
|
this.lastFrameT = timestamp;
|
|
53787
54330
|
this.lastFrameWallAt = this.wallClock();
|
|
53788
54331
|
const frameWidth = frame.width;
|
|
@@ -56534,239 +57077,6 @@ async function promoteTapeWindow(deps, input, signal) {
|
|
|
56534
57077
|
};
|
|
56535
57078
|
}
|
|
56536
57079
|
//#endregion
|
|
56537
|
-
//#region src/pipeline-analytics/store/tracking-tape-index-store.ts
|
|
56538
|
-
/**
|
|
56539
|
-
* @durable class=ledger owner=pipeline-analytics
|
|
56540
|
-
* write="one row per PROMOTED tracking-tape window (`debug.tape.promote`);
|
|
56541
|
-
* updated when the operator marks it reviewed or releases its pins;
|
|
56542
|
-
* deleted together with its file by `debug.tape.delete`."
|
|
56543
|
-
* retention="NOT an age clock and NOT track retention — a promoted window is
|
|
56544
|
-
* history being labelled (D681). Bounded by the promotion budget
|
|
56545
|
-
* (MAX_PROMOTED_TAPES = 60, 1 GiB): a promotion beyond it is REFUSED,
|
|
56546
|
-
* never satisfied by evicting another row."
|
|
56547
|
-
*/
|
|
56548
|
-
var TRACKING_TAPES_COLLECTION = "pipeline-analytics:tracking-tapes";
|
|
56549
|
-
var TRACKING_TAPES_COLUMNS = [
|
|
56550
|
-
{
|
|
56551
|
-
name: "id",
|
|
56552
|
-
type: "TEXT",
|
|
56553
|
-
primaryKey: true,
|
|
56554
|
-
notNull: true
|
|
56555
|
-
},
|
|
56556
|
-
{
|
|
56557
|
-
name: "deviceId",
|
|
56558
|
-
type: "INTEGER",
|
|
56559
|
-
notNull: true
|
|
56560
|
-
},
|
|
56561
|
-
{
|
|
56562
|
-
name: "scenario",
|
|
56563
|
-
type: "TEXT",
|
|
56564
|
-
notNull: true
|
|
56565
|
-
},
|
|
56566
|
-
{
|
|
56567
|
-
name: "note",
|
|
56568
|
-
type: "TEXT"
|
|
56569
|
-
},
|
|
56570
|
-
{
|
|
56571
|
-
name: "lighting",
|
|
56572
|
-
type: "TEXT",
|
|
56573
|
-
notNull: true
|
|
56574
|
-
},
|
|
56575
|
-
{
|
|
56576
|
-
name: "fromMs",
|
|
56577
|
-
type: "INTEGER",
|
|
56578
|
-
notNull: true
|
|
56579
|
-
},
|
|
56580
|
-
{
|
|
56581
|
-
name: "toMs",
|
|
56582
|
-
type: "INTEGER",
|
|
56583
|
-
notNull: true
|
|
56584
|
-
},
|
|
56585
|
-
{
|
|
56586
|
-
name: "state",
|
|
56587
|
-
type: "TEXT",
|
|
56588
|
-
notNull: true
|
|
56589
|
-
},
|
|
56590
|
-
{
|
|
56591
|
-
name: "frames",
|
|
56592
|
-
type: "INTEGER",
|
|
56593
|
-
notNull: true
|
|
56594
|
-
},
|
|
56595
|
-
{
|
|
56596
|
-
name: "skips",
|
|
56597
|
-
type: "INTEGER",
|
|
56598
|
-
notNull: true
|
|
56599
|
-
},
|
|
56600
|
-
{
|
|
56601
|
-
name: "gaps",
|
|
56602
|
-
type: "INTEGER",
|
|
56603
|
-
notNull: true
|
|
56604
|
-
},
|
|
56605
|
-
{
|
|
56606
|
-
name: "bytes",
|
|
56607
|
-
type: "INTEGER",
|
|
56608
|
-
notNull: true
|
|
56609
|
-
},
|
|
56610
|
-
{
|
|
56611
|
-
name: "reviewed",
|
|
56612
|
-
type: "BOOLEAN",
|
|
56613
|
-
notNull: true
|
|
56614
|
-
},
|
|
56615
|
-
{
|
|
56616
|
-
name: "trackIds",
|
|
56617
|
-
type: "TEXT",
|
|
56618
|
-
notNull: true
|
|
56619
|
-
},
|
|
56620
|
-
{
|
|
56621
|
-
name: "createdAt",
|
|
56622
|
-
type: "INTEGER",
|
|
56623
|
-
notNull: true
|
|
56624
|
-
},
|
|
56625
|
-
{
|
|
56626
|
-
name: "releasedAt",
|
|
56627
|
-
type: "INTEGER"
|
|
56628
|
-
},
|
|
56629
|
-
{
|
|
56630
|
-
name: "pinsSettled",
|
|
56631
|
-
type: "BOOLEAN",
|
|
56632
|
-
notNull: true
|
|
56633
|
-
}
|
|
56634
|
-
];
|
|
56635
|
-
var TrackingTapeRowSchema = require_clip_model_registry.object({
|
|
56636
|
-
id: require_clip_model_registry.string(),
|
|
56637
|
-
deviceId: require_clip_model_registry.number().int(),
|
|
56638
|
-
scenario: require_clip_model_registry.string(),
|
|
56639
|
-
note: require_clip_model_registry.string().nullable(),
|
|
56640
|
-
lighting: TapeLightingSchema,
|
|
56641
|
-
fromMs: require_clip_model_registry.number().int(),
|
|
56642
|
-
toMs: require_clip_model_registry.number().int(),
|
|
56643
|
-
state: require_clip_model_registry._enum(["complete", "incomplete"]),
|
|
56644
|
-
frames: require_clip_model_registry.number().int(),
|
|
56645
|
-
skips: require_clip_model_registry.number().int(),
|
|
56646
|
-
gaps: require_clip_model_registry.number().int(),
|
|
56647
|
-
bytes: require_clip_model_registry.number().int(),
|
|
56648
|
-
reviewed: require_clip_model_registry.boolean(),
|
|
56649
|
-
trackIds: require_clip_model_registry.array(require_clip_model_registry.string()),
|
|
56650
|
-
createdAt: require_clip_model_registry.number().int(),
|
|
56651
|
-
releasedAt: require_clip_model_registry.number().int().nullable(),
|
|
56652
|
-
pinsSettled: require_clip_model_registry.boolean()
|
|
56653
|
-
});
|
|
56654
|
-
var TrackIdsSchema = require_clip_model_registry.array(require_clip_model_registry.string());
|
|
56655
|
-
var TrackingTapeIndexStore = class {
|
|
56656
|
-
store;
|
|
56657
|
-
logger;
|
|
56658
|
-
constructor(deps) {
|
|
56659
|
-
this.store = deps.store;
|
|
56660
|
-
this.logger = deps.logger;
|
|
56661
|
-
}
|
|
56662
|
-
static async declare(store) {
|
|
56663
|
-
await store.declareCollection.mutate({
|
|
56664
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56665
|
-
columns: [...TRACKING_TAPES_COLUMNS],
|
|
56666
|
-
indexes: [{
|
|
56667
|
-
name: "idx_trackingtapes_device_created",
|
|
56668
|
-
columns: ["deviceId", "createdAt"]
|
|
56669
|
-
}]
|
|
56670
|
-
});
|
|
56671
|
-
}
|
|
56672
|
-
async insert(row) {
|
|
56673
|
-
const { id, trackIds, ...rest } = TrackingTapeRowSchema.parse(row);
|
|
56674
|
-
await this.store.insert.mutate({
|
|
56675
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56676
|
-
record: {
|
|
56677
|
-
id,
|
|
56678
|
-
data: {
|
|
56679
|
-
...rest,
|
|
56680
|
-
trackIds: JSON.stringify(trackIds)
|
|
56681
|
-
}
|
|
56682
|
-
}
|
|
56683
|
-
});
|
|
56684
|
-
}
|
|
56685
|
-
async get(id) {
|
|
56686
|
-
const first = (await this.store.query.query({
|
|
56687
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56688
|
-
filter: {
|
|
56689
|
-
where: { id },
|
|
56690
|
-
limit: 1
|
|
56691
|
-
}
|
|
56692
|
-
}))[0];
|
|
56693
|
-
return first === void 0 ? null : this.parse(first.id, first.data);
|
|
56694
|
-
}
|
|
56695
|
-
async list(deviceId) {
|
|
56696
|
-
const rows = await this.store.query.query({
|
|
56697
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56698
|
-
filter: {
|
|
56699
|
-
...deviceId !== void 0 ? { where: { deviceId } } : {},
|
|
56700
|
-
orderBy: {
|
|
56701
|
-
field: "createdAt",
|
|
56702
|
-
direction: "desc"
|
|
56703
|
-
},
|
|
56704
|
-
limit: 1e3
|
|
56705
|
-
}
|
|
56706
|
-
});
|
|
56707
|
-
const out = [];
|
|
56708
|
-
for (const r of rows) {
|
|
56709
|
-
const parsed = this.parse(r.id, r.data);
|
|
56710
|
-
if (parsed !== null) out.push(parsed);
|
|
56711
|
-
}
|
|
56712
|
-
return out;
|
|
56713
|
-
}
|
|
56714
|
-
async setReviewed(id, reviewed) {
|
|
56715
|
-
await this.store.update.mutate({
|
|
56716
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56717
|
-
id,
|
|
56718
|
-
data: { reviewed }
|
|
56719
|
-
});
|
|
56720
|
-
}
|
|
56721
|
-
/** Release AND unsettle in one row write: the unpins the release implies
|
|
56722
|
-
* are owed from this moment, whether or not the caller lives to make them. */
|
|
56723
|
-
async setReleased(id, atMs) {
|
|
56724
|
-
await this.store.update.mutate({
|
|
56725
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56726
|
-
id,
|
|
56727
|
-
data: {
|
|
56728
|
-
releasedAt: atMs,
|
|
56729
|
-
pinsSettled: false
|
|
56730
|
-
}
|
|
56731
|
-
});
|
|
56732
|
-
}
|
|
56733
|
-
async setPinsSettled(id, settled) {
|
|
56734
|
-
await this.store.update.mutate({
|
|
56735
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56736
|
-
id,
|
|
56737
|
-
data: { pinsSettled: settled }
|
|
56738
|
-
});
|
|
56739
|
-
}
|
|
56740
|
-
async remove(id) {
|
|
56741
|
-
await this.store.delete.mutate({
|
|
56742
|
-
collection: TRACKING_TAPES_COLLECTION,
|
|
56743
|
-
key: id
|
|
56744
|
-
});
|
|
56745
|
-
}
|
|
56746
|
-
parse(id, data) {
|
|
56747
|
-
let trackIds = [];
|
|
56748
|
-
try {
|
|
56749
|
-
trackIds = JSON.parse(String(data["trackIds"] ?? "[]"));
|
|
56750
|
-
} catch {
|
|
56751
|
-
trackIds = null;
|
|
56752
|
-
}
|
|
56753
|
-
const ids = TrackIdsSchema.safeParse(trackIds);
|
|
56754
|
-
const parsed = TrackingTapeRowSchema.safeParse({
|
|
56755
|
-
id,
|
|
56756
|
-
...data,
|
|
56757
|
-
note: data["note"] ?? null,
|
|
56758
|
-
releasedAt: data["releasedAt"] ?? null,
|
|
56759
|
-
trackIds: ids.success ? ids.data : null
|
|
56760
|
-
});
|
|
56761
|
-
if (parsed.success) return parsed.data;
|
|
56762
|
-
this.logger.warn("tracking tape index: skipped a malformed row", {
|
|
56763
|
-
meta: { id },
|
|
56764
|
-
...typeof data["deviceId"] === "number" ? { tags: { deviceId: data["deviceId"] } } : {}
|
|
56765
|
-
});
|
|
56766
|
-
return null;
|
|
56767
|
-
}
|
|
56768
|
-
};
|
|
56769
|
-
//#endregion
|
|
56770
57080
|
//#region src/pipeline-analytics/tracking-bench/recorder/tape-status.ts
|
|
56771
57081
|
/** The one node that may hold tapes: sqlite and bulk state are hub-only, and
|
|
56772
57082
|
* an agent persists nothing (spec §3.1). */
|
|
@@ -97697,6 +98007,12 @@ var TRACKER_FACT_LOG_SAMPLE_EVERY = 10;
|
|
|
97697
98007
|
* positive spawns (review M1: ~1 750 `new` decisions per camera per hour) —
|
|
97698
98008
|
* are sampled harder; the per-minute summary carries their exact counts. */
|
|
97699
98009
|
var TRACKER_PIECE_LOG_SAMPLE_EVERY = 50;
|
|
98010
|
+
/** Out-of-order frames (follow-up 617, F1: ~1 % of frames) log the first N,
|
|
98011
|
+
* then one in this many — every line carries the count; the per-minute
|
|
98012
|
+
* summary carries the exact `outOfOrderFrames`. */
|
|
98013
|
+
var TRACKER_OUT_OF_ORDER_LOG_SAMPLE_EVERY = 50;
|
|
98014
|
+
/** Clock-step WARNs past the first ten (fix round 3, MEDIUM-1). */
|
|
98015
|
+
var TRACKER_CLOCK_STEP_LOG_SAMPLE_EVERY = 50;
|
|
97700
98016
|
/** First N, then one in `every` — the refusal stream's cadence (D391). */
|
|
97701
98017
|
function sampledTrackerFact(count, every = TRACKER_FACT_LOG_SAMPLE_EVERY) {
|
|
97702
98018
|
return count <= TRACKER_FACT_LOG_ALWAYS_FIRST || count % every === 0;
|
|
@@ -102344,9 +102660,11 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
102344
102660
|
let splitCount = 0;
|
|
102345
102661
|
let ignoredCount = 0;
|
|
102346
102662
|
let newCount = 0;
|
|
102663
|
+
let outOfOrderCount = 0;
|
|
102664
|
+
let clockStepCount = 0;
|
|
102347
102665
|
const endedCounts = /* @__PURE__ */ new Map();
|
|
102348
102666
|
const logLink = (f) => {
|
|
102349
|
-
const
|
|
102667
|
+
const decision = {
|
|
102350
102668
|
source,
|
|
102351
102669
|
t: f.t,
|
|
102352
102670
|
kind: f.kind,
|
|
@@ -102355,7 +102673,10 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
102355
102673
|
cost: f.cost,
|
|
102356
102674
|
gapMs: f.gapMs,
|
|
102357
102675
|
reason: f.reason,
|
|
102358
|
-
recognition: f.recognition
|
|
102676
|
+
recognition: f.recognition
|
|
102677
|
+
};
|
|
102678
|
+
const meta = {
|
|
102679
|
+
...decision,
|
|
102359
102680
|
candidates: f.candidates
|
|
102360
102681
|
};
|
|
102361
102682
|
switch (f.kind) {
|
|
@@ -102393,7 +102714,14 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
102393
102714
|
meta
|
|
102394
102715
|
});
|
|
102395
102716
|
return;
|
|
102396
|
-
case "new":
|
|
102717
|
+
case "new": {
|
|
102718
|
+
if (f.reason === "clock-step") {
|
|
102719
|
+
trackerLog.debug("tracker: piece decided new — closed by a frame clock step", {
|
|
102720
|
+
tags: { deviceId },
|
|
102721
|
+
meta
|
|
102722
|
+
});
|
|
102723
|
+
return;
|
|
102724
|
+
}
|
|
102397
102725
|
if (f.reason === "unconfirmed") {
|
|
102398
102726
|
trackerLog.debug("tracker: piece decided new — never confirmed", {
|
|
102399
102727
|
tags: { deviceId },
|
|
@@ -102401,6 +102729,17 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
102401
102729
|
});
|
|
102402
102730
|
return;
|
|
102403
102731
|
}
|
|
102732
|
+
const rejectedPredecessors = confirmedPredecessorRejections(f.candidates);
|
|
102733
|
+
if (rejectedPredecessors.length > 0) {
|
|
102734
|
+
trackerLog.info("tracker: piece decided new — a confirmed predecessor was rejected", {
|
|
102735
|
+
tags: { deviceId },
|
|
102736
|
+
meta: {
|
|
102737
|
+
...decision,
|
|
102738
|
+
rejectedPredecessors
|
|
102739
|
+
}
|
|
102740
|
+
});
|
|
102741
|
+
return;
|
|
102742
|
+
}
|
|
102404
102743
|
newCount += 1;
|
|
102405
102744
|
if (!sampledTrackerFact(newCount, TRACKER_PIECE_LOG_SAMPLE_EVERY)) return;
|
|
102406
102745
|
trackerLog.info("tracker: piece decided new — no predecessor", {
|
|
@@ -102411,6 +102750,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
102411
102750
|
}
|
|
102412
102751
|
});
|
|
102413
102752
|
return;
|
|
102753
|
+
}
|
|
102414
102754
|
}
|
|
102415
102755
|
};
|
|
102416
102756
|
p.setTrackerObservers({
|
|
@@ -102431,6 +102771,39 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
102431
102771
|
});
|
|
102432
102772
|
},
|
|
102433
102773
|
link: logLink,
|
|
102774
|
+
clockStep: (f) => {
|
|
102775
|
+
clockStepCount += 1;
|
|
102776
|
+
if (!sampledTrackerFact(clockStepCount, TRACKER_CLOCK_STEP_LOG_SAMPLE_EVERY)) return;
|
|
102777
|
+
trackerLog.warn("tracker: frame clock stepped back — tracklets ended, clock rebased", {
|
|
102778
|
+
tags: { deviceId },
|
|
102779
|
+
meta: {
|
|
102780
|
+
source,
|
|
102781
|
+
t: f.t,
|
|
102782
|
+
lastFrameT: f.lastFrameT,
|
|
102783
|
+
behindMs: f.behindMs,
|
|
102784
|
+
ended: f.ended,
|
|
102785
|
+
clockStepCount,
|
|
102786
|
+
sampledEvery: TRACKER_CLOCK_STEP_LOG_SAMPLE_EVERY
|
|
102787
|
+
}
|
|
102788
|
+
});
|
|
102789
|
+
},
|
|
102790
|
+
outOfOrder: (f) => {
|
|
102791
|
+
outOfOrderCount += 1;
|
|
102792
|
+
if (!sampledTrackerFact(outOfOrderCount, TRACKER_OUT_OF_ORDER_LOG_SAMPLE_EVERY)) return;
|
|
102793
|
+
trackerLog.info("tracker: out-of-order frame dropped — older than the latest frame", {
|
|
102794
|
+
tags: { deviceId },
|
|
102795
|
+
meta: {
|
|
102796
|
+
source,
|
|
102797
|
+
t: f.t,
|
|
102798
|
+
lastFrameT: f.lastFrameT,
|
|
102799
|
+
behindMs: f.behindMs,
|
|
102800
|
+
detections: f.detections,
|
|
102801
|
+
pendingClockStep: f.pendingClockStep,
|
|
102802
|
+
outOfOrderCount,
|
|
102803
|
+
sampledEvery: TRACKER_OUT_OF_ORDER_LOG_SAMPLE_EVERY
|
|
102804
|
+
}
|
|
102805
|
+
});
|
|
102806
|
+
},
|
|
102434
102807
|
ended: (f) => {
|
|
102435
102808
|
const k = `${f.reason}:${String(f.confirmed)}`;
|
|
102436
102809
|
const n = (endedCounts.get(k) ?? 0) + 1;
|
|
@@ -102572,6 +102945,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
102572
102945
|
});
|
|
102573
102946
|
});
|
|
102574
102947
|
this.reportTrackerSummary(deviceId, key, processor, "frame");
|
|
102948
|
+
if (result.droppedOutOfOrder === true) return;
|
|
102575
102949
|
for (const r of processor.getLastLabelWriteRefusals()) {
|
|
102576
102950
|
const message = r.reason.kind === "macro-class" ? "label tier collapse refused" : "label write refused";
|
|
102577
102951
|
this.ctx.logger.info(message, {
|