@camstack/addon-export-alexa 1.2.51 → 1.2.52

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.
@@ -8171,6 +8171,21 @@ var RelocateJobSchema = object({
8171
8171
  bytesMoved: number().int(),
8172
8172
  /** Total files discovered up front; null while (or when) unknown. */
8173
8173
  filesTotal: number().int().nullable(),
8174
+ /**
8175
+ * Rows this run CORRECTED while moving them — a durable mutation the move
8176
+ * made that nobody asked for, so it is reported where the operator reads the
8177
+ * job rather than only in a log line.
8178
+ *
8179
+ * A footage segment records its byte count in its own NAME, and the durable
8180
+ * hour row derives its aggregates from those names. A file that does not
8181
+ * match its name therefore makes the ledger's sums — and with them quota and
8182
+ * pressure eviction — wrong by the difference, and only a rename can fix it.
8183
+ * On 2026-08-30 one such row also stalled a 110 749-file drain permanently.
8184
+ *
8185
+ * Absent on lanes where the question has no meaning: a media blob's size is
8186
+ * in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
8187
+ */
8188
+ rowsReconciled: number().int().nonnegative().optional(),
8174
8189
  startedAt: number(),
8175
8190
  finishedAt: number().nullable(),
8176
8191
  error: string().nullable()
@@ -8239,14 +8254,42 @@ var RelocateMediaInputSchema = object({
8239
8254
  /** Omitted = `move`, the pre-existing behaviour. */
8240
8255
  mode: MediaRelocateModeSchema.optional()
8241
8256
  });
8242
- /** How many rows still carry NO `locationId` — the population a repoint would
8243
- * silently re-aim at a disk that does not hold their bytes. Zero is the only
8244
- * value that permits a non-blocking `eventMedia` cutover. */
8245
- var UnstampedEventMediaCountSchema = object({
8246
- media: number().int().nonnegative(),
8247
- retrainFrames: number().int().nonnegative(),
8248
- total: number().int().nonnegative()
8257
+ /**
8258
+ * The unstamped population of ONE collection — split, because the gate and the
8259
+ * operator ask two different questions and only one of them has to be cheap.
8260
+ *
8261
+ * `present` is the GATE: "is there at least one row that would be orphaned by a
8262
+ * repoint". It is a single indexed seek to the first matching row, so it stays
8263
+ * answerable on a saturated disk and answers in O(log n) precisely in the state
8264
+ * that matters — after a seal, when the population is empty.
8265
+ *
8266
+ * `rows` is the NUMBER, for the refusal message and the operator's sense of
8267
+ * scale. It is a second, indexed `COUNT(*)`, and `null` means **not
8268
+ * measurable** — never zero. `{ present: true, rows: null }` is a legitimate
8269
+ * and useful answer: "there are some, and this read could not say how many"
8270
+ * still refuses the cutover, which is the whole job.
8271
+ */
8272
+ var UnstampedRowsSchema = object({
8273
+ present: boolean(),
8274
+ rows: number().int().nonnegative().nullable()
8249
8275
  });
8276
+ /**
8277
+ * How many rows still carry NO `locationId` — the population a repoint would
8278
+ * silently re-aim at a disk that does not hold their bytes.
8279
+ *
8280
+ * **`null` = the count could not be taken**, and it is NOT permission to cut
8281
+ * over. The gate opens on a measured absence and on nothing else; an unread
8282
+ * collection and an empty one are different facts, and this repo has already
8283
+ * paid for conflating them (`RelocateResidueSchema`, D295).
8284
+ */
8285
+ var UnstampedEventMediaCountSchema = object({
8286
+ media: UnstampedRowsSchema,
8287
+ retrainFrames: UnstampedRowsSchema,
8288
+ /** True when EITHER collection holds one. The refusal reads this. */
8289
+ anyPresent: boolean(),
8290
+ /** Sum across both, or `null` when either lane could not be counted. */
8291
+ total: number().int().nonnegative().nullable()
8292
+ }).nullable();
8250
8293
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
8251
8294
  /** The independently selectable logical storage classes — every class
8252
8295
  * `storage.listLocationDeclarations` reports, so an operator never meets a
@@ -8357,6 +8400,10 @@ var StorageMigrationMoveProgressSchema = object({
8357
8400
  /** The archive census — the **M** of "N of M" (D295). `null` = unknowable. */
8358
8401
  filesTotal: number().int().nonnegative().nullable(),
8359
8402
  bytesMoved: number().int().nonnegative(),
8403
+ /** Rows the mover corrected while moving them — see `RelocateJob`. Absent on
8404
+ * a lane that cannot reconcile. A migration that silently rewrote durable
8405
+ * rows would be the same failure as one that silently skipped them. */
8406
+ rowsReconciled: number().int().nonnegative().optional(),
8360
8407
  /** The MOVER's start, not the migration's: a drain restarted after an addon
8361
8408
  * crash gets a new mover, and a rate computed from the migration's start
8362
8409
  * would silently average in the time nothing was running. */
@@ -8144,6 +8144,21 @@ var RelocateJobSchema = object({
8144
8144
  bytesMoved: number().int(),
8145
8145
  /** Total files discovered up front; null while (or when) unknown. */
8146
8146
  filesTotal: number().int().nullable(),
8147
+ /**
8148
+ * Rows this run CORRECTED while moving them — a durable mutation the move
8149
+ * made that nobody asked for, so it is reported where the operator reads the
8150
+ * job rather than only in a log line.
8151
+ *
8152
+ * A footage segment records its byte count in its own NAME, and the durable
8153
+ * hour row derives its aggregates from those names. A file that does not
8154
+ * match its name therefore makes the ledger's sums — and with them quota and
8155
+ * pressure eviction — wrong by the difference, and only a rename can fix it.
8156
+ * On 2026-08-30 one such row also stalled a 110 749-file drain permanently.
8157
+ *
8158
+ * Absent on lanes where the question has no meaning: a media blob's size is
8159
+ * in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
8160
+ */
8161
+ rowsReconciled: number().int().nonnegative().optional(),
8147
8162
  startedAt: number(),
8148
8163
  finishedAt: number().nullable(),
8149
8164
  error: string().nullable()
@@ -8212,14 +8227,42 @@ var RelocateMediaInputSchema = object({
8212
8227
  /** Omitted = `move`, the pre-existing behaviour. */
8213
8228
  mode: MediaRelocateModeSchema.optional()
8214
8229
  });
8215
- /** How many rows still carry NO `locationId` — the population a repoint would
8216
- * silently re-aim at a disk that does not hold their bytes. Zero is the only
8217
- * value that permits a non-blocking `eventMedia` cutover. */
8218
- var UnstampedEventMediaCountSchema = object({
8219
- media: number().int().nonnegative(),
8220
- retrainFrames: number().int().nonnegative(),
8221
- total: number().int().nonnegative()
8230
+ /**
8231
+ * The unstamped population of ONE collection — split, because the gate and the
8232
+ * operator ask two different questions and only one of them has to be cheap.
8233
+ *
8234
+ * `present` is the GATE: "is there at least one row that would be orphaned by a
8235
+ * repoint". It is a single indexed seek to the first matching row, so it stays
8236
+ * answerable on a saturated disk and answers in O(log n) precisely in the state
8237
+ * that matters — after a seal, when the population is empty.
8238
+ *
8239
+ * `rows` is the NUMBER, for the refusal message and the operator's sense of
8240
+ * scale. It is a second, indexed `COUNT(*)`, and `null` means **not
8241
+ * measurable** — never zero. `{ present: true, rows: null }` is a legitimate
8242
+ * and useful answer: "there are some, and this read could not say how many"
8243
+ * still refuses the cutover, which is the whole job.
8244
+ */
8245
+ var UnstampedRowsSchema = object({
8246
+ present: boolean(),
8247
+ rows: number().int().nonnegative().nullable()
8222
8248
  });
8249
+ /**
8250
+ * How many rows still carry NO `locationId` — the population a repoint would
8251
+ * silently re-aim at a disk that does not hold their bytes.
8252
+ *
8253
+ * **`null` = the count could not be taken**, and it is NOT permission to cut
8254
+ * over. The gate opens on a measured absence and on nothing else; an unread
8255
+ * collection and an empty one are different facts, and this repo has already
8256
+ * paid for conflating them (`RelocateResidueSchema`, D295).
8257
+ */
8258
+ var UnstampedEventMediaCountSchema = object({
8259
+ media: UnstampedRowsSchema,
8260
+ retrainFrames: UnstampedRowsSchema,
8261
+ /** True when EITHER collection holds one. The refusal reads this. */
8262
+ anyPresent: boolean(),
8263
+ /** Sum across both, or `null` when either lane could not be counted. */
8264
+ total: number().int().nonnegative().nullable()
8265
+ }).nullable();
8223
8266
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
8224
8267
  /** The independently selectable logical storage classes — every class
8225
8268
  * `storage.listLocationDeclarations` reports, so an operator never meets a
@@ -8330,6 +8373,10 @@ var StorageMigrationMoveProgressSchema = object({
8330
8373
  /** The archive census — the **M** of "N of M" (D295). `null` = unknowable. */
8331
8374
  filesTotal: number().int().nonnegative().nullable(),
8332
8375
  bytesMoved: number().int().nonnegative(),
8376
+ /** Rows the mover corrected while moving them — see `RelocateJob`. Absent on
8377
+ * a lane that cannot reconcile. A migration that silently rewrote durable
8378
+ * rows would be the same failure as one that silently skipped them. */
8379
+ rowsReconciled: number().int().nonnegative().optional(),
8333
8380
  /** The MOVER's start, not the migration's: a drain restarted after an addon
8334
8381
  * crash gets a new mover, and a rate computed from the migration's start
8335
8382
  * would silently average in the time nothing was running. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-export-alexa",
3
- "version": "1.2.51",
3
+ "version": "1.2.52",
4
4
  "description": "Alexa Smart Home Skill export — hub-side OAuth provider + directive handler. The companion AWS Lambda forwards Alexa directives to this addon's /addon/export-alexa/directive endpoint.",
5
5
  "keywords": [
6
6
  "camstack",