instar 1.3.561 → 1.3.563

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.
@@ -57,6 +57,23 @@ export declare const PROTOCOL_REDISPATCH_HORIZON_MAX_MS: number;
57
57
  * safe to queue-OFF on violation, so a generous constant only tightens).
58
58
  */
59
59
  export declare const BOOT_SWEEP_WINDOW_MS: number;
60
+ /**
61
+ * Resolve the Multi-Machine Session Pool rollout STAGE from a config block.
62
+ * Returns the configured `stage` string only when the pool is BOTH enabled AND
63
+ * carries a `stage`; otherwise 'dark' (the inert default). This is the single
64
+ * source of truth for "is the session pool active, and at what stage?" — both
65
+ * the boot-time inbound-queue construction gate AND the live `_sessionPoolStage`
66
+ * getter in server.ts resolve through this one pure function, so the two can
67
+ * never drift (the original divergence is exactly what let the construction gate
68
+ * read a stale stub and keep the inbound queue dark forever — boot-order bug).
69
+ *
70
+ * @param cfg the resolved `multiMachine.sessionPool` block (liveConfig override
71
+ * merged over the static config block, or just the static block at boot).
72
+ */
73
+ export declare function resolveSessionPoolStage(cfg: {
74
+ enabled?: boolean;
75
+ stage?: string;
76
+ } | null | undefined): string;
60
77
  /** Σbackoff: total worst-case backoff across maxAttempts (capped curve). */
61
78
  export declare function sumBackoffMs(cfg: Pick<InboundQueueConfig, 'baseBackoffMs' | 'maxBackoffMs' | 'maxAttempts'>): number;
62
79
  /** The full redispatch horizon a receipt must outlive (§3.4 receipt floor). */
@@ -1 +1 @@
1
- {"version":3,"file":"inboundQueueConfig.d.ts","sourceRoot":"","sources":["../../src/core/inboundQueueConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,0BAA0B,EAAE,MAAM,CAAC;IACnC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,4BAA4B,EAAE,kBA0B1C,CAAC;AAEF,eAAO,MAAM,iCAAiC,EAAE,sBAK/C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kCAAkC,QAAsB,CAAC;AAEtE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,QAAgB,CAAC;AAElD,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,kBAAkB,EAAE,eAAe,GAAG,cAAc,GAAG,aAAa,CAAC,GAAG,MAAM,CAMpH;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,kBAAkB,GAAG,MAAM,CAEnE;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,CAAC,EAAE,kBAAkB,EACrB,CAAC,EAAE,sBAAsB,GACxB;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,kBAAkB,EAAE,CAAA;CAAE,CAkEnD"}
1
+ {"version":3,"file":"inboundQueueConfig.d.ts","sourceRoot":"","sources":["../../src/core/inboundQueueConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,0BAA0B,EAAE,MAAM,CAAC;IACnC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,4BAA4B,EAAE,kBA0B1C,CAAC;AAEF,eAAO,MAAM,iCAAiC,EAAE,sBAK/C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kCAAkC,QAAsB,CAAC;AAEtE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,QAAgB,CAAC;AAElD;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,GAC5D,MAAM,CAER;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,kBAAkB,EAAE,eAAe,GAAG,cAAc,GAAG,aAAa,CAAC,GAAG,MAAM,CAMpH;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,kBAAkB,GAAG,MAAM,CAEnE;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,CAAC,EAAE,kBAAkB,EACrB,CAAC,EAAE,sBAAsB,GACxB;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,kBAAkB,EAAE,CAAA;CAAE,CAkEnD"}
@@ -55,6 +55,22 @@ export const PROTOCOL_REDISPATCH_HORIZON_MAX_MS = 12 * 60 * 60 * 1000; // 12h
55
55
  * safe to queue-OFF on violation, so a generous constant only tightens).
56
56
  */
57
57
  export const BOOT_SWEEP_WINDOW_MS = 5 * 60 * 1000; // 5 min
58
+ /**
59
+ * Resolve the Multi-Machine Session Pool rollout STAGE from a config block.
60
+ * Returns the configured `stage` string only when the pool is BOTH enabled AND
61
+ * carries a `stage`; otherwise 'dark' (the inert default). This is the single
62
+ * source of truth for "is the session pool active, and at what stage?" — both
63
+ * the boot-time inbound-queue construction gate AND the live `_sessionPoolStage`
64
+ * getter in server.ts resolve through this one pure function, so the two can
65
+ * never drift (the original divergence is exactly what let the construction gate
66
+ * read a stale stub and keep the inbound queue dark forever — boot-order bug).
67
+ *
68
+ * @param cfg the resolved `multiMachine.sessionPool` block (liveConfig override
69
+ * merged over the static config block, or just the static block at boot).
70
+ */
71
+ export function resolveSessionPoolStage(cfg) {
72
+ return cfg?.enabled && cfg?.stage ? String(cfg.stage) : 'dark';
73
+ }
58
74
  /** Σbackoff: total worst-case backoff across maxAttempts (capped curve). */
59
75
  export function sumBackoffMs(cfg) {
60
76
  let sum = 0;
@@ -1 +1 @@
1
- {"version":3,"file":"inboundQueueConfig.js","sourceRoot":"","sources":["../../src/core/inboundQueueConfig.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"inboundQueueConfig.js","sourceRoot":"","sources":["../../src/core/inboundQueueConfig.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,10 @@
3
3
  *
4
4
  * Prevents prompt injection, path traversal, and SSRF attacks
5
5
  * by validating and cleaning user-controlled fields before use.
6
+ *
7
+ * CONTRACT-EVIDENCE: EXEMPT — pure string-validation/slug helpers; this module
8
+ * makes NO Slack API calls and touches no API-contract surface. The added
9
+ * slugifyChannelName is covered by tests/unit/slack-channel-slug.test.ts.
6
10
  */
7
11
  /**
8
12
  * Sanitize a Slack display name for safe injection into session context.
@@ -21,6 +25,19 @@ export declare function validateChannelId(id: string): boolean;
21
25
  * Must be lowercase alphanumeric with hyphens/underscores, max 80 chars.
22
26
  */
23
27
  export declare function validateChannelName(name: string): boolean;
28
+ /**
29
+ * Slugify an arbitrary string into a valid Slack channel name.
30
+ *
31
+ * Slack channel names must be lowercase and may only contain [a-z0-9-_]
32
+ * (see {@link validateChannelName}). A workspace-derived name like
33
+ * "SageMind Live Test" contains spaces and uppercase, which `createChannel`
34
+ * rejects via validate-and-throw. This produces a guaranteed-valid slug:
35
+ * lowercase, non-[a-z0-9] runs collapsed to a single hyphen, leading/trailing
36
+ * hyphens trimmed, and clamped to Slack's 80-char limit.
37
+ *
38
+ * Mirrors the session-channel slug logic in SlackAdapter.
39
+ */
40
+ export declare function slugifyChannelName(name: string): string;
24
41
  /**
25
42
  * Validate that a URL hostname belongs to *.slack.com.
26
43
  * Used to prevent SSRF via manipulated upload URLs.
@@ -1 +1 @@
1
- {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../../src/messaging/slack/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMxD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO1D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD"}
1
+ {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../../src/messaging/slack/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMxD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO1D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD"}
@@ -3,6 +3,10 @@
3
3
  *
4
4
  * Prevents prompt injection, path traversal, and SSRF attacks
5
5
  * by validating and cleaning user-controlled fields before use.
6
+ *
7
+ * CONTRACT-EVIDENCE: EXEMPT — pure string-validation/slug helpers; this module
8
+ * makes NO Slack API calls and touches no API-contract surface. The added
9
+ * slugifyChannelName is covered by tests/unit/slack-channel-slug.test.ts.
6
10
  */
7
11
  const CHANNEL_ID_PATTERN = /^[CDG][A-Z0-9]{8,12}$/;
8
12
  const CHANNEL_NAME_PATTERN = /^[a-z0-9][a-z0-9\-_]{0,79}$/;
@@ -36,6 +40,25 @@ export function validateChannelId(id) {
36
40
  export function validateChannelName(name) {
37
41
  return CHANNEL_NAME_PATTERN.test(name);
38
42
  }
43
+ /**
44
+ * Slugify an arbitrary string into a valid Slack channel name.
45
+ *
46
+ * Slack channel names must be lowercase and may only contain [a-z0-9-_]
47
+ * (see {@link validateChannelName}). A workspace-derived name like
48
+ * "SageMind Live Test" contains spaces and uppercase, which `createChannel`
49
+ * rejects via validate-and-throw. This produces a guaranteed-valid slug:
50
+ * lowercase, non-[a-z0-9] runs collapsed to a single hyphen, leading/trailing
51
+ * hyphens trimmed, and clamped to Slack's 80-char limit.
52
+ *
53
+ * Mirrors the session-channel slug logic in SlackAdapter.
54
+ */
55
+ export function slugifyChannelName(name) {
56
+ return name
57
+ .toLowerCase()
58
+ .replace(/[^a-z0-9]+/g, '-')
59
+ .replace(/^-+|-+$/g, '')
60
+ .slice(0, 80);
61
+ }
39
62
  /**
40
63
  * Validate that a URL hostname belongs to *.slack.com.
41
64
  * Used to prevent SSRF via manipulated upload URLs.
@@ -1 +1 @@
1
- {"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../../../src/messaging/slack/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,kBAAkB,GAAG,uBAAuB,CAAC;AACnD,MAAM,oBAAoB,GAAG,6BAA6B,CAAC;AAC3D,4CAA4C;AAC5C,MAAM,aAAa,GAAG,kBAAkB,CAAC;AACzC,MAAM,eAAe,GAAG,UAAU,CAAC;AAEnC;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,IAAI;SACR,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC;SAC1B,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;SAC5B,IAAI,EAAE;SACN,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAU;IAC1C,OAAO,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,OAAO,MAAM,CAAC,QAAQ,KAAK,WAAW,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACnF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI;SACR,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,KAAK,CAAC,MAAM,IAAI,EAAE;QAAE,OAAO,KAAK,CAAC;IACrC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC;AACnC,CAAC"}
1
+ {"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../../../src/messaging/slack/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,kBAAkB,GAAG,uBAAuB,CAAC;AACnD,MAAM,oBAAoB,GAAG,6BAA6B,CAAC;AAC3D,4CAA4C;AAC5C,MAAM,aAAa,GAAG,kBAAkB,CAAC;AACzC,MAAM,eAAe,GAAG,UAAU,CAAC;AAEnC;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,IAAI;SACR,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC;SAC1B,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;SAC5B,IAAI,EAAE;SACN,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAU;IAC1C,OAAO,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,IAAI;SACR,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,OAAO,MAAM,CAAC,QAAQ,KAAK,WAAW,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACnF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI;SACR,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,KAAK,CAAC,MAAM,IAAI,EAAE;QAAE,OAAO,KAAK,CAAC;IACrC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC;AACnC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.561",
3
+ "version": "1.3.563",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-06-14T10:35:51.901Z",
5
- "instarVersion": "1.3.561",
4
+ "generatedAt": "2026-06-14T11:52:44.425Z",
5
+ "instarVersion": "1.3.563",
6
6
  "entryCount": 201,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -0,0 +1,46 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The boot helpers that auto-create the Slack "Updates" and "Attention" channels
9
+ (`ensureSlackUpdatesChannel` / `ensureSlackAttentionChannel` in
10
+ `src/commands/server.ts`) passed a raw, workspace-derived name straight into
11
+ `SlackAdapter.createChannel`. When the workspace name contained spaces or
12
+ uppercase (e.g. "SageMind Live Test"), that produced an invalid Slack channel
13
+ name like `SageMind Live Test-sys-updates`, which `createChannel` rejects via
14
+ `validateChannelName` — so the channel never got created and the boot logged
15
+ `Failed to create Slack Updates channel: Invalid channel name`.
16
+
17
+ Both callers now slugify the name first through a new shared
18
+ `slugifyChannelName` helper in `src/messaging/slack/sanitize.ts` (lowercase,
19
+ collapse non-`[a-z0-9]` runs to a single hyphen, trim edge hyphens, clamp to
20
+ Slack's 80-char limit) — mirroring the per-session channel slug logic the
21
+ adapter already used on its `-sess-` path. The `createChannel` /
22
+ `validateChannelName` contract other callers rely on is untouched.
23
+
24
+ ## What to Tell Your User
25
+
26
+ If your Slack workspace name has spaces or capital letters and your agent failed
27
+ to create its Updates or Attention channel (an "Invalid channel name" error on
28
+ startup), that's now fixed — the channel name is cleaned into a valid Slack
29
+ slug before creation. Workspaces whose name was already lowercase-and-dashes see
30
+ no change at all.
31
+
32
+ ## Summary of New Capabilities
33
+
34
+ - New `slugifyChannelName(name)` helper in the Slack sanitize module — a single
35
+ source of truth for turning an arbitrary name into a valid Slack channel name.
36
+ - The Slack Updates and Attention boot channels now create reliably regardless
37
+ of workspace-name casing or spaces.
38
+
39
+ ## Evidence
40
+
41
+ - `tests/unit/slack-channel-slug.test.ts` — the exact failing name
42
+ ("SageMind Live Test-sys-updates") now slugifies to a name `validateChannelName`
43
+ accepts; covers lowercasing, space-collapse, punctuation stripping, edge-hyphen
44
+ trim, already-valid passthrough, 80-char clamp, and a regression assertion that
45
+ the raw un-slugified name is rejected.
46
+ - `npx tsc --noEmit` clean; 9/9 new unit tests green.
@@ -0,0 +1,32 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Fixed a boot-ordering bug that meant the **Durable Inbound Message Queue** (`multiMachine.sessionPool.inboundQueue`) could NEVER construct its engine, regardless of config. In `startServer()`, the queue-engine construction gate read the module-level `_sessionPoolStage()` getter while it was still its initial stub (`() => 'dark'`) — the real liveConfig-reading implementation is only assigned ~350 lines further down the same synchronous boot flow. So the gate's `_sessionPoolStage() !== 'dark'` test was always false at construction time, the engine never built, and `GET /pool/queue` answered 503 forever even with the feature enabled and a non-dark session-pool stage. The feature ships dark/dry-run by default, so the fleet never hit this; it only bites the first agent to enable it for real.
9
+
10
+ The fix resolves the stage INLINE at the construction site, reading the same `multiMachine.sessionPool` config (liveConfig override over the static block) via a new shared pure helper `resolveSessionPoolStage(cfg)` in `src/core/inboundQueueConfig.ts`, instead of consulting the not-yet-wired ref. The live `_sessionPoolStage` getter is refactored to call the same helper, so the two stage readers can never drift apart again (that drift was the root cause). No new capability, config key, HTTP route, or authority — purely a correction to WHEN an existing decision is read.
11
+
12
+ audience: agent-only
13
+ maturity: stable
14
+
15
+ A no-deferrals audit of all five `_sessionPoolStage()` call sites confirmed exactly one genuinely-premature boot-time read (the construction gate). The three runtime-handler reads (`wireTelegramRouting` x2, the `onAccepted` forwarded-message callback) are correct as-is: they execute per-message AFTER boot and close over the ref, so they see the wired implementation when invoked.
16
+
17
+ ## What to Tell Your User
18
+
19
+ Nothing to announce proactively — the inbound queue ships disabled by default, so for any agent that hasn't deliberately turned it on, nothing changes. If asked: the crash-proof holding area for messages that arrive while a conversation is mid-move between machines had a startup bug that kept it from ever turning on; it now starts correctly when enabled. For a developer agent running it live, the queue's status page now returns real data instead of "not available." Every error path still fails toward off (no queue), which is identical to the shipped default.
20
+
21
+ ## Summary of New Capabilities
22
+
23
+ No new capability — a latent behavior-correctness fix restoring intended behavior.
24
+
25
+ | Change | Effect |
26
+ |--------|--------|
27
+ | Inbound-queue construction gate reads stage inline | The queue engine constructs when `inboundQueue.enabled=true` + a non-dark `sessionPool` stage (was: never) |
28
+ | `resolveSessionPoolStage(cfg)` shared helper | Single source of truth for the pool stage; boot gate + live getter can no longer drift |
29
+
30
+ ## Evidence
31
+
32
+ Behavior-correctness fix; reproduced by code-read on `JKHeadley/main` and pinned by a fails-before/passes-after structural regression guard. `tests/unit/inbound-queue-boot-order.test.ts` (5) asserts the construction gate no longer calls the stub getter, resolves inline before gating, routes both readers through the shared helper, and leaves the stub declaration intact (4 of 5 assertions fail against pre-fix `server.ts`; all 5 pass against the fix). `tests/unit/resolve-session-pool-stage.test.ts` (5) covers both sides of the stage-resolution boundary (enabled+stage→stage; disabled/missing→dark). The existing `tests/integration/inbound-queue-route.test.ts` and `tests/e2e/inbound-queue-lifecycle.test.ts` already prove a constructed engine serves a real 200 on `/pool/queue`. `npx tsc --noEmit` clean; full lint + dark-gate (24/24, line-map unchanged) + no-silent-fallbacks (baseline 474 unchanged) + feature-delivery-completeness + route-completeness green.
@@ -0,0 +1,16 @@
1
+ # Why the Slack Updates channel failed to create (and now doesn't)
2
+
3
+ ## The one-sentence version
4
+ When your Slack workspace had a space or a capital letter in its name (like "SageMind Live Test"), the agent tried to make a Slack channel literally named "SageMind Live Test-sys-updates" — but Slack only allows lowercase, no-spaces channel names, so the creation crashed every time. Now the name is cleaned up first.
5
+
6
+ ## Picture it
7
+ Imagine a mailroom that will only accept package labels written in lowercase with dashes instead of spaces. The agent was handing it a label that said "SageMind Live Test-sys-updates" — capital letters, spaces and all — and the mailroom kept rejecting it. The fix is a tiny label-printer that rewrites the label as "sagemind-live-test-sys-updates" before handing it over.
8
+
9
+ ## What changed, precisely
10
+ - The two callers that auto-create the Slack "Updates" and "Attention" channels were passing a raw, workspace-derived name straight into channel creation.
11
+ - That raw name kept its spaces and capitals, which Slack rejects — so the channel never got made and you saw "Invalid channel name".
12
+ - Now both callers run the name through a small slugifier first (lowercase it, turn anything that isn't a-z/0-9 into a single dash, trim stray dashes, cap at Slack's 80-char limit) — exactly the same cleanup the per-session Slack channels already used.
13
+
14
+ ## Why this is safe
15
+ - It only changes how the name is *built* before creation; it does not touch the channel-creation rule that other code relies on (that rule still rejects bad names — it just never sees one now).
16
+ - A name that was already valid passes through unchanged.
@@ -0,0 +1,72 @@
1
+ # Side-Effects Review — Inbound-Queue Boot-Order Fix
2
+
3
+ **Tier:** 1 (latent behavior-correctness fix restoring intended behavior — no new capability, no new config key, no new route, no new authority). **Parent principle:** Structure > Willpower / feature-is-alive — a feature that can never construct is a broken feature; this restores the intended construction path and pins it with a regression guard.
4
+ **Files:** src/commands/server.ts, src/core/inboundQueueConfig.ts, tests/unit/resolve-session-pool-stage.test.ts (new), tests/unit/inbound-queue-boot-order.test.ts (new)
5
+
6
+ ## The bug
7
+
8
+ The Durable Inbound Message Queue (`multiMachine.sessionPool.inboundQueue`, spec `docs/specs/durable-inbound-message-queue.md`) NEVER constructed its engine, regardless of correct config, because of a boot-ordering bug in `src/commands/server.ts`:
9
+
10
+ - `let _sessionPoolStage: () => string = () => 'dark';` — a module-level stub initialized to always return `'dark'`.
11
+ - The inbound-queue engine construction is gated `if (qcfg.enabled && _sessionPoolStage() !== 'dark') { … _inboundQueue = new QueueDrainLoop(…) … }`, running SYNCHRONOUSLY in the mesh boot block (`if (meshIdMgr && meshSelfId)`) inside `startServer()`.
12
+ - The ONLY reassignment of `_sessionPoolStage` to the real (liveConfig-reading) impl executes ~350 lines BELOW that construction site, also synchronously, in the same block.
13
+
14
+ At construction time the stub is still in force → `_sessionPoolStage()` returns `'dark'` → `'dark' !== 'dark'` is false → the engine never constructs. The same gate guards the `else if (_sweptInboundStore)` cleanup branch. Net: the feature has been inert since it shipped (it ships dark/dry-run by default, so nobody on the fleet hit it). `/pool/queue` returns 503 forever even with `inboundQueue.enabled=true` + a non-dark stage.
15
+
16
+ ## The no-deferrals audit — every `_sessionPoolStage()` call site
17
+
18
+ Grepped ALL uses of `_sessionPoolStage` in `src/commands/server.ts`. Verdict for each:
19
+
20
+ | Line (main) | Context | Runs synchronously at boot before the ~16045 reassignment? | Verdict |
21
+ |---|---|---|---|
22
+ | ~443 | `let _sessionPoolStage = () => 'dark'` | n/a (the stub declaration) | the bug SOURCE — left in place by design (runtime handlers legitimately close over it) |
23
+ | ~1992 | inside `wireTelegramRouting` (the per-message inbound dispatch handler) | NO — invoked per-message at runtime, after boot; closes over the ref and sees the wired impl | FINE — not fixed |
24
+ | ~2000 | inside `wireTelegramRouting` (same handler) | NO — same as above | FINE — not fixed |
25
+ | ~14434 | inside the `onAccepted` callback (fires when a forwarded mesh message arrives) | NO — runtime mesh-message handler; closes over the ref | FINE — not fixed |
26
+ | ~15694 | the inbound-queue engine CONSTRUCTION gate | **YES** — synchronous boot read, BEFORE the ~16045 reassignment | **BUGGY — FIXED** |
27
+ | ~16045 | the `_sessionPoolStage = () => {…}` reassignment to the real impl | n/a (the assignment itself; everything after it sees the wired impl) | FINE — refactored to use the shared helper |
28
+
29
+ Exactly ONE genuinely-premature boot-time read (15694). No sibling premature read left unfixed. The three runtime-handler reads (1992/2000/14434) are correct as-is — they execute only after boot, by which time the ref is wired; the `session-pool-activation-wiring.test.ts` structural test continues to assert those handlers use `_sessionPoolStage()`, and it stays green.
30
+
31
+ ## What changed
32
+
33
+ 1. **`src/core/inboundQueueConfig.ts`** — added a pure helper `resolveSessionPoolStage(cfg)` that returns the configured `stage` only when the pool is BOTH `enabled` AND carries a `stage`, else `'dark'`. This becomes the single source of truth for the stage decision, eliminating the hand-duplicated logic that let the two readers drift. No config types, defaults, or invariants changed.
34
+ 2. **`src/commands/server.ts` (construction site, ~15694):** the gate now computes the stage INLINE — `const _sessionPoolStageNow = (() => { try { const live = liveConfig.get('multiMachine.sessionPool', fallback); return iqcMod.resolveSessionPoolStage(live); } catch { return 'dark'; } })();` — mirroring the ~16045 impl exactly (liveConfig override over the static config block), then gates on `qcfg.enabled && _sessionPoolStageNow !== 'dark'`. It no longer consults the not-yet-wired `_sessionPoolStage()` ref.
35
+ 3. **`src/commands/server.ts` (the real getter, ~16045):** refactored to call the same `resolveSessionPoolStage` helper (dynamic-imported at that site, matching the file's existing dynamic-import pattern) instead of its own inline copy of the logic. Behavior identical; now DRY with the boot gate.
36
+ 4. **Tests (new):** `tests/unit/resolve-session-pool-stage.test.ts` (5) proves the resolution logic on both sides of the decision boundary; `tests/unit/inbound-queue-boot-order.test.ts` (5) is the structural regression guard — it asserts the construction gate no longer reads the stub, resolves inline before gating, routes both readers through the shared helper, and leaves the stub declaration intact.
37
+
38
+ ## Blast radius (activation, explicit)
39
+
40
+ - **Fleet = no-op.** The inbound queue ships `enabled: false` (and `dryRun: true` even when enabled) by default. No fleet agent's behavior changes: with the queue disabled, `qcfg.enabled` is false and the gate short-circuits before the stage is even consulted.
41
+ - **Any agent with `inboundQueue.enabled=true` AND `sessionPool` stage `!== 'dark'`** will now CONSTRUCT the queue engine where before it silently did not. `/pool/queue` flips from 503 to 200. For **Echo** this is the intended **no-dark-on-dev activation** — the dev agent enabling the feature live is the first real exercise of the construction path, which is exactly the path this fixes.
42
+ - **Multi-machine posture:** machine-local construction only. This is a behavior-correctness fix — it changes WHEN an existing local decision is read, not any cross-machine protocol, route, or mesh verb. A single-machine agent that hasn't enabled the queue is wholly unaffected.
43
+ - **No new authority surface.** The construction still requires the full existing gate chain (enabled + non-dark stage + the six config-seam invariants validated by `validateInboundQueueInvariants` + dry-run handling). Nothing about WHAT the queue is allowed to do changed.
44
+
45
+ ## Risk + mitigation
46
+
47
+ - **Risk:** the inline read disagrees with the live getter (the same drift class that caused the bug). **Mitigation:** both now call the single `resolveSessionPoolStage` helper — there is no second copy of the logic to drift. Pinned by `inbound-queue-boot-order.test.ts` (asserts ≥2 helper callsites) + `resolve-session-pool-stage.test.ts`.
48
+ - **Risk:** a config-read throw at the inline site crashes boot or builds a half-configured queue. **Mitigation:** the inline resolution is try/caught and fails to `'dark'` (the safe, queue-OFF direction = the shipped default), carrying an in-brace `@silent-fallback-ok` justification. Verified against `tests/unit/no-silent-fallbacks.test.ts` (baseline unchanged at 474).
49
+ - **Risk:** the fix accidentally activates the queue on the fleet. **Mitigation:** the `qcfg.enabled` half of the gate is untouched and still defaults false; the fix only corrects the stage half. Fleet default behavior is byte-identical.
50
+
51
+ ## Migration parity
52
+
53
+ - No agent-installed files changed: no `.claude/settings.json` hooks, no `.instar/config.json` defaults, no CLAUDE.md template section, no hook scripts, no built-in skills. `resolveSessionPoolStage` is a pure code helper consumed only by `server.ts`. No `PostUpdateMigrator` change is needed — existing agents pick up the corrected construction path the moment their server runs the new code.
54
+
55
+ ## Dark-gate line-map
56
+
57
+ - UNCHANGED. The change touches `src/core/inboundQueueConfig.ts` (a new pure function, no `enabled:` literal) and `src/commands/server.ts` (no `ConfigDefaults.ts` edit). The dark-gate attributor reads `src/core/ConfigDefaults.ts` only and matches `enabled:` lines; no such line shifted. Verified: `tests/unit/lint-dev-agent-dark-gate.test.ts` → 24/24 green, unchanged.
58
+
59
+ ## Rollback
60
+
61
+ - Revert the two source edits (the inline resolution at the construction site + the helper call at the getter) and delete the helper + the two new test files. The queue reverts to never-constructing (the prior broken-but-inert state). Because the feature ships dark, the revert is a strict no-op on the fleet. No data migration, no durable-state change.
62
+
63
+ ## Tests
64
+
65
+ - `tests/unit/resolve-session-pool-stage.test.ts` (5) — the stage-resolution logic: enabled+stage→stage; enabled+missing-stage→dark; disabled→dark; empty/null/undefined→dark; non-string stage coerced.
66
+ - `tests/unit/inbound-queue-boot-order.test.ts` (5) — the structural regression guard: the construction gate does not call the stub getter; resolves inline; resolution precedes the gate; both readers use the shared helper; the stub declaration is intact. Fails-before/passes-after verified (4 of 5 assertions fail against pre-fix `server.ts`; all 5 pass against the fix).
67
+ - Existing coverage already proves feature-alive: `tests/integration/inbound-queue-route.test.ts` (engine present → 200, absent → 503) and `tests/e2e/inbound-queue-lifecycle.test.ts` (boot-sweep → construct → drain → /pool/queue 200).
68
+ - Green locally: `npx tsc --noEmit` clean; the two new suites + `session-pool-activation-wiring` + `inbound-queue-route` + `inbound-queue-config` + `no-silent-fallbacks` + `feature-delivery-completeness` + `route-completeness` + `lint-dev-agent-dark-gate` (159 tests) all pass.
69
+
70
+ ## Agent awareness
71
+
72
+ - No CLAUDE.md change. The inbound queue is already documented in the agent template ("Durable Inbound Message Queue + Hold-for-Stability"); this fix restores the documented behavior rather than adding a capability, so no `generateClaudeMd`/`migrateClaudeMd` change is required (feature-delivery-completeness green — no new tracked section). <!-- tracked: inbound-queue-boot-order-fix -->
@@ -0,0 +1,46 @@
1
+ # Side-Effects Review — Slack Updates/Attention channel name slugify
2
+
3
+ ## Change summary
4
+ Caller-side fix in `src/commands/server.ts`: the `ensureSlackUpdatesChannel` and
5
+ `ensureSlackAttentionChannel` boot helpers now slugify the workspace-derived
6
+ channel name before calling `SlackAdapter.createChannel`, via a new shared
7
+ `slugifyChannelName` helper in `src/messaging/slack/sanitize.ts`. Mirrors the
8
+ existing per-session channel slug logic in `SlackAdapter` (`-sess-` path).
9
+
10
+ ## Tier
11
+ Tier 1 — small, low-risk, single-machine Slack-adapter boot-path bugfix. No
12
+ converged spec required.
13
+
14
+ ## Files touched
15
+ - `src/messaging/slack/sanitize.ts` — adds exported `slugifyChannelName(name)`.
16
+ - `src/commands/server.ts` — imports the helper; wraps both `-sys-updates` and
17
+ `-sys-attention` channel names with it before `createChannel`.
18
+ - `tests/unit/slack-channel-slug.test.ts` — new focused unit test.
19
+
20
+ ## Behavioral side-effects
21
+ - **Channel names on FRESH creation**: a workspace name containing spaces or
22
+ uppercase now yields a slugified channel (e.g. "SageMind Live Test" →
23
+ `sagemind-live-test-sys-updates`) instead of a hard failure. For workspaces
24
+ whose name was already slug-clean (lowercase, no spaces), the produced name is
25
+ byte-identical to before — no change.
26
+ - **No change to `createChannel` / `validateChannelName`**: the validate-and-throw
27
+ behavior other callers depend on is untouched; the fix only ensures these two
28
+ callers never hand it an invalid name.
29
+ - **Idempotent at the state layer**: both helpers early-return when their
30
+ `slack-*-channel` state key is already set, so this only affects the one-time
31
+ creation path; existing installs that already created a channel are unaffected.
32
+
33
+ ## Migration parity
34
+ - No agent-installed file changed (no `.claude/settings.json` hooks, no
35
+ `.instar/config.json` defaults, no CLAUDE.md template, no hook scripts, no
36
+ built-in skills). This is server-side runtime code shipped in the normal
37
+ build — existing agents receive it on their next update with no migration.
38
+
39
+ ## Rollback
40
+ - Revert the squash commit. The change is self-contained (one helper + two call
41
+ sites + one test); no data migration, no state schema change, nothing to undo.
42
+
43
+ ## Blast radius
44
+ - Limited to the Slack adapter boot path. Telegram / WhatsApp / iMessage and all
45
+ non-Slack code paths are untouched. Dark-gate config line-map unchanged (no
46
+ ConfigDefaults edit).