@rubytech/create-maxy-code 0.1.434 → 0.1.436

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 (83) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/docs/superpowers/plans/2026-07-11-task-1557-operator-on-behalf-preference-attribution.md +542 -0
  3. package/payload/platform/docs/superpowers/specs/2026-07-11-task-1557-operator-on-behalf-preference-attribution-design.md +90 -0
  4. package/payload/platform/lib/embed-client/dist/index.d.ts +2 -2
  5. package/payload/platform/lib/embed-client/dist/index.d.ts.map +1 -1
  6. package/payload/platform/lib/embed-client/dist/index.js +114 -37
  7. package/payload/platform/lib/embed-client/dist/index.js.map +1 -1
  8. package/payload/platform/lib/embed-client/src/index.ts +120 -37
  9. package/payload/platform/plugins/admin/PLUGIN.md +1 -0
  10. package/payload/platform/plugins/admin/hooks/__tests__/askuserquestion-channel-carrier-gate.test.sh +175 -0
  11. package/payload/platform/plugins/admin/hooks/askuserquestion-channel-carrier-gate.sh +137 -0
  12. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +2 -2
  13. package/payload/platform/plugins/docs/references/internals.md +1 -1
  14. package/payload/platform/plugins/memory/PLUGIN.md +2 -0
  15. package/payload/platform/plugins/memory/mcp/dist/index.js +42 -22
  16. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  17. package/payload/platform/plugins/memory/mcp/dist/lib/embed-progress-reporter.d.ts +22 -0
  18. package/payload/platform/plugins/memory/mcp/dist/lib/embed-progress-reporter.d.ts.map +1 -0
  19. package/payload/platform/plugins/memory/mcp/dist/lib/embed-progress-reporter.js +43 -0
  20. package/payload/platform/plugins/memory/mcp/dist/lib/embed-progress-reporter.js.map +1 -0
  21. package/payload/platform/plugins/memory/mcp/dist/lib/profile-identity.d.ts +34 -0
  22. package/payload/platform/plugins/memory/mcp/dist/lib/profile-identity.d.ts.map +1 -0
  23. package/payload/platform/plugins/memory/mcp/dist/lib/profile-identity.js +22 -0
  24. package/payload/platform/plugins/memory/mcp/dist/lib/profile-identity.js.map +1 -0
  25. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-admin-home-account.d.ts +13 -0
  26. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-admin-home-account.d.ts.map +1 -0
  27. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-admin-home-account.js +26 -0
  28. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-admin-home-account.js.map +1 -0
  29. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-progress-reporter.test.d.ts +2 -0
  30. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-progress-reporter.test.d.ts.map +1 -0
  31. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-progress-reporter.test.js +52 -0
  32. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-progress-reporter.test.js.map +1 -0
  33. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-progress.test.d.ts +2 -0
  34. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-progress.test.d.ts.map +1 -0
  35. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-progress.test.js +56 -0
  36. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-progress.test.js.map +1 -0
  37. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-throughput.test.js +186 -19
  38. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-throughput.test.js.map +1 -1
  39. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-timeout.test.js +11 -9
  40. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-timeout.test.js.map +1 -1
  41. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js +18 -12
  42. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js.map +1 -1
  43. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-identity.test.d.ts +2 -0
  44. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-identity.test.d.ts.map +1 -0
  45. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-identity.test.js +72 -0
  46. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-identity.test.js.map +1 -0
  47. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-own-preference-selfheal.test.d.ts +2 -0
  48. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-own-preference-selfheal.test.d.ts.map +1 -0
  49. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-own-preference-selfheal.test.js +113 -0
  50. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-own-preference-selfheal.test.js.map +1 -0
  51. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-bootstrap.test.js +2 -2
  52. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-bootstrap.test.js.map +1 -1
  53. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-reconcile.test.js +6 -0
  54. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-reconcile.test.js.map +1 -1
  55. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-admin-home-account.test.d.ts +2 -0
  56. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-admin-home-account.test.d.ts.map +1 -0
  57. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-admin-home-account.test.js +38 -0
  58. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/resolve-admin-home-account.test.js.map +1 -0
  59. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts +9 -0
  60. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts.map +1 -1
  61. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +2 -2
  62. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
  63. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +52 -7
  64. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
  65. package/payload/platform/plugins/memory/skills/conversational-memory/SKILL.md +8 -0
  66. package/payload/platform/scripts/lib/provision-account-dir.sh +2 -1
  67. package/payload/platform/services/claude-session-manager/dist/index.js +20 -0
  68. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  69. package/payload/platform/services/claude-session-manager/dist/interactive-wedge.d.ts +42 -0
  70. package/payload/platform/services/claude-session-manager/dist/interactive-wedge.d.ts.map +1 -0
  71. package/payload/platform/services/claude-session-manager/dist/interactive-wedge.js +149 -0
  72. package/payload/platform/services/claude-session-manager/dist/interactive-wedge.js.map +1 -0
  73. package/payload/server/{chunk-UUG6ZSO5.js → chunk-LMLVOZ6G.js} +35 -2
  74. package/payload/server/maxy-edge.js +1 -1
  75. package/payload/server/public/assets/{chat-C56bmC6C.js → chat-DUc7bt5W.js} +1 -1
  76. package/payload/server/public/assets/{operator-B4wN2c53.js → operator-B3Mi3TW0.js} +1 -1
  77. package/payload/server/public/assets/page-DbUaFfk6.js +32 -0
  78. package/payload/server/public/assets/{public-DmBKnBkr.js → public-CYhDdDJd.js} +1 -1
  79. package/payload/server/public/chat.html +2 -2
  80. package/payload/server/public/operator.html +2 -2
  81. package/payload/server/public/public.html +2 -2
  82. package/payload/server/server.js +8 -7
  83. package/payload/server/public/assets/page-BIfOKi9I.js +0 -32
@@ -8,7 +8,7 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.EMBED_KEEP_ALIVE = exports.EMBED_REQUEST_TIMEOUT_MS = exports.EMBED_MS_PER_INPUT = exports.EMBED_SUBBATCH_COOLDOWN_MS = exports.EMBED_SUBBATCH_SIZE = exports.EMBED_INPUT_MAX_CHARS = void 0;
10
10
  exports.embed = embed;
11
- exports.effectiveSubBatchSize = effectiveSubBatchSize;
11
+ exports.subBatchCharBudget = subBatchCharBudget;
12
12
  exports.embedBatch = embedBatch;
13
13
  const OLLAMA_URL = process.env.OLLAMA_URL ?? "http://localhost:11434";
14
14
  const EMBED_MODEL = process.env.EMBED_MODEL ?? "nomic-embed-text";
@@ -19,17 +19,18 @@ function envInt(name, def) {
19
19
  const n = Number(raw);
20
20
  return Number.isFinite(n) ? n : def;
21
21
  }
22
- // nomic-embed-text's usable embed context is 2048 tokens. The old 8000-char cap
23
- // assumed ~4 chars/token, but dense emoji/markup content runs richer, so a
24
- // section that passed the char cap still errored with "input length exceeds the
25
- // context length". Size the default against a conservative 3 chars/token worst
26
- // case, reserving a small token margin for the tokenizer's specials, so a capped
27
- // input is provably under context: (2048 - 48) * 3 = 6000. Context is
28
- // env-overridable so raising it raises the cap; EMBED_INPUT_MAX_CHARS is also
29
- // directly overridable.
22
+ // nomic-embed-text's usable embed context is 2048 tokens. The cap has been
23
+ // tightened twice against real 400s: 8000 (assumed ~4 chars/token) still
24
+ // overflowed on dense emoji/markup, then 6000 (~3 chars/token) still 400'd on
25
+ // the densest sections with "input length exceeds the context length" because
26
+ // that content runs closer to ~2 chars/token. Size the default against a
27
+ // conservative 2 chars/token worst case, reserving a small token margin for the
28
+ // tokenizer's specials, so a capped input is provably under context:
29
+ // (2048 - 48) * 2 = 4000 (Task 1558). Context is env-overridable so raising it
30
+ // raises the cap; EMBED_INPUT_MAX_CHARS is also directly overridable.
30
31
  const EMBED_MODEL_CONTEXT_TOKENS = Math.max(1, Math.floor(envInt("EMBED_MODEL_CONTEXT_TOKENS", 2048)));
31
32
  const EMBED_CONTEXT_MARGIN_TOKENS = 48;
32
- const EMBED_WORST_CASE_CHARS_PER_TOKEN = 3;
33
+ const EMBED_WORST_CASE_CHARS_PER_TOKEN = 2;
33
34
  exports.EMBED_INPUT_MAX_CHARS = Math.max(1, Math.floor(envInt("EMBED_INPUT_MAX_CHARS", (EMBED_MODEL_CONTEXT_TOKENS - EMBED_CONTEXT_MARGIN_TOKENS) *
34
35
  EMBED_WORST_CASE_CHARS_PER_TOKEN)));
35
36
  // Batch pacing (Task 960). On a passively-cooled Pi, embedding a whole
@@ -43,19 +44,36 @@ exports.EMBED_INPUT_MAX_CHARS = Math.max(1, Math.floor(envInt("EMBED_INPUT_MAX_C
43
44
  // this pacing is defence-in-depth and faster recovery. Both knobs are
44
45
  // env-overridable so an operator can tune them from on-device thermal
45
46
  // measurement without a code change.
46
- exports.EMBED_SUBBATCH_SIZE = Math.max(1, Math.floor(envInt("EMBED_SUBBATCH_SIZE", 32)));
47
+ //
48
+ // Count ceiling after adaptive sizing (Task 1558). Since Task 1553 each POST is
49
+ // sized by a character budget derived from the device's *measured* ms-per-char,
50
+ // so EMBED_SUBBATCH_SIZE is no longer the primary timeout guard — it is the hard
51
+ // count cap layered on top. It still matters for the one case the char budget
52
+ // cannot catch: the budget is derived from the probe's observed rate, so if the
53
+ // probe runs while the machine is briefly quiet the budget is large and the next
54
+ // POST packs up to this ceiling; if desktop contention then spikes mid-batch,
55
+ // that POST runs far slower than measured and can blow EMBED_REQUEST_TIMEOUT_MS.
56
+ // A ceiling of 4 bounds that worst case (~4 x 17s cold-CPU embeds on a contended
57
+ // shared desktop ~= 68s, under the 120s timeout) so a fast-probe-then-contention
58
+ // batch still fits. On a quiet dedicated appliance (a Pi) the char budget, not
59
+ // this count, is the binding constraint.
60
+ exports.EMBED_SUBBATCH_SIZE = Math.max(1, Math.floor(envInt("EMBED_SUBBATCH_SIZE", 4)));
47
61
  exports.EMBED_SUBBATCH_COOLDOWN_MS = Math.max(0, envInt("EMBED_SUBBATCH_COOLDOWN_MS", 1000));
48
- // Throughput-aware sub-batch sizing (Task 1533). On a CPU-only embedder each
49
- // input takes ~EMBED_MS_PER_INPUT ms; a fixed 32-input POST at the char cap is
50
- // ~128 s, past the 120 s request timeout, so a full-document batch aborts and
51
- // the atomic ingest write lands nothing. Bound each POST to 80% of the timeout
52
- // so it provably completes: derive a duration ceiling and take the smaller of
53
- // it and the count ceiling (EMBED_SUBBATCH_SIZE, Task 960's thermal cap).
54
- // EMBED_MS_PER_INPUT is the budgeted worst-case wall-time for one input at the
55
- // EMBED_INPUT_MAX_CHARS cap on the measured device; env-tunable for other
56
- // hardware.
62
+ // Drift baseline (Task 1553). This was Task 1533's sizing driver — the budgeted
63
+ // worst-case wall-time for one capped input but sizing that from a single
64
+ // fixed reading is exactly what over-provisioned a POST on a device slower than
65
+ // the reading and aborted the ingest. Sizing is now measured per batch
66
+ // (nextSubBatchSize), so EMBED_MS_PER_INPUT no longer drives it. It survives as
67
+ // the reconciliation baseline: each POST compares its observed per-input time
68
+ // against this budget and warns (op=drift) when the device runs slower, so a
69
+ // device below budget is surfaced by a standing check rather than by a silent
70
+ // ingest failure. Env-tunable for other hardware.
57
71
  exports.EMBED_MS_PER_INPUT = Math.max(1, Math.floor(envInt("EMBED_MS_PER_INPUT", 6000)));
58
72
  const EMBED_TIMEOUT_UTILISATION = 0.8;
73
+ // Warn (op=drift) once a POST's observed per-input time exceeds the budget by
74
+ // this factor. 1.5 tolerates ordinary variance while catching a device that is
75
+ // materially slower than EMBED_MS_PER_INPUT.
76
+ const EMBED_DRIFT_WARN_RATIO = 1.5;
59
77
  // Explicit per-request timeout, well under undici's 300000ms headers default.
60
78
  // Without it a slow or wedged ollama returns no headers and the caller hangs a
61
79
  // silent 5 minutes before a bare `fetch failed`. With it the request aborts in
@@ -130,7 +148,17 @@ async function embedRequest(input) {
130
148
  // oversized or slow sub-batch is visible before it times out and the
131
149
  // throughput-aware sizing is verifiable from the log. inputs is the POST's
132
150
  // sub-batch size; maxChars its largest input.
133
- process.stderr.write(`[embed] op=post inputs=${inputs.length} maxChars=${maxChars} ms=${Date.now() - startedAt}\n`);
151
+ const ms = Date.now() - startedAt;
152
+ process.stderr.write(`[embed] op=post inputs=${inputs.length} maxChars=${maxChars} ms=${ms}\n`);
153
+ // Standing reconciliation (Task 1553). Compare this POST's observed per-input
154
+ // time against the EMBED_MS_PER_INPUT budget and warn on drift, so a device
155
+ // slower than budget is caught by a check rather than by a later ingest that
156
+ // aborts. Sizing already adapts to the true rate; this line makes the
157
+ // slowness legible.
158
+ const observedMsPerInput = ms / inputs.length;
159
+ if (inputs.length > 0 && observedMsPerInput > exports.EMBED_MS_PER_INPUT * EMBED_DRIFT_WARN_RATIO) {
160
+ process.stderr.write(`[embed] op=drift observedMsPerInput=${Math.round(observedMsPerInput)} budgetMsPerInput=${exports.EMBED_MS_PER_INPUT} ratio=${(observedMsPerInput / exports.EMBED_MS_PER_INPUT).toFixed(1)}\n`);
161
+ }
134
162
  return data.embeddings;
135
163
  }
136
164
  // POST one already-capped sub-batch of inputs to the embed endpoint.
@@ -141,30 +169,79 @@ async function embed(text) {
141
169
  const data = await embedRequest(capInput(text));
142
170
  return data[0];
143
171
  }
144
- // The POST size actually used by embedBatch: the smaller of the count ceiling
145
- // (thermal, Task 960) and the duration ceiling (throughput, Task 1533). At
146
- // defaults: min(32, floor(120000*0.8/6000)) = min(32, 16) = 16.
147
- function effectiveSubBatchSize() {
148
- const durationCap = Math.max(1, Math.floor((exports.EMBED_REQUEST_TIMEOUT_MS * EMBED_TIMEOUT_UTILISATION) / exports.EMBED_MS_PER_INPUT));
149
- return Math.min(exports.EMBED_SUBBATCH_SIZE, durationCap);
172
+ // The character budget for one POST, decided from the device's *measured*
173
+ // throughput rather than a fixed constant (Task 1553). Task 1533 sized every
174
+ // POST by input count against `EMBED_MS_PER_INPUT`, a single optimistic
175
+ // reading; on a device slower than that constant the derived POST was too large
176
+ // to finish inside `EMBED_REQUEST_TIMEOUT_MS`, so it aborted and the atomic
177
+ // ingest landed nothing. Sizing by *count* is also unsafe when inputs differ in
178
+ // size — an embed's wall-time scales with its characters, so a POST sized from
179
+ // a short probe (e.g. a document summary) over-provisions when the later inputs
180
+ // are near-cap sections. Bound each POST by total characters instead:
181
+ // `floor(EMBED_REQUEST_TIMEOUT_MS * 0.8 / msPerChar)`, floored at 1. A near-zero
182
+ // (very fast) rate yields an unbounded budget so the thermal count ceiling
183
+ // (`EMBED_SUBBATCH_SIZE`, Task 960) governs instead.
184
+ function subBatchCharBudget(msPerChar) {
185
+ const perChar = Math.max(msPerChar, Number.MIN_VALUE); // guard div-by-zero
186
+ return Math.max(1, Math.floor((exports.EMBED_REQUEST_TIMEOUT_MS * EMBED_TIMEOUT_UTILISATION) / perChar));
150
187
  }
151
- async function embedBatch(texts) {
188
+ async function embedBatch(texts,
189
+ // Progress callback (Task 1555). Fired after each sub-batch POST resolves
190
+ // with (done, total): done = cumulative inputs embedded so far, total =
191
+ // inputs.length. memory-ingest passes a callback that emits an MCP progress
192
+ // notification per POST, which resets Claude Code's ~30-minute stdio idle
193
+ // timer so a long single ingest is not aborted mid-write. Kept MCP-agnostic
194
+ // — a plain (done, total) callback — so embed-client carries no MCP concepts
195
+ // and every existing one-arg caller is unchanged.
196
+ onProgress) {
152
197
  const inputs = texts.map(capInput);
153
- const subBatch = effectiveSubBatchSize();
154
- // Common case an array within the sub-batch size is one POST, unchanged.
155
- if (inputs.length <= subBatch) {
156
- return postBatch(inputs);
198
+ // 0 or 1 input is exactly one POST: the warm interactive query path is
199
+ // unaffected, and the empty-array behaviour is unchanged. Report once so the
200
+ // callback contract ("fires after every POST") holds on this path too.
201
+ if (inputs.length <= 1) {
202
+ const vectors = await postBatch(inputs);
203
+ onProgress?.(inputs.length, inputs.length);
204
+ return vectors;
157
205
  }
158
- // Oversized: split into sub-batches, cooling between each (not after the
159
- // last). Vectors are concatenated in input order so callers can keep their
206
+ // Measure-and-size. Probe with one input, then pack each subsequent POST with
207
+ // as many inputs as fit the character budget derived from the worst
208
+ // ms-per-char seen so far, capped by the thermal count ceiling. Using the
209
+ // running max makes the budget monotonic — a mid-batch slowdown (e.g. the
210
+ // ingest itself loading the CPU) shrinks the remainder and it never re-expands
211
+ // into a timeout. Cool between POSTs (not after the last) so the SoC gets gaps
212
+ // (Task 960). Vectors concatenate in input order so callers keep their
160
213
  // index-aligned `embeddings[i]` ↔ `texts[i]` contract.
161
214
  const out = [];
162
- for (let i = 0; i < inputs.length; i += subBatch) {
215
+ let maxMsPerChar = null;
216
+ for (let i = 0; i < inputs.length;) {
217
+ // Build the next chunk. With no measurement yet, probe with one input.
218
+ let end = i + 1;
219
+ if (maxMsPerChar !== null) {
220
+ const charBudget = subBatchCharBudget(maxMsPerChar);
221
+ let chars = inputs[i].length;
222
+ while (end < inputs.length &&
223
+ end - i < exports.EMBED_SUBBATCH_SIZE &&
224
+ chars + inputs[end].length <= charBudget) {
225
+ chars += inputs[end].length;
226
+ end += 1;
227
+ }
228
+ }
163
229
  if (i > 0 && exports.EMBED_SUBBATCH_COOLDOWN_MS > 0) {
164
230
  await sleep(exports.EMBED_SUBBATCH_COOLDOWN_MS);
165
231
  }
166
- const chunk = inputs.slice(i, i + subBatch);
167
- out.push(...(await postBatch(chunk)));
232
+ const chunk = inputs.slice(i, end);
233
+ const chunkChars = chunk.reduce((s, t) => s + t.length, 0);
234
+ const startedAt = Date.now();
235
+ const vectors = await postBatch(chunk);
236
+ const observedMsPerChar = (Date.now() - startedAt) / Math.max(chunkChars, 1);
237
+ maxMsPerChar =
238
+ maxMsPerChar === null ? observedMsPerChar : Math.max(maxMsPerChar, observedMsPerChar);
239
+ out.push(...vectors);
240
+ i = end;
241
+ // Report progress after each POST resolves. out.length is the cumulative
242
+ // inputs embedded so far; the final iteration reports out.length ===
243
+ // inputs.length.
244
+ onProgress?.(out.length, inputs.length);
168
245
  }
169
246
  return out;
170
247
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -15,17 +15,18 @@ function envInt(name: string, def: number): number {
15
15
  return Number.isFinite(n) ? n : def;
16
16
  }
17
17
 
18
- // nomic-embed-text's usable embed context is 2048 tokens. The old 8000-char cap
19
- // assumed ~4 chars/token, but dense emoji/markup content runs richer, so a
20
- // section that passed the char cap still errored with "input length exceeds the
21
- // context length". Size the default against a conservative 3 chars/token worst
22
- // case, reserving a small token margin for the tokenizer's specials, so a capped
23
- // input is provably under context: (2048 - 48) * 3 = 6000. Context is
24
- // env-overridable so raising it raises the cap; EMBED_INPUT_MAX_CHARS is also
25
- // directly overridable.
18
+ // nomic-embed-text's usable embed context is 2048 tokens. The cap has been
19
+ // tightened twice against real 400s: 8000 (assumed ~4 chars/token) still
20
+ // overflowed on dense emoji/markup, then 6000 (~3 chars/token) still 400'd on
21
+ // the densest sections with "input length exceeds the context length" because
22
+ // that content runs closer to ~2 chars/token. Size the default against a
23
+ // conservative 2 chars/token worst case, reserving a small token margin for the
24
+ // tokenizer's specials, so a capped input is provably under context:
25
+ // (2048 - 48) * 2 = 4000 (Task 1558). Context is env-overridable so raising it
26
+ // raises the cap; EMBED_INPUT_MAX_CHARS is also directly overridable.
26
27
  const EMBED_MODEL_CONTEXT_TOKENS = Math.max(1, Math.floor(envInt("EMBED_MODEL_CONTEXT_TOKENS", 2048)));
27
28
  const EMBED_CONTEXT_MARGIN_TOKENS = 48;
28
- const EMBED_WORST_CASE_CHARS_PER_TOKEN = 3;
29
+ const EMBED_WORST_CASE_CHARS_PER_TOKEN = 2;
29
30
  export const EMBED_INPUT_MAX_CHARS = Math.max(
30
31
  1,
31
32
  Math.floor(
@@ -48,23 +49,40 @@ export const EMBED_INPUT_MAX_CHARS = Math.max(
48
49
  // this pacing is defence-in-depth and faster recovery. Both knobs are
49
50
  // env-overridable so an operator can tune them from on-device thermal
50
51
  // measurement without a code change.
51
- export const EMBED_SUBBATCH_SIZE = Math.max(1, Math.floor(envInt("EMBED_SUBBATCH_SIZE", 32)));
52
+ //
53
+ // Count ceiling after adaptive sizing (Task 1558). Since Task 1553 each POST is
54
+ // sized by a character budget derived from the device's *measured* ms-per-char,
55
+ // so EMBED_SUBBATCH_SIZE is no longer the primary timeout guard — it is the hard
56
+ // count cap layered on top. It still matters for the one case the char budget
57
+ // cannot catch: the budget is derived from the probe's observed rate, so if the
58
+ // probe runs while the machine is briefly quiet the budget is large and the next
59
+ // POST packs up to this ceiling; if desktop contention then spikes mid-batch,
60
+ // that POST runs far slower than measured and can blow EMBED_REQUEST_TIMEOUT_MS.
61
+ // A ceiling of 4 bounds that worst case (~4 x 17s cold-CPU embeds on a contended
62
+ // shared desktop ~= 68s, under the 120s timeout) so a fast-probe-then-contention
63
+ // batch still fits. On a quiet dedicated appliance (a Pi) the char budget, not
64
+ // this count, is the binding constraint.
65
+ export const EMBED_SUBBATCH_SIZE = Math.max(1, Math.floor(envInt("EMBED_SUBBATCH_SIZE", 4)));
52
66
  export const EMBED_SUBBATCH_COOLDOWN_MS = Math.max(
53
67
  0,
54
68
  envInt("EMBED_SUBBATCH_COOLDOWN_MS", 1000),
55
69
  );
56
70
 
57
- // Throughput-aware sub-batch sizing (Task 1533). On a CPU-only embedder each
58
- // input takes ~EMBED_MS_PER_INPUT ms; a fixed 32-input POST at the char cap is
59
- // ~128 s, past the 120 s request timeout, so a full-document batch aborts and
60
- // the atomic ingest write lands nothing. Bound each POST to 80% of the timeout
61
- // so it provably completes: derive a duration ceiling and take the smaller of
62
- // it and the count ceiling (EMBED_SUBBATCH_SIZE, Task 960's thermal cap).
63
- // EMBED_MS_PER_INPUT is the budgeted worst-case wall-time for one input at the
64
- // EMBED_INPUT_MAX_CHARS cap on the measured device; env-tunable for other
65
- // hardware.
71
+ // Drift baseline (Task 1553). This was Task 1533's sizing driver — the budgeted
72
+ // worst-case wall-time for one capped input but sizing that from a single
73
+ // fixed reading is exactly what over-provisioned a POST on a device slower than
74
+ // the reading and aborted the ingest. Sizing is now measured per batch
75
+ // (nextSubBatchSize), so EMBED_MS_PER_INPUT no longer drives it. It survives as
76
+ // the reconciliation baseline: each POST compares its observed per-input time
77
+ // against this budget and warns (op=drift) when the device runs slower, so a
78
+ // device below budget is surfaced by a standing check rather than by a silent
79
+ // ingest failure. Env-tunable for other hardware.
66
80
  export const EMBED_MS_PER_INPUT = Math.max(1, Math.floor(envInt("EMBED_MS_PER_INPUT", 6000)));
67
81
  const EMBED_TIMEOUT_UTILISATION = 0.8;
82
+ // Warn (op=drift) once a POST's observed per-input time exceeds the budget by
83
+ // this factor. 1.5 tolerates ordinary variance while catching a device that is
84
+ // materially slower than EMBED_MS_PER_INPUT.
85
+ const EMBED_DRIFT_WARN_RATIO = 1.5;
68
86
 
69
87
  // Explicit per-request timeout, well under undici's 300000ms headers default.
70
88
  // Without it a slow or wedged ollama returns no headers and the caller hangs a
@@ -157,9 +175,21 @@ async function embedRequest(input: string | string[]): Promise<number[][]> {
157
175
  // oversized or slow sub-batch is visible before it times out and the
158
176
  // throughput-aware sizing is verifiable from the log. inputs is the POST's
159
177
  // sub-batch size; maxChars its largest input.
178
+ const ms = Date.now() - startedAt;
160
179
  process.stderr.write(
161
- `[embed] op=post inputs=${inputs.length} maxChars=${maxChars} ms=${Date.now() - startedAt}\n`,
180
+ `[embed] op=post inputs=${inputs.length} maxChars=${maxChars} ms=${ms}\n`,
162
181
  );
182
+ // Standing reconciliation (Task 1553). Compare this POST's observed per-input
183
+ // time against the EMBED_MS_PER_INPUT budget and warn on drift, so a device
184
+ // slower than budget is caught by a check rather than by a later ingest that
185
+ // aborts. Sizing already adapts to the true rate; this line makes the
186
+ // slowness legible.
187
+ const observedMsPerInput = ms / inputs.length;
188
+ if (inputs.length > 0 && observedMsPerInput > EMBED_MS_PER_INPUT * EMBED_DRIFT_WARN_RATIO) {
189
+ process.stderr.write(
190
+ `[embed] op=drift observedMsPerInput=${Math.round(observedMsPerInput)} budgetMsPerInput=${EMBED_MS_PER_INPUT} ratio=${(observedMsPerInput / EMBED_MS_PER_INPUT).toFixed(1)}\n`,
191
+ );
192
+ }
163
193
  return data.embeddings;
164
194
  }
165
195
 
@@ -173,36 +203,89 @@ export async function embed(text: string): Promise<number[]> {
173
203
  return data[0];
174
204
  }
175
205
 
176
- // The POST size actually used by embedBatch: the smaller of the count ceiling
177
- // (thermal, Task 960) and the duration ceiling (throughput, Task 1533). At
178
- // defaults: min(32, floor(120000*0.8/6000)) = min(32, 16) = 16.
179
- export function effectiveSubBatchSize(): number {
180
- const durationCap = Math.max(
206
+ // The character budget for one POST, decided from the device's *measured*
207
+ // throughput rather than a fixed constant (Task 1553). Task 1533 sized every
208
+ // POST by input count against `EMBED_MS_PER_INPUT`, a single optimistic
209
+ // reading; on a device slower than that constant the derived POST was too large
210
+ // to finish inside `EMBED_REQUEST_TIMEOUT_MS`, so it aborted and the atomic
211
+ // ingest landed nothing. Sizing by *count* is also unsafe when inputs differ in
212
+ // size — an embed's wall-time scales with its characters, so a POST sized from
213
+ // a short probe (e.g. a document summary) over-provisions when the later inputs
214
+ // are near-cap sections. Bound each POST by total characters instead:
215
+ // `floor(EMBED_REQUEST_TIMEOUT_MS * 0.8 / msPerChar)`, floored at 1. A near-zero
216
+ // (very fast) rate yields an unbounded budget so the thermal count ceiling
217
+ // (`EMBED_SUBBATCH_SIZE`, Task 960) governs instead.
218
+ export function subBatchCharBudget(msPerChar: number): number {
219
+ const perChar = Math.max(msPerChar, Number.MIN_VALUE); // guard div-by-zero
220
+ return Math.max(
181
221
  1,
182
- Math.floor((EMBED_REQUEST_TIMEOUT_MS * EMBED_TIMEOUT_UTILISATION) / EMBED_MS_PER_INPUT),
222
+ Math.floor((EMBED_REQUEST_TIMEOUT_MS * EMBED_TIMEOUT_UTILISATION) / perChar),
183
223
  );
184
- return Math.min(EMBED_SUBBATCH_SIZE, durationCap);
185
224
  }
186
225
 
187
- export async function embedBatch(texts: string[]): Promise<number[][]> {
226
+ export async function embedBatch(
227
+ texts: string[],
228
+ // Progress callback (Task 1555). Fired after each sub-batch POST resolves
229
+ // with (done, total): done = cumulative inputs embedded so far, total =
230
+ // inputs.length. memory-ingest passes a callback that emits an MCP progress
231
+ // notification per POST, which resets Claude Code's ~30-minute stdio idle
232
+ // timer so a long single ingest is not aborted mid-write. Kept MCP-agnostic
233
+ // — a plain (done, total) callback — so embed-client carries no MCP concepts
234
+ // and every existing one-arg caller is unchanged.
235
+ onProgress?: (done: number, total: number) => void,
236
+ ): Promise<number[][]> {
188
237
  const inputs = texts.map(capInput);
189
- const subBatch = effectiveSubBatchSize();
190
238
 
191
- // Common case an array within the sub-batch size is one POST, unchanged.
192
- if (inputs.length <= subBatch) {
193
- return postBatch(inputs);
239
+ // 0 or 1 input is exactly one POST: the warm interactive query path is
240
+ // unaffected, and the empty-array behaviour is unchanged. Report once so the
241
+ // callback contract ("fires after every POST") holds on this path too.
242
+ if (inputs.length <= 1) {
243
+ const vectors = await postBatch(inputs);
244
+ onProgress?.(inputs.length, inputs.length);
245
+ return vectors;
194
246
  }
195
247
 
196
- // Oversized: split into sub-batches, cooling between each (not after the
197
- // last). Vectors are concatenated in input order so callers can keep their
248
+ // Measure-and-size. Probe with one input, then pack each subsequent POST with
249
+ // as many inputs as fit the character budget derived from the worst
250
+ // ms-per-char seen so far, capped by the thermal count ceiling. Using the
251
+ // running max makes the budget monotonic — a mid-batch slowdown (e.g. the
252
+ // ingest itself loading the CPU) shrinks the remainder and it never re-expands
253
+ // into a timeout. Cool between POSTs (not after the last) so the SoC gets gaps
254
+ // (Task 960). Vectors concatenate in input order so callers keep their
198
255
  // index-aligned `embeddings[i]` ↔ `texts[i]` contract.
199
256
  const out: number[][] = [];
200
- for (let i = 0; i < inputs.length; i += subBatch) {
257
+ let maxMsPerChar: number | null = null;
258
+ for (let i = 0; i < inputs.length; ) {
259
+ // Build the next chunk. With no measurement yet, probe with one input.
260
+ let end = i + 1;
261
+ if (maxMsPerChar !== null) {
262
+ const charBudget = subBatchCharBudget(maxMsPerChar);
263
+ let chars = inputs[i].length;
264
+ while (
265
+ end < inputs.length &&
266
+ end - i < EMBED_SUBBATCH_SIZE &&
267
+ chars + inputs[end].length <= charBudget
268
+ ) {
269
+ chars += inputs[end].length;
270
+ end += 1;
271
+ }
272
+ }
201
273
  if (i > 0 && EMBED_SUBBATCH_COOLDOWN_MS > 0) {
202
274
  await sleep(EMBED_SUBBATCH_COOLDOWN_MS);
203
275
  }
204
- const chunk = inputs.slice(i, i + subBatch);
205
- out.push(...(await postBatch(chunk)));
276
+ const chunk = inputs.slice(i, end);
277
+ const chunkChars = chunk.reduce((s, t) => s + t.length, 0);
278
+ const startedAt = Date.now();
279
+ const vectors = await postBatch(chunk);
280
+ const observedMsPerChar = (Date.now() - startedAt) / Math.max(chunkChars, 1);
281
+ maxMsPerChar =
282
+ maxMsPerChar === null ? observedMsPerChar : Math.max(maxMsPerChar, observedMsPerChar);
283
+ out.push(...vectors);
284
+ i = end;
285
+ // Report progress after each POST resolves. out.length is the cumulative
286
+ // inputs embedded so far; the final iteration reports out.length ===
287
+ // inputs.length.
288
+ onProgress?.(out.length, inputs.length);
206
289
  }
207
290
  return out;
208
291
  }
@@ -174,6 +174,7 @@ Tools are available via the `admin` MCP server.
174
174
 
175
175
  - `hooks/webfetch-preflight.mjs` — short-circuits WebFetch on JS-SPA shells with a structured `WEBFETCH_CANNOT_READ_JS_SPA` error so the agent surfaces a loud failure to the owner instead of paying the 60s extraction timeout. Fail-open on any internal error.
176
176
  - `hooks/askuserquestion-investigate-gate.sh` — PreToolUse matcher=`AskUserQuestion`. Blocks the question (exit 2) when no read-only investigation tool has fired since the latest real user turn in the session JSONL. The structural fix for the failure class where the agent fabricates a menu before evidence-gathering (session `c085ec2c-46fb-4b73-8865-68cf85866ea8` 2026-05-22 — "change remote access password" → invented options "Admin PIN / Cloudflare tunnel / WiFi password" with zero prior tool_use; post-correction the agent immediately fired `remote-auth-status` → `ToolSearch` → `remote-auth-set-password`, proving it knew the moves). **Allowlist** (exact, with trailing `__<tool>` suffix-match for namespaced `mcp__plugin_<plugin>_<server>__<tool>` aliases): `ToolSearch`, `Grep`, `Glob`, `Read`, `LS`, `NotebookRead`, `Bash`, `WebFetch`, `WebSearch`, plus the read-only admin / memory MCP tools (`*-status`, `*-list`, `*-read`, `skill-find`, `memory-find-candidates`, `profile-read`, `conversation-list`, `memory-list-attachments`, `memory-read-attachment`). **Block message:** `Blocked: AskUserQuestion requires at least one investigation tool (ToolSearch, Grep, Read, *-list, *-status, *-read, skill-find, ...) earlier in this turn. Search the operator's literal phrase first.` **Log line** (stderr, one per call): `[ask-gate] decision=<allow|block> sessionId=<id8> seen=<csv|-> reason=<allowlist-hit|no-investigation|fail-open-no-transcript|fail-open-parse-error>`. **Fail-open** on missing transcript or parse error — nudges, never bricks the UI.
177
+ - `hooks/askuserquestion-channel-carrier-gate.sh` — PreToolUse matcher=`AskUserQuestion`, registered as a **second command on the same matcher** as the investigate-gate (either exit 2 blocks; the two guard different conditions). Blocks the question (exit 2) when the session has a native channel attached, because the Claude Code channel protocol carries only the two permission methods — there is no carrier for the `AskUserQuestion` elicitation, so on an rc-spawn channel (webchat/WhatsApp/Telegram) session the harness would block the turn awaiting a selection that can never arrive and the reader renders only delivered replies, wedging the turn (live SiteDesk incident session `1a085718` 2026-07-11: `/chat` stalled on the delivered "On it…" ack with no card). **Signal:** the rc-spawn writes the channel MCP registration as a config file in `os.tmpdir()` keyed by session id (`maxy-channel-<sid>.json` / `maxy-webchat-channel-<sid>.json` / `maxy-wa-channel-<sid>.json` / `maxy-telegram-channel-<sid>.json`, `sid` sanitized `[^A-Za-z0-9_-]→_` exactly as the writers do); its presence at tool-call time is the authoritative "channel attached to this session" marker. The hook resolves the tmpdir the way Node's `os.tmpdir()` does (`${TMPDIR:-/tmp}`, trailing slash stripped). Correct in both readings of the claude.ai/code scoping question: a Pi channel process sees the tmpfile (block); a claude.ai/code process on another host never sees the Pi tmpfile (fail-open → allow, that surface can answer the card). **Block message:** `Blocked: this is a native-channel session and AskUserQuestion cannot be delivered over a channel (the channel protocol carries no elicitation card, so the turn would wedge). Ask the same question as prose in your channel reply tool and wait for the operator's next message.` **Log line** (stderr, one per decisive call): `[ask-channel] decision=<allow|block> sessionId=<id8> channel=<attached|none> reason=<channel-attached|no-channel|fail-open-no-envelope|fail-open-no-session>`. **Fail-open** on no envelope, blank session id, or absent channel file — nudges, never bricks the UI. The complementary standing check (`interactive-wedge` in the session manager) catches any un-carried interactive tool_use that slips past this hook.
177
178
  - `hooks/mcp-tool-missing.sh` — **PostToolUse hook on `mcp__.*` (directive 3).** Defence-in-depth for the `No such tool available: mcp__…` failure class that the name-binding is built to eliminate. Fires on any MCP tool call; no-op unless the `tool_response` carries `No such tool available` AND the qualified name resolves to a maxy plugin (read from the generated `hooks/lib/maxy-mcp-plugins.txt`). On a maxy match it logs one deterministic `[mcp-tool-missing] server=<server> tool=<tool>` line and exits 2 with a fixed envelope on stderr, so the agent relays a named server-unavailable failure instead of narrating "warming up" or blind-retrying. A missing non-maxy bridge tool (Playwright etc., upstream-owned) passes through (exit 0). The maxy-plugin list is regenerated and gate-diffed by `platform/scripts/check-canonical-tool-names.mjs`.
178
179
  - `hooks/post-tool-use-agent.sh` — **PostToolUse hook on `Agent`.** Drains any subagent hook-decision buffers under `~/.maxy-code/logs/hook-decisions/` modified since this parent's previous PostToolUse-Agent fire (cursor file keyed by parent session id), prints one `[hook-propagate]` line per record to stdout — Claude Code attaches the stdout as a `hook_success` attachment on the parent JSONL, making the records grep-queryable from the parent session alone. Rotates consumed buffers to `consumed/`. Emits one `[hook-propagate-census] parentSession=<…> subagentHooksObserved=<N> attachmentsEmitted=<M>` line per fire to stdout and server.log; `N != M` is the propagation regression signal. The companion emitter library `hooks/lib/hook-emit.sh` is sourced by `post-tool-use-agent.sh` and any other hook that records a block decision (4 KB stderr truncation, `truncated=true` set on the record).
179
180
  - `hooks/admin-authoring-observer.sh` — **PostToolUse hook on Write and Edit.** Observation only — never blocks; exits 0 on every path. Fires when the admin agent (not a specialist subagent — gated by `MAXY_SPECIALIST` env) writes or edits a file under `<accountDir>/output/`. Walks the session transcript from the latest real-user turn forward to detect any prior `Task` `tool_use` whose `subagent_type` starts with `specialists:`. Emits one stderr line `[admin-authoring] inline-write path=<rel> priorSpecialistSpawnInTurn=<true|false|unknown>`. A `false` value on a long-form prose file is the regression signal this hook was designed to make visible — the BioSymm proposal session (admin authored a customer-facing proposal inline despite content-producer being installed) is the failure mode this surfaces mechanically. Mechanical enforcement (refuse the write, force a re-spawn) is deferred per the task spec.