repzo 1.0.291 → 1.0.293
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/changelog.md +28 -0
- package/lib/index.d.ts +244 -2
- package/lib/index.js +541 -0
- package/lib/types/index.d.ts +4533 -1
- package/package.json +1 -1
- package/src/index.ts +1270 -0
- package/src/oas/activity-ai-object-detection-session-frame.yaml +600 -0
- package/src/oas/ai-object-detection-assigned-missions.yaml +283 -0
- package/src/oas/ai-object-detection-assignment-rule.yaml +357 -0
- package/src/oas/ai-object-detection-category.yaml +338 -0
- package/src/oas/ai-object-detection-dataset.yaml +342 -0
- package/src/oas/ai-object-detection-detection-settings.yaml +410 -0
- package/src/oas/ai-object-detection-inference.yaml +818 -0
- package/src/oas/ai-object-detection-label-group.yaml +265 -0
- package/src/oas/ai-object-detection-label-report.yaml +366 -0
- package/src/oas/ai-object-detection-label.yaml +395 -0
- package/src/oas/ai-object-detection-metric-result.yaml +734 -0
- package/src/oas/ai-object-detection-metric.yaml +559 -0
- package/src/oas/ai-object-detection-mission-results.yaml +370 -0
- package/src/oas/ai-object-detection-mission-set.yaml +250 -0
- package/src/oas/ai-object-detection-mission.yaml +349 -0
- package/src/oas/ai-object-detection-model-version-epoch.yaml +214 -0
- package/src/oas/ai-object-detection-model-version-train-agent.yaml +88 -0
- package/src/oas/ai-object-detection-model-version.yaml +567 -0
- package/src/oas/ai-object-detection-model.yaml +369 -0
- package/src/oas/ai-object-detection-segment.yaml +301 -0
- package/src/oas/ai-object-detection-session-analysis.yaml +1306 -0
- package/src/oas/ai-object-detection-session-election.yaml +193 -0
- package/src/oas/ai-object-detection-session-insight.yaml +418 -0
- package/src/oas/ai-object-detection-session.yaml +840 -0
- package/src/oas/ai-object-detection-settings.yaml +249 -0
- package/src/oas/ai-object-detection-task.yaml +1007 -0
- package/src/oas/object-detection-analytics-report.yaml +674 -0
- package/src/types/index.ts +5159 -1
|
@@ -0,0 +1,734 @@
|
|
|
1
|
+
openapi: 3.0.3
|
|
2
|
+
info:
|
|
3
|
+
title: Repzo API - AI Object Detection Metric Result
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
description: |
|
|
6
|
+
**Metric results** — one document per (analysis, metric), holding TWO
|
|
7
|
+
deliberately separate value layers:
|
|
8
|
+
|
|
9
|
+
- `computed` — what the engine calculated from the AI analysis (always
|
|
10
|
+
includes `answer` + `score` 0..1). Machine-owned: every evaluation
|
|
11
|
+
replaces it and humans can NEVER modify it through the API.
|
|
12
|
+
- `overwrite` + `flag` + `confirmed_edit` — the human layer: sparse VALUE
|
|
13
|
+
overrides of the type's overwritable keys (ratio and score are DERIVED
|
|
14
|
+
from them server-side, never accepted), a boolean attention marker,
|
|
15
|
+
and the admin review gate. Human-owned: evaluations never touch them,
|
|
16
|
+
so an override keeps ruling across recalculations.
|
|
17
|
+
|
|
18
|
+
Both layers are STRICT per-type shapes (Mongoose embedded discriminators
|
|
19
|
+
keyed by the metric type — the promotions model pattern); the stored
|
|
20
|
+
subdocuments carry an internal `type` mirror. No loose payloads.
|
|
21
|
+
|
|
22
|
+
**Output families** fix what `answer` means (`output` on the document):
|
|
23
|
+
- `compatibility` (adjacent_block) — `answer` is a boolean verdict;
|
|
24
|
+
score = answer ? 1 : 0.
|
|
25
|
+
- `numerical` (facings_count, on_shelf_availability) — `answer` is the
|
|
26
|
+
collected value. BOTH types accept an optional `target_answer`: the
|
|
27
|
+
score is then answer ÷ target (clamped to 1). Without one, OSA returns
|
|
28
|
+
its own factor (availability = answer ÷ total, so mission points =
|
|
29
|
+
weight × availability) and facings_count falls back to the family
|
|
30
|
+
default: a NON-ZERO answer earns full score, a missing or zero answer
|
|
31
|
+
scores 0.
|
|
32
|
+
- `share_of_shelf` — `answer` is the MAIN segment's measured quantity
|
|
33
|
+
(cm, cm² or facings), `total` the CONSIDERED CATEGORY (the same
|
|
34
|
+
measure over facings whose label belongs to ANY of the metric's
|
|
35
|
+
segments — the rest of the shelf never dilutes the share), `ratio`
|
|
36
|
+
their quotient, `target_answer` = target_ratio × total, and score =
|
|
37
|
+
the main segment's min(1, ratio / target_ratio). Every segment row
|
|
38
|
+
(main + context) is reported as a SegmentOutput in
|
|
39
|
+
`computed.segments[]`.
|
|
40
|
+
|
|
41
|
+
`score` / `answer` / `ratio` on the document are the DENORMALIZED
|
|
42
|
+
EFFECTIVE values — the CONFIRMED `overwrite.*` when `confirmed_edit` is
|
|
43
|
+
true, else `computed.*` — the numbers mission scoring, widgets and
|
|
44
|
+
analytics read. An unconfirmed override is stored and visible but does
|
|
45
|
+
NOT change them.
|
|
46
|
+
|
|
47
|
+
**How results appear.** Automatically: every successful session analysis
|
|
48
|
+
(and every compose-only shelf recompute) evaluates the MISSION-ASSIGNED
|
|
49
|
+
metrics — the stamped mission's list for "SCAN THIS MISSION" sessions,
|
|
50
|
+
the union over the client's currently-assigned missions for generic
|
|
51
|
+
scans. Sessions no mission covers get NO results. Manually:
|
|
52
|
+
`POST { analysis }` recalculates the same assigned set on demand —
|
|
53
|
+
idempotent and safe (an optional `metrics[]` subset can only NARROW the
|
|
54
|
+
assigned set). `source_fingerprints` snapshots the analysis's stage
|
|
55
|
+
fingerprints at evaluation time, so a mismatch marks the result stale.
|
|
56
|
+
Each result also carries a denormalized SCAN CONTEXT (`user`/`user_name`
|
|
57
|
+
= the scanning rep, `client`/`client_name`, `teams`, `visit_id`,
|
|
58
|
+
`route`, `business_day`) in the activity-model shape so shared
|
|
59
|
+
dashboard filters work unchanged.
|
|
60
|
+
|
|
61
|
+
**Re-analysis & the human layer.** A NEW analysis of the same session
|
|
62
|
+
CARRIES the previous analysis's human layer forward (flag,
|
|
63
|
+
confirmed_edit, and the entered override VALUES — an override asserts
|
|
64
|
+
the SCENE's truth, not one machine attempt's), with the derived
|
|
65
|
+
ratio/score re-computed against the fresh machine values. Every
|
|
66
|
+
evaluation and every update here also re-syncs the STORED mission
|
|
67
|
+
results (`/ai-object-detection-mission-results`) of the analysis.
|
|
68
|
+
|
|
69
|
+
**Multi-tenancy, roles & lifecycle.** Scoped by `company_namespace`
|
|
70
|
+
(inherited from the analysis — there is no namespace-injection hook and
|
|
71
|
+
no create body field for it), soft-deleted via `disabled`. `update`
|
|
72
|
+
accepts ONLY `flag`, `overwrite` and (admin-only) `confirmed_edit`;
|
|
73
|
+
`PATCH` is not supported (400). ADMINS have full access. REPS read
|
|
74
|
+
results of THEIR OWN sessions (a `session` or `analysis` filter is
|
|
75
|
+
required on list reads), may raise `flag` (never clear it) and may
|
|
76
|
+
submit value overrides — a rep override is auto-flagged and stays
|
|
77
|
+
PENDING (`confirmed_edit: false`, not effective) until an admin confirms
|
|
78
|
+
it; recalculation and removal are admin-only. Optional population of
|
|
79
|
+
`metric`, `analysis` and `session` via `populatedKeys[]` (the populated
|
|
80
|
+
document replaces the id in place).
|
|
81
|
+
servers:
|
|
82
|
+
- url: https://sv.api.repzo.me
|
|
83
|
+
security:
|
|
84
|
+
- ApiKeyAuth: []
|
|
85
|
+
- JwtAuth: []
|
|
86
|
+
paths:
|
|
87
|
+
/ai-object-detection-metric-result:
|
|
88
|
+
get:
|
|
89
|
+
summary: List metric results
|
|
90
|
+
operationId: findAiObjectDetectionMetricResult
|
|
91
|
+
parameters:
|
|
92
|
+
- in: query
|
|
93
|
+
name: _id
|
|
94
|
+
schema:
|
|
95
|
+
oneOf:
|
|
96
|
+
- type: string
|
|
97
|
+
- type: array
|
|
98
|
+
items: { type: string }
|
|
99
|
+
- in: query
|
|
100
|
+
name: analysis
|
|
101
|
+
description: Filter by the analysis _id (the common read). Required for rep tokens unless `session` is given.
|
|
102
|
+
schema:
|
|
103
|
+
oneOf:
|
|
104
|
+
- type: string
|
|
105
|
+
- type: array
|
|
106
|
+
items: { type: string }
|
|
107
|
+
- in: query
|
|
108
|
+
name: session
|
|
109
|
+
description: Filter by session _id. Rep tokens must own the session.
|
|
110
|
+
schema:
|
|
111
|
+
oneOf:
|
|
112
|
+
- type: string
|
|
113
|
+
- type: array
|
|
114
|
+
items: { type: string }
|
|
115
|
+
- in: query
|
|
116
|
+
name: metric
|
|
117
|
+
schema:
|
|
118
|
+
oneOf:
|
|
119
|
+
- type: string
|
|
120
|
+
- type: array
|
|
121
|
+
items: { type: string }
|
|
122
|
+
- in: query
|
|
123
|
+
name: user
|
|
124
|
+
description: Filter by the SCANNING rep's id (denormalized scan context).
|
|
125
|
+
schema:
|
|
126
|
+
oneOf:
|
|
127
|
+
- type: string
|
|
128
|
+
- type: array
|
|
129
|
+
items: { type: string }
|
|
130
|
+
- in: query
|
|
131
|
+
name: client
|
|
132
|
+
description: Filter by the scanned client's id (denormalized scan context).
|
|
133
|
+
schema:
|
|
134
|
+
oneOf:
|
|
135
|
+
- type: string
|
|
136
|
+
- type: array
|
|
137
|
+
items: { type: string }
|
|
138
|
+
- in: query
|
|
139
|
+
name: teams
|
|
140
|
+
description: "Filter by the scanning rep's team id(s) — pass once or as `?teams[]=`."
|
|
141
|
+
schema:
|
|
142
|
+
oneOf:
|
|
143
|
+
- type: string
|
|
144
|
+
- type: array
|
|
145
|
+
items: { type: string }
|
|
146
|
+
- in: query
|
|
147
|
+
name: type
|
|
148
|
+
schema:
|
|
149
|
+
type: string
|
|
150
|
+
enum:
|
|
151
|
+
[
|
|
152
|
+
adjacent_block,
|
|
153
|
+
facings_count,
|
|
154
|
+
on_shelf_availability,
|
|
155
|
+
share_of_shelf,
|
|
156
|
+
]
|
|
157
|
+
- in: query
|
|
158
|
+
name: flag
|
|
159
|
+
description: Only flagged (or unflagged) results.
|
|
160
|
+
schema: { type: boolean }
|
|
161
|
+
- in: query
|
|
162
|
+
name: status
|
|
163
|
+
schema:
|
|
164
|
+
type: string
|
|
165
|
+
enum: [ok, error]
|
|
166
|
+
- in: query
|
|
167
|
+
name: search
|
|
168
|
+
description: Case-insensitive substring search on the metric-name snapshot `name`.
|
|
169
|
+
schema: { type: string }
|
|
170
|
+
- in: query
|
|
171
|
+
name: disabled
|
|
172
|
+
description: "Include soft-deleted results (`true`) or only live ones (`false`). Omitted = no filter."
|
|
173
|
+
schema: { type: boolean }
|
|
174
|
+
- in: query
|
|
175
|
+
name: from_updatedAt
|
|
176
|
+
schema: { type: number }
|
|
177
|
+
- in: query
|
|
178
|
+
name: to_updatedAt
|
|
179
|
+
schema: { type: number }
|
|
180
|
+
- in: query
|
|
181
|
+
name: from_createdAt
|
|
182
|
+
schema: { type: number }
|
|
183
|
+
- in: query
|
|
184
|
+
name: to_createdAt
|
|
185
|
+
schema: { type: number }
|
|
186
|
+
- in: query
|
|
187
|
+
name: populatedKeys
|
|
188
|
+
description: "Embed refs in place of the id. Supported: `metric`, `analysis`, `session`."
|
|
189
|
+
schema:
|
|
190
|
+
type: array
|
|
191
|
+
items:
|
|
192
|
+
type: string
|
|
193
|
+
enum: [metric, analysis, session]
|
|
194
|
+
- in: query
|
|
195
|
+
name: per_page
|
|
196
|
+
schema: { type: integer, minimum: 1 }
|
|
197
|
+
- in: query
|
|
198
|
+
name: page
|
|
199
|
+
schema: { type: integer, minimum: 1 }
|
|
200
|
+
- in: query
|
|
201
|
+
name: sort
|
|
202
|
+
description: Field to sort by (default `_id`).
|
|
203
|
+
schema: { type: string }
|
|
204
|
+
- in: query
|
|
205
|
+
name: sortPageOrder
|
|
206
|
+
schema:
|
|
207
|
+
type: string
|
|
208
|
+
enum: [asc, dsc]
|
|
209
|
+
responses:
|
|
210
|
+
"200":
|
|
211
|
+
description: Paginated results.
|
|
212
|
+
content:
|
|
213
|
+
application/json:
|
|
214
|
+
schema:
|
|
215
|
+
$ref: "#/components/schemas/MetricResultFindResult"
|
|
216
|
+
"403":
|
|
217
|
+
description: Rep token without a `session`/`analysis` filter, or the session is not the rep's own.
|
|
218
|
+
post:
|
|
219
|
+
summary: Calculate / recalculate metrics for an analysis (admin)
|
|
220
|
+
description: |
|
|
221
|
+
Evaluates every ENABLED, MISSION-ASSIGNED metric (or the given subset
|
|
222
|
+
of them) against the analysis and upserts one result per metric.
|
|
223
|
+
Idempotent: `computed` is replaced, standing `flag`/`overwrite`
|
|
224
|
+
values are preserved and keep ruling the effective `score` while
|
|
225
|
+
confirmed. Also upserts the stored mission results of the session.
|
|
226
|
+
The tenant namespace comes from the caller's token — there is no
|
|
227
|
+
`company_namespace` body field.
|
|
228
|
+
operationId: createAiObjectDetectionMetricResult
|
|
229
|
+
requestBody:
|
|
230
|
+
required: true
|
|
231
|
+
content:
|
|
232
|
+
application/json:
|
|
233
|
+
schema:
|
|
234
|
+
type: object
|
|
235
|
+
required: [analysis]
|
|
236
|
+
properties:
|
|
237
|
+
analysis:
|
|
238
|
+
type: string
|
|
239
|
+
description: The SUCCESSFUL analysis to evaluate.
|
|
240
|
+
metrics:
|
|
241
|
+
type: array
|
|
242
|
+
items: { type: string }
|
|
243
|
+
description: Optional metric-id subset (default = every mission-assigned enabled metric; can only narrow that set).
|
|
244
|
+
responses:
|
|
245
|
+
"201":
|
|
246
|
+
description: Evaluation summary + the fresh result documents.
|
|
247
|
+
content:
|
|
248
|
+
application/json:
|
|
249
|
+
schema:
|
|
250
|
+
type: object
|
|
251
|
+
properties:
|
|
252
|
+
analysis: { type: string }
|
|
253
|
+
evaluated:
|
|
254
|
+
type: number
|
|
255
|
+
description: Metrics evaluated.
|
|
256
|
+
errors:
|
|
257
|
+
type: number
|
|
258
|
+
description: Metrics whose evaluation or persistence failed.
|
|
259
|
+
results:
|
|
260
|
+
type: array
|
|
261
|
+
items:
|
|
262
|
+
$ref: "#/components/schemas/MetricResult"
|
|
263
|
+
"400":
|
|
264
|
+
description: "`analysis` missing, not found, or not in `success` status."
|
|
265
|
+
"403":
|
|
266
|
+
description: Rep tokens may not recalculate.
|
|
267
|
+
/ai-object-detection-metric-result/{id}:
|
|
268
|
+
get:
|
|
269
|
+
summary: Get a metric result
|
|
270
|
+
operationId: getAiObjectDetectionMetricResult
|
|
271
|
+
parameters:
|
|
272
|
+
- in: path
|
|
273
|
+
name: id
|
|
274
|
+
required: true
|
|
275
|
+
schema: { type: string }
|
|
276
|
+
responses:
|
|
277
|
+
"200":
|
|
278
|
+
description: The result document (refs are never populated on this read).
|
|
279
|
+
content:
|
|
280
|
+
application/json:
|
|
281
|
+
schema:
|
|
282
|
+
$ref: "#/components/schemas/MetricResult"
|
|
283
|
+
"400":
|
|
284
|
+
description: Not found.
|
|
285
|
+
"403":
|
|
286
|
+
description: Rep token — the result's session is not the rep's own.
|
|
287
|
+
put:
|
|
288
|
+
summary: Human override — flag / overwrite / confirmed_edit
|
|
289
|
+
description: |
|
|
290
|
+
The ONLY writable fields are `flag`, `overwrite` and (admin-only)
|
|
291
|
+
`confirmed_edit`. `overwrite` accepts VALUE keys only — `ratio` and
|
|
292
|
+
`score` are rejected and instead DERIVED server-side from the
|
|
293
|
+
effective values by the type's own rule (SOS: ratio = answer ÷ total,
|
|
294
|
+
score = ratio ÷ target_ratio clamped; OSA: ratio = answer ÷ total,
|
|
295
|
+
score = answer ÷ target or the ratio; facings: answer ÷ target or
|
|
296
|
+
existence; compatibility: answer ? 1 : 0). `computed` is immutable
|
|
297
|
+
from the API — the AI-calculated values always remain visible next to
|
|
298
|
+
the override. Enterable keys per type:
|
|
299
|
+
- `adjacent_block`: `answer` (boolean), `member_count`, `cut_count`
|
|
300
|
+
- `facings_count`: `answer` (number)
|
|
301
|
+
- `on_shelf_availability`: `answer` (number)
|
|
302
|
+
- `share_of_shelf`: `answer`, `total`
|
|
303
|
+
|
|
304
|
+
REVIEW FLOW: any fresh `overwrite` resets `confirmed_edit` to false
|
|
305
|
+
(pending) unless the same ADMIN request sets it true; the override
|
|
306
|
+
only drives the effective `score` while confirmed. REP rules: only
|
|
307
|
+
results of the rep's own sessions; `flag` may be raised but not
|
|
308
|
+
cleared; sending a value override auto-raises `flag`;
|
|
309
|
+
`confirmed_edit` is rejected. The stored mission results of the
|
|
310
|
+
analysis are re-synced afterwards.
|
|
311
|
+
operationId: updateAiObjectDetectionMetricResult
|
|
312
|
+
parameters:
|
|
313
|
+
- in: path
|
|
314
|
+
name: id
|
|
315
|
+
required: true
|
|
316
|
+
schema: { type: string }
|
|
317
|
+
requestBody:
|
|
318
|
+
required: true
|
|
319
|
+
content:
|
|
320
|
+
application/json:
|
|
321
|
+
schema:
|
|
322
|
+
type: object
|
|
323
|
+
properties:
|
|
324
|
+
flag: { type: boolean }
|
|
325
|
+
overwrite:
|
|
326
|
+
$ref: "#/components/schemas/OverwriteInput"
|
|
327
|
+
confirmed_edit:
|
|
328
|
+
type: boolean
|
|
329
|
+
description: "ADMIN-ONLY review verdict — true makes the standing overwrite effective."
|
|
330
|
+
responses:
|
|
331
|
+
"200":
|
|
332
|
+
description: The updated result (derived overwrite ratio/score stamped; effective `score`/`answer`/`ratio` recomputed per `confirmed_edit`).
|
|
333
|
+
content:
|
|
334
|
+
application/json:
|
|
335
|
+
schema:
|
|
336
|
+
$ref: "#/components/schemas/MetricResult"
|
|
337
|
+
"400":
|
|
338
|
+
description: "Non-overwritable key, `ratio`/`score` sent, wrong value type, or `overwrite` not an object."
|
|
339
|
+
"403":
|
|
340
|
+
description: Rep clearing `flag`, sending `confirmed_edit`, or touching another rep's session.
|
|
341
|
+
"404":
|
|
342
|
+
description: Not found.
|
|
343
|
+
delete:
|
|
344
|
+
summary: Soft-delete a metric result (admin)
|
|
345
|
+
operationId: removeAiObjectDetectionMetricResult
|
|
346
|
+
parameters:
|
|
347
|
+
- in: path
|
|
348
|
+
name: id
|
|
349
|
+
required: true
|
|
350
|
+
schema: { type: string }
|
|
351
|
+
responses:
|
|
352
|
+
"200":
|
|
353
|
+
description: The disabled result.
|
|
354
|
+
content:
|
|
355
|
+
application/json:
|
|
356
|
+
schema:
|
|
357
|
+
$ref: "#/components/schemas/MetricResult"
|
|
358
|
+
"403":
|
|
359
|
+
description: Rep tokens may not remove results.
|
|
360
|
+
"404":
|
|
361
|
+
description: Not found.
|
|
362
|
+
components:
|
|
363
|
+
securitySchemes:
|
|
364
|
+
ApiKeyAuth:
|
|
365
|
+
type: apiKey
|
|
366
|
+
in: header
|
|
367
|
+
name: api-key
|
|
368
|
+
JwtAuth:
|
|
369
|
+
type: apiKey
|
|
370
|
+
in: header
|
|
371
|
+
name: Authorization
|
|
372
|
+
schemas:
|
|
373
|
+
UserStamp:
|
|
374
|
+
type: object
|
|
375
|
+
description: "Who created / last edited the document (server-stamped from the token)."
|
|
376
|
+
properties:
|
|
377
|
+
_id: { type: string }
|
|
378
|
+
name: { type: string }
|
|
379
|
+
type:
|
|
380
|
+
type: string
|
|
381
|
+
enum: [admin, rep, client, tenant]
|
|
382
|
+
admin: { type: string }
|
|
383
|
+
rep: { type: string }
|
|
384
|
+
client: { type: string }
|
|
385
|
+
tenant: { type: string }
|
|
386
|
+
AdjacentBlockComputed:
|
|
387
|
+
type: object
|
|
388
|
+
description: "Computed shape for `adjacent_block` (compatibility)."
|
|
389
|
+
properties:
|
|
390
|
+
type:
|
|
391
|
+
type: string
|
|
392
|
+
enum: [adjacent_block]
|
|
393
|
+
description: Internal discriminator mirror.
|
|
394
|
+
output:
|
|
395
|
+
type: string
|
|
396
|
+
enum: [compatibility]
|
|
397
|
+
description: Family tag stamped by the engine.
|
|
398
|
+
answer:
|
|
399
|
+
type: boolean
|
|
400
|
+
description: The verdict — contiguous AND count within [from, to].
|
|
401
|
+
score: { type: number, minimum: 0, maximum: 1 }
|
|
402
|
+
member_count: { type: number }
|
|
403
|
+
cut_count: { type: number }
|
|
404
|
+
in_range: { type: boolean }
|
|
405
|
+
blocks:
|
|
406
|
+
type: array
|
|
407
|
+
items:
|
|
408
|
+
type: object
|
|
409
|
+
properties:
|
|
410
|
+
shelf: { type: number }
|
|
411
|
+
from_stack: { type: number }
|
|
412
|
+
to_stack: { type: number }
|
|
413
|
+
count: { type: number }
|
|
414
|
+
FacingsCountComputed:
|
|
415
|
+
type: object
|
|
416
|
+
description: "Computed shape for `facings_count` (numerical)."
|
|
417
|
+
properties:
|
|
418
|
+
type:
|
|
419
|
+
type: string
|
|
420
|
+
enum: [facings_count]
|
|
421
|
+
output:
|
|
422
|
+
type: string
|
|
423
|
+
enum: [numerical]
|
|
424
|
+
description: Family tag stamped by the engine.
|
|
425
|
+
answer:
|
|
426
|
+
type: number
|
|
427
|
+
description: The collected facings count.
|
|
428
|
+
target_answer:
|
|
429
|
+
type: number
|
|
430
|
+
description: "Echo of the metric's optional target — present only when set; score then = answer ÷ target_answer (clamped)."
|
|
431
|
+
score: { type: number, minimum: 0, maximum: 1 }
|
|
432
|
+
shelves:
|
|
433
|
+
type: array
|
|
434
|
+
items:
|
|
435
|
+
type: object
|
|
436
|
+
properties:
|
|
437
|
+
shelf: { type: number }
|
|
438
|
+
count: { type: number }
|
|
439
|
+
OnShelfAvailabilityComputed:
|
|
440
|
+
type: object
|
|
441
|
+
description: "Computed shape for `on_shelf_availability` (numerical)."
|
|
442
|
+
properties:
|
|
443
|
+
type:
|
|
444
|
+
type: string
|
|
445
|
+
enum: [on_shelf_availability]
|
|
446
|
+
output:
|
|
447
|
+
type: string
|
|
448
|
+
enum: [numerical]
|
|
449
|
+
description: Family tag stamped by the engine.
|
|
450
|
+
answer:
|
|
451
|
+
type: number
|
|
452
|
+
description: "How many of the selected labels are AVAILABLE (≥ 1 facing)."
|
|
453
|
+
score:
|
|
454
|
+
type: number
|
|
455
|
+
minimum: 0
|
|
456
|
+
maximum: 1
|
|
457
|
+
description: "answer ÷ target_answer when a target is set, else `ratio` (the availability factor)."
|
|
458
|
+
target_answer:
|
|
459
|
+
type: number
|
|
460
|
+
description: "Echo of the metric's optional target — present only when set."
|
|
461
|
+
total:
|
|
462
|
+
type: number
|
|
463
|
+
description: How many labels were selected (the denominator).
|
|
464
|
+
ratio:
|
|
465
|
+
type: number
|
|
466
|
+
description: answer / total.
|
|
467
|
+
missing:
|
|
468
|
+
type: array
|
|
469
|
+
description: "The out-of-stock labels — the actionable list (names resolved at evaluation time)."
|
|
470
|
+
items:
|
|
471
|
+
type: object
|
|
472
|
+
properties:
|
|
473
|
+
label: { type: string }
|
|
474
|
+
name: { type: string }
|
|
475
|
+
present:
|
|
476
|
+
type: array
|
|
477
|
+
description: The available labels with their facing counts.
|
|
478
|
+
items:
|
|
479
|
+
type: object
|
|
480
|
+
properties:
|
|
481
|
+
label: { type: string }
|
|
482
|
+
name: { type: string }
|
|
483
|
+
facings: { type: number }
|
|
484
|
+
SegmentOutput:
|
|
485
|
+
type: object
|
|
486
|
+
description: |
|
|
487
|
+
One segment row's outcome inside a share-of-shelf evaluation.
|
|
488
|
+
Self-contained on purpose: embedded in `computed.segments[]` today
|
|
489
|
+
but ready to move to its own collection and to be reused by future
|
|
490
|
+
SOS-family metric types. Only the MAIN row carries `target_ratio`,
|
|
491
|
+
`target_answer` and `score`.
|
|
492
|
+
properties:
|
|
493
|
+
segment: { type: string }
|
|
494
|
+
name: { type: string }
|
|
495
|
+
resolved:
|
|
496
|
+
type: boolean
|
|
497
|
+
description: false = the segment was deleted after the metric referenced it.
|
|
498
|
+
main:
|
|
499
|
+
type: boolean
|
|
500
|
+
description: The row the metric's target is defined for — exactly one per metric.
|
|
501
|
+
labels:
|
|
502
|
+
type: array
|
|
503
|
+
items: { type: string }
|
|
504
|
+
description: The effective labels used (override or the segment's own).
|
|
505
|
+
answer:
|
|
506
|
+
type: number
|
|
507
|
+
description: Measured quantity in the metric's measure unit (cm or cm²).
|
|
508
|
+
overwrite_answer:
|
|
509
|
+
type: number
|
|
510
|
+
description: "The CONFIRMED answer override, colocated in the row (effective = overwrite_answer ?? answer) — present only while confirmed_edit is true. Source of truth is the result's `overwrite.answer`; the service keeps this copy in sync across override saves, confirmations and recalculations."
|
|
511
|
+
overwrite_ratio:
|
|
512
|
+
type: number
|
|
513
|
+
description: "The confirmed override's derived ratio, colocated with overwrite_answer (same lifecycle)."
|
|
514
|
+
overwrite_score:
|
|
515
|
+
type: number
|
|
516
|
+
description: "The confirmed override's derived score, colocated with overwrite_answer (same lifecycle)."
|
|
517
|
+
ratio:
|
|
518
|
+
type: number
|
|
519
|
+
description: answer / category total — rows sum to 1 when segments don't overlap.
|
|
520
|
+
target_ratio:
|
|
521
|
+
type: number
|
|
522
|
+
description: Main row only — the target share this segment must reach.
|
|
523
|
+
target_answer:
|
|
524
|
+
type: number
|
|
525
|
+
description: "Main row only — target_ratio × total: the quantity needed to hit the target."
|
|
526
|
+
score:
|
|
527
|
+
type: number
|
|
528
|
+
minimum: 0
|
|
529
|
+
maximum: 1
|
|
530
|
+
description: "Main row only — attainment vs the target (share_of_shelf: min(1, ratio / target_ratio)). Missions multiply it by their weight."
|
|
531
|
+
ShareOfShelfComputed:
|
|
532
|
+
type: object
|
|
533
|
+
description: "Computed shape for `share_of_shelf` — the MAIN segment's numbers at the top level, every row in `segments[]`."
|
|
534
|
+
properties:
|
|
535
|
+
type:
|
|
536
|
+
type: string
|
|
537
|
+
enum: [share_of_shelf]
|
|
538
|
+
output:
|
|
539
|
+
type: string
|
|
540
|
+
enum: [share_of_shelf]
|
|
541
|
+
description: Family tag stamped by the engine.
|
|
542
|
+
answer:
|
|
543
|
+
type: number
|
|
544
|
+
nullable: true
|
|
545
|
+
description: "The MAIN segment's measured quantity (cm or cm²); null when nothing was measurable."
|
|
546
|
+
score:
|
|
547
|
+
type: number
|
|
548
|
+
minimum: 0
|
|
549
|
+
maximum: 1
|
|
550
|
+
description: "= the main segment's score: min(1, ratio / target_ratio)."
|
|
551
|
+
total:
|
|
552
|
+
type: number
|
|
553
|
+
description: "The same measure over the CONSIDERED CATEGORY: facings whose label belongs to any of the metric's segments."
|
|
554
|
+
ratio:
|
|
555
|
+
type: number
|
|
556
|
+
description: answer / total — the main segment's share.
|
|
557
|
+
target_ratio:
|
|
558
|
+
type: number
|
|
559
|
+
description: The target the MAIN segment must meet (from the metric args).
|
|
560
|
+
target_answer:
|
|
561
|
+
type: number
|
|
562
|
+
description: "target_ratio × total — what the main segment needed, in measure units."
|
|
563
|
+
measure:
|
|
564
|
+
type: string
|
|
565
|
+
enum: [width_cm, area_cm2, facings]
|
|
566
|
+
unmeasured:
|
|
567
|
+
type: number
|
|
568
|
+
description: Considered facings without a physical size (excluded from both sides).
|
|
569
|
+
segments:
|
|
570
|
+
type: array
|
|
571
|
+
description: One SegmentOutput per metric row (the main one flagged + scored).
|
|
572
|
+
items:
|
|
573
|
+
$ref: "#/components/schemas/SegmentOutput"
|
|
574
|
+
Overwrite:
|
|
575
|
+
type: object
|
|
576
|
+
description: "Stored human layer — the entered VALUE keys plus the server-DERIVED `ratio`/`score`, strict per type (plus the internal `type` mirror). Which keys exist depends on the type: adjacent_block `answer` (boolean) / `member_count` / `cut_count` / `score`; facings_count `answer` / `score`; on_shelf_availability `answer` / `ratio` / `score`; share_of_shelf `answer` / `total` / `ratio` / `score`."
|
|
577
|
+
properties:
|
|
578
|
+
type:
|
|
579
|
+
type: string
|
|
580
|
+
enum:
|
|
581
|
+
[
|
|
582
|
+
adjacent_block,
|
|
583
|
+
facings_count,
|
|
584
|
+
on_shelf_availability,
|
|
585
|
+
share_of_shelf,
|
|
586
|
+
]
|
|
587
|
+
answer:
|
|
588
|
+
description: boolean for adjacent_block, number otherwise.
|
|
589
|
+
oneOf:
|
|
590
|
+
- type: boolean
|
|
591
|
+
- type: number
|
|
592
|
+
member_count: { type: number }
|
|
593
|
+
cut_count: { type: number }
|
|
594
|
+
total: { type: number }
|
|
595
|
+
ratio: { type: number }
|
|
596
|
+
score: { type: number, minimum: 0, maximum: 1 }
|
|
597
|
+
OverwriteInput:
|
|
598
|
+
type: object
|
|
599
|
+
description: "Sparse VALUE overrides — only the type's overwritable keys; `ratio`/`score` are rejected (derived). Send `{}` to clear the override."
|
|
600
|
+
properties:
|
|
601
|
+
answer:
|
|
602
|
+
description: "adjacent_block: boolean verdict; other types: number."
|
|
603
|
+
oneOf:
|
|
604
|
+
- type: boolean
|
|
605
|
+
- type: number
|
|
606
|
+
member_count:
|
|
607
|
+
type: number
|
|
608
|
+
description: adjacent_block only.
|
|
609
|
+
cut_count:
|
|
610
|
+
type: number
|
|
611
|
+
description: adjacent_block only.
|
|
612
|
+
total:
|
|
613
|
+
type: number
|
|
614
|
+
description: share_of_shelf only.
|
|
615
|
+
MetricResult:
|
|
616
|
+
type: object
|
|
617
|
+
properties:
|
|
618
|
+
_id: { type: string }
|
|
619
|
+
disabled: { type: boolean }
|
|
620
|
+
metric:
|
|
621
|
+
type: string
|
|
622
|
+
description: "Metric id (or the populated metric document when `populatedKeys` includes `metric`)."
|
|
623
|
+
analysis:
|
|
624
|
+
type: string
|
|
625
|
+
description: "Analysis id (or the populated document when requested)."
|
|
626
|
+
session:
|
|
627
|
+
type: string
|
|
628
|
+
description: "Session id (or the populated document when requested)."
|
|
629
|
+
name:
|
|
630
|
+
type: string
|
|
631
|
+
description: Metric name snapshot at evaluation time.
|
|
632
|
+
type:
|
|
633
|
+
type: string
|
|
634
|
+
enum:
|
|
635
|
+
[
|
|
636
|
+
adjacent_block,
|
|
637
|
+
facings_count,
|
|
638
|
+
on_shelf_availability,
|
|
639
|
+
share_of_shelf,
|
|
640
|
+
]
|
|
641
|
+
output:
|
|
642
|
+
type: string
|
|
643
|
+
enum: [compatibility, numerical, share_of_shelf]
|
|
644
|
+
description: The type's output family (denormalized for rendering).
|
|
645
|
+
args:
|
|
646
|
+
type: object
|
|
647
|
+
description: Args snapshot at evaluation time.
|
|
648
|
+
computed:
|
|
649
|
+
description: "Machine layer — strict per-type engine output incl. `answer` + `score` 0..1 (plus an internal `type` mirror). Never editable. Absent when the evaluation errored."
|
|
650
|
+
oneOf:
|
|
651
|
+
- $ref: "#/components/schemas/AdjacentBlockComputed"
|
|
652
|
+
- $ref: "#/components/schemas/FacingsCountComputed"
|
|
653
|
+
- $ref: "#/components/schemas/OnShelfAvailabilityComputed"
|
|
654
|
+
- $ref: "#/components/schemas/ShareOfShelfComputed"
|
|
655
|
+
user:
|
|
656
|
+
type: string
|
|
657
|
+
nullable: true
|
|
658
|
+
description: "Denormalized scan context (activity-model shape): the SCANNING rep's id — unset for admin-scanned sessions. Stamped by the evaluator; feeds the dashboard widgets' rep_id filter."
|
|
659
|
+
user_name: { type: string, nullable: true }
|
|
660
|
+
client:
|
|
661
|
+
type: string
|
|
662
|
+
nullable: true
|
|
663
|
+
description: "The scanned client's id (widget client.* filters inflate it in their header stages)."
|
|
664
|
+
client_name: { type: string, nullable: true }
|
|
665
|
+
teams:
|
|
666
|
+
type: array
|
|
667
|
+
items: { type: string }
|
|
668
|
+
description: "The scanning rep's team ids at evaluation time (team-shared dashboards)."
|
|
669
|
+
visit_id:
|
|
670
|
+
type: string
|
|
671
|
+
description: Device visit id of the visit the scan happened in (copied from the session).
|
|
672
|
+
route:
|
|
673
|
+
type: string
|
|
674
|
+
description: "`sv.routes` `_id` of the visit's route."
|
|
675
|
+
business_day:
|
|
676
|
+
type: string
|
|
677
|
+
description: "Business day of the scan, `YYYY-MM-DD`."
|
|
678
|
+
overwrite:
|
|
679
|
+
$ref: "#/components/schemas/Overwrite"
|
|
680
|
+
flag: { type: boolean }
|
|
681
|
+
confirmed_edit:
|
|
682
|
+
type: boolean
|
|
683
|
+
description: "Admin review gate — the overwrite only drives the effective score while true. A fresh overwrite resets it to false; reps can never set it."
|
|
684
|
+
score:
|
|
685
|
+
type: number
|
|
686
|
+
description: "EFFECTIVE score 0..1 (confirmed `overwrite.score`, else `computed.score`)."
|
|
687
|
+
answer:
|
|
688
|
+
description: "EFFECTIVE answer, reconciled like `score` (confirmed override wins) — boolean verdict or number per the output family. What widgets/analytics aggregate."
|
|
689
|
+
nullable: true
|
|
690
|
+
oneOf:
|
|
691
|
+
- type: boolean
|
|
692
|
+
- type: number
|
|
693
|
+
ratio:
|
|
694
|
+
type: number
|
|
695
|
+
nullable: true
|
|
696
|
+
description: "EFFECTIVE ratio, reconciled like `score` (OSA availability / SOS share; null for types without one)."
|
|
697
|
+
status:
|
|
698
|
+
type: string
|
|
699
|
+
enum: [ok, error]
|
|
700
|
+
error: { type: string, nullable: true }
|
|
701
|
+
evaluated_at:
|
|
702
|
+
type: number
|
|
703
|
+
description: Unix ms of the evaluation.
|
|
704
|
+
engine_version: { type: number }
|
|
705
|
+
source_fingerprints:
|
|
706
|
+
type: object
|
|
707
|
+
description: The analysis's stage fingerprints at evaluation time — mismatch vs the analysis's current ones = stale result.
|
|
708
|
+
creator:
|
|
709
|
+
$ref: "#/components/schemas/UserStamp"
|
|
710
|
+
editor:
|
|
711
|
+
$ref: "#/components/schemas/UserStamp"
|
|
712
|
+
company_namespace:
|
|
713
|
+
type: array
|
|
714
|
+
items: { type: string }
|
|
715
|
+
createdAt: { type: string, format: date-time }
|
|
716
|
+
updatedAt: { type: string, format: date-time }
|
|
717
|
+
MetricResultFindResult:
|
|
718
|
+
type: object
|
|
719
|
+
description: Standard paginated result envelope.
|
|
720
|
+
properties:
|
|
721
|
+
data:
|
|
722
|
+
type: array
|
|
723
|
+
items:
|
|
724
|
+
$ref: "#/components/schemas/MetricResult"
|
|
725
|
+
total_result: { type: number }
|
|
726
|
+
current_count: { type: number }
|
|
727
|
+
total_pages: { type: number }
|
|
728
|
+
current_page: { type: number }
|
|
729
|
+
per_page: { type: number }
|
|
730
|
+
first_page_url: { type: string }
|
|
731
|
+
last_page_url: { type: string }
|
|
732
|
+
next_page_url: { type: string, nullable: true }
|
|
733
|
+
prev_page_url: { type: string, nullable: true }
|
|
734
|
+
path: { type: string }
|