@intentic/constants 1.388.1 → 1.390.0

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/README.md CHANGED
@@ -37,7 +37,10 @@ flowchart LR
37
37
  on a Vue package, 4 GiB).
38
38
  - `memory-room` is the one formula for whether the sandbox has room (limit, used, free, stall, and what each workload
39
39
  class costs). The daemon's resource budget judges by it, and it is also the `memory-room` command `queue-run` asks:
40
- it asks the daemon's room socket, and applies the formula itself where no daemon answers.
40
+ it asks the daemon's room socket, and applies the formula itself where no daemon answers. (2026-11-02) A reading may
41
+ carry `host`, the machine the sandbox runs on as the daemon last heard from it: work nobody waits on then also waits
42
+ while its cost would take that machine under `host.reserveBytes`. Only the daemon adds it, so the fallback formula
43
+ never has a host to answer to.
41
44
  - `dev-previews` is the record of a conversation's managed dev preview (its demo server): where the records live
42
45
  (`/tmp/intentic-previews`), what makes one trustworthy (pid, start tick, conversation stamp, pid namespace), the cap
43
46
  of three and the ten-minute idle bound, the conversation's own port in 47150-47199, and how a preview is stopped
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentic/constants",
3
- "version": "1.388.1",
3
+ "version": "1.390.0",
4
4
  "description": "Shared constants for the intentic packages, ports, paths, and image references the daemon, CLIs and desktop app all agree on",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -40,6 +40,18 @@ export interface MemoryReading {
40
40
  readonly ioStallSustainedPercent?: number | undefined;
41
41
  // memory.events `oom_kill`, cumulative; undefined without a cgroup.
42
42
  readonly oomKills: number | undefined;
43
+ // (2026-11-02) The machine this sandbox runs on, as its agent last said, added by the daemon only while that is
44
+ // fresh; absent is "no host to answer to", never "no room". Work nobody waits on waits while it would take the host
45
+ // under `reserveBytes`.
46
+ readonly host?: HostRoom | undefined;
47
+ }
48
+
49
+ export interface HostRoom {
50
+ // The machine's name as the owner knows it (its device card), for the sentence a held command is given.
51
+ readonly name: string;
52
+ readonly availableBytes: number;
53
+ readonly totalBytes: number;
54
+ readonly reserveBytes: number;
43
55
  }
44
56
 
45
57
  export interface ShortMemory {
@@ -209,6 +209,11 @@ export const judge = (reading, { workload, attended, reservedBytes = 0, size })
209
209
  const stallSustainedPercent = reading.stallSustainedPercent ?? 0;
210
210
  const unreserved = freeBytesOf(reading);
211
211
  const counted = countedBytesOf(reading);
212
+ // Asked before the sandbox's own figures, which may measure nothing: a VM with room says nothing of the PC under it.
213
+ const hostHeld = hostWait(reading, { workload, attended, reservedBytes, size }, need, unreserved);
214
+ if (hostHeld !== undefined) {
215
+ return hostHeld;
216
+ }
212
217
  if (limitBytes === undefined || usedBytes === undefined || counted === undefined || unreserved === undefined) {
213
218
  return { verdict: "run", needBytes: need, freeBytes: undefined, reservedBytes };
214
219
  }
@@ -252,6 +257,29 @@ export const judge = (reading, { workload, attended, reservedBytes = 0, size })
252
257
  return shortOf(`Sandbox memory is low: ${used}${held}`, { limitBytes, residentBytes: usedBytes - swapBytes, swapBytes });
253
258
  };
254
259
 
260
+ // (2026-11-02) Why work nobody is waiting on should wait for the machine this sandbox runs on, or undefined while it need
261
+ // not. Everything else here reads the sandbox's own cgroup and the kernel under it, which on a Windows PC is Docker
262
+ // Desktop's WSL2 VM: on 2026-11-02 that VM read as roomy while Windows had 1.1 GB left and froze for 43 s. The daemon adds
263
+ // `reading.host` from what the host's agent last said (hosts/host-memory.ts), only while that is fresh, so a reading
264
+ // without it is "no host to answer to", never "no room". Work waits while starting it would take the host below its
265
+ // reserve, the line under which the host's agent starts giving the VM's cache back. Only the work's own cost counts here:
266
+ // the person's share in `needBytes` is room inside the sandbox, which the sandbox's own figures already keep.
267
+ const hostShortOf = (host, costBytes, reservedBytes) => {
268
+ if (host === undefined || host.availableBytes - host.reserveBytes - reservedBytes >= costBytes) {
269
+ return undefined;
270
+ }
271
+ const held = reservedBytes > 0 ? `, ${gib(reservedBytes)} of it held for work that just started` : "";
272
+ return `${host.name}, the machine this sandbox runs on, is low on memory: it has ${gib(host.availableBytes)} available of ${gib(host.totalBytes)}${held}, and heavy work waits while starting it would leave it under ${gib(host.reserveBytes)}`;
273
+ };
274
+
275
+ // The verdict that holds work nobody waits on for the host, or undefined while the host has room for it (hostShortOf).
276
+ const hostWait = (reading, { workload, attended, reservedBytes, size }, need, unreserved) => {
277
+ const diagnosis = attended ? undefined : hostShortOf(reading.host, costBytesOf(workload, size), reservedBytes);
278
+ return diagnosis === undefined
279
+ ? undefined
280
+ : { verdict: "wait", needBytes: need, freeBytes: unreserved === undefined ? undefined : Math.max(0, unreserved - reservedBytes), reservedBytes, diagnosis };
281
+ };
282
+
255
283
  // Why work nobody is waiting on should wait for the disk, or undefined while it need not (the `disk` clause).
256
284
  const diskStalled = (reading) => {
257
285
  const recent = reading.ioStallPercent ?? 0;