@adhdev/mesh-shared 1.0.60-rc.45 → 1.0.60-rc.46

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.
@@ -42,6 +42,16 @@ export declare const DELIVERY_VIAS: readonly ["local", "p2p"];
42
42
  export type DeliveryVia = typeof DELIVERY_VIAS[number];
43
43
  export declare const DISPATCH_FAILURE_REASONS: readonly ["worker_absent", "transport_error", "spawn_failed", "rejected_by_worker", "timeout"];
44
44
  export type DispatchFailureReason = typeof DISPATCH_FAILURE_REASONS[number];
45
+ /**
46
+ * Normalize a worker's own refusal code (e.g. `session_busy_with_task`,
47
+ * `mesh_sender_not_on_roster`, `provider_quota_exhausted`) into the shape
48
+ * `dispatch_failed.refusalCode` accepts: lowercase ascii + underscore, capped
49
+ * at 64 chars. Returns undefined for anything that yields no usable token, so
50
+ * a malformed/foreign code degrades to "no refusalCode" rather than smuggling
51
+ * arbitrary text through what must stay a closed-enum-like identifier slot
52
+ * (see the field's doc comment — this evidence replicates cross-machine).
53
+ */
54
+ export declare function sanitizeRefusalCode(value: unknown): string | undefined;
45
55
  export declare const CONSUME_PROFILES: readonly ["default", "native_source"];
46
56
  export type ConsumeProfile = typeof CONSUME_PROFILES[number];
47
57
  export declare const SESSION_REBOUND_REASONS: readonly ["restart", "live_holder"];
@@ -174,10 +184,25 @@ export type TurnEvidenceBody = {
174
184
  kind: 'delivery_refused';
175
185
  messageId: string;
176
186
  reason: SendRefusal;
177
- } | {
187
+ }
188
+ /**
189
+ * `refusalCode` (wiring-unification live-gap fix, 2026-09-25): the worker's own
190
+ * refusal code for an application-level `{success:false}` answer (e.g.
191
+ * `session_busy_with_task`, `mesh_sender_not_on_roster`,
192
+ * `mesh_node_bootstrap_pending`, `provider_quota_exhausted`) — optional and
193
+ * ONLY ever populated for `reason: 'rejected_by_worker'`. Deliberately an `id`
194
+ * (short enum-like token), never free text: this evidence replicates across
195
+ * machines over `mesh.<id>.events` (CONTENT-FREE BY CONSTRUCTION above), so a
196
+ * human-readable detail string must NOT travel here — it stays local (owner
197
+ * WARN log, MCP tool JSON response). Producers sanitize to `[a-z_]{1,64}`
198
+ * before emitting so a stray free-text code can never smuggle prose through
199
+ * this slot.
200
+ */
201
+ | {
178
202
  kind: 'dispatch_failed';
179
203
  workerAbsent: boolean;
180
204
  reason: DispatchFailureReason;
205
+ refusalCode?: string;
181
206
  } | {
182
207
  kind: 'duplicate_dispatch_refusal';
183
208
  holderSessionId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/mesh-shared",
3
- "version": "1.0.60-rc.45",
3
+ "version": "1.0.60-rc.46",
4
4
  "description": "ADHDev mesh-shared — pure mesh/git status normalizers shared by daemon-core and web-core",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -59,6 +59,22 @@ export type DeliveryVia = typeof DELIVERY_VIAS[number]
59
59
  export const DISPATCH_FAILURE_REASONS = ['worker_absent', 'transport_error', 'spawn_failed', 'rejected_by_worker', 'timeout'] as const
60
60
  export type DispatchFailureReason = typeof DISPATCH_FAILURE_REASONS[number]
61
61
 
62
+ /**
63
+ * Normalize a worker's own refusal code (e.g. `session_busy_with_task`,
64
+ * `mesh_sender_not_on_roster`, `provider_quota_exhausted`) into the shape
65
+ * `dispatch_failed.refusalCode` accepts: lowercase ascii + underscore, capped
66
+ * at 64 chars. Returns undefined for anything that yields no usable token, so
67
+ * a malformed/foreign code degrades to "no refusalCode" rather than smuggling
68
+ * arbitrary text through what must stay a closed-enum-like identifier slot
69
+ * (see the field's doc comment — this evidence replicates cross-machine).
70
+ */
71
+ export function sanitizeRefusalCode(value: unknown): string | undefined {
72
+ if (typeof value !== 'string') return undefined
73
+ const normalized = value.trim().toLowerCase().replace(/[^a-z_]/g, '_').replace(/_+/g, '_').replace(/^_+|_+$/g, '')
74
+ if (!normalized) return undefined
75
+ return normalized.slice(0, 64)
76
+ }
77
+
62
78
  export const CONSUME_PROFILES = ['default', 'native_source'] as const
63
79
  export type ConsumeProfile = typeof CONSUME_PROFILES[number]
64
80
 
@@ -214,7 +230,20 @@ export type TurnEvidenceBody =
214
230
  coordinator?: EvidenceCoordinatorIdentity }
215
231
  | { kind: 'delivered'; messageId: string; outcome: DeliveryOutcome; via: DeliveryVia }
216
232
  | { kind: 'delivery_refused'; messageId: string; reason: SendRefusal }
217
- | { kind: 'dispatch_failed'; workerAbsent: boolean; reason: DispatchFailureReason }
233
+ /**
234
+ * `refusalCode` (wiring-unification live-gap fix, 2026-09-25): the worker's own
235
+ * refusal code for an application-level `{success:false}` answer (e.g.
236
+ * `session_busy_with_task`, `mesh_sender_not_on_roster`,
237
+ * `mesh_node_bootstrap_pending`, `provider_quota_exhausted`) — optional and
238
+ * ONLY ever populated for `reason: 'rejected_by_worker'`. Deliberately an `id`
239
+ * (short enum-like token), never free text: this evidence replicates across
240
+ * machines over `mesh.<id>.events` (CONTENT-FREE BY CONSTRUCTION above), so a
241
+ * human-readable detail string must NOT travel here — it stays local (owner
242
+ * WARN log, MCP tool JSON response). Producers sanitize to `[a-z_]{1,64}`
243
+ * before emitting so a stray free-text code can never smuggle prose through
244
+ * this slot.
245
+ */
246
+ | { kind: 'dispatch_failed'; workerAbsent: boolean; reason: DispatchFailureReason; refusalCode?: string }
218
247
  | { kind: 'duplicate_dispatch_refusal'; holderSessionId: string; holderAttemptId?: string }
219
248
  | { kind: 'session_rebound'; toSessionId: string; reason: SessionReboundReason }
220
249
  // ── worker turn lifecycle ──
@@ -309,7 +338,7 @@ export const TURN_EVIDENCE_FIELD_SPECS: TurnEvidenceFieldSpecs = {
309
338
  },
310
339
  delivered: { messageId: id, outcome: en(DELIVERY_OUTCOMES), via: en(DELIVERY_VIAS) },
311
340
  delivery_refused: { messageId: id, reason: en(SEND_REFUSAL_REASONS) },
312
- dispatch_failed: { workerAbsent: bool, reason: en(DISPATCH_FAILURE_REASONS) },
341
+ dispatch_failed: { workerAbsent: bool, reason: en(DISPATCH_FAILURE_REASONS), refusalCode: idOpt },
313
342
  duplicate_dispatch_refusal: { holderSessionId: id, holderAttemptId: idOpt },
314
343
  session_rebound: { toSessionId: id, reason: en(SESSION_REBOUND_REASONS) },
315
344
  turn_started: { retro: bool },