@camstack/addon-pipeline 1.2.218 → 1.2.220

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.
Files changed (38) hide show
  1. package/dist/audio-analyzer/index.js +49 -5
  2. package/dist/audio-analyzer/index.mjs +46 -3
  3. package/dist/chunk-emK7D4bc.js +35 -0
  4. package/dist/{default-detection-model-AJyhoTLF.mjs → default-detection-model-DBNEc3iw.mjs} +1 -1
  5. package/dist/{default-detection-model-Bf45EQ98.js → default-detection-model-x6oNMBDH.js} +1 -1
  6. package/dist/detection-pipeline/index.js +10 -9
  7. package/dist/detection-pipeline/index.mjs +4 -4
  8. package/dist/{dist-BbvtiBNc.js → dist-ByPsWlTa.js} +57 -38
  9. package/dist/{dist-Dl6GntEh.mjs → dist-ClihWGOZ.mjs} +57 -3
  10. package/dist/{lazy-sharp-L9Lcr62v.js → lazy-sharp-BuwKlQLR.js} +2 -2
  11. package/dist/motion-wasm/index.js +2 -2
  12. package/dist/motion-wasm/index.mjs +1 -1
  13. package/dist/{node-CbCVHEvJ.js → node-CNPnaux4.js} +4 -3
  14. package/dist/{node-CEyw52D2.mjs → node-DiaTmz84.mjs} +1 -1
  15. package/dist/pipeline-runner/index.js +222 -157
  16. package/dist/pipeline-runner/index.mjs +218 -154
  17. package/dist/{process-memory-DBxdiCSF.js → process-memory-9KqRtUHt.js} +3 -2
  18. package/dist/{process-memory-Du00R6-e.mjs → process-memory-D4t8hpJd.mjs} +1 -1
  19. package/dist/recorder/index.js +334 -123
  20. package/dist/recorder/index.mjs +332 -122
  21. package/dist/{segment-demux-js-B278aBtB.mjs → segment-demux-js-CFFXVae4.mjs} +1 -1
  22. package/dist/{segment-demux-js-D7bjzY8M.js → segment-demux-js-CZefXDLx.js} +4 -3
  23. package/dist/session-decode/decode-worker-child.js +155 -74
  24. package/dist/session-decode/decode-worker-child.mjs +154 -73
  25. package/dist/stream-broker/_stub.js +1 -1
  26. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BnmbfnAd.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CtdpN7Sz.mjs} +3 -3
  27. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-yJ2CyixO.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-7hqrrd88.mjs} +1 -1
  28. package/dist/stream-broker/demux-worker-child.js +1 -1
  29. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  30. package/dist/stream-broker/{hostInit-MIKQqs86.mjs → hostInit-McoUiljf.mjs} +3 -3
  31. package/dist/stream-broker/index.js +24 -25
  32. package/dist/stream-broker/index.mjs +17 -19
  33. package/dist/stream-broker/remoteEntry.js +1 -1
  34. package/dist/worker-protocol-B2MfQLlu.js +184 -0
  35. package/dist/worker-protocol-C_W-P_g-.mjs +161 -0
  36. package/package.json +1 -1
  37. package/dist/worker-protocol-BEbD5adq.mjs +0 -264
  38. package/dist/worker-protocol-C4rh5uiS.js +0 -299
@@ -1,7 +1,8 @@
1
- const require_dist = require("./dist-BbvtiBNc.js");
1
+ const require_chunk = require("./chunk-emK7D4bc.js");
2
+ const require_dist = require("./dist-ByPsWlTa.js");
2
3
  let node_child_process = require("node:child_process");
3
4
  //#region ../../node_modules/mp4box/dist/mp4box.all.js
4
- var require_mp4box_all = /* @__PURE__ */ require_dist.__commonJSMin(((exports) => {
5
+ var require_mp4box_all = /* @__PURE__ */ require_chunk.__commonJSMin(((exports) => {
5
6
  var Log = (function() {
6
7
  var start = /* @__PURE__ */ new Date();
7
8
  var LOG_LEVEL_ERROR = 4;
@@ -6569,7 +6570,7 @@ var require_mp4box_all = /* @__PURE__ */ require_dist.__commonJSMin(((exports) =
6569
6570
  }));
6570
6571
  //#endregion
6571
6572
  //#region src/recorder/scrub/fmp4-keyframes.ts
6572
- var import_mp4box_all = /* @__PURE__ */ require_dist.__toESM(require_mp4box_all());
6573
+ var import_mp4box_all = /* @__PURE__ */ require_chunk.__toESM(require_mp4box_all());
6573
6574
  /**
6574
6575
  * Normalize an RFC 6381 codec string for WebCodecs HEVC. Apple/WebKit
6575
6576
  * WebCodecs only accepts the `hvc1.*` fourcc — a `hev1.*` string (what mp4box
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_worker_protocol = require("../worker-protocol-C4rh5uiS.js");
3
- const require_lazy_sharp = require("../lazy-sharp-L9Lcr62v.js");
2
+ const require_worker_protocol = require("../worker-protocol-B2MfQLlu.js");
3
+ const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
4
4
  //#region src/session-decode/color-conversion.ts
5
5
  /**
6
6
  * Explicit YUV→RGB colorspace/range resolution for the session-decode worker.
@@ -1602,48 +1602,68 @@ var NATIVE_RING_CAP = (() => {
1602
1602
  return Math.min(4, Math.max(0, Math.floor(raw)));
1603
1603
  })();
1604
1604
  /**
1605
- * The three native-lease knobs in force for THIS worker, resolved once at
1606
- * module load (the lease store and the demand gate are constructed with the
1607
- * worker instance, before the first `start` message).
1608
- *
1609
- * These are **operator settings**, not env vars: they live on
1610
- * `pipeline-orchestrator`'s cluster-wide globals, the pipeline-runner reads them
1611
- * over the hub-routed `addon-settings` cap, and it injects the ones the operator
1612
- * SET into this child's environment at fork time. Precedence is
1613
- * `setting > env > default` — the `CAMSTACK_SESSION_NATIVE_LEASE_*` vars survive
1614
- * as an emergency/dev override for knobs the operator has not touched. The
1615
- * resolved values AND their source are logged once per worker in
1616
- * {@link DecodeWorkerChild.handleStart}. Full contract:
1617
- * `native-lease-config.ts` and `packages/types/src/pipeline/native-lease.ts`.
1618
- */
1619
- var NATIVE_LEASE_KNOBS = require_worker_protocol.resolveNativeLeaseKnobs(process.env);
1620
- /**
1621
- * Hard RAM budget (bytes) for the native-frame HOLD store — the OOM ceiling,
1622
- * and since 2026-08-13 nothing else. {@link NATIVE_LEASE_HOLD_FRAMES} is what
1623
- * decides how much is held; this is the number above which something is wrong.
1624
- * `0` DISABLES the hold and falls back to the {@link NATIVE_RING_CAP} GPU ring.
1625
- */
1626
- var NATIVE_LEASE_BUDGET_BYTES = NATIVE_LEASE_KNOBS.values.budgetMb * 1024 * 1024;
1627
- /**
1628
- * How many delivered frames are HELD at once, each waiting for its own
1629
- * detection result. The ordinary exit is `cutTiles` / `releaseNativeLease`; this
1630
- * bound only stops a runner that stopped answering from pinning RAM, and every
1631
- * frame it drops is counted (`holdOverflow`).
1632
- */
1633
- var NATIVE_LEASE_HOLD_FRAMES = NATIVE_LEASE_KNOBS.values.holdFrames;
1634
- /**
1635
- * Hard RAM budget (bytes) for the SUBJECT TILE store — what survives a frame.
1636
- * `0` turns tiles off and restores the pre-2026-08-13 miss profile.
1637
- */
1638
- var NATIVE_TILE_BUDGET_BYTES = NATIVE_LEASE_KNOBS.values.tileBudgetMb * 1024 * 1024;
1639
- /**
1640
- * Hard RAM budget (bytes) for the SCENE TILE store — one JPEG of the whole
1641
- * native frame per detection-bearing frame, which is the only thing that can
1642
- * answer a FULL-FRAME native request after the hold ends. Separate from the
1643
- * subject budget so a key frame can never evict a face tile. `0` disables the
1644
- * rung. See `scene-tile.ts` for the measurements that sized it.
1645
- */
1646
- var NATIVE_SCENE_BUDGET_BYTES = NATIVE_LEASE_KNOBS.values.sceneBudgetMb * 1024 * 1024;
1605
+ * The native-lease knobs — hold depth, hold RAM ceiling, demand window,
1606
+ * admission mode, subject-tile budget, scene-tile budget — ARRIVE ON `start`
1607
+ * (`WorkerRequest.lease`, D453). They are **operator settings** living on
1608
+ * `pipeline-orchestrator`'s cluster-wide globals; the pipeline-runner reads
1609
+ * them and resolves `setting > env > default` in ITS process
1610
+ * (`native-lease-config.ts`), and this worker builds its stores from the
1611
+ * resolved values in {@link DecodeWorkerChild.handleStart}, before the first
1612
+ * packet. Until then it retains nothing ({@link UNSTARTED_LEASE_KNOBS}).
1613
+ *
1614
+ * Nothing here reads the environment for them any more. The child used to,
1615
+ * from `*_SETTING` vars the parent wrote at fork — which needed the Zod schemas
1616
+ * (the whole `@camstack/types` index) inside this bundle and cost every fork
1617
+ * ~130 ms and ~140 MB, measured; and it bound a worker to the knobs it was
1618
+ * FORKED with, which a pre-forked worker (`decode-worker-pool.ts`) cannot be.
1619
+ * The values AND their sources are logged once per session at `start`.
1620
+ *
1621
+ * What each knob means, in the store it sizes:
1622
+ * - `budgetMb` — hard RAM ceiling (bytes) for the native-frame HOLD store, the
1623
+ * OOM ceiling and since 2026-08-13 nothing else; `holdFrames` is what decides
1624
+ * how much is held. `0` DISABLES the hold and falls back to the
1625
+ * {@link NATIVE_RING_CAP} GPU ring.
1626
+ * - `holdFrames` — how many delivered frames are HELD at once, each waiting for
1627
+ * its own detection result. The ordinary exit is `cutTiles` /
1628
+ * `releaseNativeLease`; this bound only stops a runner that stopped answering
1629
+ * from pinning RAM, and every frame it drops is counted (`holdOverflow`).
1630
+ * - `tileBudgetMb` — the SUBJECT TILE store, what survives a frame. `0` turns
1631
+ * tiles off and restores the pre-2026-08-13 miss profile.
1632
+ * - `sceneBudgetMb` — the SCENE TILE store, one JPEG of the whole native frame
1633
+ * per detection-bearing frame, the only thing that can answer a FULL-FRAME
1634
+ * request after the hold ends. Separate from the subject budget so a key
1635
+ * frame can never evict a face tile. `0` disables the rung.
1636
+ * - `activityMs` — the {@link LeaseActivityGate} demand window: eager per-frame
1637
+ * native downloads run only within it. `0` disables the GATE (always-on eager
1638
+ * capture) — it does not disable retention.
1639
+ */
1640
+ var MB = 1024 * 1024;
1641
+ /**
1642
+ * What a worker holds BEFORE a session claims it: nothing. Hold off (`budgetMb`
1643
+ * 0 routes to the GPU ring, whose cap is env-only), tiles off, scenes off, the
1644
+ * gate open only because there is nothing behind it to open. Not the shipped
1645
+ * defaults on purpose — those live in `@camstack/types`, which this bundle no
1646
+ * longer carries, and a pre-forked worker that silently held the defaults would
1647
+ * be a worker with a configuration nobody handed it.
1648
+ */
1649
+ var UNSTARTED_LEASE_KNOBS = {
1650
+ values: {
1651
+ holdFrames: 1,
1652
+ budgetMb: 0,
1653
+ activityMs: 0,
1654
+ admission: "inferred",
1655
+ tileBudgetMb: 0,
1656
+ sceneBudgetMb: 0
1657
+ },
1658
+ sources: {
1659
+ holdFrames: "default",
1660
+ budgetMb: "default",
1661
+ activityMs: "default",
1662
+ admission: "default",
1663
+ tileBudgetMb: "default",
1664
+ sceneBudgetMb: "default"
1665
+ }
1666
+ };
1647
1667
  /**
1648
1668
  * How long a subject tile is served. A TTL is honest HERE and dishonest on the
1649
1669
  * hold: nothing is waiting on a tile, it is speculative retention against a
@@ -1690,13 +1710,6 @@ var TILE_CUT_WAIT_MS = (() => {
1690
1710
  const raw = Number(process.env["CAMSTACK_SESSION_TILE_CUT_WAIT_MS"]);
1691
1711
  return Number.isFinite(raw) && raw >= 0 ? Math.floor(raw) : 500;
1692
1712
  })();
1693
- /**
1694
- * Demand window (ms) for the lease-capture {@link LeaseActivityGate}: eager
1695
- * per-frame native downloads run only within this window of the last
1696
- * native-crop request (or dial start). `0` disables the GATE (legacy always-on
1697
- * eager capture) — it does not disable retention. Default 15000.
1698
- */
1699
- var NATIVE_LEASE_ACTIVITY_WINDOW_MS = NATIVE_LEASE_KNOBS.values.activityMs;
1700
1713
  /** How many early-withdrawn frame ids the worker remembers for the miss line. */
1701
1714
  var UNMARKED_MEMORY = 256;
1702
1715
  /**
@@ -1818,13 +1831,47 @@ async function importNodeAv(bareSpecifier) {
1818
1831
  throw bareErr;
1819
1832
  }
1820
1833
  }
1834
+ var _navLoading = null;
1835
+ var _constsLoading = null;
1821
1836
  async function getNodeAv() {
1822
- if (!_nav) _nav = await importNodeAv("node-av");
1823
- return _nav;
1837
+ if (_nav) return _nav;
1838
+ _navLoading ??= importNodeAv("node-av").then((mod) => {
1839
+ _nav = mod;
1840
+ return mod;
1841
+ });
1842
+ try {
1843
+ return await _navLoading;
1844
+ } catch (err) {
1845
+ _navLoading = null;
1846
+ throw err;
1847
+ }
1824
1848
  }
1825
1849
  async function getConstants() {
1826
- if (!_consts) _consts = await importNodeAv("node-av/constants");
1827
- return _consts;
1850
+ if (_consts) return _consts;
1851
+ _constsLoading ??= importNodeAv("node-av/constants").then((mod) => {
1852
+ _consts = mod;
1853
+ return mod;
1854
+ });
1855
+ try {
1856
+ return await _constsLoading;
1857
+ } catch (err) {
1858
+ _constsLoading = null;
1859
+ throw err;
1860
+ }
1861
+ }
1862
+ /** The HOLD store, sized from one session's knobs. */
1863
+ function buildLeaseStore(lease) {
1864
+ return new NativeLeaseStore({
1865
+ budgetBytes: lease.values.budgetMb * MB,
1866
+ maxFrames: lease.values.holdFrames
1867
+ });
1868
+ }
1869
+ /** A TILE store (subject or scene) under `budgetMb`, on the shared tile TTL. */
1870
+ function buildTileStore(budgetMb) {
1871
+ return new NativeTileStore({
1872
+ budgetBytes: budgetMb * MB,
1873
+ ttlMs: NATIVE_TILE_TTL_MS
1874
+ });
1828
1875
  }
1829
1876
  function errMessage(err) {
1830
1877
  if (err instanceof Error) return err.message;
@@ -2011,20 +2058,14 @@ var DecodeWorkerChild = class {
2011
2058
  * DOWNLOADED (system-memory) frames, retaining a large window has no VAAPI
2012
2059
  * surface-pool starvation risk. Cleared on every re-dial + teardown.
2013
2060
  */
2014
- leaseStore = new NativeLeaseStore({
2015
- budgetBytes: NATIVE_LEASE_BUDGET_BYTES,
2016
- maxFrames: NATIVE_LEASE_HOLD_FRAMES
2017
- });
2061
+ leaseStore = buildLeaseStore(UNSTARTED_LEASE_KNOBS);
2018
2062
  /**
2019
2063
  * What SURVIVES a held frame: one compressed native tile per subject, cut at
2020
2064
  * the instant the frame's detection result arrived. Every late native crop
2021
2065
  * that the hold can no longer serve is served from here — which measurement
2022
2066
  * says is the ordinary case, not the exception. See `native-tile-store.ts`.
2023
2067
  */
2024
- tileStore = new NativeTileStore({
2025
- budgetBytes: NATIVE_TILE_BUDGET_BYTES,
2026
- ttlMs: NATIVE_TILE_TTL_MS
2027
- });
2068
+ tileStore = buildTileStore(UNSTARTED_LEASE_KNOBS.values.tileBudgetMb);
2028
2069
  /**
2029
2070
  * What survives a held frame for a FULL-FRAME request: one JPEG of the whole
2030
2071
  * native raster, cut in the SAME synchronous read phase as the subject tiles.
@@ -2034,10 +2075,7 @@ var DecodeWorkerChild = class {
2034
2075
  * key frames evict the face/plate tiles the recognisers live on. Two stores
2035
2076
  * make starving that tier impossible rather than unlikely.
2036
2077
  */
2037
- sceneStore = new NativeTileStore({
2038
- budgetBytes: NATIVE_SCENE_BUDGET_BYTES,
2039
- ttlMs: NATIVE_TILE_TTL_MS
2040
- });
2078
+ sceneStore = buildTileStore(UNSTARTED_LEASE_KNOBS.values.sceneBudgetMb);
2041
2079
  /** Tiles cut / served / refused-for-containment, on the throughput line. */
2042
2080
  tilesCut = 0;
2043
2081
  tileHits = 0;
@@ -2081,7 +2119,7 @@ var DecodeWorkerChild = class {
2081
2119
  * per-frame native-res GPU→RAM download (the N100 saturation source) stops
2082
2120
  * on cameras nothing is cropping. See `lease-activity-gate.ts`.
2083
2121
  */
2084
- leaseGate = new LeaseActivityGate(NATIVE_LEASE_ACTIVITY_WINDOW_MS);
2122
+ leaseGate = new LeaseActivityGate(UNSTARTED_LEASE_KNOBS.values.activityMs);
2085
2123
  /**
2086
2124
  * WHICH delivered frames are worth a native lease — the runner marks the ones
2087
2125
  * it admitted to inference (`markInferred`), and in `inferred` mode only
@@ -2090,7 +2128,14 @@ var DecodeWorkerChild = class {
2090
2128
  * filter rests on is measured on live traffic rather than argued. See
2091
2129
  * `lease-admission-ledger.ts`.
2092
2130
  */
2093
- admission = new LeaseAdmissionLedger({ mode: NATIVE_LEASE_KNOBS.values.admission });
2131
+ admission = new LeaseAdmissionLedger({ mode: UNSTARTED_LEASE_KNOBS.values.admission });
2132
+ /**
2133
+ * The knobs this session runs under — `null` until `start` hands them over.
2134
+ * The stores above are REBUILT from them at that moment (they are empty then:
2135
+ * nothing is captured before a dial), and never again: a knob that changes
2136
+ * after the first frame is a knob with two values during a session.
2137
+ */
2138
+ lease = null;
2094
2139
  /**
2095
2140
  * DEDICATED full-frame GPU→system download filtergraph
2096
2141
  * (`scale_<be>=iw:ih,hwdownload,format=nv12,format=yuv420p`) used ONLY to
@@ -2251,7 +2296,7 @@ var DecodeWorkerChild = class {
2251
2296
  }
2252
2297
  switch (message.kind) {
2253
2298
  case "start":
2254
- this.handleStart(message.source, message.opts);
2299
+ this.handleStart(message.source, message.opts, message.lease);
2255
2300
  return;
2256
2301
  case "pull":
2257
2302
  this.handlePull();
@@ -2331,7 +2376,7 @@ var DecodeWorkerChild = class {
2331
2376
  const skipped = this.framesSkipped + this.frames.droppedCount;
2332
2377
  const rssMb = Math.round(process.memoryUsage().rss / 1048576);
2333
2378
  const ageS = Math.round((now - this.startedAt) / 1e3);
2334
- this.emitStderr(`session-decode metrics {framesDecoded:${this.framesDecoded}, framesSkipped:${skipped}, deliveredFps:${deliveredFps}, nativeCropHits:${this.nativeCropHits}, nativeCropMisses:${this.nativeCropMisses}, leaseOffered:${this.admission.offered}, leaseAdmitted:${this.admission.admitted}, leaseMarks:${this.admission.marks}, leaseUnmarkedCrops:${this.admission.unmarkedCrops}, leaseAdmission:${NATIVE_LEASE_KNOBS.values.admission}, leaseMb:${Math.round(this.leaseStore.totalBytes / 1048576)}, leaseFrames:${this.leaseStore.size}, holdOverflow:${this.leaseStore.overflowCount}, leaseReleased:${this.leaseReleased}, leaseReleaseMisses:${this.leaseReleaseMisses}, leaseReleasedEarly:${this.leaseReleasedEarly}, tilesCut:${this.tilesCut}, tileHits:${this.tileHits}, tileMisses:${this.tileMisses}, tileCutFailures:${this.tileCutFailures}, tileMissesResolvedByWait:${this.tileMissesResolvedByWait}, tileWaitTimeouts:${this.tileWaitTimeouts}, cutLatencyMsP50:${formatLatency(this.pendingCuts.latencyMs(50))}, cutLatencyMsP95:${formatLatency(this.pendingCuts.latencyMs(95))}, cutsInFlight:${this.pendingCuts.inFlight}, tileMb:${Math.round(this.tileStore.totalBytes / 1048576)}, tileFrames:${this.tileStore.frameCount}, scenesCut:${this.scenesCut}, sceneHits:${this.sceneHits}, sceneRefused:${this.sceneRefused}, sceneUnclassified:${this.sceneUnclassified}, sceneEvicted:${this.sceneStore.evictedCount}, sceneMb:${Math.round(this.sceneStore.totalBytes / 1048576)}, sceneFrames:${this.sceneStore.frameCount}, rssMb:${rssMb}, ageS:${ageS}}${final ? " (final)" : ""}\n`);
2379
+ this.emitStderr(`session-decode metrics {framesDecoded:${this.framesDecoded}, framesSkipped:${skipped}, deliveredFps:${deliveredFps}, nativeCropHits:${this.nativeCropHits}, nativeCropMisses:${this.nativeCropMisses}, leaseOffered:${this.admission.offered}, leaseAdmitted:${this.admission.admitted}, leaseMarks:${this.admission.marks}, leaseUnmarkedCrops:${this.admission.unmarkedCrops}, leaseAdmission:${this.lease?.values.admission ?? "unstarted"}, leaseMb:${Math.round(this.leaseStore.totalBytes / 1048576)}, leaseFrames:${this.leaseStore.size}, holdOverflow:${this.leaseStore.overflowCount}, leaseReleased:${this.leaseReleased}, leaseReleaseMisses:${this.leaseReleaseMisses}, leaseReleasedEarly:${this.leaseReleasedEarly}, tilesCut:${this.tilesCut}, tileHits:${this.tileHits}, tileMisses:${this.tileMisses}, tileCutFailures:${this.tileCutFailures}, tileMissesResolvedByWait:${this.tileMissesResolvedByWait}, tileWaitTimeouts:${this.tileWaitTimeouts}, cutLatencyMsP50:${formatLatency(this.pendingCuts.latencyMs(50))}, cutLatencyMsP95:${formatLatency(this.pendingCuts.latencyMs(95))}, cutsInFlight:${this.pendingCuts.inFlight}, tileMb:${Math.round(this.tileStore.totalBytes / 1048576)}, tileFrames:${this.tileStore.frameCount}, scenesCut:${this.scenesCut}, sceneHits:${this.sceneHits}, sceneRefused:${this.sceneRefused}, sceneUnclassified:${this.sceneUnclassified}, sceneEvicted:${this.sceneStore.evictedCount}, sceneMb:${Math.round(this.sceneStore.totalBytes / 1048576)}, sceneFrames:${this.sceneStore.frameCount}, rssMb:${rssMb}, ageS:${ageS}}${final ? " (final)" : ""}\n`);
2335
2380
  this.lastMetricsAt = now;
2336
2381
  this.lastDeliveredSnapshot = this.framesDelivered;
2337
2382
  if (!this.warnedLarge && rssMb >= WORKER_RSS_WARN_MB) {
@@ -2339,14 +2384,20 @@ var DecodeWorkerChild = class {
2339
2384
  this.emitStderr(`decode-worker-child: WORKER IS LARGE — rssMb=${rssMb} ageS=${ageS} framesDecoded=${this.framesDecoded}. Siblings normally recycle in ~30s; a worker this size at this age is how the host ran out of memory on 2026-08-05.\n`);
2340
2385
  }
2341
2386
  }
2342
- handleStart(source, opts) {
2387
+ handleStart(source, opts, lease) {
2343
2388
  if (this.started) {
2344
2389
  this.emitStderr("decode-worker-child: duplicate start ignored\n");
2345
2390
  return;
2346
2391
  }
2347
2392
  this.started = true;
2348
2393
  this.deviceId = source.deviceId;
2349
- this.emitStderr(`decode-worker-child: ${require_worker_protocol.formatNativeLeaseKnobs(NATIVE_LEASE_KNOBS)}\n`, "info");
2394
+ this.lease = lease;
2395
+ this.leaseStore = buildLeaseStore(lease);
2396
+ this.tileStore = buildTileStore(lease.values.tileBudgetMb);
2397
+ this.sceneStore = buildTileStore(lease.values.sceneBudgetMb);
2398
+ this.leaseGate = new LeaseActivityGate(lease.values.activityMs);
2399
+ this.admission = new LeaseAdmissionLedger({ mode: lease.values.admission });
2400
+ this.emitStderr(`decode-worker-child: ${require_worker_protocol.formatNativeLeaseKnobs(lease)}\n`, "info");
2350
2401
  this.sessionFormat = opts.format ?? "rgb";
2351
2402
  this.minIntervalMs = opts.fps && opts.fps > 0 ? 1e3 / opts.fps : 0;
2352
2403
  this.preRollMs = opts.preRollMs && opts.preRollMs > 0 ? opts.preRollMs : 0;
@@ -2400,7 +2451,7 @@ var DecodeWorkerChild = class {
2400
2451
  reservedFrameId: this.frames.reservedFrameId,
2401
2452
  marked: this.admission.isMarked(frameId),
2402
2453
  leaseFrames: this.leaseStore.size,
2403
- holdFrames: NATIVE_LEASE_HOLD_FRAMES,
2454
+ holdFrames: this.lease?.values.holdFrames ?? UNSTARTED_LEASE_KNOBS.values.holdFrames,
2404
2455
  holdOverflow: this.leaseStore.overflowCount,
2405
2456
  ...this.unmarkedBy.has(frameId) ? { unmarkedBy: this.unmarkedBy.get(frameId) } : {}
2406
2457
  }), frameId);
@@ -3562,6 +3613,35 @@ var DecodeWorkerChild = class {
3562
3613
  this.demuxer?.[Symbol.dispose]?.();
3563
3614
  this.demuxer = null;
3564
3615
  }
3616
+ /**
3617
+ * Load the native modules BEFORE any session, then say so. This is what a
3618
+ * pre-forked worker in the zygote pool (`decode-worker-pool.ts`) spends its
3619
+ * idle on — node-av's `dlopen` measured ~50 ms on the hub, and after D453
3620
+ * removed the types chunk it is the largest piece of a cold boot that is left.
3621
+ * It touches no stream, no demuxer, no GPU: a warm worker costs RSS and
3622
+ * nothing else, which is the property the pool exists for and the exact
3623
+ * inverse of the keep-warm D282 measured.
3624
+ *
3625
+ * A failure is reported, not fatal: `start` re-runs the same import and
3626
+ * fails the session the way it always has, so a node where node-av cannot
3627
+ * load is no worse off than before — it just is not warm.
3628
+ */
3629
+ async warm() {
3630
+ try {
3631
+ await getNodeAv();
3632
+ await getConstants();
3633
+ this.send({
3634
+ kind: "ready",
3635
+ warm: true
3636
+ });
3637
+ } catch (err) {
3638
+ this.emitStderr(`decode-worker-child: native module preload failed — ${errMessage(err)}\n`, "warn");
3639
+ this.send({
3640
+ kind: "ready",
3641
+ warm: false
3642
+ });
3643
+ }
3644
+ }
3565
3645
  send(reply) {
3566
3646
  process.send?.(reply);
3567
3647
  }
@@ -3619,6 +3699,7 @@ require_lazy_sharp.setSharpWarnSink((message) => {
3619
3699
  process.on("message", (message) => {
3620
3700
  worker.handleMessage(message);
3621
3701
  });
3702
+ worker.warm();
3622
3703
  process.on("disconnect", () => {
3623
3704
  worker.teardown();
3624
3705
  process.exit(0);